style(ui): eslint-plugin-tailwindcss

This commit is contained in:
Fu Diwei 2025-01-03 20:35:11 +08:00
parent 8a16893082
commit 5ce5a08e41
29 changed files with 86 additions and 67 deletions

View File

@ -15,6 +15,7 @@ module.exports = {
"plugin:import/typescript",
"plugin:prettier/recommended",
"plugin:react-hooks/recommended",
"plugin:tailwindcss/recommended",
],
ignorePatterns: ["dist", ".eslintrc.cjs"],
parser: "@typescript-eslint/parser",

17
ui/package-lock.json generated
View File

@ -48,6 +48,7 @@
"eslint-plugin-prettier": "^5.2.1",
"eslint-plugin-react-hooks": "^5.1.0",
"eslint-plugin-react-refresh": "^0.4.16",
"eslint-plugin-tailwindcss": "^3.17.5",
"fs-extra": "^11.2.0",
"postcss": "^8.4.49",
"prettier": "^3.4.2",
@ -4887,6 +4888,22 @@
"eslint": ">=8.40"
}
},
"node_modules/eslint-plugin-tailwindcss": {
"version": "3.17.5",
"resolved": "https://registry.npmmirror.com/eslint-plugin-tailwindcss/-/eslint-plugin-tailwindcss-3.17.5.tgz",
"integrity": "sha512-8Mi7p7dm+mO1dHgRHHFdPu4RDTBk69Cn4P0B40vRQR+MrguUpwmKwhZy1kqYe3Km8/4nb+cyrCF+5SodOEmaow==",
"dev": true,
"dependencies": {
"fast-glob": "^3.2.5",
"postcss": "^8.4.4"
},
"engines": {
"node": ">=18.12.0"
},
"peerDependencies": {
"tailwindcss": "^3.4.0"
}
},
"node_modules/eslint-scope": {
"version": "7.2.2",
"resolved": "https://registry.npmmirror.com/eslint-scope/-/eslint-scope-7.2.2.tgz",

View File

@ -50,6 +50,7 @@
"eslint-plugin-prettier": "^5.2.1",
"eslint-plugin-react-hooks": "^5.1.0",
"eslint-plugin-react-refresh": "^0.4.16",
"eslint-plugin-tailwindcss": "^3.17.5",
"fs-extra": "^11.2.0",
"postcss": "^8.4.49",
"prettier": "^3.4.2",

View File

@ -106,7 +106,7 @@ const ModalForm = <T extends NonNullable<unknown> = NonNullable<unknown>>({
onOk={handleOkClick}
onCancel={handleCancelClick}
>
<div className="pt-4 pb-2">
<div className="pb-2 pt-4">
<Form className={className} style={style} form={formInst} {...mergedFormProps}>
{children}
</Form>

View File

@ -247,7 +247,7 @@ const MultipleInputItem = forwardRef<MultipleInputItemInstance, MultipleInputIte
return (
<div className="flex flex-nowrap items-center space-x-2">
<div className="flex-grow">
<div className="grow">
<Input
{...props}
ref={inputRef}

View File

@ -100,7 +100,7 @@ const AccessEditModal = ({ data, loading, trigger, preset, onSubmit, ...props }:
onOk={handleClickOk}
onCancel={handleClickCancel}
>
<div className="pt-4 pb-2">
<div className="pb-2 pt-4">
<AccessEditForm ref={formRef} initialValues={data} preset={preset === "add" ? "add" : "edit"} />
</div>
</Modal>

View File

@ -36,7 +36,7 @@ const AccessSelect = ({ filter, ...props }: AccessTypeSelectProps) => {
const access = accesses.find((e) => e.id === key);
if (!access) {
return (
<Space className="flex-grow max-w-full truncate" size={4}>
<Space className="max-w-full grow truncate" size={4}>
<Avatar size="small" />
<Typography.Text className="leading-loose" ellipsis>
{key}
@ -47,7 +47,7 @@ const AccessSelect = ({ filter, ...props }: AccessTypeSelectProps) => {
const provider = accessProvidersMap.get(access.configType);
return (
<Space className="flex-grow max-w-full truncate" size={4}>
<Space className="max-w-full grow truncate" size={4}>
<Avatar src={provider?.icon} size="small" />
<Typography.Text className="leading-loose" ellipsis>
{access.name}

View File

@ -48,7 +48,7 @@ const CertificateDetail = ({ data, ...props }: CertificateDetailProps) => {
</Form.Item>
<Form.Item>
<div className="flex items-center justify-between w-full mb-2">
<div className="mb-2 flex w-full items-center justify-between">
<label>{t("certificate.props.certificate_chain")}</label>
<Tooltip title={t("common.button.copy")}>
<CopyToClipboard
@ -65,7 +65,7 @@ const CertificateDetail = ({ data, ...props }: CertificateDetailProps) => {
</Form.Item>
<Form.Item>
<div className="flex items-center justify-between w-full mb-2">
<div className="mb-2 flex w-full items-center justify-between">
<label>{t("certificate.props.private_key")}</label>
<Tooltip title={t("common.button.copy")}>
<CopyToClipboard

View File

@ -21,8 +21,8 @@ const AccessProviderSelect = (props: AccessProviderSelectProps) => {
const renderOption = (key: string) => {
const provider = accessProvidersMap.get(key);
return (
<div className="flex items-center justify-between gap-4 max-w-full overflow-hidden">
<Space className="flex-grow max-w-full truncate" size={4}>
<div className="flex max-w-full items-center justify-between gap-4 overflow-hidden">
<Space className="max-w-full grow truncate" size={4}>
<Avatar src={provider?.icon} size="small" />
<Typography.Text className="leading-loose" ellipsis>
{t(provider?.name ?? "")}

View File

@ -50,7 +50,7 @@ const DeployProviderPicker = ({ className, style, onSelect }: DeployProviderPick
return (
<Col key={index} span={12}>
<Card
className="w-full h-16 shadow-sm overflow-hidden"
className="h-16 w-full overflow-hidden shadow-sm"
styles={{ body: { height: "100%", padding: "0.5rem 1rem" } }}
hoverable
onClick={() => {

View File

@ -21,7 +21,7 @@ const DeployProviderSelect = (props: DeployProviderSelectProps) => {
const renderOption = (key: string) => {
const provider = deployProvidersMap.get(key);
return (
<Space className="flex-grow max-w-full truncate overflow-hidden" size={4}>
<Space className="max-w-full grow overflow-hidden truncate" size={4}>
<Avatar src={provider?.icon} size="small" />
<Typography.Text className="leading-loose" ellipsis>
{t(provider?.name ?? "")}

View File

@ -32,7 +32,7 @@ const WorkflowElement = ({ node }: NodeProps) => {
switch (node.type) {
case WorkflowNodeType.Start: {
return (
<div className="flex space-x-2 items-center justify-between">
<div className="flex items-center justify-between space-x-2">
<Typography.Text className="truncate">
{node.config?.executionMethod === "auto"
? t("workflow.props.trigger.auto")
@ -64,7 +64,7 @@ const WorkflowElement = ({ node }: NodeProps) => {
case WorkflowNodeType.Notify: {
const channel = notifyChannelsMap.get(node.config?.channel as string);
return (
<div className="flex space-x-2 items-center justify-between">
<div className="flex items-center justify-between space-x-2">
<Typography.Text className="truncate">{t(channel?.name ?? "")}</Typography.Text>
<Typography.Text className="truncate" type="secondary">
{(node.config?.subject as string) ?? ""}
@ -130,10 +130,10 @@ const WorkflowElement = ({ node }: NodeProps) => {
overlayInnerStyle={{ padding: 0 }}
placement="rightTop"
>
<Card className="relative w-[256px] shadow-md overflow-hidden" styles={{ body: { padding: 0 } }} hoverable>
<div className="h-[48px] px-4 py-2 flex flex-col justify-center items-center bg-primary text-white truncate">
<Card className="relative w-[256px] overflow-hidden shadow-md" styles={{ body: { padding: 0 } }} hoverable>
<div className="bg-primary flex h-[48px] flex-col items-center justify-center truncate px-4 py-2 text-white">
<div
className="w-full text-center outline-none overflow-hidden focus:bg-background focus:text-foreground focus:rounded-sm"
className="focus:bg-background focus:text-foreground w-full overflow-hidden text-center outline-none focus:rounded-sm"
contentEditable
suppressContentEditableWarning
onBlur={handleNodeNameBlur}
@ -142,8 +142,8 @@ const WorkflowElement = ({ node }: NodeProps) => {
</div>
</div>
<div className="px-4 py-2 flex flex-col justify-center">
<div className="text-sm cursor-pointer" onClick={handleNodeClick}>
<div className="flex flex-col justify-center px-4 py-2">
<div className="cursor-pointer text-sm" onClick={handleNodeClick}>
{renderNodeContent()}
</div>
</div>

View File

@ -40,7 +40,7 @@ const WorkflowRunDetailDrawer = ({ data, loading, trigger, ...props }: WorkflowR
<Alert showIcon type="error" message={<Typography.Text type="danger">{t("workflow_run.props.status.failed")}</Typography.Text>} />
</Show>
<div className="mt-4 p-4 bg-black text-stone-200 rounded-md">
<div className="mt-4 rounded-md bg-black p-4 text-stone-200">
<div className="flex flex-col space-y-3">
{data!.log.map((item, i) => {
return (
@ -49,7 +49,7 @@ const WorkflowRunDetailDrawer = ({ data, loading, trigger, ...props }: WorkflowR
<div className="flex flex-col space-y-1">
{item.outputs.map((output, j) => {
return (
<div key={j} className="flex text-sm space-x-2">
<div key={j} className="flex space-x-2 text-sm">
<div>[{dayjs(output.time).format("YYYY-MM-DD HH:mm:ss")}]</div>
{output.error ? <div className="text-red-500">{output.error}</div> : <div>{output.content}</div>}
</div>

View File

@ -45,7 +45,7 @@ const AddNode = ({ node: supnode }: NodeProps | BrandNodeProps) => {
};
return (
<div className="relative py-6 before:content-[''] before:absolute before:w-[2px] before:h-full before:left-[50%] before:-translate-x-[50%] before:top-0 before:bg-stone-200">
<div className="relative py-6 before:absolute before:left-[50%] before:top-0 before:h-full before:w-[2px] before:-translate-x-[50%] before:bg-stone-200 before:content-['']">
<Dropdown
menu={{
items: dropdownMenus.map((item) => {
@ -61,7 +61,7 @@ const AddNode = ({ node: supnode }: NodeProps | BrandNodeProps) => {
}}
trigger={["click"]}
>
<div className="bg-stone-400 hover:bg-stone-500 rounded-full size-5 z-[1] relative flex items-center justify-center cursor-pointer">
<div className="relative z-[1] flex size-5 cursor-pointer items-center justify-center rounded-full bg-stone-400 hover:bg-stone-500">
<PlusOutlinedIcon className="text-white" />
</div>
</Dropdown>

View File

@ -143,9 +143,9 @@ const ApplyNodeForm = ({ node }: ApplyNodeFormProps) => {
</Form.Item>
<Form.Item className="mb-0">
<label className="block mb-1">
<div className="flex items-center justify-between gap-4 w-full">
<div className="flex-grow max-w-full truncate">
<label className="mb-1 block">
<div className="flex w-full items-center justify-between gap-4">
<div className="max-w-full grow truncate">
<span>{t("workflow_node.apply.form.access.label")}</span>
<Tooltip title={t("workflow_node.apply.form.access.tooltip")}>
<Typography.Text className="ms-1" type="secondary">
@ -184,7 +184,7 @@ const ApplyNodeForm = ({ node }: ApplyNodeFormProps) => {
</Form.Item>
<Divider className="my-1">
<Typography.Text className="font-normal text-xs" type="secondary">
<Typography.Text className="text-xs font-normal" type="secondary">
{t("workflow_node.apply.form.advanced_config.label")}
</Typography.Text>
</Divider>

View File

@ -32,9 +32,9 @@ const BranchNode = ({ node }: BrandNodeProps) => {
return (
<>
<div className="relative flex gap-x-16 before:content-[''] before:absolute before:h-[2px] before:left-[128px] before:right-[128px] before:top-0 before:bg-stone-200">
<div className="relative flex gap-x-16 before:absolute before:inset-x-[128px] before:top-0 before:h-[2px] before:bg-stone-200 before:content-['']">
<Button
className="text-xs absolute left-[50%] -translate-x-1/2 -translate-y-1/2 z-[1]"
className="absolute left-[50%] z-[1] -translate-x-1/2 -translate-y-1/2 text-xs"
size="small"
shape="round"
variant="outlined"
@ -48,7 +48,7 @@ const BranchNode = ({ node }: BrandNodeProps) => {
{node.branches!.map((branch, index) => (
<div
key={branch.id}
className="relative flex flex-col items-center before:content-[''] before:w-[2px] before:bg-stone-200 before:absolute before:h-full before:left-[50%] before:-translate-x-[50%] before:top-0"
className="relative flex flex-col items-center before:absolute before:left-[50%] before:top-0 before:h-full before:w-[2px] before:-translate-x-[50%] before:bg-stone-200 before:content-['']"
>
<div className="relative flex flex-col items-center">{renderNodes(branch, node.id, index)}</div>
</div>

View File

@ -56,10 +56,10 @@ const ConditionNode = ({ node, branchId, branchIndex }: NodeProps) => {
overlayInnerStyle={{ padding: 0 }}
placement="rightTop"
>
<Card className="relative w-[256px] shadow-md mt-10 z-[1]" styles={{ body: { padding: 0 } }} hoverable>
<div className="h-[48px] px-4 py-2 flex flex-col justify-center items-center truncate">
<Card className="relative z-[1] mt-10 w-[256px] shadow-md" styles={{ body: { padding: 0 } }} hoverable>
<div className="flex h-[48px] flex-col items-center justify-center truncate px-4 py-2">
<div
className="w-full text-center outline-slate-200 overflow-hidden focus:bg-background focus:text-foreground focus:rounded-sm"
className="focus:bg-background focus:text-foreground w-full overflow-hidden text-center outline-slate-200 focus:rounded-sm"
contentEditable
suppressContentEditableWarning
onBlur={handleNodeNameBlur}

View File

@ -189,9 +189,9 @@ const DeployNodeForm = ({ node }: DeployFormProps) => {
</Form.Item>
<Form.Item className="mb-0">
<label className="block mb-1">
<div className="flex items-center justify-between gap-4 w-full">
<div className="flex-grow max-w-full truncate">
<label className="mb-1 block">
<div className="flex w-full items-center justify-between gap-4">
<div className="max-w-full grow truncate">
<span>{t("workflow_node.deploy.form.provider_access.label")}</span>
<Tooltip title={t("workflow_node.deploy.form.provider_access.tooltip")}>
<Typography.Text className="ms-1" type="secondary">
@ -257,7 +257,7 @@ const DeployNodeForm = ({ node }: DeployFormProps) => {
</Form.Item>
<Divider className="my-1">
<Typography.Text className="font-normal text-xs" type="secondary">
<Typography.Text className="text-xs font-normal" type="secondary">
{t("workflow_node.deploy.form.params_config.label")}
</Typography.Text>
</Divider>

View File

@ -285,9 +285,9 @@ Remove-Item -Path "$pfxPath" -Force
</Form.Item>
<Form.Item className="mb-0">
<label className="block mb-1">
<div className="flex items-center justify-between gap-4 w-full">
<div className="flex-grow max-w-full truncate">
<label className="mb-1 block">
<div className="flex w-full items-center justify-between gap-4">
<div className="max-w-full grow truncate">
<span>{t("workflow_node.deploy.form.local_post_command.label")}</span>
</div>
<div className="text-right">

View File

@ -200,9 +200,9 @@ const DeployNodeFormSSHFields = () => {
</Form.Item>
<Form.Item className="mb-0">
<label className="block mb-1">
<div className="flex items-center justify-between gap-4 w-full">
<div className="flex-grow max-w-full truncate">
<label className="mb-1 block">
<div className="flex w-full items-center justify-between gap-4">
<div className="max-w-full grow truncate">
<span>{t("workflow_node.deploy.form.ssh_post_command.label")}</span>
</div>
<div className="text-right">

View File

@ -7,7 +7,7 @@ const EndNode = () => {
return (
<div className="flex flex-col items-center">
<div className="size-[20px] rounded-full bg-stone-400"></div>
<div className="text-sm mt-2">
<div className="mt-2 text-sm">
<Typography.Text type="secondary">{t("workflow_node.end.label")}</Typography.Text>
</div>
</div>

View File

@ -81,9 +81,9 @@ const NotifyNodeForm = ({ node }: NotifyNodeFormProps) => {
</Form.Item>
<Form.Item className="mb-0">
<label className="block mb-1">
<div className="flex items-center justify-between gap-4 w-full">
<div className="flex-grow max-w-full truncate">{t("workflow_node.notify.form.channel.label")}</div>
<label className="mb-1 block">
<div className="flex w-full items-center justify-between gap-4">
<div className="max-w-full grow truncate">{t("workflow_node.notify.form.channel.label")}</div>
<div className="text-right">
<Link className="ant-typography" to="/settings/notification" target="_blank">
<Button size="small" type="link">

View File

@ -13,7 +13,7 @@ const AuthLayout = () => {
<div className="container">
<Outlet />
<Version className="fixed right-8 bottom-4" />
<Version className="fixed bottom-4 right-8" />
</div>
);
};

View File

@ -52,8 +52,8 @@ const ConsoleLayout = () => {
return (
<Layout className="min-h-screen" hasSider>
<Layout.Sider className="max-md:hidden max-md:static fixed top-0 left-0 h-full z-[20]" width="256px" theme="light">
<div className="flex flex-col items-center justify-between w-full h-full overflow-hidden">
<Layout.Sider className="fixed left-0 top-0 z-20 h-full max-md:static max-md:hidden" width="256px" theme="light">
<div className="flex size-full flex-col items-center justify-between overflow-hidden">
<div className="w-full">
<SiderMenu />
</div>
@ -64,8 +64,8 @@ const ConsoleLayout = () => {
</Layout.Sider>
<Layout className="pl-[256px] max-md:pl-0">
<Layout.Header className="sticky top-0 left-0 right-0 p-0 z-[19] shadow-sm" style={{ background: themeToken.colorBgContainer }}>
<div className="flex items-center justify-between size-full px-4 overflow-hidden">
<Layout.Header className="sticky inset-x-0 top-0 z-[19] p-0 shadow-sm" style={{ background: themeToken.colorBgContainer }}>
<div className="flex size-full items-center justify-between overflow-hidden px-4">
<div className="flex items-center gap-4">
<Button className="md:hidden" icon={<MenuOutlinedIcon />} size="large" onClick={handleSiderOpen} />
<Drawer
@ -82,7 +82,7 @@ const ConsoleLayout = () => {
<SiderMenu onSelect={() => handleSiderClose()} />
</Drawer>
</div>
<div className="flex-grow flex items-center justify-end gap-4 size-full overflow-hidden">
<div className="flex size-full grow items-center justify-end gap-4 overflow-hidden">
<Tooltip title={t("common.menu.theme")} mouseEnterDelay={2}>
<ThemeToggleButton size="large" />
</Tooltip>
@ -159,11 +159,11 @@ const SiderMenu = memo(({ onSelect }: { onSelect?: (key: string) => void }) => {
return (
<>
<Link to="/" className="flex items-center gap-2 w-full px-4 font-semibold overflow-hidden">
<img src="/logo.svg" className="w-[36px] h-[36px]" />
<span className="w-[74px] h-[64px] leading-[64px] dark:text-white truncate">Certimate</span>
<Link to="/" className="flex w-full items-center gap-2 overflow-hidden px-4 font-semibold">
<img src="/logo.svg" className="size-[36px]" />
<span className="h-[64px] w-[74px] truncate leading-[64px] dark:text-white">Certimate</span>
</Link>
<div className="flex-grow w-full overflow-x-hidden overflow-y-auto">
<div className="w-full grow overflow-y-auto overflow-x-hidden">
<Menu
items={menuItems}
mode="vertical"

View File

@ -77,7 +77,7 @@ const CertificateList = () => {
<div style={{ padding: 0 }}>
<Menu items={items} selectable={false} />
<Divider style={{ margin: 0 }} />
<Space className="justify-end w-full" style={{ padding: themeToken.paddingSM }}>
<Space className="w-full justify-end" style={{ padding: themeToken.paddingSM }}>
<Button size="small" disabled={!filters.state} onClick={handleResetClick}>
{t("common.button.reset")}
</Button>

View File

@ -39,8 +39,8 @@ const Login = () => {
<>
{NotificationContextHolder}
<Card className="mx-auto mt-32 p-10 max-w-[35em] border dark:border-stone-500 rounded-md shadow-md">
<div className="flex items-center justify-center mb-10">
<Card className="mx-auto mt-32 max-w-[35em] rounded-md border p-10 shadow-md dark:border-stone-500">
<div className="mb-10 flex items-center justify-center">
<img src="/logo.svg" className="w-16" />
</div>

View File

@ -250,7 +250,7 @@ const WorkflowDetail = () => {
<div className="py-12 lg:pr-36 xl:pr-48">
<WorkflowElements />
</div>
<div className="absolute top-0 right-0 z-[1]">
<div className="absolute right-0 top-0 z-[1]">
<Space>
<Button disabled={!allowRun} icon={<CaretRightOutlinedIcon />} loading={isRunning} type="primary" onClick={handleRunClick}>
{t("workflow.detail.orchestration.action.run")}

View File

@ -122,7 +122,7 @@ const WorkflowList = () => {
<div style={{ padding: 0 }}>
<Menu items={items} selectable={false} />
<Divider style={{ margin: 0 }} />
<Space className="justify-end w-full" style={{ padding: themeToken.paddingSM }}>
<Space className="w-full justify-end" style={{ padding: themeToken.paddingSM }}>
<Button size="small" disabled={!filters.state} onClick={handleResetClick}>
{t("common.button.reset")}
</Button>

View File

@ -73,9 +73,9 @@ const WorkflowNew = () => {
</Card>
<div className="p-4">
<div className="max-w-[960px] mx-auto px-2">
<div className="mx-auto max-w-[960px] px-2">
<Typography.Text type="secondary">
<div className="mt-4 mb-8 text-xl">{t("workflow.new.templates.title")}</div>
<div className="mb-8 mt-4 text-xl">{t("workflow.new.templates.title")}</div>
</Typography.Text>
<Row className="justify-stretch" gutter={[16, 16]}>
@ -86,9 +86,9 @@ const WorkflowNew = () => {
hoverable
onClick={() => handleTemplateSelect(TEMPLATE_KEY_STANDARD)}
>
<div className="flex items-center gap-4 w-full">
<div className="flex w-full items-center gap-4">
<Card.Meta
className="flex-grow"
className="grow"
title={t("workflow.new.templates.template.standard.title")}
description={t("workflow.new.templates.template.standard.description")}
/>
@ -103,9 +103,9 @@ const WorkflowNew = () => {
hoverable
onClick={() => handleTemplateSelect(TEMPLATE_KEY_BLANK)}
>
<div className="flex items-center gap-4 w-full">
<div className="flex w-full items-center gap-4">
<Card.Meta
className="flex-grow"
className="grow"
title={t("workflow.new.templates.template.blank.title")}
description={t("workflow.new.templates.template.blank.description")}
/>