Commit 811086b9 authored by Andy-bubu's avatar Andy-bubu

feat: refine xinyuan brand and chart colors

parent a878b481
# XinYuan Design System
Updated: 2026-08-26
Updated: 2026-09-02
## Authority
The project follows the approved Xinyuan HeroUI design system. The immutable
theme authority is `src/design-system/theme.css`; it must remain byte-identical
to the skill baseline. Project extensions belong in `tokens.css` and may add
`--rc-*` aliases without redefining HeroUI core variables.
The project follows the approved Xinyuan HeroUI design system. The theme
authority is `src/design-system/theme.css`; its current approved brand profile
uses `#DA241A` for HeroUI primary/focus and the shared restrained chart palette.
Project extensions belong in `tokens.css` and may add `--rc-*` aliases without
redefining unrelated HeroUI core variables.
Global CSS order:
......@@ -26,7 +27,16 @@ paths are not valid delivery mechanisms.
## Identity And Theme
- Primary brand: `#9E1B1B` through the authoritative `--accent` token.
- Primary brand: `#DA241A` through HeroUI's `--accent` token. HeroUI v3 uses
`--accent` as the primary Button/active/focus source; legacy numbered
`primary-50` through `primary-950` tokens are intentionally not introduced.
- Hover and pressed primary states remain HeroUI-derived shades of `#DA241A`;
they never switch to a framework blue or purple.
- Charts use the shared 16-token Xinyuan palette (`--xinyuan-chart-1` through
`--xinyuan-chart-16`) and the `--rc-chart-*` aliases. The sequence is a
restrained brand-red, warm-neutral and slate-blue family with no green or
fluorescent colors. A single series always resolves to `#DA241A` and small
series sets use the first four brand-red steps.
- Light identity: `xy-logo-red.png`.
- Dark identity: `xy-logo-white.png`.
- Root theme: the application shell is explicitly `.light`; the content canvas stays light while the Sidebar consumes the fixed dark split-shell tokens.
......
# XinYuan UI Audit
Updated: 2026-08-26
Updated: 2026-09-02
## Repository Baseline
......@@ -90,8 +90,17 @@ switcher grouping gap without changing its application source or navigation.
- `src/design-system/theme.css` retains the Xinyuan HeroUI tokens and now includes
the fixed dark Sidebar and ECharts chart tokens used by the approved baseline.
- `tokens.css`, `shell.css` and the login contract in `tailwind.css` are exact
copies of the approved `problem_rectification` shared baseline.
- HeroUI `--accent` and `--focus` are fixed to the Xinyuan Fund brand color
`#DA241A` in both theme blocks, so primary Buttons and focus states do not
inherit the default HeroUI blue. HeroUI v3 has no numbered primary scale;
`--accent` is the supported primary source.
- ECharts uses 16 `--xinyuan-chart-*` tokens in a restrained red, warm-neutral
and slate-blue sequence. Green, fluorescent and rainbow series colors were
removed; `tokens.css` only aliases `--rc-chart-*` to the authoritative chart
tokens. KPI icon tones use the same non-green family.
- `tokens.css`, `shell.css` and the login contract in `tailwind.css` retain the
approved shared baseline structure; the local brand profile overrides only
the primary/focus and chart/KPI color Tokens described above.
- Inter weights and the stable red/white Xinyuan assets are loaded globally.
- Official `@heroui-pro/react/css` loads before the Xinyuan theme and
extension Tokens. The temporary Pro CSS compatibility snapshot was removed.
......
......@@ -7,8 +7,18 @@ export const XINYUAN_CHART_PALETTE = Object.freeze([
"var(--rc-chart-6)",
"var(--rc-chart-7)",
"var(--rc-chart-8)",
"var(--rc-chart-9)",
"var(--rc-chart-10)",
"var(--rc-chart-11)",
"var(--rc-chart-12)",
"var(--rc-chart-13)",
"var(--rc-chart-14)",
"var(--rc-chart-15)",
"var(--rc-chart-16)",
]);
const SMALL_SERIES_PALETTE_INDEXES = Object.freeze([0, 1, 2, 3]);
export const XINYUAN_CHART_SEMANTIC = Object.freeze({
primary: "var(--rc-chart-primary)",
risk: "var(--rc-chart-risk)",
......@@ -41,14 +51,19 @@ export function createXinyuanChartColorMap(keys = []) {
const stableKeys = [...new Set(keys.map(normalizeChartKey).filter(Boolean))].sort();
const colorMap = new Map();
const usedIndexes = new Set();
const paletteIndexes = stableKeys.length === 1
? [0]
: stableKeys.length <= SMALL_SERIES_PALETTE_INDEXES.length
? SMALL_SERIES_PALETTE_INDEXES
: XINYUAN_CHART_PALETTE.map((_, index) => index);
stableKeys.forEach((key, keyIndex) => {
const preferredIndex = hashChartKey(key) % XINYUAN_CHART_PALETTE.length;
let paletteIndex = preferredIndex;
const preferredIndex = hashChartKey(key) % paletteIndexes.length;
let paletteIndex = paletteIndexes[preferredIndex];
if (keyIndex < XINYUAN_CHART_PALETTE.length) {
for (let offset = 0; offset < XINYUAN_CHART_PALETTE.length; offset += 1) {
const candidateIndex = (preferredIndex + offset) % XINYUAN_CHART_PALETTE.length;
if (keyIndex < paletteIndexes.length) {
for (let offset = 0; offset < paletteIndexes.length; offset += 1) {
const candidateIndex = paletteIndexes[(preferredIndex + offset) % paletteIndexes.length];
if (!usedIndexes.has(candidateIndex)) {
paletteIndex = candidateIndex;
usedIndexes.add(candidateIndex);
......
......@@ -11,7 +11,7 @@
[data-theme="light"],
[data-theme="default"] {
/* Theme Colors (Light Mode) */
--accent: oklch(57.14% 0.2156 29.20);
--accent: #DA241A;
--accent-foreground: oklch(99.11% 0 0);
--background: oklch(97.02% 0.0000 29.20);
--border: oklch(90.00% 0.0000 29.20);
......@@ -23,7 +23,7 @@
--field-border: transparent;
--field-foreground: oklch(21.03% 0.0000 29.20);
--field-placeholder: oklch(55.17% 0.0000 29.20);
--focus: oklch(57.14% 0.2156 29.20);
--focus: #DA241A;
--foreground: oklch(21.03% 0.0000 29.20);
--muted: oklch(55.17% 0.0000 29.20);
--overlay: oklch(100.00% 0.0000 29.20);
......@@ -70,22 +70,22 @@
* Ant Design remains the icon source. Resolve these CSS variables to
* concrete colors before assigning them to an ECharts option object.
*/
--xinyuan-chart-1: #d92d20;
--xinyuan-chart-2: #ef4444;
--xinyuan-chart-3: #f97316;
--xinyuan-chart-4: #f59e0b;
--xinyuan-chart-5: #22c55e;
--xinyuan-chart-6: #14b87a;
--xinyuan-chart-7: #06b6d4;
--xinyuan-chart-8: #0ea5e9;
--xinyuan-chart-9: #3b82f6;
--xinyuan-chart-10: #6366f1;
--xinyuan-chart-11: #8b5cf6;
--xinyuan-chart-12: #7c3aed;
--xinyuan-chart-13: #b42318;
--xinyuan-chart-14: #84cc16;
--xinyuan-chart-15: #a855f7;
--xinyuan-chart-16: #64748b;
--xinyuan-chart-1: #DA241A;
--xinyuan-chart-2: #B83A32;
--xinyuan-chart-3: #C95A52;
--xinyuan-chart-4: #D47A70;
--xinyuan-chart-5: #A65A45;
--xinyuan-chart-6: #B87958;
--xinyuan-chart-7: #C99772;
--xinyuan-chart-8: #6F6674;
--xinyuan-chart-9: #807783;
--xinyuan-chart-10: #938B96;
--xinyuan-chart-11: #4F6380;
--xinyuan-chart-12: #61758F;
--xinyuan-chart-13: #74879A;
--xinyuan-chart-14: #8A6F63;
--xinyuan-chart-15: #9A8174;
--xinyuan-chart-16: #B5A6A1;
--xinyuan-chart-grid: #e8e8e8;
--xinyuan-chart-axis: #737373;
--xinyuan-chart-label: #737373;
......@@ -101,7 +101,7 @@
[data-theme="dark"] {
color-scheme: dark;
/* Theme Colors (Dark Mode) */
--accent: oklch(57.14% 0.2156 29.20);
--accent: #DA241A;
--accent-foreground: oklch(99.11% 0 0);
--background: oklch(12.00% 0.0000 29.20);
--border: oklch(28.00% 0.0000 29.20);
......@@ -113,7 +113,7 @@
--field-border: transparent;
--field-foreground: oklch(99.11% 0.0000 29.20);
--field-placeholder: oklch(70.50% 0.0000 29.20);
--focus: oklch(57.14% 0.2156 29.20);
--focus: #DA241A;
--foreground: oklch(99.11% 0.0000 29.20);
--muted: oklch(70.50% 0.0000 29.20);
--overlay: oklch(21.03% 0.0000 29.20);
......
......@@ -91,14 +91,15 @@
0 4px 12px rgb(15 23 42 / 2%);
/* KPI icon surfaces. Card bodies remain neutral; only the icon well carries tone. */
--rc-metric-tone-info: oklch(55% 0.14 255);
--rc-metric-tone-success: oklch(54% 0.13 145);
--rc-metric-tone-teal: oklch(55% 0.1 205);
--rc-metric-tone-danger: oklch(52% 0.17 25);
--rc-metric-tone-warning: oklch(62% 0.12 75);
--rc-metric-tone-violet: oklch(56% 0.12 300);
--rc-metric-tone-indigo: oklch(53% 0.13 275);
--rc-metric-tone-coral: oklch(60% 0.12 48);
/* KPI icon tones use the restrained chart palette; no green is used for data emphasis. */
--rc-metric-tone-info: var(--xinyuan-chart-11);
--rc-metric-tone-success: var(--xinyuan-chart-2);
--rc-metric-tone-teal: var(--xinyuan-chart-13);
--rc-metric-tone-danger: var(--xinyuan-chart-1);
--rc-metric-tone-warning: var(--xinyuan-chart-6);
--rc-metric-tone-violet: var(--xinyuan-chart-8);
--rc-metric-tone-indigo: var(--xinyuan-chart-12);
--rc-metric-tone-coral: var(--xinyuan-chart-3);
--rc-metric-tone-neutral: var(--muted);
--rc-metric-tone-info-soft: color-mix(
in oklab,
......@@ -147,14 +148,15 @@
);
/* Data visualization only. Do not reuse UI status colors as a series palette. */
--rc-chart-1: oklch(45.32% 0.1661 27.03);
--rc-chart-2: oklch(56% 0.135 255);
--rc-chart-3: oklch(64% 0.11 220);
--rc-chart-4: oklch(56% 0.115 280);
--rc-chart-5: oklch(60% 0.095 200);
--rc-chart-6: oklch(70% 0.12 80);
--rc-chart-7: oklch(60% 0.1 295);
--rc-chart-8: oklch(57% 0.035 250);
/* Chart aliases point to the authoritative 16-color Xinyuan palette. */
--rc-chart-1: var(--xinyuan-chart-1);
--rc-chart-2: var(--xinyuan-chart-2);
--rc-chart-3: var(--xinyuan-chart-3);
--rc-chart-4: var(--xinyuan-chart-4);
--rc-chart-5: var(--xinyuan-chart-5);
--rc-chart-6: var(--xinyuan-chart-6);
--rc-chart-7: var(--xinyuan-chart-7);
--rc-chart-8: var(--xinyuan-chart-8);
--rc-chart-9: var(--xinyuan-chart-9);
--rc-chart-10: var(--xinyuan-chart-10);
--rc-chart-11: var(--xinyuan-chart-11);
......@@ -164,7 +166,7 @@
--rc-chart-15: var(--xinyuan-chart-15);
--rc-chart-16: var(--xinyuan-chart-16);
--rc-chart-primary: var(--rc-chart-1);
--rc-chart-risk: oklch(47% 0.145 27.03);
--rc-chart-risk: var(--xinyuan-chart-2);
--rc-chart-warning: var(--rc-chart-6);
--rc-chart-positive: var(--rc-chart-2);
--rc-chart-comparison: var(--rc-chart-4);
......
:root {
--pm-brand: var(--rc-brand-primary, #9e1b1b);
--pm-brand-strong: var(--rc-brand-dark, #7e1515);
--pm-brand: var(--rc-brand-primary, #DA241A);
--pm-brand-strong: var(--rc-brand-dark, #B51B14);
}
html,
......
......@@ -50,8 +50,8 @@ body .login-page {
--rc-login-field-filled-background: #fbf1f1;
--rc-login-field-filled-background-hover: #faeaea;
--rc-login-field-autofill-background: #fbf1f1;
--rc-login-field-border-hover: rgb(158 27 27 / 24%);
--rc-login-field-focus-ring: rgb(158 27 27 / 16%);
--rc-login-field-border-hover: rgb(218 36 26 / 24%);
--rc-login-field-focus-ring: rgb(218 36 26 / 16%);
}
body .login-brand img {
......
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