Skip to content

Commit 94489c2

Browse files
committed
feat(options): persist list sort mode in settings
1 parent 4d83a71 commit 94489c2

File tree

6 files changed

+72
-10
lines changed

6 files changed

+72
-10
lines changed

src/core/defaults.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { FolioStore } from './types';
1+
import { DEFAULT_SORT_MODE, type FolioStore } from './types';
22
import { DEFAULT_THEME } from '../shared/theme';
33

44
export const FOLIO_STORE_KEY = 'folio-store';
@@ -14,6 +14,7 @@ export function createDefaultStore(): FolioStore {
1414
iconVariant: 'classic',
1515
theme: DEFAULT_THEME,
1616
defaultStatus: 'unread',
17+
sortMode: DEFAULT_SORT_MODE,
1718
syncDirectory: null,
1819
lastSyncedAt: null,
1920
lastSyncError: null

src/core/repository.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import type {
77
FolioStatus,
88
FolioStore
99
} from './types';
10+
import { resolveSortMode } from './types';
1011
import { extractDomain, normalizeUrl } from './url';
1112
import { isSupportedLocale, writeStoredLocale } from '../shared/i18n/localeStore';
1213
import { getThemeIconVariant, resolveFolioTheme } from '../shared/theme';
@@ -59,6 +60,7 @@ function normalizeStore(store: FolioStore): FolioStore {
5960
theme,
6061
defaultStatus:
6162
store.settings.defaultStatus === 'reading' ? 'reading' : 'unread',
63+
sortMode: resolveSortMode(store.settings.sortMode),
6264
syncDirectory:
6365
typeof store.settings.syncDirectory === 'string'
6466
? store.settings.syncDirectory
@@ -173,6 +175,7 @@ function sanitizeImportedStore(raw: unknown, current: FolioStore): FolioStore |
173175
rawSettings.defaultStatus === 'unread' || rawSettings.defaultStatus === 'reading'
174176
? rawSettings.defaultStatus
175177
: current.settings.defaultStatus;
178+
const sortMode = resolveSortMode(rawSettings.sortMode ?? current.settings.sortMode);
176179
const theme = resolveFolioTheme(rawSettings.theme ?? current.settings.theme);
177180
const iconVariant = getThemeIconVariant(theme);
178181

@@ -186,6 +189,7 @@ function sanitizeImportedStore(raw: unknown, current: FolioStore): FolioStore |
186189
iconVariant,
187190
theme,
188191
defaultStatus,
192+
sortMode,
189193
syncDirectory:
190194
typeof current.settings.syncDirectory === 'string'
191195
? current.settings.syncDirectory
@@ -241,6 +245,7 @@ export async function getStore(): Promise<FolioStore> {
241245
'iconVariant',
242246
'theme',
243247
'defaultStatus',
248+
'sortMode',
244249
'syncDirectory',
245250
'lastSyncedAt',
246251
'lastSyncError'
@@ -439,6 +444,9 @@ export async function commit(mutation: FolioMutation): Promise<CommitResult> {
439444
if (mutation.payload.defaultStatus !== undefined) {
440445
next.settings.defaultStatus = mutation.payload.defaultStatus;
441446
}
447+
if (mutation.payload.sortMode !== undefined) {
448+
next.settings.sortMode = mutation.payload.sortMode;
449+
}
442450

443451
break;
444452
}

src/core/selectors.ts

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,7 @@
1-
import type { FolioItem, FolioStatus, FolioStore } from './types';
1+
import type { FolioItem, FolioStatus, FolioStore, SortMode } from './types';
22
import { normalizeUrl } from './url';
33

4-
export type SortMode =
5-
| 'saved_desc'
6-
| 'saved_asc'
7-
| 'domain_asc'
8-
| 'title_asc'
9-
| 'status';
4+
export type { SortMode } from './types';
105

116
export interface StatusCounts {
127
total: number;

src/core/sync/types.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ export const BACKUP_JSON_SCHEMA: Record<string, unknown> = {
7373
'iconVariant',
7474
'theme',
7575
'defaultStatus',
76+
'sortMode',
7677
'syncDirectory',
7778
'lastSyncedAt',
7879
'lastSyncError'
@@ -82,6 +83,9 @@ export const BACKUP_JSON_SCHEMA: Record<string, unknown> = {
8283
iconVariant: { enum: ['classic', 'mono'] },
8384
theme: { enum: FOLIO_THEMES },
8485
defaultStatus: { enum: ['unread', 'reading'] },
86+
sortMode: {
87+
enum: ['saved_desc', 'saved_asc', 'domain_asc', 'title_asc', 'status']
88+
},
8589
syncDirectory: { type: ['string', 'null'] },
8690
lastSyncedAt: { type: ['number', 'null'] },
8791
lastSyncError: { type: ['string', 'null'] }

src/core/types.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,28 @@ import type { FolioIconVariant } from '../shared/icons';
33
import type { FolioTheme } from '../shared/theme';
44

55
export type FolioStatus = 'unread' | 'reading' | 'done';
6+
export type SortMode =
7+
| 'saved_desc'
8+
| 'saved_asc'
9+
| 'domain_asc'
10+
| 'title_asc'
11+
| 'status';
12+
13+
export const DEFAULT_SORT_MODE: SortMode = 'saved_desc';
14+
15+
export function isSortMode(value: unknown): value is SortMode {
16+
return (
17+
value === 'saved_desc' ||
18+
value === 'saved_asc' ||
19+
value === 'domain_asc' ||
20+
value === 'title_asc' ||
21+
value === 'status'
22+
);
23+
}
24+
25+
export function resolveSortMode(value: unknown): SortMode {
26+
return isSortMode(value) ? value : DEFAULT_SORT_MODE;
27+
}
628

729
export interface FolioItem {
830
id: string;
@@ -23,6 +45,7 @@ export interface FolioSettings {
2345
iconVariant: FolioIconVariant;
2446
theme: FolioTheme;
2547
defaultStatus: 'unread' | 'reading';
48+
sortMode: SortMode;
2649
syncDirectory: string | null;
2750
lastSyncedAt: number | null;
2851
lastSyncError: string | null;
@@ -95,6 +118,7 @@ export type FolioMutation =
95118
iconVariant?: FolioIconVariant;
96119
theme?: FolioTheme;
97120
defaultStatus?: 'unread' | 'reading';
121+
sortMode?: SortMode;
98122
};
99123
}
100124
| {

src/options/App.tsx

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,13 @@ import {
6363
clearBackupDirectoryHandle,
6464
saveBackupDirectoryHandle
6565
} from '../core/sync/handleStore';
66-
import type { FolioItem, FolioMutation, FolioStatus, FolioStore } from '../core/types';
66+
import {
67+
isSortMode,
68+
type FolioItem,
69+
type FolioMutation,
70+
type FolioStatus,
71+
type FolioStore
72+
} from '../core/types';
6773

6874
type ViewKey = 'all' | FolioStatus | 'settings';
6975

@@ -309,9 +315,33 @@ export default function App(): ReactElement {
309315
setLocale(nextLocale);
310316
setThemeInput(nextTheme);
311317
setDefaultStatusInput(nextStore.settings.defaultStatus);
318+
setSortMode(nextStore.settings.sortMode);
312319
applyDocumentTheme(nextTheme);
313320
}
314321

322+
async function handleSortModeChange(value: string): Promise<void> {
323+
if (!isSortMode(value)) {
324+
return;
325+
}
326+
327+
if (value === sortMode) {
328+
return;
329+
}
330+
331+
setSortMode(value);
332+
const settingsResult = await commit({
333+
type: 'updateSettings',
334+
payload: {
335+
sortMode: value
336+
}
337+
});
338+
339+
if (!settingsResult.ok) {
340+
setNotice({ level: 'error', text: t('options.updateFailed') });
341+
await refresh();
342+
}
343+
}
344+
315345
const displayItems = useMemo(() => {
316346
if (!store) return [];
317347

@@ -1282,7 +1312,7 @@ export default function App(): ReactElement {
12821312
wrapperClassName="w-[min(22vw,180px)] min-w-[140px]"
12831313
leftIcon={<ArrowUpDown className="h-4 w-4" strokeWidth={1.9} />}
12841314
value={sortMode}
1285-
onChange={(event) => setSortMode(event.target.value as SortMode)}
1315+
onChange={(event) => void handleSortModeChange(event.target.value)}
12861316
>
12871317
<option value="saved_desc">{t('options.sortNewest')}</option>
12881318
<option value="saved_asc">{t('options.sortOldest')}</option>

0 commit comments

Comments
 (0)