chore: finish frontend ESLint migration #18
Enable every plugin recommended preset and replace Biome with ESLint formatting. Preserve API contracts and JSX whitespace; verify source, tests, builds and tooling.
This commit is contained in:
@@ -1,3 +1,6 @@
|
||||
import type { Meta, StoryObj } from "@storybook/react-vite";
|
||||
import type { FC } from "react";
|
||||
|
||||
import {
|
||||
Box,
|
||||
Code,
|
||||
@@ -9,9 +12,7 @@ import {
|
||||
Title,
|
||||
useMantineTheme,
|
||||
} from "@mantine/core";
|
||||
import type { Meta, StoryObj } from "@storybook/react-vite";
|
||||
import { colorRoles, designTokens } from "@wealthledger/ui/theme";
|
||||
import type { FC } from "react";
|
||||
|
||||
const ColorsView: FC = () => {
|
||||
const theme = useMantineTheme();
|
||||
@@ -22,31 +23,39 @@ const ColorsView: FC = () => {
|
||||
Светлая схема WealthLedger. Источник цветов и ролей —
|
||||
@wealthledger/tokens/tokens.json. Цвет не заменяет подпись состояния.
|
||||
</Text>
|
||||
<SimpleGrid cols={{ base: 1, sm: 2, lg: 3 }}>
|
||||
<SimpleGrid cols={{ base: 1, lg: 3, sm: 2 }}>
|
||||
{Object.entries(designTokens.color.roles).map(([role, token]) => (
|
||||
<Paper key={role} p="md" withBorder>
|
||||
<Stack gap="xs">
|
||||
<Box h={48} bg={`var(--wl-color-${role})`} aria-hidden="true" />
|
||||
<Box aria-hidden="true" bg={`var(--wl-color-${role})`} h={48} />
|
||||
<Text fw={700}>{role}</Text>
|
||||
<Code>--wl-color-{role}</Code>
|
||||
<Code>
|
||||
--wl-color-
|
||||
{role}
|
||||
</Code>
|
||||
<Text size="sm">
|
||||
{colorRoles[role]} ·{" "}
|
||||
{parseThemeColor({ color: colorRoles[role], theme }).value}
|
||||
{/* eslint-disable-line security/detect-object-injection -- This is a positional index into the local array, not a user-supplied object key. */ colorRoles[role]}
|
||||
{" "}
|
||||
·
|
||||
{" "}
|
||||
{parseThemeColor({ color: /* eslint-disable-line security/detect-object-injection -- This is a positional index into the local array, not a user-supplied object key. */ colorRoles[role], theme }).value}
|
||||
</Text>
|
||||
<Text size="sm">{token.description}</Text>
|
||||
</Stack>
|
||||
</Paper>
|
||||
))}
|
||||
</SimpleGrid>
|
||||
{Object.keys(designTokens.color.palettes).map((palette) => (
|
||||
<Stack key={palette} gap="xs">
|
||||
{Object.keys(designTokens.color.palettes).map(palette => (
|
||||
<Stack gap="xs" key={palette}>
|
||||
<Title order={2}>{palette}</Title>
|
||||
<SimpleGrid cols={{ base: 2, sm: 5, lg: 10 }}>
|
||||
{theme.colors[palette].map((value, shade) => (
|
||||
<SimpleGrid cols={{ base: 2, lg: 10, sm: 5 }}>
|
||||
{/* eslint-disable-line security/detect-object-injection -- This is a positional index into the local array, not a user-supplied object key. */ theme.colors[palette].map((value, shade) => (
|
||||
<Paper key={value} p="xs" withBorder>
|
||||
<Box h={40} bg={value} aria-hidden="true" />
|
||||
<Box aria-hidden="true" bg={value} h={40} />
|
||||
<Text size="sm">
|
||||
{palette}.{shade}
|
||||
{palette}
|
||||
.
|
||||
{shade}
|
||||
</Text>
|
||||
<Text size="xs">{value}</Text>
|
||||
</Paper>
|
||||
@@ -69,37 +78,65 @@ const TypographyView: FC = () => {
|
||||
return (
|
||||
<Stack style={{ overflowWrap: "anywhere" }}>
|
||||
<Title order={1}>Типографика</Title>
|
||||
<Text>Основной шрифт: {theme.fontFamily}</Text>
|
||||
<Text ff="monospace">Моноширинный: {theme.fontFamilyMonospace}</Text>
|
||||
<Text>
|
||||
Основной шрифт:
|
||||
{" "}
|
||||
{theme.fontFamily}
|
||||
</Text>
|
||||
<Text ff="monospace">
|
||||
Моноширинный:
|
||||
{" "}
|
||||
{theme.fontFamilyMonospace}
|
||||
</Text>
|
||||
<Text>
|
||||
Title задаёт смысловую иерархию; выбирайте order по структуре страницы.
|
||||
Text — основной текст, size sm/xs — подписи; mono — идентификаторы.
|
||||
</Text>
|
||||
{Object.entries(theme.headings.sizes).map(([name, value]) => (
|
||||
<Paper key={name} withBorder p="md">
|
||||
<Paper key={name} p="md" withBorder>
|
||||
<Text
|
||||
fw={theme.headings.fontWeight}
|
||||
fz={value.fontSize}
|
||||
lh={value.lineHeight}
|
||||
fw={theme.headings.fontWeight}
|
||||
>
|
||||
{name} · Заголовок WealthLedger
|
||||
{name}
|
||||
{" "}
|
||||
· Заголовок WealthLedger
|
||||
</Text>
|
||||
<Text size="sm">
|
||||
{value.fontSize} / {value.lineHeight} · weight{" "}
|
||||
{value.fontSize}
|
||||
{" "}
|
||||
/
|
||||
{" "}
|
||||
{value.lineHeight}
|
||||
{" "}
|
||||
· weight
|
||||
{" "}
|
||||
{theme.headings.fontWeight}
|
||||
</Text>
|
||||
</Paper>
|
||||
))}
|
||||
{Object.entries(theme.fontSizes).map(([size, value]) => (
|
||||
<Paper key={size} p="md" withBorder>
|
||||
<Text size={size}>Размер {size} · Пример основного текста</Text>
|
||||
<Text size={size}>
|
||||
Размер
|
||||
{" "}
|
||||
{size}
|
||||
{" "}
|
||||
· Пример основного текста
|
||||
</Text>
|
||||
<Text size="sm">
|
||||
{value} / {theme.lineHeights[size]}
|
||||
{value}
|
||||
{" "}
|
||||
/
|
||||
{" "}
|
||||
{/* eslint-disable-line security/detect-object-injection -- This is a positional index into the local array, not a user-supplied object key. */ theme.lineHeights[size]}
|
||||
</Text>
|
||||
</Paper>
|
||||
))}
|
||||
<Text>
|
||||
Веса:{" "}
|
||||
Веса:
|
||||
{" "}
|
||||
{Object.entries(theme.fontWeights)
|
||||
.map(([name, value]) => `${name} ${value}`)
|
||||
.join("; ")}
|
||||
@@ -117,31 +154,43 @@ const LayoutView: FC = () => {
|
||||
Используйте Mantine props gap/p/radius/shadow или --mantine-* в CSS.
|
||||
Шкалы принадлежат tokens.json; адаптер Mantine сохраняет
|
||||
масштабирование. Default radius:
|
||||
{theme.defaultRadius}; scale: {theme.scale}. Размеры конкретных карточек
|
||||
{theme.defaultRadius}
|
||||
; scale:
|
||||
{" "}
|
||||
{theme.scale}
|
||||
. Размеры конкретных карточек
|
||||
и их особые тени остаются локальными.
|
||||
</Text>
|
||||
<Title order={2}>Spacing</Title>
|
||||
{Object.entries(theme.spacing).map(([name, value]) => (
|
||||
<Paper key={name} p="sm" withBorder>
|
||||
<Text>
|
||||
{name} · {value}
|
||||
{name}
|
||||
{" "}
|
||||
·
|
||||
{" "}
|
||||
{value}
|
||||
</Text>
|
||||
<Box w={value} h={16} bg="blue" aria-hidden="true" />
|
||||
<Box aria-hidden="true" bg="blue" h={16} w={value} />
|
||||
</Paper>
|
||||
))}
|
||||
<Title order={2}>Radius</Title>
|
||||
<SimpleGrid cols={{ base: 1, sm: 3 }}>
|
||||
{Object.entries(theme.radius).map(([name, value]) => (
|
||||
<Paper key={name} radius={name} p="md" withBorder>
|
||||
<Paper key={name} p="md" radius={name} withBorder>
|
||||
<Text>
|
||||
{name} · {value}
|
||||
{name}
|
||||
{" "}
|
||||
·
|
||||
{" "}
|
||||
{value}
|
||||
</Text>
|
||||
</Paper>
|
||||
))}
|
||||
</SimpleGrid>
|
||||
<Title order={2}>Shadows</Title>
|
||||
{Object.entries(theme.shadows).map(([name, value]) => (
|
||||
<Paper key={name} shadow={name} p="md" withBorder>
|
||||
<Paper key={name} p="md" shadow={name} withBorder>
|
||||
<Text fw={700}>{name}</Text>
|
||||
<Text size="sm">{value}</Text>
|
||||
</Paper>
|
||||
@@ -153,7 +202,11 @@ const LayoutView: FC = () => {
|
||||
</Text>
|
||||
{Object.entries(theme.breakpoints).map(([name, value]) => (
|
||||
<Text key={name}>
|
||||
{name} · {value}
|
||||
{name}
|
||||
{" "}
|
||||
·
|
||||
{" "}
|
||||
{value}
|
||||
</Text>
|
||||
))}
|
||||
</Stack>
|
||||
@@ -161,8 +214,6 @@ const LayoutView: FC = () => {
|
||||
};
|
||||
|
||||
const meta = {
|
||||
title: "Design System/Foundations",
|
||||
tags: ["autodocs"],
|
||||
parameters: {
|
||||
controls: { disable: true },
|
||||
docs: {
|
||||
@@ -172,6 +223,8 @@ const meta = {
|
||||
},
|
||||
},
|
||||
},
|
||||
tags: ["autodocs"],
|
||||
title: "Design System/Foundations",
|
||||
} satisfies Meta;
|
||||
|
||||
export default meta;
|
||||
@@ -185,18 +238,18 @@ export const SecondaryText: Story = {
|
||||
"var(--wl-color-surface)",
|
||||
"var(--wl-color-canvas)",
|
||||
"var(--wl-color-subtle)",
|
||||
...Object.keys(designTokens.color.palettes)
|
||||
.filter((palette) => palette !== "dark")
|
||||
.flatMap((palette) => [
|
||||
`var(--mantine-color-${palette}-0)`,
|
||||
`color-mix(in srgb, var(--mantine-color-${palette}-0) 45%, var(--wl-color-surface))`,
|
||||
]),
|
||||
].map((background) => (
|
||||
<Paper key={background} p="md" withBorder style={{ background }}>
|
||||
<Text size="sm" c="dimmed">
|
||||
...Object.keys(designTokens.color.palettes).flatMap(palette => palette === "dark"
|
||||
? []
|
||||
: [
|
||||
`var(--mantine-color-${palette}-0)`,
|
||||
`color-mix(in srgb, var(--mantine-color-${palette}-0) 45%, var(--wl-color-surface))`,
|
||||
]),
|
||||
].map(background => (
|
||||
<Paper key={background} p="md" style={{ background }} withBorder>
|
||||
<Text c="dimmed" size="sm">
|
||||
22.09.2026 · Синтетические данные
|
||||
</Text>
|
||||
<Text size="xs" c="dimmed">
|
||||
<Text c="dimmed" size="xs">
|
||||
Не удалось обновить данные. Сохранён предыдущий результат.
|
||||
</Text>
|
||||
</Paper>
|
||||
|
||||
@@ -3,8 +3,8 @@ import { describe, expect, it } from "vitest";
|
||||
|
||||
function luminance(color: string) {
|
||||
const channels = [1, 3, 5]
|
||||
.map((index) => Number.parseInt(color.slice(index, index + 2), 16) / 255)
|
||||
.map((value) =>
|
||||
.map(index => Number.parseInt(color.slice(index, index + 2), 16) / 255)
|
||||
.map(value =>
|
||||
value <= 0.04045 ? value / 12.92 : ((value + 0.055) / 1.055) ** 2.4,
|
||||
);
|
||||
return channels[0] * 0.2126 + channels[1] * 0.7152 + channels[2] * 0.0722;
|
||||
@@ -13,10 +13,10 @@ describe("semantic text contrast", () => {
|
||||
it.each(["positive", "negative", "muted"] as const)(
|
||||
"keeps %s readable on canvas, white, subtle and tinted surfaces",
|
||||
(tone) => {
|
||||
const role = tokens.color.roles[tone];
|
||||
const role = /* eslint-disable-line security/detect-object-injection -- Keys come from the repository’s trusted design-token definitions. */ tokens.color.roles[tone];
|
||||
const palettes = tokens.color.palettes;
|
||||
const foreground =
|
||||
palettes[role.color as keyof typeof palettes][role.shade];
|
||||
const foreground
|
||||
= palettes[role.color as keyof typeof palettes][role.shade];
|
||||
const surfaces = [
|
||||
"#ffffff",
|
||||
palettes.gray[0],
|
||||
@@ -29,11 +29,11 @@ describe("semantic text contrast", () => {
|
||||
.map(
|
||||
([, palette]) =>
|
||||
`#${[1, 3, 5]
|
||||
.map((index) =>
|
||||
.map(index =>
|
||||
Math.round(
|
||||
Number.parseInt(palette[0].slice(index, index + 2), 16) *
|
||||
0.45 +
|
||||
255 * 0.55,
|
||||
Number.parseInt(palette[0].slice(index, index + 2), 16)
|
||||
* 0.45
|
||||
+ 255 * 0.55,
|
||||
)
|
||||
.toString(16)
|
||||
.padStart(2, "0"),
|
||||
|
||||
Reference in New Issue
Block a user