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.

perf: landing page improvements

Hugo 6ad48028 62932f81

+48 -9
+32 -6
app/routes/_renderer.tsx
··· 20 20 @media(prefers-color-scheme:dark){html:not([data-theme]){background:oklch(.13 0 0);color:oklch(.87 0 0)}} 21 21 </style>`); 22 22 23 - // In production, read the Vite manifest to emit blocking <link> tags for CSS 23 + // Inline ThemeToggle island CSS (~300B) in prod. The island loads dynamically 24 + // via honox's runtime, so its CSS normally arrives after first paint. Inlining 25 + // avoids a flash on the header button. 26 + const themeToggleCssModules = import.meta.glob<string>("/dist/static/ThemeToggle-*.css", { 27 + eager: true, 28 + query: "?raw", 29 + import: "default", 30 + }); 31 + const themeToggleCss = Object.values(themeToggleCssModules)[0] ?? ""; 32 + const inlineIslandCss = themeToggleCss ? raw(`<style>${themeToggleCss}</style>`) : null; 33 + 34 + // In production, read the Vite manifest to emit blocking <link> tags for CSS. 35 + // Walk from `isEntry` chunks along static `imports` only — dynamic-import chunks 36 + // (islands) carry their CSS via Vite's runtime when the island JS loads, so they 37 + // don't need blocking links here. Avoids ~18KB of unused island CSS on routes 38 + // that don't render those islands. 24 39 function CssLinks() { 25 40 if (!import.meta.env.PROD) return <></>; 26 41 42 + type ManifestEntry = { css?: string[]; imports?: string[]; isEntry?: boolean }; 27 43 const manifests = import.meta.glob<{ 28 - default: Record<string, { css?: string[] }>; 44 + default: Record<string, ManifestEntry>; 29 45 }>("/dist/.vite/manifest.json", { eager: true }); 30 46 const manifest = Object.values(manifests)[0]?.default; 31 47 if (!manifest) return <></>; 32 48 33 49 const base = import.meta.env.BASE_URL ?? "/"; 34 50 const seen = new Set<string>(); 35 - for (const entry of Object.values(manifest)) { 36 - for (const css of entry.css ?? []) { 37 - seen.add(css); 38 - } 51 + const visited = new Set<string>(); 52 + 53 + function walk(key: string) { 54 + if (visited.has(key)) return; 55 + visited.add(key); 56 + const entry = manifest![key]; 57 + if (!entry) return; 58 + for (const css of entry.css ?? []) seen.add(css); 59 + for (const imp of entry.imports ?? []) walk(imp); 60 + } 61 + 62 + for (const [key, entry] of Object.entries(manifest)) { 63 + if (entry.isEntry) walk(key); 39 64 } 40 65 41 66 return ( ··· 65 90 {headInline} 66 91 {!import.meta.env.PROD && <link rel="stylesheet" href="/__dev.css" />} 67 92 <CssLinks /> 93 + {inlineIslandCss} 68 94 <link rel="icon" href="/favicon.svg" type="image/svg+xml" /> 69 95 <link rel="canonical" href={canonicalUrl} /> 70 96 <title>{pageTitle}</title>
+16 -3
app/routes/index.tsx
··· 28 28 })}</script>`, 29 29 ); 30 30 31 - export default createRoute(async (c) => { 32 - const user = await getSessionUser(c); 31 + type TopLexicon = { lexicon: string; count: number }; 32 + let topLexiconsCache: { at: number; rows: TopLexicon[] } | null = null; 33 + const TOP_LEXICONS_TTL_MS = 10 * 60_000; 33 34 34 - const topLexicons = await db 35 + async function getTopLexicons(): Promise<TopLexicon[]> { 36 + const now = Date.now(); 37 + if (topLexiconsCache && now - topLexiconsCache.at < TOP_LEXICONS_TTL_MS) { 38 + return topLexiconsCache.rows; 39 + } 40 + const rows = await db 35 41 .select({ lexicon: automations.lexicon, count: count() }) 36 42 .from(automations) 37 43 .groupBy(automations.lexicon) 38 44 .orderBy(desc(count())) 39 45 .limit(10); 46 + topLexiconsCache = { at: now, rows }; 47 + return rows; 48 + } 49 + 50 + export default createRoute(async (c) => { 51 + const user = await getSessionUser(c); 52 + const topLexicons = await getTopLexicons(); 40 53 41 54 return c.render( 42 55 <AppShell header={<Header user={user} actions={<ThemeToggle />} />}>