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.

fix: better styling file handling

Hugo c41a3519 e70e6a5b

+77 -36
+7 -7
app/client.ts
··· 2 2 import "./styles/reset.css.js"; 3 3 import "./styles/theme.css.js"; 4 4 import "./styles/global.css.js"; 5 - import "./styles/sprinkles.css.js"; 6 - import "./styles/utilities.css.js"; 7 - import "./styles/components.css.js"; 8 - import "./styles/action-header.css.js"; 9 - import "./styles/pages/landing.css.js"; 10 - import "./styles/pages/login.css.js"; 11 - import "./styles/pages/profile.css.js"; 5 + 6 + // Auto-register remaining style files. Base layers above are explicit because 7 + // their globalStyle rules depend on import order; everything else is scoped. 8 + import.meta.glob( 9 + ["./**/*.css.ts", "!./styles/reset.css.ts", "!./styles/theme.css.ts", "!./styles/global.css.ts"], 10 + { eager: true }, 11 + ); 12 12 13 13 void createClient();
+21 -7
app/components/Layout/Footer/index.tsx
··· 1 + import { ExternalLink } from "../../../icons.ts"; 1 2 import * as s from "./styles.css.ts"; 2 3 4 + function ExternalFooterLink({ href, children }: { href: string; children: string }) { 5 + return ( 6 + <a 7 + href={href} 8 + class={s.link} 9 + target="_blank" 10 + rel="noopener noreferrer" 11 + aria-label={`${children} (opens in new tab)`} 12 + > 13 + {children} 14 + <ExternalLink size={12} class={s.externalIcon} /> 15 + </a> 16 + ); 17 + } 18 + 3 19 export function Footer() { 4 20 return ( 5 21 <footer class={s.footer}> ··· 8 24 <a href="/pricing" class={s.link}> 9 25 Pricing 10 26 </a> 11 - <a href="https://tangled.org/exosphere.site/airglow" class={s.link}> 27 + <ExternalFooterLink href="https://tangled.org/exosphere.site/airglow"> 12 28 Source 13 - </a> 14 - <a href="https://bsky.app/profile/airglow.run" class={s.link}> 29 + </ExternalFooterLink> 30 + <ExternalFooterLink href="https://bsky.app/profile/airglow.run"> 15 31 Bluesky 16 - </a> 17 - <a href="https://airglow.offprint.app" class={s.link}> 18 - Blog 19 - </a> 32 + </ExternalFooterLink> 33 + <ExternalFooterLink href="https://airglow.offprint.app">Blog</ExternalFooterLink> 20 34 </div> 21 35 <span>&copy; {new Date().getFullYear()} Airglow</span> 22 36 </div>
+7
app/components/Layout/Footer/styles.css.ts
··· 27 27 export const link = style({ 28 28 color: vars.color.textSecondary, 29 29 textDecoration: "none", 30 + display: "inline-flex", 31 + alignItems: "center", 32 + gap: space[1], 30 33 ":hover": { 31 34 color: vars.color.text, 32 35 }, 33 36 }); 37 + 38 + export const externalIcon = style({ 39 + opacity: 0.6, 40 + });
+1 -4
app/components/Layout/Header/index.tsx
··· 16 16 <div class={s.nav}> 17 17 {user ? ( 18 18 <> 19 + <span class={s.userInfo}>@{user.handle}</span> 19 20 <a href="/dashboard" class={s.navLink}> 20 21 Dashboard 21 22 </a> 22 - <a href="/dashboard/secrets" class={s.navLink}> 23 - Secrets 24 - </a> 25 - <span class={s.userInfo}>@{user.handle}</span> 26 23 <form method="post" action="/auth/signout"> 27 24 <button type="submit" class={s.signOutButton}> 28 25 Sign out
+6 -1
app/components/Layout/PageHeader/styles.css.ts
··· 11 11 marginBlockEnd: space[6], 12 12 }); 13 13 14 - export const actions = style({}); 14 + export const actions = style({ 15 + display: "flex", 16 + alignItems: "center", 17 + gap: space[2], 18 + flexWrap: "wrap", 19 + }); 15 20 16 21 export const description = style({ 17 22 color: vars.color.textSecondary,
-2
app/components/NsidCode/styles.css.ts
··· 11 11 inlineSize: "16px", 12 12 blockSize: "16px", 13 13 flexShrink: 0, 14 - backgroundColor: "#0a0a0a", 15 14 borderRadius: "2px", 16 - padding: "3px", 17 15 });
+2
app/icons.ts
··· 55 55 import ZapData from "lucide/icons/zap"; 56 56 import CodeData from "lucide/icons/code"; 57 57 import RepeatData from "lucide/icons/repeat"; 58 + import SettingsData from "lucide/icons/settings"; 58 59 59 60 export const Activity = icon(ActivityData); 60 61 export const ArrowLeft = icon(ArrowLeftData); ··· 84 85 export const Zap = icon(ZapData); 85 86 export const Code = icon(CodeData); 86 87 export const Repeat = icon(RepeatData); 88 + export const Settings = icon(SettingsData);
+13 -6
app/islands/AutomationForm.css.ts
··· 197 197 }); 198 198 199 199 export const submitBtn = style({ 200 - width: "100%", 201 200 display: "inline-flex", 202 201 alignItems: "center", 203 202 justifyContent: "center", 204 203 paddingBlock: space[2], 205 - paddingInline: space[4], 204 + paddingInline: space[5], 206 205 fontSize: fontSize.base, 207 206 fontWeight: fontWeight.medium, 208 207 color: vars.color.accentText, ··· 226 225 }, 227 226 }); 228 227 229 - export const stickySubmit = style({ 230 - position: "sticky", 231 - insetBlockEnd: space[4], 232 - zIndex: 10, 228 + export const submitWrap = style({ 229 + display: "flex", 230 + justifyContent: "flex-end", 233 231 }); 232 + 233 + export const stickySubmit = style([ 234 + submitWrap, 235 + { 236 + position: "sticky", 237 + insetBlockEnd: space[4], 238 + zIndex: 10, 239 + }, 240 + ]); 234 241 235 242 export const alertError = style({ 236 243 paddingBlock: space[3],
+1 -1
app/islands/AutomationForm.tsx
··· 1553 1553 1554 1554 {error && <div class={s.alertError}>{error}</div>} 1555 1555 1556 - <div class={isEdit ? s.stickySubmit : undefined}> 1556 + <div class={isEdit ? s.stickySubmit : s.submitWrap}> 1557 1557 <button 1558 1558 type="submit" 1559 1559 class={s.submitBtn}
+12 -5
app/routes/dashboard/index.tsx
··· 1 1 import { createRoute } from "honox/factory"; 2 2 import { eq } from "drizzle-orm"; 3 - import { Plus, Eye } from "../../icons.js"; 3 + import { Plus, Eye, Settings } from "../../icons.js"; 4 4 import { db } from "@/db/index.js"; 5 5 import { automations } from "@/db/schema.js"; 6 6 import { AppShell } from "../../components/Layout/AppShell/index.js"; ··· 15 15 import { NsidCode } from "../../components/NsidCode/index.js"; 16 16 import { actionTypeLabels } from "@/automations/labels.js"; 17 17 import ThemeToggle from "../../islands/ThemeToggle.js"; 18 - import { centerTextSm } from "../../styles/utilities.css.js"; 18 + import { centerTextSm, pushEnd } from "../../styles/utilities.css.js"; 19 19 20 20 export default createRoute(async (c) => { 21 21 const user = c.get("user"); ··· 30 30 title="Automations" 31 31 description={`${autos.length} automation${autos.length !== 1 ? "s" : ""}`} 32 32 actions={ 33 - <Button href="/dashboard/automations/new" size="sm"> 34 - <Plus size={16} /> New Automation 35 - </Button> 33 + <> 34 + <Button href="/dashboard/automations/new" size="sm"> 35 + <Plus size={16} /> New Automation 36 + </Button> 37 + <span class={pushEnd}> 38 + <Button href="/dashboard/secrets" variant="ghost" size="sm"> 39 + <Settings size={14} /> Secrets 40 + </Button> 41 + </span> 42 + </> 36 43 } 37 44 /> 38 45
+3 -3
app/styles/pages/automations.css.ts
··· 47 47 48 48 export const grid = style({ 49 49 display: "grid", 50 - gridTemplateColumns: "1fr", 50 + gridTemplateColumns: "minmax(0, 1fr)", 51 51 gap: space[4], 52 52 "@media": { 53 53 [mq.md]: { 54 - gridTemplateColumns: "1fr 1fr", 54 + gridTemplateColumns: "repeat(2, minmax(0, 1fr))", 55 55 }, 56 56 [mq.lg]: { 57 - gridTemplateColumns: "1fr 1fr 1fr", 57 + gridTemplateColumns: "repeat(3, minmax(0, 1fr))", 58 58 }, 59 59 }, 60 60 });
+4
app/styles/utilities.css.ts
··· 36 36 fontSize: fontSize.sm, 37 37 color: vars.color.textMuted, 38 38 }); 39 + 40 + export const pushEnd = style({ 41 + marginInlineStart: "auto", 42 + });