Skip to content

Commit 3cbe9b4

Browse files
committed
Styling on dedicated static pages
1 parent df1a0a4 commit 3cbe9b4

File tree

10 files changed

+290
-84
lines changed

10 files changed

+290
-84
lines changed

app/skybox/[slug]/page.tsx

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,29 @@ export async function generateStaticParams() {
99
return Object.keys(list).map((slug) => ({ slug }));
1010
}
1111

12+
// Function to count preview images
13+
function countPreviewImages(slug: string): number {
14+
const previewsDir = path.join(process.cwd(), 'public', 'skyboxes', slug, 'images', 'previews');
15+
try {
16+
const files = fs.readdirSync(previewsDir);
17+
// Count files that match the preview pattern (1.webp, 2.webp, etc.)
18+
return files.filter(file => /^\d+\.webp$/i.test(file)).length || 1; // Default to 1 if no previews found
19+
} catch (error) {
20+
console.error(`Error reading previews directory for ${slug}:`, error);
21+
return 1; // Default to 1 if there's an error
22+
}
23+
}
24+
1225
export default function Page({
13-
params, // 👈 promise!
26+
params,
1427
}: {
1528
params: Promise<{ slug: string }>;
1629
}) {
17-
const { slug } = use(params); // unwrap
30+
const { slug } = use(params);
1831

19-
const dataPath = path.join(process.cwd(), 'public', 'data', `${slug}.json`);
32+
const dataPath = path.join(process.cwd(), 'public', 'data', `${slug}.json`);
2033
const skyboxData = JSON.parse(fs.readFileSync(dataPath, 'utf8'));
34+
const previewCount = countPreviewImages(slug);
2135

22-
return <SkyboxClient slug={slug} skyboxData={skyboxData} />;
36+
return <SkyboxClient slug={slug} skyboxData={skyboxData} previewCount={previewCount} />;
2337
}

app/skybox/[slug]/skybox-client.tsx

Lines changed: 161 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
'use client';
22

3+
import { useState } from 'react';
34
import SunParams from '@/app/ui/sunparameters';
45
import FogParams from '@/app/ui/fogparameters';
56
import MapList from '@/app/ui/maplist';
@@ -9,87 +10,195 @@ import TechnicalDetails from '@/app/ui/technical-details';
910
interface SkyboxClientProps {
1011
slug: string;
1112
skyboxData: any;
13+
previewCount: number;
1214
}
1315

14-
export default function SkyboxClient({ slug, skyboxData }: SkyboxClientProps) {
16+
export default function SkyboxClient({ slug, skyboxData, previewCount }: SkyboxClientProps) {
17+
const [activeImage, setActiveImage] = useState(1);
18+
console.log(activeImage)
1519
const imgBase = `/Source_Skyboxes_NextJS/skyboxes/${slug}/images`;
20+
// Generate array of preview numbers based on previewCount
21+
const previews = Array.from({ length: previewCount }, (_, i) => i + 1);
1622

1723
return (
18-
<article className="max-w-4xl mx-auto">
19-
<div className="bg-neutral-900 rounded-lg shadow-xl ring-1 ring-neutral-700/60 overflow-hidden">
20-
{/* Header */}
21-
<div className="p-4">
22-
<div className="flex flex-wrap sm:flex-nowrap items-start sm:items-center justify-between gap-4">
23-
<div className="flex flex-col">
24-
<h1 className="text-2xl font-bold leading-tight">{slug}</h1>
24+
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
25+
{/* Header with Back Button */}
26+
<div className="mb-8">
27+
<button onClick={() => window.history.back()} className="inline-flex items-center text-neutral-400 hover:text-white transition-colors mb-6">
28+
<img src="/Source_Skyboxes_NextJS/icons/back.svg" alt="" className="invert w-5 h-5 mr-2" />
29+
Back to all skyboxes
30+
</button>
31+
32+
<div className="flex flex-col md:flex-row md:items-center md:justify-between gap-6">
33+
<div>
34+
<h1 className="text-3xl md:text-4xl font-bold bg-gradient-to-r from-blue-400 to-purple-500 bg-clip-text text-transparent">
35+
{/*{slug.replace(/_/g, ' ').replace(/\b\w/g, l => l.toUpperCase())}*/}
36+
{slug}
37+
</h1>
38+
<div className="mt-2 space-y-1">
2539
{skyboxData.author && (
26-
<span className="text-sm text-neutral-400">By {skyboxData.author}</span>
40+
<p className="text-lg text-neutral-300">
41+
Created by <span className="text-blue-400">{skyboxData.author}</span>
42+
</p>
43+
)}
44+
{skyboxData.license && (
45+
<p className="text-sm text-neutral-400">
46+
License:{' '}
47+
<a
48+
href={`https://creativecommons.org/licenses/${skyboxData.license.toLowerCase().replace(' ', '-')}/`}
49+
target="_blank"
50+
rel="noopener noreferrer"
51+
className="text-blue-400 hover:underline"
52+
>
53+
{skyboxData.license}
54+
</a>
55+
{skyboxData.publishDate && (
56+
<span className="text-neutral-500 text-xs ml-2">
57+
• Published {new Date(skyboxData.publishDate).toLocaleDateString('en-US', {
58+
year: 'numeric',
59+
month: 'short',
60+
day: 'numeric',
61+
})}
62+
</span>
63+
)}
64+
</p>
2765
)}
2866
</div>
29-
<DownloadButton
30-
href={`/Source_Skyboxes_NextJS/skyboxes/${slug}/downloads/${slug}.7z`}
31-
download
32-
size={skyboxData.fileSize}
33-
className="flex-shrink-0"
34-
/>
3567
</div>
68+
<DownloadButton
69+
href={`/Source_Skyboxes_NextJS/skyboxes/${slug}/downloads/${slug}.7z`}
70+
download
71+
size={skyboxData.fileSize}
72+
className="w-full md:w-auto"
73+
/>
3674
</div>
75+
</div>
3776

38-
{/* Preview Image */}
39-
<div className="relative w-full aspect-video bg-black">
40-
<img
41-
src={`${imgBase}/previews/1.webp`}
42-
alt={`${slug} skybox preview`}
43-
className="w-full h-full object-cover"
44-
/>
77+
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
78+
{/* Main Preview */}
79+
<div className="lg:col-span-2 space-y-6">
80+
<div className="relative w-full aspect-video bg-black rounded-xl overflow-hidden shadow-2xl">
81+
<img
82+
src={`${imgBase}/previews/${activeImage}.webp`}
83+
alt={`${slug} skybox preview ${activeImage}`}
84+
className="w-full h-full object-cover transition-opacity duration-300"
85+
/>
86+
<div className="absolute inset-0 bg-gradient-to-t from-black/80 to-transparent opacity-0 hover:opacity-100 transition-opacity flex items-end p-6">
87+
<p className="text-white text-sm">Preview angle: {activeImage}/{previews.length}</p>
88+
</div>
89+
</div>
90+
91+
{/* Thumbnail Grid */}
92+
<div className="grid grid-cols-6 gap-2">
93+
{previews.map((num) => (
94+
<button
95+
key={num}
96+
onClick={() => setActiveImage(num)}
97+
className={`aspect-square rounded-lg overflow-hidden transition-all ${
98+
activeImage === num
99+
? 'ring-2 ring-blue-500 ring-offset-2 ring-offset-neutral-900 transform scale-105'
100+
: 'opacity-70 hover:opacity-100'
101+
}`}
102+
>
103+
<img
104+
src={`${imgBase}/previews/${num}.webp`}
105+
alt={`Preview ${num}`}
106+
className="w-full h-full object-cover"
107+
/>
108+
</button>
109+
))}
110+
</div>
45111
</div>
46112

47-
{/* Content */}
48-
<div className="p-6 space-y-6">
113+
{/* Sidebar with Details */}
114+
<div className="space-y-8">
49115
{/* Description */}
50-
{skyboxData.description && (
51-
<p className="text-neutral-300">{skyboxData.description}</p>
52-
)}
53-
54-
{/* Technical Details
55-
<TechnicalDetails
56-
resolution={skyboxData.resolution}
57-
fileSize={skyboxData.fileSize}
58-
compatibility={skyboxData.compatibility}
59-
/>
116+
{/*
117+
<div className="bg-neutral-900/50 backdrop-blur-sm rounded-xl p-6 border border-neutral-800">
118+
<h2 className="text-xl font-semibold text-white mb-4">About this Skybox</h2>
119+
{skyboxData.description ? (
120+
<p className="text-neutral-300 leading-relaxed">{skyboxData.description}</p>
121+
) : (
122+
<p className="text-neutral-500 italic">No description available.</p>
123+
)}
124+
</div>
60125
*/}
61126

127+
{/* Technical Details */}
128+
<div className="bg-neutral-900/50 backdrop-blur-sm rounded-xl p-6 border border-neutral-800">
129+
<h2 className="text-xl font-semibold text-white mb-4">Technical Details</h2>
130+
<div className="grid grid-cols-2 gap-4">
131+
<div>
132+
<p className="text-sm text-neutral-400">Resolution</p>
133+
<p className="text-white">{skyboxData.resolution || '4096x4096'}</p>
134+
</div>
135+
<div>
136+
<p className="text-sm text-neutral-400">File Size</p>
137+
<p className="text-white">{skyboxData.fileSize || '~50MB'}</p>
138+
</div>
139+
<div>
140+
<p className="text-sm text-neutral-400">Format</p>
141+
<p className="text-white">.vtf/.vmt</p>
142+
</div>
143+
<div>
144+
<p className="text-sm text-neutral-400">Compatibility</p>
145+
<p className="text-white">Source Engine</p>
146+
</div>
147+
</div>
148+
</div>
149+
62150
{/* Sun Parameters */}
63151
{skyboxData.sunParameters && (
64-
<SunParams {...skyboxData.sunParameters} />
152+
<div className="bg-neutral-900/50 backdrop-blur-sm rounded-xl p-6 border border-neutral-800">
153+
<h2 className="text-xl font-semibold text-white mb-4">Sun Parameters</h2>
154+
<SunParams {...skyboxData.sunParameters} />
155+
</div>
65156
)}
66157

67158
{/* Fog Parameters */}
68159
{skyboxData.fogParameters && (
69-
<FogParams {...skyboxData.fogParameters} />
160+
<div className="bg-neutral-900/50 backdrop-blur-sm rounded-xl p-6 border border-neutral-800">
161+
<h2 className="text-xl font-semibold text-white mb-4">Fog Parameters</h2>
162+
<FogParams {...skyboxData.fogParameters} />
163+
</div>
70164
)}
71165

72-
{/* Map List */}
73-
{skyboxData.steamMaps && skyboxData.steamMaps.length > 0 && (
74-
<div>
75-
<h3 className="text-lg font-medium text-neutral-100 mb-4">Featured in</h3>
76-
<MapList maps={skyboxData.steamMaps} />
166+
{/* Categories
167+
{skyboxData.categories?.length > 0 && (
168+
<div className="bg-neutral-900/50 backdrop-blur-sm rounded-xl p-6 border border-neutral-800">
169+
<h2 className="text-xl font-semibold text-white mb-4">Categories</h2>
170+
<div className="flex flex-wrap gap-2">
171+
{skyboxData.categories.map((category: string) => (
172+
<span
173+
key={category}
174+
className="inline-flex items-center px-3 py-1.5 rounded-full text-sm font-medium
175+
bg-gradient-to-r from-blue-900/50 to-purple-900/50 text-blue-200
176+
border border-blue-800/30 hover:border-blue-600/50 transition-all cursor-pointer
177+
hover:bg-gradient-to-r hover:from-blue-800/50 hover:to-purple-800/50"
178+
>
179+
{category}
180+
</span>
181+
))}
182+
</div>
77183
</div>
78184
)}
185+
*/}
186+
187+
79188
</div>
80189
</div>
81190

82-
{/* Categories Section */}
83-
<div className="p-6 border-t border-neutral-800 mt-8">
84-
<h3 className="text-lg font-medium text-neutral-100 mb-4">Categories</h3>
85-
<div className="flex flex-wrap gap-2">
86-
{skyboxData.categories?.map((category: string) => (
87-
<span key={category} className="inline-flex items-center px-3 py-1 rounded-full text-sm font-medium bg-neutral-800 text-neutral-300">
88-
{category}
89-
</span>
90-
))}
191+
{/* Featured Maps */}
192+
{skyboxData.steamMaps && skyboxData.steamMaps.length > 0 && (
193+
<div className="mt-16">
194+
<div className="flex items-center justify-between mb-6">
195+
<h2 className="text-2xl font-bold bg-gradient-to-r from-blue-400 to-purple-500 bg-clip-text text-transparent">
196+
Featured in these maps
197+
</h2>
198+
</div>
199+
<MapList maps={skyboxData.steamMaps} />
91200
</div>
92-
</div>
93-
</article>
201+
)}
202+
</div>
94203
);
95204
}

app/ui/downloadbutton.tsx

Lines changed: 35 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -19,37 +19,44 @@ export default function DownloadButton({
1919
<a
2020
{...anchorProps}
2121
className={`
22-
inline-flex items-center gap-3
23-
rounded-md
24-
bg-neutral-800
25-
px-4 py-2
26-
ring-1 ring-inset ring-black/40
27-
transition
28-
hover:brightness-110 hover:shadow-lg
29-
active:scale-95
22+
group relative
23+
inline-flex items-center justify-center
24+
gap-2.5
25+
rounded-lg
26+
bg-gradient-to-br from-blue-600/90 to-purple-600/90
27+
px-5 py-2.5
28+
text-sm font-medium text-white
29+
shadow-md shadow-blue-500/20
30+
transition-all duration-200
31+
hover:shadow-lg hover:shadow-blue-500/30
32+
hover:brightness-110
33+
focus:outline-none focus:ring-2 focus:ring-blue-400 focus:ring-offset-2 focus:ring-offset-neutral-900
34+
active:scale-[0.98]
3035
${className}
3136
`}
3237
>
33-
<svg
34-
viewBox="0 0 24 24"
35-
aria-hidden="true"
36-
className="w-5 h-5 fill-current shrink-0"
37-
>
38-
<path d="M12 3a1 1 0 0 1 1 1v9.59l2.3-2.3a1 1 0 1 1 1.4 1.42l-4 4a1 1 0 0 1-1.4 0l-4-4a1 1 0 1 1 1.4-1.42L11 13.59V4a1 1 0 0 1 1-1z" />
39-
<path d="M5 19a1 1 0 0 1 1-1h12a1 1 0 1 1 0 2H6a1 1 0 0 1-1-1z" />
40-
</svg>
41-
42-
<span className="whitespace-nowrap">
43-
{label}
44-
{(format || size) && (
45-
<span className="font-normal">
46-
{' '}
47-
( {format ?? ''}
48-
{format && size ? ' • ' : ''}
49-
{size ?? ''}
50-
)
51-
</span>
52-
)}
38+
{/* Shine effect on hover */}
39+
<span
40+
className="absolute inset-0 rounded-lg bg-gradient-to-r from-white/20 via-transparent to-transparent
41+
opacity-0 group-hover:opacity-100 transition-opacity duration-300 pointer-events-none"
42+
/>
43+
44+
<span className="relative flex items-center gap-2">
45+
<img
46+
src="/Source_Skyboxes_NextJS/icons/download.svg"
47+
alt=""
48+
className="w-4 h-4 shrink-0 opacity-90 group-hover:opacity-100 transition-opacity invert brightness-0"
49+
/>
50+
<span className="whitespace-nowrap font-medium">
51+
{label}
52+
{(format || size) && (
53+
<span className="font-normal opacity-90 ml-1.5">
54+
({format ?? ''}
55+
{format && size ? ' • ' : ''}
56+
{size ?? ''})
57+
</span>
58+
)}
59+
</span>
5360
</span>
5461
</a>
5562
);

0 commit comments

Comments
 (0)