create-grist-widget 0.2.18 → 0.2.19
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/bin/create-grist-widget.mjs +15 -0
- package/package.json +1 -1
- package/template/README.md +17 -13
- package/template/scripts/deploy.mjs +19 -2
- package/template/src/components/channel-notice.tsx +3 -0
- package/template/src/components/scaffold-footer.tsx +17 -0
- package/template/src/components/template-landing.tsx +3 -0
- package/template/src/vite-env.d.ts +6 -0
- package/template/vite.config.ts +9 -0
|
@@ -50,6 +50,21 @@ for (const [file, subs] of edits) {
|
|
|
50
50
|
writeFileSync(p, content)
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
// Record which create-grist-widget release produced this scaffold -- purely
|
|
54
|
+
// informational (shown in a small landing-page footer), never read by the
|
|
55
|
+
// deploy pipeline's own version/release logic. Every scaffold gets this,
|
|
56
|
+
// including the ones the template-canary workflow generates for its `dev`
|
|
57
|
+
// and `canary/latest` branches -- so it survives even if that content is
|
|
58
|
+
// later promoted into a reference repo's `main` and copied again via
|
|
59
|
+
// GitHub's "Use this template".
|
|
60
|
+
const cliPkg = JSON.parse(
|
|
61
|
+
readFileSync(path.join(path.dirname(fileURLToPath(import.meta.url)), "..", "package.json"), "utf8"),
|
|
62
|
+
)
|
|
63
|
+
const pkgJsonPath = path.join(target, "package.json")
|
|
64
|
+
const pkgJson = JSON.parse(readFileSync(pkgJsonPath, "utf8"))
|
|
65
|
+
pkgJson.createGristWidgetVersion = cliPkg.version
|
|
66
|
+
writeFileSync(pkgJsonPath, JSON.stringify(pkgJson, null, 2) + "\n")
|
|
67
|
+
|
|
53
68
|
// Initialize git on `main` with the scaffold as its first commit, and a
|
|
54
69
|
// `dev` branch ready to push for live-preview later. Doing this here (not
|
|
55
70
|
// leaving it to whoever/whatever runs next) is what actually prevents the
|
package/package.json
CHANGED
package/template/README.md
CHANGED
|
@@ -4,7 +4,7 @@ Base template to build a Grist widget with `grist-widget-sdk`.
|
|
|
4
4
|
|
|
5
5
|
`src/main.tsx` wraps the app with `GristWidgetProvider`, `GristBoundary`, and `GristSdkAlerts`. The latter maps `getGristSdkAlertDescriptors()` from the SDK to shadcn `Alert` (`src/components/grist-sdk-alerts.tsx` + `src/components/ui/alert.tsx`); keep them in sync with the playground when you change alert styling.
|
|
6
6
|
|
|
7
|
-
Opened outside a Grist iframe, `main.tsx` picks between two components purely by URL shape (`src/lib/showcase-routing.ts`, no router needed): a bare path with no recognized channel suffix renders `TemplateLanding` (its own hero, onboarding, and released-version index); `/latest/`, `/dev/`, or `/v<version>/` renders `ChannelNotice` instead — a distinct hero explaining which build this is, chips to jump to any other version/channel (`src/lib/showcase-versions.ts`), and a copy-this-URL helper for pasting into Grist's custom widget field.
|
|
7
|
+
Opened outside a Grist iframe, `main.tsx` picks between two components purely by URL shape (`src/lib/showcase-routing.ts`, no router needed): a bare path with no recognized channel suffix renders `TemplateLanding` (its own hero, onboarding, and released-version index); `/latest/`, `/dev/`, or `/v<version>/` renders `ChannelNotice` instead — a distinct hero explaining which build this is, chips to jump to any other version/channel (`src/lib/showcase-versions.ts`), and a copy-this-URL helper for pasting into Grist's custom widget field. Both render `ScaffoldFooter` (`src/components/scaffold-footer.tsx`) at the bottom — a small, purely informational note ("Scaffolded from `create-grist-widget@X.Y.Z`") built from `package.json`'s `createGristWidgetVersion` field, which the CLI stamps on every real scaffold (`vite.config.ts` injects it as `__CREATE_GRIST_WIDGET_VERSION__`). Renders nothing if that field is absent, e.g. this pristine template source itself.
|
|
8
8
|
|
|
9
9
|
When actually embedded, `GristStatusChip` (`src/components/grist-status-chip.tsx`) shows a small pill with live handshake status — connecting, retrying with a countdown, connected, or unavailable — using `useAmbientGristHandshake()` from `grist-widget-sdk/advanced`. It must be mounted *inside* `GristWidgetProvider` (see `src/main.tsx`): it only observes that provider's own handshake manager and never mounts a second one, so it's purely observational and can never duplicate or race the real handshake (see `apps/docs/api/handshake.md`).
|
|
10
10
|
|
|
@@ -89,18 +89,22 @@ automatically.
|
|
|
89
89
|
> ⚠️ **Used GitHub's "Use this template" button instead of `npm create
|
|
90
90
|
> grist-widget`?** That path copies this repo's default branch verbatim —
|
|
91
91
|
> it doesn't run any of the CLI's own setup (renaming `package.json`,
|
|
92
|
-
> titles, etc.), and
|
|
93
|
-
>
|
|
94
|
-
>
|
|
95
|
-
>
|
|
96
|
-
>
|
|
97
|
-
>
|
|
98
|
-
>
|
|
99
|
-
> `
|
|
100
|
-
>
|
|
101
|
-
>
|
|
102
|
-
>
|
|
103
|
-
>
|
|
92
|
+
> titles, etc.), and whatever version happens to be checked into the
|
|
93
|
+
> source repo's `package.json` (which can be well past `0.0.1` — see below)
|
|
94
|
+
> comes along with it. You don't need to reset it by hand: your first real
|
|
95
|
+
> release always resolves to `v0.0.1` regardless of what `package.json`
|
|
96
|
+
> says, and that value stays untouched in the file — only the deploy
|
|
97
|
+
> pipeline's own idea of "which version is this" is overridden, once, for
|
|
98
|
+
> that first release. If you also checked **"Include all branches"** (to
|
|
99
|
+
> get `gh-pages`/Pages already set up, no manual Settings step), your first
|
|
100
|
+
> real release also automatically clears out every leftover `v<version>/`
|
|
101
|
+
> it finds — a `v<version>/` only counts as a genuine prior release once it
|
|
102
|
+
> carries a `showcase-meta.json` naming *this* repo (written by this
|
|
103
|
+
> pipeline's own `place` step), so on a repo with no genuine releases yet,
|
|
104
|
+
> everything else is provably inherited noise and gets safely wiped on your
|
|
105
|
+
> first push to `main`. Both of these only ever apply before your *first*
|
|
106
|
+
> genuine release — once one exists, they're permanently a no-op, so it's
|
|
107
|
+
> still safest to never manually re-seed `gh-pages` again after that point.
|
|
104
108
|
|
|
105
109
|
**One-time setup** (the workflow can't do this part for you):
|
|
106
110
|
|
|
@@ -80,6 +80,16 @@ function isGenuineRelease(versionDir, repo) {
|
|
|
80
80
|
}
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
/**
|
|
84
|
+
* Whether this repo has ever genuinely published a release (a v<version>/
|
|
85
|
+
* dir whose showcase-meta.json names this repo). Shared by `plan()` (forces
|
|
86
|
+
* the first release to 0.0.1) and `cleanupForeignVersionsIfFirstRelease()`
|
|
87
|
+
* (clears inherited v<version>/ noise) -- both need the exact same signal.
|
|
88
|
+
*/
|
|
89
|
+
function hasGenuineRelease(siteDir, repo) {
|
|
90
|
+
return buildVersionsManifest(siteDir, repo).length > 0
|
|
91
|
+
}
|
|
92
|
+
|
|
83
93
|
/**
|
|
84
94
|
* Build the release/dev plan from this repo's own package.json + the current
|
|
85
95
|
* gh-pages tree. Release is skipped when its immutable v<version> dir was
|
|
@@ -92,7 +102,14 @@ export function plan(siteDir, repo, event, ref, { force = false } = {}) {
|
|
|
92
102
|
return { context: "dev", base: basePathFor(repo, "dev") }
|
|
93
103
|
}
|
|
94
104
|
const pkg = JSON.parse(readFileSync("package.json", "utf8"))
|
|
95
|
-
|
|
105
|
+
// A repo's first genuine release always starts at 0.0.1, regardless of
|
|
106
|
+
// whatever package.json's version field says -- found live: a repo copied
|
|
107
|
+
// via GitHub's "Use this template" inherited "0.2.18" from the source
|
|
108
|
+
// template repo's own main branch (itself a canary-stamped scaffold that
|
|
109
|
+
// had been promoted there), instead of starting fresh. Once a repo has a
|
|
110
|
+
// genuine release, this no longer applies -- its own version bumps are
|
|
111
|
+
// its own responsibility from then on, same as `cleanupForeignVersionsIfFirstRelease`.
|
|
112
|
+
const version = hasGenuineRelease(siteDir, repo) ? pkg.version : "0.0.1"
|
|
96
113
|
if (!version) throw new Error("package.json has no version")
|
|
97
114
|
const versionDir = join(siteDir, `v${version}`)
|
|
98
115
|
const exists = isGenuineRelease(versionDir, repo)
|
|
@@ -190,7 +207,7 @@ function replaceDir(dest, srcDist) {
|
|
|
190
207
|
* permanently a no-op.
|
|
191
208
|
*/
|
|
192
209
|
export function cleanupForeignVersionsIfFirstRelease(siteDir, repo) {
|
|
193
|
-
if (
|
|
210
|
+
if (hasGenuineRelease(siteDir, repo)) return { cleaned: [] }
|
|
194
211
|
const cleaned = []
|
|
195
212
|
for (const name of existsSync(siteDir) ? readdirSync(siteDir) : []) {
|
|
196
213
|
if (!/^v\d+\.\d+\.\d+/.test(name)) continue
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useState } from "react"
|
|
2
2
|
|
|
3
|
+
import { ScaffoldFooter } from "@/components/scaffold-footer"
|
|
3
4
|
import { Button } from "@/components/ui/button"
|
|
4
5
|
import {
|
|
5
6
|
Card,
|
|
@@ -117,6 +118,8 @@ export function ChannelNotice({
|
|
|
117
118
|
>
|
|
118
119
|
← Back to the template home
|
|
119
120
|
</a>
|
|
121
|
+
|
|
122
|
+
<ScaffoldFooter />
|
|
120
123
|
</div>
|
|
121
124
|
)
|
|
122
125
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// Shown on the showcase hub and channel pages, never inside Grist (there's
|
|
2
|
+
// no room, and it's not relevant to using the widget). Purely informational:
|
|
3
|
+
// which create-grist-widget release this repo's package.json was scaffolded
|
|
4
|
+
// from -- distinct from the repo's own `version`, which the deploy pipeline
|
|
5
|
+
// always starts fresh at 0.0.1 regardless of this value (see
|
|
6
|
+
// scripts/deploy.mjs's `plan()`). Renders nothing for the pristine template
|
|
7
|
+
// source itself, or any copy predating this field.
|
|
8
|
+
export function ScaffoldFooter() {
|
|
9
|
+
if (!__CREATE_GRIST_WIDGET_VERSION__) return null
|
|
10
|
+
|
|
11
|
+
return (
|
|
12
|
+
<p className="mt-10 text-center text-xs text-muted-foreground">
|
|
13
|
+
Scaffolded from{" "}
|
|
14
|
+
<code className="text-foreground">create-grist-widget@{__CREATE_GRIST_WIDGET_VERSION__}</code>
|
|
15
|
+
</p>
|
|
16
|
+
)
|
|
17
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useState } from "react"
|
|
2
2
|
|
|
3
|
+
import { ScaffoldFooter } from "@/components/scaffold-footer"
|
|
3
4
|
import { Button } from "@/components/ui/button"
|
|
4
5
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
|
|
5
6
|
import { devUrl, formatDate, useVersions, versionUrl } from "@/lib/showcase-versions"
|
|
@@ -301,6 +302,8 @@ git push origin dev`}</code>
|
|
|
301
302
|
</ul>
|
|
302
303
|
)}
|
|
303
304
|
</section>
|
|
305
|
+
|
|
306
|
+
<ScaffoldFooter />
|
|
304
307
|
</div>
|
|
305
308
|
)
|
|
306
309
|
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/// <reference types="vite/client" />
|
|
2
|
+
|
|
3
|
+
// Injected by vite.config.ts's `define` from package.json's
|
|
4
|
+
// createGristWidgetVersion field -- null for the pristine template source
|
|
5
|
+
// itself (that field only exists on scaffolded copies).
|
|
6
|
+
declare const __CREATE_GRIST_WIDGET_VERSION__: string | null
|
package/template/vite.config.ts
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
|
+
import { readFileSync } from "fs"
|
|
1
2
|
import path from "path"
|
|
2
3
|
import tailwindcss from "@tailwindcss/vite"
|
|
3
4
|
import react from "@vitejs/plugin-react"
|
|
4
5
|
import { defineConfig } from "vite"
|
|
5
6
|
|
|
7
|
+
// Read here (Node context) rather than importing package.json into src/ --
|
|
8
|
+
// keeps the whole file out of the bundle, exposing only the one field the
|
|
9
|
+
// landing page footer needs.
|
|
10
|
+
const pkg = JSON.parse(readFileSync(path.resolve(__dirname, "package.json"), "utf8"))
|
|
11
|
+
|
|
6
12
|
// https://vite.dev/config/
|
|
7
13
|
export default defineConfig({
|
|
8
14
|
plugins: [react(), tailwindcss()],
|
|
@@ -11,4 +17,7 @@ export default defineConfig({
|
|
|
11
17
|
"@": path.resolve(__dirname, "./src"),
|
|
12
18
|
},
|
|
13
19
|
},
|
|
20
|
+
define: {
|
|
21
|
+
__CREATE_GRIST_WIDGET_VERSION__: JSON.stringify(pkg.createGristWidgetVersion ?? null),
|
|
22
|
+
},
|
|
14
23
|
})
|