Files
everyone-can-use-english/enjoy/src/renderer/components/widgets/sidebar.tsx
an-lee 0644c3bbd7 Feat: make notes on caption (#544)
* add segment model

* add note model

* db handle segment & note

* add notes & segments handler

* refactor media caption components

* segment & note create

* fix type

* update note column & may sync

* display selected words for note

* refactor selected words

* auto select words when editing note

* refactor

* refactor caption component

* display notes

* refactor notes components

* fix

* refactor segment & notes into context

* destroy note

* update locale

* fix caption switch issue

* fix layout

* refactor caption layout

* remove deprecated code

* may share note

* improve UI

* fix notes list auto update after created

* remove console.log

* add notes page

* refactor note parameters

* refactor components

* mark note on transcription

* handle no notes

* improve style

* improve style

* show context menu on selection text

* fix utils
2024-04-26 15:05:36 +08:00

260 lines
8.0 KiB
TypeScript

import {
Button,
Dialog,
DialogTrigger,
DialogContent,
ScrollArea,
DropdownMenu,
DropdownMenuTrigger,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuSub,
DropdownMenuPortal,
DropdownMenuSubContent,
DropdownMenuSubTrigger,
DropdownMenuItem,
Separator,
} from "@renderer/components/ui";
import {
SettingsIcon,
HomeIcon,
HeadphonesIcon,
VideoIcon,
NewspaperIcon,
BookMarkedIcon,
UserIcon,
BotIcon,
UsersRoundIcon,
LucideIcon,
HelpCircleIcon,
ExternalLinkIcon,
NotebookPenIcon,
} from "lucide-react";
import { useLocation, Link } from "react-router-dom";
import { t } from "i18next";
import { Preferences } from "@renderer/components";
import { AppSettingsProviderContext } from "@renderer/context";
import { useContext } from "react";
export const Sidebar = () => {
const location = useLocation();
const activeTab = location.pathname;
const { EnjoyApp } = useContext(AppSettingsProviderContext);
return (
<div
className="h-[100vh] w-16 xl:w-40 transition-all relative"
data-testid="sidebar"
>
<div className="fixed top-0 left-0 h-full w-16 xl:w-40 bg-muted">
<ScrollArea className="w-full h-full">
<div className="py-4 mb-4 flex items-center space-x-1 justify-center">
<img src="./assets/logo-light.svg" className="w-8 h-8" />
<span className="hidden xl:block text-xl font-semibold text-[#4797F5]">
ENJOY
</span>
</div>
<div className="grid gap-2">
<SidebarItem
href="/"
label={t("sidebar.home")}
tooltip={t("sidebar.home")}
active={activeTab === "/"}
Icon={HomeIcon}
/>
<Separator className="hidden xl:block" />
<SidebarItem
href="/audios"
label={t("sidebar.audios")}
tooltip={t("sidebar.audios")}
active={activeTab.startsWith("/audios")}
Icon={HeadphonesIcon}
/>
<SidebarItem
href="/videos"
label={t("sidebar.videos")}
tooltip={t("sidebar.videos")}
active={activeTab.startsWith("/videos")}
Icon={VideoIcon}
/>
<SidebarItem
href="/stories"
label={t("sidebar.stories")}
tooltip={t("sidebar.stories")}
active={activeTab.startsWith("/stories")}
Icon={NewspaperIcon}
/>
<Separator className="hidden xl:block" />
<SidebarItem
href="/conversations"
label={t("sidebar.aiAssistant")}
tooltip={t("sidebar.aiAssistant")}
active={activeTab.startsWith("/conversations")}
Icon={BotIcon}
testid="sidebar-conversations"
/>
<SidebarItem
href="/notes"
label={t("sidebar.notes")}
tooltip={t("sidebar.notes")}
active={activeTab === "/notes"}
Icon={NotebookPenIcon}
/>
<SidebarItem
href="/vocabulary"
label={t("sidebar.vocabulary")}
tooltip={t("sidebar.vocabulary")}
active={activeTab.startsWith("/vocabulary")}
Icon={BookMarkedIcon}
/>
<Separator className="hidden xl:block" />
<SidebarItem
href="/community"
label={t("sidebar.community")}
tooltip={t("sidebar.community")}
active={activeTab === "/community"}
Icon={UsersRoundIcon}
/>
<SidebarItem
href="/profile"
label={t("sidebar.profile")}
tooltip={t("sidebar.profile")}
active={activeTab.startsWith("/profile")}
Icon={UserIcon}
/>
<Separator className="hidden xl:block" />
<Dialog>
<DialogTrigger asChild>
<div className="px-1 xl:px-2">
<Button
variant="ghost"
id="preferences-button"
className="w-full xl:justify-start"
data-tooltip-id="global-tooltip"
data-tooltip-content={t("sidebar.preferences")}
data-tooltip-place="right"
>
<SettingsIcon className="xl:mr-2 h-5 w-5" />
<span className="hidden xl:block">
{t("sidebar.preferences")}
</span>
</Button>
</div>
</DialogTrigger>
<DialogContent className="max-w-screen-md xl:max-w-screen-lg h-5/6 p-0">
<Preferences />
</DialogContent>
</Dialog>
</div>
</ScrollArea>
<div className="w-full absolute bottom-0 px-1 xl:px-4 py-2">
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
variant="ghost"
className="w-full xl:justify-start px-2 xl:px-4"
>
<HelpCircleIcon className="h-5 w-5" />
<span className="ml-2 hidden xl:block">{t("help")}</span>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="px-4">
<DropdownMenuGroup>
<DropdownMenuItem
onClick={() =>
EnjoyApp.shell.openExternal("https://1000h.org/enjoy-app/")
}
className="flex justify-between space-x-2"
>
<span>{t("userGuide")}</span>
<ExternalLinkIcon className="h-4 w-4" />
</DropdownMenuItem>
</DropdownMenuGroup>
<DropdownMenuGroup>
<DropdownMenuSub>
<DropdownMenuSubTrigger>
{t("feedback")}
</DropdownMenuSubTrigger>
<DropdownMenuPortal>
<DropdownMenuSubContent>
<DropdownMenuItem
onClick={() =>
EnjoyApp.shell.openExternal(
"https://mixin.one/codes/f8ff96b8-54fb-4ad8-a6d4-5a5bdb1df13e"
)
}
className="flex justify-between space-x-2"
>
<span>Mixin</span>
<ExternalLinkIcon className="h-4 w-4" />
</DropdownMenuItem>
<DropdownMenuItem
onClick={() =>
EnjoyApp.shell.openExternal(
"https://github.com/xiaolai/everyone-can-use-english/discussions"
)
}
className="flex justify-between space-x-2"
>
<span>Github</span>
<ExternalLinkIcon className="h-4 w-4" />
</DropdownMenuItem>
</DropdownMenuSubContent>
</DropdownMenuPortal>
</DropdownMenuSub>
</DropdownMenuGroup>
</DropdownMenuContent>
</DropdownMenu>
</div>
</div>
</div>
);
};
const SidebarItem = (props: {
href: string;
label: string;
tooltip: string;
active: boolean;
Icon: LucideIcon;
testid?: string;
}) => {
const { href, label, tooltip, active, Icon, testid } = props;
return (
<Link
to={href}
data-tooltip-id="global-tooltip"
data-tooltip-content={tooltip}
data-tooltip-place="right"
data-testid={testid}
className="block px-1 xl:px-2"
>
<Button
variant={active ? "default" : "ghost"}
className="w-full xl:justify-start px-2 xl:px-4"
>
<Icon className="h-5 w-5" />
<span className="ml-2 hidden xl:block">{label}</span>
</Button>
</Link>
);
};