このコミットが含まれているのは:
@@ -271,6 +271,9 @@ const value =
|
||||
- Preserve the local TSX formatting style.
|
||||
- Do not normalize TSX to common Prettier-style React formatting unless
|
||||
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.
|
||||
- Put two blank lines before and after top-level `const` function
|
||||
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
|
||||
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 `=>`.
|
||||
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 and other associative-array-style braces, do not place
|
||||
the closing brace at the beginning of a line. Function, lambda, callback, and
|
||||
block closing braces are exempt and should stay on their own line when that
|
||||
fits the local style.
|
||||
- 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.
|
||||
- When writing braces on a single line in TypeScript or TSX JavaScript
|
||||
context, put exactly one space inside the braces, as in `{ value }` or
|
||||
`{ key: value }`.
|
||||
|
||||
@@ -126,9 +126,38 @@ pass or the remaining failure is clearly blocked.
|
||||
|
||||
- Preserve compact TSX expression shapes such as inline ternary branches and
|
||||
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.
|
||||
- Keep continuation indentation aligned with the 4-space logical indentation
|
||||
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
|
||||
single physical line.
|
||||
- Always add braces around `if`, `else`, or `for` bodies when the body spans
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import type { CSSProperties, Dispatch, FC, KeyboardEvent, SetStateAction } from 'react'
|
||||
|
||||
import { useEffect, useMemo, useState } from 'react'
|
||||
import { Helmet } from 'react-helmet-async'
|
||||
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 { SITE_TITLE } from '@/config'
|
||||
import { apiPut } from '@/lib/api'
|
||||
import {
|
||||
applyThemeSelection,
|
||||
BUILTIN_THEMES,
|
||||
createCustomThemeFromBase,
|
||||
defaultThemeTagColoursFor,
|
||||
DEFAULT_USER_SETTINGS,
|
||||
deriveUserThemeModeFromSelection,
|
||||
fetchUserSettings,
|
||||
hasStoredClientThemeSelection,
|
||||
getClientActiveThemeId,
|
||||
getClientCustomThemes,
|
||||
getResolvedThemeFromSelection,
|
||||
setClientAppearanceThemes,
|
||||
updateUserSettings,
|
||||
} from '@/lib/settings'
|
||||
import { applyThemeSelection,
|
||||
BUILTIN_THEMES,
|
||||
createCustomThemeFromBase,
|
||||
defaultThemeTagColoursFor,
|
||||
DEFAULT_USER_SETTINGS,
|
||||
deriveUserThemeModeFromSelection,
|
||||
fetchUserSettings,
|
||||
hasStoredClientThemeSelection,
|
||||
getClientActiveThemeId,
|
||||
getClientCustomThemes,
|
||||
getResolvedThemeFromSelection,
|
||||
setClientAppearanceThemes,
|
||||
updateUserSettings } from '@/lib/settings'
|
||||
import { useKeyboardShortcutSettings } from '@/lib/useKeyboardShortcuts'
|
||||
import { cn, inputClass } from '@/lib/utils'
|
||||
import { useValidationErrors } from '@/lib/useValidationErrors'
|
||||
|
||||
import type { CSSProperties, Dispatch, FC, KeyboardEvent, SetStateAction } from 'react'
|
||||
|
||||
import type { Category, Tag, User } from '@/types'
|
||||
import type {
|
||||
ActiveThemeId,
|
||||
ClientTheme,
|
||||
CustomClientTheme,
|
||||
ThemeTagColours,
|
||||
UserSettings,
|
||||
} from '@/lib/settings'
|
||||
import type { ActiveThemeId,
|
||||
ClientTheme,
|
||||
CustomClientTheme,
|
||||
ThemeTagColours,
|
||||
UserSettings } from '@/lib/settings'
|
||||
|
||||
type Props = {
|
||||
user: User | null
|
||||
setUser: Dispatch<SetStateAction<User | null>>
|
||||
}
|
||||
setUser: Dispatch<SetStateAction<User | null>> }
|
||||
|
||||
type UserFormField = 'name'
|
||||
type SettingsFormField = 'theme'
|
||||
@@ -79,14 +74,12 @@ type SharedSectionProps = {
|
||||
onResetTagColour: (category: Category) => void
|
||||
onThemeSubmit: () => void
|
||||
settingsBaseErrors: string[]
|
||||
settingsFieldErrors: Partial<Record<SettingsFormField, string[]>>
|
||||
}
|
||||
settingsFieldErrors: Partial<Record<SettingsFormField, string[]>> }
|
||||
|
||||
const tabs: TabSpec[] = [
|
||||
{ id: 'account', label: 'アカウント' },
|
||||
{ id: 'theme', label: 'テーマ' },
|
||||
{ id: 'keyboard', label: 'キーボード' },
|
||||
]
|
||||
{ id: 'keyboard', label: 'キーボード' } ]
|
||||
|
||||
const sectionClassName =
|
||||
'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> = {
|
||||
system: 'システム設定に従う',
|
||||
light: 'ライト・モード',
|
||||
dark: 'ダーク・モード',
|
||||
}
|
||||
dark: 'ダーク・モード' }
|
||||
|
||||
const builtinThemeLabel: Record<'light' | 'dark', string> = {
|
||||
light: 'ライト・モード',
|
||||
dark: 'ダーク・モード',
|
||||
}
|
||||
dark: 'ダーク・モード' }
|
||||
|
||||
|
||||
const previewTag = (
|
||||
id: number,
|
||||
@@ -122,8 +114,7 @@ const previewTag = (
|
||||
hasWiki,
|
||||
materialId: null,
|
||||
hasDeerjikists: options?.hasDeerjikists ?? false,
|
||||
children: [],
|
||||
})
|
||||
children: [] })
|
||||
|
||||
const previewTags: Record<Category, Tag> = {
|
||||
deerjikist: previewTag (1, 'にじらー', 'deerjikist', 12, true, { hasDeerjikists: true }),
|
||||
@@ -132,15 +123,14 @@ const previewTags: Record<Category, Tag> = {
|
||||
general: previewTag (4, '一般', 'general', 78, true),
|
||||
material: previewTag (5, '素材', 'material', 90, false),
|
||||
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 tab = new URLSearchParams (search).get ('tab')
|
||||
return tabs.some (candidate => candidate.id === tab)
|
||||
? tab as SettingsTab
|
||||
: 'account'
|
||||
return (tabs.some (candidate => candidate.id === tab)
|
||||
? (tab as SettingsTab)
|
||||
: 'account')
|
||||
}
|
||||
|
||||
|
||||
@@ -152,9 +142,7 @@ const themePreviewStyle = (tagColours: ThemeTagColours): CSSProperties =>
|
||||
Object.fromEntries (
|
||||
CATEGORIES.flatMap (category => [
|
||||
[`--tag-colour-${ category }`, tagColours[category]],
|
||||
[`--tag-colour-${ category }-hover`, tagColours[category]],
|
||||
]),
|
||||
) as CSSProperties
|
||||
[`--tag-colour-${ category }-hover`, tagColours[category]]])) as CSSProperties
|
||||
|
||||
|
||||
const themeLabelById = (
|
||||
@@ -169,16 +157,16 @@ const themeLabelById = (
|
||||
}
|
||||
|
||||
|
||||
const AccountSection: FC<SharedSectionProps> = ({
|
||||
name,
|
||||
onInheritOpen,
|
||||
onNameChange,
|
||||
onUserCodeOpen,
|
||||
onUserSubmit,
|
||||
user,
|
||||
userBaseErrors,
|
||||
userFieldErrors,
|
||||
}) => (
|
||||
const AccountSection: FC<SharedSectionProps> = (
|
||||
{ name,
|
||||
onInheritOpen,
|
||||
onNameChange,
|
||||
onUserCodeOpen,
|
||||
onUserSubmit,
|
||||
user,
|
||||
userBaseErrors,
|
||||
userFieldErrors },
|
||||
) => (
|
||||
<section className={sectionClassName}>
|
||||
<h2 className="text-xl font-bold">アカウント</h2>
|
||||
<FieldError messages={userBaseErrors}/>
|
||||
@@ -229,20 +217,20 @@ const AccountSection: FC<SharedSectionProps> = ({
|
||||
</section>)
|
||||
|
||||
|
||||
const ThemeSection: FC<SharedSectionProps> = ({
|
||||
draftActiveThemeId,
|
||||
draftCustomThemes,
|
||||
selectedTheme,
|
||||
draftTagColours,
|
||||
onEnsureEditableTheme,
|
||||
onResetAllTagColours,
|
||||
onResetTagColour,
|
||||
onTagColourChange,
|
||||
onThemeChange,
|
||||
onThemeSubmit,
|
||||
settingsBaseErrors,
|
||||
settingsFieldErrors,
|
||||
}) => (
|
||||
const ThemeSection: FC<SharedSectionProps> = (
|
||||
{ draftActiveThemeId,
|
||||
draftCustomThemes,
|
||||
selectedTheme,
|
||||
draftTagColours,
|
||||
onEnsureEditableTheme,
|
||||
onResetAllTagColours,
|
||||
onResetTagColour,
|
||||
onTagColourChange,
|
||||
onThemeChange,
|
||||
onThemeSubmit,
|
||||
settingsBaseErrors,
|
||||
settingsFieldErrors },
|
||||
) => (
|
||||
<section className={sectionClassName}>
|
||||
<h2 className="text-xl font-bold">テーマ</h2>
|
||||
<FieldError messages={settingsBaseErrors}/>
|
||||
@@ -389,24 +377,20 @@ const SettingPage: FC<Props> = ({ user, setUser }) => {
|
||||
useState<Record<string, CustomClientTheme>> (getClientCustomThemes ())
|
||||
const [userCodeVsbl, setUserCodeVsbl] = useState (false)
|
||||
const { conflictActionIds } = useKeyboardShortcutSettings ()
|
||||
const {
|
||||
baseErrors: userBaseErrors,
|
||||
fieldErrors: userFieldErrors,
|
||||
clearValidationErrors: clearUserValidationErrors,
|
||||
applyValidationError: applyUserValidationError,
|
||||
} = useValidationErrors<UserFormField> ()
|
||||
const {
|
||||
baseErrors: settingsBaseErrors,
|
||||
fieldErrors: settingsFieldErrors,
|
||||
clearValidationErrors: clearSettingsValidationErrors,
|
||||
applyValidationError: applySettingsValidationError,
|
||||
} = useValidationErrors<SettingsFormField> ()
|
||||
const { baseErrors: userBaseErrors,
|
||||
fieldErrors: userFieldErrors,
|
||||
clearValidationErrors: clearUserValidationErrors,
|
||||
applyValidationError: applyUserValidationError } = useValidationErrors<UserFormField> ()
|
||||
const { baseErrors: settingsBaseErrors,
|
||||
fieldErrors: settingsFieldErrors,
|
||||
clearValidationErrors: clearSettingsValidationErrors,
|
||||
applyValidationError: applySettingsValidationError } =
|
||||
useValidationErrors<SettingsFormField> ()
|
||||
|
||||
const activeTab = useMemo<SettingsTab> (() => parseTab (location.search), [location.search])
|
||||
const selectedTheme = useMemo<ClientTheme> (
|
||||
() => getResolvedThemeFromSelection (draftActiveThemeId, draftCustomThemes),
|
||||
[draftActiveThemeId, draftCustomThemes],
|
||||
)
|
||||
[draftActiveThemeId, draftCustomThemes])
|
||||
const draftTagColours = selectedTheme.tokens.tagColours
|
||||
|
||||
const setActiveTab = (tab: SettingsTab) => {
|
||||
@@ -414,15 +398,15 @@ const SettingPage: FC<Props> = ({ user, setUser }) => {
|
||||
params.set ('tab', tab)
|
||||
navigate (
|
||||
`${ location.pathname }?${ params.toString () }`,
|
||||
{ replace: true },
|
||||
)
|
||||
{ replace: true })
|
||||
}
|
||||
|
||||
const settingsTabErrors = useMemo<Record<SettingsTab, boolean>> (() => ({
|
||||
account: Boolean (userFieldErrors.name?.length),
|
||||
theme: Boolean (settingsFieldErrors.theme?.length),
|
||||
keyboard: conflictActionIds.size > 0,
|
||||
}), [conflictActionIds.size, settingsFieldErrors.theme, userFieldErrors.name])
|
||||
const settingsTabErrors = useMemo<Record<SettingsTab, boolean>> (
|
||||
() => (
|
||||
{ account: Boolean (userFieldErrors.name?.length),
|
||||
theme: Boolean (settingsFieldErrors.theme?.length),
|
||||
keyboard: conflictActionIds.size > 0 }),
|
||||
[conflictActionIds.size, settingsFieldErrors.theme, userFieldErrors.name])
|
||||
|
||||
const applyDraftThemeSelection = (
|
||||
activeThemeId: ActiveThemeId,
|
||||
@@ -432,52 +416,40 @@ const SettingPage: FC<Props> = ({ user, setUser }) => {
|
||||
setDraftCustomThemes (customThemes)
|
||||
setDraftSettings (current => ({
|
||||
...current,
|
||||
theme: deriveUserThemeModeFromSelection (activeThemeId, customThemes),
|
||||
}))
|
||||
theme: deriveUserThemeModeFromSelection (activeThemeId, customThemes) }))
|
||||
applyThemeSelection (activeThemeId, customThemes)
|
||||
}
|
||||
|
||||
const ensureEditableCustomTheme = (): {
|
||||
activeThemeId: ActiveThemeId
|
||||
customThemes: Record<string, CustomClientTheme>
|
||||
} => {
|
||||
customThemes: Record<string, CustomClientTheme> } => {
|
||||
if (draftActiveThemeId !== 'system' && draftCustomThemes[draftActiveThemeId] != null)
|
||||
{
|
||||
return {
|
||||
activeThemeId: draftActiveThemeId,
|
||||
customThemes: draftCustomThemes,
|
||||
}
|
||||
return { activeThemeId: draftActiveThemeId,
|
||||
customThemes: draftCustomThemes }
|
||||
}
|
||||
|
||||
const customTheme = createCustomThemeFromBase (
|
||||
selectedTheme.baseTheme,
|
||||
{
|
||||
...selectedTheme.tokens,
|
||||
tagColours: { ...selectedTheme.tokens.tagColours },
|
||||
},
|
||||
)
|
||||
{ ...selectedTheme.tokens,
|
||||
tagColours: { ...selectedTheme.tokens.tagColours } })
|
||||
const nextCustomThemes = {
|
||||
...draftCustomThemes,
|
||||
[customTheme.id]: customTheme,
|
||||
}
|
||||
[customTheme.id]: customTheme }
|
||||
|
||||
return {
|
||||
activeThemeId: customTheme.id,
|
||||
customThemes: nextCustomThemes,
|
||||
}
|
||||
customThemes: nextCustomThemes }
|
||||
}
|
||||
|
||||
const handleEnsureEditableTheme = (): {
|
||||
activeThemeId: ActiveThemeId
|
||||
customThemes: Record<string, CustomClientTheme>
|
||||
} => {
|
||||
customThemes: Record<string, CustomClientTheme> } => {
|
||||
const editable = ensureEditableCustomTheme ()
|
||||
|
||||
if (editable.activeThemeId !== draftActiveThemeId
|
||||
|| editable.customThemes !== draftCustomThemes)
|
||||
{
|
||||
applyDraftThemeSelection (editable.activeThemeId, editable.customThemes)
|
||||
}
|
||||
applyDraftThemeSelection (editable.activeThemeId, editable.customThemes)
|
||||
|
||||
return editable
|
||||
}
|
||||
@@ -580,9 +552,9 @@ const SettingPage: FC<Props> = ({ user, setUser }) => {
|
||||
return
|
||||
|
||||
const customThemes = getClientCustomThemes ()
|
||||
const activeThemeId = hasStoredClientThemeSelection ()
|
||||
? getClientActiveThemeId ()
|
||||
: data.theme
|
||||
const activeThemeId = (hasStoredClientThemeSelection ()
|
||||
? getClientActiveThemeId ()
|
||||
: data.theme)
|
||||
const themeMode = deriveUserThemeModeFromSelection (activeThemeId, customThemes)
|
||||
|
||||
setDraftSettings ({ ...data, theme: themeMode })
|
||||
@@ -629,71 +601,62 @@ const SettingPage: FC<Props> = ({ user, setUser }) => {
|
||||
}
|
||||
}, [draftActiveThemeId, draftCustomThemes, savedActiveThemeId, savedCustomThemes])
|
||||
|
||||
const sectionProps: SharedSectionProps | null = user ? {
|
||||
user,
|
||||
name,
|
||||
onNameChange: setName,
|
||||
onInheritOpen: () => setInheritVsbl (true),
|
||||
onUserCodeOpen: () => setUserCodeVsbl (true),
|
||||
onUserSubmit: handleUserSubmit,
|
||||
userBaseErrors,
|
||||
userFieldErrors,
|
||||
draftActiveThemeId,
|
||||
draftCustomThemes,
|
||||
selectedTheme,
|
||||
draftTagColours,
|
||||
onThemeChange: themeId => {
|
||||
applyDraftThemeSelection (themeId, draftCustomThemes)
|
||||
},
|
||||
onEnsureEditableTheme: () => {
|
||||
handleEnsureEditableTheme ()
|
||||
},
|
||||
onTagColourChange: (category, colour) => {
|
||||
const editable = handleEnsureEditableTheme ()
|
||||
const editableTheme = editable.customThemes[editable.activeThemeId]
|
||||
const nextCustomThemes = {
|
||||
...editable.customThemes,
|
||||
[editable.activeThemeId]: {
|
||||
...editableTheme,
|
||||
tokens: {
|
||||
...editableTheme.tokens,
|
||||
tagColours: {
|
||||
...editableTheme.tokens.tagColours,
|
||||
[category]: colour,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
applyDraftThemeSelection (editable.activeThemeId, nextCustomThemes)
|
||||
},
|
||||
onResetAllTagColours: () => {
|
||||
if (selectedTheme.builtin || draftActiveThemeId === 'system')
|
||||
return
|
||||
const sectionProps: SharedSectionProps | null =
|
||||
user
|
||||
? { user,
|
||||
name,
|
||||
onNameChange: setName,
|
||||
onInheritOpen: () => setInheritVsbl (true),
|
||||
onUserCodeOpen: () => setUserCodeVsbl (true),
|
||||
onUserSubmit: handleUserSubmit,
|
||||
userBaseErrors,
|
||||
userFieldErrors,
|
||||
draftActiveThemeId,
|
||||
draftCustomThemes,
|
||||
selectedTheme,
|
||||
draftTagColours,
|
||||
onThemeChange: themeId => {
|
||||
applyDraftThemeSelection (themeId, draftCustomThemes)
|
||||
},
|
||||
onEnsureEditableTheme: () => {
|
||||
handleEnsureEditableTheme ()
|
||||
},
|
||||
onTagColourChange: (category, colour) => {
|
||||
const editable = handleEnsureEditableTheme ()
|
||||
const editableTheme = editable.customThemes[editable.activeThemeId]
|
||||
const nextCustomThemes = {
|
||||
...editable.customThemes,
|
||||
[editable.activeThemeId]: {
|
||||
...editableTheme,
|
||||
tokens: {
|
||||
...editableTheme.tokens,
|
||||
tagColours: {
|
||||
...editableTheme.tokens.tagColours,
|
||||
[category]: colour } } } }
|
||||
applyDraftThemeSelection (editable.activeThemeId, nextCustomThemes)
|
||||
},
|
||||
onResetAllTagColours: () => {
|
||||
if (selectedTheme.builtin || draftActiveThemeId === 'system')
|
||||
return
|
||||
|
||||
applyDraftThemeSelection (
|
||||
draftActiveThemeId,
|
||||
{
|
||||
...draftCustomThemes,
|
||||
[draftActiveThemeId]: {
|
||||
...draftCustomThemes[draftActiveThemeId],
|
||||
tokens: {
|
||||
...draftCustomThemes[draftActiveThemeId].tokens,
|
||||
tagColours: {
|
||||
...defaultThemeTagColoursFor (selectedTheme.baseTheme),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
)
|
||||
},
|
||||
onResetTagColour: category => {
|
||||
if (selectedTheme.builtin || draftActiveThemeId === 'system')
|
||||
return
|
||||
applyDraftThemeSelection (
|
||||
draftActiveThemeId,
|
||||
{
|
||||
...draftCustomThemes,
|
||||
[draftActiveThemeId]: {
|
||||
...draftCustomThemes[draftActiveThemeId],
|
||||
tokens: {
|
||||
...draftCustomThemes[draftActiveThemeId].tokens,
|
||||
tagColours: {
|
||||
...defaultThemeTagColoursFor (selectedTheme.baseTheme) } } } })
|
||||
},
|
||||
onResetTagColour: category => {
|
||||
if (selectedTheme.builtin || draftActiveThemeId === 'system')
|
||||
return
|
||||
|
||||
applyDraftThemeSelection (
|
||||
draftActiveThemeId,
|
||||
{
|
||||
...draftCustomThemes,
|
||||
applyDraftThemeSelection (
|
||||
draftActiveThemeId,
|
||||
{ ...draftCustomThemes,
|
||||
[draftActiveThemeId]: {
|
||||
...draftCustomThemes[draftActiveThemeId],
|
||||
tokens: {
|
||||
@@ -701,17 +664,13 @@ const SettingPage: FC<Props> = ({ user, setUser }) => {
|
||||
tagColours: {
|
||||
...draftCustomThemes[draftActiveThemeId].tokens.tagColours,
|
||||
[category]:
|
||||
defaultThemeTagColoursFor (selectedTheme.baseTheme)[category],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
)
|
||||
},
|
||||
onThemeSubmit: handleThemeSubmit,
|
||||
settingsBaseErrors,
|
||||
settingsFieldErrors,
|
||||
} : null
|
||||
defaultThemeTagColoursFor (
|
||||
selectedTheme.baseTheme)[category] } } } })
|
||||
},
|
||||
onThemeSubmit: handleThemeSubmit,
|
||||
settingsBaseErrors,
|
||||
settingsFieldErrors }
|
||||
: null
|
||||
|
||||
return (
|
||||
<MainArea>
|
||||
@@ -752,12 +711,11 @@ const SettingPage: FC<Props> = ({ user, setUser }) => {
|
||||
tabIndex={activeTab === tab.id ? 0 : -1}
|
||||
className={cn (
|
||||
'rounded-xl border px-4 py-3 text-left text-sm font-medium',
|
||||
activeTab === tab.id
|
||||
? ['border-slate-900 bg-slate-900 text-white',
|
||||
'dark:border-slate-100 dark:bg-slate-100 dark:text-slate-900']
|
||||
: ['border-slate-300 bg-white text-slate-700',
|
||||
'dark:border-slate-700 dark:bg-slate-900 dark:text-slate-100'],
|
||||
)}
|
||||
(activeTab === tab.id
|
||||
? ['border-slate-900 bg-slate-900 text-white',
|
||||
'dark:border-slate-100 dark:bg-slate-100 dark:text-slate-900']
|
||||
: ['border-slate-300 bg-white text-slate-700',
|
||||
'dark:border-slate-700 dark:bg-slate-900 dark:text-slate-100']))}
|
||||
onClick={() => setActiveTab (tab.id)}
|
||||
onKeyDown={handleTabKeyDown}>
|
||||
{tab.label}
|
||||
@@ -778,8 +736,7 @@ const SettingPage: FC<Props> = ({ user, setUser }) => {
|
||||
{activeTab === 'account' && <AccountSection {...sectionProps}/>}
|
||||
{activeTab === 'theme' && <ThemeSection {...sectionProps}/>}
|
||||
{activeTab === 'keyboard' && (
|
||||
<KeyboardSettingsSection sectionClassName={sectionClassName}/>
|
||||
)}
|
||||
<KeyboardSettingsSection sectionClassName={sectionClassName}/>)}
|
||||
</>)}
|
||||
</div>)}
|
||||
</div>
|
||||
@@ -799,4 +756,5 @@ const SettingPage: FC<Props> = ({ user, setUser }) => {
|
||||
</MainArea>)
|
||||
}
|
||||
|
||||
|
||||
export default SettingPage
|
||||
|
||||
新しい課題から参照
ユーザをブロックする