@sarimarcus/content-sites-ui 0.31.6 → 0.31.7
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/CHANGELOG.md +7 -0
- package/README.md +10 -3
- package/package.json +2 -2
- package/src/affiliate/provider.ts +3 -1
- package/src/layout/BreadcrumbBand.astro +4 -3
- package/src/layout/EntityDetailShell.astro +84 -0
- package/src/layout/ListingShell.astro +4 -2
- package/src/layout/index.ts +1 -0
- package/src/primitives/index.ts +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
All packages in the platform release in lockstep; entries are per release version.
|
|
4
4
|
|
|
5
|
+
## 0.31.7 (2026-10-09)
|
|
6
|
+
|
|
7
|
+
- `./primitives` exports `ArrowGlyph`, the bare right-arrow svg that `ArrowLabel` and `LinkArrow` draw, for components that lay out their own label; `class` is emitted verbatim (SLA-3024).
|
|
8
|
+
- `./layout`: `EntityDetailShell`, the frame of an entity detail page. It renders the breadcrumb band, a `data-pagefind-body` wrapper typed by `pagefindType` around the `hero` slot with one sr-only `audience:` span per `audiences` entry, then `<main>` (`mainClass`) holding the default slot in a Container (`column`: `measure` | `content` | `false`), `after-column`, and `closer`. `pagefindScope="page"` wraps `<main>` too; `breadcrumbIgnore={false}` keeps the band indexed (SLA-3025).
|
|
9
|
+
- `./layout`: `BreadcrumbBand` takes `class`, which replaces the band's own classes (keep `pt-16`), and `ListingShell` takes `breadcrumbClass`. Default output is unchanged (SLA-3025).
|
|
10
|
+
- `./affiliate`: `HotelAffiliateCTA` and `AffiliateComparisonTable` derive `data-track-affiliate-provider="amazon"` from Amazon hosts (amazon.<tld>, amzn.to), as they already derived `booking`; an explicit provider still wins. Pages: 5 Dark Skies guides with Amazon comparison rows (SLA-3026).
|
|
11
|
+
|
|
5
12
|
## 0.31.6 (2026-10-08)
|
|
6
13
|
|
|
7
14
|
- No changes; lockstep release with core (SLA-3023).
|
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ text arrives through props and slots.
|
|
|
12
12
|
## Primitives
|
|
13
13
|
|
|
14
14
|
```ts
|
|
15
|
-
import { Icon, Badge, Chip, ArrowLabel, SectionDivider, LinkArrow, Button, Callout, FeatureList, Blockquote, SectionHeader, ResponsiveImage, ResponsivePicture, PILL_BASE, isBadgeLength, PRICE_LABEL_MAX } from '@sarimarcus/content-sites-ui/primitives';
|
|
15
|
+
import { Icon, Badge, Chip, ArrowLabel, ArrowGlyph, SectionDivider, LinkArrow, Button, Callout, FeatureList, Blockquote, SectionHeader, ResponsiveImage, ResponsivePicture, PILL_BASE, isBadgeLength, PRICE_LABEL_MAX } from '@sarimarcus/content-sites-ui/primitives';
|
|
16
16
|
```
|
|
17
17
|
|
|
18
18
|
- `Icon`: any Lucide icon by kebab-case name.
|
|
@@ -25,6 +25,8 @@ import { Icon, Badge, Chip, ArrowLabel, SectionDivider, LinkArrow, Button, Callo
|
|
|
25
25
|
attributes pass through last, so markers such as `data-section-link` reach the element.
|
|
26
26
|
- `ArrowLabel`: a label followed by an arrow that shifts right on `group-hover`. It carries no colour: the caller's
|
|
27
27
|
`class` sets it; `arrowClass` sizes the arrow (default `h-4 w-4`).
|
|
28
|
+
- `ArrowGlyph`: the bare right arrow svg that `ArrowLabel` and `LinkArrow` draw, for a component that lays out its own
|
|
29
|
+
label. `class` (required) is emitted verbatim, motion included.
|
|
28
30
|
- `SectionDivider`: a break between sections. `variant` is `dots` (default), `line`, or `quote` (with `quote` and
|
|
29
31
|
an optional `source`).
|
|
30
32
|
- `LinkArrow`: a text link with a trailing arrow. `color` is `primary` (default), `secondary`, `accent` or `onImage`;
|
|
@@ -88,7 +90,7 @@ state and one bundled controller (idempotent on `astro:page-load`, any number of
|
|
|
88
90
|
|
|
89
91
|
```ts
|
|
90
92
|
import { StaticProsePage, NotFoundPage, ArticlesListingPage, ArticleFeatureCard } from '@sarimarcus/content-sites-ui/editorial';
|
|
91
|
-
import { ListingShell } from '@sarimarcus/content-sites-ui/layout';
|
|
93
|
+
import { EntityDetailShell, ListingShell } from '@sarimarcus/content-sites-ui/layout';
|
|
92
94
|
```
|
|
93
95
|
|
|
94
96
|
The route file keeps `getStaticPaths`, queries, URLs, `<Layout title description>` (the SEO length gate reads it) and
|
|
@@ -105,7 +107,12 @@ prose stay in the route so the site's link and outbound-domain scanners still se
|
|
|
105
107
|
`overview-byline`. The overview and the author cards are props. A page above 1 renders only the nav, grid and
|
|
106
108
|
pagination. `rankByCount` ranks a topic's authors or collections by article count.
|
|
107
109
|
- `ListingShell`: listing hubs (breadcrumb, `hero`, `before-main`, Container'd `<main>`, `after-main`), one outer
|
|
108
|
-
`data-pagefind-ignore`.
|
|
110
|
+
`data-pagefind-ignore`. `breadcrumbClass` replaces the band's classes (`BreadcrumbBand` `class`).
|
|
111
|
+
- `EntityDetailShell`: entity detail pages. Breadcrumb band, then a `data-pagefind-body` wrapper typed by
|
|
112
|
+
`pagefindType` around the `hero` slot (with an sr-only `audience:` filter span per `audiences` entry), then `<main>`
|
|
113
|
+
with the default slot in a measure Container, `after-column`, and `closer` in a default Container.
|
|
114
|
+
`pagefindScope="page"` wraps `<main>` too; no `pagefindType` means no wrapper; `column={false}` drops the column
|
|
115
|
+
Container; `closer` defaults to whether the slot was passed. The hero, body and closer stay site markup.
|
|
109
116
|
|
|
110
117
|
A component exported from a barrel must not carry a `<style>` block: Astro ships it to every page that imports the
|
|
111
118
|
barrel. Put such rules in a stylesheet entry the one route imports.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sarimarcus/content-sites-ui",
|
|
3
|
-
"version": "0.31.
|
|
3
|
+
"version": "0.31.7",
|
|
4
4
|
"description": "Universal Astro UI components, layout shell and design tokens shared by the content sites.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -49,6 +49,6 @@
|
|
|
49
49
|
"@lucide/astro": "^1.23.0",
|
|
50
50
|
"astro": "^7.0.6",
|
|
51
51
|
"tailwindcss": "^4.1.18",
|
|
52
|
-
"@sarimarcus/content-sites-core": "0.31.
|
|
52
|
+
"@sarimarcus/content-sites-core": "0.31.7"
|
|
53
53
|
}
|
|
54
54
|
}
|
|
@@ -2,5 +2,7 @@
|
|
|
2
2
|
export function providerFromHref(href: string | undefined): string | undefined {
|
|
3
3
|
const host = /^https?:\/\/([^/?#:]+)/i.exec(href ?? '')?.[1]?.toLowerCase();
|
|
4
4
|
if (!host) return undefined;
|
|
5
|
-
|
|
5
|
+
if (host === 'booking.com' || host.endsWith('.booking.com')) return 'booking';
|
|
6
|
+
if (host === 'amzn.to' || /(?:^|\.)amazon\.(?:com|co\.[a-z]{2}|com\.[a-z]{2}|[a-z]{2})$/.test(host)) return 'amazon';
|
|
7
|
+
return undefined;
|
|
6
8
|
}
|
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
---
|
|
2
2
|
/**
|
|
3
3
|
* BreadcrumbBand — the muted strip under the fixed header that holds a page's breadcrumb trail (default slot).
|
|
4
|
-
* `ignore` keeps it out of the Pagefind body.
|
|
4
|
+
* `ignore` keeps it out of the Pagefind body. `class` replaces the band's own classes (keep `pt-16`, the header offset).
|
|
5
5
|
*/
|
|
6
6
|
import Container from './Container.astro';
|
|
7
7
|
|
|
8
8
|
interface Props {
|
|
9
9
|
ignore?: boolean;
|
|
10
|
+
class?: string;
|
|
10
11
|
}
|
|
11
12
|
|
|
12
|
-
const { ignore = true } = Astro.props;
|
|
13
|
+
const { ignore = true, class: className = 'pt-16 bg-muted/50 border-b border-border' } = Astro.props;
|
|
13
14
|
---
|
|
14
15
|
|
|
15
|
-
<div class=
|
|
16
|
+
<div class={className} data-pagefind-ignore={ignore ? '' : undefined}>
|
|
16
17
|
<Container class="py-3">
|
|
17
18
|
<slot />
|
|
18
19
|
</Container>
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
---
|
|
2
|
+
/**
|
|
3
|
+
* EntityDetailShell — the frame of an entity detail page: breadcrumb band, a Pagefind body wrapper around the hero
|
|
4
|
+
* (`data-pagefind-meta="type:<pagefindType>"`, with one sr-only `audience:<a>` filter span per `audiences` entry
|
|
5
|
+
* before the hero), then <main> holding the column (default slot), `after-column` and the `closer` Container.
|
|
6
|
+
* The route keeps Layout, StructuredData (a direct Layout child), the data, the hero and every body block.
|
|
7
|
+
*
|
|
8
|
+
* - `pagefindType` omitted: no wrapper; a route that indexes its body puts its own wrapper in the default slot.
|
|
9
|
+
* - `pagefindScope="page"`: the wrapper also holds <main>, for a page whose whole body is indexed.
|
|
10
|
+
* - `column={false}`: the default slot goes into <main> as is, for a body that leaves the column.
|
|
11
|
+
* - `closer`: renders the `closer` slot in a default Container; it defaults to whether that slot was passed.
|
|
12
|
+
*/
|
|
13
|
+
import BreadcrumbBand from './BreadcrumbBand.astro';
|
|
14
|
+
import Container from './Container.astro';
|
|
15
|
+
|
|
16
|
+
interface Props {
|
|
17
|
+
pagefindType?: string;
|
|
18
|
+
pagefindScope?: 'hero' | 'page';
|
|
19
|
+
audiences?: readonly string[];
|
|
20
|
+
/** `false` keeps the breadcrumb band in the Pagefind body. */
|
|
21
|
+
breadcrumbIgnore?: boolean;
|
|
22
|
+
mainClass?: string;
|
|
23
|
+
column?: 'measure' | 'content' | false;
|
|
24
|
+
closer?: boolean;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const {
|
|
28
|
+
pagefindType,
|
|
29
|
+
pagefindScope = 'hero',
|
|
30
|
+
audiences = [],
|
|
31
|
+
breadcrumbIgnore = true,
|
|
32
|
+
mainClass = 'pt-6 pb-12 lg:pt-8 lg:pb-20',
|
|
33
|
+
column = 'measure',
|
|
34
|
+
closer = Astro.slots.has('closer'),
|
|
35
|
+
} = Astro.props;
|
|
36
|
+
const meta = `type:${pagefindType}`;
|
|
37
|
+
const wrapsPage = Boolean(pagefindType) && pagefindScope === 'page';
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
<BreadcrumbBand ignore={breadcrumbIgnore}><slot name="breadcrumb" /></BreadcrumbBand>
|
|
41
|
+
|
|
42
|
+
{/* <main> is spelled out per branch: a dynamic wrapper tag buffers its children and moved hoisted scripts above it. */}
|
|
43
|
+
{wrapsPage ? (
|
|
44
|
+
<div data-pagefind-body data-pagefind-meta={meta}>
|
|
45
|
+
{audiences.map((a) => <span class="sr-only" data-pagefind-filter={`audience:${a}`}>{a}</span>)}
|
|
46
|
+
<slot name="hero" />
|
|
47
|
+
<main class={mainClass}>
|
|
48
|
+
{column ? (
|
|
49
|
+
<Container size={column}><slot /></Container>
|
|
50
|
+
) : (
|
|
51
|
+
<slot />
|
|
52
|
+
)}
|
|
53
|
+
<slot name="after-column" />
|
|
54
|
+
{closer && (
|
|
55
|
+
<Container><slot name="closer" /></Container>
|
|
56
|
+
)}
|
|
57
|
+
</main>
|
|
58
|
+
</div>
|
|
59
|
+
) : (
|
|
60
|
+
<Fragment>
|
|
61
|
+
{pagefindType ? (
|
|
62
|
+
<div data-pagefind-body data-pagefind-meta={meta}>
|
|
63
|
+
{audiences.map((a) => <span class="sr-only" data-pagefind-filter={`audience:${a}`}>{a}</span>)}
|
|
64
|
+
<slot name="hero" />
|
|
65
|
+
</div>
|
|
66
|
+
) : (
|
|
67
|
+
<Fragment>
|
|
68
|
+
{audiences.map((a) => <span class="sr-only" data-pagefind-filter={`audience:${a}`}>{a}</span>)}
|
|
69
|
+
<slot name="hero" />
|
|
70
|
+
</Fragment>
|
|
71
|
+
)}
|
|
72
|
+
<main class={mainClass}>
|
|
73
|
+
{column ? (
|
|
74
|
+
<Container size={column}><slot /></Container>
|
|
75
|
+
) : (
|
|
76
|
+
<slot />
|
|
77
|
+
)}
|
|
78
|
+
<slot name="after-column" />
|
|
79
|
+
{closer && (
|
|
80
|
+
<Container><slot name="closer" /></Container>
|
|
81
|
+
)}
|
|
82
|
+
</main>
|
|
83
|
+
</Fragment>
|
|
84
|
+
)}
|
|
@@ -15,13 +15,15 @@ interface Props {
|
|
|
15
15
|
contained?: boolean;
|
|
16
16
|
/** `false` keeps the page indexable, for a listing whose bands carry `data-pagefind-body` prose. */
|
|
17
17
|
pagefindIgnore?: boolean;
|
|
18
|
+
/** Replaces the breadcrumb band's own classes, for a hub whose band takes the hero's colour. */
|
|
19
|
+
breadcrumbClass?: string;
|
|
18
20
|
}
|
|
19
21
|
|
|
20
|
-
const { mainClass = 'py-12 lg:py-20', contained = true, pagefindIgnore = true } = Astro.props;
|
|
22
|
+
const { mainClass = 'py-12 lg:py-20', contained = true, pagefindIgnore = true, breadcrumbClass } = Astro.props;
|
|
21
23
|
---
|
|
22
24
|
|
|
23
25
|
<div data-pagefind-ignore={pagefindIgnore ? '' : undefined}>
|
|
24
|
-
<BreadcrumbBand ignore={false}>
|
|
26
|
+
<BreadcrumbBand ignore={false} class={breadcrumbClass}>
|
|
25
27
|
<slot name="breadcrumb" />
|
|
26
28
|
</BreadcrumbBand>
|
|
27
29
|
|
package/src/layout/index.ts
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
export { default as Container } from './Container.astro';
|
|
3
3
|
export { default as BreadcrumbBand } from './BreadcrumbBand.astro';
|
|
4
4
|
export { default as ListingShell } from './ListingShell.astro';
|
|
5
|
+
export { default as EntityDetailShell } from './EntityDetailShell.astro';
|
|
5
6
|
export { default as AsyncStylesheet } from './AsyncStylesheet.astro';
|
|
6
7
|
export { default as DocumentShell } from './DocumentShell.astro';
|
|
7
8
|
export { default as ConsentAnalytics } from './ConsentAnalytics.astro';
|
package/src/primitives/index.ts
CHANGED
|
@@ -3,6 +3,7 @@ export { default as Icon } from './Icon.astro';
|
|
|
3
3
|
export { default as Badge } from './Badge.astro';
|
|
4
4
|
export { default as Chip } from './Chip.astro';
|
|
5
5
|
export { default as ArrowLabel } from './ArrowLabel.astro';
|
|
6
|
+
export { default as ArrowGlyph } from './ArrowGlyph.astro';
|
|
6
7
|
export { default as RatingStars } from './RatingStars.astro';
|
|
7
8
|
export { default as SectionDivider } from './SectionDivider.astro';
|
|
8
9
|
export { default as LinkArrow } from './LinkArrow.astro';
|