Skip to content

Commit b4bdf05

Browse files
committed
feat: persist code block tab selection to locaStorage
This comes at the expense of some inevitable hydration errors
1 parent 1a5cb29 commit b4bdf05

File tree

2 files changed

+28
-7
lines changed

2 files changed

+28
-7
lines changed

src/components/codeContext.tsx

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use client';
22

3-
import {createContext, useEffect, useState} from 'react';
3+
import {createContext, useEffect, useReducer, useState} from 'react';
44
import Cookies from 'js-cookie';
55

66
type ProjectCodeKeywords = {
@@ -88,10 +88,12 @@ export const DEFAULTS: CodeKeywords = {
8888
USER: undefined,
8989
};
9090

91+
type SeledtedCodeTabs = Record<string, string | undefined>;
92+
9193
type CodeContextType = {
9294
codeKeywords: CodeKeywords;
9395
isLoading: boolean;
94-
sharedCodeSelection: [string | null, React.Dispatch<string | null>];
96+
sharedCodeSelection: [SeledtedCodeTabs, React.Dispatch<[string, string]>];
9597
sharedKeywordSelection: [
9698
Record<string, number>,
9799
React.Dispatch<Record<string, number>>,
@@ -297,8 +299,18 @@ export function CodeContextProvider({children}: {children: React.ReactNode}) {
297299
// that is the only namespace that actually has a list
298300
const sharedKeywordSelection = useState<Record<string, number>>({});
299301

302+
const storedSelections = Object.fromEntries(
303+
Object.entries(
304+
// default to an empty object if localStorage is not available on the server
305+
typeof localStorage === 'undefined' ? {} : localStorage
306+
).filter(([key]) => key.startsWith('Tabgroup:'))
307+
);
308+
300309
// Maintains the global selection for which code block tab is selected
301-
const sharedCodeSelection = useState<string | null>(null);
310+
// const sharedCodeSelection = useState<SeledtedCodeTabs>(storedSelections);
311+
const sharedCodeSelection = useReducer((tabs: SeledtedCodeTabs, [groupId, value]: [string, string]) => {
312+
return {...tabs, [groupId]: value};
313+
}, storedSelections)
302314

303315
const result: CodeContextType = {
304316
codeKeywords,

src/components/codeTabs.tsx

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,14 @@ export function CodeTabs({children}: CodeTabProps) {
8686
}
8787
});
8888

89-
const [sharedSelection, setSharedSelection] = codeContext?.sharedCodeSelection ?? [];
89+
// The groupId is used to store the selection in localStorage.
90+
// It is a unique identifier based on the tab titles.
91+
const groupId = 'Tabgroup:' + possibleChoices.sort().join('|');
9092

91-
const sharedSelectionChoice = sharedSelection
92-
? possibleChoices.find(x => x === sharedSelection)
93+
const [sharedSelections, setSharedSelections] = codeContext?.sharedCodeSelection ?? [];
94+
95+
const sharedSelectionChoice = sharedSelections
96+
? possibleChoices.find(x => x === sharedSelections[groupId])
9397
: null;
9498
const localSelectionChoice = localSelection
9599
? possibleChoices.find(x => x === localSelection)
@@ -99,6 +103,11 @@ export function CodeTabs({children}: CodeTabProps) {
99103
const finalSelection =
100104
sharedSelectionChoice ?? localSelectionChoice ?? possibleChoices[0];
101105

106+
// Save the selected tab for Tabgroup to localStorage whenever it changes
107+
useEffect(() => {
108+
localStorage.setItem(groupId, finalSelection);
109+
}, [finalSelection]);
110+
102111
// Whenever local selection and the final selection are not in sync, the local
103112
// selection is updated from the final one. This means that when the shared
104113
// selection moves to something that is unsupported by the block it stays on
@@ -117,7 +126,7 @@ export function CodeTabs({children}: CodeTabProps) {
117126
// see useEffect above.
118127
setLastScrollOffset(containerRef.current.getBoundingClientRect().y);
119128
}
120-
setSharedSelection?.(choice);
129+
setSharedSelections?.([groupId, choice]);
121130
setLocalSelection(choice);
122131
}}
123132
>

0 commit comments

Comments
 (0)