CI / changes (push) Successful in 5s
CI / openapi (push) Successful in 39s
CI / web (push) Successful in 55s
CI / go (push) Successful in 2m40s
CI / bird2 (push) Successful in 16s
CI / commitlint (push) Skipped
CI / release (push) Successful in 18s
Выровнять KPI на IconTile, вынести settings из settings-7, Sheet/AlertDialog и skip-link в общем chrome. Co-authored-by: Cursor <[email protected]>
118 lines
4.3 KiB
TypeScript
118 lines
4.3 KiB
TypeScript
import { Moon, Sun, SunMoon } from 'lucide-react'
|
|
import { useTheme } from 'next-themes'
|
|
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
|
|
import { toast } from 'sonner'
|
|
|
|
import { SettingRow } from '@/components/settings/setting-row'
|
|
import { SettingsCard } from '@/components/settings/settings-card'
|
|
import { SettingsFieldGroup } from '@/components/settings/settings-field-group'
|
|
import { Badge } from '@/components/reui/badge'
|
|
import {
|
|
ToggleGroup,
|
|
ToggleGroupItem,
|
|
} from '@evobgp/ui/components/toggle-group'
|
|
import { Switch } from '@evobgp/ui/components/switch'
|
|
import { apiMutate } from '@/lib/api-client'
|
|
import { settingsKeys, settingsQueryOptions } from '@/queries/settings'
|
|
|
|
const THEME_OPTIONS = [
|
|
{ value: 'light', label: 'Светлая', icon: Sun },
|
|
{ value: 'dark', label: 'Тёмная', icon: Moon },
|
|
{ value: 'system', label: 'Система', icon: SunMoon },
|
|
] as const
|
|
|
|
function parseShowQuickActions(value: unknown): boolean {
|
|
if (value === false || value === 0 || value === 'false' || value === '0') return false
|
|
return true
|
|
}
|
|
|
|
export function AppearanceSettingsTab() {
|
|
const { theme, setTheme } = useTheme()
|
|
const qc = useQueryClient()
|
|
const settingsQ = useQuery(settingsQueryOptions())
|
|
const showQuickActions = parseShowQuickActions(settingsQ.data?.ui_show_quick_actions)
|
|
|
|
const patchMut = useMutation({
|
|
mutationFn: (payload: Record<string, boolean>) =>
|
|
apiMutate('/v1/settings', 'PATCH', payload),
|
|
onSuccess: () => {
|
|
toast.success('Настройки интерфейса сохранены')
|
|
void qc.invalidateQueries({ queryKey: settingsKeys.all })
|
|
},
|
|
onError: (e) =>
|
|
toast.error(e instanceof Error ? e.message : 'Не удалось сохранить'),
|
|
})
|
|
|
|
return (
|
|
<div className="space-y-6">
|
|
<SettingsCard
|
|
title="Тема интерфейса"
|
|
description="Быстрый переключатель также доступен в боковой панели"
|
|
>
|
|
<SettingsFieldGroup
|
|
legend="Тема"
|
|
description="Цветовая схема всех экранов в этом браузере."
|
|
>
|
|
<SettingRow
|
|
title="Тема"
|
|
description="Влияет на цветовую схему всех экранов в этом браузере."
|
|
titleAddon={
|
|
<Badge variant="primary-light" size="sm">
|
|
мгновенно
|
|
</Badge>
|
|
}
|
|
last
|
|
>
|
|
<ToggleGroup
|
|
multiple={false}
|
|
value={[theme ?? 'system']}
|
|
onValueChange={(value) => {
|
|
if (value.length > 0) setTheme(value[0])
|
|
}}
|
|
variant="outline"
|
|
size="sm"
|
|
aria-label="Тема интерфейса"
|
|
className="w-full sm:w-auto"
|
|
>
|
|
{THEME_OPTIONS.map((option) => {
|
|
const Icon = option.icon
|
|
return (
|
|
<ToggleGroupItem key={option.value} value={option.value} className="gap-1.5">
|
|
<Icon aria-hidden className="size-3.5" />
|
|
{option.label}
|
|
</ToggleGroupItem>
|
|
)
|
|
})}
|
|
</ToggleGroup>
|
|
</SettingRow>
|
|
</SettingsFieldGroup>
|
|
</SettingsCard>
|
|
|
|
<SettingsCard
|
|
title="Дашборд"
|
|
description="Блоки на экране «Обзор»"
|
|
>
|
|
<SettingsFieldGroup
|
|
legend="Быстрые действия"
|
|
description="Показывать KPI-like плитки быстрых переходов под метриками."
|
|
>
|
|
<SettingRow
|
|
title="Быстрые действия"
|
|
description="Блок с частыми переходами (модули, сеть, деплой) на дашборде."
|
|
last
|
|
>
|
|
<Switch
|
|
checked={showQuickActions}
|
|
disabled={settingsQ.isLoading || patchMut.isPending}
|
|
onCheckedChange={(checked) =>
|
|
patchMut.mutate({ ui_show_quick_actions: checked })
|
|
}
|
|
aria-label="Показывать быстрые действия"
|
|
/>
|
|
</SettingRow>
|
|
</SettingsFieldGroup>
|
|
</SettingsCard>
|
|
</div>
|
|
)
|
|
}
|