refactor(ui): Design tokens - gradients, duration, textarea
- Replace cyan/magenta/purple gradients with primary/secondary - duration-200/300 → duration-[var(--duration-normal)] - Textarea: min-h-[100px] → min-h-24 - SearchPageHeader, DashboardPage, PlaylistHeader - UserProfilePageHeader/Hero, PlaylistDetailPageHero - SocialViewFeedItem, WishlistView, PostCard, ProductCard, CourseCard - SearchPageResults, MarketplaceHome Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
2c6e5fddb1
commit
c65da4fea6
15 changed files with 22 additions and 22 deletions
|
|
@ -155,7 +155,7 @@ export const WishlistView: React.FC = () => {
|
|||
<motion.div key={product.id} variants={cardVariants}>
|
||||
<Card
|
||||
variant="default"
|
||||
className="p-4 group hover:border-border/50 hover:-translate-y-1 hover:shadow-lg transition-all duration-200"
|
||||
className="p-4 group hover:border-border/50 hover:-translate-y-1 hover:shadow-lg transition-all duration-[var(--duration-normal)]"
|
||||
>
|
||||
<div className="flex gap-4">
|
||||
<div className="relative w-24 h-24 bg-muted rounded-lg overflow-hidden flex-shrink-0">
|
||||
|
|
|
|||
|
|
@ -27,14 +27,14 @@ const CourseCardComponent: React.FC<CourseCardProps> = ({
|
|||
return (
|
||||
<Card
|
||||
variant="default"
|
||||
className="group p-0 overflow-hidden cursor-pointer hover:border-border/80 hover:-translate-y-1 hover:shadow-xl transition-all duration-200 flex flex-col h-full"
|
||||
className="group p-0 overflow-hidden cursor-pointer hover:border-border/80 hover:-translate-y-1 hover:shadow-xl transition-all duration-[var(--duration-normal)] flex flex-col h-full"
|
||||
onClick={() => onClick(course)}
|
||||
>
|
||||
{/* Cover */}
|
||||
<div className="relative aspect-video bg-kodo-ink overflow-hidden">
|
||||
<OptimizedImage
|
||||
src={course.thumbnailUrl}
|
||||
className="w-full h-full object-cover opacity-90 group-hover:opacity-100 group-hover:scale-105 transition-all duration-300"
|
||||
className="w-full h-full object-cover opacity-90 group-hover:opacity-100 group-hover:scale-105 transition-all duration-[var(--duration-normal)]"
|
||||
alt={course.title}
|
||||
/>
|
||||
<div className="absolute inset-0 bg-background/40 opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center backdrop-blur-sm">
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ const ProductCardComponent: React.FC<ProductCardProps> = ({
|
|||
<div className="relative aspect-square overflow-hidden bg-black">
|
||||
<OptimizedImage
|
||||
src={product.coverUrl || (product as any).cover_url || 'https://picsum.photos/400'}
|
||||
className={`w-full h-full object-cover group-hover:scale-105 transition-transform duration-300 ${isPlayingPreview ? 'scale-110 blur-sm opacity-50' : ''}`}
|
||||
className={`w-full h-full object-cover group-hover:scale-105 transition-transform duration-[var(--duration-normal)] ${isPlayingPreview ? 'scale-110 blur-sm opacity-50' : ''}`}
|
||||
alt={product.title}
|
||||
/>
|
||||
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ const PostCardComponent: React.FC<PostCardProps> = ({ post }) => {
|
|||
<>
|
||||
<Card
|
||||
variant="default"
|
||||
className="p-0 overflow-hidden border-transparent hover:border-primary/20 hover:-translate-y-0.5 hover:shadow-lg transition-all duration-200 animate-fadeIn mb-4"
|
||||
className="p-0 overflow-hidden border-transparent hover:border-primary/20 hover:-translate-y-0.5 hover:shadow-lg transition-all duration-[var(--duration-normal)] animate-fadeIn mb-4"
|
||||
>
|
||||
{/* Repost Header */}
|
||||
{post.isRepost && (
|
||||
|
|
@ -177,7 +177,7 @@ const PostCardComponent: React.FC<PostCardProps> = ({ post }) => {
|
|||
<OptimizedImage
|
||||
src={post.image!}
|
||||
alt={post.content?.substring(0, 50) || 'Post image'}
|
||||
className="w-full h-full object-cover transition-transform duration-300 group-hover:scale-105"
|
||||
className="w-full h-full object-cover transition-transform duration-[var(--duration-normal)] group-hover:scale-105"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
|
@ -189,7 +189,7 @@ const PostCardComponent: React.FC<PostCardProps> = ({ post }) => {
|
|||
<img
|
||||
src={post.audioTrack.coverUrl}
|
||||
alt={post.audioTrack.title || 'Track cover'}
|
||||
className="w-full h-full object-cover transition-transform duration-300 group-hover:scale-110"
|
||||
className="w-full h-full object-cover transition-transform duration-[var(--duration-normal)] group-hover:scale-110"
|
||||
/>
|
||||
<div className="absolute inset-0 bg-background/40 flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity">
|
||||
<Play className="w-5 h-5 text-foreground fill-current" />
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
|
|||
'rounded-lg',
|
||||
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background',
|
||||
'transition-all duration-[var(--duration-fast)]',
|
||||
'min-h-[100px] resize-y',
|
||||
'min-h-24 resize-y',
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ export function SocialViewFeedItem({ track, onPlay }: SocialViewFeedItemProps) {
|
|||
>
|
||||
<Card
|
||||
variant="glass"
|
||||
className="p-0 overflow-hidden border-white/5 bg-black/20 backdrop-blur-xl hover:border-primary/20 hover-glow-cyan transition-all duration-200"
|
||||
className="p-0 overflow-hidden border-white/5 bg-black/20 backdrop-blur-xl hover:border-primary/20 hover-glow-cyan transition-all duration-[var(--duration-normal)]"
|
||||
>
|
||||
<div className="p-4 flex items-center gap-3">
|
||||
<Avatar
|
||||
|
|
@ -72,7 +72,7 @@ export function SocialViewFeedItem({ track, onPlay }: SocialViewFeedItemProps) {
|
|||
<img
|
||||
src={track.coverUrl}
|
||||
alt=""
|
||||
className="w-full h-full object-cover transition-transform duration-300 group-hover:scale-110"
|
||||
className="w-full h-full object-cover transition-transform duration-[var(--duration-normal)] group-hover:scale-110"
|
||||
/>
|
||||
<div className="absolute inset-0 bg-black/30 flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity">
|
||||
<Play className="w-6 h-6 text-white fill-current" />
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ function WelcomeBanner({ username }: { username: string }) {
|
|||
<div className="relative z-10">
|
||||
<h1 className="text-heading-1">
|
||||
{greeting},{' '}
|
||||
<span className="text-transparent bg-clip-text bg-gradient-to-r from-cyan-500 to-magenta-500">
|
||||
<span className="text-transparent bg-clip-text bg-gradient-to-r from-primary to-secondary">
|
||||
{username}
|
||||
</span>
|
||||
</h1>
|
||||
|
|
@ -73,7 +73,7 @@ function QuickActions() {
|
|||
<Link
|
||||
key={action.label}
|
||||
to={action.path}
|
||||
className="group flex items-center gap-3 p-4 rounded-xl border border-border hover:border-primary/30 hover:bg-muted/50 transition-all duration-200 animate-stagger-in"
|
||||
className="group flex items-center gap-3 p-4 rounded-xl border border-border hover:border-primary/30 hover:bg-muted/50 transition-all duration-[var(--duration-normal)] animate-stagger-in"
|
||||
style={{ animationDelay: `${i * 60}ms` }}
|
||||
>
|
||||
<div className={cn('p-2.5 rounded-lg', action.color)}>
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ export function PlaylistHeader({ playlist, className }: PlaylistHeaderProps) {
|
|||
<CardContent className="p-4 sm:p-6">
|
||||
<div className="flex flex-col md:flex-row gap-4 sm:gap-6">
|
||||
{/* Cover Image - Mobile optimized */}
|
||||
<div className="relative w-full md:w-64 h-48 sm:h-64 flex-shrink-0 rounded-lg overflow-hidden bg-gradient-to-br from-purple-500 to-pink-500">
|
||||
<div className="relative w-full md:w-64 h-48 sm:h-64 flex-shrink-0 rounded-lg overflow-hidden bg-gradient-to-br from-primary/40 to-secondary/40">
|
||||
{playlist.cover_url ? (
|
||||
<img
|
||||
src={playlist.cover_url}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ export function PlaylistDetailPageCoverAndInfo({ playlist }: PlaylistDetailPageC
|
|||
className="w-full h-full object-cover rounded-xl shadow-inner group-hover:scale-105 transition-transform duration-[var(--duration-slower)]"
|
||||
/>
|
||||
) : (
|
||||
<div className="w-full h-full bg-gradient-to-br from-cyan-900 to-magenta-900 rounded-xl flex items-center justify-center">
|
||||
<div className="w-full h-full bg-gradient-to-br from-primary/30 to-secondary/30 rounded-xl flex items-center justify-center">
|
||||
<Music className="w-20 h-20 text-white/20" />
|
||||
</div>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ interface PlaylistDetailPageHeroProps {
|
|||
export function PlaylistDetailPageHero({ playlist }: PlaylistDetailPageHeroProps) {
|
||||
return (
|
||||
<div className="relative h-80 md:h-96 w-full overflow-hidden">
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-cyan-900/50 via-black to-magenta-900/50" />
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-primary/30 via-background to-secondary/30" />
|
||||
{playlist.cover_url && (
|
||||
<div
|
||||
className="absolute inset-0 opacity-30 blur-3xl scale-110"
|
||||
|
|
|
|||
|
|
@ -40,11 +40,11 @@ export function UserProfilePageHeader({
|
|||
{/* Avatar with animated glow ring */}
|
||||
<div className="relative -mt-16 md:-mt-20 group">
|
||||
<div
|
||||
className="absolute -inset-1 rounded-3xl bg-gradient-to-br from-cyan-400 via-primary to-magenta-500 blur-xl opacity-50 group-hover:opacity-100 transition-opacity duration-[var(--duration-slow)]"
|
||||
className="absolute -inset-1 rounded-3xl bg-gradient-to-br from-primary via-primary/80 to-secondary blur-xl opacity-50 group-hover:opacity-100 transition-opacity duration-[var(--duration-slow)]"
|
||||
aria-hidden
|
||||
/>
|
||||
<div
|
||||
className="absolute -inset-0.5 rounded-3xl bg-gradient-to-br from-cyan-400 to-magenta-500 opacity-70"
|
||||
className="absolute -inset-0.5 rounded-3xl bg-gradient-to-br from-primary to-secondary opacity-70"
|
||||
aria-hidden
|
||||
/>
|
||||
<Avatar
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ export function UserProfilePageHero() {
|
|||
return (
|
||||
<div className="h-64 md:h-80 w-full relative overflow-hidden">
|
||||
{/* Base gradient layer */}
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-cyan-900/50 via-purple-900/40 to-magenta-900/50" />
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-primary/30 via-primary/20 to-secondary/30" />
|
||||
|
||||
{/* Radial highlight at center-top */}
|
||||
<div className="absolute inset-0 bg-[radial-gradient(ellipse_at_top,_var(--tw-gradient-stops))] from-primary/20 via-transparent to-transparent" />
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ export function SearchPageHeader({
|
|||
<button
|
||||
type="button"
|
||||
onClick={onClear}
|
||||
className="p-2 mr-2 hover:bg-muted/50 rounded-full transition-colors text-muted-foreground hover:text-foreground"
|
||||
className="p-2 mr-2 hover:bg-muted/50 rounded-full transition-colors duration-[var(--duration-fast)] text-muted-foreground hover:text-foreground"
|
||||
aria-label="Clear search"
|
||||
>
|
||||
<X className="w-5 h-5" />
|
||||
|
|
|
|||
|
|
@ -193,7 +193,7 @@ export function SearchPageResults({ results, query = '' }: SearchPageResultsProp
|
|||
onClick={() => navigate(`/playlists/${playlist.id}`)}
|
||||
onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); navigate(`/playlists/${playlist.id}`); } }}
|
||||
>
|
||||
<div className="h-32 bg-gradient-to-br from-purple-900 to-black relative">
|
||||
<div className="h-32 bg-gradient-to-br from-primary/30 to-background relative">
|
||||
{playlist.cover_url && (
|
||||
<img
|
||||
src={playlist.cover_url}
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ function MarketplaceHomeSkeleton() {
|
|||
return (
|
||||
<div className="min-h-screen pb-24 relative">
|
||||
{/* Background Ambience */}
|
||||
<div className="absolute inset-x-0 top-0 h-96 bg-gradient-to-b from-purple-900/20 via-background to-background pointer-events-none" />
|
||||
<div className="absolute inset-x-0 top-0 h-96 bg-gradient-to-b from-primary/20 via-background to-background pointer-events-none" />
|
||||
|
||||
<div className="container mx-auto px-4 py-8 relative z-10">
|
||||
{/* Header */}
|
||||
|
|
@ -192,7 +192,7 @@ export function MarketplaceHome() {
|
|||
return (
|
||||
<div className="min-h-screen pb-24 relative">
|
||||
{/* Background Ambience */}
|
||||
<div className="absolute inset-x-0 top-0 h-96 bg-gradient-to-b from-purple-900/20 via-background to-background pointer-events-none" />
|
||||
<div className="absolute inset-x-0 top-0 h-96 bg-gradient-to-b from-primary/20 via-background to-background pointer-events-none" />
|
||||
|
||||
<div className="container mx-auto px-4 py-8 relative z-10">
|
||||
{mutationError && (
|
||||
|
|
|
|||
Loading…
Reference in a new issue