Настройки внешнего вида
Сделай экран настроек внешнего вида: сегментированный переключатель темы на три варианта, ползунок масштаба интерфейса от 80 до 140 процентов с показом текущего значения, переключатель плотной вёрстки и раздел «Ещё» под разделителем с выбором шрифта. Справа от заголовка экрана метка с текущей темой. Состояние храни в компоненте и отдавай наружу через колбэк onChange.
appearance-settings__none__claude-code__claude-opus-5__1 · 23.09.2026, 19:59:02 мск
Первый вызов модели получил 8 646 токенов входа, включая системный промпт Claude Code. Контекст до задачи — оценка по длине текста, для русского текста она занижает число токенов в полтора-два раза.
Компилятор
- Строка 3 · TS2724
'"@jinx-ui/react"' has no exported member named 'Badge'. Did you mean 'JxBadge'? - Строка 4 · TS2724
'"@jinx-ui/react"' has no exported member named 'Divider'. Did you mean 'JxDivider'? - Строка 5 · TS2305
Module '"@jinx-ui/react"' has no exported member 'Field'. - Строка 6 · TS2305
Module '"@jinx-ui/react"' has no exported member 'Heading'. - Строка 7 · TS2305
Module '"@jinx-ui/react"' has no exported member 'Section'. - Строка 8 · TS2305
Module '"@jinx-ui/react"' has no exported member 'SegmentedControl'. - Строка 9 · TS2724
'"@jinx-ui/react"' has no exported member named 'Select'. Did you mean 'JxSelect'? - Строка 10 · TS2724
'"@jinx-ui/react"' has no exported member named 'Slider'. Did you mean 'JxSlider'? - Строка 11 · TS2305
Module '"@jinx-ui/react"' has no exported member 'Stack'. - Строка 12 · TS2724
'"@jinx-ui/react"' has no exported member named 'Switch'. Did you mean 'JxSwitch'? - Строка 13 · TS2305
Module '"@jinx-ui/react"' has no exported member 'Text'.
Линтер и покрытие
- inline-styleСтроки 74, 79, 104, 109Инлайновые стили вместо классов и токенов библиотеки
Ни одного: код написан без библиотеки, поэтому прогон не засчитан
Ожидались JxToggle, JxSlider, JxSwitch, JxDivider, JxBadge · покрытие 0%
Только формулировка задачи
Вход 2 · выход 2 423 · из кэша 8 233 · в кэш 411 · 26 с
Рендер
Код компонента
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
import { useState } from 'react';
import {
Badge,
Divider,
Field,
Heading,
Section,
SegmentedControl,
Select,
Slider,
Stack,
Switch,
Text,
} from '@jinx-ui/react';
export type Theme = 'light' | 'dark' | 'system';
export type FontFamily = 'system' | 'inter' | 'mono';
export interface AppearanceValue {
theme: Theme;
scale: number;
dense: boolean;
font: FontFamily;
}
export interface AppearanceSettingsProps {
initialValue?: Partial<AppearanceValue>;
onChange: (value: AppearanceValue) => void;
}
const THEMES: { value: Theme; label: string }[] = [
{ value: 'light', label: 'Светлая' },
{ value: 'dark', label: 'Тёмная' },
{ value: 'system', label: 'Системная' },
];
const FONTS: { value: FontFamily; label: string }[] = [
{ value: 'system', label: 'Системный' },
{ value: 'inter', label: 'Inter' },
{ value: 'mono', label: 'Моноширинный' },
];
const DEFAULTS: AppearanceValue = {
theme: 'system',
scale: 100,
dense: false,
font: 'system',
};
export default function AppearanceSettings({
initialValue,
onChange,
}: AppearanceSettingsProps) {
const [value, setValue] = useState<AppearanceValue>({
...DEFAULTS,
...initialValue,
});
const update = <K extends keyof AppearanceValue>(
key: K,
next: AppearanceValue[K],
) => {
setValue((prev) => {
const merged = { ...prev, [key]: next };
onChange(merged);
return merged;
});
};
const themeLabel =
THEMES.find((t) => t.value === value.theme)?.label ?? value.theme;
return (
<Section style={{ padding: 'var(--jx-space-6)' }}>
<Stack
direction="row"
align="center"
justify="between"
style={{ marginBottom: 'var(--jx-space-5)' }}
>
<Heading level={2}>Внешний вид</Heading>
<Badge variant="neutral">{themeLabel}</Badge>
</Stack>
<Stack direction="column" gap="var(--jx-space-5)">
<Field label="Тема" htmlFor="appearance-theme">
<SegmentedControl
id="appearance-theme"
value={value.theme}
onChange={(next: Theme) => update('theme', next)}
options={THEMES}
/>
</Field>
<Field label="Масштаб интерфейса" htmlFor="appearance-scale">
<Stack direction="row" align="center" gap="var(--jx-space-4)">
<Slider
id="appearance-scale"
min={80}
max={140}
step={5}
value={value.scale}
onChange={(next: number) => update('scale', next)}
style={{ flex: 1 }}
/>
<Text
variant="body"
tone="muted"
style={{ minWidth: 'var(--jx-size-12)', textAlign: 'right' }}
>
{value.scale}%
</Text>
</Stack>
</Field>
<Switch
checked={value.dense}
onChange={(next: boolean) => update('dense', next)}
label="Плотная вёрстка"
description="Уменьшает отступы между элементами"
/>
<Divider />
<Stack direction="column" gap="var(--jx-space-4)">
<Heading level={3}>Ещё</Heading>
<Field label="Шрифт" htmlFor="appearance-font">
<Select
id="appearance-font"
value={value.font}
onChange={(next: FontFamily) => update('font', next)}
options={FONTS}
/>
</Field>
</Stack>
</Stack>
</Section>
);
}