create-grist-widget 0.2.5 → 0.2.7
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/package.json
CHANGED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { useEffect, useState } from "react"
|
|
2
|
+
|
|
3
|
+
import { Button } from "@/components/ui/button"
|
|
4
|
+
|
|
5
|
+
// Shown instead of the widget tree when this page is opened directly in a
|
|
6
|
+
// browser tab (not embedded in a Grist iframe) -- i.e. exactly the situation
|
|
7
|
+
// anyone visiting a deployed /latest/, /v<version>/, or /dev/ URL directly is
|
|
8
|
+
// in, whether that's this monorepo's own showcase deploy or a real scaffolded
|
|
9
|
+
// widget someone hasn't customized yet. Same component either way; the only
|
|
10
|
+
// per-deploy difference is which /v<version>/ dirs actually exist upstream,
|
|
11
|
+
// which is why the version list is fetched from a fixed absolute URL rather
|
|
12
|
+
// than a path relative to wherever this happens to be deployed.
|
|
13
|
+
const VERSIONS_URL =
|
|
14
|
+
"https://arthurblanchon.github.io/grist-widget-sdk/template/versions.json"
|
|
15
|
+
|
|
16
|
+
type ReleasedVersion = {
|
|
17
|
+
version: string
|
|
18
|
+
publishedAt: string
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function useVersions() {
|
|
22
|
+
const [versions, setVersions] = useState<ReleasedVersion[] | null>(null)
|
|
23
|
+
const [error, setError] = useState(false)
|
|
24
|
+
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
let cancelled = false
|
|
27
|
+
fetch(VERSIONS_URL, { cache: "no-store" })
|
|
28
|
+
.then((res) => (res.ok ? res.json() : Promise.reject(res)))
|
|
29
|
+
.then((data: ReleasedVersion[]) => {
|
|
30
|
+
if (!cancelled) setVersions(data)
|
|
31
|
+
})
|
|
32
|
+
.catch(() => {
|
|
33
|
+
if (!cancelled) setError(true)
|
|
34
|
+
})
|
|
35
|
+
return () => {
|
|
36
|
+
cancelled = true
|
|
37
|
+
}
|
|
38
|
+
}, [])
|
|
39
|
+
|
|
40
|
+
return { versions, error }
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function formatDate(iso: string) {
|
|
44
|
+
return new Date(iso).toLocaleDateString(undefined, {
|
|
45
|
+
year: "numeric",
|
|
46
|
+
month: "short",
|
|
47
|
+
day: "numeric",
|
|
48
|
+
})
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function TemplateLanding() {
|
|
52
|
+
const { versions, error } = useVersions()
|
|
53
|
+
|
|
54
|
+
return (
|
|
55
|
+
<div className="mx-auto max-w-2xl px-6 py-16">
|
|
56
|
+
<header className="mb-10 text-center">
|
|
57
|
+
<p className="mb-2 text-sm font-medium text-muted-foreground">
|
|
58
|
+
grist-widget-template
|
|
59
|
+
</p>
|
|
60
|
+
<h1 className="font-heading text-3xl font-semibold tracking-tight">
|
|
61
|
+
Grist isn't loaded here
|
|
62
|
+
</h1>
|
|
63
|
+
<p className="mx-auto mt-3 max-w-md text-sm text-muted-foreground">
|
|
64
|
+
This page only renders inside a Grist custom widget iframe. Paste
|
|
65
|
+
its URL into Grist's custom widget field, or read on to scaffold
|
|
66
|
+
your own copy.
|
|
67
|
+
</p>
|
|
68
|
+
</header>
|
|
69
|
+
|
|
70
|
+
<div className="mb-10 rounded-lg border p-4">
|
|
71
|
+
<h2 className="mb-3 font-heading text-base font-semibold">
|
|
72
|
+
Using Claude Code?
|
|
73
|
+
</h2>
|
|
74
|
+
<ol className="mb-4 list-inside list-decimal space-y-2 text-sm text-muted-foreground">
|
|
75
|
+
<li>Create a new, empty GitHub repo for the widget.</li>
|
|
76
|
+
<li>
|
|
77
|
+
Install the{" "}
|
|
78
|
+
<a
|
|
79
|
+
href="https://github.com/apps/claude"
|
|
80
|
+
className="underline underline-offset-4 hover:text-foreground"
|
|
81
|
+
>
|
|
82
|
+
Claude GitHub App
|
|
83
|
+
</a>{" "}
|
|
84
|
+
on that repo.
|
|
85
|
+
</li>
|
|
86
|
+
<li>
|
|
87
|
+
Start a Claude Code session connected to it and ask it to
|
|
88
|
+
scaffold and push.
|
|
89
|
+
</li>
|
|
90
|
+
</ol>
|
|
91
|
+
<pre className="mb-4 overflow-x-auto rounded-lg bg-muted p-4 text-xs">
|
|
92
|
+
<code>{`npm create grist-widget my-widget
|
|
93
|
+
cd my-widget
|
|
94
|
+
|
|
95
|
+
git remote add origin https://github.com/<owner>/<repo>.git
|
|
96
|
+
git push -u origin main
|
|
97
|
+
git push origin dev`}</code>
|
|
98
|
+
</pre>
|
|
99
|
+
<Button asChild>
|
|
100
|
+
<a href="https://github.com/new" target="_blank" rel="noreferrer">
|
|
101
|
+
Create a new repository
|
|
102
|
+
</a>
|
|
103
|
+
</Button>
|
|
104
|
+
</div>
|
|
105
|
+
|
|
106
|
+
<section>
|
|
107
|
+
<h2 className="mb-3 font-heading text-base font-semibold">
|
|
108
|
+
Released template versions
|
|
109
|
+
</h2>
|
|
110
|
+
{error ? (
|
|
111
|
+
<p className="text-sm text-muted-foreground">
|
|
112
|
+
Couldn't load the version list.
|
|
113
|
+
</p>
|
|
114
|
+
) : versions === null ? (
|
|
115
|
+
<p className="text-sm text-muted-foreground">Loading…</p>
|
|
116
|
+
) : versions.length === 0 ? (
|
|
117
|
+
<p className="text-sm text-muted-foreground">
|
|
118
|
+
No versions published yet.
|
|
119
|
+
</p>
|
|
120
|
+
) : (
|
|
121
|
+
<ul className="divide-y divide-border rounded-lg border">
|
|
122
|
+
{versions.map((v, i) => (
|
|
123
|
+
<li
|
|
124
|
+
key={v.version}
|
|
125
|
+
className="flex items-center justify-between px-4 py-3"
|
|
126
|
+
>
|
|
127
|
+
<div className="flex items-center gap-2">
|
|
128
|
+
<span className="font-mono text-sm">v{v.version}</span>
|
|
129
|
+
{i === 0 && (
|
|
130
|
+
<span className="rounded-full bg-primary px-2 py-0.5 text-xs text-primary-foreground">
|
|
131
|
+
latest
|
|
132
|
+
</span>
|
|
133
|
+
)}
|
|
134
|
+
<span className="text-xs text-muted-foreground">
|
|
135
|
+
{formatDate(v.publishedAt)}
|
|
136
|
+
</span>
|
|
137
|
+
</div>
|
|
138
|
+
<a
|
|
139
|
+
href={`https://arthurblanchon.github.io/grist-widget-sdk/template/v${v.version}/`}
|
|
140
|
+
className="text-sm underline underline-offset-4 hover:text-foreground"
|
|
141
|
+
>
|
|
142
|
+
Preview
|
|
143
|
+
</a>
|
|
144
|
+
</li>
|
|
145
|
+
))}
|
|
146
|
+
</ul>
|
|
147
|
+
)}
|
|
148
|
+
</section>
|
|
149
|
+
</div>
|
|
150
|
+
)
|
|
151
|
+
}
|
package/template/src/main.tsx
CHANGED
|
@@ -3,24 +3,40 @@ import { createRoot } from "react-dom/client"
|
|
|
3
3
|
import { GristBoundary, GristWidgetProvider } from "grist-widget-sdk"
|
|
4
4
|
|
|
5
5
|
import { GristSdkAlerts } from "@/components/grist-sdk-alerts"
|
|
6
|
+
import { TemplateLanding } from "@/components/template-landing"
|
|
6
7
|
import { ThemeProvider } from "@/components/theme-provider.tsx"
|
|
7
8
|
import "./index.css"
|
|
8
9
|
import App, { GRIST_OPTIONS } from "./App.tsx"
|
|
9
10
|
|
|
11
|
+
// A Grist custom widget only ever runs embedded in Grist's own iframe.
|
|
12
|
+
// Opened directly in a browser tab (window.self === window.top), there's no
|
|
13
|
+
// Grist to connect to -- show the template's own landing content instead of
|
|
14
|
+
// mounting the widget tree at all. Same for a real scaffolded widget nobody
|
|
15
|
+
// has customized yet as for this repo's own showcase deploy of the
|
|
16
|
+
// unmodified template; nothing here is monorepo-specific except the fixed
|
|
17
|
+
// URL TemplateLanding fetches its version list from.
|
|
18
|
+
const isEmbedded = window.self !== window.top
|
|
19
|
+
|
|
10
20
|
createRoot(document.getElementById("root")!).render(
|
|
11
21
|
<StrictMode>
|
|
12
22
|
<ThemeProvider>
|
|
13
|
-
|
|
14
|
-
<
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
<
|
|
19
|
-
<
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
{isEmbedded ? (
|
|
24
|
+
<GristWidgetProvider options={GRIST_OPTIONS}>
|
|
25
|
+
<GristBoundary
|
|
26
|
+
gate={GRIST_OPTIONS.columns?.length ? "canRender" : "ready"}
|
|
27
|
+
>
|
|
28
|
+
<div className="min-h-full w-full bg-background text-foreground">
|
|
29
|
+
<GristSdkAlerts>
|
|
30
|
+
<App />
|
|
31
|
+
</GristSdkAlerts>
|
|
32
|
+
</div>
|
|
33
|
+
</GristBoundary>
|
|
34
|
+
</GristWidgetProvider>
|
|
35
|
+
) : (
|
|
36
|
+
<div className="min-h-full w-full bg-background text-foreground">
|
|
37
|
+
<TemplateLanding />
|
|
38
|
+
</div>
|
|
39
|
+
)}
|
|
24
40
|
</ThemeProvider>
|
|
25
41
|
</StrictMode>
|
|
26
42
|
)
|