Skip to content

Commit e33cf93

Browse files
authored
Pin the preview card to the widget's own manifest (#62)
A widget with no light design rendered light on a light docs page. The card and the dark-only flag now come from the widget manifest, and the preview card colours match the product's.
1 parent 031a19a commit e33cf93

4 files changed

Lines changed: 52 additions & 20 deletions

File tree

‎src/components/WidgetGroup.astro‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
---
2+
import { manifestCard } from '../lib/widget-manifest';
3+
24
/* Geometry must match WidgetPreview. See the note there. */
35
interface Item {
46
type: string;
57
file: string;
68
id: string;
79
size?: 'small' | 'medium';
8-
card?: 'dark' | 'light' | 'translucent' | null;
10+
card?: 'dark' | 'graphite' | 'light' | 'translucent' | null;
911
title: string;
1012
label?: string;
1113
}
@@ -37,6 +39,7 @@ const built = items.map((it) => {
3739
tx: (w - dw * scale) / 2,
3840
ty: (CARD_H - dh * scale) / 2,
3941
src: `/widgets/${it.type}/${it.file}?id=${encodeURIComponent(it.id)}&size=${size}&lang=en`,
42+
declared: manifestCard(it.type, it.file),
4043
};
4144
});
4245
---
@@ -49,7 +52,8 @@ const built = items.map((it) => {
4952
<div class="wpv__slot">
5053
<div
5154
class="wpv__card"
52-
data-card={b.card ?? undefined}
55+
data-card={b.card ?? b.declared.card ?? undefined}
56+
data-appearance={b.declared.appearance}
5357
style={`width:${b.w}px;height:${CARD_H}px;border-radius:${RADIUS}px;`}
5458
>
5559
<iframe

‎src/components/WidgetPreview.astro‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
---
2+
import { manifestCard } from '../lib/widget-manifest';
3+
24
/* Geometry mirrors the product and must stay in step with it: the design
35
canvas from WIDGET_DESIGN, the card width from the 1041px six-column grid,
46
WIDGET_HEIGHTS for height, WIDGET_R for the corner, and mountScaledWidget's
@@ -8,12 +10,13 @@ interface Props {
810
file: string;
911
id: string;
1012
size?: 'small' | 'medium';
11-
card?: 'dark' | 'light' | 'translucent' | null;
13+
card?: 'dark' | 'graphite' | 'light' | 'translucent' | null;
1214
title: string;
1315
caption?: string;
1416
}
1517
1618
const { type, file, id, size = 'small', card = null, title, caption } = Astro.props;
19+
const declared = manifestCard(type, file);
1720
1821
const DESIGN = { small: [170, 170], medium: [360, 170] } as const;
1922
const CARD_W = { small: 152.67, medium: 330.34 } as const;
@@ -33,7 +36,8 @@ const src = `/widgets/${type}/${file}?id=${encodeURIComponent(id)}&size=${size}&
3336
<div class="wpv__mat">
3437
<div
3538
class="wpv__card"
36-
data-card={card ?? undefined}
39+
data-card={card ?? declared.card ?? undefined}
40+
data-appearance={declared.appearance}
3741
style={`width:${w}px;height:${CARD_H}px;border-radius:${RADIUS}px;`}
3842
>
3943
<iframe

‎src/lib/widget-manifest.ts‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { readFileSync } from 'node:fs';
2+
import path from 'node:path';
3+
4+
/** The card and the dark-only flag a widget declares, so a preview cannot drift
5+
from the product. `file` picks the view when the widget has several. */
6+
export function manifestCard(type: string, viewFile: string) {
7+
try {
8+
/* From the project root: import.meta.url points into the build output. */
9+
const file = path.join(process.cwd(), 'public', 'widgets', type, 'widget.json');
10+
const m = JSON.parse(readFileSync(file, 'utf8'));
11+
const view = Object.values(m.views ?? {}).find((v: any) => v?.src === viewFile) as any;
12+
return {
13+
card: (view?.card ?? m.card ?? null) as string | null,
14+
appearance: m.appearance === 'dark' ? 'dark' : undefined,
15+
};
16+
} catch {
17+
return { card: null, appearance: undefined };
18+
}
19+
}

‎src/styles/docs.css‎

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -797,30 +797,35 @@ starlight-toc nav a {
797797
.wpv__mat > * {
798798
position: relative;
799799
}
800+
/* The product's card colours. A widget with no light design, and one that
801+
names a card, keeps the same colour in both docs themes. */
800802
.wpv__card {
801803
position: relative;
802804
overflow: hidden;
803805
flex-shrink: 0;
804-
border: 1px solid rgba(255, 255, 255, 0.09);
805-
background: rgba(0, 0, 0, 0.32);
806-
-webkit-backdrop-filter: blur(16px) saturate(140%);
807-
backdrop-filter: blur(16px) saturate(140%);
808-
}
809-
.wpv__card[data-card='dark'] {
806+
border: 1px solid rgba(255, 255, 255, 0.09);
810807
background: #1c1c1e;
811-
-webkit-backdrop-filter: none;
812-
backdrop-filter: none;
813808
}
814-
.wpv__card[data-card='light'] {
809+
:root[data-theme='light'] .wpv__card {
810+
border-color: rgba(0, 0, 0, 0.06);
815811
background: #ffffff;
816-
border-color: rgba(0, 0, 0, 0.12);
817-
-webkit-backdrop-filter: none;
818-
backdrop-filter: none;
819812
}
820-
.wpv__card[data-card='translucent'] {
821-
background: rgba(0, 0, 0, 0.25);
822-
-webkit-backdrop-filter: blur(22px) saturate(140%);
823-
backdrop-filter: blur(22px) saturate(140%);
813+
.wpv__card[data-appearance='dark'],
814+
.wpv__card[data-card='dark'],
815+
:root[data-theme='light'] .wpv__card[data-appearance='dark'],
816+
:root[data-theme='light'] .wpv__card[data-card='dark'] {
817+
border-color: rgba(255, 255, 255, 0.09);
818+
background: #1c1c1e;
819+
}
820+
.wpv__card[data-card='graphite'],
821+
:root[data-theme='light'] .wpv__card[data-card='graphite'] {
822+
border-color: rgba(255, 255, 255, 0.09);
823+
background: #2c2c2e;
824+
}
825+
.wpv__card[data-card='light'],
826+
:root[data-theme='light'] .wpv__card[data-card='light'] {
827+
border-color: rgba(0, 0, 0, 0.12);
828+
background: #ffffff;
824829
}
825830
.wpv__card iframe {
826831
position: absolute;

0 commit comments

Comments
 (0)