style: format

This commit is contained in:
Fu Diwei
2024-10-15 20:45:39 +08:00
parent b0923d54ee
commit 7ef885319e
184 changed files with 2080 additions and 10779 deletions

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="35.93" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 228"><path fill="#00D8FF" d="M210.483 73.824a171.49 171.49 0 0 0-8.24-2.597c.465-1.9.893-3.777 1.273-5.621c6.238-30.281 2.16-54.676-11.769-62.708c-13.355-7.7-35.196.329-57.254 19.526a171.23 171.23 0 0 0-6.375 5.848a155.866 155.866 0 0 0-4.241-3.917C100.759 3.829 77.587-4.822 63.673 3.233C50.33 10.957 46.379 33.89 51.995 62.588a170.974 170.974 0 0 0 1.892 8.48c-3.28.932-6.445 1.924-9.474 2.98C17.309 83.498 0 98.307 0 113.668c0 15.865 18.582 31.778 46.812 41.427a145.52 145.52 0 0 0 6.921 2.165a167.467 167.467 0 0 0-2.01 9.138c-5.354 28.2-1.173 50.591 12.134 58.266c13.744 7.926 36.812-.22 59.273-19.855a145.567 145.567 0 0 0 5.342-4.923a168.064 168.064 0 0 0 6.92 6.314c21.758 18.722 43.246 26.282 56.54 18.586c13.731-7.949 18.194-32.003 12.4-61.268a145.016 145.016 0 0 0-1.535-6.842c1.62-.48 3.21-.974 4.76-1.488c29.348-9.723 48.443-25.443 48.443-41.52c0-15.417-17.868-30.326-45.517-39.844Zm-6.365 70.984c-1.4.463-2.836.91-4.3 1.345c-3.24-10.257-7.612-21.163-12.963-32.432c5.106-11 9.31-21.767 12.459-31.957c2.619.758 5.16 1.557 7.61 2.4c23.69 8.156 38.14 20.213 38.14 29.504c0 9.896-15.606 22.743-40.946 31.14Zm-10.514 20.834c2.562 12.94 2.927 24.64 1.23 33.787c-1.524 8.219-4.59 13.698-8.382 15.893c-8.067 4.67-25.32-1.4-43.927-17.412a156.726 156.726 0 0 1-6.437-5.87c7.214-7.889 14.423-17.06 21.459-27.246c12.376-1.098 24.068-2.894 34.671-5.345a134.17 134.17 0 0 1 1.386 6.193ZM87.276 214.515c-7.882 2.783-14.16 2.863-17.955.675c-8.075-4.657-11.432-22.636-6.853-46.752a156.923 156.923 0 0 1 1.869-8.499c10.486 2.32 22.093 3.988 34.498 4.994c7.084 9.967 14.501 19.128 21.976 27.15a134.668 134.668 0 0 1-4.877 4.492c-9.933 8.682-19.886 14.842-28.658 17.94ZM50.35 144.747c-12.483-4.267-22.792-9.812-29.858-15.863c-6.35-5.437-9.555-10.836-9.555-15.216c0-9.322 13.897-21.212 37.076-29.293c2.813-.98 5.757-1.905 8.812-2.773c3.204 10.42 7.406 21.315 12.477 32.332c-5.137 11.18-9.399 22.249-12.634 32.792a134.718 134.718 0 0 1-6.318-1.979Zm12.378-84.26c-4.811-24.587-1.616-43.134 6.425-47.789c8.564-4.958 27.502 2.111 47.463 19.835a144.318 144.318 0 0 1 3.841 3.545c-7.438 7.987-14.787 17.08-21.808 26.988c-12.04 1.116-23.565 2.908-34.161 5.309a160.342 160.342 0 0 1-1.76-7.887Zm110.427 27.268a347.8 347.8 0 0 0-7.785-12.803c8.168 1.033 15.994 2.404 23.343 4.08c-2.206 7.072-4.956 14.465-8.193 22.045a381.151 381.151 0 0 0-7.365-13.322Zm-45.032-43.861c5.044 5.465 10.096 11.566 15.065 18.186a322.04 322.04 0 0 0-30.257-.006c4.974-6.559 10.069-12.652 15.192-18.18ZM82.802 87.83a323.167 323.167 0 0 0-7.227 13.238c-3.184-7.553-5.909-14.98-8.134-22.152c7.304-1.634 15.093-2.97 23.209-3.984a321.524 321.524 0 0 0-7.848 12.897Zm8.081 65.352c-8.385-.936-16.291-2.203-23.593-3.793c2.26-7.3 5.045-14.885 8.298-22.6a321.187 321.187 0 0 0 7.257 13.246c2.594 4.48 5.28 8.868 8.038 13.147Zm37.542 31.03c-5.184-5.592-10.354-11.779-15.403-18.433c4.902.192 9.899.29 14.978.29c5.218 0 10.376-.117 15.453-.343c-4.985 6.774-10.018 12.97-15.028 18.486Zm52.198-57.817c3.422 7.8 6.306 15.345 8.596 22.52c-7.422 1.694-15.436 3.058-23.88 4.071a382.417 382.417 0 0 0 7.859-13.026a347.403 347.403 0 0 0 7.425-13.565Zm-16.898 8.101a358.557 358.557 0 0 1-12.281 19.815a329.4 329.4 0 0 1-23.444.823c-7.967 0-15.716-.248-23.178-.732a310.202 310.202 0 0 1-12.513-19.846h.001a307.41 307.41 0 0 1-10.923-20.627a310.278 310.278 0 0 1 10.89-20.637l-.001.001a307.318 307.318 0 0 1 12.413-19.761c7.613-.576 15.42-.876 23.31-.876H128c7.926 0 15.743.303 23.354.883a329.357 329.357 0 0 1 12.335 19.695a358.489 358.489 0 0 1 11.036 20.54a329.472 329.472 0 0 1-11 20.722Zm22.56-122.124c8.572 4.944 11.906 24.881 6.52 51.026c-.344 1.668-.73 3.367-1.15 5.09c-10.622-2.452-22.155-4.275-34.23-5.408c-7.034-10.017-14.323-19.124-21.64-27.008a160.789 160.789 0 0 1 5.888-5.4c18.9-16.447 36.564-22.941 44.612-18.3ZM128 90.808c12.625 0 22.86 10.235 22.86 22.86s-10.235 22.86-22.86 22.86s-22.86-10.235-22.86-22.86s10.235-22.86 22.86-22.86Z"></path></svg>

Before

Width:  |  Height:  |  Size: 4.0 KiB

View File

@@ -1,14 +1,8 @@
import { useTranslation } from "react-i18next";
import { Languages } from "lucide-react";
import { useTranslation } from "react-i18next";
import { Button } from "@/components/ui/button";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu";
export default function LocaleToggle() {
const { i18n } = useTranslation();
@@ -23,9 +17,7 @@ export default function LocaleToggle() {
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
{Object.keys(i18n.store.data).map((key) => (
<DropdownMenuItem onClick={() => i18n.changeLanguage(key)}>
{i18n.store.data[key].name as string}
</DropdownMenuItem>
<DropdownMenuItem onClick={() => i18n.changeLanguage(key)}>{i18n.store.data[key].name as string}</DropdownMenuItem>
))}
</DropdownMenuContent>
</DropdownMenu>

View File

@@ -1,14 +1,6 @@
import React from "react";
const Show = ({
when,
children,
fallback,
}: {
when: boolean;
children: React.ReactNode;
fallback?: React.ReactNode;
}) => {
const Show = ({ when, children, fallback }: { when: boolean; children: React.ReactNode; fallback?: React.ReactNode }) => {
return when ? children : fallback;
};

View File

@@ -20,15 +20,8 @@ const initialState: ThemeProviderState = {
const ThemeProviderContext = createContext<ThemeProviderState>(initialState);
export function ThemeProvider({
children,
defaultTheme = "system",
storageKey = "vite-ui-theme",
...props
}: ThemeProviderProps) {
const [theme, setTheme] = useState<Theme>(
() => (localStorage.getItem(storageKey) as Theme) || defaultTheme
);
export function ThemeProvider({ children, defaultTheme = "system", storageKey = "vite-ui-theme", ...props }: ThemeProviderProps) {
const [theme, setTheme] = useState<Theme>(() => (localStorage.getItem(storageKey) as Theme) || defaultTheme);
useEffect(() => {
const root = window.document.documentElement;
@@ -36,10 +29,7 @@ export function ThemeProvider({
root.classList.remove("light", "dark");
if (theme === "system") {
const systemTheme = window.matchMedia("(prefers-color-scheme: dark)")
.matches
? "dark"
: "light";
const systemTheme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
root.classList.add(systemTheme);
return;
@@ -66,8 +56,7 @@ export function ThemeProvider({
export const useTheme = () => {
const context = useContext(ThemeProviderContext);
if (context === undefined)
throw new Error("useTheme must be used within a ThemeProvider");
if (context === undefined) throw new Error("useTheme must be used within a ThemeProvider");
return context;
};

View File

@@ -1,13 +1,8 @@
import { Moon, Sun } from "lucide-react";
import { useTranslation } from "react-i18next";
import { Moon, Sun } from "lucide-react";
import { Button } from "@/components/ui/button";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu";
import { useTheme } from "./ThemeProvider";
export function ThemeToggle() {
@@ -24,15 +19,9 @@ export function ThemeToggle() {
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem onClick={() => setTheme("light")}>
{t("common.theme.light")}
</DropdownMenuItem>
<DropdownMenuItem onClick={() => setTheme("dark")}>
{t("common.theme.dark")}
</DropdownMenuItem>
<DropdownMenuItem onClick={() => setTheme("system")}>
{t("common.theme.system")}
</DropdownMenuItem>
<DropdownMenuItem onClick={() => setTheme("light")}>{t("common.theme.light")}</DropdownMenuItem>
<DropdownMenuItem onClick={() => setTheme("dark")}>{t("common.theme.dark")}</DropdownMenuItem>
<DropdownMenuItem onClick={() => setTheme("system")}>{t("common.theme.system")}</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
);

View File

@@ -1,41 +1,24 @@
import { Input } from "@/components/ui/input";
import { useForm } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { zodResolver } from "@hookform/resolvers/zod";
import z from "zod";
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form";
import { Button } from "@/components/ui/button";
import { zodResolver } from "@hookform/resolvers/zod";
import { ClientResponseError } from "pocketbase";
import {
Access,
accessFormType,
AliyunConfig,
getUsageByConfigType,
} from "@/domain/access";
import { Button } from "@/components/ui/button";
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import { PbErrorData } from "@/domain/base";
import { Access, AliyunConfig, accessFormType, getUsageByConfigType } from "@/domain/access";
import { save } from "@/repository/access";
import { useConfig } from "@/providers/config";
import { ClientResponseError } from "pocketbase";
import { PbErrorData } from "@/domain/base";
const AccessAliyunForm = ({
data,
op,
onAfterReq,
}: {
data?: Access;
type AccessAliyunFormProps = {
op: "add" | "edit" | "copy";
data?: Access;
onAfterReq: () => void;
}) => {
};
const AccessAliyunForm = ({ data, op, onAfterReq }: AccessAliyunFormProps) => {
const { addAccess, updateAccess } = useConfig();
const { t } = useTranslation();
const formSchema = z.object({
@@ -97,19 +80,17 @@ const AccessAliyunForm = ({
updateAccess(req);
return;
}
console.log(req);
addAccess(req);
} catch (e) {
const err = e as ClientResponseError;
Object.entries(err.response.data as PbErrorData).forEach(
([key, value]) => {
form.setError(key as keyof z.infer<typeof formSchema>, {
type: "manual",
message: value.message,
});
}
);
Object.entries(err.response.data as PbErrorData).forEach(([key, value]) => {
form.setError(key as keyof z.infer<typeof formSchema>, {
type: "manual",
message: value.message,
});
});
return;
}
@@ -133,10 +114,7 @@ const AccessAliyunForm = ({
<FormItem>
<FormLabel>{t("access.authorization.form.name.label")}</FormLabel>
<FormControl>
<Input
placeholder={t("access.authorization.form.name.placeholder")}
{...field}
/>
<Input placeholder={t("access.authorization.form.name.placeholder")} {...field} />
</FormControl>
<FormMessage />
@@ -181,10 +159,7 @@ const AccessAliyunForm = ({
<FormItem>
<FormLabel>{t("access.authorization.form.access_key_id.label")}</FormLabel>
<FormControl>
<Input
placeholder={t("access.authorization.form.access_key_id.placeholder")}
{...field}
/>
<Input placeholder={t("access.authorization.form.access_key_id.placeholder")} {...field} />
</FormControl>
<FormMessage />
@@ -199,10 +174,7 @@ const AccessAliyunForm = ({
<FormItem>
<FormLabel>{t("access.authorization.form.access_key_secret.label")}</FormLabel>
<FormControl>
<Input
placeholder={t("access.authorization.form.access_key_secret.placeholder")}
{...field}
/>
<Input placeholder={t("access.authorization.form.access_key_secret.placeholder")} {...field} />
</FormControl>
<FormMessage />

View File

@@ -1,40 +1,24 @@
import { Input } from "@/components/ui/input";
import { useForm } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { zodResolver } from "@hookform/resolvers/zod";
import z from "zod";
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form";
import { Button } from "@/components/ui/button";
import { zodResolver } from "@hookform/resolvers/zod";
import { ClientResponseError } from "pocketbase";
import {
Access,
accessFormType,
CloudflareConfig,
getUsageByConfigType,
} from "@/domain/access";
import { Button } from "@/components/ui/button";
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import { PbErrorData } from "@/domain/base";
import { Access, accessFormType, CloudflareConfig, getUsageByConfigType } from "@/domain/access";
import { save } from "@/repository/access";
import { useConfig } from "@/providers/config";
import { ClientResponseError } from "pocketbase";
import { PbErrorData } from "@/domain/base";
const AccessCloudflareForm = ({
data,
op,
onAfterReq,
}: {
data?: Access;
type AccessCloudflareFormProps = {
op: "add" | "edit" | "copy";
data?: Access;
onAfterReq: () => void;
}) => {
};
const AccessCloudflareForm = ({ data, op, onAfterReq }: AccessCloudflareFormProps) => {
const { addAccess, updateAccess } = useConfig();
const { t } = useTranslation();
const formSchema = z.object({
@@ -66,7 +50,6 @@ const AccessCloudflareForm = ({
});
const onSubmit = async (data: z.infer<typeof formSchema>) => {
console.log(data);
const req: Access = {
id: data.id as string,
name: data.name,
@@ -94,14 +77,12 @@ const AccessCloudflareForm = ({
} catch (e) {
const err = e as ClientResponseError;
Object.entries(err.response.data as PbErrorData).forEach(
([key, value]) => {
form.setError(key as keyof z.infer<typeof formSchema>, {
type: "manual",
message: value.message,
});
}
);
Object.entries(err.response.data as PbErrorData).forEach(([key, value]) => {
form.setError(key as keyof z.infer<typeof formSchema>, {
type: "manual",
message: value.message,
});
});
}
};
@@ -111,7 +92,6 @@ const AccessCloudflareForm = ({
<Form {...form}>
<form
onSubmit={(e) => {
console.log(e);
e.stopPropagation();
form.handleSubmit(onSubmit)(e);
}}
@@ -124,10 +104,7 @@ const AccessCloudflareForm = ({
<FormItem>
<FormLabel>{t("access.authorization.form.name.label")}</FormLabel>
<FormControl>
<Input
placeholder={t("access.authorization.form.name.placeholder")}
{...field}
/>
<Input placeholder={t("access.authorization.form.name.placeholder")} {...field} />
</FormControl>
<FormMessage />
@@ -172,12 +149,7 @@ const AccessCloudflareForm = ({
<FormItem>
<FormLabel>{t("access.authorization.form.cloud_dns_api_token.label")}</FormLabel>
<FormControl>
<Input
placeholder={t(
"access.authorization.form.cloud_dns_api_token.placeholder"
)}
{...field}
/>
<Input placeholder={t("access.authorization.form.cloud_dns_api_token.placeholder")} {...field} />
</FormControl>
<FormMessage />

View File

@@ -1,51 +1,31 @@
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import { ScrollArea } from "@/components/ui/scroll-area";
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { Access, accessTypeMap } from "@/domain/access";
import { cn } from "@/lib/utils";
import { Label } from "../ui/label";
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectLabel,
SelectTrigger,
SelectValue,
} from "../ui/select";
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog";
import { Label } from "@/components/ui/label";
import { ScrollArea } from "@/components/ui/scroll-area";
import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue } from "@/components/ui/select";
import AccessAliyunForm from "./AccessAliyunForm";
import AccessTencentForm from "./AccessTencentForm";
import AccessHuaweicloudForm from "./AccessHuaweicloudForm";
import AccessQiniuForm from "./AccessQiniuForm";
import AccessCloudflareForm from "./AccessCloudflareForm";
import AccessNamesiloForm from "./AccessNamesiloForm";
import AccessGodaddyFrom from "./AccessGodaddyForm";
import AccessGodaddyForm from "./AccessGodaddyForm";
import AccessLocalForm from "./AccessLocalForm";
import AccessSSHForm from "./AccessSSHForm";
import AccessWebhookForm from "./AccessWebhookFrom";
import AccessWebhookForm from "./AccessWebhookForm";
import { Access, accessTypeMap } from "@/domain/access";
type TargetConfigEditProps = {
type AccessEditProps = {
op: "add" | "edit" | "copy";
className?: string;
trigger: React.ReactNode;
data?: Access;
};
export function AccessEdit({
trigger,
op,
data,
className,
}: TargetConfigEditProps) {
const AccessEdit = ({ trigger, op, data, className }: AccessEditProps) => {
const [open, setOpen] = useState(false);
const { t } = useTranslation();
@@ -123,7 +103,7 @@ export function AccessEdit({
break;
case "godaddy":
form = (
<AccessGodaddyFrom
<AccessGodaddyForm
data={data}
op={op}
onAfterReq={() => {
@@ -179,11 +159,7 @@ export function AccessEdit({
<DialogContent className="sm:max-w-[600px] w-full dark:text-stone-200">
<DialogHeader>
<DialogTitle>
{op == "add"
? t("access.authorization.add")
: op == "edit"
? t("access.authorization.edit")
: t("access.authorization.copy")}
{op == "add" ? t("access.authorization.add") : op == "edit" ? t("access.authorization.edit") : t("access.authorization.copy")}
</DialogTitle>
</DialogHeader>
<ScrollArea className="max-h-[80vh]">
@@ -204,16 +180,8 @@ export function AccessEdit({
<SelectLabel>{t("access.authorization.form.type.list")}</SelectLabel>
{typeKeys.map((key) => (
<SelectItem value={key} key={key}>
<div
className={cn(
"flex items-center space-x-2 rounded cursor-pointer",
getOptionCls(key)
)}
>
<img
src={accessTypeMap.get(key)?.[1]}
className="h-6 w-6"
/>
<div className={cn("flex items-center space-x-2 rounded cursor-pointer", getOptionCls(key))}>
<img src={accessTypeMap.get(key)?.[1]} className="h-6 w-6" />
<div>{t(accessTypeMap.get(key)?.[0] || "")}</div>
</div>
</SelectItem>
@@ -228,4 +196,6 @@ export function AccessEdit({
</DialogContent>
</Dialog>
);
}
};
export default AccessEdit;

View File

@@ -1,40 +1,24 @@
import { Input } from "@/components/ui/input";
import { useForm } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { zodResolver } from "@hookform/resolvers/zod";
import z from "zod";
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form";
import { Button } from "@/components/ui/button";
import { zodResolver } from "@hookform/resolvers/zod";
import { ClientResponseError } from "pocketbase";
import {
Access,
accessFormType,
getUsageByConfigType,
GodaddyConfig,
} from "@/domain/access";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form";
import { PbErrorData } from "@/domain/base";
import { Access, accessFormType, getUsageByConfigType, GodaddyConfig } from "@/domain/access";
import { save } from "@/repository/access";
import { useConfig } from "@/providers/config";
import { ClientResponseError } from "pocketbase";
import { PbErrorData } from "@/domain/base";
const AccessGodaddyFrom = ({
data,
op,
onAfterReq,
}: {
data?: Access;
type AccessGodaddyFormProps = {
op: "add" | "edit" | "copy";
data?: Access;
onAfterReq: () => void;
}) => {
};
const AccessGodaddyForm = ({ data, op, onAfterReq }: AccessGodaddyFormProps) => {
const { addAccess, updateAccess } = useConfig();
const { t } = useTranslation();
const formSchema = z.object({
@@ -72,7 +56,6 @@ const AccessGodaddyFrom = ({
});
const onSubmit = async (data: z.infer<typeof formSchema>) => {
console.log(data);
const req: Access = {
id: data.id as string,
name: data.name,
@@ -101,14 +84,12 @@ const AccessGodaddyFrom = ({
} catch (e) {
const err = e as ClientResponseError;
Object.entries(err.response.data as PbErrorData).forEach(
([key, value]) => {
form.setError(key as keyof z.infer<typeof formSchema>, {
type: "manual",
message: value.message,
});
}
);
Object.entries(err.response.data as PbErrorData).forEach(([key, value]) => {
form.setError(key as keyof z.infer<typeof formSchema>, {
type: "manual",
message: value.message,
});
});
}
};
@@ -118,7 +99,6 @@ const AccessGodaddyFrom = ({
<Form {...form}>
<form
onSubmit={(e) => {
console.log(e);
e.stopPropagation();
form.handleSubmit(onSubmit)(e);
}}
@@ -131,10 +111,7 @@ const AccessGodaddyFrom = ({
<FormItem>
<FormLabel>{t("access.authorization.form.name.label")}</FormLabel>
<FormControl>
<Input
placeholder={t("access.authorization.form.name.placeholder")}
{...field}
/>
<Input placeholder={t("access.authorization.form.name.placeholder")} {...field} />
</FormControl>
<FormMessage />
@@ -179,10 +156,7 @@ const AccessGodaddyFrom = ({
<FormItem>
<FormLabel>{t("access.authorization.form.godaddy_api_key.label")}</FormLabel>
<FormControl>
<Input
placeholder={t("access.authorization.form.godaddy_api_key.placeholder")}
{...field}
/>
<Input placeholder={t("access.authorization.form.godaddy_api_key.placeholder")} {...field} />
</FormControl>
<FormMessage />
@@ -197,12 +171,7 @@ const AccessGodaddyFrom = ({
<FormItem>
<FormLabel>{t("access.authorization.form.godaddy_api_secret.label")}</FormLabel>
<FormControl>
<Input
placeholder={t(
"access.authorization.form.godaddy_api_secret.placeholder"
)}
{...field}
/>
<Input placeholder={t("access.authorization.form.godaddy_api_secret.placeholder")} {...field} />
</FormControl>
<FormMessage />
@@ -220,4 +189,4 @@ const AccessGodaddyFrom = ({
);
};
export default AccessGodaddyFrom;
export default AccessGodaddyForm;

View File

@@ -1,31 +1,18 @@
import { cn } from "@/lib/utils";
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "../ui/dialog";
import { useState } from "react";
import { useForm } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { z } from "zod";
import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "../ui/form";
import { Input } from "../ui/input";
import { Button } from "../ui/button";
import { useConfig } from "@/providers/config";
import { update } from "@/repository/access_group";
import { ClientResponseError } from "pocketbase";
import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button";
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog";
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import { PbErrorData } from "@/domain/base";
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { update } from "@/repository/access_group";
import { useConfig } from "@/providers/config";
type AccessGroupEditProps = {
className?: string;
@@ -65,14 +52,12 @@ const AccessGroupEdit = ({ className, trigger }: AccessGroupEditProps) => {
} catch (e) {
const err = e as ClientResponseError;
Object.entries(err.response.data as PbErrorData).forEach(
([key, value]) => {
form.setError(key as keyof z.infer<typeof formSchema>, {
type: "manual",
message: value.message,
});
}
);
Object.entries(err.response.data as PbErrorData).forEach(([key, value]) => {
form.setError(key as keyof z.infer<typeof formSchema>, {
type: "manual",
message: value.message,
});
});
}
};
@@ -102,11 +87,7 @@ const AccessGroupEdit = ({ className, trigger }: AccessGroupEditProps) => {
<FormItem>
<FormLabel>{t("access.group.form.name.label")}</FormLabel>
<FormControl>
<Input
placeholder={t("access.group.form.name.errmsg.empty")}
{...field}
type="text"
/>
<Input placeholder={t("access.group.form.name.errmsg.empty")} {...field} type="text" />
</FormControl>
<FormMessage />

View File

@@ -1,4 +1,7 @@
import AccessGroupEdit from "@/components/certimate/AccessGroupEdit";
import { useNavigate } from "react-router-dom";
import { useTranslation } from "react-i18next";
import { Group } from "lucide-react";
import Show from "@/components/Show";
import {
AlertDialog,
@@ -12,24 +15,14 @@ import {
AlertDialogTrigger,
} from "@/components/ui/alert-dialog";
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
import { ScrollArea } from "@/components/ui/scroll-area";
import { useToast } from "@/components/ui/use-toast";
import AccessGroupEdit from "./AccessGroupEdit";
import { getProviderInfo } from "@/domain/access";
import { getErrMessage } from "@/lib/error";
import { useConfig } from "@/providers/config";
import { remove } from "@/repository/access_group";
import { Group } from "lucide-react";
import { useToast } from "@/components/ui/use-toast";
import { useNavigate } from "react-router-dom";
import { useTranslation } from "react-i18next";
const AccessGroupList = () => {
const {
@@ -68,13 +61,8 @@ const AccessGroupList = () => {
<Group size={40} className="text-primary" />
</span>
<div className="text-center text-sm text-muted-foreground mt-3">
{t("access.group.domains.nodata")}
</div>
<AccessGroupEdit
trigger={<Button>{t("access.group.add")}</Button>}
className="mt-3"
/>
<div className="text-center text-sm text-muted-foreground mt-3">{t("access.group.domains.nodata")}</div>
<AccessGroupEdit trigger={<Button>{t("access.group.add")}</Button>} className="mt-3" />
</div>
</>
</Show>
@@ -87,9 +75,7 @@ const AccessGroupList = () => {
<CardTitle>{accessGroup.name}</CardTitle>
<CardDescription>
{t("access.group.total", {
total: accessGroup.expand
? accessGroup.expand.access.length
: 0,
total: accessGroup.expand ? accessGroup.expand.access.length : 0,
})}
</CardDescription>
</CardHeader>
@@ -100,19 +86,11 @@ const AccessGroupList = () => {
<div key={access.id} className="flex flex-col mb-3">
<div className="flex items-center">
<div className="">
<img
src={getProviderInfo(access.configType)![1]}
alt="provider"
className="w-8 h-8"
></img>
<img src={getProviderInfo(access.configType)![1]} alt="provider" className="w-8 h-8"></img>
</div>
<div className="ml-3">
<div className="text-sm font-semibold text-gray-700 dark:text-gray-200">
{access.name}
</div>
<div className="text-xs text-muted-foreground">
{getProviderInfo(access.configType)![0]}
</div>
<div className="text-sm font-semibold text-gray-700 dark:text-gray-200">{access.name}</div>
<div className="text-xs text-muted-foreground">{getProviderInfo(access.configType)![0]}</div>
</div>
</div>
</div>
@@ -131,24 +109,15 @@ const AccessGroupList = () => {
</CardContent>
<CardFooter>
<div className="flex justify-end w-full">
<Show
when={
accessGroup.expand && accessGroup.expand.access.length > 0
? true
: false
}
>
<Show when={accessGroup.expand && accessGroup.expand.access.length > 0 ? true : false}>
<div>
<Button
size="sm"
variant={"link"}
onClick={() => {
navigate(
`/access?accessGroupId=${accessGroup.id}&tab=access`,
{
replace: true,
}
);
navigate(`/access?accessGroupId=${accessGroup.id}&tab=access`, {
replace: true,
});
}}
>
{t("access.group.domains")}
@@ -156,14 +125,7 @@ const AccessGroupList = () => {
</div>
</Show>
<Show
when={
!accessGroup.expand ||
accessGroup.expand.access.length == 0
? true
: false
}
>
<Show when={!accessGroup.expand || accessGroup.expand.access.length == 0 ? true : false}>
<div>
<Button size="sm" onClick={handleAddAccess}>
{t("access.authorization.add")}
@@ -180,22 +142,14 @@ const AccessGroupList = () => {
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle className="dark:text-gray-200">
{t("access.group.delete")}
</AlertDialogTitle>
<AlertDialogDescription>
{t("access.group.delete.confirm")}
</AlertDialogDescription>
<AlertDialogTitle className="dark:text-gray-200">{t("access.group.delete")}</AlertDialogTitle>
<AlertDialogDescription>{t("access.group.delete.confirm")}</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel className="dark:text-gray-200">
{t("common.cancel")}
</AlertDialogCancel>
<AlertDialogCancel className="dark:text-gray-200">{t("common.cancel")}</AlertDialogCancel>
<AlertDialogAction
onClick={() => {
handleRemoveClick(
accessGroup.id ? accessGroup.id : ""
);
handleRemoveClick(accessGroup.id ? accessGroup.id : "");
}}
>
{t("common.confirm")}

View File

@@ -1,41 +1,24 @@
import { Input } from "@/components/ui/input";
import { useForm } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { zodResolver } from "@hookform/resolvers/zod";
import z from "zod";
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form";
import { Button } from "@/components/ui/button";
import { zodResolver } from "@hookform/resolvers/zod";
import { ClientResponseError } from "pocketbase";
import {
Access,
accessFormType,
HuaweicloudConfig,
getUsageByConfigType,
} from "@/domain/access";
import { Input } from "@/components/ui/input";
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form";
import { Button } from "@/components/ui/button";
import { PbErrorData } from "@/domain/base";
import { Access, accessFormType, HuaweicloudConfig, getUsageByConfigType } from "@/domain/access";
import { save } from "@/repository/access";
import { useConfig } from "@/providers/config";
import { ClientResponseError } from "pocketbase";
import { PbErrorData } from "@/domain/base";
const AccessHuaweicloudForm = ({
data,
op,
onAfterReq,
}: {
data?: Access;
type AccessHuaweicloudFormProps = {
op: "add" | "edit" | "copy";
data?: Access;
onAfterReq: () => void;
}) => {
};
const AccessHuaweicloudForm = ({ data, op, onAfterReq }: AccessHuaweicloudFormProps) => {
const { addAccess, updateAccess } = useConfig();
const { t } = useTranslation();
const formSchema = z.object({
@@ -104,19 +87,16 @@ const AccessHuaweicloudForm = ({
updateAccess(req);
return;
}
console.log(req);
addAccess(req);
} catch (e) {
const err = e as ClientResponseError;
Object.entries(err.response.data as PbErrorData).forEach(
([key, value]) => {
form.setError(key as keyof z.infer<typeof formSchema>, {
type: "manual",
message: value.message,
});
}
);
Object.entries(err.response.data as PbErrorData).forEach(([key, value]) => {
form.setError(key as keyof z.infer<typeof formSchema>, {
type: "manual",
message: value.message,
});
});
return;
}
@@ -140,10 +120,7 @@ const AccessHuaweicloudForm = ({
<FormItem>
<FormLabel>{t("access.authorization.form.name.label")}</FormLabel>
<FormControl>
<Input
placeholder={t("access.authorization.form.name.placeholder")}
{...field}
/>
<Input placeholder={t("access.authorization.form.name.placeholder")} {...field} />
</FormControl>
<FormMessage />
@@ -188,10 +165,7 @@ const AccessHuaweicloudForm = ({
<FormItem>
<FormLabel>{t("access.authorization.form.region.label")}</FormLabel>
<FormControl>
<Input
placeholder={t("access.authorization.form.region.placeholder")}
{...field}
/>
<Input placeholder={t("access.authorization.form.region.placeholder")} {...field} />
</FormControl>
<FormMessage />
@@ -206,10 +180,7 @@ const AccessHuaweicloudForm = ({
<FormItem>
<FormLabel>{t("access.authorization.form.access_key_id.label")}</FormLabel>
<FormControl>
<Input
placeholder={t("access.authorization.form.access_key_id.placeholder")}
{...field}
/>
<Input placeholder={t("access.authorization.form.access_key_id.placeholder")} {...field} />
</FormControl>
<FormMessage />
@@ -224,10 +195,7 @@ const AccessHuaweicloudForm = ({
<FormItem>
<FormLabel>{t("access.authorization.form.access_key_secret.label")}</FormLabel>
<FormControl>
<Input
placeholder={t("access.authorization.form.access_key_secret.placeholder")}
{...field}
/>
<Input placeholder={t("access.authorization.form.access_key_secret.placeholder")} {...field} />
</FormControl>
<FormMessage />

View File

@@ -1,33 +1,24 @@
import { Access, accessFormType, getUsageByConfigType } from "@/domain/access";
import { useConfig } from "@/providers/config";
import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
import { z } from "zod";
import { useTranslation } from "react-i18next";
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "../ui/form";
import { Input } from "../ui/input";
import { Button } from "../ui/button";
import { save } from "@/repository/access";
import { z } from "zod";
import { zodResolver } from "@hookform/resolvers/zod";
import { ClientResponseError } from "pocketbase";
import { PbErrorData } from "@/domain/base";
const AccessLocalForm = ({
data,
op,
onAfterReq,
}: {
data?: Access;
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { PbErrorData } from "@/domain/base";
import { Access, accessFormType, getUsageByConfigType } from "@/domain/access";
import { save } from "@/repository/access";
import { useConfig } from "@/providers/config";
type AccessLocalFormProps = {
op: "add" | "edit" | "copy";
data?: Access;
onAfterReq: () => void;
}) => {
};
const AccessLocalForm = ({ data, op, onAfterReq }: AccessLocalFormProps) => {
const { addAccess, updateAccess, reloadAccessGroups } = useConfig();
const { t } = useTranslation();
@@ -78,14 +69,12 @@ const AccessLocalForm = ({
} catch (e) {
const err = e as ClientResponseError;
Object.entries(err.response.data as PbErrorData).forEach(
([key, value]) => {
form.setError(key as keyof z.infer<typeof formSchema>, {
type: "manual",
message: value.message,
});
}
);
Object.entries(err.response.data as PbErrorData).forEach(([key, value]) => {
form.setError(key as keyof z.infer<typeof formSchema>, {
type: "manual",
message: value.message,
});
});
return;
}
@@ -109,10 +98,7 @@ const AccessLocalForm = ({
<FormItem>
<FormLabel>{t("access.authorization.form.name.label")}</FormLabel>
<FormControl>
<Input
placeholder={t("access.authorization.form.name.placeholder")}
{...field}
/>
<Input placeholder={t("access.authorization.form.name.placeholder")} {...field} />
</FormControl>
<FormMessage />

View File

@@ -1,40 +1,24 @@
import { Input } from "@/components/ui/input";
import { useForm } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { zodResolver } from "@hookform/resolvers/zod";
import z from "zod";
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form";
import { Button } from "@/components/ui/button";
import { zodResolver } from "@hookform/resolvers/zod";
import { ClientResponseError } from "pocketbase";
import {
Access,
accessFormType,
getUsageByConfigType,
NamesiloConfig,
} from "@/domain/access";
import { Button } from "@/components/ui/button";
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import { PbErrorData } from "@/domain/base";
import { Access, accessFormType, getUsageByConfigType, NamesiloConfig } from "@/domain/access";
import { save } from "@/repository/access";
import { useConfig } from "@/providers/config";
import { ClientResponseError } from "pocketbase";
import { PbErrorData } from "@/domain/base";
const AccessNamesiloForm = ({
data,
op,
onAfterReq,
}: {
data?: Access;
type AccessNamesiloFormProps = {
op: "add" | "edit" | "copy";
data?: Access;
onAfterReq: () => void;
}) => {
};
const AccessNamesiloForm = ({ data, op, onAfterReq }: AccessNamesiloFormProps) => {
const { addAccess, updateAccess } = useConfig();
const { t } = useTranslation();
const formSchema = z.object({
@@ -93,14 +77,12 @@ const AccessNamesiloForm = ({
} catch (e) {
const err = e as ClientResponseError;
Object.entries(err.response.data as PbErrorData).forEach(
([key, value]) => {
form.setError(key as keyof z.infer<typeof formSchema>, {
type: "manual",
message: value.message,
});
}
);
Object.entries(err.response.data as PbErrorData).forEach(([key, value]) => {
form.setError(key as keyof z.infer<typeof formSchema>, {
type: "manual",
message: value.message,
});
});
}
};
@@ -110,7 +92,6 @@ const AccessNamesiloForm = ({
<Form {...form}>
<form
onSubmit={(e) => {
console.log(e);
e.stopPropagation();
form.handleSubmit(onSubmit)(e);
}}
@@ -123,10 +104,7 @@ const AccessNamesiloForm = ({
<FormItem>
<FormLabel>{t("access.authorization.form.name.label")}</FormLabel>
<FormControl>
<Input
placeholder={t("access.authorization.form.name.placeholder")}
{...field}
/>
<Input placeholder={t("access.authorization.form.name.placeholder")} {...field} />
</FormControl>
<FormMessage />
@@ -171,10 +149,7 @@ const AccessNamesiloForm = ({
<FormItem>
<FormLabel>{t("access.authorization.form.namesilo_api_key.label")}</FormLabel>
<FormControl>
<Input
placeholder={t("access.authorization.form.namesilo_api_key.placeholder")}
{...field}
/>
<Input placeholder={t("access.authorization.form.namesilo_api_key.placeholder")} {...field} />
</FormControl>
<FormMessage />

View File

@@ -1,41 +1,24 @@
import { Input } from "@/components/ui/input";
import { useForm } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { zodResolver } from "@hookform/resolvers/zod";
import z from "zod";
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form";
import { Button } from "@/components/ui/button";
import { zodResolver } from "@hookform/resolvers/zod";
import { ClientResponseError } from "pocketbase";
import {
Access,
accessFormType,
getUsageByConfigType,
QiniuConfig,
} from "@/domain/access";
import { Button } from "@/components/ui/button";
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import { PbErrorData } from "@/domain/base";
import { Access, accessFormType, getUsageByConfigType, QiniuConfig } from "@/domain/access";
import { save } from "@/repository/access";
import { useConfig } from "@/providers/config";
import { ClientResponseError } from "pocketbase";
import { PbErrorData } from "@/domain/base";
const AccessQiniuForm = ({
data,
op,
onAfterReq,
}: {
data?: Access;
type AccessQiniuFormProps = {
op: "add" | "edit" | "copy";
data?: Access;
onAfterReq: () => void;
}) => {
};
const AccessQiniuForm = ({ data, op, onAfterReq }: AccessQiniuFormProps) => {
const { addAccess, updateAccess } = useConfig();
const { t } = useTranslation();
const formSchema = z.object({
@@ -95,14 +78,12 @@ const AccessQiniuForm = ({
} catch (e) {
const err = e as ClientResponseError;
Object.entries(err.response.data as PbErrorData).forEach(
([key, value]) => {
form.setError(key as keyof z.infer<typeof formSchema>, {
type: "manual",
message: value.message,
});
}
);
Object.entries(err.response.data as PbErrorData).forEach(([key, value]) => {
form.setError(key as keyof z.infer<typeof formSchema>, {
type: "manual",
message: value.message,
});
});
return;
}
@@ -126,10 +107,7 @@ const AccessQiniuForm = ({
<FormItem>
<FormLabel>{t("access.authorization.form.name.label")}</FormLabel>
<FormControl>
<Input
placeholder={t("access.authorization.form.name.placeholder")}
{...field}
/>
<Input placeholder={t("access.authorization.form.name.placeholder")} {...field} />
</FormControl>
<FormMessage />
@@ -174,10 +152,7 @@ const AccessQiniuForm = ({
<FormItem>
<FormLabel>{t("access.authorization.form.access_key.label")}</FormLabel>
<FormControl>
<Input
placeholder={t("access.authorization.form.access_key.placeholder")}
{...field}
/>
<Input placeholder={t("access.authorization.form.access_key.placeholder")} {...field} />
</FormControl>
<FormMessage />
@@ -192,10 +167,7 @@ const AccessQiniuForm = ({
<FormItem>
<FormLabel>{t("access.authorization.form.secret_key.label")}</FormLabel>
<FormControl>
<Input
placeholder={t("access.authorization.form.secret_key.placeholder")}
{...field}
/>
<Input placeholder={t("access.authorization.form.secret_key.placeholder")} {...field} />
</FormControl>
<FormMessage />

View File

@@ -1,50 +1,31 @@
import {
Access,
accessFormType,
getUsageByConfigType,
SSHConfig,
} from "@/domain/access";
import { useConfig } from "@/providers/config";
import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
import { z } from "zod";
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "../ui/form";
import { Input } from "../ui/input";
import { Button } from "../ui/button";
import { save } from "@/repository/access";
import { ClientResponseError } from "pocketbase";
import { PbErrorData } from "@/domain/base";
import { readFileContent } from "@/lib/file";
import { useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "../ui/select";
import { cn } from "@/lib/utils";
import AccessGroupEdit from "./AccessGroupEdit";
import { useForm } from "react-hook-form";
import { z } from "zod";
import { zodResolver } from "@hookform/resolvers/zod";
import { Plus } from "lucide-react";
import { updateById } from "@/repository/access_group";
import { ClientResponseError } from "pocketbase";
const AccessSSHForm = ({
data,
op,
onAfterReq,
}: {
data?: Access;
import { Access, accessFormType, getUsageByConfigType, SSHConfig } from "@/domain/access";
import { Button } from "@/components/ui/button";
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import AccessGroupEdit from "./AccessGroupEdit";
import { readFileContent } from "@/lib/file";
import { cn } from "@/lib/utils";
import { PbErrorData } from "@/domain/base";
import { save } from "@/repository/access";
import { updateById } from "@/repository/access_group";
import { useConfig } from "@/providers/config";
type AccessSSHFormProps = {
op: "add" | "edit" | "copy";
data?: Access;
onAfterReq: () => void;
}) => {
};
const AccessSSHForm = ({ data, op, onAfterReq }: AccessSSHFormProps) => {
const {
addAccess,
updateAccess,
@@ -179,22 +160,18 @@ const AccessSSHForm = ({
} catch (e) {
const err = e as ClientResponseError;
Object.entries(err.response.data as PbErrorData).forEach(
([key, value]) => {
form.setError(key as keyof z.infer<typeof formSchema>, {
type: "manual",
message: value.message,
});
}
);
Object.entries(err.response.data as PbErrorData).forEach(([key, value]) => {
form.setError(key as keyof z.infer<typeof formSchema>, {
type: "manual",
message: value.message,
});
});
return;
}
};
const handleFileChange = async (
event: React.ChangeEvent<HTMLInputElement>
) => {
const handleFileChange = async (event: React.ChangeEvent<HTMLInputElement>) => {
const file = event.target.files?.[0];
if (!file) return;
const savedFile = file;
@@ -204,8 +181,6 @@ const AccessSSHForm = ({
};
const handleSelectFileClick = () => {
console.log(fileInputRef.current);
fileInputRef.current?.click();
};
@@ -225,16 +200,9 @@ const AccessSSHForm = ({
name="name"
render={({ field }) => (
<FormItem>
<FormLabel>
{t("access.authorization.form.name.label")}
</FormLabel>
<FormLabel>{t("access.authorization.form.name.label")}</FormLabel>
<FormControl>
<Input
placeholder={t(
"access.authorization.form.name.placeholder"
)}
{...field}
/>
<Input placeholder={t("access.authorization.form.name.placeholder")} {...field} />
</FormControl>
<FormMessage />
@@ -268,34 +236,15 @@ const AccessSSHForm = ({
}}
>
<SelectTrigger>
<SelectValue
placeholder={t(
"access.authorization.form.access_group.placeholder"
)}
/>
<SelectValue placeholder={t("access.authorization.form.access_group.placeholder")} />
</SelectTrigger>
<SelectContent>
<SelectItem value="emptyId">
<div
className={cn(
"flex items-center space-x-2 rounded cursor-pointer"
)}
>
--
</div>
<div className={cn("flex items-center space-x-2 rounded cursor-pointer")}>--</div>
</SelectItem>
{accessGroups.map((item) => (
<SelectItem
value={item.id ? item.id : ""}
key={item.id}
>
<div
className={cn(
"flex items-center space-x-2 rounded cursor-pointer"
)}
>
{item.name}
</div>
<SelectItem value={item.id ? item.id : ""} key={item.id}>
<div className={cn("flex items-center space-x-2 rounded cursor-pointer")}>{item.name}</div>
</SelectItem>
))}
</SelectContent>
@@ -312,9 +261,7 @@ const AccessSSHForm = ({
name="id"
render={({ field }) => (
<FormItem className="hidden">
<FormLabel>
{t("access.authorization.form.config.label")}
</FormLabel>
<FormLabel>{t("access.authorization.form.config.label")}</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
@@ -329,9 +276,7 @@ const AccessSSHForm = ({
name="configType"
render={({ field }) => (
<FormItem className="hidden">
<FormLabel>
{t("access.authorization.form.config.label")}
</FormLabel>
<FormLabel>{t("access.authorization.form.config.label")}</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
@@ -346,16 +291,9 @@ const AccessSSHForm = ({
name="host"
render={({ field }) => (
<FormItem className="grow">
<FormLabel>
{t("access.authorization.form.ssh_host.label")}
</FormLabel>
<FormLabel>{t("access.authorization.form.ssh_host.label")}</FormLabel>
<FormControl>
<Input
placeholder={t(
"access.authorization.form.ssh_host.placeholder"
)}
{...field}
/>
<Input placeholder={t("access.authorization.form.ssh_host.placeholder")} {...field} />
</FormControl>
<FormMessage />
@@ -368,17 +306,9 @@ const AccessSSHForm = ({
name="port"
render={({ field }) => (
<FormItem>
<FormLabel>
{t("access.authorization.form.ssh_port.label")}
</FormLabel>
<FormLabel>{t("access.authorization.form.ssh_port.label")}</FormLabel>
<FormControl>
<Input
placeholder={t(
"access.authorization.form.ssh_port.placeholder"
)}
{...field}
type="number"
/>
<Input placeholder={t("access.authorization.form.ssh_port.placeholder")} {...field} type="number" />
</FormControl>
<FormMessage />
@@ -392,16 +322,9 @@ const AccessSSHForm = ({
name="username"
render={({ field }) => (
<FormItem>
<FormLabel>
{t("access.authorization.form.username.label")}
</FormLabel>
<FormLabel>{t("access.authorization.form.username.label")}</FormLabel>
<FormControl>
<Input
placeholder={t(
"access.authorization.form.username.placeholder"
)}
{...field}
/>
<Input placeholder={t("access.authorization.form.username.placeholder")} {...field} />
</FormControl>
<FormMessage />
@@ -414,17 +337,9 @@ const AccessSSHForm = ({
name="password"
render={({ field }) => (
<FormItem>
<FormLabel>
{t("access.authorization.form.password.label")}
</FormLabel>
<FormLabel>{t("access.authorization.form.password.label")}</FormLabel>
<FormControl>
<Input
placeholder={t(
"access.authorization.form.password.placeholder"
)}
{...field}
type="password"
/>
<Input placeholder={t("access.authorization.form.password.placeholder")} {...field} type="password" />
</FormControl>
<FormMessage />
@@ -437,16 +352,9 @@ const AccessSSHForm = ({
name="key"
render={({ field }) => (
<FormItem hidden>
<FormLabel>
{t("access.authorization.form.ssh_key.label")}
</FormLabel>
<FormLabel>{t("access.authorization.form.ssh_key.label")}</FormLabel>
<FormControl>
<Input
placeholder={t(
"access.authorization.form.ssh_key.placeholder"
)}
{...field}
/>
<Input placeholder={t("access.authorization.form.ssh_key.placeholder")} {...field} />
</FormControl>
<FormMessage />
@@ -459,28 +367,14 @@ const AccessSSHForm = ({
name="keyFile"
render={({ field }) => (
<FormItem>
<FormLabel>
{t("access.authorization.form.ssh_key.label")}
</FormLabel>
<FormLabel>{t("access.authorization.form.ssh_key.label")}</FormLabel>
<FormControl>
<div>
<Button
type={"button"}
variant={"secondary"}
size={"sm"}
className="w-48"
onClick={handleSelectFileClick}
>
{fileName
? fileName
: t(
"access.authorization.form.ssh_key_file.placeholder"
)}
<Button type={"button"} variant={"secondary"} size={"sm"} className="w-48" onClick={handleSelectFileClick}>
{fileName ? fileName : t("access.authorization.form.ssh_key_file.placeholder")}
</Button>
<Input
placeholder={t(
"access.authorization.form.ssh_key.placeholder"
)}
placeholder={t("access.authorization.form.ssh_key.placeholder")}
{...field}
ref={fileInputRef}
className="hidden"

View File

@@ -1,40 +1,24 @@
import { Input } from "@/components/ui/input";
import { useForm } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { zodResolver } from "@hookform/resolvers/zod";
import z from "zod";
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form";
import { Button } from "@/components/ui/button";
import { zodResolver } from "@hookform/resolvers/zod";
import { ClientResponseError } from "pocketbase";
import {
Access,
accessFormType,
getUsageByConfigType,
TencentConfig,
} from "@/domain/access";
import { Button } from "@/components/ui/button";
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import { PbErrorData } from "@/domain/base";
import { Access, accessFormType, getUsageByConfigType, TencentConfig } from "@/domain/access";
import { save } from "@/repository/access";
import { useConfig } from "@/providers/config";
import { ClientResponseError } from "pocketbase";
import { PbErrorData } from "@/domain/base";
const AccessTencentForm = ({
data,
op,
onAfterReq,
}: {
data?: Access;
type AccessTencentFormProps = {
op: "add" | "edit" | "copy";
data?: Access;
onAfterReq: () => void;
}) => {
};
const AccessTencentForm = ({ data, op, onAfterReq }: AccessTencentFormProps) => {
const { addAccess, updateAccess } = useConfig();
const { t } = useTranslation();
const formSchema = z.object({
@@ -100,14 +84,12 @@ const AccessTencentForm = ({
} catch (e) {
const err = e as ClientResponseError;
Object.entries(err.response.data as PbErrorData).forEach(
([key, value]) => {
form.setError(key as keyof z.infer<typeof formSchema>, {
type: "manual",
message: value.message,
});
}
);
Object.entries(err.response.data as PbErrorData).forEach(([key, value]) => {
form.setError(key as keyof z.infer<typeof formSchema>, {
type: "manual",
message: value.message,
});
});
}
};
@@ -129,10 +111,7 @@ const AccessTencentForm = ({
<FormItem>
<FormLabel>{t("access.authorization.form.name.label")}</FormLabel>
<FormControl>
<Input
placeholder={t("access.authorization.form.name.placeholder")}
{...field}
/>
<Input placeholder={t("access.authorization.form.name.placeholder")} {...field} />
</FormControl>
<FormMessage />
@@ -177,10 +156,7 @@ const AccessTencentForm = ({
<FormItem>
<FormLabel>{t("access.authorization.form.secret_id.label")}</FormLabel>
<FormControl>
<Input
placeholder={t("access.authorization.form.secret_id.placeholder")}
{...field}
/>
<Input placeholder={t("access.authorization.form.secret_id.placeholder")} {...field} />
</FormControl>
<FormMessage />
@@ -195,10 +171,7 @@ const AccessTencentForm = ({
<FormItem>
<FormLabel>{t("access.authorization.form.secret_key.label")}</FormLabel>
<FormControl>
<Input
placeholder={t("access.authorization.form.secret_key.placeholder")}
{...field}
/>
<Input placeholder={t("access.authorization.form.secret_key.placeholder")} {...field} />
</FormControl>
<FormMessage />

View File

@@ -1,40 +1,24 @@
import { Input } from "@/components/ui/input";
import { useForm } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { zodResolver } from "@hookform/resolvers/zod";
import z from "zod";
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form";
import { Button } from "@/components/ui/button";
import { zodResolver } from "@hookform/resolvers/zod";
import { ClientResponseError } from "pocketbase";
import {
Access,
accessFormType,
getUsageByConfigType,
WebhookConfig,
} from "@/domain/access";
import { Button } from "@/components/ui/button";
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import { PbErrorData } from "@/domain/base";
import { Access, accessFormType, getUsageByConfigType, WebhookConfig } from "@/domain/access";
import { save } from "@/repository/access";
import { useConfig } from "@/providers/config";
import { ClientResponseError } from "pocketbase";
import { PbErrorData } from "@/domain/base";
const WebhookForm = ({
data,
op,
onAfterReq,
}: {
data?: Access;
type AccessWebhookFormProps = {
op: "add" | "edit" | "copy";
data?: Access;
onAfterReq: () => void;
}) => {
};
const AccessWebhookForm = ({ data, op, onAfterReq }: AccessWebhookFormProps) => {
const { addAccess, updateAccess } = useConfig();
const { t } = useTranslation();
const formSchema = z.object({
@@ -90,14 +74,12 @@ const WebhookForm = ({
} catch (e) {
const err = e as ClientResponseError;
Object.entries(err.response.data as PbErrorData).forEach(
([key, value]) => {
form.setError(key as keyof z.infer<typeof formSchema>, {
type: "manual",
message: value.message,
});
}
);
Object.entries(err.response.data as PbErrorData).forEach(([key, value]) => {
form.setError(key as keyof z.infer<typeof formSchema>, {
type: "manual",
message: value.message,
});
});
}
};
@@ -107,7 +89,6 @@ const WebhookForm = ({
<Form {...form}>
<form
onSubmit={(e) => {
console.log(e);
e.stopPropagation();
form.handleSubmit(onSubmit)(e);
}}
@@ -120,10 +101,7 @@ const WebhookForm = ({
<FormItem>
<FormLabel>{t("access.authorization.form.name.label")}</FormLabel>
<FormControl>
<Input
placeholder={t("access.authorization.form.name.placeholder")}
{...field}
/>
<Input placeholder={t("access.authorization.form.name.placeholder")} {...field} />
</FormControl>
<FormMessage />
@@ -168,10 +146,7 @@ const WebhookForm = ({
<FormItem>
<FormLabel>{t("access.authorization.form.webhook_url.label")}</FormLabel>
<FormControl>
<Input
placeholder={t("access.authorization.form.webhook_url.placeholder")}
{...field}
/>
<Input placeholder={t("access.authorization.form.webhook_url.placeholder")} {...field} />
</FormControl>
<FormMessage />
@@ -189,4 +164,4 @@ const WebhookForm = ({
);
};
export default WebhookForm;
export default AccessWebhookForm;

View File

@@ -1,50 +1,23 @@
import {
createContext,
useCallback,
useContext,
useEffect,
useState,
} from "react";
import { Button } from "../ui/button";
import { EditIcon, Plus, Trash2 } from "lucide-react";
import {
DeployConfig,
KVType,
targetTypeKeys,
targetTypeMap,
} from "@/domain/domain";
import Show from "../Show";
import { Alert, AlertDescription } from "../ui/alert";
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "../ui/dialog";
import { Label } from "../ui/label";
import { useConfig } from "@/providers/config";
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectLabel,
SelectTrigger,
SelectValue,
} from "../ui/select";
import { accessTypeMap } from "@/domain/access";
import { createContext, useCallback, useContext, useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { AccessEdit } from "./AccessEdit";
import { Input } from "../ui/input";
import { Textarea } from "../ui/textarea";
import KVList from "./KVList";
import { z } from "zod";
import { produce } from "immer";
import { nanoid } from "nanoid";
import { z } from "zod";
import { EditIcon, Plus, Trash2 } from "lucide-react";
import Show from "@/components/Show";
import { Alert, AlertDescription } from "@/components/ui/alert";
import { Button } from "@/components/ui/button";
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Textarea } from "@/components/ui/textarea";
import AccessEdit from "./AccessEdit";
import KVList from "./KVList";
import { DeployConfig, KVType, targetTypeKeys, targetTypeMap } from "@/domain/domain";
import { accessTypeMap } from "@/domain/access";
import { useConfig } from "@/providers/config";
type DeployEditContextProps = {
deploy: DeployConfig;
@@ -53,9 +26,7 @@ type DeployEditContextProps = {
setError: (error: Record<string, string>) => void;
};
const DeployEditContext = createContext<DeployEditContextProps>(
{} as DeployEditContextProps
);
const DeployEditContext = createContext<DeployEditContextProps>({} as DeployEditContextProps);
export const useDeployEditContext = () => {
return useContext(DeployEditContext);
@@ -156,11 +127,14 @@ const DeployList = ({ deploys, onChange }: DeployListProps) => {
);
};
export default DeployList;
type DeployItemProps = {
item: DeployConfig;
onDelete: () => void;
onSave: (deploy: DeployConfig) => void;
};
const DeployItem = ({ item, onDelete, onSave }: DeployItemProps) => {
const {
config: { accesses },
@@ -232,11 +206,8 @@ type DeployEditDialogProps = {
deployConfig?: DeployConfig;
onSave: (deploy: DeployConfig) => void;
};
const DeployEditDialog = ({
trigger,
deployConfig,
onSave,
}: DeployEditDialogProps) => {
const DeployEditDialog = ({ trigger, deployConfig, onSave }: DeployEditDialogProps) => {
const {
config: { accesses },
} = useConfig();
@@ -265,13 +236,14 @@ const DeployEditDialog = ({
useEffect(() => {
const temp = locDeployConfig.type.split("-");
console.log(temp);
let t;
if (temp && temp.length > 1) {
t = temp[1];
} else {
t = locDeployConfig.type;
}
setDeployType(t as TargetType);
setError({});
}, [locDeployConfig.type]);
@@ -366,22 +338,15 @@ const DeployEditDialog = ({
}}
>
<SelectTrigger className="mt-2">
<SelectValue
placeholder={t("domain.deployment.form.type.placeholder")}
/>
<SelectValue placeholder={t("domain.deployment.form.type.placeholder")} />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectLabel>
{t("domain.deployment.form.type.list")}
</SelectLabel>
<SelectLabel>{t("domain.deployment.form.type.list")}</SelectLabel>
{targetTypeKeys.map((item) => (
<SelectItem key={item} value={item}>
<div className="flex items-center space-x-2">
<img
className="w-6"
src={targetTypeMap.get(item)?.[1]}
/>
<img className="w-6" src={targetTypeMap.get(item)?.[1]} />
<div>{t(targetTypeMap.get(item)?.[0] ?? "")}</div>
</div>
</SelectItem>
@@ -415,24 +380,15 @@ const DeployEditDialog = ({
}}
>
<SelectTrigger className="mt-2">
<SelectValue
placeholder={t(
"domain.deployment.form.access.placeholder"
)}
/>
<SelectValue placeholder={t("domain.deployment.form.access.placeholder")} />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectLabel>
{t("domain.deployment.form.access.list")}
</SelectLabel>
<SelectLabel>{t("domain.deployment.form.access.list")}</SelectLabel>
{targetAccesses.map((item) => (
<SelectItem key={item.id} value={item.id}>
<div className="flex items-center space-x-2">
<img
className="w-6"
src={accessTypeMap.get(item.configType)?.[1]}
/>
<img className="w-6" src={accessTypeMap.get(item.configType)?.[1]} />
<div>{item.name}</div>
</div>
</SelectItem>
@@ -468,29 +424,30 @@ type TargetType = "ssh" | "cdn" | "webhook" | "local" | "oss" | "dcdn";
type DeployEditProps = {
type: TargetType;
};
const DeployEdit = ({ type }: DeployEditProps) => {
const getDeploy = () => {
switch (type) {
case "ssh":
return <DeploySSH />;
return <DeployToSSH />;
case "local":
return <DeploySSH />;
return <DeployToSSH />;
case "cdn":
return <DeployCDN />;
return <DeployToCDN />;
case "dcdn":
return <DeployCDN />;
return <DeployToCDN />;
case "oss":
return <DeployOSS />;
return <DeployToOSS />;
case "webhook":
return <DeployWebhook />;
return <DeployToWebhook />;
default:
return <DeployCDN />;
return <DeployToCDN />;
}
};
return getDeploy();
};
const DeploySSH = () => {
const DeployToSSH = () => {
const { t } = useTranslation();
const { setError } = useDeployEditContext();
@@ -536,9 +493,7 @@ const DeploySSH = () => {
<div>
<Label>{t("access.authorization.form.ssh_key_path.label")}</Label>
<Input
placeholder={t(
"access.authorization.form.ssh_key_path.placeholder"
)}
placeholder={t("access.authorization.form.ssh_key_path.placeholder")}
className="w-full mt-1"
value={data?.config?.keyPath}
onChange={(e) => {
@@ -558,9 +513,7 @@ const DeploySSH = () => {
<Textarea
className="mt-1"
value={data?.config?.preCommand}
placeholder={t(
"access.authorization.form.ssh_pre_command.placeholder"
)}
placeholder={t("access.authorization.form.ssh_pre_command.placeholder")}
onChange={(e) => {
const newData = produce(data, (draft) => {
if (!draft.config) {
@@ -595,7 +548,7 @@ const DeploySSH = () => {
);
};
const DeployCDN = () => {
const DeployToCDN = () => {
const { deploy: data, setDeploy, error, setError } = useDeployEditContext();
const { t } = useTranslation();
@@ -619,20 +572,16 @@ const DeployCDN = () => {
}
}, [data]);
const domainSchema = z
.string()
.regex(/^(?:\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$/, {
message: t("common.errmsg.domain_invalid"),
});
const domainSchema = z.string().regex(/^(?:\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$/, {
message: t("common.errmsg.domain_invalid"),
});
return (
<div className="flex flex-col space-y-2">
<div>
<Label>{t("domain.deployment.form.cdn_domain.label")}</Label>
<Input
placeholder={t(
"domain.deployment.form.cdn_domain.placeholder"
)}
placeholder={t("domain.deployment.form.cdn_domain.placeholder")}
className="w-full mt-1"
value={data?.config?.domain}
onChange={(e) => {
@@ -666,7 +615,7 @@ const DeployCDN = () => {
);
};
const DeployOSS = () => {
const DeployToOSS = () => {
const { deploy: data, setDeploy, error, setError } = useDeployEditContext();
const { t } = useTranslation();
@@ -718,11 +667,9 @@ const DeployOSS = () => {
}
}, []);
const domainSchema = z
.string()
.regex(/^(?:\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$/, {
message: t("common.errmsg.domain_invalid"),
});
const domainSchema = z.string().regex(/^(?:\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$/, {
message: t("common.errmsg.domain_invalid"),
});
const bucketSchema = z.string().min(1, {
message: t("domain.deployment.form.oss_bucket.placeholder"),
@@ -752,9 +699,7 @@ const DeployOSS = () => {
<Label>{t("domain.deployment.form.oss_bucket")}</Label>
<Input
placeholder={t(
"domain.deployment.form.oss_bucket.placeholder"
)}
placeholder={t("domain.deployment.form.oss_bucket.placeholder")}
className="w-full mt-1"
value={data?.config?.bucket}
onChange={(e) => {
@@ -820,7 +765,7 @@ const DeployOSS = () => {
);
};
const DeployWebhook = () => {
const DeployToWebhook = () => {
const { deploy: data, setDeploy } = useDeployEditContext();
const { setError } = useDeployEditContext();
@@ -846,5 +791,3 @@ const DeployWebhook = () => {
</>
);
};
export default DeployList;

View File

@@ -1,9 +1,8 @@
import { useTranslation } from "react-i18next";
import { Separator } from "@/components/ui/separator";
import { cn } from "@/lib/utils";
import { Separator } from "../ui/separator";
type DeployProgressProps = {
phase?: "check" | "apply" | "deploy";
phaseSuccess?: boolean;
@@ -24,18 +23,10 @@ const DeployProgress = ({ phase, phaseSuccess }: DeployProgressProps) => {
return (
<div className="flex items-center">
<div
className={cn(
"text-xs text-nowrap",
step === 1 ? (phaseSuccess ? "text-green-600" : "text-red-600") : "",
step > 1 ? "text-green-600" : ""
)}
>
<div className={cn("text-xs text-nowrap", step === 1 ? (phaseSuccess ? "text-green-600" : "text-red-600") : "", step > 1 ? "text-green-600" : "")}>
{t("history.props.stage.progress.check")}
</div>
<Separator
className={cn("h-1 grow max-w-[60px]", step > 1 ? "bg-green-600" : "")}
/>
<Separator className={cn("h-1 grow max-w-[60px]", step > 1 ? "bg-green-600" : "")} />
<div
className={cn(
"text-xs text-nowrap",
@@ -46,9 +37,7 @@ const DeployProgress = ({ phase, phaseSuccess }: DeployProgressProps) => {
>
{t("history.props.stage.progress.apply")}
</div>
<Separator
className={cn("h-1 grow max-w-[60px]", step > 2 ? "bg-green-600" : "")}
/>
<Separator className={cn("h-1 grow max-w-[60px]", step > 2 ? "bg-green-600" : "")} />
<div
className={cn(
"text-xs text-nowrap",

View File

@@ -1,11 +1,7 @@
import { Deployment } from "@/domain/deployment";
import { CircleCheck, CircleX } from "lucide-react";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "../ui/tooltip";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
import { Deployment } from "@/domain/deployment";
type DeployStateProps = {
deployment: Deployment;
@@ -32,9 +28,7 @@ const DeployState = ({ deployment }: DeployStateProps) => {
<TooltipTrigger asChild className="cursor-pointer">
<CircleX size={16} className="text-red-700" />
</TooltipTrigger>
<TooltipContent className="max-w-[35em]">
{error(deployment.phase)}
</TooltipContent>
<TooltipContent className="max-w-[35em]">{error(deployment.phase)}</TooltipContent>
</Tooltip>
</TooltipProvider>
) : (

View File

@@ -1,32 +1,19 @@
import { cn } from "@/lib/utils";
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "../ui/dialog";
import { z } from "zod";
import { zodResolver } from "@hookform/resolvers/zod";
import { useState } from "react";
import { useForm } from "react-hook-form";
import { useTranslation } from "react-i18next";
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "../ui/form";
import { Input } from "../ui/input";
import { Button } from "../ui/button";
import { useConfig } from "@/providers/config";
import { update } from "@/repository/settings";
import { z } from "zod";
import { zodResolver } from "@hookform/resolvers/zod";
import { ClientResponseError } from "pocketbase";
import { Button } from "@/components/ui/button";
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog";
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import { cn } from "@/lib/utils";
import { PbErrorData } from "@/domain/base";
import { useState } from "react";
import { EmailsSetting } from "@/domain/settings";
import { update } from "@/repository/settings";
import { useConfig } from "@/providers/config";
type EmailsEditProps = {
className?: string;
@@ -84,14 +71,12 @@ const EmailsEdit = ({ className, trigger }: EmailsEditProps) => {
} catch (e) {
const err = e as ClientResponseError;
Object.entries(err.response.data as PbErrorData).forEach(
([key, value]) => {
form.setError(key as keyof z.infer<typeof formSchema>, {
type: "manual",
message: value.message,
});
}
);
Object.entries(err.response.data as PbErrorData).forEach(([key, value]) => {
form.setError(key as keyof z.infer<typeof formSchema>, {
type: "manual",
message: value.message,
});
});
}
};
@@ -109,7 +94,6 @@ const EmailsEdit = ({ className, trigger }: EmailsEditProps) => {
<Form {...form}>
<form
onSubmit={(e) => {
console.log(e);
e.stopPropagation();
form.handleSubmit(onSubmit)(e);
}}
@@ -122,11 +106,7 @@ const EmailsEdit = ({ className, trigger }: EmailsEditProps) => {
<FormItem>
<FormLabel>{t("domain.application.form.email.label")}</FormLabel>
<FormControl>
<Input
placeholder={t("common.errmsg.email_empty")}
{...field}
type="email"
/>
<Input placeholder={t("common.errmsg.email_empty")} {...field} type="email" />
</FormControl>
<FormMessage />

View File

@@ -1,21 +1,14 @@
import { KVType } from "@/domain/domain";
import { useEffect, useState } from "react";
import { Label } from "../ui/label";
import { Edit, Plus, Trash2 } from "lucide-react";
import { useTranslation } from "react-i18next";
import Show from "../Show";
import {
Dialog,
DialogContent,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "../ui/dialog";
import { Input } from "../ui/input";
import { Button } from "../ui/button";
import { produce } from "immer";
import { Edit, Plus, Trash2 } from "lucide-react";
import Show from "@/components/Show";
import { Button } from "@/components/ui/button";
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { KVType } from "@/domain/domain";
type KVListProps = {
variables?: KVType[];
@@ -96,9 +89,7 @@ const KVList = ({ variables, onValueChange }: KVListProps) => {
when={!!locVariables?.length}
fallback={
<div className="border rounded-md p-3 text-sm mt-2 flex flex-col items-center">
<div className="text-muted-foreground">
{t("domain.deployment.form.variables.empty")}
</div>
<div className="text-muted-foreground">{t("domain.deployment.form.variables.empty")}</div>
<KVEdit
trigger={

View File

@@ -1,22 +1,15 @@
import { cn } from "@/lib/utils";
import Show from "../Show";
import { useCallback, useEffect, useMemo, useState } from "react";
import { FormControl, FormLabel } from "../ui/form";
import { Button } from "../ui/button";
import {
Dialog,
DialogContent,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "../ui/dialog";
import { Input } from "../ui/input";
import { z } from "zod";
import { useTranslation } from "react-i18next";
import { Edit, Plus, Trash2 } from "lucide-react";
import Show from "@/components/Show";
import { Button } from "@/components/ui/button";
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog";
import { FormControl, FormLabel } from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import { cn } from "@/lib/utils";
type StringListProps = {
className?: string;
value: string;
@@ -30,12 +23,7 @@ const titles: Record<string, string> = {
dns: "common.text.dns",
};
const StringList = ({
value,
className,
onValueChange,
valueType = "domain",
}: StringListProps) => {
const StringList = ({ value, className, onValueChange, valueType = "domain" }: StringListProps) => {
const [list, setList] = useState<string[]>([]);
const { t } = useTranslation();
@@ -101,16 +89,9 @@ const StringList = ({
when={list.length > 0}
fallback={
<div className="border rounded-md p-3 text-sm mt-2 flex flex-col items-center">
<div className="text-muted-foreground">
{t('common.text.' + valueType + '.empty')}
</div>
<div className="text-muted-foreground">{t("common.text." + valueType + ".empty")}</div>
<StringEdit
value={""}
trigger={t("common.add")}
onValueChange={addVal}
valueType={valueType}
/>
<StringEdit value={""} trigger={t("common.add")} onValueChange={addVal} valueType={valueType} />
</div>
}
>
@@ -122,12 +103,7 @@ const StringList = ({
<StringEdit
op="edit"
valueType={valueType}
trigger={
<Edit
size={16}
className="cursor-pointer text-gray-600 dark:text-white"
/>
}
trigger={<Edit size={16} className="cursor-pointer text-gray-600 dark:text-white" />}
value={item}
onValueChange={(val: string) => {
editVal(index, val);
@@ -163,13 +139,7 @@ type StringEditProps = {
op?: "add" | "edit";
};
const StringEdit = ({
trigger,
value,
onValueChange,
op = "add",
valueType,
}: StringEditProps) => {
const StringEdit = ({ trigger, value, onValueChange, op = "add", valueType }: StringEditProps) => {
const [currentValue, setCurrentValue] = useState<string>("");
const [open, setOpen] = useState<boolean>(false);
const [error, setError] = useState<string>("");
@@ -179,11 +149,9 @@ const StringEdit = ({
setCurrentValue(value);
}, [value]);
const domainSchema = z
.string()
.regex(/^(?:\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$/, {
message: t("common.errmsg.domain_invalid"),
});
const domainSchema = z.string().regex(/^(?:\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$/, {
message: t("common.errmsg.domain_invalid"),
});
const ipSchema = z.string().ip({ message: t("common.errmsg.ip_invalid") });
@@ -219,9 +187,7 @@ const StringEdit = ({
<DialogTrigger className="text-primary">{trigger}</DialogTrigger>
<DialogContent className="dark:text-white">
<DialogHeader>
<DialogTitle className="dark:text-white">
{t(titles[valueType])}
</DialogTitle>
<DialogTitle className="dark:text-white">{t(titles[valueType])}</DialogTitle>
</DialogHeader>
<Input
value={currentValue}

View File

@@ -1,7 +1,7 @@
import { BookOpen } from "lucide-react";
import { useTranslation } from "react-i18next";
import { BookOpen } from "lucide-react";
import { Separator } from "../ui/separator";
import { Separator } from "@/components/ui/separator";
import { version } from "@/domain/version";
const Version = () => {
@@ -11,19 +11,12 @@ const Version = () => {
<div className="fixed right-0 bottom-0 w-full flex justify-between p-5">
<div className=""></div>
<div className="text-muted-foreground text-sm hover:text-stone-900 dark:hover:text-stone-200 flex">
<a
href="https://docs.certimate.me"
target="_blank"
className="flex items-center"
>
<a href="https://docs.certimate.me" target="_blank" className="flex items-center">
<BookOpen size={16} />
<div className="ml-1">{t("common.menu.document")}</div>
</a>
<Separator orientation="vertical" className="mx-2" />
<a
href="https://github.com/usual2970/certimate/releases"
target="_blank"
>
<a href="https://github.com/usual2970/certimate/releases" target="_blank">
{version}
</a>
</div>

View File

@@ -1,10 +1,4 @@
import {
Pagination,
PaginationContent,
PaginationEllipsis,
PaginationItem,
PaginationLink,
} from "../ui/pagination";
import { Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink } from "@/components/ui/pagination";
type PaginationProps = {
totalPages: number;
@@ -14,11 +8,7 @@ type PaginationProps = {
type PageNumber = number | string;
const XPagination = ({
totalPages,
currentPage,
onPageChange,
}: PaginationProps) => {
const XPagination = ({ totalPages, currentPage, onPageChange }: PaginationProps) => {
const pageNeighbours = 1; // Number of page numbers to show on either side of the current page
const getPageNumbers = () => {

View File

@@ -1,15 +1,16 @@
import { Input } from "../ui/input";
import { Button } from "../ui/button";
import { Switch } from "../ui/switch";
import { Label } from "../ui/label";
import { useNotify } from "@/providers/notify";
import { NotifyChannelDingTalk, NotifyChannels } from "@/domain/settings";
import { useEffect, useState } from "react";
import { update } from "@/repository/settings";
import { getErrMessage } from "@/lib/error";
import { useToast } from "../ui/use-toast";
import { useTranslation } from "react-i18next";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Switch } from "@/components/ui/switch";
import { useToast } from "@/components/ui/use-toast";
import { getErrMessage } from "@/lib/error";
import { NotifyChannelDingTalk, NotifyChannels } from "@/domain/settings";
import { useNotify } from "@/providers/notify";
import { update } from "@/repository/settings";
type DingTalkSetting = {
id: string;
name: string;
@@ -80,9 +81,7 @@ const DingTalk = () => {
toast({
title: t("common.save.failed.message"),
description: `${t(
"settings.notification.config.failed.message"
)}: ${msg}`,
description: `${t("settings.notification.config.failed.message")}: ${msg}`,
variant: "destructive",
});
}
@@ -131,9 +130,7 @@ const DingTalk = () => {
});
}}
/>
<Label htmlFor="airplane-mode">
{t("settings.notification.config.enable")}
</Label>
<Label htmlFor="airplane-mode">{t("settings.notification.config.enable")}</Label>
</div>
<div className="flex justify-end mt-2">

View File

@@ -1,21 +1,16 @@
import { Input } from "../ui/input";
import { Textarea } from "../ui/textarea";
import { Button } from "../ui/button";
import { useEffect, useState } from "react";
import {
defaultNotifyTemplate,
NotifyTemplates,
NotifyTemplate as NotifyTemplateT,
} from "@/domain/settings";
import { getSetting, update } from "@/repository/settings";
import { useToast } from "../ui/use-toast";
import { useTranslation } from "react-i18next";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Textarea } from "@/components/ui/textarea";
import { useToast } from "@/components/ui/use-toast";
import { defaultNotifyTemplate, NotifyTemplates, NotifyTemplate as NotifyTemplateT } from "@/domain/settings";
import { getSetting, update } from "@/repository/settings";
const NotifyTemplate = () => {
const [id, setId] = useState("");
const [templates, setTemplates] = useState<NotifyTemplateT[]>([
defaultNotifyTemplate,
]);
const [templates, setTemplates] = useState<NotifyTemplateT[]>([defaultNotifyTemplate]);
const { toast } = useToast();
const { t } = useTranslation();
@@ -82,9 +77,7 @@ const NotifyTemplate = () => {
}}
/>
<div className="text-muted-foreground text-sm mt-1">
{t("settings.notification.template.variables.tips.title")}
</div>
<div className="text-muted-foreground text-sm mt-1">{t("settings.notification.template.variables.tips.title")}</div>
<Textarea
className="mt-2"
@@ -93,9 +86,7 @@ const NotifyTemplate = () => {
handleContentChange(e.target.value);
}}
></Textarea>
<div className="text-muted-foreground text-sm mt-1">
{t("settings.notification.template.variables.tips.content")}
</div>
<div className="text-muted-foreground text-sm mt-1">{t("settings.notification.template.variables.tips.content")}</div>
<div className="flex justify-end mt-2">
<Button onClick={handleSaveClick}>{t("common.save")}</Button>
</div>

View File

@@ -1,15 +1,16 @@
import { Input } from "../ui/input";
import { Button } from "../ui/button";
import { Switch } from "../ui/switch";
import { Label } from "../ui/label";
import { useNotify } from "@/providers/notify";
import { NotifyChannels, NotifyChannelTelegram } from "@/domain/settings";
import { useEffect, useState } from "react";
import { update } from "@/repository/settings";
import { getErrMessage } from "@/lib/error";
import { useToast } from "../ui/use-toast";
import { useTranslation } from "react-i18next";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Switch } from "@/components/ui/switch";
import { useToast } from "@/components/ui/use-toast";
import { getErrMessage } from "@/lib/error";
import { NotifyChannels, NotifyChannelTelegram } from "@/domain/settings";
import { update } from "@/repository/settings";
import { useNotify } from "@/providers/notify";
type TelegramSetting = {
id: string;
name: string;
@@ -80,9 +81,7 @@ const Telegram = () => {
toast({
title: t("common.save.failed.message"),
description: `${t(
"settings.notification.config.failed.message"
)}: ${msg}`,
description: `${t("settings.notification.config.failed.message")}: ${msg}`,
variant: "destructive",
});
}
@@ -132,9 +131,7 @@ const Telegram = () => {
});
}}
/>
<Label htmlFor="airplane-mode">
{t("settings.notification.config.enable")}
</Label>
<Label htmlFor="airplane-mode">{t("settings.notification.config.enable")}</Label>
</div>
<div className="flex justify-end mt-2">

View File

@@ -1,16 +1,17 @@
import { Input } from "../ui/input";
import { Button } from "../ui/button";
import { Switch } from "../ui/switch";
import { Label } from "../ui/label";
import { useNotify } from "@/providers/notify";
import { NotifyChannels, NotifyChannelWebhook } from "@/domain/settings";
import { useEffect, useState } from "react";
import { update } from "@/repository/settings";
import { getErrMessage } from "@/lib/error";
import { useToast } from "../ui/use-toast";
import { isValidURL } from "@/lib/url";
import { useTranslation } from "react-i18next";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Switch } from "@/components/ui/switch";
import { useToast } from "@/components/ui/use-toast";
import { getErrMessage } from "@/lib/error";
import { isValidURL } from "@/lib/url";
import { NotifyChannels, NotifyChannelWebhook } from "@/domain/settings";
import { update } from "@/repository/settings";
import { useNotify } from "@/providers/notify";
type WebhookSetting = {
id: string;
name: string;
@@ -89,9 +90,7 @@ const Webhook = () => {
toast({
title: t("common.save.failed.message"),
description: `${t(
"settings.notification.config.failed.message"
)}: ${msg}`,
description: `${t("settings.notification.config.failed.message")}: ${msg}`,
variant: "destructive",
});
}
@@ -127,9 +126,7 @@ const Webhook = () => {
});
}}
/>
<Label htmlFor="airplane-mode">
{t("settings.notification.config.enable")}
</Label>
<Label htmlFor="airplane-mode">{t("settings.notification.config.enable")}</Label>
</div>
<div className="flex justify-end mt-2">

View File

@@ -6,16 +6,9 @@ import { cn } from "@/lib/utils";
const Accordion = AccordionPrimitive.Root;
const AccordionItem = React.forwardRef<
React.ElementRef<typeof AccordionPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item>
>(({ className, ...props }, ref) => (
<AccordionPrimitive.Item
ref={ref}
className={cn("border-b", className)}
{...props}
/>
));
const AccordionItem = React.forwardRef<React.ElementRef<typeof AccordionPrimitive.Item>, React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item>>(
({ className, ...props }, ref) => <AccordionPrimitive.Item ref={ref} className={cn("border-b", className)} {...props} />
);
AccordionItem.displayName = "AccordionItem";
const AccordionTrigger = React.forwardRef<
@@ -25,10 +18,7 @@ const AccordionTrigger = React.forwardRef<
<AccordionPrimitive.Header className="flex">
<AccordionPrimitive.Trigger
ref={ref}
className={cn(
"flex flex-1 items-center justify-between py-4 font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180",
className
)}
className={cn("flex flex-1 items-center justify-between py-4 font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180", className)}
{...props}
>
{children}

View File

@@ -1,14 +1,14 @@
import * as React from "react"
import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog"
import * as React from "react";
import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog";
import { cn } from "@/lib/utils"
import { buttonVariants } from "@/components/ui/button"
import { cn } from "@/lib/utils";
import { buttonVariants } from "@/components/ui/button";
const AlertDialog = AlertDialogPrimitive.Root
const AlertDialog = AlertDialogPrimitive.Root;
const AlertDialogTrigger = AlertDialogPrimitive.Trigger
const AlertDialogTrigger = AlertDialogPrimitive.Trigger;
const AlertDialogPortal = AlertDialogPrimitive.Portal
const AlertDialogPortal = AlertDialogPrimitive.Portal;
const AlertDialogOverlay = React.forwardRef<
React.ElementRef<typeof AlertDialogPrimitive.Overlay>,
@@ -22,8 +22,8 @@ const AlertDialogOverlay = React.forwardRef<
{...props}
ref={ref}
/>
))
AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName
));
AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName;
const AlertDialogContent = React.forwardRef<
React.ElementRef<typeof AlertDialogPrimitive.Content>,
@@ -40,89 +40,44 @@ const AlertDialogContent = React.forwardRef<
{...props}
/>
</AlertDialogPortal>
))
AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName
));
AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName;
const AlertDialogHeader = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col space-y-2 text-center sm:text-left",
className
)}
{...props}
/>
)
AlertDialogHeader.displayName = "AlertDialogHeader"
const AlertDialogHeader = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
<div className={cn("flex flex-col space-y-2 text-center sm:text-left", className)} {...props} />
);
AlertDialogHeader.displayName = "AlertDialogHeader";
const AlertDialogFooter = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
className
)}
{...props}
/>
)
AlertDialogFooter.displayName = "AlertDialogFooter"
const AlertDialogFooter = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
<div className={cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className)} {...props} />
);
AlertDialogFooter.displayName = "AlertDialogFooter";
const AlertDialogTitle = React.forwardRef<
React.ElementRef<typeof AlertDialogPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Title>
>(({ className, ...props }, ref) => (
<AlertDialogPrimitive.Title
ref={ref}
className={cn("text-lg font-semibold", className)}
{...props}
/>
))
AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName
>(({ className, ...props }, ref) => <AlertDialogPrimitive.Title ref={ref} className={cn("text-lg font-semibold", className)} {...props} />);
AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName;
const AlertDialogDescription = React.forwardRef<
React.ElementRef<typeof AlertDialogPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Description>
>(({ className, ...props }, ref) => (
<AlertDialogPrimitive.Description
ref={ref}
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
))
AlertDialogDescription.displayName =
AlertDialogPrimitive.Description.displayName
>(({ className, ...props }, ref) => <AlertDialogPrimitive.Description ref={ref} className={cn("text-sm text-muted-foreground", className)} {...props} />);
AlertDialogDescription.displayName = AlertDialogPrimitive.Description.displayName;
const AlertDialogAction = React.forwardRef<
React.ElementRef<typeof AlertDialogPrimitive.Action>,
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Action>
>(({ className, ...props }, ref) => (
<AlertDialogPrimitive.Action
ref={ref}
className={cn(buttonVariants(), className)}
{...props}
/>
))
AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName
>(({ className, ...props }, ref) => <AlertDialogPrimitive.Action ref={ref} className={cn(buttonVariants(), className)} {...props} />);
AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName;
const AlertDialogCancel = React.forwardRef<
React.ElementRef<typeof AlertDialogPrimitive.Cancel>,
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Cancel>
>(({ className, ...props }, ref) => (
<AlertDialogPrimitive.Cancel
ref={ref}
className={cn(
buttonVariants({ variant: "outline" }),
"mt-2 sm:mt-0",
className
)}
{...props}
/>
))
AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName
<AlertDialogPrimitive.Cancel ref={ref} className={cn(buttonVariants({ variant: "outline" }), "mt-2 sm:mt-0", className)} {...props} />
));
AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName;
export {
AlertDialog,
@@ -136,4 +91,4 @@ export {
AlertDialogDescription,
AlertDialogAction,
AlertDialogCancel,
}
};

View File

@@ -9,8 +9,7 @@ const alertVariants = cva(
variants: {
variant: {
default: "bg-background text-foreground",
destructive:
"border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive",
destructive: "border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive",
},
},
defaultVariants: {
@@ -19,40 +18,18 @@ const alertVariants = cva(
}
);
const Alert = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof alertVariants>
>(({ className, variant, ...props }, ref) => (
<div
ref={ref}
role="alert"
className={cn(alertVariants({ variant }), className)}
{...props}
/>
));
const Alert = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof alertVariants>>(
({ className, variant, ...props }, ref) => <div ref={ref} role="alert" className={cn(alertVariants({ variant }), className)} {...props} />
);
Alert.displayName = "Alert";
const AlertTitle = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes<HTMLHeadingElement>
>(({ className, ...props }, ref) => (
<h5
ref={ref}
className={cn("mb-1 font-medium leading-none tracking-tight", className)}
{...props}
/>
const AlertTitle = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLHeadingElement>>(({ className, ...props }, ref) => (
<h5 ref={ref} className={cn("mb-1 font-medium leading-none tracking-tight", className)} {...props} />
));
AlertTitle.displayName = "AlertTitle";
const AlertDescription = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes<HTMLParagraphElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("text-sm [&_p]:leading-relaxed", className)}
{...props}
/>
const AlertDescription = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLParagraphElement>>(({ className, ...props }, ref) => (
<div ref={ref} className={cn("text-sm [&_p]:leading-relaxed", className)} {...props} />
));
AlertDescription.displayName = "AlertDescription";

View File

@@ -1,19 +1,16 @@
import * as React from "react"
import { cva, type VariantProps } from "class-variance-authority"
import * as React from "react";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const badgeVariants = cva(
"inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
{
variants: {
variant: {
default:
"border-transparent bg-primary text-primary-foreground hover:bg-primary/80",
secondary:
"border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
destructive:
"border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
default: "border-transparent bg-primary text-primary-foreground hover:bg-primary/80",
secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
destructive: "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
outline: "text-foreground",
},
},
@@ -21,16 +18,12 @@ const badgeVariants = cva(
variant: "default",
},
}
)
);
export interface BadgeProps
extends React.HTMLAttributes<HTMLDivElement>,
VariantProps<typeof badgeVariants> {}
export interface BadgeProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof badgeVariants> {}
function Badge({ className, variant, ...props }: BadgeProps) {
return (
<div className={cn(badgeVariants({ variant }), className)} {...props} />
)
return <div className={cn(badgeVariants({ variant }), className)} {...props} />;
}
export { Badge, badgeVariants }
export { Badge, badgeVariants };

View File

@@ -1,115 +1,57 @@
import * as React from "react"
import { Slot } from "@radix-ui/react-slot"
import { ChevronRight, MoreHorizontal } from "lucide-react"
import * as React from "react";
import { Slot } from "@radix-ui/react-slot";
import { ChevronRight, MoreHorizontal } from "lucide-react";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const Breadcrumb = React.forwardRef<
HTMLElement,
React.ComponentPropsWithoutRef<"nav"> & {
separator?: React.ReactNode
separator?: React.ReactNode;
}
>(({ ...props }, ref) => <nav ref={ref} aria-label="breadcrumb" {...props} />)
Breadcrumb.displayName = "Breadcrumb"
>(({ ...props }, ref) => <nav ref={ref} aria-label="breadcrumb" {...props} />);
Breadcrumb.displayName = "Breadcrumb";
const BreadcrumbList = React.forwardRef<
HTMLOListElement,
React.ComponentPropsWithoutRef<"ol">
>(({ className, ...props }, ref) => (
<ol
ref={ref}
className={cn(
"flex flex-wrap items-center gap-1.5 break-words text-sm text-muted-foreground sm:gap-2.5",
className
)}
{...props}
/>
))
BreadcrumbList.displayName = "BreadcrumbList"
const BreadcrumbList = React.forwardRef<HTMLOListElement, React.ComponentPropsWithoutRef<"ol">>(({ className, ...props }, ref) => (
<ol ref={ref} className={cn("flex flex-wrap items-center gap-1.5 break-words text-sm text-muted-foreground sm:gap-2.5", className)} {...props} />
));
BreadcrumbList.displayName = "BreadcrumbList";
const BreadcrumbItem = React.forwardRef<
HTMLLIElement,
React.ComponentPropsWithoutRef<"li">
>(({ className, ...props }, ref) => (
<li
ref={ref}
className={cn("inline-flex items-center gap-1.5", className)}
{...props}
/>
))
BreadcrumbItem.displayName = "BreadcrumbItem"
const BreadcrumbItem = React.forwardRef<HTMLLIElement, React.ComponentPropsWithoutRef<"li">>(({ className, ...props }, ref) => (
<li ref={ref} className={cn("inline-flex items-center gap-1.5", className)} {...props} />
));
BreadcrumbItem.displayName = "BreadcrumbItem";
const BreadcrumbLink = React.forwardRef<
HTMLAnchorElement,
React.ComponentPropsWithoutRef<"a"> & {
asChild?: boolean
asChild?: boolean;
}
>(({ asChild, className, ...props }, ref) => {
const Comp = asChild ? Slot : "a"
const Comp = asChild ? Slot : "a";
return (
<Comp
ref={ref}
className={cn("transition-colors hover:text-foreground", className)}
{...props}
/>
)
})
BreadcrumbLink.displayName = "BreadcrumbLink"
return <Comp ref={ref} className={cn("transition-colors hover:text-foreground", className)} {...props} />;
});
BreadcrumbLink.displayName = "BreadcrumbLink";
const BreadcrumbPage = React.forwardRef<
HTMLSpanElement,
React.ComponentPropsWithoutRef<"span">
>(({ className, ...props }, ref) => (
<span
ref={ref}
role="link"
aria-disabled="true"
aria-current="page"
className={cn("font-normal text-foreground", className)}
{...props}
/>
))
BreadcrumbPage.displayName = "BreadcrumbPage"
const BreadcrumbPage = React.forwardRef<HTMLSpanElement, React.ComponentPropsWithoutRef<"span">>(({ className, ...props }, ref) => (
<span ref={ref} role="link" aria-disabled="true" aria-current="page" className={cn("font-normal text-foreground", className)} {...props} />
));
BreadcrumbPage.displayName = "BreadcrumbPage";
const BreadcrumbSeparator = ({
children,
className,
...props
}: React.ComponentProps<"li">) => (
<li
role="presentation"
aria-hidden="true"
className={cn("[&>svg]:size-3.5", className)}
{...props}
>
const BreadcrumbSeparator = ({ children, className, ...props }: React.ComponentProps<"li">) => (
<li role="presentation" aria-hidden="true" className={cn("[&>svg]:size-3.5", className)} {...props}>
{children ?? <ChevronRight />}
</li>
)
BreadcrumbSeparator.displayName = "BreadcrumbSeparator"
);
BreadcrumbSeparator.displayName = "BreadcrumbSeparator";
const BreadcrumbEllipsis = ({
className,
...props
}: React.ComponentProps<"span">) => (
<span
role="presentation"
aria-hidden="true"
className={cn("flex h-9 w-9 items-center justify-center", className)}
{...props}
>
const BreadcrumbEllipsis = ({ className, ...props }: React.ComponentProps<"span">) => (
<span role="presentation" aria-hidden="true" className={cn("flex h-9 w-9 items-center justify-center", className)} {...props}>
<MoreHorizontal className="h-4 w-4" />
<span className="sr-only">More</span>
</span>
)
BreadcrumbEllipsis.displayName = "BreadcrumbElipssis"
);
BreadcrumbEllipsis.displayName = "BreadcrumbElipssis";
export {
Breadcrumb,
BreadcrumbList,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbPage,
BreadcrumbSeparator,
BreadcrumbEllipsis,
}
export { Breadcrumb, BreadcrumbList, BreadcrumbItem, BreadcrumbLink, BreadcrumbPage, BreadcrumbSeparator, BreadcrumbEllipsis };

View File

@@ -1,8 +1,8 @@
import * as React from "react"
import { Slot } from "@radix-ui/react-slot"
import { cva, type VariantProps } from "class-variance-authority"
import * as React from "react";
import { Slot } from "@radix-ui/react-slot";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const buttonVariants = cva(
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
@@ -10,12 +10,9 @@ const buttonVariants = cva(
variants: {
variant: {
default: "bg-primary text-primary-foreground hover:bg-primary/90",
destructive:
"bg-destructive text-destructive-foreground hover:bg-destructive/90",
outline:
"border border-input bg-background hover:bg-accent hover:text-accent-foreground",
secondary:
"bg-secondary text-secondary-foreground hover:bg-secondary/80",
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "text-primary underline-offset-4 hover:underline",
},
@@ -31,26 +28,16 @@ const buttonVariants = cva(
size: "default",
},
}
)
);
export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {
asChild?: boolean
export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
asChild?: boolean;
}
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, asChild = false, ...props }, ref) => {
const Comp = asChild ? Slot : "button"
return (
<Comp
className={cn(buttonVariants({ variant, size, className }))}
ref={ref}
{...props}
/>
)
}
)
Button.displayName = "Button"
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(({ className, variant, size, asChild = false, ...props }, ref) => {
const Comp = asChild ? Slot : "button";
return <Comp className={cn(buttonVariants({ variant, size, className }))} ref={ref} {...props} />;
});
Button.displayName = "Button";
export { Button, buttonVariants }
export { Button, buttonVariants };

View File

@@ -1,79 +1,35 @@
import * as React from "react"
import * as React from "react";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const Card = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn(
"rounded-lg border bg-card text-card-foreground shadow-sm",
className
)}
{...props}
/>
))
Card.displayName = "Card"
const Card = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(({ className, ...props }, ref) => (
<div ref={ref} className={cn("rounded-lg border bg-card text-card-foreground shadow-sm", className)} {...props} />
));
Card.displayName = "Card";
const CardHeader = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("flex flex-col space-y-1.5 p-6", className)}
{...props}
/>
))
CardHeader.displayName = "CardHeader"
const CardHeader = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(({ className, ...props }, ref) => (
<div ref={ref} className={cn("flex flex-col space-y-1.5 p-6", className)} {...props} />
));
CardHeader.displayName = "CardHeader";
const CardTitle = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes<HTMLHeadingElement>
>(({ className, ...props }, ref) => (
<h3
ref={ref}
className={cn(
"text-2xl font-semibold leading-none tracking-tight",
className
)}
{...props}
/>
))
CardTitle.displayName = "CardTitle"
const CardTitle = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLHeadingElement>>(({ className, ...props }, ref) => (
<h3 ref={ref} className={cn("text-2xl font-semibold leading-none tracking-tight", className)} {...props} />
));
CardTitle.displayName = "CardTitle";
const CardDescription = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes<HTMLParagraphElement>
>(({ className, ...props }, ref) => (
<p
ref={ref}
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
))
CardDescription.displayName = "CardDescription"
const CardDescription = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLParagraphElement>>(({ className, ...props }, ref) => (
<p ref={ref} className={cn("text-sm text-muted-foreground", className)} {...props} />
));
CardDescription.displayName = "CardDescription";
const CardContent = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
const CardContent = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(({ className, ...props }, ref) => (
<div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
))
CardContent.displayName = "CardContent"
));
CardContent.displayName = "CardContent";
const CardFooter = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("flex items-center p-6 pt-0", className)}
{...props}
/>
))
CardFooter.displayName = "CardFooter"
const CardFooter = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(({ className, ...props }, ref) => (
<div ref={ref} className={cn("flex items-center p-6 pt-0", className)} {...props} />
));
CardFooter.displayName = "CardFooter";
export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }
export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent };

View File

@@ -1,120 +1,75 @@
import * as React from "react"
import * as DialogPrimitive from "@radix-ui/react-dialog"
import { X } from "lucide-react"
import * as React from "react";
import * as DialogPrimitive from "@radix-ui/react-dialog";
import { X } from "lucide-react";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const Dialog = DialogPrimitive.Root
const Dialog = DialogPrimitive.Root;
const DialogTrigger = DialogPrimitive.Trigger
const DialogTrigger = DialogPrimitive.Trigger;
const DialogPortal = DialogPrimitive.Portal
const DialogPortal = DialogPrimitive.Portal;
const DialogClose = DialogPrimitive.Close
const DialogClose = DialogPrimitive.Close;
const DialogOverlay = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Overlay>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
>(({ className, ...props }, ref) => (
<DialogPrimitive.Overlay
ref={ref}
className={cn(
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
className
)}
{...props}
/>
))
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName
const DialogContent = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
>(({ className, children, ...props }, ref) => (
<DialogPortal>
<DialogOverlay />
<DialogPrimitive.Content
const DialogOverlay = React.forwardRef<React.ElementRef<typeof DialogPrimitive.Overlay>, React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>>(
({ className, ...props }, ref) => (
<DialogPrimitive.Overlay
ref={ref}
className={cn(
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
className
)}
{...props}
>
{children}
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
<X className="h-4 w-4" />
<span className="sr-only">Close</span>
</DialogPrimitive.Close>
</DialogPrimitive.Content>
</DialogPortal>
))
DialogContent.displayName = DialogPrimitive.Content.displayName
/>
)
);
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
const DialogHeader = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col space-y-1.5 text-center sm:text-left",
className
)}
{...props}
/>
)
DialogHeader.displayName = "DialogHeader"
const DialogContent = React.forwardRef<React.ElementRef<typeof DialogPrimitive.Content>, React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>>(
({ className, children, ...props }, ref) => (
<DialogPortal>
<DialogOverlay />
<DialogPrimitive.Content
ref={ref}
className={cn(
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
className
)}
{...props}
>
{children}
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
<X className="h-4 w-4" />
<span className="sr-only">Close</span>
</DialogPrimitive.Close>
</DialogPrimitive.Content>
</DialogPortal>
)
);
DialogContent.displayName = DialogPrimitive.Content.displayName;
const DialogFooter = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
className
)}
{...props}
/>
)
DialogFooter.displayName = "DialogFooter"
const DialogHeader = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
<div className={cn("flex flex-col space-y-1.5 text-center sm:text-left", className)} {...props} />
);
DialogHeader.displayName = "DialogHeader";
const DialogTitle = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
>(({ className, ...props }, ref) => (
<DialogPrimitive.Title
ref={ref}
className={cn(
"text-lg font-semibold leading-none tracking-tight",
className
)}
{...props}
/>
))
DialogTitle.displayName = DialogPrimitive.Title.displayName
const DialogFooter = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
<div className={cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className)} {...props} />
);
DialogFooter.displayName = "DialogFooter";
const DialogTitle = React.forwardRef<React.ElementRef<typeof DialogPrimitive.Title>, React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>>(
({ className, ...props }, ref) => (
<DialogPrimitive.Title ref={ref} className={cn("text-lg font-semibold leading-none tracking-tight", className)} {...props} />
)
);
DialogTitle.displayName = DialogPrimitive.Title.displayName;
const DialogDescription = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
>(({ className, ...props }, ref) => (
<DialogPrimitive.Description
ref={ref}
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
))
DialogDescription.displayName = DialogPrimitive.Description.displayName
>(({ className, ...props }, ref) => <DialogPrimitive.Description ref={ref} className={cn("text-sm text-muted-foreground", className)} {...props} />);
DialogDescription.displayName = DialogPrimitive.Description.displayName;
export {
Dialog,
DialogPortal,
DialogOverlay,
DialogClose,
DialogTrigger,
DialogContent,
DialogHeader,
DialogFooter,
DialogTitle,
DialogDescription,
}
export { Dialog, DialogPortal, DialogOverlay, DialogClose, DialogTrigger, DialogContent, DialogHeader, DialogFooter, DialogTitle, DialogDescription };

View File

@@ -1,116 +1,62 @@
import * as React from "react"
import { Drawer as DrawerPrimitive } from "vaul"
import * as React from "react";
import { Drawer as DrawerPrimitive } from "vaul";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const Drawer = ({
shouldScaleBackground = true,
...props
}: React.ComponentProps<typeof DrawerPrimitive.Root>) => (
<DrawerPrimitive.Root
shouldScaleBackground={shouldScaleBackground}
{...props}
/>
)
Drawer.displayName = "Drawer"
const Drawer = ({ shouldScaleBackground = true, ...props }: React.ComponentProps<typeof DrawerPrimitive.Root>) => (
<DrawerPrimitive.Root shouldScaleBackground={shouldScaleBackground} {...props} />
);
Drawer.displayName = "Drawer";
const DrawerTrigger = DrawerPrimitive.Trigger
const DrawerTrigger = DrawerPrimitive.Trigger;
const DrawerPortal = DrawerPrimitive.Portal
const DrawerPortal = DrawerPrimitive.Portal;
const DrawerClose = DrawerPrimitive.Close
const DrawerClose = DrawerPrimitive.Close;
const DrawerOverlay = React.forwardRef<
React.ElementRef<typeof DrawerPrimitive.Overlay>,
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Overlay>
>(({ className, ...props }, ref) => (
<DrawerPrimitive.Overlay
ref={ref}
className={cn("fixed inset-0 z-50 bg-black/80", className)}
{...props}
/>
))
DrawerOverlay.displayName = DrawerPrimitive.Overlay.displayName
const DrawerOverlay = React.forwardRef<React.ElementRef<typeof DrawerPrimitive.Overlay>, React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Overlay>>(
({ className, ...props }, ref) => <DrawerPrimitive.Overlay ref={ref} className={cn("fixed inset-0 z-50 bg-black/80", className)} {...props} />
);
DrawerOverlay.displayName = DrawerPrimitive.Overlay.displayName;
const DrawerContent = React.forwardRef<
React.ElementRef<typeof DrawerPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Content>
>(({ className, children, ...props }, ref) => (
<DrawerPortal>
<DrawerOverlay />
<DrawerPrimitive.Content
ref={ref}
className={cn(
"fixed inset-x-0 bottom-0 z-50 mt-24 flex h-auto flex-col rounded-t-[10px] border bg-background",
className
)}
{...props}
>
<div className="mx-auto mt-4 h-2 w-[100px] rounded-full bg-muted" />
{children}
</DrawerPrimitive.Content>
</DrawerPortal>
))
DrawerContent.displayName = "DrawerContent"
const DrawerContent = React.forwardRef<React.ElementRef<typeof DrawerPrimitive.Content>, React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Content>>(
({ className, children, ...props }, ref) => (
<DrawerPortal>
<DrawerOverlay />
<DrawerPrimitive.Content
ref={ref}
className={cn("fixed inset-x-0 bottom-0 z-50 mt-24 flex h-auto flex-col rounded-t-[10px] border bg-background", className)}
{...props}
>
<div className="mx-auto mt-4 h-2 w-[100px] rounded-full bg-muted" />
{children}
</DrawerPrimitive.Content>
</DrawerPortal>
)
);
DrawerContent.displayName = "DrawerContent";
const DrawerHeader = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn("grid gap-1.5 p-4 text-center sm:text-left", className)}
{...props}
/>
)
DrawerHeader.displayName = "DrawerHeader"
const DrawerHeader = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
<div className={cn("grid gap-1.5 p-4 text-center sm:text-left", className)} {...props} />
);
DrawerHeader.displayName = "DrawerHeader";
const DrawerFooter = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn("mt-auto flex flex-col gap-2 p-4", className)}
{...props}
/>
)
DrawerFooter.displayName = "DrawerFooter"
const DrawerFooter = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
<div className={cn("mt-auto flex flex-col gap-2 p-4", className)} {...props} />
);
DrawerFooter.displayName = "DrawerFooter";
const DrawerTitle = React.forwardRef<
React.ElementRef<typeof DrawerPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Title>
>(({ className, ...props }, ref) => (
<DrawerPrimitive.Title
ref={ref}
className={cn(
"text-lg font-semibold leading-none tracking-tight",
className
)}
{...props}
/>
))
DrawerTitle.displayName = DrawerPrimitive.Title.displayName
const DrawerTitle = React.forwardRef<React.ElementRef<typeof DrawerPrimitive.Title>, React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Title>>(
({ className, ...props }, ref) => (
<DrawerPrimitive.Title ref={ref} className={cn("text-lg font-semibold leading-none tracking-tight", className)} {...props} />
)
);
DrawerTitle.displayName = DrawerPrimitive.Title.displayName;
const DrawerDescription = React.forwardRef<
React.ElementRef<typeof DrawerPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Description>
>(({ className, ...props }, ref) => (
<DrawerPrimitive.Description
ref={ref}
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
))
DrawerDescription.displayName = DrawerPrimitive.Description.displayName
>(({ className, ...props }, ref) => <DrawerPrimitive.Description ref={ref} className={cn("text-sm text-muted-foreground", className)} {...props} />);
DrawerDescription.displayName = DrawerPrimitive.Description.displayName;
export {
Drawer,
DrawerPortal,
DrawerOverlay,
DrawerTrigger,
DrawerClose,
DrawerContent,
DrawerHeader,
DrawerFooter,
DrawerTitle,
DrawerDescription,
}
export { Drawer, DrawerPortal, DrawerOverlay, DrawerTrigger, DrawerClose, DrawerContent, DrawerHeader, DrawerFooter, DrawerTitle, DrawerDescription };

View File

@@ -1,25 +1,25 @@
import * as React from "react"
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"
import { Check, ChevronRight, Circle } from "lucide-react"
import * as React from "react";
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
import { Check, ChevronRight, Circle } from "lucide-react";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const DropdownMenu = DropdownMenuPrimitive.Root
const DropdownMenu = DropdownMenuPrimitive.Root;
const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger
const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
const DropdownMenuGroup = DropdownMenuPrimitive.Group
const DropdownMenuGroup = DropdownMenuPrimitive.Group;
const DropdownMenuPortal = DropdownMenuPrimitive.Portal
const DropdownMenuPortal = DropdownMenuPrimitive.Portal;
const DropdownMenuSub = DropdownMenuPrimitive.Sub
const DropdownMenuSub = DropdownMenuPrimitive.Sub;
const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup
const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
const DropdownMenuSubTrigger = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {
inset?: boolean
inset?: boolean;
}
>(({ className, inset, children, ...props }, ref) => (
<DropdownMenuPrimitive.SubTrigger
@@ -34,9 +34,8 @@ const DropdownMenuSubTrigger = React.forwardRef<
{children}
<ChevronRight className="ml-auto h-4 w-4" />
</DropdownMenuPrimitive.SubTrigger>
))
DropdownMenuSubTrigger.displayName =
DropdownMenuPrimitive.SubTrigger.displayName
));
DropdownMenuSubTrigger.displayName = DropdownMenuPrimitive.SubTrigger.displayName;
const DropdownMenuSubContent = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
@@ -50,9 +49,8 @@ const DropdownMenuSubContent = React.forwardRef<
)}
{...props}
/>
))
DropdownMenuSubContent.displayName =
DropdownMenuPrimitive.SubContent.displayName
));
DropdownMenuSubContent.displayName = DropdownMenuPrimitive.SubContent.displayName;
const DropdownMenuContent = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.Content>,
@@ -69,13 +67,13 @@ const DropdownMenuContent = React.forwardRef<
{...props}
/>
</DropdownMenuPrimitive.Portal>
))
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName
));
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
const DropdownMenuItem = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
inset?: boolean
inset?: boolean;
}
>(({ className, inset, ...props }, ref) => (
<DropdownMenuPrimitive.Item
@@ -87,8 +85,8 @@ const DropdownMenuItem = React.forwardRef<
)}
{...props}
/>
))
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName
));
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
const DropdownMenuCheckboxItem = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,
@@ -110,9 +108,8 @@ const DropdownMenuCheckboxItem = React.forwardRef<
</span>
{children}
</DropdownMenuPrimitive.CheckboxItem>
))
DropdownMenuCheckboxItem.displayName =
DropdownMenuPrimitive.CheckboxItem.displayName
));
DropdownMenuCheckboxItem.displayName = DropdownMenuPrimitive.CheckboxItem.displayName;
const DropdownMenuRadioItem = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,
@@ -133,51 +130,29 @@ const DropdownMenuRadioItem = React.forwardRef<
</span>
{children}
</DropdownMenuPrimitive.RadioItem>
))
DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName
));
DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
const DropdownMenuLabel = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.Label>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {
inset?: boolean
inset?: boolean;
}
>(({ className, inset, ...props }, ref) => (
<DropdownMenuPrimitive.Label
ref={ref}
className={cn(
"px-2 py-1.5 text-sm font-semibold",
inset && "pl-8",
className
)}
{...props}
/>
))
DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName
<DropdownMenuPrimitive.Label ref={ref} className={cn("px-2 py-1.5 text-sm font-semibold", inset && "pl-8", className)} {...props} />
));
DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
const DropdownMenuSeparator = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>
>(({ className, ...props }, ref) => (
<DropdownMenuPrimitive.Separator
ref={ref}
className={cn("-mx-1 my-1 h-px bg-muted", className)}
{...props}
/>
))
DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName
>(({ className, ...props }, ref) => <DropdownMenuPrimitive.Separator ref={ref} className={cn("-mx-1 my-1 h-px bg-muted", className)} {...props} />);
DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
const DropdownMenuShortcut = ({
className,
...props
}: React.HTMLAttributes<HTMLSpanElement>) => {
return (
<span
className={cn("ml-auto text-xs tracking-widest opacity-60", className)}
{...props}
/>
)
}
DropdownMenuShortcut.displayName = "DropdownMenuShortcut"
const DropdownMenuShortcut = ({ className, ...props }: React.HTMLAttributes<HTMLSpanElement>) => {
return <span className={cn("ml-auto text-xs tracking-widest opacity-60", className)} {...props} />;
};
DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
export {
DropdownMenu,
@@ -195,4 +170,4 @@ export {
DropdownMenuSubContent,
DropdownMenuSubTrigger,
DropdownMenuRadioGroup,
}
};

View File

@@ -1,57 +1,42 @@
import * as React from "react"
import * as LabelPrimitive from "@radix-ui/react-label"
import { Slot } from "@radix-ui/react-slot"
import {
Controller,
ControllerProps,
FieldPath,
FieldValues,
FormProvider,
useFormContext,
} from "react-hook-form"
import * as React from "react";
import { Controller, ControllerProps, FieldPath, FieldValues, FormProvider, useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next";
import * as LabelPrimitive from "@radix-ui/react-label";
import { Slot } from "@radix-ui/react-slot";
import { cn } from "@/lib/utils"
import { Label } from "@/components/ui/label"
import { useTranslation } from "react-i18next"
import { Label } from "@/components/ui/label";
import { cn } from "@/lib/utils";
const Form = FormProvider
const Form = FormProvider;
type FormFieldContextValue<
TFieldValues extends FieldValues = FieldValues,
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
> = {
name: TName
}
type FormFieldContextValue<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>> = {
name: TName;
};
const FormFieldContext = React.createContext<FormFieldContextValue>(
{} as FormFieldContextValue
)
const FormFieldContext = React.createContext<FormFieldContextValue>({} as FormFieldContextValue);
const FormField = <
TFieldValues extends FieldValues = FieldValues,
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
>({
const FormField = <TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>>({
...props
}: ControllerProps<TFieldValues, TName>) => {
return (
<FormFieldContext.Provider value={{ name: props.name }}>
<Controller {...props} />
</FormFieldContext.Provider>
)
}
);
};
const useFormField = () => {
const fieldContext = React.useContext(FormFieldContext)
const itemContext = React.useContext(FormItemContext)
const { getFieldState, formState } = useFormContext()
const fieldContext = React.useContext(FormFieldContext);
const itemContext = React.useContext(FormItemContext);
const { getFieldState, formState } = useFormContext();
const fieldState = getFieldState(fieldContext.name, formState)
const fieldState = getFieldState(fieldContext.name, formState);
if (!fieldContext) {
throw new Error("useFormField should be used within <FormField>")
throw new Error("useFormField should be used within <FormField>");
}
const { id } = itemContext
const { id } = itemContext;
return {
id,
@@ -60,120 +45,73 @@ const useFormField = () => {
formDescriptionId: `${id}-form-item-description`,
formMessageId: `${id}-form-item-message`,
...fieldState,
}
}
};
};
type FormItemContextValue = {
id: string
}
id: string;
};
const FormItemContext = React.createContext<FormItemContextValue>(
{} as FormItemContextValue
)
const FormItemContext = React.createContext<FormItemContextValue>({} as FormItemContextValue);
const FormItem = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => {
const id = React.useId()
const FormItem = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(({ className, ...props }, ref) => {
const id = React.useId();
return (
<FormItemContext.Provider value={{ id }}>
<div ref={ref} className={cn("space-y-2", className)} {...props} />
</FormItemContext.Provider>
)
})
FormItem.displayName = "FormItem"
);
});
FormItem.displayName = "FormItem";
const FormLabel = React.forwardRef<
React.ElementRef<typeof LabelPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>
>(({ className, ...props }, ref) => {
const { error, formItemId } = useFormField()
const FormLabel = React.forwardRef<React.ElementRef<typeof LabelPrimitive.Root>, React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>>(
({ className, ...props }, ref) => {
const { error, formItemId } = useFormField();
return (
<Label
ref={ref}
className={cn(error && "text-destructive", className)}
htmlFor={formItemId}
{...props}
/>
)
})
FormLabel.displayName = "FormLabel"
return <Label ref={ref} className={cn(error && "text-destructive", className)} htmlFor={formItemId} {...props} />;
}
);
FormLabel.displayName = "FormLabel";
const FormControl = React.forwardRef<
React.ElementRef<typeof Slot>,
React.ComponentPropsWithoutRef<typeof Slot>
>(({ ...props }, ref) => {
const { error, formItemId, formDescriptionId, formMessageId } = useFormField()
const FormControl = React.forwardRef<React.ElementRef<typeof Slot>, React.ComponentPropsWithoutRef<typeof Slot>>(({ ...props }, ref) => {
const { error, formItemId, formDescriptionId, formMessageId } = useFormField();
return (
<Slot
ref={ref}
id={formItemId}
aria-describedby={
!error
? `${formDescriptionId}`
: `${formDescriptionId} ${formMessageId}`
}
aria-describedby={!error ? `${formDescriptionId}` : `${formDescriptionId} ${formMessageId}`}
aria-invalid={!!error}
{...props}
/>
)
})
FormControl.displayName = "FormControl"
);
});
FormControl.displayName = "FormControl";
const FormDescription = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes<HTMLParagraphElement>
>(({ className, ...props }, ref) => {
const { formDescriptionId } = useFormField()
const FormDescription = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLParagraphElement>>(({ className, ...props }, ref) => {
const { formDescriptionId } = useFormField();
return (
<p
ref={ref}
id={formDescriptionId}
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
)
})
FormDescription.displayName = "FormDescription"
return <p ref={ref} id={formDescriptionId} className={cn("text-sm text-muted-foreground", className)} {...props} />;
});
FormDescription.displayName = "FormDescription";
const FormMessage = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes<HTMLParagraphElement>
>(({ className, children, ...props }, ref) => {
const { error, formMessageId } = useFormField()
const { t } = useTranslation()
const FormMessage = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLParagraphElement>>(({ className, children, ...props }, ref) => {
const { error, formMessageId } = useFormField();
const { t } = useTranslation();
const body = error ? t(String(error?.message)) : children
const body = error ? t(String(error?.message)) : children;
if (!body) {
return null
return null;
}
return (
<p
ref={ref}
id={formMessageId}
className={cn("text-sm font-medium text-destructive", className)}
{...props}
>
<p ref={ref} id={formMessageId} className={cn("text-sm font-medium text-destructive", className)} {...props}>
{body}
</p>
)
})
FormMessage.displayName = "FormMessage"
);
});
FormMessage.displayName = "FormMessage";
export {
useFormField,
Form,
FormItem,
FormLabel,
FormControl,
FormDescription,
FormMessage,
FormField,
}
export { useFormField, Form, FormItem, FormLabel, FormControl, FormDescription, FormMessage, FormField };

View File

@@ -1,25 +1,22 @@
import * as React from "react"
import * as React from "react";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
export interface InputProps
extends React.InputHTMLAttributes<HTMLInputElement> {}
export interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {}
const Input = React.forwardRef<HTMLInputElement, InputProps>(
({ className, type, ...props }, ref) => {
return (
<input
type={type}
className={cn(
"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
className
)}
ref={ref}
{...props}
/>
)
}
)
Input.displayName = "Input"
const Input = React.forwardRef<HTMLInputElement, InputProps>(({ className, type, ...props }, ref) => {
return (
<input
type={type}
className={cn(
"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
className
)}
ref={ref}
{...props}
/>
);
});
Input.displayName = "Input";
export { Input }
export { Input };

View File

@@ -1,24 +1,15 @@
import * as React from "react"
import * as LabelPrimitive from "@radix-ui/react-label"
import { cva, type VariantProps } from "class-variance-authority"
import * as React from "react";
import * as LabelPrimitive from "@radix-ui/react-label";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const labelVariants = cva(
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
)
const labelVariants = cva("text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70");
const Label = React.forwardRef<
React.ElementRef<typeof LabelPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &
VariantProps<typeof labelVariants>
>(({ className, ...props }, ref) => (
<LabelPrimitive.Root
ref={ref}
className={cn(labelVariants(), className)}
{...props}
/>
))
Label.displayName = LabelPrimitive.Root.displayName
React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> & VariantProps<typeof labelVariants>
>(({ className, ...props }, ref) => <LabelPrimitive.Root ref={ref} className={cn(labelVariants(), className)} {...props} />);
Label.displayName = LabelPrimitive.Root.displayName;
export { Label }
export { Label };

View File

@@ -1,66 +1,44 @@
import * as React from "react"
import * as NavigationMenuPrimitive from "@radix-ui/react-navigation-menu"
import { cva } from "class-variance-authority"
import { ChevronDown } from "lucide-react"
import * as React from "react";
import * as NavigationMenuPrimitive from "@radix-ui/react-navigation-menu";
import { ChevronDown } from "lucide-react";
import { cva } from "class-variance-authority";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const NavigationMenu = React.forwardRef<
React.ElementRef<typeof NavigationMenuPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Root>
>(({ className, children, ...props }, ref) => (
<NavigationMenuPrimitive.Root
ref={ref}
className={cn(
"relative z-10 flex max-w-max flex-1 items-center justify-center",
className
)}
{...props}
>
<NavigationMenuPrimitive.Root ref={ref} className={cn("relative z-10 flex max-w-max flex-1 items-center justify-center", className)} {...props}>
{children}
<NavigationMenuViewport />
</NavigationMenuPrimitive.Root>
))
NavigationMenu.displayName = NavigationMenuPrimitive.Root.displayName
));
NavigationMenu.displayName = NavigationMenuPrimitive.Root.displayName;
const NavigationMenuList = React.forwardRef<
React.ElementRef<typeof NavigationMenuPrimitive.List>,
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.List>
>(({ className, ...props }, ref) => (
<NavigationMenuPrimitive.List
ref={ref}
className={cn(
"group flex flex-1 list-none items-center justify-center space-x-1",
className
)}
{...props}
/>
))
NavigationMenuList.displayName = NavigationMenuPrimitive.List.displayName
<NavigationMenuPrimitive.List ref={ref} className={cn("group flex flex-1 list-none items-center justify-center space-x-1", className)} {...props} />
));
NavigationMenuList.displayName = NavigationMenuPrimitive.List.displayName;
const NavigationMenuItem = NavigationMenuPrimitive.Item
const NavigationMenuItem = NavigationMenuPrimitive.Item;
const navigationMenuTriggerStyle = cva(
"group inline-flex h-10 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus:outline-none disabled:pointer-events-none disabled:opacity-50 data-[active]:bg-accent/50 data-[state=open]:bg-accent/50"
)
);
const NavigationMenuTrigger = React.forwardRef<
React.ElementRef<typeof NavigationMenuPrimitive.Trigger>,
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Trigger>
>(({ className, children, ...props }, ref) => (
<NavigationMenuPrimitive.Trigger
ref={ref}
className={cn(navigationMenuTriggerStyle(), "group", className)}
{...props}
>
{children}{" "}
<ChevronDown
className="relative top-[1px] ml-1 h-3 w-3 transition duration-200 group-data-[state=open]:rotate-180"
aria-hidden="true"
/>
<NavigationMenuPrimitive.Trigger ref={ref} className={cn(navigationMenuTriggerStyle(), "group", className)} {...props}>
{children} <ChevronDown className="relative top-[1px] ml-1 h-3 w-3 transition duration-200 group-data-[state=open]:rotate-180" aria-hidden="true" />
</NavigationMenuPrimitive.Trigger>
))
NavigationMenuTrigger.displayName = NavigationMenuPrimitive.Trigger.displayName
));
NavigationMenuTrigger.displayName = NavigationMenuPrimitive.Trigger.displayName;
const NavigationMenuContent = React.forwardRef<
React.ElementRef<typeof NavigationMenuPrimitive.Content>,
@@ -74,10 +52,10 @@ const NavigationMenuContent = React.forwardRef<
)}
{...props}
/>
))
NavigationMenuContent.displayName = NavigationMenuPrimitive.Content.displayName
));
NavigationMenuContent.displayName = NavigationMenuPrimitive.Content.displayName;
const NavigationMenuLink = NavigationMenuPrimitive.Link
const NavigationMenuLink = NavigationMenuPrimitive.Link;
const NavigationMenuViewport = React.forwardRef<
React.ElementRef<typeof NavigationMenuPrimitive.Viewport>,
@@ -93,9 +71,8 @@ const NavigationMenuViewport = React.forwardRef<
{...props}
/>
</div>
))
NavigationMenuViewport.displayName =
NavigationMenuPrimitive.Viewport.displayName
));
NavigationMenuViewport.displayName = NavigationMenuPrimitive.Viewport.displayName;
const NavigationMenuIndicator = React.forwardRef<
React.ElementRef<typeof NavigationMenuPrimitive.Indicator>,
@@ -111,9 +88,8 @@ const NavigationMenuIndicator = React.forwardRef<
>
<div className="relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm bg-border shadow-md" />
</NavigationMenuPrimitive.Indicator>
))
NavigationMenuIndicator.displayName =
NavigationMenuPrimitive.Indicator.displayName
));
NavigationMenuIndicator.displayName = NavigationMenuPrimitive.Indicator.displayName;
export {
navigationMenuTriggerStyle,
@@ -125,4 +101,4 @@ export {
NavigationMenuLink,
NavigationMenuIndicator,
NavigationMenuViewport,
}
};

View File

@@ -1,36 +1,21 @@
import * as React from "react";
import { useTranslation } from "react-i18next";
import { ChevronLeft, ChevronRight, MoreHorizontal } from "lucide-react";
import { cn } from "@/lib/utils";
import { ButtonProps, buttonVariants } from "@/components/ui/button";
import { useTranslation } from "react-i18next";
import { cn } from "@/lib/utils";
const Pagination = ({ className, ...props }: React.ComponentProps<"nav">) => (
<nav
role="navigation"
aria-label="pagination"
className={cn("mx-auto flex w-full justify-center", className)}
{...props}
/>
<nav role="navigation" aria-label="pagination" className={cn("mx-auto flex w-full justify-center", className)} {...props} />
);
Pagination.displayName = "Pagination";
const PaginationContent = React.forwardRef<
HTMLUListElement,
React.ComponentProps<"ul">
>(({ className, ...props }, ref) => (
<ul
ref={ref}
className={cn("flex flex-row items-center gap-1", className)}
{...props}
/>
const PaginationContent = React.forwardRef<HTMLUListElement, React.ComponentProps<"ul">>(({ className, ...props }, ref) => (
<ul ref={ref} className={cn("flex flex-row items-center gap-1", className)} {...props} />
));
PaginationContent.displayName = "PaginationContent";
const PaginationItem = React.forwardRef<
HTMLLIElement,
React.ComponentProps<"li">
>(({ className, ...props }, ref) => (
const PaginationItem = React.forwardRef<HTMLLIElement, React.ComponentProps<"li">>(({ className, ...props }, ref) => (
<li ref={ref} className={cn("", className)} {...props} />
));
PaginationItem.displayName = "PaginationItem";
@@ -40,12 +25,7 @@ type PaginationLinkProps = {
} & Pick<ButtonProps, "size"> &
React.ComponentProps<"a">;
const PaginationLink = ({
className,
isActive,
size = "icon",
...props
}: PaginationLinkProps) => (
const PaginationLink = ({ className, isActive, size = "icon", ...props }: PaginationLinkProps) => (
<a
aria-current={isActive ? "page" : undefined}
className={cn(
@@ -60,19 +40,11 @@ const PaginationLink = ({
);
PaginationLink.displayName = "PaginationLink";
const PaginationPrevious = ({
className,
...props
}: React.ComponentProps<typeof PaginationLink>) => {
const PaginationPrevious = ({ className, ...props }: React.ComponentProps<typeof PaginationLink>) => {
const { t } = useTranslation();
return (
<PaginationLink
aria-label="Go to previous page"
size="default"
className={cn("gap-1 pl-2.5", className)}
{...props}
>
<PaginationLink aria-label="Go to previous page" size="default" className={cn("gap-1 pl-2.5", className)} {...props}>
<ChevronLeft className="h-4 w-4" />
<span>{t("common.pagination.prev")}</span>
</PaginationLink>
@@ -80,19 +52,11 @@ const PaginationPrevious = ({
};
PaginationPrevious.displayName = "PaginationPrevious";
const PaginationNext = ({
className,
...props
}: React.ComponentProps<typeof PaginationLink>) => {
const PaginationNext = ({ className, ...props }: React.ComponentProps<typeof PaginationLink>) => {
const { t } = useTranslation();
return (
<PaginationLink
aria-label="Go to next page"
size="default"
className={cn("gap-1 pr-2.5", className)}
{...props}
>
<PaginationLink aria-label="Go to next page" size="default" className={cn("gap-1 pr-2.5", className)} {...props}>
<span>{t("common.pagination.next")}</span>
<ChevronRight className="h-4 w-4" />
</PaginationLink>
@@ -100,18 +64,11 @@ const PaginationNext = ({
};
PaginationNext.displayName = "PaginationNext";
const PaginationEllipsis = ({
className,
...props
}: React.ComponentProps<"span">) => {
const PaginationEllipsis = ({ className, ...props }: React.ComponentProps<"span">) => {
const { t } = useTranslation();
return (
<span
aria-hidden
className={cn("flex h-9 w-9 items-center justify-center", className)}
{...props}
>
<span aria-hidden className={cn("flex h-9 w-9 items-center justify-center", className)} {...props}>
<MoreHorizontal className="h-4 w-4" />
<span className="sr-only">{t("common.pagination.more")}</span>
</span>
@@ -119,12 +76,4 @@ const PaginationEllipsis = ({
};
PaginationEllipsis.displayName = "PaginationEllipsis";
export {
Pagination,
PaginationContent,
PaginationEllipsis,
PaginationItem,
PaginationLink,
PaginationNext,
PaginationPrevious,
};
export { Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious };

View File

@@ -1,26 +1,15 @@
import * as React from "react"
import * as ProgressPrimitive from "@radix-ui/react-progress"
import * as React from "react";
import * as ProgressPrimitive from "@radix-ui/react-progress";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const Progress = React.forwardRef<
React.ElementRef<typeof ProgressPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof ProgressPrimitive.Root>
>(({ className, value, ...props }, ref) => (
<ProgressPrimitive.Root
ref={ref}
className={cn(
"relative h-4 w-full overflow-hidden rounded-full bg-secondary",
className
)}
{...props}
>
<ProgressPrimitive.Indicator
className="h-full w-full flex-1 bg-primary transition-all"
style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
/>
</ProgressPrimitive.Root>
))
Progress.displayName = ProgressPrimitive.Root.displayName
const Progress = React.forwardRef<React.ElementRef<typeof ProgressPrimitive.Root>, React.ComponentPropsWithoutRef<typeof ProgressPrimitive.Root>>(
({ className, value, ...props }, ref) => (
<ProgressPrimitive.Root ref={ref} className={cn("relative h-4 w-full overflow-hidden rounded-full bg-secondary", className)} {...props}>
<ProgressPrimitive.Indicator className="h-full w-full flex-1 bg-primary transition-all" style={{ transform: `translateX(-${100 - (value || 0)}%)` }} />
</ProgressPrimitive.Root>
)
);
Progress.displayName = ProgressPrimitive.Root.displayName;
export { Progress }
export { Progress };

View File

@@ -1,42 +1,34 @@
import * as React from "react"
import * as RadioGroupPrimitive from "@radix-ui/react-radio-group"
import { Circle } from "lucide-react"
import * as React from "react";
import * as RadioGroupPrimitive from "@radix-ui/react-radio-group";
import { Circle } from "lucide-react";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const RadioGroup = React.forwardRef<
React.ElementRef<typeof RadioGroupPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root>
>(({ className, ...props }, ref) => {
return (
<RadioGroupPrimitive.Root
className={cn("grid gap-2", className)}
{...props}
ref={ref}
/>
)
})
RadioGroup.displayName = RadioGroupPrimitive.Root.displayName
const RadioGroup = React.forwardRef<React.ElementRef<typeof RadioGroupPrimitive.Root>, React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root>>(
({ className, ...props }, ref) => {
return <RadioGroupPrimitive.Root className={cn("grid gap-2", className)} {...props} ref={ref} />;
}
);
RadioGroup.displayName = RadioGroupPrimitive.Root.displayName;
const RadioGroupItem = React.forwardRef<
React.ElementRef<typeof RadioGroupPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item>
>(({ className, ...props }, ref) => {
return (
<RadioGroupPrimitive.Item
ref={ref}
className={cn(
"aspect-square h-4 w-4 rounded-full border border-primary text-primary ring-offset-background focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
className
)}
{...props}
>
<RadioGroupPrimitive.Indicator className="flex items-center justify-center">
<Circle className="h-2.5 w-2.5 fill-current text-current" />
</RadioGroupPrimitive.Indicator>
</RadioGroupPrimitive.Item>
)
})
RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName
const RadioGroupItem = React.forwardRef<React.ElementRef<typeof RadioGroupPrimitive.Item>, React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item>>(
({ className, ...props }, ref) => {
return (
<RadioGroupPrimitive.Item
ref={ref}
className={cn(
"aspect-square h-4 w-4 rounded-full border border-primary text-primary ring-offset-background focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
className
)}
{...props}
>
<RadioGroupPrimitive.Indicator className="flex items-center justify-center">
<Circle className="h-2.5 w-2.5 fill-current text-current" />
</RadioGroupPrimitive.Indicator>
</RadioGroupPrimitive.Item>
);
}
);
RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName;
export { RadioGroup, RadioGroupItem }
export { RadioGroup, RadioGroupItem };

View File

@@ -1,25 +1,18 @@
import * as React from "react"
import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area"
import * as React from "react";
import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const ScrollArea = React.forwardRef<
React.ElementRef<typeof ScrollAreaPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Root>
>(({ className, children, ...props }, ref) => (
<ScrollAreaPrimitive.Root
ref={ref}
className={cn("relative overflow-hidden", className)}
{...props}
>
<ScrollAreaPrimitive.Viewport className="h-full w-full rounded-[inherit]">
{children}
</ScrollAreaPrimitive.Viewport>
<ScrollBar />
<ScrollAreaPrimitive.Corner />
</ScrollAreaPrimitive.Root>
))
ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName
const ScrollArea = React.forwardRef<React.ElementRef<typeof ScrollAreaPrimitive.Root>, React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Root>>(
({ className, children, ...props }, ref) => (
<ScrollAreaPrimitive.Root ref={ref} className={cn("relative overflow-hidden", className)} {...props}>
<ScrollAreaPrimitive.Viewport className="h-full w-full rounded-[inherit]">{children}</ScrollAreaPrimitive.Viewport>
<ScrollBar />
<ScrollAreaPrimitive.Corner />
</ScrollAreaPrimitive.Root>
)
);
ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName;
const ScrollBar = React.forwardRef<
React.ElementRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>,
@@ -30,17 +23,15 @@ const ScrollBar = React.forwardRef<
orientation={orientation}
className={cn(
"flex touch-none select-none transition-colors",
orientation === "vertical" &&
"h-full w-2.5 border-l border-l-transparent p-[1px]",
orientation === "horizontal" &&
"h-2.5 flex-col border-t border-t-transparent p-[1px]",
orientation === "vertical" && "h-full w-2.5 border-l border-l-transparent p-[1px]",
orientation === "horizontal" && "h-2.5 flex-col border-t border-t-transparent p-[1px]",
className
)}
{...props}
>
<ScrollAreaPrimitive.ScrollAreaThumb className="relative flex-1 rounded-full bg-border" />
</ScrollAreaPrimitive.ScrollAreaScrollbar>
))
ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName
));
ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName;
export { ScrollArea, ScrollBar }
export { ScrollArea, ScrollBar };

View File

@@ -1,148 +1,112 @@
import * as React from "react"
import * as SelectPrimitive from "@radix-ui/react-select"
import { Check, ChevronDown, ChevronUp } from "lucide-react"
import * as React from "react";
import * as SelectPrimitive from "@radix-ui/react-select";
import { Check, ChevronDown, ChevronUp } from "lucide-react";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const Select = SelectPrimitive.Root
const Select = SelectPrimitive.Root;
const SelectGroup = SelectPrimitive.Group
const SelectGroup = SelectPrimitive.Group;
const SelectValue = SelectPrimitive.Value
const SelectValue = SelectPrimitive.Value;
const SelectTrigger = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Trigger>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>
>(({ className, children, ...props }, ref) => (
<SelectPrimitive.Trigger
ref={ref}
className={cn(
"flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
className
)}
{...props}
>
{children}
<SelectPrimitive.Icon asChild>
<ChevronDown className="h-4 w-4 opacity-50" />
</SelectPrimitive.Icon>
</SelectPrimitive.Trigger>
))
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName
const SelectTrigger = React.forwardRef<React.ElementRef<typeof SelectPrimitive.Trigger>, React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>>(
({ className, children, ...props }, ref) => (
<SelectPrimitive.Trigger
ref={ref}
className={cn(
"flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
className
)}
{...props}
>
{children}
<SelectPrimitive.Icon asChild>
<ChevronDown className="h-4 w-4 opacity-50" />
</SelectPrimitive.Icon>
</SelectPrimitive.Trigger>
)
);
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
const SelectScrollUpButton = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>
>(({ className, ...props }, ref) => (
<SelectPrimitive.ScrollUpButton
ref={ref}
className={cn(
"flex cursor-default items-center justify-center py-1",
className
)}
{...props}
>
<SelectPrimitive.ScrollUpButton ref={ref} className={cn("flex cursor-default items-center justify-center py-1", className)} {...props}>
<ChevronUp className="h-4 w-4" />
</SelectPrimitive.ScrollUpButton>
))
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName
));
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
const SelectScrollDownButton = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>
>(({ className, ...props }, ref) => (
<SelectPrimitive.ScrollDownButton
ref={ref}
className={cn(
"flex cursor-default items-center justify-center py-1",
className
)}
{...props}
>
<SelectPrimitive.ScrollDownButton ref={ref} className={cn("flex cursor-default items-center justify-center py-1", className)} {...props}>
<ChevronDown className="h-4 w-4" />
</SelectPrimitive.ScrollDownButton>
))
SelectScrollDownButton.displayName =
SelectPrimitive.ScrollDownButton.displayName
));
SelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName;
const SelectContent = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
>(({ className, children, position = "popper", ...props }, ref) => (
<SelectPrimitive.Portal>
<SelectPrimitive.Content
const SelectContent = React.forwardRef<React.ElementRef<typeof SelectPrimitive.Content>, React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>>(
({ className, children, position = "popper", ...props }, ref) => (
<SelectPrimitive.Portal>
<SelectPrimitive.Content
ref={ref}
className={cn(
"relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
position === "popper" &&
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
className
)}
position={position}
{...props}
>
<SelectScrollUpButton />
<SelectPrimitive.Viewport
className={cn("p-1", position === "popper" && "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]")}
>
{children}
</SelectPrimitive.Viewport>
<SelectScrollDownButton />
</SelectPrimitive.Content>
</SelectPrimitive.Portal>
)
);
SelectContent.displayName = SelectPrimitive.Content.displayName;
const SelectLabel = React.forwardRef<React.ElementRef<typeof SelectPrimitive.Label>, React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>>(
({ className, ...props }, ref) => <SelectPrimitive.Label ref={ref} className={cn("py-1.5 pl-8 pr-2 text-sm font-semibold", className)} {...props} />
);
SelectLabel.displayName = SelectPrimitive.Label.displayName;
const SelectItem = React.forwardRef<React.ElementRef<typeof SelectPrimitive.Item>, React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>>(
({ className, children, ...props }, ref) => (
<SelectPrimitive.Item
ref={ref}
className={cn(
"relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
position === "popper" &&
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
className
)}
position={position}
{...props}
>
<SelectScrollUpButton />
<SelectPrimitive.Viewport
className={cn(
"p-1",
position === "popper" &&
"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
)}
>
{children}
</SelectPrimitive.Viewport>
<SelectScrollDownButton />
</SelectPrimitive.Content>
</SelectPrimitive.Portal>
))
SelectContent.displayName = SelectPrimitive.Content.displayName
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<SelectPrimitive.ItemIndicator>
<Check className="h-4 w-4" />
</SelectPrimitive.ItemIndicator>
</span>
const SelectLabel = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Label>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>
>(({ className, ...props }, ref) => (
<SelectPrimitive.Label
ref={ref}
className={cn("py-1.5 pl-8 pr-2 text-sm font-semibold", className)}
{...props}
/>
))
SelectLabel.displayName = SelectPrimitive.Label.displayName
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
</SelectPrimitive.Item>
)
);
SelectItem.displayName = SelectPrimitive.Item.displayName;
const SelectItem = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
>(({ className, children, ...props }, ref) => (
<SelectPrimitive.Item
ref={ref}
className={cn(
"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
className
)}
{...props}
>
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<SelectPrimitive.ItemIndicator>
<Check className="h-4 w-4" />
</SelectPrimitive.ItemIndicator>
</span>
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
</SelectPrimitive.Item>
))
SelectItem.displayName = SelectPrimitive.Item.displayName
const SelectSeparator = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Separator>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>
>(({ className, ...props }, ref) => (
<SelectPrimitive.Separator
ref={ref}
className={cn("-mx-1 my-1 h-px bg-muted", className)}
{...props}
/>
))
SelectSeparator.displayName = SelectPrimitive.Separator.displayName
const SelectSeparator = React.forwardRef<React.ElementRef<typeof SelectPrimitive.Separator>, React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>>(
({ className, ...props }, ref) => <SelectPrimitive.Separator ref={ref} className={cn("-mx-1 my-1 h-px bg-muted", className)} {...props} />
);
SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
export {
Select,
@@ -155,4 +119,4 @@ export {
SelectSeparator,
SelectScrollUpButton,
SelectScrollDownButton,
}
};

View File

@@ -1,29 +1,19 @@
import * as React from "react"
import * as SeparatorPrimitive from "@radix-ui/react-separator"
import * as React from "react";
import * as SeparatorPrimitive from "@radix-ui/react-separator";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const Separator = React.forwardRef<
React.ElementRef<typeof SeparatorPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof SeparatorPrimitive.Root>
>(
(
{ className, orientation = "horizontal", decorative = true, ...props },
ref
) => (
const Separator = React.forwardRef<React.ElementRef<typeof SeparatorPrimitive.Root>, React.ComponentPropsWithoutRef<typeof SeparatorPrimitive.Root>>(
({ className, orientation = "horizontal", decorative = true, ...props }, ref) => (
<SeparatorPrimitive.Root
ref={ref}
decorative={decorative}
orientation={orientation}
className={cn(
"shrink-0 bg-border",
orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]",
className
)}
className={cn("shrink-0 bg-border", orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]", className)}
{...props}
/>
)
)
Separator.displayName = SeparatorPrimitive.Root.displayName
);
Separator.displayName = SeparatorPrimitive.Root.displayName;
export { Separator }
export { Separator };

View File

@@ -1,7 +1,7 @@
import * as React from "react";
import * as SheetPrimitive from "@radix-ui/react-dialog";
import { cva, type VariantProps } from "class-variance-authority";
import { X } from "lucide-react";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils";
@@ -13,19 +13,18 @@ const SheetClose = SheetPrimitive.Close;
const SheetPortal = SheetPrimitive.Portal;
const SheetOverlay = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Overlay>,
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Overlay>
>(({ className, ...props }, ref) => (
<SheetPrimitive.Overlay
className={cn(
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
className
)}
{...props}
ref={ref}
/>
));
const SheetOverlay = React.forwardRef<React.ElementRef<typeof SheetPrimitive.Overlay>, React.ComponentPropsWithoutRef<typeof SheetPrimitive.Overlay>>(
({ className, ...props }, ref) => (
<SheetPrimitive.Overlay
className={cn(
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
className
)}
{...props}
ref={ref}
/>
)
);
SheetOverlay.displayName = SheetPrimitive.Overlay.displayName;
const sheetVariants = cva(
@@ -34,11 +33,9 @@ const sheetVariants = cva(
variants: {
side: {
top: "inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",
bottom:
"inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",
bottom: "inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",
left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",
right:
"inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm",
right: "inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm",
},
},
defaultVariants: {
@@ -47,92 +44,43 @@ const sheetVariants = cva(
}
);
interface SheetContentProps
extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>,
VariantProps<typeof sheetVariants> {}
interface SheetContentProps extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>, VariantProps<typeof sheetVariants> {}
const SheetContent = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Content>,
SheetContentProps
>(({ side = "right", className, children, ...props }, ref) => (
<SheetPortal>
<SheetOverlay />
<SheetPrimitive.Content
ref={ref}
className={cn(sheetVariants({ side }), className)}
{...props}
>
{children}
<SheetPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary">
<X className="h-4 w-4 dark:text-stone-200" />
<span className="sr-only">Close</span>
</SheetPrimitive.Close>
</SheetPrimitive.Content>
</SheetPortal>
));
const SheetContent = React.forwardRef<React.ElementRef<typeof SheetPrimitive.Content>, SheetContentProps>(
({ side = "right", className, children, ...props }, ref) => (
<SheetPortal>
<SheetOverlay />
<SheetPrimitive.Content ref={ref} className={cn(sheetVariants({ side }), className)} {...props}>
{children}
<SheetPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary">
<X className="h-4 w-4 dark:text-stone-200" />
<span className="sr-only">Close</span>
</SheetPrimitive.Close>
</SheetPrimitive.Content>
</SheetPortal>
)
);
SheetContent.displayName = SheetPrimitive.Content.displayName;
const SheetHeader = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col space-y-2 text-center sm:text-left",
className
)}
{...props}
/>
const SheetHeader = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
<div className={cn("flex flex-col space-y-2 text-center sm:text-left", className)} {...props} />
);
SheetHeader.displayName = "SheetHeader";
const SheetFooter = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
className
)}
{...props}
/>
const SheetFooter = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
<div className={cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className)} {...props} />
);
SheetFooter.displayName = "SheetFooter";
const SheetTitle = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Title>
>(({ className, ...props }, ref) => (
<SheetPrimitive.Title
ref={ref}
className={cn("text-lg font-semibold text-foreground", className)}
{...props}
/>
));
const SheetTitle = React.forwardRef<React.ElementRef<typeof SheetPrimitive.Title>, React.ComponentPropsWithoutRef<typeof SheetPrimitive.Title>>(
({ className, ...props }, ref) => <SheetPrimitive.Title ref={ref} className={cn("text-lg font-semibold text-foreground", className)} {...props} />
);
SheetTitle.displayName = SheetPrimitive.Title.displayName;
const SheetDescription = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Description>
>(({ className, ...props }, ref) => (
<SheetPrimitive.Description
ref={ref}
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
));
>(({ className, ...props }, ref) => <SheetPrimitive.Description ref={ref} className={cn("text-sm text-muted-foreground", className)} {...props} />);
SheetDescription.displayName = SheetPrimitive.Description.displayName;
export {
Sheet,
SheetPortal,
SheetOverlay,
SheetTrigger,
SheetClose,
SheetContent,
SheetHeader,
SheetFooter,
SheetTitle,
SheetDescription,
};
export { Sheet, SheetPortal, SheetOverlay, SheetTrigger, SheetClose, SheetContent, SheetHeader, SheetFooter, SheetTitle, SheetDescription };

View File

@@ -1,27 +1,26 @@
import * as React from "react"
import * as SwitchPrimitives from "@radix-ui/react-switch"
import * as React from "react";
import * as SwitchPrimitives from "@radix-ui/react-switch";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const Switch = React.forwardRef<
React.ElementRef<typeof SwitchPrimitives.Root>,
React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root>
>(({ className, ...props }, ref) => (
<SwitchPrimitives.Root
className={cn(
"peer inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",
className
)}
{...props}
ref={ref}
>
<SwitchPrimitives.Thumb
const Switch = React.forwardRef<React.ElementRef<typeof SwitchPrimitives.Root>, React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root>>(
({ className, ...props }, ref) => (
<SwitchPrimitives.Root
className={cn(
"pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0"
"peer inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",
className
)}
/>
</SwitchPrimitives.Root>
))
Switch.displayName = SwitchPrimitives.Root.displayName
{...props}
ref={ref}
>
<SwitchPrimitives.Thumb
className={cn(
"pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0"
)}
/>
</SwitchPrimitives.Root>
)
);
Switch.displayName = SwitchPrimitives.Root.displayName;
export { Switch }
export { Switch };

View File

@@ -1,117 +1,47 @@
import * as React from "react"
import * as React from "react";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const Table = React.forwardRef<
HTMLTableElement,
React.HTMLAttributes<HTMLTableElement>
>(({ className, ...props }, ref) => (
const Table = React.forwardRef<HTMLTableElement, React.HTMLAttributes<HTMLTableElement>>(({ className, ...props }, ref) => (
<div className="relative w-full overflow-auto">
<table
ref={ref}
className={cn("w-full caption-bottom text-sm", className)}
{...props}
/>
<table ref={ref} className={cn("w-full caption-bottom text-sm", className)} {...props} />
</div>
))
Table.displayName = "Table"
));
Table.displayName = "Table";
const TableHeader = React.forwardRef<
HTMLTableSectionElement,
React.HTMLAttributes<HTMLTableSectionElement>
>(({ className, ...props }, ref) => (
const TableHeader = React.forwardRef<HTMLTableSectionElement, React.HTMLAttributes<HTMLTableSectionElement>>(({ className, ...props }, ref) => (
<thead ref={ref} className={cn("[&_tr]:border-b", className)} {...props} />
))
TableHeader.displayName = "TableHeader"
));
TableHeader.displayName = "TableHeader";
const TableBody = React.forwardRef<
HTMLTableSectionElement,
React.HTMLAttributes<HTMLTableSectionElement>
>(({ className, ...props }, ref) => (
<tbody
ref={ref}
className={cn("[&_tr:last-child]:border-0", className)}
{...props}
/>
))
TableBody.displayName = "TableBody"
const TableBody = React.forwardRef<HTMLTableSectionElement, React.HTMLAttributes<HTMLTableSectionElement>>(({ className, ...props }, ref) => (
<tbody ref={ref} className={cn("[&_tr:last-child]:border-0", className)} {...props} />
));
TableBody.displayName = "TableBody";
const TableFooter = React.forwardRef<
HTMLTableSectionElement,
React.HTMLAttributes<HTMLTableSectionElement>
>(({ className, ...props }, ref) => (
<tfoot
ref={ref}
className={cn(
"border-t bg-muted/50 font-medium [&>tr]:last:border-b-0",
className
)}
{...props}
/>
))
TableFooter.displayName = "TableFooter"
const TableFooter = React.forwardRef<HTMLTableSectionElement, React.HTMLAttributes<HTMLTableSectionElement>>(({ className, ...props }, ref) => (
<tfoot ref={ref} className={cn("border-t bg-muted/50 font-medium [&>tr]:last:border-b-0", className)} {...props} />
));
TableFooter.displayName = "TableFooter";
const TableRow = React.forwardRef<
HTMLTableRowElement,
React.HTMLAttributes<HTMLTableRowElement>
>(({ className, ...props }, ref) => (
<tr
ref={ref}
className={cn(
"border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted",
className
)}
{...props}
/>
))
TableRow.displayName = "TableRow"
const TableRow = React.forwardRef<HTMLTableRowElement, React.HTMLAttributes<HTMLTableRowElement>>(({ className, ...props }, ref) => (
<tr ref={ref} className={cn("border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted", className)} {...props} />
));
TableRow.displayName = "TableRow";
const TableHead = React.forwardRef<
HTMLTableCellElement,
React.ThHTMLAttributes<HTMLTableCellElement>
>(({ className, ...props }, ref) => (
<th
ref={ref}
className={cn(
"h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0",
className
)}
{...props}
/>
))
TableHead.displayName = "TableHead"
const TableHead = React.forwardRef<HTMLTableCellElement, React.ThHTMLAttributes<HTMLTableCellElement>>(({ className, ...props }, ref) => (
<th ref={ref} className={cn("h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0", className)} {...props} />
));
TableHead.displayName = "TableHead";
const TableCell = React.forwardRef<
HTMLTableCellElement,
React.TdHTMLAttributes<HTMLTableCellElement>
>(({ className, ...props }, ref) => (
<td
ref={ref}
className={cn("p-4 align-middle [&:has([role=checkbox])]:pr-0", className)}
{...props}
/>
))
TableCell.displayName = "TableCell"
const TableCell = React.forwardRef<HTMLTableCellElement, React.TdHTMLAttributes<HTMLTableCellElement>>(({ className, ...props }, ref) => (
<td ref={ref} className={cn("p-4 align-middle [&:has([role=checkbox])]:pr-0", className)} {...props} />
));
TableCell.displayName = "TableCell";
const TableCaption = React.forwardRef<
HTMLTableCaptionElement,
React.HTMLAttributes<HTMLTableCaptionElement>
>(({ className, ...props }, ref) => (
<caption
ref={ref}
className={cn("mt-4 text-sm text-muted-foreground", className)}
{...props}
/>
))
TableCaption.displayName = "TableCaption"
const TableCaption = React.forwardRef<HTMLTableCaptionElement, React.HTMLAttributes<HTMLTableCaptionElement>>(({ className, ...props }, ref) => (
<caption ref={ref} className={cn("mt-4 text-sm text-muted-foreground", className)} {...props} />
));
TableCaption.displayName = "TableCaption";
export {
Table,
TableHeader,
TableBody,
TableFooter,
TableHead,
TableRow,
TableCell,
TableCaption,
}
export { Table, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption };

View File

@@ -1,53 +1,47 @@
import * as React from "react"
import * as TabsPrimitive from "@radix-ui/react-tabs"
import * as React from "react";
import * as TabsPrimitive from "@radix-ui/react-tabs";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const Tabs = TabsPrimitive.Root
const Tabs = TabsPrimitive.Root;
const TabsList = React.forwardRef<
React.ElementRef<typeof TabsPrimitive.List>,
React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>
>(({ className, ...props }, ref) => (
<TabsPrimitive.List
ref={ref}
className={cn(
"inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground",
className
)}
{...props}
/>
))
TabsList.displayName = TabsPrimitive.List.displayName
const TabsList = React.forwardRef<React.ElementRef<typeof TabsPrimitive.List>, React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>>(
({ className, ...props }, ref) => (
<TabsPrimitive.List
ref={ref}
className={cn("inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground", className)}
{...props}
/>
)
);
TabsList.displayName = TabsPrimitive.List.displayName;
const TabsTrigger = React.forwardRef<
React.ElementRef<typeof TabsPrimitive.Trigger>,
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>
>(({ className, ...props }, ref) => (
<TabsPrimitive.Trigger
ref={ref}
className={cn(
"inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm",
className
)}
{...props}
/>
))
TabsTrigger.displayName = TabsPrimitive.Trigger.displayName
const TabsTrigger = React.forwardRef<React.ElementRef<typeof TabsPrimitive.Trigger>, React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>>(
({ className, ...props }, ref) => (
<TabsPrimitive.Trigger
ref={ref}
className={cn(
"inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm",
className
)}
{...props}
/>
)
);
TabsTrigger.displayName = TabsPrimitive.Trigger.displayName;
const TabsContent = React.forwardRef<
React.ElementRef<typeof TabsPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>
>(({ className, ...props }, ref) => (
<TabsPrimitive.Content
ref={ref}
className={cn(
"mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
className
)}
{...props}
/>
))
TabsContent.displayName = TabsPrimitive.Content.displayName
const TabsContent = React.forwardRef<React.ElementRef<typeof TabsPrimitive.Content>, React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>>(
({ className, ...props }, ref) => (
<TabsPrimitive.Content
ref={ref}
className={cn(
"mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
className
)}
{...props}
/>
)
);
TabsContent.displayName = TabsPrimitive.Content.displayName;
export { Tabs, TabsList, TabsTrigger, TabsContent }
export { Tabs, TabsList, TabsTrigger, TabsContent };

View File

@@ -1,24 +1,21 @@
import * as React from "react"
import * as React from "react";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
export interface TextareaProps
extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {}
export interface TextareaProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {}
const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
({ className, ...props }, ref) => {
return (
<textarea
className={cn(
"flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
className
)}
ref={ref}
{...props}
/>
)
}
)
Textarea.displayName = "Textarea"
const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(({ className, ...props }, ref) => {
return (
<textarea
className={cn(
"flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
className
)}
ref={ref}
{...props}
/>
);
});
Textarea.displayName = "Textarea";
export { Textarea }
export { Textarea };

View File

@@ -1,26 +1,25 @@
import * as React from "react"
import * as ToastPrimitives from "@radix-ui/react-toast"
import { cva, type VariantProps } from "class-variance-authority"
import { X } from "lucide-react"
import * as React from "react";
import * as ToastPrimitives from "@radix-ui/react-toast";
import { X } from "lucide-react";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const ToastProvider = ToastPrimitives.Provider
const ToastProvider = ToastPrimitives.Provider;
const ToastViewport = React.forwardRef<
React.ElementRef<typeof ToastPrimitives.Viewport>,
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Viewport>
>(({ className, ...props }, ref) => (
<ToastPrimitives.Viewport
ref={ref}
className={cn(
"fixed top-0 z-[100] flex max-h-screen w-full flex-col-reverse p-4 sm:bottom-0 sm:right-0 sm:top-auto sm:flex-col md:max-w-[420px]",
className
)}
{...props}
/>
))
ToastViewport.displayName = ToastPrimitives.Viewport.displayName
const ToastViewport = React.forwardRef<React.ElementRef<typeof ToastPrimitives.Viewport>, React.ComponentPropsWithoutRef<typeof ToastPrimitives.Viewport>>(
({ className, ...props }, ref) => (
<ToastPrimitives.Viewport
ref={ref}
className={cn(
"fixed top-0 z-[100] flex max-h-screen w-full flex-col-reverse p-4 sm:bottom-0 sm:right-0 sm:top-auto sm:flex-col md:max-w-[420px]",
className
)}
{...props}
/>
)
);
ToastViewport.displayName = ToastPrimitives.Viewport.displayName;
const toastVariants = cva(
"group pointer-events-auto relative flex w-full items-center justify-between space-x-4 overflow-hidden rounded-md border p-6 pr-8 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full",
@@ -28,100 +27,67 @@ const toastVariants = cva(
variants: {
variant: {
default: "border bg-background text-foreground",
destructive:
"destructive group border-destructive bg-destructive text-destructive-foreground",
destructive: "destructive group border-destructive bg-destructive text-destructive-foreground",
},
},
defaultVariants: {
variant: "default",
},
}
)
);
const Toast = React.forwardRef<
React.ElementRef<typeof ToastPrimitives.Root>,
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Root> &
VariantProps<typeof toastVariants>
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Root> & VariantProps<typeof toastVariants>
>(({ className, variant, ...props }, ref) => {
return (
<ToastPrimitives.Root
return <ToastPrimitives.Root ref={ref} className={cn(toastVariants({ variant }), className)} {...props} />;
});
Toast.displayName = ToastPrimitives.Root.displayName;
const ToastAction = React.forwardRef<React.ElementRef<typeof ToastPrimitives.Action>, React.ComponentPropsWithoutRef<typeof ToastPrimitives.Action>>(
({ className, ...props }, ref) => (
<ToastPrimitives.Action
ref={ref}
className={cn(toastVariants({ variant }), className)}
className={cn(
"inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 text-sm font-medium ring-offset-background transition-colors hover:bg-secondary focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 group-[.destructive]:border-muted/40 group-[.destructive]:hover:border-destructive/30 group-[.destructive]:hover:bg-destructive group-[.destructive]:hover:text-destructive-foreground group-[.destructive]:focus:ring-destructive",
className
)}
{...props}
/>
)
})
Toast.displayName = ToastPrimitives.Root.displayName
);
ToastAction.displayName = ToastPrimitives.Action.displayName;
const ToastAction = React.forwardRef<
React.ElementRef<typeof ToastPrimitives.Action>,
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Action>
>(({ className, ...props }, ref) => (
<ToastPrimitives.Action
ref={ref}
className={cn(
"inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 text-sm font-medium ring-offset-background transition-colors hover:bg-secondary focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 group-[.destructive]:border-muted/40 group-[.destructive]:hover:border-destructive/30 group-[.destructive]:hover:bg-destructive group-[.destructive]:hover:text-destructive-foreground group-[.destructive]:focus:ring-destructive",
className
)}
{...props}
/>
))
ToastAction.displayName = ToastPrimitives.Action.displayName
const ToastClose = React.forwardRef<React.ElementRef<typeof ToastPrimitives.Close>, React.ComponentPropsWithoutRef<typeof ToastPrimitives.Close>>(
({ className, ...props }, ref) => (
<ToastPrimitives.Close
ref={ref}
className={cn(
"absolute right-2 top-2 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-2 group-hover:opacity-100 group-[.destructive]:text-red-300 group-[.destructive]:hover:text-red-50 group-[.destructive]:focus:ring-red-400 group-[.destructive]:focus:ring-offset-red-600",
className
)}
toast-close=""
{...props}
>
<X className="h-4 w-4" />
</ToastPrimitives.Close>
)
);
ToastClose.displayName = ToastPrimitives.Close.displayName;
const ToastClose = React.forwardRef<
React.ElementRef<typeof ToastPrimitives.Close>,
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Close>
>(({ className, ...props }, ref) => (
<ToastPrimitives.Close
ref={ref}
className={cn(
"absolute right-2 top-2 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-2 group-hover:opacity-100 group-[.destructive]:text-red-300 group-[.destructive]:hover:text-red-50 group-[.destructive]:focus:ring-red-400 group-[.destructive]:focus:ring-offset-red-600",
className
)}
toast-close=""
{...props}
>
<X className="h-4 w-4" />
</ToastPrimitives.Close>
))
ToastClose.displayName = ToastPrimitives.Close.displayName
const ToastTitle = React.forwardRef<
React.ElementRef<typeof ToastPrimitives.Title>,
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Title>
>(({ className, ...props }, ref) => (
<ToastPrimitives.Title
ref={ref}
className={cn("text-sm font-semibold", className)}
{...props}
/>
))
ToastTitle.displayName = ToastPrimitives.Title.displayName
const ToastTitle = React.forwardRef<React.ElementRef<typeof ToastPrimitives.Title>, React.ComponentPropsWithoutRef<typeof ToastPrimitives.Title>>(
({ className, ...props }, ref) => <ToastPrimitives.Title ref={ref} className={cn("text-sm font-semibold", className)} {...props} />
);
ToastTitle.displayName = ToastPrimitives.Title.displayName;
const ToastDescription = React.forwardRef<
React.ElementRef<typeof ToastPrimitives.Description>,
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Description>
>(({ className, ...props }, ref) => (
<ToastPrimitives.Description
ref={ref}
className={cn("text-sm opacity-90", className)}
{...props}
/>
))
ToastDescription.displayName = ToastPrimitives.Description.displayName
>(({ className, ...props }, ref) => <ToastPrimitives.Description ref={ref} className={cn("text-sm opacity-90", className)} {...props} />);
ToastDescription.displayName = ToastPrimitives.Description.displayName;
type ToastProps = React.ComponentPropsWithoutRef<typeof Toast>
type ToastProps = React.ComponentPropsWithoutRef<typeof Toast>;
type ToastActionElement = React.ReactElement<typeof ToastAction>
type ToastActionElement = React.ReactElement<typeof ToastAction>;
export {
type ToastProps,
type ToastActionElement,
ToastProvider,
ToastViewport,
Toast,
ToastTitle,
ToastDescription,
ToastClose,
ToastAction,
}
export { type ToastProps, type ToastActionElement, ToastProvider, ToastViewport, Toast, ToastTitle, ToastDescription, ToastClose, ToastAction };

View File

@@ -1,15 +1,8 @@
import {
Toast,
ToastClose,
ToastDescription,
ToastProvider,
ToastTitle,
ToastViewport,
} from "@/components/ui/toast"
import { useToast } from "@/components/ui/use-toast"
import { Toast, ToastClose, ToastDescription, ToastProvider, ToastTitle, ToastViewport } from "@/components/ui/toast";
import { useToast } from "@/components/ui/use-toast";
export function Toaster() {
const { toasts } = useToast()
const { toasts } = useToast();
return (
<ToastProvider>
@@ -18,16 +11,14 @@ export function Toaster() {
<Toast key={id} {...props}>
<div className="grid gap-1">
{title && <ToastTitle>{title}</ToastTitle>}
{description && (
<ToastDescription>{description}</ToastDescription>
)}
{description && <ToastDescription>{description}</ToastDescription>}
</div>
{action}
<ToastClose />
</Toast>
)
);
})}
<ToastViewport />
</ToastProvider>
)
);
}

View File

@@ -1,28 +1,27 @@
import * as React from "react"
import * as TooltipPrimitive from "@radix-ui/react-tooltip"
import * as React from "react";
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const TooltipProvider = TooltipPrimitive.Provider
const TooltipProvider = TooltipPrimitive.Provider;
const Tooltip = TooltipPrimitive.Root
const Tooltip = TooltipPrimitive.Root;
const TooltipTrigger = TooltipPrimitive.Trigger
const TooltipTrigger = TooltipPrimitive.Trigger;
const TooltipContent = React.forwardRef<
React.ElementRef<typeof TooltipPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
>(({ className, sideOffset = 4, ...props }, ref) => (
<TooltipPrimitive.Content
ref={ref}
sideOffset={sideOffset}
className={cn(
"z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className
)}
{...props}
/>
))
TooltipContent.displayName = TooltipPrimitive.Content.displayName
const TooltipContent = React.forwardRef<React.ElementRef<typeof TooltipPrimitive.Content>, React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>>(
({ className, sideOffset = 4, ...props }, ref) => (
<TooltipPrimitive.Content
ref={ref}
sideOffset={sideOffset}
className={cn(
"z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className
)}
{...props}
/>
)
);
TooltipContent.displayName = TooltipPrimitive.Content.displayName;
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };

View File

@@ -80,9 +80,7 @@ export const reducer = (state: State, action: Action): State => {
case "UPDATE_TOAST":
return {
...state,
toasts: state.toasts.map((t) =>
t.id === action.toast.id ? { ...t, ...action.toast } : t
),
toasts: state.toasts.map((t) => (t.id === action.toast.id ? { ...t, ...action.toast } : t)),
};
case "DISMISS_TOAST": {

View File

@@ -1,11 +1,7 @@
export type Setting = {
id?: string;
name?: string;
content?:
| EmailsSetting
| NotifyTemplates
| NotifyChannels
| SSLProviderSetting;
content?: EmailsSetting | NotifyTemplates | NotifyChannels | SSLProviderSetting;
};
export type EmailsSetting = {
@@ -27,10 +23,7 @@ export type NotifyChannels = {
webhook?: NotifyChannel;
};
export type NotifyChannel =
| NotifyChannelDingTalk
| NotifyChannelTelegram
| NotifyChannelWebhook;
export type NotifyChannel = NotifyChannelDingTalk | NotifyChannelTelegram | NotifyChannelWebhook;
export type NotifyChannelDingTalk = {
accessToken: string;

View File

@@ -2,8 +2,6 @@
@tailwind components;
@tailwind utilities;
@layer base {
:root {
--background: 0 0% 100%;

View File

@@ -16,7 +16,7 @@
"common.update": "Update",
"common.update.succeeded.message": "Update Successful",
"common.update.failed.message": "Update Failed",
"common.text.domain": "Domain",
"common.text.domain.empty": "No Domain",
"common.text.ip": "IP Address",
@@ -42,7 +42,7 @@
"common.theme.light": "Light",
"common.theme.dark": "Dark",
"common.theme.system": "System",
"common.errmsg.string_max": "Please enter no more than {{max}} characters",
"common.errmsg.email_invalid": "Please enter a valid email address",
"common.errmsg.email_empty": "Please enter email",
@@ -53,14 +53,14 @@
"common.errmsg.url_invalid": "Please enter a valid URL",
"common.provider.aliyun": "Alibaba Cloud",
"common.provider.aliyun.cdn": "Alibaba Cloud-CDN",
"common.provider.aliyun.oss": "Alibaba Cloud-OSS",
"common.provider.aliyun.dcdn": "Alibaba Cloud-DCDN",
"common.provider.aliyun.oss": "Alibaba Cloud - OSS",
"common.provider.aliyun.cdn": "Alibaba Cloud - CDN",
"common.provider.aliyun.dcdn": "Alibaba Cloud - DCDN",
"common.provider.tencent": "Tencent",
"common.provider.tencent.cdn": "Tencent-CDN",
"common.provider.tencent.cdn": "Tencent - CDN",
"common.provider.huaweicloud": "Huawei Cloud",
"common.provider.qiniu": "Qiniu",
"common.provider.qiniu.cdn": "Qiniu-CDN",
"common.provider.qiniu.cdn": "Qiniu - CDN",
"common.provider.cloudflare": "Cloudflare",
"common.provider.namesilo": "Namesilo",
"common.provider.godaddy": "GoDaddy",

View File

@@ -1,6 +1,6 @@
{
"dashboard.page.title": "Dashboard",
"dashboard.statistics.all": "All",
"dashboard.statistics.near_expired": "About to Expire",
"dashboard.statistics.enabled": "Enabled",

View File

@@ -2,7 +2,7 @@
"domain.page.title": "Domain List",
"domain.nodata": "Please add a domain to start deploying the certificate.",
"domain.add": "Add Domain",
"domain.edit": "Edit Domain",
"domain.delete": "Delete Domain",

View File

@@ -10,6 +10,6 @@
"history.props.stage.progress.apply": "Apply",
"history.props.stage.progress.deploy": "Deploy",
"history.props.last_execution_time": "Last Execution Time",
"history.log": "Log"
}

View File

@@ -16,7 +16,7 @@
"common.update": "更新",
"common.update.succeeded.message": "修改成功",
"common.update.failed.message": "修改失败",
"common.text.domain": "域名",
"common.text.domain.empty": "无域名",
"common.text.ip": "IP 地址",
@@ -53,14 +53,14 @@
"common.errmsg.url_invalid": "请输入正确的 URL",
"common.provider.tencent": "腾讯云",
"common.provider.tencent.cdn": "腾讯云-CDN",
"common.provider.tencent.cdn": "腾讯云 - CDN",
"common.provider.aliyun": "阿里云",
"common.provider.aliyun.cdn": "阿里云-CDN",
"common.provider.aliyun.oss": "阿里云-OSS",
"common.provider.aliyun.dcdn": "阿里云-DCDN",
"common.provider.aliyun.oss": "阿里云 - OSS",
"common.provider.aliyun.cdn": "阿里云 - CDN",
"common.provider.aliyun.dcdn": "阿里云 - DCDN",
"common.provider.huaweicloud": "华为云",
"common.provider.qiniu": "七牛云",
"common.provider.qiniu.cdn": "七牛云-CDN",
"common.provider.qiniu.cdn": "七牛云 - CDN",
"common.provider.cloudflare": "Cloudflare",
"common.provider.namesilo": "Namesilo",
"common.provider.godaddy": "GoDaddy",

View File

@@ -1,8 +1,8 @@
{
"domain.page.title": "域名列表",
"domain.nodata": "请添加域名开始部署证书吧。",
"domain.add": "新增域名",
"domain.edit": "编辑域名",
"domain.delete": "删除域名",
@@ -14,7 +14,7 @@
"domain.deploy.failed.message": "执行失败",
"domain.deploy.failed.tips": "执行失败,请在 <1>部署历史</1> 查看详情。",
"domain.deploy_forced": "强行部署",
"domain.props.expiry": "有效期限",
"domain.props.expiry.date1": "有效期 {{date}} 天",
"domain.props.expiry.date2": "{{date}} 到期",

View File

@@ -10,6 +10,6 @@
"history.props.stage.progress.apply": "获取",
"history.props.stage.progress.deploy": "部署",
"history.props.last_execution_time": "最近执行时间",
"history.log": "日志"
}

View File

@@ -1,11 +1,7 @@
export const getErrMessage = (error: unknown): string => {
if (error instanceof Error) {
return error.message;
} else if (
typeof error === "object" &&
error !== null &&
"message" in error
) {
} else if (typeof error === "object" && error !== null && "message" in error) {
return String(error.message);
} else if (typeof error === "string") {
return error;

View File

@@ -1,6 +1,6 @@
import { type ClassValue, clsx } from "clsx"
import { twMerge } from "tailwind-merge"
import { type ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
return twMerge(clsx(inputs));
}

View File

@@ -1,10 +1,11 @@
import React from "react";
import ReactDOM from "react-dom/client";
import "./global.css";
import { RouterProvider } from "react-router-dom";
import { router } from "./router.tsx";
import { ThemeProvider } from "./components/ThemeProvider.tsx";
import "@/i18n";
import "./i18n";
import "./global.css";
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>

View File

@@ -1,27 +1,15 @@
import {
Link,
Navigate,
Outlet,
useLocation,
useNavigate,
} from "react-router-dom";
import { CircleUser, Earth, History, Home, Menu, Server } from "lucide-react";
import { Link, Navigate, Outlet, useLocation, useNavigate } from "react-router-dom";
import { useTranslation } from "react-i18next";
import { CircleUser, Earth, History, Home, Menu, Server } from "lucide-react";
import LocaleToggle from "@/components/LocaleToggle";
import { ThemeToggle } from "@/components/ThemeToggle";
import { Button } from "@/components/ui/button";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu";
import { Sheet, SheetContent, SheetTrigger } from "@/components/ui/sheet";
import { cn } from "@/lib/utils";
import { ConfigProvider } from "@/providers/config";
import { getPb } from "@/repository/api";
import { ThemeToggle } from "@/components/ThemeToggle";
import LocaleToggle from "@/components/LocaleToggle";
import { ConfigProvider } from "@/providers/config";
import Version from "@/components/certimate/Version";
@@ -33,14 +21,15 @@ export default function Dashboard() {
if (!getPb().authStore.isValid || !getPb().authStore.isAdmin) {
return <Navigate to="/login" />;
}
const currentPath = location.pathname;
const getClass = (path: string) => {
console.log(currentPath);
if (path == currentPath) {
return "bg-muted text-primary";
}
return "text-muted-foreground";
};
const handleLogoutClick = () => {
getPb().authStore.clear();
navigate("/login");
@@ -49,6 +38,7 @@ export default function Dashboard() {
const handleSettingClick = () => {
navigate("/setting/account");
};
return (
<>
<ConfigProvider>
@@ -63,44 +53,20 @@ export default function Dashboard() {
</div>
<div className="flex-1">
<nav className="grid items-start px-2 text-sm font-medium lg:px-4">
<Link
to="/"
className={cn(
"flex items-center gap-3 rounded-lg px-3 py-2 transition-all hover:text-primary",
getClass("/")
)}
>
<Link to="/" className={cn("flex items-center gap-3 rounded-lg px-3 py-2 transition-all hover:text-primary", getClass("/"))}>
<Home className="h-4 w-4" />
{t("dashboard.page.title")}
</Link>
<Link
to="/domains"
className={cn(
"flex items-center gap-3 rounded-lg px-3 py-2 transition-all hover:text-primary",
getClass("/domains")
)}
>
<Link to="/domains" className={cn("flex items-center gap-3 rounded-lg px-3 py-2 transition-all hover:text-primary", getClass("/domains"))}>
<Earth className="h-4 w-4" />
{t("domain.page.title")}
</Link>
<Link
to="/access"
className={cn(
"flex items-center gap-3 rounded-lg px-3 py-2 transition-all hover:text-primary",
getClass("/access")
)}
>
<Link to="/access" className={cn("flex items-center gap-3 rounded-lg px-3 py-2 transition-all hover:text-primary", getClass("/access"))}>
<Server className="h-4 w-4" />
{t("access.page.title")}
</Link>
<Link
to="/history"
className={cn(
"flex items-center gap-3 rounded-lg px-3 py-2 transition-all hover:text-primary",
getClass("/history")
)}
>
<Link to="/history" className={cn("flex items-center gap-3 rounded-lg px-3 py-2 transition-all hover:text-primary", getClass("/history"))}>
<History className="h-4 w-4" />
{t("history.page.title")}
</Link>
@@ -112,51 +78,32 @@ export default function Dashboard() {
<header className="flex h-14 items-center gap-4 border-b dark:border-stone-500 bg-muted/40 px-4 lg:h-[60px] lg:px-6">
<Sheet>
<SheetTrigger asChild>
<Button
variant="outline"
size="icon"
className="shrink-0 md:hidden"
>
<Button variant="outline" size="icon" className="shrink-0 md:hidden">
<Menu className="h-5 w-5 dark:text-white" />
<span className="sr-only">Toggle navigation menu</span>
</Button>
</SheetTrigger>
<SheetContent side="left" className="flex flex-col">
<nav className="grid gap-2 text-lg font-medium">
<Link
to="/"
className="flex items-center gap-2 text-lg font-semibold"
>
<Link to="/" className="flex items-center gap-2 text-lg font-semibold">
<img src="/vite.svg" className="w-[36px] h-[36px]" />
<span className="dark:text-white">Certimate</span>
<span className="sr-only">Certimate</span>
</Link>
<Link
to="/"
className={cn(
"mx-[-0.65rem] flex items-center gap-4 rounded-xl px-3 py-2 hover:text-foreground",
getClass("/")
)}
>
<Link to="/" className={cn("mx-[-0.65rem] flex items-center gap-4 rounded-xl px-3 py-2 hover:text-foreground", getClass("/"))}>
<Home className="h-5 w-5" />
{t("dashboard.page.title")}
</Link>
<Link
to="/domains"
className={cn(
"mx-[-0.65rem] flex items-center gap-4 rounded-xl px-3 py-2 hover:text-foreground",
getClass("/domains")
)}
className={cn("mx-[-0.65rem] flex items-center gap-4 rounded-xl px-3 py-2 hover:text-foreground", getClass("/domains"))}
>
<Earth className="h-5 w-5" />
{t("domain.page.title")}
</Link>
<Link
to="/access"
className={cn(
"mx-[-0.65rem] flex items-center gap-4 rounded-xl px-3 py-2 hover:text-foreground",
getClass("/access")
)}
className={cn("mx-[-0.65rem] flex items-center gap-4 rounded-xl px-3 py-2 hover:text-foreground", getClass("/access"))}
>
<Server className="h-5 w-5" />
{t("access.page.title")}
@@ -164,10 +111,7 @@ export default function Dashboard() {
<Link
to="/history"
className={cn(
"mx-[-0.65rem] flex items-center gap-4 rounded-xl px-3 py-2 hover:text-foreground",
getClass("/history")
)}
className={cn("mx-[-0.65rem] flex items-center gap-4 rounded-xl px-3 py-2 hover:text-foreground", getClass("/history"))}
>
<History className="h-5 w-5" />
{t("history.page.title")}
@@ -180,22 +124,14 @@ export default function Dashboard() {
<LocaleToggle />
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
variant="secondary"
size="icon"
className="rounded-full"
>
<Button variant="secondary" size="icon" className="rounded-full">
<CircleUser className="h-5 w-5" />
<span className="sr-only">Toggle user menu</span>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem onClick={handleSettingClick}>
{t("common.menu.settings")}
</DropdownMenuItem>
<DropdownMenuItem onClick={handleLogoutClick}>
{t("common.menu.logout")}
</DropdownMenuItem>
<DropdownMenuItem onClick={handleSettingClick}>{t("common.menu.settings")}</DropdownMenuItem>
<DropdownMenuItem onClick={handleLogoutClick}>{t("common.menu.logout")}</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</header>

View File

@@ -1,13 +1,13 @@
import Version from "@/components/certimate/Version";
import { getPb } from "@/repository/api";
import { Navigate, Outlet } from "react-router-dom";
import Version from "@/components/certimate/Version";
import { getPb } from "@/repository/api";
const LoginLayout = () => {
if (getPb().authStore.isValid && getPb().authStore.isAdmin) {
return <Navigate to="/" />;
}
return (
<div className="container">
<Outlet />

View File

@@ -1,10 +1,10 @@
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { Toaster } from "@/components/ui/toaster";
import { KeyRound, Megaphone, ShieldCheck, UserRound } from "lucide-react";
import { useEffect, useState } from "react";
import { Outlet, useLocation, useNavigate } from "react-router-dom";
import { useTranslation } from "react-i18next";
import { KeyRound, Megaphone, ShieldCheck, UserRound } from "lucide-react";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { Toaster } from "@/components/ui/toaster";
const SettingLayout = () => {
const location = useLocation();
@@ -21,9 +21,7 @@ const SettingLayout = () => {
return (
<div>
<Toaster />
<div className="text-muted-foreground border-b dark:border-stone-500 py-5">
{t("settings.page.title")}
</div>
<div className="text-muted-foreground border-b dark:border-stone-500 py-5">{t("settings.page.title")}</div>
<div className="w-full mt-5 p-0 md:p-3 flex justify-center">
<Tabs defaultValue="account" className="w-full" value={tabValue}>
<TabsList className="mx-auto">

View File

@@ -1,17 +1,7 @@
import { AccessEdit } from "@/components/certimate/AccessEdit";
import AccessGroupEdit from "@/components/certimate/AccessGroupEdit";
import AccessGroupList from "@/components/certimate/AccessGroupList";
import XPagination from "@/components/certimate/XPagination";
import { Button } from "@/components/ui/button";
import { Separator } from "@/components/ui/separator";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { Access as AccessType, accessTypeMap } from "@/domain/access";
import { convertZulu2Beijing } from "@/lib/time";
import { useConfig } from "@/providers/config";
import { remove } from "@/repository/access";
import { t } from "i18next";
import { Key } from "lucide-react";
import { useLocation, useNavigate } from "react-router-dom";
import { useTranslation } from "react-i18next";
import { Key } from "lucide-react";
import {
AlertDialog,
AlertDialogAction,
@@ -23,8 +13,20 @@ import {
AlertDialogTitle,
AlertDialogTrigger,
} from "@/components/ui/alert-dialog.tsx";
import { Button } from "@/components/ui/button";
import { Separator } from "@/components/ui/separator";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import AccessEdit from "@/components/certimate/AccessEdit";
import AccessGroupEdit from "@/components/certimate/AccessGroupEdit";
import AccessGroupList from "@/components/certimate/AccessGroupList";
import XPagination from "@/components/certimate/XPagination";
import { convertZulu2Beijing } from "@/lib/time";
import { Access as AccessType, accessTypeMap } from "@/domain/access";
import { remove } from "@/repository/access";
import { useConfig } from "@/providers/config";
const Access = () => {
const { t } = useTranslation();
const { config, deleteAccess } = useConfig();
const { accesses } = config;
@@ -66,11 +68,7 @@ const Access = () => {
)}
</div>
<Tabs
defaultValue={tab ? tab : "access"}
value={tab ? tab : "access"}
className="w-full mt-5"
>
<Tabs defaultValue={tab ? tab : "access"} value={tab ? tab : "access"} className="w-full mt-5">
<TabsList className="space-x-5 px-3">
<TabsTrigger
value="access"
@@ -96,14 +94,8 @@ const Access = () => {
<Key size={40} className="text-primary" />
</span>
<div className="text-center text-sm text-muted-foreground mt-3">
{t("access.authorization.nodata")}
</div>
<AccessEdit
trigger={<Button>{t("access.authorization.add")}</Button>}
op="add"
className="mt-3"
/>
<div className="text-center text-sm text-muted-foreground mt-3">{t("access.authorization.nodata")}</div>
<AccessEdit trigger={<Button>{t("access.authorization.add")}</Button>} op="add" className="mt-3" />
</div>
) : (
<>
@@ -125,25 +117,14 @@ const Access = () => {
className="flex flex-col sm:flex-row text-secondary-foreground border-b dark:border-stone-500 sm:p-2 hover:bg-muted/50 text-sm"
key={access.id}
>
<div className="sm:w-48 w-full pt-1 sm:pt-0 flex items-center">
{access.name}
</div>
<div className="sm:w-48 w-full pt-1 sm:pt-0 flex items-center">{access.name}</div>
<div className="sm:w-48 w-full pt-1 sm:pt-0 flex items-center space-x-2">
<img
src={accessTypeMap.get(access.configType)?.[1]}
className="w-6"
/>
<div>
{t(accessTypeMap.get(access.configType)?.[0] || "")}
</div>
<img src={accessTypeMap.get(access.configType)?.[1]} className="w-6" />
<div>{t(accessTypeMap.get(access.configType)?.[0] || "")}</div>
</div>
<div className="sm:w-60 w-full pt-1 sm:pt-0 flex items-center">
{access.created && convertZulu2Beijing(access.created)}
</div>
<div className="sm:w-60 w-full pt-1 sm:pt-0 flex items-center">
{access.updated && convertZulu2Beijing(access.updated)}
</div>
<div className="sm:w-60 w-full pt-1 sm:pt-0 flex items-center">{access.created && convertZulu2Beijing(access.created)}</div>
<div className="sm:w-60 w-full pt-1 sm:pt-0 flex items-center">{access.updated && convertZulu2Beijing(access.updated)}</div>
<div className="flex items-center grow justify-start pt-1 sm:pt-0">
<AccessEdit
trigger={
@@ -173,17 +154,11 @@ const Access = () => {
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle className="dark:text-gray-200">
{t("access.authorization.delete")}
</AlertDialogTitle>
<AlertDialogDescription>
{t("access.authorization.delete.confirm")}
</AlertDialogDescription>
<AlertDialogTitle className="dark:text-gray-200">{t("access.authorization.delete")}</AlertDialogTitle>
<AlertDialogDescription>{t("access.authorization.delete.confirm")}</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel className="dark:text-gray-200">
{t("common.cancel")}
</AlertDialogCancel>
<AlertDialogCancel className="dark:text-gray-200">{t("common.cancel")}</AlertDialogCancel>
<AlertDialogAction
onClick={() => {
handleDelete(access);

View File

@@ -1,30 +1,18 @@
import DeployProgress from "@/components/certimate/DeployProgress";
import DeployState from "@/components/certimate/DeployState";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import { Button } from "@/components/ui/button";
import {
Sheet,
SheetContent,
SheetHeader,
SheetTitle,
SheetTrigger,
} from "@/components/ui/sheet";
import { Deployment, DeploymentListReq, Log } from "@/domain/deployment";
import { Statistic } from "@/domain/domain";
import { convertZulu2Beijing } from "@/lib/time";
import { list } from "@/repository/deployment";
import { statistics } from "@/repository/domains";
import {
Ban,
CalendarX2,
LoaderPinwheel,
Smile,
SquareSigma,
} from "lucide-react";
import { useEffect, useState } from "react";
import { Link, useNavigate } from "react-router-dom";
import { useTranslation } from "react-i18next";
import { Ban, CalendarX2, LoaderPinwheel, Smile, SquareSigma } from "lucide-react";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import { Button } from "@/components/ui/button";
import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger } from "@/components/ui/sheet";
import DeployProgress from "@/components/certimate/DeployProgress";
import DeployState from "@/components/certimate/DeployState";
import { convertZulu2Beijing } from "@/lib/time";
import { Statistic } from "@/domain/domain";
import { Deployment, DeploymentListReq, Log } from "@/domain/deployment";
import { statistics } from "@/repository/domains";
import { list } from "@/repository/deployment";
const Dashboard = () => {
const [statistic, setStatistic] = useState<Statistic>();
@@ -65,9 +53,7 @@ const Dashboard = () => {
<SquareSigma size={48} strokeWidth={1} className="text-blue-400" />
</div>
<div>
<div className="text-muted-foreground font-semibold">
{t("dashboard.statistics.all")}
</div>
<div className="text-muted-foreground font-semibold">{t("dashboard.statistics.all")}</div>
<div className="flex items-baseline">
<div className="text-3xl text-stone-700 dark:text-stone-200">
{statistic?.total ? (
@@ -78,9 +64,7 @@ const Dashboard = () => {
0
)}
</div>
<div className="ml-1 text-stone-700 dark:text-stone-200">
{t("dashboard.statistics.unit")}
</div>
<div className="ml-1 text-stone-700 dark:text-stone-200">{t("dashboard.statistics.unit")}</div>
</div>
</div>
</div>
@@ -90,9 +74,7 @@ const Dashboard = () => {
<CalendarX2 size={48} strokeWidth={1} className="text-red-400" />
</div>
<div>
<div className="text-muted-foreground font-semibold">
{t("dashboard.statistics.near_expired")}
</div>
<div className="text-muted-foreground font-semibold">{t("dashboard.statistics.near_expired")}</div>
<div className="flex items-baseline">
<div className="text-3xl text-stone-700 dark:text-stone-200">
{statistic?.expired ? (
@@ -103,25 +85,17 @@ const Dashboard = () => {
0
)}
</div>
<div className="ml-1 text-stone-700 dark:text-stone-200">
{t("dashboard.statistics.unit")}
</div>
<div className="ml-1 text-stone-700 dark:text-stone-200">{t("dashboard.statistics.unit")}</div>
</div>
</div>
</div>
<div className="border w-full md:w-[250px] 3xl:w-[300px] flex items-center rounded-md p-3 shadow-lg">
<div className="p-3">
<LoaderPinwheel
size={48}
strokeWidth={1}
className="text-green-400"
/>
<LoaderPinwheel size={48} strokeWidth={1} className="text-green-400" />
</div>
<div>
<div className="text-muted-foreground font-semibold">
{t("dashboard.statistics.enabled")}
</div>
<div className="text-muted-foreground font-semibold">{t("dashboard.statistics.enabled")}</div>
<div className="flex items-baseline">
<div className="text-3xl text-stone-700 dark:text-stone-200">
{statistic?.enabled ? (
@@ -132,9 +106,7 @@ const Dashboard = () => {
0
)}
</div>
<div className="ml-1 text-stone-700 dark:text-stone-200">
{t("dashboard.statistics.unit")}
</div>
<div className="ml-1 text-stone-700 dark:text-stone-200">{t("dashboard.statistics.unit")}</div>
</div>
</div>
</div>
@@ -144,25 +116,18 @@ const Dashboard = () => {
<Ban size={48} strokeWidth={1} className="text-gray-400" />
</div>
<div>
<div className="text-muted-foreground font-semibold">
{t("dashboard.statistics.disabled")}
</div>
<div className="text-muted-foreground font-semibold">{t("dashboard.statistics.disabled")}</div>
<div className="flex items-baseline">
<div className="text-3xl text-stone-700 dark:text-stone-200">
{statistic?.disabled ? (
<Link
to="/domains?state=disabled"
className="hover:underline"
>
<Link to="/domains?state=disabled" className="hover:underline">
{statistic?.disabled}
</Link>
) : (
0
)}
</div>
<div className="ml-1 text-stone-700 dark:text-stone-200">
{t("dashboard.statistics.unit")}
</div>
<div className="ml-1 text-stone-700 dark:text-stone-200">{t("dashboard.statistics.unit")}</div>
</div>
</div>
</div>
@@ -173,9 +138,7 @@ const Dashboard = () => {
</div>
<div>
<div className="text-muted-foreground mt-5 text-sm">
{t("dashboard.history")}
</div>
<div className="text-muted-foreground mt-5 text-sm">{t("dashboard.history")}</div>
{deployments?.length == 0 ? (
<>
@@ -207,9 +170,7 @@ const Dashboard = () => {
<div className="w-24">{t("history.props.status")}</div>
<div className="w-56">{t("history.props.stage")}</div>
<div className="w-56 sm:ml-2 text-center">
{t("history.props.last_execution_time")}
</div>
<div className="w-56 sm:ml-2 text-center">{t("history.props.last_execution_time")}</div>
<div className="grow">{t("common.text.operations")}</div>
</div>
@@ -220,27 +181,20 @@ const Dashboard = () => {
className="flex flex-col sm:flex-row text-secondary-foreground border-b dark:border-stone-500 sm:p-2 hover:bg-muted/50 text-sm"
>
<div className="sm:w-48 w-full pt-1 sm:pt-0 flex items-center">
{deployment.expand.domain?.domain
.split(";")
.map((domain: string) => (
<>
{domain}
<br />
</>
))}
{deployment.expand.domain?.domain.split(";").map((domain: string) => (
<>
{domain}
<br />
</>
))}
</div>
<div className="sm:w-24 w-full pt-1 sm:pt-0 flex items-center">
<DeployState deployment={deployment} />
</div>
<div className="sm:w-56 w-full pt-1 sm:pt-0 flex items-center">
<DeployProgress
phase={deployment.phase}
phaseSuccess={deployment.phaseSuccess}
/>
</div>
<div className="sm:w-56 w-full pt-1 sm:pt-0 flex items-center sm:justify-center">
{convertZulu2Beijing(deployment.deployedAt)}
<DeployProgress phase={deployment.phase} phaseSuccess={deployment.phaseSuccess} />
</div>
<div className="sm:w-56 w-full pt-1 sm:pt-0 flex items-center sm:justify-center">{convertZulu2Beijing(deployment.deployedAt)}</div>
<div className="flex items-center grow justify-start pt-1 sm:pt-0 sm:ml-2">
<Sheet>
<SheetTrigger asChild>
@@ -265,11 +219,7 @@ const Dashboard = () => {
<div>[{item.time}]</div>
<div className="ml-2">{item.message}</div>
</div>
{item.error && (
<div className="mt-1 text-red-600">
{item.error}
</div>
)}
{item.error && <div className="mt-1 text-red-600">{item.error}</div>}
</div>
);
})}
@@ -287,17 +237,9 @@ const Dashboard = () => {
</div>
{item.info &&
item.info.map((info: string) => {
return (
<div className="mt-1 text-green-600">
{info}
</div>
);
return <div className="mt-1 text-green-600">{info}</div>;
})}
{item.error && (
<div className="mt-1 text-red-600">
{item.error}
</div>
)}
{item.error && <div className="mt-1 text-red-600">{item.error}</div>}
</div>
);
})}
@@ -313,11 +255,7 @@ const Dashboard = () => {
<div>[{item.time}]</div>
<div className="ml-2">{item.message}</div>
</div>
{item.error && (
<div className="mt-1 text-red-600">
{item.error}
</div>
)}
{item.error && <div className="mt-1 text-red-600">{item.error}</div>}
</div>
);
})}

View File

@@ -1,53 +1,30 @@
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import z from "zod";
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form";
import { Button } from "@/components/ui/button";
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectLabel,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { useConfig } from "@/providers/config";
import { useEffect, useState } from "react";
import { useLocation } from "react-router-dom";
import { useForm } from "react-hook-form";
import { useTranslation } from "react-i18next";
import z from "zod";
import { zodResolver } from "@hookform/resolvers/zod";
import { Plus } from "lucide-react";
import { ClientResponseError } from "pocketbase";
import { Button } from "@/components/ui/button";
import { Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator } from "@/components/ui/breadcrumb";
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Toaster } from "@/components/ui/toaster";
import { useToast } from "@/components/ui/use-toast";
import AccessEdit from "@/components/certimate/AccessEdit";
import DeployList from "@/components/certimate/DeployList";
import EmailsEdit from "@/components/certimate/EmailsEdit";
import StringList from "@/components/certimate/StringList";
import { cn } from "@/lib/utils";
import { PbErrorData } from "@/domain/base";
import { accessTypeMap } from "@/domain/access";
import { EmailsSetting } from "@/domain/settings";
import { DeployConfig, Domain } from "@/domain/domain";
import { save, get } from "@/repository/domains";
import { ClientResponseError } from "pocketbase";
import { PbErrorData } from "@/domain/base";
import { useToast } from "@/components/ui/use-toast";
import { Toaster } from "@/components/ui/toaster";
import { useLocation } from "react-router-dom";
import { Plus } from "lucide-react";
import { AccessEdit } from "@/components/certimate/AccessEdit";
import { accessTypeMap } from "@/domain/access";
import EmailsEdit from "@/components/certimate/EmailsEdit";
import { cn } from "@/lib/utils";
import { EmailsSetting } from "@/domain/settings";
import { useTranslation } from "react-i18next";
import StringList from "@/components/certimate/StringList";
import { Input } from "@/components/ui/input";
import DeployList from "@/components/certimate/DeployList";
import {
Breadcrumb,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbList,
BreadcrumbPage,
BreadcrumbSeparator,
} from "@/components/ui/breadcrumb";
import { useConfig } from "@/providers/config";
const Edit = () => {
const {
@@ -115,7 +92,6 @@ const Edit = () => {
const { toast } = useToast();
const onSubmit = async (data: z.infer<typeof formSchema>) => {
console.log(data);
const req: Domain = {
id: data.id as string,
crontab: "0 0 * * *",
@@ -147,14 +123,12 @@ const Edit = () => {
} catch (e) {
const err = e as ClientResponseError;
Object.entries(err.response.data as PbErrorData).forEach(
([key, value]) => {
form.setError(key as keyof z.infer<typeof formSchema>, {
type: "manual",
message: value.message,
});
}
);
Object.entries(err.response.data as PbErrorData).forEach(([key, value]) => {
form.setError(key as keyof z.infer<typeof formSchema>, {
type: "manual",
message: value.message,
});
});
return;
}
@@ -182,14 +156,12 @@ const Edit = () => {
} catch (e) {
const err = e as ClientResponseError;
Object.entries(err.response.data as PbErrorData).forEach(
([key, value]) => {
form.setError(key as keyof z.infer<typeof formSchema>, {
type: "manual",
message: value.message,
});
}
);
Object.entries(err.response.data as PbErrorData).forEach(([key, value]) => {
form.setError(key as keyof z.infer<typeof formSchema>, {
type: "manual",
message: value.message,
});
});
return;
}
@@ -203,16 +175,12 @@ const Edit = () => {
<Breadcrumb>
<BreadcrumbList>
<BreadcrumbItem>
<BreadcrumbLink href="#/domains">
{t("domain.page.title")}
</BreadcrumbLink>
<BreadcrumbLink href="#/domains">{t("domain.page.title")}</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbPage>
{domain?.id ? t("domain.edit") : t("domain.add")}
</BreadcrumbPage>
<BreadcrumbPage>{domain?.id ? t("domain.edit") : t("domain.add")}</BreadcrumbPage>
</BreadcrumbItem>
</BreadcrumbList>
</Breadcrumb>
@@ -220,10 +188,7 @@ const Edit = () => {
<div className="mt-5 flex w-full justify-center md:space-x-10 flex-col md:flex-row">
<div className="w-full md:w-[200px] text-muted-foreground space-x-3 md:space-y-3 flex-row md:flex-col flex md:mt-5">
<div
className={cn(
"cursor-pointer text-right",
tab === "apply" ? "text-primary" : ""
)}
className={cn("cursor-pointer text-right", tab === "apply" ? "text-primary" : "")}
onClick={() => {
setTab("apply");
}}
@@ -231,10 +196,7 @@ const Edit = () => {
{t("domain.application.tab")}
</div>
<div
className={cn(
"cursor-pointer text-right",
tab === "deploy" ? "text-primary" : ""
)}
className={cn("cursor-pointer text-right", tab === "deploy" ? "text-primary" : "")}
onClick={() => {
if (!domain?.id) {
toast({
@@ -251,17 +213,9 @@ const Edit = () => {
</div>
</div>
<div className="flex flex-col">
<div
className={cn(
"w-full md:w-[35em] p-5 rounded mt-3 md:mt-0",
tab == "deploy" && "hidden"
)}
>
<div className={cn("w-full md:w-[35em] p-5 rounded mt-3 md:mt-0", tab == "deploy" && "hidden")}>
<Form {...form}>
<form
onSubmit={form.handleSubmit(onSubmit)}
className="space-y-8 dark:text-stone-200"
>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8 dark:text-stone-200">
{/* 域名 */}
<FormField
control={form.control}
@@ -288,11 +242,7 @@ const Edit = () => {
render={({ field }) => (
<FormItem>
<FormLabel className="flex w-full justify-between">
<div>
{t("domain.application.form.email.label") +
" " +
t("domain.application.form.email.tips")}
</div>
<div>{t("domain.application.form.email.label") + " " + t("domain.application.form.email.tips")}</div>
<EmailsEdit
trigger={
<div className="font-normal text-primary hover:underline cursor-pointer flex items-center">
@@ -311,24 +261,16 @@ const Edit = () => {
}}
>
<SelectTrigger>
<SelectValue
placeholder={t(
"domain.application.form.email.errmsg.empty"
)}
/>
<SelectValue placeholder={t("domain.application.form.email.errmsg.empty")} />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectLabel>
{t("domain.application.form.email.list")}
</SelectLabel>
{(emails.content as EmailsSetting).emails.map(
(item) => (
<SelectItem key={item} value={item}>
<div>{item}</div>
</SelectItem>
)
)}
<SelectLabel>{t("domain.application.form.email.list")}</SelectLabel>
{(emails.content as EmailsSetting).emails.map((item) => (
<SelectItem key={item} value={item}>
<div>{item}</div>
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
@@ -365,30 +307,17 @@ const Edit = () => {
}}
>
<SelectTrigger>
<SelectValue
placeholder={t(
"domain.application.form.access.placeholder"
)}
/>
<SelectValue placeholder={t("domain.application.form.access.placeholder")} />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectLabel>
{t("domain.application.form.access.list")}
</SelectLabel>
<SelectLabel>{t("domain.application.form.access.list")}</SelectLabel>
{accesses
.filter((item) => item.usage != "deploy")
.map((item) => (
<SelectItem key={item.id} value={item.id}>
<div className="flex items-center space-x-2">
<img
className="w-6"
src={
accessTypeMap.get(
item.configType
)?.[1]
}
/>
<img className="w-6" src={accessTypeMap.get(item.configType)?.[1]} />
<div>{item.name}</div>
</div>
</SelectItem>
@@ -409,22 +338,15 @@ const Edit = () => {
name="timeout"
render={({ field }) => (
<FormItem>
<FormLabel>
{t("domain.application.form.timeout.label")}
</FormLabel>
<FormLabel>{t("domain.application.form.timeout.label")}</FormLabel>
<FormControl>
<Input
type="number"
placeholder={t(
"ddomain.application.form.timeout.placeholder"
)}
placeholder={t("ddomain.application.form.timeout.placeholder")}
{...field}
value={field.value}
onChange={(e) => {
form.setValue(
"timeout",
parseInt(e.target.value)
);
form.setValue("timeout", parseInt(e.target.value));
}}
/>
</FormControl>
@@ -454,20 +376,13 @@ const Edit = () => {
/>
<div className="flex justify-end">
<Button type="submit">
{domain?.id ? t("common.save") : t("common.next")}
</Button>
<Button type="submit">{domain?.id ? t("common.save") : t("common.next")}</Button>
</div>
</form>
</Form>
</div>
<div
className={cn(
"flex flex-col space-y-5 w-full md:w-[35em]",
tab == "apply" && "hidden"
)}
>
<div className={cn("flex flex-col space-y-5 w-full md:w-[35em]", tab == "apply" && "hidden")}>
<DeployList
deploys={domain?.deployConfig ?? []}
onChange={(list: DeployConfig[]) => {

View File

@@ -1,7 +1,13 @@
import { useEffect, useState } from "react";
import { Link, useLocation, useNavigate } from "react-router-dom";
import { useTranslation, Trans } from "react-i18next";
import { TooltipContent, TooltipProvider } from "@radix-ui/react-tooltip";
import { Earth } from "lucide-react";
import Show from "@/components/Show";
import DeployProgress from "@/components/certimate/DeployProgress";
import DeployState from "@/components/certimate/DeployState";
import XPagination from "@/components/certimate/XPagination";
import Show from "@/components/Show";
import {
AlertDialogAction,
AlertDialogCancel,
@@ -14,28 +20,15 @@ import {
AlertDialogTrigger,
} from "@/components/ui/alert-dialog";
import { Button } from "@/components/ui/button";
import { Separator } from "@/components/ui/separator";
import { Switch } from "@/components/ui/switch";
import { Toaster } from "@/components/ui/toaster";
import { Tooltip, TooltipTrigger } from "@/components/ui/tooltip";
import { useToast } from "@/components/ui/use-toast";
import { Domain } from "@/domain/domain";
import { CustomFile, saveFiles2ZIP } from "@/lib/file";
import { convertZulu2Beijing, getDate } from "@/lib/time";
import {
list,
remove,
save,
subscribeId,
unsubscribeId,
} from "@/repository/domains";
import { TooltipContent, TooltipProvider } from "@radix-ui/react-tooltip";
import { Earth } from "lucide-react";
import { useEffect, useState } from "react";
import { Link, useLocation, useNavigate } from "react-router-dom";
import { useTranslation, Trans } from "react-i18next";
import { Domain } from "@/domain/domain";
import { list, remove, save, subscribeId, unsubscribeId } from "@/repository/domains";
const Home = () => {
const toast = useToast();
@@ -115,7 +108,6 @@ const Home = () => {
try {
unsubscribeId(domain.id ?? "");
subscribeId(domain.id ?? "", (resp) => {
console.log(resp);
const updatedDomains = domains.map((domain) => {
if (domain.id === resp.id) {
return { ...resp };
@@ -139,10 +131,7 @@ const Home = () => {
// 这里的 text 只是占位作用,实际文案在 src/i18n/locales/[lang].json
<Trans i18nKey="domain.deploy.failed.tips">
text1
<Link
to={`/history?domain=${domain.id}`}
className="underline text-blue-500"
>
<Link to={`/history?domain=${domain.id}`} className="underline text-blue-500">
text2
</Link>
text3
@@ -189,9 +178,7 @@ const Home = () => {
<Earth size={40} className="text-primary" />
</span>
<div className="text-center text-sm text-muted-foreground mt-3">
{t("domain.nodata")}
</div>
<div className="text-center text-sm text-muted-foreground mt-3">{t("domain.nodata")}</div>
<Button onClick={handleCreateClick} className="mt-3">
{t("domain.add")}
</Button>
@@ -202,15 +189,9 @@ const Home = () => {
<div className="hidden sm:flex sm:flex-row text-muted-foreground text-sm border-b dark:border-stone-500 sm:p-2 mt-5">
<div className="w-36">{t("common.text.domain")}</div>
<div className="w-40">{t("domain.props.expiry")}</div>
<div className="w-32">
{t("domain.props.last_execution_status")}
</div>
<div className="w-64">
{t("domain.props.last_execution_stage")}
</div>
<div className="w-40 sm:ml-2">
{t("domain.props.last_execution_time")}
</div>
<div className="w-32">{t("domain.props.last_execution_status")}</div>
<div className="w-64">{t("domain.props.last_execution_stage")}</div>
<div className="w-40 sm:ml-2">{t("domain.props.last_execution_time")}</div>
<div className="w-24">{t("domain.props.enable")}</div>
<div className="grow">{t("common.text.operations")}</div>
</div>
@@ -232,9 +213,7 @@ const Home = () => {
<div>
{domain.expiredAt ? (
<>
<div>
{t("domain.props.expiry.date1", { date: 90 })}
</div>
<div>{t("domain.props.expiry.date1", { date: 90 })}</div>
<div>
{t("domain.props.expiry.date2", {
date: getDate(domain.expiredAt),
@@ -257,18 +236,13 @@ const Home = () => {
</div>
<div className="sm:w-64 w-full pt-1 sm:pt-0 flex items-center">
{domain.lastDeployedAt && domain.expand?.lastDeployment ? (
<DeployProgress
phase={domain.expand.lastDeployment?.phase}
phaseSuccess={domain.expand.lastDeployment?.phaseSuccess}
/>
<DeployProgress phase={domain.expand.lastDeployment?.phase} phaseSuccess={domain.expand.lastDeployment?.phaseSuccess} />
) : (
"---"
)}
</div>
<div className="sm:w-40 pt-1 sm:pt-0 sm:ml-2 flex items-center">
{domain.lastDeployedAt
? convertZulu2Beijing(domain.lastDeployedAt)
: "---"}
{domain.lastDeployedAt ? convertZulu2Beijing(domain.lastDeployedAt) : "---"}
</div>
<div className="sm:w-24 flex items-center">
<TooltipProvider>
@@ -283,57 +257,33 @@ const Home = () => {
</TooltipTrigger>
<TooltipContent>
<div className="border rounded-sm px-3 bg-background text-muted-foreground text-xs">
{domain.enabled
? t("domain.props.enable.disabled")
: t("domain.props.enable.enabled")}
{domain.enabled ? t("domain.props.enable.disabled") : t("domain.props.enable.enabled")}
</div>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</div>
<div className="flex items-center grow justify-start pt-1 sm:pt-0">
<Button
variant={"link"}
className="p-0"
onClick={() => handleHistoryClick(domain.id ?? "")}
>
<Button variant={"link"} className="p-0" onClick={() => handleHistoryClick(domain.id ?? "")}>
{t("domain.history")}
</Button>
<Show when={domain.enabled ? true : false}>
<Separator orientation="vertical" className="h-4 mx-2" />
<Button
variant={"link"}
className="p-0"
onClick={() => handleRightNowClick(domain)}
>
<Button variant={"link"} className="p-0" onClick={() => handleRightNowClick(domain)}>
{t("domain.deploy")}
</Button>
</Show>
<Show
when={
(domain.enabled ? true : false) && domain.deployed
? true
: false
}
>
<Show when={(domain.enabled ? true : false) && domain.deployed ? true : false}>
<Separator orientation="vertical" className="h-4 mx-2" />
<Button
variant={"link"}
className="p-0"
onClick={() => handleForceClick(domain)}
>
<Button variant={"link"} className="p-0" onClick={() => handleForceClick(domain)}>
{t("domain.deploy_forced")}
</Button>
</Show>
<Show when={domain.expiredAt ? true : false}>
<Separator orientation="vertical" className="h-4 mx-2" />
<Button
variant={"link"}
className="p-0"
onClick={() => handleDownloadClick(domain)}
>
<Button variant={"link"} className="p-0" onClick={() => handleDownloadClick(domain)}>
{t("common.download")}
</Button>
</Show>
@@ -349,17 +299,11 @@ const Home = () => {
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>
{t("domain.delete")}
</AlertDialogTitle>
<AlertDialogDescription>
{t("domain.delete.confirm")}
</AlertDialogDescription>
<AlertDialogTitle>{t("domain.delete")}</AlertDialogTitle>
<AlertDialogDescription>{t("domain.delete.confirm")}</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>
{t("common.cancel")}
</AlertDialogCancel>
<AlertDialogCancel>{t("common.cancel")}</AlertDialogCancel>
<AlertDialogAction
onClick={() => {
handleDeleteClick(domain.id ?? "");
@@ -372,11 +316,7 @@ const Home = () => {
</AlertDialog>
<Separator orientation="vertical" className="h-4 mx-2" />
<Button
variant={"link"}
className="p-0"
onClick={() => handleEditClick(domain.id ?? "")}
>
<Button variant={"link"} className="p-0" onClick={() => handleEditClick(domain.id ?? "")}>
{t("common.edit")}
</Button>
</>

View File

@@ -1,23 +1,17 @@
import DeployProgress from "@/components/certimate/DeployProgress";
import DeployState from "@/components/certimate/DeployState";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import { Button } from "@/components/ui/button";
import { ScrollArea } from "@/components/ui/scroll-area";
import {
Sheet,
SheetContent,
SheetHeader,
SheetTitle,
SheetTrigger,
} from "@/components/ui/sheet";
import { Deployment, DeploymentListReq, Log } from "@/domain/deployment";
import { convertZulu2Beijing } from "@/lib/time";
import { list } from "@/repository/deployment";
import { Smile } from "lucide-react";
import { useEffect, useState } from "react";
import { useNavigate, useSearchParams } from "react-router-dom";
import { useTranslation } from "react-i18next";
import { Smile } from "lucide-react";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import { Button } from "@/components/ui/button";
import { ScrollArea } from "@/components/ui/scroll-area";
import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger } from "@/components/ui/sheet";
import DeployProgress from "@/components/certimate/DeployProgress";
import DeployState from "@/components/certimate/DeployState";
import { convertZulu2Beijing } from "@/lib/time";
import { Deployment, DeploymentListReq, Log } from "@/domain/deployment";
import { list } from "@/repository/deployment";
const History = () => {
const navigate = useNavigate();
@@ -71,9 +65,7 @@ const History = () => {
<div className="w-24">{t("history.props.status")}</div>
<div className="w-56">{t("history.props.stage")}</div>
<div className="w-56 sm:ml-2 text-center">
{t("history.props.last_execution_time")}
</div>
<div className="w-56 sm:ml-2 text-center">{t("history.props.last_execution_time")}</div>
<div className="grow">{t("common.text.operations")}</div>
</div>
@@ -84,27 +76,20 @@ const History = () => {
className="flex flex-col sm:flex-row text-secondary-foreground border-b dark:border-stone-500 sm:p-2 hover:bg-muted/50 text-sm"
>
<div className="sm:w-48 w-full pt-1 sm:pt-0 flex items-center">
{deployment.expand.domain?.domain
.split(";")
.map((domain: string) => (
<>
{domain}
<br />
</>
))}
{deployment.expand.domain?.domain.split(";").map((domain: string) => (
<>
{domain}
<br />
</>
))}
</div>
<div className="sm:w-24 w-full pt-1 sm:pt-0 flex items-center">
<DeployState deployment={deployment} />
</div>
<div className="sm:w-56 w-full pt-1 sm:pt-0 flex items-center">
<DeployProgress
phase={deployment.phase}
phaseSuccess={deployment.phaseSuccess}
/>
</div>
<div className="sm:w-56 w-full pt-1 sm:pt-0 flex items-center sm:justify-center">
{convertZulu2Beijing(deployment.deployedAt)}
<DeployProgress phase={deployment.phase} phaseSuccess={deployment.phaseSuccess} />
</div>
<div className="sm:w-56 w-full pt-1 sm:pt-0 flex items-center sm:justify-center">{convertZulu2Beijing(deployment.deployedAt)}</div>
<div className="flex items-center grow justify-start pt-1 sm:pt-0 sm:ml-2">
<Sheet>
<SheetTrigger asChild>
@@ -129,11 +114,7 @@ const History = () => {
<div>[{item.time}]</div>
<div className="ml-2">{item.message}</div>
</div>
{item.error && (
<div className="mt-1 text-red-600">
{item.error}
</div>
)}
{item.error && <div className="mt-1 text-red-600">{item.error}</div>}
</div>
);
})}
@@ -151,17 +132,9 @@ const History = () => {
</div>
{item.info &&
item.info.map((info: string) => {
return (
<div className="mt-1 text-green-600">
{info}
</div>
);
return <div className="mt-1 text-green-600">{info}</div>;
})}
{item.error && (
<div className="mt-1 text-red-600">
{item.error}
</div>
)}
{item.error && <div className="mt-1 text-red-600">{item.error}</div>}
</div>
);
})}
@@ -177,11 +150,7 @@ const History = () => {
<div>[{item.time}]</div>
<div className="ml-2">{item.message}</div>
</div>
{item.error && (
<div className="mt-1 text-red-600">
{item.error}
</div>
)}
{item.error && <div className="mt-1 text-red-600">{item.error}</div>}
</div>
);
})}

View File

@@ -1,21 +1,14 @@
import { useForm } from "react-hook-form";
import { useNavigate } from "react-router-dom";
import { z } from "zod";
import { useForm } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { z } from "zod";
import { zodResolver } from "@hookform/resolvers/zod";
import { Button } from "@/components/ui/button";
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form";
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import { getErrMessage } from "@/lib/error";
import { getPb } from "@/repository/api";
import { zodResolver } from "@hookform/resolvers/zod";
const formSchema = z.object({
username: z.string().email({
@@ -56,10 +49,7 @@ const Login = () => {
<img src="/vite.svg" className="w-16" />
</div>
<Form {...form}>
<form
onSubmit={form.handleSubmit(onSubmit)}
className="space-y-8 dark:text-stone-200"
>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8 dark:text-stone-200">
<FormField
control={form.control}
name="username"

View File

@@ -1,23 +1,16 @@
import { useState } from "react";
import { useNavigate } from "react-router-dom";
import { useForm } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { z } from "zod";
import { zodResolver } from "@hookform/resolvers/zod";
import { Button } from "@/components/ui/button";
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form";
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import { useToast } from "@/components/ui/use-toast";
import { getErrMessage } from "@/lib/error";
import { getPb } from "@/repository/api";
import { zodResolver } from "@hookform/resolvers/zod";
import { useState } from "react";
import { useForm } from "react-hook-form";
import { useNavigate } from "react-router-dom";
import { useTranslation } from "react-i18next";
import { z } from "zod";
const formSchema = z.object({
email: z.string().email("settings.account.email.errmsg.invalid"),
@@ -65,10 +58,7 @@ const Account = () => {
<>
<div className="w-full md:max-w-[35em]">
<Form {...form}>
<form
onSubmit={form.handleSubmit(onSubmit)}
className="space-y-8 dark:text-stone-200"
>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8 dark:text-stone-200">
<FormField
control={form.control}
name="email"

View File

@@ -1,15 +1,11 @@
import { useTranslation } from "react-i18next";
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@/components/ui/accordion";
import DingTalk from "@/components/notify/DingTalk";
import NotifyTemplate from "@/components/notify/NotifyTemplate";
import Telegram from "@/components/notify/Telegram";
import Webhook from "@/components/notify/Webhook";
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@/components/ui/accordion";
import { NotifyProvider } from "@/providers/notify";
import { useTranslation } from "react-i18next";
const Notify = () => {
const { t } = useTranslation();
@@ -20,9 +16,7 @@ const Notify = () => {
<div className="border rounded-sm p-5 shadow-lg">
<Accordion type={"multiple"} className="dark:text-stone-200">
<AccordionItem value="item-1" className="dark:border-stone-200">
<AccordionTrigger>
{t("settings.notification.template.label")}
</AccordionTrigger>
<AccordionTrigger>{t("settings.notification.template.label")}</AccordionTrigger>
<AccordionContent>
<NotifyTemplate />
</AccordionContent>

View File

@@ -1,22 +1,15 @@
import { useForm } from "react-hook-form";
import { useNavigate } from "react-router-dom";
import { useTranslation } from "react-i18next";
import { z } from "zod";
import { zodResolver } from "@hookform/resolvers/zod";
import { Button } from "@/components/ui/button";
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form";
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import { useToast } from "@/components/ui/use-toast";
import { getErrMessage } from "@/lib/error";
import { getPb } from "@/repository/api";
import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
import { useNavigate } from "react-router-dom";
import { useTranslation } from "react-i18next";
import { z } from "zod";
const formSchema = z
.object({
@@ -51,10 +44,7 @@ const Password = () => {
const onSubmit = async (values: z.infer<typeof formSchema>) => {
try {
await getPb().admins.authWithPassword(
getPb().authStore.model?.email,
values.oldPassword
);
await getPb().admins.authWithPassword(getPb().authStore.model?.email, values.oldPassword);
} catch (e) {
const message = getErrMessage(e);
form.setError("oldPassword", { message });
@@ -88,26 +78,15 @@ const Password = () => {
<>
<div className="w-full md:max-w-[35em]">
<Form {...form}>
<form
onSubmit={form.handleSubmit(onSubmit)}
className="space-y-8 dark:text-stone-200"
>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8 dark:text-stone-200">
<FormField
control={form.control}
name="oldPassword"
render={({ field }) => (
<FormItem>
<FormLabel>
{t("settings.password.current_password.label")}
</FormLabel>
<FormLabel>{t("settings.password.current_password.label")}</FormLabel>
<FormControl>
<Input
placeholder={t(
"settings.password.current_password.placeholder"
)}
{...field}
type="password"
/>
<Input placeholder={t("settings.password.current_password.placeholder")} {...field} type="password" />
</FormControl>
<FormMessage />
@@ -120,17 +99,9 @@ const Password = () => {
name="newPassword"
render={({ field }) => (
<FormItem>
<FormLabel>
{t("settings.password.new_password.label")}
</FormLabel>
<FormLabel>{t("settings.password.new_password.label")}</FormLabel>
<FormControl>
<Input
placeholder={t(
"settings.password.new_password.placeholder"
)}
{...field}
type="password"
/>
<Input placeholder={t("settings.password.new_password.placeholder")} {...field} type="password" />
</FormControl>
<FormMessage />
@@ -143,17 +114,9 @@ const Password = () => {
name="confirmPassword"
render={({ field }) => (
<FormItem>
<FormLabel>
{t("settings.password.confirm_password.label")}
</FormLabel>
<FormLabel>{t("settings.password.confirm_password.label")}</FormLabel>
<FormControl>
<Input
placeholder={t(
"settings.password.confirm_password.placeholder"
)}
{...field}
type="password"
/>
<Input placeholder={t("settings.password.confirm_password.placeholder")} {...field} type="password" />
</FormControl>
<FormMessage />

View File

@@ -1,34 +1,19 @@
import { Button } from "@/components/ui/button";
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
import { useToast } from "@/components/ui/use-toast";
import {
SSLProvider as SSLProviderType,
SSLProviderSetting,
Setting,
} from "@/domain/settings";
import { getErrMessage } from "@/lib/error";
import { cn } from "@/lib/utils";
import { getSetting, update } from "@/repository/settings";
import { zodResolver } from "@hookform/resolvers/zod";
import { useEffect, useState } from "react";
import { useForm } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { z } from "zod";
import { zodResolver } from "@hookform/resolvers/zod";
import { Button } from "@/components/ui/button";
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
import { useToast } from "@/components/ui/use-toast";
import { getErrMessage } from "@/lib/error";
import { cn } from "@/lib/utils";
import { SSLProvider as SSLProviderType, SSLProviderSetting, Setting } from "@/domain/settings";
import { getSetting, update } from "@/repository/settings";
const SSLProvider = () => {
const { t } = useTranslation();
@@ -64,10 +49,7 @@ const SSLProvider = () => {
form.setValue("provider", content.provider);
form.setValue("eabKid", content.config[content.provider].eabKid);
form.setValue(
"eabHmacKey",
content.config[content.provider].eabHmacKey
);
form.setValue("eabHmacKey", content.config[content.provider].eabHmacKey);
setProvider(content.provider);
} else {
form.setValue("provider", "letsencrypt");
@@ -137,10 +119,7 @@ const SSLProvider = () => {
<>
<div className="w-full md:max-w-[35em]">
<Form {...form}>
<form
onSubmit={form.handleSubmit(onSubmit)}
className="space-y-8 dark:text-stone-200"
>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8 dark:text-stone-200">
<FormField
control={form.control}
name="provider"
@@ -160,16 +139,8 @@ const SSLProvider = () => {
<div className="flex items-center space-x-2">
<RadioGroupItem value="letsencrypt" id="letsencrypt" />
<Label htmlFor="letsencrypt">
<div
className={cn(
"flex items-center space-x-2 border p-2 rounded cursor-pointer",
getOptionCls("letsencrypt")
)}
>
<img
src={"/imgs/providers/letsencrypt.svg"}
className="h-6"
/>
<div className={cn("flex items-center space-x-2 border p-2 rounded cursor-pointer", getOptionCls("letsencrypt"))}>
<img src={"/imgs/providers/letsencrypt.svg"} className="h-6" />
<div>{"Let's Encrypt"}</div>
</div>
</Label>
@@ -177,16 +148,8 @@ const SSLProvider = () => {
<div className="flex items-center space-x-2">
<RadioGroupItem value="zerossl" id="zerossl" />
<Label htmlFor="zerossl">
<div
className={cn(
"flex items-center space-x-2 border p-2 rounded cursor-pointer",
getOptionCls("zerossl")
)}
>
<img
src={"/imgs/providers/zerossl.svg"}
className="h-6"
/>
<div className={cn("flex items-center space-x-2 border p-2 rounded cursor-pointer", getOptionCls("zerossl"))}>
<img src={"/imgs/providers/zerossl.svg"} className="h-6" />
<div>{"ZeroSSL"}</div>
</div>
</Label>
@@ -201,11 +164,7 @@ const SSLProvider = () => {
<FormItem hidden={provider !== "zerossl"}>
<FormLabel>EAB_KID</FormLabel>
<FormControl>
<Input
placeholder={t("settings.ca.eab_kid.errmsg.empty")}
{...field}
type="text"
/>
<Input placeholder={t("settings.ca.eab_kid.errmsg.empty")} {...field} type="text" />
</FormControl>
<FormMessage />
@@ -220,13 +179,7 @@ const SSLProvider = () => {
<FormItem hidden={provider !== "zerossl"}>
<FormLabel>EAB_HMAC_KEY</FormLabel>
<FormControl>
<Input
placeholder={t(
"settings.ca.eab_hmac_key.errmsg.empty"
)}
{...field}
type="text"
/>
<Input placeholder={t("settings.ca.eab_hmac_key.errmsg.empty")} {...field} type="text" />
</FormControl>
<FormMessage />

View File

@@ -1,18 +1,12 @@
import { createContext, ReactNode, useCallback, useContext, useEffect, useReducer } from "react";
import { Access } from "@/domain/access";
import { AccessGroup } from "@/domain/access_groups";
import { Setting } from "@/domain/settings";
import { list } from "@/repository/access";
import { list as getAccessGroups } from "@/repository/access_group";
import {
createContext,
ReactNode,
useCallback,
useContext,
useEffect,
useReducer,
} from "react";
import { configReducer } from "./reducer";
import { getEmails } from "@/repository/settings";
import { Setting } from "@/domain/settings";
import { AccessGroup } from "@/domain/access_groups";
import { configReducer } from "./reducer";
export type ConfigData = {
accesses: Access[];

View File

@@ -1,7 +1,7 @@
import { Access } from "@/domain/access";
import { ConfigData } from ".";
import { EmailsSetting, Setting } from "@/domain/settings";
import { AccessGroup } from "@/domain/access_groups";
import { EmailsSetting, Setting } from "@/domain/settings";
import { ConfigData } from "./";
type Action =
| { type: "ADD_ACCESS"; payload: Access }
@@ -12,10 +12,7 @@ type Action =
| { type: "ADD_EMAIL"; payload: string }
| { type: "SET_ACCESS_GROUPS"; payload: AccessGroup[] };
export const configReducer = (
state: ConfigData,
action: Action
): ConfigData => {
export const configReducer = (state: ConfigData, action: Action): ConfigData => {
switch (action.type) {
case "SET_ACCESSES": {
return {
@@ -32,17 +29,13 @@ export const configReducer = (
case "DELETE_ACCESS": {
return {
...state,
accesses: state.accesses.filter(
(access) => access.id !== action.payload
),
accesses: state.accesses.filter((access) => access.id !== action.payload),
};
}
case "UPDATE_ACCESS": {
return {
...state,
accesses: state.accesses.map((access) =>
access.id === action.payload.id ? action.payload : access
),
accesses: state.accesses.map((access) => (access.id === action.payload.id ? action.payload : access)),
};
}
case "SET_EMAILS": {
@@ -57,10 +50,7 @@ export const configReducer = (
emails: {
...state.emails,
content: {
emails: [
...(state.emails.content as EmailsSetting).emails,
action.payload,
],
emails: [...(state.emails.content as EmailsSetting).emails, action.payload],
},
},
};

View File

@@ -1,13 +1,7 @@
import { ReactNode, useContext, createContext, useEffect, useReducer, useCallback } from "react";
import { NotifyChannel, Setting } from "@/domain/settings";
import { getSetting } from "@/repository/settings";
import {
ReactNode,
useContext,
createContext,
useEffect,
useReducer,
useCallback,
} from "react";
import { notifyReducer } from "./reducer";
export type NotifyContext = {
@@ -37,15 +31,12 @@ export const NotifyProvider = ({ children }: ContainerProps) => {
featchData();
}, []);
const setChannel = useCallback(
(data: { channel: string; data: NotifyChannel }) => {
dispatchNotify({
type: "SET_CHANNEL",
payload: data,
});
},
[]
);
const setChannel = useCallback((data: { channel: string; data: NotifyChannel }) => {
dispatchNotify({
type: "SET_CHANNEL",
payload: data,
});
}, []);
const setChannels = useCallback((setting: Setting) => {
dispatchNotify({

View File

@@ -1,6 +1,7 @@
import moment from "moment";
import { Access } from "@/domain/access";
import { getPb } from "./api";
import moment from "moment";
export const list = async () => {
return await getPb().collection("access").getFullList<Access>({

View File

@@ -1,14 +1,12 @@
import { Access } from "@/domain/access";
import { AccessGroup } from "@/domain/access_groups";
import { getPb } from "./api";
import { Access } from "@/domain/access";
export const list = async () => {
const resp = await getPb()
.collection("access_groups")
.getFullList<AccessGroup>({
sort: "-created",
expand: "access",
});
const resp = await getPb().collection("access_groups").getFullList<AccessGroup>({
sort: "-created",
expand: "access",
});
return resp;
};
@@ -31,9 +29,7 @@ export const remove = async (id: string) => {
export const update = async (accessGroup: AccessGroup) => {
const pb = getPb();
if (accessGroup.id) {
return await pb
.collection("access_groups")
.update(accessGroup.id, accessGroup);
return await pb.collection("access_groups").update(accessGroup.id, accessGroup);
}
return await pb.collection("access_groups").create(accessGroup);
};

View File

@@ -1,6 +1,8 @@
import PocketBase from "pocketbase";
const apiDomain = import.meta.env.VITE_API_DOMAIN;
console.log(apiDomain);
let pb: PocketBase;
export const getPb = () => {
if (pb) return pb;

View File

@@ -11,15 +11,15 @@ export const list = async (req: DeploymentListReq) => {
if (req.perPage) {
perPage = req.perPage;
}
let filter = "domain!=null";
if (req.domain) {
filter = `domain="${req.domain}"`;
}
return await getPb()
.collection("deployments")
.getList<Deployment>(page, perPage, {
filter: filter,
sort: "-deployedAt",
expand: "domain",
});
return await getPb().collection("deployments").getList<Deployment>(page, perPage, {
filter: filter,
sort: "-deployedAt",
expand: "domain",
});
};

View File

@@ -1,6 +1,6 @@
import { getTimeAfter } from "@/lib/time";
import { Domain, Statistic } from "@/domain/domain";
import { getPb } from "./api";
import { getTimeAfter } from "@/lib/time";
type DomainListReq = {
domain?: string;
@@ -10,6 +10,8 @@ type DomainListReq = {
};
export const list = async (req: DomainListReq) => {
const pb = getPb();
let page = 1;
if (req.page) {
page = req.page;
@@ -19,7 +21,7 @@ export const list = async (req: DomainListReq) => {
if (req.perPage) {
perPage = req.perPage;
}
const pb = getPb();
let filter = "";
if (req.state === "enabled") {
filter = "enabled=true";

View File

@@ -3,9 +3,7 @@ import { getPb } from "./api";
export const getEmails = async () => {
try {
const resp = await getPb()
.collection("settings")
.getFirstListItem<Setting>("name='emails'");
const resp = await getPb().collection("settings").getFirstListItem<Setting>("name='emails'");
return resp;
} catch (e) {
return {
@@ -16,9 +14,7 @@ export const getEmails = async () => {
export const getSetting = async (name: string) => {
try {
const resp = await getPb()
.collection("settings")
.getFirstListItem<Setting>(`name='${name}'`);
const resp = await getPb().collection("settings").getFirstListItem<Setting>(`name='${name}'`);
return resp;
} catch (e) {
const rs: Setting = {