diff --git a/frontend/src/components/PackageCard.jsx b/frontend/src/components/PackageCard.jsx index a52a519..47d8b4b 100644 --- a/frontend/src/components/PackageCard.jsx +++ b/frontend/src/components/PackageCard.jsx @@ -1,5 +1,5 @@ import { useNavigate } from 'react-router-dom'; -import { CheckCircle, AlertTriangle, Star, ArrowDownToLine } from 'lucide-react'; +import { CheckCircle, AlertTriangle, Star, ArrowRight } from 'lucide-react'; export default function PackageCard({ pkg }) { const navigate = useNavigate(); @@ -9,55 +9,61 @@ export default function PackageCard({ pkg }) { return (
navigate(`/package/${pkg.name}`)} role="button" tabIndex={0} onKeyDown={(e) => e.key === 'Enter' && navigate(`/package/${pkg.name}`)} > - {/* Top row: name + badge */} -
-
-
-

- {pkg.name} -

- {pkg.installed && } - {pkg.out_of_date && } +
+ {/* Top: Name and badges */} +
+
+
+

+ {pkg.name} +

+ {pkg.installed && } + {pkg.out_of_date && } +
+ + {pkg.version || '—'} +
- - {pkg.version || '—'} - + {sourceLabel}
- {sourceLabel} + + {/* Mid: Description */} +

+ {pkg.description || 'No description available'} +

- {/* Description */} -

- {pkg.description || 'No description available'} -

- - {/* Footer */} -
-
- {pkg.votes !== undefined && ( + {/* Bottom: Stats & Action */} +
+
+ {pkg.votes !== undefined && pkg.votes > 0 && ( - {pkg.votes} + {pkg.votes} )} {pkg.popularity > 0 && ( - {pkg.popularity.toFixed(2)} + Pop: {pkg.popularity.toFixed(1)} )}
- {pkg.installed ? ( - Installed - ) : ( - - Get - - )} + + + Details +
); diff --git a/frontend/src/components/SearchBar.jsx b/frontend/src/components/SearchBar.jsx index 7a088d1..d4b3483 100644 --- a/frontend/src/components/SearchBar.jsx +++ b/frontend/src/components/SearchBar.jsx @@ -10,7 +10,7 @@ export default function SearchBar({ onSearch, initialQuery = '' }) { }, [query, onSearch]); return ( -
+ * { animation: fadeIn 0.35s ease-out both; } -.stagger > *:nth-child(1) { animation-delay: 30ms; } -.stagger > *:nth-child(2) { animation-delay: 60ms; } -.stagger > *:nth-child(3) { animation-delay: 90ms; } -.stagger > *:nth-child(4) { animation-delay: 120ms; } -.stagger > *:nth-child(5) { animation-delay: 150ms; } -.stagger > *:nth-child(6) { animation-delay: 180ms; } -.stagger > *:nth-child(7) { animation-delay: 210ms; } -.stagger > *:nth-child(8) { animation-delay: 240ms; } -.stagger > *:nth-child(n+9) { animation-delay: 270ms; } - -/* ═══════════════════════════════════════════════ - Layout Structure + App Structure ═══════════════════════════════════════════════ */ .app-layout { display: flex; min-height: 100vh; - background: var(--bg-base); } .sidebar { @@ -223,24 +191,24 @@ body { left: 0; top: 0; bottom: 0; - width: 272px; + width: 280px; z-index: 50; display: flex; flex-direction: column; - padding: 28px 20px; - overflow-y: auto; + padding: 32px 24px; background: var(--bg-sidebar); - backdrop-filter: blur(24px) saturate(1.4); - -webkit-backdrop-filter: blur(24px) saturate(1.4); border-right: 1px solid var(--border-primary); + backdrop-filter: blur(20px); + -webkit-backdrop-filter: blur(20px); transition: transform var(--transition-spring), background var(--transition-normal); } .main-content { - margin-left: 272px; + margin-left: 280px; flex: 1; min-height: 100vh; - padding: 36px 48px; + padding: 40px 48px; + background-color: var(--bg-base); transition: margin-left var(--transition-spring); } @@ -258,21 +226,20 @@ body { } /* ═══════════════════════════════════════════════ - Nav Items + Sidebar Items ═══════════════════════════════════════════════ */ .nav-link { display: flex; align-items: center; - gap: 14px; - padding: 11px 16px; + gap: 12px; + padding: 10px 16px; border-radius: var(--radius-md); color: var(--text-secondary); text-decoration: none; - font-size: 0.9rem; + font-size: 0.92rem; font-weight: 500; transition: all var(--transition-fast); - position: relative; } .nav-link:hover { background: var(--accent-muted); @@ -283,20 +250,9 @@ body { color: var(--accent); font-weight: 600; } -.nav-link.active::before { - content: ''; - position: absolute; - left: 0; - top: 50%; - transform: translateY(-50%); - width: 3px; - height: 20px; - background: var(--accent); - border-radius: 0 var(--radius-full) var(--radius-full) 0; -} /* ═══════════════════════════════════════════════ - Card System + Cards & Elements ═══════════════════════════════════════════════ */ .card { @@ -313,74 +269,63 @@ body { cursor: pointer; } .card-interactive:hover { - transform: translateY(-4px); - box-shadow: var(--shadow-lg); + transform: translateY(-2px); + background: var(--bg-card-hover); border-color: var(--border-secondary); + box-shadow: var(--shadow-md); } -/* ═══════════════════════════════════════════════ - Badges - ═══════════════════════════════════════════════ */ - .badge { display: inline-flex; align-items: center; - gap: 4px; padding: 3px 10px; border-radius: var(--radius-full); - font-size: 0.68rem; + font-size: 0.7rem; font-weight: 700; - letter-spacing: 0.04em; + letter-spacing: 0.03em; text-transform: uppercase; } .badge-pacman { background: var(--accent-muted); color: var(--accent); + border: 1px solid rgba(2, 132, 199, 0.25); } .badge-aur { background: var(--amber-muted); color: var(--amber); + border: 1px solid rgba(245, 158, 11, 0.25); } .badge-installed { background: var(--green-muted); color: var(--green); + border: 1px solid rgba(16, 185, 129, 0.25); } -/* ═══════════════════════════════════════════════ - Buttons - ═══════════════════════════════════════════════ */ - +/* Buttons */ .btn { display: inline-flex; align-items: center; justify-content: center; gap: 8px; - padding: 10px 22px; + padding: 10px 20px; border-radius: var(--radius-md); - font-size: 0.85rem; + font-size: 0.88rem; font-weight: 600; - font-family: var(--font-sans); cursor: pointer; border: none; transition: all var(--transition-fast); - white-space: nowrap; } .btn:disabled { - opacity: 0.5; + opacity: 0.6; cursor: not-allowed; - transform: none !important; - box-shadow: none !important; } .btn-primary { background: var(--accent); - color: white; - box-shadow: 0 2px 12px var(--accent-glow); + color: #ffffff; } .btn-primary:hover:not(:disabled) { background: var(--accent-hover); - transform: translateY(-1px); - box-shadow: 0 4px 20px var(--accent-glow); } .btn-secondary { @@ -389,37 +334,32 @@ body { border: 1px solid var(--border-primary); } .btn-secondary:hover:not(:disabled) { - border-color: var(--border-secondary); background: var(--bg-tertiary); + border-color: var(--border-secondary); } .btn-danger { background: var(--red-muted); color: var(--red); - border: 1px solid rgba(239, 68, 68, 0.2); + border: 1px solid rgba(239, 68, 68, 0.3); } .btn-danger:hover:not(:disabled) { - background: rgba(239, 68, 68, 0.15); - border-color: rgba(239, 68, 68, 0.4); + background: rgba(239, 68, 68, 0.25); } .btn-ghost { background: transparent; color: var(--text-secondary); - padding: 8px 14px; } .btn-ghost:hover:not(:disabled) { - background: var(--bg-tertiary); + background: var(--bg-secondary); color: var(--text-primary); } -/* ═══════════════════════════════════════════════ - Inputs - ═══════════════════════════════════════════════ */ - +/* Inputs */ .input { width: 100%; - padding: 11px 16px; + padding: 10px 16px; background: var(--bg-input); border: 1px solid var(--border-primary); border-radius: var(--radius-md); @@ -429,41 +369,36 @@ body { outline: none; transition: all var(--transition-fast); } -.input::placeholder { color: var(--text-tertiary); } +.input::placeholder { + color: var(--text-tertiary); +} .input:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-glow); } -/* ═══════════════════════════════════════════════ - Typography - ═══════════════════════════════════════════════ */ - +/* Typography Helpers */ .page-title { - font-size: 1.75rem; + font-size: 1.8rem; font-weight: 800; - letter-spacing: -0.03em; + letter-spacing: -0.02em; color: var(--text-primary); - line-height: 1.2; } - .page-subtitle { font-size: 0.95rem; - color: var(--text-secondary); - margin-top: 4px; + color: var(--text-tertiary); } -/* ═══════════════════════════════════════════════ - Grids - ═══════════════════════════════════════════════ */ - +/* Layout Grids */ .pkg-grid { display: grid; - grid-template-columns: repeat(auto-fill, minmax(340px, 1fr)); - gap: 20px; + grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); + gap: 16px; } -@media (max-width: 720px) { - .pkg-grid { grid-template-columns: 1fr; } +@media (max-width: 640px) { + .pkg-grid { + grid-template-columns: 1fr; + } } .cat-grid { @@ -472,38 +407,33 @@ body { gap: 16px; } -/* ═══════════════════════════════════════════════ - Utility Components - ═══════════════════════════════════════════════ */ - +/* Shimmer Loader */ .shimmer { background: linear-gradient(90deg, var(--bg-secondary) 25%, var(--bg-tertiary) 50%, var(--bg-secondary) 75%); background-size: 200% 100%; - animation: shimmer 1.5s infinite; + animation: shimmer-anim 1.5s infinite; border-radius: var(--radius-md); } +@keyframes shimmer-anim { + 0% { background-position: -200% 0; } + 100% { background-position: 200% 0; } +} .spinner { - width: 28px; height: 28px; + width: 28px; + height: 28px; border: 3px solid var(--border-primary); border-top-color: var(--accent); border-radius: 50%; - animation: spin 0.7s linear infinite; + animation: spin-anim 0.8s linear infinite; +} +@keyframes spin-anim { + to { transform: rotate(360deg); } } -.divider { - height: 1px; - background: var(--border-primary); - border: none; -} - -/* ═══════════════════════════════════════════════ - Theme Toggle - ═══════════════════════════════════════════════ */ - +/* Theme Toggle Button */ .theme-toggle { - position: relative; width: 40px; height: 40px; border-radius: var(--radius-md); @@ -521,23 +451,3 @@ body { color: var(--text-primary); background: var(--bg-tertiary); } - -/* ═══════════════════════════════════════════════ - Decorative - ═══════════════════════════════════════════════ */ - -.gradient-text { - background: linear-gradient(135deg, var(--accent), var(--violet)); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - background-clip: text; -} - -.glow-ring { - position: absolute; - border-radius: 50%; - background: var(--accent); - opacity: 0.06; - filter: blur(60px); - pointer-events: none; -} diff --git a/frontend/src/layouts/MainLayout.jsx b/frontend/src/layouts/MainLayout.jsx index 75e11d2..844d313 100644 --- a/frontend/src/layouts/MainLayout.jsx +++ b/frontend/src/layouts/MainLayout.jsx @@ -42,37 +42,39 @@ export default function MainLayout() { setSidebarOpen(false)} />
- {/* ── Top Bar ── */} -
- {/* Mobile menu */} - +
+ {/* ── Top Bar ── */} +
+ {/* Mobile menu */} + - {/* Search */} -
- + {/* Search */} +
+ +
+ + {/* Theme toggle */} + +
+ + {/* ── Page ── */} +
+
- - {/* Theme toggle */} - -
- - {/* ── Page ── */} -
-
diff --git a/frontend/src/pages/Updates.jsx b/frontend/src/pages/Updates.jsx index b3f3c7a..2749893 100644 --- a/frontend/src/pages/Updates.jsx +++ b/frontend/src/pages/Updates.jsx @@ -95,12 +95,10 @@ export default function Updates() {
{updates.map((u, i) => (
e.currentTarget.style.background = 'var(--bg-card-hover)'} - onMouseLeave={(e) => e.currentTarget.style.background = 'transparent'} >