feat(structures): hero image header on structure detail page
When the structure type has an image, render it as a full-bleed cover behind the page header with vertical and horizontal gradient overlays; text shifts to white for contrast. Headers without an image keep the previous plain layout.
This commit is contained in:
parent
fff9e82d62
commit
802873c7fa
1 changed files with 40 additions and 7 deletions
|
|
@ -72,6 +72,12 @@ export default async function StructureDetailPage({ params }: StructureDetailPag
|
||||||
? convertLexicalToPlaintext({ data: structureType.description })
|
? convertLexicalToPlaintext({ data: structureType.description })
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
|
const image =
|
||||||
|
typeof structureType.image === "object" && structureType.image !== null
|
||||||
|
? structureType.image
|
||||||
|
: null;
|
||||||
|
const imageUrl = image?.url ?? null;
|
||||||
|
|
||||||
const totalValue = storedResources.reduce((sum, entry) => {
|
const totalValue = storedResources.reduce((sum, entry) => {
|
||||||
const resource = entry.resource as Resource;
|
const resource = entry.resource as Resource;
|
||||||
if (!resource || typeof resource === "number") return sum;
|
if (!resource || typeof resource === "number") return sum;
|
||||||
|
|
@ -80,22 +86,49 @@ export default async function StructureDetailPage({ params }: StructureDetailPag
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="p-5 flex flex-col gap-6 max-w-7xl">
|
<div className="p-5 flex flex-col gap-6 max-w-7xl">
|
||||||
<div className="flex flex-col gap-3">
|
<header
|
||||||
|
className={`relative flex flex-col gap-3 overflow-hidden rounded-lg${
|
||||||
|
imageUrl ? " min-h-[280px] justify-between border border-border p-5" : ""
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{imageUrl ? (
|
||||||
|
<>
|
||||||
|
<img
|
||||||
|
src={imageUrl}
|
||||||
|
alt={structure.name}
|
||||||
|
fetchPriority="high"
|
||||||
|
className="absolute inset-0 size-full object-cover"
|
||||||
|
/>
|
||||||
|
<div className="absolute inset-0 bg-gradient-to-b from-black/50 via-black/40 to-background" />
|
||||||
|
<div className="absolute inset-0 bg-gradient-to-r from-black/30 via-transparent to-black/40" />
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
|
|
||||||
<Link
|
<Link
|
||||||
href="/logistics"
|
href="/logistics"
|
||||||
className="text-sm text-muted-foreground hover:text-primary transition-colors flex items-center gap-1 w-fit"
|
className="relative z-10 text-sm text-muted-foreground hover:text-primary transition-colors flex items-center gap-1 w-fit"
|
||||||
>
|
>
|
||||||
<ArrowLeftIcon className="size-3" />
|
<ArrowLeftIcon className="size-3" />
|
||||||
Back to Structures
|
Back to Structures
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
<div className="flex items-start justify-between gap-4">
|
<div className="relative z-10 flex items-start justify-between gap-4">
|
||||||
<div className="flex flex-col gap-1">
|
<div className="flex flex-col gap-1">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<Building2Icon className="size-5 text-muted-foreground" />
|
<Building2Icon
|
||||||
<h1 className="text-lg font-semibold">{structure.name}</h1>
|
className={`size-5 ${imageUrl ? "text-white/80" : "text-muted-foreground"}`}
|
||||||
|
/>
|
||||||
|
<h1
|
||||||
|
className={`text-lg font-semibold ${imageUrl ? "text-white drop-shadow-md" : ""}`}
|
||||||
|
>
|
||||||
|
{structure.name}
|
||||||
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-2 text-sm text-muted-foreground">
|
<div
|
||||||
|
className={`flex items-center gap-2 text-sm ${
|
||||||
|
imageUrl ? "text-white/70" : "text-muted-foreground"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
<span>{structureType.name}</span>
|
<span>{structureType.name}</span>
|
||||||
<span>·</span>
|
<span>·</span>
|
||||||
<span>{getCategoryLabel(structureType.category)}</span>
|
<span>{getCategoryLabel(structureType.category)}</span>
|
||||||
|
|
@ -116,7 +149,7 @@ export default async function StructureDetailPage({ params }: StructureDetailPag
|
||||||
{user && <ManageStorageButton structureId={structure.id} />}
|
{user && <ManageStorageButton structureId={structure.id} />}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</header>
|
||||||
|
|
||||||
{description && <p className="text-sm text-muted-foreground">{description}</p>}
|
{description && <p className="text-sm text-muted-foreground">{description}</p>}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue