mirror of
https://github.com/woodchen-ink/certimate.git
synced 2025-07-18 17:31:55 +08:00
125 lines
5.2 KiB
TypeScript
125 lines
5.2 KiB
TypeScript
import { memo, useEffect, useMemo, useRef, useState } from "react";
|
|
import { useTranslation } from "react-i18next";
|
|
import { Avatar, Card, Col, Empty, Flex, Input, type InputRef, Row, Tag, Typography } from "antd";
|
|
|
|
import Show from "@/components/Show";
|
|
import { ACCESS_USAGES, type AccessProvider, type AccessUsageType, accessProvidersMap } from "@/domain/provider";
|
|
import { mergeCls } from "@/utils/css";
|
|
|
|
export type AccessProviderPickerProps = {
|
|
className?: string;
|
|
style?: React.CSSProperties;
|
|
autoFocus?: boolean;
|
|
filter?: (record: AccessProvider) => boolean;
|
|
placeholder?: string;
|
|
showOptionTags?: boolean | { [key in AccessUsageType]?: boolean };
|
|
onSelect?: (value: string) => void;
|
|
};
|
|
|
|
const AccessProviderPicker = ({ className, style, autoFocus, filter, placeholder, showOptionTags, onSelect }: AccessProviderPickerProps) => {
|
|
const { t } = useTranslation();
|
|
|
|
const [keyword, setKeyword] = useState<string>();
|
|
const keywordInputRef = useRef<InputRef>(null);
|
|
useEffect(() => {
|
|
if (autoFocus) {
|
|
setTimeout(() => keywordInputRef.current?.focus(), 1);
|
|
}
|
|
}, []);
|
|
|
|
const providers = useMemo(() => {
|
|
return Array.from(accessProvidersMap.values())
|
|
.filter((provider) => {
|
|
if (filter) {
|
|
return filter(provider);
|
|
}
|
|
|
|
return true;
|
|
})
|
|
.filter((provider) => {
|
|
if (keyword) {
|
|
const value = keyword.toLowerCase();
|
|
return provider.type.toLowerCase().includes(value) || t(provider.name).toLowerCase().includes(value);
|
|
}
|
|
|
|
return true;
|
|
});
|
|
}, [filter, keyword]);
|
|
|
|
const showOptionTagForDNS = useMemo(() => {
|
|
return typeof showOptionTags === "object" ? !!showOptionTags[ACCESS_USAGES.DNS] : !!showOptionTags;
|
|
}, [showOptionTags]);
|
|
const showOptionTagForHosting = useMemo(() => {
|
|
return typeof showOptionTags === "object" ? !!showOptionTags[ACCESS_USAGES.HOSTING] : !!showOptionTags;
|
|
}, [showOptionTags]);
|
|
const showOptionTagForCA = useMemo(() => {
|
|
return typeof showOptionTags === "object" ? !!showOptionTags[ACCESS_USAGES.CA] : !!showOptionTags;
|
|
}, [showOptionTags]);
|
|
const showOptionTagForNotification = useMemo(() => {
|
|
return typeof showOptionTags === "object" ? !!showOptionTags[ACCESS_USAGES.NOTIFICATION] : !!showOptionTags;
|
|
}, [showOptionTags]);
|
|
|
|
const handleProviderTypeSelect = (value: string) => {
|
|
onSelect?.(value);
|
|
};
|
|
|
|
return (
|
|
<div className={className} style={style}>
|
|
<Input.Search ref={keywordInputRef} placeholder={placeholder ?? t("common.text.search")} onChange={(e) => setKeyword(e.target.value.trim())} />
|
|
|
|
<div className="mt-4">
|
|
<Show when={providers.length > 0} fallback={<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />}>
|
|
<Row gutter={[16, 16]}>
|
|
{providers.map((provider, index) => {
|
|
return (
|
|
<Col key={index} xs={24} md={12} span={8}>
|
|
<Card
|
|
className={mergeCls("h-20 w-full overflow-hidden shadow-sm", provider.builtin ? " cursor-not-allowed" : "")}
|
|
styles={{ body: { height: "100%", padding: "0.5rem 1rem" } }}
|
|
hoverable
|
|
onClick={() => {
|
|
if (provider.builtin) {
|
|
return;
|
|
}
|
|
|
|
handleProviderTypeSelect(provider.type);
|
|
}}
|
|
>
|
|
<Flex className="size-full overflow-hidden" align="center" gap={8}>
|
|
<Avatar src={provider.icon} size="small" />
|
|
<div className="flex-1 overflow-hidden">
|
|
<Typography.Text className="mb-1 line-clamp-1" type={provider.builtin ? "secondary" : undefined}>
|
|
{t(provider.name)}
|
|
</Typography.Text>
|
|
<div className="origin-left scale-[80%]">
|
|
<Show when={provider.builtin}>
|
|
<Tag>{t("access.props.provider.builtin")}</Tag>
|
|
</Show>
|
|
<Show when={showOptionTagForDNS && provider.usages.includes(ACCESS_USAGES.DNS)}>
|
|
<Tag color="orange">{t("access.props.provider.usage.dns")}</Tag>
|
|
</Show>
|
|
<Show when={showOptionTagForHosting && provider.usages.includes(ACCESS_USAGES.HOSTING)}>
|
|
<Tag color="geekblue">{t("access.props.provider.usage.hosting")}</Tag>
|
|
</Show>
|
|
<Show when={showOptionTagForCA && provider.usages.includes(ACCESS_USAGES.CA)}>
|
|
<Tag color="magenta">{t("access.props.provider.usage.ca")}</Tag>
|
|
</Show>
|
|
<Show when={showOptionTagForNotification && provider.usages.includes(ACCESS_USAGES.NOTIFICATION)}>
|
|
<Tag color="cyan">{t("access.props.provider.usage.notification")}</Tag>
|
|
</Show>
|
|
</div>
|
|
</div>
|
|
</Flex>
|
|
</Card>
|
|
</Col>
|
|
);
|
|
})}
|
|
</Row>
|
|
</Show>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default memo(AccessProviderPicker);
|