mirror of
https://github.com/sqlchat/sqlchat.git
synced 2025-09-29 02:54:58 +08:00
feat: implement Popover kit component
This commit is contained in:
@ -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>
|
||||
|
@ -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;
|
||||
|
@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
|
25
src/components/kit/Popover.tsx
Normal file
25
src/components/kit/Popover.tsx
Normal 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;
|
@ -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>
|
||||
))}
|
||||
|
Reference in New Issue
Block a user