@bongos/core 1.21.91 → 1.21.92
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/.bongos-core.json +39 -39
- package/docs/copy-inventory.md +357 -367
- package/docs/copy-registry.json +559 -641
- package/docs/module-api-changelog.md +2 -0
- package/docs/page-inventory.json +15 -18
- package/docs/page-readings.json +1235 -918
- package/modules/public-landing/public/projects-hall-live.states.json +6 -35
- package/modules/public-landing/public/projects.html +1019 -983
- package/modules/public-landing/public/projects.probes.json +15 -18
- package/modules/public-landing/public/projects.states.json +22 -25
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/release-notes.json +6 -0
- package/src/module-api.js +1 -1
- package/tests/onboard.mjs +8 -8
- package/tests/project_invite_ui.mjs +6 -5
- package/tests/projects_hub.mjs +77 -98
- package/tests/projects_hub_app_status.mjs +3 -3
- package/tests/projects_hub_app_step.mjs +8 -8
- package/tests/projects_hub_cloud_hop.mjs +29 -53
- package/tests/projects_hub_look.mjs +29 -39
- package/tests/projects_hub_module_picker.mjs +32 -39
- package/tests/projects_hub_pre_uat.mjs +11 -14
- package/tests/wizard_demo.mjs +30 -25
- package/tests/wizard_draft_resume.mjs +24 -32
- package/tests/wizard_front_door.mjs +91 -243
- package/tests/wizard_intent_resume.mjs +28 -48
- package/tests/wizard_one_page.mjs +201 -0
- package/tests/wizard_physics.mjs +46 -41
- package/tests/wizard_physics_more.mjs +71 -106
- package/tests/wizard_ship_mode.mjs +1 -1
- package/tests/wizard_six_screens.mjs +0 -129
|
@@ -91,19 +91,13 @@
|
|
|
91
91
|
/* show() moves focus to each panel's h1 for keyboard/SR context — keep the
|
|
92
92
|
focus, lose the ring (a black rectangle around a heading; owner walk) */
|
|
93
93
|
h1[tabindex="-1"]:focus:not(:focus-visible){outline:none;}
|
|
94
|
-
/* the one tick
|
|
95
|
-
.termsAck{display:flex;gap:
|
|
96
|
-
.termsAck input{width:
|
|
97
|
-
.termsAck span{font-size:
|
|
98
|
-
.termsRead{display:inline-block;min-height:24px;line-height:
|
|
99
|
-
/* the
|
|
100
|
-
|
|
101
|
-
rest, the accent only on the one that goes on */
|
|
102
|
-
.doorPill{display:inline-grid;grid-template-columns:1fr 1fr;gap:6px;padding:7px;margin:6px 0 16px;border-radius:999px;border:1px solid var(--rule);background:color-mix(in srgb,var(--bg) 55%,transparent);}
|
|
103
|
-
#view-new .doorPill .btn.ghost{border-color:transparent;}
|
|
104
|
-
#view-new .doorPill .btn.ghost:hover{border-color:var(--rule);}
|
|
105
|
-
/* the demo route (task 1004420): one screen inside the fork — steppers on the wizard's
|
|
106
|
-
field grammar, the fit check as one quiet line, two teammates */
|
|
94
|
+
/* the one tick above Create: the box in the accent, the whole row the target */
|
|
95
|
+
.termsAck{display:flex;gap:12px;align-items:flex-start;cursor:pointer;max-width:62ch;margin:28px 0 0;padding:0;}
|
|
96
|
+
.termsAck input{width:18px;height:18px;margin:3px 0 0;flex:none;accent-color:var(--accent);}
|
|
97
|
+
.termsAck span{font-size:14px;line-height:1.5;color:var(--ink-soft);}
|
|
98
|
+
.termsRead{display:inline-block;min-height:24px;line-height:21px;color:var(--link-ink);text-decoration:underline;text-underline-offset:3px;}
|
|
99
|
+
/* the demo route (task 1004420): opened in place at the top of part 01 — steppers on
|
|
100
|
+
the wizard's field grammar, the fit check as one quiet line, two teammates */
|
|
107
101
|
.demoSteppers{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:0 24px;}
|
|
108
102
|
.demoStep{display:flex;align-items:center;gap:12px;margin-top:6px;}
|
|
109
103
|
.demoStep output{min-width:2ch;text-align:center;font-family:var(--font-display);font-weight:300;font-size:28px;color:var(--ink);}
|
|
@@ -183,6 +177,7 @@ h1[tabindex="-1"]:focus:not(:focus-visible){outline:none;}
|
|
|
183
177
|
--rm-mug:color-mix(in srgb,var(--sea) 11%,#000);
|
|
184
178
|
--rm-leaf-1:color-mix(in srgb,var(--sea) 20%,#000);
|
|
185
179
|
--rm-leaf-2:color-mix(in srgb,var(--sea) 26%,#000);
|
|
180
|
+
--rm-pane:color-mix(in srgb,var(--accent) 92%,#fff);
|
|
186
181
|
--seed:.45;
|
|
187
182
|
position:fixed;left:0;right:0;top:var(--top-h,64px);bottom:0;z-index:0;overflow:hidden;pointer-events:none;
|
|
188
183
|
background:var(--rm-room);
|
|
@@ -221,13 +216,79 @@ h1[tabindex="-1"]:focus:not(:focus-visible){outline:none;}
|
|
|
221
216
|
/* the seed: the world's chrome blob, hanging in the window's sky */
|
|
222
217
|
#view-new .rmSeed{left:120px;top:120px;width:120px;height:120px;transform:scale(var(--seed));transform-origin:50% 50%;}
|
|
223
218
|
#view-new .rmSeed img{display:block;width:100%;height:100%;object-fit:contain;filter:drop-shadow(0 0 22px var(--rm-glow));}
|
|
219
|
+
/* the seed grows as the page fills in (paintFill: a name, a kind, the checks, the tick) */
|
|
224
220
|
#view-new .wizRoom[data-screen="signin"]{--seed:.3;}
|
|
225
|
-
#view-new .wizRoom[data-screen="
|
|
226
|
-
#view-new .wizRoom[data-screen="
|
|
227
|
-
#view-new .wizRoom[data-screen="
|
|
228
|
-
#view-new .wizRoom[data-screen="
|
|
229
|
-
#view-new .wizRoom[data-screen="look"]{--seed:.85;}
|
|
221
|
+
#view-new .wizRoom[data-screen="page"][data-fill="1"]{--seed:.55;}
|
|
222
|
+
#view-new .wizRoom[data-screen="page"][data-fill="2"]{--seed:.65;}
|
|
223
|
+
#view-new .wizRoom[data-screen="page"][data-fill="3"]{--seed:.75;}
|
|
224
|
+
#view-new .wizRoom[data-screen="page"][data-fill="4"]{--seed:.85;}
|
|
230
225
|
#view-new .wizRoom[data-screen="done"]{--seed:1.1;}
|
|
226
|
+
/* the clouds and the patch of sun belong to the day room; at night they are not there */
|
|
227
|
+
#view-new .rmCloud{background:var(--rm-star);border-radius:40px;opacity:0;}
|
|
228
|
+
#view-new .rmCloud::before,#view-new .rmCloud::after{content:"";position:absolute;background:inherit;border-radius:50%;}
|
|
229
|
+
#view-new .rmC1{left:40px;top:70px;width:110px;height:26px;}
|
|
230
|
+
#view-new .rmC1::before{left:22px;top:-16px;width:44px;height:38px;}
|
|
231
|
+
#view-new .rmC1::after{left:54px;top:-10px;width:34px;height:30px;}
|
|
232
|
+
#view-new .rmC2{left:230px;top:140px;width:80px;height:20px;}
|
|
233
|
+
#view-new .rmC2::before{left:16px;top:-12px;width:32px;height:28px;}
|
|
234
|
+
#view-new .rmC2::after{left:40px;top:-8px;width:26px;height:22px;}
|
|
235
|
+
#view-new .rmSun{left:calc(50% + 120px);top:672px;width:520px;height:120px;opacity:0;background:var(--rm-glow);transform:skewX(-28deg);filter:blur(10px);}
|
|
236
|
+
#view-new .rmLight{background:var(--rm-pane);}
|
|
237
|
+
/* ── the day room (task 1004648; the mockup's [data-sky="day"]): the same drawing in
|
|
238
|
+
daylight — a sunny sky with clouds, a sun for the moon, lighter towers with unlit
|
|
239
|
+
windows, a warm wall and floor, the lamp off and a patch of sun on the floor. Every
|
|
240
|
+
colour is still a mix of the fifteen with black or white. The words' own tokens are
|
|
241
|
+
re-pointed for a light ground on the view's children (never :root): the status inks
|
|
242
|
+
are read off the page's own through --wz-*, declared one level up so no token ever
|
|
243
|
+
names itself. ── */
|
|
244
|
+
#view-new{--wz-ok:var(--ok);--wz-err:var(--err);--wz-warn:var(--warn);}
|
|
245
|
+
#view-new[data-sky="day"]>*{
|
|
246
|
+
--ink:color-mix(in srgb,#fff 10%,#000);
|
|
247
|
+
--ink-soft:color-mix(in srgb,#fff 24%,#000);
|
|
248
|
+
--ink-faint:color-mix(in srgb,#fff 36%,#000);
|
|
249
|
+
--rule:rgba(0,0,0,.14);
|
|
250
|
+
--rule-soft:rgba(0,0,0,.08);
|
|
251
|
+
--line:rgba(0,0,0,.1);
|
|
252
|
+
--ctl-line:rgba(0,0,0,.45);
|
|
253
|
+
--bg:color-mix(in srgb,var(--accent) 6%,#fff);
|
|
254
|
+
--bg-card:#fff;
|
|
255
|
+
--card:color-mix(in srgb,var(--accent) 4%,#fff);
|
|
256
|
+
--glass:rgba(255,255,255,.52);
|
|
257
|
+
--glass-strong:rgba(255,255,255,.75);
|
|
258
|
+
--glass-edge:rgba(0,0,0,.16);
|
|
259
|
+
--accent-deep:color-mix(in srgb,var(--terracotta) 78%,#000);
|
|
260
|
+
--link-ink:color-mix(in srgb,var(--terracotta) 78%,#000);
|
|
261
|
+
--ok:color-mix(in srgb,var(--wz-ok) 40%,#000);
|
|
262
|
+
--err:color-mix(in srgb,var(--wz-err) 55%,#000);
|
|
263
|
+
--warn:color-mix(in srgb,var(--wz-warn) 45%,#000);
|
|
264
|
+
--focus:color-mix(in srgb,var(--terracotta) 78%,#000);
|
|
265
|
+
color-scheme:light;
|
|
266
|
+
}
|
|
267
|
+
#view-new[data-sky="day"] .wizRoom{
|
|
268
|
+
--rm-room:color-mix(in srgb,var(--accent) 9%,color-mix(in srgb,#fff 92%,#000));
|
|
269
|
+
--rm-frame:color-mix(in srgb,var(--terracotta) 14%,color-mix(in srgb,#fff 84%,#000));
|
|
270
|
+
--rm-night:color-mix(in srgb,var(--sea) 30%,#fff);
|
|
271
|
+
--rm-moon:var(--gold);
|
|
272
|
+
--rm-halo:color-mix(in srgb,var(--gold) 50%,transparent);
|
|
273
|
+
--rm-star:#fff;
|
|
274
|
+
--rm-tower-1:color-mix(in srgb,var(--sea) 28%,color-mix(in srgb,#fff 70%,#000));
|
|
275
|
+
--rm-tower-2:color-mix(in srgb,var(--sea) 30%,color-mix(in srgb,#fff 64%,#000));
|
|
276
|
+
--rm-tower-3:color-mix(in srgb,var(--sea) 26%,color-mix(in srgb,#fff 76%,#000));
|
|
277
|
+
--rm-pane:color-mix(in srgb,var(--sea) 8%,#fff);
|
|
278
|
+
--rm-floor:color-mix(in srgb,var(--terracotta) 10%,color-mix(in srgb,#fff 88%,#000));
|
|
279
|
+
--rm-edge:rgba(0,0,0,.08);
|
|
280
|
+
--rm-glow:color-mix(in srgb,var(--gold) 55%,transparent);
|
|
281
|
+
--rm-stem:color-mix(in srgb,var(--terracotta) 12%,color-mix(in srgb,#fff 76%,#000));
|
|
282
|
+
--rm-shade:color-mix(in srgb,var(--terracotta) 12%,color-mix(in srgb,#fff 82%,#000));
|
|
283
|
+
--rm-mug:color-mix(in srgb,var(--terracotta) 12%,color-mix(in srgb,#fff 78%,#000));
|
|
284
|
+
--rm-leaf-1:color-mix(in srgb,var(--wz-ok) 32%,color-mix(in srgb,#fff 46%,#000));
|
|
285
|
+
--rm-leaf-2:color-mix(in srgb,var(--wz-ok) 36%,color-mix(in srgb,#fff 40%,#000));
|
|
286
|
+
}
|
|
287
|
+
#view-new[data-sky="day"] .rmMoon{left:380px;top:40px;width:70px;height:70px;box-shadow:0 0 80px 26px var(--rm-halo);}
|
|
288
|
+
#view-new[data-sky="day"] .rmStar,#view-new[data-sky="day"] .rmGlow{opacity:0;}
|
|
289
|
+
#view-new[data-sky="day"] .rmCloud{opacity:.9;}
|
|
290
|
+
#view-new[data-sky="day"] .rmSun{opacity:.7;}
|
|
291
|
+
#view-new[data-sky="day"] .rmGrain{opacity:.04;}
|
|
231
292
|
/* soft film grain over the room — the lofi texture, no colour of its own */
|
|
232
293
|
#view-new .rmGrain{inset:0;opacity:.07;mix-blend-mode:overlay;background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2' stitchTiles='stitch'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>");}
|
|
233
294
|
@media (prefers-reduced-motion:no-preference){
|
|
@@ -239,6 +300,11 @@ h1[tabindex="-1"]:focus:not(:focus-visible){outline:none;}
|
|
|
239
300
|
#view-new .rmS5{animation-delay:-5s;}
|
|
240
301
|
#view-new .rmGlow{animation:rmBreathe 9s ease-in-out infinite;}
|
|
241
302
|
#view-new .rmSeed img{animation:rmFloat 8s ease-in-out infinite;}
|
|
303
|
+
#view-new .rmCloud{animation:rmDrift 60s linear infinite;}
|
|
304
|
+
#view-new .rmC2{animation-delay:-25s;}
|
|
305
|
+
#view-new .wizRoom,#view-new .wizRoom>*,#view-new .rmWindow>*{transition:background .8s ease,opacity .8s ease,box-shadow .8s ease;}
|
|
306
|
+
#view-new[data-sky="day"] .rmStar,#view-new[data-sky="day"] .rmGlow{animation:none;}
|
|
307
|
+
@keyframes rmDrift{from{transform:translateX(-30px)}to{transform:translateX(60px)}}
|
|
242
308
|
@keyframes rmTwinkle{0%,100%{opacity:.9}50%{opacity:.35}}
|
|
243
309
|
@keyframes rmBreathe{0%,100%{opacity:1}50%{opacity:.7}}
|
|
244
310
|
@keyframes rmFloat{0%,100%{transform:translateY(0)}50%{transform:translateY(-6px)}}
|
|
@@ -246,7 +312,7 @@ h1[tabindex="-1"]:focus:not(:focus-visible){outline:none;}
|
|
|
246
312
|
/* under 900 the window steps back and dims behind the words; the lamp, mug and plant go */
|
|
247
313
|
@media (max-width:900px){
|
|
248
314
|
#view-new .rmWindow{left:auto;right:-140px;top:24px;opacity:.35;}
|
|
249
|
-
#view-new .rmGlow,#view-new .rmStem,#view-new .rmShade,#view-new .rmMug,#view-new .rmLeaf{display:none;}
|
|
315
|
+
#view-new .rmGlow,#view-new .rmSun,#view-new .rmStem,#view-new .rmShade,#view-new .rmMug,#view-new .rmLeaf{display:none;}
|
|
250
316
|
#view-new .rmFloor{top:auto;height:80px;}
|
|
251
317
|
}
|
|
252
318
|
/* under 600 the words fill the screen, so the window fades further and its lit windows
|
|
@@ -258,65 +324,114 @@ h1[tabindex="-1"]:focus:not(:focus-visible){outline:none;}
|
|
|
258
324
|
/* the words column above the room, held to the mockup's measure so the window never
|
|
259
325
|
slides under it; headings in the mockup's sentence case */
|
|
260
326
|
#view-new .wrap{position:relative;z-index:1;min-height:calc(100vh - var(--top-h,64px) - 120px);}
|
|
327
|
+
/* the footer stands on its own ground above the fixed room, so its links keep their ink
|
|
328
|
+
whichever room is behind the page (task 1004648) */
|
|
329
|
+
body:has(#view-new:not([hidden])) footer.foot{position:relative;z-index:1;background:var(--bg);}
|
|
261
330
|
#view-new .panel{max-width:600px;}
|
|
331
|
+
#view-new #panel-page{max-width:560px;}
|
|
262
332
|
.wizTop{display:flex;align-items:center;gap:16px;min-height:44px;margin:0 0 28px;max-width:600px;}
|
|
263
333
|
.wizEyebrow{font-family:var(--label-face);font-size:var(--label-size);letter-spacing:var(--label-space);text-transform:uppercase;color:var(--ink-faint);}
|
|
264
|
-
.
|
|
265
|
-
.wizBack:hover{color:var(--ink);}
|
|
266
|
-
.wizBack[hidden]{display:none;}
|
|
267
|
-
.demoTag{display:inline-block;margin-left:12px;padding:3px 10px;border-radius:999px;font-family:var(--label-face);font-size:var(--label-size);letter-spacing:var(--label-space);text-transform:uppercase;color:var(--accent);border:1px solid color-mix(in srgb,var(--accent) 55%,transparent);vertical-align:middle;}
|
|
334
|
+
.demoTag{display:inline-block;margin-left:12px;padding:3px 10px;border-radius:999px;font-family:var(--label-face);font-size:var(--label-size);letter-spacing:var(--label-space);text-transform:uppercase;color:var(--accent-deep);border:1px solid color-mix(in srgb,var(--accent) 55%,transparent);vertical-align:middle;}
|
|
268
335
|
.demoTag[hidden]{display:none;}
|
|
269
|
-
.fillOffer{margin:0 0
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
.
|
|
278
|
-
.
|
|
336
|
+
.fillOffer{margin:14px 0 0;}
|
|
337
|
+
/* ── the one page (task 1004648; the design of record docs/design/mocks/day-night-rooms/):
|
|
338
|
+
the heading, the demo as a small link under it, then three parts as glass cards in
|
|
339
|
+
one column — 01 your project, 02 how it's run, 03 Connect GitHub — with the terms
|
|
340
|
+
tick and Create between the second and the third. ── */
|
|
341
|
+
.pageSub{margin:14px 0 0;font-size:18px;line-height:1.5;font-weight:300;color:var(--ink-soft);max-width:62ch;}
|
|
342
|
+
.pageSub[hidden]{display:none;}
|
|
343
|
+
#view-new .pageSub .linklike{display:inline;min-height:24px;padding:0;font:inherit;color:var(--link-ink);text-decoration:underline;text-underline-offset:3px;}
|
|
344
|
+
#view-new .pageSub .linklike:hover{color:var(--ink);}
|
|
345
|
+
.wizParts{margin-top:20px;}
|
|
346
|
+
.wizParts[hidden]{display:none;}
|
|
347
|
+
.part{margin-top:28px;padding:24px 26px;border-radius:22px;background:var(--glass);border:1px solid var(--glass-edge);-webkit-backdrop-filter:blur(16px);backdrop-filter:blur(16px);}
|
|
348
|
+
.part h2{display:flex;align-items:baseline;flex-wrap:wrap;gap:4px 12px;margin:0;font-family:var(--font-display);font-size:22px;font-weight:300;letter-spacing:-.01em;line-height:1.3;text-transform:none;color:var(--ink);}
|
|
349
|
+
.part h2 .n{font-family:var(--font-mono);font-size:11px;letter-spacing:.1em;color:var(--ink-faint);}
|
|
350
|
+
.part h2 .state{margin-left:auto;font-family:var(--font-body);font-size:13px;font-weight:400;letter-spacing:0;color:var(--ink-faint);}
|
|
351
|
+
.part h2[tabindex="-1"]:focus:not(:focus-visible){outline:none;}
|
|
352
|
+
.part .wizField:first-of-type{margin-top:20px;}
|
|
353
|
+
.part.waiting h2{color:var(--ink-soft);}
|
|
354
|
+
.part.live{border-color:color-mix(in srgb,var(--accent) 55%,transparent);}
|
|
355
|
+
.partSub{margin:12px 0 0;font-size:15px;line-height:1.5;font-weight:300;color:var(--ink-soft);max-width:62ch;}
|
|
356
|
+
.partH3{margin:0 0 6px;font-family:var(--font-display);font-size:20px;font-weight:300;letter-spacing:-.01em;color:var(--ink);}
|
|
357
|
+
.partH3:focus:not(:focus-visible){outline:none;}
|
|
358
|
+
.partH3 em{font-style:normal;}
|
|
359
|
+
.demoView{margin:18px 0 6px;padding:0 0 14px;border-bottom:1px solid var(--rule);}
|
|
360
|
+
.demoLede{margin:0 0 14px;}
|
|
361
|
+
.demoActs{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-top:12px;}
|
|
362
|
+
.checksHead{margin:26px 0 16px;padding-top:18px;border-top:1px solid var(--rule);font-size:13px;line-height:1.5;color:var(--ink-soft);}
|
|
363
|
+
.checksStop{margin-top:22px;padding:16px;border-radius:14px;background:color-mix(in srgb,var(--err) 10%,transparent);border:1px solid var(--err);}
|
|
364
|
+
.checksStop p{margin:0;font-size:14.5px;line-height:1.5;color:var(--ink);}
|
|
365
|
+
/* the page's own fields: the mockup's glass boxes, a 48px row, the boundary held to
|
|
366
|
+
3:1 on its ground in both rooms */
|
|
367
|
+
#view-new .part input[type=text],#view-new .part input[type=password],#view-new .part select{
|
|
368
|
+
width:100%;min-height:48px;padding:0 16px;border-radius:14px;border:1px solid color-mix(in srgb,var(--ink) 40%,transparent);
|
|
369
|
+
background:var(--glass-strong);color:var(--ink);font-family:var(--font-body);font-size:16px;outline:none;}
|
|
370
|
+
#view-new .part input[type=text]:focus,#view-new .part input[type=password]:focus,#view-new .part select:focus{border-color:color-mix(in srgb,var(--accent) 70%,var(--ink));}
|
|
371
|
+
#view-new .part select{appearance:none;cursor:pointer;}
|
|
372
|
+
#view-new .part select option{background:var(--bg-card);color:var(--ink);}
|
|
373
|
+
#view-new .part .wizField>span{margin-bottom:8px;font-family:var(--font-body);font-size:13px;letter-spacing:0;text-transform:none;color:var(--ink-soft);}
|
|
374
|
+
#view-new .part .wizField small{font-size:12.5px;color:var(--ink-faint);}
|
|
375
|
+
#view-new .part .wizField{margin:20px 0 0;}
|
|
376
|
+
#view-new .part .physRow2 .wizField{margin-top:0;}
|
|
377
|
+
/* the chips: every short choice on the page is a row of glass pills, the chosen one in
|
|
378
|
+
the accent's soft fill (the mockup's .chip) */
|
|
379
|
+
#view-new .part .typeCards:not(#modCards):not(.physSuiteGrid),
|
|
380
|
+
#view-new .part .choices{display:flex;flex-wrap:wrap;gap:8px;margin:0;padding:0;border:0;}
|
|
381
|
+
#view-new .part .typeCards:not(#modCards):not(.physSuiteGrid) .tpill,
|
|
382
|
+
#view-new .part .choices .choice{display:inline-flex;align-items:center;min-height:38px;padding:0 15px;border:0;border-radius:999px;cursor:pointer;
|
|
383
|
+
font-family:var(--font-body);font-size:14px;font-weight:400;color:var(--ink-soft);background:var(--glass-strong);border:1px solid var(--glass-edge);}
|
|
384
|
+
#view-new .part .typeCards:not(#modCards):not(.physSuiteGrid) .tpill::before,
|
|
385
|
+
#view-new .part .choices .choice b::before{display:none;}
|
|
386
|
+
#view-new .part .choices .choice b{margin:0;font-size:14px;font-weight:400;color:inherit;}
|
|
387
|
+
#view-new .part .choices .choice p{display:none;}
|
|
388
|
+
#view-new .part .typeCards:not(#modCards):not(.physSuiteGrid) .tpill[aria-pressed=true],
|
|
389
|
+
#view-new .part .choices .choice[aria-pressed=true]{background:color-mix(in srgb,var(--accent) 16%,transparent);color:var(--ink);border:1px solid color-mix(in srgb,var(--accent) 60%,transparent);}
|
|
390
|
+
#view-new .part .typeCards .tpill[disabled]{opacity:.45;cursor:default;}
|
|
391
|
+
#view-new .part .typeCards .tpill[hidden]{display:none;}
|
|
392
|
+
/* Create, with the recap beside it, and the reason it waits under it */
|
|
393
|
+
.createBar{display:flex;align-items:center;gap:18px;flex-wrap:wrap;margin-top:24px;}
|
|
394
|
+
#view-new .createBar #doCreate{min-height:52px;padding:0 28px;}
|
|
395
|
+
#view-new .createBar #doCreate:disabled{background:color-mix(in srgb,var(--accent) 40%,transparent);border:0;color:var(--ink);cursor:default;}
|
|
396
|
+
.wizRecap{margin:0;font-size:14px;line-height:1.5;color:var(--ink-soft);overflow-wrap:anywhere;}
|
|
397
|
+
.createWhy{margin-top:8px;}
|
|
398
|
+
/* part 02: one hairline ledger of rows. Each row is its label, its value with one plain
|
|
399
|
+
line under it, and Change, which reads Done while the row is open over the control
|
|
400
|
+
it always was. Inside an open row the choices are the same chips. */
|
|
401
|
+
.setRows{margin:14px 0 0;border-top:1px solid var(--rule);}
|
|
402
|
+
.setRow{display:grid;grid-template-columns:108px minmax(0,1fr) auto;gap:0 14px;align-items:start;padding:13px 0;border-bottom:1px solid var(--rule);}
|
|
403
|
+
.setRow:last-child{border-bottom:0;}
|
|
279
404
|
.setRow[hidden]{display:none;}
|
|
280
|
-
.setRow .k{font-size:13px;line-height:22px;color:var(--ink-faint);
|
|
405
|
+
.setRow .k{font-size:13px;line-height:22px;color:var(--ink-faint);}
|
|
281
406
|
.setRow .v{min-width:0;}
|
|
282
|
-
.setRow .rowV{display:block;font-size:
|
|
283
|
-
.setRow .rowS{display:block;margin-top:
|
|
407
|
+
.setRow .rowV{display:block;font-size:15px;line-height:1.45;color:var(--ink);overflow-wrap:anywhere;}
|
|
408
|
+
.setRow .rowS{display:block;margin-top:2px;font-size:12.5px;line-height:1.45;color:var(--ink-faint);overflow-wrap:anywhere;}
|
|
284
409
|
.setRow .rowS:empty{display:none;}
|
|
285
410
|
.setRow .acts{display:flex;gap:6px;flex:none;}
|
|
286
|
-
.setRow .acts button{min-height:
|
|
287
|
-
.setRow [data-row-chg]{border:1px solid var(--glass-edge);background:var(--glass);color:var(--ink-soft);}
|
|
411
|
+
.setRow .acts button{min-height:32px;padding:0 4px;border:0;background:none;font:inherit;font-size:13px;white-space:nowrap;cursor:pointer;color:var(--link-ink);text-decoration:underline;text-underline-offset:3px;}
|
|
288
412
|
.setRow [data-row-chg]:hover{color:var(--ink);}
|
|
289
413
|
.setRow [data-row-chg][hidden]{display:none;}
|
|
290
|
-
.
|
|
414
|
+
.swDot{display:inline-block;box-sizing:border-box;width:14px;height:14px;margin-right:8px;border-radius:50%;vertical-align:-2px;border:1px solid var(--glass-edge);}
|
|
291
415
|
.setRow .opts{margin-top:12px;}
|
|
292
416
|
.setRow .opts .wizField{margin-bottom:12px;}
|
|
293
417
|
.setRow .opts .hint:empty{display:none;}
|
|
294
|
-
/*
|
|
295
|
-
.setRow .opts .choices,
|
|
296
|
-
.setRow .opts .typeCards
|
|
297
|
-
.setRow .opts #teamCards{display:inline-flex;flex-wrap:wrap;gap:0;border:1px solid var(--rule);border-radius:999px;padding:3px;margin:0 8px 12px 0;vertical-align:top;}
|
|
298
|
-
.setRow .opts .choices .choice,
|
|
299
|
-
.setRow .opts .typeCards.physCells:not(.physSuiteGrid) .tpill,
|
|
300
|
-
.setRow .opts #teamCards .tpill{display:inline-flex;align-items:center;gap:6px;min-height:32px;padding:0 14px;border:0;border-radius:999px;font-size:14px;font-weight:500;color:var(--ink-soft);background:none;}
|
|
301
|
-
.setRow .opts .choices .choice b{margin:0;font-size:14px;color:inherit;}
|
|
302
|
-
.setRow .opts .choices .choice b::before,
|
|
303
|
-
.setRow .opts .typeCards.physCells:not(.physSuiteGrid) .tpill::before,
|
|
304
|
-
.setRow .opts #teamCards .tpill::before{display:none;}
|
|
305
|
-
.setRow .opts .choices .choice p{display:none;}
|
|
418
|
+
/* inside an open row the chip groups sit one under another */
|
|
419
|
+
#view-new .setRow .opts .choices,
|
|
420
|
+
#view-new .setRow .opts .typeCards:not(#modCards):not(.physSuiteGrid){margin:0 0 12px;}
|
|
306
421
|
.setRow .opts .reassure{font-size:13px;margin:0 0 12px;}
|
|
307
|
-
.setRow .opts .choices .choice[aria-pressed=true],
|
|
308
|
-
.setRow .opts .typeCards.physCells:not(.physSuiteGrid) .tpill[aria-pressed=true],
|
|
309
|
-
.setRow .opts #teamCards .tpill[aria-pressed=true]{background:color-mix(in srgb,var(--accent) 18%,transparent);color:var(--ink);}
|
|
310
422
|
/* a reason for a question the table hides explains nothing on screen */
|
|
311
423
|
.physExisting[hidden] + .physWhy{display:none;}
|
|
424
|
+
/* the phone: the label and Change share a line, the value and its control take the width */
|
|
312
425
|
@media (max-width:560px){
|
|
313
|
-
.setRow{grid-template-columns:minmax(0,1fr);gap:
|
|
314
|
-
.setRow .k{
|
|
426
|
+
.setRow{grid-template-columns:minmax(0,1fr) auto;grid-template-areas:"k acts" "v v";gap:2px 0;}
|
|
427
|
+
.setRow .k{grid-area:k;}
|
|
428
|
+
.setRow .v{grid-area:v;}
|
|
429
|
+
.setRow .acts{grid-area:acts;}
|
|
315
430
|
}
|
|
316
|
-
/*
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
.
|
|
431
|
+
/* the phone: the parts take the width, the pairs stack, the rows' labels sit above */
|
|
432
|
+
@media (max-width:900px){
|
|
433
|
+
.part{padding:20px 18px;}
|
|
434
|
+
.pageSub{font-size:16px;}
|
|
320
435
|
}
|
|
321
436
|
|
|
322
437
|
/* a field: the label in the label face above, the input on one bottom
|
|
@@ -458,10 +573,8 @@ h1[tabindex="-1"]:focus:not(:focus-visible){outline:none;}
|
|
|
458
573
|
#panel-done[data-moment="wait"] #doneModules,
|
|
459
574
|
#panel-done[data-moment="wait"] .samePath,
|
|
460
575
|
#panel-done[data-moment="wait"] .again{display:none;}
|
|
461
|
-
|
|
462
|
-
#panel-done
|
|
463
|
-
#panel-done[data-moment="wait"].hopSignin .humanSteps>li:not([data-onboard-step="oauth-app"]){display:none;}
|
|
464
|
-
#panel-done[data-moment="wait"].hopSignin .humanSteps>li::before{content:none;}
|
|
576
|
+
/* part 03 before Create: the heading, its state and the sentence; the rest waits */
|
|
577
|
+
#panel-done:not(.on) .doneBody,#panel-done:not(.on) .again{display:none;}
|
|
465
578
|
.hopStatus{font-size:14px;font-weight:400;line-height:1.45;color:var(--ink-soft);margin:0;min-height:20px;}
|
|
466
579
|
.hopBar{height:3px;background:var(--rule-soft);margin:10px 0 12px;overflow:hidden;}
|
|
467
580
|
.hopBar span{display:block;height:100%;width:0;background:var(--accent);transition:width .8s ease;}
|
|
@@ -475,24 +588,24 @@ h1[tabindex="-1"]:focus:not(:focus-visible){outline:none;}
|
|
|
475
588
|
.hopHint{font-size:13px;color:var(--ink-faint);margin-right:auto;}
|
|
476
589
|
@media (hover:none){.hopHint{display:none;}}
|
|
477
590
|
.hopScore{font-family:var(--label-face);font-size:var(--label-size);letter-spacing:var(--label-space);text-transform:uppercase;color:var(--ink-soft);}
|
|
478
|
-
.hopWhile{font-size:14px;color:var(--ink-soft);margin-top:16px;}
|
|
479
|
-
.hopWhile button{min-height:24px;}
|
|
480
591
|
/* reduced motion: the sky stands still and there is nothing to steer */
|
|
481
592
|
.hop.isStill .hopRow{display:none;}
|
|
482
|
-
/* ARRIVE — the strip's three dots stand down (its note stays: it carries the
|
|
483
|
-
address), and the checklist shows one step at a time under a pager */
|
|
593
|
+
/* ARRIVE — the strip's three dots stand down (its note stays: it carries the address) */
|
|
484
594
|
#panel-done[data-moment="arrive"] #liveProgress .stages{display:none;}
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
#panel-done
|
|
488
|
-
.
|
|
489
|
-
#panel-done
|
|
490
|
-
.
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
}
|
|
495
|
-
|
|
595
|
+
/* the checklist (task 1004648, the mockup's steps): one dot per step — an empty ring,
|
|
596
|
+
a tick in the ok ink once the server has verified it — and every step on show */
|
|
597
|
+
#panel-done .humanSteps{margin-top:18px;}
|
|
598
|
+
#panel-done .humanSteps>li{grid-template-columns:24px 1fr;gap:0 12px;padding:12px 0 14px;border-top:0;}
|
|
599
|
+
#panel-done .humanSteps>li:last-child{border-bottom:0;}
|
|
600
|
+
#panel-done .humanSteps>li::before{content:"";box-sizing:border-box;width:24px;height:24px;padding:0;border-radius:50%;border:1px solid var(--glass-edge);
|
|
601
|
+
display:inline-flex;align-items:center;justify-content:center;font-family:var(--font-body);font-size:13px;letter-spacing:0;}
|
|
602
|
+
#panel-done .humanSteps>li.sdone::before{content:"✓";text-transform:none;color:var(--ok);background:color-mix(in srgb,var(--ok) 12%,transparent);border:1px solid var(--ok);}
|
|
603
|
+
#panel-done .humanSteps>li.slocked::before{border:1px solid var(--rule-soft);}
|
|
604
|
+
#panel-done .humanSteps b{font-size:15px;line-height:24px;}
|
|
605
|
+
.alive{margin-top:18px;padding-top:18px;border-top:1px solid var(--rule);}
|
|
606
|
+
#view-new .aliveH{margin:0;font-family:var(--font-display);font-size:28px;font-weight:200;letter-spacing:-.02em;line-height:1.2;text-transform:none;color:var(--ink);}
|
|
607
|
+
#view-new #panel-done .lede{margin:8px 0 0;font-size:14.5px;line-height:1.5;color:var(--ink-soft);}
|
|
608
|
+
#view-new #panel-done .lede a{color:var(--link-ink);text-decoration:underline;text-underline-offset:3px;}
|
|
496
609
|
|
|
497
610
|
/* ── the standup strip (task 2083), drawn as the lifecycle rail (DESIGN.md):
|
|
498
611
|
three hairlines, a 7px dot, one lit step — no plate, no connector, no
|
|
@@ -579,6 +692,8 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
579
692
|
fallback before a choice is painted. */
|
|
580
693
|
.lookGrid{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,300px);gap:28px;align-items:start;}
|
|
581
694
|
@media (max-width:760px){.lookGrid{grid-template-columns:minmax(0,1fr);}}
|
|
695
|
+
/* in part 02's Look row the picker has one column's width, so its preview sits under it */
|
|
696
|
+
#reviewRows .lookGrid{grid-template-columns:minmax(0,1fr);}
|
|
582
697
|
.lookSw{flex:none;display:inline-flex;gap:3px;margin-top:3px;}
|
|
583
698
|
.lookSw i{display:block;width:14px;height:14px;border-radius:50%;border:1px solid var(--rule);}
|
|
584
699
|
.lookSw.custom i{background:conic-gradient(var(--sea),var(--accent),var(--terracotta),var(--sea));}
|
|
@@ -1419,45 +1534,45 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
1419
1534
|
</section>
|
|
1420
1535
|
|
|
1421
1536
|
<!-- ══════════════════ VIEW · NEW PROJECT ══════════════════════════════════
|
|
1422
|
-
The whole create
|
|
1423
|
-
§4 — that route now 302s here).
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1537
|
+
The whole create flow, absorbed from /create (task 1002763; direction
|
|
1538
|
+
§4 — that route now 302s here). Since task 1004648 it is ONE page (the design
|
|
1539
|
+
of record docs/design/mocks/day-night-rooms/): sign-in stays the gate in front,
|
|
1540
|
+
then three parts — 01 your project, 02 how it's run (a summary to skim, each row
|
|
1541
|
+
opening today's real control in place), 03 Connect GitHub once the project
|
|
1542
|
+
exists. Same trust boundary as ever: every button here only ENQUEUES a
|
|
1543
|
+
provisioning request (ADR 0111). The page carries a static `on` so a no-script
|
|
1544
|
+
visitor still reads it rather than an empty card. -->
|
|
1429
1545
|
<section id="view-new" hidden>
|
|
1430
|
-
<!-- the
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
:root, no literal); the chrome seed hangs in the window and grows
|
|
1434
|
-
|
|
1435
|
-
breathe and the seed's float, all inside the kill
|
|
1436
|
-
|
|
1546
|
+
<!-- the room (tasks 1004504 and 1004648): the studio's lofi room behind the page. Night
|
|
1547
|
+
after dark, a day room in daylight — day from 07:00 to 18:59 on the viewer's own
|
|
1548
|
+
clock (data-sky on #view-new, re-checked each minute). Every colour is a mix of the
|
|
1549
|
+
fifteen (no page :root, no literal); the chrome seed hangs in the window and grows
|
|
1550
|
+
as the page fills in (data-screen + data-fill). The only motion is a slow twinkle,
|
|
1551
|
+
the clouds' drift, the lamp's breathe and the seed's float, all inside the kill
|
|
1552
|
+
switch. Decoration only. -->
|
|
1553
|
+
<div class="wizRoom" id="wizRoom" data-screen="page" data-fill="0" aria-hidden="true">
|
|
1437
1554
|
<div class="rmWindow">
|
|
1438
1555
|
<span class="rmMoon"></span>
|
|
1439
1556
|
<span class="rmStar rmS1"></span><span class="rmStar rmS2"></span><span class="rmStar rmS3"></span><span class="rmStar rmS4"></span><span class="rmStar rmS5"></span>
|
|
1557
|
+
<span class="rmCloud rmC1"></span><span class="rmCloud rmC2"></span>
|
|
1440
1558
|
<span class="rmSeed"><img src="/assets/world/r2-chrome-blob-one-cut.webp" alt=""></span>
|
|
1441
1559
|
<span class="rmTower rmT1"></span><span class="rmTower rmT2"></span><span class="rmTower rmT3"></span><span class="rmTower rmT4"></span><span class="rmTower rmT5"></span>
|
|
1442
1560
|
<span class="rmLight rmL1"></span><span class="rmLight rmL2"></span><span class="rmLight rmL3"></span><span class="rmLight rmL4"></span><span class="rmLight rmL5"></span><span class="rmLight rmL6"></span>
|
|
1443
1561
|
<span class="rmMullion"></span>
|
|
1444
1562
|
</div>
|
|
1445
|
-
<span class="rmFloor"></span>
|
|
1563
|
+
<span class="rmFloor"></span><span class="rmSun"></span>
|
|
1446
1564
|
<span class="rmGlow"></span><span class="rmStem"></span><span class="rmShade"></span>
|
|
1447
1565
|
<span class="rmMug"></span><span class="rmLeaf rmF1"></span><span class="rmLeaf rmF2"></span>
|
|
1448
1566
|
<span class="rmGrain"></span>
|
|
1449
1567
|
</div>
|
|
1450
1568
|
<div class="wrap viewWrap">
|
|
1451
1569
|
<div class="card">
|
|
1452
|
-
<!-- no progress rail (owner, 2026-10-01): the eyebrow names where you are and one
|
|
1453
|
-
Back walks the screens backwards -->
|
|
1454
1570
|
<div class="wizTop">
|
|
1455
1571
|
<span class="wizEyebrow" id="wizEyebrow">New project</span>
|
|
1456
|
-
<button type="button" class="wizBack" id="wizBack" hidden>← Back</button>
|
|
1457
1572
|
</div>
|
|
1458
1573
|
<div class="createSplit">
|
|
1459
1574
|
<div>
|
|
1460
|
-
<!--
|
|
1575
|
+
<!-- sign in: the gate in front, unchanged -->
|
|
1461
1576
|
<section class="panel" id="panel-gate" aria-labelledby="gate-h">
|
|
1462
1577
|
<h1 id="gate-h">Make something.</h1>
|
|
1463
1578
|
<p class="lede">Sign in with GitHub to start your project.</p>
|
|
@@ -1482,591 +1597,564 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
1482
1597
|
<div class="alert" id="wizGateAlert" role="alert"></div>
|
|
1483
1598
|
</section>
|
|
1484
1599
|
|
|
1485
|
-
<!--
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
in place (task 1004420), then joins the ordinary flow marked "demo". The panel
|
|
1490
|
-
carries a static `on` so a no-script visitor reads it rather than an empty card. -->
|
|
1491
|
-
<section class="panel on" id="panel-fork" aria-labelledby="fork-h">
|
|
1600
|
+
<!-- the one page (task 1004648): three parts, nothing to confirm. Create waits only
|
|
1601
|
+
for a name and the terms tick; the screening stop still runs before anything
|
|
1602
|
+
is created. -->
|
|
1603
|
+
<section class="panel on" id="panel-page" aria-labelledby="page-h">
|
|
1492
1604
|
<!-- The standup already being watched, kept one click away (task 1003503).
|
|
1493
1605
|
Baked markup, hidden until enter() has a record to name. -->
|
|
1494
1606
|
<p class="resumeOffer" id="wizResume" hidden>still watching <strong id="wizResumeName">your project</strong> — <a href="#" id="wizResumeGo">resume it</a></p>
|
|
1495
|
-
<
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
<
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1607
|
+
<h1 id="page-h">Make something.<span class="demoTag" id="demoTag" hidden>demo</span></h1>
|
|
1608
|
+
<p class="pageSub" id="pageSub">Three parts, one page. Just looking? <button type="button" class="linklike" id="wizDemo" aria-controls="demoSetup" aria-expanded="false">Try a small demo instead</button>.</p>
|
|
1609
|
+
|
|
1610
|
+
<div class="wizParts" id="wizParts">
|
|
1611
|
+
<!-- 01 · your project -->
|
|
1612
|
+
<div class="part" id="part-project" aria-labelledby="p1-h">
|
|
1613
|
+
<h2 id="p1-h"><span class="n">01</span>Your project</h2>
|
|
1614
|
+
<!-- auto-fill: the answers this account gave on its most recent project -->
|
|
1615
|
+
<p class="fillOffer" id="physFillOffer" hidden><button type="button" class="linklike" id="physFromAccount">Fill these in from my last project</button></p>
|
|
1616
|
+
<!-- the demo route (task 1004420, BV2.PS09): opened in place at the top of part
|
|
1617
|
+
01 by the small link under the heading; the rest of the page is unchanged
|
|
1618
|
+
and marked "demo" (D9). The fit check is a copy of modules/provisioning/demo.js
|
|
1619
|
+
fitCheck, held equal by tests/wizard_demo.mjs. -->
|
|
1620
|
+
<div id="demoSetup" class="demoView" hidden>
|
|
1621
|
+
<h3 class="partH3" id="demo-h1" tabindex="-1">Try a demo.</h3>
|
|
1622
|
+
<p class="hint demoLede">A small, time-boxed project to learn by doing. You can keep it at the end.</p>
|
|
1623
|
+
<div class="demoSteppers">
|
|
1624
|
+
<div class="wizField"><span id="demoPeopleLbl">People, you included</span>
|
|
1625
|
+
<div class="demoStep" role="group" aria-labelledby="demoPeopleLbl">
|
|
1626
|
+
<button type="button" class="btn small ghost" data-demo-step="people" data-by="-1" aria-label="One fewer person">−</button>
|
|
1627
|
+
<output id="demoPeople" aria-live="polite">3</output>
|
|
1628
|
+
<button type="button" class="btn small ghost" data-demo-step="people" data-by="1" aria-label="One more person">+</button>
|
|
1629
|
+
</div>
|
|
1630
|
+
</div>
|
|
1631
|
+
<div class="wizField"><span id="demoHoursLbl">Hours each</span>
|
|
1632
|
+
<div class="demoStep" role="group" aria-labelledby="demoHoursLbl">
|
|
1633
|
+
<button type="button" class="btn small ghost" data-demo-step="hours" data-by="-1" aria-label="One hour less">−</button>
|
|
1634
|
+
<output id="demoHours" aria-live="polite">4</output>
|
|
1635
|
+
<button type="button" class="btn small ghost" data-demo-step="hours" data-by="1" aria-label="One hour more">+</button>
|
|
1636
|
+
</div>
|
|
1637
|
+
</div>
|
|
1523
1638
|
</div>
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
<
|
|
1639
|
+
<label class="wizField"><span>Your idea</span>
|
|
1640
|
+
<input type="text" id="demoIdea" maxlength="600" placeholder="A voting app for movie night" autocomplete="off">
|
|
1641
|
+
</label>
|
|
1642
|
+
<p class="hint demoFitLine" aria-live="polite"><span id="demoFitSum">3 people × 4 hours = 12 builder-hours.</span> <span id="demoFitVerdict">Enough for a small version. Trim it to one shared list, voting and a winner reveal; accounts and notifications will not fit.</span></p>
|
|
1643
|
+
<div class="demoInvites" id="demoInvites">
|
|
1644
|
+
<label class="wizField"><span>Invite by GitHub handle</span>
|
|
1645
|
+
<input type="text" id="demoInvite1" placeholder="teammate’s handle" autocomplete="off" autocapitalize="off" spellcheck="false" maxlength="39">
|
|
1646
|
+
</label>
|
|
1647
|
+
<label class="wizField"><span>And one more</span>
|
|
1648
|
+
<input type="text" id="demoInvite2" placeholder="teammate’s handle" autocomplete="off" autocapitalize="off" spellcheck="false" maxlength="39">
|
|
1649
|
+
</label>
|
|
1650
|
+
</div>
|
|
1651
|
+
<p class="finePrint">An unkept demo goes offline after 30 days. We warn you first, and it can come back.</p>
|
|
1652
|
+
<div class="demoActs">
|
|
1653
|
+
<button type="button" class="btn small" id="demoStart">Use these</button>
|
|
1654
|
+
<button type="button" class="linklike" id="demoCancel">Make a real project instead</button>
|
|
1530
1655
|
</div>
|
|
1531
1656
|
</div>
|
|
1532
|
-
</div>
|
|
1533
|
-
<label class="wizField"><span>Your idea</span>
|
|
1534
|
-
<input type="text" id="demoIdea" maxlength="600" placeholder="A voting app for movie night" autocomplete="off">
|
|
1535
|
-
</label>
|
|
1536
|
-
<p class="hint demoFitLine" aria-live="polite"><span id="demoFitSum">3 people × 4 hours = 12 builder-hours.</span> <span id="demoFitVerdict">Enough for a small version. Trim it to one shared list, voting and a winner reveal; accounts and notifications will not fit.</span></p>
|
|
1537
|
-
<div class="demoInvites" id="demoInvites">
|
|
1538
|
-
<label class="wizField"><span>Invite by GitHub handle</span>
|
|
1539
|
-
<input type="text" id="demoInvite1" placeholder="teammate’s handle" autocomplete="off" autocapitalize="off" spellcheck="false" maxlength="39">
|
|
1540
|
-
</label>
|
|
1541
|
-
<label class="wizField"><span>And one more</span>
|
|
1542
|
-
<input type="text" id="demoInvite2" placeholder="teammate’s handle" autocomplete="off" autocapitalize="off" spellcheck="false" maxlength="39">
|
|
1543
|
-
</label>
|
|
1544
|
-
</div>
|
|
1545
|
-
<p class="finePrint">An unkept demo goes offline after 30 days. We warn you first, and it can come back.</p>
|
|
1546
|
-
<div class="nav">
|
|
1547
|
-
<span></span>
|
|
1548
|
-
<button type="button" class="btn" id="demoStart">Continue</button>
|
|
1549
|
-
</div>
|
|
1550
|
-
</div>
|
|
1551
|
-
</section>
|
|
1552
1657
|
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
<
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
<button type="button" class="tpill" data-type="non-profit" aria-pressed="false">Non-profit</button>
|
|
1569
|
-
<button type="button" class="tpill" data-type="not-sure" aria-pressed="false">Not sure</button>
|
|
1658
|
+
<!-- the name, the kind (task 1002772 — a declaration, closed vocabulary, Not
|
|
1659
|
+
sure the escape hatch) and the optional sentence that puts the project on
|
|
1660
|
+
the public map (ADR 0182 D4) -->
|
|
1661
|
+
<label class="wizField"><span>Name</span>
|
|
1662
|
+
<input type="text" id="newName" placeholder="Moonbase" autocomplete="off" maxlength="80" aria-label="Project name">
|
|
1663
|
+
<div class="hint" id="h-name"> </div>
|
|
1664
|
+
</label>
|
|
1665
|
+
<div class="wizField"><span id="typeLbl">Kind</span>
|
|
1666
|
+
<div class="typeCards" id="typeCards" role="group" aria-labelledby="typeLbl">
|
|
1667
|
+
<button type="button" class="tpill" data-type="game" aria-pressed="false">Game</button>
|
|
1668
|
+
<button type="button" class="tpill" data-type="research" aria-pressed="false">Research</button>
|
|
1669
|
+
<button type="button" class="tpill" data-type="business" aria-pressed="false">Business</button>
|
|
1670
|
+
<button type="button" class="tpill" data-type="non-profit" aria-pressed="false">Non-profit</button>
|
|
1671
|
+
<button type="button" class="tpill" data-type="not-sure" aria-pressed="false">Not sure</button>
|
|
1672
|
+
</div>
|
|
1570
1673
|
</div>
|
|
1571
|
-
<
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
<input type="text" id="f-desc" maxlength="600" placeholder="A co-op space game built by its players" autocomplete="off">
|
|
1575
|
-
</label>
|
|
1576
|
-
<div class="nav">
|
|
1577
|
-
<span></span>
|
|
1578
|
-
<button type="submit" class="btn">Continue</button>
|
|
1579
|
-
</div>
|
|
1580
|
-
</form>
|
|
1581
|
-
</section>
|
|
1674
|
+
<label class="wizField"><span>In a sentence <small>(optional, it goes on the public map)</small></span>
|
|
1675
|
+
<input type="text" id="f-desc" maxlength="600" placeholder="A co-op space game built by its players" autocomplete="off">
|
|
1676
|
+
</label>
|
|
1582
1677
|
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
<form data-next="4" id="checksForm">
|
|
1595
|
-
<div class="physRow2">
|
|
1596
|
-
<label class="wizField"><span>Where are you?</span><select id="physCountry"><option value="">Choose…</option></select></label>
|
|
1597
|
-
<label class="wizField" id="physRegionField" hidden><span>State or province</span><select id="physRegion"><option value="">Choose…</option></select></label>
|
|
1598
|
-
</div>
|
|
1599
|
-
<div class="wizField"><span id="physGeoLbl">Where will builders be?</span>
|
|
1600
|
-
<div class="typeCards physCells" role="group" aria-labelledby="physGeoLbl">
|
|
1601
|
-
<button type="button" class="tpill" data-phys="builder_geography" data-val="us-only" aria-pressed="false">US only</button>
|
|
1602
|
-
<button type="button" class="tpill" data-phys="builder_geography" data-val="us-eu" aria-pressed="false">US and EU</button>
|
|
1603
|
-
<button type="button" class="tpill" data-phys="builder_geography" data-val="global" aria-pressed="false">Anywhere</button>
|
|
1604
|
-
<button type="button" class="tpill" data-phys="builder_geography" data-val="not-sure" aria-pressed="false">Not sure</button>
|
|
1678
|
+
<!-- the quick checks: the planet-physics answers that change something (tasks
|
|
1679
|
+
1004418 and 1004419), under planet-physics.js's own keys. Create asks
|
|
1680
|
+
POST /provisioning/physics-check first — the same screen and soft-limit
|
|
1681
|
+
table the create runs — and a stop ends the page there, before anything
|
|
1682
|
+
exists. The age tiers are described, never claimed as enforced (spec D6).
|
|
1683
|
+
A demo's answers are the demo's own, so the checks stand down for it. -->
|
|
1684
|
+
<div class="checks" id="checksMain">
|
|
1685
|
+
<p class="checksHead">A few quick checks. They decide which legal and payout options we can offer.</p>
|
|
1686
|
+
<div class="physRow2">
|
|
1687
|
+
<label class="wizField"><span>Where are you?</span><select id="physCountry"><option value="">Choose…</option></select></label>
|
|
1688
|
+
<label class="wizField" id="physRegionField" hidden><span>State or province</span><select id="physRegion"><option value="">Choose…</option></select></label>
|
|
1605
1689
|
</div>
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1690
|
+
<div class="wizField"><span id="physAgeLbl">Will anyone under 18 build?</span>
|
|
1691
|
+
<div class="typeCards physCells" role="group" aria-labelledby="physAgeLbl">
|
|
1692
|
+
<button type="button" class="tpill" data-phys="minors_on_board" data-val="false" aria-pressed="false">No</button>
|
|
1693
|
+
<button type="button" class="tpill" data-phys="minors_on_board" data-val="true" aria-pressed="false">Yes</button>
|
|
1694
|
+
</div>
|
|
1611
1695
|
</div>
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
<p class="finePrint">A guardian signs for each young builder and controls their payouts. The platform does not check ages for you yet.</p>
|
|
1621
|
-
</div>
|
|
1622
|
-
<div class="wizField" id="physIntent"><span id="physWhoLbl">Who’s behind it?</span>
|
|
1623
|
-
<div class="typeCards physCells" role="group" aria-labelledby="physWhoLbl">
|
|
1624
|
-
<button type="button" class="tpill" data-phys="entity" data-val="intent-solo" aria-pressed="false">Just me</button>
|
|
1625
|
-
<button type="button" class="tpill" data-phys="entity" data-val="intent-company" aria-pressed="false">A company</button>
|
|
1626
|
-
<button type="button" class="tpill" data-phys="entity" data-val="intent-nonprofit" aria-pressed="false">A nonprofit</button>
|
|
1627
|
-
<button type="button" class="tpill" data-phys="entity" data-val="intent-unsure" aria-pressed="false">Not sure yet</button>
|
|
1696
|
+
<div class="physNote" id="physAges" hidden>
|
|
1697
|
+
<p class="physNoteH">The age tiers young builders work under</p>
|
|
1698
|
+
<dl class="physTiers">
|
|
1699
|
+
<dt>13 to 15</dt><dd>Non-monetary tracks only</dd>
|
|
1700
|
+
<dt>16 to 17</dt><dd>Paid work, with a guardian’s co-signature and a work-permit attestation</dd>
|
|
1701
|
+
<dt>18 and over</dt><dd>Full access</dd>
|
|
1702
|
+
</dl>
|
|
1703
|
+
<p class="finePrint">A guardian signs for each young builder and controls their payouts. The platform does not check ages for you yet.</p>
|
|
1628
1704
|
</div>
|
|
1629
|
-
<
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
<button type="button" class="tpill" data-phys="entity" data-val="corporate-division" aria-pressed="false">Division of a corporation</button>
|
|
1637
|
-
<button type="button" class="tpill" data-phys="entity" data-val="research" aria-pressed="false">Research entity</button>
|
|
1705
|
+
<div class="wizField"><span id="physGeoLbl">Where will builders be?</span>
|
|
1706
|
+
<div class="typeCards physCells" role="group" aria-labelledby="physGeoLbl">
|
|
1707
|
+
<button type="button" class="tpill" data-phys="builder_geography" data-val="us-only" aria-pressed="false">US only</button>
|
|
1708
|
+
<button type="button" class="tpill" data-phys="builder_geography" data-val="us-eu" aria-pressed="false">US and EU</button>
|
|
1709
|
+
<button type="button" class="tpill" data-phys="builder_geography" data-val="global" aria-pressed="false">Anywhere</button>
|
|
1710
|
+
<button type="button" class="tpill" data-phys="builder_geography" data-val="not-sure" aria-pressed="false">Not sure</button>
|
|
1711
|
+
</div>
|
|
1638
1712
|
</div>
|
|
1639
|
-
<
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1713
|
+
<div class="wizField" id="physIntent"><span id="physWhoLbl">Who’s behind it?</span>
|
|
1714
|
+
<div class="typeCards physCells" role="group" aria-labelledby="physWhoLbl">
|
|
1715
|
+
<button type="button" class="tpill" data-phys="entity" data-val="intent-solo" aria-pressed="false">Just me</button>
|
|
1716
|
+
<button type="button" class="tpill" data-phys="entity" data-val="intent-company" aria-pressed="false">A company</button>
|
|
1717
|
+
<button type="button" class="tpill" data-phys="entity" data-val="intent-nonprofit" aria-pressed="false">A nonprofit</button>
|
|
1718
|
+
<button type="button" class="tpill" data-phys="entity" data-val="intent-unsure" aria-pressed="false">Not sure yet</button>
|
|
1719
|
+
</div>
|
|
1720
|
+
<button type="button" class="physLink" id="physHaveEntity">We already have a legal entity</button>
|
|
1643
1721
|
</div>
|
|
1644
|
-
<
|
|
1645
|
-
|
|
1646
|
-
<
|
|
1647
|
-
|
|
1722
|
+
<div class="wizField" id="physForms" hidden><span>Your legal entity</span>
|
|
1723
|
+
<p class="physGrp">Organization</p>
|
|
1724
|
+
<div class="typeCards physCells" role="group" aria-label="Organization">
|
|
1725
|
+
<button type="button" class="tpill" data-phys="entity" data-val="nonprofit" aria-pressed="false">Nonprofit</button>
|
|
1726
|
+
<button type="button" class="tpill" data-phys="entity" data-val="for-profit" aria-pressed="false">For-profit company</button>
|
|
1727
|
+
<button type="button" class="tpill" data-phys="entity" data-val="corporate-division" aria-pressed="false">Division of a corporation</button>
|
|
1728
|
+
<button type="button" class="tpill" data-phys="entity" data-val="research" aria-pressed="false">Research entity</button>
|
|
1729
|
+
</div>
|
|
1730
|
+
<p class="physGrp">Group</p>
|
|
1731
|
+
<div class="typeCards physCells" role="group" aria-label="Group">
|
|
1732
|
+
<button type="button" class="tpill" data-phys="entity" data-val="university-project" aria-pressed="false">University project</button>
|
|
1733
|
+
<button type="button" class="tpill" data-phys="entity" data-val="social-group" aria-pressed="false">Social group</button>
|
|
1734
|
+
</div>
|
|
1735
|
+
<p class="physGrp">Individual</p>
|
|
1736
|
+
<div class="typeCards physCells" role="group" aria-label="Individual">
|
|
1737
|
+
<button type="button" class="tpill" data-phys="entity" data-val="single-owner-llc" aria-pressed="false">Single-owner LLC</button>
|
|
1738
|
+
<button type="button" class="tpill" data-phys="entity" data-val="private-individual" aria-pressed="false">Private individual</button>
|
|
1739
|
+
</div>
|
|
1740
|
+
<button type="button" class="physLink" id="physNoEntity">We don’t have one yet</button>
|
|
1648
1741
|
</div>
|
|
1649
|
-
<
|
|
1742
|
+
<div class="hint" id="h-phys"> </div>
|
|
1650
1743
|
</div>
|
|
1651
|
-
|
|
1652
|
-
<div class="
|
|
1653
|
-
<span></
|
|
1654
|
-
<
|
|
1744
|
+
<!-- the screening stop, in place: nothing is created -->
|
|
1745
|
+
<div class="checksStop" id="checksStop" role="alert" hidden>
|
|
1746
|
+
<h3 class="partH3" id="phys-hstop" tabindex="-1">This can’t be built <em>on <span data-brand-product-inline>Cloud Bongos</span></em></h3>
|
|
1747
|
+
<p id="physStopMsg"></p>
|
|
1748
|
+
<div class="demoActs">
|
|
1749
|
+
<button type="button" class="btn small ghost" id="physStartOver">Change my answers</button>
|
|
1750
|
+
<a class="btn small" href="/contact">Contact us</a>
|
|
1751
|
+
</div>
|
|
1655
1752
|
</div>
|
|
1656
|
-
</form>
|
|
1657
|
-
</div>
|
|
1658
|
-
<!-- the screening stop: nothing is created -->
|
|
1659
|
-
<div id="checksStop" hidden>
|
|
1660
|
-
<h1 id="phys-hstop">This can’t be built <em>on <span data-brand-product-inline>Cloud Bongos</span></em></h1>
|
|
1661
|
-
<p class="lede" id="physStopMsg"></p>
|
|
1662
|
-
<div class="nav">
|
|
1663
|
-
<button type="button" class="btn ghost" id="physStartOver">Start over</button>
|
|
1664
|
-
<a class="btn" href="/contact">Contact us</a>
|
|
1665
1753
|
</div>
|
|
1666
|
-
</div>
|
|
1667
|
-
</section>
|
|
1668
1754
|
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
<
|
|
1692
|
-
<
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
<div id="
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
<
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
</label>
|
|
1738
|
-
<!-- visibility stated BEFORE GitHub's own radio is the first place it appears (task 1002721) -->
|
|
1739
|
-
<div class="hint" style="grid-column:1 / -1;">Public or private both work, and we never change it.</div>
|
|
1755
|
+
<!-- 02 · how it's run: a summary to skim, not a gate (task 1004648). Every row is
|
|
1756
|
+
prefilled from the answers above; Change opens today's own control in place —
|
|
1757
|
+
moved here whole, so every handler and id is the one it always was — and Done
|
|
1758
|
+
closes it again. No row needs confirming. -->
|
|
1759
|
+
<div class="part" id="part-run" aria-labelledby="p2-h">
|
|
1760
|
+
<h2 id="p2-h"><span class="n">02</span>How it’s run <span class="state">filled in from your answers</span></h2>
|
|
1761
|
+
<div class="setRows" id="reviewRows">
|
|
1762
|
+
|
|
1763
|
+
<div class="setRow" data-row="code">
|
|
1764
|
+
<span class="k">Code</span>
|
|
1765
|
+
<div class="v"><span class="rowV" data-row-v></span><small class="rowS" data-row-s></small>
|
|
1766
|
+
<div class="opts" hidden>
|
|
1767
|
+
<div class="typeCards physCells" role="group" aria-label="Your project’s state">
|
|
1768
|
+
<button type="button" class="tpill" data-phys="project_state" data-val="new" aria-pressed="false">Starting from zero</button>
|
|
1769
|
+
<button type="button" class="tpill" data-phys="project_state" data-val="existing" aria-pressed="false">Already started</button>
|
|
1770
|
+
</div>
|
|
1771
|
+
<fieldset class="physExisting" id="physExisting" data-limit="existing_work" hidden>
|
|
1772
|
+
<legend>What already exists? Pick all that apply, then your main one.</legend>
|
|
1773
|
+
<label class="physCheck"><input type="checkbox" data-work="code"> <span>Code files</span> <span class="physMain"><input type="radio" name="physMain" value="code" aria-label="Code files is the main one"> main</span></label>
|
|
1774
|
+
<label class="physCheck"><input type="checkbox" data-work="digital-files"> <span>Digital files <small>Word documents, spreadsheets, other software.</small></span> <span class="physMain"><input type="radio" name="physMain" value="digital-files" aria-label="Digital files is the main one"> main</span></label>
|
|
1775
|
+
<label class="physCheck"><input type="checkbox" data-work="physical-work"> <span>Physical files or work <small>You’ll describe it later, in words or a document.</small></span> <span class="physMain"><input type="radio" name="physMain" value="physical-work" aria-label="Physical files or work is the main one"> main</span></label>
|
|
1776
|
+
</fieldset>
|
|
1777
|
+
<p class="physWhy" data-why="existing_work" hidden></p>
|
|
1778
|
+
<div class="choices" role="group" aria-label="Starting point">
|
|
1779
|
+
<button type="button" class="choice" id="c-green" aria-pressed="true">
|
|
1780
|
+
<b>A new GitHub repo</b>
|
|
1781
|
+
<p>Private, set up for you</p>
|
|
1782
|
+
</button>
|
|
1783
|
+
<button type="button" class="choice" id="c-adopt" aria-pressed="false">
|
|
1784
|
+
<b>A repo I already have</b>
|
|
1785
|
+
<p>Public or private</p>
|
|
1786
|
+
</button>
|
|
1787
|
+
</div>
|
|
1788
|
+
<div class="reassure" id="adoptNote">Nothing is overwritten. You see conflicts first, and open issues become tasks.</div>
|
|
1789
|
+
<!-- GitHub-integrated repo picker (adopt) + auto-create (fresh) — task 1002099.
|
|
1790
|
+
Without repo access we fall back to the manual owner/repo inputs
|
|
1791
|
+
(#manualHome), which stay authoritative. No repo-access ask here (task
|
|
1792
|
+
1004555): every hub sign-in asks for repo access (ADR 0364), and a
|
|
1793
|
+
missing token is fetched by one automatic GitHub round-trip. Only when
|
|
1794
|
+
that hop could not help does this line show, above the manual fields. -->
|
|
1795
|
+
<div id="ghNoAccess" class="hint" hidden>We couldn’t read your GitHub repositories just now, so enter the repo by hand below.</div>
|
|
1796
|
+
<div id="ghBusy" class="hint" hidden>Reading your GitHub repositories…</div>
|
|
1797
|
+
<div id="ghAdopt" class="wizField" hidden>
|
|
1798
|
+
<span>Pick one of your repositories</span>
|
|
1799
|
+
<input type="text" id="ghSearch" placeholder="Search your repos…" autocomplete="off" aria-label="Search your repositories">
|
|
1800
|
+
<div id="ghList" class="ghlist" role="group" aria-label="Your repositories"></div>
|
|
1801
|
+
<div class="hint" id="ghAdoptHint"> </div>
|
|
1802
|
+
<!-- visibility stated on EVERY repo path (task 1002721) -->
|
|
1803
|
+
<div class="hint">We never change it: public stays public, private stays private.</div>
|
|
1804
|
+
</div>
|
|
1805
|
+
<div id="ghFresh" class="wizField" hidden>
|
|
1806
|
+
<span>New repository name</span>
|
|
1807
|
+
<input type="text" id="ghNewName" placeholder="moonbase" autocomplete="off" maxlength="100" aria-label="New repository name">
|
|
1808
|
+
<!-- visibility is stated on EVERY repo path (task 1002721); updateFreshPreview()
|
|
1809
|
+
replaces this floor with the same claim plus the resolved repo URL -->
|
|
1810
|
+
<div class="hint" id="ghFreshHint">A new <strong>private</strong> repo. You can make it public later.</div>
|
|
1811
|
+
</div>
|
|
1812
|
+
<div class="row2" id="manualHome">
|
|
1813
|
+
<label class="wizField"><span>GitHub owner <small>(user or org)</small></span>
|
|
1814
|
+
<input type="text" id="f-owner" placeholder="acme" autocomplete="off" maxlength="60">
|
|
1815
|
+
</label>
|
|
1816
|
+
<label class="wizField"><span>Repository name</span>
|
|
1817
|
+
<input type="text" id="f-repo" placeholder="moonbase" autocomplete="off" maxlength="120">
|
|
1818
|
+
</label>
|
|
1819
|
+
<!-- visibility stated BEFORE GitHub's own radio is the first place it appears (task 1002721) -->
|
|
1820
|
+
<div class="hint" style="grid-column:1 / -1;">Public or private both work, and we never change it.</div>
|
|
1821
|
+
</div>
|
|
1822
|
+
<div class="hint" id="h-home"> </div>
|
|
1740
1823
|
</div>
|
|
1741
|
-
<div class="hint" id="h-home"> </div>
|
|
1742
1824
|
</div>
|
|
1825
|
+
<span class="acts"><button type="button" class="rowChg" data-row-chg aria-expanded="false">Change</button></span>
|
|
1743
1826
|
</div>
|
|
1744
|
-
<span class="acts"><button type="button" class="rowChg" data-row-chg aria-expanded="false">Edit</button></span>
|
|
1745
|
-
</div>
|
|
1746
1827
|
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
<div class="hint" id="h-slug"> </div>
|
|
1757
|
-
</label>
|
|
1758
|
-
<div class="addrConfirm" id="addrConfirm">
|
|
1759
|
-
<div class="addrBig" id="addrAssigned"></div>
|
|
1760
|
-
<p id="addrAssignedNote">Yours once it’s set up. You can add your own domain any time.</p>
|
|
1761
|
-
<details id="addrCustom">
|
|
1762
|
-
<summary>A domain I own</summary>
|
|
1763
|
-
<div class="inner">
|
|
1764
|
-
<label class="wizField"><span>Domain you own</span>
|
|
1765
|
-
<input type="text" id="f-domain" placeholder="moonbase.example.com" autocomplete="off" maxlength="253" spellcheck="false">
|
|
1766
|
-
<div class="hint" id="h-domain"> </div>
|
|
1767
|
-
</label>
|
|
1768
|
-
</div>
|
|
1769
|
-
</details>
|
|
1770
|
-
<label class="addrOpt"><input type="checkbox" id="f-noaddr">
|
|
1771
|
-
<span>No address yet. Sign-in can’t be switched on until it has one.</span>
|
|
1828
|
+
<!-- the address (tasks 1002704, 1002898 N8, PS19): the assigned address is
|
|
1829
|
+
stated, and both alternatives sit under it, on every path, the demo's too -->
|
|
1830
|
+
<div class="setRow" data-row="address">
|
|
1831
|
+
<span class="k">Address</span>
|
|
1832
|
+
<div class="v"><span class="rowV" data-row-v></span><small class="rowS" data-row-s></small>
|
|
1833
|
+
<div class="opts" hidden>
|
|
1834
|
+
<label class="wizField"><span>Project handle</span>
|
|
1835
|
+
<input type="text" id="f-slug" placeholder="moonbase" autocomplete="off" maxlength="40" spellcheck="false">
|
|
1836
|
+
<div class="hint" id="h-slug"> </div>
|
|
1772
1837
|
</label>
|
|
1838
|
+
<div class="addrConfirm" id="addrConfirm">
|
|
1839
|
+
<div class="addrBig" id="addrAssigned"></div>
|
|
1840
|
+
<p id="addrAssignedNote">Yours once it’s set up. You can add your own domain any time.</p>
|
|
1841
|
+
<details id="addrCustom">
|
|
1842
|
+
<summary>A domain I own</summary>
|
|
1843
|
+
<div class="inner">
|
|
1844
|
+
<label class="wizField"><span>Domain you own</span>
|
|
1845
|
+
<input type="text" id="f-domain" placeholder="moonbase.example.com" autocomplete="off" maxlength="253" spellcheck="false">
|
|
1846
|
+
<div class="hint" id="h-domain"> </div>
|
|
1847
|
+
</label>
|
|
1848
|
+
</div>
|
|
1849
|
+
</details>
|
|
1850
|
+
<label class="addrOpt"><input type="checkbox" id="f-noaddr">
|
|
1851
|
+
<span>No address yet. Sign-in can’t be switched on until it has one.</span>
|
|
1852
|
+
</label>
|
|
1853
|
+
</div>
|
|
1773
1854
|
</div>
|
|
1774
1855
|
</div>
|
|
1856
|
+
<span class="acts"><button type="button" class="rowChg" data-row-chg aria-expanded="false">Change</button></span>
|
|
1775
1857
|
</div>
|
|
1776
|
-
<span class="acts"><button type="button" class="rowChg" data-row-chg aria-expanded="false">Edit</button></span>
|
|
1777
|
-
</div>
|
|
1778
1858
|
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
<input type="radio" name="appPlatform" value="later" checked>
|
|
1790
|
-
<span><b>Decide later</b>
|
|
1791
|
-
<span>There’s no app to host until your builders write one.</span></span>
|
|
1792
|
-
</label>
|
|
1793
|
-
<label class="appOpt" id="appOptRender">
|
|
1794
|
-
<input type="radio" name="appPlatform" value="render" aria-describedby="appRenderWhat">
|
|
1795
|
-
<span><b>Render</b>
|
|
1796
|
-
<span id="appRenderWhat">We set it up on your own Render account. Render bills you directly.</span></span>
|
|
1797
|
-
</label>
|
|
1798
|
-
</fieldset>
|
|
1799
|
-
<p class="renderWhy" id="renderLater" role="status" hidden>Your new repo has no app yet, so nothing is created on Render now. Set it up from your project’s page once there is one.</p>
|
|
1800
|
-
<div class="renderSetup" id="renderSetup" hidden>
|
|
1801
|
-
<p class="renderWhy">Used once to create your app on your Render account, then thrown away — not kept, not even in this browser. A key can act on your whole Render account. Render bills you directly. <a href="https://dashboard.render.com/u/settings#api-keys" target="_blank" rel="noopener noreferrer">Create a key in Render</a></p>
|
|
1802
|
-
<div class="renderKeyRow">
|
|
1803
|
-
<label class="wizField"><span>Render API key</span>
|
|
1804
|
-
<input type="password" id="f-renderKey" autocomplete="off" spellcheck="false" maxlength="200" placeholder="rnd_…" aria-describedby="h-renderKey">
|
|
1805
|
-
</label>
|
|
1806
|
-
<button type="button" class="btn ghost small" id="renderCheck">Check key</button>
|
|
1859
|
+
<!-- the team (question 5, task 1004419): one person, or a team with a count and
|
|
1860
|
+
the month-three guess the founder corrects; who can join a team is the team
|
|
1861
|
+
shape the extras' preselect reads (task 1002341) -->
|
|
1862
|
+
<div class="setRow" data-row="team">
|
|
1863
|
+
<span class="k">Team</span>
|
|
1864
|
+
<div class="v"><span class="rowV" data-row-v></span><small class="rowS" data-row-s></small>
|
|
1865
|
+
<div class="opts" hidden>
|
|
1866
|
+
<div class="typeCards physCells" role="group" aria-label="One or many">
|
|
1867
|
+
<button type="button" class="tpill" data-phys-solo="one" aria-pressed="false">Just you to start</button>
|
|
1868
|
+
<button type="button" class="tpill" data-phys-solo="many" aria-pressed="false">A team</button>
|
|
1807
1869
|
</div>
|
|
1808
|
-
<div
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
<select id="f-renderRuntime">
|
|
1820
|
-
<option value="node">Node.js</option><option value="python">Python</option><option value="ruby">Ruby</option>
|
|
1821
|
-
<option value="go">Go</option><option value="rust">Rust</option><option value="elixir">Elixir</option>
|
|
1822
|
-
<option value="docker">Docker — use my repository’s Dockerfile</option>
|
|
1823
|
-
</select>
|
|
1824
|
-
</label>
|
|
1825
|
-
<label class="wizField" id="renderBuildWrap"><span>Build command <small>— Render needs one; the usual one is filled in</small></span>
|
|
1826
|
-
<input type="text" id="f-renderBuild" autocomplete="off" spellcheck="false" maxlength="500" placeholder="for example: npm ci">
|
|
1827
|
-
</label>
|
|
1828
|
-
<label class="wizField" id="renderStartWrap"><span>Start command</span>
|
|
1829
|
-
<input type="text" id="f-renderStart" autocomplete="off" spellcheck="false" maxlength="500" placeholder="for example: npm start">
|
|
1830
|
-
</label>
|
|
1831
|
-
<label class="wizField"><span>Plan</span>
|
|
1832
|
-
<select id="f-renderPlan"></select>
|
|
1833
|
-
</label>
|
|
1834
|
-
<label class="addrOpt"><input type="checkbox" id="f-renderDb">
|
|
1835
|
-
<span>My app needs a database (Render Postgres)</span>
|
|
1836
|
-
</label>
|
|
1837
|
-
<label class="wizField" id="renderDbPlanWrap" hidden><span>Database plan</span>
|
|
1838
|
-
<select id="f-renderDbPlan"></select>
|
|
1870
|
+
<div id="physTeam" hidden>
|
|
1871
|
+
<div class="wizField"><span id="physStartLbl">People at the start, you included</span>
|
|
1872
|
+
<div class="demoStep" role="group" aria-labelledby="physStartLbl">
|
|
1873
|
+
<button type="button" class="btn small ghost" data-phys-count="-1" aria-label="One fewer">−</button>
|
|
1874
|
+
<output id="physStartN" aria-live="polite">2</output>
|
|
1875
|
+
<button type="button" class="btn small ghost" data-phys-count="1" aria-label="One more">+</button>
|
|
1876
|
+
</div>
|
|
1877
|
+
</div>
|
|
1878
|
+
<p class="physGuessLine" id="physGuessLine" aria-live="polite"></p>
|
|
1879
|
+
<label class="wizField physAdjust"><span>Adjust month three</span>
|
|
1880
|
+
<input type="range" id="physExpected" min="2" max="30" step="1" value="5">
|
|
1839
1881
|
</label>
|
|
1882
|
+
<div class="wizField"><span id="teamLbl">Who can join?</span>
|
|
1883
|
+
<div class="typeCards" id="teamCards" role="group" aria-labelledby="teamLbl">
|
|
1884
|
+
<button type="button" class="tpill" data-team="small-team" aria-pressed="false">People I invite</button>
|
|
1885
|
+
<button type="button" class="tpill" data-team="community" aria-pressed="false">Anyone can apply</button>
|
|
1886
|
+
</div>
|
|
1887
|
+
</div>
|
|
1840
1888
|
</div>
|
|
1841
|
-
<div class="hint" id="h-render" role="status"> </div>
|
|
1842
1889
|
</div>
|
|
1843
1890
|
</div>
|
|
1891
|
+
<span class="acts"><button type="button" class="rowChg" data-row-chg aria-expanded="false">Change</button></span>
|
|
1844
1892
|
</div>
|
|
1845
|
-
<span class="acts"><button type="button" class="rowChg" data-row-chg aria-expanded="false">Edit</button></span>
|
|
1846
|
-
</div>
|
|
1847
1893
|
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1894
|
+
<!-- the extras (tasks 1002339, 1002340): the type's suggested set until the
|
|
1895
|
+
owner says otherwise; the server resolves the same bundle from the same
|
|
1896
|
+
declaration (ADR 0237), so accepting and changing nothing are one answer.
|
|
1897
|
+
The always-on core is stated as a clause, never as dead toggles. -->
|
|
1898
|
+
<div class="setRow" data-row="extras">
|
|
1899
|
+
<span class="k">Extras</span>
|
|
1900
|
+
<div class="v"><span class="rowV" data-row-v></span><small class="rowS" data-row-s></small>
|
|
1901
|
+
<div class="opts" hidden>
|
|
1902
|
+
<div class="wizField"><span id="modLbl">Extras for this project</span>
|
|
1903
|
+
<input type="text" id="modQ" placeholder="Search extras…" autocomplete="off" aria-label="Search the extras by name" aria-describedby="modFilterNote">
|
|
1904
|
+
<div class="hint" id="modFilterNote" aria-live="polite"></div>
|
|
1905
|
+
<div class="typeCards" id="modCards" role="group" aria-labelledby="modLbl"></div>
|
|
1906
|
+
</div>
|
|
1907
|
+
<div class="modWhy" id="modWhy" aria-live="polite"></div>
|
|
1908
|
+
<div class="reassure" id="modCoreNote"></div>
|
|
1860
1909
|
</div>
|
|
1861
|
-
<div class="modWhy" id="modWhy" aria-live="polite"></div>
|
|
1862
|
-
<div class="reassure" id="modCoreNote"></div>
|
|
1863
1910
|
</div>
|
|
1911
|
+
<span class="acts"><button type="button" class="rowChg" data-row-chg aria-expanded="false">Change</button></span>
|
|
1864
1912
|
</div>
|
|
1865
|
-
<span class="acts"><button type="button" class="rowChg" data-row-chg aria-expanded="false">Edit</button></span>
|
|
1866
|
-
</div>
|
|
1867
1913
|
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1914
|
+
<!-- rewards (question 6): intent only, pick several; never asked of a founder
|
|
1915
|
+
building alone (the table hides it, and this row goes with it) -->
|
|
1916
|
+
<div class="setRow" data-row="rewards">
|
|
1917
|
+
<span class="k">Rewards</span>
|
|
1918
|
+
<div class="v"><span class="rowV" data-row-v></span><small class="rowS" data-row-s></small>
|
|
1919
|
+
<div class="opts" hidden>
|
|
1920
|
+
<div class="typeCards physCells" role="group" aria-label="Rewards being considered">
|
|
1921
|
+
<button type="button" class="tpill" data-phys="reward_intents" data-val="non-monetary" aria-pressed="false">Learning and fun</button>
|
|
1922
|
+
<button type="button" class="tpill" data-phys="reward_intents" data-val="cash" aria-pressed="false">Cash for work</button>
|
|
1923
|
+
<button type="button" class="tpill" data-phys="reward_intents" data-val="equity" aria-pressed="false">Equity</button>
|
|
1924
|
+
<button type="button" class="tpill" data-phys="reward_intents" data-val="future-payouts" aria-pressed="false">Future payouts</button>
|
|
1925
|
+
</div>
|
|
1926
|
+
<ul class="physWhyList" data-why-list="reward_intents" hidden></ul>
|
|
1878
1927
|
</div>
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1928
|
+
</div>
|
|
1929
|
+
<span class="acts"><button type="button" class="rowChg" data-row-chg aria-expanded="false">Change</button></span>
|
|
1930
|
+
</div>
|
|
1931
|
+
|
|
1932
|
+
<!-- where the app runs (tasks 1004351, 1004352; ADR 0345): the hall is ours to
|
|
1933
|
+
host, so this row is only the owner's APP. "Decide later" is the default.
|
|
1934
|
+
The Render key lives in a variable only: never the draft, a URL or a log. -->
|
|
1935
|
+
<div class="setRow" data-row="app">
|
|
1936
|
+
<span class="k">Hosting</span>
|
|
1937
|
+
<div class="v"><span class="rowV" data-row-v></span><small class="rowS" data-row-s></small>
|
|
1938
|
+
<div class="opts" hidden>
|
|
1939
|
+
<fieldset class="appOpts" id="appOpts">
|
|
1940
|
+
<legend>Where your app runs</legend>
|
|
1941
|
+
<label class="appOpt">
|
|
1942
|
+
<input type="radio" name="appPlatform" value="later" checked>
|
|
1943
|
+
<span><b>Decide later</b>
|
|
1944
|
+
<span>There’s no app to host until your builders write one.</span></span>
|
|
1945
|
+
</label>
|
|
1946
|
+
<label class="appOpt" id="appOptRender">
|
|
1947
|
+
<input type="radio" name="appPlatform" value="render" aria-describedby="appRenderWhat">
|
|
1948
|
+
<span><b>Render</b>
|
|
1949
|
+
<span id="appRenderWhat">We set it up on your own Render account. Render bills you directly.</span></span>
|
|
1950
|
+
</label>
|
|
1951
|
+
</fieldset>
|
|
1952
|
+
<p class="renderWhy" id="renderLater" role="status" hidden>Your new repo has no app yet, so nothing is created on Render now. Set it up from your project’s page once there is one.</p>
|
|
1953
|
+
<div class="renderSetup" id="renderSetup" hidden>
|
|
1954
|
+
<p class="renderWhy">Used once to create your app on your Render account, then thrown away — not kept, not even in this browser. A key can act on your whole Render account. Render bills you directly. <a href="https://dashboard.render.com/u/settings#api-keys" target="_blank" rel="noopener noreferrer">Create a key in Render</a></p>
|
|
1955
|
+
<div class="renderKeyRow">
|
|
1956
|
+
<label class="wizField"><span>Render API key</span>
|
|
1957
|
+
<input type="password" id="f-renderKey" autocomplete="off" spellcheck="false" maxlength="200" placeholder="rnd_…" aria-describedby="h-renderKey">
|
|
1958
|
+
</label>
|
|
1959
|
+
<button type="button" class="btn ghost small" id="renderCheck">Check key</button>
|
|
1885
1960
|
</div>
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
<
|
|
1894
|
-
|
|
1961
|
+
<div class="hint" id="h-renderKey" role="status"> </div>
|
|
1962
|
+
<fieldset class="appOpts" id="renderWs" hidden>
|
|
1963
|
+
<legend>Which Render workspace</legend>
|
|
1964
|
+
<div id="renderWsList"></div>
|
|
1965
|
+
</fieldset>
|
|
1966
|
+
<fieldset class="appOpts" id="renderSvc" hidden>
|
|
1967
|
+
<legend>A new app, or one you already run</legend>
|
|
1968
|
+
<div id="renderSvcList"></div>
|
|
1969
|
+
</fieldset>
|
|
1970
|
+
<div class="renderNew" id="renderNew" hidden>
|
|
1971
|
+
<label class="wizField"><span>Your app is built with</span>
|
|
1972
|
+
<select id="f-renderRuntime">
|
|
1973
|
+
<option value="node">Node.js</option><option value="python">Python</option><option value="ruby">Ruby</option>
|
|
1974
|
+
<option value="go">Go</option><option value="rust">Rust</option><option value="elixir">Elixir</option>
|
|
1975
|
+
<option value="docker">Docker — use my repository’s Dockerfile</option>
|
|
1976
|
+
</select>
|
|
1977
|
+
</label>
|
|
1978
|
+
<label class="wizField" id="renderBuildWrap"><span>Build command <small>— Render needs one; the usual one is filled in</small></span>
|
|
1979
|
+
<input type="text" id="f-renderBuild" autocomplete="off" spellcheck="false" maxlength="500" placeholder="for example: npm ci">
|
|
1980
|
+
</label>
|
|
1981
|
+
<label class="wizField" id="renderStartWrap"><span>Start command</span>
|
|
1982
|
+
<input type="text" id="f-renderStart" autocomplete="off" spellcheck="false" maxlength="500" placeholder="for example: npm start">
|
|
1983
|
+
</label>
|
|
1984
|
+
<label class="wizField"><span>Plan</span>
|
|
1985
|
+
<select id="f-renderPlan"></select>
|
|
1986
|
+
</label>
|
|
1987
|
+
<label class="addrOpt"><input type="checkbox" id="f-renderDb">
|
|
1988
|
+
<span>My app needs a database (Render Postgres)</span>
|
|
1989
|
+
</label>
|
|
1990
|
+
<label class="wizField" id="renderDbPlanWrap" hidden><span>Database plan</span>
|
|
1991
|
+
<select id="f-renderDbPlan"></select>
|
|
1992
|
+
</label>
|
|
1895
1993
|
</div>
|
|
1994
|
+
<div class="hint" id="h-render" role="status"> </div>
|
|
1896
1995
|
</div>
|
|
1897
1996
|
</div>
|
|
1898
1997
|
</div>
|
|
1998
|
+
<span class="acts"><button type="button" class="rowChg" data-row-chg aria-expanded="false">Change</button></span>
|
|
1899
1999
|
</div>
|
|
1900
|
-
<span class="acts"><button type="button" class="rowChg" data-row-chg aria-expanded="false">Edit</button></span>
|
|
1901
|
-
</div>
|
|
1902
2000
|
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
2001
|
+
<!-- how much we run (question 7): "Some of it" (hybrid) or "On my machines"
|
|
2002
|
+
(local) reveals the service checklist -->
|
|
2003
|
+
<div class="setRow" data-row="run">
|
|
2004
|
+
<span class="k">We run</span>
|
|
2005
|
+
<div class="v"><span class="rowV" data-row-v></span><small class="rowS" data-row-s></small>
|
|
2006
|
+
<div class="opts" hidden>
|
|
2007
|
+
<div class="typeCards physCells" role="group" aria-label="How much is run for you">
|
|
2008
|
+
<button type="button" class="tpill" data-phys="framing" data-val="managed" aria-pressed="false">Everything, for you</button>
|
|
2009
|
+
<button type="button" class="tpill" data-phys="framing" data-val="hybrid" aria-pressed="false">Some of it</button>
|
|
2010
|
+
<button type="button" class="tpill" data-phys="framing" data-val="local" aria-pressed="false">On my machines</button>
|
|
2011
|
+
<button type="button" class="tpill" data-phys="framing" data-val="open-source" aria-pressed="false">Free core only</button>
|
|
2012
|
+
</div>
|
|
2013
|
+
<p class="physWhy" data-why="services" hidden></p>
|
|
2014
|
+
<fieldset class="physSuite" id="physSuite" hidden>
|
|
2015
|
+
<legend id="physSuiteLbl">Your hybrid suite</legend>
|
|
2016
|
+
<div class="typeCards physCells physSuiteGrid">
|
|
2017
|
+
<button type="button" class="tpill" data-phys="services" data-val="hosting" aria-pressed="false">Hosting</button>
|
|
2018
|
+
<button type="button" class="tpill" data-phys="services" data-val="labor-payment" aria-pressed="false">Labor payment and HR</button>
|
|
2019
|
+
<button type="button" class="tpill" data-phys="services" data-val="starter-kit" aria-pressed="false">Starting module kit</button>
|
|
2020
|
+
<button type="button" class="tpill" data-phys="services" data-val="marketplace-buy" aria-pressed="false">Module marketplace: buy</button>
|
|
2021
|
+
<button type="button" class="tpill" data-phys="services" data-val="marketplace-sell" aria-pressed="false">Module marketplace: sell</button>
|
|
2022
|
+
<button type="button" class="tpill" data-phys="services" data-val="guild-access" aria-pressed="false">Builder guild access</button>
|
|
2023
|
+
<button type="button" class="tpill" data-phys="services" data-val="guild-create" aria-pressed="false">Create a builder guild</button>
|
|
2024
|
+
<button type="button" class="tpill" data-phys="services" data-val="company-creation" aria-pressed="false">Company creation</button>
|
|
2025
|
+
<button type="button" class="tpill" data-phys="services" data-val="cbaas-consulting" aria-pressed="false">Expert consulting</button>
|
|
2026
|
+
<button type="button" class="tpill" data-phys="services" data-val="public-marketing" aria-pressed="false">Public marketed project</button>
|
|
2027
|
+
</div>
|
|
2028
|
+
<ul class="physWhyList" data-why-list="services" hidden></ul>
|
|
2029
|
+
</fieldset>
|
|
1914
2030
|
</div>
|
|
1915
|
-
<ul class="physWhyList" data-why-list="reward_intents" hidden></ul>
|
|
1916
2031
|
</div>
|
|
2032
|
+
<span class="acts"><button type="button" class="rowChg" data-row-chg aria-expanded="false">Change</button></span>
|
|
1917
2033
|
</div>
|
|
1918
|
-
<span class="acts"><button type="button" class="rowChg" data-row-chg aria-expanded="false">Edit</button></span>
|
|
1919
|
-
</div>
|
|
1920
2034
|
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
<div class="
|
|
1925
|
-
<
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
<
|
|
1929
|
-
|
|
1930
|
-
|
|
2035
|
+
<!-- how finished work ships (task 1004629, ADR 0369): Auto unless the owner
|
|
2036
|
+
says otherwise. It rides the create as ship_mode and becomes the project's
|
|
2037
|
+
own ship mode, which its settings page can change any time. -->
|
|
2038
|
+
<div class="setRow" data-row="ship">
|
|
2039
|
+
<span class="k">Shipping</span>
|
|
2040
|
+
<div class="v"><span class="rowV" data-row-v></span><small class="rowS" data-row-s></small>
|
|
2041
|
+
<div class="opts" hidden>
|
|
2042
|
+
<fieldset class="appOpts" id="shipOpts">
|
|
2043
|
+
<legend>When the AI finishes a task</legend>
|
|
2044
|
+
<label class="appOpt">
|
|
2045
|
+
<input type="radio" name="shipMode" value="auto" checked>
|
|
2046
|
+
<span><b>Auto (recommended)</b>
|
|
2047
|
+
<span>The AI ships finished work on its own. You don’t run any commands.</span></span>
|
|
2048
|
+
</label>
|
|
2049
|
+
<label class="appOpt">
|
|
2050
|
+
<input type="radio" name="shipMode" value="manual">
|
|
2051
|
+
<span><b>Manual</b>
|
|
2052
|
+
<span>The AI stops before each ship and waits for you to approve it.</span></span>
|
|
2053
|
+
</label>
|
|
2054
|
+
</fieldset>
|
|
1931
2055
|
</div>
|
|
1932
|
-
<p class="physWhy" data-why="services" hidden></p>
|
|
1933
|
-
<fieldset class="physSuite" id="physSuite" hidden>
|
|
1934
|
-
<legend id="physSuiteLbl">Your hybrid suite</legend>
|
|
1935
|
-
<div class="typeCards physCells physSuiteGrid">
|
|
1936
|
-
<button type="button" class="tpill" data-phys="services" data-val="hosting" aria-pressed="false">Hosting</button>
|
|
1937
|
-
<button type="button" class="tpill" data-phys="services" data-val="labor-payment" aria-pressed="false">Labor payment and HR</button>
|
|
1938
|
-
<button type="button" class="tpill" data-phys="services" data-val="starter-kit" aria-pressed="false">Starting module kit</button>
|
|
1939
|
-
<button type="button" class="tpill" data-phys="services" data-val="marketplace-buy" aria-pressed="false">Module marketplace: buy</button>
|
|
1940
|
-
<button type="button" class="tpill" data-phys="services" data-val="marketplace-sell" aria-pressed="false">Module marketplace: sell</button>
|
|
1941
|
-
<button type="button" class="tpill" data-phys="services" data-val="guild-access" aria-pressed="false">Builder guild access</button>
|
|
1942
|
-
<button type="button" class="tpill" data-phys="services" data-val="guild-create" aria-pressed="false">Create a builder guild</button>
|
|
1943
|
-
<button type="button" class="tpill" data-phys="services" data-val="company-creation" aria-pressed="false">Company creation</button>
|
|
1944
|
-
<button type="button" class="tpill" data-phys="services" data-val="cbaas-consulting" aria-pressed="false">Expert consulting</button>
|
|
1945
|
-
<button type="button" class="tpill" data-phys="services" data-val="public-marketing" aria-pressed="false">Public marketed project</button>
|
|
1946
|
-
</div>
|
|
1947
|
-
<ul class="physWhyList" data-why-list="services" hidden></ul>
|
|
1948
|
-
</fieldset>
|
|
1949
2056
|
</div>
|
|
2057
|
+
<span class="acts"><button type="button" class="rowChg" data-row-chg aria-expanded="false">Change</button></span>
|
|
1950
2058
|
</div>
|
|
1951
|
-
<span class="acts"><button type="button" class="rowChg" data-row-chg aria-expanded="false">Edit</button></span>
|
|
1952
|
-
</div>
|
|
1953
2059
|
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
<
|
|
1959
|
-
|
|
1960
|
-
<div class="
|
|
1961
|
-
<
|
|
1962
|
-
<
|
|
1963
|
-
|
|
1964
|
-
<input type="radio" name="shipMode" value="auto" checked>
|
|
1965
|
-
<span><b>Auto (recommended)</b>
|
|
1966
|
-
<span>The AI ships finished work on its own. You don’t run any commands.</span></span>
|
|
1967
|
-
</label>
|
|
1968
|
-
<label class="appOpt">
|
|
1969
|
-
<input type="radio" name="shipMode" value="manual">
|
|
1970
|
-
<span><b>Manual</b>
|
|
1971
|
-
<span>The AI stops before each ship and waits for you to approve it.</span></span>
|
|
1972
|
-
</label>
|
|
1973
|
-
</fieldset>
|
|
2060
|
+
<!-- a look (task 1004421, ADR 0358): colours, a logo and the night tint, so
|
|
2061
|
+
builders in several projects always know which hall they are in.
|
|
2062
|
+
lookKit.buildLookPicker fills it — the same picker the manage page's "Its
|
|
2063
|
+
look" uses — and the choice is sent right after Create (sendLook). -->
|
|
2064
|
+
<div class="setRow" data-row="look">
|
|
2065
|
+
<span class="k">Look</span>
|
|
2066
|
+
<div class="v"><span class="rowV"><span class="swDot" id="lookDot" aria-hidden="true"></span><span data-row-v></span></span><small class="rowS" data-row-s></small>
|
|
2067
|
+
<div class="opts" hidden>
|
|
2068
|
+
<div class="lookPick" id="wizLook"></div>
|
|
2069
|
+
</div>
|
|
1974
2070
|
</div>
|
|
2071
|
+
<span class="acts"><button type="button" class="rowChg" data-row-chg aria-expanded="false">Change</button></span>
|
|
1975
2072
|
</div>
|
|
1976
|
-
<span class="acts"><button type="button" class="rowChg" data-row-chg aria-expanded="false">Edit</button></span>
|
|
1977
2073
|
</div>
|
|
1978
2074
|
</div>
|
|
1979
|
-
<div class="hint" id="h-review"> </div>
|
|
1980
|
-
<div class="nav">
|
|
1981
|
-
<span></span>
|
|
1982
|
-
<button type="submit" class="btn" id="reviewGo">Looks right, continue</button>
|
|
1983
|
-
</div>
|
|
1984
|
-
</form>
|
|
1985
|
-
</section>
|
|
1986
2075
|
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
<p class="wizRecap" id="wizRecap"></p>
|
|
1996
|
-
<div class="alert" id="createAlert" role="alert"></div>
|
|
1997
|
-
<div class="nav">
|
|
1998
|
-
<span></span>
|
|
1999
|
-
<button type="button" class="btn big" id="doCreate">Create my project</button>
|
|
2076
|
+
<!-- the terms (tasks 1004417 and 1004648): the one required tick, above Create. It
|
|
2077
|
+
rides the create as `terms_acknowledged` and the SERVER records which terms
|
|
2078
|
+
version it was (modules/provisioning/terms-ack.js), so this page never names one. -->
|
|
2079
|
+
<label class="termsAck">
|
|
2080
|
+
<input type="checkbox" id="termsAck" aria-describedby="h-terms">
|
|
2081
|
+
<span>I can sign for this project, and I accept the <a class="termsRead" href="/terms" target="_blank" rel="noopener">terms</a>.</span>
|
|
2082
|
+
</label>
|
|
2083
|
+
<div class="hint" id="h-terms"> </div>
|
|
2000
2084
|
</div>
|
|
2001
|
-
<p class="finePrint">Right after, you’ll get the few steps only you can do.</p>
|
|
2002
|
-
</section>
|
|
2003
2085
|
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
<div class="
|
|
2007
|
-
<
|
|
2008
|
-
<
|
|
2009
|
-
</div>
|
|
2010
|
-
<p class="lede" id="doneLede"></p>
|
|
2011
|
-
<p class="hint" id="doneRender" role="status" hidden></p>
|
|
2012
|
-
<p class="hint" id="doneLook" role="status" hidden></p>
|
|
2013
|
-
<div id="doneApp" hidden></div>
|
|
2014
|
-
<!-- the STABLE live region: the strip inside is rebuilt every 5s tick,
|
|
2015
|
-
and a live region that is itself replaced never announces -->
|
|
2016
|
-
<div id="liveProgress" role="status" aria-live="polite"></div>
|
|
2017
|
-
<!-- the wait (task 1004578): one status line, a thin bar, and the cloud
|
|
2018
|
-
hop — one cloud per public project on the platform, in its planet's
|
|
2019
|
-
colour. Shown only while data-moment="wait"; under reduced motion
|
|
2020
|
-
the sky is drawn once and stands still. -->
|
|
2021
|
-
<div class="hop" id="hop">
|
|
2022
|
-
<p class="hopStatus" id="hopStatus" role="status" aria-live="polite"></p>
|
|
2023
|
-
<div class="hopBar" aria-hidden="true"><span id="hopBarFill"></span></div>
|
|
2024
|
-
<div class="hopStage">
|
|
2025
|
-
<canvas id="hopCanvas" tabindex="0" role="img" aria-label="A cloud-hopping game to pass the wait: each cloud is a public project on the platform. Arrow keys steer, space jumps."></canvas>
|
|
2026
|
-
</div>
|
|
2027
|
-
<div class="hopRow">
|
|
2028
|
-
<button type="button" class="btn small ghost" id="hopLeft" aria-label="Move left">←</button>
|
|
2029
|
-
<button type="button" class="btn small ghost" id="hopJump">Jump</button>
|
|
2030
|
-
<button type="button" class="btn small ghost" id="hopRight" aria-label="Move right">→</button>
|
|
2031
|
-
<span class="hopHint">Arrows or A and D steer, space jumps.</span>
|
|
2032
|
-
<span class="hopScore" id="hopScore" aria-live="polite"></span>
|
|
2033
|
-
</div>
|
|
2034
|
-
<p class="hopWhile" id="hopWhile" hidden>While you wait, <button type="button" class="linklike" id="hopSignin" aria-expanded="false">set up GitHub sign-in</button>.</p>
|
|
2086
|
+
<!-- Create, with the one-line recap beside it; the reason it waits says itself
|
|
2087
|
+
under it while it does -->
|
|
2088
|
+
<div class="createBar">
|
|
2089
|
+
<button type="button" class="btn big" id="doCreate">Create my project</button>
|
|
2090
|
+
<span class="wizRecap" id="wizRecap"></span>
|
|
2035
2091
|
</div>
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
<
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
<
|
|
2047
|
-
<
|
|
2092
|
+
<p class="hint createWhy" id="createWhy" aria-live="polite"> </p>
|
|
2093
|
+
<div class="alert" id="createAlert" role="alert"></div>
|
|
2094
|
+
|
|
2095
|
+
<!-- 03 · Connect GitHub: waits until the project exists, then drives the steps only
|
|
2096
|
+
the founder can do (today's onboard-plan steps, task 1002694), drawn as one
|
|
2097
|
+
checklist that ticks itself from what the server has verified. -->
|
|
2098
|
+
<div class="part waiting" id="panel-done" aria-labelledby="done-part-h">
|
|
2099
|
+
<h2 id="done-part-h"><span class="n">03</span>Connect GitHub <span class="state" id="ghState">opens once your project exists</span></h2>
|
|
2100
|
+
<p class="partSub">One trip to GitHub. Approve the app, pick your repo, and you land back here. We tick each step as it happens, from any tab or device.</p>
|
|
2101
|
+
<div class="doneBody" id="doneBody">
|
|
2102
|
+
<p class="hint" id="doneRender" role="status" hidden></p>
|
|
2103
|
+
<p class="hint" id="doneLook" role="status" hidden></p>
|
|
2104
|
+
<div id="doneApp" hidden></div>
|
|
2105
|
+
<ol class="humanSteps" id="humanSteps"></ol>
|
|
2106
|
+
<!-- the STABLE live region: the strip inside is rebuilt every 5s tick,
|
|
2107
|
+
and a live region that is itself replaced never announces -->
|
|
2108
|
+
<div id="liveProgress" role="status" aria-live="polite"></div>
|
|
2109
|
+
<!-- the wait (task 1004578): one status line, a thin bar, and the cloud
|
|
2110
|
+
hop — one cloud per public project on the platform, in its planet's
|
|
2111
|
+
colour. Shown only while data-moment="wait"; under reduced motion
|
|
2112
|
+
the sky is drawn once and stands still. -->
|
|
2113
|
+
<div class="hop" id="hop">
|
|
2114
|
+
<p class="hopStatus" id="hopStatus" role="status" aria-live="polite"></p>
|
|
2115
|
+
<div class="hopBar" aria-hidden="true"><span id="hopBarFill"></span></div>
|
|
2116
|
+
<div class="hopStage">
|
|
2117
|
+
<canvas id="hopCanvas" tabindex="0" role="img" aria-label="A cloud-hopping game to pass the wait: each cloud is a public project on the platform. Arrow keys steer, space jumps."></canvas>
|
|
2118
|
+
</div>
|
|
2119
|
+
<div class="hopRow">
|
|
2120
|
+
<button type="button" class="btn small ghost" id="hopLeft" aria-label="Move left">←</button>
|
|
2121
|
+
<button type="button" class="btn small ghost" id="hopJump">Jump</button>
|
|
2122
|
+
<button type="button" class="btn small ghost" id="hopRight" aria-label="Move right">→</button>
|
|
2123
|
+
<span class="hopHint">Arrows or A and D steer, space jumps.</span>
|
|
2124
|
+
<span class="hopScore" id="hopScore" aria-live="polite"></span>
|
|
2125
|
+
</div>
|
|
2126
|
+
</div>
|
|
2127
|
+
<div class="alive">
|
|
2128
|
+
<h2 class="aliveH" id="done-h">Setting up your project</h2>
|
|
2129
|
+
<p class="lede" id="doneLede"></p>
|
|
2130
|
+
<!-- the invite step (task 1002346, BV1.R27; ADR 0249) — OPTIONAL, and it stands
|
|
2131
|
+
HERE because an invite needs a project that already exists. Hidden until the
|
|
2132
|
+
created record carries an id and a slug; the script is the only thing that
|
|
2133
|
+
shows it. -->
|
|
2134
|
+
<div class="inviteBox" id="wizInvite" hidden>
|
|
2135
|
+
<p class="finePrint">Invite your first builders. They become founding builders. Optional: the invite comes from your project’s hall, and you can invite anyone later.</p>
|
|
2136
|
+
<div class="attach">
|
|
2137
|
+
<label class="vh" for="wizInviteWho">GitHub handle</label>
|
|
2138
|
+
<input type="text" id="wizInviteWho" placeholder="GitHub handle" autocomplete="off" autocapitalize="off" spellcheck="false" maxlength="200">
|
|
2139
|
+
<button type="button" class="btn small" data-invite-send="wizInvite">Invite</button>
|
|
2140
|
+
<button type="button" class="btn small ghost" data-invite-skip="wizInvite">Skip</button>
|
|
2141
|
+
</div>
|
|
2142
|
+
<div class="inviteWhy" id="wizInviteWhy"></div>
|
|
2143
|
+
<p class="inviteWhy" id="wizDemoTeam" hidden></p>
|
|
2144
|
+
<ul class="suggList" id="wizInviteSugg"></ul>
|
|
2145
|
+
<ul class="inviteList" id="wizInviteList"></ul>
|
|
2146
|
+
<div class="projMsg" id="wizInviteMsg" role="status" aria-live="polite"></div>
|
|
2147
|
+
</div>
|
|
2148
|
+
<!-- the way back, the doneModules idiom: an optional step is a default
|
|
2149
|
+
rather than a dead end only if the panel names where it lives after -->
|
|
2150
|
+
<p class="samePath" id="wizInviteLater"></p>
|
|
2151
|
+
<!-- the extras row was a default (task 1002342, BV1.R23) — one line saying
|
|
2152
|
+
where they live afterwards, so accepting them is never a dead end -->
|
|
2153
|
+
<p class="samePath" id="doneModules"></p>
|
|
2154
|
+
<p class="samePath">These steps are the same however a project is created.</p>
|
|
2155
|
+
</div>
|
|
2048
2156
|
</div>
|
|
2049
|
-
<div class="inviteWhy" id="wizInviteWhy"></div>
|
|
2050
|
-
<p class="inviteWhy" id="wizDemoTeam" hidden></p>
|
|
2051
|
-
<ul class="suggList" id="wizInviteSugg"></ul>
|
|
2052
|
-
<ul class="inviteList" id="wizInviteList"></ul>
|
|
2053
|
-
<div class="projMsg" id="wizInviteMsg" role="status" aria-live="polite"></div>
|
|
2054
|
-
</div>
|
|
2055
|
-
<!-- the way back, the doneModules idiom: an optional step is a default
|
|
2056
|
-
rather than a dead end only if the panel names where it lives after -->
|
|
2057
|
-
<p class="samePath" id="wizInviteLater"></p>
|
|
2058
|
-
<h2 class="stepsHead" id="doneStepsHead">Your steps — the parts only you can play</h2>
|
|
2059
|
-
<ol class="humanSteps" id="humanSteps"></ol>
|
|
2060
|
-
<!-- the arrival shows the steps one at a time (task 1004578) -->
|
|
2061
|
-
<div class="stepPager" id="stepPager">
|
|
2062
|
-
<span class="stepCount" id="stepCount" aria-live="polite"></span>
|
|
2063
|
-
<button type="button" class="btn small ghost" id="stepBack">← Back</button>
|
|
2064
|
-
<button type="button" class="btn small" id="stepNext">Continue</button>
|
|
2065
2157
|
</div>
|
|
2066
|
-
<!-- the extras row was a default (task 1002342, BV1.R23) — one line saying
|
|
2067
|
-
where they live afterwards, so accepting them is never a dead end -->
|
|
2068
|
-
<p class="samePath" id="doneModules"></p>
|
|
2069
|
-
<p class="samePath">These steps are the same however a project is created.</p>
|
|
2070
2158
|
</section>
|
|
2071
2159
|
</div>
|
|
2072
2160
|
</div>
|
|
@@ -4486,13 +4574,12 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
4486
4574
|
marking the skipped ones done. Bump this key on EVERY renumbering
|
|
4487
4575
|
(-v6: the front door's two screens took steps 1 and 2, task 1004417;
|
|
4488
4576
|
-v7: the Look step took 10, so review is 11 and done 12, task 1004421;
|
|
4489
|
-
-v9: the six blended screens, task 1004504
|
|
4490
|
-
|
|
4491
|
-
|
|
4492
|
-
|
|
4493
|
-
|
|
4494
|
-
|
|
4495
|
-
var DRAFT_KEY = 'cb-create-draft-v9';
|
|
4577
|
+
-v9: the six blended screens, task 1004504;
|
|
4578
|
+
-v10: one page, task 1004648 — gate 0, the page 1, created 2). */
|
|
4579
|
+
/* `termsAck` is the required tick above Create (tasks 1004417 and 1004648). It is
|
|
4580
|
+
the founder's own answer, so it lives in the draft like every other one and
|
|
4581
|
+
survives the GitHub round-trip; the server, not this page, names the terms version. */
|
|
4582
|
+
var DRAFT_KEY = 'cb-create-draft-v10';
|
|
4496
4583
|
var CREATED_KEY = 'cb-created-instance';
|
|
4497
4584
|
/* `description` + `teamShape` are the optional About step (task 1002334) —
|
|
4498
4585
|
both legitimately stay empty, and empty is what the create request omits. */
|
|
@@ -4501,7 +4588,7 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
4501
4588
|
request omits the field), [] = the owner switched them all off, [...] =
|
|
4502
4589
|
what they picked. Never seed it with the preselect — that would store an
|
|
4503
4590
|
answer nobody gave. */
|
|
4504
|
-
var state = { step: 0, name: '', projType: null, description: '', teamShape: null, modules: null, mode: 'greenfield', owner: '', ownerTouched: false, repo: '', repoTouched: false, slug: '', slugTouched: false, domain: '', noAddress: false, appPlatform: 'later', shipMode: 'auto', physics: null, demo: null, look: null, termsAck: false
|
|
4591
|
+
var state = { step: 0, name: '', projType: null, description: '', teamShape: null, modules: null, mode: 'greenfield', modeChosen: false, owner: '', ownerTouched: false, repo: '', repoTouched: false, slug: '', slugTouched: false, domain: '', noAddress: false, appPlatform: 'later', shipMode: 'auto', physics: null, demo: null, look: null, termsAck: false };
|
|
4505
4592
|
try { Object.assign(state, JSON.parse(sessionStorage.getItem(DRAFT_KEY) || '{}')); } catch (e) {}
|
|
4506
4593
|
var authKnown = false; /* flips true when the boot's /me settles, either way */
|
|
4507
4594
|
|
|
@@ -4515,7 +4602,7 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
4515
4602
|
state.name = handedName.trim().slice(0, 80);
|
|
4516
4603
|
state.slug = deriveSlug(state.name); state.slugTouched = false;
|
|
4517
4604
|
state.repo = deriveRepo(state.name); state.repoTouched = false;
|
|
4518
|
-
state.step =
|
|
4605
|
+
state.step = 1;
|
|
4519
4606
|
try { sessionStorage.setItem(DRAFT_KEY, JSON.stringify(state)); } catch (e) {}
|
|
4520
4607
|
}
|
|
4521
4608
|
} catch (e) {}
|
|
@@ -4706,93 +4793,117 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
4706
4793
|
try { sessionStorage.setItem(DRAFT_KEY, JSON.stringify(state)); } catch (e) {}
|
|
4707
4794
|
}
|
|
4708
4795
|
|
|
4709
|
-
/* ──
|
|
4710
|
-
|
|
4711
|
-
|
|
4712
|
-
|
|
4713
|
-
|
|
4714
|
-
|
|
4715
|
-
Back walks backwards. A demo skips the checks — its answers are the demo's own. */
|
|
4716
|
-
var panels = { 0: 'panel-gate', 1: 'panel-fork', 2: 'panel-what', 3: 'panel-checks', 4: 'panel-review', 5: 'panel-look', 6: 'panel-done' };
|
|
4717
|
-
var SCREEN = { 0: 'signin', 1: 'fork', 2: 'what', 3: 'checks', 4: 'review', 5: 'look', 6: 'done' };
|
|
4796
|
+
/* ── the page (task 1004648, the design of record docs/design/mocks/day-night-rooms/) ──
|
|
4797
|
+
gate 0 (sign in) · the page 1 (01 your project, 02 how it's run, the terms tick and
|
|
4798
|
+
Create) · created 2 (the same page: parts 01 and 02 stand down behind the recap and
|
|
4799
|
+
03 Connect GitHub goes live). There are no screens to walk, so there is no Back. */
|
|
4800
|
+
var panels = { 0: 'panel-gate', 1: 'panel-page', 2: 'panel-page' };
|
|
4801
|
+
var SCREEN = { 0: 'signin', 1: 'page', 2: 'done' };
|
|
4718
4802
|
function eyebrowFor(step) {
|
|
4719
4803
|
if (step === 0) return 'Sign in';
|
|
4720
|
-
if (step ===
|
|
4721
|
-
|
|
4722
|
-
return state.demo && step > 1 ? 'New demo' : 'New project';
|
|
4723
|
-
}
|
|
4724
|
-
/* where Back goes from each screen: the demo's own screen first, then the one before */
|
|
4725
|
-
function prevStep(step) {
|
|
4726
|
-
if (step === 4 && state.demo) return 2;
|
|
4727
|
-
return step - 1;
|
|
4804
|
+
if (step === 2) return 'Founding';
|
|
4805
|
+
return state.demo ? 'New demo' : 'New project';
|
|
4728
4806
|
}
|
|
4729
4807
|
function show(step, moveFocus) {
|
|
4730
4808
|
state.step = step;
|
|
4731
|
-
|
|
4732
|
-
|
|
4733
|
-
|
|
4809
|
+
var created = step === 2;
|
|
4810
|
+
$('panel-gate').classList.toggle('on', step === 0);
|
|
4811
|
+
$('panel-page').classList.toggle('on', step !== 0);
|
|
4812
|
+
$('wizParts').hidden = created;
|
|
4813
|
+
$('pageSub').hidden = created;
|
|
4814
|
+
var done = $('panel-done');
|
|
4815
|
+
done.classList.toggle('on', created);
|
|
4816
|
+
done.classList.toggle('waiting', !created);
|
|
4817
|
+
done.classList.toggle('live', created);
|
|
4734
4818
|
saveDraft();
|
|
4735
|
-
/* the room's seed grows
|
|
4819
|
+
/* the room's seed grows as the page fills in (CSS reads data-screen + data-fill) */
|
|
4736
4820
|
$('wizRoom').setAttribute('data-screen', SCREEN[step]);
|
|
4737
4821
|
$('wizEyebrow').textContent = eyebrowFor(step);
|
|
4738
|
-
$('wizBack').hidden = step === 0 || step === 6 || (step === 1 && $('demoSetup').hidden);
|
|
4739
4822
|
$('demoTag').hidden = !state.demo;
|
|
4740
4823
|
/* focus moves ONLY on a deliberate step (the hub rule setView already
|
|
4741
4824
|
applies to this view: never on boot, never on a background settle) */
|
|
4742
4825
|
if (moveFocus) {
|
|
4743
|
-
var h = $(panels[step]).querySelector('h1');
|
|
4826
|
+
var h = created ? $('done-part-h') : $(panels[step]).querySelector('h1');
|
|
4744
4827
|
if (h) { h.setAttribute('tabindex', '-1'); h.focus({ preventScroll: false }); }
|
|
4745
4828
|
}
|
|
4746
|
-
|
|
4747
|
-
|
|
4748
|
-
|
|
4749
|
-
if (
|
|
4750
|
-
|
|
4751
|
-
|
|
4752
|
-
|
|
4753
|
-
|
|
4754
|
-
|
|
4755
|
-
|
|
4756
|
-
|
|
4757
|
-
|
|
4758
|
-
|
|
4759
|
-
|
|
4760
|
-
|
|
4761
|
-
|
|
4762
|
-
|
|
4829
|
+
/* the cloud hop's motion runs only while part 03 is live (task 1004578) — a
|
|
4830
|
+
start/stop, not a paint: renderDone paints the part */
|
|
4831
|
+
if (typeof hopStart === 'function') { if (created) hopStart(); else hopStop(); }
|
|
4832
|
+
if (step === 1) paintPage();
|
|
4833
|
+
else paintCreate();
|
|
4834
|
+
if (typeof stepsPaint === 'function') stepsPaint();
|
|
4835
|
+
}
|
|
4836
|
+
/* The page hosts every control at once, so it paints them all on entry. The repo
|
|
4837
|
+
probe is authenticated — never fire it before /me settles (a pre-auth probe 401s
|
|
4838
|
+
for strangers and could seed the draft's owner with a placeholder). */
|
|
4839
|
+
function paintPage() {
|
|
4840
|
+
physLoadAccountOnce();
|
|
4841
|
+
physDefaults();
|
|
4842
|
+
paintChecks();
|
|
4843
|
+
renderModules();
|
|
4844
|
+
syncHome();
|
|
4845
|
+
if (authKnown) ensureRepoAccess();
|
|
4846
|
+
/* re-check on every entry: a handle free ten minutes ago may not be now (N10) */
|
|
4847
|
+
checkSlugAvailable(); renderAddrPanel();
|
|
4848
|
+
syncAppStep(); syncRenderSetup(); syncShipStep();
|
|
4849
|
+
renderLook();
|
|
4850
|
+
paintSetup();
|
|
4851
|
+
paintCreate();
|
|
4852
|
+
}
|
|
4853
|
+
|
|
4854
|
+
/* ── the room's sky (task 1004648): day from 07:00 to 18:59 on the viewer's own
|
|
4855
|
+
clock, night otherwise, re-checked each minute. Only an attribute changes here;
|
|
4856
|
+
CSS draws both rooms, and the kill switch stops their motion. ── */
|
|
4857
|
+
function skyAt(d) { var h = d.getHours(); return h >= 7 && h < 19 ? 'day' : 'night'; }
|
|
4858
|
+
function paintSky() { root.setAttribute('data-sky', skyAt(new Date())); }
|
|
4859
|
+
paintSky();
|
|
4860
|
+
setInterval(paintSky, 60000);
|
|
4861
|
+
|
|
4862
|
+
/* ── Create waits for two things only (task 1004648): a name, and the terms tick.
|
|
4863
|
+
The reason it waits is said under it, in place; the summary rows never gate it. ── */
|
|
4864
|
+
var createBusy = false;
|
|
4865
|
+
function createWhy() {
|
|
4866
|
+
if (!String(state.name || '').trim()) return 'Give it a name first.';
|
|
4867
|
+
if (!state.termsAck) return 'Tick the terms to create your project.';
|
|
4868
|
+
return '';
|
|
4869
|
+
}
|
|
4870
|
+
function paintCreate() {
|
|
4871
|
+
var cb = $('doCreate');
|
|
4872
|
+
if (state.step === 2) {
|
|
4873
|
+
cb.disabled = true; cb.textContent = 'Created';
|
|
4874
|
+
$('createWhy').textContent = ' ';
|
|
4875
|
+
} else if (!createBusy) {
|
|
4876
|
+
var why = createWhy();
|
|
4877
|
+
cb.disabled = !!why; cb.textContent = 'Create my project';
|
|
4878
|
+
$('createWhy').textContent = why || ' ';
|
|
4763
4879
|
}
|
|
4764
|
-
|
|
4765
|
-
|
|
4766
|
-
|
|
4767
|
-
|
|
4768
|
-
|
|
4769
|
-
|
|
4770
|
-
if (state.
|
|
4771
|
-
if (state.
|
|
4772
|
-
if (
|
|
4773
|
-
|
|
4774
|
-
|
|
4775
|
-
/* ── the front door (tasks 1004417 and 1004504) ── the tick mirrors into the draft,
|
|
4776
|
-
and both doors wait for it: nothing past the fork until the terms are accepted */
|
|
4777
|
-
function paintDoors() {
|
|
4778
|
-
$('wizDemo').disabled = !state.termsAck;
|
|
4779
|
-
$('wizStart').disabled = !state.termsAck;
|
|
4880
|
+
renderRecap();
|
|
4881
|
+
paintFill();
|
|
4882
|
+
}
|
|
4883
|
+
/* how far the page has filled in: the seed in the window grows with it */
|
|
4884
|
+
function paintFill() {
|
|
4885
|
+
var a = phys().answers, n = 0;
|
|
4886
|
+
if (String(state.name || '').trim()) n++;
|
|
4887
|
+
if (state.projType) n++;
|
|
4888
|
+
if (a.home_country || a.builder_geography || a.entity || a.minors_on_board === true || a.minors_on_board === false) n++;
|
|
4889
|
+
if (state.termsAck) n++;
|
|
4890
|
+
$('wizRoom').setAttribute('data-fill', String(n));
|
|
4780
4891
|
}
|
|
4781
4892
|
$('termsAck').checked = !!state.termsAck;
|
|
4782
4893
|
$('termsAck').addEventListener('change', function () {
|
|
4783
4894
|
state.termsAck = !!this.checked;
|
|
4784
4895
|
if (state.termsAck) { $('h-terms').textContent = ' '; $('h-terms').className = 'hint'; }
|
|
4785
|
-
paintDoors();
|
|
4786
4896
|
saveDraft();
|
|
4897
|
+
paintCreate();
|
|
4787
4898
|
});
|
|
4788
|
-
paintDoors();
|
|
4789
4899
|
/* ── the demo route (task 1004420, BV2.PS09) ──
|
|
4790
|
-
"Try
|
|
4791
|
-
|
|
4792
|
-
|
|
4793
|
-
|
|
4794
|
-
|
|
4795
|
-
|
|
4900
|
+
"Try a small demo instead", the small link under the heading, opens the demo in
|
|
4901
|
+
place at the top of part 01: the people, the hours each, the idea, a first read of
|
|
4902
|
+
what fits, and up to two teammates. "Use these" marks the page "demo" and the rest
|
|
4903
|
+
of the page is unchanged: a demo is a normal project marked "demo" (D9), so the
|
|
4904
|
+
create carries `demo` and the server applies the demo's picked answers and makes it
|
|
4905
|
+
private to the team — which is why its quick checks stand down. The time box is
|
|
4906
|
+
soft (D3). The limits and the fit sentences are copies of
|
|
4796
4907
|
modules/provisioning/demo.js, held equal by tests/wizard_demo.mjs. */
|
|
4797
4908
|
var DEMO_LIMITS = { people: [1, 12], hours: [1, 40] };
|
|
4798
4909
|
var demoDraft = state.demo
|
|
@@ -4822,13 +4933,10 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
4822
4933
|
$('demoInvites').hidden = others === 0;
|
|
4823
4934
|
$('demoInvite2').closest('label').hidden = others < 2;
|
|
4824
4935
|
}
|
|
4825
|
-
function demoShow(
|
|
4826
|
-
$('
|
|
4827
|
-
$('
|
|
4828
|
-
|
|
4829
|
-
$('wizEyebrow').textContent = eyebrowFor(state.step);
|
|
4830
|
-
$('wizBack').hidden = which === 'intro';
|
|
4831
|
-
if (which !== 'intro') {
|
|
4936
|
+
function demoShow(open) {
|
|
4937
|
+
$('demoSetup').hidden = !open;
|
|
4938
|
+
$('wizDemo').setAttribute('aria-expanded', open ? 'true' : 'false');
|
|
4939
|
+
if (open) {
|
|
4832
4940
|
paintDemo();
|
|
4833
4941
|
var h = $('demo-h1');
|
|
4834
4942
|
h.setAttribute('tabindex', '-1'); h.focus({ preventScroll: false });
|
|
@@ -4837,7 +4945,15 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
4837
4945
|
$('demoIdea').value = demoDraft.idea;
|
|
4838
4946
|
$('demoInvite1').value = demoDraft.invites[0] || '';
|
|
4839
4947
|
$('demoInvite2').value = demoDraft.invites[1] || '';
|
|
4840
|
-
$('wizDemo').addEventListener('click', function () {
|
|
4948
|
+
$('wizDemo').addEventListener('click', function () { demoShow($('demoSetup').hidden); });
|
|
4949
|
+
/* back to a real project: the demo's answers go, and the quick checks come back */
|
|
4950
|
+
$('demoCancel').addEventListener('click', function () {
|
|
4951
|
+
state.demo = null;
|
|
4952
|
+
saveDraft();
|
|
4953
|
+
demoShow(false);
|
|
4954
|
+
show(1);
|
|
4955
|
+
$('wizDemo').focus();
|
|
4956
|
+
});
|
|
4841
4957
|
root.querySelectorAll('[data-demo-step]').forEach(function (b) {
|
|
4842
4958
|
b.addEventListener('click', function () {
|
|
4843
4959
|
var key = b.getAttribute('data-demo-step');
|
|
@@ -4860,10 +4976,10 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
4860
4976
|
$('f-desc').value = state.description;
|
|
4861
4977
|
}
|
|
4862
4978
|
state.teamShape = demoDraft.people > 1 ? 'small-team' : 'solo';
|
|
4863
|
-
/* the demo's own rows are the demo's answers, so the review asks again */
|
|
4864
|
-
state.confirmed = {};
|
|
4865
4979
|
saveDraft();
|
|
4866
|
-
|
|
4980
|
+
demoShow(false);
|
|
4981
|
+
show(1);
|
|
4982
|
+
$('newName').focus();
|
|
4867
4983
|
});
|
|
4868
4984
|
/* the done panel's invite step names the demo's teammates (task 1004420): the hub
|
|
4869
4985
|
holds no invite of its own, so the founder sends each from the project's own box.
|
|
@@ -4937,17 +5053,31 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
4937
5053
|
state.repo = deriveRepo(state.name);
|
|
4938
5054
|
$('f-repo').value = state.repo;
|
|
4939
5055
|
}
|
|
4940
|
-
|
|
4941
|
-
|
|
4942
|
-
|
|
4943
|
-
|
|
4944
|
-
unconfirm(['code', 'address']);
|
|
5056
|
+
paintNameHint();
|
|
5057
|
+
/* the repo and the address follow the name, so their rows repaint with it */
|
|
5058
|
+
if (!state.slugTouched) checkSlugAvailable();
|
|
5059
|
+
if (!state.repoTouched && repoAccess === true && state.mode !== 'adopt') { $('ghNewName').value = state.repo; updateFreshPreview(); }
|
|
4945
5060
|
saveDraft();
|
|
5061
|
+
renderAddrPanel();
|
|
5062
|
+
paintSetup();
|
|
5063
|
+
paintCreate();
|
|
4946
5064
|
});
|
|
4947
|
-
|
|
5065
|
+
/* the handle under the name, built from nodes: the name is typed, so never markup */
|
|
5066
|
+
function paintNameHint() {
|
|
5067
|
+
var h = $('h-name');
|
|
5068
|
+
h.className = 'hint';
|
|
5069
|
+
h.textContent = '';
|
|
5070
|
+
if (!state.slug) { h.textContent = ' '; return; }
|
|
5071
|
+
h.appendChild(document.createTextNode('its handle on the platform: '));
|
|
5072
|
+
var code = document.createElement('code');
|
|
5073
|
+
code.textContent = state.slug;
|
|
5074
|
+
h.appendChild(code);
|
|
5075
|
+
}
|
|
5076
|
+
if (state.name && state.slug) paintNameHint();
|
|
4948
5077
|
|
|
4949
|
-
function setMode(mode) {
|
|
5078
|
+
function setMode(mode, chosen) {
|
|
4950
5079
|
state.mode = mode;
|
|
5080
|
+
if (chosen) state.modeChosen = true;
|
|
4951
5081
|
$('c-green').setAttribute('aria-pressed', String(mode === 'greenfield'));
|
|
4952
5082
|
$('c-adopt').setAttribute('aria-pressed', String(mode === 'adopt'));
|
|
4953
5083
|
$('adoptNote').classList.toggle('on', mode === 'adopt');
|
|
@@ -4955,8 +5085,8 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
4955
5085
|
syncHome();
|
|
4956
5086
|
if (typeof paintSetup === 'function') paintSetup();
|
|
4957
5087
|
}
|
|
4958
|
-
$('c-green').addEventListener('click', function () { setMode('greenfield'); });
|
|
4959
|
-
$('c-adopt').addEventListener('click', function () { setMode('adopt'); });
|
|
5088
|
+
$('c-green').addEventListener('click', function () { setMode('greenfield', true); });
|
|
5089
|
+
$('c-adopt').addEventListener('click', function () { setMode('adopt', true); });
|
|
4960
5090
|
setMode(state.mode);
|
|
4961
5091
|
|
|
4962
5092
|
/* ── the kind (task 1002772) ── a declaration: the pill is the answer */
|
|
@@ -4968,11 +5098,12 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
4968
5098
|
root.querySelectorAll('#typeCards .tpill').forEach(function (b) {
|
|
4969
5099
|
b.addEventListener('click', function () {
|
|
4970
5100
|
state.projType = b.getAttribute('data-type');
|
|
4971
|
-
$('h-projtype').innerHTML = ' '; $('h-projtype').className = 'hint';
|
|
4972
5101
|
paintType(state.projType);
|
|
4973
|
-
/* the suggested extras follow the kind, so the review asks about them again */
|
|
4974
|
-
unconfirm(['extras']);
|
|
4975
5102
|
saveDraft();
|
|
5103
|
+
/* the suggested extras follow the kind, so their row repaints with it */
|
|
5104
|
+
renderModules();
|
|
5105
|
+
paintSetup();
|
|
5106
|
+
paintCreate();
|
|
4976
5107
|
});
|
|
4977
5108
|
});
|
|
4978
5109
|
paintType(state.projType || null);
|
|
@@ -4981,7 +5112,7 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
4981
5112
|
The sentence is optional and half the publish gate (ADR 0182 D4): it is what puts
|
|
4982
5113
|
the project on the public map, which the field's own label says. The team shape is
|
|
4983
5114
|
what the extras' preselect reads: "solo" follows a team of one, and a team says who
|
|
4984
|
-
can join (people invited, or anyone applying) on
|
|
5115
|
+
can join (people invited, or anyone applying) on part 02's Team row. */
|
|
4985
5116
|
function teamLabel(t) {
|
|
4986
5117
|
var b = t && root.querySelector('#teamCards .tpill[data-team="' + t + '"]');
|
|
4987
5118
|
return b ? b.textContent : '';
|
|
@@ -5000,7 +5131,6 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
5000
5131
|
b.addEventListener('click', function () {
|
|
5001
5132
|
state.teamShape = b.getAttribute('data-team');
|
|
5002
5133
|
paintTeam(state.teamShape);
|
|
5003
|
-
unconfirm(['extras']);
|
|
5004
5134
|
saveDraft();
|
|
5005
5135
|
paintSetup();
|
|
5006
5136
|
});
|
|
@@ -5048,7 +5178,7 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
5048
5178
|
exact dishonesty the About row's "off the public map" clause exists to
|
|
5049
5179
|
prevent, one screen before Create. */
|
|
5050
5180
|
function repaintForBundles() {
|
|
5051
|
-
if (state.step ===
|
|
5181
|
+
if (state.step === 1) { renderModules(); paintSetup(); }
|
|
5052
5182
|
}
|
|
5053
5183
|
/* The row for the declared type, or null before the read lands / for a type
|
|
5054
5184
|
the table has no row for (including no type at all). */
|
|
@@ -5439,9 +5569,9 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
5439
5569
|
});
|
|
5440
5570
|
|
|
5441
5571
|
/* ── planet physics (tasks 1004418 and 1004419, BV2.PS07 + PS11; regrouped by task 1004504) ──
|
|
5442
|
-
Geography, ages and entity are
|
|
5443
|
-
|
|
5444
|
-
|
|
5572
|
+
Geography, ages and entity are part 01's quick checks; the project's state, the
|
|
5573
|
+
builders, the rewards and the framing are part 02's rows, each prefilled there and
|
|
5574
|
+
never confirmed (task 1004648). The answers live in state.physics.answers under
|
|
5445
5575
|
planet-physics.js's own keys, so the create sends them as `detail` untouched.
|
|
5446
5576
|
The vocabularies below are COPIES of that file's (a page cannot require a
|
|
5447
5577
|
module), held equal by tests/wizard_physics.mjs and wizard_physics_more.mjs. */
|
|
@@ -5477,6 +5607,8 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
5477
5607
|
var PHYS_FRAMINGS = ['managed', 'hybrid', 'local', 'open-source'];
|
|
5478
5608
|
var PHYS_SERVICES = ['hosting', 'labor-payment', 'starter-kit', 'marketplace-buy', 'marketplace-sell', 'guild-access', 'guild-create', 'company-creation', 'cbaas-consulting', 'public-marketing'];
|
|
5479
5609
|
var PHYS_MANY = ['reward_intents', 'services'];
|
|
5610
|
+
/* part 01's quick checks: an answer to any of these asks the table again */
|
|
5611
|
+
var PHYS_CHECK_KEYS = ['builder_geography', 'minors_on_board', 'entity'];
|
|
5480
5612
|
/* the suite a hybrid or local framing starts from (the canvas's Framing frame) */
|
|
5481
5613
|
var PHYS_SUITE_START = { hybrid: ['hosting', 'starter-kit', 'marketplace-buy', 'guild-access'], local: ['starter-kit', 'marketplace-buy', 'guild-access'] };
|
|
5482
5614
|
/* what the review and the reasons say for each answer */
|
|
@@ -5561,9 +5693,9 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
5561
5693
|
if (state.teamShape) d.team_shape = state.teamShape;
|
|
5562
5694
|
return Object.keys(d).length ? d : undefined;
|
|
5563
5695
|
}
|
|
5564
|
-
/*
|
|
5565
|
-
founder's own: a new project, all managed, one person.
|
|
5566
|
-
|
|
5696
|
+
/* Part 02's prefilled answers, written once on the way in and never over a
|
|
5697
|
+
founder's own: a new project, all managed, one person. Nothing needs confirming
|
|
5698
|
+
(task 1004648): what the summary says is what Create files. */
|
|
5567
5699
|
function physDefaults() {
|
|
5568
5700
|
var a = phys().answers;
|
|
5569
5701
|
if (!a.project_state) a.project_state = 'new';
|
|
@@ -5571,7 +5703,7 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
5571
5703
|
if (!Number.isInteger(a.builders_at_start)) { a.builders_at_start = 1; a.builders_expected = 1; }
|
|
5572
5704
|
if (physSolo()) state.teamShape = 'solo';
|
|
5573
5705
|
else if (!state.teamShape || state.teamShape === 'solo') state.teamShape = 'small-team';
|
|
5574
|
-
if (state.mode === 'greenfield' && a.project_state === 'existing' && Array.isArray(a.existing_work) && a.existing_work.indexOf('code') !== -1 && !
|
|
5706
|
+
if (state.mode === 'greenfield' && a.project_state === 'existing' && Array.isArray(a.existing_work) && a.existing_work.indexOf('code') !== -1 && !state.modeChosen) setMode('adopt');
|
|
5575
5707
|
saveDraft();
|
|
5576
5708
|
}
|
|
5577
5709
|
|
|
@@ -5649,11 +5781,13 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
5649
5781
|
b.setAttribute('aria-pressed', String(on));
|
|
5650
5782
|
});
|
|
5651
5783
|
}
|
|
5652
|
-
/*
|
|
5653
|
-
|
|
5654
|
-
entities for someone who already has one)
|
|
5784
|
+
/* part 01's quick checks: country and region, where builders will be, anyone under
|
|
5785
|
+
18 (the tiers shown for a yes), and who is behind it (the full list of legal
|
|
5786
|
+
entities for someone who already has one). A demo's answers are its own, so its
|
|
5787
|
+
checks stand down. */
|
|
5655
5788
|
function paintChecks() {
|
|
5656
5789
|
var p = phys(), a = p.answers;
|
|
5790
|
+
$('checksMain').hidden = physStopped || !!state.demo;
|
|
5657
5791
|
physPaintPills();
|
|
5658
5792
|
$('physAges').hidden = a.minors_on_board !== true;
|
|
5659
5793
|
var forms = PHYS_ENTITY_FORMS.indexOf(a.entity) !== -1 || p.entityForms === true;
|
|
@@ -5662,12 +5796,16 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
5662
5796
|
physFillSelects();
|
|
5663
5797
|
physApplyLimits();
|
|
5664
5798
|
}
|
|
5799
|
+
/* the screening stop, in place of the checks: nothing is created */
|
|
5800
|
+
var physStopped = false;
|
|
5665
5801
|
function checksShow(which) {
|
|
5666
|
-
|
|
5667
|
-
$('checksStop').hidden =
|
|
5668
|
-
$('
|
|
5669
|
-
|
|
5670
|
-
|
|
5802
|
+
physStopped = which === 'stop';
|
|
5803
|
+
$('checksStop').hidden = !physStopped;
|
|
5804
|
+
$('checksMain').hidden = physStopped || !!state.demo;
|
|
5805
|
+
if (physStopped) {
|
|
5806
|
+
var h = $('phys-hstop');
|
|
5807
|
+
h.setAttribute('tabindex', '-1'); h.focus({ preventScroll: false });
|
|
5808
|
+
}
|
|
5671
5809
|
}
|
|
5672
5810
|
|
|
5673
5811
|
/* the Team size row's controls: one or many, the start count, and the month-three guess */
|
|
@@ -5704,9 +5842,11 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
5704
5842
|
}).then(function (r) { return r.ok ? r.json() : null; }).catch(function () { return null; });
|
|
5705
5843
|
}
|
|
5706
5844
|
/* What the table hides follows the team and the framing, so a change to either on
|
|
5707
|
-
|
|
5845
|
+
part 02 asks it again and repaints the rows it touches. */
|
|
5708
5846
|
function physRecheck() {
|
|
5847
|
+
if (state.demo) return;
|
|
5709
5848
|
physCheck().then(function (res) {
|
|
5849
|
+
if (res && res.stop) { $('physStopMsg').textContent = res.message || ''; checksShow('stop'); return; }
|
|
5710
5850
|
if (!res || !res.soft_limits) return;
|
|
5711
5851
|
physLimits = res.soft_limits.limits || [];
|
|
5712
5852
|
physApplyLimits();
|
|
@@ -5714,37 +5854,26 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
5714
5854
|
});
|
|
5715
5855
|
}
|
|
5716
5856
|
|
|
5717
|
-
/*
|
|
5718
|
-
one the create runs —
|
|
5719
|
-
|
|
5720
|
-
|
|
5721
|
-
|
|
5722
|
-
|
|
5723
|
-
|
|
5724
|
-
if (
|
|
5725
|
-
|
|
5726
|
-
|
|
5727
|
-
|
|
5728
|
-
|
|
5729
|
-
physBusy = true;
|
|
5730
|
-
physDefaults();
|
|
5731
|
-
physCheck().then(function (res) {
|
|
5732
|
-
physBusy = false;
|
|
5733
|
-
if (res && res.stop) { $('physStopMsg').textContent = res.message || ''; checksShow('stop'); return; }
|
|
5734
|
-
physLimits = (res && res.soft_limits && res.soft_limits.limits) || [];
|
|
5735
|
-
show(4, true);
|
|
5857
|
+
/* The screening stop (task 1004418), asked by Create itself (task 1004648): the
|
|
5858
|
+
server's own screen — the one the create runs — over the answers given so far,
|
|
5859
|
+
with the sentence from part 01. A stop ends the page there, in place of the
|
|
5860
|
+
checks, before anything exists; otherwise its soft limits shape part 02. An
|
|
5861
|
+
unanswered check is not a stop: the create runs the same screen and is the
|
|
5862
|
+
authority. Resolves true when Create may go on. */
|
|
5863
|
+
function physScreen() {
|
|
5864
|
+
if (state.demo) return Promise.resolve(true);
|
|
5865
|
+
return physCheck().then(function (res) {
|
|
5866
|
+
if (res && res.stop) { $('physStopMsg').textContent = res.message || ''; checksShow('stop'); return false; }
|
|
5867
|
+
if (res && res.soft_limits) { physLimits = res.soft_limits.limits || []; physApplyLimits(); paintSetup(); }
|
|
5868
|
+
return true;
|
|
5736
5869
|
});
|
|
5737
|
-
return false;
|
|
5738
5870
|
}
|
|
5739
5871
|
|
|
5872
|
+
/* the stop's way back: the answers stay, so the founder changes the one that stopped it */
|
|
5740
5873
|
$('physStartOver').addEventListener('click', function () {
|
|
5741
|
-
state.description = '';
|
|
5742
|
-
if ($('f-desc')) $('f-desc').value = '';
|
|
5743
|
-
phys().answers = {};
|
|
5744
|
-
state.confirmed = {};
|
|
5745
|
-
saveDraft();
|
|
5746
|
-
show(2, true);
|
|
5747
5874
|
checksShow('main');
|
|
5875
|
+
paintChecks();
|
|
5876
|
+
$('physCountry').focus();
|
|
5748
5877
|
});
|
|
5749
5878
|
root.querySelectorAll('#view-new [data-phys]').forEach(function (b) {
|
|
5750
5879
|
b.addEventListener('click', function () {
|
|
@@ -5763,9 +5892,12 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
5763
5892
|
}
|
|
5764
5893
|
if (k === 'project_state' && a[k] !== 'existing') { delete a.existing_work; delete a.main_work; }
|
|
5765
5894
|
if (k === 'framing') physFramingChanged();
|
|
5895
|
+
/* what the table hides follows the checks too, and a stop says itself at once */
|
|
5896
|
+
else if (PHYS_CHECK_KEYS.indexOf(k) !== -1) physRecheck();
|
|
5766
5897
|
physHint(''); saveDraft();
|
|
5767
5898
|
paintChecks();
|
|
5768
5899
|
paintSetup();
|
|
5900
|
+
paintCreate();
|
|
5769
5901
|
});
|
|
5770
5902
|
});
|
|
5771
5903
|
/* A hybrid or local framing starts from the canvas's suite until the founder picks
|
|
@@ -5773,7 +5905,6 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
5773
5905
|
function physFramingChanged() {
|
|
5774
5906
|
var p = phys(), a = p.answers;
|
|
5775
5907
|
if ((a.framing === 'hybrid' || a.framing === 'local') && !p.suiteTouched) a.services = PHYS_SUITE_START[a.framing].slice();
|
|
5776
|
-
unconfirm(['app']);
|
|
5777
5908
|
physRecheck();
|
|
5778
5909
|
}
|
|
5779
5910
|
/* the Team size row's controls: one or many, the start count, the guess */
|
|
@@ -5787,7 +5918,6 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
5787
5918
|
a.builders_at_start = 2; a.builders_expected = physGuess(2); p.guessTouched = false;
|
|
5788
5919
|
state.teamShape = 'small-team';
|
|
5789
5920
|
}
|
|
5790
|
-
unconfirm(['rewards', 'extras']);
|
|
5791
5921
|
saveDraft(); paintSetup(); physRecheck();
|
|
5792
5922
|
});
|
|
5793
5923
|
});
|
|
@@ -5829,7 +5959,7 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
5829
5959
|
var a = phys().answers;
|
|
5830
5960
|
a.home_country = $('physCountry').value || null;
|
|
5831
5961
|
if (a.home_region && a.home_region.indexOf((a.home_country || '') + '-') !== 0) a.home_region = null;
|
|
5832
|
-
physHint(''); saveDraft(); paintChecks();
|
|
5962
|
+
physHint(''); saveDraft(); paintChecks(); paintCreate(); physRecheck();
|
|
5833
5963
|
});
|
|
5834
5964
|
$('physRegion').addEventListener('change', function () { phys().answers.home_region = $('physRegion').value || null; saveDraft(); });
|
|
5835
5965
|
$('physHaveEntity').addEventListener('click', function () { phys().entityForms = true; saveDraft(); paintChecks(); });
|
|
@@ -5937,46 +6067,6 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
5937
6067
|
return true;
|
|
5938
6068
|
}
|
|
5939
6069
|
|
|
5940
|
-
/* per-screen validation on Continue */
|
|
5941
|
-
function validateStep(step) {
|
|
5942
|
-
/* the front door's one tick (task 1004417): nothing past it until it is given.
|
|
5943
|
-
The fork's own submit door is "Start my project": a real project, not the demo. */
|
|
5944
|
-
if (step === 1) {
|
|
5945
|
-
if (!state.termsAck) {
|
|
5946
|
-
$('h-terms').textContent = 'Tick the box to go on. It’s how your project records that you accepted the terms.';
|
|
5947
|
-
$('h-terms').className = 'hint err';
|
|
5948
|
-
return false;
|
|
5949
|
-
}
|
|
5950
|
-
if (state.demo) { state.demo = null; state.confirmed = {}; }
|
|
5951
|
-
return true;
|
|
5952
|
-
}
|
|
5953
|
-
if (step === 2) {
|
|
5954
|
-
if (!state.name.trim()) { $('h-name').textContent = 'Give it a name to start.'; $('h-name').className = 'hint err'; return false; }
|
|
5955
|
-
if (!state.projType) {
|
|
5956
|
-
$('h-projtype').textContent = 'Pick one — Not sure is a fine answer.';
|
|
5957
|
-
$('h-projtype').className = 'hint err';
|
|
5958
|
-
return false;
|
|
5959
|
-
}
|
|
5960
|
-
return true;
|
|
5961
|
-
}
|
|
5962
|
-
/* the quick checks walk to the review themselves, after the server's screen */
|
|
5963
|
-
if (step === 3) return checksAdvance();
|
|
5964
|
-
/* the review: every row that applies confirmed at once, each still true */
|
|
5965
|
-
if (step === 4) return confirmAllRows();
|
|
5966
|
-
return true;
|
|
5967
|
-
}
|
|
5968
|
-
|
|
5969
|
-
root.querySelectorAll('.panel form').forEach(function (form) {
|
|
5970
|
-
form.addEventListener('submit', function (ev) {
|
|
5971
|
-
ev.preventDefault();
|
|
5972
|
-
var next = Number(form.getAttribute('data-next'));
|
|
5973
|
-
if (!validateStep(next - 1)) return;
|
|
5974
|
-
/* a demo's answers are the demo's own, so it skips the quick checks */
|
|
5975
|
-
if (next === 3 && state.demo) { physDefaults(); show(4, true); return; }
|
|
5976
|
-
show(next, true);
|
|
5977
|
-
});
|
|
5978
|
-
});
|
|
5979
|
-
|
|
5980
6070
|
var appOptsEl = root.querySelector('#appOpts');
|
|
5981
6071
|
if (appOptsEl) appOptsEl.addEventListener('change', function (ev) {
|
|
5982
6072
|
if (ev.target && ev.target.name === 'appPlatform' && !ev.target.disabled) { state.appPlatform = ev.target.value; saveDraft(); syncRenderSetup(); paintSetup(); }
|
|
@@ -6033,7 +6123,7 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
6033
6123
|
: 'Once the project is up, we create your app on your Render account. Your key is used once, then thrown away.';
|
|
6034
6124
|
/* then the app's own progress, from the same read the project's page uses (task 1004353) */
|
|
6035
6125
|
var box = $('doneApp');
|
|
6036
|
-
if (box) watchApp(instanceId, box, function () { return state.step ===
|
|
6126
|
+
if (box) watchApp(instanceId, box, function () { return state.step === 2; }, 5000);
|
|
6037
6127
|
});
|
|
6038
6128
|
}).catch(function (err) {
|
|
6039
6129
|
note.className = 'hint err';
|
|
@@ -6053,7 +6143,7 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
6053
6143
|
state wholesale), so the picker never edits an orphaned copy */
|
|
6054
6144
|
if (!lookPicker || lookPickerModel !== state.look) {
|
|
6055
6145
|
lookPickerModel = state.look;
|
|
6056
|
-
lookPicker = lookKit.buildLookPicker($('wizLook'), state.look, function () { saveDraft(); }, 'wiz',
|
|
6146
|
+
lookPicker = lookKit.buildLookPicker($('wizLook'), state.look, function () { saveDraft(); paintSetup(); }, 'wiz',
|
|
6057
6147
|
function () { return state.name; });
|
|
6058
6148
|
} else lookPicker.repaint();
|
|
6059
6149
|
}
|
|
@@ -6070,7 +6160,7 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
6070
6160
|
});
|
|
6071
6161
|
}
|
|
6072
6162
|
|
|
6073
|
-
/* ──
|
|
6163
|
+
/* ── part 02's controls: the app platform and the ship mode (tasks 1004351, 1004629) ── */
|
|
6074
6164
|
/* the app row (task 1004351): a native radio group, so the draft only mirrors it.
|
|
6075
6165
|
An older draft has no appPlatform, and a value this page does not offer (a
|
|
6076
6166
|
platform still marked soon, or one that was removed) reads as 'later' — the
|
|
@@ -6104,31 +6194,25 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
6104
6194
|
root.querySelectorAll('#shipOpts input[name=shipMode]').forEach(function (i) { i.checked = i.value === pick; });
|
|
6105
6195
|
}
|
|
6106
6196
|
|
|
6107
|
-
|
|
6197
|
+
/* ── part 02, how it's run (task 1004648): a summary to skim, not a gate ──
|
|
6198
|
+
Every row is prefilled from the answers and says its value with one plain line
|
|
6199
|
+
under it. Change opens the row's own control in place (the old steps' controls,
|
|
6200
|
+
moved whole, so every handler and id is the one it always was) and reads Done
|
|
6201
|
+
while it is open; one row is open at a time. No row needs confirming. */
|
|
6202
|
+
var ROWS = ['code', 'address', 'team', 'extras', 'rewards', 'app', 'run', 'ship', 'look'];
|
|
6108
6203
|
function rowEl(key) { return root.querySelector('#reviewRows .setRow[data-row="' + key + '"]'); }
|
|
6109
|
-
function confirmedRows() {
|
|
6110
|
-
if (!state.confirmed || typeof state.confirmed !== 'object') state.confirmed = {};
|
|
6111
|
-
return state.confirmed;
|
|
6112
|
-
}
|
|
6113
6204
|
/* a row the answers make not apply: rewards for someone building alone (the table
|
|
6114
6205
|
hides the question) */
|
|
6115
6206
|
function rowApplies(key) { return !(key === 'rewards' && physSkips(6)); }
|
|
6116
|
-
/* a row whose value is fixed, so it is
|
|
6117
|
-
|
|
6207
|
+
/* a row whose value is fixed, so it is said but never changed here: the demo's own
|
|
6208
|
+
answers, and the app platform a local or open-source framing rules out */
|
|
6118
6209
|
function rowFixed(key) {
|
|
6119
6210
|
if (state.demo && (key === 'team' || key === 'rewards' || key === 'run')) return true;
|
|
6120
6211
|
return key === 'app' && appSkipped();
|
|
6121
6212
|
}
|
|
6122
|
-
|
|
6123
|
-
|
|
6124
|
-
|
|
6125
|
-
}
|
|
6126
|
-
function unconfirm(keys) {
|
|
6127
|
-
var c = confirmedRows();
|
|
6128
|
-
keys.forEach(function (k) { delete c[k]; });
|
|
6129
|
-
if (state.step === 4) paintSetup();
|
|
6130
|
-
}
|
|
6131
|
-
/* the checks a row's own old step made on Next — a row cannot be confirmed past them */
|
|
6213
|
+
/* the checks a row's own old step made on Next. Nothing is confirmed, but a row
|
|
6214
|
+
whose answer cannot be filed as it stands (no repo picked yet, a handle that is
|
|
6215
|
+
taken, a Render key not checked) keeps Create from filing it. */
|
|
6132
6216
|
function rowValid(key) {
|
|
6133
6217
|
if (key === 'code') return validateCode();
|
|
6134
6218
|
if (key === 'address') return validateAddress();
|
|
@@ -6137,6 +6221,10 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
6137
6221
|
if (key === 'run') return !!phys().answers.framing;
|
|
6138
6222
|
return true;
|
|
6139
6223
|
}
|
|
6224
|
+
function firstInvalidRow() {
|
|
6225
|
+
for (var i = 0; i < ROWS.length; i++) if (rowApplies(ROWS[i]) && !rowValid(ROWS[i])) return ROWS[i];
|
|
6226
|
+
return null;
|
|
6227
|
+
}
|
|
6140
6228
|
function openRow(key) {
|
|
6141
6229
|
var row = rowEl(key);
|
|
6142
6230
|
if (!row || rowFixed(key)) return;
|
|
@@ -6150,6 +6238,7 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
6150
6238
|
if (key === 'code') syncHome();
|
|
6151
6239
|
if (key === 'app') { syncAppStep(); syncRenderSetup(); }
|
|
6152
6240
|
if (key === 'ship') syncShipStep();
|
|
6241
|
+
if (key === 'look') renderLook();
|
|
6153
6242
|
}
|
|
6154
6243
|
function closeRow(key) {
|
|
6155
6244
|
var row = rowEl(key);
|
|
@@ -6157,58 +6246,20 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
6157
6246
|
row.querySelector('.opts').hidden = true;
|
|
6158
6247
|
var chg = row.querySelector('[data-row-chg]');
|
|
6159
6248
|
chg.setAttribute('aria-expanded', 'false');
|
|
6160
|
-
chg.textContent = '
|
|
6161
|
-
}
|
|
6162
|
-
/* Done on an open row, or the page's one "Looks right, continue": the row's own
|
|
6163
|
-
checks first — a row that fails stays open with its reason showing — then it is
|
|
6164
|
-
the founder's answer. The extras row turns "the suggested set" into an answer
|
|
6165
|
-
given, a different fact from never asked. */
|
|
6166
|
-
function confirmRow(key) {
|
|
6167
|
-
if (!rowValid(key)) { openRow(key); return false; }
|
|
6168
|
-
/* only once the catalog is here: without it the suggested set is unknown, and an
|
|
6169
|
-
empty answer would switch off the very bundle the server applies to no answer */
|
|
6170
|
-
if (key === 'extras' && starterBundles) state.modules = pickedModules();
|
|
6171
|
-
confirmedRows()[key] = true;
|
|
6172
|
-
closeRow(key);
|
|
6173
|
-
saveDraft();
|
|
6174
|
-
paintSetup();
|
|
6175
|
-
return true;
|
|
6176
|
-
}
|
|
6177
|
-
/* the page's one confirmation (task 1004550): every row that applies, in order,
|
|
6178
|
-
through its own check; the first that fails opens with its reason and stops it */
|
|
6179
|
-
function confirmAllRows() {
|
|
6180
|
-
var rows = unconfirmedRows();
|
|
6181
|
-
for (var i = 0; i < rows.length; i++) {
|
|
6182
|
-
if (!confirmRow(rows[i])) {
|
|
6183
|
-
var row = rowEl(rows[i]);
|
|
6184
|
-
if (row && row.scrollIntoView) row.scrollIntoView({ block: 'center' });
|
|
6185
|
-
$('h-review').textContent = 'Fix the row that’s open, then continue.';
|
|
6186
|
-
$('h-review').className = 'hint err';
|
|
6187
|
-
return false;
|
|
6188
|
-
}
|
|
6189
|
-
}
|
|
6190
|
-
$('h-review').textContent = '\u00a0'; $('h-review').className = 'hint';
|
|
6191
|
-
return true;
|
|
6192
|
-
}
|
|
6193
|
-
/* back to the review from a later screen with rows left to confirm: show the first
|
|
6194
|
-
one that fails its check opened, and confirm nothing on the founder's behalf */
|
|
6195
|
-
function reopenReview() {
|
|
6196
|
-
show(4, true);
|
|
6197
|
-
var bad = unconfirmedRows().filter(function (k) { return !rowValid(k); })[0];
|
|
6198
|
-
if (bad) openRow(bad);
|
|
6249
|
+
chg.textContent = 'Change';
|
|
6199
6250
|
}
|
|
6200
6251
|
$('reviewRows').addEventListener('click', function (ev) {
|
|
6201
6252
|
var t = ev.target.closest && ev.target.closest('[data-row-chg]');
|
|
6202
6253
|
if (!t) return;
|
|
6203
6254
|
var key = t.closest('.setRow').getAttribute('data-row');
|
|
6204
|
-
/* Done: the row's check, then closed — or left open with its reason */
|
|
6255
|
+
/* Done: the row's own check, then closed — or left open with its reason showing */
|
|
6205
6256
|
if (rowEl(key).classList.contains('open')) {
|
|
6206
|
-
if (
|
|
6257
|
+
if (rowValid(key)) { closeRow(key); paintSetup(); t.focus({ preventScroll: true }); }
|
|
6207
6258
|
return;
|
|
6208
6259
|
}
|
|
6209
|
-
/*
|
|
6210
|
-
ROWS.forEach(function (k) { if (k !== key && rowEl(k).classList.contains('open') && rowValid(k))
|
|
6211
|
-
|
|
6260
|
+
/* Change: one row open at a time — another open row closes if its answer holds */
|
|
6261
|
+
ROWS.forEach(function (k) { if (k !== key && rowEl(k).classList.contains('open') && rowValid(k)) closeRow(k); });
|
|
6262
|
+
openRow(key); paintSetup();
|
|
6212
6263
|
});
|
|
6213
6264
|
/* an open row's value line follows what is typed or picked under it, live — the
|
|
6214
6265
|
controls' own handlers run first (they are on the targets), then the row repaints */
|
|
@@ -6220,9 +6271,16 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
6220
6271
|
var row = ev.target.closest('.setRow'), t = rowText(row.getAttribute('data-row'));
|
|
6221
6272
|
row.querySelector('[data-row-v]').textContent = t.v;
|
|
6222
6273
|
row.querySelector('[data-row-s]').textContent = t.s;
|
|
6274
|
+
if (row.getAttribute('data-row') !== 'look') paintCreate();
|
|
6223
6275
|
}
|
|
6224
6276
|
});
|
|
6225
6277
|
});
|
|
6278
|
+
/* the look row's swatch: the chosen look's own accent, or the founder's */
|
|
6279
|
+
function lookAccent(lk) {
|
|
6280
|
+
if (lk.look === 'custom') return lk.accent || '';
|
|
6281
|
+
var L = lookKit.LOOKS[lk.look];
|
|
6282
|
+
return L ? L.colors.accent : '';
|
|
6283
|
+
}
|
|
6226
6284
|
|
|
6227
6285
|
/* what each row says: its value and one plain line under it */
|
|
6228
6286
|
function rowText(key) {
|
|
@@ -6237,14 +6295,14 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
6237
6295
|
var av = !custom && !state.noAddress ? slugAvailState() : 'unknown';
|
|
6238
6296
|
if (state.noAddress && !custom) return { v: 'No address yet', s: 'Sign-in can’t be switched on until it has one.' };
|
|
6239
6297
|
/* a dotless host (local dev) assigns nothing, so the row asks for a domain or the opt-out */
|
|
6240
|
-
if (!resolvedDomain()) return { v: 'No address assigned here', s: 'Add a domain you own, or go without one for now.' };
|
|
6298
|
+
if (!resolvedDomain()) return { v: validSlug(state.slug) ? 'No address assigned here' : 'Name it first', s: validSlug(state.slug) ? 'Add a domain you own, or go without one for now.' : 'The address comes with the name.' };
|
|
6241
6299
|
return {
|
|
6242
|
-
v: resolvedDomain()
|
|
6300
|
+
v: resolvedDomain(),
|
|
6243
6301
|
s: custom ? 'Your own domain. Your projects page walks you through pointing it here.'
|
|
6244
6302
|
: av === 'taken' ? 'Already taken — change the handle.'
|
|
6245
6303
|
: av === 'yours' ? 'You already have that one — change the handle.'
|
|
6246
6304
|
: av === 'reserved' ? 'Reserved by the platform — change the handle.'
|
|
6247
|
-
: '
|
|
6305
|
+
: 'You can add your own domain later.'
|
|
6248
6306
|
};
|
|
6249
6307
|
}
|
|
6250
6308
|
if (key === 'app') {
|
|
@@ -6252,6 +6310,8 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
6252
6310
|
return { v: appPlatformChoice() === 'render' ? 'Render' : 'Decide later', s: appRowDetail() };
|
|
6253
6311
|
}
|
|
6254
6312
|
if (key === 'extras') {
|
|
6313
|
+
/* no kind yet: the suggestion follows the kind, so say that rather than "0" */
|
|
6314
|
+
if (state.modules === null && !state.projType) return { v: 'Just the core for now', s: 'Pick a kind and we suggest extras for it.' };
|
|
6255
6315
|
var picked = pickedModules();
|
|
6256
6316
|
var lead = !starterBundles
|
|
6257
6317
|
? (state.modules === null ? 'The suggested set' : 'The extras you picked')
|
|
@@ -6262,7 +6322,7 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
6262
6322
|
}
|
|
6263
6323
|
if (key === 'team') {
|
|
6264
6324
|
if (state.demo) return { v: state.demo.people + (state.demo.people === 1 ? ' person' : ' people'), s: state.demo.hours_each + (state.demo.hours_each === 1 ? ' hour' : ' hours') + ' each. When the time box runs out, we ask if you want to keep it.' };
|
|
6265
|
-
if (physSolo()) return { v: '
|
|
6325
|
+
if (physSolo()) return { v: 'Just you to start', s: 'Open to invites.' };
|
|
6266
6326
|
return { v: a.builders_at_start + ' people now', s: 'About ' + a.builders_expected + ' by month three · ' + (state.teamShape === 'community' ? 'anyone can apply' : 'people you invite') + '.' };
|
|
6267
6327
|
}
|
|
6268
6328
|
if (key === 'rewards') {
|
|
@@ -6286,12 +6346,20 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
6286
6346
|
? { v: 'Manual', s: 'The AI waits for you to approve each ship. You can change this later in your project’s settings.' }
|
|
6287
6347
|
: { v: 'Auto (recommended)', s: 'The AI ships finished work on its own. You can change this later in your project’s settings.' };
|
|
6288
6348
|
}
|
|
6349
|
+
if (key === 'look') {
|
|
6350
|
+
var lk = state.look || defaultLook();
|
|
6351
|
+
var L = lookKit.LOOKS[lk.look];
|
|
6352
|
+
var name = L ? L.title.replace(/^The /, '') : 'Your own colours';
|
|
6353
|
+
return {
|
|
6354
|
+
v: name.charAt(0).toUpperCase() + name.slice(1),
|
|
6355
|
+
s: (lk.logo ? 'With your logo.' : 'Add a logo later from the project page.') + (lk.nightTint === false ? ' Night tint off.' : '')
|
|
6356
|
+
};
|
|
6357
|
+
}
|
|
6289
6358
|
return { v: '', s: '' };
|
|
6290
6359
|
}
|
|
6291
|
-
/* paint every row from the draft
|
|
6360
|
+
/* paint every row from the draft */
|
|
6292
6361
|
function paintSetup() {
|
|
6293
6362
|
if (!ROWS) return; /* boot: setMode() runs before this block has run */
|
|
6294
|
-
var c = confirmedRows();
|
|
6295
6363
|
var suite = phys().answers.framing === 'hybrid' || phys().answers.framing === 'local';
|
|
6296
6364
|
$('physSuite').hidden = !suite;
|
|
6297
6365
|
$('physSuiteLbl').textContent = phys().answers.framing === 'local' ? 'Your local suite' : 'Your hybrid suite';
|
|
@@ -6308,19 +6376,15 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
6308
6376
|
ROWS.forEach(function (key) {
|
|
6309
6377
|
var row = rowEl(key), t = rowText(key);
|
|
6310
6378
|
row.hidden = !rowApplies(key);
|
|
6311
|
-
row.classList.toggle('done', !!c[key]);
|
|
6312
6379
|
row.querySelector('[data-row-v]').textContent = t.v;
|
|
6313
6380
|
row.querySelector('[data-row-s]').textContent = t.s;
|
|
6314
6381
|
row.querySelector('[data-row-chg]').hidden = rowFixed(key);
|
|
6315
6382
|
});
|
|
6383
|
+
$('lookDot').style.background = lookAccent(state.look || defaultLook());
|
|
6316
6384
|
}
|
|
6317
|
-
/*
|
|
6385
|
+
/* the one line beside Create: what it is about to make */
|
|
6318
6386
|
function renderRecap() {
|
|
6319
|
-
var
|
|
6320
|
-
/* every road back to this screen gets a live button — the create path disables
|
|
6321
|
-
it and only the failure branch used to restore it */
|
|
6322
|
-
cb.disabled = false; cb.textContent = 'Create my project';
|
|
6323
|
-
var bits = [state.name || state.slug, typeLabel(state.projType) || '', state.mode === 'adopt' ? 'your repo' : 'new repo', resolvedDomain() || 'no address yet'];
|
|
6387
|
+
var bits = [String(state.name || '').trim() || state.slug, typeLabel(state.projType) || '', state.mode === 'adopt' ? 'your repo' : 'new repo', resolvedDomain() || 'no address yet'];
|
|
6324
6388
|
if (state.demo) bits.push('demo');
|
|
6325
6389
|
$('wizRecap').textContent = bits.filter(Boolean).join(' · ');
|
|
6326
6390
|
}
|
|
@@ -6400,15 +6464,29 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
6400
6464
|
var btn = this;
|
|
6401
6465
|
var alertBox = $('createAlert');
|
|
6402
6466
|
alertBox.classList.remove('on');
|
|
6403
|
-
/* a
|
|
6404
|
-
|
|
6405
|
-
|
|
6406
|
-
|
|
6407
|
-
|
|
6408
|
-
|
|
6409
|
-
if (
|
|
6467
|
+
/* a name and the terms tick, and nothing else (task 1004648); the button already
|
|
6468
|
+
waits for both, so this only guards a click that raced a change */
|
|
6469
|
+
if (createWhy()) { paintCreate(); $(String(state.name || '').trim() ? 'termsAck' : 'newName').focus(); return; }
|
|
6470
|
+
/* no row is confirmed, but one that cannot be filed as it stands opens with its
|
|
6471
|
+
reason, and Create waits for it */
|
|
6472
|
+
var bad = firstInvalidRow();
|
|
6473
|
+
if (bad) {
|
|
6474
|
+
ROWS.forEach(function (k) { if (k !== bad && rowEl(k).classList.contains('open')) closeRow(k); });
|
|
6475
|
+
openRow(bad);
|
|
6476
|
+
paintSetup();
|
|
6477
|
+
var badRow = rowEl(bad);
|
|
6478
|
+
if (badRow && badRow.scrollIntoView) badRow.scrollIntoView({ block: 'center' });
|
|
6479
|
+
$('createWhy').textContent = 'Fix the row that’s open, then create.';
|
|
6480
|
+
return;
|
|
6481
|
+
}
|
|
6482
|
+
createBusy = true;
|
|
6410
6483
|
btn.disabled = true; btn.textContent = 'Raising it into the sky…';
|
|
6411
|
-
|
|
6484
|
+
/* the screening stop first: an answer the platform cannot serve stops the page
|
|
6485
|
+
here, before anything — the repo included — exists */
|
|
6486
|
+
physScreen().then(function (ok) {
|
|
6487
|
+
if (!ok) { var stop = new Error('stopped'); stop.stopped = true; throw stop; }
|
|
6488
|
+
return ensureFreshRepo();
|
|
6489
|
+
}).then(function () {
|
|
6412
6490
|
return fetch(API + '/provisioning/instances', {
|
|
6413
6491
|
method: 'POST', credentials: 'same-origin',
|
|
6414
6492
|
headers: { 'Content-Type': 'application/json' },
|
|
@@ -6476,21 +6554,24 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
6476
6554
|
}));
|
|
6477
6555
|
sessionStorage.removeItem(DRAFT_KEY);
|
|
6478
6556
|
} catch (e) {}
|
|
6557
|
+
createBusy = false;
|
|
6479
6558
|
renderDone();
|
|
6480
|
-
show(
|
|
6559
|
+
show(2, true);
|
|
6481
6560
|
sendRenderSetup(data.instance && data.instance.id); // the key rides the new project's own setup run (task 1004352)
|
|
6482
6561
|
sendLookSetup(data.instance && data.instance.id); // the look + logo, like the Render key: right after Create (task 1004421)
|
|
6483
6562
|
startProgress(data.instance && data.instance.id);
|
|
6484
6563
|
}).catch(function (err) {
|
|
6564
|
+
createBusy = false;
|
|
6485
6565
|
if (String(err && err.message) === 'signing in') return;
|
|
6486
|
-
|
|
6566
|
+
paintCreate();
|
|
6567
|
+
if (err && err.stopped) return; /* the stop says itself, in place of the checks */
|
|
6487
6568
|
if (err && err.gotoHome) {
|
|
6488
|
-
/* A repo-creation problem (name taken / reconnect) —
|
|
6489
|
-
|
|
6490
|
-
show(4, true);
|
|
6491
|
-
delete confirmedRows().code;
|
|
6569
|
+
/* A repo-creation problem (name taken / reconnect) — open the Code row with the
|
|
6570
|
+
reason, so the founder fixes it where the repo is chosen. */
|
|
6492
6571
|
openRow('code');
|
|
6493
6572
|
paintSetup();
|
|
6573
|
+
var codeRow = rowEl('code');
|
|
6574
|
+
if (codeRow && codeRow.scrollIntoView) codeRow.scrollIntoView({ block: 'center' });
|
|
6494
6575
|
$('h-home').textContent = err.homeMsg || 'Please check the repository again.';
|
|
6495
6576
|
$('h-home').className = 'hint err';
|
|
6496
6577
|
return;
|
|
@@ -7216,13 +7297,14 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
7216
7297
|
is three-valued and null is its "nothing said" sentinel; leaving the key out
|
|
7217
7298
|
left it UNDEFINED, which is not null — so pickedModules() reached .slice()
|
|
7218
7299
|
on it and the second project's Modules step threw. */
|
|
7219
|
-
state = { step: 1, name: '', projType: null, description: '', teamShape: null, modules: null, mode: 'greenfield', owner: '', ownerTouched: false, repo: '', repoTouched: false, slug: '', slugTouched: false, domain: '', noAddress: false, appPlatform: 'later', shipMode: 'auto', physics: null, demo: null, look: null, termsAck: false
|
|
7300
|
+
state = { step: 1, name: '', projType: null, description: '', teamShape: null, modules: null, mode: 'greenfield', modeChosen: false, owner: '', ownerTouched: false, repo: '', repoTouched: false, slug: '', slugTouched: false, domain: '', noAddress: false, appPlatform: 'later', shipMode: 'auto', physics: null, demo: null, look: null, termsAck: false };
|
|
7220
7301
|
$('newName').value = ''; $('f-owner').value = ''; $('f-repo').value = ''; $('f-slug').value = ''; $('f-domain').value = '';
|
|
7221
7302
|
$('f-noaddr').checked = false; $('f-desc').value = '';
|
|
7222
|
-
$('termsAck').checked = false;
|
|
7303
|
+
$('termsAck').checked = false; demoShow(false); checksShow('main');
|
|
7304
|
+
ROWS.forEach(function (k) { if (rowEl(k).classList.contains('open')) closeRow(k); });
|
|
7223
7305
|
/* Re-seed the owner from the signed-in account for the next project. */
|
|
7224
7306
|
if (me && me.github_login) { state.owner = me.github_login; $('f-owner').value = state.owner; }
|
|
7225
|
-
|
|
7307
|
+
paintNameHint();
|
|
7226
7308
|
paintType(null);
|
|
7227
7309
|
paintTeam(null);
|
|
7228
7310
|
setMode('greenfield');
|
|
@@ -7601,8 +7683,7 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
7601
7683
|
panel.setAttribute('data-moment', hop.target);
|
|
7602
7684
|
$('hop').classList.remove('hopFading');
|
|
7603
7685
|
if (hop.target === 'wait') hopStart(); else hopStop();
|
|
7604
|
-
|
|
7605
|
-
if (hop.target !== 'wait') { panel.classList.remove('hopSignin'); $('hopSignin').setAttribute('aria-expanded', 'false'); }
|
|
7686
|
+
stepsPaint();
|
|
7606
7687
|
}
|
|
7607
7688
|
if (m === 'arrive' && was === 'wait' && !REDUCED && hop.raf && performance.now() - hop.since > 2500) {
|
|
7608
7689
|
cancelAnimationFrame(hop.raf); hop.raf = 0;
|
|
@@ -7618,9 +7699,7 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
7618
7699
|
hop.target = ''; hop.since = 0; hop.tr = 0; hop.trDone = null; hop.p = null;
|
|
7619
7700
|
hop.best = 0; hop.maxed = false;
|
|
7620
7701
|
if (hop.w) hopBuild();
|
|
7621
|
-
|
|
7622
|
-
var panel = $('panel-done');
|
|
7623
|
-
panel.removeAttribute('data-moment'); panel.classList.remove('hopSignin');
|
|
7702
|
+
$('panel-done').removeAttribute('data-moment');
|
|
7624
7703
|
}
|
|
7625
7704
|
|
|
7626
7705
|
/* the status line and the bar read what the strip already says — one
|
|
@@ -7636,54 +7715,19 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
7636
7715
|
$('hopBarFill').style.width = Math.max(4, lis ? Math.min(100, done / lis * 100) : 0) + '%';
|
|
7637
7716
|
}
|
|
7638
7717
|
|
|
7639
|
-
/*
|
|
7640
|
-
|
|
7641
|
-
|
|
7642
|
-
|
|
7643
|
-
|
|
7644
|
-
|
|
7645
|
-
|
|
7646
|
-
var panel = $('panel-done'), list = $('humanSteps');
|
|
7647
|
-
if (!panel || !list) return;
|
|
7718
|
+
/* Part 03's checklist (task 1004648): every step on show at once, each ticking
|
|
7719
|
+
itself from what the server has verified (renderSteps, change-only), and the
|
|
7720
|
+
part's state line saying where the founder is. It replaces the paged steps. */
|
|
7721
|
+
function stepsPaint() {
|
|
7722
|
+
var list = $('humanSteps'), st = $('ghState');
|
|
7723
|
+
if (!list || !st) return;
|
|
7724
|
+
if (state.step !== 2) { st.textContent = 'opens once your project exists'; return; }
|
|
7648
7725
|
var items = Array.prototype.slice.call(list.children);
|
|
7649
|
-
var
|
|
7650
|
-
|
|
7651
|
-
|
|
7652
|
-
|
|
7653
|
-
if (!items.length) { $('stepCount').textContent = ''; $('stepBack').hidden = true; $('stepNext').hidden = true; return; }
|
|
7654
|
-
if (fresh) stepAuto = true;
|
|
7655
|
-
if (stepAuto || !(stepIdx >= 0)) {
|
|
7656
|
-
stepIdx = 0;
|
|
7657
|
-
for (var i = 0; i < items.length; i++) { if (!items[i].classList.contains('sdone')) { stepIdx = i; break; } }
|
|
7658
|
-
}
|
|
7659
|
-
stepIdx = Math.max(0, Math.min(items.length - 1, stepIdx));
|
|
7660
|
-
items.forEach(function (li, j) {
|
|
7661
|
-
li.classList.toggle('cur', j === stepIdx);
|
|
7662
|
-
/* a hidden step never counts, so the one on show carries its own number */
|
|
7663
|
-
li.setAttribute('data-n', (j < 9 ? '0' : '') + (j + 1));
|
|
7664
|
-
});
|
|
7665
|
-
$('stepCount').textContent = 'Step ' + (stepIdx + 1) + ' of ' + items.length;
|
|
7666
|
-
$('stepBack').hidden = stepIdx <= 0;
|
|
7667
|
-
$('stepNext').hidden = stepIdx >= items.length - 1;
|
|
7668
|
-
}
|
|
7669
|
-
function stepGo(d) {
|
|
7670
|
-
stepAuto = false;
|
|
7671
|
-
stepIdx += d;
|
|
7672
|
-
stepsPaint();
|
|
7673
|
-
var cur = $('humanSteps').querySelector('li.cur');
|
|
7674
|
-
if (cur) { cur.setAttribute('tabindex', '-1'); cur.focus(); }
|
|
7726
|
+
var done = items.filter(function (li) { return li.classList.contains('sdone'); }).length;
|
|
7727
|
+
st.textContent = items.length && done === items.length ? 'connected ✓'
|
|
7728
|
+
: manifestInFlight() ? 'waiting on GitHub…'
|
|
7729
|
+
: done ? done + ' of ' + items.length + ' done' : 'ready';
|
|
7675
7730
|
}
|
|
7676
|
-
$('stepNext').addEventListener('click', function () { stepGo(1); });
|
|
7677
|
-
$('stepBack').addEventListener('click', function () { stepGo(-1); });
|
|
7678
|
-
|
|
7679
|
-
$('hopSignin').addEventListener('click', function () {
|
|
7680
|
-
var panel = $('panel-done');
|
|
7681
|
-
var open = !panel.classList.contains('hopSignin');
|
|
7682
|
-
panel.classList.toggle('hopSignin', open);
|
|
7683
|
-
this.setAttribute('aria-expanded', open ? 'true' : 'false');
|
|
7684
|
-
var li = $('humanSteps').querySelector('[data-onboard-step="oauth-app"]');
|
|
7685
|
-
if (open && li) { li.setAttribute('tabindex', '-1'); li.focus(); }
|
|
7686
|
-
});
|
|
7687
7731
|
|
|
7688
7732
|
(function hopInput() {
|
|
7689
7733
|
var cv = $('hopCanvas');
|
|
@@ -7757,23 +7801,22 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
7757
7801
|
another project" the only way out.
|
|
7758
7802
|
|
|
7759
7803
|
The reset fires only when there is a SECOND DRAFT to lose, and the draft's own
|
|
7760
|
-
step is what says so. A landed create clears DRAFT_KEY — but show(
|
|
7761
|
-
persists the
|
|
7804
|
+
step is what says so. A landed create clears DRAFT_KEY — but show(2) then
|
|
7805
|
+
persists the created page's own position straight back into it, so "is there a
|
|
7762
7806
|
draft?" is always yes and would have skipped the reset forever, leaving the
|
|
7763
|
-
finished project’s name sitting in the fresh form. Only
|
|
7764
|
-
|
|
7807
|
+
finished project’s name sitting in the fresh form. Only step 1, the page, is a
|
|
7808
|
+
draft: anything else is the created page's bookkeeping, not a project someone
|
|
7765
7809
|
is part-way through typing. */
|
|
7766
7810
|
function enterCreated(created, focus) {
|
|
7767
7811
|
if (focus && !resumeIntent) {
|
|
7768
7812
|
var draft = null;
|
|
7769
7813
|
try { draft = JSON.parse(sessionStorage.getItem(DRAFT_KEY) || 'null'); } catch (e) {}
|
|
7770
|
-
|
|
7771
|
-
if (!at) { resetForNewProject(); at = 1; }
|
|
7814
|
+
if (!(draft && draft.step === 1)) resetForNewProject();
|
|
7772
7815
|
paintResumeOffer(created);
|
|
7773
|
-
/*
|
|
7774
|
-
|
|
7775
|
-
show(
|
|
7776
|
-
|
|
7816
|
+
/* the page's own focus target is its first control, the name, not the heading —
|
|
7817
|
+
the same deliberate-nav rule enter() applies below */
|
|
7818
|
+
show(1, false);
|
|
7819
|
+
$('newName').focus();
|
|
7777
7820
|
return;
|
|
7778
7821
|
}
|
|
7779
7822
|
resumeIntent = false;
|
|
@@ -7798,7 +7841,7 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
7798
7841
|
manifestState = created.manifest_state; manifestPending = true;
|
|
7799
7842
|
}
|
|
7800
7843
|
renderDone();
|
|
7801
|
-
show(
|
|
7844
|
+
show(2, !!focus);
|
|
7802
7845
|
startProgress(created.id);
|
|
7803
7846
|
resumePolls();
|
|
7804
7847
|
}
|
|
@@ -7810,32 +7853,25 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
7810
7853
|
function enter(focus) {
|
|
7811
7854
|
if (authKnown && !me) { show(0, !!focus); return; }
|
|
7812
7855
|
var created = authKnown ? createdRecord() : null;
|
|
7813
|
-
/* A draft
|
|
7814
|
-
|
|
7815
|
-
|
|
7816
|
-
|
|
7817
|
-
|
|
7818
|
-
|
|
7819
|
-
var draftInFlight = state.step
|
|
7856
|
+
/* A draft on the page (step 1) beside a stored create is a SECOND project being
|
|
7857
|
+
typed. A reload or a GitHub round-trip (repo access) is that same visit
|
|
7858
|
+
continuing, so the draft keeps its place and the earlier project stays one
|
|
7859
|
+
click away on the resume line — it used to land on the earlier project's done
|
|
7860
|
+
panel, dropping the founder out of the draft (task 1004549). A deliberate nav
|
|
7861
|
+
still goes through enterCreated. */
|
|
7862
|
+
var draftInFlight = state.step === 1;
|
|
7820
7863
|
if (created && created.id && (focus || !draftInFlight || resumeIntent)) { enterCreated(created, !!focus); return; }
|
|
7821
7864
|
paintResumeOffer(created && created.id ? created : null);
|
|
7822
|
-
/*
|
|
7823
|
-
|
|
7824
|
-
|
|
7825
|
-
|
|
7826
|
-
|
|
7827
|
-
|
|
7828
|
-
|
|
7829
|
-
|
|
7830
|
-
|
|
7831
|
-
|
|
7832
|
-
var resumeStep = state.step;
|
|
7833
|
-
show(1, false);
|
|
7834
|
-
if (!authKnown && resumeStep >= 1 && resumeStep <= 5) { state.step = resumeStep; saveDraft(); }
|
|
7835
|
-
if (focus) $('termsAck').focus();
|
|
7836
|
-
} else {
|
|
7837
|
-
show(step, !!focus);
|
|
7838
|
-
}
|
|
7865
|
+
/* Pre-auth the page is a PLACEHOLDER, not where the visitor is — but show()
|
|
7866
|
+
persists whatever step it renders, so it used to overwrite the draft's real
|
|
7867
|
+
position and leave onAuth() nothing to re-enter to (task 1003683). Put the real
|
|
7868
|
+
step back after rendering the placeholder, in memory AND in the draft. The page
|
|
7869
|
+
itself holds back the authenticated side effects (the repo probe) until /me
|
|
7870
|
+
answers. */
|
|
7871
|
+
var resumeStep = state.step;
|
|
7872
|
+
show(1, false);
|
|
7873
|
+
if (!authKnown) { state.step = resumeStep; saveDraft(); }
|
|
7874
|
+
if (focus) $('newName').focus();
|
|
7839
7875
|
}
|
|
7840
7876
|
/* leave() — park the polls (C8). The due tick would park itself anyway;
|
|
7841
7877
|
this just stops the timers immediately so nothing fires off-stage. */
|
|
@@ -10803,7 +10839,7 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
10803
10839
|
Proof: ../../../tests/project_invite_ui.mjs ══ */
|
|
10804
10840
|
|
|
10805
10841
|
var INVITE_MOUNTS = {
|
|
10806
|
-
wizInvite: { who: 'wizInviteWho', list: 'wizInviteList', msg: 'wizInviteMsg', after: '
|
|
10842
|
+
wizInvite: { who: 'wizInviteWho', list: 'wizInviteList', msg: 'wizInviteMsg', after: 'wizInviteLater', why: 'wizInviteWhy', sugg: 'wizInviteSugg' },
|
|
10807
10843
|
mInvite: { who: 'mInviteWho', list: 'mInviteList', msg: 'mInviteMsg', after: null, why: 'mInviteWhy', sugg: 'mInviteSugg', guild: 'mInviteGuild', guildMsg: 'mInviteGuildMsg' }
|
|
10808
10844
|
};
|
|
10809
10845
|
var inviteSlug = {}; /* mount id → the slug it invites to; '' means no step at all */
|