feat: add main app route skeleton

This commit is contained in:
QiuSW
2026-07-08 23:06:48 +08:00
parent 4c1de99d65
commit 811a9c889f
16 changed files with 849 additions and 30 deletions
@@ -0,0 +1,79 @@
<script setup lang="ts">
type SummaryTone = 'blue' | 'green' | 'amber' | 'red' | 'slate' | 'violet'
type SummaryItem = {
label: string
value: string
helper?: string
tone?: SummaryTone
}
withDefaults(defineProps<{
eyebrow?: string
title: string
description: string
status?: string
items?: SummaryItem[]
}>(), {
eyebrow: '',
status: '骨架已就绪',
items: () => [],
})
const toneClasses: Record<SummaryTone, string> = {
blue: 'border-blue-200 bg-blue-50 text-blue-900 dark:border-blue-900/50 dark:bg-blue-950/40 dark:text-blue-100',
green: 'border-emerald-200 bg-emerald-50 text-emerald-900 dark:border-emerald-900/50 dark:bg-emerald-950/40 dark:text-emerald-100',
amber: 'border-amber-200 bg-amber-50 text-amber-900 dark:border-amber-900/50 dark:bg-amber-950/40 dark:text-amber-100',
red: 'border-rose-200 bg-rose-50 text-rose-900 dark:border-rose-900/50 dark:bg-rose-950/40 dark:text-rose-100',
slate: 'border-slate-200 bg-white text-slate-900 dark:border-slate-700 dark:bg-slate-900 dark:text-slate-100',
violet: 'border-violet-200 bg-violet-50 text-violet-900 dark:border-violet-900/50 dark:bg-violet-950/40 dark:text-violet-100',
}
function toneClass(tone?: SummaryTone) {
return toneClasses[tone || 'slate']
}
</script>
<template>
<section class="min-h-full w-full">
<div class="flex w-full flex-col gap-4">
<header class="flex flex-col gap-3 border-b border-slate-200 pb-4 dark:border-slate-800 md:flex-row md:items-start md:justify-between">
<div class="min-w-0">
<p v-if="eyebrow" class="mb-1 text-xs font-semibold uppercase text-slate-500 dark:text-slate-400">
{{ eyebrow }}
</p>
<h1 class="mb-1 text-2xl font-semibold text-slate-950 dark:text-white">
{{ title }}
</h1>
<p class="max-w-3xl text-sm leading-6 text-slate-600 dark:text-slate-300">
{{ description }}
</p>
</div>
<span v-if="status" class="inline-flex shrink-0 items-center rounded-md border border-slate-200 bg-white px-3 py-1 text-xs font-medium text-slate-600 dark:border-slate-700 dark:bg-slate-900 dark:text-slate-300">
{{ status }}
</span>
</header>
<div v-if="items.length" class="grid grid-cols-1 gap-3 md:grid-cols-2 xl:grid-cols-4">
<div
v-for="item in items"
:key="item.label"
class="rounded-lg border p-4"
:class="toneClass(item.tone)"
>
<p class="text-xs font-medium opacity-75">
{{ item.label }}
</p>
<p class="mt-2 text-2xl font-semibold">
{{ item.value }}
</p>
<p v-if="item.helper" class="mt-1 text-xs opacity-70">
{{ item.helper }}
</p>
</div>
</div>
<slot />
</div>
</section>
</template>