feat: implement Popover kit component

This commit is contained in:
steven
2023-04-12 17:00:21 +08:00
parent ce7ed9e821
commit 63ece9d969
9 changed files with 102 additions and 44 deletions

View File

@ -14,6 +14,7 @@
"@mui/material": "^5.11.14",
"@mui/styled-engine-sc": "^5.11.11",
"@radix-ui/react-dialog": "^1.0.3",
"@radix-ui/react-popover": "^1.0.5",
"@radix-ui/react-select": "^1.2.1",
"@radix-ui/react-tooltip": "^1.0.5",
"@vercel/analytics": "^0.1.11",

31
pnpm-lock.yaml generated
View File

@ -16,6 +16,9 @@ dependencies:
'@radix-ui/react-dialog':
specifier: ^1.0.3
version: 1.0.3(@types/react@18.0.28)(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-popover':
specifier: ^1.0.5
version: 1.0.5(@types/react@18.0.28)(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-select':
specifier: ^1.2.1
version: 1.2.1(@types/react@18.0.28)(react-dom@18.2.0)(react@18.2.0)
@ -964,6 +967,34 @@ packages:
react: 18.2.0
dev: false
/@radix-ui/react-popover@1.0.5(@types/react@18.0.28)(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-GRHZ8yD12MrN2NLobHPE8Rb5uHTxd9x372DE9PPNnBjpczAQHcZ5ne0KXG4xpf+RDdXSzdLv9ym6mYJCDTaUZg==}
peerDependencies:
react: ^16.8 || ^17.0 || ^18.0
react-dom: ^16.8 || ^17.0 || ^18.0
dependencies:
'@babel/runtime': 7.21.0
'@radix-ui/primitive': 1.0.0
'@radix-ui/react-compose-refs': 1.0.0(react@18.2.0)
'@radix-ui/react-context': 1.0.0(react@18.2.0)
'@radix-ui/react-dismissable-layer': 1.0.3(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-focus-guards': 1.0.0(react@18.2.0)
'@radix-ui/react-focus-scope': 1.0.2(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-id': 1.0.0(react@18.2.0)
'@radix-ui/react-popper': 1.1.1(@types/react@18.0.28)(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-portal': 1.0.2(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-presence': 1.0.0(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-primitive': 1.0.2(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-slot': 1.0.1(react@18.2.0)
'@radix-ui/react-use-controllable-state': 1.0.0(react@18.2.0)
aria-hidden: 1.2.3
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
react-remove-scroll: 2.5.5(@types/react@18.0.28)(react@18.2.0)
transitivePeerDependencies:
- '@types/react'
dev: false
/@radix-ui/react-popper@1.1.1(@types/react@18.0.28)(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-keYDcdMPNMjSC8zTsZ8wezUMiWM9Yj14wtF3s0PTIs9srnEPC9Kt2Gny1T3T81mmSeyDjZxsD9N5WCwNNb712w==}
peerDependencies:

View File

@ -18,10 +18,10 @@ const SettingModal = (props: Props) => {
return (
<Dialog title={t("setting.self")} onClose={close}>
<div className="w-full flex flex-col justify-start items-start space-y-3 pt-4">
<div className="w-full flex flex-row justify-start items-start flex-wrap">
<div className="w-full flex flex-row justify-start items-start flex-wrap gap-2">
<a
href="https://discord.gg/z6kakemDjm"
className="w-auto px-4 py-2 rounded-full bg-indigo-600 text-white text-sm font-medium flex flex-row justify-center items-center mr-2 mb-2 hover:underline hover:shadow"
className="w-auto px-4 py-2 rounded-full bg-indigo-600 text-white text-sm font-medium flex flex-row justify-center items-center hover:underline hover:shadow"
target="_blank"
>
<Icon.BsDiscord className="w-4 h-auto mr-1" />
@ -37,7 +37,7 @@ const SettingModal = (props: Props) => {
<LocaleSelector />
</div>
<div className="w-full flex flex-row justify-between items-center gap-2">
<span>Theme</span>
<span>{t("setting.theme.self")}</span>
<ThemeSelector />
</div>
</div>

View File

@ -1,3 +1,4 @@
import { useTranslation } from "react-i18next";
import { useSettingStore } from "@/store";
import { Theme } from "@/types";
import Select from "./kit/Select";
@ -7,30 +8,31 @@ interface ThemeItem {
label: string;
}
const themeItemList: ThemeItem[] = [
{
value: "system",
label: "System",
},
{
value: "light",
label: "Light",
},
{
value: "dark",
label: "Dark",
},
];
const ThemeSelector = () => {
const { t } = useTranslation();
const settingStore = useSettingStore();
const theme = settingStore.setting.theme;
const themeItemList: ThemeItem[] = [
{
value: "system",
label: t("setting.theme.system"),
},
{
value: "light",
label: t("setting.theme.light"),
},
{
value: "dark",
label: t("setting.theme.dark"),
},
];
const handleThemeChange = (theme: Theme) => {
settingStore.setTheme(theme);
};
return <Select className="w-28" value={theme} itemList={themeItemList} onValueChange={handleThemeChange} />;
return <Select className="w-40" value={theme} itemList={themeItemList} onValueChange={handleThemeChange} />;
};
export default ThemeSelector;

View File

@ -1,34 +1,21 @@
import { Popover } from "@mui/material";
import { useState } from "react";
import { useTranslation } from "react-i18next";
import Icon from "./Icon";
import Popover from "./kit/Popover";
const WeChatQRCodeView = () => {
const { t } = useTranslation();
const [wechatAnchorEl, setWeChatAnchorEl] = useState<HTMLElement | null>(null);
const openWeChatQrCodePopover = Boolean(wechatAnchorEl);
return (
<>
<div
className="w-auto px-4 py-2 mr-2 mb-2 rounded-full cursor-pointer bg-green-600 text-white text-sm font-medium flex flex-row justify-center items-center hover:shadow"
onClick={(e) => setWeChatAnchorEl(e.currentTarget)}
>
<Icon.BsWechat className="w-4 h-auto mr-1" />
{t("social.join-wechat-group")}
</div>
<Popover
open={openWeChatQrCodePopover}
anchorEl={wechatAnchorEl}
onClose={() => setWeChatAnchorEl(null)}
anchorOrigin={{
vertical: "bottom",
horizontal: "left",
}}
>
<img className="w-64 h-auto" src="/wechat-qrcode.webp" alt="wechat qrcode" />
</Popover>
</>
<Popover
tigger={
<div className="w-auto px-4 py-2 rounded-full cursor-pointer bg-green-600 text-white text-sm font-medium flex flex-row justify-center items-center hover:shadow">
<Icon.BsWechat className="w-4 h-auto mr-1" />
{t("social.join-wechat-group")}
</div>
}
>
<img className="w-40 h-auto" src="/wechat-qrcode.webp" alt="wechat qrcode" />
</Popover>
);
};

View File

@ -0,0 +1,25 @@
import * as PopoverUI from "@radix-ui/react-popover";
import { ReactNode } from "react";
interface Props {
className?: string;
children: ReactNode;
tigger: ReactNode;
}
const Popover = (props: Props) => {
const { className, children, tigger } = props;
return (
<PopoverUI.Root>
<PopoverUI.Trigger asChild>{tigger}</PopoverUI.Trigger>
<PopoverUI.Portal>
<PopoverUI.Content className={`${className || ""} z-[9999] p-2 bg-white dark:bg-zinc-700 shadow-lg rounded-lg`} sideOffset={5}>
{children}
</PopoverUI.Content>
</PopoverUI.Portal>
</PopoverUI.Root>
);
};
export default Popover;

View File

@ -40,7 +40,7 @@ const Select = (props: Props) => {
<SelectUI.Group>
{placeholder && <SelectUI.Label className="w-full px-3 mt-2 mb-1 text-sm text-gray-400">{placeholder}</SelectUI.Label>}
{itemList.map((item) => (
<SelectItem key={item.label} value={item.value}>
<SelectItem key={item.label} className="whitespace-nowrap" value={item.value}>
{item.label}
</SelectItem>
))}

View File

@ -36,6 +36,12 @@
"self": "Basic",
"language": "Language"
},
"theme": {
"self": "Theme",
"system": "Follow system",
"light": "Light",
"dark": "Dark"
},
"openai-api-configuration": {
"self": "OpenAI API configuration"
},

View File

@ -36,6 +36,12 @@
"self": "基础",
"language": "语言"
},
"theme": {
"self": "主题",
"system": "跟随系统",
"light": "浅色",
"dark": "深色"
},
"openai-api-configuration": {
"self": "OpenAI API 配置"
},