このコミットが含まれているのは:
2026-07-05 02:59:48 +09:00
コミット 95b4db1fc2
12個のファイルの変更1017行の追加82行の削除
+120
ファイルの表示
@@ -1,7 +1,9 @@
import { CATEGORIES } from '@/consts'
import { apiGet, apiPatch } from '@/lib/api'
import { DEFAULT_KEY_BINDINGS, normaliseKeyBinding } from '@/lib/keyboardShortcuts'
import type { Category, FetchPostsOrder, FetchTagsOrder } from '@/types'
import type { KeyBinding, ShortcutActionId } from '@/lib/keyboardShortcuts'
export type UserSettings = {
theme: 'system' | 'light' | 'dark'
@@ -61,6 +63,11 @@ type ClientListSettings = {
limit?: ClientListLimit
order?: string }
export type ClientKeyboardSettings = {
enabled?: boolean
bindings?: Partial<Record<ShortcutActionId, KeyBinding | null>>
}
export type ClientAppearanceSettings = {
activeThemeId?: ActiveThemeId
customThemes?: Record<string, CustomClientTheme>
@@ -80,6 +87,7 @@ export const DEFAULT_USER_SETTINGS: UserSettings = {
// Browser-local settings only. These are device or screen specific.
export type ClientSettings = {
appearance?: ClientAppearanceSettings
keyboard?: ClientKeyboardSettings
panes?: Record<string, ClientPaneSettings>
lists?: Partial<Record<ClientListKey, ClientListSettings>>
theatre?: {
@@ -295,6 +303,118 @@ const validListLimit = (value: unknown): ClientListLimit | null =>
value === 20 || value === 50 || value === 100 ? value : null
const normaliseKeyboardBindings = (
bindings: unknown,
): Partial<Record<ShortcutActionId, KeyBinding | null>> => {
if (!(bindings) || typeof bindings !== 'object')
return { }
return Object.keys (DEFAULT_KEY_BINDINGS).reduce<
Partial<Record<ShortcutActionId, KeyBinding | null>>
> (
(normalised, actionId) => {
const value = (bindings as Record<string, unknown>)[actionId]
if (value === null)
{
normalised[actionId as ShortcutActionId] = null
return normalised
}
const binding = normaliseKeyBinding (value)
if (binding != null)
normalised[actionId as ShortcutActionId] = binding
return normalised
},
{ },
)
}
export const getClientKeyboardSettings = (): ClientKeyboardSettings => {
const keyboard = loadClientSettings ().keyboard
return {
enabled: keyboard?.enabled !== false,
bindings: normaliseKeyboardBindings (keyboard?.bindings),
}
}
export const setClientKeyboardSettings = (
keyboard: ClientKeyboardSettings,
): ClientKeyboardSettings => {
const next: ClientKeyboardSettings = {
enabled: keyboard.enabled !== false,
bindings: normaliseKeyboardBindings (keyboard.bindings),
}
updateClientSettings (settings => ({
...settings,
keyboard: next,
}))
return next
}
export const getEffectiveKeyBindings = (
bindings: Partial<Record<ShortcutActionId, KeyBinding | null>> =
getClientKeyboardSettings ().bindings ?? { },
): Record<ShortcutActionId, KeyBinding | null> =>
Object.keys (DEFAULT_KEY_BINDINGS).reduce<Record<ShortcutActionId, KeyBinding | null>> (
(effectiveBindings, actionId) => {
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 },
)
export const setClientKeyBinding = (
actionId: ShortcutActionId,
binding: KeyBinding | null,
): ClientKeyboardSettings => {
const current = getClientKeyboardSettings ()
return setClientKeyboardSettings ({
...current,
bindings: {
...(current.bindings ?? { }),
[actionId]: binding,
},
})
}
export const resetClientKeyBinding = (
actionId: ShortcutActionId,
): ClientKeyboardSettings => {
const current = getClientKeyboardSettings ()
const nextBindings = { ...(current.bindings ?? { }) }
delete nextBindings[actionId]
return setClientKeyboardSettings ({
...current,
bindings: nextBindings,
})
}
export const resetAllClientKeyBindings = (): ClientKeyboardSettings => {
const current = getClientKeyboardSettings ()
return setClientKeyboardSettings ({
...current,
bindings: { },
})
}
const normaliseHexColour = (value: string): string | null =>
/^#[0-9a-fA-F]{6}$/.test (value) ? value.toLowerCase () : null