refactor(status_bar/language): stop reusing UI for greater customisibility

This commit is contained in:
Elian Doran
2025-12-12 18:29:40 +02:00
parent 31c5323fd9
commit 4dc773c1a3
3 changed files with 99 additions and 67 deletions

View File

@@ -3,10 +3,15 @@ import "./StatusBar.css";
import FNote from "../../entities/fnote";
import { t } from "../../services/i18n";
import { openInAppHelpFromUrl } from "../../services/utils";
import { FormListItem } from "../react/FormList";
import { FormDropdownDivider, FormListItem } from "../react/FormList";
import { useNoteContext } from "../react/hooks";
import { NoteLanguageSelector } from "../ribbon/BasicPropertiesTab";
import { ContentLanguagesModal, NoteLanguageSelector, useLanguageSwitcher } from "../ribbon/BasicPropertiesTab";
import Breadcrumb from "./Breadcrumb";
import { useState } from "preact/hooks";
import { createPortal } from "preact/compat";
import { useProcessedLocales } from "../type_widgets/options/components/LocaleSelector";
import Dropdown from "../react/Dropdown";
import { Locale } from "@triliumnext/commons";
interface StatusBarContext {
note: FNote;
@@ -32,16 +37,44 @@ export default function StatusBar() {
}
function LanguageSwitcher({ note }: StatusBarContext) {
const [ modalShown, setModalShown ] = useState(false);
const { locales, DEFAULT_LOCALE, currentNoteLanguage, setCurrentNoteLanguage } = useLanguageSwitcher(note);
const { activeLocale, processedLocales } = useProcessedLocales(locales, DEFAULT_LOCALE, currentNoteLanguage ?? DEFAULT_LOCALE.id);
return (
<NoteLanguageSelector
note={note}
extraChildren={(
<>
<Dropdown text={getLocaleName(activeLocale)}>
{processedLocales.map(locale => {
if (typeof locale === "object") {
return <FormListItem
rtl={locale.rtl}
checked={locale.id === currentNoteLanguage}
onClick={() => setCurrentNoteLanguage(locale.id)}
>{locale.name}</FormListItem>
} else {
return <FormDropdownDivider />
}
})}
<FormDropdownDivider />
<FormListItem
onClick={() => openInAppHelpFromUrl("veGu4faJErEM")}
icon="bx bx-help-circle"
>{t("note_language.help-on-languages")}</FormListItem>
<FormListItem
onClick={() => setModalShown(true)}
icon="bx bx-cog"
>{t("note_language.configure-languages")}</FormListItem>
</Dropdown>
{createPortal(
<ContentLanguagesModal modalShown={modalShown} setModalShown={setModalShown} />,
document.body
)}
compact
/>
</>
);
}
export function getLocaleName(locale: Locale | null | undefined) {
if (!locale) return "";
if (!locale.id) return "-";
return locale.id.toLocaleUpperCase();
}

View File

@@ -330,12 +330,32 @@ function NoteLanguageSwitch({ note }: { note?: FNote | null }) {
);
}
export function NoteLanguageSelector({ note, extraChildren, ...restProps }: {
note: FNote | null | undefined,
extraChildren?: ComponentChildren,
compact?: boolean;
}) {
export function NoteLanguageSelector({ note }: { note: FNote | null | undefined }) {
const [ modalShown, setModalShown ] = useState(false);
const { locales, DEFAULT_LOCALE, currentNoteLanguage, setCurrentNoteLanguage } = useLanguageSwitcher(note);
return (
<>
<LocaleSelector
locales={locales}
defaultLocale={DEFAULT_LOCALE}
currentValue={currentNoteLanguage} onChange={setCurrentNoteLanguage}
extraChildren={<>
<FormListItem
onClick={() => setModalShown(true)}
icon="bx bx-cog"
>{t("note_language.configure-languages")}</FormListItem>
</>}
/>
{createPortal(
<ContentLanguagesModal modalShown={modalShown} setModalShown={setModalShown} />,
document.body
)}
</>
);
}
export function useLanguageSwitcher(note: FNote | null | undefined) {
const [ languages ] = useTriliumOption("languages");
const DEFAULT_LOCALE = {
id: "",
@@ -347,31 +367,10 @@ export function NoteLanguageSelector({ note, extraChildren, ...restProps }: {
const filteredLanguages = getAvailableLocales().filter((l) => typeof l !== "object" || enabledLanguages.includes(l.id));
return filteredLanguages;
}, [ languages ]);
return (
<>
<LocaleSelector
locales={locales}
defaultLocale={DEFAULT_LOCALE}
currentValue={currentNoteLanguage ?? ""} onChange={setCurrentNoteLanguage}
extraChildren={<>
{extraChildren}
<FormListItem
onClick={() => setModalShown(true)}
icon="bx bx-cog"
>{t("note_language.configure-languages")}</FormListItem>
</>}
{...restProps}
/>
{createPortal(
<ContentLanguagesModal modalShown={modalShown} setModalShown={setModalShown} />,
document.body
)}
</>
);
return { locales, DEFAULT_LOCALE, currentNoteLanguage, setCurrentNoteLanguage };
}
function ContentLanguagesModal({ modalShown, setModalShown }: { modalShown: boolean, setModalShown: (shown: boolean) => void }) {
export function ContentLanguagesModal({ modalShown, setModalShown }: { modalShown: boolean, setModalShown: (shown: boolean) => void }) {
return (
<Modal
className="content-languages-modal"

View File

@@ -5,15 +5,42 @@ import { useMemo } from "preact/hooks";
import Dropdown from "../../../react/Dropdown";
import { FormDropdownDivider, FormListItem } from "../../../react/FormList";
export function LocaleSelector({ id, locales, currentValue, onChange, defaultLocale, extraChildren, compact }: {
export function LocaleSelector({ id, locales, currentValue, onChange, defaultLocale, extraChildren }: {
id?: string;
locales: Locale[],
currentValue: string,
currentValue: string | null | undefined,
onChange: (newLocale: string) => void,
defaultLocale?: Locale,
extraChildren?: ComponentChildren,
compact?: boolean;
}) {
const currentValueWithDefault = currentValue ?? defaultLocale?.id ?? "";
const { activeLocale, processedLocales } = useProcessedLocales(locales, defaultLocale, currentValueWithDefault);
return (
<Dropdown id={id} text={activeLocale?.name}>
{processedLocales.map(locale => {
if (typeof locale === "object") {
return <FormListItem
rtl={locale.rtl}
checked={locale.id === currentValue}
onClick={() => {
onChange(locale.id);
}}
>{locale.name}</FormListItem>
} else {
return <FormDropdownDivider />
}
})}
{extraChildren && (
<>
<FormDropdownDivider />
{extraChildren}
</>
)}
</Dropdown>
);
}
export function useProcessedLocales(locales: Locale[], defaultLocale: Locale | undefined, currentValue: string) {
const activeLocale = defaultLocale?.id === currentValue ? defaultLocale : locales.find(l => l.id === currentValue);
const processedLocales = useMemo(() => {
@@ -36,35 +63,8 @@ export function LocaleSelector({ id, locales, currentValue, onChange, defaultLoc
];
}
if (extraChildren) {
items.push("---");
}
return items;
}, [ locales ]);
}, [ locales, defaultLocale ]);
return (
<Dropdown id={id} text={getLocaleName(activeLocale, compact)}>
{processedLocales.map(locale => {
if (typeof locale === "object") {
return <FormListItem
rtl={locale.rtl}
checked={locale.id === currentValue}
onClick={() => {
onChange(locale.id);
}}
>{locale.name}</FormListItem>
} else {
return <FormDropdownDivider />
}
})}
{extraChildren}
</Dropdown>
);
}
function getLocaleName(locale: Locale | null | undefined, compact: boolean | undefined) {
if (!locale) return "";
if (!compact) return locale.name;
if (!locale.id) return "-";
return locale.id.toLocaleUpperCase();
return { activeLocale, processedLocales };
}