efficient-web-builder 6.0.0 → 7.1.1
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 +238 -0
- package/README.md +42 -0
- package/dist/components/ApplyCornersToSiblings.js +1 -1
- package/dist/components/Banner.js +1 -1
- package/dist/components/BlockGapField.js +1 -1
- package/dist/components/BlogPostSource.js +1 -1
- package/dist/components/Breadcrumb.js +1 -1
- package/dist/components/CardShadowField.js +1 -1
- package/dist/components/CategoryBar.js +1 -1
- package/dist/components/ChatSettingsPanel.js +1 -1
- package/dist/components/ClearColoursDialog.js +1 -1
- package/dist/components/CornersField.js +1 -1
- package/dist/components/DocBody.js +5 -5
- package/dist/components/DuplicateToPageMenu.js +1 -1
- package/dist/components/FAQ.js +1 -1
- package/dist/components/Flex.js +1 -1
- package/dist/components/Footprint.js +3 -3
- package/dist/components/HeroImageField.js +1 -1
- package/dist/components/HeroSection.js +2 -2
- package/dist/components/HeroSingle.js +1 -1
- package/dist/components/HeroSlide.js +1 -1
- package/dist/components/HoverEffectField.js +1 -1
- package/dist/components/ImageFocusRow.js +1 -1
- package/dist/components/IntegrationsSection.js +1 -1
- package/dist/components/IntroBleed.js +1 -1
- package/dist/components/KeyFeatures.js +1 -1
- package/dist/components/LocationsGroupedField.js +1 -1
- package/dist/components/MediaUploadField.js +1 -1
- package/dist/components/MultiSelectField.js +1 -1
- package/dist/components/PagesPanel.js +1 -1
- package/dist/components/PartInkControl.js +1 -1
- package/dist/components/PartResetDot.js +1 -1
- package/dist/components/PartSettingsPanel.js +1 -1
- package/dist/components/PartTextBox.js +1 -1
- package/dist/components/PhotographyField.js +1 -1
- package/dist/components/ProcessSteps.js +1 -1
- package/dist/components/SearchSelectField.d.ts +1 -1
- package/dist/components/SearchSelectField.js +1 -1
- package/dist/components/SectionEditor.js +1 -1
- package/dist/components/SectionTextEntries.js +1 -1
- package/dist/components/SectionThemePicker.js +1 -1
- package/dist/components/Series.js +1 -1
- package/dist/components/ShadowColourField.js +1 -1
- package/dist/components/SideSpaceField.js +1 -1
- package/dist/components/SiteFields.js +1 -1
- package/dist/components/SiteWidthField.js +1 -1
- package/dist/components/SlotChildRows.js +1 -1
- package/dist/components/SocialLinksPanel.js +1 -1
- package/dist/components/SourceStatus.js +1 -1
- package/dist/components/SpecStrip.js +1 -1
- package/dist/components/Split.js +1 -1
- package/dist/components/StandaloneSectionEditor.js +1 -1
- package/dist/components/StatsParagraph.js +1 -1
- package/dist/components/StorefrontLinkField.js +1 -1
- package/dist/components/StylesPanel.js +1 -1
- package/dist/components/SwitchToBoxFooter.js +1 -1
- package/dist/components/Testimonials.js +1 -1
- package/dist/components/TextStyleRow.js +1 -1
- package/dist/components/TextStylesField.js +1 -1
- package/dist/components/ThemeCard.js +1 -1
- package/dist/components/ThemeColourField.js +1 -1
- package/dist/components/ThemeField.js +1 -1
- package/dist/components/TickerSection.js +1 -1
- package/dist/components/TickerSettingsPanel.js +1 -1
- package/dist/components/TitleWithButtons.js +1 -1
- package/dist/components/WebsiteScreenParts.js +1 -1
- package/dist/components/WebsiteSettingsPanel.js +1 -1
- package/dist/components/WidthFollowField.js +1 -1
- package/dist/components/preview-devices.js +1 -1
- package/dist/components/storefront-editor.css +93 -123
- package/dist/components/useLocationsTree.js +1 -1
- package/dist/lib/content/ink.d.ts +36 -0
- package/dist/lib/content/ink.js +1 -0
- package/dist/lib/content/section-surface.js +1 -1
- package/dist/lib/editor-words-catalogue.d.ts +1178 -0
- package/dist/lib/editor-words-catalogue.js +11 -0
- package/dist/lib/editor-words.d.ts +15 -0
- package/dist/lib/editor-words.js +1 -0
- package/dist/lib/links/link-picker-setup.js +1 -1
- package/dist/lib/page-rows.d.ts +8 -0
- package/dist/lib/page-rows.js +1 -0
- package/dist/lib/puck/ColourControl.js +1 -1
- package/dist/lib/puck/MarkupToolbar.js +1 -1
- package/dist/lib/puck/apply-card-corners.js +1 -1
- package/dist/lib/puck/blocks/general/Breadcrumb/render.js +1 -1
- package/dist/lib/puck/blocks/general/Cards/render.js +1 -1
- package/dist/lib/puck/blocks/general/CategoryBar/render.js +1 -1
- package/dist/lib/puck/blocks/general/Chart/render.js +2 -2
- package/dist/lib/puck/blocks/general/DocBody/render.js +1 -1
- package/dist/lib/puck/blocks/general/DocMasthead/render.js +1 -1
- package/dist/lib/puck/blocks/general/DocTabs/render.js +1 -1
- package/dist/lib/puck/blocks/general/FAQ/render.js +1 -1
- package/dist/lib/puck/blocks/general/Footprint/render.js +2 -2
- package/dist/lib/puck/blocks/general/KeyFeatures/render.js +1 -1
- package/dist/lib/puck/blocks/general/Logos/render.js +1 -1
- package/dist/lib/puck/blocks/general/Masthead/render.js +1 -1
- package/dist/lib/puck/blocks/general/OrderSummary/render.js +1 -1
- package/dist/lib/puck/blocks/general/PaymentBadges/render.js +1 -1
- package/dist/lib/puck/blocks/general/ProcessSteps/render.js +1 -1
- package/dist/lib/puck/blocks/general/Series/render.js +1 -1
- package/dist/lib/puck/blocks/general/StatsParagraph/render.js +1 -1
- package/dist/lib/puck/blocks/general/Testimonials/render.js +1 -1
- package/dist/lib/puck/blocks/general/Timeline/render.js +2 -2
- package/dist/lib/puck/blocks/general/TimelineTrack/render.js +1 -1
- package/dist/lib/puck/blocks/scaffold.js +1 -1
- package/dist/lib/puck/controls.js +1 -1
- package/dist/lib/puck/footer-block-row-name.js +1 -1
- package/dist/lib/puck/page-root-fields.js +1 -1
- package/dist/lib/puck/theme-swatches.js +1 -1
- package/dist/lib/source-rules/editor-words.d.ts +26 -0
- package/dist/lib/source-rules/editor-words.js +3 -0
- package/dist/lib/source-rules/mirrored-rows-agree.js +1 -1
- package/dist/lib/source-rules/part-style-naming.js +1 -1
- package/dist/lib/source-rules/support/label-extraction.js +2 -2
- package/dist/lib/theme-save-message.js +1 -1
- package/package.json +6 -5
- package/dist/components/HeadingAudit.d.ts +0 -1
- package/dist/components/HeadingAudit.js +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,243 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 7.1.1 - 2026-10-14
|
|
4
|
+
|
|
5
|
+
- **"Duplicate to page" has no trailing dots** (owner ruling, 2026-10-14:
|
|
6
|
+
"…" means only that words were cut, so no button, link or menu label ends in
|
|
7
|
+
it). The menu heading now says the phrase the menu already names itself by,
|
|
8
|
+
so the editor's catalogue has one phrase fewer: `"Duplicate to page…"` is
|
|
9
|
+
gone. No host has a word for it (searched efficient-storefront,
|
|
10
|
+
efficient-admin-portal, efficient-storefront-blocks and efficient-easel).
|
|
11
|
+
- **`efficient-shell-ui-check` counts it now.** The dev shell is 7.19.0 and
|
|
12
|
+
`ui-kit.config.json` names `ellipsis-label`, which reads the phrase handed to
|
|
13
|
+
`say()`. Peer ranges are unchanged.
|
|
14
|
+
|
|
15
|
+
## 7.1.0 - 2026-10-14
|
|
16
|
+
|
|
17
|
+
- **The Layers head names the open page** ("About us", not "/about"; owner,
|
|
18
|
+
2026-10-14, editor audit item 10). The Pages head's second line names the
|
|
19
|
+
website, so the Layers head's names the page: each says what its panel is
|
|
20
|
+
about. The website hands the screen `useDocumentLabel`; the address stays
|
|
21
|
+
as the fallback while the list loads.
|
|
22
|
+
- **The page list is held once** (`lib/page-rows`): the Pages panel and the
|
|
23
|
+
Layers head read the same rows from one `listPages()` per site, instead of
|
|
24
|
+
the panel keeping its own copy.
|
|
25
|
+
|
|
26
|
+
## 7.0.1 - 2026-10-14
|
|
27
|
+
|
|
28
|
+
- **The Pages panel has one way to add a page** (Lewis, 2026-10-14). The bottom
|
|
29
|
+
"+ New page" button and its `.sf-pages-new` rules are gone. The panel head's
|
|
30
|
+
New page icon button already did the same thing. An empty list now says
|
|
31
|
+
"No pages yet. Add one with + above." and points at that head button. A host
|
|
32
|
+
that translated "No pages yet" gives the new sentence instead.
|
|
33
|
+
- **Pages list rows keep a 4px gap** (`.sf-pgroup-body`, `var(--space-4)`), the
|
|
34
|
+
shell Tree's own row gap. A hovered row next to the selected one is now two
|
|
35
|
+
rounded shapes, not one block.
|
|
36
|
+
- **The add dialog's busy button keeps saying "Add page"** and shows the shell
|
|
37
|
+
Button's spinner (`loading`). The "Adding…" label is gone (no trailing dots on
|
|
38
|
+
a button). The words catalogue is rewritten: 1,176 phrases.
|
|
39
|
+
- The new guard `scripts/test-pages-panel-one-add.ts` holds all three.
|
|
40
|
+
|
|
41
|
+
## 7.0.0 - 2026-10-14
|
|
42
|
+
|
|
43
|
+
- **The Layers panel no longer shows the heading outline** (owner,
|
|
44
|
+
2026-10-14, editor audit). The box under the tree — the heading count,
|
|
45
|
+
"No H1 — add one for SEO." and the list of headings by level — is removed,
|
|
46
|
+
not moved: it is not a layer, "H1" and "SEO" are not a merchant's words, and
|
|
47
|
+
on an empty page it read as an error. The website hands the screen no
|
|
48
|
+
`treeFoot` any more.
|
|
49
|
+
- **Breaking: `components/HeadingAudit` is deleted** (it was reachable through
|
|
50
|
+
the package's `./*` export). No host imports it. Its four words are out of
|
|
51
|
+
the editor's catalogue, and the `.sf-tree-tool` rule is gone with it.
|
|
52
|
+
- `lib/puck/heading-outline` stays: the one-H1 rule's join and the
|
|
53
|
+
storefront's guards still read it.
|
|
54
|
+
|
|
55
|
+
## 6.1.1 - 2026-10-14
|
|
56
|
+
|
|
57
|
+
- **The editor's stylesheet reads the shell's tokens instead of restating
|
|
58
|
+
them** (the duplicate scan of 2026-10-13, GG for Lewis). Every text size
|
|
59
|
+
reads a shell step token, as the shell's own `ui.css` does:
|
|
60
|
+
`var(--text-sm)` for 14, `--text-xs` for 12, `--text-2xs` for 11, and so on
|
|
61
|
+
(80 rules). The settings panel's side padding reads `var(--space-16)`, and
|
|
62
|
+
`var(--space-8)` in the narrow step. Same pixels; one place each. The theme
|
|
63
|
+
card's preview keeps its own px (a drawing).
|
|
64
|
+
- **Two rules no markup draws are deleted**: `.sf-addempty-sub` and
|
|
65
|
+
`.sf-readability-head`. Neither class appears in any repository's source
|
|
66
|
+
(web-builder, easel, storefront, storefront-blocks, admin and the portals);
|
|
67
|
+
the only hits were old CSS copies inlined in storefront's
|
|
68
|
+
`scripts/harness/*.html` snapshots.
|
|
69
|
+
- The padding guards' reader (`scripts/panel-body-padding.ts`) resolves the
|
|
70
|
+
shell's `--space-*` scale from the installed shell's `ui.css`, in px.
|
|
71
|
+
|
|
72
|
+
## 6.1.0 - 2026-10-14
|
|
73
|
+
|
|
74
|
+
**The editor speaks its host's language.** A host that runs in another
|
|
75
|
+
language hands the editor its words, and the editor says them where it draws
|
|
76
|
+
them (programme: Foyerboard on EFFICIENT, editor languages step 3). In English
|
|
77
|
+
nothing reads differently.
|
|
78
|
+
|
|
79
|
+
- **One seam, `lib/editor-words`.** `configureEditorWords(words, locale,
|
|
80
|
+
easel)` lays a host's words over the English, during its frame's render, as
|
|
81
|
+
it configures `lib/web-runtime`; `say(english, values)` and
|
|
82
|
+
`sayCount(one, other, n)` answer the host's word, or the English. The words
|
|
83
|
+
are keyed by the English they replace: a plain word is a string, a sentence
|
|
84
|
+
names its values in braces (`"Delete {name}": "{name} löschen"`), and a
|
|
85
|
+
host may give a function of the values for a plural or an agreement. A word
|
|
86
|
+
left out, or empty, reads in English. The language is fixed for the life of
|
|
87
|
+
a page (harness UI-25), and plain functions read the words as well as
|
|
88
|
+
components, so they are the module's state.
|
|
89
|
+
- **The English stays the key; it is translated where it is shown.** A
|
|
90
|
+
settings row's label is still the literal its control builder is given, so
|
|
91
|
+
`field-groups` (`bucketOf`, `LABEL_BUCKET`, `RETIRED`), `field-noun`,
|
|
92
|
+
`ThemeCard`'s `ROW_ICON` and the label rules in `lib/source-rules` read the
|
|
93
|
+
same English. Inside `lib/puck/controls` every row says its label, hint,
|
|
94
|
+
placeholder, note and choices at render; the group headings, the Swatches'
|
|
95
|
+
names, the reset marks' details, the focal and placement grids' cells, the
|
|
96
|
+
text lists and the coordinates field do too.
|
|
97
|
+
- **Panels and dialogs** — Pages, Site styles, Styles, Theme, the part
|
|
98
|
+
settings, the Locations field, the text styles, Duplicate to page, Clear
|
|
99
|
+
colours, the chat, social and ticker panels, the section editor's head —
|
|
100
|
+
**block names and Add-panel blurbs** (said in the screen's block look:
|
|
101
|
+
`labelAtLevel`, `descriptions`, `categoryLabel`, and an Add target's
|
|
102
|
+
choices), the **preview devices**, and the **placeholders drawn on the
|
|
103
|
+
canvas while editing** (`phPrev`, and the scaffold rows of the general
|
|
104
|
+
blocks) read the seam.
|
|
105
|
+
- **A host's places are phrases of their own**: "Storefront ▸ Sites ▸
|
|
106
|
+
Settings", "Storefront → Blog" and "the admin" are each a phrase passed into
|
|
107
|
+
the sentence that names them, so a host whose menu is elsewhere renames them
|
|
108
|
+
once, in English too.
|
|
109
|
+
- **What is written into a page stays English** (harness UI-25): a block's
|
|
110
|
+
default content, a saved name, a seeded section. What a visitor reads on the
|
|
111
|
+
published page is never the editor's words.
|
|
112
|
+
- **Easel's words reach the parts that cannot read easel's provider.** A reset
|
|
113
|
+
mark (`SettingsDefaultReset`) drawn inside a control builder's closure is
|
|
114
|
+
handed the panel words the host's frame passed with `configureEditorWords`
|
|
115
|
+
(`editorEaselWords()`); the picture box, the Locations tree and the ticker's
|
|
116
|
+
Layers row are handed `useEaselStrings()`'s. The screen's own leaves (the
|
|
117
|
+
save pill, the right-click menu, Copy / Paste style, the Add panel's tiles)
|
|
118
|
+
are efficient-easel 3.1.0's to hand, and are with it.
|
|
119
|
+
- **The phrases are a typed catalogue**, `lib/editor-words-catalogue`
|
|
120
|
+
(`WEB_BUILDER_WORDS`, `WebBuilderPhrase`, 1,181 phrases), written from the
|
|
121
|
+
source by `pnpm run words` and held to it by the new tree-wide rule
|
|
122
|
+
`lib/source-rules/editor-words` (`scripts/test-editor-words.ts`). A host
|
|
123
|
+
types its words as `EditorWordsFor<WebBuilderPhrase>`. The rule reads a
|
|
124
|
+
phrase a builder or `say` is given as a literal; one built at run time
|
|
125
|
+
(`${kind} colour`) is not read and stays English, which is why such phrases
|
|
126
|
+
are now written whole (`"Padding top"`, `"{value} on desktop"`).
|
|
127
|
+
- **Peer `efficient-shell ^5.6.0 || ^6.4.0 || ^7.7.0`** (was `^5.6.0`), as
|
|
128
|
+
efficient-easel 3.0.0 has it; dev `^7.7.0`. The typecheck, every guard and
|
|
129
|
+
the build pass on 7.x.
|
|
130
|
+
- **Peer `efficient-easel ^2.0.0 || ^3.1.0`** (was `^2.0.0`). 3.1.0 is the
|
|
131
|
+
easel whose screen says its last words from the catalogue, hands its own
|
|
132
|
+
leaves their words and names a block row through the layer's
|
|
133
|
+
`labelAtLevel`, so a host on it gets the whole editor in its language; on
|
|
134
|
+
2.x the screen's own parts and a block row's name stay English. Checked
|
|
135
|
+
against a local build of 3.1.0 before it was published: the typecheck, the
|
|
136
|
+
boundary, the screen rule and all 150 other guards pass (the one that fails
|
|
137
|
+
is the dev pin's own, which the injected build does not satisfy by design).
|
|
138
|
+
Dev stays on 2.2.0 until 3.1.0 is on npm.
|
|
139
|
+
|
|
140
|
+
- **The colour row's hex box is the swatch's small rung** (`size="sm"`).
|
|
141
|
+
From efficient-shell 7.11.0 the shell's `HexInput` defaults to a larger
|
|
142
|
+
rung, and in the row's fixed `.sf-colour-hexwrap` (4.75rem) `#FFFFFF` showed
|
|
143
|
+
as `#FFFFF` (the value was unchanged). A shell before the prop draws the
|
|
144
|
+
small box it always did. `test-one-colour-control` §5 holds the box to the
|
|
145
|
+
shell's own small rung.
|
|
146
|
+
|
|
147
|
+
### For hosts
|
|
148
|
+
|
|
149
|
+
- A host in English needs nothing. A host in another language calls
|
|
150
|
+
`configureEditorWords(words, locale, useEaselStrings())` while its frame
|
|
151
|
+
renders (efficient-storefront-blocks does it for its `WebsiteEditor`'s
|
|
152
|
+
`words` / `locale`), and wraps the editor in efficient-easel's
|
|
153
|
+
`EaselStringsProvider`.
|
|
154
|
+
- The storefront's own guards that read a builder file's text are unaffected:
|
|
155
|
+
every word a guard pinned is still the English literal, now inside `say("…")`
|
|
156
|
+
where it is drawn. Three guards here read through `say("…")` now
|
|
157
|
+
(`mirrored-rows-agree`, `part-style-naming`, the panel label reader).
|
|
158
|
+
|
|
159
|
+
### Guards
|
|
160
|
+
|
|
161
|
+
- New rule `lib/source-rules/editor-words` (`scripts/test-editor-words.ts`):
|
|
162
|
+
the reader on a fixture, a floor of 900 phrases, and the catalogue equal to
|
|
163
|
+
what the source says.
|
|
164
|
+
- New `scripts/test-editor-words-say.tsx`: a host's word, its values, a
|
|
165
|
+
function word, the English for a word left out, empty or throwing; a
|
|
166
|
+
control's row drawn in the host's words while its field keeps its English
|
|
167
|
+
label; a canvas placeholder said only while editing; and the English back
|
|
168
|
+
byte for byte with no words.
|
|
169
|
+
- `test-shell-peer-range` holds the wider range and a 7.x dev shell;
|
|
170
|
+
`test-panel-parts-from-the-shell` holds every range to start at 5.6.0.
|
|
171
|
+
- `support/label-extraction`'s JSX label reader, `mirrored-rows-agree`,
|
|
172
|
+
`part-style-naming`, `test-part-follows-style`, `test-clear-formatting` and
|
|
173
|
+
`test-save-as-template-action` read `label={say("…")}` as the label they
|
|
174
|
+
read before.
|
|
175
|
+
|
|
176
|
+
## 6.0.3 - 2026-10-13
|
|
177
|
+
|
|
178
|
+
- **A block on a dark picture paints light ink, words and placeholders
|
|
179
|
+
alike** (card [FIX] Dark Text On Dark Hero Boxes, audit item 28). A
|
|
180
|
+
Heading or Text dropped into a Hero's box painted the page's ink (#111 on
|
|
181
|
+
a light site) on the dark overlay: the layer set `color` only, and a block
|
|
182
|
+
paints `text-fg` / `text-fg-dim` / `border-line`, which read the TOKENS
|
|
183
|
+
`--fg` / `--fg-dim` / `--site-line`. Every layer that puts blocks on a
|
|
184
|
+
darkened picture now sets the tokens too: the Hero's box layer, a Hero
|
|
185
|
+
slide's group layer, a Box with a darkened background image (it set no ink
|
|
186
|
+
at all before), the Banner and Split copy on a photograph, and IntroBleed.
|
|
187
|
+
The empty Heading and Text placeholders follow, as they are the same
|
|
188
|
+
elements.
|
|
189
|
+
- **One list of ink tokens, `lib/content/ink`.** `SECTION_PALETTE` names each
|
|
190
|
+
colour a section theme hands its band, with its token and whether it is ink;
|
|
191
|
+
`inkStyle(source)` is the one way a layer changes the ink, and
|
|
192
|
+
`ON_MEDIA_INK_STYLE` is the on-media ink (`--overlay-fg`, its dim and its
|
|
193
|
+
rule as thinned mixes, no raw hex). `sectionAccentVars` now emits its
|
|
194
|
+
`--sf-sec-*` from the same list, byte for byte as before.
|
|
195
|
+
- **Split's body on a photograph** is `text-fg-dim` again (the on-media dim);
|
|
196
|
+
the `opacity-85` patch that stood in for it is gone.
|
|
197
|
+
- Host follow-up: a host's `.sf-section-accent` / `.sf-header-theme` map each
|
|
198
|
+
`--sf-sec-<role>` onto its token; the storefront's own guard should pin that
|
|
199
|
+
list to `SECTION_PALETTE` when it moves to this release. A published hero
|
|
200
|
+
with boxes, every slide, and a Banner, Split or IntroBleed on a photograph
|
|
201
|
+
carry the new style attribute, so the storefront's byte baseline moves.
|
|
202
|
+
|
|
203
|
+
## 6.0.2 - 2026-10-13
|
|
204
|
+
|
|
205
|
+
- **Every text size in the editor's stylesheet is a type step** (9 / 11 /
|
|
206
|
+
12 / 14 / 16 / 18 / 20 / 24 / 30; Lewis, 2026-10-12). Each move is the one
|
|
207
|
+
the 10-12 type ruling names. GG confirmed on 2026-10-13 that "never smaller"
|
|
208
|
+
is about spacing and heights, not type.
|
|
209
|
+
- 10 → 11 ("other 10px → 11"): the dropdown caret, the page's Draft tag,
|
|
210
|
+
the chooser's meta line, the theme warning, the readability head.
|
|
211
|
+
- 10.5 → 11 (the same rule): the add card's description, the part chip,
|
|
212
|
+
the gallery count.
|
|
213
|
+
- 11.5 → 12 ("12 = table heads, grey meta (11.5, 12.5 → 12)"): the
|
|
214
|
+
site-wide row's description, the form summary warning, the part-style
|
|
215
|
+
state, the gallery filter.
|
|
216
|
+
- 12.5 → 12 (the same rule; "add-section card name 12.5 → 12"): the
|
|
217
|
+
site-wide row's name, the add card's name and its Add button, the empty
|
|
218
|
+
state's line.
|
|
219
|
+
- 15 → 16 ("15/17 → 16"): the add card's plus and the large A of the text
|
|
220
|
+
scale.
|
|
221
|
+
- The theme card's preview keeps its own sizes (7.5 / 8.5 / 9.5px): it is a
|
|
222
|
+
picture of a page, drawn small, and its type is the drawing's.
|
|
223
|
+
|
|
224
|
+
## 6.0.1 - 2026-10-13
|
|
225
|
+
|
|
226
|
+
- **The settings panel's side padding is 16** (was 14). The spacing scale
|
|
227
|
+
Lewis ruled on 2026-10-12 is 2 / 4 / 8 / 12 / 16 / …, and a value off it
|
|
228
|
+
goes up, never down (2026-10-13). The narrow step stays 8. The content
|
|
229
|
+
width card 66212 protects (241px) now needs a 285px panel, so the
|
|
230
|
+
container line moves from `< 280px` to `< 284px`, for the body padding
|
|
231
|
+
and for the segmented strip's narrow padding together (one edge, one
|
|
232
|
+
number). At the 320 default the tab strip is 277 with a scrollbar, still
|
|
233
|
+
clear of the 270 its widest tier needs.
|
|
234
|
+
- **The editor's 13px text is 14** (the type steps: 9 / 11 / 12 / 14 / 16 /
|
|
235
|
+
…; 13 → 14 by name). The inspector's inputs, textareas and selects, the
|
|
236
|
+
dropdown trigger, the page list's search and its new-page row, the
|
|
237
|
+
chooser and its items, the read-only field, the preview pin's label, the
|
|
238
|
+
column step's value, the note, and the part-style options: 14 rules.
|
|
239
|
+
easel's own 13px rules move in easel's pull request.
|
|
240
|
+
|
|
3
241
|
## 6.0.0 - 2026-10-13
|
|
4
242
|
|
|
5
243
|
- **Breaking: efficient-shell ^5.6.0** (peer; was `^4.171.0 || ^5.0.0`). The
|
package/README.md
CHANGED
|
@@ -32,6 +32,48 @@ What a host adds, it hands over on the editor's session
|
|
|
32
32
|
|
|
33
33
|
The storefront's are assembled in its `lib/storefront-editor.ts`.
|
|
34
34
|
|
|
35
|
+
## The editor's words in a host's language
|
|
36
|
+
|
|
37
|
+
The editor speaks English, and a host that runs in another language lays its
|
|
38
|
+
own words over it (6.1.0). The English stays in the code, where it is said,
|
|
39
|
+
and many of the words are also keys (a row is filed under its tab and given
|
|
40
|
+
its glyph by its English label), so it is translated where it is SHOWN:
|
|
41
|
+
|
|
42
|
+
- **The words are keyed by the English they replace.**
|
|
43
|
+
`efficient-web-builder/lib/editor-words-catalogue` exports
|
|
44
|
+
`WEB_BUILDER_WORDS`, every phrase the editor says (a settings row's label,
|
|
45
|
+
hint and choices, a group heading, a panel's and a dialog's words, a block's
|
|
46
|
+
name and its Add-panel blurb, a placeholder drawn on the canvas while
|
|
47
|
+
editing), and the type of its keys, `WebBuilderPhrase`. It is written from
|
|
48
|
+
the source by `pnpm run words` and held to it by
|
|
49
|
+
`scripts/test-editor-words.ts`, so a host typing its catalogue as
|
|
50
|
+
`EditorWordsFor<WebBuilderPhrase>` fails its typecheck on a phrase it lacks.
|
|
51
|
+
- **A sentence with a value names it in braces**, in the English and in the
|
|
52
|
+
host's word alike: `"Delete {name}": "{name} löschen"`. A host may give a
|
|
53
|
+
function of the values instead, for a plural or an agreement the braces
|
|
54
|
+
cannot say (`"{n} pages": ({ n }) => …`). A count is two phrases
|
|
55
|
+
(`sayCount("{n} page", "{n} pages", n)`).
|
|
56
|
+
- **Names of a host's places are phrases of their own**, so a host renames
|
|
57
|
+
them once, in English too: the editor says "Storefront ▸ Sites ▸ Settings"
|
|
58
|
+
and "the admin", where an EFFICIENT admin has them, and a host whose menu
|
|
59
|
+
is elsewhere says its own.
|
|
60
|
+
- **The host hands its words once, while its frame renders**, with
|
|
61
|
+
`configureEditorWords(words, locale)` from `lib/editor-words` — as it
|
|
62
|
+
configures `lib/web-runtime`. The words are fixed for the life of a page
|
|
63
|
+
(harness UI-25), one editor is mounted at a time, and they are read by plain
|
|
64
|
+
functions as well as components, so they are the module's state, not a
|
|
65
|
+
React context. A word left out reads in English.
|
|
66
|
+
- **What is written into a page stays English**: a block's default content, a
|
|
67
|
+
saved name. And what a visitor reads on the published page is never the
|
|
68
|
+
editor's words.
|
|
69
|
+
- **The engine's words are efficient-easel's** (`EaselStringsProvider`); a host
|
|
70
|
+
wraps the editor in it. The parts the builder draws itself that take
|
|
71
|
+
easel's words as a prop (a picture box, a Locations tree) are handed
|
|
72
|
+
`useEaselStrings()`'s.
|
|
73
|
+
|
|
74
|
+
`efficient-storefront-blocks` adds the phrases of its own blocks the same way
|
|
75
|
+
and takes a host's words on its `WebsiteEditor` (`words`, `locale`).
|
|
76
|
+
|
|
35
77
|
Two checks hold the rule, both in CI and both without an allow-list:
|
|
36
78
|
|
|
37
79
|
- `pnpm run typecheck` — `@/…` points at `src/` and nowhere else, so an import
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as l}from"react/jsx-runtime";import{useCallback as
|
|
1
|
+
"use client";import{jsx as l}from"react/jsx-runtime";import{useCallback as u,useEffect as a,useRef as m,useState as f}from"react";import{useEasel as C}from"efficient-easel/easel";import{SettingsAction as d}from"efficient-easel/panel";import{say as y}from"../lib/editor-words.js";import{applyCorners as A,applyCornersDoneLabel as S,applyCornersNote as b,planApplyCorners as _}from"../lib/puck/apply-card-corners.js";import{useSectionOps as x}from"../lib/puck/use-section-ops.js";const E=2200,L="apply-corners-to-siblings",P="Apply to all cards";function N({plan:e,doneCount:n,onPress:r}){return l(d,{id:L,label:y(P),note:b(e),disabled:!e.can,done:n!==null,doneLabel:S(n??0),onPress:r})}function O(){const{appState:e,config:n}=C(i=>i),r=x(),[p,s]=f(null),o=m(null);a(()=>()=>{o.current&&clearTimeout(o.current)},[]);const t=_(n,e.data.content??[],e.ui.itemSelector),c=u(()=>{A(t,r.replaceComponent),t.can&&(s(t.others),o.current&&clearTimeout(o.current),o.current=setTimeout(()=>s(null),E))},[t,r]);return l(N,{plan:t,doneCount:p,onPress:c})}export{E as APPLY_CORNERS_DONE_MS,P as APPLY_CORNERS_LABEL,N as ApplyCornersButton,O as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as e,jsxs as r}from"react/jsx-runtime";import h from"./BlockFrame.js";import f from"./Btn.js";import{media as
|
|
1
|
+
import{jsx as e,jsxs as r}from"react/jsx-runtime";import h from"./BlockFrame.js";import f from"./Btn.js";import{media as g}from"../lib/media.js";import v from"./SectionEyebrow.js";import{renderGold as t,renderHeadline as u,splitParagraphs as N}from"./goldPhrases.js";import{ON_MEDIA_INK_STYLE as b}from"../lib/content/ink.js";function y({eyebrow:i,title:s,body:n,ctaText:l,ctaHref:m,imageSrc:a,contained:d,overlay:o=60}){const p=Math.min(Math.max(o,0),100)/100;return e(h,{contained:d,className:"py-6",children:r("div",{className:"sf-card relative overflow-hidden border border-line bg-surface px-10 py-16 max-[800px]:px-6 max-[800px]:py-10",children:[a&&r("div",{className:"absolute inset-0","aria-hidden":!0,children:[e("img",{src:g(a),alt:"",className:"h-full w-full object-cover"}),e("div",{className:"absolute inset-0",style:{background:`rgba(0,0,0,${p})`}})]}),r("div",{className:"relative z-[1] flex max-w-[680px] flex-col gap-5",style:a?b:void 0,children:[i&&e(v,{text:i}),s&&e("h2",{className:"font-heading2 text-[length:min(var(--size-headingMedium,44px),var(--sf-heading-max,9999px))] font-medium leading-[1.05] tracking-[-0.03em] max-[800px]:text-[length:min(var(--size-headingMedium,32px),var(--sf-heading-max,9999px))]",children:u(s,!1)}),n&&N(n).map((c,x)=>e("p",{className:"text-[length:var(--size-body,16px)] leading-[1.6] opacity-85",children:t(c)},x)),l&&e("div",{className:"mt-2 self-start",children:e(f,{href:m||"#",variant:"primary",children:t(l)})})]})]})})}export{y as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as
|
|
1
|
+
"use client";import{jsx as t}from"react/jsx-runtime";import{SettingsDefaultReset as r,SettingsField as c}from"efficient-easel/panel";import{AlignSeparateIcon as d}from"efficient-easel/icons";import{CONTAINER_GAP_BUILT_IN as p,SITE_BLOCK_GAP as o}from"../lib/content/container-gap.js";import{say as e,editorEaselWords as m}from"../lib/editor-words.js";import{Slider as f}from"../lib/puck/controls.js";const u="The space between the blocks inside a row, a grid or a box. Default means each one keeps the spacing it already has.",i="Block gap",_=p.Grid;function g({value:n,onChange:l,showHint:s=!0}){const a=n===null;return t(c,{label:e(i),labelId:"sf-block-gap",icon:t(d,{}),value:a?void 0:`${n}px`,changed:!a,action:t(r,{words:m()?.panel,label:e(i),changed:!a,detail:e("each block's own spacing"),onReset:()=>l(null)}),hint:s?e(u):void 0,children:t(f,{min:o.min,max:o.max,step:o.step,value:a?_:n,readout:!1,ariaLabel:e(i),onChange:l})})}export{g as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as
|
|
1
|
+
"use client";import{jsx as o,Fragment as i,jsxs as B}from"react/jsx-runtime";import{useContext as P}from"react";import{SettingsField as m}from"efficient-easel/panel";import{FieldSelect as g}from"efficient-easel/fields";import{BlogPostIcon as f}from"efficient-easel/icons";import{StorefrontDocumentContext as L}from"./StorefrontDocumentContext.js";import{loadStorefrontBlogPosts as N}from"./useStorefrontBlogPosts.js";import{useSnapshotSource as F}from"./useSnapshotSource.js";import T from"./SourceStatus.js";import{say as t}from"../lib/editor-words.js";function j(e){if(!e)return"";const n=new Date(e);return Number.isNaN(n.getTime())?"":n.toLocaleDateString("en-US",{year:"numeric",month:"short",day:"2-digit"})}function h(e){return{slug:e.slug,image:e.coverImage,title:e.title,dek:e.excerpt,date:j(e.publishedAt),href:e.href}}function w({value:e,onChange:n}){const r=P(L);return r&&!r.capabilities.hasBlog?e?.slug?o(C,{value:e,onChange:n}):o(i,{}):o(D,{value:e,onChange:n})}function C({value:e,onChange:n}){return o("div",{children:o(m,{label:t("Blog post source"),icon:o(f,{}),hint:o(i,{children:t("Linked to a blog post. This editor has no blog to pick another from; choose “None (manual)” to author the section yourself.")}),children:o(g,{value:e.slug,ariaLabel:t("Blog post source"),onChange:r=>r?void 0:n(null),options:[{label:t("None (manual)"),value:""},{label:e.title||e.slug,value:e.slug}]})})})}function D({value:e,onChange:n}){const{rows:r,loading:p,refreshing:a,errored:d,refresh:b}=F({load:N,resolve:(s,l)=>s.find(c=>c.slug===l.slug),snapshot:h,value:e,onChange:n}),k=s=>{if(!s){n(null);return}const l=(r??[]).find(c=>c.slug===s);l&&n(h(l))},S=e?.slug&&!(r??[]).some(s=>s.slug===e.slug),y=d?"error":a?"loading":"idle",u=t("Storefront → Blog"),x=d?t("Couldn’t reach {place}.",{place:u}):a?t("Syncing from {place}…",{place:u}):t("Linked to “{name}”",{name:e?.title||e?.slug||""});return B("div",{children:[o(m,{label:t("Blog post source"),icon:o(f,{}),hint:e?.slug?void 0:o(i,{children:t("Pick a post from {place} to auto-fill this section, or keep “None (manual)” to author it yourself below.",{place:u})}),children:o(g,{value:e?.slug??"",ariaLabel:t("Blog post source"),onChange:k,readOnly:p,options:[{label:t("None (manual)"),value:""},...S?[{label:t("{name} (unavailable)",{name:e.title||e.slug}),value:e.slug}]:[],...(r??[]).map(s=>({label:s.title,value:s.slug}))]})}),e?.slug?o(T,{status:y,statusText:x,onRefresh:b,busy:a,hint:o(i,{children:t("Auto-fills the cover image, headline, dek, date and link from this post each time you open the editor. Those fields are hidden while a post is linked; the remaining fields stay yours to set.")})}):null]})}export{w as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as r,jsxs as s,Fragment as c}from"react/jsx-runtime";import{Fragment as f}from"react";import{SiteLink as x}from"../lib/site-runtime.js";import{renderChrome as m,renderGold as d}from"./goldPhrases.js";function
|
|
1
|
+
import{jsx as r,jsxs as s,Fragment as c}from"react/jsx-runtime";import{Fragment as f}from"react";import{SiteLink as x}from"../lib/site-runtime.js";import{renderChrome as m,renderGold as d}from"./goldPhrases.js";import{say as h}from"../lib/editor-words.js";function g({items:o,meta:t,editing:p=!1}){const l=(o??[]).filter(e=>e?.label?.trim()),a=l.length>0?l:p?[{label:h("Breadcrumb")}]:[];return a.length===0&&!t?null:s("nav",{className:"flex items-center gap-4 border-b border-line px-[var(--sf-site-gutter,40px)] py-6 font-mono text-[length:var(--size-label,13px)] uppercase tracking-[0.2em] text-fg-dim max-[720px]:px-[min(20px,var(--sf-site-gutter,40px))] max-[720px]:py-4",children:[a.map((e,n)=>{const i=n===a.length-1;return s(f,{children:[n>0&&r("span",{className:"opacity-40",children:"/"}),e.href&&!i?r(x,{href:e.href,className:"hover:text-fg",children:m(e.label)}):r("span",{className:i?"text-fg":void 0,children:m(e.label)})]},n)}),t&&s(c,{children:[r("span",{className:"opacity-40",children:"·"}),r("span",{children:d(t)})]})]})}export{g as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as
|
|
1
|
+
"use client";import{jsx as t}from"react/jsx-runtime";import{SettingsDefaultReset as p,SettingsField as c,SettingsSegmented as f}from"efficient-easel/panel";import{ShadowIcon as x}from"efficient-easel/icons";import{say as e,editorEaselWords as h}from"../lib/editor-words.js";import{CARD_SHADOWS as u,DEFAULT_CARD_SHADOW as r}from"../lib/theme.js";const a={none:"None",soft:"Soft",lifted:"Lifted"},S="Applies to cards — products, brands, journal entries and filter cells. Round things like swatches and status dots are never shadowed.",m={none:"none",soft:"0 1px 1px rgba(20, 20, 22, 0.10), 0 2px 4px -1px rgba(20, 20, 22, 0.14)",lifted:"0 1px 2px rgba(20, 20, 22, 0.10), 0 4px 7px -2px rgba(20, 20, 22, 0.30)"},b={labelsPx:90.25,widestLabelPx:34.6};function A({value:n,onChange:s,showHint:l=!0}){const d=n===null,i=n??r;return t(c,{label:e("Card shadow"),icon:t(x,{}),value:e(a[i]),changed:!d,action:t(p,{words:h()?.panel,label:e("Card shadow"),changed:!d,detail:e(a[r]),onReset:()=>s(null)}),hint:l?e(S):void 0,children:t(f,{options:u.map(o=>({id:o,label:e(a[o]),icon:t("span",{className:"sf-shadow-chip",style:{boxShadow:m[o]}})})),value:i,ariaLabel:e("Card shadow"),fit:b,onChange:s})})}export{A as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as r,jsxs as n}from"react/jsx-runtime";import{SiteLink as g}from"../lib/site-runtime.js";import{renderChrome as
|
|
1
|
+
import{jsx as r,jsxs as n}from"react/jsx-runtime";import{SiteLink as g}from"../lib/site-runtime.js";import{renderChrome as o}from"./goldPhrases.js";import{STICKY_UNDERHEADER_CLASS as u}from"../lib/puck/header-clearance.js";import{say as v}from"../lib/editor-words.js";function k({tabs:m,activeTab:l,links:d,sticky:b=!0,editing:f=!1}){const i=(m??[]).filter(e=>e?.label?.trim()),a=i.length>0?i:f?[{label:v("Tab")}]:[],s=(d??[]).filter(e=>e?.label?.trim());if(a.length===0&&s.length===0)return null;const c=l?a.findIndex(e=>e.label.toLowerCase()===l.toLowerCase()):-1,h=c===-1?0:c;return r("nav",{className:`${b?`${u} sticky top-[var(--sf-header-h,88px)] z-40 `:""}border-b border-line px-[var(--sf-site-gutter,40px)] backdrop-blur-md max-[1100px]:px-[min(16px,var(--sf-site-gutter,40px))]`,style:{background:"color-mix(in oklab, var(--bg) 92%, transparent)"},children:n("div",{className:"mx-auto flex max-w-[calc(var(--sf-site-width,1600px)_-_var(--sf-site-gutter,40px)*2)] items-stretch gap-0 overflow-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",children:[a.map((e,t)=>{const p=t===h,x=e.count?.trim()?e.count:"";return n("span",{className:["relative whitespace-nowrap border-r border-line px-[22px] py-[18px] font-mono text-[length:var(--size-label,13px)] uppercase tracking-[0.22em] transition-colors",t===0?"border-l border-line":"",p?"text-fg":"text-fg-dim hover:text-fg"].join(" "),children:[o(e.label),x&&r("span",{className:"ml-2 text-[length:var(--size-body,12px)] text-accent opacity-70",children:o(x)}),p&&r("span",{className:"absolute inset-x-0 -bottom-px h-[2px] bg-accent"})]},t)}),s.length>0&&r("div",{className:"ml-auto flex border-l border-line",children:s.map((e,t)=>n(g,{href:e.href||"#",className:"flex items-center gap-2.5 px-[22px] py-[18px] font-mono text-[length:var(--size-label,13px)] uppercase tracking-[0.22em] text-fg-dim hover:text-fg",children:[o(e.label)," ",r("span",{className:"text-accent",children:"↗"})]},t))})]})})}export{k as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as e,Fragment as b,jsxs as d}from"react/jsx-runtime";import{useEffect as
|
|
1
|
+
"use client";import{jsx as e,Fragment as b,jsxs as d}from"react/jsx-runtime";import{useEffect as f,useId as g,useState as p}from"react";import{usePreviewChat as w}from"./PreviewChatContext.js";import{SettingsField as c,SettingsSwitch as C}from"efficient-easel/panel";import{EyeIcon as y,TypeIcon as E}from"efficient-easel/icons";import{GroupLabel as L}from"../lib/puck/controls.js";import{say as n}from"../lib/editor-words.js";const T="Chat with us",v="We usually reply within a few minutes",x="Hi! Ask us anything — about a wheel, an order, or fitment. Leave your details and we’ll reply.";function h({label:t,value:a,placeholder:i,onCommit:l,multiline:m=!1}){const[r,s]=p(a);f(()=>s(a),[a]);const u=()=>{r!==a&&l(r)};return e(c,{label:t,icon:e(E,{}),children:m?e("textarea",{value:r,placeholder:i,rows:3,onChange:o=>s(o.target.value),onBlur:u,"aria-label":t}):e("input",{type:"text",value:r,placeholder:i,onChange:o=>s(o.target.value),onBlur:u,onKeyDown:o=>{o.key==="Enter"&&o.currentTarget.blur()},"aria-label":t,autoComplete:"off"})})}function I(){const{chat:t,setChat:a}=w(),i=g();return d(b,{children:[e(c,{label:n("Show the chat bubble"),labelId:i,icon:e(y,{}),action:e(C,{checked:t.enabled,onChange:l=>a({enabled:l}),ariaLabelledBy:i}),hint:t.enabled?n("The floating chat bubble shows in the corner of every page."):n("The chat bubble is hidden across the whole site.")}),e(L,{label:"Wording"}),e(h,{label:n("Title"),value:t.title,placeholder:T,onCommit:l=>a({title:l})}),e(h,{label:n("Subtitle"),value:t.subtitle,placeholder:v,onCommit:l=>a({subtitle:l})}),e(h,{label:n("Greeting message"),value:t.greeting,placeholder:x,onCommit:l=>a({greeting:l}),multiline:!0}),e("p",{className:"es-field-hint sf-hint-keep",children:n("Leave a field blank to use the built-in wording.")})]})}export{I as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{
|
|
1
|
+
"use client";import{jsx as e,Fragment as i,jsxs as n}from"react/jsx-runtime";import{Button as r,Dialog as l}from"efficient-shell/ui";import{say as s,sayCount as h}from"../lib/editor-words.js";function c(t){return h("This site has {n} color theme of its own. Clearing takes them away and puts back the four the shop supplies.","This site has {n} color themes of its own. Clearing takes them away and puts back the four the shop supplies.",t)}function d({count:t,onCancel:o,onConfirm:a}){return n(l,{open:!0,onClose:o,role:"alertdialog",size:"sm",title:s("Clear this site’s colors?"),footer:n(i,{children:[e(r,{variant:"secondary",onClick:o,children:s("Cancel")}),e(r,{variant:"danger",onClick:a,children:s("Clear colors")})]}),children:[e("p",{children:c(t)}),e("p",{className:"mt-2 font-medium",children:s("This cannot be undone.")})]})}export{d as ClearColoursDialog};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as
|
|
1
|
+
"use client";import{jsx as t}from"react/jsx-runtime";import{SettingsDefaultReset as l,SettingsField as d}from"efficient-easel/panel";import{SquareIcon as u}from"efficient-easel/icons";import{CORNER_RADIUS_MAX as c,CORNER_RADIUS_MIN as i}from"../lib/theme.js";import{say as e,editorEaselWords as p}from"../lib/editor-words.js";import{Slider as m}from"../lib/puck/controls.js";const R="Applies to panels, cards, inputs and buttons. Round things — color swatches, switches, status dots — stay round.",s="Corners";function f({value:n,onChange:r,showHint:a=!0}){const o=n===null;return t(d,{label:e(s),icon:t(u,{}),value:o?void 0:`${n}px`,changed:!o,action:t(l,{words:p()?.panel,label:e(s),changed:!o,detail:e("the built-in corners"),onReset:()=>r(null)}),hint:a?e(R):void 0,children:t(m,{min:i,max:c,step:1,value:n??i,readout:!1,ariaLabel:e(s),onChange:r})})}export{s as CORNERS_LABEL,f as default};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import{jsx as r,jsxs as
|
|
2
|
-
`).split(/\n[ \t]*\n/))
|
|
3
|
-
`).map(a=>a.replace(/\s+$/,"")).filter(a=>a.trim()!=="").forEach((a,
|
|
4
|
-
${a}`:
|
|
1
|
+
import{jsx as r,jsxs as f}from"react/jsx-runtime";import{renderGold as c}from"./goldPhrases.js";import{storefrontLines as u}from"../lib/markup.js";import{say as p}from"../lib/editor-words.js";function y(o,s){return o.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")||`section-${s+1}`}function v(o){const s=[];for(const d of o.replace(/\r\n?/g,`
|
|
2
|
+
`).split(/\n[ \t]*\n/))d.split(`
|
|
3
|
+
`).map(a=>a.replace(/\s+$/,"")).filter(a=>a.trim()!=="").forEach((a,x)=>{const m=u(a)[0].bullet,n=s.at(-1),e=x===0||!n||n.type==="ul"!==m;if(m){const t=a.slice(2);!e&&n?.type==="ul"?n.items.push(t):s.push({type:"ul",items:[t]})}else!e&&n?.type==="p"?n.text+=`
|
|
4
|
+
${a}`:s.push({type:"p",text:a})});return s}const w=()=>[{label:p("First section"),heading:p("Your *first* section."),body:p(`Write the opening paragraph here.
|
|
5
5
|
|
|
6
6
|
- Start a line with a dash for a bullet.
|
|
7
|
-
- Add as many as you like.`},{label:"Second section",heading:"Your *second* section.",body:"Leave a blank line between paragraphs to start a new one."}],
|
|
7
|
+
- Add as many as you like.`)},{label:p("Second section"),heading:p("Your *second* section."),body:p("Leave a blank line between paragraphs to start a new one.")}],N=120;function S({tocTitle:o,sections:s,editing:d=!1,stickyTop:g=N}){const a=(s??[]).filter(e=>(e.heading??"").trim()!==""||(e.label??"").trim()!==""||(e.body??"").trim()!=="");if(a.length===0&&!d)return null;const x=a.length===0&&d?w():a,m=new Set,n=x.map((e,t)=>{const i=y(e.label||e.heading||"",t);let l=i,h=2;for(;m.has(l);)l=`${i}-${h++}`;return m.add(l),l});return r("section",{className:"relative z-[2] bg-bg",children:f("div",{className:"mx-auto grid max-w-[var(--sf-site-width,1600px)] grid-cols-[240px_1fr] items-start gap-20 border-b border-line px-[var(--sf-site-gutter,40px)] py-20 max-[900px]:grid-cols-1 max-[900px]:gap-10 max-[900px]:px-[min(24px,var(--sf-site-gutter,40px))] max-[900px]:py-[60px]",children:[f("aside",{className:"sticky flex flex-col self-start max-[900px]:static",style:{top:g},children:[o&&r("h4",{className:"mb-[18px] font-mono text-[length:var(--size-label,12px)] uppercase tracking-[0.3em] text-accent",children:c(o)}),x.map((e,t)=>f("a",{href:`#${n[t]}`,className:`flex items-center justify-between gap-3 border-b border-line py-2.5 font-mono text-[length:var(--size-label,13px)] uppercase tracking-[0.18em] text-fg-dim transition-colors hover:text-fg${t===0?" border-t":""}`,children:[r("span",{children:c(e.label||"Section")}),r("span",{className:"text-accent",children:String(t+1).padStart(2,"0")})]},n[t]))]}),r("div",{className:"flex flex-col gap-16",children:x.map((e,t)=>f("article",{id:n[t],className:"flex flex-col gap-[18px]",style:{scrollMarginTop:g},children:[f("span",{className:"font-mono text-[length:var(--size-label,12px)] uppercase tracking-[0.3em] text-accent",children:[String(t+1).padStart(2,"0")," · ",c(e.label||"Section")]}),e.heading&&r("h2",{className:"mb-2 border-b border-line pb-[18px] font-heading2 text-[length:min(var(--size-headingMedium,clamp(28px,3.5vw,44px)),var(--sf-heading-max,9999px))] font-medium uppercase leading-[1.04] tracking-[-0.025em]",children:c(e.heading)}),v(e.body??"").map((i,l)=>i.type==="ul"?r("ul",{className:"flex max-w-[680px] list-none flex-col gap-2.5 pl-0",children:i.items.map((h,b)=>r("li",{className:"relative pl-6 font-serif text-[length:var(--size-body,17px)] leading-[1.65] text-fg-dim before:absolute before:-top-0.5 before:left-1.5 before:text-[length:var(--size-body,24px)] before:leading-none before:text-accent before:content-['·']",children:c(h)},b))},l):r("p",{className:"max-w-[680px] font-serif text-[length:var(--size-body,17px)] leading-[1.7] text-fg-dim",children:c(i.text)},l))]},n[t]))})]})})}export{S as default,y as sectionAnchorId};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as t,jsxs as
|
|
1
|
+
"use client";import{jsx as t,jsxs as g,Fragment as A}from"react/jsx-runtime";import{useCallback as L,useRef as z,useState as s}from"react";import{InspectorIconButton as W}from"efficient-easel/chrome";import{PopupMenu as H,PopupMenuItem as Y,PopupMenuLabel as a}from"efficient-shell/ui";import{CopyToPageIcon as $}from"efficient-easel/icons";import{backendOf as M}from"../lib/website-session.js";import{useEditorSession as q}from"../lib/editor-session-context.js";import{say as n}from"../lib/editor-words.js";import{cloneNodeWithFreshIds as G}from"../lib/puck/section-doc.js";import{FOOTER_TYPE as J}from"../lib/puck/content-tree.js";function K({node:N,currentSlug:T,siteId:i,tokenRef:h,runAuthed:D,onNotify:I}){const[c,r]=s(!1),[y,x]=s(null),o=q(),[j,u]=s(!1),[d,b]=s(null),P=z(null),[p,B]=s(null),F=L(async()=>{if(o.usesBridgedToken&&!h.current){u(!0);return}try{x(await M(o).pages.list(i?{siteId:i}:void 0))}catch{u(!0)}},[h,i,o]),O=()=>{if(c){r(!1);return}const e=P.current?.getBoundingClientRect();e&&B({top:e.bottom+6,right:Math.max(8,window.innerWidth-e.right)}),x(null),u(!1),F(),r(!0)},k=(y??[]).filter(e=>e.slug!==T),R=async e=>{if(d)return;b(e.slug);const w=G(N),S=o.documentHooks?.storedNode?.(w)??w,C=M(o).pages,v=await D(async()=>{const m=await C.load({id:e.id});if(!m)throw new Error(`Page "${e.slug}" no longer exists.`);const f=m.layout??{},l=Array.isArray(f.content)?[...f.content]:[],E=l.findIndex(_=>_?.type===J);l.splice(E===-1?l.length:E,0,S),await C.save(e.id,{layout:{root:{},zones:{},...f,content:l}},{version:m.version,clientId:""})});b(null),r(!1),I?.(v?n("Duplicated to “{name}”",{name:e.label}):n("Couldn’t duplicate the section — please retry"),v?"success":"error")};return g(A,{children:[t("span",{"data-menu-toggle":!0,style:{display:"contents"},children:t(W,{buttonRef:P,label:n("Duplicate to another page"),hasPopup:"menu",expanded:c,onClick:O,children:t($,{size:15})})}),c&&p&&t(H,{portal:!0,style:{top:p.top,right:p.right},onClose:()=>r(!1),children:g("div",{role:"menu","aria-label":n("Duplicate to page"),children:[t(a,{children:n("Duplicate to page")}),j?t(a,{children:n("Couldn’t load pages")}):y===null?t(a,{children:n("Loading…")}):k.length===0?t(a,{children:n("No other pages")}):k.map(e=>g(Y,{role:"menuitem",disabled:d!==null,onClick:()=>{R(e)},children:[t("span",{className:"min-w-0 flex-1 truncate",children:e.label}),d===e.slug?t("span",{className:"shrink-0 text-xs",children:n("Copying…")}):e.draft&&t("span",{className:"shrink-0 text-xs",children:n("draft")})]},e.id))]})})]})}export{K as default};
|
package/dist/components/FAQ.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{Fragment as
|
|
1
|
+
import{Fragment as v,jsx as e,jsxs as c}from"react/jsx-runtime";import{stripMarkup as A}from"../lib/markup.js";import{renderGold as i,renderHeadline as E}from"./goldPhrases.js";import F from"./SectionHeader.js";import S from"./SectionTextPartBridge.js";import{TEXT_REGION_ATTR as R,regionStyle as T,textRegionPartKey as z}from"../lib/sections/text-regions.js";import{FAQ_REGIONS as I}from"../lib/sections/faq-text-regions.js";import{SIZE_STEP_OF_ROLE as O}from"../lib/fonts.js";import{say as o}from"../lib/editor-words.js";function y(t){return A(t).trim()}function x(t,r){return t?{[R]:r}:{}}function d(t,r){const a=t?.[z(r)]?.role;return T(a,I[r],O)}function j({editing:t,nodeId:r,children:a}){return!t||!r?e(v,{children:a}):e(S,{nodeId:r,sectionType:"FAQ",children:a})}const Q="relative z-[2] bg-bg px-[var(--sf-site-gutter,40px)] py-[120px] max-[800px]:px-[min(20px,var(--sf-site-gutter,40px))] max-[800px]:py-[70px]",k="relative z-[2] bg-bg px-[var(--sf-site-gutter,40px)] pt-0 pb-[120px] max-[800px]:px-[min(20px,var(--sf-site-gutter,40px))] max-[800px]:pt-0 max-[800px]:pb-[70px]";function L({num:t,title:r,link:a,items:_,defaultOpen:b=!0,editing:s=!1,omitHead:u=!1,nodeId:w,partStyles:p}){const l=(_??[]).filter(n=>(n.question??"").trim()!==""),N=s&&l.length===0;if(l.length===0&&!s)return null;const f=N?[{question:o("Add your first question"),answer:o("Write the answer here.")},{question:o("Add another question"),answer:o("Write the answer here.")}]:l,g=f.filter(n=>(n.answer??"").trim()!=="").map(n=>({"@type":"Question",name:y(n.question??""),acceptedAnswer:{"@type":"Answer",text:y(n.answer??"")}})),h=!s&&g.length>0?JSON.stringify({"@context":"https://schema.org","@type":"FAQPage",mainEntity:g}).replace(/</g,"\\u003c"):null,q=r?E(r,!0):void 0;return c("section",{className:u?k:Q,children:[e("style",{children:".faq-acc__ico{transition:transform .2s ease}details[open]>summary .faq-acc__ico{transform:rotate(45deg)}"}),h&&e("script",{type:"application/ld+json",dangerouslySetInnerHTML:{__html:h}}),u?null:e(F,{num:t!==void 0?i(t):void 0,title:q,link:a?{text:i(a.text),href:a.href}:void 0,accent:!0}),e(j,{editing:s,nodeId:w,children:e("div",{children:f.map((n,m)=>c("details",{open:m===0&&b,className:"border-b border-line",children:[c("summary",{className:"flex cursor-pointer list-none items-center gap-6 py-7 [&::-webkit-details-marker]:hidden max-[800px]:gap-4 max-[800px]:py-5",children:[e("span",{className:"font-mono text-[length:var(--size-label,14px)] tracking-[0.2em] text-accent",...x(s,"number"),style:d(p,"number"),children:String(m+1).padStart(2,"0")}),e("span",{className:"flex-1 font-display text-[length:var(--size-body,18px)] font-medium uppercase tracking-[0.02em] text-fg max-[800px]:text-[length:var(--size-body,15px)]",...x(s,"question"),style:d(p,"question"),children:i(n.question??"")}),e("span",{"aria-hidden":!0,className:"faq-acc__ico shrink-0 text-[length:var(--size-body,22px)] leading-none text-fg-dim",children:"+"})]}),n.answer&&e("div",{className:"pb-8 pl-11 pr-8 max-[800px]:pl-0 max-[800px]:pr-0",children:e("p",{className:"max-w-[760px] text-[length:var(--size-body,15px)] leading-[1.7] text-fg-dim",...x(s,"answer"),style:d(p,"answer"),children:i(n.answer)})})]},m))})})]})}export{L as default};
|
package/dist/components/Flex.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as s,jsxs as
|
|
1
|
+
import{jsx as s,jsxs as T,Fragment as X}from"react/jsx-runtime";import K from"./BoxTabs.js";import U from"./SiteGutterFrame.js";import{BoxSurfaceProvider as Y}from"./BoxSurfaceContext.js";import{useInSiteHeader as q}from"./PhoneMenuTools.js";import{FRAME_BASE as J,FRAME_GUTTER as Q}from"./BlockFrame.js";import{containerGapProps as V}from"../lib/content/container-gap.js";import{boxLayoutClasses as Z,boxBlockSpacingClass as ee,boxPhoneRowClasses as se,boxShareClasses as oe,boxWrapClass as re}from"../lib/content/box-layout.js";import{BOX_CARD_PAD as e,BOX_OWNS_SIDES_CLASS as te,boxDarkenStyle as ae,boxPlacementClasses as ne,CARD_SHADOW_CLASS as le,isBackgroundBox as ie}from"../lib/content/box-background.js";import{sectionPadAttrs as me}from"../lib/content/section-padding.js";import{ON_MEDIA_INK_STYLE as ce}from"../lib/content/ink.js";function fe({direction:r,label:k,gap:E,justify:g,align:v,wrap:P,share:w,phoneRow:B,blockSpacing:D,bgImage:i,darken:F,darkenStyle:j,placement:O,padTop:m,padBottom:c,padTopPhone:f,padBottomPhone:u,padLeft:d,padRight:b,padLeftPhone:p,padRightPhone:y,contained:H=!0,fillHeight:I=!1,content:L}){const t=ie(i),x=q(),S=[oe(w),ee(D)].filter(Boolean).join(" "),R=S?` ${S}`:"",$=["flex",r==="row"?`flex-row ${se(B)}`:"flex-col",re(P),t?ne(O??"center",r):Z(g,v)].join(" ")+R,o=I||t?" h-full":"",C=t||x?"":" py-6",z=`${J}${C} ${Q}${o}`,G=x?o.trim():`w-full${C}${o}`,a=V("Flex",E,r==="row"?"inline":"block"),_=s(L,{className:`${$}${a.className}${o}`,style:a.style,minEmptyHeight:120}),h=r==="tabs"?s(K,{className:`${$}${a.className}${o}`,style:a.style,children:_}):_,M=k?.trim()||void 0,A=W=>s(U,{contained:H,framedClass:z,fillClass:G,tabLabel:M,children:W});if(!t)return A(h);const n=ae(F,j),l=me(typeof m=="number"?m:e.desktop,typeof c=="number"?c:e.desktop,typeof f=="number"?f:e.phone,typeof u=="number"?u:e.phone,typeof d=="number"?d:e.side,typeof b=="number"?b:e.side,typeof p=="number"?p:e.sidePhone,typeof y=="number"?y:e.sidePhone),N=s("div",{className:`relative z-[1] ${te} ${l?.className??""}`.trimEnd(),style:n?{...l?.style,...ce}:l?.style,children:h});return A(s(X,{children:T("div",{className:`relative isolate overflow-hidden ${le}${o}`,style:{backgroundImage:`url(${i})`,backgroundSize:"cover",backgroundPosition:"center"},children:[n&&s("div",{className:"absolute inset-0 z-0",style:n,"aria-hidden":!0}),n?s(Y,{children:N}):N]})}))}export{fe as default};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use client";import{jsx as r,Fragment as nt,jsxs as w}from"react/jsx-runtime";import{useEffect as S,useRef as f,useState as P}from"react";import{MAP_PALETTE as Q,mapBackgroundFor as F,mapMarkerColorFor as U,mapPaletteFor as H,mapStylesFor as X,watchMapTheme as rt}from"../lib/map-styles.js";import{hasMapCoords as J,loadGoogleMaps as ot}from"../lib/maps-loader.js";import{resolveMapId as at,resolveMapsKey as st,useSiteMapId as lt,useSiteMapsKey as it}from"../lib/maps-config.js";import{bucketByGroup as ct,groupColsClass as pt}from"../lib/locations-grid.js";import ut from"./EditorialSectionHead.js";import{LocationGroupHeader as dt}from"./LocationGroupHeader.js";import{renderGold as mt,renderHeadline as ft}from"./goldPhrases.js";import gt from"./PartStyledText.js";const
|
|
1
|
+
"use client";import{jsx as r,Fragment as nt,jsxs as w}from"react/jsx-runtime";import{useEffect as S,useRef as f,useState as P}from"react";import{MAP_PALETTE as Q,mapBackgroundFor as F,mapMarkerColorFor as U,mapPaletteFor as H,mapStylesFor as X,watchMapTheme as rt}from"../lib/map-styles.js";import{hasMapCoords as J,loadGoogleMaps as ot}from"../lib/maps-loader.js";import{resolveMapId as at,resolveMapsKey as st,useSiteMapId as lt,useSiteMapsKey as it}from"../lib/maps-config.js";import{bucketByGroup as ct,groupColsClass as pt}from"../lib/locations-grid.js";import ut from"./EditorialSectionHead.js";import{LocationGroupHeader as dt}from"./LocationGroupHeader.js";import{renderGold as mt,renderHeadline as ft}from"./goldPhrases.js";import gt from"./PartStyledText.js";import{say as xt}from"../lib/editor-words.js";const bt=11,yt=6,q=60;function G(t){return t.replace(/[&<>"']/g,o=>o==="&"?"&":o==="<"?"<":o===">"?">":o==='"'?""":"'")}function V(t,o,u){return{path:o.SymbolPath.CIRCLE,scale:t.hq?bt:yt,fillColor:U(u),fillOpacity:1,strokeColor:U(u),strokeOpacity:t.hq?.3:.25,strokeWeight:t.hq?14:9}}function Y(t,o,u,e,l,M){l.forEach(a=>a.setMap(null)),l.clear();const g=new o.LatLngBounds;return e.forEach((a,x)=>{if(!J(a.lat,a.lng))return;g.extend({lat:a.lat,lng:a.lng});const m=new o.Marker({map:t,position:{lat:a.lat,lng:a.lng},icon:V(a,o,u),title:a.city,zIndex:a.hq?100:10,cursor:"pointer"});m.addListener("click",()=>M(x)),l.set(x,m)}),g}function vt(t){return`
|
|
2
2
|
.footprint-map .gm-style { font-family: var(--font-role-label), var(--font-mono-fallback) !important; }
|
|
3
3
|
.footprint-map .gm-style .gm-style-iw-c {
|
|
4
4
|
background: ${t.bg} !important;
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
.footprint-map .gm-style button[aria-label="Close"] > span {
|
|
17
17
|
background-color: ${t.closeX} !important;
|
|
18
18
|
}
|
|
19
|
-
`}function T({pal:t}){const o=t?t.marker:"var(--accent)",u=t?t.info.bg:"var(--site-surface)",e=t?t.background:"var(--bg)",l=t?`color-mix(in oklab, ${t.info.fgDim} 12%, transparent)`:"color-mix(in oklab, var(--fg) 3%, transparent)";return w(nt,{children:[r("div",{className:"pointer-events-none absolute inset-0",style:{backgroundImage:`radial-gradient(60% 70% at 50% 50%, color-mix(in oklab, ${o} 8%, ${u}) 0%, ${u} 60%, ${e} 100%)`}}),r("div",{className:"pointer-events-none absolute inset-0",style:{backgroundImage:`repeating-linear-gradient(0deg, transparent 0 22px, ${l} 22px 23px), repeating-linear-gradient(90deg, transparent 0 22px, ${l} 22px 23px)`}})]})}function
|
|
19
|
+
`}function T({pal:t}){const o=t?t.marker:"var(--accent)",u=t?t.info.bg:"var(--site-surface)",e=t?t.background:"var(--bg)",l=t?`color-mix(in oklab, ${t.info.fgDim} 12%, transparent)`:"color-mix(in oklab, var(--fg) 3%, transparent)";return w(nt,{children:[r("div",{className:"pointer-events-none absolute inset-0",style:{backgroundImage:`radial-gradient(60% 70% at 50% 50%, color-mix(in oklab, ${o} 8%, ${u}) 0%, ${u} 60%, ${e} 100%)`}}),r("div",{className:"pointer-events-none absolute inset-0",style:{backgroundImage:`repeating-linear-gradient(0deg, transparent 0 22px, ${l} 22px 23px), repeating-linear-gradient(90deg, transparent 0 22px, ${l} 22px 23px)`}})]})}function ht({sectionNumber:t="",heading:o="",tagline:u="",offices:e=[],apiKey:l="",mapId:M="",mapTheme:g="auto",padTop:a,padBottom:x,editing:m,omitHead:$=!1}){const L=typeof a=="number"?a:120,z=typeof x=="number"?x:120,[b,h]=P(null),v=e.length===0&&!t&&!o&&!u;if(S(()=>{h(n=>n!==null&&n>=e.length?null:n)},[e]),v&&!m)return null;const N=ct(e,n=>String(n.group??""),()=>"");return r("section",{className:"relative z-[2] bg-bg",children:w("div",{className:"mx-auto max-w-[var(--sf-site-width,1600px)] border-b border-line px-[var(--sf-site-gutter,40px)] max-[1100px]:px-[min(24px,var(--sf-site-gutter,40px))] max-[800px]:px-[min(20px,var(--sf-site-gutter,40px))]",style:{paddingTop:L,paddingBottom:z},children:[!$&&(t||o||u)&&r(ut,{num:t,title:o?ft(o):void 0,desc:u||void 0,spaceBelow:"mb-12"}),r(kt,{offices:e,apiKey:l,mapId:M,mapTheme:g,activeIndex:b,onSelect:h}),e.length>0&&r("div",{className:"mt-12 flex flex-col gap-8",children:N.map((n,C)=>w("div",{children:[n.key&&r(dt,{groupKey:n.key,count:n.items.length}),r("div",{className:["grid gap-[2px] bg-bg",pt(n.items.length),n.items.length>2?"max-[1100px]:grid-cols-2 max-[700px]:grid-cols-1":n.items.length===2?"max-[700px]:grid-cols-1":""].join(" "),children:n.items.map(({item:i,index:k})=>{const A=b===k;return w("button",{type:"button",onClick:()=>h(k),"aria-pressed":A,className:["flex flex-col gap-1.5 bg-bg px-6 py-5 text-left transition-colors outline outline-1 -outline-offset-1",A?"outline-accent":"outline-transparent hover:outline-line"].join(" "),children:[w("span",{className:"flex items-center gap-2.5 font-mono text-[length:var(--size-label,11px)] uppercase tracking-[0.28em]",children:[i.hq&&r("span",{className:"border border-accent bg-accent px-1.5 py-0.5 text-[length:var(--size-body,10px)] text-bg",children:"HQ"}),i.role&&r("span",{className:"text-accent",children:i.role})]}),i.city&&r("span",{className:"font-display text-[length:var(--size-body,18px)] font-medium leading-[1.2] tracking-[-0.01em] text-fg",children:r(gt,{value:i.city,children:i.city})}),i.country&&r("span",{className:"font-mono text-[length:var(--size-label,11px)] uppercase tracking-[0.2em] text-fg-dim",children:i.country}),i.address&&r("span",{className:"font-mono text-[length:var(--size-label,11px)] uppercase tracking-[0.2em] text-fg-dim",children:mt(i.address)})]},k)})})]},n.key?`g:${n.key}`:`ungrouped:${C}`))}),e.length===0&&m&&r("p",{className:"mt-8 font-mono text-[length:var(--size-label,12px)] uppercase tracking-[0.24em] text-fg-dim",children:xt("Add an office in the inspector")})]})})}function kt({offices:t,apiKey:o,mapId:u,mapTheme:e,activeIndex:l,onSelect:M}){const g=st(o,it()),a=at(u,lt()),x=!!g&&t.some(c=>J(c.lat,c.lng)),m=e!=="auto",$=H(e),L=f(null),z=f(null),b=f(null),h=f(null),v=f(new Map),N=f(null),n=f(null),C=f(null),i=f(M);i.current=M;const k=f(t);k.current=t;const A=f(l);A.current=l;const[_,D]=P(!1),[j,K]=P(Q.dark),[tt,W]=P(Q.dark.background);return S(()=>{K(H(e)),W(F(e))},[e]),S(()=>{if(!x)return;const c=L.current;if(!c)return;let d=!1,p=null;const I=async()=>{try{const s=await ot(g);if(d||!z.current)return;const y=new s.Map(z.current,{center:{lat:25,lng:0},zoom:2,minZoom:1,maxZoom:5,disableDefaultUI:!0,gestureHandling:"cooperative",keyboardShortcuts:!1,clickableIcons:!1,backgroundColor:F(e),...a?{mapId:a}:{styles:X(e)}});b.current=y,h.current=s;const R=Y(y,s,e,k.current,v.current,B=>i.current(B));n.current=R,R.isEmpty()||y.fitBounds(R,q);const O=new s.InfoWindow({disableAutoPan:!0});O.addListener("closeclick",()=>i.current(null)),N.current=O,y.addListener("click",()=>i.current(null)),y.addListener("tilesloaded",()=>{d||D(!0)}),e==="auto"&&!a&&(p=rt(()=>{d||!b.current||(b.current.setOptions({styles:X(e),backgroundColor:F(e)}),v.current.forEach((B,et)=>{const Z=k.current[et];Z&&B.setIcon(V(Z,s,e))}),K(H(e)),W(F(e)))}))}catch(s){console.error("[FootprintMap] Maps SDK failed:",s)}},E=new IntersectionObserver(s=>{for(const y of s)if(y.isIntersecting){E.disconnect(),I();break}},{rootMargin:"200px"});return E.observe(c),()=>{d=!0,E.disconnect(),p?.(),N.current?.close(),N.current=null,b.current=null,h.current=null,v.current.forEach(s=>s.setMap(null)),v.current.clear(),n.current=null,D(!1)}},[x,g,a,e]),S(()=>{const c=b.current,d=h.current;if(!c||!d)return;const p=Y(c,d,e,t,v.current,I=>i.current(I));n.current=p,A.current===null&&!p.isEmpty()&&c.fitBounds(p,q)},[t,e]),S(()=>{const c=b.current,d=N.current;if(!c||!d)return;if(l===null){d.close(),C.current!==null&&n.current&&!n.current.isEmpty()&&c.fitBounds(n.current,q),C.current=null;return}const p=t[l],I=v.current.get(l);if(!p||!I){d.close(),C.current=l;return}c.panTo({lat:p.lat,lng:p.lng});const E=c.getZoom();E!=null&&E<4&&c.setZoom(4);const s=j.info,y=p.hq?`<span style="background:${s.accent};color:${s.bg};padding:1px 6px;font-size:10px;letter-spacing:0.18em;">HQ</span>`:"",R=p.role?`<span style="color:${s.accent};">${G(p.role)}</span>`:"";d.setContent(`
|
|
20
20
|
<div style="padding:10px 14px 12px;min-width:180px;color:${s.fg};">
|
|
21
21
|
<div style="display:flex;align-items:center;gap:8px;font-family:var(--font-role-label),var(--font-mono-fallback);font-size:11px;letter-spacing:0.28em;text-transform:uppercase;">
|
|
22
22
|
${y}${R}
|
|
@@ -24,4 +24,4 @@
|
|
|
24
24
|
<div style="font-family:var(--font-display),Georgia,serif;font-size:20px;font-weight:500;line-height:1.2;margin-top:6px;color:${s.fg};">${G(p.city)}</div>
|
|
25
25
|
<div style="font-family:var(--font-role-label),var(--font-mono-fallback);font-size:11px;letter-spacing:0.2em;text-transform:uppercase;color:${s.fgDim};margin-top:4px;">${G(p.country)}</div>
|
|
26
26
|
</div>
|
|
27
|
-
`),d.open({map:c,anchor:I}),C.current=l},[l,_,j,t]),x?w("div",{ref:L,className:"sf-card footprint-map relative aspect-[16/9] w-full overflow-hidden border border-line max-[720px]:aspect-[4/5]",style:{backgroundColor:tt},children:[r("style",{dangerouslySetInnerHTML:{__html:
|
|
27
|
+
`),d.open({map:c,anchor:I}),C.current=l},[l,_,j,t]),x?w("div",{ref:L,className:"sf-card footprint-map relative aspect-[16/9] w-full overflow-hidden border border-line max-[720px]:aspect-[4/5]",style:{backgroundColor:tt},children:[r("style",{dangerouslySetInnerHTML:{__html:vt(j.info)}}),r(T,{pal:m?$:void 0}),r("div",{ref:z,className:"gmap-canvas absolute inset-0 transition-opacity duration-500",style:{opacity:_?1:0}}),r("div",{className:["pointer-events-none absolute inset-0 flex items-center justify-center font-mono text-[length:var(--size-label,12px)] uppercase tracking-[0.24em] text-fg-dim transition-opacity duration-500",_?"opacity-0":"opacity-100"].join(" "),children:"Loading map…"})]}):w("div",{className:["relative aspect-[16/9] w-full overflow-hidden border border-line max-[720px]:aspect-[4/5]",m?"":"bg-bg"].join(" "),style:m?{backgroundColor:$.background}:void 0,children:[r(T,{pal:m?$:void 0}),r("div",{className:["absolute inset-0 flex items-center justify-center px-6 text-center font-mono text-[length:var(--size-label,12px)] uppercase tracking-[0.24em]",m?"":"text-fg-dim"].join(" "),style:m?{color:$.info.fgDim}:void 0,children:g?"Add office coordinates to plot the map":"Add a Google Maps API key to show the map"})]})}export{ht as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as
|
|
1
|
+
"use client";import{jsx as l}from"react/jsx-runtime";import{SettingsDefaultReset as h,SettingsField as g,SettingsSegmented as p}from"efficient-easel/panel";import{say as e,editorEaselWords as c}from"../lib/editor-words.js";import{WIDTH_CHOICE_LABEL as d}from"../lib/content/section-width.js";import{ImageIcon as m}from"efficient-easel/icons";const o="Hero image",i=[{followsWidth:!1,label:d.full},{followsWidth:!0,label:d.page}],u="Whether the big picture at the top of a page runs edge to edge, or sits inside the page width. The words follow the page width either way.";function w({value:a,onChange:n,showHint:f=!0}){const s=a===null,r=a??!1;return l(g,{label:e(o),icon:l(m,{}),value:e(i.find(t=>t.followsWidth===r).label),changed:!s,action:l(h,{words:c()?.panel,label:e(o),changed:!s,detail:e(i.find(t=>!t.followsWidth).label),onReset:()=>n(null)}),hint:f?e(u):void 0,children:l(p,{options:i.map(t=>({id:t.followsWidth,label:e(t.label)})),value:r,ariaLabel:e(o),onChange:n})})}export{o as HERO_IMAGE_LABEL,w as default};
|