less buttons
This commit is contained in:
6
.vscode/settings.json
vendored
6
.vscode/settings.json
vendored
@@ -9,5 +9,9 @@
|
|||||||
},
|
},
|
||||||
"[css]": {
|
"[css]": {
|
||||||
"editor.defaultFormatter": "rvest.vs-code-prettier-eslint"
|
"editor.defaultFormatter": "rvest.vs-code-prettier-eslint"
|
||||||
}
|
},
|
||||||
|
"tailwindCSS.classFunctions": [
|
||||||
|
"cva",
|
||||||
|
"cx"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import React, { useRef } from "react";
|
import React, { useRef } from "react";
|
||||||
import { Button } from "@/design-system/base/button";
|
import { LightButton } from "@/design-system/base/button";
|
||||||
import { FileInputProps } from "../../types/controls";
|
import { FileInputProps } from "../../types/controls";
|
||||||
|
|
||||||
interface FileInputComponentProps extends FileInputProps {
|
interface FileInputComponentProps extends FileInputProps {
|
||||||
@@ -34,15 +34,14 @@ export function FileInput({ accept, onFileSelect, disabled, className, children
|
|||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
className="hidden"
|
className="hidden"
|
||||||
/>
|
/>
|
||||||
<Button
|
<LightButton
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
variant="secondary"
|
|
||||||
size="sm"
|
size="sm"
|
||||||
className={className}
|
className={className}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</Button>
|
</LightButton>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -7,7 +7,7 @@ import {
|
|||||||
FolderPlus,
|
FolderPlus,
|
||||||
Trash2,
|
Trash2,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import { CircleButton, DashedButton } from "@/design-system/base/button";
|
import { CircleButton, LightButton } from "@/design-system/base/button";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
@@ -135,7 +135,7 @@ export function FoldersClient({ userId }: { userId: string; }) {
|
|||||||
<PageHeader title={t("title")} subtitle={t("subtitle")} />
|
<PageHeader title={t("title")} subtitle={t("subtitle")} />
|
||||||
|
|
||||||
{/* 新建文件夹按钮 */}
|
{/* 新建文件夹按钮 */}
|
||||||
<DashedButton
|
<LightButton
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
const folderName = prompt(t("enterFolderName"));
|
const folderName = prompt(t("enterFolderName"));
|
||||||
if (!folderName) return;
|
if (!folderName) return;
|
||||||
@@ -154,11 +154,11 @@ export function FoldersClient({ userId }: { userId: string; }) {
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
className="w-full"
|
className="w-full border-dashed"
|
||||||
>
|
>
|
||||||
<FolderPlus size={18} />
|
<FolderPlus size={18} />
|
||||||
<span>{loading ? t("creating") : t("newFolder")}</span>
|
<span>{loading ? t("creating") : t("newFolder")}</span>
|
||||||
</DashedButton>
|
</LightButton>
|
||||||
|
|
||||||
{/* 文件夹列表 */}
|
{/* 文件夹列表 */}
|
||||||
<div className="mt-4">
|
<div className="mt-4">
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { AddTextPairModal } from "./AddTextPairModal";
|
|||||||
import { TextPairCard } from "./TextPairCard";
|
import { TextPairCard } from "./TextPairCard";
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
import { PageLayout } from "@/components/ui/PageLayout";
|
import { PageLayout } from "@/components/ui/PageLayout";
|
||||||
import { PrimaryButton, IconButton, LinkButton } from "@/design-system/base/button";
|
import { PrimaryButton, CircleButton, LinkButton } from "@/design-system/base/button";
|
||||||
import { CardList } from "@/components/ui/CardList";
|
import { CardList } from "@/components/ui/CardList";
|
||||||
import { actionCreatePair, actionDeletePairById, actionGetPairsByFolderId } from "@/modules/folder/folder-aciton";
|
import { actionCreatePair, actionDeletePairById, actionGetPairsByFolderId } from "@/modules/folder/folder-aciton";
|
||||||
import { TSharedPair } from "@/shared/folder-type";
|
import { TSharedPair } from "@/shared/folder-type";
|
||||||
@@ -81,12 +81,13 @@ export function InFolder({ folderId, isReadOnly }: { folderId: number; isReadOnl
|
|||||||
{t("memorize")}
|
{t("memorize")}
|
||||||
</PrimaryButton>
|
</PrimaryButton>
|
||||||
{!isReadOnly && (
|
{!isReadOnly && (
|
||||||
<IconButton
|
<CircleButton
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setAddModal(true);
|
setAddModal(true);
|
||||||
}}
|
}}
|
||||||
icon={<Plus size={18} className="text-gray-700" />}
|
>
|
||||||
/>
|
<Plus size={18} className="text-gray-700" />
|
||||||
|
</CircleButton>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -15,7 +15,12 @@ export function LanguageSettings() {
|
|||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Languages onClick={handleLanguageClick} size={28} className="text-white hover:text-white/80" />
|
<GhostLightButton
|
||||||
|
size="md"
|
||||||
|
onClick={handleLanguageClick}
|
||||||
|
>
|
||||||
|
<Languages size={20} />
|
||||||
|
</GhostLightButton>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
{showLanguageMenu && (
|
{showLanguageMenu && (
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -9,20 +9,12 @@ export { Card, type CardVariant, type CardPadding, type CardProps } from '@/desi
|
|||||||
export {
|
export {
|
||||||
Button,
|
Button,
|
||||||
PrimaryButton,
|
PrimaryButton,
|
||||||
SecondaryButton,
|
|
||||||
LightButton,
|
LightButton,
|
||||||
SuccessButton,
|
|
||||||
WarningButton,
|
|
||||||
ErrorButton,
|
|
||||||
GhostButton,
|
|
||||||
GhostLightButton,
|
GhostLightButton,
|
||||||
OutlineButton,
|
|
||||||
LinkButton,
|
LinkButton,
|
||||||
IconButton,
|
|
||||||
IconClick,
|
IconClick,
|
||||||
CircleButton,
|
CircleButton,
|
||||||
CircleToggleButton,
|
CircleToggleButton,
|
||||||
DashedButton,
|
|
||||||
type ButtonVariant,
|
type ButtonVariant,
|
||||||
type ButtonSize,
|
type ButtonSize,
|
||||||
type ButtonProps
|
type ButtonProps
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ import { cn } from "@/design-system/lib/utils";
|
|||||||
*/
|
*/
|
||||||
const buttonVariants = cva(
|
const buttonVariants = cva(
|
||||||
// 基础样式
|
// 基础样式
|
||||||
"border flex-inline items-center justify-center gap-2 rounded-md font-semibold shadow transition-all duration-250 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
|
"inline-flex items-center justify-center gap-2 rounded-md font-semibold shadow leading-none transition-all duration-250 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
|
||||||
{
|
{
|
||||||
variants: {
|
variants: {
|
||||||
variant: {
|
variant: {
|
||||||
@@ -56,9 +56,9 @@ const buttonVariants = cva(
|
|||||||
link: "text-primary-500 hover:text-primary-600 hover:underline shadow-none px-0",
|
link: "text-primary-500 hover:text-primary-600 hover:underline shadow-none px-0",
|
||||||
},
|
},
|
||||||
size: {
|
size: {
|
||||||
sm: "h-8 px-3 text-sm",
|
sm: "px-2.5 py-1.5 text-sm",
|
||||||
md: "h-10 px-4 text-base",
|
md: "px-4 py-2 text-base",
|
||||||
lg: "h-12 px-6 text-lg",
|
lg: "px-6 py-3 text-lg",
|
||||||
},
|
},
|
||||||
fullWidth: {
|
fullWidth: {
|
||||||
true: "w-full",
|
true: "w-full",
|
||||||
@@ -248,50 +248,22 @@ export const PrimaryButton = (props: Omit<ButtonProps, "variant">) => (
|
|||||||
<Button variant="primary" {...props} />
|
<Button variant="primary" {...props} />
|
||||||
);
|
);
|
||||||
|
|
||||||
export const SecondaryButton = (props: Omit<ButtonProps, "variant">) => (
|
// LightButton: 次要按钮
|
||||||
|
export const LightButton = (props: Omit<ButtonProps, "variant">) => (
|
||||||
<Button variant="secondary" {...props} />
|
<Button variant="secondary" {...props} />
|
||||||
);
|
);
|
||||||
|
|
||||||
// LightButton: 次要按钮的别名(向后兼容)
|
|
||||||
export const LightButton = SecondaryButton;
|
|
||||||
|
|
||||||
export const SuccessButton = (props: Omit<ButtonProps, "variant">) => (
|
|
||||||
<Button variant="success" {...props} />
|
|
||||||
);
|
|
||||||
|
|
||||||
export const WarningButton = (props: Omit<ButtonProps, "variant">) => (
|
|
||||||
<Button variant="warning" {...props} />
|
|
||||||
);
|
|
||||||
|
|
||||||
export const ErrorButton = (props: Omit<ButtonProps, "variant">) => (
|
|
||||||
<Button variant="error" {...props} />
|
|
||||||
);
|
|
||||||
|
|
||||||
export const GhostButton = (props: Omit<ButtonProps, "variant">) => (
|
|
||||||
<Button variant="ghost" {...props} />
|
|
||||||
);
|
|
||||||
|
|
||||||
// GhostLightButton: 透明按钮(白色文字,用于深色背景)
|
// GhostLightButton: 透明按钮(白色文字,用于深色背景)
|
||||||
export const GhostLightButton = (props: Omit<ButtonProps, "variant">) => (
|
export const GhostLightButton = (props: Omit<ButtonProps, "variant">) => (
|
||||||
<Button variant="ghost-light" {...props} />
|
<Button variant="ghost-light" {...props} />
|
||||||
);
|
);
|
||||||
|
|
||||||
export const OutlineButton = (props: Omit<ButtonProps, "variant">) => (
|
|
||||||
<Button variant="outline" {...props} />
|
|
||||||
);
|
|
||||||
|
|
||||||
export const LinkButton = (props: Omit<ButtonProps, "variant">) => (
|
export const LinkButton = (props: Omit<ButtonProps, "variant">) => (
|
||||||
<Button variant="link" {...props} />
|
<Button variant="link" {...props} />
|
||||||
);
|
);
|
||||||
|
|
||||||
// ========== 其他便捷组件 ==========
|
// ========== 其他便捷组件 ==========
|
||||||
|
|
||||||
// IconButton: SVG 图标按钮(使用 ghost 变体)
|
|
||||||
export const IconButton = (props: Omit<ButtonProps, "variant"> & { icon?: React.ReactNode }) => {
|
|
||||||
const { icon, ...rest } = props;
|
|
||||||
return <Button variant="ghost" leftIcon={icon} {...rest} />;
|
|
||||||
};
|
|
||||||
|
|
||||||
// IconClick: 图片图标按钮(支持 Next.js Image)
|
// IconClick: 图片图标按钮(支持 Next.js Image)
|
||||||
export const IconClick = (props: Omit<ButtonProps, "variant"> & {
|
export const IconClick = (props: Omit<ButtonProps, "variant"> & {
|
||||||
src?: string;
|
src?: string;
|
||||||
@@ -344,8 +316,3 @@ export const CircleToggleButton = (props: Omit<ButtonProps, "variant"> & { selec
|
|||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
// DashedButton: 虚线边框按钮(使用 outline 变体近似)
|
|
||||||
export const DashedButton = (props: Omit<ButtonProps, "variant">) => (
|
|
||||||
<Button variant="outline" className="border-dashed" {...props} />
|
|
||||||
);
|
|
||||||
|
|||||||
Reference in New Issue
Block a user