|
1 | | -import { type ChangeEventHandler, useCallback, useEffect, useMemo, useState } from 'react'; |
| 1 | +import { type ChangeEventHandler, useCallback, useEffect, useMemo, useRef, useState } from 'react'; |
2 | 2 | import { useTimeoutToggle } from '$hooks/useTimeoutToggle'; |
3 | 3 | import { copyToClipboard, downloadTextFile } from '$utils/dom'; |
4 | 4 | import { useQuery, useQueryClient } from '@tanstack/react-query'; |
@@ -214,6 +214,9 @@ export function ThemeCatalogSettings({ |
214 | 214 | const [browseOpen, setBrowseOpen] = useState(false); |
215 | 215 | const [importModalOpen, setImportModalOpen] = useState(false); |
216 | 216 |
|
| 217 | + const appearanceCatalogBrowseWasOpenRef = useRef(false); |
| 218 | + const tweakFavoritesSnapshotAtAppearanceCatalogOpenRef = useRef<Set<string>>(new Set()); |
| 219 | + |
217 | 220 | useEffect(() => { |
218 | 221 | if (isAppearanceMode) { |
219 | 222 | onBrowseOpenChange?.(browseOpen); |
@@ -248,6 +251,19 @@ export function ThemeCatalogSettings({ |
248 | 251 | 'themeChatAutoPreviewAnyUrl' |
249 | 252 | ); |
250 | 253 |
|
| 254 | + useEffect(() => { |
| 255 | + if (!isAppearanceMode) { |
| 256 | + appearanceCatalogBrowseWasOpenRef.current = false; |
| 257 | + return; |
| 258 | + } |
| 259 | + if (browseOpen && !appearanceCatalogBrowseWasOpenRef.current) { |
| 260 | + tweakFavoritesSnapshotAtAppearanceCatalogOpenRef.current = new Set( |
| 261 | + tweakFavorites.map((f) => f.fullUrl.trim()).filter(Boolean) |
| 262 | + ); |
| 263 | + } |
| 264 | + appearanceCatalogBrowseWasOpenRef.current = browseOpen; |
| 265 | + }, [browseOpen, isAppearanceMode, tweakFavorites]); |
| 266 | + |
251 | 267 | const [themeSearch, setThemeSearch] = useState(''); |
252 | 268 | const [tweakSearch, setTweakSearch] = useState(''); |
253 | 269 | const [kindFilter, setKindFilter] = useState<'all' | 'light' | 'dark'>('all'); |
@@ -779,7 +795,15 @@ export function ThemeCatalogSettings({ |
779 | 795 | }, [patchSettings]); |
780 | 796 |
|
781 | 797 | const setTweakApplied = useCallback( |
782 | | - async (fullUrl: string, apply: boolean, hint?: { displayName?: string; basename?: string }) => { |
| 798 | + async ( |
| 799 | + fullUrl: string, |
| 800 | + apply: boolean, |
| 801 | + hint?: { |
| 802 | + displayName?: string; |
| 803 | + basename?: string; |
| 804 | + pruneUnpinnedFavoriteOnDisable?: boolean; |
| 805 | + } |
| 806 | + ) => { |
783 | 807 | const trimmed = fullUrl.trim(); |
784 | 808 | if (!trimmed) return; |
785 | 809 |
|
@@ -811,10 +835,25 @@ export function ThemeCatalogSettings({ |
811 | 835 | }); |
812 | 836 | } else { |
813 | 837 | const nextEnabled = enabledTweakFullUrls.filter((u) => u !== trimmed); |
814 | | - patchSettings({ |
815 | | - themeRemoteEnabledTweakFullUrls: nextEnabled, |
816 | | - themeRemoteTweakFavorites: pruneTweakFavorites(tweakFavorites, nextEnabled), |
817 | | - }); |
| 838 | + if (hint?.pruneUnpinnedFavoriteOnDisable) { |
| 839 | + const enabledSet = new Set(nextEnabled); |
| 840 | + const inLibraryBeforeThisCatalogVisit = |
| 841 | + tweakFavoritesSnapshotAtAppearanceCatalogOpenRef.current; |
| 842 | + const nextTweakFavs = tweakFavorites.filter( |
| 843 | + (f) => |
| 844 | + f.pinned === true || |
| 845 | + enabledSet.has(f.fullUrl) || |
| 846 | + inLibraryBeforeThisCatalogVisit.has(f.fullUrl.trim()) |
| 847 | + ); |
| 848 | + patchSettings({ |
| 849 | + themeRemoteEnabledTweakFullUrls: nextEnabled, |
| 850 | + themeRemoteTweakFavorites: nextTweakFavs, |
| 851 | + }); |
| 852 | + } else { |
| 853 | + patchSettings({ |
| 854 | + themeRemoteEnabledTweakFullUrls: nextEnabled, |
| 855 | + }); |
| 856 | + } |
818 | 857 | } |
819 | 858 | }, |
820 | 859 | [enabledTweakFullUrls, patchSettings, prefetchFull, pruneTweakFavorites, tweakFavorites] |
@@ -1468,6 +1507,7 @@ export function ThemeCatalogSettings({ |
1468 | 1507 | setTweakApplied(row.fullUrl, v, { |
1469 | 1508 | displayName: row.displayName, |
1470 | 1509 | basename: row.basename, |
| 1510 | + pruneUnpinnedFavoriteOnDisable: true, |
1471 | 1511 | }) |
1472 | 1512 | } |
1473 | 1513 | /> |
|
0 commit comments