feat: добавил svg иконки
🚀 Create and publish a Docker image / Detect changes in backend and frontend (push) Successful in 8s
🚀 Create and publish a Docker image / Build & publish backend image (push) Successful in 12s
🚀 Create and publish a Docker image / Build & publish frontend image (push) Successful in 25s
🚀 Create and publish a Docker image / Update stack on Portainer (push) Successful in 6s
🚀 Create and publish a Docker image / Detect changes in backend and frontend (push) Successful in 8s
🚀 Create and publish a Docker image / Build & publish backend image (push) Successful in 12s
🚀 Create and publish a Docker image / Build & publish frontend image (push) Successful in 25s
🚀 Create and publish a Docker image / Update stack on Portainer (push) Successful in 6s
This commit is contained in:
@@ -10,6 +10,7 @@ import LectureCard from '@/components/ui/LectureCard.vue'
|
||||
import ProgressBar from '@/components/ui/ProgressBar.vue'
|
||||
import AchievementBadge from '@/components/ui/AchievementBadge.vue'
|
||||
import EmptyState from '@/components/ui/EmptyState.vue'
|
||||
import AppIcon from '@/components/ui/AppIcon.vue'
|
||||
import { formatUserName } from '@/utils/formatUserName'
|
||||
|
||||
const auth = useAuthStore()
|
||||
@@ -40,7 +41,10 @@ onMounted(async () => {
|
||||
<div class="dashboard page-content">
|
||||
<div class="dashboard-welcome">
|
||||
<div>
|
||||
<h1 class="page-title">Добрый день, {{ formatUserName(user.name) }}! 👋</h1>
|
||||
<h1 class="page-title">
|
||||
Добрый день, {{ formatUserName(user.name) }}!
|
||||
<AppIcon class="inline-icon" icon="hand-stop" :size="18" />
|
||||
</h1>
|
||||
<p class="text-secondary">{{ user.institute }} · {{ user.direction }} · {{ user.year }} курс</p>
|
||||
</div>
|
||||
<div class="quick-actions">
|
||||
@@ -56,9 +60,18 @@ onMounted(async () => {
|
||||
<div class="section-title">Ближайшая лекция</div>
|
||||
<div class="next-title">{{ nextLecture.title }}</div>
|
||||
<div class="next-meta">
|
||||
<span>📅 Завтра, {{ nextLecture.time }}</span>
|
||||
<span>🏛 {{ nextLecture.building }}, ауд. {{ nextLecture.room ?? 'онлайн' }}</span>
|
||||
<span>👤 {{ nextLecture.teacher }}</span>
|
||||
<span class="meta-line">
|
||||
<AppIcon class="meta-icon" icon="calendar" :size="14" />
|
||||
Завтра, {{ nextLecture.time }}
|
||||
</span>
|
||||
<span class="meta-line">
|
||||
<AppIcon class="meta-icon" icon="building" :size="14" />
|
||||
{{ nextLecture.building }}, ауд. {{ nextLecture.room ?? 'онлайн' }}
|
||||
</span>
|
||||
<span class="meta-line">
|
||||
<AppIcon class="meta-icon" icon="user" :size="14" />
|
||||
{{ nextLecture.teacher }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="next-actions">
|
||||
@@ -70,10 +83,10 @@ onMounted(async () => {
|
||||
<EmptyState v-else-if="!lectures.loading" title="Пока нет лекций" subtitle="Каталог пуст или данные ещё не синхронизированы." />
|
||||
|
||||
<div class="stats-row">
|
||||
<StatsWidget label="Посещено лекций" :value="user.lecturesAttended ?? 12" icon="📚" color="green" />
|
||||
<StatsWidget label="Часов обучения" :value="user.hoursLearned ?? 18.5" icon="⏱" color="aqua" />
|
||||
<StatsWidget label="Монет" :value="user.coins" icon="💰" color="orange" />
|
||||
<StatsWidget label="Уровень" :value="user.level" icon="⭐" color="purple" sub="текущий уровень" />
|
||||
<StatsWidget label="Посещено лекций" :value="user.lecturesAttended ?? 12" icon="books" color="green" />
|
||||
<StatsWidget label="Часов обучения" :value="user.hoursLearned ?? 18.5" icon="stopwatch" color="aqua" />
|
||||
<StatsWidget label="Монет" :value="user.coins" icon="coin" color="orange" />
|
||||
<StatsWidget label="Уровень" :value="user.level" icon="star" color="purple" sub="текущий уровень" />
|
||||
</div>
|
||||
|
||||
<GlassCard>
|
||||
@@ -88,7 +101,12 @@ onMounted(async () => {
|
||||
|
||||
<section>
|
||||
<div class="section-header">
|
||||
<h2 class="section-title">✨ Рекомендуемые лекции</h2>
|
||||
<h2 class="section-title">
|
||||
<span class="title-with-icon">
|
||||
<AppIcon class="title-icon" icon="sparkles" :size="18" />
|
||||
Рекомендуемые лекции
|
||||
</span>
|
||||
</h2>
|
||||
<button class="link-btn" @click="router.push('/catalog')">Все лекции →</button>
|
||||
</div>
|
||||
<EmptyState v-if="lectures.loading" title="Загружаем рекомендации" subtitle="Получаем данные с backend." />
|
||||
@@ -105,7 +123,12 @@ onMounted(async () => {
|
||||
|
||||
<section class="two-column">
|
||||
<GlassCard>
|
||||
<div class="section-title">🏆 Достижения</div>
|
||||
<div class="section-title">
|
||||
<span class="title-with-icon">
|
||||
<AppIcon class="title-icon" icon="trophy" :size="18" />
|
||||
Достижения
|
||||
</span>
|
||||
</div>
|
||||
<div class="achievements">
|
||||
<AchievementBadge
|
||||
v-for="a in achievements"
|
||||
@@ -120,7 +143,12 @@ onMounted(async () => {
|
||||
</div>
|
||||
</GlassCard>
|
||||
<GlassCard>
|
||||
<div class="section-title">🔔 Напоминания</div>
|
||||
<div class="section-title">
|
||||
<span class="title-with-icon">
|
||||
<AppIcon class="title-icon" icon="bell" :size="18" />
|
||||
Напоминания
|
||||
</span>
|
||||
</div>
|
||||
<div class="reminders">
|
||||
<div class="reminder-item" v-for="n in reminders" :key="n.id">
|
||||
<div class="reminder-title">{{ n.title }}</div>
|
||||
@@ -146,6 +174,8 @@ onMounted(async () => {
|
||||
.next-lecture { display: flex; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
|
||||
.next-title { font-size: 18px; font-weight: 700; margin: 6px 0; }
|
||||
.next-meta { display: flex; flex-direction: column; gap: 4px; color: var(--color-text-secondary); font-size: 13px; }
|
||||
.meta-line { display: inline-flex; align-items: center; gap: 6px; }
|
||||
.meta-icon { color: var(--color-text-secondary); }
|
||||
.next-actions { display: flex; gap: 10px; align-items: flex-start; }
|
||||
.stats-row {
|
||||
display: grid;
|
||||
@@ -156,6 +186,9 @@ onMounted(async () => {
|
||||
.xp-header { display: flex; justify-content: space-between; font-size: 13px; font-weight: 600; }
|
||||
.xp-val { color: var(--color-text-secondary); }
|
||||
.section-header { display: flex; align-items: center; justify-content: space-between; }
|
||||
.title-with-icon { display: inline-flex; align-items: center; gap: 8px; }
|
||||
.title-icon { color: var(--color-text); }
|
||||
.inline-icon { color: var(--color-text); vertical-align: middle; }
|
||||
.cards-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import { computed } from 'vue'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
import GlassCard from '@/components/ui/GlassCard.vue'
|
||||
import AppIcon from '@/components/ui/AppIcon.vue'
|
||||
|
||||
const userStore = useUserStore()
|
||||
|
||||
@@ -16,11 +17,11 @@ const grouped = computed(() => {
|
||||
})
|
||||
|
||||
const typeIcon: Record<string, string> = {
|
||||
reminder: '⏰',
|
||||
'schedule-change': '🗓️',
|
||||
achievement: '🏆',
|
||||
coins: '💰',
|
||||
recommendation: '✨',
|
||||
reminder: 'alarm',
|
||||
'schedule-change': 'calendar-event',
|
||||
achievement: 'trophy',
|
||||
coins: 'coin',
|
||||
recommendation: 'sparkles',
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -36,7 +37,7 @@ const typeIcon: Record<string, string> = {
|
||||
<div class="group-title">{{ day }}</div>
|
||||
<div class="items">
|
||||
<div v-for="n in items" :key="n.id" class="item" :class="{ unread: !n.read }">
|
||||
<div class="icon">{{ typeIcon[n.type] }}</div>
|
||||
<AppIcon class="icon" :icon="typeIcon[n.type]" :size="20" />
|
||||
<div>
|
||||
<div class="item-title">{{ n.title }}</div>
|
||||
<div class="item-body">{{ n.body }}</div>
|
||||
@@ -56,7 +57,7 @@ const typeIcon: Record<string, string> = {
|
||||
.items { display: flex; flex-direction: column; gap: 10px; }
|
||||
.item { display: flex; gap: 12px; padding: 10px; border-radius: var(--radius-sm); background: rgba(255,255,255,0.6); border: 1px solid var(--color-border-glass); }
|
||||
.item.unread { border-color: rgba(34,197,94,0.4); background: rgba(34,197,94,0.08); }
|
||||
.icon { font-size: 20px; }
|
||||
.icon { color: var(--color-text); flex-shrink: 0; }
|
||||
.item-title { font-weight: 600; }
|
||||
.item-body { font-size: 13px; color: var(--color-text-secondary); }
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user