From 586c66a159a9a4e30ae414070ffa83f06d9209ed Mon Sep 17 00:00:00 2001 From: Ku6epXBOCTuK Date: Mon, 31 Aug 2026 08:31:33 +0500 Subject: [PATCH] fix: update style, resolve old css leaks issue --- web/src/app.css | 488 +++++++++++---------- web/src/lib/components/kit/ToolCard.svelte | 6 +- web/src/lib/components/kit/TopBar.svelte | 3 +- web/src/lib/styles/design2.css | 172 +++++--- web/src/routes/+layout.svelte | 9 + web/src/routes/preview/kit/+page.svelte | 42 +- 6 files changed, 381 insertions(+), 339 deletions(-) diff --git a/web/src/app.css b/web/src/app.css index 5bb615e..f78f9cc 100644 --- a/web/src/app.css +++ b/web/src/app.css @@ -1,281 +1,283 @@ -:root { - color-scheme: light; +@layer app { + :root { + color-scheme: light; - --bg: #f6f7f9; - --surface: #ffffff; - --text: #1b1e24; - --text-muted: #5c6470; - --accent: #2563eb; - --accent-hover: #1d4ed8; - --accent-contrast: #ffffff; - --link: var(--accent); - --border: #dfe2e8; - --danger: #e5484d; - --danger-strong: #b3261e; - --check-a: #eceff3; - --check-b: #ffffff; + --bg: #f6f7f9; + --surface: #ffffff; + --text: #1b1e24; + --text-muted: #5c6470; + --accent: #2563eb; + --accent-hover: #1d4ed8; + --accent-contrast: #ffffff; + --link: var(--accent); + --border: #dfe2e8; + --danger: #e5484d; + --danger-strong: #b3261e; + --check-a: #eceff3; + --check-b: #ffffff; - --space-1: 0.25rem; - --space-2: 0.5rem; - --space-3: 1rem; - --space-4: 1.5rem; - --space-5: 2.5rem; + --space-1: 0.25rem; + --space-2: 0.5rem; + --space-3: 1rem; + --space-4: 1.5rem; + --space-5: 2.5rem; - --radius-s: 6px; - --radius-m: 10px; + --radius-s: 6px; + --radius-m: 10px; - --text-xs: 0.8rem; - --text-s: 0.85rem; - --text-m: 0.95rem; - --text-l: 1.1rem; - --text-xl: 1.25rem; - --text-xxl: 1.75rem; - --leading-tight: 1.25; + --text-xs: 0.8rem; + --text-s: 0.85rem; + --text-m: 0.95rem; + --text-l: 1.1rem; + --text-xl: 1.25rem; + --text-xxl: 1.75rem; + --leading-tight: 1.25; - --shadow-card: 0 4px 14px rgb(37 99 235 / 12%); - --transition-fast: 120ms ease; + --shadow-card: 0 4px 14px rgb(37 99 235 / 12%); + --transition-fast: 120ms ease; - --control-height: 2.4rem; - --control-max-width: 16rem; + --control-height: 2.4rem; + --control-max-width: 16rem; - --font-sans: - system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, - sans-serif; - --font-mono: ui-monospace, "Cascadia Code", Consolas, monospace; -} + --font-sans: + system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, + sans-serif; + --font-mono: ui-monospace, "Cascadia Code", Consolas, monospace; + } -[data-theme="dark"] { - color-scheme: dark; + [data-theme="dark"] { + color-scheme: dark; - --bg: #12151a; - --surface: #1b2027; - --text: #e6e9ee; - --text-muted: #98a1ad; - --accent-hover: #4c85f0; - --link: #6ea0ff; - --border: #303842; - --danger: #ff7479; - --danger-strong: #ff8589; - --check-a: #232830; - --check-b: #171b21; + --bg: #12151a; + --surface: #1b2027; + --text: #e6e9ee; + --text-muted: #98a1ad; + --accent-hover: #4c85f0; + --link: #6ea0ff; + --border: #303842; + --danger: #ff7479; + --danger-strong: #ff8589; + --check-a: #232830; + --check-b: #171b21; - --shadow-card: 0 4px 14px rgb(0 0 0 / 45%); -} + --shadow-card: 0 4px 14px rgb(0 0 0 / 45%); + } -*, -*::before, -*::after { - box-sizing: border-box; -} + *, + *::before, + *::after { + box-sizing: border-box; + } -* { - margin: 0; -} + * { + margin: 0; + } -html { - font-family: var(--font-sans); - color: var(--text); - background: var(--bg); - line-height: 1.55; - -webkit-text-size-adjust: 100%; -} + html { + font-family: var(--font-sans); + color: var(--text); + background: var(--bg); + line-height: 1.55; + -webkit-text-size-adjust: 100%; + } -body { - min-height: 100dvh; -} + body { + min-height: 100dvh; + } -h1 { - font-size: var(--text-xxl); - line-height: var(--leading-tight); - letter-spacing: -0.01em; -} + h1 { + font-size: var(--text-xxl); + line-height: var(--leading-tight); + letter-spacing: -0.01em; + } -h2 { - font-size: var(--text-xl); - line-height: var(--leading-tight); -} + h2 { + font-size: var(--text-xl); + line-height: var(--leading-tight); + } -p, -label { - font-size: var(--text-m); -} + p, + label { + font-size: var(--text-m); + } -a { - color: var(--link); - text-decoration: none; -} + a { + color: var(--link); + text-decoration: none; + } -a:hover { - text-decoration: underline; -} + a:hover { + text-decoration: underline; + } -button, -input, -select { - font: inherit; - color: inherit; -} + button, + input, + select { + font: inherit; + color: inherit; + } -:focus-visible { - outline: 2px solid var(--accent); - outline-offset: 2px; - border-radius: var(--radius-s); -} + :focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; + border-radius: var(--radius-s); + } -.text-muted { - color: var(--text-muted); -} + .text-muted { + color: var(--text-muted); + } -.text-caption { - font-size: var(--text-s); -} + .text-caption { + font-size: var(--text-s); + } -.heading-section { - font-size: var(--text-l); - color: var(--text-muted); - text-transform: uppercase; - letter-spacing: 0.04em; -} + .heading-section { + font-size: var(--text-l); + color: var(--text-muted); + text-transform: uppercase; + letter-spacing: 0.04em; + } -.panel { - background: var(--surface); - border: 1px solid var(--border); - border-radius: var(--radius-m); -} + .panel { + background: var(--surface); + border: 1px solid var(--border); + border-radius: var(--radius-m); + } -.control { - padding: var(--space-1) var(--space-2); - border: 1px solid var(--border); - border-radius: var(--radius-s); - background: var(--surface); - max-width: var(--control-max-width); -} + .control { + padding: var(--space-1) var(--space-2); + border: 1px solid var(--border); + border-radius: var(--radius-s); + background: var(--surface); + max-width: var(--control-max-width); + } -input.control[type="number"] { - font-family: var(--font-mono); - width: 100%; -} + input.control[type="number"] { + font-family: var(--font-mono); + width: 100%; + } -.error-banner { - padding: var(--space-2) var(--space-3); - border: 1px solid var(--danger); - border-radius: var(--radius-s); - background: color-mix(in srgb, var(--danger) 8%, var(--surface)); - color: var(--danger-strong); - font-size: var(--text-s); -} + .error-banner { + padding: var(--space-2) var(--space-3); + border: 1px solid var(--danger); + border-radius: var(--radius-s); + background: color-mix(in srgb, var(--danger) 8%, var(--surface)); + color: var(--danger-strong); + font-size: var(--text-s); + } -.visually-hidden { - position: absolute; - width: 1px; - height: 1px; - margin: -1px; - padding: 0; - overflow: hidden; - clip: rect(0 0 0 0); - white-space: nowrap; - border: 0; -} + .visually-hidden { + position: absolute; + width: 1px; + height: 1px; + margin: -1px; + padding: 0; + overflow: hidden; + clip: rect(0 0 0 0); + white-space: nowrap; + border: 0; + } -.tool-stage { - display: grid; - grid-template-columns: repeat(2, minmax(0, 1fr)); - gap: var(--space-4); - padding: var(--space-4); - align-items: start; - width: 100%; -} - -.tool-stage.single { - grid-template-columns: 1fr; -} - -.tool-stage .cell { - min-width: 0; - display: flex; - flex-direction: column; - gap: var(--space-2); -} - -.tool-stage .cell + .cell { - border-left: 1px solid var(--border); - padding-left: var(--space-4); -} - -.cell-media { - flex: 1; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - min-height: 14rem; - position: relative; - width: 100%; -} - -.chain-stack { - display: flex; - flex-direction: column; - gap: var(--space-3); - margin-top: var(--space-4); -} - -.edge-legend { - position: absolute; - top: -0.65em; - padding: 0 var(--space-2); - background: var(--surface); - color: var(--text-muted); - font-size: var(--text-xs); - text-transform: uppercase; - letter-spacing: 0.04em; - line-height: 1.3; - white-space: nowrap; - z-index: 1; -} - -.params-sep { - position: relative; - border-top: 1px solid var(--border); - margin: 0 var(--space-4); - padding-bottom: var(--space-3); -} - -/* Панель этапа для инлайн-раскладки: исходник | параметры | результат */ -.pane { - position: relative; - display: flex; - flex-direction: column; - min-width: 0; -} - -.pane-legend { - top: -0.65em; - left: 50%; - transform: translateX(-50%); -} - -.actions-row { - display: flex; - gap: var(--space-1); - align-items: stretch; - width: 100%; -} - -.actions-row > button { - flex: 1; - min-width: 0; -} - -@media (max-width: 48rem) { .tool-stage { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: var(--space-4); + padding: var(--space-4); + align-items: start; + width: 100%; + } + + .tool-stage.single { grid-template-columns: 1fr; } + .tool-stage .cell { + min-width: 0; + display: flex; + flex-direction: column; + gap: var(--space-2); + } + .tool-stage .cell + .cell { - border-left: none; - padding-left: 0; + border-left: 1px solid var(--border); + padding-left: var(--space-4); + } + + .cell-media { + flex: 1; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + min-height: 14rem; + position: relative; + width: 100%; + } + + .chain-stack { + display: flex; + flex-direction: column; + gap: var(--space-3); + margin-top: var(--space-4); + } + + .edge-legend { + position: absolute; + top: -0.65em; + padding: 0 var(--space-2); + background: var(--surface); + color: var(--text-muted); + font-size: var(--text-xs); + text-transform: uppercase; + letter-spacing: 0.04em; + line-height: 1.3; + white-space: nowrap; + z-index: 1; + } + + .params-sep { + position: relative; border-top: 1px solid var(--border); - padding-top: var(--space-4); + margin: 0 var(--space-4); + padding-bottom: var(--space-3); + } + + /* Панель этапа для инлайн-раскладки: исходник | параметры | результат */ + .pane { + position: relative; + display: flex; + flex-direction: column; + min-width: 0; + } + + .pane-legend { + top: -0.65em; + left: 50%; + transform: translateX(-50%); + } + + .actions-row { + display: flex; + gap: var(--space-1); + align-items: stretch; + width: 100%; + } + + .actions-row > button { + flex: 1; + min-width: 0; + } + + @media (max-width: 48rem) { + .tool-stage { + grid-template-columns: 1fr; + } + + .tool-stage .cell + .cell { + border-left: none; + padding-left: 0; + border-top: 1px solid var(--border); + padding-top: var(--space-4); + } } } diff --git a/web/src/lib/components/kit/ToolCard.svelte b/web/src/lib/components/kit/ToolCard.svelte index fafa6d1..57c7c69 100644 --- a/web/src/lib/components/kit/ToolCard.svelte +++ b/web/src/lib/components/kit/ToolCard.svelte @@ -1,8 +1,8 @@ - + {#if icon}{/if} {title} diff --git a/web/src/lib/components/kit/TopBar.svelte b/web/src/lib/components/kit/TopBar.svelte index 6e4b3b9..aa77b10 100644 --- a/web/src/lib/components/kit/TopBar.svelte +++ b/web/src/lib/components/kit/TopBar.svelte @@ -77,6 +77,7 @@ gap: 10px; font: 600 14px var(--font-mono); color: var(--foreground); + text-decoration: none; } .brand-mark { background: var(--blue); @@ -101,7 +102,7 @@ } .nav a { color: var(--muted); - font: 12px var(--font-mono); + font: 10px var(--font-mono); text-decoration: none; } .nav a:hover { diff --git a/web/src/lib/styles/design2.css b/web/src/lib/styles/design2.css index a22e745..be74c5f 100644 --- a/web/src/lib/styles/design2.css +++ b/web/src/lib/styles/design2.css @@ -5,76 +5,104 @@ @import "@fontsource/ibm-plex-mono/400.css"; @import "@fontsource/ibm-plex-mono/500.css"; -/* Минимальный reset (новый дизайн грузится только на preview-маршрутах). */ -*, -*::before, -*::after { - box-sizing: border-box; -} -html, -body { - margin: 0; - padding: 0; -} - -/* Базовая типографика и палитра: без этого весь текст наследует UA-дефолт - (Times New Roman / чёрный), что даёт сотни расхождений с рефом. */ -html { - color-scheme: light dark; - font-family: var(--font-sans); - -webkit-text-size-adjust: 100%; -} -body { - font-family: var(--font-sans); - color: var(--foreground); - background: var(--background); - -webkit-font-smoothing: antialiased; - text-rendering: optimizeLegibility; -} - -/* Форм-контролы не наследуют шрифт семьи по умолчанию (браузер ставит Arial). */ -button, -input, -select, -textarea, -optgroup { - font: inherit; -} - -/* Новый дизайн: токены (§2 плана redesign). - Файл грузится только layout'ом новой ветки (preview/+layout), поэтому - глобально не конфликтует со старым app.css. */ - -:root { - --font-sans: "IBM Plex Sans", sans-serif; - --font-mono: "IBM Plex Mono", monospace; - - --background: #eef1f4; - --panel: #f8fafb; - --foreground: #17212b; - --muted: #6d7883; - --line: #cbd3da; - - --blue: #1769d2; - --cyan: #00a8c7; - --amber: #bd7411; - --success: rgb(35, 131, 84); - --success2: rgb(37, 169, 106); - --danger: #e5484d; - - --radius: 4px; -} - -[data-theme="dark"] { - --background: #11171d; - --panel: #182129; - --foreground: #e8eef2; - --muted: #91a0ac; - --line: #33414c; - - --blue: #54a2ff; - --cyan: #00a8c7; - --amber: #bd7411; - --success: #25a96a; - --danger: #ff7479; +/* Порядок cascade-слоёв (дубль из корневого +layout.svelte — идемпотентен и + страхует случай, когда design2.css грузится раньше корневого layout): */ +@layer app, design; + +/* Новый дизайн — слой design. В слое design правила выигрывают у того же + правила из слоя app (старый app.css) по слою, а не по порядку , + поэтому утечка app.css на /preview при SPA-переходе не перебивает design2. */ +@layer design { + /* Минимальный reset (новый дизайн грузится только на preview-маршрутах). */ + *, + *::before, + *::after { + box-sizing: border-box; + } + html, + body { + margin: 0; + padding: 0; + } + + /* Базовая типографика и палитра: без этого весь текст наследует UA-дефолт + (Times New Roman / чёрный), что даёт сотни расхождений с рефом. */ + html { + color-scheme: light dark; + font-family: var(--font-sans); + -webkit-text-size-adjust: 100%; + } + body { + font-family: var(--font-sans); + color: var(--foreground); + background: var(--background); + -webkit-font-smoothing: antialiased; + text-rendering: optimizeLegibility; + } + + /* Форм-контролы не наследуют шрифт семьи по умолчанию (браузер ставит Arial). */ + button, + input, + select, + textarea, + optgroup { + font: inherit; + } + + /* Перебивки глобальных правил старого app.css (слой app ниже), чтобы при + утечке app.css на /preview новый дизайн не получал старую типографику. + Пустые — заполни при необходимости. */ + a, + a:hover { + /* color: inherit; text-decoration: none; */ + } + h1, + h2 { + /* font-size: revert; line-height: revert; letter-spacing: revert; */ + } + p, + label { + /* font-size: revert; */ + } + :focus-visible { + /* outline: revert; */ + } + + /* Новый дизайн: токены (§2 плана redesign). + Файл грузится только layout'ом новой ветки (preview/+layout), поэтому + глобально не конфликтует со старым app.css. */ + + :root { + --font-sans: "IBM Plex Sans", sans-serif; + --font-mono: "IBM Plex Mono", monospace; + + --background: #eef1f4; + --panel: #f8fafb; + --foreground: #17212b; + --muted: #6d7883; + --line: #cbd3da; + + --blue: #1769d2; + --cyan: #00a8c7; + --amber: #bd7411; + --success: rgb(35, 131, 84); + --success2: rgb(37, 169, 106); + --danger: #e5484d; + + --radius: 4px; + } + + [data-theme="dark"] { + --background: #11171d; + --panel: #182129; + --foreground: #e8eef2; + --muted: #91a0ac; + --line: #33414c; + + --blue: #54a2ff; + --cyan: #00a8c7; + --amber: #bd7411; + --success: #25a96a; + --danger: #ff7479; + } } diff --git a/web/src/routes/+layout.svelte b/web/src/routes/+layout.svelte index 9300351..da1132f 100644 --- a/web/src/routes/+layout.svelte +++ b/web/src/routes/+layout.svelte @@ -17,3 +17,12 @@ {@render children()} + + diff --git a/web/src/routes/preview/kit/+page.svelte b/web/src/routes/preview/kit/+page.svelte index 0459dff..7998a7a 100644 --- a/web/src/routes/preview/kit/+page.svelte +++ b/web/src/routes/preview/kit/+page.svelte @@ -1,29 +1,29 @@