|
1 | | -import React, { useState, useEffect } from 'react'; |
2 | | -import { Link } from 'react-router-dom'; |
3 | | -import { ArrowLeft, ArrowRight, Star, Hash } from '@phosphor-icons/react'; |
4 | | -import { motion } from 'framer-motion'; |
5 | | -import Seo from '../components/Seo'; |
6 | | -import { appIcons } from '../utils/appIcons'; |
7 | | -import GenerativeArt from '../components/GenerativeArt'; |
8 | | - |
9 | | -const PinnedAppCard = ({ app, index }) => { |
10 | | - const Icon = appIcons[app.icon] || Star; |
11 | | - |
12 | | - return ( |
13 | | - <motion.div |
14 | | - whileHover={{ y: -5 }} |
15 | | - className="group relative flex flex-col overflow-hidden rounded-sm bg-zinc-900 border border-white/10 h-full" |
16 | | - > |
17 | | - <Link to={app.to} className="flex flex-col h-full"> |
18 | | - {/* Visual Header */} |
19 | | - <div className="relative h-48 w-full overflow-hidden border-b border-white/5"> |
20 | | - <GenerativeArt |
21 | | - seed={app.title + (app.icon || 'pinned')} |
22 | | - className="w-full h-full opacity-40 transition-transform duration-700 ease-out group-hover:scale-110" |
23 | | - /> |
24 | | - <div className="absolute inset-0 bg-gradient-to-t from-zinc-900 to-transparent" /> |
25 | | - |
26 | | - {/* Icon Overlay */} |
27 | | - <div className="absolute inset-0 flex items-center justify-center pointer-events-none"> |
28 | | - <div className="p-4 rounded-full bg-black/40 backdrop-blur-md border border-white/10 text-emerald-400 transform group-hover:scale-110 transition-transform duration-500"> |
29 | | - <Icon size={40} weight="duotone" /> |
30 | | - </div> |
31 | | - </div> |
32 | | - |
33 | | - {/* Rank Badge */} |
34 | | - <div className="absolute top-3 left-3 flex items-center gap-2 px-2 py-1 bg-black/60 backdrop-blur-md rounded border border-white/10"> |
35 | | - <span className="font-mono text-[10px] font-bold text-white uppercase tracking-widest"> |
36 | | - Rank {index + 1} |
37 | | - </span> |
38 | | - </div> |
39 | | - </div> |
40 | | - |
41 | | - {/* Content */} |
42 | | - <div className="flex flex-col flex-grow p-6"> |
43 | | - <div className="flex items-center gap-2 mb-3"> |
44 | | - <span className="font-mono text-[10px] text-gray-500 uppercase tracking-widest flex items-center gap-1"> |
45 | | - <Hash size={12} className="text-emerald-500" /> |
46 | | - ID: {String(app.pinned_order).padStart(3, '0')} |
47 | | - </span> |
48 | | - <span className="text-gray-700 text-[10px]">•</span> |
49 | | - <span className="font-mono text-[10px] text-emerald-500 uppercase tracking-widest"> |
50 | | - Pinned |
51 | | - </span> |
52 | | - </div> |
53 | | - |
54 | | - <h3 className="text-2xl font-bold font-sans uppercase text-white mb-3 group-hover:text-emerald-400 transition-colors tracking-tight"> |
55 | | - {app.title} |
56 | | - </h3> |
57 | | - |
58 | | - <p className="text-sm text-gray-400 line-clamp-3 leading-relaxed mb-6 flex-grow font-sans"> |
59 | | - {app.description} |
60 | | - </p> |
61 | | - |
62 | | - <div className="mt-auto pt-4 flex items-center justify-between border-t border-white/5"> |
63 | | - <span className="text-[10px] font-mono font-bold uppercase tracking-widest text-gray-500 group-hover:text-white transition-colors"> |
64 | | - Open Application |
65 | | - </span> |
66 | | - <ArrowRight |
67 | | - weight="bold" |
68 | | - size={16} |
69 | | - className="text-emerald-500 transform -translate-x-2 opacity-0 transition-all duration-300 group-hover:translate-x-0 group-hover:opacity-100" |
70 | | - /> |
71 | | - </div> |
72 | | - </div> |
73 | | - </Link> |
74 | | - </motion.div> |
75 | | - ); |
76 | | -}; |
| 1 | +import React from 'react'; |
| 2 | +import { useVisualSettings } from '../context/VisualSettingsContext'; |
| 3 | +import BrutalistPinnedAppPage from './brutalist-views/BrutalistPinnedAppPage'; |
| 4 | +import LuxePinnedAppsPage from './luxe-views/LuxePinnedAppsPage'; |
77 | 5 |
|
78 | 6 | const PinnedAppPage = () => { |
79 | | - const [pinnedApps, setPinnedApps] = useState([]); |
80 | | - const [isLoading, setIsLoading] = useState(true); |
81 | | - |
82 | | - useEffect(() => { |
83 | | - fetch('/apps/apps.json') |
84 | | - .then((res) => res.json()) |
85 | | - .then((data) => { |
86 | | - const allApps = Object.values(data).flatMap((cat) => |
87 | | - cat.apps.map((app) => ({ ...app, categoryName: cat.name })), |
88 | | - ); |
89 | | - const pinned = allApps |
90 | | - .filter((app) => app.pinned_order) |
91 | | - .sort((a, b) => a.pinned_order - b.pinned_order); |
92 | | - setPinnedApps(pinned); |
93 | | - }) |
94 | | - .catch((err) => console.error(err)) |
95 | | - .finally(() => setIsLoading(false)); |
96 | | - }, []); |
97 | | - |
98 | | - return ( |
99 | | - <div className="min-h-screen bg-[#050505] text-white selection:bg-emerald-500/30"> |
100 | | - <Seo |
101 | | - title="Featured Apps | Fezcodex" |
102 | | - description="A curated selection of core tools and essential applications." |
103 | | - keywords={['pinned', 'apps', 'tools', 'featured', 'core']} |
104 | | - /> |
105 | | - <div className="mx-auto max-w-7xl px-6 py-24 md:px-12"> |
106 | | - {/* Header Section */} |
107 | | - <header className="mb-20 text-center md:text-left"> |
108 | | - <Link |
109 | | - to="/apps" |
110 | | - className="mb-12 inline-flex items-center gap-2 text-xs font-mono text-gray-500 hover:text-white transition-colors uppercase tracking-widest" |
111 | | - > |
112 | | - <ArrowLeft weight="bold" /> |
113 | | - <span>All Applications</span> |
114 | | - </Link> |
115 | | - |
116 | | - <div className="flex flex-col gap-4"> |
117 | | - <h1 className="text-6xl md:text-8xl font-black tracking-tighter text-white mb-4 leading-none uppercase"> |
118 | | - Featured |
119 | | - </h1> |
120 | | - <p className="text-gray-400 font-mono text-sm max-w-2xl uppercase tracking-[0.2em] leading-relaxed mx-auto md:mx-0"> |
121 | | - A curated collection of essential tools and high-performance |
122 | | - modules. |
123 | | - </p> |
124 | | - </div> |
125 | | - </header> |
| 7 | + const { fezcodexTheme } = useVisualSettings(); |
126 | 8 |
|
127 | | - {isLoading ? ( |
128 | | - <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8"> |
129 | | - {[...Array(6)].map((_, i) => ( |
130 | | - <div |
131 | | - key={i} |
132 | | - className="h-80 w-full bg-white/5 border border-white/10 rounded-sm animate-pulse" |
133 | | - /> |
134 | | - ))} |
135 | | - </div> |
136 | | - ) : ( |
137 | | - <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8 auto-rows-fr"> |
138 | | - {pinnedApps.map((app, index) => ( |
139 | | - <motion.div |
140 | | - key={app.slug} |
141 | | - initial={{ opacity: 0, y: 20 }} |
142 | | - animate={{ opacity: 1, y: 0 }} |
143 | | - transition={{ duration: 0.4, delay: index * 0.05 }} |
144 | | - > |
145 | | - <PinnedAppCard app={app} index={index} /> |
146 | | - </motion.div> |
147 | | - ))} |
148 | | - </div> |
149 | | - )} |
| 9 | + if (fezcodexTheme === 'luxe') { |
| 10 | + return <LuxePinnedAppsPage />; |
| 11 | + } |
150 | 12 |
|
151 | | - {!isLoading && pinnedApps.length === 0 && ( |
152 | | - <div className="py-32 text-center font-mono text-gray-600 uppercase tracking-widest border border-dashed border-white/10"> |
153 | | - No featured applications found. |
154 | | - </div> |
155 | | - )} |
156 | | - </div> |
157 | | - </div> |
158 | | - ); |
| 13 | + return <BrutalistPinnedAppPage />; |
159 | 14 | }; |
160 | 15 |
|
161 | 16 | export default PinnedAppPage; |
0 commit comments