Skip to content

Commit

Permalink
Settings page 5/5 (there is still something to do)
Browse files Browse the repository at this point in the history
  • Loading branch information
P-man2976 committed Oct 26, 2023
1 parent ae7b6e7 commit 11c152d
Show file tree
Hide file tree
Showing 9 changed files with 287 additions and 7 deletions.
87 changes: 87 additions & 0 deletions packages/react/src/components/topic/TopicPicker.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { useState, useEffect } from "react";
import { ChevronsUpDown } from "lucide-react";
import { Button } from "@/shadcn/ui/button";
import {
Command,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
CommandList,
} from "@/shadcn/ui/command";
import { Popover, PopoverTrigger, PopoverContent } from "@/shadcn/ui/popover";
import { useTranslation } from "react-i18next";
import { useAtom, useAtomValue } from "jotai/react";
import { useSearchAutoCompleteMutation } from "@/services/search.service";
import atomWithDebounce from "@/lib/atomWithDebounce";

const { debouncedValueAtom, currentValueAtom } = atomWithDebounce("", 300);

interface TopicPickerProps {
onSelect: (topicId: string) => void;
}

export function TopicPicker({ onSelect }: TopicPickerProps) {
const [deboundcedValue, setDebouncedValue] = useAtom(debouncedValueAtom);
const currentValue = useAtomValue(currentValueAtom);
const { t } = useTranslation();
const [open, setOpen] = useState(false);

const { data, isPending, mutate } = useSearchAutoCompleteMutation();

useEffect(() => {
mutate({
q: deboundcedValue,
t: "topic",
n: 10,
});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [deboundcedValue]);

return (
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild>
<Button
variant="outline"
role="combobox"
size="lg"
aria-expanded={open}
className="w-full justify-between px-4"
>
{t("component.topicPicker.pickLabel")}
<ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
</Button>
</PopoverTrigger>
<PopoverContent className="max-w-[80vw] p-0">
<Command>
<CommandInput
value={currentValue}
onValueChange={setDebouncedValue}
placeholder={t("component.topicPicker.searchLabel")}
/>
<CommandList>
<CommandEmpty>{t("component.topicPicker.notFound")}</CommandEmpty>
<CommandGroup>
{data?.topic?.map(({ id }) => (
<CommandItem
key={id}
onSelect={(topicId) => {
onSelect(topicId);
setOpen(false);
}}
>
{id}
</CommandItem>
))}
{isPending && (
<CommandItem className="flex justify-center py-2" disabled>
<div className="i-lucide:loader-2 animate-spin" />
</CommandItem>
)}
</CommandGroup>
</CommandList>
</Command>
</PopoverContent>
</Popover>
);
}
14 changes: 11 additions & 3 deletions packages/react/src/locales/en/ui.yml
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,10 @@ component:
pickDate: Pick a date...
toast:
copiedToClipboard: Copied to clipboard
topicPicker:
searchLabel: Search topics...
notFound: No topic found
pickLabel: Pick topics...
views:
channel:
video: Videos
Expand Down Expand Up @@ -323,9 +327,9 @@ views:
gridSizeLabel: Thumbnail/Grid Size
gridSizeMsg: Change thumbnail/video grid size on Home/Favorites page
gridSize:
- Large
- Medium
- Small
- Grid
- List
- Dense List
hideCollabStreamsLabel: Hide Collab Streams
hideCollabStreamsMsg: Hide collab streams from your favorites feed
hidePlaceholderStreams: Hide Placeholder Streams
Expand All @@ -339,6 +343,10 @@ views:
languageSearch: Search language...
languageNotfound: No language found
userNotLinked: Not linked
defaultHomepage:
lastVisitedOrgHome: Last Visited Org Home
favoritesWhenLoggedIn: Favorites (When Logged In)
hideFeaturesLabel: Hide Features
app:
update_available: An update is available
update_btn: Update
Expand Down
10 changes: 10 additions & 0 deletions packages/react/src/routes/router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ const Settings = React.lazy(() => import("./settings"));
const SettingsLang = React.lazy(() => import("./settings/lang"));
const SettingsTheme = React.lazy(() => import("./settings/theme"));
const SettingsUser = React.lazy(() => import("./settings/user"));
const SettingsHomepage = React.lazy(() => import("./settings/homepage"));
const SettingsBlocked = React.lazy(() => import("./settings/blocked"));
const About = React.lazy(() => import("./about"));
const AboutGeneral = React.lazy(() => import("./about/general"));
const AboutChangelog = React.lazy(() => import("./about/changelog"));
Expand Down Expand Up @@ -97,6 +99,14 @@ const router = createBrowserRouter([
path: "user",
element: <SettingsUser />,
},
{
path: "homepage",
element: <SettingsHomepage />,
},
{
path: "blocked",
element: <SettingsBlocked />,
},
// Add children routes similar to above pattern
],
},
Expand Down
8 changes: 8 additions & 0 deletions packages/react/src/routes/settings/blocked.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { blockedChannelsAtom } from "@/store/settings";
import { useAtom } from "jotai";

export default function SettingsBlocked() {
const [blockedChannels, setBlockedChannels] = useAtom(blockedChannelsAtom);

return <div className="flex flex-col gap-2"></div>;
}
160 changes: 160 additions & 0 deletions packages/react/src/routes/settings/homepage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
import { SettingsItem } from "@/components/settings/SettingsItem";
import { TopicPicker } from "@/components/topic/TopicPicker";
import { cn } from "@/lib/utils";
import { Badge } from "@/shadcn/ui/badge";
import { Label } from "@/shadcn/ui/label";
import { RadioGroup, RadioGroupItem } from "@/shadcn/ui/radio-group";
import { Switch } from "@/shadcn/ui/switch";
import {
defaultOpenAtom,
hideCollabStreamsAtom,
hidePlaceholderAtom,
hideThumbnailAtom,
homeViewModeAtom,
ignoredTopicsAtom,
} from "@/store/settings";
import { useAtom } from "jotai";
import { useTranslation } from "react-i18next";

export default function SettingsHomepage() {
const { t } = useTranslation();
const [defaultOpen, setDefaultOpen] = useAtom(defaultOpenAtom);
const [homeViewMode, setHomeViewMode] = useAtom(homeViewModeAtom);
const [ignoredTopics, setIgnoredTopics] = useAtom(ignoredTopicsAtom);
const [hideThumbnail, setHideThumbnail] = useAtom(hideThumbnailAtom);
const [hideCollab, setHideCollab] = useAtom(hideCollabStreamsAtom);
const [hidePlaceholder, setHidePlaceholder] = useAtom(hidePlaceholderAtom);

const defaultPages = [
{
value: "Home",
label: t("views.settings.defaultHomepage.lastVisitedOrgHome"),
},
{
value: "Favorites",
label: t("views.settings.defaultHomepage.favoritesWhenLoggedIn"),
},
];

const gridSizes = [
{
value: "grid",
label: t("views.settings.gridSize.0"),
},
{
value: "list",
label: t("views.settings.gridSize.1"),
},
{
value: "denseList",
label: t("views.settings.gridSize.2"),
},
];

const hideFeatures = [
{
label: t("views.settings.hideVideoThumbnailsLabel"),
value: hideThumbnail,
onChange: () => setHideThumbnail(!hideThumbnail),
},
{
label: t("views.settings.hideCollabStreamsLabel"),
value: hideCollab,
onChange: () => setHideCollab(!hideCollab),
},
{
label: t("views.settings.hidePlaceholderStreams"),
value: hidePlaceholder,
onChange: () => setHidePlaceholder(!hidePlaceholder),
},
];

return (
<div className="flex flex-col p-2 md:p-4">
<SettingsItem label={t("views.settings.defaultPage")}>
<RadioGroup
className="flex w-full flex-col gap-0 rounded-lg border border-base"
value={defaultOpen}
onValueChange={(val: "Home" | "Favorites") => setDefaultOpen(val)}
>
{defaultPages.map(({ label, value }, index) => (
<Label
className={cn(
"flex w-full min-w-[18rem] items-center justify-between gap-4 p-4 hover:cursor-pointer",
{ "bg-base-4": index % 2 },
)}
>
{label}
<RadioGroupItem value={value} />
</Label>
))}
</RadioGroup>
</SettingsItem>
<SettingsItem label={t("views.settings.gridSizeLabel")}>
<RadioGroup
className="ml-auto flex gap-0 rounded-lg"
onValueChange={(val: "grid" | "list" | "denseList") =>
setHomeViewMode(val)
}
>
{gridSizes.map(({ label, value }) => (
<Label
className={cn(
"bg-base-4 border-base border-r-2 px-4 py-2 text-lg first:rounded-l-lg last:rounded-r-lg last:border-r-0 hover:cursor-pointer",
{ "bg-secondary-9": value === homeViewMode },
)}
>
{label}
<RadioGroupItem value={value} className="sr-only" />
</Label>
))}
</RadioGroup>
</SettingsItem>
<SettingsItem label={t("views.settings.ignoredTopicsLabel")}>
<div className="flex w-full flex-col gap-2">
<TopicPicker
onSelect={(topic) =>
setIgnoredTopics((currentTopics) => [...currentTopics, topic])
}
/>
<div className="flex flex-wrap gap-2">
{ignoredTopics.map((topic) => (
<Badge
onClick={() =>
setIgnoredTopics((currentTopics) =>
currentTopics.filter((t) => t !== topic),
)
}
>
{topic}
<div className="i-heroicons:x-mark ml-1" />
</Badge>
))}
</div>
</div>
</SettingsItem>
<SettingsItem label={t("views.settings.hideFeaturesLabel")}>
<div className="flex w-full flex-col rounded-lg border border-base">
{hideFeatures.map(({ label, value, onChange }, index) => (
<Label
className={cn(
"flex min-w-[18rem] w-full justify-between items-center gap-4 px-4 py-4 hover:cursor-pointer",
{
"bg-base-4": index % 2,
},
)}
htmlFor={`hidefeature-${label}`}
>
{label}
<Switch
id={`hidefeature-${label}`}
checked={value}
onCheckedChange={onChange}
/>
</Label>
))}
</div>
</SettingsItem>
</div>
);
}
4 changes: 2 additions & 2 deletions packages/react/src/routes/settings/lang.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,11 @@ export default function SettingsLang() {
</div>
</SettingsItem>
<SettingsItem label={t("views.settings.clipLanguageSelection")}>
<div className="flex w-full flex-col">
<div className="flex w-full flex-col rounded-lg border border-base">
{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",
"flex min-w-[18rem] w-full justify-between items-center gap-4 px-4 py-4 hover:cursor-pointer",
{
"bg-base-4": index % 2,
},
Expand Down
2 changes: 1 addition & 1 deletion packages/react/src/services/search.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useMutation } from "@tanstack/react-query";

interface SearchAutoCompleteParams {
q?: string;
t?: ChannelType;
t?: SearchAutoCompleteType[] | SearchAutoCompleteType;
n?: number;
}

Expand Down
2 changes: 1 addition & 1 deletion packages/react/src/store/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export const hideThumbnailAtom = atom(false);
export const hidePlaceholderAtom = atom(false);
export const homeViewModeAtom = atom<"grid" | "list" | "denseList">("grid");
export const gridDensityAtom = atom(0);
export const defaultOpenAtom = atom("Home");
export const defaultOpenAtom = atom<"Favorites" | "Home">("Home");
export const hideCollabStreamsAtom = atom(false);
export const filterDeadStreamsAtom = atom(true);
export const ignoredTopicsAtom = atom<string[]>([]);
Expand Down
7 changes: 7 additions & 0 deletions packages/react/src/types/search.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
type SearchAutoCompleteType = "vtuber" | "any_channel" | "topic";

interface SearchAutoComplete {
vtuber?: SearchAutoCompleteChannel[];
topic?: SearchAutoCompleteTopic[];
}

interface SearchAutoCompleteChannel {
Expand All @@ -8,3 +11,7 @@ interface SearchAutoCompleteChannel {
english_name?: string;
org?: string;
}

interface SearchAutoCompleteTopic {
id: string;
}

0 comments on commit 11c152d

Please sign in to comment.