Настройки внешнего вида

Сделай экран настроек внешнего вида: сегментированный переключатель темы на три варианта, ползунок масштаба интерфейса от 80 до 140 процентов с показом текущего значения, переключатель плотной вёрстки и раздел «Ещё» под разделителем с выбором шрифта. Справа от заголовка экрана метка с текущей темой. Состояние храни в компоненте и отдавай наружу через колбэк onChange.

appearance-settings__docs__claude-code__claude-opus-5__1 · 23.09.2026, 20:21:49 мск

Проверки пройдены
Доки · claude-opus-5 · Claude Code
Контекст до задачи~22 702
Токенов на прогон48 749
Цена$0.283
Ошибок компилятора0

Первый вызов модели получил 47 399 токенов входа, включая системный промпт Claude Code. Контекст до задачи — оценка по длине текста, для русского текста она занижает число токенов в полтора-два раза.

Компилятор

Ошибок нет: все компоненты и пропсы существуют.

Линтер и покрытие

  • inline-styleСтроки 54, 66, 68, 82, 83
    Инлайновые стили вместо классов и токенов библиотеки
Компоненты библиотеки

JxBadge, JxDivider, JxSelect, JxSlider, JxSwitch, JxToggle

Ожидались JxToggle, JxSlider, JxSwitch, JxDivider, JxBadge · покрытие 100%

Контекст

Доки (llms-full.txt, ~22548)

Вход 2 · выход 1 350 · из кэша 8 233 · в кэш 39 164 · 13 с

Рендер

Код компонента

tsx121 строка
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
import { useState } from 'react';
import {
  JxToggle,
  JxSlider,
  JxSwitch,
  JxDivider,
  JxSelect,
  JxBadge,
} from '@jinx-ui/react';

type ThemeValue = 'light' | 'dark' | 'system';

export interface AppearanceSettings {
  theme: ThemeValue;
  scale: number;
  dense: boolean;
  fontFamily: string;
}

const themeItems: Array<{ value: ThemeValue; label: string }> = [
  { value: 'light', label: 'Светлая' },
  { value: 'dark', label: 'Тёмная' },
  { value: 'system', label: 'Системная' },
];

const fontOptions = [
  { value: 'sans', label: 'Inter Tight', meta: 'Без засечек' },
  { value: 'display', label: 'Fraunces', meta: 'С засечками' },
  { value: 'mono', label: 'JetBrains Mono', meta: 'Моноширинный' },
];

function AppearanceSettingsScreen({
  defaultSettings = { theme: 'system', scale: 100, dense: false, fontFamily: 'sans' },
  onChange,
}: {
  defaultSettings?: AppearanceSettings;
  onChange?: (settings: AppearanceSettings) => void;
}) {
  const [settings, setSettings] = useState<AppearanceSettings>(defaultSettings);

  const update = (patch: Partial<AppearanceSettings>) => {
    setSettings((prev) => {
      const next = { ...prev, ...patch };
      onChange?.(next);
      return next;
    });
  };

  const themeLabel =
    themeItems.find((item) => item.value === settings.theme)?.label ?? settings.theme;

  return (
    <section
      style={{
        display: 'flex',
        flexDirection: 'column',
        gap: '20px',
        padding: '24px',
        background: 'var(--jx-surface)',
        border: '1px solid var(--jx-border)',
        borderRadius: 'var(--jx-r-lg)',
        color: 'var(--jx-text)',
        fontFamily: 'var(--jx-font-sans)',
      }}
    >
      <header style={{ display: 'flex', alignItems: 'center', gap: '12px' }}>
        <h2
          style={{
            margin: 0,
            fontFamily: 'var(--jx-font-display)',
            fontSize: '20px',
            color: 'var(--jx-text)',
          }}
        >
          Внешний вид
        </h2>
        <JxBadge tone="accent" dot>
          {themeLabel}
        </JxBadge>
      </header>

      <div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>
        <span style={{ fontSize: '13px', color: 'var(--jx-text-2)' }}>Тема оформления</span>
        <JxToggle
          items={themeItems}
          value={settings.theme}
          onValueChange={(value) => update({ theme: value as ThemeValue })}
        />
      </div>

      <JxSlider
        label="Масштаб интерфейса"
        min={80}
        max={140}
        step={10}
        unit="%"
        showOutput
        value={settings.scale}
        onValueChange={(value) => update({ scale: value })}
      />

      <JxSwitch
        label="Плотная вёрстка"
        checked={settings.dense}
        onChange={(event) => update({ dense: event.target.checked })}
      />

      <JxDivider label="Ещё" />

      <JxSelect
        label="Шрифт"
        placeholder="Выберите шрифт"
        options={fontOptions}
        value={settings.fontFamily}
        onValueChange={(value) => update({ fontFamily: value })}
      />
    </section>
  );
}

export default AppearanceSettingsScreen;