ReplyEditor: added language picker
This commit is contained in:
parent
a1a587a77f
commit
4cf065fe1f
4 changed files with 120 additions and 4 deletions
86
src/timelines/ChooseTootLang.tsx
Normal file
86
src/timelines/ChooseTootLang.tsx
Normal 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;
|
|
@ -27,11 +27,16 @@ import {
|
|||
People as PeopleIcon,
|
||||
ThreeP as ThreePIcon,
|
||||
ListAlt as ListAltIcon,
|
||||
Visibility,
|
||||
Translate,
|
||||
} from "@suid/icons-material";
|
||||
import type { Account } from "../accounts/stores";
|
||||
import tootComposers from "./TootComposer.module.css";
|
||||
import { makeEventListener } from "@solid-primitives/event-listener";
|
||||
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";
|
||||
|
||||
|
@ -154,17 +159,19 @@ const TootVisibilityPickerDialog: Component<{
|
|||
const ReplyEditor: Component<{
|
||||
profile: Account;
|
||||
replyToDisplayName: string;
|
||||
isTyping?: boolean
|
||||
onTypingChange: (value: boolean) => void
|
||||
isTyping?: boolean;
|
||||
onTypingChange: (value: boolean) => void;
|
||||
}> = (props) => {
|
||||
let inputRef: HTMLTextAreaElement;
|
||||
const buttonId = createUniqueId();
|
||||
const menuId = createUniqueId();
|
||||
|
||||
const typing = () => props.isTyping
|
||||
const setTyping = (v: boolean) => props.onTypingChange(v)
|
||||
const typing = () => props.isTyping;
|
||||
const setTyping = (v: boolean) => props.onTypingChange(v);
|
||||
const [visibility, setVisibility] = createSignal<TootVisibility>("public");
|
||||
const [permPicker, setPermPicker] = createSignal(false);
|
||||
const [language, setLanguage] = createSignal(useLanguage()().split("-")[0]);
|
||||
const [langPickerOpen, setLangPickerOpen] = createSignal(false);
|
||||
|
||||
onMount(() => {
|
||||
makeEventListener(inputRef, "focus", () => setTyping(true));
|
||||
|
@ -218,7 +225,13 @@ const ReplyEditor: Component<{
|
|||
"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}>
|
||||
<Visibility sx={{ marginTop: "-0.15em", marginRight: "0.25em" }} />
|
||||
{visibilityText()}
|
||||
<ArrowDropDown sx={{ marginTop: "-0.25em" }} />
|
||||
</Button>
|
||||
|
@ -230,6 +243,17 @@ const ReplyEditor: Component<{
|
|||
visibility={visibility()}
|
||||
onVisibilityChange={setVisibility}
|
||||
/>
|
||||
|
||||
<BottomSheet
|
||||
open={langPickerOpen()}
|
||||
onClose={() => setLangPickerOpen(false)}
|
||||
>
|
||||
<ChooseTootLang
|
||||
code={language()}
|
||||
onCodeChange={setLanguage}
|
||||
onClose={[setLangPickerOpen, false]}
|
||||
/>
|
||||
</BottomSheet>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
3
src/timelines/i18n/en.json
Normal file
3
src/timelines/i18n/en.json
Normal file
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"Choose Language": "Choose Language"
|
||||
}
|
3
src/timelines/i18n/zh-Hans.json
Normal file
3
src/timelines/i18n/zh-Hans.json
Normal file
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"Choose Language": "选择语言"
|
||||
}
|
Loading…
Reference in a new issue