refactor: update component styles and structure for consistency (upgrade tailwindv4)

- Adjusted layout and styling in AuthCard, LoginForm, RegisterForm, and SocialLoginButton for improved alignment and responsiveness.
- Updated icon sizes in various components to maintain uniformity.
- Enhanced Card components in ContactFormCard, DeleteAccountCard, ResetPasswordCard, UpdateAvatarCard, UpdateNameCard, UpdatePasswordCard, and NewsletterFormCard with consistent padding and margin.
- Refined Navbar and BackButtonSmall for better user interaction with cursor styles.
- Removed unused CSS variables from globals.css to streamline styles.
This commit is contained in:
javayhu 2025-03-21 10:13:31 +08:00
parent 711a5b65b6
commit 73ac2ba2cb
18 changed files with 46 additions and 138 deletions

View File

@ -32,7 +32,7 @@ export const AuthCard = ({
}: AuthCardProps) => {
return (
<Card className={cn('shadow-xs border border-border', className)}>
<CardHeader className="items-center">
<CardHeader className="flex flex-col items-center">
<LocaleLink href="/" prefetch={false}>
<Logo className="mb-2" />
</LocaleLink>

View File

@ -152,9 +152,9 @@ export const LoginForm = ({ className }: { className?: string }) => {
disabled={isPending}
>
{showPassword ? (
<EyeOffIcon className="h-4 w-4 text-muted-foreground" />
<EyeOffIcon className="size-4 text-muted-foreground" />
) : (
<EyeIcon className="h-4 w-4 text-muted-foreground" />
<EyeIcon className="size-4 text-muted-foreground" />
)}
<span className="sr-only">
{showPassword ? t('hidePassword') : t('showPassword')}

View File

@ -151,9 +151,9 @@ export const RegisterForm = () => {
disabled={isPending}
>
{showPassword ? (
<EyeOffIcon className="h-4 w-4 text-muted-foreground" />
<EyeOffIcon className="size-4 text-muted-foreground" />
) : (
<EyeIcon className="h-4 w-4 text-muted-foreground" />
<EyeIcon className="size-4 text-muted-foreground" />
)}
<span className="sr-only">
{showPassword ? t('hidePassword') : t('showPassword')}
@ -172,7 +172,7 @@ export const RegisterForm = () => {
disabled={isPending}
size="lg"
type="submit"
className="w-full flex items-center justify-center gap-2"
className="cursor-pointer w-full flex items-center justify-center gap-2"
>
{isPending ? (
<Icons.spinner className="w-4 h-4 animate-spin" />

View File

@ -73,7 +73,7 @@ export const SocialLoginButton = () => {
<DividerWithText text={t('or')} />
<Button
size="lg"
className="w-full"
className="w-full cursor-pointer"
variant="outline"
onClick={() => onClick('google')}
disabled={isLoading === 'google'}
@ -81,13 +81,13 @@ export const SocialLoginButton = () => {
{isLoading === 'google' ? (
<Icons.spinner className="mr-2 size-4 animate-spin" />
) : (
<GoogleIcon className="size-5 mr-2" />
<GoogleIcon className="size-4 mr-2" />
)}
<span>{t('signInWithGoogle')}</span>
</Button>
<Button
size="lg"
className="w-full"
className="w-full cursor-pointer"
variant="outline"
onClick={() => onClick('github')}
disabled={isLoading === 'github'}
@ -95,7 +95,7 @@ export const SocialLoginButton = () => {
{isLoading === 'github' ? (
<Icons.spinner className="mr-2 size-4 animate-spin" />
) : (
<GitHubIcon className="size-5 mr-2" />
<GitHubIcon className="size-4 mr-2" />
)}
<span>{t('signInWithGitHub')}</span>
</Button>

View File

@ -85,7 +85,7 @@ export function ContactFormCard() {
};
return (
<Card className="mx-auto max-w-lg overflow-hidden">
<Card className="mx-auto max-w-lg overflow-hidden pt-6 pb-0">
<CardHeader>
<CardTitle className="text-lg font-bold">
{t('title')}
@ -152,7 +152,7 @@ export function ContactFormCard() {
<FormError message={error} />
</CardContent>
<CardFooter className="px-6 py-4 flex justify-between items-center bg-muted rounded-none">
<CardFooter className="mt-6 px-6 py-4 flex justify-between items-center bg-muted rounded-none">
<Button type="submit" disabled={isSubmitting}>
{isSubmitting ? t('submitting') : t('submit')}
</Button>

View File

@ -9,7 +9,7 @@ import {
} from "react";
const COOKIE_NAME = "active_theme";
const DEFAULT_THEME = "default";
const DEFAULT_THEME = "blue";
function setThemeCookie(theme: string) {
if (typeof window === "undefined") return;

View File

@ -95,9 +95,9 @@ export function NavbarMobile({
justify-center rounded-md border"
>
{open ? (
<XIcon className="size-8" />
<XIcon className="size-4" />
) : (
<MenuIcon className="size-8" />
<MenuIcon className="size-4" />
)}
</Button>
</div>
@ -139,7 +139,7 @@ function MainMobileMenu({ userLoggedIn, onLinkClicked }: MainMobileMenuProps) {
<div className="size-full flex flex-col items-start space-y-4">
{/* action buttons */}
{userLoggedIn ? null : (
<div className="w-full flex flex-col gap-4">
<div className="w-full flex flex-col gap-4 px-4">
<LocaleLink
href={Routes.Login}
onClick={onLinkClicked}
@ -170,7 +170,7 @@ function MainMobileMenu({ userLoggedIn, onLinkClicked }: MainMobileMenuProps) {
)}
{/* main menu */}
<ul className="w-full">
<ul className="w-full px-4">
{menuLinks &&
menuLinks.map((item) => {
const isActive = item.href

View File

@ -32,7 +32,7 @@ interface NavBarProps {
const customNavigationMenuTriggerStyle = cn(
navigationMenuTriggerStyle(),
'relative bg-transparent text-muted-foreground',
'relative bg-transparent text-muted-foreground cursor-pointer',
'hover:bg-transparent hover:text-foreground focus:bg-transparent focus:text-foreground',
'data-active:font-semibold data-active:bg-transparent data-active:text-foreground',
'data-[state=open]:bg-transparent data-[state=open]:text-foreground'
@ -213,7 +213,7 @@ export function Navbar({ scroll }: NavBarProps) {
) : (
<div className="flex items-center gap-x-4">
<LoginWrapper mode="modal" asChild>
<Button variant="outline" size="sm">
<Button variant="outline" size="sm" className="cursor-pointer">
{t('Common.login')}
</Button>
</LoginWrapper>

View File

@ -81,7 +81,7 @@ export function DeleteAccountCard({ className }: DeleteAccountCardProps) {
};
return (
<Card className={cn("w-full max-w-lg md:max-w-xl border-destructive/50 overflow-hidden", className)}>
<Card className={cn("w-full max-w-lg md:max-w-xl border-destructive/50 overflow-hidden pt-6 pb-0", className)}>
<CardHeader>
<CardTitle className="text-lg font-bold text-destructive">
{t('deleteAccount.title')}
@ -101,10 +101,11 @@ export function DeleteAccountCard({ className }: DeleteAccountCardProps) {
</div>
)}
</CardContent>
<CardFooter className="px-6 py-4 flex justify-end items-center bg-muted rounded-none">
<CardFooter className="mt-6 px-6 py-4 flex justify-end items-center bg-muted rounded-none">
<Button
variant="destructive"
onClick={() => setShowConfirmation(true)}
className="cursor-pointer"
>
{t('deleteAccount.button')}
</Button>
@ -125,6 +126,7 @@ export function DeleteAccountCard({ className }: DeleteAccountCardProps) {
<Button
variant="outline"
onClick={() => setShowConfirmation(false)}
className="cursor-pointer"
>
{t('cancel')}
</Button>
@ -132,6 +134,7 @@ export function DeleteAccountCard({ className }: DeleteAccountCardProps) {
variant="destructive"
onClick={handleDeleteAccount}
disabled={isDeleting}
className="cursor-pointer"
>
{isDeleting ? t('deleteAccount.deleting') : t('deleteAccount.confirm')}
</Button>

View File

@ -51,7 +51,7 @@ export function ResetPasswordCard({ className }: ResetPasswordCardProps) {
};
return (
<Card className={cn("w-full max-w-lg md:max-w-xl overflow-hidden", className)}>
<Card className={cn("w-full max-w-lg md:max-w-xl overflow-hidden pt-6 pb-0", className)}>
<CardHeader>
<CardTitle className="text-lg font-bold">
{t('setupPassword.title')}
@ -65,8 +65,8 @@ export function ResetPasswordCard({ className }: ResetPasswordCardProps) {
{t('setupPassword.info')}
</p>
</CardContent>
<CardFooter className="px-6 py-4 flex justify-end items-center bg-muted rounded-none">
<Button onClick={handleSetupPassword}>
<CardFooter className="mt-6 px-6 py-4 flex justify-end items-center bg-muted rounded-none">
<Button onClick={handleSetupPassword} className="cursor-pointer">
{t('setupPassword.button')}
</Button>
</CardFooter>

View File

@ -128,7 +128,7 @@ export function UpdateAvatarCard({ className }: UpdateAvatarCardProps) {
};
return (
<Card className={cn("w-full max-w-lg md:max-w-xl overflow-hidden", className)}>
<Card className={cn("w-full max-w-lg md:max-w-xl overflow-hidden pt-6 pb-0", className)}>
<CardHeader>
<CardTitle className="text-lg font-bold">
{t('avatar.title')}
@ -153,6 +153,7 @@ export function UpdateAvatarCard({ className }: UpdateAvatarCardProps) {
size="sm"
onClick={handleUploadClick}
disabled={isUploading}
className="cursor-pointer"
>
{isUploading ? t('avatar.uploading') : t('avatar.uploadAvatar')}
</Button>
@ -160,7 +161,7 @@ export function UpdateAvatarCard({ className }: UpdateAvatarCardProps) {
<FormError message={error} />
</CardContent>
<CardFooter className="px-6 py-4 flex justify-between items-center bg-muted rounded-none">
<CardFooter className="mt-6 px-6 py-4 flex justify-between items-center bg-muted rounded-none">
<p className="text-sm text-muted-foreground">
{t('avatar.recommendation')}
</p>

View File

@ -107,7 +107,7 @@ export function UpdateNameCard({ className }: UpdateNameCardProps) {
};
return (
<Card className={cn("w-full max-w-lg md:max-w-xl overflow-hidden", className)}>
<Card className={cn("w-full max-w-lg md:max-w-xl overflow-hidden pt-6 pb-0", className)}>
<CardHeader>
<CardTitle className="text-lg font-bold">
{t('name.title')}
@ -136,12 +136,12 @@ export function UpdateNameCard({ className }: UpdateNameCardProps) {
/>
<FormError message={error} />
</CardContent>
<CardFooter className="px-6 py-4 flex justify-between items-center bg-muted rounded-none">
<CardFooter className="mt-6 px-6 py-4 flex justify-between items-center bg-muted rounded-none">
<p className="text-sm text-muted-foreground">
{t('name.hint')}
</p>
<Button type="submit" disabled={isSaving}>
<Button type="submit" disabled={isSaving} className="cursor-pointer">
{isSaving ? t('saving') : t('save')}
</Button>
</CardFooter>

View File

@ -114,7 +114,7 @@ export function UpdatePasswordCard({ className }: UpdatePasswordCardProps) {
};
return (
<Card className={cn("w-full max-w-lg md:max-w-xl overflow-hidden", className)}>
<Card className={cn("w-full max-w-lg md:max-w-xl overflow-hidden pt-6 pb-0", className)}>
<CardHeader>
<CardTitle className="text-lg font-bold">
{t('password.title')}
@ -180,13 +180,13 @@ export function UpdatePasswordCard({ className }: UpdatePasswordCardProps) {
type="button"
variant="ghost"
size="sm"
className="absolute right-0 top-0 h-full px-3 py-2 hover:bg-transparent"
className="cursor-pointer absolute right-0 top-0 h-full px-3 py-2 hover:bg-transparent"
onClick={() => setShowNewPassword(!showNewPassword)}
>
{showNewPassword ? (
<EyeOffIcon className="h-4 w-4" />
<EyeOffIcon className="size-4" />
) : (
<EyeIcon className="h-4 w-4" />
<EyeIcon className="size-4" />
)}
<span className="sr-only">
{showNewPassword ? t('password.hidePassword') : t('password.showPassword')}
@ -200,12 +200,12 @@ export function UpdatePasswordCard({ className }: UpdatePasswordCardProps) {
/>
<FormError message={error} />
</CardContent>
<CardFooter className="px-6 py-4 flex justify-between items-center bg-muted rounded-none">
<CardFooter className="mt-6 px-6 py-4 flex justify-between items-center bg-muted rounded-none">
<p className="text-sm text-muted-foreground">
{t('password.hint')}
</p>
<Button type="submit" disabled={isSaving}>
<Button type="submit" disabled={isSaving} className="cursor-pointer">
{isSaving ? t('saving') : t('save')}
</Button>
</CardFooter>

View File

@ -158,7 +158,7 @@ export function NewsletterFormCard({ className }: NewsletterFormCardProps) {
};
return (
<Card className={cn("w-full max-w-lg md:max-w-xl overflow-hidden", className)}>
<Card className={cn("w-full max-w-lg md:max-w-xl overflow-hidden pt-6 pb-0", className)}>
<CardHeader>
<CardTitle className="text-lg font-bold">
{t('newsletter.title')}
@ -189,6 +189,7 @@ export function NewsletterFormCard({ className }: NewsletterFormCardProps) {
}}
disabled={isUpdating}
aria-readonly={isUpdating}
className="cursor-pointer"
/>
</FormControl>
</FormItem>
@ -196,7 +197,7 @@ export function NewsletterFormCard({ className }: NewsletterFormCardProps) {
/>
<FormError message={error} />
</CardContent>
<CardFooter className="px-6 py-4 bg-muted rounded-none">
<CardFooter className="mt-6 px-6 py-4 bg-muted rounded-none">
<p className="text-sm text-muted-foreground">
{t('newsletter.hint')}
</p>

View File

@ -30,7 +30,7 @@ export default function BackButtonSmall({
>
{/* if href is provided, use it, otherwise use the router.back() */}
<Link href={href || '#'} onClick={handleBack}>
<ArrowLeftIcon className="size-5" />
<ArrowLeftIcon className="size-4" />
</Link>
</Button>
);

View File

@ -185,7 +185,7 @@ const components = {
code: ({ className, ...props }: React.HTMLAttributes<HTMLElement>) => (
<code
className={cn(
'relative rounded px-[0.3rem] py-[0.2rem] font-mono text-sm',
'text-foreground font-medium relative rounded px-[0.3rem] py-[0.2rem] font-mono text-sm',
className
)}
{...props}

View File

@ -78,7 +78,7 @@ export function WaitlistFormCard() {
};
return (
<Card className="mx-auto max-w-lg overflow-hidden">
<Card className="mx-auto max-w-lg overflow-hidden pt-6 pb-0">
<CardHeader>
<CardTitle className="text-lg font-bold">
{t('title')}
@ -110,7 +110,7 @@ export function WaitlistFormCard() {
<FormError message={error} />
</CardContent>
<CardFooter className="px-6 py-4 flex justify-between items-center bg-muted rounded-none">
<CardFooter className="mt-6 px-6 py-4 flex justify-between items-center bg-muted rounded-none">
<Button type="submit" disabled={isSubmitting}>
{isSubmitting ? t('subscribing') : t('subscribe')}
</Button>

View File

@ -160,103 +160,6 @@
--sidebar-ring: oklch(0.553 0.013 58.071);
}
/* @theme {
--color-background: hsl(var(--background));
--color-foreground: hsl(var(--foreground));
--color-card: hsl(var(--card));
--color-card-foreground: hsl(var(--card-foreground));
--color-popover: hsl(var(--popover));
--color-popover-foreground: hsl(var(--popover-foreground));
--color-primary: hsl(var(--primary));
--color-primary-foreground: hsl(var(--primary-foreground));
--color-secondary: hsl(var(--secondary));
--color-secondary-foreground: hsl(var(--secondary-foreground));
--color-muted: hsl(var(--muted));
--color-muted-foreground: hsl(var(--muted-foreground));
--color-accent: hsl(var(--accent));
--color-accent-foreground: hsl(var(--accent-foreground));
--color-destructive: hsl(var(--destructive));
--color-destructive-foreground: hsl(var(--destructive-foreground));
--color-border: hsl(var(--border));
--color-input: hsl(var(--input));
--color-ring: hsl(var(--ring));
--color-chart-1: hsl(var(--chart-1));
--color-chart-2: hsl(var(--chart-2));
--color-chart-3: hsl(var(--chart-3));
--color-chart-4: hsl(var(--chart-4));
--color-chart-5: hsl(var(--chart-5));
--color-sidebar: hsl(var(--sidebar-background));
--color-sidebar-foreground: hsl(var(--sidebar-foreground));
--color-sidebar-primary: hsl(var(--sidebar-primary));
--color-sidebar-primary-foreground: hsl(var(--sidebar-primary-foreground));
--color-sidebar-accent: hsl(var(--sidebar-accent));
--color-sidebar-accent-foreground: hsl(var(--sidebar-accent-foreground));
--color-sidebar-border: hsl(var(--sidebar-border));
--color-sidebar-ring: hsl(var(--sidebar-ring));
--color-color-1: hsl(var(--color-1));
--color-color-2: hsl(var(--color-2));
--color-color-3: hsl(var(--color-3));
--color-color-4: hsl(var(--color-4));
--color-color-5: hsl(var(--color-5));
--radius-lg: var(--radius);
--radius-md: calc(var(--radius) - 2px);
--radius-sm: calc(var(--radius) - 4px);
--animate-shiny-text: shiny-text 8s infinite;
--animate-rainbow: rainbow var(--speed, 2s) infinite linear;
--animate-accordion-down: accordion-down 0.2s ease-out;
--animate-accordion-up: accordion-up 0.2s ease-out;
@keyframes shiny-text {
0%,
90%,
100% {
background-position: calc(-100% - var(--shiny-width)) 0;
}
30%,
60% {
background-position: calc(100% + var(--shiny-width)) 0;
}
}
@keyframes rainbow {
0% {
background-position: 0%;
}
100% {
background-position: 200%;
}
}
@keyframes accordion-down {
from {
height: 0;
}
to {
height: var(--radix-accordion-content-height);
}
}
@keyframes accordion-up {
from {
height: var(--radix-accordion-content-height);
}
to {
height: 0;
}
}
} */
/*
The default border color has changed to `currentColor` in Tailwind CSS v4,
so we've added these compatibility styles to make sure everything still