style: 更新了应用的样式和主题,调整了颜色变量以支持深色模式
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "web",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"version": "1.0.4",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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" };
|
||||
|
||||
|
||||
@@ -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; }
|
||||
|
||||
Reference in New Issue
Block a user