152 lines
3.2 KiB
Vue
152 lines
3.2 KiB
Vue
|
|
<script setup lang="ts">
|
|||
|
|
import { computed, onMounted, ref } from 'vue'
|
|||
|
|
import { fetchTeams } from './api'
|
|||
|
|
import type { Team } from './types'
|
|||
|
|
import TeamSidebar from './components/TeamSidebar.vue'
|
|||
|
|
import SprintTable from './components/SprintTable.vue'
|
|||
|
|
|
|||
|
|
const teams = ref<Team[]>([])
|
|||
|
|
const selectedTeamId = ref<number | null>(null)
|
|||
|
|
const loadingTeams = ref(true)
|
|||
|
|
const teamsError = ref<string | null>(null)
|
|||
|
|
|
|||
|
|
onMounted(async () => {
|
|||
|
|
try {
|
|||
|
|
teams.value = await fetchTeams()
|
|||
|
|
if (teams.value.length > 0) {
|
|||
|
|
selectedTeamId.value = teams.value[0].id
|
|||
|
|
}
|
|||
|
|
} catch (error) {
|
|||
|
|
teamsError.value = error instanceof Error ? error.message : 'Не удалось загрузить команды'
|
|||
|
|
} finally {
|
|||
|
|
loadingTeams.value = false
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
function selectTeam(teamId: number) {
|
|||
|
|
selectedTeamId.value = teamId
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const selectedTeam = computed(
|
|||
|
|
() => teams.value.find((team) => team.id === selectedTeamId.value) ?? null,
|
|||
|
|
)
|
|||
|
|
</script>
|
|||
|
|
|
|||
|
|
<template>
|
|||
|
|
<div class="layout">
|
|||
|
|
<aside class="sidebar">
|
|||
|
|
<div class="sidebar__header">
|
|||
|
|
<h1 class="sidebar__title">Команды</h1>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div v-if="loadingTeams" class="sidebar__state">Загрузка...</div>
|
|||
|
|
<div v-else-if="teamsError" class="sidebar__state sidebar__state--error">{{ teamsError }}</div>
|
|||
|
|
<TeamSidebar
|
|||
|
|
v-else
|
|||
|
|
:teams="teams"
|
|||
|
|
:selected-team-id="selectedTeamId"
|
|||
|
|
@select="selectTeam"
|
|||
|
|
/>
|
|||
|
|
</aside>
|
|||
|
|
|
|||
|
|
<main class="main">
|
|||
|
|
<header class="main__header">
|
|||
|
|
<h2 class="main__title">
|
|||
|
|
{{ selectedTeam?.name ?? 'Сводка по спринтам' }}
|
|||
|
|
</h2>
|
|||
|
|
<p class="main__subtitle">Спринты отсортированы по дате начала</p>
|
|||
|
|
</header>
|
|||
|
|
|
|||
|
|
<SprintTable v-if="selectedTeamId !== null" :team-id="selectedTeamId" />
|
|||
|
|
<div v-else class="main__empty">Выберите команду в сайдбаре</div>
|
|||
|
|
</main>
|
|||
|
|
</div>
|
|||
|
|
</template>
|
|||
|
|
|
|||
|
|
<style scoped>
|
|||
|
|
.layout {
|
|||
|
|
display: grid;
|
|||
|
|
grid-template-columns: 240px 1fr;
|
|||
|
|
min-height: 100vh;
|
|||
|
|
background: #23272a;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.sidebar {
|
|||
|
|
position: relative;
|
|||
|
|
display: flex;
|
|||
|
|
flex-direction: column;
|
|||
|
|
padding: 8px 0 16px;
|
|||
|
|
background: #1e2226;
|
|||
|
|
border-right: 0.5px solid rgba(255, 255, 255, 0.06);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.sidebar__header {
|
|||
|
|
padding: 12px 16px 4px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.sidebar__title {
|
|||
|
|
margin: 0;
|
|||
|
|
font-size: 11px;
|
|||
|
|
font-weight: 600;
|
|||
|
|
letter-spacing: 0.04em;
|
|||
|
|
text-transform: uppercase;
|
|||
|
|
color: rgba(235, 235, 245, 0.55);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.sidebar__state {
|
|||
|
|
padding: 8px 16px;
|
|||
|
|
font-size: 13px;
|
|||
|
|
color: rgba(235, 235, 245, 0.45);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.sidebar__state--error {
|
|||
|
|
color: #ff6961;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.main {
|
|||
|
|
padding: 28px 36px;
|
|||
|
|
overflow-x: auto;
|
|||
|
|
background: #23272a;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.main__header {
|
|||
|
|
margin-bottom: 24px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.main__title {
|
|||
|
|
margin: 0 0 4px;
|
|||
|
|
font-size: 1.625rem;
|
|||
|
|
font-weight: 600;
|
|||
|
|
letter-spacing: -0.02em;
|
|||
|
|
color: #f5f5f7;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.main__subtitle {
|
|||
|
|
margin: 0;
|
|||
|
|
color: rgba(235, 235, 245, 0.55);
|
|||
|
|
font-size: 0.875rem;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.main__empty {
|
|||
|
|
color: rgba(235, 235, 245, 0.45);
|
|||
|
|
padding: 48px 0;
|
|||
|
|
text-align: center;
|
|||
|
|
font-size: 0.9375rem;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@media (max-width: 900px) {
|
|||
|
|
.layout {
|
|||
|
|
grid-template-columns: 1fr;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.sidebar {
|
|||
|
|
border-right: none;
|
|||
|
|
border-bottom: 0.5px solid rgba(255, 255, 255, 0.06);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.main {
|
|||
|
|
padding: 24px 20px;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
</style>
|