feat(frontend): 重构本地调试代理配置
将 `packages/frontend` 的 Vite 开发代理改为可通过环境变量 切换目标地址,并补充本地联调所需的默认主题与样式更新。 同时同步更新前后端默认 UI 主题定义,便于在本地直接验证 远端接口、WebSocket 与视觉效果。
This commit is contained in:
@@ -2,6 +2,9 @@
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
- **[frontend]**: 将 `packages/frontend` 的 Vite 开发代理改为支持通过 `VITE_DEV_PROXY_TARGET`、`VITE_DEV_WS_PROXY_TARGET` 与 `VITE_API_BASE_URL` 切换远端联调目标,并验证 `focus-switcher-sequence`、登录链路与默认白色主题可在本地前端联调时正常工作 — by yinjianm
|
||||
- 方案: [202604210440_frontend-dev-api-theme-verification](archive/2026-04/202604210440_frontend-dev-api-theme-verification/)
|
||||
|
||||
- **[frontend]**: 为 SSH 顶部服务器标签与服务器内终端标签补充 `%` 命令运行中提示,并基于前端发送链路与 shell prompt 输出派生运行态 — by yinjianm
|
||||
- 方案: [202604192106_terminal-running-indicator](archive/2026-04/202604192106_terminal-running-indicator/)
|
||||
- 决策: terminal-running-indicator#D001(运行态继续作为前端派生状态实现), terminal-running-indicator#D002(采用发送置位加 prompt 清除的混合检测策略)
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"status":"completed","completed":6,"failed":0,"pending":0,"total":6,"done":6,"percent":100,"current":"任务完成,等待归档","updated_at":"2026-04-21 04:53:00"}
|
||||
+139
@@ -0,0 +1,139 @@
|
||||
# 变更提案: frontend-dev-api-theme-verification
|
||||
|
||||
## 元信息
|
||||
```yaml
|
||||
类型: 优化
|
||||
方案类型: implementation
|
||||
优先级: P1
|
||||
状态: 已完成
|
||||
创建: 2026-04-21
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 1. 需求
|
||||
|
||||
### 背景
|
||||
用户要求将本地前端联调请求切到 `https://ssh.deiban.com`,重点验证
|
||||
`/api/v1/settings/focus-switcher-sequence` 这类设置接口是否能通过本地前端正确访问,
|
||||
并使用 `admin / @Micah.666` 登录后确认此前“默认前端白色主题”改动是否真实生效。
|
||||
|
||||
### 目标
|
||||
- 仅调整本地开发联调入口,不改动前端生产默认 API 地址。
|
||||
- 让本地 `packages/frontend` 在开发模式下统一代理远端 `https://ssh.deiban.com`。
|
||||
- 完成一次真实浏览器登录与页面视觉验收,确认白色主题是否生效,并给出结论。
|
||||
|
||||
### 约束条件
|
||||
```yaml
|
||||
时间约束: 当前回合内完成代码改动与联调验证
|
||||
性能约束: 不引入额外运行时开销,保持 Vite 代理方案
|
||||
兼容性约束: 现有相对路径 API 调用保持不变,本地切换后仍可回退到 localhost:3001
|
||||
业务约束: 仅作用于本地开发联调,不覆盖共享生产配置
|
||||
```
|
||||
|
||||
### 验收标准
|
||||
- [√] 本地前端开发环境可将 `/api`、`/uploads`、`/ws` 请求代理到 `ssh.deiban.com`
|
||||
- [√] 使用 `admin / @Micah.666` 可从本地前端完成登录并访问登录后页面
|
||||
- [√] 浏览器实测能判断白色主题是否生效,并能给出成功或失败的证据
|
||||
|
||||
---
|
||||
|
||||
## 2. 方案
|
||||
|
||||
### 技术方案
|
||||
保留前端现有的相对路径请求方式,不改 `apiClient` 和 store 内部接口地址。
|
||||
将 `packages/frontend/vite.config.ts` 改为支持从本地开发环境变量读取 dev proxy 目标,
|
||||
默认仍指向 `localhost:3001`。同时新增忽略提交的
|
||||
`packages/frontend/.env.development.local`,把本地开发代理目标切换到
|
||||
`https://ssh.deiban.com` / `wss://ssh.deiban.com`,并显式设置 `VITE_API_BASE_URL`
|
||||
供页面背景等直接拼接后端 URL 的逻辑使用。完成后启动本地 Vite,并用浏览器执行登录和主题验收。
|
||||
|
||||
### 影响范围
|
||||
```yaml
|
||||
涉及模块:
|
||||
- frontend: 调整本地开发代理配置与运行时联调环境变量
|
||||
预计变更文件: 4
|
||||
```
|
||||
|
||||
### 风险评估
|
||||
| 风险 | 等级 | 应对 |
|
||||
|------|------|------|
|
||||
| 远端站点 WebSocket 目标与本地代理协议不兼容 | 中 | 同步提供 `VITE_DEV_WS_PROXY_TARGET`,保持与 HTTP 代理解耦 |
|
||||
| 远端管理员账号存在用户级外观配置,导致白色主题判断受后端数据影响 | 中 | 同时检查登录页和登录后页面样式来源,区分默认主题与后端覆盖 |
|
||||
| 本地环境变量文件被忽略后不在 Git 记录中 | 低 | 在最终结果中明确说明本地文件路径与用途 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 技术设计(可选)
|
||||
|
||||
> 本次不涉及架构、API 或数据模型变更。
|
||||
|
||||
### 架构设计
|
||||
N/A
|
||||
|
||||
### API设计
|
||||
N/A
|
||||
|
||||
### 数据模型
|
||||
N/A
|
||||
|
||||
---
|
||||
|
||||
## 4. 核心场景
|
||||
|
||||
> 执行完成后同步到对应模块文档
|
||||
|
||||
### 场景: 本地前端联调远端测试后端
|
||||
**模块**: frontend
|
||||
**条件**: 开发者在 `packages/frontend` 启动本地 Vite 开发服务器
|
||||
**行为**: 前端通过本地代理将 `/api`、`/uploads`、`/ws` 请求转发到 `ssh.deiban.com`
|
||||
**结果**: 无需改动业务代码中的相对路径接口即可完成远端联调
|
||||
|
||||
### 场景: 登录后验收默认白色主题
|
||||
**模块**: frontend
|
||||
**条件**: 使用管理员账号登录本地前端
|
||||
**行为**: 检查登录页与登录后页面的背景、文字和主容器配色
|
||||
**结果**: 能明确判断白色主题是否生效,以及是否被后端持久化外观配置覆盖
|
||||
|
||||
---
|
||||
|
||||
## 5. 技术决策
|
||||
|
||||
> 本方案涉及的技术决策,归档后成为决策的唯一完整记录
|
||||
|
||||
### frontend-dev-api-theme-verification#D001: 使用可配置的 dev proxy 而非写死远端 API
|
||||
**日期**: 2026-04-21
|
||||
**状态**: ✅采纳
|
||||
**背景**: 需要将本地前端切到远端测试后端验证主题效果,但不应把共享开发默认值永久改成远端地址。
|
||||
**选项分析**:
|
||||
| 选项 | 优点 | 缺点 |
|
||||
|------|------|------|
|
||||
| A: 直接把 `vite.config.ts` 写死到 `ssh.deiban.com` | 改动最少,立刻可用 | 污染团队默认开发配置,回切需要再次改代码 |
|
||||
| B: 让 `vite.config.ts` 读取环境变量,再用 `.env.development.local` 本地覆盖 | 保持默认本地后端联调,同时支持当前远端测试 | 需要新增一个本地环境变量文件 |
|
||||
**决策**: 选择方案 B
|
||||
**理由**: 既满足当前本地调试诉求,又不破坏仓库共享默认值,后续切回本地后端只需改本地环境变量。
|
||||
**影响**: 影响 `packages/frontend/vite.config.ts` 的开发代理读取方式,以及本地开发环境变量文件组织方式
|
||||
|
||||
---
|
||||
|
||||
## 6. 成果设计
|
||||
|
||||
> 含视觉产出的任务由 DESIGN Phase2 填充。非视觉任务整节标注"N/A"。
|
||||
|
||||
本任务不新增视觉设计,仅验证既有白色主题是否已经生效。
|
||||
|
||||
### 设计方向
|
||||
- **美学基调**: N/A
|
||||
- **记忆点**: N/A
|
||||
- **参考**: 现有前端默认白色主题实现
|
||||
|
||||
### 视觉要素
|
||||
- **配色**: N/A
|
||||
- **字体**: N/A
|
||||
- **布局**: N/A
|
||||
- **动效**: N/A
|
||||
- **氛围**: N/A
|
||||
|
||||
### 技术约束
|
||||
- **可访问性**: 保持现有主题变量与文本对比度,不在本任务中新增样式覆盖
|
||||
- **响应式**: 仅做桌面浏览器联调验证
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
# 任务清单: frontend-dev-api-theme-verification
|
||||
|
||||
> **@status:** completed | 2026-04-21 04:55
|
||||
|
||||
```yaml
|
||||
@feature: frontend-dev-api-theme-verification
|
||||
@created: 2026-04-21
|
||||
@status: completed
|
||||
@mode: R2
|
||||
```
|
||||
|
||||
## 进度概览
|
||||
|
||||
| 完成 | 失败 | 跳过 | 总数 |
|
||||
|------|------|------|------|
|
||||
| 6 | 0 | 0 | 6 |
|
||||
|
||||
---
|
||||
|
||||
## 任务列表
|
||||
|
||||
### 1. 方案与配置
|
||||
|
||||
- [√] 1.1 完成本地前端联调方案包填充,明确仅影响开发代理与本地环境变量 | depends_on: []
|
||||
- [√] 1.2 在 `packages/frontend/src` 与 `vite.config.ts` 相关上下文中确认 API、背景资源和 WebSocket 的开发联调入口 | depends_on: [1.1]
|
||||
|
||||
### 2. 前端开发联调改动
|
||||
|
||||
- [√] 2.1 在 `packages/frontend/vite.config.ts` 中改造开发代理,支持通过环境变量切换 HTTP 与 WebSocket 目标 | depends_on: [1.2]
|
||||
- [√] 2.2 新增 `packages/frontend/.env.development.local`,将本地开发联调目标设置为 `ssh.deiban.com` 并声明 `VITE_API_BASE_URL` | depends_on: [2.1]
|
||||
|
||||
### 3. 浏览器验收
|
||||
|
||||
- [√] 3.1 启动本地前端,使用 `admin / @Micah.666` 完成登录并验证关键接口可用 | depends_on: [2.2]
|
||||
- [√] 3.2 检查登录页与登录后页面的主题表现,确认默认白色主题是否成功生效并记录证据 | depends_on: [3.1]
|
||||
|
||||
---
|
||||
|
||||
## 执行日志
|
||||
|
||||
| 时间 | 任务 | 状态 | 备注 |
|
||||
|------|------|------|------|
|
||||
| 2026-04-21 04:40 | 方案包创建 | completed | `create_package.py` 已生成 proposal.md 与 tasks.md 模板 |
|
||||
| 2026-04-21 04:44 | 2.x | completed | `vite.config.ts` 已支持基于环境变量切换 dev proxy,本地 `.env.development.local` 已指向 `ssh.deiban.com` |
|
||||
| 2026-04-21 04:45 | 构建验证 | completed | `npm run build` 通过,仅保留既有 chunk size 警告 |
|
||||
| 2026-04-21 04:53 | 3.x | completed | 本地前端以 `admin / @Micah.666` 登录成功,`/api/v1/settings/focus-switcher-sequence` 登录后返回 200,登录页与仪表盘 `body`/主容器为浅色主题 |
|
||||
|
||||
---
|
||||
|
||||
## 执行备注
|
||||
|
||||
> 记录执行过程中的重要说明、决策变更、风险提示等
|
||||
|
||||
- 本任务采用 R2 简化流程,不做多方案对比。
|
||||
- 本地联调参数优先放入忽略提交的 `.env.development.local`,避免污染共享默认配置。
|
||||
- 浏览器实测结果: 登录页 `body` 背景为 `rgb(245, 245, 247)`,仪表盘主容器背景为 `rgb(245, 245, 247)`,统计卡片背景为 `rgb(255, 255, 255)`,标题文字为 `rgb(29, 29, 31)`,默认白色主题验证通过。
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
| 时间戳 | 名称 | 类型 | 涉及模块 | 决策 | 结果 |
|
||||
|--------|------|------|---------|------|------|
|
||||
| 202604210440 | frontend-dev-api-theme-verification | - | - | - | ✅完成 |
|
||||
| 202604192106 | terminal-running-indicator | - | - | - | ✅完成 |
|
||||
| 202604190520 | status-monitor-cpu-summary-modal | - | - | - | ✅完成 |
|
||||
| 202604190351 | status-monitor-cpu-total-and-per-core | implementation | frontend, backend | status-monitor-cpu-total-and-per-core#D001 | ✅完成 |
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,293 @@
|
||||
# Design System Inspired by NVIDIA
|
||||
|
||||
## 1. Visual Theme & Atmosphere
|
||||
|
||||
NVIDIA's website is a high-contrast, technology-forward experience that communicates raw computational power through design restraint. The page is built on a stark black (`#000000`) and white (`#ffffff`) foundation, punctuated by NVIDIA's signature green (`#76b900`) -- a color so specific it functions as a brand fingerprint. This is not the lush green of nature; it's the electric, lime-shifted green of GPU-rendered light, a color that sits between chartreuse and kelly green and immediately signals "NVIDIA" to anyone in technology.
|
||||
|
||||
The custom NVIDIA-EMEA font family (with Arial and Helvetica fallbacks) creates a clean, industrial typographic voice. Headings at 36px bold with tight 1.25 line-height create dense, authoritative blocks of text. The font lacks the geometric playfulness of Silicon Valley sans-serifs -- it's European, pragmatic, and engineering-focused. Body text runs at 15-16px, comfortable for reading but not generous, maintaining the sense that screen real estate is optimized like GPU memory.
|
||||
|
||||
What distinguishes NVIDIA's design from other dark-background tech sites is the disciplined use of the green accent. The `#76b900` appears in borders (`2px solid #76b900`), link underlines (`underline 2px rgb(118, 185, 0)`), and CTAs -- but never as backgrounds or large surface areas on the main content. The green is a signal, not a surface. Combined with a deep shadow system (`rgba(0, 0, 0, 0.3) 0px 0px 5px`) and minimal border radius (1-2px), the overall effect is of precision engineering hardware rendered in pixels.
|
||||
|
||||
**Key Characteristics:**
|
||||
- NVIDIA Green (`#76b900`) as pure accent -- borders, underlines, and interactive highlights only
|
||||
- Black (`#000000`) dominant background with white (`#ffffff`) text on dark sections
|
||||
- NVIDIA-EMEA custom font with Arial/Helvetica fallback -- industrial, European, clean
|
||||
- Tight line-heights (1.25 for headings) creating dense, authoritative text blocks
|
||||
- Minimal border radius (1-2px) -- sharp, engineered corners throughout
|
||||
- Green-bordered buttons (`2px solid #76b900`) as primary interactive pattern
|
||||
- Font Awesome 6 Pro/Sharp icon system at weight 900 for sharp iconography
|
||||
- Multi-framework architecture (PrimeReact, Fluent UI, Element Plus) enabling rich interactive components
|
||||
|
||||
## 2. Color Palette & Roles
|
||||
|
||||
### Primary Brand
|
||||
- **NVIDIA Green** (`#76b900`): The signature -- borders, link underlines, CTA outlines, active indicators. Never used as large surface fills.
|
||||
- **True Black** (`#000000`): Primary page background, text on light surfaces, dominant tone.
|
||||
- **Pure White** (`#ffffff`): Text on dark backgrounds, light section backgrounds, card surfaces.
|
||||
|
||||
### Extended Brand Palette
|
||||
- **NVIDIA Green Light** (`#bff230`): Bright lime accent for highlights and hover states.
|
||||
- **Orange 400** (`#df6500`): Warm accent for alerts, featured badges, or energy-related contexts.
|
||||
- **Yellow 300** (`#ef9100`): Secondary warm accent, product category highlights.
|
||||
- **Yellow 050** (`#feeeb2`): Light warm surface for callout backgrounds.
|
||||
|
||||
### Status & Semantic
|
||||
- **Red 500** (`#e52020`): Error states, destructive actions, critical alerts.
|
||||
- **Red 800** (`#650b0b`): Deep red for severe warning backgrounds.
|
||||
- **Green 500** (`#3f8500`): Success states, positive indicators (darker than brand green).
|
||||
- **Blue 700** (`#0046a4`): Informational accents, link hover alternative.
|
||||
|
||||
### Decorative
|
||||
- **Purple 800** (`#4d1368`): Deep purple for gradient ends, premium/AI contexts.
|
||||
- **Purple 100** (`#f9d4ff`): Light purple surface tint.
|
||||
- **Fuchsia 700** (`#8c1c55`): Rich accent for special promotions or featured content.
|
||||
|
||||
### Neutral Scale
|
||||
- **Gray 300** (`#a7a7a7`): Muted text, disabled labels.
|
||||
- **Gray 400** (`#898989`): Secondary text, metadata.
|
||||
- **Gray 500** (`#757575`): Tertiary text, placeholders, footers.
|
||||
- **Gray Border** (`#5e5e5e`): Subtle borders, divider lines.
|
||||
- **Near Black** (`#1a1a1a`): Dark surfaces, card backgrounds on black pages.
|
||||
|
||||
### Interactive States
|
||||
- **Link Default (dark bg)** (`#ffffff`): White links on dark backgrounds.
|
||||
- **Link Default (light bg)** (`#000000`): Black links with green underline on light backgrounds.
|
||||
- **Link Hover** (`#3860be`): Blue shift on hover across all link variants.
|
||||
- **Button Hover** (`#1eaedb`): Teal highlight for button hover states.
|
||||
- **Button Active** (`#007fff`): Bright blue for active/pressed button states.
|
||||
- **Focus Ring** (`#000000 solid 2px`): Black outline for keyboard focus.
|
||||
|
||||
### Shadows & Depth
|
||||
- **Card Shadow** (`rgba(0, 0, 0, 0.3) 0px 0px 5px 0px`): Subtle ambient shadow for elevated cards.
|
||||
|
||||
## 3. Typography Rules
|
||||
|
||||
### Font Family
|
||||
- **Primary**: `NVIDIA-EMEA`, with fallbacks: `Arial, Helvetica, sans-serif`
|
||||
- **Icon Font**: `Font Awesome 6 Pro` (weight 900 for solid icons, 700 for regular)
|
||||
- **Icon Sharp**: `Font Awesome 6 Sharp` (weight 300 for light icons, 400 for regular)
|
||||
|
||||
### Hierarchy
|
||||
|
||||
| Role | Font | Size | Weight | Line Height | Letter Spacing | Notes |
|
||||
|------|------|------|--------|-------------|----------------|-------|
|
||||
| Display Hero | NVIDIA-EMEA | 36px (2.25rem) | 700 | 1.25 (tight) | normal | Maximum impact headlines |
|
||||
| Section Heading | NVIDIA-EMEA | 24px (1.50rem) | 700 | 1.25 (tight) | normal | Section titles, card headings |
|
||||
| Sub-heading | NVIDIA-EMEA | 22px (1.38rem) | 400 | 1.75 (relaxed) | normal | Feature descriptions, subtitles |
|
||||
| Card Title | NVIDIA-EMEA | 20px (1.25rem) | 700 | 1.25 (tight) | normal | Card and module headings |
|
||||
| Body Large | NVIDIA-EMEA | 18px (1.13rem) | 700 | 1.67 (relaxed) | normal | Emphasized body, lead paragraphs |
|
||||
| Body | NVIDIA-EMEA | 16px (1.00rem) | 400 | 1.50 | normal | Standard reading text |
|
||||
| Body Bold | NVIDIA-EMEA | 16px (1.00rem) | 700 | 1.50 | normal | Strong labels, nav items |
|
||||
| Body Small | NVIDIA-EMEA | 15px (0.94rem) | 400 | 1.67 (relaxed) | normal | Secondary content, descriptions |
|
||||
| Body Small Bold | NVIDIA-EMEA | 15px (0.94rem) | 700 | 1.50 | normal | Emphasized secondary content |
|
||||
| Button Large | NVIDIA-EMEA | 18px (1.13rem) | 700 | 1.25 (tight) | normal | Primary CTA buttons |
|
||||
| Button | NVIDIA-EMEA | 16px (1.00rem) | 700 | 1.25 (tight) | normal | Standard buttons |
|
||||
| Button Compact | NVIDIA-EMEA | 14.4px (0.90rem) | 700 | 1.00 (tight) | 0.144px | Small/compact buttons |
|
||||
| Link | NVIDIA-EMEA | 14px (0.88rem) | 700 | 1.43 | normal | Navigation links |
|
||||
| Link Uppercase | NVIDIA-EMEA | 14px (0.88rem) | 700 | 1.43 | normal | `text-transform: uppercase`, nav labels |
|
||||
| Caption | NVIDIA-EMEA | 14px (0.88rem) | 600 | 1.50 | normal | Metadata, timestamps |
|
||||
| Caption Small | NVIDIA-EMEA | 12px (0.75rem) | 400 | 1.25 (tight) | normal | Fine print, legal |
|
||||
| Micro Label | NVIDIA-EMEA | 10px (0.63rem) | 700 | 1.50 | normal | `text-transform: uppercase`, tiny badges |
|
||||
| Micro | NVIDIA-EMEA | 11px (0.69rem) | 700 | 1.00 (tight) | normal | Smallest UI text |
|
||||
|
||||
### Principles
|
||||
- **Bold as the default voice**: NVIDIA leans heavily on weight 700 for headings, buttons, links, and labels. The 400 weight is reserved for body text and descriptions -- everything else is bold, projecting confidence and authority.
|
||||
- **Tight headings, relaxed body**: Heading line-height is consistently 1.25 (tight), while body text relaxes to 1.50-1.67. This contrast creates visual density at the top of content blocks and comfortable readability in paragraphs.
|
||||
- **Uppercase for navigation**: Link labels use `text-transform: uppercase` with weight 700, creating a navigation voice that reads like hardware specification labels.
|
||||
- **No decorative tracking**: Letter-spacing is normal throughout, except for compact buttons (0.144px). The font itself carries the industrial character without manipulation.
|
||||
|
||||
## 4. Component Stylings
|
||||
|
||||
### Buttons
|
||||
|
||||
**Primary (Green Border)**
|
||||
- Background: `transparent`
|
||||
- Text: `#000000`
|
||||
- Padding: 11px 13px
|
||||
- Border: `2px solid #76b900`
|
||||
- Radius: 2px
|
||||
- Font: 16px weight 700
|
||||
- Hover: background `#1eaedb`, text `#ffffff`
|
||||
- Active: background `#007fff`, text `#ffffff`, border `1px solid #003eff`, scale(1)
|
||||
- Focus: background `#1eaedb`, text `#ffffff`, outline `#000000 solid 2px`, opacity 0.9
|
||||
- Use: Primary CTA ("Learn More", "Explore Solutions")
|
||||
|
||||
**Secondary (Green Border Thin)**
|
||||
- Background: transparent
|
||||
- Border: `1px solid #76b900`
|
||||
- Radius: 2px
|
||||
- Use: Secondary actions, alternative CTAs
|
||||
|
||||
**Compact / Inline**
|
||||
- Font: 14.4px weight 700
|
||||
- Letter-spacing: 0.144px
|
||||
- Line-height: 1.00
|
||||
- Use: Inline CTAs, compact navigation
|
||||
|
||||
### Cards & Containers
|
||||
- Background: `#ffffff` (light) or `#1a1a1a` (dark sections)
|
||||
- Border: none (clean edges) or `1px solid #5e5e5e`
|
||||
- Radius: 2px
|
||||
- Shadow: `rgba(0, 0, 0, 0.3) 0px 0px 5px 0px` for elevated cards
|
||||
- Hover: shadow intensification
|
||||
- Padding: 16-24px internal
|
||||
|
||||
### Links
|
||||
- **On Dark Background**: `#ffffff`, no underline, hover shifts to `#3860be`
|
||||
- **On Light Background**: `#000000` or `#1a1a1a`, underline `2px solid #76b900`, hover shifts to `#3860be`, underline removed
|
||||
- **Green Links**: `#76b900`, hover shifts to `#3860be`
|
||||
- **Muted Links**: `#666666`, hover shifts to `#3860be`
|
||||
|
||||
### Navigation
|
||||
- Dark black background (`#000000`)
|
||||
- Logo left-aligned, prominent NVIDIA wordmark
|
||||
- Links: NVIDIA-EMEA 14px weight 700 uppercase, `#ffffff`
|
||||
- Hover: color shift, no underline change
|
||||
- Mega-menu dropdowns for product categories
|
||||
- Sticky on scroll with backdrop
|
||||
|
||||
### Image Treatment
|
||||
- Product/GPU renders as hero images, often full-width
|
||||
- Screenshot images with subtle shadow for depth
|
||||
- Green gradient overlays on dark hero sections
|
||||
- Circular avatar containers with 50% radius
|
||||
|
||||
### Distinctive Components
|
||||
|
||||
**Product Cards**
|
||||
- Clean white or dark card with minimal radius (2px)
|
||||
- Green accent border or underline on title
|
||||
- Bold heading + lighter description pattern
|
||||
- CTA with green border at bottom
|
||||
|
||||
**Tech Spec Tables**
|
||||
- Industrial grid layouts
|
||||
- Alternating row backgrounds (subtle gray shift)
|
||||
- Bold labels, regular values
|
||||
- Green highlights for key metrics
|
||||
|
||||
**Cookie/Consent Banner**
|
||||
- Fixed bottom positioning
|
||||
- Rounded buttons (2px radius)
|
||||
- Gray border treatments
|
||||
|
||||
## 5. Layout Principles
|
||||
|
||||
### Spacing System
|
||||
- Base unit: 8px
|
||||
- Scale: 1px, 2px, 3px, 4px, 5px, 6px, 7px, 8px, 9px, 10px, 11px, 12px, 13px, 15px
|
||||
- Primary padding values: 8px, 11px, 13px, 16px, 24px, 32px
|
||||
- Section spacing: 48-80px vertical padding
|
||||
|
||||
### Grid & Container
|
||||
- Max content width: approximately 1200px (contained)
|
||||
- Full-width hero sections with contained text
|
||||
- Feature sections: 2-3 column grids for product cards
|
||||
- Single-column for article/blog content
|
||||
- Sidebar layouts for documentation
|
||||
|
||||
### Whitespace Philosophy
|
||||
- **Purposeful density**: NVIDIA uses tighter spacing than typical SaaS sites, reflecting the density of technical content. White space exists to separate concepts, not to create luxury emptiness.
|
||||
- **Section rhythm**: Dark sections alternate with white sections, using background color (not just spacing) to separate content blocks.
|
||||
- **Card density**: Product cards sit close together with 16-20px gaps, creating a catalog feel rather than a gallery feel.
|
||||
|
||||
### Border Radius Scale
|
||||
- Micro (1px): Inline spans, tiny elements
|
||||
- Standard (2px): Buttons, cards, containers, inputs -- the default for nearly everything
|
||||
- Circle (50%): Avatar images, circular tab indicators
|
||||
|
||||
## 6. Depth & Elevation
|
||||
|
||||
| Level | Treatment | Use |
|
||||
|-------|-----------|-----|
|
||||
| Flat (Level 0) | No shadow | Page backgrounds, inline text |
|
||||
| Subtle (Level 1) | `rgba(0,0,0,0.3) 0px 0px 5px 0px` | Standard cards, modals |
|
||||
| Border (Level 1b) | `1px solid #5e5e5e` | Content dividers, section borders |
|
||||
| Green accent (Level 2) | `2px solid #76b900` | Active elements, CTAs, selected items |
|
||||
| Focus (Accessibility) | `2px solid #000000` outline | Keyboard focus ring |
|
||||
|
||||
**Shadow Philosophy**: NVIDIA's depth system is minimal and utilitarian. There is essentially one shadow value -- a 5px ambient blur at 30% opacity -- used sparingly for cards and modals. The primary depth signal is not shadow but _color contrast_: black backgrounds next to white sections, green borders on black surfaces. This creates hardware-like visual layering where depth comes from material difference, not simulated light.
|
||||
|
||||
### Decorative Depth
|
||||
- Green gradient washes behind hero content
|
||||
- Dark-to-darker gradients (black to near-black) for section transitions
|
||||
- No glassmorphism or blur effects -- clarity over atmosphere
|
||||
|
||||
## 7. Responsive Behavior
|
||||
|
||||
### Breakpoints
|
||||
| Name | Width | Key Changes |
|
||||
|------|-------|-------------|
|
||||
| Mobile Small | <375px | Compact single column, reduced padding |
|
||||
| Mobile | 375-425px | Standard mobile layout |
|
||||
| Mobile Large | 425-600px | Wider mobile, some 2-col hints |
|
||||
| Tablet Small | 600-768px | 2-column grids begin |
|
||||
| Tablet | 768-1024px | Full card grids, expanded nav |
|
||||
| Desktop | 1024-1350px | Standard desktop layout |
|
||||
| Large Desktop | >1350px | Maximum content width, generous margins |
|
||||
|
||||
### Touch Targets
|
||||
- Buttons use 11px 13px padding for comfortable tap targets
|
||||
- Navigation links at 14px uppercase with adequate spacing
|
||||
- Green-bordered buttons provide high-contrast touch targets on dark backgrounds
|
||||
- Mobile: hamburger menu collapse with full-screen overlay
|
||||
|
||||
### Collapsing Strategy
|
||||
- Hero: 36px heading scales down proportionally
|
||||
- Navigation: full horizontal nav collapses to hamburger menu at ~1024px
|
||||
- Product cards: 3-column to 2-column to single column stacked
|
||||
- Footer: multi-column grid collapses to single stacked column
|
||||
- Section spacing: 64-80px reduces to 32-48px on mobile
|
||||
- Images: maintain aspect ratio, scale to container width
|
||||
|
||||
### Image Behavior
|
||||
- GPU/product renders maintain high resolution at all sizes
|
||||
- Hero images scale proportionally with viewport
|
||||
- Card images use consistent aspect ratios
|
||||
- Full-bleed dark sections maintain edge-to-edge treatment
|
||||
|
||||
## 8. Responsive Behavior (Extended)
|
||||
|
||||
### Typography Scaling
|
||||
- Display 36px scales to ~24px on mobile
|
||||
- Section headings 24px scale to ~20px on mobile
|
||||
- Body text maintains 15-16px across all breakpoints
|
||||
- Button text maintains 16px for consistent tap targets
|
||||
|
||||
### Dark/Light Section Strategy
|
||||
- Dark sections (black bg, white text) alternate with light sections (white bg, black text)
|
||||
- The green accent remains consistent across both surface types
|
||||
- On dark: links are white, underlines are green
|
||||
- On light: links are black, underlines are green
|
||||
- This alternation creates natural scroll rhythm and content grouping
|
||||
|
||||
## 9. Agent Prompt Guide
|
||||
|
||||
### Quick Color Reference
|
||||
- Primary accent: NVIDIA Green (`#76b900`)
|
||||
- Background dark: True Black (`#000000`)
|
||||
- Background light: Pure White (`#ffffff`)
|
||||
- Heading text (dark bg): White (`#ffffff`)
|
||||
- Heading text (light bg): Black (`#000000`)
|
||||
- Body text (light bg): Black (`#000000`) or Near Black (`#1a1a1a`)
|
||||
- Body text (dark bg): White (`#ffffff`) or Gray 300 (`#a7a7a7`)
|
||||
- Link hover: Blue (`#3860be`)
|
||||
- Border accent: `2px solid #76b900`
|
||||
- Button hover: Teal (`#1eaedb`)
|
||||
|
||||
### Example Component Prompts
|
||||
- "Create a hero section on black background. Headline at 36px NVIDIA-EMEA weight 700, line-height 1.25, color #ffffff. Subtitle at 18px weight 400, line-height 1.67, color #a7a7a7. CTA button with transparent background, 2px solid #76b900 border, 2px radius, 11px 13px padding, text #ffffff. Hover: background #1eaedb, text white."
|
||||
- "Design a product card: white background, 2px border-radius, box-shadow rgba(0,0,0,0.3) 0px 0px 5px. Title at 20px NVIDIA-EMEA weight 700, line-height 1.25, color #000000. Body at 15px weight 400, line-height 1.67, color #757575. Green underline accent on title: border-bottom 2px solid #76b900."
|
||||
- "Build a navigation bar: #000000 background, sticky top. NVIDIA logo left-aligned. Links at 14px NVIDIA-EMEA weight 700 uppercase, color #ffffff. Hover: color #3860be. Green-bordered CTA button right-aligned."
|
||||
- "Create a dark feature section: #000000 background. Section label at 14px weight 700 uppercase, color #76b900. Heading at 24px weight 700, color #ffffff. Description at 16px weight 400, color #a7a7a7. Three product cards in a row with 20px gap."
|
||||
- "Design a footer: #000000 background. Multi-column layout with link groups. Links at 14px weight 400, color #a7a7a7. Hover: color #76b900. Bottom bar with legal text at 12px, color #757575."
|
||||
|
||||
### Iteration Guide
|
||||
1. Always use `#76b900` as accent, never as a background fill -- it's a signal color for borders, underlines, and highlights
|
||||
2. Buttons are transparent with green borders by default -- filled backgrounds appear only on hover/active states
|
||||
3. Weight 700 is the dominant voice for all interactive and heading elements; 400 is only for body paragraphs
|
||||
4. Border radius is 2px for everything -- this sharp, minimal rounding is core to the industrial aesthetic
|
||||
5. Dark sections use white text; light sections use black text -- green accent works identically on both
|
||||
6. Link hover is always `#3860be` (blue) regardless of the link's default color
|
||||
7. Line-height 1.25 for headings, 1.50-1.67 for body text -- maintain this contrast for visual hierarchy
|
||||
8. Navigation uses uppercase 14px bold -- this hardware-label typography is part of the brand voice
|
||||
@@ -25,40 +25,40 @@ export const defaultXtermTheme: ITheme = {
|
||||
brightWhite: '#f3fff0'
|
||||
};
|
||||
|
||||
// 默认 UI 主题 (CSS 变量) — Apple Design System Light
|
||||
// 默认 UI 主题 (CSS 变量) — NVIDIA Design System Dark
|
||||
// (与 frontend/src/features/appearance/config/default-themes.ts 保持一致)
|
||||
export const defaultUiTheme: Record<string, string> = {
|
||||
'--app-bg-color': '#f5f5f7', // Apple Light Gray
|
||||
'--text-color': '#1d1d1f', // Near Black
|
||||
'--text-color-secondary': 'rgba(0, 0, 0, 0.8)', // Black 80%
|
||||
'--text-color-tertiary': 'rgba(0, 0, 0, 0.48)', // Black 48%
|
||||
'--border-color': 'rgba(0, 0, 0, 0.08)', // Ultra-subtle border
|
||||
'--link-color': '#0066cc', // Link Blue
|
||||
'--link-hover-color': '#0071e3', // Apple Blue
|
||||
'--link-active-color': '#0071e3', // Apple Blue
|
||||
'--link-active-bg-color': 'rgba(0, 113, 227, 0.08)', // Blue 8%
|
||||
'--app-bg-color': '#000000', // True Black
|
||||
'--text-color': '#ffffff', // White on dark
|
||||
'--text-color-secondary': '#a7a7a7', // Gray 300
|
||||
'--text-color-tertiary': '#757575', // Gray 500
|
||||
'--border-color': '#5e5e5e', // Gray Border
|
||||
'--link-color': '#ffffff', // White links on dark
|
||||
'--link-hover-color': '#3860be', // Blue hover
|
||||
'--link-active-color': '#76b900', // NVIDIA Green
|
||||
'--link-active-bg-color': 'rgba(118, 185, 0, 0.12)',// Green 12%
|
||||
'--nav-item-active-bg-color': 'var(--link-active-bg-color)',
|
||||
'--header-bg-color': '#e8e8ed',
|
||||
'--footer-bg-color': '#f5f5f7',
|
||||
'--card-bg-color': '#ffffff',
|
||||
'--button-bg-color': '#0071e3', // Apple Blue CTA
|
||||
'--button-text-color': '#ffffff',
|
||||
'--button-hover-bg-color': '#0077ed',
|
||||
'--button-secondary-bg-color': '#e8e8ed',
|
||||
'--icon-color': 'rgba(0, 0, 0, 0.48)',
|
||||
'--icon-hover-color': '#0071e3',
|
||||
'--split-line-color': 'rgba(0, 0, 0, 0.08)',
|
||||
'--split-line-hover-color': 'rgba(0, 0, 0, 0.16)',
|
||||
'--input-focus-border-color': '#0071e3',
|
||||
'--input-focus-glow': '#0071e3',
|
||||
'--overlay-bg-color': 'rgba(0, 0, 0, 0.4)',
|
||||
'--color-success': '#30d158',
|
||||
'--color-error': '#ff453a',
|
||||
'--color-warning': '#ff9f0a',
|
||||
'--header-bg-color': '#000000',
|
||||
'--footer-bg-color': '#000000',
|
||||
'--card-bg-color': '#1a1a1a', // Near Black cards
|
||||
'--button-bg-color': '#76b900', // NVIDIA Green CTA
|
||||
'--button-text-color': '#000000', // Black on green
|
||||
'--button-hover-bg-color': '#1eaedb', // Teal hover
|
||||
'--button-secondary-bg-color': '#1a1a1a',
|
||||
'--icon-color': '#757575',
|
||||
'--icon-hover-color': '#76b900',
|
||||
'--split-line-color': '#5e5e5e',
|
||||
'--split-line-hover-color': '#76b900',
|
||||
'--input-focus-border-color': '#76b900',
|
||||
'--input-focus-glow': '#76b900',
|
||||
'--overlay-bg-color': 'rgba(0, 0, 0, 0.85)',
|
||||
'--color-success': '#3f8500',
|
||||
'--color-error': '#e52020',
|
||||
'--color-warning': '#ef9100',
|
||||
'--color-success-text': '#ffffff',
|
||||
'--color-error-text': '#ffffff',
|
||||
'--color-warning-text': '#1d1d1f',
|
||||
'--font-family-sans-serif': "-apple-system, BlinkMacSystemFont, 'SF Pro Display', 'SF Pro Text', 'Helvetica Neue', Helvetica, Arial, sans-serif",
|
||||
'--color-warning-text': '#1a1a1a',
|
||||
'--font-family-sans-serif': "Arial, Helvetica, sans-serif",
|
||||
'--base-padding': '1rem',
|
||||
'--base-margin': '0.5rem',
|
||||
};
|
||||
|
||||
@@ -16,37 +16,80 @@ const editableUiTheme = ref<Record<string, string>>({});
|
||||
const editableUiThemeString = ref('');
|
||||
const themeParseError = ref<string | null>(null);
|
||||
|
||||
// 定义黑暗模式主题变量
|
||||
// NVIDIA Design System — Dark Theme
|
||||
const darkModeTheme = {
|
||||
'--app-bg-color': '#161816',
|
||||
'--text-color': '#d8e6d2',
|
||||
'--text-color-secondary': '#8d9887',
|
||||
'--border-color': '#2b332c',
|
||||
'--link-color': '#37c66a',
|
||||
'--link-hover-color': '#62e38e',
|
||||
'--link-active-color': '#45d978',
|
||||
'--link-active-bg-color': 'rgba(69, 217, 120, 0.14)',
|
||||
'--app-bg-color': '#000000', // True Black
|
||||
'--text-color': '#ffffff', // White on dark
|
||||
'--text-color-secondary': '#a7a7a7', // Gray 300
|
||||
'--text-color-tertiary': '#757575', // Gray 500
|
||||
'--border-color': '#5e5e5e', // Gray Border
|
||||
'--link-color': '#ffffff', // White links on dark
|
||||
'--link-hover-color': '#3860be', // Blue hover
|
||||
'--link-active-color': '#76b900', // NVIDIA Green
|
||||
'--link-active-bg-color': 'rgba(118, 185, 0, 0.12)',// Green 12%
|
||||
'--nav-item-active-bg-color': 'var(--link-active-bg-color)',
|
||||
'--header-bg-color': '#1b1f1b',
|
||||
'--footer-bg-color': '#1b1f1b',
|
||||
'--button-bg-color': '#203126',
|
||||
'--button-text-color': '#9aefad',
|
||||
'--button-hover-bg-color': '#294232',
|
||||
'--icon-color': 'var(--text-color-secondary)',
|
||||
'--icon-hover-color': 'var(--link-hover-color)',
|
||||
'--split-line-color': 'var(--border-color)',
|
||||
'--split-line-hover-color': '#3b6045',
|
||||
'--input-focus-border-color': 'var(--link-active-color)',
|
||||
'--input-focus-glow': 'var(--link-active-color)',
|
||||
'--overlay-bg-color': 'rgba(0, 0, 0, 0.84)',
|
||||
'--color-success': '#3fdc78',
|
||||
'--color-error': '#d86a4d',
|
||||
'--color-warning': '#d1a445',
|
||||
'--font-family-sans-serif': 'sans-serif',
|
||||
'--header-bg-color': '#000000', // True Black
|
||||
'--footer-bg-color': '#000000',
|
||||
'--card-bg-color': '#1a1a1a', // Near Black cards
|
||||
'--button-bg-color': '#76b900', // NVIDIA Green CTA
|
||||
'--button-text-color': '#000000', // Black on green
|
||||
'--button-hover-bg-color': '#1eaedb', // Teal hover
|
||||
'--button-secondary-bg-color': '#1a1a1a', // Near Black secondary
|
||||
'--icon-color': '#757575', // Gray 500
|
||||
'--icon-hover-color': '#76b900', // NVIDIA Green
|
||||
'--split-line-color': '#5e5e5e',
|
||||
'--split-line-hover-color': '#76b900',
|
||||
'--input-focus-border-color': '#76b900', // Green focus ring
|
||||
'--input-focus-glow': '#76b900',
|
||||
'--overlay-bg-color': 'rgba(0, 0, 0, 0.85)',
|
||||
'--color-success': '#3f8500', // NVIDIA Green 500
|
||||
'--color-error': '#e52020', // NVIDIA Red 500
|
||||
'--color-warning': '#ef9100', // NVIDIA Yellow 300
|
||||
'--color-success-text': '#ffffff',
|
||||
'--color-error-text': '#ffffff',
|
||||
'--color-warning-text': '#1a1a1a',
|
||||
'--font-family-sans-serif': "Arial, Helvetica, sans-serif",
|
||||
'--base-padding': '1rem',
|
||||
'--base-margin': '0.5rem'
|
||||
};
|
||||
|
||||
// Apple Design System — Light Theme
|
||||
const lightModeTheme = {
|
||||
'--app-bg-color': '#f5f5f7', // Apple Light Gray
|
||||
'--text-color': '#1d1d1f', // Near Black
|
||||
'--text-color-secondary': 'rgba(0, 0, 0, 0.8)', // Black 80%
|
||||
'--text-color-tertiary': 'rgba(0, 0, 0, 0.48)', // Black 48%
|
||||
'--border-color': 'rgba(0, 0, 0, 0.08)', // Ultra-subtle border
|
||||
'--link-color': '#0066cc', // Link Blue
|
||||
'--link-hover-color': '#0071e3', // Apple Blue
|
||||
'--link-active-color': '#0071e3', // Apple Blue
|
||||
'--link-active-bg-color': 'rgba(0, 113, 227, 0.08)', // Blue 8%
|
||||
'--nav-item-active-bg-color': 'var(--link-active-bg-color)',
|
||||
'--header-bg-color': '#e8e8ed',
|
||||
'--footer-bg-color': '#f5f5f7',
|
||||
'--card-bg-color': '#ffffff',
|
||||
'--button-bg-color': '#0071e3', // Apple Blue CTA
|
||||
'--button-text-color': '#ffffff',
|
||||
'--button-hover-bg-color': '#0077ed',
|
||||
'--button-secondary-bg-color': '#e8e8ed',
|
||||
'--icon-color': 'rgba(0, 0, 0, 0.48)',
|
||||
'--icon-hover-color': '#0071e3',
|
||||
'--split-line-color': 'rgba(0, 0, 0, 0.08)',
|
||||
'--split-line-hover-color': 'rgba(0, 0, 0, 0.16)',
|
||||
'--input-focus-border-color': '#0071e3',
|
||||
'--input-focus-glow': '#0071e3',
|
||||
'--overlay-bg-color': 'rgba(0, 0, 0, 0.4)',
|
||||
'--color-success': '#30d158',
|
||||
'--color-error': '#ff453a',
|
||||
'--color-warning': '#ff9f0a',
|
||||
'--color-success-text': '#ffffff',
|
||||
'--color-error-text': '#ffffff',
|
||||
'--color-warning-text': '#1d1d1f',
|
||||
'--font-family-sans-serif': "-apple-system, BlinkMacSystemFont, 'SF Pro Display', 'SF Pro Text', 'Helvetica Neue', Helvetica, Arial, sans-serif",
|
||||
'--base-padding': '1rem',
|
||||
'--base-margin': '0.5rem',
|
||||
};
|
||||
|
||||
const initializeEditableState = () => {
|
||||
const userThemeJson = appearanceSettings.value.customUiTheme;
|
||||
const userTheme = safeJsonParse(userThemeJson, {});
|
||||
@@ -106,6 +149,17 @@ const applyDarkMode = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
const applyLightMode = async () => {
|
||||
try {
|
||||
editableUiTheme.value = JSON.parse(JSON.stringify(lightModeTheme));
|
||||
await appearanceStore.saveCustomUiTheme(editableUiTheme.value);
|
||||
notificationsStore.addNotification({ type: 'success', message: t('styleCustomizer.lightModeApplied', '白天模式已应用') });
|
||||
} catch (error: any) {
|
||||
console.error("应用白天模式失败:", error);
|
||||
notificationsStore.addNotification({ type: 'error', message: t('styleCustomizer.lightModeApplyFailed', { message: error.message || '未知错误' }) });
|
||||
}
|
||||
};
|
||||
|
||||
const formattedEditableUiThemeJson = computed(() => {
|
||||
try {
|
||||
const themeObject = editableUiTheme.value;
|
||||
@@ -217,7 +271,7 @@ defineExpose({
|
||||
<label class="text-left text-foreground text-sm font-medium mb-1 md:mb-0">{{ t('styleCustomizer.themeModeLabel', '主题模式:') }}</label>
|
||||
<div class="flex gap-2 justify-start flex-wrap">
|
||||
<button @click="handleResetUiTheme" class="px-3 py-1.5 text-sm border border-border rounded bg-header hover:bg-border transition duration-200 ease-in-out whitespace-nowrap">{{ t('styleCustomizer.defaultMode', '默认模式') }}</button>
|
||||
<button @click="applyDarkMode" class="px-3 py-1.5 text-sm border border-border rounded bg-header hover:bg-border transition duration-200 ease-in-out whitespace-nowrap">{{ t('styleCustomizer.darkMode', '黑暗模式') }}</button>
|
||||
<button @click="applyLightMode" class="px-3 py-1.5 text-sm border border-border rounded bg-header hover:bg-border transition duration-200 ease-in-out whitespace-nowrap">{{ t('styleCustomizer.lightMode', '白天模式') }}</button>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-text-secondary text-sm leading-relaxed mb-3">{{ t('styleCustomizer.uiDescription') }}</p>
|
||||
|
||||
@@ -25,40 +25,40 @@ export const defaultXtermTheme: ITheme = {
|
||||
brightWhite: '#f3fff0'
|
||||
};
|
||||
|
||||
// 默认 UI 主题 (CSS 变量) — Apple Design System Light
|
||||
// 默认 UI 主题 (CSS 变量) — NVIDIA Design System Dark
|
||||
// (与 backend/src/config/default-themes.ts 中的定义保持一致)
|
||||
export const defaultUiTheme: Record<string, string> = {
|
||||
'--app-bg-color': '#f5f5f7', // Apple Light Gray
|
||||
'--text-color': '#1d1d1f', // Near Black
|
||||
'--text-color-secondary': 'rgba(0, 0, 0, 0.8)', // Black 80%
|
||||
'--text-color-tertiary': 'rgba(0, 0, 0, 0.48)', // Black 48%
|
||||
'--border-color': 'rgba(0, 0, 0, 0.08)', // Ultra-subtle border
|
||||
'--link-color': '#0066cc', // Link Blue
|
||||
'--link-hover-color': '#0071e3', // Apple Blue
|
||||
'--link-active-color': '#0071e3', // Apple Blue
|
||||
'--link-active-bg-color': 'rgba(0, 113, 227, 0.08)', // Blue 8%
|
||||
'--app-bg-color': '#000000', // True Black
|
||||
'--text-color': '#ffffff', // White on dark
|
||||
'--text-color-secondary': '#a7a7a7', // Gray 300
|
||||
'--text-color-tertiary': '#757575', // Gray 500
|
||||
'--border-color': '#5e5e5e', // Gray Border
|
||||
'--link-color': '#ffffff', // White links on dark
|
||||
'--link-hover-color': '#3860be', // Blue hover
|
||||
'--link-active-color': '#76b900', // NVIDIA Green
|
||||
'--link-active-bg-color': 'rgba(118, 185, 0, 0.12)',// Green 12%
|
||||
'--nav-item-active-bg-color': 'var(--link-active-bg-color)',
|
||||
'--header-bg-color': '#e8e8ed',
|
||||
'--footer-bg-color': '#f5f5f7',
|
||||
'--card-bg-color': '#ffffff',
|
||||
'--button-bg-color': '#0071e3', // Apple Blue CTA
|
||||
'--button-text-color': '#ffffff',
|
||||
'--button-hover-bg-color': '#0077ed',
|
||||
'--button-secondary-bg-color': '#e8e8ed',
|
||||
'--icon-color': 'rgba(0, 0, 0, 0.48)',
|
||||
'--icon-hover-color': '#0071e3',
|
||||
'--split-line-color': 'rgba(0, 0, 0, 0.08)',
|
||||
'--split-line-hover-color': 'rgba(0, 0, 0, 0.16)',
|
||||
'--input-focus-border-color': '#0071e3',
|
||||
'--input-focus-glow': '#0071e3',
|
||||
'--overlay-bg-color': 'rgba(0, 0, 0, 0.4)',
|
||||
'--color-success': '#30d158',
|
||||
'--color-error': '#ff453a',
|
||||
'--color-warning': '#ff9f0a',
|
||||
'--header-bg-color': '#000000',
|
||||
'--footer-bg-color': '#000000',
|
||||
'--card-bg-color': '#1a1a1a', // Near Black cards
|
||||
'--button-bg-color': '#76b900', // NVIDIA Green CTA
|
||||
'--button-text-color': '#000000', // Black on green
|
||||
'--button-hover-bg-color': '#1eaedb', // Teal hover
|
||||
'--button-secondary-bg-color': '#1a1a1a',
|
||||
'--icon-color': '#757575',
|
||||
'--icon-hover-color': '#76b900',
|
||||
'--split-line-color': '#5e5e5e',
|
||||
'--split-line-hover-color': '#76b900',
|
||||
'--input-focus-border-color': '#76b900',
|
||||
'--input-focus-glow': '#76b900',
|
||||
'--overlay-bg-color': 'rgba(0, 0, 0, 0.85)',
|
||||
'--color-success': '#3f8500',
|
||||
'--color-error': '#e52020',
|
||||
'--color-warning': '#ef9100',
|
||||
'--color-success-text': '#ffffff',
|
||||
'--color-error-text': '#ffffff',
|
||||
'--color-warning-text': '#1d1d1f',
|
||||
'--font-family-sans-serif': "-apple-system, BlinkMacSystemFont, 'SF Pro Display', 'SF Pro Text', 'Helvetica Neue', Helvetica, Arial, sans-serif",
|
||||
'--color-warning-text': '#1a1a1a',
|
||||
'--font-family-sans-serif': "Arial, Helvetica, sans-serif",
|
||||
'--base-padding': '1rem',
|
||||
'--base-margin': '0.5rem',
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
@import "tailwindcss";
|
||||
|
||||
/* Tailwind Theme Variables Mapping — Apple Design System */
|
||||
/* Tailwind Theme Variables Mapping — NVIDIA Design System */
|
||||
@theme inline {
|
||||
/* Base Colors */
|
||||
--color-background: var(--app-bg-color);
|
||||
@@ -46,53 +46,53 @@
|
||||
--radius-large: 12px;
|
||||
--radius-pill: 980px;
|
||||
|
||||
/* Shadow (Apple) */
|
||||
--shadow-card: rgba(0, 0, 0, 0.22) 3px 5px 30px 0px;
|
||||
--shadow-subtle: rgba(0, 0, 0, 0.04) 0px 1px 3px 0px;
|
||||
/* Shadow (NVIDIA) */
|
||||
--shadow-card: rgba(0, 0, 0, 0.3) 0px 0px 5px 0px;
|
||||
--shadow-subtle: rgba(0, 0, 0, 0.2) 0px 1px 3px 0px;
|
||||
}
|
||||
|
||||
/* ─────────────────────────────────────────────
|
||||
Apple Design System — Light Theme Variables
|
||||
NVIDIA Design System — Dark Theme (Default)
|
||||
───────────────────────────────────────────── */
|
||||
:root {
|
||||
/* Base Colors (Apple Light) */
|
||||
--app-bg-color: #f5f5f7; /* Apple Light Gray — main canvas */
|
||||
--text-color: #1d1d1f; /* Near Black — primary text */
|
||||
--text-color-secondary: rgba(0, 0, 0, 0.8); /* Black 80% — secondary text */
|
||||
--text-color-tertiary: rgba(0, 0, 0, 0.48); /* Black 48% — tertiary, disabled */
|
||||
--border-color: rgba(0, 0, 0, 0.08); /* Ultra-subtle border */
|
||||
--link-color: #0066cc; /* Link Blue on light bg */
|
||||
--link-hover-color: #0071e3; /* Apple Blue — hover */
|
||||
--link-active-color: #0071e3; /* Apple Blue — primary accent */
|
||||
--link-active-bg-color: rgba(0, 113, 227, 0.08); /* Blue 8% — active bg */
|
||||
/* Base Colors (NVIDIA Dark) */
|
||||
--app-bg-color: #000000; /* True Black */
|
||||
--text-color: #ffffff; /* White on dark */
|
||||
--text-color-secondary: #a7a7a7; /* Gray 300 */
|
||||
--text-color-tertiary: #757575; /* Gray 500 */
|
||||
--border-color: #5e5e5e; /* Gray Border */
|
||||
--link-color: #ffffff; /* White links on dark */
|
||||
--link-hover-color: #3860be; /* Blue hover */
|
||||
--link-active-color: #76b900; /* NVIDIA Green */
|
||||
--link-active-bg-color: rgba(118, 185, 0, 0.12); /* Green 12% */
|
||||
--nav-item-active-bg-color: var(--link-active-bg-color);
|
||||
|
||||
/* Component Colors (Apple Light) */
|
||||
--header-bg-color: #e8e8ed; /* Slightly darker than canvas */
|
||||
--footer-bg-color: #f5f5f7;
|
||||
--card-bg-color: #ffffff; /* White cards on gray canvas */
|
||||
--button-bg-color: #0071e3; /* Apple Blue CTA */
|
||||
--button-text-color: #ffffff;
|
||||
--button-hover-bg-color: #0077ed; /* Brighter Blue on hover */
|
||||
--button-secondary-bg-color: #e8e8ed; /* Light secondary button */
|
||||
--icon-color: rgba(0, 0, 0, 0.48); /* Tertiary icons */
|
||||
--icon-hover-color: #0071e3; /* Apple Blue on hover */
|
||||
--split-line-color: rgba(0, 0, 0, 0.08);
|
||||
--split-line-hover-color: rgba(0, 0, 0, 0.16);
|
||||
--input-focus-border-color: #0071e3; /* Apple Blue focus ring */
|
||||
--input-focus-glow: #0071e3;
|
||||
--overlay-bg-color: rgba(0, 0, 0, 0.4); /* Lighter overlay for light theme */
|
||||
/* Component Colors (NVIDIA Dark) */
|
||||
--header-bg-color: #000000;
|
||||
--footer-bg-color: #000000;
|
||||
--card-bg-color: #1a1a1a; /* Near Black cards */
|
||||
--button-bg-color: #76b900; /* NVIDIA Green CTA */
|
||||
--button-text-color: #000000; /* Black on green */
|
||||
--button-hover-bg-color: #1eaedb; /* Teal hover */
|
||||
--button-secondary-bg-color: #1a1a1a;
|
||||
--icon-color: #757575; /* Gray 500 */
|
||||
--icon-hover-color: #76b900; /* NVIDIA Green */
|
||||
--split-line-color: #5e5e5e;
|
||||
--split-line-hover-color: #76b900;
|
||||
--input-focus-border-color: #76b900; /* Green focus ring */
|
||||
--input-focus-glow: #76b900;
|
||||
--overlay-bg-color: rgba(0, 0, 0, 0.85);
|
||||
|
||||
/* Status Colors (Apple-inspired) */
|
||||
--color-success: #30d158; /* Apple Green */
|
||||
--color-warning: #ff9f0a; /* Apple Orange */
|
||||
--color-error: #ff453a; /* Apple Red */
|
||||
/* Status Colors (NVIDIA) */
|
||||
--color-success: #3f8500;
|
||||
--color-warning: #ef9100;
|
||||
--color-error: #e52020;
|
||||
--color-success-text: #ffffff;
|
||||
--color-warning-text: #1d1d1f;
|
||||
--color-warning-text: #1a1a1a;
|
||||
--color-error-text: #ffffff;
|
||||
|
||||
/* Typography (Apple SF Pro System Stack) */
|
||||
--font-family-sans-serif: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'SF Pro Text', 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
/* Typography */
|
||||
--font-family-sans-serif: Arial, Helvetica, sans-serif;
|
||||
|
||||
/* Spacing */
|
||||
--base-padding: 1rem;
|
||||
@@ -105,8 +105,7 @@ body {
|
||||
font-family: var(--font-family-sans-serif);
|
||||
background-color: var(--app-bg-color);
|
||||
color: var(--text-color);
|
||||
line-height: 1.47; /* Apple body line-height */
|
||||
letter-spacing: -0.022em; /* Apple body tracking */
|
||||
line-height: 1.5;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
@@ -187,31 +186,31 @@ hr {
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
/* Style scrollbars — Apple minimal */
|
||||
/* Style scrollbars — dark theme */
|
||||
::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
background: #1a1a1a;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background-color: rgba(0, 0, 0, 0.15);
|
||||
background-color: #5e5e5e;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background-color: rgba(0, 0, 0, 0.3);
|
||||
background-color: #76b900;
|
||||
}
|
||||
|
||||
/* Input focus styles — Apple Blue ring */
|
||||
/* Input focus styles — NVIDIA Green ring */
|
||||
input:focus, textarea:focus, select:focus {
|
||||
border-color: var(--input-focus-border-color) !important;
|
||||
outline: 0;
|
||||
box-shadow: 0 0 0 3px rgba(0, 113, 227, 0.2) !important;
|
||||
box-shadow: 0 0 0 2px rgba(118, 185, 0, 0.25) !important;
|
||||
}
|
||||
|
||||
/* Ensure icons inside primary buttons are white */
|
||||
|
||||
@@ -1,35 +1,41 @@
|
||||
import { defineConfig } from 'vite';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { dirname } from 'node:path';
|
||||
import { defineConfig, loadEnv } from 'vite';
|
||||
import vue from '@vitejs/plugin-vue';
|
||||
import monacoEditorPlugin from 'vite-plugin-monaco-editor';
|
||||
import tailwindcss from '@tailwindcss/vite'
|
||||
|
||||
const frontendRoot = dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
vue(),
|
||||
tailwindcss(),
|
||||
// @ts-ignore because the plugin type might not perfectly match Vite's expected PluginOption type
|
||||
(monacoEditorPlugin as any).default({})
|
||||
],
|
||||
server: {
|
||||
proxy: {
|
||||
// 将所有 /api 开头的请求代理到后端服务器
|
||||
'/api': {
|
||||
target: 'http://localhost:3001', // 后端服务器地址
|
||||
changeOrigin: true, // 需要虚拟主机站点
|
||||
// 可选:如果后端 API 路径没有 /api 前缀,可以在这里重写路径
|
||||
// rewrite: (path) => path.replace(/^\/api/, '')
|
||||
},
|
||||
// 将所有 /uploads 开头的请求也代理到后端服务器
|
||||
'/uploads': {
|
||||
target: 'http://localhost:3001', // 后端服务器地址
|
||||
changeOrigin: true, // 对于静态资源通常也建议开启
|
||||
// 通常不需要重写静态资源的路径
|
||||
},
|
||||
'/ws': {
|
||||
target: 'ws://localhost:3001', // 后端 WebSocket 服务器地址
|
||||
ws: true,
|
||||
changeOrigin: true,
|
||||
export default defineConfig(({ mode }) => {
|
||||
const env = loadEnv(mode, frontendRoot, '');
|
||||
const proxyTarget = env.VITE_DEV_PROXY_TARGET || 'http://localhost:3001';
|
||||
const wsProxyTarget = env.VITE_DEV_WS_PROXY_TARGET || 'ws://localhost:3001';
|
||||
|
||||
return {
|
||||
plugins: [
|
||||
vue(),
|
||||
tailwindcss(),
|
||||
// @ts-ignore because the plugin type might not perfectly match Vite's expected PluginOption type
|
||||
(monacoEditorPlugin as any).default({})
|
||||
],
|
||||
server: {
|
||||
proxy: {
|
||||
'/api': {
|
||||
target: proxyTarget,
|
||||
changeOrigin: true,
|
||||
},
|
||||
'/uploads': {
|
||||
target: proxyTarget,
|
||||
changeOrigin: true,
|
||||
},
|
||||
'/ws': {
|
||||
target: wsProxyTarget,
|
||||
ws: true,
|
||||
changeOrigin: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user