2026-01-07 09:31:02 +00:00
|
|
|
import { Button } from '../ui/button';
|
2026-02-03 08:40:54 +00:00
|
|
|
import { Card } from '../ui/card';
|
2026-02-08 23:00:21 +00:00
|
|
|
import { EmptyState } from '../ui/empty-state';
|
2026-02-09 22:04:35 +00:00
|
|
|
import { Skeleton } from '../ui/skeleton';
|
2026-02-03 08:40:54 +00:00
|
|
|
import { useCartStore } from '../../stores/cartStore';
|
2026-01-07 09:31:02 +00:00
|
|
|
import { Product } from '../../types';
|
2026-02-03 08:40:54 +00:00
|
|
|
import { Heart, Pause, Play, ShoppingCart, Trash2, Zap } from 'lucide-react';
|
|
|
|
|
import React, { useState } from 'react';
|
feat(ui): education, gamification, developer, admin views polish
Education:
- CourseCard: lessons count badge, progress bar, backdrop-blur on badges
- EducationView: framer-motion stagger on grid
- Filters: interactive color-coded pills (Beginner/Intermediate/Advanced)
- MyCoursesView: stagger animation, semantic token migration
Gamification:
- LeaderboardView: gold/silver/bronze podium styling with glow + accents
- AchievementCard: shine sweep animation on hover, lift effect
- AchievementsView: stagger animation with filter re-animation
- XPBar: semantic token fix
Developer dashboard:
- API key copy-to-clipboard with icon toggle
- Status indicator badges with animated pulse dot
Commerce/Admin:
- WishlistView: stagger animation, hover lift
- PurchasesView: stagger on list items
- Admin views: consistent headers, semantic tokens (text-white → text-foreground)
18 files modified, all text-white → text-foreground migrations
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-09 23:48:45 +00:00
|
|
|
import { motion } from 'framer-motion';
|
2026-01-26 13:12:17 +00:00
|
|
|
import { useToast } from '../../components/feedback/ToastProvider';
|
Phase 2 stabilisation: code mort, Modal→Dialog, feature flags, tests, router split, Rust legacy
Bloc A - Code mort:
- Suppression Studio (components, views, features)
- Suppression gamification + services mock (projectService, storageService, gamificationService)
- Mise à jour Sidebar, Navbar, locales
Bloc B - Frontend:
- Suppression modal.tsx deprecated, Modal.stories (doublon Dialog)
- Feature flags: PLAYLIST_SEARCH, PLAYLIST_RECOMMENDATIONS, ROLE_MANAGEMENT = true
- Suppression 19 tests orphelins, retrait exclusions vitest.config
Bloc C - Backend:
- Extraction routes_auth.go depuis router.go
Bloc D - Rust:
- Suppression security_legacy.rs (code mort, patterns déjà dans security/)
2026-02-14 16:23:32 +00:00
|
|
|
import { useAuthStore } from '@/features/auth/store/authStore';
|
|
|
|
|
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
|
|
|
|
import { marketplaceService } from '@/services/marketplaceService';
|
2026-01-07 09:31:02 +00:00
|
|
|
|
feat(ui): education, gamification, developer, admin views polish
Education:
- CourseCard: lessons count badge, progress bar, backdrop-blur on badges
- EducationView: framer-motion stagger on grid
- Filters: interactive color-coded pills (Beginner/Intermediate/Advanced)
- MyCoursesView: stagger animation, semantic token migration
Gamification:
- LeaderboardView: gold/silver/bronze podium styling with glow + accents
- AchievementCard: shine sweep animation on hover, lift effect
- AchievementsView: stagger animation with filter re-animation
- XPBar: semantic token fix
Developer dashboard:
- API key copy-to-clipboard with icon toggle
- Status indicator badges with animated pulse dot
Commerce/Admin:
- WishlistView: stagger animation, hover lift
- PurchasesView: stagger on list items
- Admin views: consistent headers, semantic tokens (text-white → text-foreground)
18 files modified, all text-white → text-foreground migrations
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-09 23:48:45 +00:00
|
|
|
const gridVariants = {
|
|
|
|
|
visible: { transition: { staggerChildren: 0.06, delayChildren: 0.04 } },
|
|
|
|
|
};
|
|
|
|
|
const cardVariants = {
|
|
|
|
|
hidden: { opacity: 0, y: 16, scale: 0.97 },
|
|
|
|
|
visible: {
|
|
|
|
|
opacity: 1,
|
|
|
|
|
y: 0,
|
|
|
|
|
scale: 1,
|
|
|
|
|
transition: { duration: 0.35, ease: [0.33, 1, 0.68, 1] as const },
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
Phase 2 stabilisation: code mort, Modal→Dialog, feature flags, tests, router split, Rust legacy
Bloc A - Code mort:
- Suppression Studio (components, views, features)
- Suppression gamification + services mock (projectService, storageService, gamificationService)
- Mise à jour Sidebar, Navbar, locales
Bloc B - Frontend:
- Suppression modal.tsx deprecated, Modal.stories (doublon Dialog)
- Feature flags: PLAYLIST_SEARCH, PLAYLIST_RECOMMENDATIONS, ROLE_MANAGEMENT = true
- Suppression 19 tests orphelins, retrait exclusions vitest.config
Bloc C - Backend:
- Extraction routes_auth.go depuis router.go
Bloc D - Rust:
- Suppression security_legacy.rs (code mort, patterns déjà dans security/)
2026-02-14 16:23:32 +00:00
|
|
|
const WISHLIST_QUERY_KEY = ['wishlist'];
|
2026-01-07 09:31:02 +00:00
|
|
|
|
|
|
|
|
export const WishlistView: React.FC = () => {
|
2026-02-03 08:40:54 +00:00
|
|
|
const addToCart = useCartStore((state) => state.addItem);
|
2026-01-13 18:47:57 +00:00
|
|
|
const { addToast } = useToast();
|
Phase 2 stabilisation: code mort, Modal→Dialog, feature flags, tests, router split, Rust legacy
Bloc A - Code mort:
- Suppression Studio (components, views, features)
- Suppression gamification + services mock (projectService, storageService, gamificationService)
- Mise à jour Sidebar, Navbar, locales
Bloc B - Frontend:
- Suppression modal.tsx deprecated, Modal.stories (doublon Dialog)
- Feature flags: PLAYLIST_SEARCH, PLAYLIST_RECOMMENDATIONS, ROLE_MANAGEMENT = true
- Suppression 19 tests orphelins, retrait exclusions vitest.config
Bloc C - Backend:
- Extraction routes_auth.go depuis router.go
Bloc D - Rust:
- Suppression security_legacy.rs (code mort, patterns déjà dans security/)
2026-02-14 16:23:32 +00:00
|
|
|
const queryClient = useQueryClient();
|
|
|
|
|
const isAuthenticated = useAuthStore((s) => s.isAuthenticated);
|
2026-01-13 18:47:57 +00:00
|
|
|
const [playingPreview, setPlayingPreview] = useState<string | null>(null);
|
|
|
|
|
|
Phase 2 stabilisation: code mort, Modal→Dialog, feature flags, tests, router split, Rust legacy
Bloc A - Code mort:
- Suppression Studio (components, views, features)
- Suppression gamification + services mock (projectService, storageService, gamificationService)
- Mise à jour Sidebar, Navbar, locales
Bloc B - Frontend:
- Suppression modal.tsx deprecated, Modal.stories (doublon Dialog)
- Feature flags: PLAYLIST_SEARCH, PLAYLIST_RECOMMENDATIONS, ROLE_MANAGEMENT = true
- Suppression 19 tests orphelins, retrait exclusions vitest.config
Bloc C - Backend:
- Extraction routes_auth.go depuis router.go
Bloc D - Rust:
- Suppression security_legacy.rs (code mort, patterns déjà dans security/)
2026-02-14 16:23:32 +00:00
|
|
|
const {
|
|
|
|
|
data: wishlist = [],
|
|
|
|
|
isLoading,
|
|
|
|
|
isError,
|
|
|
|
|
error,
|
|
|
|
|
} = useQuery({
|
|
|
|
|
queryKey: WISHLIST_QUERY_KEY,
|
|
|
|
|
queryFn: () => marketplaceService.getWishlist(),
|
|
|
|
|
enabled: isAuthenticated,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const removeMutation = useMutation({
|
|
|
|
|
mutationFn: (productId: string) => marketplaceService.removeFromWishlist(productId),
|
|
|
|
|
onSuccess: () => {
|
|
|
|
|
queryClient.invalidateQueries({ queryKey: WISHLIST_QUERY_KEY });
|
|
|
|
|
addToast('Removed from wishlist', 'info');
|
|
|
|
|
},
|
|
|
|
|
onError: (err: Error) => {
|
|
|
|
|
addToast(err.message || 'Failed to remove from wishlist', 'error');
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
2026-01-13 18:47:57 +00:00
|
|
|
const handleRemove = (id: string) => {
|
Phase 2 stabilisation: code mort, Modal→Dialog, feature flags, tests, router split, Rust legacy
Bloc A - Code mort:
- Suppression Studio (components, views, features)
- Suppression gamification + services mock (projectService, storageService, gamificationService)
- Mise à jour Sidebar, Navbar, locales
Bloc B - Frontend:
- Suppression modal.tsx deprecated, Modal.stories (doublon Dialog)
- Feature flags: PLAYLIST_SEARCH, PLAYLIST_RECOMMENDATIONS, ROLE_MANAGEMENT = true
- Suppression 19 tests orphelins, retrait exclusions vitest.config
Bloc C - Backend:
- Extraction routes_auth.go depuis router.go
Bloc D - Rust:
- Suppression security_legacy.rs (code mort, patterns déjà dans security/)
2026-02-14 16:23:32 +00:00
|
|
|
if (!isAuthenticated) return;
|
|
|
|
|
removeMutation.mutate(id);
|
2026-01-13 18:47:57 +00:00
|
|
|
};
|
2026-01-07 09:31:02 +00:00
|
|
|
|
2026-01-13 18:47:57 +00:00
|
|
|
const handleAddToCart = (product: Product) => {
|
|
|
|
|
addToCart(product);
|
|
|
|
|
handleRemove(product.id);
|
|
|
|
|
};
|
2026-01-07 09:31:02 +00:00
|
|
|
|
2026-01-13 18:47:57 +00:00
|
|
|
const handleAddAll = () => {
|
|
|
|
|
wishlist.forEach((p) => addToCart(p));
|
Phase 2 stabilisation: code mort, Modal→Dialog, feature flags, tests, router split, Rust legacy
Bloc A - Code mort:
- Suppression Studio (components, views, features)
- Suppression gamification + services mock (projectService, storageService, gamificationService)
- Mise à jour Sidebar, Navbar, locales
Bloc B - Frontend:
- Suppression modal.tsx deprecated, Modal.stories (doublon Dialog)
- Feature flags: PLAYLIST_SEARCH, PLAYLIST_RECOMMENDATIONS, ROLE_MANAGEMENT = true
- Suppression 19 tests orphelins, retrait exclusions vitest.config
Bloc C - Backend:
- Extraction routes_auth.go depuis router.go
Bloc D - Rust:
- Suppression security_legacy.rs (code mort, patterns déjà dans security/)
2026-02-14 16:23:32 +00:00
|
|
|
wishlist.forEach((p) => handleRemove(p.id));
|
2026-01-13 18:47:57 +00:00
|
|
|
addToast('All items moved to cart', 'success');
|
|
|
|
|
};
|
2026-01-07 09:31:02 +00:00
|
|
|
|
Phase 2 stabilisation: code mort, Modal→Dialog, feature flags, tests, router split, Rust legacy
Bloc A - Code mort:
- Suppression Studio (components, views, features)
- Suppression gamification + services mock (projectService, storageService, gamificationService)
- Mise à jour Sidebar, Navbar, locales
Bloc B - Frontend:
- Suppression modal.tsx deprecated, Modal.stories (doublon Dialog)
- Feature flags: PLAYLIST_SEARCH, PLAYLIST_RECOMMENDATIONS, ROLE_MANAGEMENT = true
- Suppression 19 tests orphelins, retrait exclusions vitest.config
Bloc C - Backend:
- Extraction routes_auth.go depuis router.go
Bloc D - Rust:
- Suppression security_legacy.rs (code mort, patterns déjà dans security/)
2026-02-14 16:23:32 +00:00
|
|
|
if (!isAuthenticated) {
|
|
|
|
|
return (
|
|
|
|
|
<EmptyState
|
|
|
|
|
variant="centered"
|
|
|
|
|
icon={<Heart className="w-full h-full" />}
|
|
|
|
|
title="Sign in to view your wishlist"
|
|
|
|
|
description="Create an account or log in to save items you love."
|
|
|
|
|
action={{
|
|
|
|
|
label: 'Sign in',
|
|
|
|
|
onClick: () => (window.location.href = '/login'),
|
|
|
|
|
}}
|
|
|
|
|
size="lg"
|
|
|
|
|
className="min-h-96"
|
|
|
|
|
/>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isError) {
|
|
|
|
|
return (
|
|
|
|
|
<EmptyState
|
|
|
|
|
variant="centered"
|
|
|
|
|
icon={<Heart className="w-full h-full" />}
|
|
|
|
|
title="Could not load wishlist"
|
|
|
|
|
description={error instanceof Error ? error.message : 'Something went wrong.'}
|
|
|
|
|
action={{
|
|
|
|
|
label: 'Try again',
|
|
|
|
|
onClick: () => queryClient.invalidateQueries({ queryKey: WISHLIST_QUERY_KEY }),
|
|
|
|
|
}}
|
|
|
|
|
size="lg"
|
|
|
|
|
className="min-h-96"
|
|
|
|
|
/>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-09 22:04:35 +00:00
|
|
|
if (isLoading) {
|
|
|
|
|
return (
|
|
|
|
|
<div className="max-w-6xl mx-auto pb-20">
|
|
|
|
|
<div className="flex flex-col md:flex-row justify-between items-end border-b border-border/50 pb-6 gap-4 mb-8">
|
|
|
|
|
<div>
|
|
|
|
|
<Skeleton className="h-9 w-48 mb-2" />
|
|
|
|
|
<Skeleton variant="text" className="w-32" />
|
|
|
|
|
</div>
|
|
|
|
|
<Skeleton className="h-10 w-44" />
|
|
|
|
|
</div>
|
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
|
|
|
|
{[1, 2, 3].map((i) => (
|
|
|
|
|
<Skeleton key={i} className="h-96 w-full rounded-lg" />
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-13 18:47:57 +00:00
|
|
|
if (wishlist.length === 0) {
|
|
|
|
|
return (
|
2026-02-08 23:00:21 +00:00
|
|
|
<EmptyState
|
2026-02-09 22:23:09 +00:00
|
|
|
variant="centered"
|
2026-02-08 23:00:21 +00:00
|
|
|
icon={<Heart className="w-full h-full" />}
|
|
|
|
|
title="Your wishlist is empty"
|
2026-02-09 22:23:09 +00:00
|
|
|
description="Explore the marketplace and save items you love."
|
|
|
|
|
action={{
|
|
|
|
|
label: 'Browse Marketplace',
|
|
|
|
|
onClick: () => (window.location.href = '/marketplace'),
|
|
|
|
|
}}
|
2026-02-08 23:00:21 +00:00
|
|
|
size="lg"
|
2026-02-09 22:23:09 +00:00
|
|
|
className="min-h-96"
|
2026-02-08 23:00:21 +00:00
|
|
|
/>
|
2026-01-13 18:47:57 +00:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className="animate-fadeIn max-w-6xl mx-auto pb-20">
|
2026-02-07 15:07:09 +00:00
|
|
|
<div className="flex flex-col md:flex-row justify-between items-end border-b border-border/50 pb-6 gap-4 mb-8">
|
2026-01-13 18:47:57 +00:00
|
|
|
<div>
|
2026-02-12 00:49:07 +00:00
|
|
|
<h1 className="text-3xl font-heading font-bold text-foreground mb-2 tracking-tight">
|
2026-01-13 18:47:57 +00:00
|
|
|
WISHLIST
|
|
|
|
|
</h1>
|
2026-02-07 15:07:09 +00:00
|
|
|
<p className="text-muted-foreground font-mono text-sm">
|
2026-01-13 18:47:57 +00:00
|
|
|
{wishlist.length} saved items
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
<Button
|
|
|
|
|
variant="primary"
|
|
|
|
|
icon={<ShoppingCart className="w-4 h-4" />}
|
|
|
|
|
onClick={handleAddAll}
|
|
|
|
|
>
|
|
|
|
|
ADD ALL TO CART
|
|
|
|
|
</Button>
|
|
|
|
|
</div>
|
2026-01-07 09:31:02 +00:00
|
|
|
|
feat(ui): education, gamification, developer, admin views polish
Education:
- CourseCard: lessons count badge, progress bar, backdrop-blur on badges
- EducationView: framer-motion stagger on grid
- Filters: interactive color-coded pills (Beginner/Intermediate/Advanced)
- MyCoursesView: stagger animation, semantic token migration
Gamification:
- LeaderboardView: gold/silver/bronze podium styling with glow + accents
- AchievementCard: shine sweep animation on hover, lift effect
- AchievementsView: stagger animation with filter re-animation
- XPBar: semantic token fix
Developer dashboard:
- API key copy-to-clipboard with icon toggle
- Status indicator badges with animated pulse dot
Commerce/Admin:
- WishlistView: stagger animation, hover lift
- PurchasesView: stagger on list items
- Admin views: consistent headers, semantic tokens (text-white → text-foreground)
18 files modified, all text-white → text-foreground migrations
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-09 23:48:45 +00:00
|
|
|
<motion.div
|
|
|
|
|
className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6"
|
|
|
|
|
variants={gridVariants}
|
|
|
|
|
initial="hidden"
|
|
|
|
|
animate="visible"
|
|
|
|
|
>
|
2026-01-13 18:47:57 +00:00
|
|
|
{wishlist.map((product) => (
|
feat(ui): education, gamification, developer, admin views polish
Education:
- CourseCard: lessons count badge, progress bar, backdrop-blur on badges
- EducationView: framer-motion stagger on grid
- Filters: interactive color-coded pills (Beginner/Intermediate/Advanced)
- MyCoursesView: stagger animation, semantic token migration
Gamification:
- LeaderboardView: gold/silver/bronze podium styling with glow + accents
- AchievementCard: shine sweep animation on hover, lift effect
- AchievementsView: stagger animation with filter re-animation
- XPBar: semantic token fix
Developer dashboard:
- API key copy-to-clipboard with icon toggle
- Status indicator badges with animated pulse dot
Commerce/Admin:
- WishlistView: stagger animation, hover lift
- PurchasesView: stagger on list items
- Admin views: consistent headers, semantic tokens (text-white → text-foreground)
18 files modified, all text-white → text-foreground migrations
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-09 23:48:45 +00:00
|
|
|
<motion.div key={product.id} variants={cardVariants}>
|
2026-01-13 18:47:57 +00:00
|
|
|
<Card
|
|
|
|
|
variant="default"
|
fix: stabilize builds, tests, and lint across all stacks
Complete stabilization pass bringing all 3 stacks to green:
Frontend (apps/web/):
- Fix TypeScript nullability in useSeason.ts, useTimeOfDay.ts hooks
- Disable no-undef in ESLint config (TypeScript handles it; JSX misidentified)
- Rename 306 story imports from @storybook/react to @storybook/react-vite
- Fix conditional hook call in useMediaQuery.ts useIsTablet
- Move useQuery to top of LoginPage.tsx component
- Remove useless try/catch in GearFormModal.tsx
- Fix stale closure in ResetPasswordPage.tsx handleChange
- Make Storybook decorators (withRouter, withQueryClient, withToast, withAudio)
no-ops since global StorybookDecorator already provides these — prevents
nested Router / duplicate provider crashes in vitest-browser
- Fix nested MemoryRouter in 3 page stories (TrackDetail, PlaylistDetail, UserProfile)
- Update i18n initialization in test setup (await init before changeLanguage)
- Update ~30 test assertions from English to French to match i18n translations
- Update test assertions to match SUMI V3 design changes (shadow vs border)
- Fix remaining story type errors (PlayerError, PlaylistBatchActions,
TrackFilters, VirtualizedChatMessages)
Backend (veza-backend-api/):
- Fix response_test.go RespondWithAppError signature (2 args, not 3)
- Fix TestErrorContractAuthEndpoints expected error codes
(ErrCodeUnauthorized vs ErrCodeInvalidCredentials)
- Fix TestTrackHandler_GetTrackLikes_Success missing auth middleware setup
- Fix TestPlaybackAnalyticsService_GetTrackStats k-anonymity threshold
(needs 5 unique users, not 1)
- Replace NOW() PostgreSQL function with time.Now() parameter in marketplace
service for SQLite test compatibility
- Add missing AutoMigrate entries in marketplace_test.go
(ProductImage, ProductPreview, ProductLicense, ProductReview)
Results:
- Frontend TypeCheck: 617 errors -> 0 errors
- Frontend ESLint: 349 errors -> 0 errors
- Frontend Vitest: 196 failing tests -> 1 skipped (3396/3397 passing)
- Backend go vet: 1 error -> 0 errors
- Backend tests: 5 failing -> all 13 packages passing
- Rust: 150/150 tests passing (unchanged)
- Storybook audit: 0 errors across 1244 stories
Triage report: docs/TRIAGE_REPORT.md
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 14:48:07 +00:00
|
|
|
className="p-4 group hover:shadow-[0_0_12px_rgba(26,26,30,0.08)] transition-all duration-[var(--sumi-duration-normal)]"
|
2026-01-13 18:47:57 +00:00
|
|
|
>
|
|
|
|
|
<div className="flex gap-4">
|
2026-02-07 15:07:09 +00:00
|
|
|
<div className="relative w-24 h-24 bg-muted rounded-lg overflow-hidden flex-shrink-0">
|
2026-01-13 18:47:57 +00:00
|
|
|
<img
|
|
|
|
|
src={product.coverUrl}
|
2026-02-12 01:09:29 +00:00
|
|
|
className="w-full h-full object-cover group-hover:scale-110 transition-transform duration-[var(--sumi-duration-slow)]"
|
2026-01-13 18:47:57 +00:00
|
|
|
/>
|
|
|
|
|
<div
|
|
|
|
|
className="absolute inset-0 bg-black/40 flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity cursor-pointer"
|
|
|
|
|
onClick={() =>
|
|
|
|
|
setPlayingPreview(
|
|
|
|
|
playingPreview === product.id ? null : product.id,
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
>
|
|
|
|
|
{playingPreview === product.id ? (
|
2026-02-12 01:09:29 +00:00
|
|
|
<Pause className="w-8 h-8 text-foreground" />
|
2026-01-13 18:47:57 +00:00
|
|
|
) : (
|
2026-02-12 01:09:29 +00:00
|
|
|
<Play className="w-8 h-8 text-foreground fill-current" />
|
2026-01-13 18:47:57 +00:00
|
|
|
)}
|
2026-01-07 18:39:21 +00:00
|
|
|
</div>
|
2026-01-13 18:47:57 +00:00
|
|
|
{product.isHot && (
|
2026-02-07 15:07:09 +00:00
|
|
|
<div className="absolute top-1 left-1 bg-warning text-warning-foreground text-xs font-bold px-1.5 py-0.5 rounded">
|
2026-01-13 18:47:57 +00:00
|
|
|
<Zap className="w-2 h-2 inline" /> HOT
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
2026-01-07 09:31:02 +00:00
|
|
|
|
2026-01-13 18:47:57 +00:00
|
|
|
<div className="flex-1 min-w-0 flex flex-col justify-between">
|
2026-01-07 18:39:21 +00:00
|
|
|
<div>
|
feat(ui): education, gamification, developer, admin views polish
Education:
- CourseCard: lessons count badge, progress bar, backdrop-blur on badges
- EducationView: framer-motion stagger on grid
- Filters: interactive color-coded pills (Beginner/Intermediate/Advanced)
- MyCoursesView: stagger animation, semantic token migration
Gamification:
- LeaderboardView: gold/silver/bronze podium styling with glow + accents
- AchievementCard: shine sweep animation on hover, lift effect
- AchievementsView: stagger animation with filter re-animation
- XPBar: semantic token fix
Developer dashboard:
- API key copy-to-clipboard with icon toggle
- Status indicator badges with animated pulse dot
Commerce/Admin:
- WishlistView: stagger animation, hover lift
- PurchasesView: stagger on list items
- Admin views: consistent headers, semantic tokens (text-white → text-foreground)
18 files modified, all text-white → text-foreground migrations
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-09 23:48:45 +00:00
|
|
|
<h3 className="font-bold text-foreground truncate">
|
2026-01-13 18:47:57 +00:00
|
|
|
{product.title}
|
|
|
|
|
</h3>
|
2026-02-07 15:07:09 +00:00
|
|
|
<p className="text-xs text-muted-foreground truncate">
|
2026-01-13 18:47:57 +00:00
|
|
|
{product.author}
|
|
|
|
|
</p>
|
2026-02-07 15:07:09 +00:00
|
|
|
<p className="text-xs text-muted-foreground mt-1 capitalize">
|
2026-01-13 18:47:57 +00:00
|
|
|
{product.type}
|
|
|
|
|
</p>
|
2026-01-07 18:39:21 +00:00
|
|
|
</div>
|
2026-02-07 15:07:09 +00:00
|
|
|
<div className="text-lg font-mono font-bold text-muted-foreground">
|
2026-01-13 18:47:57 +00:00
|
|
|
${product.price}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2026-01-07 09:31:02 +00:00
|
|
|
</div>
|
|
|
|
|
|
ui(tokens): migrate border-kodo-steel to border-border (86 files, 269 instances)
Replace legacy hardcoded border-kodo-steel (RGB 59,69,84, theme-unaware)
with semantic border-border token across 86 user-facing components.
Covers UI primitives (checkbox, badge, modal, table, textarea, alert,
radio-group, avatar), all modals, settings views, social features,
playlist views, inventory, chat, commerce, and cloud file browser.
Only story/test files retain the legacy token.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-08 23:07:00 +00:00
|
|
|
<div className="flex gap-2 mt-4 pt-4 border-t border-border/30">
|
2026-01-13 18:47:57 +00:00
|
|
|
<Button
|
|
|
|
|
variant="secondary"
|
|
|
|
|
size="sm"
|
|
|
|
|
className="flex-1"
|
|
|
|
|
onClick={() => handleAddToCart(product)}
|
|
|
|
|
>
|
|
|
|
|
Add to Cart
|
|
|
|
|
</Button>
|
|
|
|
|
<Button
|
|
|
|
|
variant="ghost"
|
|
|
|
|
size="icon"
|
2026-02-07 15:07:09 +00:00
|
|
|
className="text-muted-foreground hover:text-destructive"
|
2026-01-13 18:47:57 +00:00
|
|
|
onClick={() => handleRemove(product.id)}
|
|
|
|
|
>
|
|
|
|
|
<Trash2 className="w-4 h-4" />
|
|
|
|
|
</Button>
|
2026-01-07 18:39:21 +00:00
|
|
|
</div>
|
2026-01-13 18:47:57 +00:00
|
|
|
</Card>
|
feat(ui): education, gamification, developer, admin views polish
Education:
- CourseCard: lessons count badge, progress bar, backdrop-blur on badges
- EducationView: framer-motion stagger on grid
- Filters: interactive color-coded pills (Beginner/Intermediate/Advanced)
- MyCoursesView: stagger animation, semantic token migration
Gamification:
- LeaderboardView: gold/silver/bronze podium styling with glow + accents
- AchievementCard: shine sweep animation on hover, lift effect
- AchievementsView: stagger animation with filter re-animation
- XPBar: semantic token fix
Developer dashboard:
- API key copy-to-clipboard with icon toggle
- Status indicator badges with animated pulse dot
Commerce/Admin:
- WishlistView: stagger animation, hover lift
- PurchasesView: stagger on list items
- Admin views: consistent headers, semantic tokens (text-white → text-foreground)
18 files modified, all text-white → text-foreground migrations
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-09 23:48:45 +00:00
|
|
|
</motion.div>
|
2026-01-13 18:47:57 +00:00
|
|
|
))}
|
feat(ui): education, gamification, developer, admin views polish
Education:
- CourseCard: lessons count badge, progress bar, backdrop-blur on badges
- EducationView: framer-motion stagger on grid
- Filters: interactive color-coded pills (Beginner/Intermediate/Advanced)
- MyCoursesView: stagger animation, semantic token migration
Gamification:
- LeaderboardView: gold/silver/bronze podium styling with glow + accents
- AchievementCard: shine sweep animation on hover, lift effect
- AchievementsView: stagger animation with filter re-animation
- XPBar: semantic token fix
Developer dashboard:
- API key copy-to-clipboard with icon toggle
- Status indicator badges with animated pulse dot
Commerce/Admin:
- WishlistView: stagger animation, hover lift
- PurchasesView: stagger on list items
- Admin views: consistent headers, semantic tokens (text-white → text-foreground)
18 files modified, all text-white → text-foreground migrations
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-09 23:48:45 +00:00
|
|
|
</motion.div>
|
2026-01-13 18:47:57 +00:00
|
|
|
</div>
|
|
|
|
|
);
|
2026-01-07 09:31:02 +00:00
|
|
|
};
|