このコミットが含まれているのは:
@@ -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 }`.
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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,8 +16,7 @@ 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,
|
||||||
@@ -31,25 +28,23 @@ import {
|
|||||||
getClientCustomThemes,
|
getClientCustomThemes,
|
||||||
getResolvedThemeFromSelection,
|
getResolvedThemeFromSelection,
|
||||||
setClientAppearanceThemes,
|
setClientAppearanceThemes,
|
||||||
updateUserSettings,
|
updateUserSettings } from '@/lib/settings'
|
||||||
} 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,
|
UserSettings } from '@/lib/settings'
|
||||||
} 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,8 +217,8 @@ const AccountSection: FC<SharedSectionProps> = ({
|
|||||||
</section>)
|
</section>)
|
||||||
|
|
||||||
|
|
||||||
const ThemeSection: FC<SharedSectionProps> = ({
|
const ThemeSection: FC<SharedSectionProps> = (
|
||||||
draftActiveThemeId,
|
{ draftActiveThemeId,
|
||||||
draftCustomThemes,
|
draftCustomThemes,
|
||||||
selectedTheme,
|
selectedTheme,
|
||||||
draftTagColours,
|
draftTagColours,
|
||||||
@@ -241,8 +229,8 @@ const ThemeSection: FC<SharedSectionProps> = ({
|
|||||||
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,
|
applyValidationError: applyUserValidationError } = useValidationErrors<UserFormField> ()
|
||||||
} = useValidationErrors<UserFormField> ()
|
const { baseErrors: settingsBaseErrors,
|
||||||
const {
|
|
||||||
baseErrors: settingsBaseErrors,
|
|
||||||
fieldErrors: settingsFieldErrors,
|
fieldErrors: settingsFieldErrors,
|
||||||
clearValidationErrors: clearSettingsValidationErrors,
|
clearValidationErrors: clearSettingsValidationErrors,
|
||||||
applyValidationError: applySettingsValidationError,
|
applyValidationError: applySettingsValidationError } =
|
||||||
} = useValidationErrors<SettingsFormField> ()
|
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),
|
() => (
|
||||||
|
{ account: Boolean (userFieldErrors.name?.length),
|
||||||
theme: Boolean (settingsFieldErrors.theme?.length),
|
theme: Boolean (settingsFieldErrors.theme?.length),
|
||||||
keyboard: conflictActionIds.size > 0,
|
keyboard: conflictActionIds.size > 0 }),
|
||||||
}), [conflictActionIds.size, settingsFieldErrors.theme, userFieldErrors.name])
|
[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,8 +601,9 @@ 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
|
||||||
|
? { user,
|
||||||
name,
|
name,
|
||||||
onNameChange: setName,
|
onNameChange: setName,
|
||||||
onInheritOpen: () => setInheritVsbl (true),
|
onInheritOpen: () => setInheritVsbl (true),
|
||||||
@@ -659,11 +632,7 @@ const SettingPage: FC<Props> = ({ user, setUser }) => {
|
|||||||
...editableTheme.tokens,
|
...editableTheme.tokens,
|
||||||
tagColours: {
|
tagColours: {
|
||||||
...editableTheme.tokens.tagColours,
|
...editableTheme.tokens.tagColours,
|
||||||
[category]: colour,
|
[category]: colour } } } }
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
applyDraftThemeSelection (editable.activeThemeId, nextCustomThemes)
|
applyDraftThemeSelection (editable.activeThemeId, nextCustomThemes)
|
||||||
},
|
},
|
||||||
onResetAllTagColours: () => {
|
onResetAllTagColours: () => {
|
||||||
@@ -679,12 +648,7 @@ const SettingPage: FC<Props> = ({ user, setUser }) => {
|
|||||||
tokens: {
|
tokens: {
|
||||||
...draftCustomThemes[draftActiveThemeId].tokens,
|
...draftCustomThemes[draftActiveThemeId].tokens,
|
||||||
tagColours: {
|
tagColours: {
|
||||||
...defaultThemeTagColoursFor (selectedTheme.baseTheme),
|
...defaultThemeTagColoursFor (selectedTheme.baseTheme) } } } })
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
onResetTagColour: category => {
|
onResetTagColour: category => {
|
||||||
if (selectedTheme.builtin || draftActiveThemeId === 'system')
|
if (selectedTheme.builtin || draftActiveThemeId === 'system')
|
||||||
@@ -692,8 +656,7 @@ const SettingPage: FC<Props> = ({ user, setUser }) => {
|
|||||||
|
|
||||||
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,
|
onThemeSubmit: handleThemeSubmit,
|
||||||
settingsBaseErrors,
|
settingsBaseErrors,
|
||||||
settingsFieldErrors,
|
settingsFieldErrors }
|
||||||
} : null
|
: 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
|
||||||
|
|||||||
新しい課題から参照
ユーザをブロックする