@bygghammar/cms-platform 0.71.0 → 0.72.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.72.0
4
+
5
+ - `HeroFullBlock`: four new "Text colour" options for busy media — light/dark text
6
+ with an opposite-colour outline, and light/dark text with a soft shadow. The
7
+ treatment applies to the eyebrow, title and body only; buttons, overlay and
8
+ header hero detection are unchanged, and existing pages keep `light`.
9
+
3
10
  ## 0.67.0
4
11
 
5
12
  - `CabinTabsBlock`: removed the mobile right-edge arrow hint; the horizontal tab
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bygghammar/cms-platform",
3
- "version": "0.71.0",
3
+ "version": "0.72.0",
4
4
  "description": "Shared CMS platform: blocks, block types, i18n core, UI primitives and design-token contract used by every Bygghammar/Voyara site.",
5
5
  "type": "module",
6
6
  "sideEffects": [
@@ -943,6 +943,10 @@ function HeroFullInspector({ block, patch }: BlockPatchProps) {
943
943
  {sel("Text colour", "textTone", p.textTone ?? "light", [
944
944
  { value: "light", label: "Light text (dark media)" },
945
945
  { value: "dark", label: "Dark text (light media)" },
946
+ { value: "light-shadow", label: "Light text + soft shadow (best on photos)" },
947
+ { value: "dark-shadow", label: "Dark text + soft light shadow" },
948
+ { value: "light-outline", label: "Light text with dark outline" },
949
+ { value: "dark-outline", label: "Dark text with light outline" },
946
950
  ])}
947
951
  {sel("Title size", "titleSize", p.titleSize ?? "lg", [
948
952
  { value: "sm", label: "Small" },
@@ -45,7 +45,26 @@ export function HeroFullBlock({ props: p }: { props: HeroFullProps }) {
45
45
 
46
46
  const align = p.textAlign ?? "left";
47
47
  const vertical = p.verticalAlign ?? "center";
48
- const dark = (p.textTone ?? "light") === "light";
48
+ const tone = p.textTone ?? "light";
49
+ const dark = tone.startsWith("light");
50
+ // Legibility treatment for text sitting on detailed photos or video: an
51
+ // opposite-colour outline, or a soft shadow that keeps the typography clean.
52
+ const legibility = tone.endsWith("-outline")
53
+ ? ({
54
+ paintOrder: "stroke fill",
55
+ WebkitTextStrokeWidth: "0.045em",
56
+ WebkitTextStrokeColor: dark ? "#000" : "#fff",
57
+ textShadow: dark
58
+ ? "0 0 2px rgba(0,0,0,0.9)"
59
+ : "0 0 2px rgba(255,255,255,0.9)",
60
+ } as const)
61
+ : tone.endsWith("-shadow")
62
+ ? ({
63
+ textShadow: dark
64
+ ? "0 1px 2px rgba(0,0,0,0.55), 0 4px 18px rgba(0,0,0,0.45)"
65
+ : "0 1px 2px rgba(255,255,255,0.7), 0 4px 18px rgba(255,255,255,0.6)",
66
+ } as const)
67
+ : undefined;
49
68
  const mediaType = p.mediaType ?? "image";
50
69
 
51
70
  const image = p.image;
@@ -163,12 +182,16 @@ export function HeroFullBlock({ props: p }: { props: HeroFullProps }) {
163
182
  <div className={`flex w-full ${rowClass}`}>
164
183
  <div className={`flex w-full flex-col ${alignClass} ${WIDTHS[p.contentWidth ?? "normal"]} ${textColor}`}>
165
184
  {p.eyebrow ? (
166
- <span className={`text-[0.65rem] uppercase tracking-[0.3em] md:text-[0.72rem] ${eyebrowColor}`}>
185
+ <span
186
+ style={legibility}
187
+ className={`text-[0.65rem] uppercase tracking-[0.3em] md:text-[0.72rem] ${eyebrowColor}`}
188
+ >
167
189
  {t(p.eyebrow)}
168
190
  </span>
169
191
  ) : null}
170
192
  {p.title ? (
171
193
  <h1
194
+ style={legibility}
172
195
  className={`mt-4 ${TITLE_SIZES[p.titleSize ?? "lg"]} leading-[1.02] tracking-[-0.02em] ${
173
196
  (p.titleFont ?? "serif") === "serif" ? "font-serif" : "font-sans font-semibold"
174
197
  } ${p.titleUppercase ? "uppercase tracking-[0.04em]" : ""} whitespace-pre-line`}
@@ -177,7 +200,7 @@ export function HeroFullBlock({ props: p }: { props: HeroFullProps }) {
177
200
  </h1>
178
201
  ) : null}
179
202
  {p.body ? (
180
- <p className={`mt-5 whitespace-pre-line text-base leading-relaxed md:text-lg ${mutedColor} ${WIDTHS[p.contentWidth ?? "normal"] === "max-w-none" ? "" : ""}`}>
203
+ <p style={legibility} className={`mt-5 whitespace-pre-line text-base leading-relaxed md:text-lg ${mutedColor} ${WIDTHS[p.contentWidth ?? "normal"] === "max-w-none" ? "" : ""}`}>
181
204
  {t(p.body)}
182
205
  </p>
183
206
  ) : null}
@@ -173,7 +173,17 @@ export type HeroFullProps = {
173
173
  overlay?: "none" | "light" | "medium" | "strong" | "bottom" | "top" | "side";
174
174
  textAlign?: "left" | "center" | "right";
175
175
  verticalAlign?: "top" | "center" | "bottom";
176
- textTone?: "light" | "dark";
176
+ /**
177
+ * Text colour and legibility treatment. The `light`/`dark` prefix decides the
178
+ * text colour; the suffix adds an outline or soft shadow for busy media.
179
+ */
180
+ textTone?:
181
+ | "light"
182
+ | "dark"
183
+ | "light-outline"
184
+ | "dark-outline"
185
+ | "light-shadow"
186
+ | "dark-shadow";
177
187
  contentWidth?: "narrow" | "normal" | "wide" | "full";
178
188
  titleSize?: "sm" | "md" | "lg" | "xl";
179
189
  titleFont?: "serif" | "sans";