@at-flux/astroflare 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -35,6 +35,8 @@ import { forms } from '@at-flux/astroflare/core';
35
35
 
36
36
  - `Modal.astro` — Headless modal using native `<dialog>` and `<app-modal>` web component (`class` applies to the panel)
37
37
  - `ModalTrigger.astro` — Trigger that opens a modal by ID using `<modal-trigger>` web component
38
+ - `ContactModalCta.astro` — Opinionated contact button (solid pill or text link) wrapped in `ModalTrigger`
39
+ - `InstagramProfileLink.astro` — Small Instagram icon + `@handle` link with safe defaults
38
40
  - `Section.astro` — Page section with optional `narrow` and `contentOnly` (inner width wrapper without outer padding)
39
41
  - `ThemeToggle.astro` — Dark/light mode toggle using `<theme-toggle>` web component
40
42
  - `ClientRouterLoadingSpinner.astro` — Loading spinner for Astro view transitions
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@at-flux/astroflare",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "type": "module",
5
5
  "description": "Reusable headless components, styles, and utilities for Astro + Tailwind v4 + Cloudflare projects",
6
6
  "author": "Taylor Siviter <taylor@siviter.xyz>",
@@ -0,0 +1,30 @@
1
+ ---
2
+ import ModalTrigger from './ModalTrigger.astro';
3
+
4
+ interface Props {
5
+ /** Target dialog id (must match `<dialog id="…">`). */
6
+ modalId?: string;
7
+ label: string;
8
+ /** `solid` — primary pill; `text` — tertiary link style (e.g. inline in prose). */
9
+ variant?: 'solid' | 'text';
10
+ class?: string;
11
+ }
12
+
13
+ const {
14
+ modalId = 'contact-modal',
15
+ label,
16
+ variant = 'solid',
17
+ class: className = '',
18
+ } = Astro.props;
19
+
20
+ const solidClass =
21
+ 'btn-primary-solid inline-flex items-center gap-2 rounded-full bg-[var(--color-primary)] px-6 py-3 text-sm font-semibold shadow-md transition-all hover:scale-105 hover:opacity-95 hover:shadow-lg no-underline';
22
+ const textClass =
23
+ 'inline-flex items-center gap-2 font-bold text-[var(--color-tertiary)] no-underline hover:text-[var(--color-secondary)]';
24
+ ---
25
+
26
+ <ModalTrigger modalId={modalId} class={className}>
27
+ <button type='button' class:list={[variant === 'solid' ? solidClass : textClass]}>
28
+ {label}
29
+ </button>
30
+ </ModalTrigger>
@@ -0,0 +1,45 @@
1
+ ---
2
+ interface Props {
3
+ /** Instagram username without @ */
4
+ handle: string;
5
+ href?: string;
6
+ class?: string;
7
+ 'aria-label'?: string;
8
+ }
9
+
10
+ const {
11
+ handle: rawHandle,
12
+ href,
13
+ class: className = '',
14
+ 'aria-label': ariaLabel,
15
+ } = Astro.props;
16
+
17
+ const handle = rawHandle.replace(/^@/, '');
18
+ const url = href ?? `https://www.instagram.com/${handle}`;
19
+ const a11yLabel = ariaLabel ?? `Instagram: @${handle}`;
20
+ ---
21
+
22
+ <a
23
+ href={url}
24
+ target='_blank'
25
+ rel='noopener noreferrer'
26
+ class:list={['area-handle no-underline', className]}
27
+ aria-label={a11yLabel}
28
+ >
29
+ <svg
30
+ width='13'
31
+ height='13'
32
+ viewBox='0 0 24 24'
33
+ fill='none'
34
+ stroke='currentColor'
35
+ stroke-width='2'
36
+ stroke-linecap='round'
37
+ stroke-linejoin='round'
38
+ aria-hidden='true'
39
+ >
40
+ <rect x='2' y='2' width='20' height='20' rx='5' ry='5' />
41
+ <circle cx='12' cy='12' r='5' />
42
+ <circle cx='17.5' cy='6.5' r='1.5' fill='currentColor' stroke='none' />
43
+ </svg>
44
+ @{handle}
45
+ </a>