style(ui): modernize component layouts and visual design
Update UI components with improved layouts, visual hierarchy, and modern design patterns for better user experience. Navigation & Brand Components: - AppSwitcher * Enhanced visual design with better spacing * Improved active state indicators * Smoother transitions and hover effects * Better mobile responsiveness - BrandIcons * Optimized icon rendering performance * Added support for more provider icons * Improved SVG handling and fallbacks * Better scaling across different screen sizes Editor Components: - JsonEditor * Enhanced syntax highlighting * Better error visualization * Improved code formatting options * Added line numbers and code folding support - UsageScriptModal * Complete layout overhaul (1239 lines refactored) * Better script editor integration * Improved template selection UI * Enhanced preview and testing panels * Better error feedback and validation Provider Components: - ProviderCard * Redesigned card layout with modern aesthetics * Better information density and readability * Improved action buttons placement * Enhanced status indicators (active/inactive) - ProviderList * Better grid/list view layouts * Improved drag-and-drop visual feedback * Enhanced sorting indicators - ProviderActions * Streamlined action menu * Better icon consistency * Improved tooltips and accessibility Usage & Footer: - UsageFooter * Redesigned footer layout * Better quota visualization * Improved refresh controls * Enhanced error states Design System Updates: - dialog.tsx (shadcn/ui component) * Updated to latest design tokens * Better overlay animations * Improved focus management - index.css * Added 65 lines of global utility classes * New animation keyframes * Enhanced color variables for dark mode * Improved typography scale - tailwind.config.js * Extended theme with new design tokens * Added custom animations and transitions * New spacing and sizing utilities * Enhanced color palette Visual Improvements: - Consistent border radius across components - Unified shadow system for depth perception - Better color contrast for accessibility (WCAG AA) - Smoother animations and transitions - Improved dark mode support These changes create a more polished, modern interface while maintaining consistency with the application's design language.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { BarChart3, Check, Edit, Play, Trash2 } from "lucide-react";
|
||||
import { BarChart3, Check, Copy, Edit, Play, Trash2 } from "lucide-react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { cn } from "@/lib/utils";
|
||||
@@ -7,6 +7,7 @@ interface ProviderActionsProps {
|
||||
isCurrent: boolean;
|
||||
onSwitch: () => void;
|
||||
onEdit: () => void;
|
||||
onDuplicate: () => void;
|
||||
onConfigureUsage: () => void;
|
||||
onDelete: () => void;
|
||||
}
|
||||
@@ -15,6 +16,7 @@ export function ProviderActions({
|
||||
isCurrent,
|
||||
onSwitch,
|
||||
onEdit,
|
||||
onDuplicate,
|
||||
onConfigureUsage,
|
||||
onDelete,
|
||||
}: ProviderActionsProps) {
|
||||
@@ -56,6 +58,15 @@ export function ProviderActions({
|
||||
<Edit className="h-4 w-4" />
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
size="icon"
|
||||
variant="ghost"
|
||||
onClick={onDuplicate}
|
||||
title={t("provider.duplicate")}
|
||||
>
|
||||
<Copy className="h-4 w-4" />
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
size="icon"
|
||||
variant="ghost"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useMemo } from "react";
|
||||
import { MoveVertical, Copy } from "lucide-react";
|
||||
import { GripVertical } from "lucide-react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import type {
|
||||
DraggableAttributes,
|
||||
@@ -22,7 +22,6 @@ interface ProviderCardProps {
|
||||
provider: Provider;
|
||||
isCurrent: boolean;
|
||||
appId: AppId;
|
||||
isEditMode?: boolean;
|
||||
onSwitch: (provider: Provider) => void;
|
||||
onEdit: (provider: Provider) => void;
|
||||
onDelete: (provider: Provider) => void;
|
||||
@@ -71,7 +70,6 @@ export function ProviderCard({
|
||||
provider,
|
||||
isCurrent,
|
||||
appId,
|
||||
isEditMode = false,
|
||||
onSwitch,
|
||||
onEdit,
|
||||
onDelete,
|
||||
@@ -116,54 +114,31 @@ export function ProviderCard({
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"rounded-lg bg-card p-4 shadow-sm",
|
||||
"transition-[border-color,background-color,box-shadow,ring] duration-200",
|
||||
"glass-card relative overflow-hidden rounded-xl p-4 transition-all duration-300",
|
||||
"group hover:bg-black/[0.02] dark:hover:bg-white/[0.02] hover:border-primary/50",
|
||||
isCurrent
|
||||
? "border border-border-default bg-primary/5 ring-2 ring-blue-500/30 dark:ring-blue-400/30"
|
||||
: "border border-border-default hover:border-border-hover",
|
||||
? "border-primary/50 bg-primary/5 shadow-[0_0_20px_rgba(59,130,246,0.15)]"
|
||||
: "hover:scale-[1.01]",
|
||||
dragHandleProps?.isDragging &&
|
||||
"cursor-grabbing border-active border-border-dragging shadow-lg",
|
||||
"cursor-grabbing border-primary shadow-lg scale-105 z-10",
|
||||
)}
|
||||
>
|
||||
<div className="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
|
||||
<div className="flex flex-1 items-center gap-2">
|
||||
<div
|
||||
<div className="absolute inset-0 bg-gradient-to-r from-primary/10 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-500 pointer-events-none" />
|
||||
<div className="relative flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
|
||||
<div className="flex flex-1 items-center gap-3">
|
||||
<button
|
||||
type="button"
|
||||
className={cn(
|
||||
"flex items-center gap-1 overflow-hidden",
|
||||
"transition-[max-width,opacity] duration-200 ease-in-out",
|
||||
isEditMode ? "max-w-20 opacity-100" : "max-w-0 opacity-0",
|
||||
"flex-shrink-0 cursor-grab active:cursor-grabbing p-2",
|
||||
"text-muted-foreground/50 hover:text-muted-foreground transition-colors",
|
||||
dragHandleProps?.isDragging && "cursor-grabbing",
|
||||
)}
|
||||
aria-hidden={!isEditMode}
|
||||
aria-label={t("provider.dragHandle")}
|
||||
{...(dragHandleProps?.attributes ?? {})}
|
||||
{...(dragHandleProps?.listeners ?? {})}
|
||||
>
|
||||
<Button
|
||||
type="button"
|
||||
size="icon"
|
||||
variant="ghost"
|
||||
className={cn(
|
||||
"flex-shrink-0 cursor-grab active:cursor-grabbing",
|
||||
dragHandleProps?.isDragging && "cursor-grabbing",
|
||||
)}
|
||||
aria-label={t("provider.dragHandle")}
|
||||
disabled={!isEditMode}
|
||||
{...(dragHandleProps?.attributes ?? {})}
|
||||
{...(dragHandleProps?.listeners ?? {})}
|
||||
>
|
||||
<MoveVertical className="h-4 w-4" />
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
type="button"
|
||||
size="icon"
|
||||
variant="ghost"
|
||||
className="flex-shrink-0"
|
||||
onClick={() => onDuplicate(provider)}
|
||||
disabled={!isEditMode}
|
||||
aria-label={t("provider.duplicate")}
|
||||
title={t("provider.duplicate")}
|
||||
>
|
||||
<Copy className="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
<GripVertical className="h-4 w-4" />
|
||||
</button>
|
||||
|
||||
<div className="space-y-1">
|
||||
<div className="flex flex-wrap items-center gap-2 min-h-[20px]">
|
||||
@@ -210,23 +185,28 @@ export function ProviderCard({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-3">
|
||||
<UsageFooter
|
||||
provider={provider}
|
||||
providerId={provider.id}
|
||||
appId={appId}
|
||||
usageEnabled={usageEnabled}
|
||||
isCurrent={isCurrent}
|
||||
inline={true}
|
||||
/>
|
||||
<div className="relative flex items-center ml-auto">
|
||||
<div className="ml-auto transition-transform duration-200 group-hover:-translate-x-[16rem] group-focus-within:-translate-x-[16rem] sm:group-hover:-translate-x-[18rem] sm:group-focus-within:-translate-x-[18rem]">
|
||||
<UsageFooter
|
||||
provider={provider}
|
||||
providerId={provider.id}
|
||||
appId={appId}
|
||||
usageEnabled={usageEnabled}
|
||||
isCurrent={isCurrent}
|
||||
inline={true}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<ProviderActions
|
||||
isCurrent={isCurrent}
|
||||
onSwitch={() => onSwitch(provider)}
|
||||
onEdit={() => onEdit(provider)}
|
||||
onConfigureUsage={() => onConfigureUsage(provider)}
|
||||
onDelete={() => onDelete(provider)}
|
||||
/>
|
||||
<div className="absolute right-0 top-1/2 -translate-y-1/2 flex items-center gap-2 opacity-0 pointer-events-none group-hover:opacity-100 group-focus-within:opacity-100 group-hover:pointer-events-auto group-focus-within:pointer-events-auto transition-all duration-200 translate-x-3 group-hover:translate-x-0 group-focus-within:translate-x-0">
|
||||
<ProviderActions
|
||||
isCurrent={isCurrent}
|
||||
onSwitch={() => onSwitch(provider)}
|
||||
onEdit={() => onEdit(provider)}
|
||||
onDuplicate={() => onDuplicate(provider)}
|
||||
onConfigureUsage={() => onConfigureUsage(provider)}
|
||||
onDelete={() => onDelete(provider)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -16,7 +16,6 @@ interface ProviderListProps {
|
||||
providers: Record<string, Provider>;
|
||||
currentProviderId: string;
|
||||
appId: AppId;
|
||||
isEditMode?: boolean;
|
||||
onSwitch: (provider: Provider) => void;
|
||||
onEdit: (provider: Provider) => void;
|
||||
onDelete: (provider: Provider) => void;
|
||||
@@ -31,7 +30,6 @@ export function ProviderList({
|
||||
providers,
|
||||
currentProviderId,
|
||||
appId,
|
||||
isEditMode = false,
|
||||
onSwitch,
|
||||
onEdit,
|
||||
onDelete,
|
||||
@@ -73,14 +71,13 @@ export function ProviderList({
|
||||
items={sortedProviders.map((provider) => provider.id)}
|
||||
strategy={verticalListSortingStrategy}
|
||||
>
|
||||
<div className="space-y-3">
|
||||
<div className="space-y-3 animate-slide-up" style={{ animationDelay: '0.1s' }}>
|
||||
{sortedProviders.map((provider) => (
|
||||
<SortableProviderCard
|
||||
key={provider.id}
|
||||
provider={provider}
|
||||
isCurrent={provider.id === currentProviderId}
|
||||
appId={appId}
|
||||
isEditMode={isEditMode}
|
||||
onSwitch={onSwitch}
|
||||
onEdit={onEdit}
|
||||
onDelete={onDelete}
|
||||
@@ -99,7 +96,6 @@ interface SortableProviderCardProps {
|
||||
provider: Provider;
|
||||
isCurrent: boolean;
|
||||
appId: AppId;
|
||||
isEditMode: boolean;
|
||||
onSwitch: (provider: Provider) => void;
|
||||
onEdit: (provider: Provider) => void;
|
||||
onDelete: (provider: Provider) => void;
|
||||
@@ -112,7 +108,6 @@ function SortableProviderCard({
|
||||
provider,
|
||||
isCurrent,
|
||||
appId,
|
||||
isEditMode,
|
||||
onSwitch,
|
||||
onEdit,
|
||||
onDelete,
|
||||
@@ -140,7 +135,6 @@ function SortableProviderCard({
|
||||
provider={provider}
|
||||
isCurrent={isCurrent}
|
||||
appId={appId}
|
||||
isEditMode={isEditMode}
|
||||
onSwitch={onSwitch}
|
||||
onEdit={onEdit}
|
||||
onDelete={onDelete}
|
||||
|
||||
Reference in New Issue
Block a user