feat(ui): adopt Tailwind v4 design system and archive change

- Add tailwindcss v4 + @tailwindcss/vite to mall, shop-admin, admin
- Add @vmall/shared/theme.css tokens with html[data-accent] presets
- Add @vmall/ui kit (VBtn/VBadge/VField/VInput/VCard/VPanel/VTable/VPage,
  VAccentSwatch, useAccent) as a Nuxt module
- Convert all three apps to kit + utilities; delete ui.css/mall.css and
  every <style scoped>; consoles get accent presets, mall locked to red
- Fix VCard boolean prop default (padding) and PDP/store stale
  useAsyncData keys on param navigation
- Archive adopt-tailwind-design-system; new frontend-ui capability spec
This commit is contained in:
Chengdong Zhang
2026-09-22 18:22:50 +08:00
parent 4d2ee3b0bf
commit 0d0e10b97b
101 changed files with 2833 additions and 7207 deletions
+31 -66
View File
@@ -4,86 +4,51 @@ const { t } = useI18n();
</script>
<template>
<div class="topbar">
<div class="w1200 topbar-in">
<ul class="left">
<li><NuxtLink to="/">{{ t("shell.officialSite") }}</NuxtLink></li>
<li>|</li>
<li><NuxtLink to="/">{{ t("shell.mallHome") }}</NuxtLink></li>
<li>|</li>
<li><NuxtLink to="/">{{ t("shell.contact") }}</NuxtLink></li>
<li>|</li>
<li><NuxtLink to="/">{{ t("shell.about") }}</NuxtLink></li>
<li>|</li>
<li class="city">{{ t("shell.city") }}</li>
<div class="h-[30px] border-b border-border bg-[#f9f9f9] text-[12px] leading-[30px] text-muted">
<div class="mx-auto flex h-full max-w-mall items-center justify-between px-4">
<ul class="flex items-center">
<li><NuxtLink to="/" class="px-1 hover:text-primary">{{ t("shell.officialSite") }}</NuxtLink></li>
<li class="px-1 text-border">|</li>
<li><NuxtLink to="/" class="px-1 hover:text-primary">{{ t("shell.mallHome") }}</NuxtLink></li>
<li class="px-1 text-border">|</li>
<li><NuxtLink to="/" class="px-1 hover:text-primary">{{ t("shell.contact") }}</NuxtLink></li>
<li class="px-1 text-border">|</li>
<li><NuxtLink to="/" class="px-1 hover:text-primary">{{ t("shell.about") }}</NuxtLink></li>
<li class="px-1 text-border">|</li>
<li class="px-1 text-primary">{{ t("shell.city") }}</li>
</ul>
<ul class="right">
<ul class="flex items-center">
<!-- The token lives in localStorage, so the server cannot know whether
anyone is signed in. Rendering this branch client-only keeps the
hydrated DOM in step with the server's logged-out markup; without
it, validating the session before hydration reports mismatches. -->
<ClientOnly>
<template v-if="session.isLoggedIn">
<li>{{ t("shell.welcome") }}<NuxtLink to="/user" class="red">{{ session.user?.display_name }}</NuxtLink></li>
<li>|</li>
<li><NuxtLink to="/user">{{ t("shell.userCenter") }}</NuxtLink></li>
<li>|</li>
<li class="clickable" @click="session.logout()">{{ t("shell.logout") }}</li>
<li class="px-1">
{{ t("shell.welcome") }}
<NuxtLink to="/user" class="text-primary hover:text-primary-hover">{{ session.user?.display_name }}</NuxtLink>
</li>
<li class="px-1 text-border">|</li>
<li><NuxtLink to="/user" class="px-1 hover:text-primary">{{ t("shell.userCenter") }}</NuxtLink></li>
<li class="px-1 text-border">|</li>
<li class="cursor-pointer px-1 hover:text-primary" @click="session.logout()">{{ t("shell.logout") }}</li>
</template>
<template v-else>
<li><NuxtLink to="/login" class="red">{{ t("shell.login") }}</NuxtLink></li>
<li><NuxtLink to="/register">{{ t("shell.register") }}</NuxtLink></li>
<li><NuxtLink to="/login" class="px-1 text-primary hover:text-primary-hover">{{ t("shell.login") }}</NuxtLink></li>
<li><NuxtLink to="/register" class="px-1 hover:text-primary">{{ t("shell.register") }}</NuxtLink></li>
</template>
<template #fallback>
<li><NuxtLink to="/login" class="red">{{ t("shell.login") }}</NuxtLink></li>
<li><NuxtLink to="/register">{{ t("shell.register") }}</NuxtLink></li>
<li><NuxtLink to="/login" class="px-1 text-primary hover:text-primary-hover">{{ t("shell.login") }}</NuxtLink></li>
<li><NuxtLink to="/register" class="px-1 hover:text-primary">{{ t("shell.register") }}</NuxtLink></li>
</template>
</ClientOnly>
<li>|</li>
<li><NuxtLink to="/stores" class="red">{{ t("shell.sellerJoin") }}</NuxtLink></li>
<li>|</li>
<li><NuxtLink to="/">{{ t("shell.mobile") }}</NuxtLink></li>
<li>|</li>
<li><NuxtLink to="/">{{ t("shell.appDownload") }}</NuxtLink></li>
<li class="px-1 text-border">|</li>
<li><NuxtLink to="/stores" class="px-1 text-primary hover:text-primary-hover">{{ t("shell.sellerJoin") }}</NuxtLink></li>
<li class="px-1 text-border">|</li>
<li><NuxtLink to="/" class="px-1 hover:text-primary">{{ t("shell.mobile") }}</NuxtLink></li>
<li class="px-1 text-border">|</li>
<li><NuxtLink to="/" class="px-1 hover:text-primary">{{ t("shell.appDownload") }}</NuxtLink></li>
</ul>
</div>
</div>
</template>
<style scoped>
.topbar {
border-bottom: 1px solid var(--mall-line);
height: 30px;
background: #f9f9f9;
font-size: 12px;
line-height: 30px;
}
.topbar-in {
display: flex;
justify-content: space-between;
}
ul {
display: flex;
list-style: none;
margin: 0;
padding: 0;
}
li {
padding: 0 5px;
}
a {
color: inherit;
text-decoration: none;
}
a:hover,
.clickable:hover {
color: var(--mall-red);
cursor: pointer;
}
.red {
color: var(--mall-red);
}
.city {
color: var(--mall-red);
}
</style>