fix: update design with references
This commit is contained in:
@@ -337,7 +337,7 @@ src/routes/preview/tools/[id]/+page.svelte
|
|||||||
### Шаг 4. Переключатель и проверка
|
### Шаг 4. Переключатель и проверка
|
||||||
|
|
||||||
- [x] **[C15]** В старой шапке ссылка «Preview v2» → `/preview`, ставит `localStorage['easy-png-tools:preview-v2']='1'`.
|
- [x] **[C15]** В старой шапке ссылка «Preview v2» → `/preview`, ставит `localStorage['easy-png-tools:preview-v2']='1'`.
|
||||||
- [x] **[C16]** Внешний вид `/preview/*` приведён к `refs-html/`: тип шага — приглушённый, индекс шага — синий, подпись плитки — синяя, бренд топбара — `--foreground`, `Segmented` 10px/32px, стек шрифтов сверен с рефом; старые тесты прогнаны (без регрессий).
|
- [x] **[C16]** База под дизайн: рабочий переключатель тем (persist в localStorage, применяется на `<html>`; проверено — фон `#eef1f4`↔`#11171d`), `TopBar` приведён к виду `demo.html` (бренд + синий хлебный крош `/* страница */`, безрамочные иконки, язык — active = `--foreground`/`--background`), страницы `/preview/*` на всю ширину (убран `max-width`). Точечное выравнивание к рефу отложено: реф-дизайн неконсистентен.
|
||||||
(доказательство отсутствия регресса). Фиксы по результатам — отдельными
|
(доказательство отсутствия регресса). Фиксы по результатам — отдельными
|
||||||
мелкими коммитами.
|
мелкими коммитами.
|
||||||
|
|
||||||
|
|||||||
@@ -6,10 +6,11 @@
|
|||||||
icon: Component<{ size?: number; class?: string }>;
|
icon: Component<{ size?: number; class?: string }>;
|
||||||
label: string;
|
label: string;
|
||||||
onclick?: () => void;
|
onclick?: () => void;
|
||||||
variant?: "ghost" | "solid" | "accent";
|
variant?: "ghost" | "solid" | "accent" | "bare";
|
||||||
size?: number;
|
size?: number;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
let {
|
let {
|
||||||
icon,
|
icon,
|
||||||
label,
|
label,
|
||||||
@@ -57,6 +58,18 @@
|
|||||||
color: #042;
|
color: #042;
|
||||||
border-color: var(--cyan);
|
border-color: var(--cyan);
|
||||||
}
|
}
|
||||||
|
.icon-btn--bare {
|
||||||
|
width: auto;
|
||||||
|
height: auto;
|
||||||
|
padding: 6px;
|
||||||
|
border: 0;
|
||||||
|
border-radius: 0;
|
||||||
|
color: var(--muted);
|
||||||
|
}
|
||||||
|
.icon-btn--bare:hover:not(:disabled) {
|
||||||
|
color: var(--foreground);
|
||||||
|
border-color: transparent;
|
||||||
|
}
|
||||||
.icon-btn:disabled {
|
.icon-btn:disabled {
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import IconButton from "./IconButton.svelte";
|
import IconButton from "./IconButton.svelte";
|
||||||
import Segmented from "./Segmented.svelte";
|
|
||||||
import StatusDot from "./StatusDot.svelte";
|
import StatusDot from "./StatusDot.svelte";
|
||||||
import { CircleHelp, Moon, Sun } from "@lucide/svelte";
|
import { CircleHelp, Moon, Sun } from "@lucide/svelte";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
theme: "light" | "dark";
|
theme: "light" | "dark";
|
||||||
|
crumb?: string;
|
||||||
ontoggle: () => void;
|
ontoggle: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
let { theme, ontoggle }: Props = $props();
|
let { theme, crumb, ontoggle }: Props = $props();
|
||||||
|
|
||||||
let lang = $state("RU");
|
let lang = $state("RU");
|
||||||
</script>
|
</script>
|
||||||
@@ -18,22 +18,31 @@
|
|||||||
<div class="brand">
|
<div class="brand">
|
||||||
<span class="brand-mark">EP</span>
|
<span class="brand-mark">EP</span>
|
||||||
<span>easy-png-tools</span>
|
<span>easy-png-tools</span>
|
||||||
|
{#if crumb}<span class="version">{crumb}</span>{/if}
|
||||||
</div>
|
</div>
|
||||||
<div class="top-actions">
|
<div class="top-actions">
|
||||||
<span class="status"><StatusDot /> AUTO PIPELINE</span>
|
<span class="status"><StatusDot /> AUTO PIPELINE</span>
|
||||||
<IconButton icon={CircleHelp} label="Help" onclick={() => {}} />
|
<IconButton icon={CircleHelp} label="Help" variant="bare" onclick={() => {}} />
|
||||||
<IconButton
|
<IconButton
|
||||||
icon={theme === "light" ? Moon : Sun}
|
icon={theme === "light" ? Moon : Sun}
|
||||||
label="Toggle theme"
|
label="Toggle theme"
|
||||||
|
variant="bare"
|
||||||
onclick={ontoggle}
|
onclick={ontoggle}
|
||||||
/>
|
/>
|
||||||
<Segmented
|
<div class="lang" role="group" aria-label="Language">
|
||||||
bind:value={lang}
|
<button
|
||||||
options={[
|
type="button"
|
||||||
{ value: "RU", label: "RU" },
|
class="lang-btn"
|
||||||
{ value: "EN", label: "EN" },
|
class:active={lang === "RU"}
|
||||||
]}
|
onclick={() => (lang = "RU")}>RU</button
|
||||||
/>
|
>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="lang-btn"
|
||||||
|
class:active={lang === "EN"}
|
||||||
|
onclick={() => (lang = "EN")}>EN</button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
@@ -66,6 +75,11 @@
|
|||||||
display: grid;
|
display: grid;
|
||||||
place-items: center;
|
place-items: center;
|
||||||
}
|
}
|
||||||
|
.version {
|
||||||
|
font: 10px var(--font-mono);
|
||||||
|
letter-spacing: 0.12em;
|
||||||
|
color: var(--blue);
|
||||||
|
}
|
||||||
.top-actions {
|
.top-actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -79,4 +93,26 @@
|
|||||||
font: 10px var(--font-mono);
|
font: 10px var(--font-mono);
|
||||||
letter-spacing: 0.08em;
|
letter-spacing: 0.08em;
|
||||||
}
|
}
|
||||||
|
.lang {
|
||||||
|
display: inline-flex;
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
border-radius: var(--radius);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.lang-btn {
|
||||||
|
border: 0;
|
||||||
|
background: transparent;
|
||||||
|
color: var(--muted);
|
||||||
|
font: 10px var(--font-mono);
|
||||||
|
letter-spacing: 0.06em;
|
||||||
|
padding: 6px 9px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.lang-btn + .lang-btn {
|
||||||
|
border-left: 1px solid var(--line);
|
||||||
|
}
|
||||||
|
.lang-btn.active {
|
||||||
|
background: var(--foreground);
|
||||||
|
color: var(--background);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import "$lib/styles/design2.css";
|
import "$lib/styles/design2.css";
|
||||||
import type { Snippet } from "svelte";
|
import type { Snippet } from "svelte";
|
||||||
|
import { page } from "$app/stores";
|
||||||
import AppShell from "$lib/components/kit/AppShell.svelte";
|
import AppShell from "$lib/components/kit/AppShell.svelte";
|
||||||
import TopBar from "$lib/components/kit/TopBar.svelte";
|
import TopBar from "$lib/components/kit/TopBar.svelte";
|
||||||
|
|
||||||
@@ -10,13 +11,40 @@
|
|||||||
|
|
||||||
let { children }: Props = $props();
|
let { children }: Props = $props();
|
||||||
|
|
||||||
let theme = $state<"light" | "dark">("light");
|
type Theme = "light" | "dark";
|
||||||
|
const stored =
|
||||||
|
typeof localStorage !== "undefined"
|
||||||
|
? (localStorage.getItem("easy-png-tools:theme") as Theme | null)
|
||||||
|
: null;
|
||||||
|
let theme = $state<Theme>(stored ?? "light");
|
||||||
|
|
||||||
function toggle() {
|
function toggle() {
|
||||||
theme = theme === "light" ? "dark" : "light";
|
theme = theme === "light" ? "dark" : "light";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$effect(() => {
|
||||||
|
document.documentElement.dataset.theme = theme;
|
||||||
|
try {
|
||||||
|
localStorage.setItem("easy-png-tools:theme", theme);
|
||||||
|
} catch {
|
||||||
|
/* ignore */
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let crumb = $derived(toCrumb($page.url.pathname));
|
||||||
|
|
||||||
|
function toCrumb(path: string): string {
|
||||||
|
const seg = path
|
||||||
|
.replace(/^\/preview/, "")
|
||||||
|
.replace(/^\//, "")
|
||||||
|
.split("/")
|
||||||
|
.filter(Boolean);
|
||||||
|
const label = seg.length ? seg.join(" / ").toUpperCase() : "PREVIEW";
|
||||||
|
return "/ " + label;
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="preview-root" data-theme={theme}>
|
<div class="preview-root" data-theme={theme}>
|
||||||
<TopBar {theme} ontoggle={toggle} />
|
<TopBar {theme} {crumb} ontoggle={toggle} />
|
||||||
<AppShell>{@render children()}</AppShell>
|
<AppShell>{@render children()}</AppShell>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -250,8 +250,8 @@
|
|||||||
grid-template-columns: minmax(0, 1.05fr) minmax(520px, 0.95fr);
|
grid-template-columns: minmax(0, 1.05fr) minmax(520px, 0.95fr);
|
||||||
align-items: start;
|
align-items: start;
|
||||||
gap: 56px;
|
gap: 56px;
|
||||||
max-width: 1680px;
|
max-width: none;
|
||||||
margin: 0 auto;
|
margin: auto;
|
||||||
padding: 60px clamp(24px, 4vw, 72px) 72px;
|
padding: 60px clamp(24px, 4vw, 72px) 72px;
|
||||||
}
|
}
|
||||||
.workspace {
|
.workspace {
|
||||||
|
|||||||
@@ -214,9 +214,9 @@
|
|||||||
|
|
||||||
<style>
|
<style>
|
||||||
.showcase {
|
.showcase {
|
||||||
max-width: 880px;
|
max-width: none;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
padding: 2.5rem 1.25rem 4rem;
|
padding: 2.5rem clamp(24px, 4vw, 72px) 4rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 1.25rem;
|
gap: 1.25rem;
|
||||||
|
|||||||
@@ -50,9 +50,9 @@
|
|||||||
|
|
||||||
<style>
|
<style>
|
||||||
.catalog {
|
.catalog {
|
||||||
max-width: 880px;
|
max-width: none;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
padding: 2.5rem 1.25rem 4rem;
|
padding: 2.5rem clamp(24px, 4vw, 72px) 4rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 1.25rem;
|
gap: 1.25rem;
|
||||||
|
|||||||
Reference in New Issue
Block a user