Skip to content

Commit

Permalink
Settings page 1/5 (language)
Browse files Browse the repository at this point in the history
  • Loading branch information
P-man2976 committed Oct 23, 2023
1 parent 3341de7 commit e42084e
Show file tree
Hide file tree
Showing 9 changed files with 196 additions and 11 deletions.
2 changes: 1 addition & 1 deletion packages/react/src/components/layout/InlayContainer.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { DetailedHTMLProps, HTMLAttributes, Suspense, useState } from "react";
import { DetailedHTMLProps, HTMLAttributes, Suspense } from "react";
import { Loading } from "../common/Loading";
import { Link, Outlet, useLocation, useNavigate } from "react-router-dom";
import { Button } from "@/shadcn/ui/button";
Expand Down
15 changes: 15 additions & 0 deletions packages/react/src/components/settings/SettingsItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Children, ReactNode } from "react";

interface SettingsItemProps {
label: string;
children: ReactNode;
}

export function SettingsItem({ label, children }: SettingsItemProps) {
return (
<div className="border-base flex min-h-[6rem] flex-wrap justify-between gap-4 border-b-2 py-6 last:border-b-0">
<h3 className="text-xl font-bold">{label}</h3>
{Children.only(children)}
</div>
);
}
5 changes: 5 additions & 0 deletions packages/react/src/locales/en/ui.yml
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,11 @@ views:
ignoredTopicsMsg: Hide videos with these topics from the Home and Favorites pages
theme: Theme
moreSettings: More Settings
user: User & Account
homepage: Homepage & Filters
blockedChannels: Blocked Channels
languageSearch: Search language...
languageNotfound: No language found
app:
update_available: An update is available
update_btn: Update
Expand Down
5 changes: 5 additions & 0 deletions packages/react/src/routes/router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import React from "react";

const Login = React.lazy(() => import("./login"));
const Settings = React.lazy(() => import("./settings"));
const SettingsLang = React.lazy(() => import("./settings/lang"));
const About = React.lazy(() => import("./about"));
const AboutGeneral = React.lazy(() => import("./about/general"));
const AboutChangelog = React.lazy(() => import("./about/changelog"));
Expand Down Expand Up @@ -82,6 +83,10 @@ const router = createBrowserRouter([
path: "settings",
element: <Settings />,
children: [
{
path: "lang",
element: <SettingsLang />,
},
// Add children routes similar to above pattern
],
},
Expand Down
9 changes: 0 additions & 9 deletions packages/react/src/routes/settings.tsx

This file was deleted.

43 changes: 43 additions & 0 deletions packages/react/src/routes/settings/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import {
InlayContainer,
InlayContainerRoutes,
} from "@/components/layout/InlayContainer";
import { useMemo } from "react";
import { useTranslation } from "react-i18next";

export default function Settings() {
const { t } = useTranslation();

const routes: InlayContainerRoutes[] = useMemo(
() => [
{
icon: "i-heroicons:language",
href: "/settings/lang",
label: t("views.settings.languageSettings"),
},
{
icon: "i-heroicons:moon",
href: "/settings/themes",
label: t("views.settings.theme"),
},
{
icon: "i-heroicons:user",
href: "/settings/user",
label: t("views.settings.user"),
},
{
icon: "i-heroicons:funnel",
href: "/settings/homepage",
label: t("views.settings.homepage"),
},
{
icon: "i-heroicons:eye-slash",
href: "/settings/blocked",
label: t("views.settings.blockedChannels"),
},
],
[t],
);

return <InlayContainer routes={routes} />;
}
124 changes: 124 additions & 0 deletions packages/react/src/routes/settings/lang.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import { SettingsItem } from "@/components/settings/SettingsItem";
import { TL_LANGS } from "@/lib/consts";
import { langs } from "@/lib/i18n";
import { cn } from "@/lib/utils";
import { Button } from "@/shadcn/ui/button";
import { Checkbox } from "@/shadcn/ui/checkbox";
import {
Command,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
} from "@/shadcn/ui/command";
import { Label } from "@/shadcn/ui/label";
import { Popover, PopoverContent, PopoverTrigger } from "@/shadcn/ui/popover";
import { Switch } from "@/shadcn/ui/switch";
import { clipLanguageAtom, englishNameAtom } from "@/store/settings";
import { useAtom } from "jotai";
import { useState } from "react";
import { useTranslation } from "react-i18next";

export default function SettingsLang() {
const [useENName, setUseENName] = useAtom(englishNameAtom);
const [clipLangs, setClipLangs] = useAtom(clipLanguageAtom);
const [langOpen, setLangOpen] = useState(false);
const { i18n, t } = useTranslation();

return (
<div className="flex flex-col p-2 md:p-4">
<SettingsItem label={t("views.settings.languageSettings")}>
<div className="flex flex-col gap-2">
<Popover open={langOpen} onOpenChange={setLangOpen}>
<PopoverTrigger asChild>
<Button
size="lg"
variant="outline"
role="combobox"
aria-expanded={langOpen}
className="border-base w-fit min-w-[240px] justify-between px-4"
>
{langs.find(({ val }) => i18n.language === val)?.display}
<div className="i-lucide:chevrons-up-down ml-2 h-4 w-4 shrink-0 opacity-50" />
</Button>
</PopoverTrigger>
<PopoverContent className="w-fit min-w-[240px] p-0">
<Command>
<CommandInput
placeholder={t("views.settings.languageSearch")}
/>
<CommandEmpty>
{t("views.settings.languageNotfound")}
</CommandEmpty>
<CommandGroup>
{langs.map(({ val, display }) => (
<CommandItem
key={val}
onSelect={() => {
i18n.changeLanguage(val);
setLangOpen(false);
}}
>
<div
className={cn(
"i-heroicons:check mr-2 h-4 w-4",
val === i18n.language ? "opacity-100" : "opacity-0",
)}
/>
{display}
</CommandItem>
))}
</CommandGroup>
</Command>
</PopoverContent>
</Popover>
<div className="text-base-11 flex items-center gap-1 text-xs">
<div className="i-heroicons:heart" />
{langs.find(({ val }) => i18n.language === val)?.credit}
</div>
</div>
</SettingsItem>
<SettingsItem label={t("views.settings.useEnglishNameLabel")}>
<div className="flex min-w-full items-center gap-4">
<Label htmlFor="use_english_names" className="text-base-11">
{t("views.settings.useEnglishNameMsg")}
</Label>
<div className="flex grow" />
<Switch
id="use_english_names"
checked={useENName}
onCheckedChange={setUseENName}
/>
</div>
</SettingsItem>
<SettingsItem label={t("views.settings.clipLanguageSelection")}>
<div className="flex w-full flex-col">
{TL_LANGS.map(({ text, value }, index) => (
<Label
className={cn(
"flex min-w-[18rem] w-full justify-between items-center gap-4 px-4 py-4",
{
"bg-base-4": index % 2,
},
)}
htmlFor={`cliplang-${value}`}
>
{text}
<Checkbox
id={`cliplang-${value}`}
checked={clipLangs.includes(value)}
onCheckedChange={(checked) =>
setClipLangs((langs) =>
checked
? [...langs, value]
: langs.filter((lang) => lang !== value),
)
}
/>
</Label>
))}
</div>
</SettingsItem>
</div>
);
}
2 changes: 1 addition & 1 deletion packages/react/src/store/i18n.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import dayjs from "dayjs";
import { atom, useSetAtom } from "jotai";
import type { i18n } from "i18next";
import { useCallback, useEffect } from "react";
import { useEffect } from "react";
import { useTranslation } from "react-i18next";

export const localeAtom = atom({
Expand Down
2 changes: 2 additions & 0 deletions packages/react/src/store/settings.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { atom } from "jotai";

export const englishNameAtom = atom(false);
export const clipLanguageAtom = atom<string[]>([]);
export const redirectModeAtom = atom(false);
export const hideThumbnailAtom = atom(false);
export const hidePlaceholderAtom = atom(false);
Expand Down

0 comments on commit e42084e

Please sign in to comment.