style: 更新了应用的样式和主题,调整了颜色变量以支持深色模式

This commit is contained in:
2026-01-24 01:34:24 +08:00
parent a8c96d84f0
commit 9abcab2c6a
21 changed files with 312 additions and 127 deletions

View File

@@ -1,7 +1,7 @@
{
"name": "web",
"private": true,
"version": "0.0.0",
"version": "1.0.4",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -10,6 +10,24 @@ const isAdmin = computed(() => userRef.value?.role === "admin");
const menuOpen = ref(false);
// theme: light | dark
const theme = ref(
(typeof localStorage !== "undefined" && localStorage.getItem("bb_theme")) ||
(typeof window !== "undefined" && window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches
? "dark"
: "light")
);
function applyTheme(next) {
const isDark = (next || theme.value) === "dark";
const root = document.documentElement;
root.classList.toggle("theme-dark", isDark);
}
function toggleTheme() {
theme.value = theme.value === "dark" ? "light" : "dark";
}
function toggleMenu() {
menuOpen.value = !menuOpen.value;
}
@@ -62,6 +80,7 @@ function onDocPointerDown(e) {
onMounted(() => {
document.addEventListener("pointerdown", onDocPointerDown);
applyTheme();
});
watch(
@@ -77,6 +96,15 @@ onMounted(() => {
if (loggedIn.value) ensureMe();
});
watch(
() => theme.value,
(next) => {
try { localStorage.setItem("bb_theme", next); } catch {}
applyTheme(next);
},
{ immediate: false }
);
onBeforeUnmount(() => {
document.removeEventListener("pointerdown", onDocPointerDown);
});
@@ -107,12 +135,15 @@ router.afterEach(() => {
</button>
<div v-if="menuOpen" class="menu" role="menu">
<RouterLink class="menuItem menuItem--import" to="/import" role="menuitem">导入 / 导出</RouterLink>
<button class="menuItem" type="button" role="menuitem" @click="toggleTheme">
切换{{ theme === 'dark' ? '浅色' : '深色' }}
</button>
<a class="menuItem" href="http://mark.cloud-xl.top:9527/extension-dist.zip" role="menuitem" download>
下载插件
</a>
<RouterLink class="menuItem menuItem--password" to="/passwords" role="menuitem">密码管理</RouterLink>
<RouterLink class="menuItem menuItem--password" to="/passwords" role="menuitem">管理密码</RouterLink>
<RouterLink v-if="isAdmin" class="menuItem" to="/admin" role="menuitem">管理用户</RouterLink>
<RouterLink class="menuItem menuItem--import" to="/import" role="menuitem">导入导出</RouterLink>
<button class="menuItem danger" type="button" role="menuitem" @click="logout">退出登录</button>
</div>
</div>
@@ -138,13 +169,13 @@ router.afterEach(() => {
</template>
<style scoped>
.nav { position: sticky; top: 0; z-index: 10; background: rgba(255,255,255,0.55); backdrop-filter: blur(14px); border-bottom: 1px solid rgba(255,255,255,0.35); }
.nav { position: sticky; top: 0; z-index: 10; background: var(--bb-nav-bg); backdrop-filter: blur(14px); border-bottom: 1px solid rgba(255,255,255,0.35); }
.navInner { max-width: 1100px; margin: 0 auto; padding: 10px 16px; display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.brand { display: inline-flex; align-items: center; gap: 10px; font-weight: 900; color: var(--bb-text); text-decoration: none; letter-spacing: -0.02em; }
.brandMark { width: 34px; height: 34px; border-radius: 12px; display: grid; place-items: center; background: var(--bb-clay); box-shadow: var(--bb-shadow-clay); border: 1px solid rgba(255,255,255,0.7); }
.brandText { font-size: 14px; }
.links { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; justify-content: flex-end; }
.link { color: var(--bb-text); text-decoration: none; padding: 9px 12px; border-radius: 14px; transition: transform 120ms ease, box-shadow 120ms ease, background 150ms, color 150ms; background: rgba(255,255,255,0.25); border: 1px solid rgba(255,255,255,0.45); }
.link { color: var(--bb-text); text-decoration: none; padding: 9px 12px; border-radius: 14px; transition: transform 120ms ease, box-shadow 120ms ease, background 150ms, color 150ms; background: var(--bb-panel); border: 1px solid rgba(255,255,255,0.45); }
.link:hover { box-shadow: 0 10px 30px rgba(15, 23, 42, 0.10); transform: translateY(-1px); }
.link.router-link-active {
background: linear-gradient(135deg, var(--bb-primary), var(--bb-cta));
@@ -165,7 +196,7 @@ router.afterEach(() => {
width: 220px;
padding: 8px;
border-radius: 16px;
background: rgba(255,255,255,0.72);
background: var(--bb-menu-bg);
border: 1px solid rgba(255,255,255,0.5);
backdrop-filter: blur(16px);
box-shadow: 0 20px 70px rgba(15, 23, 42, 0.16);
@@ -179,15 +210,17 @@ router.afterEach(() => {
padding: 10px 12px;
border-radius: 14px;
border: 1px solid rgba(255,255,255,0.35);
background: rgba(255,255,255,0.35);
background: var(--bb-menu-item-bg);
color: var(--bb-text);
text-decoration: none;
cursor: pointer;
font-size: 15px;
}
.menuItem + .menuItem { margin-top: 8px; }
.menuItem:hover { background: rgba(255,255,255,0.6); }
.menuItem:hover { background: var(--bb-menu-item-hover); }
.menuItem.danger { color: #991b1b; background: rgba(254, 202, 202, 0.35); border-color: rgba(254, 202, 202, 0.6); }
@media (max-width: 640px) {
.menuItem--import { display: none; }
.menuItem--password { display: none; }

View File

@@ -66,8 +66,8 @@ onBeforeUnmount(() => {
max-height: min(84vh, 860px);
overflow: auto;
border-radius: 18px;
border: 1px solid rgba(255,255,255,0.65);
background: rgba(255,255,255,0.82);
border: 1px solid var(--bb-modal-border);
background: var(--bb-modal-bg);
backdrop-filter: blur(14px);
box-shadow: 0 18px 60px rgba(15, 23, 42, 0.18);
}
@@ -105,4 +105,28 @@ onBeforeUnmount(() => {
.bb-modalBody {
padding: 14px;
}
:global(.theme-dark) .bb-modalBackdrop {
background: rgba(0, 0, 0, 0.75);
}
:global(.theme-dark) .bb-modalPanel {
background: var(--bb-modal-bg);
border-color: var(--bb-modal-border);
box-shadow: 0 18px 60px rgba(0,0,0,0.55);
}
:global(.theme-dark) .bb-modalHeader {
border-bottom: 1px solid rgba(148,163,184,0.18);
}
:global(.theme-dark) .bb-modalClose {
background: #3a3a3a;
border-color: rgba(148,163,184,0.32);
color: #ffffff;
}
:global(.theme-dark) .bb-modalClose:hover {
background: #444444;
}
</style>

View File

@@ -418,18 +418,19 @@ onMounted(async () => {
text-align: left;
padding: 10px 12px;
border-radius: 16px;
border: 1px solid rgba(255,255,255,0.45);
background: rgba(255,255,255,0.35);
border: 1px solid var(--bb-border);
background: var(--bb-folder-bg);
cursor: pointer;
display: flex;
align-items: center;
justify-content: space-between;
gap: 10px;
}
.bb-adminFolderHeader:hover { background: rgba(255,255,255,0.6); }
.bb-adminFolderHeader:hover { background: var(--bb-folder-hover); }
.bb-adminFolderHeader .name { font-weight: 900; color: var(--bb-text); }
.bb-adminFolderHeader .meta { font-size: 12px; color: rgba(19, 78, 74, 0.72); }
.bb-adminFolderHeader .meta { font-size: 12px; color: var(--bb-muted); }
.bb-adminFolderBody { margin-top: 10px; }
.bb-adminFolderDel { white-space: nowrap; }
.bb-adminActions { display: flex; gap: 8px; flex-wrap: wrap; }
</style>

View File

@@ -859,17 +859,17 @@ onBeforeUnmount(() => {
text-align: left;
padding: 8px 10px;
border-radius: 16px;
border: 1px solid rgba(255,255,255,0.45);
background: rgba(255,255,255,0.35);
border: 1px solid var(--bb-border);
background: var(--bb-folder-bg);
cursor: pointer;
display: flex;
align-items: center;
justify-content: space-between;
gap: 10px;
}
.bb-myFolderHeader:hover { background: rgba(255,255,255,0.6); }
.bb-myFolderHeader:hover { background: var(--bb-folder-hover); }
.bb-myFolderHeader .name { font-weight: 900; color: var(--bb-text); flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bb-myFolderHeader .meta { font-size: 12px; color: rgba(19, 78, 74, 0.72); }
.bb-myFolderHeader .meta { font-size: 12px; color: var(--bb-muted); }
.bb-myFolderBody { margin-top: 10px; }
/* Sticky open folder header (keeps the row visible while scrolling long lists) */
@@ -879,9 +879,9 @@ onBeforeUnmount(() => {
z-index: 30;
padding: 4px;
border-radius: 18px;
background: rgba(255,255,255,0.72);
background: var(--bb-folder-bg);
backdrop-filter: blur(12px);
border: 1px solid rgba(255,255,255,0.55);
border: 1px solid var(--bb-border);
}
.bb-folderDelete{
@@ -910,4 +910,14 @@ onBeforeUnmount(() => {
.bb-dragHint:active { cursor: grabbing; }
.bb-modalForm { display: grid; gap: 10px; }
:global(.theme-dark) .bb-myFolder.is-open > .bb-myFolderHeaderRow {
background: var(--bb-dark-panel);
border-color: rgba(148,163,184,0.32);
}
:global(.theme-dark) .bb-dragHint {
background: #3a3a3a;
border-color: rgba(148,163,184,0.32);
color: #ffffff;
}
</style>

View File

@@ -22,9 +22,6 @@ export const router = createRouter({
router.beforeEach(async (to) => {
const loggedIn = Boolean(tokenRef.value);
// 已登录访问首页时,跳转到个人页
if (to.path === "/" && loggedIn) return { path: "/my" };
// 已登录访问登录页:直接去“我的”
if (to.path === "/login" && loggedIn) return { path: "/my" };

View File

@@ -4,11 +4,23 @@
/* Educational-platform claymorphism palette (vibrant + friendly) */
--bb-bg: #f0fdfa;
--bb-text: #134e4a;
--bb-muted: rgba(19, 78, 74, 0.72);
--bb-primary: #0d9488;
--bb-primary-weak: #2dd4bf;
--bb-cta: #ea580c;
--bb-border: rgba(19, 78, 74, 0.12);
--bb-border-strong: rgba(19, 78, 74, 0.20);
--bb-panel: rgba(255,255,255,0.55);
--bb-panel-strong: rgba(255,255,255,0.82);
--bb-panel-hover: rgba(255,255,255,0.75);
--bb-menu-bg: rgba(255,255,255,0.72);
--bb-menu-item-bg: rgba(255,255,255,0.35);
--bb-menu-item-hover: rgba(255,255,255,0.6);
--bb-nav-bg: rgba(255,255,255,0.55);
--bb-modal-bg: rgba(255,255,255,0.82);
--bb-modal-border: rgba(255,255,255,0.65);
--bb-folder-bg: rgba(255,255,255,0.35);
--bb-folder-hover: rgba(255,255,255,0.6);
--bb-font-heading: "Baloo 2", Inter, ui-sans-serif, system-ui;
@@ -105,7 +117,7 @@ input:focus-visible {
}
.bb-muted {
color: rgba(19, 78, 74, 0.72);
color: var(--bb-muted);
font-size: 12px;
}
@@ -983,3 +995,119 @@ input:focus-visible {
.bb-card--interactive:hover {
animation: bb-float 2.8s ease-in-out infinite;
}
/* --- Dark theme overrides --- */
.theme-dark {
--bb-text: #e2e8f0;
--bb-muted: rgba(226,232,240,0.82);
--bb-border: rgba(148, 163, 184, 0.28);
--bb-border-strong: rgba(148, 163, 184, 0.45);
--bb-primary: #22c55e;
--bb-primary-weak: rgba(34, 197, 94, 0.25);
--bb-cta: #38bdf8;
--bb-dark-panel: #2E2E2E;
--bb-panel: #2E2E2E;
--bb-panel-strong: #2E2E2E;
--bb-panel-hover: #3a3a3a;
--bb-menu-bg: #2E2E2E;
--bb-menu-item-bg: #3a3a3a;
--bb-menu-item-hover: #444444;
--bb-nav-bg: #2E2E2E;
--bb-modal-bg: #2E2E2E;
--bb-modal-border: rgba(148,163,184,0.32);
--bb-folder-bg: #2E2E2E;
--bb-folder-hover: #3a3a3a;
--bb-gradient: linear-gradient(180deg, #000000 0%, #050910 55%, #000000 100%);
--bb-clay: linear-gradient(145deg, rgba(46, 46, 46, 0.95), rgba(36, 36, 36, 0.92));
--bb-shadow-clay: 0 22px 60px rgba(0, 0, 0, 0.55), 0 2px 0 rgba(255,255,255,0.06) inset, 0 -2px 0 rgba(0,0,0,0.35) inset;
}
.theme-dark body {
background: var(--bb-gradient);
color: var(--bb-text);
}
.theme-dark a { color: #38bdf8; }
.theme-dark a:hover { color: #22c55e; }
/* Navigation */
.theme-dark .nav { background: var(--bb-nav-bg); border-bottom: 1px solid rgba(148,163,184,0.35); }
.theme-dark .link { background: var(--bb-dark-panel); border: 1px solid rgba(148,163,184,0.28); color: var(--bb-text); }
.theme-dark .link.router-link-active { box-shadow: 0 12px 30px rgba(0,0,0,0.55); }
.theme-dark .brandMark { background: var(--bb-dark-panel); border-color: rgba(148,163,184,0.35); }
/* Menu */
.theme-dark .menu { background: var(--bb-menu-bg); border: 1px solid rgba(148,163,184,0.28); box-shadow: 0 24px 80px rgba(0,0,0,0.65); }
.theme-dark .menuItem { background: var(--bb-menu-item-bg); border: 1px solid rgba(148,163,184,0.28); color: var(--bb-text); }
.theme-dark .menuItem:hover { background: var(--bb-menu-item-hover); }
.theme-dark .menuItem.danger { color: #fecaca; background: rgba(185, 28, 28, 0.35); border-color: rgba(248, 113, 113, 0.45); }
/* Inputs / selects */
.theme-dark .bb-input,
.theme-dark .bb-select,
.theme-dark .bb-fileName,
.theme-dark .bb-selectTrigger { background: var(--bb-dark-panel); border-color: rgba(148,163,184,0.32); color: var(--bb-text); }
.theme-dark .bb-selectMenu { background: var(--bb-dark-panel); border-color: rgba(148,163,184,0.32); box-shadow: 0 22px 60px rgba(0,0,0,0.65); }
.theme-dark .bb-selectOption { color: var(--bb-text); }
.theme-dark .bb-selectOption:hover { background: rgba(34, 197, 94, 0.16); }
.theme-dark .bb-selectPlaceholder { color: rgba(226,232,240,0.72); }
/* Buttons */
.theme-dark .bb-btn--secondary { background: #3a3a3a; color: #ffffff; border-color: rgba(148,163,184,0.32); }
.theme-dark .bb-btn--danger { background: #3b0a0a; color: #ffffff; border-color: rgba(248,113,113,0.55); }
/* Cards / panels */
.theme-dark .bb-card,
.theme-dark .bb-pill,
.theme-dark .bb-miniStat,
.theme-dark .bb-iconBubble,
.theme-dark .bb-footerInner,
.theme-dark .bb-ctaGhost,
.theme-dark .bb-stat,
.theme-dark .bb-empty {
background: var(--bb-dark-panel);
border-color: rgba(148,163,184,0.32);
color: var(--bb-text);
}
.theme-dark .bb-alert { background: rgba(56,189,248,0.16); border-color: rgba(56,189,248,0.45); color: #e0f2fe; }
.theme-dark .bb-alert--ok { background: rgba(34,197,94,0.16); border-color: rgba(34,197,94,0.45); color: #d1fae5; }
.theme-dark .bb-alert--error { background: rgba(239,68,68,0.16); border-color: rgba(239,68,68,0.45); color: #fecaca; }
.theme-dark .bb-muted,
.theme-dark .bb-label,
.theme-dark .bb-footerCol a,
.theme-dark .bb-heroSub { color: rgba(226,232,240,0.82); }
.theme-dark ::placeholder { color: rgba(226,232,240,0.55); }
.theme-dark .bb-searchClear { background: #3a3a3a; border-color: rgba(148,163,184,0.32); color: rgba(226,232,240,0.82); }
.theme-dark .bb-searchClear:hover { background: #444444; }
/* Folder headers + drag hints */
.theme-dark .bb-myFolderHeader { background: var(--bb-folder-bg); border-color: rgba(148,163,184,0.32); color: var(--bb-text); }
.theme-dark .bb-myFolderHeader:hover { background: var(--bb-folder-hover); }
.theme-dark .bb-myFolderHeader .meta { color: var(--bb-muted); }
.theme-dark .bb-myFolder.is-open > .bb-myFolderHeaderRow {
background: var(--bb-dark-panel);
border-color: rgba(148,163,184,0.32);
}
.theme-dark .bb-dragHint {
background: #3a3a3a;
border-color: rgba(148,163,184,0.32);
color: #ffffff;
}
/* Modal dark */
.theme-dark .bb-modalBackdrop { background: rgba(0, 0, 0, 0.75); }
.theme-dark .bb-modalPanel {
background: var(--bb-modal-bg);
border-color: var(--bb-modal-border);
box-shadow: 0 18px 60px rgba(0,0,0,0.55);
}
.theme-dark .bb-modalHeader { border-bottom: 1px solid rgba(148,163,184,0.18); }
.theme-dark .bb-modalClose {
background: #3a3a3a;
border-color: rgba(148,163,184,0.32);
color: #ffffff;
}
.theme-dark .bb-modalClose:hover { background: #444444; }