@bongos/core 1.20.75 → 1.20.77
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 +53 -33
- package/docs/copy-inventory.md +546 -482
- package/docs/copy-registry.json +1208 -631
- package/docs/module-api-changelog.md +4 -0
- package/docs/page-inventory.json +10 -1
- package/docs/page-readings.json +1204 -1061
- package/modules/hall-ui/public/profile-roles.js +170 -0
- package/modules/hall-ui/public/profile.css +42 -5
- package/modules/hall-ui/public/profile.html +12 -5
- package/modules/hall-ui/public/profile.js +66 -27
- package/modules/hall-ui/public/profile.states.json +39 -1
- package/modules/hall-ui/records/profile-roles.md +32 -0
- package/modules/provisioning/planet-physics.js +8 -0
- package/modules/provisioning/soft-limits.js +9 -0
- package/modules/public-landing/public/projects.html +579 -37
- package/modules/public-landing/public/projects.probes.json +6 -3
- package/modules/public-landing/public/projects.states.json +20 -14
- package/modules/ui-design/kit/serve.js +26 -3
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/release-notes.json +12 -0
- package/src/module-api.js +1 -1
- package/tests/founding_builders.mjs +2 -1
- package/tests/helpers.mjs +4 -0
- package/tests/profile_role_headline.mjs +201 -0
- package/tests/profile_ui_cross_project.mjs +3 -0
- package/tests/projects_hub_app_step.mjs +4 -1
- package/tests/provisioning_planet_physics.mjs +24 -2
- package/tests/wizard_physics.mjs +11 -4
- package/tests/wizard_physics_more.mjs +470 -0
|
@@ -215,6 +215,60 @@ h1[tabindex="-1"]:focus:not(:focus-visible){outline:none;}
|
|
|
215
215
|
.physCallout{color:var(--ink);text-transform:none;letter-spacing:0;font-family:var(--font-body);font-size:13px;}
|
|
216
216
|
.physCoords{color:var(--ink-faint);}
|
|
217
217
|
@media (max-width:840px){ .physRow2{grid-template-columns:1fr;} }
|
|
218
|
+
/* questions 5 to 7 and the summary (task 1004419, BV2.PS11). The rail strikes a question
|
|
219
|
+
the answers skip; the options are the wizard's hairline pills in one column, the suite a
|
|
220
|
+
two-column grid; the growth guess is a ledger of three months over a range. */
|
|
221
|
+
.physRail li.skipped,#view-new .steps li.skipped .slbl{text-decoration:line-through;text-decoration-color:var(--ink-faint);}
|
|
222
|
+
.typeCards.physOpts{grid-template-columns:1fr;}
|
|
223
|
+
.physOpts .tpill,.physSuiteGrid .tpill{align-items:flex-start;border-left:0;padding-left:0;border-top:1px solid var(--rule-soft);}
|
|
224
|
+
.physOpts .tpill:first-child{border-top:0;}
|
|
225
|
+
.physOpts .tpill::before,.physSuiteGrid .tpill::before{margin-top:6px;}
|
|
226
|
+
.physSuite{margin:4px 0 12px;padding:0;border:0;}
|
|
227
|
+
.physSuite legend{font-family:var(--label-face);font-size:var(--label-size);letter-spacing:var(--label-space);text-transform:uppercase;color:var(--ink-faint);margin:0 0 6px;padding:0;}
|
|
228
|
+
.typeCards.physSuiteGrid{grid-template-columns:repeat(2,minmax(0,1fr));gap:0 16px;}
|
|
229
|
+
.physSuiteGrid .tpill:nth-child(-n+2){border-top:0;}
|
|
230
|
+
.physWhyList{margin:0 0 14px;padding:0 0 0 18px;font-size:14px;line-height:1.5;color:var(--ink-soft);max-width:62ch;}
|
|
231
|
+
.physGuess{margin:12px 0 10px;padding:14px 0 0;border-top:1px solid var(--rule);max-width:62ch;}
|
|
232
|
+
.physGuessLine{font-size:15px;line-height:1.5;color:var(--ink);margin:0 0 12px;}
|
|
233
|
+
.physMonths{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));grid-template-rows:auto auto;grid-auto-flow:column;gap:2px 16px;margin:0 0 6px;padding-top:10px;border-top:1px solid var(--rule-soft);}
|
|
234
|
+
.physMonths dt{font-family:var(--label-face);font-size:var(--label-size);letter-spacing:var(--label-space);text-transform:uppercase;color:var(--ink-faint);}
|
|
235
|
+
.physMonths dd{margin:0;font-family:var(--font-display);font-weight:300;font-size:30px;line-height:1.1;color:var(--ink);font-variant-numeric:tabular-nums;}
|
|
236
|
+
.physAdjust input[type=range]{display:block;width:100%;min-height:24px;margin:6px 0 0;accent-color:var(--accent);background:none;}
|
|
237
|
+
.physLedger dd{display:flex;align-items:flex-start;gap:12px;}
|
|
238
|
+
.physLedger dd>span{flex:1;min-width:0;}
|
|
239
|
+
.physLedger .physLink{flex:none;}
|
|
240
|
+
@media (max-width:520px){ .typeCards.physSuiteGrid{grid-template-columns:1fr;} .physSuiteGrid .tpill:nth-child(2){border-top:1px solid var(--rule-soft);} }
|
|
241
|
+
/* the stage's new bodies: hairline rings, beads for moons, the platform's mark as the
|
|
242
|
+
sun the planet orbits — nearer the more the platform runs, absent for its own system */
|
|
243
|
+
.physBelt{position:absolute;left:50%;top:50%;border:1px solid var(--rule);border-radius:50%;transform:translate(-50%,-50%) rotate(-16deg);}
|
|
244
|
+
.physBelt[data-ring="1"]{width:76%;height:22%;}
|
|
245
|
+
.physBelt[data-ring="2"]{width:84%;height:25%;}
|
|
246
|
+
.physBelt[data-ring="3"]{width:92%;height:28%;border-color:var(--rule-soft);}
|
|
247
|
+
.physBelt[data-ring="4"]{width:98%;height:31%;border-color:var(--rule-soft);}
|
|
248
|
+
.physMoons,.physGhosts{position:absolute;border-radius:50%;}
|
|
249
|
+
.physMoons{inset:20%;}
|
|
250
|
+
.physGhosts{inset:9%;}
|
|
251
|
+
.physMoons img,.physGhosts img{position:absolute;width:12%;height:auto;transform:translate(-50%,-50%);}
|
|
252
|
+
.physGhosts img{width:8%;opacity:.45;}
|
|
253
|
+
/* the first places taken are the ones clear of the caption under the planet */
|
|
254
|
+
.physMoons img:nth-child(1),.physGhosts img:nth-child(1){left:50%;top:0;}
|
|
255
|
+
.physMoons img:nth-child(2),.physGhosts img:nth-child(2){left:0;top:50%;}
|
|
256
|
+
.physMoons img:nth-child(3),.physGhosts img:nth-child(3){left:100%;top:50%;}
|
|
257
|
+
.physMoons img:nth-child(4),.physGhosts img:nth-child(4){left:85.4%;top:14.6%;}
|
|
258
|
+
.physMoons img:nth-child(5){left:14.6%;top:14.6%;}
|
|
259
|
+
.physMoons img:nth-child(6){left:50%;top:100%;}
|
|
260
|
+
.physStage .physCap,.physStage .physFoot{z-index:2;}
|
|
261
|
+
.physStage .physCap,.physStage .physCallout,.physStage .physCoords{text-shadow:var(--type-halo);}
|
|
262
|
+
.physSun{position:absolute;width:15%;height:auto;left:var(--sun-x);top:var(--sun-y);transform:translate(-50%,-50%);}
|
|
263
|
+
.physTether{position:absolute;left:50%;top:50%;width:var(--sun-d);height:0;border-top:1px dashed var(--rule);transform-origin:0 0;transform:rotate(-45deg);}
|
|
264
|
+
#physStage[data-orbit="near"]{--sun-x:73%;--sun-y:27%;--sun-d:33%;}
|
|
265
|
+
#physStage[data-orbit="mid"]{--sun-x:80%;--sun-y:20%;--sun-d:42%;}
|
|
266
|
+
#physStage[data-orbit="far"]{--sun-x:87%;--sun-y:13%;--sun-d:52%;}
|
|
267
|
+
@media (prefers-reduced-motion:no-preference){
|
|
268
|
+
.physMoons{animation:physOrbit 160s linear infinite;}
|
|
269
|
+
.physGhosts{animation:physOrbit 260s linear infinite reverse;}
|
|
270
|
+
@keyframes physOrbit{to{transform:rotate(360deg);}}
|
|
271
|
+
}
|
|
218
272
|
/* under 520 the two doors cannot sit side by side at 48px, so they stack —
|
|
219
273
|
still two equal doors in one object */
|
|
220
274
|
@media (max-width:520px){
|
|
@@ -1486,8 +1540,8 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
1486
1540
|
Autofill, State, StateExisting, NotPossible, Geography, Ages, Entity and
|
|
1487
1541
|
EntityExisting frames, docs/design/project-startup-direction.md). ONE rail step
|
|
1488
1542
|
with its own inner sequence, so the wizard's numbering moved by one and the
|
|
1489
|
-
canvas's seven-question rail lives inside the panel (questions 5 to 7
|
|
1490
|
-
BV2.PS11). Left: the question, its choices and the doors. Right: the field plate
|
|
1543
|
+
canvas's seven-question rail lives inside the panel (questions 5 to 7 and the
|
|
1544
|
+
summary joined it in BV2.PS11, task 1004419). Left: the question, its choices and the doors. Right: the field plate
|
|
1491
1545
|
with the planet forming from the world's own plates as the answers come in.
|
|
1492
1546
|
Every answer rides the create request's `detail` (planet-physics.js); the stop
|
|
1493
1547
|
screen and the soft-limit table come from POST /provisioning/physics-check, the
|
|
@@ -1496,9 +1550,12 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
1496
1550
|
<section class="panel" id="panel-physics" aria-labelledby="phys-h0">
|
|
1497
1551
|
<div class="forkBody physBody">
|
|
1498
1552
|
<div>
|
|
1499
|
-
|
|
1553
|
+
<!-- the voice (spec D5, task 1004419): a formed organization reads the plain
|
|
1554
|
+
professional copy, everyone else the planet's. Both variants are baked;
|
|
1555
|
+
physPaintVoice() shows one. -->
|
|
1556
|
+
<p class="physCrumb"><span data-voice="planet">planet creation · part 1 of 2 · planet physics</span><span data-voice="pro" hidden>project setup · part 1 of 2 · project profile</span></p>
|
|
1500
1557
|
<ol class="physRail" id="physRail" aria-label="Planet physics questions">
|
|
1501
|
-
<li data-q="1">state</li><li data-q="2">geography</li><li data-q="3">ages</li><li data-q="4">entity</li><li>builders</li><li>rewards</li><li>framing</li>
|
|
1558
|
+
<li data-q="1">state</li><li data-q="2">geography</li><li data-q="3">ages</li><li data-q="4">entity</li><li data-q="5"><span data-voice="planet">builders</span><span data-voice="pro" hidden>team</span></li><li data-q="6">rewards</li><li data-q="7">framing</li>
|
|
1502
1559
|
</ol>
|
|
1503
1560
|
<form data-next="4" id="physForm">
|
|
1504
1561
|
<div class="physQ" data-q="0">
|
|
@@ -1598,6 +1655,85 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
1598
1655
|
</div>
|
|
1599
1656
|
</div>
|
|
1600
1657
|
|
|
1658
|
+
<!-- questions 5 to 7 and the summary (task 1004419, BV2.PS11; the canvas's
|
|
1659
|
+
Builders, BuildersPro, Rewards, Framing and Physics frames). Further
|
|
1660
|
+
screens of this same step, so the wizard is not renumbered. -->
|
|
1661
|
+
<div class="physQ" data-q="5" hidden>
|
|
1662
|
+
<h1 id="phys-h5"><span data-voice="planet">Who will live <em>on your planet?</em></span><span data-voice="pro" hidden>How many people <em>will work on this?</em></span></h1>
|
|
1663
|
+
<p class="lede"><span data-voice="planet">One builder, or many? This can always change.</span><span data-voice="pro" hidden>One person or a team. You can change this at any time.</span></p>
|
|
1664
|
+
<div class="typeCards physCells" role="group" aria-label="One or many">
|
|
1665
|
+
<button type="button" class="tpill" data-phys-solo="one" aria-pressed="false"><span><span data-voice="planet">One</span><span data-voice="pro" hidden>One person</span> <small><span data-voice="planet">Just me, building solo.</span><span data-voice="pro" hidden>A single contributor.</span></small></span></button>
|
|
1666
|
+
<button type="button" class="tpill" data-phys-solo="many" aria-pressed="false"><span><span data-voice="planet">Many</span><span data-voice="pro" hidden>A team</span> <small><span data-voice="planet">A team, now or soon.</span><span data-voice="pro" hidden>Several contributors, now or soon.</span></small></span></button>
|
|
1667
|
+
</div>
|
|
1668
|
+
<div id="physTeam" hidden>
|
|
1669
|
+
<div class="wizField"><span id="physStartLbl"><span data-voice="planet">Builders at the start, you included</span><span data-voice="pro" hidden>Contributors at the start</span></span>
|
|
1670
|
+
<div class="demoStep" role="group" aria-labelledby="physStartLbl">
|
|
1671
|
+
<button type="button" class="btn small ghost" data-phys-count="-1" aria-label="One fewer">−</button>
|
|
1672
|
+
<output id="physStartN" aria-live="polite">2</output>
|
|
1673
|
+
<button type="button" class="btn small ghost" data-phys-count="1" aria-label="One more">+</button>
|
|
1674
|
+
</div>
|
|
1675
|
+
</div>
|
|
1676
|
+
<div class="physGuess">
|
|
1677
|
+
<p class="physNoteH"><span data-voice="planet">A growth guess</span><span data-voice="pro" hidden>Our estimate</span></p>
|
|
1678
|
+
<p class="physGuessLine" id="physGuessLine" aria-live="polite"></p>
|
|
1679
|
+
<dl class="physMonths">
|
|
1680
|
+
<dt>Month 1</dt><dd id="physM1">2</dd>
|
|
1681
|
+
<dt>Month 2</dt><dd id="physM2">4</dd>
|
|
1682
|
+
<dt>Month 3</dt><dd id="physM3">5</dd>
|
|
1683
|
+
</dl>
|
|
1684
|
+
<label class="wizField physAdjust"><span>Adjust month three</span>
|
|
1685
|
+
<input type="range" id="physExpected" min="2" max="30" step="1" value="5">
|
|
1686
|
+
</label>
|
|
1687
|
+
</div>
|
|
1688
|
+
</div>
|
|
1689
|
+
</div>
|
|
1690
|
+
|
|
1691
|
+
<div class="physQ" data-q="6" hidden>
|
|
1692
|
+
<h1 id="phys-h6"><span data-voice="planet">How will builders <em>be rewarded?</em></span><span data-voice="pro" hidden>How will contributors <em>be rewarded?</em></span></h1>
|
|
1693
|
+
<p class="lede"><span data-voice="planet">Pick everything you’re considering. This is intent only: you’ll design the binding rewards later, once your entity is settled.</span><span data-voice="pro" hidden>Select every option you are considering. Nothing here is binding: the reward terms are set later, once the entity is settled.</span></p>
|
|
1694
|
+
<div class="typeCards physCells physOpts" role="group" aria-label="Rewards being considered">
|
|
1695
|
+
<button type="button" class="tpill" data-phys="reward_intents" data-val="non-monetary" aria-pressed="false"><span>Non-monetary <small>Entertainment, learning, experience, volunteering.</small></span></button>
|
|
1696
|
+
<button type="button" class="tpill" data-phys="reward_intents" data-val="cash" aria-pressed="false"><span>Cash for work <small>Paid in money for the work done.</small></span></button>
|
|
1697
|
+
<button type="button" class="tpill" data-phys="reward_intents" data-val="equity" aria-pressed="false"><span>Equity or shares <small>A stake in the entity.</small></span></button>
|
|
1698
|
+
<button type="button" class="tpill" data-phys="reward_intents" data-val="future-payouts" aria-pressed="false"><span>Future profits or payouts <small>Paid later, tied to conditions you set.</small></span></button>
|
|
1699
|
+
</div>
|
|
1700
|
+
<ul class="physWhyList" data-why-list="reward_intents" hidden></ul>
|
|
1701
|
+
</div>
|
|
1702
|
+
|
|
1703
|
+
<div class="physQ" data-q="7" hidden>
|
|
1704
|
+
<h1 id="phys-h7">How much should <em><span data-brand-product-inline>Cloud Bongos</span> run for you?</em></h1>
|
|
1705
|
+
<p class="lede">Not binding. It just speeds up your setup.</p>
|
|
1706
|
+
<div class="typeCards physCells physOpts" role="group" aria-label="How much is run for you">
|
|
1707
|
+
<button type="button" class="tpill" data-phys="framing" data-val="managed" aria-pressed="false"><span>A · All managed <small>The full suite, run for you.</small></span></button>
|
|
1708
|
+
<button type="button" class="tpill" data-phys="framing" data-val="hybrid" aria-pressed="false"><span>B · Hybrid <small>Choose what you want from the full suite.</small></span></button>
|
|
1709
|
+
<button type="button" class="tpill" data-phys="framing" data-val="local" aria-pressed="false"><span>C · Local or internal <small>Choose from the suite, and keep your data on your own machines.</small></span></button>
|
|
1710
|
+
<button type="button" class="tpill" data-phys="framing" data-val="open-source" aria-pressed="false"><span>D · Open source, local <small>Just the free core. Build on your own machines and pay only for what you add.</small></span></button>
|
|
1711
|
+
</div>
|
|
1712
|
+
<p class="physWhy" data-why="services" hidden></p>
|
|
1713
|
+
<fieldset class="physSuite" id="physSuite" hidden>
|
|
1714
|
+
<legend id="physSuiteLbl">Your hybrid suite</legend>
|
|
1715
|
+
<div class="typeCards physCells physSuiteGrid">
|
|
1716
|
+
<button type="button" class="tpill" data-phys="services" data-val="hosting" aria-pressed="false">Hosting</button>
|
|
1717
|
+
<button type="button" class="tpill" data-phys="services" data-val="labor-payment" aria-pressed="false">Labor payment and HR</button>
|
|
1718
|
+
<button type="button" class="tpill" data-phys="services" data-val="starter-kit" aria-pressed="false">Starting module kit</button>
|
|
1719
|
+
<button type="button" class="tpill" data-phys="services" data-val="marketplace-buy" aria-pressed="false">Module marketplace: buy</button>
|
|
1720
|
+
<button type="button" class="tpill" data-phys="services" data-val="marketplace-sell" aria-pressed="false">Module marketplace: sell</button>
|
|
1721
|
+
<button type="button" class="tpill" data-phys="services" data-val="guild-access" aria-pressed="false">Builder guild access</button>
|
|
1722
|
+
<button type="button" class="tpill" data-phys="services" data-val="guild-create" aria-pressed="false">Create a builder guild</button>
|
|
1723
|
+
<button type="button" class="tpill" data-phys="services" data-val="company-creation" aria-pressed="false">Company creation</button>
|
|
1724
|
+
<button type="button" class="tpill" data-phys="services" data-val="cbaas-consulting" aria-pressed="false">Expert consulting</button>
|
|
1725
|
+
<button type="button" class="tpill" data-phys="services" data-val="public-marketing" aria-pressed="false">Public marketed project</button>
|
|
1726
|
+
</div>
|
|
1727
|
+
<ul class="physWhyList" data-why-list="services" hidden></ul>
|
|
1728
|
+
</fieldset>
|
|
1729
|
+
</div>
|
|
1730
|
+
|
|
1731
|
+
<div class="physQ" data-q="sum" hidden>
|
|
1732
|
+
<h1 id="phys-hsum"><span data-voice="planet">Your planet’s <em>physics</em></span><span data-voice="pro" hidden>Your project’s <em>profile</em></span></h1>
|
|
1733
|
+
<p class="lede"><span data-voice="planet">This is what shapes your planet. Change any answer before it’s born.</span><span data-voice="pro" hidden>This is what shapes your project. Change any answer before it is created.</span></p>
|
|
1734
|
+
<dl class="demoLedger physLedger" id="physSummary"></dl>
|
|
1735
|
+
</div>
|
|
1736
|
+
|
|
1601
1737
|
<div class="physQ" data-q="stop" hidden>
|
|
1602
1738
|
<h1 id="phys-hstop">This can’t be built <em>on <span data-brand-product-inline>Cloud Bongos</span></em></h1>
|
|
1603
1739
|
<p class="lede" id="physStopMsg"></p>
|
|
@@ -1617,8 +1753,16 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
1617
1753
|
<div class="forkStage physStage" id="physStage" aria-hidden="true">
|
|
1618
1754
|
<span class="forkOrbit"></span>
|
|
1619
1755
|
<span class="forkOrbit forkOrbitDash"></span>
|
|
1756
|
+
<!-- task 1004419: rings for the rewards being considered, moons for the
|
|
1757
|
+
builders (the faint ones on the dashed orbit are the expected growth), and
|
|
1758
|
+
the planet's orbit around the platform's mark, set by the framing -->
|
|
1759
|
+
<span class="physBelt" data-ring="1" hidden></span><span class="physBelt" data-ring="2" hidden></span><span class="physBelt" data-ring="3" hidden></span><span class="physBelt" data-ring="4" hidden></span>
|
|
1760
|
+
<span class="physGhosts" id="physGhosts" hidden><img src="/assets/world/r3-frost-bead-cut.webp" alt=""><img src="/assets/world/r3-frost-bead-cut.webp" alt=""><img src="/assets/world/r3-frost-bead-cut.webp" alt=""><img src="/assets/world/r3-frost-bead-cut.webp" alt=""></span>
|
|
1761
|
+
<span class="physMoons" id="physMoons" hidden><img src="/assets/world/r3-frost-bead-cut.webp" alt=""><img src="/assets/world/r3-frost-bead-cut.webp" alt=""><img src="/assets/world/r3-frost-bead-cut.webp" alt=""><img src="/assets/world/r3-frost-bead-cut.webp" alt=""><img src="/assets/world/r3-frost-bead-cut.webp" alt=""><img src="/assets/world/r3-frost-bead-cut.webp" alt=""></span>
|
|
1762
|
+
<span class="physTether" id="physTether" hidden></span>
|
|
1620
1763
|
<span class="physGuard" id="physGuard" hidden></span>
|
|
1621
1764
|
<img class="forkSeed physPlanet" id="physPlanet" src="/assets/world/r2-chrome-blob-one-cut.webp" alt="">
|
|
1765
|
+
<img class="physSun" id="physSun" src="/assets/world/r2-bongos-chrome-a-cut.webp" alt="" hidden>
|
|
1622
1766
|
<p class="physCap"><span id="physCapLbl">planet physics</span> · <span id="physCapN">0 of 7</span></p>
|
|
1623
1767
|
<div class="physFoot"><p class="physCallout" id="physCallout">physics · the rules it lives by · each answer shapes your planet here</p>
|
|
1624
1768
|
<p class="physCoords" id="physCoords"></p></div>
|
|
@@ -1667,6 +1811,8 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
1667
1811
|
<b id="typeCardName"></b>
|
|
1668
1812
|
<p id="typeCardDesc"></p>
|
|
1669
1813
|
</div>
|
|
1814
|
+
<!-- pre-filled from the planet-physics answers (task 1004419), and says so -->
|
|
1815
|
+
<p class="physWhy" id="typePrefill" hidden></p>
|
|
1670
1816
|
<div class="hint" id="h-projtype"> </div>
|
|
1671
1817
|
<div class="nav">
|
|
1672
1818
|
<button type="button" class="btn ghost" data-back="4">← Back</button>
|
|
@@ -1767,6 +1913,8 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
1767
1913
|
<p>Layer <span data-brand-product-inline>Cloud Bongos</span> onto an existing repository — history, code, and backlog intact. Public or private, we never change it.</p>
|
|
1768
1914
|
</button>
|
|
1769
1915
|
</div>
|
|
1916
|
+
<!-- pre-filled from the planet-physics answers (task 1004419), and says so -->
|
|
1917
|
+
<p class="physWhy" id="homePrefill" hidden></p>
|
|
1770
1918
|
<div class="reassure" id="adoptNote">Adopting never overwrites your files: you get a conflict pre-flight first, nothing is written until you accept, and your existing backlog (issues, TODOs) is imported as real tasks.</div>
|
|
1771
1919
|
|
|
1772
1920
|
<!-- GitHub-integrated repo picker (adopt) + auto-create (fresh) — task 1002099.
|
|
@@ -4850,6 +4998,8 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
4850
4998
|
var now = !landed && n === cur;
|
|
4851
4999
|
li.classList.toggle('now', now);
|
|
4852
5000
|
li.classList.toggle('done', landed || n < cur);
|
|
5001
|
+
/* a step the planet-physics answers skip (task 1004419); still reachable */
|
|
5002
|
+
li.classList.toggle('skipped', step < 13 && physStepSkipped(n));
|
|
4853
5003
|
if (now) li.setAttribute('aria-current', 'step'); else li.removeAttribute('aria-current');
|
|
4854
5004
|
/* a step already answered is a way BACK (task 1003246): only those take
|
|
4855
5005
|
the button role, the tab stop and the data-goto the delegated handler
|
|
@@ -4891,6 +5041,7 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
4891
5041
|
/* the picker repaints on entry, not once at boot: the owner can walk back
|
|
4892
5042
|
to the Type step and change the answer the preselect is keyed to */
|
|
4893
5043
|
if (step === 3) paintPhysics();
|
|
5044
|
+
if (step === 5 || step === 8) physPaintPrefillNotes();
|
|
4894
5045
|
if (step === 7) renderModules();
|
|
4895
5046
|
if (step === 8) { syncHome(); if (authKnown) ensureRepoAccess(); }
|
|
4896
5047
|
/* a resumed draft can land PAST the Home step with the probe never run —
|
|
@@ -5069,6 +5220,7 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
5069
5220
|
$('adoptNote').classList.toggle('on', mode === 'adopt');
|
|
5070
5221
|
saveDraft();
|
|
5071
5222
|
syncHome();
|
|
5223
|
+
physPaintPrefillNotes();
|
|
5072
5224
|
}
|
|
5073
5225
|
$('c-green').addEventListener('click', function () { setMode('greenfield'); });
|
|
5074
5226
|
$('c-adopt').addEventListener('click', function () { setMode('adopt'); });
|
|
@@ -5096,6 +5248,7 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
5096
5248
|
state.projType = b.getAttribute('data-type');
|
|
5097
5249
|
$('h-projtype').innerHTML = ' '; $('h-projtype').className = 'hint';
|
|
5098
5250
|
paintType(state.projType);
|
|
5251
|
+
physPaintPrefillNotes();
|
|
5099
5252
|
saveDraft();
|
|
5100
5253
|
});
|
|
5101
5254
|
});
|
|
@@ -5605,12 +5758,13 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
5605
5758
|
saveDraft();
|
|
5606
5759
|
});
|
|
5607
5760
|
|
|
5608
|
-
/* ── planet physics, questions 1 to
|
|
5761
|
+
/* ── planet physics, questions 1 to 7 (tasks 1004418 and 1004419, BV2.PS07 + PS11) ──
|
|
5609
5762
|
One wizard step with its own inner sequence: 0 account-or-scratch, 1 state,
|
|
5610
|
-
2 geography, 3 ages, 4 entity,
|
|
5611
|
-
|
|
5612
|
-
them as `detail` untouched.
|
|
5613
|
-
(a page cannot require a
|
|
5763
|
+
2 geography, 3 ages, 4 entity, 5 builders, 6 rewards, 7 framing, the summary
|
|
5764
|
+
('sum') and the stop screen. The answers live in state.physics.answers under
|
|
5765
|
+
planet-physics.js's own keys, so the create sends them as `detail` untouched.
|
|
5766
|
+
The vocabularies below are COPIES of that file's (a page cannot require a
|
|
5767
|
+
module), held equal by tests/wizard_physics.mjs and wizard_physics_more.mjs. */
|
|
5614
5768
|
var PHYS_COUNTRIES = ('AD AE AF AG AI AL AM AO AQ AR AS AT AU AW AX AZ BA BB BD BE BF BG BH BI BJ BL BM BN BO BQ ' +
|
|
5615
5769
|
'BR BS BT BV BW BY BZ CA CC CD CF CG CH CI CK CL CM CN CO CR CU CV CW CX CY CZ DE DJ DK DM ' +
|
|
5616
5770
|
'DO DZ EC EE EG EH ER ES ET FI FJ FK FM FO FR GA GB GD GE GF GG GH GI GL GM GN GP GQ GR GS ' +
|
|
@@ -5649,7 +5803,43 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
5649
5803
|
};
|
|
5650
5804
|
var PHYS_CORE_WORD = { frost: 'individual', chrome: 'group', gold: 'organization', obsidian: 'nonprofit' };
|
|
5651
5805
|
var PHYS_GEO_WORD = { 'us-only': 'us only', 'us-eu': 'us + eu', 'global': 'global', 'not-sure': 'not sure yet' };
|
|
5652
|
-
|
|
5806
|
+
/* Questions 5 to 7 (task 1004419). The voice (spec D5): a formed organization
|
|
5807
|
+
reads the plain professional copy; individuals, groups and every "not yet" read
|
|
5808
|
+
the planet's. The lists are planet-physics.js's, in its order. */
|
|
5809
|
+
var PHYS_ORGS = ['nonprofit', 'for-profit', 'corporate-division', 'research'];
|
|
5810
|
+
var PHYS_REWARDS = ['non-monetary', 'cash', 'equity', 'future-payouts'];
|
|
5811
|
+
var PHYS_FRAMINGS = ['managed', 'hybrid', 'local', 'open-source'];
|
|
5812
|
+
var PHYS_SERVICES = ['hosting', 'labor-payment', 'starter-kit', 'marketplace-buy', 'marketplace-sell', 'guild-access', 'guild-create', 'company-creation', 'cbaas-consulting', 'public-marketing'];
|
|
5813
|
+
var PHYS_MANY = ['reward_intents', 'services'];
|
|
5814
|
+
/* the suite a hybrid or local framing starts from (the canvas's Framing frame) */
|
|
5815
|
+
var PHYS_SUITE_START = { hybrid: ['hosting', 'starter-kit', 'marketplace-buy', 'guild-access'], local: ['starter-kit', 'marketplace-buy', 'guild-access'] };
|
|
5816
|
+
/* the framing is the planet's orbit around the platform: all managed is close,
|
|
5817
|
+
hybrid the middle, local far, and open source a system of its own */
|
|
5818
|
+
var PHYS_ORBIT = { managed: 'near', hybrid: 'mid', local: 'far', 'open-source': 'own' };
|
|
5819
|
+
var PHYS_ORBIT_WORD = { managed: 'a close orbit around the platform', hybrid: 'a middle orbit around the platform', local: 'a far orbit around the platform', 'open-source': 'a system of its own' };
|
|
5820
|
+
/* what the summary says for each answer */
|
|
5821
|
+
var PHYS_SAY = {
|
|
5822
|
+
project_state: { 'new': 'New', existing: 'Existing' },
|
|
5823
|
+
builder_geography: { 'us-only': 'Builders in the US only', 'us-eu': 'Builders in the US and EU', global: 'Builders anywhere', 'not-sure': 'Not sure yet where builders will be' },
|
|
5824
|
+
entity: {
|
|
5825
|
+
'intent-company': 'Probably a company', 'intent-nonprofit': 'Probably a nonprofit', 'intent-solo': 'Just me for now', 'intent-unsure': 'Don’t know yet',
|
|
5826
|
+
nonprofit: 'Nonprofit', 'for-profit': 'For-profit company', 'corporate-division': 'Division of a corporation', research: 'Research entity',
|
|
5827
|
+
'university-project': 'University project', 'social-group': 'Social group', 'single-owner-llc': 'Single-owner LLC', 'private-individual': 'Private individual'
|
|
5828
|
+
},
|
|
5829
|
+
reward_intents: { 'non-monetary': 'Non-monetary', cash: 'Cash for work', equity: 'Equity or shares', 'future-payouts': 'Future profits or payouts' },
|
|
5830
|
+
framing: { managed: 'All managed', hybrid: 'Hybrid', local: 'Local or internal', 'open-source': 'Open source, local' },
|
|
5831
|
+
services: {
|
|
5832
|
+
hosting: 'Hosting', 'labor-payment': 'Labor payment and HR', 'starter-kit': 'Starting module kit', 'marketplace-buy': 'Module marketplace: buy',
|
|
5833
|
+
'marketplace-sell': 'Module marketplace: sell', 'guild-access': 'Builder guild access', 'guild-create': 'Create a builder guild',
|
|
5834
|
+
'company-creation': 'Company creation', 'cbaas-consulting': 'Expert consulting', 'public-marketing': 'Public marketed project'
|
|
5835
|
+
}
|
|
5836
|
+
};
|
|
5837
|
+
/* the project type the entity suggests for the Type step (a pre-fill the founder sees and can change) */
|
|
5838
|
+
var PHYS_TYPE = {
|
|
5839
|
+
'intent-company': 'business', 'for-profit': 'business', 'corporate-division': 'business', 'single-owner-llc': 'business',
|
|
5840
|
+
'intent-nonprofit': 'non-profit', nonprofit: 'non-profit', research: 'research', 'university-project': 'research'
|
|
5841
|
+
};
|
|
5842
|
+
var PHYS_LAST = 7;
|
|
5653
5843
|
var physLimits = [];
|
|
5654
5844
|
|
|
5655
5845
|
function phys() {
|
|
@@ -5661,15 +5851,122 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
5661
5851
|
work only for an existing planet (the soft-limit table hides it for a new one). */
|
|
5662
5852
|
function physDetail() {
|
|
5663
5853
|
var a = phys().answers, out = {};
|
|
5664
|
-
['project_state', 'home_country', 'home_region', 'builder_geography', 'minors_on_board', 'entity'
|
|
5854
|
+
['project_state', 'home_country', 'home_region', 'builder_geography', 'minors_on_board', 'entity',
|
|
5855
|
+
'builders_at_start', 'builders_expected', 'framing'].forEach(function (k) {
|
|
5665
5856
|
if (a[k] !== undefined && a[k] !== null && a[k] !== '') out[k] = a[k];
|
|
5666
5857
|
});
|
|
5667
5858
|
if (a.project_state === 'existing' && Array.isArray(a.existing_work) && a.existing_work.length) {
|
|
5668
5859
|
out.existing_work = a.existing_work.slice();
|
|
5669
5860
|
if (a.main_work && a.existing_work.indexOf(a.main_work) !== -1) out.main_work = a.main_work;
|
|
5670
5861
|
}
|
|
5862
|
+
/* the rewards only when the question was asked (never for a founder building
|
|
5863
|
+
alone), the suite only for the two framings that choose from it — each in
|
|
5864
|
+
the vocabulary's own order */
|
|
5865
|
+
if (Array.isArray(a.reward_intents) && !physSolo() && !physHidden('reward_intents')) {
|
|
5866
|
+
out.reward_intents = PHYS_REWARDS.filter(function (r) { return a.reward_intents.indexOf(r) !== -1; });
|
|
5867
|
+
}
|
|
5868
|
+
if ((a.framing === 'hybrid' || a.framing === 'local') && Array.isArray(a.services)) {
|
|
5869
|
+
out.services = PHYS_SERVICES.filter(function (s) { return a.services.indexOf(s) !== -1; });
|
|
5870
|
+
}
|
|
5871
|
+
/* the voice follows the entity (spec D5), stored so settings can switch it later */
|
|
5872
|
+
if (a.entity) out.voice = physVoice();
|
|
5671
5873
|
return out;
|
|
5672
5874
|
}
|
|
5875
|
+
function physVoice() { return PHYS_ORGS.indexOf(phys().answers.entity) !== -1 ? 'professional' : 'planet'; }
|
|
5876
|
+
function physSolo() { var a = phys().answers; return a.builders_at_start === 1 && a.builders_expected === 1; }
|
|
5877
|
+
function physHidden(option) { return physLimits.some(function (l) { return l && l.option === option && l.effect === 'hide'; }); }
|
|
5878
|
+
/* a question the answers skip: rewards, when the table hides them (building alone) */
|
|
5879
|
+
function physSkips(q) { return q === 6 && physHidden('reward_intents'); }
|
|
5880
|
+
/* the month-three guess the founder corrects: roughly 2.6 times the start */
|
|
5881
|
+
function physGuess(start) { return Math.min(100000, Math.max(start + 1, Math.round(start * 2.6))); }
|
|
5882
|
+
function physAnswered(q) {
|
|
5883
|
+
var a = phys().answers;
|
|
5884
|
+
if (q === 1) return !!a.project_state && (a.project_state !== 'existing' || (Array.isArray(a.existing_work) && a.existing_work.indexOf(a.main_work) !== -1));
|
|
5885
|
+
if (q === 2) return !!a.home_country && !!a.builder_geography;
|
|
5886
|
+
if (q === 3) return a.minors_on_board === true || a.minors_on_board === false;
|
|
5887
|
+
if (q === 4) return !!a.entity;
|
|
5888
|
+
if (q === 5) return Number.isInteger(a.builders_at_start) && Number.isInteger(a.builders_expected) && a.builders_expected >= a.builders_at_start;
|
|
5889
|
+
if (q === 6) return Array.isArray(a.reward_intents) && a.reward_intents.length > 0;
|
|
5890
|
+
if (q === 7) return !!a.framing;
|
|
5891
|
+
return false;
|
|
5892
|
+
}
|
|
5893
|
+
/* Where Continue goes from question q: the next one that applies — or, once the
|
|
5894
|
+
founder came here from the summary's "change", straight back to the summary
|
|
5895
|
+
unless a later question still needs an answer. */
|
|
5896
|
+
function physNextQ(q) {
|
|
5897
|
+
var p = phys();
|
|
5898
|
+
for (var n = q + 1; n <= PHYS_LAST; n++) {
|
|
5899
|
+
if (physSkips(n)) continue;
|
|
5900
|
+
if (!p.fromSum || !physAnswered(n)) return n;
|
|
5901
|
+
}
|
|
5902
|
+
return 'sum';
|
|
5903
|
+
}
|
|
5904
|
+
function physPrevQ(q) {
|
|
5905
|
+
var from = q === 'sum' ? PHYS_LAST + 1 : q;
|
|
5906
|
+
for (var n = from - 1; n >= 1; n--) if (!physSkips(n)) return n;
|
|
5907
|
+
return 0;
|
|
5908
|
+
}
|
|
5909
|
+
|
|
5910
|
+
/* ── the technical steps, pre-filled from the answers (task 1004419) ──
|
|
5911
|
+
What the answers suggest, applied only where the founder has not chosen for
|
|
5912
|
+
themselves (the field still holds its default, or what we filled last time), so
|
|
5913
|
+
walking back to change an answer moves the suggestion and never their choice. */
|
|
5914
|
+
var PHYS_PREFILL_DEFAULT = { projType: null, teamShape: null, mode: 'greenfield' };
|
|
5915
|
+
function physPrefillFor() {
|
|
5916
|
+
var a = phys().answers, out = {};
|
|
5917
|
+
if (PHYS_TYPE[a.entity]) out.projType = PHYS_TYPE[a.entity];
|
|
5918
|
+
if (physSolo()) out.teamShape = 'solo';
|
|
5919
|
+
if (a.project_state) out.mode = a.project_state === 'existing' && Array.isArray(a.existing_work) && a.existing_work.indexOf('code') !== -1 ? 'adopt' : 'greenfield';
|
|
5920
|
+
return out;
|
|
5921
|
+
}
|
|
5922
|
+
function physPrefill() {
|
|
5923
|
+
var want = physPrefillFor(), was = state.prefilled || {}, now = {};
|
|
5924
|
+
Object.keys(PHYS_PREFILL_DEFAULT).forEach(function (k) {
|
|
5925
|
+
var cur = state[k] === undefined ? PHYS_PREFILL_DEFAULT[k] : state[k];
|
|
5926
|
+
var untouched = cur === PHYS_PREFILL_DEFAULT[k] || (was[k] !== undefined && cur === was[k]);
|
|
5927
|
+
if (!untouched) return;
|
|
5928
|
+
if (want[k] !== undefined) { state[k] = want[k]; now[k] = want[k]; } else state[k] = PHYS_PREFILL_DEFAULT[k];
|
|
5929
|
+
});
|
|
5930
|
+
state.prefilled = now;
|
|
5931
|
+
/* a step the answers skip keeps its default answer */
|
|
5932
|
+
if (physStepSkipped(10)) state.appPlatform = 'later';
|
|
5933
|
+
if (typeof setMode === 'function') setMode(state.mode);
|
|
5934
|
+
if (typeof paintType === 'function') paintType(state.projType || null);
|
|
5935
|
+
if (typeof paintTeam === 'function') paintTeam(state.teamShape || null);
|
|
5936
|
+
saveDraft();
|
|
5937
|
+
return now;
|
|
5938
|
+
}
|
|
5939
|
+
/* The technical steps that do not apply to these answers: a planet built on its
|
|
5940
|
+
own machines (framing local, or open source) has no app platform to pick. A demo
|
|
5941
|
+
is all managed, whatever an abandoned walk through the questions left behind. */
|
|
5942
|
+
function physStepSkipped(n) {
|
|
5943
|
+
if (state.demo) return false;
|
|
5944
|
+
var a = (state.physics && state.physics.answers) || {};
|
|
5945
|
+
return n === 10 && (a.framing === 'local' || a.framing === 'open-source');
|
|
5946
|
+
}
|
|
5947
|
+
/* the wizard's Next and Back step over a skipped step; the rail still reaches it */
|
|
5948
|
+
function physPastSkips(n, dir) {
|
|
5949
|
+
while (n > 0 && n < 13 && physStepSkipped(n)) n += dir;
|
|
5950
|
+
return n;
|
|
5951
|
+
}
|
|
5952
|
+
/* the line on the Type and Home steps saying the answer came from the questions */
|
|
5953
|
+
function physPaintPrefillNotes() {
|
|
5954
|
+
if (!PHYS_SAY) return; /* setMode runs once at boot, above where these are set */
|
|
5955
|
+
var pf = state.prefilled || {}, a = (state.physics && state.physics.answers) || {};
|
|
5956
|
+
var whose = PHYS_ORGS.indexOf(a.entity) !== -1 ? 'your project' : 'your planet';
|
|
5957
|
+
var t = $('typePrefill');
|
|
5958
|
+
var tOn = !!pf.projType && state.projType === pf.projType && !!PHYS_SAY.entity[a.entity];
|
|
5959
|
+
t.hidden = !tOn;
|
|
5960
|
+
t.textContent = tOn ? 'Picked from your answer “' + PHYS_SAY.entity[a.entity] + '”. Change it if another fits better.' : '';
|
|
5961
|
+
var h = $('homePrefill');
|
|
5962
|
+
var hOn = !!pf.mode && state.mode === pf.mode;
|
|
5963
|
+
h.hidden = !hOn;
|
|
5964
|
+
h.textContent = !hOn ? '' : pf.mode === 'adopt'
|
|
5965
|
+
? 'Adopt is picked because ' + whose + ' already has code. Choose Start fresh if it should begin again.'
|
|
5966
|
+
: a.project_state === 'existing'
|
|
5967
|
+
? 'Start fresh is picked because what ' + whose + ' has so far is not code.'
|
|
5968
|
+
: 'Start fresh is picked because ' + whose + ' is new.';
|
|
5969
|
+
}
|
|
5673
5970
|
function createDetail() {
|
|
5674
5971
|
var d = physDetail();
|
|
5675
5972
|
if (state.teamShape) d.team_shape = state.teamShape;
|
|
@@ -5706,13 +6003,48 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
5706
6003
|
: '/assets/world/r2-chrome-blob-one-cut.webp';
|
|
5707
6004
|
var img = $('physPlanet');
|
|
5708
6005
|
if (img.getAttribute('src') !== src) img.setAttribute('src', src);
|
|
5709
|
-
|
|
6006
|
+
var size = p.q === 'stop' ? 0 : p.q === 'sum' ? 6
|
|
6007
|
+
: Math.min(6, Math.max(1, Math.min(typeof p.q === 'number' ? p.q : 0, PHYS_LAST) + (a.project_state === 'existing' ? 2 : 1)));
|
|
6008
|
+
img.setAttribute('data-size', String(size));
|
|
5710
6009
|
img.hidden = p.q === 'stop';
|
|
5711
|
-
$('physGuard').hidden = a.minors_on_board !== true;
|
|
6010
|
+
$('physGuard').hidden = a.minors_on_board !== true || p.q === 'stop';
|
|
5712
6011
|
$('physStage').classList.toggle('physStopped', p.q === 'stop');
|
|
5713
|
-
|
|
5714
|
-
|
|
6012
|
+
var pro = physVoice() === 'professional';
|
|
6013
|
+
$('physCapLbl').textContent = pro ? 'project profile' : 'planet physics';
|
|
6014
|
+
$('physCapN').textContent = p.q === 'stop' ? 'stopped' : p.q === 'sum' ? 'complete' : (typeof p.q === 'number' ? p.q : 0) + ' of 7';
|
|
6015
|
+
/* task 1004419: moons for the builders now (beads of the core's material), faint
|
|
6016
|
+
ones on the dashed orbit for the expected growth, a ring per reward being
|
|
6017
|
+
considered, and the orbit around the platform's mark the framing sets */
|
|
6018
|
+
var live = p.q !== 'stop';
|
|
6019
|
+
var at = live && Number.isInteger(a.builders_at_start) ? a.builders_at_start : 0;
|
|
6020
|
+
var exp = live && Number.isInteger(a.builders_expected) ? a.builders_expected : 0;
|
|
6021
|
+
var bead = '/assets/world/r3-' + (mat && mat !== 'chrome' ? mat : 'frost') + '-bead-cut.webp';
|
|
6022
|
+
var nMoons = Math.min(at, 6), nGhosts = Math.min(Math.max(exp - at, 0), 4);
|
|
6023
|
+
root.querySelectorAll('#physMoons img, #physGhosts img').forEach(function (m) { if (m.getAttribute('src') !== bead) m.setAttribute('src', bead); });
|
|
6024
|
+
root.querySelectorAll('#physMoons img').forEach(function (m, i) { m.hidden = i >= nMoons; });
|
|
6025
|
+
root.querySelectorAll('#physGhosts img').forEach(function (m, i) { m.hidden = i >= nGhosts; });
|
|
6026
|
+
$('physMoons').hidden = nMoons === 0;
|
|
6027
|
+
$('physGhosts').hidden = nGhosts === 0;
|
|
6028
|
+
var rewards = live && Array.isArray(a.reward_intents) && !physSolo() && !physHidden('reward_intents') ? a.reward_intents : [];
|
|
6029
|
+
root.querySelectorAll('#physStage .physBelt').forEach(function (b, i) { b.hidden = i >= rewards.length; });
|
|
6030
|
+
var orbit = live && a.framing ? PHYS_ORBIT[a.framing] : 'none';
|
|
6031
|
+
$('physStage').setAttribute('data-orbit', orbit);
|
|
6032
|
+
$('physSun').hidden = orbit === 'none' || orbit === 'own';
|
|
6033
|
+
$('physTether').hidden = orbit === 'none' || orbit === 'own';
|
|
6034
|
+
var rewardWords = rewards.map(function (r) { return PHYS_SAY.reward_intents[r].toLowerCase(); }).join(', ');
|
|
6035
|
+
var call = pro ? 'profile · each answer shapes your project here' : 'physics · the rules it lives by · each answer shapes your planet here';
|
|
5715
6036
|
if (p.q === 'stop') call = 'no planet forms · stopped at state · nothing was created';
|
|
6037
|
+
else if (p.q === 'sum') call = pro ? 'profile · seven answers · ready for setup' : 'physics · seven answers, one planet · ready for its coordinates';
|
|
6038
|
+
else if (p.q === 7 && a.framing) call = pro
|
|
6039
|
+
? 'framing · ' + PHYS_SAY.framing[a.framing].toLowerCase()
|
|
6040
|
+
: 'orbit · ' + PHYS_SAY.framing[a.framing].toLowerCase() + ' · ' + PHYS_ORBIT_WORD[a.framing];
|
|
6041
|
+
else if (p.q === 6 && rewards.length) call = pro
|
|
6042
|
+
? 'rewards · ' + rewards.length + ' being considered · ' + rewardWords
|
|
6043
|
+
: 'rings · ' + rewards.length + (rewards.length === 1 ? ' current of value · ' : ' currents of value · ') + rewardWords;
|
|
6044
|
+
else if (p.q === 5 && at) call = physSolo()
|
|
6045
|
+
? (pro ? 'team · one person' : 'moons · just you · one moon')
|
|
6046
|
+
: (pro ? 'team · ' + at + (at === 1 ? ' contributor' : ' contributors') + ' · estimated ' + exp + ' by month three'
|
|
6047
|
+
: 'moons · ' + at + (at === 1 ? ' builder now' : ' builders now') + ' · the dashed orbit holds about ' + exp + ' by month three');
|
|
5716
6048
|
else if (p.q === 4 && mat) call = 'core · ' + PHYS_CORE_WORD[mat] + ' · a ' + mat + ' core';
|
|
5717
6049
|
else if (p.q === 3 && a.minors_on_board === true) call = 'protective ring · under 18s on board · the age tiers apply';
|
|
5718
6050
|
else if (p.q === 2 && a.home_country) call = 'coordinates · ' + (a.home_region || a.home_country).toLowerCase() + (a.builder_geography ? ' · builders ' + PHYS_GEO_WORD[a.builder_geography] : '');
|
|
@@ -5724,24 +6056,55 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
5724
6056
|
if (a.builder_geography) coords.push('builders ' + PHYS_GEO_WORD[a.builder_geography]);
|
|
5725
6057
|
if (a.minors_on_board !== undefined && a.minors_on_board !== null) coords.push(a.minors_on_board ? 'ages 13+' : 'ages 18+');
|
|
5726
6058
|
if (mat) coords.push('core ' + PHYS_CORE_WORD[mat]);
|
|
6059
|
+
if (at) coords.push((pro ? 'team ' : 'builders ') + (physSolo() ? '1' : at + ' → ' + exp));
|
|
6060
|
+
if (rewards.length) coords.push('rewards ' + rewards.map(function (r) { return r === 'future-payouts' ? 'future' : r; }).join(', '));
|
|
6061
|
+
if (live && a.framing) coords.push((pro ? 'framing ' : 'orbit ') + a.framing);
|
|
5727
6062
|
$('physCoords').textContent = coords.join(' · ');
|
|
5728
6063
|
}
|
|
5729
6064
|
|
|
5730
6065
|
/* The soft-limit table's verdicts (spec D6): an option it hides is hidden and
|
|
5731
6066
|
one it greys is disabled, each with its reason beside it. */
|
|
6067
|
+
/* Task 1004419 widened it to the list questions: a member the table hides is
|
|
6068
|
+
hidden and one it greys disabled, and either leaves the founder's list (it can
|
|
6069
|
+
no longer be chosen); a member's reasons gather once each in its question's
|
|
6070
|
+
why list, naming the options they are about. A whole question it hides, the
|
|
6071
|
+
flow skips (physSkips) or hides (data-limit). */
|
|
5732
6072
|
function physApplyLimits() {
|
|
6073
|
+
var a = phys().answers;
|
|
5733
6074
|
root.querySelectorAll('#panel-physics [data-why]').forEach(function (el) { el.hidden = true; el.textContent = ''; });
|
|
5734
|
-
root.querySelectorAll('#panel-physics [data-limit-grey]').forEach(function (el) { el.removeAttribute('data-limit-grey'); el.disabled = false; });
|
|
6075
|
+
root.querySelectorAll('#panel-physics [data-limit-grey]').forEach(function (el) { el.removeAttribute('data-limit-grey'); el.disabled = false; el.title = ''; });
|
|
6076
|
+
root.querySelectorAll('#panel-physics [data-limit-hide]').forEach(function (el) { el.removeAttribute('data-limit-hide'); el.hidden = false; });
|
|
6077
|
+
var lists = {};
|
|
5735
6078
|
physLimits.forEach(function (l) {
|
|
5736
|
-
var key = String(l.option || '');
|
|
6079
|
+
var key = String((l && l.option) || '');
|
|
6080
|
+
var parts = key.split(':');
|
|
5737
6081
|
var why = root.querySelector('#panel-physics [data-why="' + key + '"]');
|
|
5738
|
-
if (why && l.reason) { why.textContent = l.reason; why.hidden = false; }
|
|
5739
|
-
if (
|
|
5740
|
-
|
|
5741
|
-
|
|
5742
|
-
|
|
5743
|
-
|
|
6082
|
+
if (why && l.reason) { why.textContent = why.textContent ? why.textContent + ' ' + l.reason : l.reason; why.hidden = false; }
|
|
6083
|
+
if (!parts[1]) {
|
|
6084
|
+
if (l.effect === 'hide') root.querySelectorAll('#panel-physics [data-limit="' + key + '"]').forEach(function (el) { el.hidden = true; });
|
|
6085
|
+
return;
|
|
6086
|
+
}
|
|
6087
|
+
/* a note is offered as it is, with its reason in the list below */
|
|
6088
|
+
root.querySelectorAll('#panel-physics [data-phys="' + parts[0] + '"][data-val="' + parts[1] + '"]').forEach(function (b) {
|
|
6089
|
+
if (l.effect === 'grey') { b.disabled = true; b.setAttribute('data-limit-grey', '1'); b.title = l.reason || ''; }
|
|
6090
|
+
if (l.effect === 'hide') { b.hidden = true; b.setAttribute('data-limit-hide', '1'); }
|
|
6091
|
+
});
|
|
6092
|
+
if ((l.effect === 'grey' || l.effect === 'hide') && PHYS_MANY.indexOf(parts[0]) !== -1 && Array.isArray(a[parts[0]])) {
|
|
6093
|
+
a[parts[0]] = a[parts[0]].filter(function (v) { return v !== parts[1]; });
|
|
5744
6094
|
}
|
|
6095
|
+
if (l.effect === 'hide' || !l.reason || !PHYS_SAY[parts[0]]) return;
|
|
6096
|
+
var byReason = lists[parts[0]] = lists[parts[0]] || {};
|
|
6097
|
+
(byReason[l.reason] = byReason[l.reason] || []).push(PHYS_SAY[parts[0]][parts[1]] || parts[1]);
|
|
6098
|
+
});
|
|
6099
|
+
root.querySelectorAll('#panel-physics [data-why-list]').forEach(function (ul) {
|
|
6100
|
+
while (ul.firstChild) ul.removeChild(ul.firstChild);
|
|
6101
|
+
var byReason = lists[ul.getAttribute('data-why-list')] || {};
|
|
6102
|
+
Object.keys(byReason).forEach(function (reason) {
|
|
6103
|
+
var li = document.createElement('li');
|
|
6104
|
+
li.textContent = byReason[reason].join(', ') + ': ' + reason;
|
|
6105
|
+
ul.appendChild(li);
|
|
6106
|
+
});
|
|
6107
|
+
ul.hidden = !Object.keys(byReason).length;
|
|
5745
6108
|
});
|
|
5746
6109
|
}
|
|
5747
6110
|
|
|
@@ -5753,15 +6116,25 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
5753
6116
|
root.querySelectorAll('#physRail li').forEach(function (li) {
|
|
5754
6117
|
var n = Number(li.getAttribute('data-q'));
|
|
5755
6118
|
li.classList.toggle('now', n === p.q);
|
|
5756
|
-
li.classList.toggle('done', !!n && typeof p.q === 'number' && n < p.q);
|
|
6119
|
+
li.classList.toggle('done', !!n && (p.q === 'sum' || (typeof p.q === 'number' && n < p.q)) && !physSkips(n));
|
|
6120
|
+
li.classList.toggle('skipped', physSkips(n));
|
|
5757
6121
|
});
|
|
5758
6122
|
$('physRail').hidden = p.q === 'stop' || p.q === 0;
|
|
5759
6123
|
$('physNav').hidden = p.q === 'stop';
|
|
6124
|
+
physPaintVoice();
|
|
5760
6125
|
root.querySelectorAll('[data-phys-start]').forEach(function (b) { b.setAttribute('aria-pressed', String(b.getAttribute('data-phys-start') === p.start)); });
|
|
5761
6126
|
root.querySelectorAll('#panel-physics [data-phys]').forEach(function (b) {
|
|
5762
|
-
var v = a[b.getAttribute('data-phys')];
|
|
5763
|
-
|
|
6127
|
+
var v = a[b.getAttribute('data-phys')], val = b.getAttribute('data-val');
|
|
6128
|
+
var on = Array.isArray(v) ? v.indexOf(val) !== -1 : v !== undefined && v !== null && String(v) === val;
|
|
6129
|
+
b.setAttribute('aria-pressed', String(on));
|
|
5764
6130
|
});
|
|
6131
|
+
physPaintTeam();
|
|
6132
|
+
var suite = a.framing === 'hybrid' || a.framing === 'local';
|
|
6133
|
+
$('physSuite').hidden = !suite;
|
|
6134
|
+
$('physSuiteLbl').textContent = a.framing === 'local' ? 'Your local suite' : 'Your hybrid suite';
|
|
6135
|
+
if (p.q === 'sum') physPaintSummary();
|
|
6136
|
+
$('physNext').textContent = p.q !== 'sum' ? 'Continue →'
|
|
6137
|
+
: physVoice() === 'professional' ? 'Continue to setup →' : 'Create my planet →';
|
|
5765
6138
|
var existing = a.project_state === 'existing';
|
|
5766
6139
|
$('physExisting').hidden = !existing;
|
|
5767
6140
|
var works = Array.isArray(a.existing_work) ? a.existing_work : [];
|
|
@@ -5781,6 +6154,97 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
5781
6154
|
physPaintStage();
|
|
5782
6155
|
}
|
|
5783
6156
|
|
|
6157
|
+
/* the voice (spec D5): show the baked variant the entity answer picks */
|
|
6158
|
+
function physPaintVoice() {
|
|
6159
|
+
var v = physVoice() === 'professional' ? 'pro' : 'planet';
|
|
6160
|
+
root.querySelectorAll('#panel-physics [data-voice]').forEach(function (el) { el.hidden = el.getAttribute('data-voice') !== v; });
|
|
6161
|
+
}
|
|
6162
|
+
|
|
6163
|
+
/* question 5: one or many, the start count, and the month-three guess */
|
|
6164
|
+
function physPaintTeam() {
|
|
6165
|
+
var a = phys().answers, many = Number.isInteger(a.builders_at_start) && !physSolo();
|
|
6166
|
+
root.querySelectorAll('[data-phys-solo]').forEach(function (b) {
|
|
6167
|
+
var on = b.getAttribute('data-phys-solo') === 'one' ? physSolo() : many;
|
|
6168
|
+
b.setAttribute('aria-pressed', String(on));
|
|
6169
|
+
});
|
|
6170
|
+
$('physTeam').hidden = !many;
|
|
6171
|
+
if (!many) return;
|
|
6172
|
+
var start = a.builders_at_start, exp = a.builders_expected;
|
|
6173
|
+
var pro = physVoice() === 'professional';
|
|
6174
|
+
$('physStartN').textContent = String(start);
|
|
6175
|
+
$('physM1').textContent = String(start);
|
|
6176
|
+
$('physM2').textContent = String(Math.round(Math.sqrt(start * exp)));
|
|
6177
|
+
$('physM3').textContent = String(exp);
|
|
6178
|
+
var range = $('physExpected');
|
|
6179
|
+
range.setAttribute('min', String(Math.max(2, start)));
|
|
6180
|
+
range.setAttribute('max', String(Math.min(100000, Math.max(30, physGuess(start) * 3, exp))));
|
|
6181
|
+
range.value = String(exp);
|
|
6182
|
+
range.setAttribute('aria-valuetext', exp + (pro ? ' contributors' : ' builders') + ' by month three');
|
|
6183
|
+
$('physGuessLine').textContent = pro
|
|
6184
|
+
? 'Based on your project, we estimate ' + exp + ' contributors by month three. Adjust it if you know better.'
|
|
6185
|
+
: 'From what you’re building, we’d expect about ' + exp + ' builders by month three. Nobody can estimate builder growth cold, so we guess first and you correct.';
|
|
6186
|
+
}
|
|
6187
|
+
|
|
6188
|
+
/* the summary: every answer, each with a way back to its question */
|
|
6189
|
+
function physCountryName(code) {
|
|
6190
|
+
try { return new Intl.DisplayNames(['en'], { type: 'region' }).of(code) || code; } catch (e) { return code; }
|
|
6191
|
+
}
|
|
6192
|
+
function physSummaryRows() {
|
|
6193
|
+
var a = phys().answers, pro = physVoice() === 'professional';
|
|
6194
|
+
var rows = [];
|
|
6195
|
+
var told = String(state.description || '').trim();
|
|
6196
|
+
rows.push({ q: 1, k: 'State', v: PHYS_SAY.project_state[a.project_state] || 'Not answered', s: told });
|
|
6197
|
+
rows.push({ q: 2, k: 'Geography', v: a.home_country ? physCountryName(a.home_country) + (a.home_region && PHYS_REGIONS[a.home_region] ? ' (' + PHYS_REGIONS[a.home_region] + ')' : '') : 'Not answered',
|
|
6198
|
+
s: PHYS_SAY.builder_geography[a.builder_geography] || '' });
|
|
6199
|
+
rows.push({ q: 3, k: 'Under 18', v: a.minors_on_board === true ? 'Yes' : a.minors_on_board === false ? 'No' : 'Not answered',
|
|
6200
|
+
s: a.minors_on_board === true ? 'The age tiers apply, and a guardian signs for each young builder' : a.minors_on_board === false ? 'Everyone building is an adult' : '' });
|
|
6201
|
+
rows.push({ q: 4, k: pro ? 'Entity' : 'You are', v: PHYS_SAY.entity[a.entity] || 'Not answered',
|
|
6202
|
+
s: PHYS_ENTITY_FORMS.indexOf(a.entity) !== -1 ? 'An entity already formed' : a.entity ? 'The binding choice comes later' : '' });
|
|
6203
|
+
var solo = physSolo();
|
|
6204
|
+
rows.push({ q: 5, k: pro ? 'Team' : 'Builders', v: solo ? 'Just you' : Number.isInteger(a.builders_at_start) ? a.builders_at_start + ' now' : 'Not answered',
|
|
6205
|
+
s: solo ? (pro ? 'A single contributor' : 'Building solo') : Number.isInteger(a.builders_expected) ? 'About ' + a.builders_expected + ' by month three' : '' });
|
|
6206
|
+
var hiddenWhy = physLimits.filter(function (l) { return l && l.option === 'reward_intents' && l.effect === 'hide'; })[0];
|
|
6207
|
+
var rewards = Array.isArray(a.reward_intents) ? a.reward_intents : [];
|
|
6208
|
+
if (physSkips(6)) rows.push({ q: 5, k: 'Rewards', v: 'Not asked', s: hiddenWhy ? hiddenWhy.reason : '' });
|
|
6209
|
+
else rows.push({ q: 6, k: 'Rewards', v: rewards.length ? PHYS_REWARDS.filter(function (r) { return rewards.indexOf(r) !== -1; }).map(function (r) { return PHYS_SAY.reward_intents[r]; }).join(', ') : 'Not answered',
|
|
6210
|
+
s: rewards.length ? 'Intent only' : '' });
|
|
6211
|
+
var services = Array.isArray(a.services) ? a.services : [];
|
|
6212
|
+
rows.push({ q: 7, k: 'Framing', v: PHYS_SAY.framing[a.framing] || 'Not answered',
|
|
6213
|
+
s: a.framing === 'managed' ? 'The whole suite, run for you'
|
|
6214
|
+
: a.framing === 'open-source' ? 'The free core, on your own machines'
|
|
6215
|
+
: (a.framing === 'hybrid' || a.framing === 'local') ? (services.length ? PHYS_SERVICES.filter(function (x) { return services.indexOf(x) !== -1; }).map(function (x) { return PHYS_SAY.services[x]; }).join(', ') : 'No services picked yet') : '' });
|
|
6216
|
+
return rows;
|
|
6217
|
+
}
|
|
6218
|
+
function physPaintSummary() {
|
|
6219
|
+
var dl = $('physSummary');
|
|
6220
|
+
while (dl.firstChild) dl.removeChild(dl.firstChild);
|
|
6221
|
+
physSummaryRows().forEach(function (r) {
|
|
6222
|
+
var dt = document.createElement('dt');
|
|
6223
|
+
dt.textContent = r.k;
|
|
6224
|
+
var dd = document.createElement('dd');
|
|
6225
|
+
var body = document.createElement('span');
|
|
6226
|
+
body.textContent = r.v;
|
|
6227
|
+
if (r.s) { var sm = document.createElement('small'); sm.textContent = r.s; body.appendChild(sm); }
|
|
6228
|
+
var change = document.createElement('button');
|
|
6229
|
+
change.type = 'button';
|
|
6230
|
+
change.className = 'physLink';
|
|
6231
|
+
change.textContent = 'change';
|
|
6232
|
+
change.setAttribute('data-phys-goto', String(r.q));
|
|
6233
|
+
change.setAttribute('aria-label', 'Change ' + r.k.toLowerCase());
|
|
6234
|
+
change.addEventListener('click', function () { physChange(r.q); });
|
|
6235
|
+
dd.appendChild(body);
|
|
6236
|
+
dd.appendChild(change);
|
|
6237
|
+
dl.appendChild(dt);
|
|
6238
|
+
dl.appendChild(dd);
|
|
6239
|
+
});
|
|
6240
|
+
}
|
|
6241
|
+
/* "change": back to that question; Continue from it returns to the summary */
|
|
6242
|
+
function physChange(q) {
|
|
6243
|
+
phys().fromSum = true;
|
|
6244
|
+
physHint('');
|
|
6245
|
+
physGo(q);
|
|
6246
|
+
}
|
|
6247
|
+
|
|
5784
6248
|
function physHint(msg) {
|
|
5785
6249
|
$('h-phys').textContent = msg || ' ';
|
|
5786
6250
|
$('h-phys').className = msg ? 'hint err' : 'hint';
|
|
@@ -5793,6 +6257,7 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
5793
6257
|
}
|
|
5794
6258
|
function physGo(q) {
|
|
5795
6259
|
phys().q = q;
|
|
6260
|
+
if (q === 'sum') phys().fromSum = false;
|
|
5796
6261
|
saveDraft();
|
|
5797
6262
|
paintPhysics();
|
|
5798
6263
|
var h = root.querySelector('#panel-physics .physQ[data-q="' + q + '"] h1');
|
|
@@ -5819,22 +6284,43 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
5819
6284
|
physBusy = false;
|
|
5820
6285
|
if (res && res.stop) { $('physStopMsg').textContent = res.message || ''; physGo('stop'); return; }
|
|
5821
6286
|
physLimits = (res && res.soft_limits && res.soft_limits.limits) || [];
|
|
5822
|
-
physGo(
|
|
6287
|
+
physGo(physNextQ(1));
|
|
5823
6288
|
});
|
|
5824
6289
|
return false;
|
|
5825
6290
|
}
|
|
5826
6291
|
if (p.q === 2) {
|
|
5827
6292
|
if (!a.home_country) { physHint('Pick your country.'); return false; }
|
|
5828
6293
|
if (!a.builder_geography) { physHint('Say where you expect builders to be. Not sure yet is a fine answer.'); return false; }
|
|
5829
|
-
physGo(
|
|
6294
|
+
physGo(physNextQ(2)); return false;
|
|
5830
6295
|
}
|
|
5831
6296
|
if (p.q === 3) {
|
|
5832
6297
|
if (a.minors_on_board !== true && a.minors_on_board !== false) { physHint('Answer yes or no to go on.'); return false; }
|
|
5833
|
-
physGo(
|
|
6298
|
+
physGo(physNextQ(3)); return false;
|
|
6299
|
+
}
|
|
6300
|
+
/* from question 4 on, the table is asked again on every Continue: what it hides
|
|
6301
|
+
or greys on the next screens depends on the answers just given */
|
|
6302
|
+
if (p.q >= 4 && p.q <= PHYS_LAST) {
|
|
6303
|
+
if (!physAnswered(p.q)) {
|
|
6304
|
+
physHint(p.q === 4 ? 'Pick the one that fits best. Don’t know yet is a fine answer.'
|
|
6305
|
+
: p.q === 5 ? 'Say one or many to go on.'
|
|
6306
|
+
: p.q === 6 ? 'Pick at least one. Non-monetary is a fine answer.'
|
|
6307
|
+
: 'Pick how much should be run for you to go on.');
|
|
6308
|
+
return false;
|
|
6309
|
+
}
|
|
6310
|
+
if (physBusy) return false;
|
|
6311
|
+
physBusy = true;
|
|
6312
|
+
var from = p.q;
|
|
6313
|
+
physCheck().then(function (res) {
|
|
6314
|
+
physBusy = false;
|
|
6315
|
+
if (res && res.soft_limits) physLimits = res.soft_limits.limits || [];
|
|
6316
|
+
physGo(physNextQ(from));
|
|
6317
|
+
});
|
|
6318
|
+
return false;
|
|
5834
6319
|
}
|
|
5835
|
-
|
|
5836
|
-
|
|
5837
|
-
|
|
6320
|
+
/* the summary's Create my planet: the answers pre-fill the technical steps,
|
|
6321
|
+
and the wizard moves on to the first of them, the name */
|
|
6322
|
+
if (p.q === 'sum') {
|
|
6323
|
+
physPrefill();
|
|
5838
6324
|
show(4, true);
|
|
5839
6325
|
return false;
|
|
5840
6326
|
}
|
|
@@ -5844,7 +6330,8 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
5844
6330
|
$('physBack').addEventListener('click', function () {
|
|
5845
6331
|
var p = phys();
|
|
5846
6332
|
physHint('');
|
|
5847
|
-
|
|
6333
|
+
p.fromSum = false;
|
|
6334
|
+
if (p.q === 'sum' || (typeof p.q === 'number' && p.q > 0)) physGo(physPrevQ(p.q)); else show(2, true);
|
|
5848
6335
|
});
|
|
5849
6336
|
$('physStartOver').addEventListener('click', function () {
|
|
5850
6337
|
state.description = '';
|
|
@@ -5866,12 +6353,64 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
5866
6353
|
b.addEventListener('click', function () {
|
|
5867
6354
|
var k = b.getAttribute('data-phys'), raw = b.getAttribute('data-val');
|
|
5868
6355
|
var v = raw === 'true' ? true : raw === 'false' ? false : raw;
|
|
5869
|
-
var
|
|
5870
|
-
|
|
6356
|
+
var p = phys(), a = p.answers;
|
|
6357
|
+
if (PHYS_MANY.indexOf(k) !== -1) {
|
|
6358
|
+
/* a list question: each click adds or takes away one member */
|
|
6359
|
+
var list = Array.isArray(a[k]) ? a[k].slice() : [];
|
|
6360
|
+
var at = list.indexOf(v);
|
|
6361
|
+
if (at === -1) list.push(v); else list.splice(at, 1);
|
|
6362
|
+
a[k] = list;
|
|
6363
|
+
if (k === 'services') p.suiteTouched = true;
|
|
6364
|
+
} else {
|
|
6365
|
+
a[k] = a[k] === v ? null : v; /* a second click un-says it, like the team pills */
|
|
6366
|
+
}
|
|
5871
6367
|
if (k === 'project_state' && a[k] !== 'existing') { delete a.existing_work; delete a.main_work; }
|
|
6368
|
+
if (k === 'framing') physFramingChanged();
|
|
5872
6369
|
physHint(''); saveDraft(); paintPhysics();
|
|
5873
6370
|
});
|
|
5874
6371
|
});
|
|
6372
|
+
/* A hybrid or local framing starts from the canvas's suite until the founder picks
|
|
6373
|
+
for themselves; the table is asked again, since what it hides follows the framing. */
|
|
6374
|
+
function physFramingChanged() {
|
|
6375
|
+
var p = phys(), a = p.answers;
|
|
6376
|
+
if ((a.framing === 'hybrid' || a.framing === 'local') && !p.suiteTouched) a.services = PHYS_SUITE_START[a.framing].slice();
|
|
6377
|
+
physCheck().then(function (res) {
|
|
6378
|
+
if (!res || !res.soft_limits) return;
|
|
6379
|
+
physLimits = res.soft_limits.limits || [];
|
|
6380
|
+
paintPhysics();
|
|
6381
|
+
});
|
|
6382
|
+
}
|
|
6383
|
+
/* question 5's controls: one or many, the start count, the guess */
|
|
6384
|
+
root.querySelectorAll('[data-phys-solo]').forEach(function (b) {
|
|
6385
|
+
b.addEventListener('click', function () {
|
|
6386
|
+
var p = phys(), a = p.answers;
|
|
6387
|
+
if (b.getAttribute('data-phys-solo') === 'one') {
|
|
6388
|
+
a.builders_at_start = 1; a.builders_expected = 1; p.guessTouched = false;
|
|
6389
|
+
} else if (physSolo() || !Number.isInteger(a.builders_at_start)) {
|
|
6390
|
+
a.builders_at_start = 2; a.builders_expected = physGuess(2); p.guessTouched = false;
|
|
6391
|
+
}
|
|
6392
|
+
physHint(''); saveDraft(); paintPhysics();
|
|
6393
|
+
});
|
|
6394
|
+
});
|
|
6395
|
+
root.querySelectorAll('[data-phys-count]').forEach(function (b) {
|
|
6396
|
+
b.addEventListener('click', function () {
|
|
6397
|
+
var p = phys(), a = p.answers;
|
|
6398
|
+
var start = Math.min(100000, Math.max(1, (Number.isInteger(a.builders_at_start) ? a.builders_at_start : 2) + Number(b.getAttribute('data-phys-count'))));
|
|
6399
|
+
a.builders_at_start = start;
|
|
6400
|
+
/* the guess follows the start until the founder corrects it; "many" always
|
|
6401
|
+
expects company, or it would read as building alone */
|
|
6402
|
+
if (!p.guessTouched) a.builders_expected = physGuess(start);
|
|
6403
|
+
a.builders_expected = Math.max(a.builders_expected || 0, start, 2);
|
|
6404
|
+
saveDraft(); paintPhysics();
|
|
6405
|
+
});
|
|
6406
|
+
});
|
|
6407
|
+
$('physExpected').addEventListener('input', function () {
|
|
6408
|
+
var p = phys(), a = p.answers, n = Math.round(Number($('physExpected').value));
|
|
6409
|
+
if (!Number.isFinite(n)) return;
|
|
6410
|
+
a.builders_expected = Math.max(n, a.builders_at_start || 1, 2);
|
|
6411
|
+
p.guessTouched = true;
|
|
6412
|
+
saveDraft(); physPaintTeam(); physPaintStage();
|
|
6413
|
+
});
|
|
5875
6414
|
root.querySelectorAll('#physExisting [data-work]').forEach(function (cb) {
|
|
5876
6415
|
cb.addEventListener('change', function () {
|
|
5877
6416
|
var a = phys().answers, w = cb.getAttribute('data-work');
|
|
@@ -6029,11 +6568,12 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
6029
6568
|
form.addEventListener('submit', function (ev) {
|
|
6030
6569
|
ev.preventDefault();
|
|
6031
6570
|
var next = Number(form.getAttribute('data-next'));
|
|
6032
|
-
|
|
6571
|
+
/* a step the planet-physics answers skip is stepped over (task 1004419) */
|
|
6572
|
+
if (validateStep(next - 1)) show(physPastSkips(next, 1), true);
|
|
6033
6573
|
});
|
|
6034
6574
|
});
|
|
6035
6575
|
root.querySelectorAll('[data-back]').forEach(function (btn) {
|
|
6036
|
-
btn.addEventListener('click', function () { show(Number(btn.getAttribute('data-back')), true); });
|
|
6576
|
+
btn.addEventListener('click', function () { show(physPastSkips(Number(btn.getAttribute('data-back')), -1), true); });
|
|
6037
6577
|
});
|
|
6038
6578
|
|
|
6039
6579
|
/* ── review ── */
|
|
@@ -6053,6 +6593,8 @@ summary{min-height:24px;padding:3px 0;}
|
|
|
6053
6593
|
root.querySelectorAll('#appOpts input[name=appPlatform]').forEach(function (i) { i.checked = i.value === pick; });
|
|
6054
6594
|
}
|
|
6055
6595
|
function appRow() {
|
|
6596
|
+
/* the step the framing skipped (task 1004419) */
|
|
6597
|
+
if (physStepSkipped(10)) return 'Runs on your own machines, as your framing says — you can choose a platform later from the project’s page';
|
|
6056
6598
|
if (appPlatformChoice() !== 'render') return 'Not chosen yet — you can decide later';
|
|
6057
6599
|
if (renderLater()) return 'Render — set up from your project’s page once your app has code. Nothing is created on Render now.';
|
|
6058
6600
|
var ws =esc(state.renderOwnerName || state.renderOwnerId || '');
|