-
爱维宠物医院管理平台
-
-
-
-
-
-
-
-
- 登录
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 登 录
+
+
+
+
+
+
+
+ 其他登录方式
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
🐕
+
🐈
+
🏥
+
💉
+
🦴
+
🐾
+
+
+
✨ 专业 · 贴心 · 高效
+
专业宠物医疗
用心呵护每一刻
+
为爱宠提供最优质的医疗服务
让每一个生命都得到最好的照顾
+
+
+
+ 在线预约
+
+
+
+ 电子病历
+
+
+
+ 智能提醒
+
+
+
+
+
diff --git a/frontend/src/pages/Register.vue b/frontend/src/pages/Register.vue
new file mode 100644
index 0000000..381c91a
--- /dev/null
+++ b/frontend/src/pages/Register.vue
@@ -0,0 +1,716 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 我已阅读并同意 服务条款 和 隐私政策
+
+
+
+
+
+ 注 册
+
+
+
+
+
+
+
+
+
+
+
+
+
🐕
+
🐈
+
🏥
+
💉
+
🦴
+
🐾
+
+
+
✨ 专业 · 贴心 · 高效
+
开启您的
宠物医疗之旅
+
注册即享专业宠物医疗服务
让爱宠健康每一刻
+
+
+
+ 在线预约
+
+
+
+ 电子病历
+
+
+
+ 智能提醒
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/frontend/src/router/index.ts b/frontend/src/router/index.ts
index 689d87f..8e12dae 100644
--- a/frontend/src/router/index.ts
+++ b/frontend/src/router/index.ts
@@ -3,6 +3,7 @@ import { useAuthStore } from '../store/auth';
const routes: RouteRecordRaw[] = [
{ path: '/login', name: 'login', component: () => import('../pages/Login.vue') },
+ { path: '/register', name: 'register', component: () => import('../pages/Register.vue') },
{
path: '/',
component: () => import('../layouts/MainLayout.vue'),
@@ -34,10 +35,10 @@ const router = createRouter({
router.beforeEach((to) => {
const auth = useAuthStore();
- if (to.path !== '/login' && !auth.token) {
+ if (to.path !== '/login' && to.path !== '/register' && !auth.token) {
return '/login';
}
- if (to.path === '/login' && auth.token) {
+ if ((to.path === '/login' || to.path === '/register') && auth.token) {
return '/dashboard';
}
const roles = to.meta?.roles as string[] | undefined;
diff --git a/frontend/src/styles/global.css b/frontend/src/styles/global.css
index c01c4d0..70b142b 100644
--- a/frontend/src/styles/global.css
+++ b/frontend/src/styles/global.css
@@ -1,131 +1,492 @@
+@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap');
+
:root {
+ /* 主色调 - 清新青绿色系 */
+ --primary: #0d9488;
+ --primary-light: #14b8a6;
+ --primary-hover: #0f766e;
+ --primary-dark: #115e59;
+
+ /* 功能色 */
+ --success: #10b981;
+ --success-light: #d1fae5;
+ --success-dark: #059669;
+ --warning: #f59e0b;
+ --warning-light: #fef3c7;
+ --warning-dark: #d97706;
+ --danger: #ef4444;
+ --danger-light: #fee2e2;
+ --danger-dark: #dc2626;
+ --info: #3b82f6;
+ --info-light: #dbeafe;
+ --info-dark: #2563eb;
+
+ /* 中性色 */
--app-bg: #f8fafc;
--panel-bg: #ffffff;
- --primary: #3b82f6;
- --primary-hover: #2563eb;
- --secondary: #64748b;
- --success: #10b981;
- --warning: #f59e0b;
- --danger: #ef4444;
--text: #1e293b;
--text-secondary: #64748b;
+ --text-muted: #94a3b8;
--border: #e2e8f0;
- --shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1);
- --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
- --radius: 8px;
- --transition: all 0.2s ease;
+ --border-light: #f1f5f9;
+ --border-hover: #cbd5e1;
+
+ /* 阴影 */
+ --shadow-xs: 0 1px 2px 0 rgba(0, 0, 0, 0.03);
+ --shadow-sm: 0 1px 3px 0 rgba(0, 0, 0, 0.06), 0 1px 2px -1px rgba(0, 0, 0, 0.06);
+ --shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.08), 0 2px 4px -2px rgba(0, 0, 0, 0.08);
+ --shadow-md: 0 10px 15px -3px rgba(0, 0, 0, 0.08), 0 4px 6px -4px rgba(0, 0, 0, 0.08);
+ --shadow-lg: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1);
+ --shadow-xl: 0 25px 50px -12px rgba(0, 0, 0, 0.15);
+ --shadow-primary: 0 4px 14px rgba(13, 148, 136, 0.35);
+ --shadow-success: 0 4px 14px rgba(16, 185, 129, 0.35);
+ --shadow-warning: 0 4px 14px rgba(245, 158, 11, 0.35);
+ --shadow-danger: 0 4px 14px rgba(239, 68, 68, 0.35);
+
+ /* 圆角 */
+ --radius-xs: 4px;
+ --radius-sm: 8px;
+ --radius: 12px;
+ --radius-md: 16px;
+ --radius-lg: 20px;
+ --radius-xl: 24px;
+ --radius-full: 9999px;
+
+ /* 过渡 */
+ --transition-fast: all 0.15s cubic-bezier(0.4, 0, 0.2, 1);
+ --transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
+ --transition-slow: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+ --transition-bounce: all 0.4s cubic-bezier(0.68, -0.55, 0.265, 1.55);
}
* {
box-sizing: border-box;
}
+html {
+ scroll-behavior: smooth;
+}
+
body {
margin: 0;
- font-family: "PingFang SC", "Microsoft YaHei", "Helvetica Neue", Arial, sans-serif;
+ font-family: "Inter", "PingFang SC", "Microsoft YaHei", "Helvetica Neue", Arial, sans-serif;
background: var(--app-bg);
color: var(--text);
- line-height: 1.5;
+ line-height: 1.6;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
}
+/* 页面容器 */
.page {
padding: 24px;
- max-width: 1400px;
+ max-width: 1440px;
margin: 0 auto;
+ animation: pageEnter 0.5s cubic-bezier(0.4, 0, 0.2, 1);
}
-.panel {
- background: var(--panel-bg);
- border-radius: var(--radius);
- padding: 24px;
- box-shadow: var(--shadow);
- margin-bottom: 24px;
+@keyframes pageEnter {
+ from {
+ opacity: 0;
+ transform: translateY(20px) scale(0.98);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0) scale(1);
+ }
+}
+
+/* 通用动画 */
+@keyframes fadeIn {
+ from { opacity: 0; }
+ to { opacity: 1; }
+}
+
+@keyframes fadeInUp {
+ from {
+ opacity: 0;
+ transform: translateY(20px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+@keyframes fadeInDown {
+ from {
+ opacity: 0;
+ transform: translateY(-20px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+@keyframes fadeInLeft {
+ from {
+ opacity: 0;
+ transform: translateX(-20px);
+ }
+ to {
+ opacity: 1;
+ transform: translateX(0);
+ }
+}
+
+@keyframes fadeInRight {
+ from {
+ opacity: 0;
+ transform: translateX(20px);
+ }
+ to {
+ opacity: 1;
+ transform: translateX(0);
+ }
+}
+
+@keyframes scaleIn {
+ from {
+ opacity: 0;
+ transform: scale(0.9);
+ }
+ to {
+ opacity: 1;
+ transform: scale(1);
+ }
+}
+
+@keyframes slideUp {
+ from { transform: translateY(100%); }
+ to { transform: translateY(0); }
+}
+
+@keyframes slideDown {
+ from { transform: translateY(-100%); }
+ to { transform: translateY(0); }
+}
+
+@keyframes bounce {
+ 0%, 100% { transform: translateY(0); }
+ 50% { transform: translateY(-10px); }
+}
+
+@keyframes pulse {
+ 0%, 100% {
+ opacity: 1;
+ transform: scale(1);
+ }
+ 50% {
+ opacity: 0.7;
+ transform: scale(1.05);
+ }
+}
+
+@keyframes spin {
+ from { transform: rotate(0deg); }
+ to { transform: rotate(360deg); }
+}
+
+@keyframes shimmer {
+ 0% { background-position: -200% 0; }
+ 100% { background-position: 200% 0; }
+}
+
+@keyframes float {
+ 0%, 100% { transform: translateY(0px); }
+ 50% { transform: translateY(-10px); }
+}
+
+@keyframes ripple {
+ 0% {
+ transform: scale(0);
+ opacity: 1;
+ }
+ 100% {
+ transform: scale(4);
+ opacity: 0;
+ }
+}
+
+/* 动画工具类 */
+.animate-fade-in { animation: fadeIn 0.3s ease-out; }
+.animate-fade-in-up { animation: fadeInUp 0.4s ease-out; }
+.animate-fade-in-down { animation: fadeInDown 0.4s ease-out; }
+.animate-fade-in-left { animation: fadeInLeft 0.4s ease-out; }
+.animate-fade-in-right { animation: fadeInRight 0.4s ease-out; }
+.animate-scale-in { animation: scaleIn 0.3s ease-out; }
+.animate-bounce { animation: bounce 2s infinite; }
+.animate-pulse { animation: pulse 2s infinite; }
+.animate-spin { animation: spin 1s linear infinite; }
+.animate-float { animation: float 3s ease-in-out infinite; }
+
+/* 延迟类 */
+.delay-100 { animation-delay: 0.1s; }
+.delay-200 { animation-delay: 0.2s; }
+.delay-300 { animation-delay: 0.3s; }
+.delay-400 { animation-delay: 0.4s; }
+.delay-500 { animation-delay: 0.5s; }
+
+/* 悬停效果 */
+.hover-lift {
transition: var(--transition);
}
-.panel:hover {
- box-shadow: var(--shadow-lg);
+.hover-lift:hover {
+ transform: translateY(-4px);
+ box-shadow: var(--shadow-md);
}
-.page-title {
- font-size: 24px;
- font-weight: 600;
- margin: 0 0 24px;
- color: var(--text);
+.hover-scale {
+ transition: var(--transition);
+}
+
+.hover-scale:hover {
+ transform: scale(1.02);
+}
+
+.hover-glow {
+ transition: var(--transition);
+}
+
+.hover-glow:hover {
+ box-shadow: 0 0 20px rgba(13, 148, 136, 0.3);
+}
+
+/* 面板样式 */
+.panel {
+ background: var(--panel-bg);
+ border-radius: var(--radius-lg);
+ padding: 28px;
+ box-shadow: var(--shadow-sm);
+ border: 1px solid var(--border-light);
+ transition: var(--transition-slow);
position: relative;
- padding-bottom: 12px;
-}
-
-.page-title::after {
- content: '';
- position: absolute;
- bottom: 0;
- left: 0;
- width: 50px;
- height: 3px;
- background: var(--primary);
- border-radius: 3px;
-}
-
-.inline-form {
- display: flex;
- flex-wrap: wrap;
- gap: 16px;
- align-items: center;
- margin-bottom: 20px;
- padding-bottom: 20px;
- border-bottom: 1px solid var(--border);
-}
-
-.table-actions {
- display: flex;
- gap: 8px;
-}
-
-.t-table {
- border-radius: var(--radius);
overflow: hidden;
}
-.t-btn {
- border-radius: var(--radius) !important;
- transition: var(--transition) !important;
+.panel::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ height: 1px;
+ background: linear-gradient(90deg, transparent, rgba(255,255,255,0.8), transparent);
}
-.t-btn--variant-outline {
- border-color: var(--primary) !important;
+.panel:hover {
+ box-shadow: var(--shadow-md);
+ transform: translateY(-2px);
+ border-color: var(--border-hover);
+}
+
+/* 玻璃态面板 */
+.panel-glass {
+ background: rgba(255, 255, 255, 0.8);
+ backdrop-filter: blur(20px);
+ border: 1px solid rgba(255, 255, 255, 0.3);
+}
+
+/* 渐变面板 */
+.panel-gradient {
+ background: linear-gradient(135deg, var(--panel-bg) 0%, var(--app-bg) 100%);
+}
+
+/* 页面标题 */
+.page-title {
+ font-size: 32px;
+ font-weight: 800;
+ margin: 0 0 12px;
+ color: var(--text);
+ background: linear-gradient(135deg, var(--text) 0%, var(--text-secondary) 100%);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ background-clip: text;
+ letter-spacing: -0.5px;
+}
+
+.page-subtitle {
+ font-size: 15px;
+ color: var(--text-secondary);
+ margin: 0;
+ font-weight: 500;
+}
+
+/* TDesign 组件样式覆盖 */
+
+/* 按钮样式优化 */
+.t-button--theme-primary {
+ background: linear-gradient(135deg, var(--primary), var(--primary-light)) !important;
+ border: none !important;
+ box-shadow: var(--shadow-primary);
+ font-weight: 600;
+ position: relative;
+ overflow: hidden;
+}
+
+.t-button--theme-primary::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: -100%;
+ width: 100%;
+ height: 100%;
+ background: linear-gradient(90deg, transparent, rgba(255,255,255,0.3), transparent);
+ transition: left 0.5s;
+}
+
+.t-button--theme-primary:hover {
+ transform: translateY(-2px);
+ box-shadow: 0 8px 25px rgba(13, 148, 136, 0.45);
+}
+
+.t-button--theme-primary:hover::before {
+ left: 100%;
+}
+
+.t-button--theme-primary:active {
+ transform: translateY(0);
+}
+
+.t-button--variant-outline {
+ border: 2px solid var(--primary) !important;
color: var(--primary) !important;
+ background: transparent !important;
+ font-weight: 600;
+ transition: var(--transition);
}
-.t-btn--variant-outline:hover {
- background: var(--primary) !important;
- color: white !important;
+.t-button--variant-outline:hover {
+ background: rgba(13, 148, 136, 0.08) !important;
+ border-color: var(--primary-dark) !important;
+ color: var(--primary-dark) !important;
+ transform: translateY(-1px);
}
-.t-btn--theme-primary {
- background: var(--primary) !important;
- border-color: var(--primary) !important;
+.t-button--variant-text {
+ font-weight: 500;
+ transition: var(--transition);
}
-.t-btn--theme-primary:hover {
- background: var(--primary-hover) !important;
- border-color: var(--primary-hover) !important;
+.t-button--variant-text:hover {
+ background: rgba(13, 148, 136, 0.08) !important;
}
+/* 输入框样式 */
+.t-input {
+ border-radius: var(--radius-sm);
+ transition: var(--transition);
+ border: 2px solid var(--border);
+}
+
+.t-input:hover {
+ border-color: var(--border-hover);
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
+}
+
+.t-input:focus {
+ border-color: var(--primary);
+ box-shadow: 0 0 0 4px rgba(13, 148, 136, 0.1);
+}
+
+.t-input__inner {
+ font-size: 15px;
+ font-weight: 500;
+}
+
+.t-input__prefix-icon {
+ color: var(--text-muted);
+ transition: var(--transition);
+}
+
+.t-input:focus-within .t-input__prefix-icon {
+ color: var(--primary);
+}
+
+/* 表格样式 */
+.t-table {
+ border-radius: var(--radius);
+ overflow: hidden;
+ border: 1px solid var(--border-light);
+}
+
+.t-table__header {
+ background: linear-gradient(135deg, #f8fafc, #f1f5f9);
+}
+
+.t-table__th-cell {
+ font-weight: 700;
+ color: var(--text);
+ padding: 18px 16px;
+ font-size: 13px;
+ text-transform: uppercase;
+ letter-spacing: 0.5px;
+}
+
+.t-table__row {
+ transition: var(--transition);
+}
+
+.t-table__row:hover {
+ background: rgba(13, 148, 136, 0.04);
+}
+
+.t-table__td {
+ padding: 16px;
+ font-size: 14px;
+ color: var(--text-secondary);
+}
+
+.t-table--striped .t-table__row:nth-child(even) {
+ background: rgba(248, 250, 252, 0.5);
+}
+
+.t-table--striped .t-table__row:nth-child(even):hover {
+ background: rgba(13, 148, 136, 0.05);
+}
+
+/* 标签样式 */
.t-tag {
- border-radius: 20px !important;
+ border-radius: var(--radius-full) !important;
padding: 4px 12px !important;
font-size: 12px !important;
font-weight: 500 !important;
+ border: none !important;
}
+/* 卡片样式 */
.t-card {
border-radius: var(--radius) !important;
+ box-shadow: var(--shadow-sm) !important;
+ border: 1px solid var(--border-light) !important;
+ transition: var(--transition);
+}
+
+.t-card:hover {
box-shadow: var(--shadow) !important;
}
-.t-form__controls {
- margin-top: 10px !important;
+/* 表单样式 */
+.t-form__item {
+ margin-bottom: 20px;
+}
+
+.t-form__label {
+ font-weight: 500;
+ color: var(--text);
+}
+
+/* 对话框样式 */
+.t-dialog {
+ border-radius: var(--radius-lg) !important;
+ overflow: hidden;
+}
+
+.t-dialog__header {
+ padding: 24px 24px 16px !important;
+ border-bottom: 1px solid var(--border-light);
}
.t-dialog__body {
@@ -134,41 +495,119 @@ body {
.t-dialog__footer {
padding: 16px 24px 24px !important;
+ border-top: 1px solid var(--border-light);
}
-.form-section-title {
- font-size: 16px;
+/* 菜单样式 */
+.t-menu {
+ border-radius: var(--radius);
+}
+
+.t-menu__item {
+ border-radius: var(--radius-sm);
+ margin: 4px 8px;
+ transition: var(--transition);
+}
+
+.t-menu__item.t-is-active {
+ background: linear-gradient(135deg, rgba(13, 148, 136, 0.1), rgba(20, 184, 166, 0.1));
+ color: var(--primary);
font-weight: 600;
- color: var(--text);
- margin: 24px 0 16px;
- padding-left: 12px;
- border-left: 4px solid var(--primary);
}
+/* 分页样式 */
+.t-pagination {
+ padding: 16px 0;
+}
+
+.t-pagination__number.t-is-current {
+ background: linear-gradient(135deg, var(--primary), var(--primary-light)) !important;
+ border-color: transparent !important;
+}
+
+/* 状态徽章 */
.status-badge {
- display: inline-block;
- padding: 4px 12px;
- border-radius: 20px;
+ display: inline-flex;
+ align-items: center;
+ gap: 6px;
+ padding: 6px 14px;
+ border-radius: var(--radius-full);
font-size: 12px;
- font-weight: 500;
+ font-weight: 600;
+}
+
+.status-badge::before {
+ content: '';
+ width: 6px;
+ height: 6px;
+ border-radius: 50%;
}
.status-pending {
- background: #fef3c7;
- color: #d97706;
+ background: var(--warning-light);
+ color: #b45309;
}
-.status-active {
- background: #d1fae5;
- color: #059669;
+.status-pending::before { background: var(--warning); }
+
+.status-active,
+.status-processing {
+ background: var(--info-light);
+ color: #1d4ed8;
}
-.status-completed {
- background: #dbeafe;
- color: #2563eb;
+.status-active::before,
+.status-processing::before { background: var(--info); }
+
+.status-completed,
+.status-success {
+ background: var(--success-light);
+ color: #047857;
}
-.status-cancelled {
- background: #fee2e2;
- color: #dc2626;
+.status-completed::before,
+.status-success::before { background: var(--success); }
+
+.status-cancelled,
+.status-error {
+ background: var(--danger-light);
+ color: #b91c1c;
+}
+
+.status-cancelled::before,
+.status-error::before { background: var(--danger); }
+
+/* 滚动条样式 */
+::-webkit-scrollbar {
+ width: 8px;
+ height: 8px;
+}
+
+::-webkit-scrollbar-track {
+ background: var(--border-light);
+ border-radius: var(--radius-full);
+}
+
+::-webkit-scrollbar-thumb {
+ background: var(--text-muted);
+ border-radius: var(--radius-full);
+}
+
+::-webkit-scrollbar-thumb:hover {
+ background: var(--text-secondary);
+}
+
+/* 响应式调整 */
+@media (max-width: 768px) {
+ .page {
+ padding: 16px;
+ }
+
+ .page-title {
+ font-size: 22px;
+ }
+
+ .panel {
+ padding: 16px;
+ }
}
diff --git a/frontend/src/styles/theme.css b/frontend/src/styles/theme.css
new file mode 100644
index 0000000..e3a6559
--- /dev/null
+++ b/frontend/src/styles/theme.css
@@ -0,0 +1,98 @@
+/* Pet Hospital Theme Variables */
+:root {
+ /* Primary Brand Colors */
+ --brand-primary: #4361ee;
+ --brand-secondary: #3f37c9;
+ --brand-accent: #4cc9f0;
+
+ /* Status Colors */
+ --status-success: #4ade80;
+ --status-warning: #facc15;
+ --status-error: #f87171;
+ --status-info: #60a5fa;
+
+ /* Neutral Palette */
+ --neutral-50: #f8fafc;
+ --neutral-100: #f1f5f9;
+ --neutral-200: #e2e8f0;
+ --neutral-300: #cbd5e1;
+ --neutral-400: #94a3b8;
+ --neutral-500: #64748b;
+ --neutral-600: #475569;
+ --neutral-700: #334155;
+ --neutral-800: #1e293b;
+ --neutral-900: #0f172a;
+
+ /* Backgrounds */
+ --bg-app: var(--neutral-50);
+ --bg-panel: #ffffff;
+ --bg-hover: var(--neutral-100);
+
+ /* Text */
+ --text-primary: var(--neutral-800);
+ --text-secondary: var(--neutral-600);
+ --text-muted: var(--neutral-500);
+ --text-inverse: #ffffff;
+
+ /* Borders */
+ --border-default: var(--neutral-200);
+ --border-subtle: var(--neutral-300);
+
+ /* Shadows */
+ --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
+ --shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1);
+ --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1);
+ --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1);
+ --shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1);
+
+ /* Radius */
+ --radius-xs: 4px;
+ --radius-sm: 6px;
+ --radius: 8px;
+ --radius-lg: 12px;
+ --radius-xl: 16px;
+ --radius-full: 9999px;
+
+ /* Transitions */
+ --transition-fast: all 0.15s ease;
+ --transition: all 0.2s ease;
+ --transition-slow: all 0.3s ease;
+
+ /* Spacing */
+ --space-xxs: 4px;
+ --space-xs: 8px;
+ --space-sm: 12px;
+ --space: 16px;
+ --space-md: 20px;
+ --space-lg: 24px;
+ --space-xl: 32px;
+ --space-xxl: 40px;
+
+ /* Typography */
+ --font-size-xs: 12px;
+ --font-size-sm: 14px;
+ --font-size: 16px;
+ --font-size-lg: 18px;
+ --font-size-xl: 20px;
+ --font-size-xxl: 24px;
+ --font-size-xxxl: 32px;
+
+ --font-weight-normal: 400;
+ --font-weight-medium: 500;
+ --font-weight-semibold: 600;
+ --font-weight-bold: 700;
+}
+
+/* Dark mode support (optional) */
+@media (prefers-color-scheme: dark) {
+ :root {
+ --bg-app: var(--neutral-900);
+ --bg-panel: var(--neutral-800);
+ --bg-hover: var(--neutral-700);
+ --text-primary: var(--neutral-100);
+ --text-secondary: var(--neutral-300);
+ --text-muted: var(--neutral-400);
+ --border-default: var(--neutral-700);
+ --border-subtle: var(--neutral-600);
+ }
+}
\ No newline at end of file
diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts
index bfb8e86..c07b9ab 100644
--- a/frontend/vite.config.ts
+++ b/frontend/vite.config.ts
@@ -7,7 +7,7 @@ export default defineConfig({
port: 5173,
proxy: {
'/api': {
- target: 'http://localhost:8081',
+ target: 'http://localhost:8080',
changeOrigin: true,
},
},