@hubpav/hwio-ui 0.3.0 → 0.4.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hubpav/hwio-ui",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "HARDWARIO web design system for Astro: DaisyUI 5 themes generated from the brand tokens, the Tailwind entry stylesheet and the HWio* components.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -31,9 +31,9 @@
31
31
  "build": "node scripts/build-themes.mjs"
32
32
  },
33
33
  "dependencies": {
34
- "@hubpav/hwio-brand": "0.3.0",
35
- "@hubpav/hwio-web-runtime": "0.3.0",
36
- "@hubpav/hwio-web-worker": "0.3.0",
34
+ "@hubpav/hwio-brand": "0.4.0",
35
+ "@hubpav/hwio-web-runtime": "0.4.0",
36
+ "@hubpav/hwio-web-worker": "0.4.0",
37
37
  "daisyui": "5.7.28"
38
38
  },
39
39
  "peerDependencies": {
@@ -1,14 +1,16 @@
1
1
  ---
2
2
  /** Exclusive accordion on native <details name>, optional FAQPage JSON-LD. Answers are text unless `html` is set. */
3
- interface Props { items: { q: string; a: string }[]; name?: string; html?: boolean; jsonLd?: boolean; class?: string }
3
+ /** An answer is one paragraph, or several as an array. */
4
+ interface Props { items: { q: string; a: string | string[] }[]; name?: string; html?: boolean; jsonLd?: boolean; class?: string }
4
5
  const { items, name = 'hwio-faq', html = false, jsonLd = true, class: className = '' } = Astro.props;
5
- const ld = { '@context': 'https://schema.org', '@type': 'FAQPage', mainEntity: items.map((i) => ({ '@type': 'Question', name: i.q, acceptedAnswer: { '@type': 'Answer', text: i.a } })) };
6
+ const paragraphs = (a: string | string[]) => (Array.isArray(a) ? a : [a]);
7
+ const ld = { '@context': 'https://schema.org', '@type': 'FAQPage', mainEntity: items.map((i) => ({ '@type': 'Question', name: i.q, acceptedAnswer: { '@type': 'Answer', text: paragraphs(i.a).join(' ') } })) };
6
8
  ---
7
9
  <div class:list={['space-y-3', className]}>
8
10
  {items.map((item) => (
9
11
  <details class="collapse collapse-arrow border border-base-300 bg-base-100" name={name}>
10
12
  <summary class="collapse-title font-semibold">{item.q}</summary>
11
- <div class="collapse-content opacity-90">{html ? <div set:html={item.a} /> : <p>{item.a}</p>}</div>
13
+ <div class="collapse-content space-y-3 opacity-90">{html ? <div set:html={paragraphs(item.a).join('')} /> : paragraphs(item.a).map((p) => <p>{p}</p>)}</div>
12
14
  </details>
13
15
  ))}
14
16
  </div>
@@ -19,10 +19,12 @@ interface Props {
19
19
  labels: { nav: string; menu: string; close: string; theme?: string; languages?: string };
20
20
  /** Viewport from which the inline nav and CTAs replace the drawer (default lg; xl for long navs). */
21
21
  desktopFrom?: 'lg' | 'xl';
22
+ /** Desktop language control: dropdown (default) or inline pills (two-language sites). */
23
+ languageVariant?: 'dropdown' | 'pills';
22
24
  id?: string;
23
25
  class?: string;
24
26
  }
25
- const { nav, ctas = [], languages = [], showThemeToggle = true, scrollspy = false, labels, desktopFrom = 'lg', id = 'hwio-nav-drawer', class: className = '' } = Astro.props;
27
+ const { nav, ctas = [], languages = [], showThemeToggle = true, scrollspy = false, labels, desktopFrom = 'lg', languageVariant = 'dropdown', id = 'hwio-nav-drawer', class: className = '' } = Astro.props;
26
28
  const BREAK = {
27
29
  lg: { nav: 'hidden flex-1 justify-center lg:flex', ctas: 'hidden items-center gap-2 lg:flex', drawer: 'drawer drawer-end w-auto lg:hidden' },
28
30
  xl: { nav: 'hidden flex-1 justify-center xl:flex', ctas: 'hidden items-center gap-2 xl:flex', drawer: 'drawer drawer-end w-auto xl:hidden' },
@@ -57,7 +59,7 @@ const CTA_VARIANT = { primary: 'primary', secondary: 'secondary', ghost: 'ghost'
57
59
 
58
60
  <div class="ml-auto flex items-center gap-2">
59
61
  {showThemeToggle && <HWioThemeToggle label={labels.theme ?? 'Theme'} />}
60
- {languages.length > 1 && <HWioLanguageSwitcher items={languages} label={labels.languages ?? 'Language'} />}
62
+ {languages.length > 1 && <HWioLanguageSwitcher items={languages} label={labels.languages ?? 'Language'} variant={languageVariant} />}
61
63
  <div class={bp.ctas}>
62
64
  {ctas.map((cta) => (
63
65
  <HWioButton href={cta.href} external={cta.external} variant={CTA_VARIANT[cta.variant ?? 'primary']} size="sm" track={cta.track ?? { id: 'header-cta', location: 'header' }} class={cta.icon ? '2xl:px-4 px-2.5' : ''} aria-label={cta.icon ? cta.label : undefined} title={cta.icon ? cta.label : undefined}>
@@ -2,7 +2,7 @@
2
2
  import type { HWioCta } from '../types';
3
3
  import HWioButton from './HWioButton.astro';
4
4
  import HWioIcon from './HWioIcon.astro';
5
- interface Tier { eyebrow?: string; name: string; price?: string; description?: string; features: string[]; cta?: HWioCta; featured?: boolean; badge?: string }
5
+ interface Tier { eyebrow?: string; name: string; price?: string; pricePrefix?: string; period?: string; description?: string; features: string[]; cta?: HWioCta; featured?: boolean; badge?: string }
6
6
  interface Props { tiers: Tier[]; class?: string }
7
7
  const { tiers, class: className = '' } = Astro.props;
8
8
  const COLS = { 1: 'grid gap-6', 2: 'grid gap-6 md:grid-cols-2', 3: 'grid gap-6 md:grid-cols-3', 4: 'grid gap-6 md:grid-cols-2 lg:grid-cols-4' } as const;
@@ -15,9 +15,15 @@ const cols = (Math.min(Math.max(tiers.length, 1), 4) as 1 | 2 | 3 | 4);
15
15
  {tier.eyebrow && <p class="hwio-kicker">{tier.eyebrow}</p>}
16
16
  <div class="flex items-start justify-between gap-2">
17
17
  <h3 class="card-title text-[1.375rem]">{tier.name}</h3>
18
- {tier.badge && <span class="badge badge-primary">{tier.badge}</span>}
18
+ {tier.badge && <span class="badge badge-primary shrink-0 whitespace-nowrap">{tier.badge}</span>}
19
19
  </div>
20
- {tier.price && <p class="text-3xl font-bold">{tier.price}</p>}
20
+ {tier.price && (
21
+ <p class="flex flex-wrap items-baseline gap-x-1.5">
22
+ {tier.pricePrefix && <span class="hwio-muted text-sm">{tier.pricePrefix}</span>}
23
+ <span class="text-3xl font-bold tracking-tight">{tier.price}</span>
24
+ {tier.period && <span class="hwio-muted text-sm">{tier.period}</span>}
25
+ </p>
26
+ )}
21
27
  {tier.description && <p class="opacity-80">{tier.description}</p>}
22
28
  <ul class="my-4 space-y-2 text-sm">
23
29
  {tier.features.map((f) => <li class="flex items-start gap-2"><HWioIcon name="check" size="sm" class="mt-0.5 shrink-0 text-accent" /><span>{f}</span></li>)}