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

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

appearance-settings__docs-rules__claude-code__claude-opus-5__1 · 23.09.2026, 21:58:24 мск

Проверки пройдены
Доки + правила · claude-opus-5 · Claude Code
Контекст до задачи~23 785
Токенов на прогон50 472
Цена$0.294
Ошибок компилятора0

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

Компилятор

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

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

  • inline-styleСтроки 57, 71, 80, 94, 95
    Инлайновые стили вместо классов и токенов библиотеки
Компоненты библиотеки

JxBadge, JxDivider, JxSelect, JxSlider, JxSwitch, JxToggle

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

Контекст

Доки (llms-full.txt, ~22548) · Правила (jinx-ui, ~1083)

Вход 2 · выход 1 368 · из кэша 8 233 · в кэш 40 869 · 14 с

Рендер

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

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

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

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

const FONTS = [
  { value: 'sans', label: 'Inter Tight', meta: 'по умолчанию' },
  { value: 'display', label: 'Fraunces' },
  { value: 'mono', label: 'JetBrains Mono' },
];

export default function AppearanceSettingsScreen({
  defaultValue,
  onChange,
}: {
  defaultValue?: Partial<AppearanceSettings>;
  onChange?: (settings: AppearanceSettings) => void;
}) {
  const [settings, setSettings] = useState<AppearanceSettings>({
    theme: defaultValue?.theme ?? 'system',
    scale: defaultValue?.scale ?? 100,
    compact: defaultValue?.compact ?? false,
    fontFamily: defaultValue?.fontFamily ?? 'sans',
  });

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

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

  return (
    <section
      style={{
        display: 'flex',
        flexDirection: 'column',
        gap: 24,
        maxWidth: 560,
        padding: 24,
        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',
          justifyContent: 'space-between',
          gap: 12,
          flexWrap: 'wrap',
        }}
      >
        <h2
          style={{
            margin: 0,
            fontFamily: 'var(--jx-font-display)',
            fontSize: 20,
            color: 'var(--jx-text)',
          }}
        >
          Внешний вид
        </h2>
        <JxBadge tone="accent" dot>
          {themeLabel}
        </JxBadge>
      </header>

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

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

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

      <JxDivider label="Ещё" />

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