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,
|
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>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
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