このコミットが含まれているのは:
2026-07-05 03:27:58 +09:00
コミット 3a9ac8af32
3個のファイルの変更206行の追加201行の削除
+23 -5
ファイルの表示
@@ -271,6 +271,9 @@ const value =
- Preserve the local TSX formatting style. - Preserve the local TSX formatting style.
- Do not normalize TSX to common Prettier-style React formatting unless - Do not normalize TSX to common Prettier-style React formatting unless
explicitly asked. explicitly asked.
- Treat TSX formatting rules as hard constraints, not preferences. Before
finishing a TSX edit, inspect the edited hunks for closing `)`, `]`, and `}`
placement and fix violations instead of relying on formatter defaults.
- Prefer `const` arrow functions for TypeScript/TSX component and helper declarations. - Prefer `const` arrow functions for TypeScript/TSX component and helper declarations.
- Put two blank lines before and after top-level `const` function - Put two blank lines before and after top-level `const` function
declarations, unless imports, exports, or file boundaries make that awkward. declarations, unless imports, exports, or file boundaries make that awkward.
@@ -281,14 +284,29 @@ const value =
- In TypeScript and TSX function declarations, including `const` arrow - In TypeScript and TSX function declarations, including `const` arrow
function declarations, when the parameter list spans multiple lines, always function declarations, when the parameter list spans multiple lines, always
put the closing parenthesis at the beginning of its own line before the return put the closing parenthesis at the beginning of its own line before the return
type or `=>`. type or `=>`. Do not put that closing `)` at the end of the previous line.
- Do not write React component declarations in the common Prettier form
`const Component = ({ ... }) => (` when the destructured parameter spans
multiple lines. Use the project form with the opening `(` after `=`, the
destructured object as the argument, and the closing parameter `)` on its own
line before `=>`.
- In TypeScript and TSX, never place a closing parenthesis at the beginning of - In TypeScript and TSX, never place a closing parenthesis at the beginning of
a line except for a multi-line function declaration parameter list. a line except for a multi-line function declaration parameter list.
- Never place a closing square bracket at the beginning of a line. - Never place a closing square bracket at the beginning of a line.
- For object literals and other associative-array-style braces, do not place - For object literals, type literals, import/export named bindings, destructuring
the closing brace at the beginning of a line. Function, lambda, callback, and patterns, and other associative-array-style braces, do not place the closing
block closing braces are exempt and should stay on their own line when that brace at the beginning of a line. Keep `}` on the same line as the final
fits the local style. property, binding, or specifier unless that would violate the line limit.
Function, lambda, callback, and block closing braces are exempt and should
stay on their own line when that fits the local style. When a function,
lambda, callback, or block body spans multiple lines, do not put its closing
`}` at the end of the previous line.
- For arrays and tuple-like lists, do not place the closing `]` at the
beginning of a line. Keep `]` on the same line as the final element unless
that would violate the line limit.
- For function and method calls, do not place the closing `)` at the beginning
of a line. The only TypeScript/TSX exception is the closing parameter `)` of a
multi-line function declaration.
- When writing braces on a single line in TypeScript or TSX JavaScript - When writing braces on a single line in TypeScript or TSX JavaScript
context, put exactly one space inside the braces, as in `{ value }` or context, put exactly one space inside the braces, as in `{ value }` or
`{ key: value }`. `{ key: value }`.
+29
ファイルの表示
@@ -126,9 +126,38 @@ pass or the remaining failure is clearly blocked.
- Preserve compact TSX expression shapes such as inline ternary branches and - Preserve compact TSX expression shapes such as inline ternary branches and
closing `</div>)` forms when nearby code uses them. closing `</div>)` forms when nearby code uses them.
- Treat TSX formatting rules as hard constraints, not preferences. Before
finishing a TSX edit, inspect the edited hunks for closing `)`, `]`, and `}`
placement and fix violations instead of relying on formatter defaults.
- For long Tailwind `className` strings, wrap across lines only when needed. - For long Tailwind `className` strings, wrap across lines only when needed.
- Keep continuation indentation aligned with the 4-space logical indentation - Keep continuation indentation aligned with the 4-space logical indentation
rule, using tabs only as leading 8-space compression. rule, using tabs only as leading 8-space compression.
- In TypeScript and TSX function declarations, including `const` arrow
function declarations, when the parameter list spans multiple lines, always
put the closing parenthesis at the beginning of its own line before the return
type or `=>`. Do not put that closing `)` at the end of the previous line.
- Do not write React component declarations in the common Prettier form
`const Component = ({ ... }) => (` when the destructured parameter spans
multiple lines. Use the project form with the opening `(` after `=`, the
destructured object as the argument, and the closing parameter `)` on its own
line before `=>`.
- In TypeScript and TSX, never place a closing parenthesis at the beginning of
a line except for a multi-line function declaration parameter list.
- Never place a closing square bracket at the beginning of a line.
- For object literals, type literals, import/export named bindings, destructuring
patterns, and other associative-array-style braces, do not place the closing
brace at the beginning of a line. Keep `}` on the same line as the final
property, binding, or specifier unless that would violate the line limit.
Function, lambda, callback, and block closing braces are exempt and should
stay on their own line when that fits the local style. When a function,
lambda, callback, or block body spans multiple lines, do not put its closing
`}` at the end of the previous line.
- For arrays and tuple-like lists, do not place the closing `]` at the
beginning of a line. Keep `]` on the same line as the final element unless
that would violate the line limit.
- For function and method calls, do not place the closing `)` at the beginning
of a line. The only TypeScript/TSX exception is the closing parameter `)` of a
multi-line function declaration.
- Do not add braces around `if`, `else`, or `for` bodies when the body is a - Do not add braces around `if`, `else`, or `for` bodies when the body is a
single physical line. single physical line.
- Always add braces around `if`, `else`, or `for` bodies when the body spans - Always add braces around `if`, `else`, or `for` bodies when the body spans
+154 -196
ファイルの表示
@@ -1,5 +1,3 @@
import type { CSSProperties, Dispatch, FC, KeyboardEvent, SetStateAction } from 'react'
import { useEffect, useMemo, useState } from 'react' import { useEffect, useMemo, useState } from 'react'
import { Helmet } from 'react-helmet-async' import { Helmet } from 'react-helmet-async'
import { useLocation, useNavigate } from 'react-router-dom' import { useLocation, useNavigate } from 'react-router-dom'
@@ -18,38 +16,35 @@ import { Button } from '@/components/ui/button'
import { toast } from '@/components/ui/use-toast' import { toast } from '@/components/ui/use-toast'
import { SITE_TITLE } from '@/config' import { SITE_TITLE } from '@/config'
import { apiPut } from '@/lib/api' import { apiPut } from '@/lib/api'
import { import { applyThemeSelection,
applyThemeSelection, BUILTIN_THEMES,
BUILTIN_THEMES, createCustomThemeFromBase,
createCustomThemeFromBase, defaultThemeTagColoursFor,
defaultThemeTagColoursFor, DEFAULT_USER_SETTINGS,
DEFAULT_USER_SETTINGS, deriveUserThemeModeFromSelection,
deriveUserThemeModeFromSelection, fetchUserSettings,
fetchUserSettings, hasStoredClientThemeSelection,
hasStoredClientThemeSelection, getClientActiveThemeId,
getClientActiveThemeId, getClientCustomThemes,
getClientCustomThemes, getResolvedThemeFromSelection,
getResolvedThemeFromSelection, setClientAppearanceThemes,
setClientAppearanceThemes, updateUserSettings } from '@/lib/settings'
updateUserSettings,
} from '@/lib/settings'
import { useKeyboardShortcutSettings } from '@/lib/useKeyboardShortcuts' import { useKeyboardShortcutSettings } from '@/lib/useKeyboardShortcuts'
import { cn, inputClass } from '@/lib/utils' import { cn, inputClass } from '@/lib/utils'
import { useValidationErrors } from '@/lib/useValidationErrors' import { useValidationErrors } from '@/lib/useValidationErrors'
import type { CSSProperties, Dispatch, FC, KeyboardEvent, SetStateAction } from 'react'
import type { Category, Tag, User } from '@/types' import type { Category, Tag, User } from '@/types'
import type { import type { ActiveThemeId,
ActiveThemeId, ClientTheme,
ClientTheme, CustomClientTheme,
CustomClientTheme, ThemeTagColours,
ThemeTagColours, UserSettings } from '@/lib/settings'
UserSettings,
} from '@/lib/settings'
type Props = { type Props = {
user: User | null user: User | null
setUser: Dispatch<SetStateAction<User | null>> setUser: Dispatch<SetStateAction<User | null>> }
}
type UserFormField = 'name' type UserFormField = 'name'
type SettingsFormField = 'theme' type SettingsFormField = 'theme'
@@ -79,14 +74,12 @@ type SharedSectionProps = {
onResetTagColour: (category: Category) => void onResetTagColour: (category: Category) => void
onThemeSubmit: () => void onThemeSubmit: () => void
settingsBaseErrors: string[] settingsBaseErrors: string[]
settingsFieldErrors: Partial<Record<SettingsFormField, string[]>> settingsFieldErrors: Partial<Record<SettingsFormField, string[]>> }
}
const tabs: TabSpec[] = [ const tabs: TabSpec[] = [
{ id: 'account', label: 'アカウント' }, { id: 'account', label: 'アカウント' },
{ id: 'theme', label: 'テーマ' }, { id: 'theme', label: 'テーマ' },
{ id: 'keyboard', label: 'キーボード' }, { id: 'keyboard', label: 'キーボード' } ]
]
const sectionClassName = const sectionClassName =
'space-y-4 rounded-xl border border-border bg-background/80 p-4' 'space-y-4 rounded-xl border border-border bg-background/80 p-4'
@@ -94,13 +87,12 @@ const sectionClassName =
const themeLabel: Record<UserSettings['theme'], string> = { const themeLabel: Record<UserSettings['theme'], string> = {
system: 'システム設定に従う', system: 'システム設定に従う',
light: 'ライト・モード', light: 'ライト・モード',
dark: 'ダーク・モード', dark: 'ダーク・モード' }
}
const builtinThemeLabel: Record<'light' | 'dark', string> = { const builtinThemeLabel: Record<'light' | 'dark', string> = {
light: 'ライト・モード', light: 'ライト・モード',
dark: 'ダーク・モード', dark: 'ダーク・モード' }
}
const previewTag = ( const previewTag = (
id: number, id: number,
@@ -122,8 +114,7 @@ const previewTag = (
hasWiki, hasWiki,
materialId: null, materialId: null,
hasDeerjikists: options?.hasDeerjikists ?? false, hasDeerjikists: options?.hasDeerjikists ?? false,
children: [], children: [] })
})
const previewTags: Record<Category, Tag> = { const previewTags: Record<Category, Tag> = {
deerjikist: previewTag (1, 'にじらー', 'deerjikist', 12, true, { hasDeerjikists: true }), deerjikist: previewTag (1, 'にじらー', 'deerjikist', 12, true, { hasDeerjikists: true }),
@@ -132,15 +123,14 @@ const previewTags: Record<Category, Tag> = {
general: previewTag (4, '一般', 'general', 78, true), general: previewTag (4, '一般', 'general', 78, true),
material: previewTag (5, '素材', 'material', 90, false), material: previewTag (5, '素材', 'material', 90, false),
meta: previewTag (6, 'メタ', 'meta', 21, true), meta: previewTag (6, 'メタ', 'meta', 21, true),
nico: previewTag (7, 'nico:sm9', 'nico', 43, false), nico: previewTag (7, 'nico:sm9', 'nico', 43, false) }
}
const parseTab = (search: string): SettingsTab => { const parseTab = (search: string): SettingsTab => {
const tab = new URLSearchParams (search).get ('tab') const tab = new URLSearchParams (search).get ('tab')
return tabs.some (candidate => candidate.id === tab) return (tabs.some (candidate => candidate.id === tab)
? tab as SettingsTab ? (tab as SettingsTab)
: 'account' : 'account')
} }
@@ -152,9 +142,7 @@ const themePreviewStyle = (tagColours: ThemeTagColours): CSSProperties =>
Object.fromEntries ( Object.fromEntries (
CATEGORIES.flatMap (category => [ CATEGORIES.flatMap (category => [
[`--tag-colour-${ category }`, tagColours[category]], [`--tag-colour-${ category }`, tagColours[category]],
[`--tag-colour-${ category }-hover`, tagColours[category]], [`--tag-colour-${ category }-hover`, tagColours[category]]])) as CSSProperties
]),
) as CSSProperties
const themeLabelById = ( const themeLabelById = (
@@ -169,16 +157,16 @@ const themeLabelById = (
} }
const AccountSection: FC<SharedSectionProps> = ({ const AccountSection: FC<SharedSectionProps> = (
name, { name,
onInheritOpen, onInheritOpen,
onNameChange, onNameChange,
onUserCodeOpen, onUserCodeOpen,
onUserSubmit, onUserSubmit,
user, user,
userBaseErrors, userBaseErrors,
userFieldErrors, userFieldErrors },
}) => ( ) => (
<section className={sectionClassName}> <section className={sectionClassName}>
<h2 className="text-xl font-bold"></h2> <h2 className="text-xl font-bold"></h2>
<FieldError messages={userBaseErrors}/> <FieldError messages={userBaseErrors}/>
@@ -229,20 +217,20 @@ const AccountSection: FC<SharedSectionProps> = ({
</section>) </section>)
const ThemeSection: FC<SharedSectionProps> = ({ const ThemeSection: FC<SharedSectionProps> = (
draftActiveThemeId, { draftActiveThemeId,
draftCustomThemes, draftCustomThemes,
selectedTheme, selectedTheme,
draftTagColours, draftTagColours,
onEnsureEditableTheme, onEnsureEditableTheme,
onResetAllTagColours, onResetAllTagColours,
onResetTagColour, onResetTagColour,
onTagColourChange, onTagColourChange,
onThemeChange, onThemeChange,
onThemeSubmit, onThemeSubmit,
settingsBaseErrors, settingsBaseErrors,
settingsFieldErrors, settingsFieldErrors },
}) => ( ) => (
<section className={sectionClassName}> <section className={sectionClassName}>
<h2 className="text-xl font-bold"></h2> <h2 className="text-xl font-bold"></h2>
<FieldError messages={settingsBaseErrors}/> <FieldError messages={settingsBaseErrors}/>
@@ -389,24 +377,20 @@ const SettingPage: FC<Props> = ({ user, setUser }) => {
useState<Record<string, CustomClientTheme>> (getClientCustomThemes ()) useState<Record<string, CustomClientTheme>> (getClientCustomThemes ())
const [userCodeVsbl, setUserCodeVsbl] = useState (false) const [userCodeVsbl, setUserCodeVsbl] = useState (false)
const { conflictActionIds } = useKeyboardShortcutSettings () const { conflictActionIds } = useKeyboardShortcutSettings ()
const { const { baseErrors: userBaseErrors,
baseErrors: userBaseErrors, fieldErrors: userFieldErrors,
fieldErrors: userFieldErrors, clearValidationErrors: clearUserValidationErrors,
clearValidationErrors: clearUserValidationErrors, applyValidationError: applyUserValidationError } = useValidationErrors<UserFormField> ()
applyValidationError: applyUserValidationError, const { baseErrors: settingsBaseErrors,
} = useValidationErrors<UserFormField> () fieldErrors: settingsFieldErrors,
const { clearValidationErrors: clearSettingsValidationErrors,
baseErrors: settingsBaseErrors, applyValidationError: applySettingsValidationError } =
fieldErrors: settingsFieldErrors, useValidationErrors<SettingsFormField> ()
clearValidationErrors: clearSettingsValidationErrors,
applyValidationError: applySettingsValidationError,
} = useValidationErrors<SettingsFormField> ()
const activeTab = useMemo<SettingsTab> (() => parseTab (location.search), [location.search]) const activeTab = useMemo<SettingsTab> (() => parseTab (location.search), [location.search])
const selectedTheme = useMemo<ClientTheme> ( const selectedTheme = useMemo<ClientTheme> (
() => getResolvedThemeFromSelection (draftActiveThemeId, draftCustomThemes), () => getResolvedThemeFromSelection (draftActiveThemeId, draftCustomThemes),
[draftActiveThemeId, draftCustomThemes], [draftActiveThemeId, draftCustomThemes])
)
const draftTagColours = selectedTheme.tokens.tagColours const draftTagColours = selectedTheme.tokens.tagColours
const setActiveTab = (tab: SettingsTab) => { const setActiveTab = (tab: SettingsTab) => {
@@ -414,15 +398,15 @@ const SettingPage: FC<Props> = ({ user, setUser }) => {
params.set ('tab', tab) params.set ('tab', tab)
navigate ( navigate (
`${ location.pathname }?${ params.toString () }`, `${ location.pathname }?${ params.toString () }`,
{ replace: true }, { replace: true })
)
} }
const settingsTabErrors = useMemo<Record<SettingsTab, boolean>> (() => ({ const settingsTabErrors = useMemo<Record<SettingsTab, boolean>> (
account: Boolean (userFieldErrors.name?.length), () => (
theme: Boolean (settingsFieldErrors.theme?.length), { account: Boolean (userFieldErrors.name?.length),
keyboard: conflictActionIds.size > 0, theme: Boolean (settingsFieldErrors.theme?.length),
}), [conflictActionIds.size, settingsFieldErrors.theme, userFieldErrors.name]) keyboard: conflictActionIds.size > 0 }),
[conflictActionIds.size, settingsFieldErrors.theme, userFieldErrors.name])
const applyDraftThemeSelection = ( const applyDraftThemeSelection = (
activeThemeId: ActiveThemeId, activeThemeId: ActiveThemeId,
@@ -432,52 +416,40 @@ const SettingPage: FC<Props> = ({ user, setUser }) => {
setDraftCustomThemes (customThemes) setDraftCustomThemes (customThemes)
setDraftSettings (current => ({ setDraftSettings (current => ({
...current, ...current,
theme: deriveUserThemeModeFromSelection (activeThemeId, customThemes), theme: deriveUserThemeModeFromSelection (activeThemeId, customThemes) }))
}))
applyThemeSelection (activeThemeId, customThemes) applyThemeSelection (activeThemeId, customThemes)
} }
const ensureEditableCustomTheme = (): { const ensureEditableCustomTheme = (): {
activeThemeId: ActiveThemeId activeThemeId: ActiveThemeId
customThemes: Record<string, CustomClientTheme> customThemes: Record<string, CustomClientTheme> } => {
} => {
if (draftActiveThemeId !== 'system' && draftCustomThemes[draftActiveThemeId] != null) if (draftActiveThemeId !== 'system' && draftCustomThemes[draftActiveThemeId] != null)
{ {
return { return { activeThemeId: draftActiveThemeId,
activeThemeId: draftActiveThemeId, customThemes: draftCustomThemes }
customThemes: draftCustomThemes,
}
} }
const customTheme = createCustomThemeFromBase ( const customTheme = createCustomThemeFromBase (
selectedTheme.baseTheme, selectedTheme.baseTheme,
{ { ...selectedTheme.tokens,
...selectedTheme.tokens, tagColours: { ...selectedTheme.tokens.tagColours } })
tagColours: { ...selectedTheme.tokens.tagColours },
},
)
const nextCustomThemes = { const nextCustomThemes = {
...draftCustomThemes, ...draftCustomThemes,
[customTheme.id]: customTheme, [customTheme.id]: customTheme }
}
return { return {
activeThemeId: customTheme.id, activeThemeId: customTheme.id,
customThemes: nextCustomThemes, customThemes: nextCustomThemes }
}
} }
const handleEnsureEditableTheme = (): { const handleEnsureEditableTheme = (): {
activeThemeId: ActiveThemeId activeThemeId: ActiveThemeId
customThemes: Record<string, CustomClientTheme> customThemes: Record<string, CustomClientTheme> } => {
} => {
const editable = ensureEditableCustomTheme () const editable = ensureEditableCustomTheme ()
if (editable.activeThemeId !== draftActiveThemeId if (editable.activeThemeId !== draftActiveThemeId
|| editable.customThemes !== draftCustomThemes) || editable.customThemes !== draftCustomThemes)
{ applyDraftThemeSelection (editable.activeThemeId, editable.customThemes)
applyDraftThemeSelection (editable.activeThemeId, editable.customThemes)
}
return editable return editable
} }
@@ -580,9 +552,9 @@ const SettingPage: FC<Props> = ({ user, setUser }) => {
return return
const customThemes = getClientCustomThemes () const customThemes = getClientCustomThemes ()
const activeThemeId = hasStoredClientThemeSelection () const activeThemeId = (hasStoredClientThemeSelection ()
? getClientActiveThemeId () ? getClientActiveThemeId ()
: data.theme : data.theme)
const themeMode = deriveUserThemeModeFromSelection (activeThemeId, customThemes) const themeMode = deriveUserThemeModeFromSelection (activeThemeId, customThemes)
setDraftSettings ({ ...data, theme: themeMode }) setDraftSettings ({ ...data, theme: themeMode })
@@ -629,71 +601,62 @@ const SettingPage: FC<Props> = ({ user, setUser }) => {
} }
}, [draftActiveThemeId, draftCustomThemes, savedActiveThemeId, savedCustomThemes]) }, [draftActiveThemeId, draftCustomThemes, savedActiveThemeId, savedCustomThemes])
const sectionProps: SharedSectionProps | null = user ? { const sectionProps: SharedSectionProps | null =
user, user
name, ? { user,
onNameChange: setName, name,
onInheritOpen: () => setInheritVsbl (true), onNameChange: setName,
onUserCodeOpen: () => setUserCodeVsbl (true), onInheritOpen: () => setInheritVsbl (true),
onUserSubmit: handleUserSubmit, onUserCodeOpen: () => setUserCodeVsbl (true),
userBaseErrors, onUserSubmit: handleUserSubmit,
userFieldErrors, userBaseErrors,
draftActiveThemeId, userFieldErrors,
draftCustomThemes, draftActiveThemeId,
selectedTheme, draftCustomThemes,
draftTagColours, selectedTheme,
onThemeChange: themeId => { draftTagColours,
applyDraftThemeSelection (themeId, draftCustomThemes) onThemeChange: themeId => {
}, applyDraftThemeSelection (themeId, draftCustomThemes)
onEnsureEditableTheme: () => { },
handleEnsureEditableTheme () onEnsureEditableTheme: () => {
}, handleEnsureEditableTheme ()
onTagColourChange: (category, colour) => { },
const editable = handleEnsureEditableTheme () onTagColourChange: (category, colour) => {
const editableTheme = editable.customThemes[editable.activeThemeId] const editable = handleEnsureEditableTheme ()
const nextCustomThemes = { const editableTheme = editable.customThemes[editable.activeThemeId]
...editable.customThemes, const nextCustomThemes = {
[editable.activeThemeId]: { ...editable.customThemes,
...editableTheme, [editable.activeThemeId]: {
tokens: { ...editableTheme,
...editableTheme.tokens, tokens: {
tagColours: { ...editableTheme.tokens,
...editableTheme.tokens.tagColours, tagColours: {
[category]: colour, ...editableTheme.tokens.tagColours,
}, [category]: colour } } } }
}, applyDraftThemeSelection (editable.activeThemeId, nextCustomThemes)
}, },
} onResetAllTagColours: () => {
applyDraftThemeSelection (editable.activeThemeId, nextCustomThemes) if (selectedTheme.builtin || draftActiveThemeId === 'system')
}, return
onResetAllTagColours: () => {
if (selectedTheme.builtin || draftActiveThemeId === 'system')
return
applyDraftThemeSelection ( applyDraftThemeSelection (
draftActiveThemeId, draftActiveThemeId,
{ {
...draftCustomThemes, ...draftCustomThemes,
[draftActiveThemeId]: { [draftActiveThemeId]: {
...draftCustomThemes[draftActiveThemeId], ...draftCustomThemes[draftActiveThemeId],
tokens: { tokens: {
...draftCustomThemes[draftActiveThemeId].tokens, ...draftCustomThemes[draftActiveThemeId].tokens,
tagColours: { tagColours: {
...defaultThemeTagColoursFor (selectedTheme.baseTheme), ...defaultThemeTagColoursFor (selectedTheme.baseTheme) } } } })
}, },
}, onResetTagColour: category => {
}, if (selectedTheme.builtin || draftActiveThemeId === 'system')
}, return
)
},
onResetTagColour: category => {
if (selectedTheme.builtin || draftActiveThemeId === 'system')
return
applyDraftThemeSelection ( applyDraftThemeSelection (
draftActiveThemeId, draftActiveThemeId,
{ { ...draftCustomThemes,
...draftCustomThemes,
[draftActiveThemeId]: { [draftActiveThemeId]: {
...draftCustomThemes[draftActiveThemeId], ...draftCustomThemes[draftActiveThemeId],
tokens: { tokens: {
@@ -701,17 +664,13 @@ const SettingPage: FC<Props> = ({ user, setUser }) => {
tagColours: { tagColours: {
...draftCustomThemes[draftActiveThemeId].tokens.tagColours, ...draftCustomThemes[draftActiveThemeId].tokens.tagColours,
[category]: [category]:
defaultThemeTagColoursFor (selectedTheme.baseTheme)[category], defaultThemeTagColoursFor (
}, selectedTheme.baseTheme)[category] } } } })
}, },
}, onThemeSubmit: handleThemeSubmit,
}, settingsBaseErrors,
) settingsFieldErrors }
}, : null
onThemeSubmit: handleThemeSubmit,
settingsBaseErrors,
settingsFieldErrors,
} : null
return ( return (
<MainArea> <MainArea>
@@ -752,12 +711,11 @@ const SettingPage: FC<Props> = ({ user, setUser }) => {
tabIndex={activeTab === tab.id ? 0 : -1} tabIndex={activeTab === tab.id ? 0 : -1}
className={cn ( className={cn (
'rounded-xl border px-4 py-3 text-left text-sm font-medium', 'rounded-xl border px-4 py-3 text-left text-sm font-medium',
activeTab === tab.id (activeTab === tab.id
? ['border-slate-900 bg-slate-900 text-white', ? ['border-slate-900 bg-slate-900 text-white',
'dark:border-slate-100 dark:bg-slate-100 dark:text-slate-900'] 'dark:border-slate-100 dark:bg-slate-100 dark:text-slate-900']
: ['border-slate-300 bg-white text-slate-700', : ['border-slate-300 bg-white text-slate-700',
'dark:border-slate-700 dark:bg-slate-900 dark:text-slate-100'], 'dark:border-slate-700 dark:bg-slate-900 dark:text-slate-100']))}
)}
onClick={() => setActiveTab (tab.id)} onClick={() => setActiveTab (tab.id)}
onKeyDown={handleTabKeyDown}> onKeyDown={handleTabKeyDown}>
{tab.label} {tab.label}
@@ -778,8 +736,7 @@ const SettingPage: FC<Props> = ({ user, setUser }) => {
{activeTab === 'account' && <AccountSection {...sectionProps}/>} {activeTab === 'account' && <AccountSection {...sectionProps}/>}
{activeTab === 'theme' && <ThemeSection {...sectionProps}/>} {activeTab === 'theme' && <ThemeSection {...sectionProps}/>}
{activeTab === 'keyboard' && ( {activeTab === 'keyboard' && (
<KeyboardSettingsSection sectionClassName={sectionClassName}/> <KeyboardSettingsSection sectionClassName={sectionClassName}/>)}
)}
</>)} </>)}
</div>)} </div>)}
</div> </div>
@@ -799,4 +756,5 @@ const SettingPage: FC<Props> = ({ user, setUser }) => {
</MainArea>) </MainArea>)
} }
export default SettingPage export default SettingPage