Skip to content

Commit 7018341

Browse files
committed
update theme cache
1 parent 337ef7e commit 7018341

4 files changed

Lines changed: 59 additions & 45 deletions

File tree

app/src/contexts/Theme.tsx

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react'
22
import { Theme } from '../types/Theme'
3-
import { usePreference } from './Preference'
3+
import { usePreference, type Preference } from './Preference'
4+
import { usePersistent } from '../hooks/usePersistent'
45
import { Themes } from '../data/themes'
56
import { ThemeProvider as BaseThemeProvider, CfmActionsProvider, migrateTheme } from '@concrnt/ui'
67
import { useClient } from './Client'
@@ -17,6 +18,24 @@ interface Props {
1718
children: React.ReactNode
1819
}
1920

21+
// 前回解決されたテーマのlocalStorageキャッシュ。ThemeProviderが解決のたびに書き、
22+
// client構築前(CachedThemeProvider)とカスタムテーマの非同期ロード完了までのつなぎ
23+
// (ThemeProvider自身のフォールバック)が読む
24+
const CACHED_THEME_KEY = 'cachedTheme'
25+
26+
// clientなしで前回のテーマを適用する軽量版Provider。起動時ローディングなど
27+
// ThemeProviderの外側で使う。キャッシュ未生成時(初回起動)はpreferenceの
28+
// テーマ名をビルトインから引き、それも無ければblue
29+
export const CachedThemeProvider = (props: { children: React.ReactNode }) => {
30+
const [cachedPref] = usePersistent<Preference>('preference')
31+
const [cachedTheme] = usePersistent<Theme>(CACHED_THEME_KEY)
32+
return (
33+
<BaseThemeProvider theme={cachedTheme ?? Themes[cachedPref?.themeName ?? ''] ?? Themes.blue}>
34+
{props.children}
35+
</BaseThemeProvider>
36+
)
37+
}
38+
2039
interface ThemeLibraryState {
2140
customThemes: Record<string, Theme>
2241
reloadThemes: () => Promise<void>
@@ -35,13 +54,16 @@ export const ThemeProvider = (props: Props) => {
3554
const { client } = useClient()
3655
const [themeName, setThemeName] = usePreference('themeName')
3756
const [customThemes, setCustomThemes] = useState<Record<string, Theme>>({})
38-
const theme = props.theme ?? customThemes[themeName] ?? Themes[themeName] ?? Themes.blue
57+
// カスタムテーマはロード完了までcustomThemesに入らないため、その間は前回キャッシュで
58+
// つなぐ(blueに落とすとローディング画面からの切替時に一瞬デフォルトテーマがチラつく)
59+
const [cachedTheme] = usePersistent<Theme>(CACHED_THEME_KEY)
60+
const theme = props.theme ?? customThemes[themeName] ?? Themes[themeName] ?? cachedTheme ?? Themes.blue
3961

40-
// 次回起動時のCachedThemeProvider用に、解決できたテーマをキャッシュする。
41-
// カスタムテーマはロード完了前は解決できないため、未解決のままblueを書き込まないよう条件付き
62+
// 解決できたテーマをキャッシュする。カスタムテーマはロード完了前は解決できないため、
63+
// 未解決のままblueを書き込まないよう条件付き
4264
useEffect(() => {
4365
const resolved = customThemes[themeName] ?? Themes[themeName]
44-
if (resolved) localStorage.setItem('cachedTheme', JSON.stringify(resolved))
66+
if (resolved) localStorage.setItem(CACHED_THEME_KEY, JSON.stringify(resolved))
4567
}, [customThemes, themeName])
4668

4769
const reloadThemes = useCallback(async () => {

app/src/main.tsx

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ import { ScannerProvider } from './contexts/Scanner'
88

99
import { LoadingFull } from './components/LoadingFull'
1010
import { ClientProvider, useClientSetupProgress } from './contexts/Client'
11-
import { ThemeProvider } from './contexts/Theme'
12-
import { PreferenceProvider, type Preference } from './contexts/Preference'
11+
import { CachedThemeProvider, ThemeProvider } from './contexts/Theme'
12+
import { PreferenceProvider } from './contexts/Preference'
1313
import { OverlayProvider } from './contexts/Overlay'
1414
import { ComposerProvider } from './contexts/Composer'
1515
import { MediaViewerProvider } from './contexts/MediaViewer'
@@ -24,23 +24,7 @@ import { KeyboardProvider } from './contexts/Keyboard'
2424
import { BackHandlerProvider } from './contexts/BackHandler'
2525
import { OverlayStackBackBridge } from './components/OverlayStackBackBridge'
2626
import { AgeGateProvider } from './contexts/AgeGate'
27-
import { CssVar, OverlayStackProvider, Text, ThemeProvider as BaseThemeProvider } from '@concrnt/ui'
28-
import { Themes } from './data/themes'
29-
import { type Theme } from './types/Theme'
30-
import { usePersistent } from './hooks/usePersistent'
31-
import { type ReactNode } from 'react'
32-
33-
// 設定(cckv)ロード前でも、前回解決されたテーマのキャッシュ(cachedTheme)から前回のテーマを引く。
34-
// キャッシュ未生成時はpreferenceのテーマ名をビルトインから引き、それも無ければblue
35-
const CachedThemeProvider = ({ children }: { children: ReactNode }) => {
36-
const [cachedPref] = usePersistent<Preference>('preference')
37-
const [cachedTheme] = usePersistent<Theme>('cachedTheme')
38-
return (
39-
<BaseThemeProvider theme={cachedTheme ?? Themes[cachedPref?.themeName ?? ''] ?? Themes.blue}>
40-
{children}
41-
</BaseThemeProvider>
42-
)
43-
}
27+
import { CssVar, OverlayStackProvider, Text } from '@concrnt/ui'
4428

4529
const ClientLoadingScreen = () => {
4630
const progress = useClientSetupProgress()

web/src/contexts/Theme.tsx

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react'
22
import { Theme } from '../types/Theme'
3-
import { usePreference } from './Preference'
3+
import { usePreference, type Preference } from './Preference'
4+
import { usePersistent } from '../hooks/usePersistent'
45
import { Themes } from '../data/themes'
56
import { ThemeProvider as BaseThemeProvider, CfmActionsProvider, migrateTheme } from '@concrnt/ui'
67
import { useClient } from './Client'
@@ -17,6 +18,24 @@ interface Props {
1718
children: React.ReactNode
1819
}
1920

21+
// 前回解決されたテーマのlocalStorageキャッシュ。ThemeProviderが解決のたびに書き、
22+
// client構築前(CachedThemeProvider)とカスタムテーマの非同期ロード完了までのつなぎ
23+
// (ThemeProvider自身のフォールバック)が読む
24+
const CACHED_THEME_KEY = 'cachedTheme'
25+
26+
// clientなしで前回のテーマを適用する軽量版Provider。起動時ローディングなど
27+
// ThemeProviderの外側で使う。キャッシュ未生成時(初回起動)はpreferenceの
28+
// テーマ名をビルトインから引き、それも無ければblue
29+
export const CachedThemeProvider = (props: { children: React.ReactNode }) => {
30+
const [cachedPref] = usePersistent<Preference>('preference')
31+
const [cachedTheme] = usePersistent<Theme>(CACHED_THEME_KEY)
32+
return (
33+
<BaseThemeProvider theme={cachedTheme ?? Themes[cachedPref?.themeName ?? ''] ?? Themes.blue}>
34+
{props.children}
35+
</BaseThemeProvider>
36+
)
37+
}
38+
2039
interface ThemeLibraryState {
2140
customThemes: Record<string, Theme>
2241
reloadThemes: () => Promise<void>
@@ -35,13 +54,16 @@ export const ThemeProvider = (props: Props) => {
3554
const { client } = useClient()
3655
const [themeName, setThemeName] = usePreference('themeName')
3756
const [customThemes, setCustomThemes] = useState<Record<string, Theme>>({})
38-
const theme = props.theme ?? customThemes[themeName] ?? Themes[themeName] ?? Themes.blue
57+
// カスタムテーマはロード完了までcustomThemesに入らないため、その間は前回キャッシュで
58+
// つなぐ(blueに落とすとローディング画面からの切替時に一瞬デフォルトテーマがチラつく)
59+
const [cachedTheme] = usePersistent<Theme>(CACHED_THEME_KEY)
60+
const theme = props.theme ?? customThemes[themeName] ?? Themes[themeName] ?? cachedTheme ?? Themes.blue
3961

40-
// 次回起動時のCachedThemeProvider用に、解決できたテーマをキャッシュする。
41-
// カスタムテーマはロード完了前は解決できないため、未解決のままblueを書き込まないよう条件付き
62+
// 解決できたテーマをキャッシュする。カスタムテーマはロード完了前は解決できないため、
63+
// 未解決のままblueを書き込まないよう条件付き
4264
useEffect(() => {
4365
const resolved = customThemes[themeName] ?? Themes[themeName]
44-
if (resolved) localStorage.setItem('cachedTheme', JSON.stringify(resolved))
66+
if (resolved) localStorage.setItem(CACHED_THEME_KEY, JSON.stringify(resolved))
4567
}, [customThemes, themeName])
4668

4769
const reloadThemes = useCallback(async () => {

web/src/main.tsx

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,8 @@ import { BrowserRouter, Navigate, Route, Routes, useNavigate, useParams } from '
88

99
import { LoadingFull } from './components/LoadingFull'
1010
import { ClientProvider, useClient, useClientSetupProgress } from './contexts/Client'
11-
import { ThemeProvider } from './contexts/Theme'
12-
import { PreferenceProvider, type Preference } from './contexts/Preference'
13-
import { usePersistent } from './hooks/usePersistent'
11+
import { CachedThemeProvider, ThemeProvider } from './contexts/Theme'
12+
import { PreferenceProvider } from './contexts/Preference'
1413
import { EmojiPickerProvider } from './contexts/EmojiPicker'
1514
import { ComposerProvider } from './contexts/Composer'
1615
import { MediaViewerProvider } from './contexts/MediaViewer'
@@ -57,7 +56,6 @@ import { CssVar, IconButton, OverlayStackProvider, Text } from '@concrnt/ui'
5756
import { ThemeProvider as BaseThemeProvider } from '@concrnt/ui'
5857
import { MdArrowBack } from 'react-icons/md'
5958
import { Themes } from './data/themes'
60-
import { type Theme } from './types/Theme'
6159

6260
const ClientLoadingScreen = () => {
6361
const progress = useClientSetupProgress()
@@ -123,18 +121,6 @@ const hasSession = (() => {
123121
return !!domain && (!!masterKey || !!subKey)
124122
})()
125123

126-
// 設定(cckv)ロード前でも、前回解決されたテーマのキャッシュ(cachedTheme)から前回のテーマを引く。
127-
// キャッシュ未生成時はpreferenceのテーマ名をビルトインから引き、それも無ければblue
128-
const CachedThemeProvider = ({ children }: { children: ReactNode }) => {
129-
const [cachedPref] = usePersistent<Preference>('preference')
130-
const [cachedTheme] = usePersistent<Theme>('cachedTheme')
131-
return (
132-
<BaseThemeProvider theme={cachedTheme ?? Themes[cachedPref?.themeName ?? ''] ?? Themes.blue}>
133-
{children}
134-
</BaseThemeProvider>
135-
)
136-
}
137-
138124
// client(≒プロフィール)が変わったら配下をまるごと作り直し、
139125
// 古いプロフィール由来のstate(タブ選択やビューのローカルstateなど)を持ち越さない。
140126
// BrowserRouterは外側にあるためURLは維持され、ルート要素だけが再構築される

0 commit comments

Comments
 (0)