Redesign frontend UI with premium SaaS styling and app icon
- Restyle design system: refined color palette, 16px base font, antialiased text rendering, improved typography hierarchy across all pages - Update base components (button, input, card, checkbox, dialog, sidebar) with modern rounded corners, subtle shadows, and smooth transitions - Redesign layout: remove header bar, move controls to sidebar footer, add two-column todo dashboard with stats and upcoming reminders - Replace hardcoded slate colors with design token system throughout - Add app icon (favicon, apple-icon, sidebar logo) from notify_icon.png - Improve typography: page titles 20px, section titles 18px, sidebar nav 14px, stats 24px semibold, body text with proper line-height Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -2,38 +2,18 @@
|
||||
|
||||
import type { ReactNode } from "react";
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { SidebarInset, SidebarProvider } from "@/components/ui/sidebar";
|
||||
import AppSidebar from "@/components/AppSidebar";
|
||||
import LanguageSwitcher from "@/components/LanguageSwitcher";
|
||||
import { clearToken } from "@/lib/auth";
|
||||
import { useTranslation } from "@/lib/i18n";
|
||||
import { NotificationProvider } from "@/lib/notification-context";
|
||||
import { UserProvider } from "@/lib/user-context";
|
||||
|
||||
const AppShellContent = ({ children }: { children: ReactNode }) => {
|
||||
const t = useTranslation();
|
||||
|
||||
return (
|
||||
<SidebarProvider defaultOpen>
|
||||
<div className="flex min-h-screen bg-slate-100 p-6">
|
||||
<div className="flex min-h-screen bg-muted/50 p-6">
|
||||
<AppSidebar />
|
||||
<SidebarInset>
|
||||
<div className="mx-auto flex w-full max-w-6xl flex-col gap-6 px-6">
|
||||
<div className="rounded-xl bg-white p-4 shadow-sm">
|
||||
<div className="flex flex-wrap items-center justify-between gap-4">
|
||||
<div>
|
||||
<h1 className="text-xl font-semibold leading-tight text-slate-900">Notify</h1>
|
||||
<p className="text-sm text-slate-500">{t("appDesc")}</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<LanguageSwitcher />
|
||||
<Button variant="outline" onClick={() => clearToken()}>
|
||||
{t("logout")}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full max-w-[1200px] py-6 px-6">
|
||||
<div className="grid gap-5">{children}</div>
|
||||
</div>
|
||||
</SidebarInset>
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
"use client";
|
||||
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { usePathname } from "next/navigation";
|
||||
import { Bell, BellDot, ListTodo, Settings, UserPlus } from "lucide-react";
|
||||
import { Bell, BellDot, ListTodo, LogOut, Settings, UserPlus } from "lucide-react";
|
||||
|
||||
import {
|
||||
Sidebar,
|
||||
@@ -10,7 +11,6 @@ import {
|
||||
SidebarFooter,
|
||||
SidebarGroup,
|
||||
SidebarGroupContent,
|
||||
SidebarGroupLabel,
|
||||
SidebarHeader,
|
||||
SidebarMenu,
|
||||
SidebarMenuButton,
|
||||
@@ -18,9 +18,11 @@ import {
|
||||
SidebarSeparator,
|
||||
} from "@/components/ui/sidebar";
|
||||
import Avatar from "@/components/ui/avatar";
|
||||
import LanguageSwitcher from "@/components/LanguageSwitcher";
|
||||
import { useTranslation, type TranslationKey } from "@/lib/i18n";
|
||||
import { useNotification } from "@/lib/notification-context";
|
||||
import { useUser } from "@/lib/user-context";
|
||||
import { clearToken } from "@/lib/auth";
|
||||
|
||||
const navItems: { href: string; labelKey: TranslationKey; icon: typeof ListTodo }[] = [
|
||||
{ href: "/todos", labelKey: "navTodo", icon: ListTodo },
|
||||
@@ -40,19 +42,14 @@ const AppSidebar = () => {
|
||||
<Sidebar variant="inset" className="h-[calc(100vh-3rem)] self-start bg-white">
|
||||
<SidebarHeader className="gap-2 px-3 py-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="flex h-8 w-8 items-center justify-center rounded-full bg-blue-500/10 text-blue-600">
|
||||
<span className="text-base font-semibold">◎</span>
|
||||
</span>
|
||||
<span className="text-base font-semibold group-data-[state=collapsed]/sidebar:hidden">
|
||||
<Image src="/notify_icon.png" alt="Notify" width={28} height={28} className="h-7 w-7 rounded-lg" />
|
||||
<span className="text-[15px] font-semibold tracking-tight text-foreground group-data-[state=collapsed]/sidebar:hidden">
|
||||
notify
|
||||
</span>
|
||||
</div>
|
||||
</SidebarHeader>
|
||||
<SidebarContent>
|
||||
<SidebarGroup>
|
||||
<SidebarGroupLabel className="group-data-[state=collapsed]/sidebar:hidden">
|
||||
{t("navigation")}
|
||||
</SidebarGroupLabel>
|
||||
<SidebarGroupContent>
|
||||
<SidebarMenu>
|
||||
{navItems.map((item) => {
|
||||
@@ -67,7 +64,7 @@ const AppSidebar = () => {
|
||||
>
|
||||
<Link href={item.href}>
|
||||
<span className="relative">
|
||||
<item.icon className="h-4 w-4" />
|
||||
<item.icon className={`h-[18px] w-[18px] ${isActive ? "text-sidebar-primary" : "text-muted-foreground"}`} />
|
||||
{isNotifications && unreadCount > 0 && (
|
||||
<span className="absolute -right-1 -top-1 hidden h-2 w-2 rounded-full bg-red-500 group-data-[state=collapsed]/sidebar:inline-flex" />
|
||||
)}
|
||||
@@ -90,12 +87,25 @@ const AppSidebar = () => {
|
||||
</SidebarGroup>
|
||||
</SidebarContent>
|
||||
<SidebarSeparator />
|
||||
<SidebarFooter className="px-3 py-4">
|
||||
<div className="flex items-center gap-2 group-data-[state=collapsed]/sidebar:justify-center">
|
||||
<Avatar username={user?.username} src={user?.avatar} size="sm" />
|
||||
<span className="text-sm font-medium text-slate-700 group-data-[state=collapsed]/sidebar:hidden">
|
||||
{user?.username}
|
||||
</span>
|
||||
<SidebarFooter className="px-3 py-3">
|
||||
<div className="flex items-center justify-between group-data-[state=collapsed]/sidebar:justify-center">
|
||||
<div className="flex items-center gap-2 min-w-0">
|
||||
<Avatar username={user?.username} src={user?.avatar} size="sm" />
|
||||
<span className="truncate text-sm font-medium text-foreground/80 group-data-[state=collapsed]/sidebar:hidden">
|
||||
{user?.username}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-1 group-data-[state=collapsed]/sidebar:hidden">
|
||||
<LanguageSwitcher />
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => clearToken()}
|
||||
className="inline-flex h-8 w-8 items-center justify-center rounded-lg text-muted-foreground transition-colors hover:bg-muted hover:text-foreground"
|
||||
title={t("logout")}
|
||||
>
|
||||
<LogOut className="h-4 w-4" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</SidebarFooter>
|
||||
</Sidebar>
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
import { useState } from "react";
|
||||
import { Globe } from "lucide-react";
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
@@ -17,28 +16,28 @@ const languages: { value: Locale; label: string }[] = [
|
||||
];
|
||||
|
||||
const LanguageSwitcher = () => {
|
||||
const { locale, setLocale, t } = useI18n();
|
||||
const { locale, setLocale } = useI18n();
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<Popover open={open} onOpenChange={setOpen}>
|
||||
<PopoverTrigger asChild>
|
||||
<Button variant="outline" size="sm" className="gap-2">
|
||||
<button
|
||||
type="button"
|
||||
className="inline-flex h-8 w-8 items-center justify-center rounded-lg text-muted-foreground transition-colors hover:bg-muted hover:text-foreground"
|
||||
>
|
||||
<Globe className="h-4 w-4" />
|
||||
<span className="hidden sm:inline">
|
||||
{languages.find((l) => l.value === locale)?.label}
|
||||
</span>
|
||||
</Button>
|
||||
</button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-32 p-1" align="end">
|
||||
<div className="flex flex-col gap-1">
|
||||
<div className="flex flex-col gap-0.5">
|
||||
{languages.map((lang) => (
|
||||
<button
|
||||
key={lang.value}
|
||||
className={`w-full rounded-md px-3 py-2 text-left text-sm transition-colors hover:bg-slate-100 ${
|
||||
className={`w-full rounded-lg px-3 py-2 text-left text-sm transition-colors hover:bg-muted ${
|
||||
locale === lang.value
|
||||
? "bg-slate-100 font-medium text-slate-900"
|
||||
: "text-slate-600"
|
||||
? "bg-muted font-medium text-foreground"
|
||||
: "text-muted-foreground"
|
||||
}`}
|
||||
onClick={() => {
|
||||
setLocale(lang.value);
|
||||
|
||||
@@ -138,9 +138,9 @@ const SettingsPanel = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<Card className="bg-white">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>{t("settings")}</CardTitle>
|
||||
<CardTitle className="text-xl">{t("settings")}</CardTitle>
|
||||
<CardDescription>{t("settingsDesc")}</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
@@ -176,7 +176,7 @@ const SettingsPanel = () => {
|
||||
{t("removeAvatar")}
|
||||
</Button>
|
||||
)}
|
||||
<p className="text-xs text-slate-500">{t("avatarHint")}</p>
|
||||
<p className="text-xs text-muted-foreground">{t("avatarHint")}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -201,11 +201,11 @@ const SettingsPanel = () => {
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label>{t("notificationChannels")}</Label>
|
||||
<div className="rounded-lg bg-slate-50/80">
|
||||
<div className="rounded-xl bg-muted/50 border border-border/60">
|
||||
<div className="flex items-center justify-between px-4 py-3">
|
||||
<div>
|
||||
<div className="text-sm font-medium text-slate-800">{t("webNotifications")}</div>
|
||||
<div className="text-xs text-slate-500">{t("webNotificationsDesc")}</div>
|
||||
<div className="text-sm font-medium text-foreground">{t("webNotifications")}</div>
|
||||
<div className="text-xs leading-relaxed text-muted-foreground">{t("webNotificationsDesc")}</div>
|
||||
</div>
|
||||
<Checkbox
|
||||
id="inapp"
|
||||
@@ -215,11 +215,11 @@ const SettingsPanel = () => {
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div className="mx-4 h-px bg-slate-200/50" />
|
||||
<div className="mx-4 h-px bg-border/60" />
|
||||
<div className="flex items-center justify-between px-4 py-3">
|
||||
<div>
|
||||
<div className="text-sm font-medium text-slate-800">{t("barkAlerts")}</div>
|
||||
<div className="text-xs text-slate-500">{t("barkAlertsDesc")}</div>
|
||||
<div className="text-sm font-medium text-foreground">{t("barkAlerts")}</div>
|
||||
<div className="text-xs leading-relaxed text-muted-foreground">{t("barkAlertsDesc")}</div>
|
||||
</div>
|
||||
<Checkbox
|
||||
id="bark"
|
||||
@@ -242,8 +242,8 @@ const SettingsPanel = () => {
|
||||
</div>
|
||||
|
||||
{/* Change Password Section */}
|
||||
<div className="mt-8 pt-6 border-t border-slate-200">
|
||||
<h3 className="text-lg font-medium mb-4">{t("changePassword")}</h3>
|
||||
<div className="mt-8 pt-6 border-t border-border">
|
||||
<h3 className="text-lg font-semibold tracking-tight mb-4">{t("changePassword")}</h3>
|
||||
<div className="space-y-4">
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="currentPassword">{t("currentPassword")}</Label>
|
||||
|
||||
@@ -18,7 +18,7 @@ const AlertDialogOverlay = React.forwardRef<
|
||||
>(({ className, ...props }, ref) => (
|
||||
<AlertDialogPrimitive.Overlay
|
||||
className={cn(
|
||||
"fixed inset-0 z-50 bg-black/50 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
||||
"fixed inset-0 z-50 bg-black/40 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
@@ -36,7 +36,7 @@ const AlertDialogContent = React.forwardRef<
|
||||
<AlertDialogPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 bg-white p-6 shadow-xl duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-xl",
|
||||
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 bg-card p-6 shadow-2xl duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] rounded-2xl",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
@@ -64,7 +64,7 @@ const AlertDialogTitle = React.forwardRef<
|
||||
>(({ className, ...props }, ref) => (
|
||||
<AlertDialogPrimitive.Title
|
||||
ref={ref}
|
||||
className={cn("text-lg font-semibold text-slate-900", className)}
|
||||
className={cn("text-lg font-semibold text-foreground", className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
@@ -76,7 +76,7 @@ const AlertDialogDescription = React.forwardRef<
|
||||
>(({ className, ...props }, ref) => (
|
||||
<AlertDialogPrimitive.Description
|
||||
ref={ref}
|
||||
className={cn("text-sm text-slate-500", className)}
|
||||
className={cn("text-sm text-muted-foreground", className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
|
||||
@@ -5,16 +5,16 @@ import { cva, type VariantProps } from "class-variance-authority"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const buttonVariants = cva(
|
||||
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
||||
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-lg text-sm font-medium transition-all duration-150 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/20 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default:
|
||||
"bg-primary text-primary-foreground shadow hover:bg-primary/90",
|
||||
"bg-primary text-primary-foreground shadow-sm hover:bg-primary/90 hover:shadow-md",
|
||||
destructive:
|
||||
"bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
|
||||
outline:
|
||||
"border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
|
||||
"border border-border/80 bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
|
||||
secondary:
|
||||
"bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
|
||||
ghost: "hover:bg-accent hover:text-accent-foreground",
|
||||
@@ -22,8 +22,8 @@ const buttonVariants = cva(
|
||||
},
|
||||
size: {
|
||||
default: "h-9 px-4 py-2",
|
||||
sm: "h-8 rounded-md px-3 text-xs",
|
||||
lg: "h-10 rounded-md px-8",
|
||||
sm: "h-8 rounded-lg px-3 text-xs",
|
||||
lg: "h-10 rounded-lg px-8",
|
||||
icon: "h-9 w-9",
|
||||
},
|
||||
},
|
||||
|
||||
@@ -6,7 +6,7 @@ const Card = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElemen
|
||||
({ className, ...props }, ref) => (
|
||||
<div
|
||||
ref={ref}
|
||||
className={cn("rounded-xl bg-card text-card-foreground shadow-sm", className)}
|
||||
className={cn("rounded-2xl border border-border/60 bg-card text-card-foreground shadow-[0_1px_3px_0_rgb(0_0_0/0.04)]", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
@@ -15,14 +15,14 @@ Card.displayName = "Card";
|
||||
|
||||
const CardHeader = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
|
||||
({ className, ...props }, ref) => (
|
||||
<div ref={ref} className={cn("flex flex-col space-y-1.5 p-6", className)} {...props} />
|
||||
<div ref={ref} className={cn("flex flex-col space-y-1.5 p-6 pb-4", className)} {...props} />
|
||||
)
|
||||
);
|
||||
CardHeader.displayName = "CardHeader";
|
||||
|
||||
const CardTitle = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLHeadingElement>>(
|
||||
({ className, ...props }, ref) => (
|
||||
<h3 ref={ref} className={cn("text-lg font-semibold leading-none tracking-tight", className)} {...props} />
|
||||
<h3 ref={ref} className={cn("text-lg font-semibold leading-snug tracking-tight text-foreground", className)} {...props} />
|
||||
)
|
||||
);
|
||||
CardTitle.displayName = "CardTitle";
|
||||
@@ -31,7 +31,7 @@ const CardDescription = React.forwardRef<
|
||||
HTMLParagraphElement,
|
||||
React.HTMLAttributes<HTMLParagraphElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<p ref={ref} className={cn("text-sm text-muted-foreground", className)} {...props} />
|
||||
<p ref={ref} className={cn("mt-1 text-sm text-muted-foreground", className)} {...props} />
|
||||
));
|
||||
CardDescription.displayName = "CardDescription";
|
||||
|
||||
|
||||
@@ -11,13 +11,13 @@ const Checkbox = React.forwardRef<
|
||||
<CheckboxPrimitive.Root
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
|
||||
"peer h-[18px] w-[18px] shrink-0 rounded-[5px] border border-border transition-colors duration-150 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/20 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:border-primary data-[state=checked]:text-primary-foreground",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<CheckboxPrimitive.Indicator className={cn("flex items-center justify-center text-current")}>
|
||||
<Check className="h-3.5 w-3.5" />
|
||||
<Check className="h-3.5 w-3.5" strokeWidth={3} />
|
||||
</CheckboxPrimitive.Indicator>
|
||||
</CheckboxPrimitive.Root>
|
||||
));
|
||||
|
||||
@@ -21,7 +21,7 @@ const DialogOverlay = React.forwardRef<
|
||||
<DialogPrimitive.Overlay
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"fixed inset-0 z-50 bg-black/50 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
||||
"fixed inset-0 z-50 bg-black/40 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
@@ -38,13 +38,13 @@ const DialogContent = React.forwardRef<
|
||||
<DialogPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 bg-white p-6 shadow-xl duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-xl",
|
||||
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 bg-card p-6 shadow-2xl duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] rounded-2xl",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-white transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-slate-950 focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-slate-100 data-[state=open]:text-slate-500">
|
||||
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-md opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-primary/20 focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-muted data-[state=open]:text-muted-foreground">
|
||||
<X className="h-4 w-4" />
|
||||
<span className="sr-only">Close</span>
|
||||
</DialogPrimitive.Close>
|
||||
@@ -72,7 +72,7 @@ const DialogTitle = React.forwardRef<
|
||||
>(({ className, ...props }, ref) => (
|
||||
<DialogPrimitive.Title
|
||||
ref={ref}
|
||||
className={cn("text-lg font-semibold leading-none tracking-tight text-slate-900", className)}
|
||||
className={cn("text-lg font-semibold leading-none tracking-tight text-foreground", className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
@@ -84,7 +84,7 @@ const DialogDescription = React.forwardRef<
|
||||
>(({ className, ...props }, ref) => (
|
||||
<DialogPrimitive.Description
|
||||
ref={ref}
|
||||
className={cn("text-sm text-slate-500", className)}
|
||||
className={cn("text-sm text-muted-foreground", className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
|
||||
@@ -8,7 +8,7 @@ const Input = React.forwardRef<HTMLInputElement, React.InputHTMLAttributes<HTMLI
|
||||
<input
|
||||
type={type}
|
||||
className={cn(
|
||||
"flex h-10 w-full rounded-lg border border-input/60 bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/30 disabled:cursor-not-allowed disabled:opacity-50",
|
||||
"flex h-10 w-full rounded-xl border border-border bg-background px-3 py-2 text-sm transition-colors duration-150 ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground hover:border-primary/40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/20 focus-visible:border-primary/60 disabled:cursor-not-allowed disabled:opacity-50",
|
||||
className
|
||||
)}
|
||||
ref={ref}
|
||||
|
||||
@@ -66,7 +66,7 @@ const Sidebar = React.forwardRef<
|
||||
data-state={open ? "expanded" : "collapsed"}
|
||||
style={
|
||||
{
|
||||
"--sidebar-width": "16rem",
|
||||
"--sidebar-width": "14rem",
|
||||
"--sidebar-width-collapsed": "4.25rem",
|
||||
...style,
|
||||
} as React.CSSProperties
|
||||
@@ -116,7 +116,7 @@ const SidebarGroupLabel = React.forwardRef<HTMLDivElement, React.HTMLAttributes<
|
||||
({ className, ...props }, ref) => (
|
||||
<div
|
||||
ref={ref}
|
||||
className={cn("px-2 text-xs font-medium uppercase text-sidebar-foreground/60", className)}
|
||||
className={cn("px-2 text-[11px] font-semibold uppercase tracking-wider text-sidebar-foreground/50", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
@@ -145,12 +145,12 @@ const SidebarMenuItem = React.forwardRef<HTMLLIElement, React.HTMLAttributes<HTM
|
||||
SidebarMenuItem.displayName = "SidebarMenuItem";
|
||||
|
||||
const sidebarMenuButtonVariants = cva(
|
||||
"flex w-full items-center gap-2 rounded-lg px-3 py-2 text-sm font-medium text-sidebar-foreground transition-colors hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
|
||||
"flex w-full items-center gap-2 rounded-lg px-3 py-2 text-[14px] font-medium text-sidebar-foreground/80 transition-all duration-150 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
|
||||
{
|
||||
variants: {
|
||||
isActive: {
|
||||
true: "bg-sidebar-accent text-sidebar-primary font-semibold",
|
||||
false: "",
|
||||
true: "border-l-2 border-sidebar-primary bg-sidebar-primary/[0.06] text-sidebar-primary font-semibold",
|
||||
false: "border-l-2 border-transparent",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
@@ -177,7 +177,7 @@ SidebarMenuButton.displayName = "SidebarMenuButton";
|
||||
|
||||
const SidebarSeparator = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
|
||||
({ className, ...props }, ref) => (
|
||||
<div ref={ref} className={cn("mx-3 my-2 h-px bg-sidebar-border/50", className)} {...props} />
|
||||
<div ref={ref} className={cn("mx-3 my-2 h-px bg-sidebar-border/40", className)} {...props} />
|
||||
)
|
||||
);
|
||||
SidebarSeparator.displayName = "SidebarSeparator";
|
||||
|
||||
Reference in New Issue
Block a user