Commit 8d3f79cf authored by 陈曦's avatar 陈曦
Browse files

继续修改首页、登录页、后台的所有设计风格

parent b4412353
<template> <template>
<header class="glass sticky top-0 z-30 border-b border-gray-200/50 dark:border-dark-700/50"> <header class="app-header sticky top-0 z-30 border-b border-gray-200/40 dark:border-white/[0.05]">
<div class="flex h-16 items-center justify-between px-4 md:px-6"> <div class="flex h-16 items-center justify-between px-4 md:px-6">
<!-- Left: Mobile Menu Toggle + Page Title --> <!-- Left: Mobile Menu Toggle + Page Title -->
<div class="flex items-center gap-4"> <div class="flex items-center gap-4">
...@@ -335,4 +335,13 @@ onBeforeUnmount(() => { ...@@ -335,4 +335,13 @@ onBeforeUnmount(() => {
opacity: 0; opacity: 0;
transform: scale(0.95) translateY(-4px); transform: scale(0.95) translateY(-4px);
} }
.app-header {
background: rgba(241, 245, 251, 0.85);
backdrop-filter: blur(20px);
}
:global(.dark) .app-header {
background: rgba(8, 14, 28, 0.85);
backdrop-filter: blur(20px);
}
</style> </style>
<template> <template>
<div class="min-h-screen bg-gray-50 dark:bg-dark-950"> <div class="app-root min-h-screen">
<!-- Background Decoration --> <!-- Background Decoration -->
<div class="pointer-events-none fixed inset-0 bg-mesh-gradient"></div> <div class="pointer-events-none fixed inset-0 app-bg-layer"></div>
<!-- Sidebar --> <!-- Sidebar -->
<AppSidebar /> <AppSidebar />
...@@ -50,3 +50,25 @@ onMounted(() => { ...@@ -50,3 +50,25 @@ onMounted(() => {
defineExpose({ replayTour }) defineExpose({ replayTour })
</script> </script>
<style scoped>
.app-root {
background: #f1f5fb;
}
:global(.dark) .app-root {
background: #080e1c;
}
.app-bg-layer {
background:
radial-gradient(at 15% 30%, rgba(99, 102, 241, 0.06) 0px, transparent 50%),
radial-gradient(at 85% 10%, rgba(20, 184, 166, 0.05) 0px, transparent 50%),
radial-gradient(at 60% 80%, rgba(139, 92, 246, 0.04) 0px, transparent 50%);
}
:global(.dark) .app-bg-layer {
background:
radial-gradient(at 15% 30%, rgba(99, 102, 241, 0.08) 0px, transparent 50%),
radial-gradient(at 85% 10%, rgba(20, 184, 166, 0.06) 0px, transparent 50%),
radial-gradient(at 60% 80%, rgba(139, 92, 246, 0.05) 0px, transparent 50%);
}
</style>
...@@ -60,7 +60,7 @@ ...@@ -60,7 +60,7 @@
<div v-if="!sidebarCollapsed" class="sidebar-section-title"> <div v-if="!sidebarCollapsed" class="sidebar-section-title">
{{ t('nav.myAccount') }} {{ t('nav.myAccount') }}
</div> </div>
<div v-else class="mx-3 my-3 h-px bg-gray-200 dark:bg-dark-700"></div> <div v-else class="mx-3 my-3 h-px" style="background: rgba(255,255,255,0.06)"></div>
<router-link <router-link
v-for="item in personalNavItems" v-for="item in personalNavItems"
...@@ -105,7 +105,7 @@ ...@@ -105,7 +105,7 @@
</nav> </nav>
<!-- Bottom Section --> <!-- Bottom Section -->
<div class="mt-auto border-t border-gray-100 p-3 dark:border-dark-800"> <div class="mt-auto p-3" style="border-top: 1px solid rgba(255,255,255,0.05)">
<!-- Theme Toggle --> <!-- Theme Toggle -->
<button <button
@click="toggleTheme" @click="toggleTheme"
......
<template> <template>
<div class="auth-root relative flex min-h-screen items-center justify-center overflow-hidden p-4"> <div class="auth-split min-h-screen">
<!-- Background -->
<div class="pointer-events-none absolute inset-0 overflow-hidden">
<div class="auth-orb auth-orb-tr"></div>
<div class="auth-orb auth-orb-bl"></div>
<div class="auth-grid"></div>
<div class="auth-scan"></div>
</div>
<!-- Content --> <!-- ══════════════════════════════════════════
<div class="relative z-10 w-full max-w-md"> LEFT PANEL — AI Visual (hidden on mobile)
══════════════════════════════════════════ -->
<div class="auth-left hidden lg:flex">
<!-- Brand --> <!-- Background layers -->
<div class="mb-8 text-center"> <div class="pointer-events-none absolute inset-0 overflow-hidden">
<template v-if="settingsLoaded"> <div class="left-aurora left-aurora-1"></div>
<!-- Logo --> <div class="left-aurora left-aurora-2"></div>
<div class="auth-logo-wrap mb-5 inline-flex h-16 w-16 items-center justify-center overflow-hidden rounded-2xl"> </div>
<img :src="siteLogo || '/logo.png'" alt="Logo" class="h-full w-full object-contain" />
<div class="relative z-10 flex h-full flex-col px-12 py-10">
<!-- Logo + Brand -->
<div class="flex items-center gap-3">
<template v-if="settingsLoaded">
<div class="left-logo-wrap">
<img :src="siteLogo || '/logo.png'" alt="Logo" class="h-full w-full object-contain" />
</div>
<div>
<div class="text-base font-bold text-white">{{ siteName }}</div>
<div class="font-mono text-[10px] uppercase tracking-widest text-violet-400/60">// AI Gateway</div>
</div>
</template>
</div>
<!-- Center: Orbital AI Visualization -->
<div class="flex flex-1 flex-col items-center justify-center">
<div class="orbital-viz">
<!-- Hub -->
<div class="hub-outer">
<div class="hub-ring hub-ring-1"></div>
<div class="hub-ring hub-ring-2"></div>
<div class="hub-core">
<svg class="h-8 w-8 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5">
<path stroke-linecap="round" stroke-linejoin="round" d="M9.813 15.904L9 18.75l-.813-2.846a4.5 4.5 0 00-3.09-3.09L2.25 12l2.846-.813a4.5 4.5 0 003.09-3.09L9 5.25l.813 2.846a4.5 4.5 0 003.09 3.09L15.75 12l-2.846.813a4.5 4.5 0 00-3.09 3.09z" />
</svg>
</div>
</div>
<!-- Orbiting model chips -->
<div class="orbit-chip chip-0">
<span class="chip-dot" style="background: #f97316"></span>
<span>Claude</span>
</div>
<div class="orbit-chip chip-1">
<span class="chip-dot" style="background: #22c55e"></span>
<span>GPT-4o</span>
</div>
<div class="orbit-chip chip-2">
<span class="chip-dot" style="background: #3b82f6"></span>
<span>Gemini</span>
</div>
<div class="orbit-chip chip-3">
<span class="chip-dot" style="background: #f43f5e"></span>
<span>DeepSeek</span>
</div>
<div class="orbit-chip chip-4">
<span class="chip-dot" style="background: #a855f7"></span>
<span>Llama</span>
</div>
<!-- Connecting lines (SVG) -->
<svg class="orbit-lines" viewBox="0 0 340 340" fill="none" xmlns="http://www.w3.org/2000/svg">
<!-- Lines from center (170,170) to chip positions -->
<line x1="170" y1="170" x2="275" y2="90" stroke="rgba(139,92,246,0.18)" stroke-width="1" stroke-dasharray="4 4">
<animate attributeName="stroke-dashoffset" values="0;-16" dur="1.2s" repeatCount="indefinite"/>
</line>
<line x1="170" y1="170" x2="300" y2="200" stroke="rgba(20,184,166,0.18)" stroke-width="1" stroke-dasharray="4 4">
<animate attributeName="stroke-dashoffset" values="0;-16" dur="1.6s" repeatCount="indefinite"/>
</line>
<line x1="170" y1="170" x2="200" y2="295" stroke="rgba(59,130,246,0.18)" stroke-width="1" stroke-dasharray="4 4">
<animate attributeName="stroke-dashoffset" values="0;-16" dur="2.0s" repeatCount="indefinite"/>
</line>
<line x1="170" y1="170" x2="65" y2="270" stroke="rgba(244,63,94,0.18)" stroke-width="1" stroke-dasharray="4 4">
<animate attributeName="stroke-dashoffset" values="0;-16" dur="1.4s" repeatCount="indefinite"/>
</line>
<line x1="170" y1="170" x2="55" y2="130" stroke="rgba(168,85,247,0.18)" stroke-width="1" stroke-dasharray="4 4">
<animate attributeName="stroke-dashoffset" values="0;-16" dur="1.8s" repeatCount="indefinite"/>
</line>
</svg>
</div>
<!-- Tagline -->
<div class="mt-10 text-center">
<h2 class="mb-3 text-2xl font-bold text-white">One Key.<br>Every Model.</h2>
<p class="max-w-xs text-sm leading-relaxed text-slate-400">
{{ siteSubtitle }}
</p>
</div>
</div>
<!-- Feature bullets -->
<div class="space-y-4 pb-4">
<div v-for="f in leftFeatures" :key="f.text" class="left-feature-row">
<div class="left-feature-icon" :style="{ background: f.iconBg }">
<component :is="f.icon" />
</div>
<div>
<div class="text-sm font-medium text-slate-200">{{ f.text }}</div>
<div class="text-xs text-slate-500">{{ f.desc }}</div>
</div>
</div> </div>
</div>
<!-- Site name --> <!-- Copyright -->
<h1 class="auth-site-name mb-2 text-3xl font-black tracking-tight"> <div class="pt-6 font-mono text-[10px] text-slate-700">
{{ siteName }} &copy; {{ currentYear }} {{ siteName }}
</h1> </div>
</div>
</div>
<!-- Subtitle --> <!-- ══════════════════════════════════════════
<p class="auth-subtitle font-mono text-xs uppercase tracking-widest"> RIGHT PANEL — Form
// {{ siteSubtitle }} ══════════════════════════════════════════ -->
</p> <div class="auth-right">
<!-- Mobile: tiny logo strip -->
<div class="mb-8 flex items-center gap-2.5 lg:hidden">
<template v-if="settingsLoaded">
<div class="h-8 w-8 overflow-hidden rounded-lg shadow-glow">
<img :src="siteLogo || '/logo.png'" alt="Logo" class="h-full w-full object-contain" />
</div>
<span class="text-base font-bold text-gray-900 dark:text-white">{{ siteName }}</span>
</template> </template>
</div> </div>
<!-- Card --> <!-- Form card -->
<div class="auth-card rounded-2xl p-8"> <div class="auth-form-card">
<slot /> <slot />
</div> </div>
<!-- Footer links --> <!-- Footer links -->
<div class="mt-6 text-center text-sm"> <div class="mt-5 text-center text-sm">
<slot name="footer" /> <slot name="footer" />
</div> </div>
<!-- Copyright --> <!-- Copyright (mobile only) -->
<div class="mt-8 text-center font-mono text-xs text-slate-600"> <div class="mt-8 text-center font-mono text-xs text-gray-400 dark:text-slate-700 lg:hidden">
&copy; {{ currentYear }} {{ siteName }}. All rights reserved. &copy; {{ currentYear }} {{ siteName }}. All rights reserved.
</div> </div>
</div> </div>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { computed, onMounted } from 'vue' import { computed, defineComponent, h, onMounted } from 'vue'
import { useAppStore } from '@/stores' import { useAppStore } from '@/stores'
import { sanitizeUrl } from '@/utils/url' import { sanitizeUrl } from '@/utils/url'
...@@ -61,117 +157,295 @@ const siteName = computed(() => appStore.siteName || 'TrafficAPI') ...@@ -61,117 +157,295 @@ const siteName = computed(() => appStore.siteName || 'TrafficAPI')
const siteLogo = computed(() => sanitizeUrl(appStore.siteLogo || '', { allowRelative: true, allowDataUrl: true })) const siteLogo = computed(() => sanitizeUrl(appStore.siteLogo || '', { allowRelative: true, allowDataUrl: true }))
const siteSubtitle = computed(() => appStore.cachedPublicSettings?.site_subtitle || 'Intelligent AI Traffic Routing & Management') const siteSubtitle = computed(() => appStore.cachedPublicSettings?.site_subtitle || 'Intelligent AI Traffic Routing & Management')
const settingsLoaded = computed(() => appStore.publicSettingsLoaded) const settingsLoaded = computed(() => appStore.publicSettingsLoaded)
const currentYear = computed(() => new Date().getFullYear()) const currentYear = computed(() => new Date().getFullYear())
// Inline icon components for feature bullets
const ShieldIcon = defineComponent({
render: () => h('svg', { class: 'h-4 w-4 text-white', fill: 'none', viewBox: '0 0 24 24', stroke: 'currentColor', 'stroke-width': '1.5' }, [
h('path', { 'stroke-linecap': 'round', 'stroke-linejoin': 'round', d: 'M9 12.75L11.25 15 15 9.75m-3-7.036A11.959 11.959 0 013.598 6 11.99 11.99 0 003 9.749c0 5.592 3.824 10.29 9 11.623 5.176-1.332 9-6.03 9-11.622 0-1.31-.21-2.571-.598-3.751h-.152c-3.196 0-6.1-1.248-8.25-3.285z' })
])
})
const BoltIcon = defineComponent({
render: () => h('svg', { class: 'h-4 w-4 text-white', fill: 'none', viewBox: '0 0 24 24', stroke: 'currentColor', 'stroke-width': '1.5' }, [
h('path', { 'stroke-linecap': 'round', 'stroke-linejoin': 'round', d: 'M3.75 13.5l10.5-11.25L12 10.5h8.25L9.75 21.75 12 13.5H3.75z' })
])
})
const ChartIcon = defineComponent({
render: () => h('svg', { class: 'h-4 w-4 text-white', fill: 'none', viewBox: '0 0 24 24', stroke: 'currentColor', 'stroke-width': '1.5' }, [
h('path', { 'stroke-linecap': 'round', 'stroke-linejoin': 'round', d: 'M3 13.125C3 12.504 3.504 12 4.125 12h2.25c.621 0 1.125.504 1.125 1.125v6.75C7.5 20.496 6.996 21 6.375 21h-2.25A1.125 1.125 0 013 19.875v-6.75zM9.75 8.625c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125v11.25c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 01-1.125-1.125V8.625zM16.5 4.125c0-.621.504-1.125 1.125-1.125h2.25C20.496 3 21 3.504 21 4.125v15.75c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 01-1.125-1.125V4.125z' })
])
})
const leftFeatures = [
{
text: '统一 API 接入点',
desc: '一个 Key 打通所有 AI 服务商,无需多套凭证',
icon: ShieldIcon,
iconBg: 'linear-gradient(135deg,#6366f1,#8b5cf6)',
},
{
text: '智能负载均衡',
desc: '自动分发流量,账户异常时即时切换,零中断',
icon: BoltIcon,
iconBg: 'linear-gradient(135deg,#14b8a6,#06b6d4)',
},
{
text: '实时流量分析',
desc: '请求量、延迟、费用全透明,按用户精细管控',
icon: ChartIcon,
iconBg: 'linear-gradient(135deg,#a855f7,#ec4899)',
},
]
onMounted(() => { onMounted(() => {
appStore.fetchPublicSettings() appStore.fetchPublicSettings()
}) })
</script> </script>
<style scoped> <style scoped>
/* ── Root ────────────────────────────────── */ /* ══════════════════════════════════════════════
.auth-root { SPLIT LAYOUT
background: #182a40; ══════════════════════════════════════════════ */
color: white; .auth-split {
display: flex;
min-height: 100vh;
}
/* ── LEFT PANEL ────────────────────────────── */
.auth-left {
position: relative;
width: 55%;
max-width: 600px;
flex-shrink: 0;
background: #060c1a;
overflow: hidden;
flex-direction: column;
} }
/* ── Background layers ───────────────────── */ /* Aurora blobs on left panel */
.auth-orb { .left-aurora {
position: absolute; position: absolute;
border-radius: 50%; border-radius: 50%;
filter: blur(90px); filter: blur(100px);
pointer-events: none; pointer-events: none;
} }
.auth-orb-tr { .left-aurora-1 {
top: -10%; top: -15%;
right: -10%; right: -15%;
width: 420px; width: 450px;
height: 420px; height: 450px;
background: radial-gradient(ellipse, rgba(20,184,166,0.18) 0%, transparent 70%); background: radial-gradient(ellipse, rgba(139,92,246,0.22) 0%, transparent 65%);
animation: la-drift-1 20s ease-in-out infinite alternate;
} }
.auth-orb-bl { .left-aurora-2 {
bottom: -10%; bottom: -10%;
left: -10%; left: -10%;
width: 380px; width: 350px;
height: 380px; height: 350px;
background: radial-gradient(ellipse, rgba(6,182,212,0.13) 0%, transparent 70%); background: radial-gradient(ellipse, rgba(20,184,166,0.18) 0%, transparent 65%);
animation: la-drift-2 24s ease-in-out infinite alternate;
}
@keyframes la-drift-1 {
from { transform: translate(0,0) scale(1); }
to { transform: translate(-20px,20px) scale(1.06); }
}
@keyframes la-drift-2 {
from { transform: translate(0,0) scale(1); }
to { transform: translate(20px,-20px) scale(1.04); }
} }
.auth-grid {
.left-logo-wrap {
width: 36px;
height: 36px;
border-radius: 9px;
overflow: hidden;
box-shadow: 0 0 0 1px rgba(139,92,246,0.3), 0 0 16px rgba(139,92,246,0.15);
flex-shrink: 0;
}
/* ── ORBITAL VISUALIZATION ──────────────────── */
.orbital-viz {
position: relative;
width: 340px;
height: 340px;
}
/* Hub */
.hub-outer {
position: absolute; position: absolute;
inset: 0; top: 50%;
background-image: left: 50%;
linear-gradient(rgba(20,184,166,0.07) 1px, transparent 1px), transform: translate(-50%, -50%);
linear-gradient(90deg, rgba(20,184,166,0.07) 1px, transparent 1px); display: flex;
background-size: 48px 48px; align-items: center;
justify-content: center;
} }
.auth-scan { .hub-ring {
position: absolute; position: absolute;
left: 0; border-radius: 50%;
right: 0; border: 1px solid rgba(139,92,246,0.15);
height: 1px; animation: hub-pulse 3s ease-in-out infinite;
background: linear-gradient(90deg, transparent 0%, rgba(20,184,166,0.45) 30%, rgba(20,184,166,0.7) 50%, rgba(20,184,166,0.45) 70%, transparent 100%); }
animation: auth-scan 12s linear infinite; .hub-ring-1 {
box-shadow: 0 0 8px rgba(20,184,166,0.35); width: 80px;
} height: 80px;
@keyframes auth-scan { animation-delay: 0s;
0% { top: 0%; opacity: 0; } }
4% { opacity: 1; } .hub-ring-2 {
96% { opacity: 0.4; } width: 110px;
100% { top: 100%; opacity: 0; } height: 110px;
} border-color: rgba(20,184,166,0.1);
animation-delay: 0.8s;
/* ── Logo ────────────────────────────────── */ }
.auth-logo-wrap { @keyframes hub-pulse {
box-shadow: 0%,100% { transform: scale(1); opacity: 0.6; }
0 0 0 1px rgba(20,184,166,0.3), 50% { transform: scale(1.06); opacity: 1; }
0 0 20px rgba(20,184,166,0.18), }
0 8px 24px rgba(0,0,0,0.4); .hub-core {
} width: 64px;
height: 64px;
/* ── Brand text ──────────────────────────── */ border-radius: 16px;
.auth-site-name { background: linear-gradient(135deg, #3730a3, #4f46e5, #7c3aed);
background: linear-gradient(135deg, #ffffff 0%, #7dd3c8 45%, #14b8a6 100%); box-shadow: 0 0 32px rgba(99,102,241,0.5), 0 0 64px rgba(99,102,241,0.2);
-webkit-background-clip: text; display: flex;
-webkit-text-fill-color: transparent; align-items: center;
background-clip: text; justify-content: center;
} position: relative;
.auth-subtitle { z-index: 2;
color: rgba(20,184,166,0.5); }
}
/* Orbit chips — positioned around center */
/* ── Card ────────────────────────────────── */ .orbit-chip {
.auth-card { position: absolute;
background: rgba(26,46,72,0.72); display: flex;
border: 1px solid rgba(255,255,255,0.09); align-items: center;
backdrop-filter: blur(18px); gap: 6px;
box-shadow: padding: 5px 11px 5px 8px;
0 0 0 1px rgba(20,184,166,0.08), border-radius: 20px;
0 24px 60px rgba(0,0,0,0.45), border: 1px solid rgba(255,255,255,0.08);
0 0 50px rgba(20,184,166,0.05); background: rgba(15,22,40,0.85);
} backdrop-filter: blur(8px);
font-size: 11px;
/* ── Slot overrides: make child inputs/links readable ── */ font-weight: 500;
color: #cbd5e1;
white-space: nowrap;
animation: chip-float 4s ease-in-out infinite;
}
.chip-dot {
width: 7px;
height: 7px;
border-radius: 50%;
flex-shrink: 0;
}
/* Position each chip around the orbital */
.chip-0 { top: 6%; left: 62%; animation-delay: 0.0s; }
.chip-1 { top: 44%; left: 80%; animation-delay: 0.6s; }
.chip-2 { top: 78%; left: 52%; animation-delay: 1.2s; }
.chip-3 { top: 72%; left: 6%; animation-delay: 1.8s; }
.chip-4 { top: 12%; left: 2%; animation-delay: 2.4s; }
@keyframes chip-float {
0%,100% { transform: translateY(0); }
50% { transform: translateY(-6px); }
}
/* SVG connecting lines */
.orbit-lines {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
pointer-events: none;
}
/* Feature rows */
.left-feature-row {
display: flex;
align-items: flex-start;
gap: 12px;
}
.left-feature-icon {
width: 34px;
height: 34px;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
/* ── RIGHT PANEL ─────────────────────────── */
.auth-right {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 40px 32px;
background: #f8fafc;
min-height: 100vh;
}
/* Dark mode right panel */
:global(.dark) .auth-right {
background: #0f172a;
}
.auth-form-card {
width: 100%;
max-width: 400px;
background: white;
border-radius: 20px;
border: 1px solid rgba(0,0,0,0.06);
box-shadow: 0 4px 32px rgba(0,0,0,0.08), 0 1px 4px rgba(0,0,0,0.04);
padding: 36px 32px;
}
:global(.dark) .auth-form-card {
background: #1e293b;
border-color: rgba(255,255,255,0.08);
box-shadow: 0 4px 32px rgba(0,0,0,0.4);
}
/* Override slot content for right panel (light mode) */
:deep(h2) {
color: #0f172a !important;
}
:global(.dark) :deep(h2) {
color: white !important;
}
:deep(.input-label) { :deep(.input-label) {
color: #374151;
}
:global(.dark) :deep(.input-label) {
color: #94a3b8; color: #94a3b8;
} }
:deep(.input) { :deep(.input) {
background: #f9fafb;
border-color: #e5e7eb;
color: #0f172a;
}
:global(.dark) :deep(.input) {
background: rgba(15,28,48,0.7); background: rgba(15,28,48,0.7);
border-color: rgba(255,255,255,0.1); border-color: rgba(255,255,255,0.1);
color: white; color: white;
} }
:deep(.input:focus) { :deep(.input:focus) {
border-color: rgba(20,184,166,0.5); border-color: #8b5cf6;
box-shadow: 0 0 0 3px rgba(20,184,166,0.12); box-shadow: 0 0 0 3px rgba(139, 92, 246, 0.15);
} }
:deep(.input::placeholder) { :deep(.input::placeholder) {
color: #475569; color: #9ca3af;
} }
:deep(h2) { :global(.dark) :deep(.input::placeholder) {
color: white !important; color: #475569;
} }
:deep(.text-gray-500), :deep(.text-gray-500),
:deep(.dark\:text-dark-400) { :deep(.dark\:text-dark-400) {
color: #6b7280 !important;
}
:global(.dark) :deep(.text-gray-500),
:global(.dark) :deep(.dark\:text-dark-400) {
color: #64748b !important; color: #64748b !important;
} }
</style> </style>
...@@ -40,6 +40,13 @@ export default { ...@@ -40,6 +40,13 @@ export default {
} }
} }
}, },
// Pipeline visualization labels
pipeline: {
gateway: 'Gateway',
balancer: 'Balancer',
aiPool: 'AI Pool',
response: 'Response',
},
// Solutions section // Solutions section
solutions: { solutions: {
title: 'TrafficAPI Solves This', title: 'TrafficAPI Solves This',
......
...@@ -40,6 +40,13 @@ export default { ...@@ -40,6 +40,13 @@ export default {
} }
} }
}, },
// 管道可视化标签
pipeline: {
gateway: '网关',
balancer: '均衡器',
aiPool: 'AI 池',
response: '响应',
},
// 解决方案区块 // 解决方案区块
solutions: { solutions: {
title: 'TrafficAPI 为你解决', title: 'TrafficAPI 为你解决',
......
...@@ -96,16 +96,26 @@ ...@@ -96,16 +96,26 @@
@apply inline-flex items-center justify-center gap-2; @apply inline-flex items-center justify-center gap-2;
@apply rounded-xl px-4 py-2.5 text-sm font-medium; @apply rounded-xl px-4 py-2.5 text-sm font-medium;
@apply transition-all duration-200 ease-out; @apply transition-all duration-200 ease-out;
@apply focus:outline-none focus:ring-2 focus:ring-primary-500/50 focus:ring-offset-2; @apply focus:outline-none;
@apply disabled:transform-none disabled:cursor-not-allowed disabled:opacity-50; @apply disabled:transform-none disabled:cursor-not-allowed disabled:opacity-50;
@apply active:scale-[0.98]; @apply active:scale-[0.98];
} }
.btn-primary { .btn-primary {
@apply bg-gradient-to-r from-primary-500 to-primary-600; background: linear-gradient(135deg, #7c3aed, #8b5cf6);
@apply text-white shadow-md shadow-primary-500/25; color: white;
@apply hover:from-primary-600 hover:to-primary-700 hover:shadow-lg hover:shadow-primary-500/30; box-shadow: 0 4px 14px rgba(139, 92, 246, 0.35);
@apply dark:shadow-primary-500/20; }
.btn-primary:hover {
background: linear-gradient(135deg, #6d28d9, #7c3aed);
box-shadow: 0 6px 20px rgba(139, 92, 246, 0.45);
transform: translateY(-1px);
}
.btn-primary:focus {
outline: none;
box-shadow: 0 0 0 3px rgba(139, 92, 246, 0.35), 0 4px 14px rgba(139, 92, 246, 0.3);
} }
.btn-secondary { .btn-secondary {
...@@ -165,7 +175,7 @@ ...@@ -165,7 +175,7 @@
@apply text-gray-900 dark:text-gray-100; @apply text-gray-900 dark:text-gray-100;
@apply placeholder:text-gray-400 dark:placeholder:text-dark-400; @apply placeholder:text-gray-400 dark:placeholder:text-dark-400;
@apply transition-all duration-200; @apply transition-all duration-200;
@apply focus:border-primary-500 focus:outline-none focus:ring-2 focus:ring-primary-500/30; @apply focus:outline-none focus:border-[#8b5cf6] focus:ring-2 focus:ring-[#8b5cf6]/20;
@apply disabled:cursor-not-allowed disabled:bg-gray-100 dark:disabled:bg-dark-900; @apply disabled:cursor-not-allowed disabled:bg-gray-100 dark:disabled:bg-dark-900;
} }
...@@ -522,11 +532,12 @@ ...@@ -522,11 +532,12 @@
@apply border-l-primary-500; @apply border-l-primary-500;
} }
/* ============ 侧边栏 ============ */ /* ============ 侧边栏 — 恒暗风格 ============ */
.sidebar { .sidebar {
@apply fixed inset-y-0 left-0 z-40; @apply fixed inset-y-0 left-0 z-40;
@apply w-64 bg-white dark:bg-dark-900; @apply w-64;
@apply border-r border-gray-200 dark:border-dark-800; background: #0c1220;
border-right: 1px solid rgba(139, 92, 246, 0.08);
@apply flex flex-col; @apply flex flex-col;
@apply transition-transform duration-300; @apply transition-transform duration-300;
} }
...@@ -534,7 +545,7 @@ ...@@ -534,7 +545,7 @@
.sidebar-header { .sidebar-header {
@apply h-16 px-6; @apply h-16 px-6;
@apply flex items-center gap-3; @apply flex items-center gap-3;
@apply border-b border-gray-100 dark:border-dark-800; border-bottom: 1px solid rgba(255, 255, 255, 0.05);
} }
.sidebar-nav { .sidebar-nav {
...@@ -544,16 +555,26 @@ ...@@ -544,16 +555,26 @@
.sidebar-link { .sidebar-link {
@apply flex items-center gap-3 rounded-xl px-3 py-2.5; @apply flex items-center gap-3 rounded-xl px-3 py-2.5;
@apply text-sm font-medium; @apply text-sm font-medium;
@apply text-gray-600 dark:text-dark-300; color: rgba(148, 163, 184, 0.85);
@apply transition-all duration-200; @apply transition-all duration-200;
@apply hover:bg-gray-100 dark:hover:bg-dark-800; }
@apply hover:text-gray-900 dark:hover:text-white;
.sidebar-link:hover {
background: rgba(255, 255, 255, 0.055);
color: rgba(226, 232, 240, 1);
} }
.sidebar-link-active { .sidebar-link-active {
@apply bg-primary-50 dark:bg-primary-900/20; background: linear-gradient(135deg, rgba(99, 102, 241, 0.18), rgba(20, 184, 166, 0.12));
@apply text-primary-600 dark:text-primary-400; border-left: 2px solid #14b8a6;
@apply hover:bg-primary-100 dark:hover:bg-primary-900/30; padding-left: calc(0.75rem - 2px);
color: #5eead4 !important;
box-shadow: inset 0 0 16px rgba(20, 184, 166, 0.04);
}
.sidebar-link-active:hover {
background: linear-gradient(135deg, rgba(99, 102, 241, 0.24), rgba(20, 184, 166, 0.18));
color: #5eead4 !important;
} }
.sidebar-section { .sidebar-section {
...@@ -563,7 +584,7 @@ ...@@ -563,7 +584,7 @@
.sidebar-section-title { .sidebar-section-title {
@apply mb-2 px-3; @apply mb-2 px-3;
@apply text-xs font-semibold uppercase tracking-wider; @apply text-xs font-semibold uppercase tracking-wider;
@apply text-gray-400 dark:text-dark-500; color: rgba(100, 116, 139, 0.7);
} }
/* ============ 页面头部 ============ */ /* ============ 页面头部 ============ */
......
This diff is collapsed.
...@@ -80,7 +80,7 @@ ...@@ -80,7 +80,7 @@
<router-link <router-link
v-if="passwordResetEnabled && !backendModeEnabled" v-if="passwordResetEnabled && !backendModeEnabled"
to="/forgot-password" to="/forgot-password"
class="text-sm font-medium text-primary-600 transition-colors hover:text-primary-500 dark:text-primary-400 dark:hover:text-primary-300" class="text-sm font-medium transition-colors" style="color: #8b5cf6;"
> >
{{ t('auth.forgotPassword') }} {{ t('auth.forgotPassword') }}
</router-link> </router-link>
......
...@@ -67,8 +67,8 @@ export default { ...@@ -67,8 +67,8 @@ export default {
boxShadow: { boxShadow: {
glass: '0 8px 32px rgba(0, 0, 0, 0.08)', glass: '0 8px 32px rgba(0, 0, 0, 0.08)',
'glass-sm': '0 4px 16px rgba(0, 0, 0, 0.06)', 'glass-sm': '0 4px 16px rgba(0, 0, 0, 0.06)',
glow: '0 0 20px rgba(20, 184, 166, 0.25)', glow: '0 0 0 1px rgba(99, 102, 241, 0.25), 0 0 20px rgba(99, 102, 241, 0.15)',
'glow-lg': '0 0 40px rgba(20, 184, 166, 0.35)', 'glow-lg': '0 0 40px rgba(99, 102, 241, 0.35)',
card: '0 1px 3px rgba(0, 0, 0, 0.04), 0 1px 2px rgba(0, 0, 0, 0.06)', card: '0 1px 3px rgba(0, 0, 0, 0.04), 0 1px 2px rgba(0, 0, 0, 0.06)',
'card-hover': '0 10px 40px rgba(0, 0, 0, 0.08)', 'card-hover': '0 10px 40px rgba(0, 0, 0, 0.08)',
'inner-glow': 'inset 0 1px 0 rgba(255, 255, 255, 0.1)' 'inner-glow': 'inset 0 1px 0 rgba(255, 255, 255, 0.1)'
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment