@sarimarcus/content-sites-ui 0.29.1 → 0.29.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/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
All packages in the platform release in lockstep; entries are per release version.
|
|
4
4
|
|
|
5
|
+
## 0.29.2 (2026-10-06)
|
|
6
|
+
|
|
7
|
+
- `./navigation`: `ArticlesNavMenu`'s feature image is a CSS background applied once the menu has opened, so a page load no longer fetches it; it stays painted through the close fade (the controller marks a dropdown `data-opened` on its first open), falls back to the 1x file where `image-set()` is unsupported, and is decorative when there is no alt text (SLA-2993).
|
|
8
|
+
|
|
5
9
|
## 0.29.1 (2026-10-06)
|
|
6
10
|
|
|
7
11
|
- `./editorial`: `ArticleTopicPage` takes `proseClass`, the overview's prose theme modifier added to `prose` (default `prose-lg`, as before), so a dark site can render the overview in its own prose colours (SLA-2994).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sarimarcus/content-sites-ui",
|
|
3
|
-
"version": "0.29.
|
|
3
|
+
"version": "0.29.2",
|
|
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.29.
|
|
52
|
+
"@sarimarcus/content-sites-core": "0.29.2"
|
|
53
53
|
}
|
|
54
54
|
}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { normalizePagePath } from '@sarimarcus/content-sites-core/url';
|
|
9
9
|
import { formatUtcDate } from '@sarimarcus/content-sites-core/dates';
|
|
10
|
-
import
|
|
10
|
+
import { getImage } from 'astro:assets';
|
|
11
11
|
import NavDropdown from './NavDropdown.astro';
|
|
12
12
|
import NavMenuLink from './NavMenuLink.astro';
|
|
13
13
|
import MobileNavSection from './MobileNavSection.astro';
|
|
@@ -51,6 +51,14 @@ const day = (iso?: string) => formatUtcDate(iso, { day: 'numeric', month: 'short
|
|
|
51
51
|
const [first, ...rest] = latest;
|
|
52
52
|
const feature = first?.image ? first : undefined;
|
|
53
53
|
const rows = feature ? rest : latest;
|
|
54
|
+
// The feature image is a CSS background that only an open menu applies, so a page load never fetches it
|
|
55
|
+
// (an <img> in the hidden panel would load on every page). A background has no srcset, so this is the one place
|
|
56
|
+
// that picks widths instead of ResponsiveImage; the variant service snaps them to existing files.
|
|
57
|
+
const featureBg = feature?.image
|
|
58
|
+
? await Promise.all([480, 960].map((width) => getImage({ src: feature.image!, width })))
|
|
59
|
+
: undefined;
|
|
60
|
+
const featureStyle = featureBg
|
|
61
|
+
&& `--articles-nav-feature-1x: url("${featureBg[0].src}"); --articles-nav-feature: image-set(url("${featureBg[0].src}") 1x, url("${featureBg[1].src}") 2x)`;
|
|
54
62
|
---
|
|
55
63
|
|
|
56
64
|
{variant === 'desktop' ? (
|
|
@@ -67,7 +75,7 @@ const rows = feature ? rest : latest;
|
|
|
67
75
|
{feature && (
|
|
68
76
|
<a href={feature.href} aria-current={here(feature.href) ? 'page' : undefined} class:list={[`group block p-2 rounded-lg hover:bg-muted transition-colors ${ring}`, here(feature.href) && 'bg-muted']}>
|
|
69
77
|
<div class="aspect-video rounded-md overflow-hidden bg-muted">
|
|
70
|
-
<
|
|
78
|
+
<div role={feature.imageAlt ? 'img' : undefined} aria-label={feature.imageAlt || undefined} aria-hidden={feature.imageAlt ? undefined : 'true'} class="articles-nav-feature w-full h-full bg-cover bg-center transition-transform duration-300 group-hover:scale-[1.03]" style={featureStyle} />
|
|
71
79
|
</div>
|
|
72
80
|
{(feature.eyebrow || feature.date) && (
|
|
73
81
|
<span class="mt-2 block text-xs">
|
|
@@ -115,3 +123,19 @@ const rows = feature ? rest : latest;
|
|
|
115
123
|
{topics.map((link) => <MobileNavLink link={link} tone={tone} active={on(link.href)} />)}
|
|
116
124
|
</MobileNavSection>
|
|
117
125
|
)}
|
|
126
|
+
|
|
127
|
+
<style>
|
|
128
|
+
/* data-opened is set on the first open and kept; :focus-within covers a keyboard visit before any script runs. */
|
|
129
|
+
:global([data-nav-dropdown][data-opened]) .articles-nav-feature,
|
|
130
|
+
:global(.nav-dropdown:focus-within) .articles-nav-feature {
|
|
131
|
+
background-image: var(--articles-nav-feature, none);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/* A var() holding an unsupported image-set() computes to none, so older engines get the 1x file instead. */
|
|
135
|
+
@supports not (background-image: image-set(url('x.webp') 1x)) {
|
|
136
|
+
:global([data-nav-dropdown][data-opened]) .articles-nav-feature,
|
|
137
|
+
:global(.nav-dropdown:focus-within) .articles-nav-feature {
|
|
138
|
+
background-image: var(--articles-nav-feature-1x, none);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
</style>
|
|
@@ -17,6 +17,8 @@ const controlled = (el: Element) => {
|
|
|
17
17
|
function setDropdown(button: HTMLButtonElement, open: boolean): void {
|
|
18
18
|
if (open) dropdownButtons().forEach((other) => other !== button && other.setAttribute('aria-expanded', 'false'));
|
|
19
19
|
button.setAttribute('aria-expanded', String(open));
|
|
20
|
+
// Stays set after the first open, so content deferred until then (ArticlesNavMenu's image) never unpaints mid-fade.
|
|
21
|
+
if (open) button.closest<HTMLElement>('[data-nav-dropdown]')?.setAttribute('data-opened', '');
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
function setMobileMenu(root: HTMLElement, toggle: HTMLButtonElement, open: boolean, focus: boolean): void {
|