From 3112f77823dd946cda00c2cb6d8502ee1497471a Mon Sep 17 00:00:00 2001 From: Will Washburn Date: Tue, 15 Sep 2026 09:36:09 -0700 Subject: [PATCH 01/12] feat(web): add Teams landing and Cloud signup handoff --- .gitignore | 3 + docs/design/teams-dashboard-concept.md | 63 +++++++ docs/teams-onboarding.md | 39 ++++ package-lock.json | 3 +- package.json | 3 +- scripts/stage-probe.mjs | 18 ++ web/app/landing.module.css | 10 + web/app/sitemap.ts | 1 + .../teams/onboarding/[[...stage]]/page.tsx | 20 ++ web/app/teams/page.tsx | 176 ++++++++++++++++++ web/app/teams/teams-landing.module.css | 102 ++++++++++ web/components/SiteFooter.tsx | 1 + web/components/SiteNav.tsx | 2 + web/components/home/ContextCapabilities.tsx | 4 +- web/components/home/DeliveryFeature.tsx | 15 +- web/components/home/DeploymentCall.tsx | 53 +++--- web/components/home/FlowFileAnimation.tsx | 49 ++++- web/components/home/HeroTerminalMarquee.tsx | 28 ++- web/lib/site-analytics.ts | 1 + web/lib/teams-onboarding.ts | 13 ++ web/lib/test/teams-onboarding.test.ts | 12 ++ web/next.config.mjs | 19 +- web/package.json | 3 +- web/public/authors/ingrid.png | Bin 0 -> 680889 bytes web/public/authors/mary.png | Bin 0 -> 814828 bytes web/public/install.sh | 86 +++++++++ web/public/teams/teams-dashboard-concept.png | Bin 0 -> 1346749 bytes .../teams/teams-session-overview-concept.png | Bin 0 -> 1417238 bytes 28 files changed, 671 insertions(+), 53 deletions(-) create mode 100644 docs/design/teams-dashboard-concept.md create mode 100644 docs/teams-onboarding.md create mode 100644 scripts/stage-probe.mjs create mode 100644 web/app/teams/onboarding/[[...stage]]/page.tsx create mode 100644 web/app/teams/page.tsx create mode 100644 web/app/teams/teams-landing.module.css create mode 100644 web/lib/teams-onboarding.ts create mode 100644 web/lib/test/teams-onboarding.test.ts create mode 100644 web/public/authors/ingrid.png create mode 100644 web/public/authors/mary.png create mode 100644 web/public/install.sh create mode 100644 web/public/teams/teams-dashboard-concept.png create mode 100644 web/public/teams/teams-session-overview-concept.png diff --git a/.gitignore b/.gitignore index 28fa614d..db8d3176 100644 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,6 @@ web/waitlist.json # Palate website-builder skill telemetry, written at the repo root during agent sessions build-manifest.json + +# Native probe builds are staged locally, not committed with the website. +web/public/downloads/agent-relay-probe/ diff --git a/docs/design/teams-dashboard-concept.md b/docs/design/teams-dashboard-concept.md new file mode 100644 index 00000000..f6d6ebb2 --- /dev/null +++ b/docs/design/teams-dashboard-concept.md @@ -0,0 +1,63 @@ +# Teams dashboard concept + +Asset: `web/public/teams/teams-dashboard-concept.png` (1585 × 992). + +Created using the built-in imagegen tool. This is a product concept with example +sessions, not a screenshot of a connected account. The image links to its full-size +version from the Teams landing page. + +## Design brief + +A flat navy desktop interface with one session table grouped by the human running +the agents. Columns: Session, Tool, Status, Pull request, Updated. Statuses are +Working, Idle, and Finished; only finished sessions have PR links. The important +columns sit before Updated so they remain visible in the landing page's right crop. + +| Teammate | Session | Tool | Status | PR | +| --- | --- | --- | --- | --- | +| Will Washburn | Add Google sign-in | Claude Code | Working | | +| Will Washburn | Improve onboarding copy | Codex | Idle | | +| Will Washburn | Fix duplicate uploads | Claude Code | Finished | #482 | +| Maya Chen | Build sessions search | Codex | Working | | +| Maya Chen | Review retry handling | Gemini CLI | Idle | | +| Maya Chen | Add team invitations | Claude Code | Finished | #487 | +| Alex Rivera | Audit session sharing | Claude Code | Working | | +| Alex Rivera | Update setup guide | OpenCode | Finished | #491 | + +## Surface cleanup prompt + +Edit this Agent Relay Teams dashboard screenshot. Preserve the exact layout, +dimensions, all text, all eight rows, all three human groups, status dots, and all +PR numbers. Change ONLY the surface rendering. The current image has strange +black/blue/green mottled patches and waves in the background and behind rows. +Remove EVERY such artifact. Make the ENTIRE screenshot fully opaque, perfectly +flat, clean digital UI. Every background surface must be a solid uniform navy +color: page #0b1c2a, top bar #102536, group headers #132b3c, session rows #0e2333, +subtle first-row highlight #18394f. Thin solid separators. Absolutely NO +transparency, no black cut-out holes, no gradients, no grain, no glow, no textures, +no ripples, no smoke, no shadows. This is a pixel-sharp product screenshot of a +normal flat application, not an artistic treatment. Keep text and icons crisp +with clean antialiasing and excellent contrast. Small status dots remain blue for +Working, amber for Idle, green for Finished. Preserve all exact existing content. + +## Branding correction prompt + +Built-in imagegen edit using the existing dashboard as the target and +`web/public/brand-kit/agent-relay-logo-horizontal-transparent.png` as the +authoritative branding reference. + +Use case: compositing. +Input image 1: edit target, the existing Agent Relay sessions dashboard concept. +Input image 2: authoritative logo insert from the repository's brand kit, agent-relay-logo-horizontal-transparent.png. +Replace ONLY the incorrect top-left text logo in image 1 with the EXACT real horizontal logo from image 2: the two interlocking rounded blue diamond/chevron shapes (bright sky-blue left shape, darker blue right shape) and the white lowercase agentrelay wordmark with its specific original letterforms. Composite the provided branding, do not invent or redesign the symbol or typeset a substitute. The input logo has large transparent margins: ignore those margins and use only the visible logo artwork. Fit the complete real lockup at about x=28..180, y=22..47 within the existing top bar, centered vertically; preserve the logo's original aspect ratio. Retain the existing divider around x=211 and the AgentWorkforce workspace selector. +Preserve all other pixels and layout as closely as possible: original 1585x992 canvas, navy backgrounds, all navigation, all text, table rows, three human groups, tool icons, statuses, PR numbers, and separators. No added ornamentation. No new elements. Final result must be a crisp screenshot with the actual supplied Agent Relay brand lockup in the top left. + +## Final logo spacing prompt + +Built-in imagegen edit to increase the separation between the mark and wordmark +at the landing page's displayed image size. + +Use case: precise-object-edit. +Edit only the spacing in the Agent Relay logo at the TOP LEFT of this existing dashboard screenshot. +The blue symbol currently ends around x=78 and the white wordmark begins around x=82. Increase that 4px gap to a clear 16px gap by shifting ONLY the entire white "agentrelay" wordmark about 12 pixels to the right, so it starts around x=94 and ends around x=227. Keep the blue symbol in its current location and at its current size, about x=34..78. Keep the divider at x=244. Keep the exact existing official blue symbol shape and exact existing white wordmark letterforms, height, weight, and baseline. Do not redesign or typeset new branding. The symbol and wordmark should feel separate with comfortable breathing room even when this screenshot is displayed at half size. +Everything else is invariant: same 1585x992 canvas, same header positions, workspace selector, navigation, backgrounds, all table rows, text, statuses, tool icons, and PR numbers. Make no other visual changes. Preserve the rest of the screenshot. diff --git a/docs/teams-onboarding.md b/docs/teams-onboarding.md new file mode 100644 index 00000000..115f3f67 --- /dev/null +++ b/docs/teams-onboarding.md @@ -0,0 +1,39 @@ +# Teams entry into Cloud + +The marketing `/teams` signup buttons link directly to Cloud's Google auth +endpoint, `/cloud/api/auth/google/start?next=%2Fteams%2Fconnect`. They use a +full browser navigation so Cloud can set OAuth cookies and redirect to Google. +The post-auth `/teams/connect` destination preserves Teams signup attribution +and then redirects to `/cloud/dashboard`. + +Old `/teams/onboarding` links redirect to `/cloud/teams/connect`. The former +`/account`, `/install`, and `/sessions` routes also redirect for compatibility; +they render no marketing onboarding UI. Machine, workspace, and account context +is accepted only when it passes the ID allowlist. Arbitrary return URLs are discarded. + +Cloud handles Google auth and sends the user to `/cloud/dashboard`. Accounts +created through this Teams flow are marked directly on Cloud's `users` table +with `signup_source = teams` and `dashboard_version = 2`. They see the new Hello +world dashboard. Existing accounts keep their current dashboard, including +when signing in through the Teams link. The assignment persists across logins. +The migration adds both columns without changing existing user data; existing +accounts default to version `1` with an unknown (NULL) signup source. + +## Local development + +In the Cloud companion checkout, run `npm run dev:local` (see its +`docs/local-teams.md`). Here, run `npm run dev:teams`. Open +`http://127.0.0.1:3100/teams`. The development-only `/cloud/*` proxy forwards to +Cloud at `127.0.0.1:3101`, preserving one origin for API requests and auth cookies. +Keep `NEXT_PUBLIC_CLOUD_URL` unset. + +Google needs a development OAuth client with the exact callback +`http://127.0.0.1:3100/cloud/api/auth/callback/google`. Without it, visit +`http://127.0.0.1:3100/cloud/api/auth/dev-login?source=teams` to create a separate +local Teams signup. The test login without `source=teams` retains the original +local account for testing the existing dashboard. + +The Cloud companion owns cohort persistence, dashboard routing, and all future +setup functionality. V2 intentionally contains only Hello world for now. Its +migration must land before the runtime change under the existing reviewed PR +and human release gates. diff --git a/package-lock.json b/package-lock.json index 39558180..ab0e86f0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16684,7 +16684,8 @@ "@types/react-dom": "^19.2.3", "typescript": "^5.9.3", "vitest": "^4.1.0", - "wrangler": "^4.91.0" + "wrangler": "^4.91.0", + "esbuild": "0.25.4" }, "engines": { "node": ">=20.9.0" diff --git a/package.json b/package.json index e9d7d78b..f1119451 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "dev": "npm --workspace web run dev", "build": "npm --workspace web run build", "test": "npm --workspaces run test", - "preview": "npm --workspace web run preview" + "preview": "npm --workspace web run preview", + "dev:teams": "CLOUD_DEV_ORIGIN=http://127.0.0.1:3101 npm --workspace web run dev -- --hostname 127.0.0.1 --port 3100" } } diff --git a/scripts/stage-probe.mjs b/scripts/stage-probe.mjs new file mode 100644 index 00000000..24d255c7 --- /dev/null +++ b/scripts/stage-probe.mjs @@ -0,0 +1,18 @@ +#!/usr/bin/env node +import { copyFile, mkdir, readFile, writeFile, chmod } from 'node:fs/promises'; +import { createHash } from 'node:crypto'; +import { resolve, dirname, isAbsolute } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { parseArgs } from 'node:util'; +const { values } = parseArgs({ options: { binary: { type: 'string' }, platform: { type: 'string' } } }); +if (!values.binary || !isAbsolute(values.binary) || !/^(darwin|linux)-(arm64|x64)$/.test(values.platform ?? '')) { + throw new Error('Use --binary /absolute/native-binary --platform darwin-arm64 (or supported linux/macOS variant).'); +} +const root = resolve(dirname(fileURLToPath(import.meta.url)), '..'); +const destination = resolve(root, 'web/public/downloads/agent-relay-probe', values.platform); +const bytes = await readFile(values.binary); +await mkdir(destination, { recursive: true }); +await copyFile(values.binary, resolve(destination, 'agent-relay-probe')); +await chmod(resolve(destination, 'agent-relay-probe'), 0o755); +await writeFile(resolve(destination, 'agent-relay-probe.sha256'), createHash('sha256').update(bytes).digest('hex') + ' agent-relay-probe\n'); +console.log('Staged native probe and SHA-256 for local website testing.'); diff --git a/web/app/landing.module.css b/web/app/landing.module.css index eeadb395..d11cd01a 100644 --- a/web/app/landing.module.css +++ b/web/app/landing.module.css @@ -2220,6 +2220,16 @@ border-bottom: 1px solid rgba(116, 184, 226, 0.14); } +.heroTermAvatar { + flex: none; + width: 24px; + height: 24px; + margin-left: auto; + border-radius: 50%; + object-fit: cover; + border: 1px solid rgba(159, 212, 245, 0.4); +} + .heroTermTraffic { display: inline-flex; flex: none; diff --git a/web/app/sitemap.ts b/web/app/sitemap.ts index e2c7bad8..2273d838 100644 --- a/web/app/sitemap.ts +++ b/web/app/sitemap.ts @@ -13,6 +13,7 @@ export default function sitemap(): MetadataRoute.Sitemap { const now = new Date(); const staticRoutes: MetadataRoute.Sitemap = [ + { url: absoluteUrl('/teams'), lastModified: now, changeFrequency: 'weekly', priority: 0.9 }, { url: absoluteUrl('/'), lastModified: now, diff --git a/web/app/teams/onboarding/[[...stage]]/page.tsx b/web/app/teams/onboarding/[[...stage]]/page.tsx new file mode 100644 index 00000000..c8944291 --- /dev/null +++ b/web/app/teams/onboarding/[[...stage]]/page.tsx @@ -0,0 +1,20 @@ +import type { Metadata } from 'next'; +import { notFound, redirect } from 'next/navigation'; +import { teamsConnectHref } from '../../../../lib/teams-onboarding'; + +export const metadata: Metadata = { + title: 'Sign in to Agent Relay Teams', + description: 'Continue to your team’s dashboard in Agent Relay Cloud.', + robots: { index: false, follow: true }, +}; + +export default async function TeamsOnboardingPage({ params, searchParams }: { + params: Promise<{ stage?: string[] }>; + searchParams: Promise>; +}) { + const { stage } = await params; + // Old setup links remain usable, but the marketing site has no authenticated + // onboarding screens. Cloud owns sign-in and the dashboard destination. + if (stage?.length && (stage.length !== 1 || !['account', 'install', 'sessions'].includes(stage[0]))) notFound(); + redirect(teamsConnectHref(await searchParams)); +} diff --git a/web/app/teams/page.tsx b/web/app/teams/page.tsx new file mode 100644 index 00000000..13cba75f --- /dev/null +++ b/web/app/teams/page.tsx @@ -0,0 +1,176 @@ +import { ContextCapabilities } from '../../components/home/ContextCapabilities'; +import type { Metadata } from 'next'; +import Image from 'next/image'; +import dashboardConcept from '../../public/teams/teams-dashboard-concept.png'; +import sessionConcept from '../../public/teams/teams-session-overview-concept.png'; +import { ArrowRight } from 'lucide-react'; +import { HeroTerminalMarquee } from '../../components/home/HeroTerminalMarquee'; +import { DeploymentCall } from '../../components/home/DeploymentCall'; +import { MessagingFeature } from '../../components/home/MessagingFeature'; +import { DurableWorkflowFeature } from '../../components/home/DeliveryFeature'; +import { InvestorStrip } from '../../components/InvestorStrip'; +import { GitHubIcon, WaveDivider } from '../../components/home/icons'; +import { SiteNav } from '../../components/SiteNav'; +import { SiteFooter } from '../../components/SiteFooter'; +import { absoluteUrl } from '../../lib/site'; +import { teamsCloudUrl } from '../../lib/teams-onboarding'; +import home from '../landing.module.css'; +import flows from '../flows/flows.module.css'; +import { IntegrationMarquee } from '../flows/IntegrationMarquee'; +import s from './teams-landing.module.css'; + +export const metadata: Metadata = { + title: 'Agent Relay Teams | Your team’s coding sessions', + description: 'Connect your computer to Agent Relay and bring your team’s coding sessions into one shared history.', + alternates: { canonical: absoluteUrl('/teams') }, +}; + +export default function TeamsPage() { + const signupHref = teamsCloudUrl('/api/auth/google/start?next=%2Fteams%2Fconnect'); + const setupLink = ( + + Sign up + + ); + + return ( +
+ Skip to content + + +
+
+
+
+

+ See what every agent on your team is doing +

+

+ Share your coding agent sessions with your team, find overlapping work, and discover whats working for everyone. +

+ +
+
+ + + +
+ +
+ +
+ +
+
+

Your whole team's coding agents, under one roof

+

Connect your coding tools. Follow the work, understand the decisions, and share what’s worth repeating.

+
+
+ + Dashboard concept: eight coding sessions grouped under Will, Maya, and Alex, with coding tools, Working, Idle, and Finished statuses, and pull request links on finished sessions. + +
+
+ +
+ +
+
+

Catch up on the work.
Understand the decisions.

+

Open any agent session to see what it’s working toward, the constraints it’s following, and how long it’s been running. Read the conversation, or replay it from the start.

+
+
+ + Session detail concept for Add Google sign-in: an intent and constraints overview, Working status, running time of 18 minutes 42 seconds, a Replay conversation button, and the rendered conversation between Will Washburn and Claude Code. + +
+
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+
+

Open source.
Run it anywhere.

+

+ Your laptop, your servers, or our cloud. Agent Relay runs where your work lives, + with the source code in your hands. +

+ +
+
+ +
+ +
+
+

Connect the tools you already use.

+

+ Give all the agents on the relay controlled access to the tools they need through a virtual file system. +

+
+ + +
+ + +
+
+ + +
+ ); +} diff --git a/web/app/teams/teams-landing.module.css b/web/app/teams/teams-landing.module.css new file mode 100644 index 00000000..7b0b1d50 --- /dev/null +++ b/web/app/teams/teams-landing.module.css @@ -0,0 +1,102 @@ +/* Shared landing structure, typography, bands, and buttons come from Flows. */ +.page :is(a, button):focus-visible { + outline: 2px solid var(--flows-accent-strong); + outline-offset: 5px; +} + +.page { + --agent-tools-band-bg: var(--flows-band-blue); + background: #0d2638; +} + +.setupSection { scroll-margin-top: 100px; } + +.page .integrationsSection, +.page .activitySection { --section-bg: #193650; } + +.activitySection { display: grid; grid-template-columns: minmax(0, .95fr) minmax(0, 1.05fr); align-items: center; gap: clamp(2.5rem, 5vw, 5rem); scroll-margin-top: 80px; --section-pattern-opacity: 0; } +.activityIntro { max-width: 440px; margin: 0; text-align: left; } +.activityIntro h2 { margin: 0; font-family: var(--font-heading), sans-serif; color: var(--flows-text); font-size: clamp(2.25rem, 3.8vw, 3.2rem); font-weight: 500; line-height: 1.1; letter-spacing: -0.035em; text-wrap: balance; } +.activityIntro p { max-width: 400px; margin: 1.5rem 0 0; color: var(--flows-muted); font-size: clamp(1rem, 1.5vw, 1.125rem); line-height: 1.75; } + +.productScreenshot { width: calc(100% + max(10rem, (100vw - 1140px) / 2)); min-width: 640px; margin: 0; } +.productScreenshot > a { display: block; border: 1px solid #405c72; border-radius: 12px; overflow: hidden; background: #0b1c2a; } +.productScreenshot img { display: block; width: 100%; height: auto; } +.productScreenshot figcaption { margin-top: 14px; color: #94b0c5; font-size: 13px; line-height: 1.6; } + +.page [data-marquee-band] { + margin-top: 16px; +} + +.setupSteps { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: clamp(2rem, 5vw, 4.5rem); + margin: 3.5rem 0 0; + padding: 0 1rem; + list-style: none; +} + +.setupSteps > li { min-width: 0; } +.setupSteps svg { width: 28px; height: 28px; color: var(--flows-accent-strong); } +.setupSteps h3 { margin: 1.3rem 0 0.8rem; font-size: 1.15rem; font-weight: 500; } +.setupSteps p { margin: 0; color: var(--flows-muted); font-size: 1rem; line-height: 1.75; } + +.historyFeature { + display: grid; + grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); + align-items: center; + gap: clamp(3rem, 7vw, 7rem); +} + +.journey { display: grid; justify-items: center; padding: 1rem 0; } +.journeySource, .journeyDestination { text-align: center; } +.journeySource > svg, .journeyDestination > svg { width: 42px; height: 42px; margin: 0 auto 1rem; color: var(--flows-accent-strong); stroke-width: 1.3; } +.journeySource > span, .journeyDestination > span { font-size: 1.15rem; font-weight: 500; } +.journey p { margin: 0.6rem 0 0; font-size: 0.9rem; color: var(--flows-muted); } +.journeyLine { height: 45px; width: 1px; background: var(--flows-line-strong); margin: 14px 0; } +.journeyRelay { display: flex; align-items: center; gap: 12px; padding: 16px 26px; border: 1px solid var(--flows-line-strong); border-radius: 8px; background: var(--flows-band-dark); font-size: 1rem; } +.journeyRelay svg { width: 24px; color: var(--flows-accent-strong); } + +.historyCopy h2 { margin: 0; font-family: var(--font-heading), sans-serif; font-size: clamp(2rem, 3.7vw, 3.2rem); font-weight: 500; line-height: 1.12; letter-spacing: -0.03em; } +.historyCopy > p { margin: 1.5rem 0 0; color: var(--flows-muted); font-size: 1.08rem; line-height: 1.75; } +.historyDetails { display: grid; gap: 1.25rem; margin: 2rem 0 0; padding: 0; list-style: none; } +.historyDetails li { display: flex; align-items: flex-start; gap: 14px; color: var(--flows-muted); font-size: 0.95rem; line-height: 1.7; } +.historyDetails svg { flex-shrink: 0; width: 19px; height: 19px; margin-top: 4px; color: var(--flows-accent-strong); } +.finalSection { padding-bottom: 3rem; } + +@media (max-width: 960px) { + .activitySection { grid-template-columns: 1fr; gap: 2.5rem; } + .activityIntro { max-width: 640px; } + .activityIntro p { max-width: 560px; } + .productScreenshot { width: 100%; min-width: 0; } +} + +@media (max-width: 700px) { + .activityIntro h2 { font-size: clamp(1.7rem, 8.4vw, 2.2rem); } + .productScreenshot figcaption { font-size: 12px; } + .setupSteps { grid-template-columns: 1fr; gap: 2rem; max-width: 440px; margin: 2.5rem auto 0; padding: 0; } + .setupSteps h3 { margin-top: 1rem; } + .historyFeature { grid-template-columns: 1fr; gap: 3.5rem; } + .historyCopy { order: -1; } + .journey { padding: 0; } +} + +/* Session detail follows the team-wide activity view. */ +.sessionSection { display: grid; grid-template-columns: minmax(0, .95fr) minmax(0, 1.05fr); align-items: center; gap: clamp(2.5rem, 5vw, 5rem); --section-bg: #0d2638; --section-pattern-opacity: 0; scroll-margin-top: 100px; } +.sessionIntro { grid-column: 1; grid-row: 1; max-width: 440px; margin: 0; text-align: left; } +.sessionIntro h2 { margin: 0; font-family: var(--font-heading), sans-serif; color: var(--flows-text); font-size: clamp(2rem, 3.8vw, 3.2rem); font-weight: 500; line-height: 1.1; letter-spacing: -0.035em; text-wrap: balance; } +.sessionIntro p { max-width: 400px; margin: 1.5rem 0 0; color: var(--flows-muted); font-size: clamp(1rem, 1.5vw, 1.125rem); line-height: 1.75; } +.sessionScreenshot { grid-column: 2; grid-row: 1; justify-self: start; width: calc(100% + max(10rem, (100vw - 1140px) / 2)); min-width: 640px; margin: 0; } +.sessionScreenshot a { display: block; overflow: hidden; border: 1px solid #405c72; border-radius: 12px; background: #0b1c2a; } +.sessionScreenshot img { display: block; width: 100%; height: auto; } +@media (max-width: 960px) { + .sessionSection { grid-template-columns: 1fr; gap: 2.5rem; } + .sessionIntro { grid-column: auto; grid-row: auto; max-width: 640px; } + .sessionIntro p { max-width: 560px; } + .sessionScreenshot { grid-column: auto; grid-row: auto; width: 100%; min-width: 0; } +} +@media (max-width: 700px) { + .sessionIntro h2 { font-size: clamp(1.7rem, 8.4vw, 2.2rem); } + .sessionScreenshot a { border-radius: 8px; } +} diff --git a/web/components/SiteFooter.tsx b/web/components/SiteFooter.tsx index b6025660..9a80dcba 100644 --- a/web/components/SiteFooter.tsx +++ b/web/components/SiteFooter.tsx @@ -22,6 +22,7 @@ const footerColumns: FooterColumn[] = [ links: [ { label: 'Relay Cloud', href: 'https://agentrelay.com/cloud' }, { label: 'Flows', href: '/flows' }, + { label: 'Teams', href: '/teams' }, { label: 'Skip', href: 'https://heyskip.dev' }, { label: 'Pear', href: '/pear' }, ], diff --git a/web/components/SiteNav.tsx b/web/components/SiteNav.tsx index baab760f..2b42a696 100644 --- a/web/components/SiteNav.tsx +++ b/web/components/SiteNav.tsx @@ -92,6 +92,7 @@ export function SiteNav({
{!hideLinks && (