paneltir 0.8.0 → 0.10.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/CLAUDE_MD_SNIPPET.md +34 -5
- package/INSTALL.md +68 -12
- package/README.md +1 -1
- package/bin/paneltir.mjs +304 -5
- package/dist/index.d.ts +327 -9
- package/dist/index.js +870 -417
- package/dist/style.css +122 -0
- package/fingerprint.json +5 -4
- package/package.json +50 -3
- package/template/.claude/skills/panel/SKILL.md +70 -0
package/dist/style.css
CHANGED
|
@@ -841,6 +841,128 @@
|
|
|
841
841
|
color: var(--pt-color-success);
|
|
842
842
|
}
|
|
843
843
|
|
|
844
|
+
/* src/components/Setup/SetupWizard.css */
|
|
845
|
+
.pt-wizard {
|
|
846
|
+
display: flex;
|
|
847
|
+
flex-direction: column;
|
|
848
|
+
gap: var(--pt-space-lg);
|
|
849
|
+
}
|
|
850
|
+
.pt-wizard__head {
|
|
851
|
+
display: flex;
|
|
852
|
+
align-items: baseline;
|
|
853
|
+
justify-content: space-between;
|
|
854
|
+
gap: var(--pt-space-sm);
|
|
855
|
+
flex-wrap: wrap;
|
|
856
|
+
}
|
|
857
|
+
.pt-wizard__progress {
|
|
858
|
+
margin: 0;
|
|
859
|
+
font-family: var(--pt-font-mono);
|
|
860
|
+
font-size: 12px;
|
|
861
|
+
color: var(--pt-color-ink-faint);
|
|
862
|
+
}
|
|
863
|
+
.pt-wizard__step {
|
|
864
|
+
padding: var(--pt-space-lg);
|
|
865
|
+
border: var(--pt-border-width) solid var(--pt-color-line);
|
|
866
|
+
border-radius: var(--pt-radius-panel);
|
|
867
|
+
background: var(--pt-color-panel);
|
|
868
|
+
}
|
|
869
|
+
.pt-wizard__step--done {
|
|
870
|
+
border-color: var(--pt-color-success);
|
|
871
|
+
}
|
|
872
|
+
.pt-wizard__now {
|
|
873
|
+
margin: 0 0 var(--pt-space-xs);
|
|
874
|
+
font-size: 11px;
|
|
875
|
+
letter-spacing: var(--pt-label-tracking);
|
|
876
|
+
text-transform: uppercase;
|
|
877
|
+
color: var(--pt-color-ink-faint);
|
|
878
|
+
}
|
|
879
|
+
.pt-wizard__label {
|
|
880
|
+
margin: 0 0 var(--pt-space-xs);
|
|
881
|
+
font-size: 16px;
|
|
882
|
+
color: var(--pt-color-ink);
|
|
883
|
+
}
|
|
884
|
+
.pt-wizard__var {
|
|
885
|
+
margin: 0 0 var(--pt-space-sm);
|
|
886
|
+
font-family: var(--pt-font-mono);
|
|
887
|
+
font-size: 12.5px;
|
|
888
|
+
color: var(--pt-color-accent);
|
|
889
|
+
overflow-wrap: anywhere;
|
|
890
|
+
}
|
|
891
|
+
.pt-wizard__enables {
|
|
892
|
+
margin: 0 0 var(--pt-space-sm);
|
|
893
|
+
font-size: 13px;
|
|
894
|
+
line-height: 1.5;
|
|
895
|
+
color: var(--pt-color-ink-dim);
|
|
896
|
+
}
|
|
897
|
+
.pt-wizard__fix {
|
|
898
|
+
font-size: 13px;
|
|
899
|
+
line-height: 1.55;
|
|
900
|
+
color: var(--pt-color-ink-dim);
|
|
901
|
+
}
|
|
902
|
+
.pt-wizard__fix ol,
|
|
903
|
+
.pt-wizard__fix ul {
|
|
904
|
+
margin: 0;
|
|
905
|
+
padding-left: 18px;
|
|
906
|
+
}
|
|
907
|
+
.pt-wizard__fix li {
|
|
908
|
+
margin-bottom: 4px;
|
|
909
|
+
}
|
|
910
|
+
.pt-wizard__fix code,
|
|
911
|
+
.pt-wizard__prompt {
|
|
912
|
+
font-family: var(--pt-font-mono);
|
|
913
|
+
background: var(--pt-color-raised);
|
|
914
|
+
color: var(--pt-color-ink);
|
|
915
|
+
border-radius: var(--pt-radius-square);
|
|
916
|
+
overflow-wrap: anywhere;
|
|
917
|
+
}
|
|
918
|
+
.pt-wizard__fix code {
|
|
919
|
+
font-size: 12px;
|
|
920
|
+
padding: 1px 5px;
|
|
921
|
+
}
|
|
922
|
+
.pt-wizard__actions {
|
|
923
|
+
display: flex;
|
|
924
|
+
align-items: center;
|
|
925
|
+
gap: var(--pt-space-sm);
|
|
926
|
+
flex-wrap: wrap;
|
|
927
|
+
margin-top: var(--pt-space-md);
|
|
928
|
+
}
|
|
929
|
+
.pt-wizard__said {
|
|
930
|
+
margin: 0;
|
|
931
|
+
font-size: 12.5px;
|
|
932
|
+
color: var(--pt-color-warning);
|
|
933
|
+
}
|
|
934
|
+
.pt-wizard__verify {
|
|
935
|
+
margin: var(--pt-space-sm) 0 0;
|
|
936
|
+
padding-left: 18px;
|
|
937
|
+
font-size: 13px;
|
|
938
|
+
line-height: 1.55;
|
|
939
|
+
color: var(--pt-color-ink-dim);
|
|
940
|
+
}
|
|
941
|
+
.pt-wizard__done-title {
|
|
942
|
+
margin: 0 0 var(--pt-space-xs);
|
|
943
|
+
font-size: 11px;
|
|
944
|
+
letter-spacing: var(--pt-label-tracking);
|
|
945
|
+
text-transform: uppercase;
|
|
946
|
+
color: var(--pt-color-ink-faint);
|
|
947
|
+
}
|
|
948
|
+
.pt-wizard__done ul {
|
|
949
|
+
margin: 0;
|
|
950
|
+
padding-left: 18px;
|
|
951
|
+
font-size: 13px;
|
|
952
|
+
color: var(--pt-color-ink-dim);
|
|
953
|
+
}
|
|
954
|
+
.pt-wizard__stuck {
|
|
955
|
+
padding-top: var(--pt-space-md);
|
|
956
|
+
border-top: var(--pt-border-width) solid var(--pt-color-line-faint);
|
|
957
|
+
}
|
|
958
|
+
.pt-wizard__prompt {
|
|
959
|
+
margin: 0 0 var(--pt-space-sm);
|
|
960
|
+
padding: var(--pt-space-sm);
|
|
961
|
+
font-size: 12px;
|
|
962
|
+
line-height: 1.5;
|
|
963
|
+
white-space: pre-wrap;
|
|
964
|
+
}
|
|
965
|
+
|
|
844
966
|
/* src/components/Notifications/Notifications.css */
|
|
845
967
|
.pt-bell {
|
|
846
968
|
position: relative;
|
package/fingerprint.json
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "paneltir",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"hash": "sha256:
|
|
5
|
-
"fileCount":
|
|
6
|
-
"
|
|
3
|
+
"version": "0.10.0",
|
|
4
|
+
"hash": "sha256:4de7ef7076563e4c3118ac16b645737a44c4c0675115d9a9d7bbff562d5ecb74",
|
|
5
|
+
"fileCount": 163,
|
|
6
|
+
"templateHash": "sha256:7f9accd11920a0c189dd683bdb96635a606960afeca71e02c2a26a0257acefd8",
|
|
7
|
+
"generatedAt": "2026-09-11T02:49:51.562Z"
|
|
7
8
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "paneltir",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "A React UI kit for admin panels: page frame, a board with touch-ready drag and drop, detail sheets, and a whole panel in one component. Structure and behaviour are fixed; colour and brand belong to each project.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"author": "DFKlabs (https://DFKlabs.com)",
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
"check:boards": "node scripts/check-boards.mjs",
|
|
65
65
|
"demo:install": "npm --prefix examples/demo ci",
|
|
66
66
|
"demo:build": "npm --prefix examples/demo run build",
|
|
67
|
-
"verify": "npm run typecheck && npm run build && npm run icons:check && npm run seo:check && npm run test:auth && npm run test:marketplace && npm run test:init && npm run test:board && npm run test:updates && npm run check:boards && npm run check:docs && npm run check:package && npm run fingerprint:check",
|
|
67
|
+
"verify": "npm run typecheck && npm run build && npm run icons:check && npm run seo:check && npm run test:auth && npm run test:marketplace && npm run test:init && npm run test:board && npm run test:gate && npm run test:move && npm run test:theme && npm run test:setup && npm run test:updates && npm run release-notes:check && npm run check:boards && npm run check:docs && npm run check:package && npm run fingerprint:check",
|
|
68
68
|
"site:install": "npm --prefix site ci",
|
|
69
69
|
"site:dev": "npm --prefix site run dev",
|
|
70
70
|
"site:build": "npm --prefix site run build",
|
|
@@ -72,8 +72,14 @@
|
|
|
72
72
|
"check:docs": "node scripts/check-docs.mjs",
|
|
73
73
|
"check:package": "node scripts/check-package.mjs",
|
|
74
74
|
"test:init": "node scripts/test-init.mjs",
|
|
75
|
+
"release-notes": "node scripts/release-notes.mjs",
|
|
76
|
+
"release-notes:check": "node scripts/release-notes.mjs --check",
|
|
75
77
|
"test:updates": "node scripts/test-updates.mjs",
|
|
76
|
-
"test:board": "node scripts/test-board.mjs"
|
|
78
|
+
"test:board": "node scripts/test-board.mjs",
|
|
79
|
+
"test:move": "node scripts/test-move.mjs",
|
|
80
|
+
"test:theme": "node scripts/test-theme.mjs",
|
|
81
|
+
"test:setup": "node scripts/test-setup.mjs",
|
|
82
|
+
"test:gate": "node scripts/test-gate.mjs"
|
|
77
83
|
},
|
|
78
84
|
"peerDependencies": {
|
|
79
85
|
"react": ">=18",
|
|
@@ -91,5 +97,46 @@
|
|
|
91
97
|
},
|
|
92
98
|
"engines": {
|
|
93
99
|
"node": ">=20"
|
|
100
|
+
},
|
|
101
|
+
"paneltirRelease": {
|
|
102
|
+
"version": "0.10.0",
|
|
103
|
+
"date": "2026-09-11",
|
|
104
|
+
"entries": [
|
|
105
|
+
{
|
|
106
|
+
"kind": "feature",
|
|
107
|
+
"text": {
|
|
108
|
+
"en": "`paneltir doctor` says whether the files this project copied are still the ones the installed kit ships — and separates \"you edited it\" from \"we changed it underneath you\", which a diff cannot.",
|
|
109
|
+
"es": "`paneltir doctor` dice si los archivos que copió este proyecto siguen siendo los del kit instalado — y separa «lo editaste tú» de «lo cambiamos nosotros debajo», que un diff no puede."
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"kind": "feature",
|
|
114
|
+
"text": {
|
|
115
|
+
"en": "The setup list can carry a row for the copied gate. Import `.paneltir/gate.json` and pass it as `gate`; without it the panel says nothing about those files rather than guessing.",
|
|
116
|
+
"es": "La lista de configuración puede llevar una fila para la puerta copiada. Importa `.paneltir/gate.json` y pásalo como `gate`; sin él el panel no dice nada de esos archivos en vez de suponer."
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
"kind": "feature",
|
|
121
|
+
"text": {
|
|
122
|
+
"en": "`paneltir run \"what this pass did\"` appends to the board's revisions, so the record does not depend on anyone remembering at the end of a session.",
|
|
123
|
+
"es": "`paneltir run \"qué hizo esta pasada\"` añade una entrada a las revisiones del tablero, así el registro no depende de que alguien se acuerde al final de la sesión."
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
"kind": "fix",
|
|
128
|
+
"text": {
|
|
129
|
+
"en": "`paneltir init` and `paneltir doctor` no longer need React installed. They loaded the component bundle at startup, so they failed in a project that had not installed it yet — which is exactly when `init` is run.",
|
|
130
|
+
"es": "`paneltir init` y `paneltir doctor` ya no necesitan React instalado. Cargaban el bundle de componentes al arrancar, así que fallaban en un proyecto que aún no lo tenía — que es justo cuando se ejecuta `init`."
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
"kind": "chore",
|
|
135
|
+
"text": {
|
|
136
|
+
"en": "The rules a project needs are checked to actually reach it: the documents a project keeps must name `extraThemes` and `paneltir doctor`, or the build fails saying why.",
|
|
137
|
+
"es": "Se comprueba que las reglas que un proyecto necesita le lleguen de verdad: los documentos que el proyecto conserva tienen que nombrar `extraThemes` y `paneltir doctor`, o la build falla diciendo por qué."
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
]
|
|
94
141
|
}
|
|
95
142
|
}
|
|
@@ -132,6 +132,76 @@ Never invent a palette. If the project has no colours of its own, say so and
|
|
|
132
132
|
leave the theme alone — the kit ships presets for exactly that case, and one
|
|
133
133
|
of them is a light theme.
|
|
134
134
|
|
|
135
|
+
And when you hand this project's own theme to `PanelApp`, it goes in
|
|
136
|
+
**`extraThemes`** and never in `themes`. `extraThemes` offers it as well as the
|
|
137
|
+
kit's four; `themes` means "exactly these", so one theme passed there deletes
|
|
138
|
+
every preset and the settings sheet shows a single row. Two projects were
|
|
139
|
+
installed that way before the distinction existed, and the symptom reads as the
|
|
140
|
+
kit having no themes rather than as a prop being wrong.
|
|
141
|
+
|
|
142
|
+
## When the panel behaves oddly for no visible reason
|
|
143
|
+
|
|
144
|
+
The gate — `middleware.ts`, `lib/session.ts`, `api/*.ts` — was copied into this
|
|
145
|
+
project once and does **not** update when the kit does. So a fix released
|
|
146
|
+
upstream can be missing here while every version number on the screen looks
|
|
147
|
+
current, and nothing says so: the `HTTP 500` on saving lived in
|
|
148
|
+
`api/panel-state.ts` and stayed in projects installed before the fix.
|
|
149
|
+
|
|
150
|
+
npx paneltir doctor
|
|
151
|
+
|
|
152
|
+
`.paneltir/gate.json` is what makes that answer sharp, and it belongs in git:
|
|
153
|
+
it records what `init` copied and from where. Ignored, it vanishes on the next
|
|
154
|
+
clone and every file degrades to "differs" — the one answer that cannot say
|
|
155
|
+
whether you moved it or we did.
|
|
156
|
+
|
|
157
|
+
It separates the three answers that need different actions: *yours* (you edited
|
|
158
|
+
it), *BEHIND* (you did not touch it and the template moved), and *BOTH*. The
|
|
159
|
+
middle one is invisible to `git diff`, because there is nothing in this
|
|
160
|
+
project's history to compare against. `paneltir init --force` replaces the gate
|
|
161
|
+
and never the board — read the diff first when a file is marked BOTH, or the
|
|
162
|
+
edit is lost.
|
|
163
|
+
|
|
164
|
+
## Setting the panel up in the first place
|
|
165
|
+
|
|
166
|
+
The panel is asked for this by name: its walkthrough carries a line the owner
|
|
167
|
+
can paste into a session here, and it points at this file. So when somebody
|
|
168
|
+
arrives asking you to set up the Paneltir panel, this is the answer, and the
|
|
169
|
+
job is to walk them through it rather than to hand them a list.
|
|
170
|
+
|
|
171
|
+
Four things live in the **hosting environment** — never in this repository, and
|
|
172
|
+
never in the board.
|
|
173
|
+
|
|
174
|
+
| | What it is | Without it |
|
|
175
|
+
| --- | --- | --- |
|
|
176
|
+
| `ADMIN_PASSWORD` | The panel's password. | The gate answers 503 rather than letting anyone in. It fails closed on purpose: a panel with no password must not become a public one. |
|
|
177
|
+
| `GH_TOKEN` | A GitHub fine-grained token, **Contents: read and write, on this repository only**. | Everything works and Save fails. |
|
|
178
|
+
| `PANEL_REPO` | This project's `owner/repo`. | Save has nowhere to write. There is no default, because writing to the wrong repository is worse than not writing. |
|
|
179
|
+
| `SESSION_SECRET` | Optional; signs the session cookie. Defaults to `ADMIN_PASSWORD`. | Nothing, until the password changes — at which point every session already issued ends, which is usually what was wanted. |
|
|
180
|
+
|
|
181
|
+
`PANEL_FILE` is there too, and only matters when the board is somewhere other
|
|
182
|
+
than `src/data/panel-state.json`.
|
|
183
|
+
|
|
184
|
+
Three things are worth saying while you walk somebody through it:
|
|
185
|
+
|
|
186
|
+
- **Environment variables are read at deploy time.** Adding one to a running
|
|
187
|
+
deployment changes nothing until it redeploys. More than half of "I added it
|
|
188
|
+
and it still says missing" is this.
|
|
189
|
+
- **Scope the token to this repository alone.** A token that can write to
|
|
190
|
+
everything is a token whose blast radius is everything, and this one only
|
|
191
|
+
ever commits one file.
|
|
192
|
+
- **Check, do not assume.** The panel's Help screen asks the server what is
|
|
193
|
+
actually set and reports *whether*, never the value. That answer is worth
|
|
194
|
+
more than a screenshot of a settings page.
|
|
195
|
+
|
|
196
|
+
Then two things to try before the gate is trusted, because a door nobody has
|
|
197
|
+
pushed is not known to be shut:
|
|
198
|
+
|
|
199
|
+
1. Open `/admin` signed out. It must land on the sign-in screen.
|
|
200
|
+
2. Signed out, request the panel's own JavaScript bundle. It must answer 401.
|
|
201
|
+
A page that is protected while its bundle is not leaves the board readable
|
|
202
|
+
by anyone who opens the HTML — and that is the failure that looks exactly
|
|
203
|
+
like everything working.
|
|
204
|
+
|
|
135
205
|
## When the board will not open
|
|
136
206
|
|
|
137
207
|
Run `npx paneltir board`. It reads the file and names every problem by
|