diff --git a/AGENTS.md b/AGENTS.md
index 2c1f926..5917b9c 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -376,6 +376,23 @@ const value =
short object literals, or short callback bodies that already fit the local
line-length and delimiter rules. Expanding compact local code without a
readability need is a minor style violation.
+- In TypeScript and TSX, treat short object literals, short returned objects,
+ short typed object shapes, and short function-call object arguments as
+ compact associative syntax by default. If they fit locally, keep the opening
+ `{` on the same line as the first property and keep the closing `}` on the
+ same line as the final property. Do not explode them into vertical
+ Prettier-style blocks without a concrete readability or line-length reason.
+- In TypeScript and TSX, when a compact associative form is broken across two
+ lines, keep the opening `{` with the first property and the closing `}` with
+ the final property. A shape like `{\n key: value,\n}` is wrong even when
+ line length would permit it.
+- In TypeScript and TSX, when a short call such as `apiGet<...> (...)`,
+ `apiPatch<...> (...)`, `setState (...)`, `updateClientSettings (...)`, or
+ `window.dispatchEvent (...)` already fits within the local style, do not
+ add extra vertical layers around the object argument or callback body.
+- In TypeScript and TSX, after editing a file, inspect the file tail and
+ remove meaningless blank lines before `export default` or the end of file.
+ A stray empty line before `export default` is a minor style offence.
- Use correct British English spelling for new identifiers, filenames,
component names, helper names, comments, and developer-facing prose unless
editing an already established American-English API that must keep its
@@ -470,6 +487,92 @@ setDirtyStates (
Penalty: minor offence when semantics stay intact. It is not necessarily
broken, but it ignores the repository's compact associative style.
+#### Prettier-style exploded object literals that should stay compact
+
+Bad:
+
+```ts
+const next = {
+ enabled: keyboard?.enabled !== false,
+ bindings: normaliseKeyboardBindings (keyboard?.bindings),
+}
+```
+
+Good:
+
+```ts
+const next = {
+ enabled: keyboard?.enabled !== false,
+ bindings: normaliseKeyboardBindings (keyboard?.bindings) }
+```
+
+Also good when short enough:
+
+```ts
+const next = { enabled: keyboard?.enabled !== false,
+ bindings: normaliseKeyboardBindings (keyboard?.bindings) }
+```
+
+Rule: for compact associative syntax, keep `{` with the first property and `}`
+with the final property unless line length truly forces a different shape.
+Do not mechanically apply the common Prettier block form.
+Penalty: medium-severity offence. The code still runs, but it violates a core
+repository formatting habit that must be preserved consistently.
+
+#### Exploded object arguments inside short calls
+
+Bad:
+
+```ts
+updateClientSettings (settings => ({
+ ...settings,
+ keyboard: next,
+}))
+```
+
+Good:
+
+```ts
+updateClientSettings (settings => ({
+ ...settings,
+ keyboard: next }))
+```
+
+Rule: a call-expression closing `)` must not drift onto its own line, and a
+short object argument should not be exploded more than necessary. Keep the
+callback's returned object compact when it fits.
+Penalty: medium-severity offence. This usually means the edit was formatted
+mechanically instead of by reading the local style.
+
+#### Stray blank line before `export default`
+
+Bad:
+
+```ts
+const Component: FC = () => {
+ return
+}
+
+
+export default Component
+```
+
+Good:
+
+```ts
+const Component: FC = () => {
+ return
+}
+
+export default Component
+```
+
+Rule: do not leave an extra empty line between the last top-level declaration
+and `export default` unless some surrounding file structure genuinely requires
+visual separation.
+Penalty: minor offence. It is small, but it is easy to avoid and should not
+recur.
+
### Frontend delimiter decision table
Use this table before accepting any edited TypeScript or TSX hunk. The table is
diff --git a/frontend/src/lib/settings.ts b/frontend/src/lib/settings.ts
index 3714bcf..8b943e2 100644
--- a/frontend/src/lib/settings.ts
+++ b/frontend/src/lib/settings.ts
@@ -152,10 +152,9 @@ export type ClientSettings = {
keyboard?: ClientKeyboardSettings
panes?: Record
lists?: Partial>
- theatre?: {
- layoutMode?: TheatreLayoutMode
- tagFlow?: TheatreTagFlow }
- gekanator?: { backgroundMotion?: GekanatorBackgroundMotionMode }
+ theatre?: { layoutMode?: TheatreLayoutMode
+ tagFlow?: TheatreTagFlow }
+ gekanator?: { backgroundMotion?: GekanatorBackgroundMotionMode }
reducedMotion?: string
embedAutoLoad?: string
thumbnailMode?: string }
@@ -273,23 +272,20 @@ export const DARK_THEME_TOKENS: ThemeTokens = {
topNavMenuLink: '#93c5fd',
tagColours: DEFAULT_DARK_THEME_TAG_COLOURS }
export const BUILTIN_THEMES: Record = {
- light: {
- id: 'light',
- name: 'ライト・モード',
- builtin: true,
- baseTheme: 'light',
- tokens: LIGHT_THEME_TOKENS },
- dark: {
- id: 'dark',
- name: 'ダーク・モード',
- builtin: true,
- baseTheme: 'dark',
- tokens: DARK_THEME_TOKENS } }
+ light: { id: 'light',
+ name: 'ライト・モード',
+ builtin: true,
+ baseTheme: 'light',
+ tokens: LIGHT_THEME_TOKENS },
+ dark: { id: 'dark',
+ name: 'ダーク・モード',
+ builtin: true,
+ baseTheme: 'dark',
+ tokens: DARK_THEME_TOKENS } }
const LEGACY_THEATRE_LAYOUT_STORAGE_KEY = 'theatre-layout-mode'
const LEGACY_THEATRE_TAG_FLOW_STORAGE_KEY = 'theatre-tag-flow'
-const LEGACY_GEKANATOR_BACKGROUND_MOTION_STORAGE_KEY =
- 'gekanator:background-motion:v1'
+const LEGACY_GEKANATOR_BACKGROUND_MOTION_STORAGE_KEY = 'gekanator:background-motion:v1'
const LEGACY_MIGRATED_THEME_ID = 'custom:legacy-migrated'
@@ -304,18 +300,16 @@ const createCustomThemeId = (): `custom:${ string }` => {
export const fetchUserSettings = async (): Promise => {
const raw = await apiGet<{
- theme: UserSettings['theme']
+ theme: UserSettings['theme']
auto_fetch_title: UserSettings['autoFetchTitle']
auto_fetch_thumbnail: UserSettings['autoFetchThumbnail']
- wiki_editor_mode: UserSettings['wikiEditorMode']
- }> ('/users/settings')
+ wiki_editor_mode: UserSettings['wikiEditorMode'] }> ('/users/settings')
return {
theme: raw.theme,
autoFetchTitle: raw.auto_fetch_title,
autoFetchThumbnail: raw.auto_fetch_thumbnail,
- wikiEditorMode: raw.wiki_editor_mode,
- }
+ wikiEditorMode: raw.wiki_editor_mode }
}
@@ -326,15 +320,13 @@ export const updateUserSettings = async (
theme: UserSettings['theme']
auto_fetch_title: UserSettings['autoFetchTitle']
auto_fetch_thumbnail: UserSettings['autoFetchThumbnail']
- wiki_editor_mode: UserSettings['wikiEditorMode']
- }> ('/users/settings', settings)
+ wiki_editor_mode: UserSettings['wikiEditorMode'] }> ('/users/settings', settings)
return {
theme: raw.theme,
autoFetchTitle: raw.auto_fetch_title,
autoFetchThumbnail: raw.auto_fetch_thumbnail,
- wikiEditorMode: raw.wiki_editor_mode,
- }
+ wikiEditorMode: raw.wiki_editor_mode }
}
@@ -364,8 +356,7 @@ export const saveClientSettings = (settings: ClientSettings): void => {
if (typeof window !== 'undefined')
{
window.dispatchEvent (new CustomEvent (CLIENT_SETTINGS_EVENT, {
- detail: settings,
- }))
+ detail: settings }))
}
}
@@ -428,25 +419,22 @@ const normaliseKeyboardBindings = (
if (!(bindings) || typeof bindings !== 'object')
return { }
- return Object.keys (DEFAULT_KEY_BINDINGS).reduce<
- Partial>
- > (
- (normalised, actionId) => {
- const value = (bindings as Record)[actionId]
- if (value === null)
- {
- normalised[actionId as ShortcutActionId] = null
- return normalised
- }
+ return (
+ Object.keys (DEFAULT_KEY_BINDINGS)
+ .reduce>> ((normalised, actionId) => {
+ const value = (bindings as Record)[actionId]
+ if (value === null)
+ {
+ normalised[actionId as ShortcutActionId] = null
+ return normalised
+ }
- const binding = normaliseKeyBinding (value)
- if (binding != null)
- normalised[actionId as ShortcutActionId] = binding
+ const binding = normaliseKeyBinding (value)
+ if (binding != null)
+ normalised[actionId as ShortcutActionId] = binding
- return normalised
- },
- { },
- )
+ return normalised
+ }, { }))
}
@@ -455,8 +443,7 @@ export const getClientKeyboardSettings = (): ClientKeyboardSettings => {
return {
enabled: keyboard?.enabled !== false,
- bindings: normaliseKeyboardBindings (keyboard?.bindings),
- }
+ bindings: normaliseKeyboardBindings (keyboard?.bindings) }
}
@@ -495,10 +482,7 @@ export const applyClientAnimationMode = (mode: ClientAnimationMode): void => {
export const setClientAnimationMode = (
animation: ClientAnimationMode,
): ClientBehaviorSettings =>
- setClientBehaviorSettings ({
- ...getClientBehaviorSettings (),
- animation,
- })
+ setClientBehaviorSettings ({ ...getClientBehaviorSettings (), animation })
export const getClientLinkPreloadMode = (): ClientLinkPreloadMode =>
@@ -509,10 +493,7 @@ export const getClientLinkPreloadMode = (): ClientLinkPreloadMode =>
export const setClientLinkPreloadMode = (
linkPreload: ClientLinkPreloadMode,
): ClientBehaviorSettings =>
- setClientBehaviorSettings ({
- ...getClientBehaviorSettings (),
- linkPreload,
- })
+ setClientBehaviorSettings ({ ...getClientBehaviorSettings (), linkPreload })
export const getClientTagRelationDisplayMode = (): ClientTagRelationDisplayMode =>
@@ -523,10 +504,7 @@ export const getClientTagRelationDisplayMode = (): ClientTagRelationDisplayMode
export const setClientTagRelationDisplayMode = (
tagRelationDisplay: ClientTagRelationDisplayMode,
): ClientBehaviorSettings =>
- setClientBehaviorSettings ({
- ...getClientBehaviorSettings (),
- tagRelationDisplay,
- })
+ setClientBehaviorSettings ({ ...getClientBehaviorSettings (), tagRelationDisplay })
export const getClientEmbedAutoLoadMode = (): ClientEmbedAutoLoadMode =>
@@ -538,10 +516,7 @@ export const getClientEmbedAutoLoadMode = (): ClientEmbedAutoLoadMode =>
export const setClientEmbedAutoLoadMode = (
embedAutoLoad: ClientEmbedAutoLoadMode,
): ClientBehaviorSettings =>
- setClientBehaviorSettings ({
- ...getClientBehaviorSettings (),
- embedAutoLoad,
- })
+ setClientBehaviorSettings ({ ...getClientBehaviorSettings (), embedAutoLoad })
export const getClientThumbnailMode = (): ClientThumbnailMode =>
@@ -553,10 +528,7 @@ export const getClientThumbnailMode = (): ClientThumbnailMode =>
export const setClientThumbnailMode = (
thumbnailMode: ClientThumbnailMode,
): ClientBehaviorSettings =>
- setClientBehaviorSettings ({
- ...getClientBehaviorSettings (),
- thumbnailMode,
- })
+ setClientBehaviorSettings ({ ...getClientBehaviorSettings (), thumbnailMode })
export const getClientBehaviorSettings = (): ClientBehaviorSettings => ({
@@ -564,8 +536,7 @@ export const getClientBehaviorSettings = (): ClientBehaviorSettings => ({
linkPreload: getClientLinkPreloadMode (),
tagRelationDisplay: getClientTagRelationDisplayMode (),
embedAutoLoad: getClientEmbedAutoLoadMode (),
- thumbnailMode: getClientThumbnailMode (),
-})
+ thumbnailMode: getClientThumbnailMode () })
export const setClientBehaviorSettings = (
@@ -574,30 +545,21 @@ export const setClientBehaviorSettings = (
const next: ClientBehaviorSettings = {
animation: (
normaliseAnimationMode (behavior.animation)
- ?? getClientAnimationMode ()
- ),
+ ?? getClientAnimationMode ()),
linkPreload: (
normaliseLinkPreloadMode (behavior.linkPreload)
- ?? getClientLinkPreloadMode ()
- ),
+ ?? getClientLinkPreloadMode ()),
tagRelationDisplay: (
normaliseTagRelationDisplayMode (behavior.tagRelationDisplay)
- ?? getClientTagRelationDisplayMode ()
- ),
+ ?? getClientTagRelationDisplayMode ()),
embedAutoLoad: (
normaliseEmbedAutoLoadMode (behavior.embedAutoLoad)
- ?? getClientEmbedAutoLoadMode ()
- ),
+ ?? getClientEmbedAutoLoadMode ()),
thumbnailMode: (
normaliseThumbnailMode (behavior.thumbnailMode)
- ?? getClientThumbnailMode ()
- ),
- }
+ ?? getClientThumbnailMode ()) }
- updateClientSettings (settings => ({
- ...settings,
- behavior: next,
- }))
+ updateClientSettings (settings => ({ ...settings, behavior: next }))
applyClientAnimationMode (next.animation ?? 'normal')
return next
}
@@ -608,13 +570,9 @@ export const setClientKeyboardSettings = (
): ClientKeyboardSettings => {
const next: ClientKeyboardSettings = {
enabled: keyboard.enabled !== false,
- bindings: normaliseKeyboardBindings (keyboard.bindings),
- }
+ bindings: normaliseKeyboardBindings (keyboard.bindings) }
- updateClientSettings (settings => ({
- ...settings,
- keyboard: next,
- }))
+ updateClientSettings (settings => ({ ...settings, keyboard: next }))
return next
}
@@ -626,15 +584,14 @@ export const getEffectiveKeyBindings = (
): Record =>
Object.keys (DEFAULT_KEY_BINDINGS).reduce> (
(effectiveBindings, actionId) => {
- const key = actionId as ShortcutActionId
- effectiveBindings[key] =
- Object.prototype.hasOwnProperty.call (bindings, key)
- ? bindings[key] ?? null
- : DEFAULT_KEY_BINDINGS[key]
- return effectiveBindings
+ const key = actionId as ShortcutActionId
+ effectiveBindings[key] =
+ Object.prototype.hasOwnProperty.call (bindings, key)
+ ? bindings[key] ?? null
+ : DEFAULT_KEY_BINDINGS[key]
+ return effectiveBindings
},
- { ...DEFAULT_KEY_BINDINGS },
- )
+ { ...DEFAULT_KEY_BINDINGS })
export const setClientKeyBinding = (
@@ -645,11 +602,7 @@ export const setClientKeyBinding = (
return setClientKeyboardSettings ({
...current,
- bindings: {
- ...(current.bindings ?? { }),
- [actionId]: binding,
- },
- })
+ bindings: { ...(current.bindings ?? { }), [actionId]: binding } })
}
@@ -660,20 +613,14 @@ export const resetClientKeyBinding = (
const nextBindings = { ...(current.bindings ?? { }) }
delete nextBindings[actionId]
- return setClientKeyboardSettings ({
- ...current,
- bindings: nextBindings,
- })
+ return setClientKeyboardSettings ({ ...current, bindings: nextBindings })
}
export const resetAllClientKeyBindings = (): ClientKeyboardSettings => {
const current = getClientKeyboardSettings ()
- return setClientKeyboardSettings ({
- ...current,
- bindings: { },
- })
+ return setClientKeyboardSettings ({ ...current, bindings: { } })
}
@@ -696,21 +643,20 @@ const themeCopyName = (baseTheme: BuiltinThemeId): string =>
const appearanceFromSettings = (): ClientAppearanceSettings =>
loadClientSettings ().appearance ?? { }
+
let cachedUserThemeSlots: UserThemeSlotMap = { }
export const hasStoredClientThemeSelection = (): boolean => {
const appearance = appearanceFromSettings ()
- return (
- appearance.themeMode != null
- || appearance.activeLightThemeSlotNo != null
- || appearance.activeDarkThemeSlotNo != null
- || appearance.activeThemeSlot != null
- || appearance.activeThemeId != null
- || appearance.customThemes != null
- || appearance.theme != null
- || appearance.tagColours != null
- )
+ return (appearance.themeMode != null
+ || appearance.activeLightThemeSlotNo != null
+ || appearance.activeDarkThemeSlotNo != null
+ || appearance.activeThemeSlot != null
+ || appearance.activeThemeId != null
+ || appearance.customThemes != null
+ || appearance.theme != null
+ || appearance.tagColours != null)
}
@@ -723,12 +669,10 @@ const mixHexColour = (
const src = source.slice (1)
const dst = target.slice (1)
const channels = [0, 2, 4].map (offset => {
- const srcValue = parseInt (src.slice (offset, offset + 2), 16)
- const dstValue = parseInt (dst.slice (offset, offset + 2), 16)
- const mixed = Math.round (
- srcValue + (dstValue - srcValue) * clampedRatio,
- )
- return mixed.toString (16).padStart (2, '0')
+ const srcValue = parseInt (src.slice (offset, offset + 2), 16)
+ const dstValue = parseInt (dst.slice (offset, offset + 2), 16)
+ const mixed = Math.round (srcValue + (dstValue - srcValue) * clampedRatio)
+ return mixed.toString (16).padStart (2, '0')
})
return `#${ channels.join ('') }`
@@ -749,10 +693,8 @@ const legacyThemeSlotSelection = (): ThemeSlotSelection => {
return 'builtin:light'
if (appearance.activeThemeId === 'dark')
return 'builtin:dark'
- if (
- typeof appearance.activeThemeId === 'string'
- && customThemes[appearance.activeThemeId] != null
- )
+ if (typeof appearance.activeThemeId === 'string'
+ && customThemes[appearance.activeThemeId] != null)
return `builtin:${ customThemes[appearance.activeThemeId].baseTheme }`
if (appearance.theme === 'light')
return 'builtin:light'
@@ -764,11 +706,9 @@ const legacyThemeSlotSelection = (): ThemeSlotSelection => {
const legacyThemeMode = (): ClientThemeMode =>
normaliseThemeMode (appearanceFromSettings ().theme)
- ?? (
- legacyThemeSlotSelection () === 'system'
+ ?? (legacyThemeSlotSelection () === 'system'
? 'system'
- : (baseThemeOfSelection (legacyThemeSlotSelection ()) ?? 'system')
- )
+ : (baseThemeOfSelection (legacyThemeSlotSelection ()) ?? 'system'))
const legacyThemeSlotNoFor = (
@@ -778,7 +718,7 @@ const legacyThemeSlotNoFor = (
if (isUserThemeSlotSelection (legacySelection))
{
- const [_, selectionBaseTheme, slotNo] = legacySelection.split (':')
+ const [, selectionBaseTheme, slotNo] = legacySelection.split (':')
if (selectionBaseTheme === baseTheme)
return Number (slotNo) as UserThemeSlotNo
}
@@ -798,20 +738,12 @@ export const setClientActiveThemeSlot = (
): void => {
updateClientSettings (settings => ({
...settings,
- appearance: {
- ...(settings.appearance ?? { }),
- activeThemeSlot,
- },
- }))
+ appearance: { ...(settings.appearance ?? { }), activeThemeSlot } }))
}
-export const getClientThemeMode = (): UserSettings['theme'] => {
- return (
- normaliseThemeMode (appearanceFromSettings ().themeMode)
- ?? legacyThemeMode ()
- )
-}
+export const getClientThemeMode = (): UserSettings['theme'] =>
+ normaliseThemeMode (appearanceFromSettings ().themeMode) ?? legacyThemeMode ()
export const getClientActiveLightThemeSlotNo = (): UserThemeSlotNo =>
@@ -827,10 +759,9 @@ export const getClientActiveDarkThemeSlotNo = (): UserThemeSlotNo =>
export const setClientThemeAppearance = (
{ themeMode,
activeLightThemeSlotNo,
- activeDarkThemeSlotNo }: {
- themeMode: ClientThemeMode
- activeLightThemeSlotNo: UserThemeSlotNo
- activeDarkThemeSlotNo: UserThemeSlotNo },
+ activeDarkThemeSlotNo }: { themeMode: ClientThemeMode
+ activeLightThemeSlotNo: UserThemeSlotNo
+ activeDarkThemeSlotNo: UserThemeSlotNo },
): void => {
updateClientSettings (settings => ({
...settings,
@@ -838,9 +769,7 @@ export const setClientThemeAppearance = (
...(settings.appearance ?? { }),
themeMode,
activeLightThemeSlotNo,
- activeDarkThemeSlotNo,
- },
- }))
+ activeDarkThemeSlotNo } }))
}
@@ -848,8 +777,7 @@ export const setClientThemeMode = (theme: UserSettings['theme']): void => {
setClientThemeAppearance ({
themeMode: theme,
activeLightThemeSlotNo: getClientActiveLightThemeSlotNo (),
- activeDarkThemeSlotNo: getClientActiveDarkThemeSlotNo (),
- })
+ activeDarkThemeSlotNo: getClientActiveDarkThemeSlotNo () })
}
@@ -887,15 +815,14 @@ const normaliseThemeTagColours = (
): ThemeTagColours =>
CATEGORIES.reduce (
(colours, category) => {
- const candidate = input?.[category]
- colours[category] =
- typeof candidate === 'string' && normaliseHexColour (candidate) != null
- ? candidate
- : fallback[category]
- return colours
+ const candidate = input?.[category]
+ colours[category] =
+ typeof candidate === 'string' && normaliseHexColour (candidate) != null
+ ? candidate
+ : fallback[category]
+ return colours
},
- { ...fallback },
- )
+ { ...fallback })
const normaliseThemeTokenValue = (
@@ -916,9 +843,9 @@ const cssColourFromThemeToken = (
if (normalisedHex != null)
return normalisedHex
- return /^-?\d+(?:\.\d+)?\s+\d+(?:\.\d+)?%\s+\d+(?:\.\d+)?%$/.test (value)
- ? `hsl(${ value })`
- : fallback
+ return (/^-?\d+(?:\.\d+)?\s+\d+(?:\.\d+)?%\s+\d+(?:\.\d+)?%$/.test (value)
+ ? `hsl(${ value })`
+ : fallback)
}
@@ -928,16 +855,12 @@ const clamp = (value: number, min: number, max: number): number =>
const parseHslComponents = (
value: string,
-): { h: number
- s: number
- l: number } | null => {
- const raw = value.startsWith ('hsl(') && value.endsWith (')')
- ? value.slice (4, -1)
- : value
+): { h: number; s: number; l: number } | null => {
+ const raw = (value.startsWith ('hsl(') && value.endsWith (')')
+ ? value.slice (4, -1)
+ : value)
const match =
- raw.match (
- /^(-?\d+(?:\.\d+)?)\s+(\d+(?:\.\d+)?)%\s+(\d+(?:\.\d+)?)%$/,
- )
+ raw.match (/^(-?\d+(?:\.\d+)?)\s+(\d+(?:\.\d+)?)%\s+(\d+(?:\.\d+)?)%$/)
if (match == null)
return null
@@ -945,8 +868,7 @@ const parseHslComponents = (
return {
h: Number (match[1]),
s: Number (match[2]),
- l: Number (match[3]),
- }
+ l: Number (match[3]) }
}
@@ -987,9 +909,7 @@ const deriveMutedForeground = (
l: clamp (
foregroundHsl.l + (backgroundHsl.l - foregroundHsl.l) * .35,
0,
- 100,
- ),
- })
+ 100) })
}
@@ -1006,11 +926,9 @@ const deriveTopNavTokens = (
mobileActiveBackground: (
baseTheme === 'dark'
? editable.activeBackground
- : editable.rootBackgroundDesktop
- ),
+ : editable.rootBackgroundDesktop),
brandLink: editable.brandLink,
- menuLink: link,
-})
+ menuLink: link })
export const buildThemeTokens = (
@@ -1047,41 +965,33 @@ export const buildThemeTokens = (
tokens.topNavRootBackgroundMobile
?? legacyTopNavTokens.topNavRootBackgroundMobile
?? legacyTopNavTokens.topNavBackground,
- fallback.topNavRootBackgroundMobile,
- )
+ fallback.topNavRootBackgroundMobile)
const topNavRootBackgroundDesktop = normaliseTopNavColourValue (
tokens.topNavRootBackgroundDesktop
?? legacyTopNavTokens.topNavRootBackgroundDesktop
?? legacyTopNavTokens.topNavBackground,
- fallback.topNavRootBackgroundDesktop,
- )
+ fallback.topNavRootBackgroundDesktop)
const topNavActiveBackground = normaliseTopNavColourValue (
tokens.topNavActiveBackground
?? legacyTopNavTokens.topNavActiveBackground
?? legacyTopNavTokens.topNavHighlightBackground
?? legacyTopNavTokens.topNavHighlightBackground,
- fallback.topNavActiveBackground,
- )
+ fallback.topNavActiveBackground)
const topNavBrandLink = normaliseTopNavColourValue (
tokens.topNavBrandLink
?? legacyTopNavTokens.topNavBrandLink
?? legacyTopNavTokens.topNavLink,
- fallback.topNavBrandLink,
- )
+ fallback.topNavBrandLink)
const topNavMenuLink = cssColourFromThemeToken (
link,
- fallback.topNavMenuLink,
- )
+ fallback.topNavMenuLink)
const resolvedTopNav = deriveTopNavTokens (
baseTheme,
- {
- rootBackgroundMobile: topNavRootBackgroundMobile,
- rootBackgroundDesktop: topNavRootBackgroundDesktop,
- activeBackground: topNavActiveBackground,
- brandLink: topNavBrandLink,
- },
- topNavMenuLink,
- )
+ { rootBackgroundMobile: topNavRootBackgroundMobile,
+ rootBackgroundDesktop: topNavRootBackgroundDesktop,
+ activeBackground: topNavActiveBackground,
+ brandLink: topNavBrandLink },
+ topNavMenuLink)
return {
background,
@@ -1098,8 +1008,7 @@ export const buildThemeTokens = (
mutedForeground: deriveMutedForeground (
foreground,
background,
- fallback.mutedForeground,
- ),
+ fallback.mutedForeground),
accent,
accentForeground: readableForegroundFor (accent),
destructive: fallback.destructive,
@@ -1115,17 +1024,14 @@ export const buildThemeTokens = (
topNavMobileActiveBackground: resolvedTopNav.mobileActiveBackground,
topNavBrandLink: resolvedTopNav.brandLink,
topNavMenuLink: resolvedTopNav.menuLink,
- tagColours: normaliseThemeTagColours (tokens.tagColours, fallback.tagColours),
- }
+ tagColours: normaliseThemeTagColours (tokens.tagColours, fallback.tagColours) }
}
const normaliseTopNavColourValue = (
value: unknown,
fallback: string,
-): string => {
- return cssColourFromThemeToken (value, fallback)
-}
+): string => cssColourFromThemeToken (value, fallback)
const normaliseThemeTokens = (
@@ -1161,39 +1067,36 @@ const normaliseThemeTokens = (
return buildThemeTokens (
baseTheme,
- {
- ...tokens,
- background,
- foreground,
- card,
- muted,
- primary,
- accent,
- border,
- link,
- topNavRootBackgroundMobile:
- tokens.topNavRootBackgroundMobile
- ?? legacyTopNavTokens.topNavRootBackgroundMobile
- ?? legacyTopNavTokens.topNavBackground,
- topNavRootBackgroundDesktop:
- tokens.topNavRootBackgroundDesktop
- ?? legacyTopNavTokens.topNavRootBackgroundDesktop
- ?? legacyTopNavTokens.topNavBackground,
- topNavActiveBackground:
- tokens.topNavActiveBackground
- ?? legacyTopNavTokens.topNavActiveBackground
- ?? legacyTopNavTokens.topNavHighlightBackground,
- topNavBrandLink:
- tokens.topNavBrandLink
- ?? legacyTopNavTokens.topNavBrandLink
- ?? legacyTopNavTokens.topNavLink,
- topNavMenuLink:
- tokens.topNavMenuLink
- ?? legacyTopNavTokens.topNavMenuLink
- ?? link,
- tagColours: normaliseThemeTagColours (tokens.tagColours, fallback.tagColours),
- },
- )
+ { ...tokens,
+ background,
+ foreground,
+ card,
+ muted,
+ primary,
+ accent,
+ border,
+ link,
+ topNavRootBackgroundMobile:
+ tokens.topNavRootBackgroundMobile
+ ?? legacyTopNavTokens.topNavRootBackgroundMobile
+ ?? legacyTopNavTokens.topNavBackground,
+ topNavRootBackgroundDesktop:
+ tokens.topNavRootBackgroundDesktop
+ ?? legacyTopNavTokens.topNavRootBackgroundDesktop
+ ?? legacyTopNavTokens.topNavBackground,
+ topNavActiveBackground:
+ tokens.topNavActiveBackground
+ ?? legacyTopNavTokens.topNavActiveBackground
+ ?? legacyTopNavTokens.topNavHighlightBackground,
+ topNavBrandLink:
+ tokens.topNavBrandLink
+ ?? legacyTopNavTokens.topNavBrandLink
+ ?? legacyTopNavTokens.topNavLink,
+ topNavMenuLink:
+ tokens.topNavMenuLink
+ ?? legacyTopNavTokens.topNavMenuLink
+ ?? link,
+ tagColours: normaliseThemeTagColours (tokens.tagColours, fallback.tagColours) })
}
@@ -1252,8 +1155,7 @@ export const getDefaultUserThemeSlot = (
): UserThemeSlot => ({
baseTheme,
slotNo,
- tokens: normaliseThemeTokens ({ }, baseTheme),
-})
+ tokens: normaliseThemeTokens ({ }, baseTheme) })
const normaliseUserThemeSlot = (
@@ -1266,12 +1168,10 @@ const normaliseUserThemeSlot = (
const baseTheme = slot.baseTheme
const slotNo = slot.slotNo
- if (
- baseTheme == null
+ if (baseTheme == null
|| !(isBuiltinThemeId (baseTheme))
|| slotNo == null
- || !(USER_THEME_SLOT_NOS.includes (slotNo as UserThemeSlotNo))
- )
+ || !(USER_THEME_SLOT_NOS.includes (slotNo as UserThemeSlotNo)))
return null
return {
@@ -1279,8 +1179,7 @@ const normaliseUserThemeSlot = (
slotNo: slotNo as UserThemeSlotNo,
tokens: normaliseThemeTokens (slot.tokens, baseTheme),
createdAt: typeof slot.createdAt === 'string' ? slot.createdAt : undefined,
- updatedAt: typeof slot.updatedAt === 'string' ? slot.updatedAt : undefined,
- }
+ updatedAt: typeof slot.updatedAt === 'string' ? slot.updatedAt : undefined }
}
@@ -1292,8 +1191,7 @@ export const normaliseUserThemeSlots = (
map[getUserThemeSlotSelection (slot.baseTheme, slot.slotNo)] = slot
return map
},
- { },
- )
+ { })
const normaliseCustomTheme = (
@@ -1306,13 +1204,11 @@ const normaliseCustomTheme = (
const id = typeof theme.id === 'string' ? theme.id : null
const name = typeof theme.name === 'string' ? theme.name : null
const baseTheme = typeof theme.baseTheme === 'string' ? theme.baseTheme : null
- if (
- id == null
+ if (id == null
|| !(isCustomThemeId (id))
|| name == null
|| baseTheme == null
- || !(isBuiltinThemeId (baseTheme))
- )
+ || !(isBuiltinThemeId (baseTheme)))
return null
return {
@@ -1321,21 +1217,16 @@ const normaliseCustomTheme = (
builtin: false,
baseTheme,
tokens: normaliseThemeTokens (
- {
- ...(theme.tokens && typeof theme.tokens === 'object'
- ? theme.tokens as Partial
- : { }),
- tagColours: (
- theme.tokens
- && typeof theme.tokens === 'object'
- && 'tagColours' in theme.tokens
- )
- ? (theme.tokens as { tagColours?: Partial }).tagColours
- : theme.tagColours as Partial | undefined,
- },
- baseTheme,
- ),
- }
+ { ...(theme.tokens && typeof theme.tokens === 'object'
+ ? theme.tokens as Partial
+ : { }),
+ tagColours: (
+ (theme.tokens
+ && typeof theme.tokens === 'object'
+ && 'tagColours' in theme.tokens)
+ ? (theme.tokens as { tagColours?: Partial }).tagColours
+ : theme.tagColours as Partial | undefined) },
+ baseTheme) }
}
@@ -1347,13 +1238,12 @@ export const getClientCustomThemes = (): Record => {
{
return Object.entries (customThemes).reduce> (
(themes, [key, rawTheme]) => {
- const theme = normaliseCustomTheme (rawTheme)
- if (theme != null)
- themes[key] = theme
- return themes
+ const theme = normaliseCustomTheme (rawTheme)
+ if (theme != null)
+ themes[key] = theme
+ return themes
},
- { },
- )
+ { })
}
const legacyTagColours = appearance.tagColours
@@ -1371,11 +1261,7 @@ export const getClientCustomThemes = (): Record => {
...(baseTheme === 'dark' ? DARK_THEME_TOKENS : LIGHT_THEME_TOKENS),
tagColours: normaliseThemeTagColours (
legacyTagColours,
- defaultThemeTagColoursFor (baseTheme),
- ),
- },
- },
- }
+ defaultThemeTagColoursFor (baseTheme)) } } }
}
@@ -1385,12 +1271,11 @@ export const fetchUserThemeSlots = async (): Promise => {
slotNo: UserThemeSlotNo
tokens: ThemeTokens
createdAt: string
- updatedAt: string
- }>> ('/users/theme_slots')
+ updatedAt: string }>> ('/users/theme_slots')
- return raw
- .map (slot => normaliseUserThemeSlot (slot))
- .filter ((slot): slot is UserThemeSlot => slot != null)
+ return (raw
+ .map (slot => normaliseUserThemeSlot (slot))
+ .filter ((slot): slot is UserThemeSlot => slot != null))
}
@@ -1404,8 +1289,7 @@ export const upsertUserThemeSlot = async (
slotNo: UserThemeSlotNo
tokens: ThemeTokens
createdAt: string
- updatedAt: string
- }> (`/users/theme_slots/${ baseTheme }/${ slotNo }`, { tokens })
+ updatedAt: string }> (`/users/theme_slots/${ baseTheme }/${ slotNo }`, { tokens })
const slot = normaliseUserThemeSlot (raw)
if (slot == null)
@@ -1427,10 +1311,9 @@ export const getCachedUserThemeSlots = (): UserThemeSlotMap =>
export const resolveDisplayedTheme = (
{ themeMode,
activeLightThemeSlotNo,
- activeDarkThemeSlotNo }: {
- themeMode: ClientThemeMode
- activeLightThemeSlotNo: UserThemeSlotNo
- activeDarkThemeSlotNo: UserThemeSlotNo },
+ activeDarkThemeSlotNo }: { themeMode: ClientThemeMode
+ activeLightThemeSlotNo: UserThemeSlotNo
+ activeDarkThemeSlotNo: UserThemeSlotNo },
themeSlots: UserThemeSlotMap = getCachedUserThemeSlots (),
): ResolvedDisplayedTheme => {
const baseTheme = resolveThemeMode (themeMode)
@@ -1445,9 +1328,8 @@ export const resolveDisplayedTheme = (
baseTheme,
selection,
slotNo,
- tokens: themeSlots[selection]?.tokens
- ?? getDefaultUserThemeSlot (baseTheme, slotNo).tokens,
- }
+ tokens: (themeSlots[selection]?.tokens
+ ?? getDefaultUserThemeSlot (baseTheme, slotNo).tokens) }
}
@@ -1464,28 +1346,21 @@ export const getClientActiveThemeId = (): ActiveThemeId => {
const appearance = appearanceFromSettings ()
const customThemes = getClientCustomThemes ()
- if (
- typeof appearance.activeThemeId === 'string'
- && (
- appearance.activeThemeId === 'system'
+ if (typeof appearance.activeThemeId === 'string'
+ && (appearance.activeThemeId === 'system'
|| isBuiltinThemeId (appearance.activeThemeId)
- || customThemes[appearance.activeThemeId] != null
- )
- )
+ || customThemes[appearance.activeThemeId] != null))
return appearance.activeThemeId
- if (
- Object.keys (customThemes).length > 0
+ if (Object.keys (customThemes).length > 0
&& appearance.tagColours != null
- && Object.keys (appearance.tagColours).length > 0
- )
+ && Object.keys (appearance.tagColours).length > 0)
return LEGACY_MIGRATED_THEME_ID
- if (typeof appearance.theme === 'string' && (
- appearance.theme === 'system'
- || appearance.theme === 'light'
- || appearance.theme === 'dark'
- ))
+ if (typeof appearance.theme === 'string'
+ && (appearance.theme === 'system'
+ || appearance.theme === 'light'
+ || appearance.theme === 'dark'))
return appearance.theme
return DEFAULT_USER_SETTINGS.theme
@@ -1532,8 +1407,7 @@ export const resolveThemeFromSlotSelection = (
selection,
baseTheme,
builtin: true,
- tokens: BUILTIN_THEMES[baseTheme].tokens,
- }
+ tokens: BUILTIN_THEMES[baseTheme].tokens }
}
if (isBuiltinThemeSlotSelection (selection))
@@ -1543,8 +1417,7 @@ export const resolveThemeFromSlotSelection = (
selection,
baseTheme,
builtin: true,
- tokens: BUILTIN_THEMES[baseTheme].tokens,
- }
+ tokens: BUILTIN_THEMES[baseTheme].tokens }
}
const baseTheme = baseThemeOfSelection (selection) ?? 'light'
@@ -1552,9 +1425,8 @@ export const resolveThemeFromSlotSelection = (
selection,
baseTheme,
builtin: false,
- tokens: themeSlots[selection]?.tokens
- ?? getDefaultUserThemeSlot (baseTheme, slotNoOfSelection (selection)).tokens,
- }
+ tokens: (themeSlots[selection]?.tokens
+ ?? getDefaultUserThemeSlot (baseTheme, slotNoOfSelection (selection)).tokens) }
}
@@ -1576,21 +1448,15 @@ export const createCustomThemeFromBase = (
name: themeCopyName (baseTheme),
builtin: false,
baseTheme,
- tokens: tokens ?? {
- ...(baseTheme === 'dark' ? DARK_THEME_TOKENS : LIGHT_THEME_TOKENS),
- },
- }
+ tokens: tokens ?? { ...(baseTheme === 'dark' ? DARK_THEME_TOKENS : LIGHT_THEME_TOKENS) } }
}
export const getClientThemeTagColours = (
activeThemeId: ActiveThemeId = getClientActiveThemeId (),
customThemes: Record = getClientCustomThemes (),
-): ThemeTagColours => {
- return {
- ...getResolvedThemeFromSelection (activeThemeId, customThemes).tokens.tagColours,
- }
-}
+): ThemeTagColours =>
+ ({ ...getResolvedThemeFromSelection (activeThemeId, customThemes).tokens.tagColours })
export const setClientAppearanceThemes = (
@@ -1604,9 +1470,7 @@ export const setClientAppearanceThemes = (
activeThemeId,
customThemes,
theme: undefined,
- tagColours: undefined,
- },
- }))
+ tagColours: undefined } }))
}
@@ -1620,17 +1484,10 @@ export const setClientThemeTagColours = (
setClientAppearanceThemes (
activeThemeId,
- {
- ...customThemes,
- [activeThemeId]: {
- ...customThemes[activeThemeId],
- tokens: {
- ...customThemes[activeThemeId].tokens,
- tagColours,
- },
- },
- },
- )
+ { ...customThemes,
+ [activeThemeId]: {
+ ...customThemes[activeThemeId],
+ tokens: { ...customThemes[activeThemeId].tokens, tagColours } } })
}
@@ -1647,12 +1504,11 @@ export const applyThemeTagColours = (tagColours: ThemeTagColours): void => {
const root = document.documentElement
CATEGORIES.forEach (category => {
- const colour = tagColours[category]
- root.style.setProperty (`--tag-colour-${ category }`, colour)
- root.style.setProperty (
- `--tag-colour-${ category }-hover`,
- mixHexColour (colour, '#ffffff', .18),
- )
+ const colour = tagColours[category]
+ root.style.setProperty (`--tag-colour-${ category }`, colour)
+ root.style.setProperty (
+ `--tag-colour-${ category }-hover`,
+ mixHexColour (colour, '#ffffff', .18))
})
}
@@ -1680,38 +1536,14 @@ export const applyThemeTokens = (tokens: ThemeTokens): void => {
root.style.setProperty ('--input', tokens.input)
root.style.setProperty ('--ring', tokens.ring)
root.style.setProperty ('--theme-link', tokens.link)
- root.style.setProperty (
- '--top-nav-root-bg-mobile',
- tokens.topNavRootBackgroundMobile,
- )
- root.style.setProperty (
- '--top-nav-root-bg-desktop',
- tokens.topNavRootBackgroundDesktop,
- )
- root.style.setProperty (
- '--top-nav-active-bg',
- tokens.topNavActiveBackground,
- )
- root.style.setProperty (
- '--top-nav-submenu-bg',
- tokens.topNavSubmenuBackground,
- )
- root.style.setProperty (
- '--top-nav-mobile-menu-bg',
- tokens.topNavRootBackgroundMobile,
- )
- root.style.setProperty (
- '--top-nav-mobile-active-bg',
- tokens.topNavMobileActiveBackground,
- )
- root.style.setProperty (
- '--top-nav-brand-link',
- tokens.topNavBrandLink,
- )
- root.style.setProperty (
- '--top-nav-menu-link',
- tokens.topNavMenuLink,
- )
+ root.style.setProperty ('--top-nav-root-bg-mobile', tokens.topNavRootBackgroundMobile)
+ root.style.setProperty ('--top-nav-root-bg-desktop', tokens.topNavRootBackgroundDesktop)
+ root.style.setProperty ('--top-nav-active-bg', tokens.topNavActiveBackground)
+ root.style.setProperty ('--top-nav-submenu-bg', tokens.topNavSubmenuBackground)
+ root.style.setProperty ('--top-nav-mobile-menu-bg', tokens.topNavRootBackgroundMobile)
+ root.style.setProperty ('--top-nav-mobile-active-bg', tokens.topNavMobileActiveBackground)
+ root.style.setProperty ('--top-nav-brand-link', tokens.topNavBrandLink)
+ root.style.setProperty ('--top-nav-menu-link', tokens.topNavMenuLink)
applyThemeTagColours (tokens.tagColours)
}
@@ -1730,17 +1562,14 @@ export const applyThemeSelection = (
export const applyThemeAppearanceState = (
{ themeMode,
activeLightThemeSlotNo,
- activeDarkThemeSlotNo }: {
- themeMode: ClientThemeMode
- activeLightThemeSlotNo: UserThemeSlotNo
- activeDarkThemeSlotNo: UserThemeSlotNo },
+ activeDarkThemeSlotNo }: { themeMode: ClientThemeMode
+ activeLightThemeSlotNo: UserThemeSlotNo
+ activeDarkThemeSlotNo: UserThemeSlotNo },
themeSlots: UserThemeSlotMap = getCachedUserThemeSlots (),
): void => {
- const theme = resolveDisplayedTheme ({
- themeMode,
- activeLightThemeSlotNo,
- activeDarkThemeSlotNo,
- }, themeSlots)
+ const theme = resolveDisplayedTheme ({ themeMode,
+ activeLightThemeSlotNo,
+ activeDarkThemeSlotNo }, themeSlots)
applyThemeMode (theme.baseTheme)
applyThemeTokens (theme.tokens)
@@ -1753,8 +1582,7 @@ export const applyClientAppearance = (
applyThemeAppearanceState ({
themeMode: getClientThemeMode (),
activeLightThemeSlotNo: getClientActiveLightThemeSlotNo (),
- activeDarkThemeSlotNo: getClientActiveDarkThemeSlotNo (),
- }, themeSlots)
+ activeDarkThemeSlotNo: getClientActiveDarkThemeSlotNo () }, themeSlots)
}
@@ -1786,20 +1614,17 @@ export const setClientListSettings = (
[listKey]: {
...(settings.lists?.[listKey] ?? { }),
...(limit == null ? { } : { limit }),
- ...(order == null ? { } : { order }),
- },
- },
- }))
+ ...(order == null ? { } : { order }) } } }))
}
const legacyTheatreLayoutMode = (): TheatreLayoutMode | null => {
const value = localStorage.getItem (LEGACY_THEATRE_LAYOUT_STORAGE_KEY)
- return (
- value === 'threeColumns'
- || value === 'tagsBottom'
- || value === 'commentsBottom'
- ) ? value : null
+ return ((value === 'threeColumns'
+ || value === 'tagsBottom'
+ || value === 'commentsBottom')
+ ? value
+ : null)
}
@@ -1841,11 +1666,10 @@ export const setClientTheatreTagFlow = (tagFlow: TheatreTagFlow): void => {
}
-export const getClientGekanatorBackgroundMotion =
- (): GekanatorBackgroundMotionMode =>
- loadClientSettings ().gekanator?.backgroundMotion
- ?? legacyGekanatorBackgroundMotion ()
- ?? 'on'
+export const getClientGekanatorBackgroundMotion = (): GekanatorBackgroundMotionMode =>
+ loadClientSettings ().gekanator?.backgroundMotion
+ ?? legacyGekanatorBackgroundMotion ()
+ ?? 'on'
export const setClientGekanatorBackgroundMotion = (
@@ -1853,8 +1677,7 @@ export const setClientGekanatorBackgroundMotion = (
): void => {
updateClientSettings (settings => ({
...settings,
- gekanator: { ...(settings.gekanator ?? { }), backgroundMotion },
- }))
+ gekanator: { ...(settings.gekanator ?? { }), backgroundMotion } }))
}
@@ -1880,11 +1703,7 @@ export const setClientPaneWidthPx = (
...(settings.panes?.[paneKey] ?? { }),
widthPxByBreakpoint: {
...(settings.panes?.[paneKey]?.widthPxByBreakpoint ?? { }),
- [breakpoint]: widthPx,
- },
- },
- },
- }))
+ [breakpoint]: widthPx } } } }))
}
@@ -1898,8 +1717,5 @@ export const setClientPaneCollapsed = (
...(settings.panes ?? { }),
[paneKey]: {
...(settings.panes?.[paneKey] ?? { }),
- collapsed,
- },
- },
- }))
+ collapsed } } }))
}
diff --git a/frontend/src/pages/users/SettingPage.tsx b/frontend/src/pages/users/SettingPage.tsx
index 12b796d..de45233 100644
--- a/frontend/src/pages/users/SettingPage.tsx
+++ b/frontend/src/pages/users/SettingPage.tsx
@@ -1445,4 +1445,5 @@ const SettingPage: FC = ({ user, setUser }) => {
)
}
+
export default SettingPage