generated from VLADIMIR/template_frontend
up
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
<script setup lang="ts">
|
||||
import { darkTheme, NButton, NConfigProvider } from 'naive-ui'
|
||||
import { nextTick, ref } from 'vue'
|
||||
|
||||
import ComponentDesignCatalog from '@/components/ComponentDesignCatalog.vue'
|
||||
import GameDesignPreview from '@/components/GameDesignPreview.vue'
|
||||
import SiteDesignPreview from '@/components/SiteDesignPreview.vue'
|
||||
const tabs = [
|
||||
{ name: 'site', label: 'Сайт' },
|
||||
{ name: 'game', label: 'Игра' },
|
||||
{ name: 'components', label: 'Компоненты' },
|
||||
] as const
|
||||
const activeTab = ref<(typeof tabs)[number]['name']>('site')
|
||||
const tabList = ref<HTMLElement | null>(null)
|
||||
async function handleTabKey(event: KeyboardEvent) {
|
||||
if (!['ArrowLeft', 'ArrowRight', 'Home', 'End'].includes(event.key)) return
|
||||
event.preventDefault()
|
||||
const index = tabs.findIndex((tab) => tab.name === activeTab.value)
|
||||
const nextIndex =
|
||||
event.key === 'Home'
|
||||
? 0
|
||||
: event.key === 'End'
|
||||
? tabs.length - 1
|
||||
: (index + (event.key === 'ArrowRight' ? 1 : -1) + tabs.length) % tabs.length
|
||||
activeTab.value = tabs[nextIndex]!.name
|
||||
await nextTick()
|
||||
tabList.value?.querySelector<HTMLButtonElement>('[aria-selected="true"]')?.focus()
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<n-config-provider :theme="darkTheme">
|
||||
<header class="design-header">Вечерний детектив · Дизайн-система</header>
|
||||
<main class="center-block-custom design-scroll">
|
||||
<div
|
||||
ref="tabList"
|
||||
class="design-tabs"
|
||||
role="tablist"
|
||||
aria-label="Стили оформления"
|
||||
@keydown="handleTabKey"
|
||||
>
|
||||
<n-button
|
||||
v-for="tab in tabs"
|
||||
:id="`tab-${tab.name}`"
|
||||
:key="tab.name"
|
||||
role="tab"
|
||||
:aria-selected="activeTab === tab.name"
|
||||
:aria-controls="`panel-${tab.name}`"
|
||||
:tabindex="activeTab === tab.name ? 0 : -1"
|
||||
:type="activeTab === tab.name ? 'primary' : 'default'"
|
||||
@click="activeTab = tab.name"
|
||||
>{{ tab.label }}</n-button
|
||||
>
|
||||
</div>
|
||||
<div
|
||||
:id="`panel-${activeTab}`"
|
||||
role="tabpanel"
|
||||
:aria-labelledby="`tab-${activeTab}`"
|
||||
tabindex="0"
|
||||
>
|
||||
<SiteDesignPreview v-if="activeTab === 'site'" />
|
||||
<GameDesignPreview v-else-if="activeTab === 'game'" />
|
||||
<ComponentDesignCatalog v-else />
|
||||
</div>
|
||||
</main>
|
||||
</n-config-provider>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.design-header {
|
||||
align-items: center;
|
||||
background: var(--brand-background);
|
||||
color: var(--brand-text);
|
||||
display: flex;
|
||||
font-size: 16px;
|
||||
height: 70px;
|
||||
left: 0;
|
||||
padding: 0 16px;
|
||||
position: fixed;
|
||||
right: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.design-scroll {
|
||||
background: var(--brand-background);
|
||||
}
|
||||
|
||||
.design-tabs {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
padding: 16px;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user