Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added public/img/xhibiter/gradient.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/img/xhibiter/gradient_light.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/app/admin/review-queue.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -877,7 +877,7 @@ function QueueRow({
/* Three states that are actually distinguishable on a #faf7f6 page:
page, white on hover, ink when selected. */
className={`w-full rounded-tight px-3 py-2.5 text-left transition-colors ${
selected ? "bg-ink text-t-invert" : "hover:bg-surface"
selected ? "bg-ink text-t-invert" : "hover:bg-xh-jacarta-50"
}`}
>
<p className="font-medium">{profile.name}</p>
Expand Down
2 changes: 1 addition & 1 deletion src/app/contact/contact-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ export function ContactForm({ email, about }: { email: string; about?: string })
return (
<form onSubmit={onSubmit} className="mt-14 grid gap-x-8 gap-y-10 sm:grid-cols-2">
{about ? (
<p className="rounded-tight bg-surface px-5 py-4 text-sm text-t-muted sm:col-span-2">
<p className="rounded-tight border border-stroke bg-surface px-5 py-4 text-sm text-t-muted sm:col-span-2">
Enquiring about <strong className="font-medium text-t-bright">{about}</strong>.
Bluehex passes it on — practitioners are not contacted directly.
</p>
Expand Down
83 changes: 51 additions & 32 deletions src/app/globals.css
Original file line number Diff line number Diff line change
@@ -1,48 +1,50 @@
@import "tailwindcss";

/* ------------------------------------------------------------------
* Design tokens ported from the Code.Sydney site.
* Design tokens. Originally ported from the Code.Sydney site; the values are
* now the Xhibiter "Home 2" palette (violet accent, jacarta navy text, Cal Sans
* and DM Sans), swapped in at token level so every component follows.
*
* That stylesheet sets the root font-size to 10px and expresses every
* dimension in rem against that. We keep the browser default 16px root here
* and carry the values across in px, so a `1.6rem` radius over there reads as
* `16px` here.
*
* `ink` is the high-contrast fill — near-black here — and `t-invert` is the
* `ink` is the high-contrast fill — the violet accent here — and `t-invert` is the
* text that sits on top of it. Every component reads these roles rather than
* literal colours, so re-theming is a token-level swap. Single scheme by
* design: the page stays light regardless of OS preference.
* ------------------------------------------------------------------ */
@theme {
/* surfaces */
--color-page: #faf7f6;
--color-page: #ffffff;
--color-surface: #ffffff;
--color-surface-shade: #e0dddb;
--color-ink: #161616;
--color-ink-tint: #1c1c1c;
--color-surface-shade: #e7e8ec;
--color-ink: #8358ff;
--color-ink-tint: #7444ff;

/* brand accents */
--color-accent: #9f8be7;
--color-lime: #ddf160;
--color-accent: #8358ff;
--color-lime: #b9a0ff;

/* text ramp */
--color-t-bright: #161616;
--color-t-medium: #303030;
--color-t-muted: #585858;
--color-t-faint: #b2aead;
--color-t-bright: #131740;
--color-t-medium: #363a5d;
--color-t-muted: #5a5d79;
--color-t-faint: #a1a2b3;
--color-t-invert: #ffffff;
--color-t-invert-muted: #acacac;
--color-t-invert-muted: #e7e8ec;

/* Feedback. One colour, used only where something is wrong: a form error, and
nothing else. Dark enough on `--color-page` and on `--color-surface` to
clear 4.5:1 at the 12px these messages are set in — and never the only
signal, since every message that uses it is text beside the field it is
about. */
--color-danger: #a02724;
--color-danger: #b42318;

/* strokes */
--color-stroke: #e0dddb;
--color-stroke-strong: #161616;
--color-stroke: #e7e8ec;
--color-stroke-strong: #8358ff;

/* Radii. Named by role, not by a size letter: Tailwind already owns the
single-letter suffixes for sides, so a `--radius-l` token produces a
Expand All @@ -51,13 +53,30 @@
as a half-rounded box. Same trap as naming a colour `base` and losing
`text-base`. Keep these names multi-letter and unlike any built-in. */
--radius-tight: 10px;
--radius-card: 26px;
--radius-block: 38px;
--radius-huge: 80px;
--radius-card: 20px;
--radius-block: 24px;
--radius-huge: 40px;

/* type */
--font-display: var(--font-funnel-display), ui-sans-serif, system-ui, sans-serif;
--font-sans: var(--font-funnel-sans), ui-sans-serif, system-ui, sans-serif;
--font-display: var(--font-cal-sans), ui-sans-serif, system-ui, sans-serif;
--font-sans: var(--font-dm-sans), ui-sans-serif, system-ui, sans-serif;

/* The raw Xhibiter scale, for the places that want a specific step rather
than a role — the home page and the gradient page titles. */
--color-xh-jacarta-50: #f4f4f6;
--color-xh-jacarta-100: #e7e8ec;
--color-xh-jacarta-200: #c4c5cf;
--color-xh-jacarta-300: #a1a2b3;
--color-xh-jacarta-400: #7d7f96;
--color-xh-jacarta-500: #5a5d79;
--color-xh-jacarta-600: #363a5d;
--color-xh-jacarta-700: #131740;
--color-xh-green: #10b981;

--shadow-xh-accent-volume:
5px 5px 10px rgba(108, 106, 213, 0.25), inset 2px 2px 6px #a78df0, inset -5px -5px 10px #6336e4;
--shadow-xh-white-volume:
5px 5px 10px rgba(108, 106, 212, 0.25), inset 2px 2px 6px #eef1f9, inset -5px -5px 10px #dfe3ef;
}

@layer base {
Expand All @@ -79,17 +98,17 @@
h5,
h6 {
font-family: var(--font-display);
font-weight: 500;
letter-spacing: -0.02em;
font-weight: 400;
letter-spacing: -0.01em;
line-height: 1.06;
text-wrap: balance;
}

/* Tracking is tight at display sizes and normal at body sizes, so it is set
per-heading rather than globally. */
::selection {
background-color: var(--color-lime);
color: var(--color-ink);
background-color: var(--color-ink);
color: var(--color-t-invert);
}

:focus-visible {
Expand Down Expand Up @@ -117,19 +136,19 @@
/* Display headline scale — fluid between the mobile and 1600px extremes so
the giant section titles never need per-breakpoint overrides. */
.display-1 {
font-size: clamp(3.25rem, 11vw, 11.5rem);
line-height: 0.92;
letter-spacing: -0.04em;
font-size: clamp(2.75rem, 7vw, 5.25rem);
line-height: 1;
letter-spacing: -0.02em;
}

.display-2 {
font-size: clamp(2.5rem, 6.2vw, 5.5rem);
line-height: 1.02;
letter-spacing: -0.03em;
font-size: clamp(2.1rem, 4.4vw, 3.5rem);
line-height: 1.06;
letter-spacing: -0.015em;
}

.display-3 {
font-size: clamp(1.9rem, 3.4vw, 2.9rem);
font-size: clamp(1.5rem, 2.4vw, 2rem);
line-height: 1.12;
letter-spacing: -0.02em;
}
Expand Down
30 changes: 23 additions & 7 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
import type { Metadata } from "next";
import { Funnel_Display, Funnel_Sans } from "next/font/google";
import { Cal_Sans, DM_Sans } from "next/font/google";
import Image from "next/image";
import { SiteFooter } from "@/components/site-footer";
import { SiteHeader } from "@/components/site-header";
import { site } from "@/lib/site";
import "./globals.css";

const funnelDisplay = Funnel_Display({
variable: "--font-funnel-display",
/* Cal Sans for display, DM Sans for body — the Xhibiter pair. */
const calSans = Cal_Sans({
variable: "--font-cal-sans",
weight: "400",
subsets: ["latin"],
display: "swap",
});

const funnelSans = Funnel_Sans({
variable: "--font-funnel-sans",
const dmSans = DM_Sans({
variable: "--font-dm-sans",
subsets: ["latin"],
display: "swap",
});
Expand Down Expand Up @@ -49,11 +52,24 @@ export default function RootLayout({ children }: LayoutProps<"/">) {
return (
<html
lang="en"
className={`${funnelDisplay.variable} ${funnelSans.variable} h-full antialiased`}
className={`${calSans.variable} ${dmSans.variable} h-full antialiased`}
>
<body className="flex min-h-full flex-col" suppressHydrationWarning>
<SiteHeader />
<main className="flex-1">{children}</main>
<main className="relative isolate flex-1">
{/* The Home 2 gradient behind the top of every page, faded out so it
never ends on a hard edge. Pages that open with their own gradient
band simply cover it. */}
<Image
src="/img/xhibiter/gradient.jpg"
alt=""
width={1920}
height={900}
priority
className="pointer-events-none absolute inset-x-0 top-0 -z-10 h-[56rem] w-full object-cover object-top [mask-image:linear-gradient(to_bottom,#000_55%,transparent)]"
/>
{children}
</main>
<SiteFooter />
</body>
</html>
Expand Down
48 changes: 26 additions & 22 deletions src/app/meetups/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { Metadata } from "next";
import { Collaborators } from "@/components/collaborators";
import { MeetupEvents } from "@/components/meetup-events";
import { Button, SectionLabel } from "@/components/ui";
import { Button, Hero } from "@/components/ui";
import { listUpcomingEvents } from "@/lib/events";
import { site } from "@/lib/site";

Expand All @@ -27,27 +28,30 @@ export default async function MeetupsPage() {

return (
<>
<section className="container-x pt-36 pb-20 md:pt-48 md:pb-28">
<SectionLabel>Meetups</SectionLabel>

<h1 className="display-1 mt-8 max-w-6xl">Meetups.</h1>

<p className="mt-10 max-w-2xl text-lg text-t-muted md:text-xl">
The Code.Sydney Claude community meets weekly in Sydney — beginners and builders
both. See what&rsquo;s next below, or join the group to get notified of every one.
</p>

<div className="mt-12 flex flex-wrap gap-4">
<Button href="#meetups" size="lg">
See what&rsquo;s next
</Button>
<Button href={site.meetup} variant="outline" size="lg">
Join the group
</Button>
</div>
</section>

<section id="meetups" className="container-x scroll-mt-24 pb-16 md:pb-24">
<Hero
label="Meetups"
title="Meetups."
lead={
<>
The Code.Sydney Claude community meets weekly in Sydney — beginners and builders
both. See what&rsquo;s next below, or join the group to get notified of every one.
</>
}
actions={
<>
<Button href="#meetups" size="lg">
See what&rsquo;s next
</Button>
<Button href={site.meetup} variant="outline" size="lg">
Join the group
</Button>
</>
}
>
<Collaborators />
</Hero>

<section id="meetups" className="container-x scroll-mt-24 py-16 md:py-24">
<MeetupEvents events={events} />
</section>
</>
Expand Down
4 changes: 2 additions & 2 deletions src/app/metadata.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ import { site } from "@/lib/site";
transform rather than a runtime module, so importing the layout under Vitest
throws without this. Only `variable` is read by the layout. */
vi.mock("next/font/google", () => ({
Funnel_Display: () => ({ variable: "--font-funnel-display" }),
Funnel_Sans: () => ({ variable: "--font-funnel-sans" }),
Cal_Sans: () => ({ variable: "--font-cal-sans" }),
DM_Sans: () => ({ variable: "--font-dm-sans" }),
}));

const { metadata } = await import("./layout");
Expand Down
6 changes: 3 additions & 3 deletions src/app/p/_lib/profile-detail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,9 @@ export function ProfileDetail({
};

return (
/* A white card, because `bg-page` is a warm off-white and body copy at
`text-t-muted` on it reads as grey on grey. */
<article className="mx-auto max-w-3xl rounded-card bg-surface p-8 md:p-12">
/* A bordered white card, so the profile reads as one panel over the
gradient behind the top of the page. */
<article className="mx-auto max-w-3xl rounded-card border border-stroke bg-surface p-8 md:p-12">
<div className="flex flex-wrap items-center gap-3">
{badged ? (
<p className="inline-flex items-center gap-2 rounded-full bg-ink px-4 py-1.5 text-sm font-medium text-t-invert">
Expand Down
40 changes: 16 additions & 24 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { AgentDirectory } from "@/components/agent-directory";
import { Collaborators } from "@/components/collaborators";
import { Button, SectionLabel } from "@/components/ui";
import { Button, Hero } from "@/components/ui";
import { agents } from "@/lib/agents";
import { site } from "@/lib/site";

Expand All @@ -16,31 +16,23 @@ import { site } from "@/lib/site";
export default function HomePage() {
return (
<>
{/* ---------------------------------------------------------------- */}
{/* Hero */}
{/* ---------------------------------------------------------------- */}
<section className="container-x pt-36 pb-20 md:pt-48 md:pb-28">
<SectionLabel>Agent Exchange</SectionLabel>

<h1 className="display-1 mt-8 max-w-6xl">Agent Exchange.</h1>

<p className="mt-10 max-w-2xl text-lg text-t-muted md:text-xl">{site.tagline}</p>

<div className="mt-12 flex flex-wrap gap-4">
<Button href="#agents" size="lg">
Browse agents
</Button>
<Button href="/contact" variant="outline" size="lg">
List your agent
</Button>
</div>

<Hero
title="Agent Exchange."
lead={site.tagline}
actions={
<>
<Button href="#agents" size="lg">
Browse agents
</Button>
<Button href="/contact" variant="outline" size="lg">
List your agent
</Button>
</>
}
>
<Collaborators />
</section>
</Hero>

{/* ---------------------------------------------------------------- */}
{/* Agent directory — search, filters, listings */}
{/* ---------------------------------------------------------------- */}
<AgentDirectory agents={agents} />
</>
);
Expand Down
Loading
Loading