Add 'activeLocale'

This change tracks the "active locale" in memory, and when the
language is changed a re-render occurs. After this change, the
URL does not change in the process of changing language
This commit is contained in:
0x1eef 2024-10-18 03:23:28 -03:00
parent a03dcae2d7
commit e802d6ef19
3 changed files with 40 additions and 30 deletions

View file

@ -2,32 +2,40 @@ import { Quran, TLocale } from "Quran";
import { Select } from "~/components/Select"; import { Select } from "~/components/Select";
type Props = { type Props = {
locale: TLocale;
isOpen: boolean; isOpen: boolean;
setIsOpen: (v: boolean) => void; setIsOpen: (v: boolean) => void;
activeLocale: TLocale;
setActiveLocale: (v: TLocale) => void;
}; };
export function LanguageSelect({ locale, isOpen, setIsOpen }: Props) { export function LanguageSelect({
isOpen,
setIsOpen,
activeLocale,
setActiveLocale,
}: Props) {
const locales = Object.values(Quran.locales); const locales = Object.values(Quran.locales);
return ( return (
<Select <Select
value={locale.name} value={activeLocale.name}
className="language-select w-20" className="language-select w-20"
isOpen={isOpen} isOpen={isOpen}
setIsOpen={setIsOpen} setIsOpen={setIsOpen}
> >
{locales.map((l: TLocale, i: number) => { {locales.map((l: TLocale, i: number) => {
const href = `/${l.name}`;
return ( return (
<Select.Option <Select.Option
key={i} key={i}
className={classNames( className={classNames(
"flex h-5 text-sm w-full items-center justify-center no-underline mb-1 rounded", "flex h-5 text-sm w-full items-center justify-center no-underline mb-1 rounded",
l.direction, l.direction,
l.name === locale.name ? "active" : undefined, l.name === activeLocale.name ? "active" : undefined,
)} )}
value={l.name} value={l.name}
href={l.name === locale.name ? undefined : href} onClick={(e: React.ChangeEvent) => [
e.preventDefault(),
setActiveLocale(l),
]}
> >
{l.displayName} {l.displayName}
</Select.Option> </Select.Option>

View file

@ -4,20 +4,22 @@ import { formatNumber, TFunction } from "~/lib/t";
import { Arrow } from "~/components/Icon"; import { Arrow } from "~/components/Icon";
import { Head } from "~/components/Head"; import { Head } from "~/components/Head";
import { LanguageSelect, ThemeSelect } from "~/components/Select"; import { LanguageSelect, ThemeSelect } from "~/components/Select";
import { Filter } from "./Filter";
import "@css/main/SurahIndex.scss"; import "@css/main/SurahIndex.scss";
type Props = { type Props = {
locale: TLocale; locale: TLocale;
surahs: Surah[]; surahs: Record<"string", Surah[]>;
t: TFunction; t: TFunction;
}; };
export function SurahIndex({ locale, surahs, t }: Props) { export function SurahIndex({ locale, surahs, t }: Props) {
const [activeLocale, setActiveLocale] = useState<TLocale>(locale);
const index = surahs[activeLocale.name];
const [theme, setTheme] = useTheme(); const [theme, setTheme] = useTheme();
const [index, setIndex] = useState<Surah[]>(surahs);
const [showLangDropdown, setShowLangDropdown] = useState<boolean>(false); const [showLangDropdown, setShowLangDropdown] = useState<boolean>(false);
const [showThemeDropdown, setShowThemeDropdown] = useState<boolean>(false); const [showThemeDropdown, setShowThemeDropdown] = useState<boolean>(false);
const rootRef = useRef<HTMLDivElement>(null); const rootRef = useRef<HTMLDivElement>(null);
const activeEl = useMemo( const activeEl = useMemo(
() => document.activeElement, () => document.activeElement,
@ -42,15 +44,16 @@ export function SurahIndex({ locale, surahs, t }: Props) {
className={classNames( className={classNames(
"flex flex-col h-full content surah-index theme", "flex flex-col h-full content surah-index theme",
theme, theme,
locale.name, activeLocale.name,
locale.direction, activeLocale.direction,
)} )}
> >
<Head title={t(locale, "TheNobleQuran")} locale={locale}> <Head title={t(activeLocale, "TheNobleQuran")} locale={activeLocale}>
<LanguageSelect <LanguageSelect
isOpen={showLangDropdown} isOpen={showLangDropdown}
setIsOpen={setShowLangDropdown} setIsOpen={setShowLangDropdown}
locale={locale} locale={activeLocale}
setActiveLocale={setActiveLocale}
/> />
<ThemeSelect <ThemeSelect
isOpen={showThemeDropdown} isOpen={showThemeDropdown}
@ -63,28 +66,28 @@ export function SurahIndex({ locale, surahs, t }: Props) {
{index.map((surah, key) => ( {index.map((surah, key) => (
<li <li
className={classNames("flex justify-center surah", { className={classNames("flex justify-center surah", {
"w-full": locale.direction === "ltr", "w-full": activeLocale.direction === "ltr",
"w-1/2": locale.direction === "rtl", "w-1/2": activeLocale.direction === "rtl",
})} })}
key={key} key={key}
> >
<a <a
className="flex items-center color-primary no-underline rounded w-11/12 h-8" className="flex items-center color-primary no-underline rounded w-11/12 h-8"
href={`/${locale.name}/${surah.id}/`} href={`/${activeLocale.name}/${surah.id}/`}
> >
<span className="background-secondary color-white rounded flex w-8 font-extrabold w-5 mr-3 justify-center text-center"> <span className="background-secondary color-white rounded flex w-8 font-extrabold w-5 mr-3 justify-center text-center">
{formatNumber(locale, surah.id)} {formatNumber(activeLocale, surah.id)}
</span> </span>
<span>{surah.name}</span> <span>{surah.name}</span>
{locale.direction === "ltr" && ( {activeLocale.direction === "ltr" && (
<div className="flex justify-end grow pr-3"> <div className="flex justify-end grow pr-3">
<div className="flex flex-col"> <div className="flex flex-col">
<span className="transliterated" lang="en"> <span className="transliterated" lang="en">
{surah.translitName} {surah.translitName}
</span> </span>
<span className="ayat flex justify-end text-sm"> <span className="ayat flex justify-end text-sm">
{formatNumber(locale, surah.numberOfAyah)}{" "} {formatNumber(activeLocale, surah.numberOfAyah)}{" "}
{t(locale, "ayat")} {t(activeLocale, "ayat")}
</span> </span>
</div> </div>
</div> </div>
@ -96,23 +99,22 @@ export function SurahIndex({ locale, surahs, t }: Props) {
<footer className="flex flex-row justify-between mb-5 h-12"> <footer className="flex flex-row justify-between mb-5 h-12">
<a <a
className="flex flex-row items-center no-underline" className="flex flex-row items-center no-underline"
href={`/${locale.name}/random/`} href={`/${activeLocale.name}/random/`}
> >
{locale.direction === "ltr" ? ( {activeLocale.direction === "ltr" ? (
<Arrow direction="right" /> <Arrow direction="right" />
) : ( ) : (
<Arrow direction="left" /> <Arrow direction="left" />
)} )}
<span <span
className={classNames({ className={classNames({
"pl-3": locale.direction === "ltr", "pl-3": activeLocale.direction === "ltr",
"pr-3": locale.direction === "rtl", "pr-3": activeLocale.direction === "rtl",
})} })}
> >
{t(locale, "ChooseRandomChapter")} {t(activeLocale, "ChooseRandomChapter")}
</span> </span>
</a> </a>
<Filter t={t} locale={locale} surahs={surahs} setIndex={setIndex} />
</footer> </footer>
</div> </div>
); );

View file

@ -30,25 +30,25 @@ document.addEventListener("DOMContentLoaded", () => {
<SurahIndex <SurahIndex
path="/" path="/"
locale={Quran.locales["en"]} locale={Quran.locales["en"]}
surahs={Quran.surahs["en"]} surahs={Quran.surahs}
t={t} t={t}
/> />
<SurahIndex <SurahIndex
path="/en" path="/en"
locale={Quran.locales["en"]} locale={Quran.locales["en"]}
surahs={Quran.surahs["en"]} surahs={Quran.surahs}
t={t} t={t}
/> />
<SurahIndex <SurahIndex
path="/ar" path="/ar"
locale={Quran.locales["ar"]} locale={Quran.locales["ar"]}
surahs={Quran.surahs["ar"]} surahs={Quran.surahs}
t={t} t={t}
/> />
<SurahIndex <SurahIndex
path="/fa" path="/fa"
locale={Quran.locales["fa"]} locale={Quran.locales["fa"]}
surahs={Quran.surahs["fa"]} surahs={Quran.surahs}
t={t} t={t}
/> />
<SurahStream path="/:localeId/:surahId" t={t} /> <SurahStream path="/:localeId/:surahId" t={t} />