@bygghammar/cms-platform 0.77.0 → 0.79.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,3 +1,30 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@bygghammar/cms-platform`, newest first. Each `##`
4
+ heading is a published npm version; the release workflow requires a heading that
5
+ matches `package.json` exactly. See
6
+ [CONTRIBUTING.md](./CONTRIBUTING.md#changelog-conventions) for the conventions.
7
+
8
+ Versions 0.1.0 through 0.78.0 predate this repository and were reconstructed
9
+ from the published npm tarballs.
10
+
11
+ ## 0.79.0
12
+
13
+ - Search engines status card: added step-by-step help text explaining how to
14
+ block indexing (`SITE_INDEXING=off`, staging default) or allow it
15
+ (`SITE_INDEXING=on` in production), what the safe fallback is when the
16
+ variable is unset, and that blocked deployments serve `Disallow: /` plus a
17
+ `noindex, nofollow` header while true privacy still needs Traefik basic auth.
18
+ - Site settings now renders the same shared `IndexingStatusCard` as the SEO
19
+ screens instead of its own inline card, so the status and help text stay
20
+ identical in both places.
21
+
22
+ ## 0.78.0
23
+
24
+ - Countdown block: the unit tiles now always stay on a single row on mobile.
25
+ Tiles shrink to fit (with smaller mobile padding, digits, labels and gaps)
26
+ instead of wrapping; desktop sizing and all colour/layout settings unchanged.
27
+
1
28
  ## 0.77.0
2
29
 
3
30
  - Global Sections list: preview thumbnails now use the section's first block type
package/README.md CHANGED
@@ -106,29 +106,23 @@ Keep any existing registration module in the consuming application's
106
106
  `sideEffects` allowlist as defence in depth until every entry point uses the
107
107
  explicit contract. CSS must also remain in that allowlist.
108
108
 
109
- ## Publishing
109
+ ## Repository, development and releases
110
110
 
111
- This directory is the maintained source for the public npm package. Releases
112
- use npm Trusted Publishing from GitHub Actions; do not publish from a laptop or
113
- create an npm token.
111
+ The canonical source of truth is <https://github.com/byggis79/cms-platform>
112
+ (private). This repository is standalone — it is no longer a directory inside a
113
+ site repository, and it must never be copied back into a consuming site.
114
114
 
115
- 1. Merge the reviewed version bump and wait for Checks to pass on `main`.
116
- 2. Run **Actions → Publish CMS platform → Run workflow** from `main` and enter
117
- the exact version from this package.
118
- 3. Verify the new public version before updating consuming CMS lockfiles.
119
-
120
- Never place an npm token or `.npmrc` in the repository. Consumers install an
121
- explicit released version such as `@bygghammar/cms-platform@^0.1.1`.
115
+ ```bash
116
+ bun install
117
+ bun run check # typecheck + tests + package verification
118
+ ```
122
119
 
123
- ### Release checks and troubleshooting
120
+ The package ships TypeScript sources; there is no build output. Every change
121
+ goes through a pull request, and every release is triggered by pushing a
122
+ `vX.Y.Z` tag that matches `package.json`, which publishes to npm from GitHub
123
+ Actions using the repository secret `NPM_TOKEN`. Never publish manually.
124
124
 
125
- The workflow type-checks the package and runs
126
- `tests/cms-platform-host-contract.test.tsx` before requesting npm's OIDC
127
- publishing credential. Keep Vitest's include glob compatible with both
128
- `*.test.ts` and `*.test.tsx`; otherwise the release stops with “No test files
129
- found” before npm is contacted.
125
+ See [CONTRIBUTING.md](./CONTRIBUTING.md) for the full workflow and changelog
126
+ conventions. Consumers install an explicit released version such as
127
+ `@bygghammar/cms-platform@0.78.0`.
130
128
 
131
- If a release run fails, read its failed step before rerunning it. A failed run
132
- does not publish a partial package. After a successful run, verify the public
133
- registry reports the requested version, then update each consuming application
134
- and its frozen lockfile in a separate pull request.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bygghammar/cms-platform",
3
- "version": "0.77.0",
3
+ "version": "0.79.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": [
@@ -21,8 +21,7 @@
21
21
  ],
22
22
  "repository": {
23
23
  "type": "git",
24
- "url": "git+https://github.com/byggis79/devsba.git",
25
- "directory": "packages/cms-platform"
24
+ "url": "git+https://github.com/byggis79/cms-platform.git"
26
25
  },
27
26
  "exports": {
28
27
  ".": "./src/index.ts",
@@ -300,5 +299,46 @@
300
299
  "bin": {
301
300
  "cms-platform-migrations": "scripts/sync-migrations.mjs",
302
301
  "create-cms-site": "scripts/create-cms-site.mjs"
302
+ },
303
+ "homepage": "https://github.com/byggis79/cms-platform#readme",
304
+ "bugs": {
305
+ "url": "https://github.com/byggis79/cms-platform/issues"
306
+ },
307
+ "scripts": {
308
+ "typecheck": "tsc --noEmit",
309
+ "test": "vitest run",
310
+ "test:watch": "vitest",
311
+ "verify:pack": "node ops/verify-pack.mjs",
312
+ "check": "bun run typecheck && bun run test && bun run verify:pack"
313
+ },
314
+ "devDependencies": {
315
+ "@dnd-kit/core": "^6.3.1",
316
+ "@dnd-kit/sortable": "^10.0.0",
317
+ "@dnd-kit/utilities": "^3.2.2",
318
+ "@supabase/supabase-js": "^2.110.8",
319
+ "@tanstack/react-query": "^5.101.1",
320
+ "@tanstack/react-router": "1.170.18",
321
+ "@tanstack/react-start": "1.168.32",
322
+ "@tiptap/extension-highlight": "^3.29.2",
323
+ "@tiptap/extension-image": "^3.29.2",
324
+ "@tiptap/extension-subscript": "^3.29.2",
325
+ "@tiptap/extension-superscript": "^3.29.2",
326
+ "@tiptap/extension-table": "^3.29.2",
327
+ "@tiptap/extension-text-align": "^3.29.2",
328
+ "@tiptap/extension-text-style": "^3.29.2",
329
+ "@tiptap/extensions": "^3.29.2",
330
+ "@tiptap/pm": "^3.29.2",
331
+ "@tiptap/react": "^3.29.2",
332
+ "@tiptap/starter-kit": "^3.29.2",
333
+ "@types/node": "^22.10.2",
334
+ "@types/react": "19.2.17",
335
+ "@types/react-dom": "19.2.3",
336
+ "lucide-react": "^0.575.0",
337
+ "react": "^19.2.0",
338
+ "react-dom": "^19.2.0",
339
+ "sonner": "^2.0.7",
340
+ "typescript": "^5.8.3",
341
+ "vitest": "^4.1.10",
342
+ "zod": "^3.24.2"
303
343
  }
304
344
  }
@@ -33,10 +33,29 @@ export function IndexingStatusCard({
33
33
  <div className="mt-1 text-sm text-ink">{status}</div>
34
34
  <div className="mt-2 text-[11px] uppercase tracking-wider text-ink/40">{source}</div>
35
35
  <p className="mt-3 text-xs text-ink/50">
36
- Indexing is an environment fact, not a setting here: set <code>SITE_INDEXING=off</code> on
37
- staging and <code>SITE_INDEXING=on</code> in production. A blocked deployment serves{" "}
38
- <code>Disallow: /</code> in robots.txt and a <code>noindex, nofollow</code> header on every
39
- response.
36
+ Indexing is an environment fact, not a setting here — this card is read-only. It is
37
+ controlled per deployment by environment variables, so a content restore can never flip it:
38
+ </p>
39
+ <ul className="mt-2 list-disc space-y-1 pl-4 text-xs text-ink/50">
40
+ <li>
41
+ <strong className="font-medium text-ink/70">To block indexing (noindex):</strong> set{" "}
42
+ <code>SITE_INDEXING=off</code> for the environment and redeploy. Staging should always
43
+ run with this.
44
+ </li>
45
+ <li>
46
+ <strong className="font-medium text-ink/70">To allow indexing:</strong> set{" "}
47
+ <code>SITE_INDEXING=on</code> for the production environment and redeploy.
48
+ </li>
49
+ <li>
50
+ When <code>SITE_INDEXING</code> is unset, <code>SITE_ENV=production</code> means indexed
51
+ and anything else defaults to blocked.
52
+ </li>
53
+ </ul>
54
+ <p className="mt-2 text-xs text-ink/50">
55
+ A blocked deployment serves <code>Disallow: /</code> in robots.txt and a{" "}
56
+ <code>noindex, nofollow</code> header on every response, so it can never be indexed even if
57
+ a link leaks. Blocking does not hide the site from people — for truly private staging, add
58
+ HTTP basic auth in Traefik on top.
40
59
  </p>
41
60
  </div>
42
61
  );
@@ -12,6 +12,7 @@ import {
12
12
  type SiteSettingOverrides,
13
13
  } from "../config/site-config";
14
14
  import type { IndexingPolicy } from "../site/indexing";
15
+ import { IndexingStatusCard } from "./IndexingStatusCard";
15
16
 
16
17
  export type SiteSettingsDeps = {
17
18
  /** Code config with any stored overrides already applied. */
@@ -148,17 +149,6 @@ export function SiteSettingsView({ deps }: { deps: SiteSettingsDeps }) {
148
149
  originSource === "environment" ? "From SITE_URL" : "Code fallback \u2014 SITE_URL unset",
149
150
  ],
150
151
  ["Locales", config.locales.join(", "), "Set in code"],
151
- [
152
- "Search engines",
153
- indexing ? (indexing.mode === "block" ? "Blocked \u2014 not indexed" : "Indexed") : "Unknown",
154
- indexing
155
- ? indexing.source === "SITE_INDEXING"
156
- ? `From SITE_INDEXING=${indexing.value}`
157
- : indexing.source === "SITE_ENV"
158
- ? `From SITE_ENV=${indexing.value}`
159
- : "Safe default \u2014 SITE_INDEXING unset"
160
- : "Set SITE_INDEXING per environment",
161
- ],
162
152
  [
163
153
  "Backoffice",
164
154
  `${config.backofficePath} (${config.backofficeLocale})`,
@@ -171,16 +161,14 @@ export function SiteSettingsView({ deps }: { deps: SiteSettingsDeps }) {
171
161
  <dd className="mt-2 text-[11px] uppercase tracking-wider text-ink/40">{source}</dd>
172
162
  </div>
173
163
  ))}
164
+ {/* Same shared card as the SEO screens — one place for the indexing help text. */}
165
+ <IndexingStatusCard indexing={indexing} />
174
166
  </dl>
175
167
  <p className="mt-3 max-w-2xl text-xs text-ink/50">
176
168
  These are structural: the locale set and backoffice path are compiled into the build,
177
169
  and the public origin differs per environment. They are read from code and environment on
178
170
  purpose, so a deployment can never disagree with what the database says. Indexing is the
179
- same kind of fact: set <code>SITE_INDEXING=off</code> on staging and{" "}
180
- <code>SITE_INDEXING=on</code> in production. A blocked deployment serves{" "}
181
- <code>Disallow: /</code> in robots.txt and a <code>noindex, nofollow</code> header on every
182
- response, so it can never be indexed even if a link leaks. For truly private staging, add
183
- HTTP basic auth in Traefik on top — a password is the only thing that keeps humans out.
171
+ same kind of fact — see the Search engines card for how it is controlled per environment.
184
172
  </p>
185
173
 
186
174
  <section className={`mt-8 ${cardClass}`}>
@@ -10,12 +10,28 @@ import { useCountdownReplacement } from "../countdown-replacement";
10
10
  import type { CountdownProps } from "../types";
11
11
 
12
12
  const TILE_SIZE = {
13
- sm: { box: "min-w-14 px-3 py-2.5", digit: "text-2xl md:text-3xl", unit: "text-[0.55rem]" },
14
- md: { box: "min-w-20 px-4 py-3.5", digit: "text-3xl md:text-5xl", unit: "text-[0.6rem]" },
15
- lg: { box: "min-w-28 px-6 py-5", digit: "text-4xl md:text-6xl", unit: "text-[0.68rem]" },
13
+ sm: {
14
+ box: "min-w-0 flex-1 px-2 py-2 sm:min-w-14 sm:flex-none sm:px-3 sm:py-2.5",
15
+ digit: "text-xl sm:text-2xl md:text-3xl",
16
+ unit: "text-[0.5rem] sm:text-[0.55rem]",
17
+ },
18
+ md: {
19
+ box: "min-w-0 flex-1 px-2 py-2.5 sm:min-w-20 sm:flex-none sm:px-4 sm:py-3.5",
20
+ digit: "text-2xl sm:text-3xl md:text-5xl",
21
+ unit: "text-[0.5rem] sm:text-[0.6rem]",
22
+ },
23
+ lg: {
24
+ box: "min-w-0 flex-1 px-2 py-3 sm:min-w-28 sm:flex-none sm:px-6 sm:py-5",
25
+ digit: "text-2xl sm:text-4xl md:text-6xl",
26
+ unit: "text-[0.5rem] sm:text-[0.68rem]",
27
+ },
16
28
  } as const;
17
29
 
18
- const GAP = { sm: "gap-2", md: "gap-3 md:gap-4", lg: "gap-5 md:gap-7" } as const;
30
+ const GAP = {
31
+ sm: "gap-1.5 sm:gap-2",
32
+ md: "gap-1.5 sm:gap-3 md:gap-4",
33
+ lg: "gap-2 sm:gap-5 md:gap-7",
34
+ } as const;
19
35
  const PADDING = {
20
36
  compact: "py-8 md:py-10",
21
37
  normal: "py-14 md:py-20",
@@ -149,11 +165,12 @@ export function CountdownBlock({ props: p }: { props: CountdownProps }) {
149
165
  <>
150
166
  {heading(p.title, p.body)}
151
167
  <div
152
- className={`mt-8 flex flex-wrap items-stretch ${GAP[p.gap ?? "md"]} ${align.row}`}
168
+ className={`mt-8 flex w-full flex-nowrap items-stretch sm:w-auto sm:flex-wrap ${GAP[p.gap ?? "md"]} ${align.row}`}
153
169
  aria-live="off"
154
170
  >
155
171
  {units.map((u, i) => (
156
- <div key={i} className="flex items-stretch">
172
+ <div key={i} className="flex min-w-0 flex-1 items-stretch sm:flex-none">
173
+
157
174
  <div
158
175
  className={`flex flex-col items-center justify-center bg-[var(--cd-tile-bg)] ${size.box} ${border} ${shadow}`}
159
176
  style={{ borderRadius: "var(--cd-radius)" }}