ReplyEditor: added language picker

This commit is contained in:
thislight 2024-09-27 14:53:28 +08:00
parent a1a587a77f
commit 4cf065fe1f
4 changed files with 120 additions and 4 deletions

View file

@ -0,0 +1,86 @@
import {
For,
onMount,
type Component,
type JSX,
} from "solid-js";
import Scaffold from "../material/Scaffold";
import {
AppBar,
IconButton,
List,
ListItemButton,
ListItemSecondaryAction,
ListItemText,
Radio,
Toolbar,
} from "@suid/material";
import { Close as CloseIcon } from "@suid/icons-material";
import iso639_1 from "iso-639-1";
import { createTranslator } from "../platform/i18n";
import { Title } from "../material/typography";
type ChooseTootLangProps = {
code: string;
onCodeChange: (ncode?: string) => void;
onClose?: JSX.EventHandlerUnion<HTMLButtonElement, MouseEvent>;
};
const ChooseTootLang: Component<ChooseTootLangProps> = (props) => {
let listRef: HTMLUListElement;
const [t] = createTranslator(
(code) =>
import(`./i18n/${code}.json`) as Promise<{
default: Record<string, string | undefined>;
}>,
);
onMount(() => {
const code = props.code;
const el = listRef.querySelector(`[data-langcode="${code}"]`);
if (el) {
el.scrollIntoView({ behavior: "auto" });
}
});
return (
<Scaffold
topbar={
<AppBar position="static">
<Toolbar
variant="dense"
sx={{ paddingTop: "var(--safe-area-inset-top, 0px)" }}
>
<IconButton color="inherit" onClick={props.onClose} disableRipple>
<CloseIcon />
</IconButton>
<Title>{t("Choose Language")}</Title>
</Toolbar>
</AppBar>
}
>
<List
ref={listRef!}
sx={{
paddingBottom: "var(--safe-area-inset-bottom, 0)",
}}
>
<For each={iso639_1.getAllCodes()}>
{(code) => (
<ListItemButton
data-langcode={code}
onClick={() => props.onCodeChange(code)}
>
<ListItemText>{iso639_1.getNativeName(code)}</ListItemText>
<ListItemSecondaryAction>
<Radio checked={props.code == code}></Radio>
</ListItemSecondaryAction>
</ListItemButton>
)}
</For>
</List>
</Scaffold>
);
};
export default ChooseTootLang;

View file

@ -27,11 +27,16 @@ import {
People as PeopleIcon, People as PeopleIcon,
ThreeP as ThreePIcon, ThreeP as ThreePIcon,
ListAlt as ListAltIcon, ListAlt as ListAltIcon,
Visibility,
Translate,
} from "@suid/icons-material"; } from "@suid/icons-material";
import type { Account } from "../accounts/stores"; import type { Account } from "../accounts/stores";
import tootComposers from "./TootComposer.module.css"; import tootComposers from "./TootComposer.module.css";
import { makeEventListener } from "@solid-primitives/event-listener"; import { makeEventListener } from "@solid-primitives/event-listener";
import BottomSheet from "../material/BottomSheet"; import BottomSheet from "../material/BottomSheet";
import { useLanguage } from "../platform/i18n";
import iso639_1 from "iso-639-1";
import ChooseTootLang from "./ChooseTootLang";
type TootVisibility = "public" | "unlisted" | "private" | "direct"; type TootVisibility = "public" | "unlisted" | "private" | "direct";
@ -154,17 +159,19 @@ const TootVisibilityPickerDialog: Component<{
const ReplyEditor: Component<{ const ReplyEditor: Component<{
profile: Account; profile: Account;
replyToDisplayName: string; replyToDisplayName: string;
isTyping?: boolean isTyping?: boolean;
onTypingChange: (value: boolean) => void onTypingChange: (value: boolean) => void;
}> = (props) => { }> = (props) => {
let inputRef: HTMLTextAreaElement; let inputRef: HTMLTextAreaElement;
const buttonId = createUniqueId(); const buttonId = createUniqueId();
const menuId = createUniqueId(); const menuId = createUniqueId();
const typing = () => props.isTyping const typing = () => props.isTyping;
const setTyping = (v: boolean) => props.onTypingChange(v) const setTyping = (v: boolean) => props.onTypingChange(v);
const [visibility, setVisibility] = createSignal<TootVisibility>("public"); const [visibility, setVisibility] = createSignal<TootVisibility>("public");
const [permPicker, setPermPicker] = createSignal(false); const [permPicker, setPermPicker] = createSignal(false);
const [language, setLanguage] = createSignal(useLanguage()().split("-")[0]);
const [langPickerOpen, setLangPickerOpen] = createSignal(false);
onMount(() => { onMount(() => {
makeEventListener(inputRef, "focus", () => setTyping(true)); makeEventListener(inputRef, "focus", () => setTyping(true));
@ -218,7 +225,13 @@ const ReplyEditor: Component<{
"margin-top": "8px", "margin-top": "8px",
}} }}
> >
<Button onClick={[setLangPickerOpen, true]}>
<Translate sx={{ marginTop: "-0.25em", marginRight: "0.25em" }} />
{iso639_1.getNativeName(language())}
<ArrowDropDown sx={{ marginTop: "-0.25em" }} />
</Button>
<Button onClick={[setPermPicker, true]} id={buttonId}> <Button onClick={[setPermPicker, true]} id={buttonId}>
<Visibility sx={{ marginTop: "-0.15em", marginRight: "0.25em" }} />
{visibilityText()} {visibilityText()}
<ArrowDropDown sx={{ marginTop: "-0.25em" }} /> <ArrowDropDown sx={{ marginTop: "-0.25em" }} />
</Button> </Button>
@ -230,6 +243,17 @@ const ReplyEditor: Component<{
visibility={visibility()} visibility={visibility()}
onVisibilityChange={setVisibility} onVisibilityChange={setVisibility}
/> />
<BottomSheet
open={langPickerOpen()}
onClose={() => setLangPickerOpen(false)}
>
<ChooseTootLang
code={language()}
onCodeChange={setLanguage}
onClose={[setLangPickerOpen, false]}
/>
</BottomSheet>
</div> </div>
); );
}; };

View file

@ -0,0 +1,3 @@
{
"Choose Language": "Choose Language"
}

View file

@ -0,0 +1,3 @@
{
"Choose Language": "选择语言"
}