-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Move language preferences to new persistence + context (#1837)
- Loading branch information
Showing
15 changed files
with
233 additions
and
190 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import React from 'react' | ||
import {Provider as LanguagesProvider} from './languages' | ||
|
||
export {useLanguagePrefs, useSetLanguagePrefs} from './languages' | ||
|
||
export function Provider({children}: React.PropsWithChildren<{}>) { | ||
return <LanguagesProvider>{children}</LanguagesProvider> | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
import React from 'react' | ||
import * as persisted from '#/state/persisted' | ||
|
||
type SetStateCb = ( | ||
v: persisted.Schema['languagePrefs'], | ||
) => persisted.Schema['languagePrefs'] | ||
type StateContext = persisted.Schema['languagePrefs'] | ||
type SetContext = (fn: SetStateCb) => void | ||
|
||
const stateContext = React.createContext<StateContext>( | ||
persisted.defaults.languagePrefs, | ||
) | ||
const setContext = React.createContext<SetContext>((_: SetStateCb) => {}) | ||
|
||
export function Provider({children}: React.PropsWithChildren<{}>) { | ||
const [state, setState] = React.useState(persisted.get('languagePrefs')) | ||
|
||
const setStateWrapped = React.useCallback( | ||
(fn: SetStateCb) => { | ||
const v = fn(persisted.get('languagePrefs')) | ||
setState(v) | ||
persisted.write('languagePrefs', v) | ||
}, | ||
[setState], | ||
) | ||
|
||
React.useEffect(() => { | ||
return persisted.onUpdate(() => { | ||
setState(persisted.get('languagePrefs')) | ||
}) | ||
}, [setStateWrapped]) | ||
|
||
return ( | ||
<stateContext.Provider value={state}> | ||
<setContext.Provider value={setStateWrapped}> | ||
{children} | ||
</setContext.Provider> | ||
</stateContext.Provider> | ||
) | ||
} | ||
|
||
export function useLanguagePrefs() { | ||
return React.useContext(stateContext) | ||
} | ||
|
||
export function useSetLanguagePrefs() { | ||
return React.useContext(setContext) | ||
} | ||
|
||
export function getContentLanguages() { | ||
return persisted.get('languagePrefs').contentLanguages | ||
} | ||
|
||
export function toggleContentLanguage( | ||
state: StateContext, | ||
setState: SetContext, | ||
code2: string, | ||
) { | ||
if (state.contentLanguages.includes(code2)) { | ||
setState(v => ({ | ||
...v, | ||
contentLanguages: v.contentLanguages.filter(lang => lang !== code2), | ||
})) | ||
} else { | ||
setState(v => ({ | ||
...v, | ||
contentLanguages: v.contentLanguages.concat(code2), | ||
})) | ||
} | ||
} | ||
|
||
export function toPostLanguages(postLanguage: string): string[] { | ||
// filter out empty strings if exist | ||
return postLanguage.split(',').filter(Boolean) | ||
} | ||
|
||
export function hasPostLanguage(postLanguage: string, code2: string): boolean { | ||
return toPostLanguages(postLanguage).includes(code2) | ||
} | ||
|
||
export function togglePostLanguage( | ||
state: StateContext, | ||
setState: SetContext, | ||
code2: string, | ||
) { | ||
if (hasPostLanguage(state.postLanguage, code2)) { | ||
setState(v => ({ | ||
...v, | ||
postLanguage: toPostLanguages(v.postLanguage) | ||
.filter(lang => lang !== code2) | ||
.join(','), | ||
})) | ||
} else { | ||
// sort alphabetically for deterministic comparison in context menu | ||
setState(v => ({ | ||
...v, | ||
postLanguage: toPostLanguages(v.postLanguage) | ||
.concat([code2]) | ||
.sort((a, b) => a.localeCompare(b)) | ||
.join(','), | ||
})) | ||
} | ||
} | ||
|
||
/** | ||
* Saves whatever language codes are currently selected into a history array, | ||
* which is then used to populate the language selector menu. | ||
*/ | ||
export function savePostLanguageToHistory(setState: SetContext) { | ||
// filter out duplicate `this.postLanguage` if exists, and prepend | ||
// value to start of array | ||
setState(v => ({ | ||
...v, | ||
postLanguageHistory: [v.postLanguage] | ||
.concat( | ||
v.postLanguageHistory.filter( | ||
commaSeparatedLangCodes => commaSeparatedLangCodes !== v.postLanguage, | ||
), | ||
) | ||
.slice(0, 6), | ||
})) | ||
} |
Oops, something went wrong.