···6262 </div>
6363 </Container>
6464 </AppShell>,
6565- { title: "Sign in — Airglow" },
6565+ {
6666+ title: "Sign in — Airglow",
6767+ description:
6868+ "Sign in to Airglow with your AT Protocol identity to create automations and webhooks.",
6969+ },
6670 );
6771});
6872
+62-40
app/routes/index.tsx
···11import { createRoute } from "honox/factory";
22import { desc, count } from "drizzle-orm";
33+import { raw } from "hono/html";
34import { Webhook, FilePlus2, Filter, Activity } from "../icons.js";
45import { getSessionUser } from "@/auth/middleware.js";
56import { db } from "@/db/index.js";
···1314import ThemeToggle from "../islands/ThemeToggle.js";
1415import * as s from "../styles/pages/landing.css.js";
15161717+const jsonLd = raw(
1818+ `<script type="application/ld+json">${JSON.stringify({
1919+ "@context": "https://schema.org",
2020+ "@type": "WebApplication",
2121+ name: "Airglow",
2222+ url: "https://airglow.run",
2323+ description:
2424+ "Automate the AT Protocol and Bluesky — webhooks, record creation, and Jetstream event filtering.",
2525+ applicationCategory: "DeveloperApplication",
2626+ operatingSystem: "Web",
2727+ })}</script>`,
2828+);
2929+1630export default createRoute(async (c) => {
1731 const user = await getSessionUser(c);
1832···25392640 return c.render(
2741 <AppShell header={<Header user={user} actions={<ThemeToggle />} />}>
4242+ {jsonLd}
2843 <Container>
2944 <section class={s.hero}>
3030- <h1 class={s.heroTitle}>Automations for the AT Protocol</h1>
4545+ <h1 class={s.heroTitle}>Webhooks & Automations for the AT Protocol</h1>
3146 <p class={s.heroSubtitle}>
3232- Listen to events across the AT Protocol network and trigger actions automatically.
3333- Filter by lexicon, deliver webhooks, create records on your PDS, and track every run.
4747+ Automate Bluesky and the AT Protocol network. Listen to Jetstream events, filter by
4848+ lexicon, deliver webhooks, create records on your PDS, and track every run.
3449 </p>
3550 {user ? (
3651 <Button href="/dashboard" size="lg">
···4358 )}
4459 </section>
45604646- <section class={s.features}>
4747- <div class={s.featureCard}>
4848- <div class={s.featureIcon}>
4949- <Webhook size={28} />
6161+ <section>
6262+ <h2 class={s.stepsTitle}>Features</h2>
6363+ <div class={s.features}>
6464+ <div class={s.featureCard}>
6565+ <div class={s.featureIcon}>
6666+ <Webhook size={28} />
6767+ </div>
6868+ <h3 class={s.featureTitle}>Webhook Delivery</h3>
6969+ <p class={s.featureDesc}>
7070+ Receive HTTP POST callbacks instantly when matching events occur on the AT Protocol
7171+ network via Jetstream.
7272+ </p>
5073 </div>
5151- <h3 class={s.featureTitle}>Webhook Delivery</h3>
5252- <p class={s.featureDesc}>
5353- Receive HTTP POST callbacks instantly when matching events occur on the AT Protocol
5454- network via Jetstream.
5555- </p>
5656- </div>
5757- <div class={s.featureCard}>
5858- <div class={s.featureIcon}>
5959- <FilePlus2 size={28} />
7474+ <div class={s.featureCard}>
7575+ <div class={s.featureIcon}>
7676+ <FilePlus2 size={28} />
7777+ </div>
7878+ <h3 class={s.featureTitle}>Record Creation</h3>
7979+ <p class={s.featureDesc}>
8080+ Automatically create records on your PDS when events match. Use templates with
8181+ placeholders to build records from event data.
8282+ </p>
6083 </div>
6161- <h3 class={s.featureTitle}>Record Creation</h3>
6262- <p class={s.featureDesc}>
6363- Automatically create records on your PDS when events match. Use templates with
6464- placeholders to build records from event data.
6565- </p>
6666- </div>
6767- <div class={s.featureCard}>
6868- <div class={s.featureIcon}>
6969- <Filter size={28} />
8484+ <div class={s.featureCard}>
8585+ <div class={s.featureIcon}>
8686+ <Filter size={28} />
8787+ </div>
8888+ <h3 class={s.featureTitle}>Smart Filtering</h3>
8989+ <p class={s.featureDesc}>
9090+ Listen to specific record types by NSID. Add field-level conditions with operators
9191+ like equals, starts with, or contains.
9292+ </p>
7093 </div>
7171- <h3 class={s.featureTitle}>Smart Filtering</h3>
7272- <p class={s.featureDesc}>
7373- Listen to specific record types by NSID. Add field-level conditions with operators
7474- like equals, starts with, or contains.
7575- </p>
7676- </div>
7777- <div class={s.featureCard}>
7878- <div class={s.featureIcon}>
7979- <Activity size={28} />
9494+ <div class={s.featureCard}>
9595+ <div class={s.featureIcon}>
9696+ <Activity size={28} />
9797+ </div>
9898+ <h3 class={s.featureTitle}>Delivery Tracking</h3>
9999+ <p class={s.featureDesc}>
100100+ Full delivery log with status codes, retry attempts, and error details. Know exactly
101101+ what happened with every event.
102102+ </p>
80103 </div>
8181- <h3 class={s.featureTitle}>Delivery Tracking</h3>
8282- <p class={s.featureDesc}>
8383- Full delivery log with status codes, retry attempts, and error details. Know exactly
8484- what happened with every event.
8585- </p>
86104 </div>
87105 </section>
88106···139157 </section>
140158 </Container>
141159 </AppShell>,
142142- { title: "Airglow — Automations for the AT Protocol" },
160160+ {
161161+ title: "Airglow — Webhooks & Automations for the AT Protocol",
162162+ description:
163163+ "Automate Bluesky and the AT Protocol. Set up webhooks, create records, and filter Jetstream events by lexicon — no code required.",
164164+ },
143165 );
144166});
+6-1
app/routes/lexicons/[nsid].tsx
···178178 </Stack>
179179 </Container>
180180 </AppShell>,
181181- { title: `${nsid} — Airglow` },
181181+ {
182182+ title: `${nsid} — Airglow`,
183183+ description: description
184184+ ? `${description.replace(/\.?$/, ".")} Browse automations for ${nsid} on Airglow.`
185185+ : `Browse automations using the ${nsid} AT Protocol lexicon on Airglow.`,
186186+ },
182187 );
183188});
+63
app/routes/lexicons/index.tsx
···11+import { createRoute } from "honox/factory";
22+import { desc, count } from "drizzle-orm";
33+import { getSessionUser } from "@/auth/middleware.js";
44+import { db } from "@/db/index.js";
55+import { automations } from "@/db/schema.js";
66+import { AppShell } from "../../components/Layout/AppShell/index.js";
77+import { Header } from "../../components/Layout/Header/index.js";
88+import { Container } from "../../components/Layout/Container/index.js";
99+import { PageHeader } from "../../components/Layout/PageHeader/index.js";
1010+import { Table } from "../../components/Table/index.js";
1111+import { InlineCode } from "../../components/CodeBlock/index.js";
1212+import ThemeToggle from "../../islands/ThemeToggle.js";
1313+1414+export default createRoute(async (c) => {
1515+ const user = await getSessionUser(c);
1616+1717+ const lexicons = await db
1818+ .select({ lexicon: automations.lexicon, count: count() })
1919+ .from(automations)
2020+ .groupBy(automations.lexicon)
2121+ .orderBy(desc(count()));
2222+2323+ return c.render(
2424+ <AppShell header={<Header user={user} actions={<ThemeToggle />} />}>
2525+ <Container>
2626+ <PageHeader
2727+ title="AT Protocol Lexicons"
2828+ description={`Browse ${lexicons.length} lexicon${lexicons.length !== 1 ? "s" : ""} with active automations on Airglow.`}
2929+ />
3030+3131+ {lexicons.length > 0 ? (
3232+ <Table>
3333+ <thead>
3434+ <tr>
3535+ <th>NSID</th>
3636+ <th>Automations</th>
3737+ </tr>
3838+ </thead>
3939+ <tbody>
4040+ {lexicons.map((row) => (
4141+ <tr key={row.lexicon}>
4242+ <td>
4343+ <a href={`/lexicons/${row.lexicon}`}>
4444+ <InlineCode>{row.lexicon}</InlineCode>
4545+ </a>
4646+ </td>
4747+ <td>{row.count}</td>
4848+ </tr>
4949+ ))}
5050+ </tbody>
5151+ </Table>
5252+ ) : (
5353+ <p>No lexicons with active automations yet.</p>
5454+ )}
5555+ </Container>
5656+ </AppShell>,
5757+ {
5858+ title: "AT Protocol Lexicons — Airglow",
5959+ description:
6060+ "Browse AT Protocol lexicons with active automations on Airglow. Discover webhooks and automations for Bluesky and the AT Protocol network.",
6161+ },
6262+ );
6363+});
+4-1
app/routes/u/[handle]/index.tsx
···215215 </Stack>
216216 </Container>
217217 </AppShell>,
218218- { title: `@${profileUser?.handle ?? handle} — Airglow` },
218218+ {
219219+ title: `@${profileUser?.handle ?? handle} — Airglow`,
220220+ description: `See @${profileUser?.handle ?? handle}'s automations and lexicons on Airglow — automation platform for the AT Protocol.`,
221221+ },
219222 );
220223});