Webhooks for the AT Protocol airglow.run
atproto atprotocol automation webhook
12
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: og-image

Hugo 21fc91b3 39ceb684

+106 -11
+1
app/components/Button/styles.css.ts
··· 33 33 boxShadow: `${vars.shadow.highlight}, ${vars.shadow.sm}`, 34 34 ":hover": { 35 35 backgroundColor: vars.color.accentHover, 36 + color: "white", 36 37 }, 37 38 ":active": { 38 39 backgroundColor: vars.color.accentActive,
+1 -3
app/routes/_renderer.tsx
··· 25 25 if (!import.meta.env.PROD) return <></>; 26 26 27 27 const manifests = import.meta.glob<{ 28 - default: Record<string, { css?: string[]; isDynamicEntry?: boolean }>; 28 + default: Record<string, { css?: string[] }>; 29 29 }>("/dist/.vite/manifest.json", { eager: true }); 30 30 const manifest = Object.values(manifests)[0]?.default; 31 31 if (!manifest) return <></>; ··· 33 33 const base = import.meta.env.BASE_URL ?? "/"; 34 34 const seen = new Set<string>(); 35 35 for (const entry of Object.values(manifest)) { 36 - // Island CSS loads on-demand when their JS hydrates — no need to render-block 37 - if (entry.isDynamicEntry) continue; 38 36 for (const css of entry.css ?? []) { 39 37 seen.add(css); 40 38 }
+2 -2
app/routes/index.tsx
··· 48 48 lexicon, deliver webhooks, create records on your PDS, and track every run. 49 49 </p> 50 50 {user ? ( 51 - <Button href="/dashboard" size="lg"> 51 + <Button href="/dashboard"> 52 52 Go to Dashboard 53 53 </Button> 54 54 ) : ( 55 - <Button href="/auth/login" size="lg"> 55 + <Button href="/auth/login"> 56 56 Get Started 57 57 </Button> 58 58 )}
+95
app/routes/og-image.tsx
··· 1 + import { createRoute } from "honox/factory"; 2 + import { raw } from "hono/html"; 3 + 4 + const ogStyles = raw(`<style> 5 + body { margin: 0; background: oklch(0.13 0 0); } 6 + .og { 7 + width: 1200px; 8 + height: 630px; 9 + display: flex; 10 + flex-direction: column; 11 + align-items: center; 12 + justify-content: center; 13 + gap: 32px; 14 + background: oklch(0.13 0 0); 15 + color: oklch(0.87 0 0); 16 + font-family: Inter, Roboto, "Helvetica Neue", Arial, sans-serif; 17 + position: relative; 18 + overflow: hidden; 19 + } 20 + /* Decorative glow rings behind logo */ 21 + .og::before { 22 + content: ""; 23 + position: absolute; 24 + top: 50%; 25 + left: 50%; 26 + width: 500px; 27 + height: 500px; 28 + transform: translate(-50%, -55%); 29 + border-radius: 50%; 30 + background: radial-gradient(circle, oklch(0.75 0.18 65 / 0.08) 0%, transparent 70%); 31 + pointer-events: none; 32 + } 33 + .logo { 34 + position: relative; 35 + z-index: 1; 36 + } 37 + .title { 38 + font-size: 64px; 39 + font-weight: 700; 40 + letter-spacing: -0.02em; 41 + line-height: 1.15; 42 + color: oklch(0.93 0 0); 43 + position: relative; 44 + z-index: 1; 45 + margin: 0; 46 + } 47 + .tagline { 48 + font-size: 28px; 49 + font-weight: 400; 50 + color: oklch(0.55 0 0); 51 + max-width: 700px; 52 + text-align: center; 53 + line-height: 1.4; 54 + position: relative; 55 + z-index: 1; 56 + margin: 0; 57 + } 58 + .url { 59 + position: absolute; 60 + bottom: 32px; 61 + right: 40px; 62 + font-size: 22px; 63 + font-weight: 500; 64 + color: oklch(0.75 0.18 65); 65 + z-index: 1; 66 + } 67 + </style>`); 68 + 69 + export default createRoute((c) => { 70 + return c.html( 71 + <html lang="en"> 72 + <head> 73 + <meta charset="utf-8" /> 74 + <meta name="robots" content="noindex" /> 75 + {ogStyles} 76 + </head> 77 + <body> 78 + <div class="og"> 79 + <div class="logo"> 80 + <svg viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg" width="80" height="80"> 81 + <circle cx="32" cy="32" r="10" fill="#E8923A" /> 82 + <circle cx="32" cy="32" r="20" stroke="#E8923A" stroke-width="3.5" opacity="0.45" /> 83 + <circle cx="32" cy="32" r="29" stroke="#E8923A" stroke-width="2.5" opacity="0.2" /> 84 + </svg> 85 + </div> 86 + <h1 class="title">Airglow</h1> 87 + <p class="tagline"> 88 + Webhooks &amp; Automations for the AT&nbsp;Protocol 89 + </p> 90 + <span class="url">airglow.run</span> 91 + </div> 92 + </body> 93 + </html>, 94 + ); 95 + });
+1
app/server.ts
··· 26 26 }), 27 27 ); 28 28 app.use("/favicon.svg", serveStatic({ root: "./dist" })); 29 + app.use("/og-image.png", serveStatic({ root: "./dist" })); 29 30 } 30 31 31 32 // Security headers on all responses
+6 -6
app/styles/tokens/colors.ts
··· 7 7 elevated: "oklch(0.21 0 0)", 8 8 border: "oklch(0.25 0 0)", 9 9 borderSubtle: "oklch(0.20 0 0)", 10 - text: "oklch(0.87 0 0)", 11 - textSecondary: "oklch(0.65 0 0)", 12 - textMuted: "oklch(0.45 0 0)", 10 + text: "oklch(0.90 0 0)", 11 + textSecondary: "oklch(0.68 0 0)", 12 + textMuted: "oklch(0.50 0 0)", 13 13 heading: "oklch(0.93 0 0)", 14 14 15 15 link: "oklch(0.78 0.14 65)", ··· 40 40 borderSubtle: "oklch(0.92 0 0)", 41 41 text: "oklch(0.23 0 0)", 42 42 textSecondary: "oklch(0.45 0 0)", 43 - textMuted: "oklch(0.62 0 0)", 43 + textMuted: "oklch(0.55 0 0)", 44 44 heading: "oklch(0.15 0 0)", 45 45 46 - link: "oklch(0.55 0.18 65)", 47 - linkHover: "oklch(0.48 0.20 65)", 46 + link: "oklch(0.48 0.18 65)", 47 + linkHover: "oklch(0.42 0.20 65)", 48 48 49 49 accent: "oklch(0.62 0.20 65)", 50 50 accentHover: "oklch(0.57 0.22 65)",
public/og-image.png

This is a binary file and will not be displayed.