fixed Dev mode
This commit is contained in:
@@ -97,7 +97,24 @@
|
||||
// Said out loud whenever this run is not the installed ODIAN. A dev client looks exactly
|
||||
// like the real one on screen, and mistaking the two is how a bug gets chased in the
|
||||
// wrong tree - or a demo gets given from an unbuilt branch.
|
||||
const devRun = $derived((s?.dev ?? null) !== null && (launcher.settings?.dev_mode ?? false));
|
||||
const devOn = $derived(launcher.devOn);
|
||||
const devRun = $derived(launcher.devReady);
|
||||
const devRoot = $derived(launcher.settings?.dev_root ?? "");
|
||||
const devTarget = $derived(launcher.settings?.dev_target ?? "client");
|
||||
const devBuild = $derived(launcher.settings?.dev_build ?? false);
|
||||
const savingDev = $derived(busy === "settings");
|
||||
// One stack either way: both clients talk to the same API and the same database, which is
|
||||
// the only way a .exe/web divergence is visible at all.
|
||||
const TARGETS = [
|
||||
{ key: "client", name: "ODIAN", note: "Odian.exe" },
|
||||
{ key: "web", name: "Web", note: ":5173" },
|
||||
{ key: "both", name: "Both", note: "one stack" },
|
||||
] as const;
|
||||
|
||||
async function browseCheckout() {
|
||||
const path = await launcher.pickFolder();
|
||||
if (path) await launcher.setDev({ dev_root: path });
|
||||
}
|
||||
// Named only when it is someone ELSE: running as yourself is not worth a warning.
|
||||
const devUser = $derived.by(() => {
|
||||
const asked = launcher.settings?.dev_user?.trim() ?? "";
|
||||
@@ -221,16 +238,79 @@
|
||||
<button class="btn-link" disabled={blocked} onclick={() => launcher.openSync()}>Sync</button>
|
||||
</p>
|
||||
{/if}
|
||||
{#if devRun}
|
||||
<p class="secondary attention">
|
||||
<Icon name="alert" size={14} />
|
||||
<span>
|
||||
Dev mode: ODIAN runs from your checkout, not from the installed
|
||||
<strong>{s?.installed ?? "version"}</strong>.{#if devUser}
|
||||
Running as <strong>{devUser}</strong> — sync is off.{/if}
|
||||
</span>
|
||||
</p>
|
||||
{#if devOn}
|
||||
<!-- Dev mode's own controls, where the launching happens. Everything that decides
|
||||
what Launch does is here rather than behind Settings: the target, the checkout,
|
||||
and whether it builds first. -->
|
||||
<section class="dev" aria-label="Dev mode">
|
||||
<header class="dev-head">
|
||||
<Icon name="code" size={13} />
|
||||
<span class="dev-title">DEV</span>
|
||||
<!-- What Launch will actually start, in three words. The folder is not repeated
|
||||
here: it is in the field two rows down. -->
|
||||
<span class="dev-from mono">{devRun ? TARGETS.find((o) => o.key === devTarget)?.name ?? "" : "no checkout"}</span>
|
||||
</header>
|
||||
|
||||
<div class="dev-targets" role="radiogroup" aria-label="Launch starts">
|
||||
{#each TARGETS as option (option.key)}
|
||||
<label class="dev-target" class:on={devTarget === option.key}>
|
||||
<input
|
||||
type="radio"
|
||||
name="dev-target"
|
||||
value={option.key}
|
||||
checked={devTarget === option.key}
|
||||
disabled={blocked || savingDev}
|
||||
onchange={() => launcher.setDev({ dev_target: option.key })}
|
||||
/>
|
||||
<span class="dev-target-name">{option.name}</span>
|
||||
<span class="dev-target-note mono">{option.note}</span>
|
||||
</label>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<div class="dev-row">
|
||||
<input
|
||||
class="dev-path"
|
||||
type="text"
|
||||
spellcheck="false"
|
||||
placeholder="Folder holding ODIAN_Engine"
|
||||
value={devRoot}
|
||||
disabled={blocked || savingDev}
|
||||
onchange={(e) => launcher.setDev({ dev_root: e.currentTarget.value.trim() })}
|
||||
/>
|
||||
<button type="button" class="btn" disabled={blocked || savingDev} onclick={browseCheckout}>Browse…</button>
|
||||
</div>
|
||||
|
||||
<div class="dev-row wrap">
|
||||
<label class="dev-check">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={devBuild}
|
||||
disabled={blocked || savingDev}
|
||||
onchange={(e) => launcher.setDev({ dev_build: e.currentTarget.checked })}
|
||||
/>
|
||||
<span>Build first</span>
|
||||
</label>
|
||||
{#if s?.online}
|
||||
<!-- The stack is the install's, so its tiles and its data are still worth
|
||||
refreshing from the DHP while there is a line to it. -->
|
||||
<button class="btn-link" disabled={blocked} onclick={() => launcher.syncTiles()}>Sync tiles</button>
|
||||
<button class="btn-link" disabled={blocked} onclick={() => launcher.syncNow()}>Sync database</button>
|
||||
{:else}
|
||||
<span class="dev-offline mono">offline — tiles and data stay as they are</span>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
{#if !devRun}
|
||||
<p class="dev-note">Name the folder that holds <code>ODIAN_Engine</code> and Launch runs from it.</p>
|
||||
{:else if devUser}
|
||||
<p class="dev-note attention">
|
||||
Running as <strong>{devUser}</strong> — this PC will not sync with the DHP.
|
||||
</p>
|
||||
{/if}
|
||||
</section>
|
||||
{/if}
|
||||
|
||||
{#if unfinished}
|
||||
<p class="secondary attention">
|
||||
<Icon name="alert" size={14} />
|
||||
@@ -376,6 +456,114 @@
|
||||
</section>
|
||||
|
||||
<style>
|
||||
/* Dev mode's controls. Deliberately compact and deliberately here: what Launch will do
|
||||
is decided in the same place you press it, not two drawers away. */
|
||||
.dev {
|
||||
margin-top: 0.75rem;
|
||||
padding: 0.7rem 0.75rem;
|
||||
border: 1px solid color-mix(in srgb, #46d17f 32%, transparent);
|
||||
border-radius: 8px;
|
||||
background: color-mix(in srgb, #46d17f 7%, transparent);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.55rem;
|
||||
}
|
||||
.dev-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
color: #46d17f;
|
||||
}
|
||||
.dev-title {
|
||||
font-size: 0.72rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.12em;
|
||||
}
|
||||
.dev-from {
|
||||
margin-left: auto;
|
||||
font-size: 0.72rem;
|
||||
color: var(--text-dim, #9aa3ad);
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
max-width: 55%;
|
||||
direction: rtl; /* keep the END of a long path, which is the part that differs */
|
||||
text-align: right;
|
||||
}
|
||||
.dev-targets {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 0.35rem;
|
||||
}
|
||||
.dev-target {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 0.1rem;
|
||||
padding: 0.35rem 0.25rem;
|
||||
border: 1px solid var(--line, #2a3139);
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
line-height: 1.2;
|
||||
}
|
||||
.dev-target.on {
|
||||
border-color: color-mix(in srgb, #46d17f 60%, transparent);
|
||||
background: color-mix(in srgb, #46d17f 14%, transparent);
|
||||
}
|
||||
.dev-target:has(input:disabled) {
|
||||
opacity: 0.55;
|
||||
cursor: default;
|
||||
}
|
||||
.dev-target input {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
.dev-target-name {
|
||||
font-size: 0.82rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
.dev-target-note {
|
||||
font-size: 0.68rem;
|
||||
color: var(--text-dim, #9aa3ad);
|
||||
}
|
||||
.dev-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
}
|
||||
.dev-row.wrap {
|
||||
flex-wrap: wrap;
|
||||
row-gap: 0.3rem;
|
||||
}
|
||||
.dev-path {
|
||||
flex: 1 1 auto;
|
||||
min-width: 0;
|
||||
padding: 0.3rem 0.45rem;
|
||||
font-size: 0.78rem;
|
||||
font-family: inherit;
|
||||
color: inherit;
|
||||
background: rgba(0, 0, 0, 0.25);
|
||||
border: 1px solid var(--line, #2a3139);
|
||||
border-radius: 6px;
|
||||
}
|
||||
.dev-check {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.35rem;
|
||||
font-size: 0.8rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.dev-offline,
|
||||
.dev-note {
|
||||
font-size: 0.75rem;
|
||||
color: var(--text-dim, #9aa3ad);
|
||||
margin: 0;
|
||||
}
|
||||
.dev-note code {
|
||||
font-size: 0.72rem;
|
||||
}
|
||||
|
||||
.action {
|
||||
display: grid;
|
||||
gap: 14px;
|
||||
|
||||
Reference in New Issue
Block a user