field-guide / src /lib /components /partner /PartnerPage.svelte
pngwn
Add partner logos, nav popout menu, FAQ updates; fix scroll-spy
560169d
Raw
History Blame Contribute Delete
9.36 kB
<script lang="ts">
import type { PartnerData } from '$lib/data/partners';
import { RESOURCE_GLYPH } from '$lib/data/partners';
import { PARTNER_LOGOS } from '$lib/data/content';
import Icon from '../Icon.svelte';
import StampBadge from '../StampBadge.svelte';
import TopoBackdrop from '../TopoBackdrop.svelte';
import LinkRow from '../LinkRow.svelte';
import ModelCard from './ModelCard.svelte';
import CapabilityCard from './CapabilityCard.svelte';
interface Props {
data: PartnerData;
}
let { data }: Props = $props();
const isModels = $derived(data.type === 'models');
const hasCatalog = $derived(
isModels ? !!data.models?.length : !!data.capabilities?.length
);
const hasResources = $derived(!!data.resources?.length || !!data.starterSpace);
// 01..0n section numbering, skipping sections that aren't rendered
const labels = $derived.by(() => {
let n = 0;
const next = () => String(++n).padStart(2, '0');
return {
offer: next(),
catalog: hasCatalog ? next() : '',
guide: data.guide?.length ? next() : '',
resources: hasResources ? next() : '',
prize: data.prize ? next() : '',
support: data.support?.length ? next() : ''
};
});
</script>
<svelte:head>
<title>{data.name} · Build Small</title>
</svelte:head>
<div class="app-root" style="--paccent:{data.accent}">
<!-- top bar / breadcrumb -->
<nav class="pbar">
<div class="wrap pbar__inner">
<div class="crumb">
<a href="/">Build Small</a>
<span class="crumb__sep">/</span>
<a href="/#partners">Partners</a>
<span class="crumb__sep">/</span>
<b>{data.name}</b>
</div>
<a
class="btn btn--accent"
href="/"
style="margin-left:auto;padding:8px 15px;font-size:13px;background:var(--paccent);border-color:var(--paccent)"
>
<Icon name="arrow" size={14} stroke="#fff" rotate={180} /> Back to hub
</a>
</div>
</nav>
<!-- header -->
<header class="phead">
<TopoBackdrop opacity={0.1} stroke="var(--paccent)" />
<div class="wrap phead__grid" style="position:relative">
<div>
<div style="display:flex;align-items:center;gap:14px;flex-wrap:wrap">
<div class="plogo"><img src={PARTNER_LOGOS[data.id]} alt={data.name} loading="lazy" /></div>
<span class="psize-chip"><Icon name="cube" size={14} stroke="var(--paccent)" /> {data.sizeRange}</span>
</div>
<h1 class="display" style="font-size:clamp(40px,6vw,72px);margin-top:22px">{data.name}</h1>
<p class="lede" style="margin-top:18px;max-width:52ch">{data.tagline}</p>
<LinkRow
links={data.links && Object.keys(data.links).length ? data.links : { website: data.url }}
accent="var(--paccent)"
style="margin-top:24px"
/>
</div>
{#if data.prize}
<div class="floaty"><StampBadge glyph="star" accent="var(--paccent)" size={132} /></div>
{/if}
</div>
</header>
<!-- what they offer -->
<section class="section section--tight">
<div class="wrap">
<div class="section-label"><span class="coord">{labels.offer}</span><span class="eyebrow">What they offer</span></div>
<p
class="display"
style="font-weight:600;font-stretch:106%;font-size:clamp(22px,3vw,32px);line-height:1.18;text-wrap:pretty;max-width:900px"
>
{data.offer}
</p>
</div>
</section>
<!-- models / capabilities -->
{#if hasCatalog}
<section class="section section--tight">
<div class="wrap">
<div class="section-label"><span class="coord">{labels.catalog}</span><span class="eyebrow">{isModels ? 'Models & products' : 'Capabilities'}</span></div>
<h2 class="display" style="font-size:clamp(28px,4vw,44px);margin-bottom:28px">
{isModels ? 'The kit, sized small' : 'What you can run'}
</h2>
<div class="pcards">
{#if isModels}
{#each data.models ?? [] as m (m.name)}<ModelCard {m} />{/each}
{:else}
{#each data.capabilities ?? [] as c (c.name)}<CapabilityCard {c} />{/each}
{/if}
</div>
</div>
</section>
{/if}
<!-- selection guide -->
{#if data.guide?.length}
<section class="section section--tight">
<div class="wrap">
<div class="section-label"><span class="coord">{labels.guide}</span><span class="eyebrow">Build this with us</span></div>
<h2 class="display" style="font-size:clamp(28px,4vw,44px);margin-bottom:28px">If you want to build…</h2>
<div class="guide" style="max-width:940px">
{#each data.guide as g, i (i)}
<div class="guide__row">
<div class="guide__want"><b>{g.want}</b></div>
<div class="guide__arrow"><Icon name="arrow" size={22} stroke="var(--paccent)" /></div>
<div class="guide__use"><b>{g.use}</b><span class="coord">{g.note}</span></div>
</div>
{/each}
</div>
</div>
</section>
{/if}
<!-- getting started -->
{#if hasResources}
<section class="section section--tight">
<div class="wrap">
<div class="section-label"><span class="coord">{labels.resources}</span><span class="eyebrow">Getting started</span></div>
{#if data.resources?.length}
<div class="reslist">
{#each data.resources as r (r.label)}
<a class="resitem" href={r.url} target="_blank" rel="noreferrer">
<span class="resitem__glyph"><Icon name={RESOURCE_GLYPH[r.kind] || 'link'} size={19} stroke="var(--paccent)" /></span>
<span style="font-weight:600;font-family:var(--font-display);font-stretch:104%">{r.label}</span>
<span class="resitem__arrow"><Icon name="arrow" size={17} stroke="var(--ink-faint)" /></span>
</a>
{/each}
</div>
{/if}
{#if data.starterSpace}
<div class="starter" style="margin-top:18px">
<StampBadge glyph="play" accent="var(--paccent)" size={72} spin={false} />
<div style="flex:1">
<div class="coord" style="color:var(--paccent)">STARTER SPACE</div>
<div class="display" style="font-size:21px;margin-top:4px;font-stretch:106%">{data.starterSpace.name}</div>
<p style="color:var(--ink-2);font-size:14.5px;margin:6px 0 0">{data.starterSpace.desc}</p>
</div>
<a
class="btn btn--accent"
href={data.starterSpace.url}
target="_blank"
rel="noreferrer"
style="background:var(--paccent);border-color:var(--paccent);flex:none"
>
Fork it <Icon name="arrow" size={16} stroke="#fff" />
</a>
</div>
{/if}
</div>
</section>
{/if}
<!-- eligible prize -->
{#if data.prize}
<section class="section section--tight">
<div class="wrap">
<div class="section-label"><span class="coord">{labels.prize}</span><span class="eyebrow">Eligible prize</span></div>
<div class="pprize">
<TopoBackdrop opacity={0.07} stroke="rgba(51,49,43,.5)" />
<div style="position:relative"><StampBadge glyph="star" accent="var(--amber)" size={104} /></div>
<div style="position:relative">
<div class="coord" style="color:var(--amber-deep)">{data.name.toUpperCase()} · SPONSOR PRIZE</div>
<h3 class="display" style="font-size:clamp(26px,3.4vw,38px);margin-top:6px">{data.prize.title}</h3>
<p style="margin-top:12px;font-size:15.5px;color:var(--ink-2);max-width:52ch">
<b style="font-family:var(--font-display)">To qualify · </b>{data.prize.criteria}
</p>
</div>
<div style="position:relative;text-align:right">
<div class="display" style="font-size:clamp(30px,4vw,46px);color:var(--amber);line-height:1">{data.prize.award}</div>
<a href="/#prizes" class="chip" style="margin-top:12px;border-color:var(--ink)">
All prizes <Icon name="arrow" size={14} />
</a>
</div>
</div>
</div>
</section>
{/if}
<!-- support -->
{#if data.support?.length}
<section class="section section--tight" style="padding-bottom:84px">
<div class="wrap">
<div class="section-label"><span class="coord">{labels.support}</span><span class="eyebrow">How to get help</span></div>
<h2 class="display" style="font-size:clamp(28px,4vw,44px);margin-bottom:28px">Stuck? Holler.</h2>
<div class="support">
{#each data.support as s (s.channel + s.handle)}
<a class="supitem" href={s.url ?? '#'} target={s.url ? '_blank' : undefined} rel={s.url ? 'noreferrer' : undefined}>
<span class="supitem__glyph"><Icon name={s.glyph} size={22} stroke="#fff" /></span>
<span>
<div style="font-weight:600;font-family:var(--font-display);font-stretch:104%">{s.channel}</div>
<div class="supitem__handle">{s.handle}</div>
</span>
</a>
{/each}
</div>
</div>
</section>
{/if}
<!-- footer -->
<footer class="footer">
<TopoBackdrop opacity={0.08} stroke="rgba(244,238,225,.4)" />
<div
class="wrap"
style="position:relative;display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:24px"
>
<div>
<div class="display" style="font-size:26px">BUILD SMALL</div>
<p style="color:rgba(244,238,225,.7);margin-top:8px;font-size:14px">Build something small, local, and yours.</p>
</div>
<div style="display:flex;gap:12px;flex-wrap:wrap">
<a class="btn btn--ghost" href="/#partners" style="color:var(--paper);border-color:rgba(244,238,225,.4)">All partners</a>
<a class="btn btn--accent" href="/#recommender" style="background:var(--paccent);border-color:var(--paccent)">
Find your kit <Icon name="arrow" size={16} stroke="#fff" />
</a>
</div>
</div>
</footer>
</div>