Compare commits

..

2 Commits

Author SHA1 Message Date
8f25791fa1 less buttons 2026-02-14 02:08:40 +08:00
b586c1071b ... 2026-02-10 15:11:09 +08:00
8 changed files with 31 additions and 63 deletions

View File

@@ -9,5 +9,9 @@
}, },
"[css]": { "[css]": {
"editor.defaultFormatter": "rvest.vs-code-prettier-eslint" "editor.defaultFormatter": "rvest.vs-code-prettier-eslint"
} },
"tailwindCSS.classFunctions": [
"cva",
"cx"
]
} }

View File

@@ -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>
</> </>
); );
} }

View File

@@ -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">

View File

@@ -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>

View File

@@ -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>

View File

@@ -14,14 +14,14 @@ export async function Navbar() {
}); });
return ( return (
<div className="flex justify-between items-center w-full h-16 px-4 md:px-8 bg-[#35786f] text-white"> <div className="flex justify-between items-center w-full h-16 px-4 md:px-8 bg-primary-500 text-white">
<GhostLightButton href="/" className="border-b hidden! md:block!" size="md"> <GhostLightButton href="/" className="border-b hidden! md:block!" size="md">
{t("title")} {t("title")}
</GhostLightButton> </GhostLightButton>
<GhostLightButton className="block! md:hidden!" size="md" href={"/"}> <GhostLightButton className="block! md:hidden!" size="md" href={"/"}>
<Home size={20} /> <Home size={20} />
</GhostLightButton> </GhostLightButton>
<div className="flex gap-0.5 justify-center items-center flex-wrap"> <div className="flex gap-0.5 justify-center items-center">
<LanguageSettings /> <LanguageSettings />
<GhostLightButton <GhostLightButton
className="md:hidden! block!" className="md:hidden! block!"

View File

@@ -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

View File

@@ -41,7 +41,7 @@ import { cn } from "@/design-system/lib/utils";
*/ */
const buttonVariants = cva( const buttonVariants = cva(
// 基础样式 // 基础样式
"inline-flex 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} />
);