Experience / Application
Connections
Connections — the cards other people have handed you.
One pile, not a grid of tiles. These arrived as objects, a few at a time, and a pile is the only presentation that keeps that true: it says how many without listing them, and it hands you the most recent one face up. A grid would turn a stack of cards from a week of meeting people into a directory.
The pile decides its own orientation — portrait on a phone, landscape from
sm up — so this page only says what is in it.
Beside it, the events those cards came from. Cards arrive in bursts — a conference, a dinner — and "where did I meet this person" is the question people actually use to find one again, so the timeline is the index and the pile is what it opens. Selecting an event puts that event's cards on the desk; an event nobody has been to yet has an empty desk, which is the honest answer rather than a hidden one.
Under the pile, everyone else in it. A pile hands you one card at a time, and without a contents page the third person you met is three swipes away with nothing to say they are there at all.
The page has one shape at every width and two arrangements of it: on a
phone the timeline is a row of dots above the desk, and from lg it is a
rail beside it, where a screen wide enough for a pile has width to spare
on either side.
Nothing persists. Notes written here live for as long as the page does.
Not exported from @meetcard/deck — this is a composed screen, built from the components below rather than shipped as one.
Stories
The desk with room either side of it: the events in a rail on the left, the pile in the middle, everyone else in it underneath.
Source
const Default = () => <Connections />;Flipping through — the next card comes to the top of the pile.
Source
const AdvancingThePile = () => <Connections />;The index is the way back. A pile hands you one card at a time, so the third person you met is three swipes away with nothing to say they are there — unless the page lists them.
Source
const PickingSomeoneFromTheIndex = () => <Connections />;The private-note pill turns the card over rather than opening a panel somewhere else — what you wrote about someone belongs on the back of their card.
Source
const TurningACardOver = () => <Connections />;Phone. The pile stands its cards up — same 3.5x2in object, turned — and the card re-lays itself around that: portrait, then the ways to reach them, then the name.
The timeline is a row of dots above the desk with the selected event named underneath, so the desk's own summary of that event stands down rather than saying it twice. The index becomes a strip of faces: at this width it is a way back to a card, not something to read.
Source
const Mobile = () => <Connections />;One pixel short of the rail. The timeline is still a line above the desk — labels and all — and the page is one column, which is the arrangement every width between a phone and a laptop gets.
Source
const BelowTheRail = () => <Connections />;The timeline is the index and the pile is what it opens: moving along the line puts a different event's cards on the desk, squared up from the top.
Source
const MovingAlongTheTimeline = () => <Connections />;An event nobody has been to yet has an empty desk. Said plainly rather than hidden — a timeline that skipped its empty events would be lying about where the cards came from. There is no index either: a contents page for nothing is furniture.
Source
const AnEventWithNoCards = () => <Connections />;In the shell, where the desk finally has a room to sit in.
Source
const InAppShell = () => (
<AppShell currentId="/connections">
<Connections />
</AppShell>
);Props
| Prop | Type | Default | Description |
|---|---|---|---|
connections | Connection[] | [
{
slug: 'ben@meetcard',
eventId: 'founders-dinner',
name: 'Ben Ackles',
tagline: 'What a lovable guy',
title: 'Builder',
company: 'MeetCard',
location: 'Boulder, Colorado',
note: 'Met at the Front Range meetup — wants to talk about the deck metaphor.',
feeling: 'hot',
},
{
slug: 'grace@sextant',
eventId: 'founders-dinner',
name: 'Grace Okafor',
tagline: 'Ask me about supply chains.',
title: 'Head of Operations',
company: 'Sextant',
location: 'Denver, Colorado',
},
{
slug: 'mika@ply',
eventId: 'founders-dinner',
name: 'Mika Tanaka',
tagline: 'Always three prototypes deep.',
title: 'Principal Engineer',
company: 'Ply',
location: 'Seattle, Washington',
},
{
slug: 'renee@harborlight',
eventId: 'saastr-annual',
name: 'Renée Ashford',
tagline: 'Pricing is a product.',
title: 'VP Revenue',
company: 'Harborlight',
location: 'San Francisco, California',
note: 'Wants the deck demo before their Q1 planning.',
},
{
slug: 'devon@northbound',
eventId: 'saastr-annual',
name: 'Devon Iyer',
tagline: 'Runs on conference coffee.',
title: 'Founder',
company: 'Northbound',
location: 'Austin, Texas',
},
] | Seeds the page. Notes stay local — Deck has no data layer. |
defaultEventId | string | — | Which event the page opens on. Defaults to the most recent past one. |
events | TimelineEvent[] | [
{
id: 'saastr-annual',
name: 'SaaStr Annual',
date: '2027-09-09',
location: 'San Francisco, CA',
},
{
id: 'founders-dinner',
name: 'Founders Dinner',
date: '2027-11-12',
location: 'Denver, CO',
},
{
id: 'revops-summit',
name: 'RevOps Summit',
date: '2028-01-22',
location: 'Chicago, IL',
},
] | The events on the line beside the pile, oldest first. |
today | string | '2027-12-01' | ISO date the timeline is read from. Pinned in stories and tests. |