mirror of
https://github.com/block/buzz.git
synced 2026-11-02 15:31:27 +00:00
Shared compute in the community is worth noticing even when this machine is neither using nor adding to it -- that is the moment to either tap in or contribute, and a static slate dot said nothing. Pulse is now a named signal rather than a boolean, because two different facts want motion and a single flag would make a throb ambiguous: - activity -- real work is in flight on this node right now - invite -- there is compute here, and we are outside it They are deliberately unalike. Activity uses Tailwind's stock ping: quick and insistent, because something is happening. Invite breathes on a new 2.8s keyframe in slate and never reaches full opacity: noticeable on a second glance, never competing with unread badges. An empty or unfetched community still never throbs -- an invitation to join a mesh that does not exist would be a lie told with animation. Signed-off-by: Michael Neale <michael.neale@gmail.com>
124 lines
4.9 KiB
JavaScript
124 lines
4.9 KiB
JavaScript
/** @type {import('tailwindcss').Config} */
|
|
export default {
|
|
theme: {
|
|
extend: {
|
|
// Sub-`text-xs` ramp for meta text (timestamps, count badges, tracking
|
|
// labels) and tiny glyphs. Defined in rem so Cmd +/- zoom — which scales
|
|
// the root <html> font-size — keeps scaling them. Do NOT reintroduce
|
|
// arbitrary `text-[…rem]` / `text-[…px]` literals; the px-text guard
|
|
// rejects them. Stock scale picks up from here: xs (12px), sm (14px)…
|
|
fontSize: {
|
|
"2xs": "0.6875rem", // 11px — meta-text workhorse (timestamps, badges)
|
|
"3xs": "0.5rem", // 8px — tiny glyphs / micro labels
|
|
badge: "0.625rem", // 10px — compact status badges
|
|
// 40px — onboarding page titles (tightened tracking for large display type)
|
|
title: ["2.5rem", { lineHeight: "1.15", letterSpacing: "-0.02em" }],
|
|
// 36px — the backup-step private key, shown large in monospace
|
|
"nsec-key": ["2.25rem", { lineHeight: "1.3" }],
|
|
},
|
|
boxShadow: {
|
|
"content-edge": "-1px -1px 0 0 hsl(var(--sidebar-border) / 0.45)",
|
|
// Edge + elevation for a surface anchored to the right of the content
|
|
// area, whose only exposed edge faces left. Tailwind's stock shadows are
|
|
// all y-offset, so they cast almost nothing sideways — `shadow-xl` on a
|
|
// left-facing edge is nearly invisible. Both layers run -x so they wrap
|
|
// the surface's rounded left corners: the hairline draws the boundary
|
|
// (and carries dark mode, where a black shadow reads as nothing), the
|
|
// soft layer carries the lift. A left-only `border` can't do this job —
|
|
// it tapers out at each corner instead of turning it.
|
|
"panel-left":
|
|
"-1px 0 0 0 hsl(var(--border) / 0.8), -16px 0 32px -12px rgb(0 0 0 / 0.18)",
|
|
},
|
|
borderRadius: {
|
|
lg: "var(--radius)",
|
|
md: "calc(var(--radius) - 2px)",
|
|
sm: "calc(var(--radius) - 4px)",
|
|
},
|
|
spacing: {
|
|
4.5: "1.125rem",
|
|
},
|
|
keyframes: {
|
|
// The mesh-invite pulse: there is shared compute in the community and
|
|
// this machine is neither using nor adding to it. Deliberately unlike
|
|
// Tailwind's stock `ping`, which is quick and insistent because it
|
|
// signals something happening *now*. Nothing is happening here, so this
|
|
// breathes slowly and never reaches full opacity — noticeable on a
|
|
// second glance, never competing with unread badges.
|
|
"mesh-invite": {
|
|
"0%, 100%": { transform: "scale(1)", opacity: "0.55" },
|
|
"50%": { transform: "scale(2)", opacity: "0" },
|
|
},
|
|
},
|
|
animation: {
|
|
"mesh-invite": "mesh-invite 2.8s cubic-bezier(0.4, 0, 0.6, 1) infinite",
|
|
},
|
|
fontFamily: {
|
|
sans: [
|
|
'"Inter Variable"',
|
|
"Inter",
|
|
'"Avenir Next"',
|
|
'"Segoe UI"',
|
|
"sans-serif",
|
|
],
|
|
},
|
|
colors: {
|
|
background: "hsl(var(--background))",
|
|
foreground: "hsl(var(--foreground))",
|
|
card: {
|
|
DEFAULT: "hsl(var(--card))",
|
|
foreground: "hsl(var(--card-foreground))",
|
|
},
|
|
popover: {
|
|
DEFAULT: "hsl(var(--popover))",
|
|
foreground: "hsl(var(--popover-foreground))",
|
|
},
|
|
primary: {
|
|
DEFAULT: "hsl(var(--primary))",
|
|
foreground: "hsl(var(--primary-foreground))",
|
|
},
|
|
secondary: {
|
|
DEFAULT: "hsl(var(--secondary))",
|
|
foreground: "hsl(var(--secondary-foreground))",
|
|
},
|
|
muted: {
|
|
DEFAULT: "hsl(var(--muted))",
|
|
foreground: "hsl(var(--muted-foreground))",
|
|
},
|
|
accent: {
|
|
DEFAULT: "hsl(var(--accent))",
|
|
foreground: "hsl(var(--accent-foreground))",
|
|
},
|
|
destructive: {
|
|
DEFAULT: "hsl(var(--destructive))",
|
|
foreground: "hsl(var(--destructive-foreground))",
|
|
},
|
|
border: "hsl(var(--border))",
|
|
input: "hsl(var(--input))",
|
|
ring: "hsl(var(--ring))",
|
|
sidebar: {
|
|
DEFAULT: "hsl(var(--sidebar-background))",
|
|
foreground: "hsl(var(--sidebar-foreground))",
|
|
primary: "hsl(var(--sidebar-primary))",
|
|
"primary-foreground": "hsl(var(--sidebar-primary-foreground))",
|
|
active: "hsl(var(--sidebar-active))",
|
|
"active-foreground": "hsl(var(--sidebar-active-foreground))",
|
|
accent: "hsl(var(--sidebar-accent))",
|
|
"accent-foreground": "hsl(var(--sidebar-accent-foreground))",
|
|
border: "hsl(var(--sidebar-border))",
|
|
ring: "hsl(var(--sidebar-ring))",
|
|
},
|
|
status: {
|
|
added: "var(--status-added)",
|
|
deleted: "var(--status-deleted)",
|
|
modified: "var(--status-modified)",
|
|
},
|
|
warning: {
|
|
DEFAULT: "var(--ui-warning)",
|
|
bg: "var(--ui-warning-bg)",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
plugins: [],
|
|
};
|