@at-flux/astroflare
v1.0.9
Published
Reusable headless components, styles, and utilities for Astro + Tailwind v4 + Cloudflare projects
Maintainers
Readme
@at-flux/astroflare
Reusable headless components, styles, and utilities for Astro + Tailwind v4 + Cloudflare projects.
For type-safe DOM helpers, use the separate package @at-flux/dom.
Package entrypoints
| Subpath | Contents |
| ---------------------------------- | --------------------------------------------- |
| @at-flux/astroflare | Core — forms utilities (same as ./core) |
| @at-flux/astroflare/core | Forms; also exposes the forms namespace |
| @at-flux/astroflare/forms | Resend email + form HTML helpers |
| @at-flux/astroflare/components/* | Astro components (source) |
| @at-flux/astroflare/styles/* | CSS (source) |
Examples
// Flat imports from core
import { sendEmail } from "@at-flux/astroflare";
// Explicit subpaths
import { renderEmailTemplate } from "@at-flux/astroflare/forms";
// Namespaced (from core / root)
import { forms } from "@at-flux/astroflare/core";Contents
Components (Astro)
Modal.astro— Headless modal using native<dialog>and<app-modal>web component (classapplies to the panel)ModalTrigger.astro— Trigger that opens a modal by ID using<modal-trigger>web componentContactModalCta.astro— Opinionated contact button (solid pill or text link) wrapped inModalTriggerInstagramProfileLink.astro— Small Instagram icon +@handlelink with safe defaultsSection.astro— Page section with optionalnarrowandcontentOnly(inner width wrapper without outer padding)ThemeToggle.astro— Dark/light mode toggle using<theme-toggle>web componentIconButton.astro— Accessible icon-only control that renders<button>or<a>ClientRouterLoadingSpinner.astro— Loading spinner for Astro view transitionsTooltip.astro— Lightweight hover/focus tooltip wrapper for compact metadata summariesListSummary.astro— Generic inline list truncation with+Noverflow and tooltip detailsTagSummary.astro— Generic deterministic tag pill list with+Ntooltip overflowMediaProtect.astro— Style-agnostic media wrapper that applies no-save classes with delegated drag/context-menu protectionFilterPills.astro— Tag-colored filter chips with analloption and active-state stylingPager.astro— Pagination UI primitive for both browser-only and link-driven query paginationCollectionQuery.astro— Unified collection filtering/pagination component (client mode by default; URL-driven server mode withuseServer)CollectionFooterControls.astro— Server-only row: optionalsummaryslot,Pager, and page-size<form>(same query contract asCollectionQueryserver mode)
Component props reference
Modal.astro:id,class,backdropClass,panelClass,closeButtonClass,contentClassModalTrigger.astro:modalId,classContactModalCta.astro:modalId,label,variant,classInstagramProfileLink.astro:handle,href,class,aria-labelSection.astro:id,class,narrow,contentOnlyThemeToggle.astro:classIconButton.astro:label,href,class,id, passthrough attributesTooltip.astro:text,position,class,panelClassListSummary.astro:items,visibleCount,separator,class,emptyLabel,overflowClass,tooltipPosition,itemCaseTagSummary.astro:items,visibleCount,class,itemClass,overflowClass,itemCase,colorOverridesMediaProtect.astro:class,containerClass,drag,contextMenuFilterPills.astro:items,includeAll,allLabel,allHref,active,itemCase,colorOverrides,classPager.astro:pageCount,activePage,items,classCollectionQuery.astro:useServer,pathname,query,totalPages,currentPage,filters,maxPageButtons,filtersClass,pagerClass,perPage,class- when
useServeristrue,pathname,query,totalPages, andcurrentPageare required
- when
CollectionFooterControls.astro:pathname,query,totalPages,currentPage,sizeOptions,maxPageButtons,class— slotsummaryfor “Showing X–Y of Z” text
Server Islands Pattern
CollectionQuery.astro supports two modes:
- client mode (default): static cards are filtered/paged in the browser
- server mode (
useServer): renders querystring links for filters + pager
For server mode, mount with server:defer at the page callsite:
<CollectionQuery
useServer
pathname={Astro.url.pathname}
query={activeQuery}
totalPages={pageData.totalPages}
currentPage={currentPage}
filters={filters}
server:defer
/>The package styleguide uses the Node adapter, so the server-island pattern can be exercised there with server:defer.
Slot customization (headless overrides)
Use named slots to replace the default filter/pager rendering:
<CollectionQuery useServer {...props}>
<div slot="filters">
<!-- your custom filter UI -->
</div>
<!-- default slot: your collection items -->
<div>...</div>
<div slot="pager">
<!-- your custom pager UI -->
</div>
</CollectionQuery>Styles (CSS)
styles/prose.css— Markdown prose styling using CSS custom propertiesstyles/no-save.css— Image protection utilities (prevent right-click, drag, select)styles/accessibility.css— Focus styles, reduced motion, selection stylingstyles/scrollbar.css— Branded scrollbar styling
Utilities
getTagPalette(tag, options?)— Deterministic, readable tag color assignment with optional explicit overridesformatDisplayDate(date, config?)— Consistent card/detail date formatting with locale override supportparseCollectionQuery+paginateCollection+buildCollectionHref+buildPageSequence+matchesCollectionFilters+formatCollectionRangeLabel+resolveIslandSearchString— URL-driven filtering and pagination (filtersas stringified JSON).resolveIslandSearchStringis for server islands (pass the page’s search from the page; fall back toReferer).formatCollectionRangeLabelis for “Showing result N of T” / “Showing results a–b of T” footers.astroflare-link-localis shipped in this package; run it from any project that depends on@at-flux/astroflare(it walks up to the nearestpackage.jsonthat lists the dep).statusshows whether a local overlay is active. See Local checkout below.
Usage
Local checkout without changing package.json or lockfile
Keep @at-flux/astroflare on a normal semver range in package.json and run pnpm install so the lockfile records the registry version. Then overlay the install with a symlink (only under node_modules):
pnpm exec astroflare-link-local link /absolute/or/relative/path/to/astroflare/packages/astroflare
# or
ASTROFLARE_LOCAL_PATH=../../ts-libs/astroflare/packages/astroflare pnpm exec astroflare-link-localUSE_LOCAL_ASTROFLARE=1(ortrue/yes) is supported only together withASTROFLARE_LOCAL_PATHorUSE_LOCAL_ASTROFLARE_PATH(path topackages/astroflare).unlinkremoves the overlay and runspnpm installagain sonode_modulesmatches the lockfile:
pnpm exec astroflare-link-local unlinkstatusshows whether an overlay is active.
Re-running pnpm install may replace the symlink with the store copy; run link again if that happens.
Local Import (file: protocol) — alternative
{
"dependencies": {
"@at-flux/astroflare": "file:../../ts-libs/astroflare/packages/astroflare"
}
}Components
---
import Modal from '@at-flux/astroflare/components/Modal.astro';
import ModalTrigger from '@at-flux/astroflare/components/ModalTrigger.astro';
---Styles
@import "@at-flux/astroflare/styles/prose.css";
@import "@at-flux/astroflare/styles/no-save.css";Testing
From repo root:
pnpm install
pnpm --filter @at-flux/astroflare testOr in packages/astroflare:
pnpm testStyleguide (dev-only)
Use the package-local styleguide to preview all astroflare components in one place.
pnpm styleguide:dev