feat(deck): entity + ecosystem slides and 16-slide registry
Title becomes the 3-way collaboration; new EntitiesSlide (three partners), per-entity deep-dives (Archipelago/Solunar/Chateau) via a shared EntityDetail, and an EcosystemSlide selling the identical membership/kiosk/ app experience at every location. Deck registry reordered to 16 slides. (Old Locations/City/Farm slides + LocationDetail were removed in the preceding commit.) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
673d937abe
commit
7acc2b550d
8 changed files with 205 additions and 14 deletions
|
|
@ -8,9 +8,11 @@ import TitleSlide from './slides/TitleSlide.vue'
|
||||||
import VisionSlide from './slides/VisionSlide.vue'
|
import VisionSlide from './slides/VisionSlide.vue'
|
||||||
import NetworkSlide from './slides/NetworkSlide.vue'
|
import NetworkSlide from './slides/NetworkSlide.vue'
|
||||||
import TechSlide from './slides/TechSlide.vue'
|
import TechSlide from './slides/TechSlide.vue'
|
||||||
import LocationsSlide from './slides/LocationsSlide.vue'
|
import EntitiesSlide from './slides/EntitiesSlide.vue'
|
||||||
import CitySlide from './slides/CitySlide.vue'
|
import ArchipelagoSlide from './slides/ArchipelagoSlide.vue'
|
||||||
import FarmSlide from './slides/FarmSlide.vue'
|
import SolunarSlide from './slides/SolunarSlide.vue'
|
||||||
|
import ChateauSlide from './slides/ChateauSlide.vue'
|
||||||
|
import EcosystemSlide from './slides/EcosystemSlide.vue'
|
||||||
import RevenueSlide from './slides/RevenueSlide.vue'
|
import RevenueSlide from './slides/RevenueSlide.vue'
|
||||||
import InvestmentOverviewSlide from './slides/InvestmentOverviewSlide.vue'
|
import InvestmentOverviewSlide from './slides/InvestmentOverviewSlide.vue'
|
||||||
import CostBreakdownSlide from './slides/CostBreakdownSlide.vue'
|
import CostBreakdownSlide from './slides/CostBreakdownSlide.vue'
|
||||||
|
|
@ -23,10 +25,12 @@ const slides = [
|
||||||
{ id: 'title', label: 'Title', component: TitleSlide },
|
{ id: 'title', label: 'Title', component: TitleSlide },
|
||||||
{ id: 'vision', label: 'Vision', component: VisionSlide },
|
{ id: 'vision', label: 'Vision', component: VisionSlide },
|
||||||
{ id: 'network', label: 'The network', component: NetworkSlide },
|
{ id: 'network', label: 'The network', component: NetworkSlide },
|
||||||
{ id: 'tech', label: 'Technology', component: TechSlide },
|
{ id: 'tech', label: 'Core stack', component: TechSlide },
|
||||||
{ id: 'locations', label: 'Two nodes', component: LocationsSlide },
|
{ id: 'entities', label: 'Three entities', component: EntitiesSlide },
|
||||||
{ id: 'city', label: 'City node', component: CitySlide },
|
{ id: 'archipelago', label: 'Archipelago', component: ArchipelagoSlide },
|
||||||
{ id: 'farm', label: 'Farm node', component: FarmSlide },
|
{ id: 'solunar', label: 'Solunar Society', component: SolunarSlide },
|
||||||
|
{ id: 'chateau', label: 'Chateau du Faune', component: ChateauSlide },
|
||||||
|
{ id: 'ecosystem', label: 'One membership', component: EcosystemSlide },
|
||||||
{ id: 'revenue', label: 'Revenue', component: RevenueSlide },
|
{ id: 'revenue', label: 'Revenue', component: RevenueSlide },
|
||||||
{ id: 'invest-overview', label: 'The raise', component: InvestmentOverviewSlide },
|
{ id: 'invest-overview', label: 'The raise', component: InvestmentOverviewSlide },
|
||||||
{ id: 'cost-breakdown', label: 'Cost breakdown', component: CostBreakdownSlide },
|
{ id: 'cost-breakdown', label: 'Cost breakdown', component: CostBreakdownSlide },
|
||||||
|
|
@ -48,7 +52,7 @@ const transitionName = computed(() => (direction.value === 1 ? 'slide-next' : 's
|
||||||
class="pointer-events-none absolute inset-x-0 top-0 z-20 flex items-center justify-between px-6 py-5 text-sand-dim"
|
class="pointer-events-none absolute inset-x-0 top-0 z-20 flex items-center justify-between px-6 py-5 text-sand-dim"
|
||||||
>
|
>
|
||||||
<span class="font-display text-sm font-semibold tracking-wide text-sand">
|
<span class="font-display text-sm font-semibold tracking-wide text-sand">
|
||||||
{{ brand.name }}
|
{{ brand.short }}
|
||||||
</span>
|
</span>
|
||||||
<span class="text-xs uppercase tracking-[0.2em]">{{ current.label }}</span>
|
<span class="text-xs uppercase tracking-[0.2em]">{{ current.label }}</span>
|
||||||
</header>
|
</header>
|
||||||
|
|
|
||||||
76
src/deck/components/EntityDetail.vue
Normal file
76
src/deck/components/EntityDetail.vue
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import SlideFrame from './SlideFrame.vue'
|
||||||
|
import Icon from './Icon.vue'
|
||||||
|
import PlaceholderBadge from './PlaceholderBadge.vue'
|
||||||
|
import { accentText, accentRing, accentDot, type Entity } from '../data'
|
||||||
|
|
||||||
|
const props = defineProps<{ entity: Entity }>()
|
||||||
|
const a = props.entity.accent
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<SlideFrame :kicker="entity.kind">
|
||||||
|
<div class="flex flex-wrap items-center gap-3">
|
||||||
|
<h2 class="font-display text-4xl font-semibold text-sand lg:text-5xl">{{ entity.name }}</h2>
|
||||||
|
<span
|
||||||
|
class="rounded-full border px-3 py-0.5 text-xs uppercase tracking-wider"
|
||||||
|
:class="[accentRing[a], accentText[a]]"
|
||||||
|
>
|
||||||
|
{{ entity.role }}
|
||||||
|
</span>
|
||||||
|
<PlaceholderBadge label="name" />
|
||||||
|
</div>
|
||||||
|
<p class="mt-4 max-w-2xl text-lg text-sand-dim">{{ entity.blurb }}</p>
|
||||||
|
|
||||||
|
<div class="mt-8 grid gap-6 lg:grid-cols-3">
|
||||||
|
<!-- unique traits -->
|
||||||
|
<div class="lg:col-span-1">
|
||||||
|
<p class="text-xs font-semibold uppercase tracking-[0.2em]" :class="accentText[a]">
|
||||||
|
What makes it unique
|
||||||
|
</p>
|
||||||
|
<ul class="mt-4 space-y-3">
|
||||||
|
<li v-for="t in entity.traits" :key="t" class="flex items-start gap-3 text-sm text-sand-dim">
|
||||||
|
<span class="mt-0.5 grid size-5 shrink-0 place-items-center rounded-full" :class="accentRing[a]">
|
||||||
|
<Icon name="Check" class="size-3" :class="accentText[a]" />
|
||||||
|
</span>
|
||||||
|
{{ t }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- spaces -->
|
||||||
|
<div class="rounded-2xl border p-6" :class="accentRing[a]">
|
||||||
|
<p class="text-xs font-semibold uppercase tracking-[0.2em]" :class="accentText[a]">On site</p>
|
||||||
|
<div class="mt-4 grid grid-cols-1 gap-2">
|
||||||
|
<div
|
||||||
|
v-for="s in entity.spaces"
|
||||||
|
:key="s"
|
||||||
|
class="flex items-center gap-2 rounded-lg bg-white/[0.03] px-3 py-2 text-sm text-sand"
|
||||||
|
>
|
||||||
|
<span class="size-1.5 rounded-full" :class="accentDot[a]" />
|
||||||
|
{{ s }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- revenue + shared-stack reminder -->
|
||||||
|
<div class="flex flex-col gap-4">
|
||||||
|
<div class="rounded-2xl border p-6" :class="accentRing[a]">
|
||||||
|
<p class="text-xs font-semibold uppercase tracking-[0.2em]" :class="accentText[a]">
|
||||||
|
How it earns
|
||||||
|
</p>
|
||||||
|
<ul class="mt-3 space-y-1.5 text-sm text-sand-dim">
|
||||||
|
<li v-for="r in entity.revenue" :key="r" class="flex items-center gap-2">
|
||||||
|
<Icon name="Coins" class="size-3.5" :class="accentText[a]" />
|
||||||
|
{{ r }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2 rounded-2xl border border-white/10 bg-white/[0.03] px-4 py-3 text-xs text-sand-dim">
|
||||||
|
<Icon name="Layers" class="size-4 text-amber-300" />
|
||||||
|
Runs the full core stack — same membership, kiosk & app as every node.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</SlideFrame>
|
||||||
|
</template>
|
||||||
8
src/deck/slides/ArchipelagoSlide.vue
Normal file
8
src/deck/slides/ArchipelagoSlide.vue
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import EntityDetail from '../components/EntityDetail.vue'
|
||||||
|
import { entityById } from '../data'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<EntityDetail :entity="entityById('archipelago')" />
|
||||||
|
</template>
|
||||||
8
src/deck/slides/ChateauSlide.vue
Normal file
8
src/deck/slides/ChateauSlide.vue
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import EntityDetail from '../components/EntityDetail.vue'
|
||||||
|
import { entityById } from '../data'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<EntityDetail :entity="entityById('chateau')" />
|
||||||
|
</template>
|
||||||
32
src/deck/slides/EcosystemSlide.vue
Normal file
32
src/deck/slides/EcosystemSlide.vue
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import SlideFrame from '../components/SlideFrame.vue'
|
||||||
|
import Icon from '../components/Icon.vue'
|
||||||
|
import { userEcosystem, entities } from '../data'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<SlideFrame
|
||||||
|
kicker="One membership, everywhere"
|
||||||
|
title="The same full experience, at every location"
|
||||||
|
subtitle="Wherever you are in the network — city, festival or farm — the ecosystem is identical. Your card, your money, your identity travel with you."
|
||||||
|
>
|
||||||
|
<div class="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
||||||
|
<div
|
||||||
|
v-for="item in userEcosystem"
|
||||||
|
:key="item.title"
|
||||||
|
class="rounded-2xl border border-white/10 bg-white/[0.03] p-5"
|
||||||
|
>
|
||||||
|
<span class="grid size-10 place-items-center rounded-xl bg-amber-400/10 text-amber-300">
|
||||||
|
<Icon :name="item.icon" class="size-5" />
|
||||||
|
</span>
|
||||||
|
<h3 class="mt-4 font-display text-lg font-semibold text-sand">{{ item.title }}</h3>
|
||||||
|
<p class="mt-1.5 text-sm leading-relaxed text-sand-dim">{{ item.body }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-6 flex flex-wrap items-center justify-center gap-x-3 gap-y-1 text-xs text-sand-dim">
|
||||||
|
<span>Works identically at</span>
|
||||||
|
<span v-for="e in entities" :key="e.id" class="font-medium text-sand">{{ e.name }}</span>
|
||||||
|
</div>
|
||||||
|
</SlideFrame>
|
||||||
|
</template>
|
||||||
44
src/deck/slides/EntitiesSlide.vue
Normal file
44
src/deck/slides/EntitiesSlide.vue
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import SlideFrame from '../components/SlideFrame.vue'
|
||||||
|
import Icon from '../components/Icon.vue'
|
||||||
|
import { entities, accentText, accentRing } from '../data'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<SlideFrame
|
||||||
|
kicker="The collaboration"
|
||||||
|
title="Three entities, one network"
|
||||||
|
subtitle="Deliberately different — a city hub, a travelling festival, a farm — each with its own character, all running the identical core stack."
|
||||||
|
>
|
||||||
|
<div class="grid gap-5 md:grid-cols-3">
|
||||||
|
<div
|
||||||
|
v-for="e in entities"
|
||||||
|
:key="e.id"
|
||||||
|
class="flex flex-col rounded-2xl border p-6"
|
||||||
|
:class="accentRing[e.accent]"
|
||||||
|
>
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<span class="grid size-11 place-items-center rounded-xl bg-white/5" :class="accentText[e.accent]">
|
||||||
|
<Icon :name="e.icon" class="size-6" />
|
||||||
|
</span>
|
||||||
|
<div>
|
||||||
|
<h3 class="font-display text-xl font-semibold text-sand">{{ e.name }}</h3>
|
||||||
|
<p class="text-xs uppercase tracking-wider" :class="accentText[e.accent]">{{ e.role }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p class="mt-4 flex-1 text-sm leading-relaxed text-sand-dim">{{ e.blurb }}</p>
|
||||||
|
|
||||||
|
<div class="mt-5 flex items-center gap-2 border-t border-white/10 pt-4 text-xs text-sand-dim">
|
||||||
|
<Icon name="Layers" class="size-4 text-amber-300" />
|
||||||
|
Full core stack & membership
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p class="mt-6 text-center text-sm text-sand-dim">
|
||||||
|
Same card, same kiosk, same app — the
|
||||||
|
<span class="text-sand">full experience regardless of location.</span>
|
||||||
|
</p>
|
||||||
|
</SlideFrame>
|
||||||
|
</template>
|
||||||
8
src/deck/slides/SolunarSlide.vue
Normal file
8
src/deck/slides/SolunarSlide.vue
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import EntityDetail from '../components/EntityDetail.vue'
|
||||||
|
import { entityById } from '../data'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<EntityDetail :entity="entityById('solunar')" />
|
||||||
|
</template>
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import SlideFrame from '../components/SlideFrame.vue'
|
import SlideFrame from '../components/SlideFrame.vue'
|
||||||
import PlaceholderBadge from '../components/PlaceholderBadge.vue'
|
import PlaceholderBadge from '../components/PlaceholderBadge.vue'
|
||||||
import { brand } from '../data'
|
import { brand, entities, accentText } from '../data'
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
@ -12,19 +12,30 @@ import { brand } from '../data'
|
||||||
<PlaceholderBadge label="draft" />
|
<PlaceholderBadge label="draft" />
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<h1 class="font-display text-6xl font-bold tracking-tight text-sand sm:text-7xl lg:text-8xl">
|
<h1 class="font-display text-5xl font-bold tracking-tight text-sand sm:text-6xl lg:text-7xl">
|
||||||
{{ brand.name }}
|
{{ brand.name }}
|
||||||
</h1>
|
</h1>
|
||||||
<p class="mt-4 text-lg text-pine-300 sm:text-xl">{{ brand.fullName }}</p>
|
|
||||||
|
|
||||||
<p class="mt-8 max-w-2xl text-balance text-xl text-sand sm:text-2xl">
|
<p class="mt-6 max-w-2xl text-balance text-xl text-sand sm:text-2xl">
|
||||||
{{ brand.tagline }}
|
{{ brand.tagline }}
|
||||||
</p>
|
</p>
|
||||||
<p class="mt-4 max-w-xl text-balance text-sm text-sand-dim sm:text-base">
|
|
||||||
|
<!-- the three collaborating entities -->
|
||||||
|
<div class="mt-10 flex flex-wrap items-center justify-center gap-x-3 gap-y-2 text-sm text-sand-dim">
|
||||||
|
<span class="uppercase tracking-[0.2em]">A collaboration between</span>
|
||||||
|
</div>
|
||||||
|
<div class="mt-3 flex flex-wrap items-center justify-center gap-3">
|
||||||
|
<template v-for="(e, i) in entities" :key="e.id">
|
||||||
|
<span class="font-display text-lg font-semibold" :class="accentText[e.accent]">{{ e.name }}</span>
|
||||||
|
<span v-if="i < entities.length - 1" class="text-sand-dim">·</span>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p class="mt-8 max-w-xl text-balance text-sm text-sand-dim">
|
||||||
{{ brand.subtagline }}
|
{{ brand.subtagline }}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class="mt-14 text-xs text-sand-dim">
|
<p class="mt-12 text-xs text-sand-dim">
|
||||||
Use <kbd class="rounded border border-white/15 px-1.5 py-0.5">→</kbd> /
|
Use <kbd class="rounded border border-white/15 px-1.5 py-0.5">→</kbd> /
|
||||||
<kbd class="rounded border border-white/15 px-1.5 py-0.5">←</kbd> to navigate
|
<kbd class="rounded border border-white/15 px-1.5 py-0.5">←</kbd> to navigate
|
||||||
</p>
|
</p>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue