Skip to content

Commit cbff77d

Browse files
committed
Modal formatting updates
1 parent d9c0afe commit cbff77d

File tree

5 files changed

+93
-91
lines changed

5 files changed

+93
-91
lines changed

app/ui/fogparameters.tsx

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,28 @@ import { ParamSection, ParamRow } from './parametersections';
44
type Fog = { primaryFogColor?: number[]; secondaryFogColor?: number[] };
55

66
export default function FogParams(f: Fog) {
7-
if (!f || (!f.primaryFogColor && !f.secondaryFogColor)) return null;
7+
const { primaryFogColor, secondaryFogColor } = f ?? {};
8+
9+
const noData = !primaryFogColor && !secondaryFogColor;
10+
811
return (
912
<ParamSection title="Fog Parameters">
10-
{f.primaryFogColor?.length && (
13+
{noData ? (
14+
<ParamRow label="">
15+
<span className="italic text-neutral-500">
16+
No data available.
17+
</span>
18+
</ParamRow>
19+
) : (
20+
<>
1121
<ParamRow label="Primary Fog Color">
12-
<Swatch rgb={f.primaryFogColor!}/>
22+
{primaryFogColor && <Swatch rgb={primaryFogColor} />}
1323
</ParamRow>
14-
)}
15-
{f.secondaryFogColor?.length && (
1624
<ParamRow label="Secondary Fog Color">
17-
<Swatch rgb={f.secondaryFogColor!}/>
25+
{secondaryFogColor && <Swatch rgb={secondaryFogColor} />}
1826
</ParamRow>
19-
)}
27+
</>
28+
)}
2029
</ParamSection>
2130
);
22-
}
31+
}

app/ui/modal.tsx

Lines changed: 36 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -16,89 +16,78 @@ type Meta = {
1616
fileSize?: string;
1717
};
1818

19-
function EnvironmentPanel({
20-
sun,
21-
fog,
22-
}: {
23-
sun: Parameters<typeof SunParams>[0];
24-
fog: Parameters<typeof FogParams>[0];
25-
}) {
26-
return (
27-
<div
28-
className="
29-
grid gap-10
30-
lg:grid-cols-2 /* ≥1024 px: two columns */
31-
lg:gap-x-12
32-
"
33-
>
34-
<SunParams {...sun} />
35-
<FogParams {...fog} />
36-
</div>
37-
);
19+
function useModalBehaviour(onClose: () => void) {
20+
useEffect(() => {
21+
const prev = document.documentElement.style.overflow;
22+
document.documentElement.style.overflow = 'hidden';
23+
return () => (document.documentElement.style.overflow = prev);
24+
}, []);
25+
26+
useEffect(() => {
27+
const h = (e: KeyboardEvent) => e.key === 'Escape' && onClose();
28+
window.addEventListener('keydown', h);
29+
return () => window.removeEventListener('keydown', h);
30+
}, [onClose]);
3831
}
3932

4033
export default function Modal({ slug, onClose }: { slug: string; onClose: () => void }) {
4134
const [meta, setMeta] = useState<Meta | null>(null);
4235
const imgBase = `/Source_Skyboxes_NextJS/skyboxes/${slug}/images`;
43-
36+
4437
useEffect(() => { fetch(`/Source_Skyboxes_NextJS/data/${slug}.json`).then(r=>r.ok?r.json():null).then(setMeta); }, [slug]);
45-
useEffect(() => { const o=document.documentElement.style.overflow; document.documentElement.style.overflow='hidden'; return ()=>{document.documentElement.style.overflow=o}},[]);
46-
useEffect(() => { const h=(e:KeyboardEvent)=>e.key==='Escape'&&onClose(); window.addEventListener('keydown',h); return ()=>window.removeEventListener('keydown',h)},[onClose]);
38+
useModalBehaviour(onClose);
4739

4840
return (
4941
<div onClick={onClose} className="fixed inset-0 z-50 bg-black/75 backdrop-blur-sm flex items-center justify-center p-4">
5042
<article onClick={e=>e.stopPropagation()} className="w-full max-w-[90vw] sm:max-w-xl md:max-w-2xl lg:max-w-3xl xl:max-w-4xl max-h-[70vh] overflow-y-auto overscroll-contain bg-neutral-900 rounded-lg shadow-xl ring-1 ring-neutral-700/60">
51-
<div className="m-4">
52-
5343
{/* Header */}
54-
<div className="flex items-center justify-between">
44+
<div className="flex items-center justify-between p-4">
5545

5646
{/* Title */}
57-
<div>
58-
<h2 className="text-xl font-bold">{slug}</h2>
47+
<div className="flex flex-col">
48+
<h2 className="text-2xl font-bold">{slug}</h2>
49+
{/* Author */}
5950
<span className="text-sm text-neutral-400">By {meta?.author}</span>
6051
</div>
6152

6253
{/* Download Button */}
63-
<div className="flex items-center">
54+
<div className="flex">
6455
<DownloadButton
6556
href={`/Source_Skyboxes_NextJS/skyboxes/${slug}/download/${slug}.7z`}
6657
download
67-
//format=".7z"
6858
size={meta?.fileSize}
6959
/>
7060
</div>
7161
</div>
7262

7363
{/* Preview */}
74-
<div className="relative w-full aspect-[16/9] mb-6 mt-2">
75-
<img src={`${imgBase}/previews/1.webp`} alt="" className="absolute inset-0 w-full h-full object-cover rounded-md" />
64+
<div className="p-4 relative w-full aspect-[16/9]">
65+
<img src={`${imgBase}/previews/1.webp`} alt={`${slug} preview`} className="w-full h-full object-cover rounded-md" />
7666
</div>
7767

7868
{/* Tabs */}
79-
<div className="lg:grid lg:grid-cols-[1fr_auto]">
69+
<div className="lg:grid lg:grid-cols-[1fr_auto] p-4">
8070
<Tabs items={[
8171
{
8272
value: 'environment',
8373
label: 'Environment Parameters',
8474
content: (
8575
<div
86-
className="
87-
grid gap-10
88-
lg:grid-cols-2 lg:gap-x-12
89-
items-start /* top-align all children */
90-
"
91-
>
92-
<SunParams {...meta?.sunParameters} />
93-
<FogParams {...meta?.fogParameters} />
94-
</div>
95-
),
96-
},
97-
{ value: 'community-maps', label: 'Community Maps', content: <MapList maps={meta?.steamMaps} /> },
98-
]} />
76+
className="
77+
grid gap-10
78+
lg:grid-cols-2 lg:gap-x-12
79+
items-start
80+
"
81+
>
82+
<SunParams {...meta?.sunParameters} />
83+
<FogParams {...meta?.fogParameters} />
84+
</div>
85+
),
86+
},
87+
{ value: 'community-maps', label: 'Community Maps', content: <MapList maps={meta?.steamMaps} /> },
88+
]} />
9989
</div>
100-
101-
</div>
90+
10291
</article>
10392
</div>
10493
);

app/ui/parametersections.tsx

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,20 @@ export function ParamSection({
3434
}
3535

3636
export function ParamRow({
37-
label,
38-
children,
39-
}: {
40-
label: string;
41-
children: ReactNode;
42-
}) {
43-
return (
44-
<>
45-
<dt className="text-neutral-400 font-medium">{label}</dt>
46-
<dd className="text-neutral-100">{children}</dd>
47-
</>
48-
);
49-
}
37+
label,
38+
children,
39+
}: {
40+
label: string;
41+
children?: ReactNode; /* ⬅️ now optional */
42+
}) {
43+
return (
44+
<>
45+
<dt className="text-neutral-400 font-medium">{label}</dt>
46+
<dd className="text-neutral-100">
47+
{children ?? (
48+
<span className="italic text-neutral-500">N/A</span>
49+
)}
50+
</dd>
51+
</>
52+
);
53+
}

app/ui/sunparameters.tsx

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,28 +9,33 @@ type Sun = {
99
};
1010

1111
export default function SunParams(s: Sun) {
12-
if (!s) return null;
12+
const { sunAngle, pitch, brightness, ambience } = s ?? {};
1313

14-
const { sunAngle, pitch, brightness, ambience } = s;
15-
16-
if (!sunAngle && pitch === undefined && !brightness && !ambience) return null;
14+
const noData =
15+
sunAngle === undefined &&
16+
pitch === undefined &&
17+
!brightness &&
18+
!ambience;
1719

1820
return (
1921
<ParamSection title="Sun Parameters">
20-
{sunAngle && <ParamRow label="Sun Angle">{sunAngle}</ParamRow>}
21-
22-
{pitch !== undefined && <ParamRow label="Pitch">{pitch}</ParamRow>}
23-
24-
{brightness && (
25-
<ParamRow label="Brightness">
26-
<Swatch rgb={brightness} />
27-
</ParamRow>
28-
)}
29-
30-
{ambience && (
31-
<ParamRow label="Ambient">
32-
<Swatch rgb={ambience} />
22+
{noData ? (
23+
<ParamRow label="">
24+
<span className="italic text-neutral-500">
25+
No data available.
26+
</span>
3327
</ParamRow>
28+
) : (
29+
<>
30+
<ParamRow label="Sun Angle">{sunAngle}</ParamRow>
31+
<ParamRow label="Pitch">{pitch}</ParamRow>
32+
<ParamRow label="Brightness">
33+
{brightness && <Swatch rgb={brightness} />}
34+
</ParamRow>
35+
<ParamRow label="Ambient">
36+
{ambience && <Swatch rgb={ambience} />}
37+
</ParamRow>
38+
</>
3439
)}
3540
</ParamSection>
3641
);

app/ui/tabs.tsx

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,13 @@
33
import { useState, ReactNode } from 'react';
44

55
export interface TabItem {
6-
/** unique key for this tab */
76
value: string;
8-
/** the button label */
97
label: string;
10-
/** what to render when active */
118
content: ReactNode;
129
}
1310

1411
export interface TabsProps {
15-
/** list of tabs to show */
1612
items: TabItem[];
17-
/** which tab to open by default (falls back to the first) */
1813
defaultValue?: string;
1914
}
2015

@@ -26,7 +21,7 @@ export function Tabs({ items, defaultValue }: TabsProps) {
2621
return (
2722
<div className="w-full">
2823
{/* Full-width tab bar with equal-width buttons */}
29-
<div className="flex w-full divide-x divide-neutral-700/60 rounded-md p-1">
24+
<div className="flex w-full divide-x divide-neutral-700/60 rounded-md">
3025
{items.map(({ value, label }) => {
3126
const isActive = value === active;
3227
return (

0 commit comments

Comments
 (0)