Merge branch 'import-component'
This commit is contained in:
commit
6b999a5a82
@ -7,7 +7,7 @@
|
|||||||
<div class="tabs in left-align">
|
<div class="tabs in left-align">
|
||||||
<a
|
<a
|
||||||
class="spaced"
|
class="spaced"
|
||||||
class:active={currentPath.startsWith("/editor")}
|
class:active={!currentPath.startsWith("/about")}
|
||||||
href="/editor">Editor</a
|
href="/editor">Editor</a
|
||||||
>
|
>
|
||||||
<!--
|
<!--
|
||||||
@ -17,11 +17,6 @@
|
|||||||
href="/import">Import</a
|
href="/import">Import</a
|
||||||
>
|
>
|
||||||
-->
|
-->
|
||||||
<a
|
|
||||||
class="spaced"
|
|
||||||
class:active={currentPath.startsWith("/export")}
|
|
||||||
href="/export/print">Export</a
|
|
||||||
>
|
|
||||||
<a
|
<a
|
||||||
class="spaced"
|
class="spaced"
|
||||||
class:active={currentPath.startsWith("/about")}
|
class:active={currentPath.startsWith("/about")}
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { getContext } from "svelte";
|
||||||
|
|
||||||
import Identification from "./ShipEdit/Identification.svelte";
|
import Identification from "./ShipEdit/Identification.svelte";
|
||||||
import Propulsion from "./ShipEdit/Propulsion.svelte";
|
import Propulsion from "./ShipEdit/Propulsion.svelte";
|
||||||
import shipDux from "$lib/store/ship";
|
import shipDux from "$lib/store/ship";
|
||||||
@ -20,6 +22,8 @@
|
|||||||
export let structure = {};
|
export let structure = {};
|
||||||
export let weaponry = {};
|
export let weaponry = {};
|
||||||
export let carrier = {};
|
export let carrier = {};
|
||||||
|
|
||||||
|
const api = getContext("api");
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
@ -28,4 +32,6 @@
|
|||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
}
|
}
|
||||||
|
.reset {
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
import Field from "$lib/components/Field.svelte";
|
import Field from "$lib/components/Field.svelte";
|
||||||
import { candidateShipTypes } from "./Identification/shipTypes.js";
|
import { candidateShipTypes } from "./Identification/shipTypes.js";
|
||||||
import ShipCost from "./Identification/ShipCost.svelte";
|
import ShipCost from "./Identification/ShipCost.svelte";
|
||||||
|
import shipDux from "$lib/store/ship";
|
||||||
|
|
||||||
export let shipClass = "";
|
export let shipClass = "";
|
||||||
export let shipType = "";
|
export let shipType = "";
|
||||||
|
@ -19,117 +19,121 @@ import { adfcDux } from "./ship/weaponry/adfc";
|
|||||||
import { weaponsDux } from "./ship/weaponry/weapons";
|
import { weaponsDux } from "./ship/weaponry/weapons";
|
||||||
|
|
||||||
if (typeof process !== "undefined") {
|
if (typeof process !== "undefined") {
|
||||||
process.env.UPDEEP_MODE = "dangerously_never_freeze";
|
process.env.UPDEEP_MODE = "dangerously_never_freeze";
|
||||||
}
|
}
|
||||||
|
|
||||||
const structure = new Updux({
|
const structure = new Updux({
|
||||||
initialState: {},
|
initialState: {},
|
||||||
subduxes: {
|
subduxes: {
|
||||||
streamlining,
|
streamlining,
|
||||||
cargo: cargoDux,
|
cargo: cargoDux,
|
||||||
hull: hullDux,
|
hull: hullDux,
|
||||||
screens: screensDux,
|
screens: screensDux,
|
||||||
armor: armorDux,
|
armor: armorDux,
|
||||||
carrier: carrierDux,
|
carrier: carrierDux,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const propulsion = new Updux({
|
const propulsion = new Updux({
|
||||||
initialState: {},
|
initialState: {},
|
||||||
subduxes: {
|
subduxes: {
|
||||||
ftl,
|
ftl,
|
||||||
drive,
|
drive,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const weaponry = new Updux({
|
const weaponry = new Updux({
|
||||||
initialState: {},
|
initialState: {},
|
||||||
subduxes: {
|
subduxes: {
|
||||||
adfc: adfcDux,
|
adfc: adfcDux,
|
||||||
firecons: fireconsDux,
|
firecons: fireconsDux,
|
||||||
weapons: weaponsDux,
|
weapons: weaponsDux,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const restore = createPayloadAction<typeof shipDux.initialState>("restore");
|
const restore = createPayloadAction<typeof shipDux.initialState>("restore");
|
||||||
|
const importShip =
|
||||||
|
createPayloadAction<typeof shipDux.initialState>("importShip");
|
||||||
|
|
||||||
const shipDux = new Updux({
|
const shipDux = new Updux({
|
||||||
actions: {
|
actions: {
|
||||||
restore,
|
restore,
|
||||||
},
|
importShip,
|
||||||
initialState: {
|
},
|
||||||
schemaVersion: "1",
|
initialState: {
|
||||||
},
|
schemaVersion: "1",
|
||||||
subduxes: {
|
},
|
||||||
identification,
|
subduxes: {
|
||||||
structure,
|
identification,
|
||||||
propulsion,
|
structure,
|
||||||
carrier: carrierDux,
|
propulsion,
|
||||||
weaponry,
|
carrier: carrierDux,
|
||||||
},
|
weaponry,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
shipDux.addMutation(restore, (state) => () => state);
|
shipDux.addMutation(restore, (state) => () => state);
|
||||||
|
shipDux.addMutation(importShip, (state) => () => state);
|
||||||
|
|
||||||
shipDux.addReaction((api) => {
|
shipDux.addReaction((api) => {
|
||||||
return createSelector(
|
return createSelector(
|
||||||
api.selectors.getFtlType,
|
api.selectors.getFtlType,
|
||||||
api.selectors.getShipMass,
|
api.selectors.getShipMass,
|
||||||
(type, mass) => api.dispatch.setFtlReqs(calcFtlReqs(type, mass))
|
(type, mass) => api.dispatch.setFtlReqs(calcFtlReqs(type, mass))
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
shipDux.addReaction((api) => {
|
shipDux.addReaction((api) => {
|
||||||
const setShipReqs = memoize((cost, usedMass) =>
|
const setShipReqs = memoize((cost, usedMass) =>
|
||||||
api.dispatch.setShipReqs({ cost, usedMass })
|
api.dispatch.setShipReqs({ cost, usedMass })
|
||||||
);
|
);
|
||||||
|
|
||||||
return (state) => {
|
return (state) => {
|
||||||
let cost = 0;
|
let cost = 0;
|
||||||
let mass = 0;
|
let mass = 0;
|
||||||
|
|
||||||
let subsystems = R.values(R.omit(state, ["identification"]));
|
let subsystems = R.values(R.omit(state, ["identification"]));
|
||||||
|
|
||||||
while (subsystems.length > 0) {
|
while (subsystems.length > 0) {
|
||||||
const subsystem = subsystems.shift();
|
const subsystem = subsystems.shift();
|
||||||
if (typeof subsystem !== "object") continue;
|
if (typeof subsystem !== "object") continue;
|
||||||
|
|
||||||
if (subsystem.reqs) {
|
if (subsystem.reqs) {
|
||||||
cost += subsystem.reqs.cost ?? 0;
|
cost += subsystem.reqs.cost ?? 0;
|
||||||
mass += subsystem.reqs.mass ?? 0;
|
mass += subsystem.reqs.mass ?? 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
subsystems.push(...Object.values(subsystem));
|
subsystems.push(...Object.values(subsystem));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Number.isNaN(cost)) {
|
if (Number.isNaN(cost)) {
|
||||||
console.log(state.weaponry.weapons);
|
console.log(state.weaponry.weapons);
|
||||||
throw new Error();
|
throw new Error();
|
||||||
}
|
}
|
||||||
|
|
||||||
setShipReqs(cost, mass);
|
setShipReqs(cost, mass);
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
shipDux.addReaction((api) =>
|
shipDux.addReaction((api) =>
|
||||||
createSelector(
|
createSelector(
|
||||||
api.selectors.getShipMass,
|
api.selectors.getShipMass,
|
||||||
(state) => state.propulsion.drive.rating,
|
(state) => state.propulsion.drive.rating,
|
||||||
(state) => state.propulsion.drive.advanced,
|
(state) => state.propulsion.drive.advanced,
|
||||||
(mass, rating, advanced) =>
|
(mass, rating, advanced) =>
|
||||||
api.dispatch.setDriveReqs(calcDriveReqs(mass, rating, advanced))
|
api.dispatch.setDriveReqs(calcDriveReqs(mass, rating, advanced))
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
shipDux.addReaction((api) =>
|
shipDux.addReaction((api) =>
|
||||||
createSelector(
|
createSelector(
|
||||||
// (state) => state,
|
// (state) => state,
|
||||||
api.selectors.getShipMass,
|
api.selectors.getShipMass,
|
||||||
api.selectors.getStreamlining,
|
api.selectors.getStreamlining,
|
||||||
(mass, type) => {
|
(mass, type) => {
|
||||||
api.dispatch.setStreamliningReqs(calcStreamliningReqs(type, mass));
|
api.dispatch.setStreamliningReqs(calcStreamliningReqs(type, mass));
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
shipDux.addReaction(screensReqsReaction);
|
shipDux.addReaction(screensReqsReaction);
|
||||||
|
42
src/routes/(editor)/+layout.svelte
Normal file
42
src/routes/(editor)/+layout.svelte
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<nav class="m l left">
|
||||||
|
<!-- set them as active -->
|
||||||
|
<a href="/editor">
|
||||||
|
<i>edit</i>
|
||||||
|
<span>editor</span>
|
||||||
|
</a>
|
||||||
|
<a href="/export/print">
|
||||||
|
<i>print</i>
|
||||||
|
<span>print</span>
|
||||||
|
</a>
|
||||||
|
<a href="/export">
|
||||||
|
<i>output</i>
|
||||||
|
<span>export</span>
|
||||||
|
</a>
|
||||||
|
<a href="/import">
|
||||||
|
<i>input</i>
|
||||||
|
<span>import</span>
|
||||||
|
</a>
|
||||||
|
<a on:click={handleReset}>
|
||||||
|
<i>restart_alt</i>
|
||||||
|
<span>reset</span>
|
||||||
|
</a>
|
||||||
|
</nav>
|
||||||
|
<slot />
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { getContext } from "svelte";
|
||||||
|
import shipDux from "$lib/store/ship";
|
||||||
|
|
||||||
|
export let api = getContext("api");
|
||||||
|
|
||||||
|
async function handleReset() {
|
||||||
|
if (!(await window.confirm("really reset the ship?"))) return;
|
||||||
|
api?.dispatch?.importShip(shipDux.initialState);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
nav {
|
||||||
|
margin-top: 70px;
|
||||||
|
}
|
||||||
|
</style>
|
11
src/routes/(editor)/export/+page.svelte
Normal file
11
src/routes/(editor)/export/+page.svelte
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<Serialized data={$shipData} />
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { getContext } from "svelte";
|
||||||
|
|
||||||
|
import Serialized from "./Serialized.svelte";
|
||||||
|
|
||||||
|
const api = getContext("api");
|
||||||
|
|
||||||
|
let shipData = api.svelteStore;
|
||||||
|
</script>
|
@ -6,16 +6,25 @@
|
|||||||
on:error={copyError}>{copyLabel} <i>content_paste</i></button
|
on:error={copyError}>{copyLabel} <i>content_paste</i></button
|
||||||
>
|
>
|
||||||
<button on:click={handleSave}>download <i>download</i></button>
|
<button on:click={handleSave}>download <i>download</i></button>
|
||||||
|
<div class="field suffix border">
|
||||||
|
<select bind:value={format}>
|
||||||
|
<option>json</option>
|
||||||
|
<option>yaml</option>
|
||||||
|
</select>
|
||||||
|
<i>arrow_drop_down</i>
|
||||||
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
<pre><code>{data}</code></pre>
|
<pre><code>{serialized}</code></pre>
|
||||||
<a hidden {href} {download} bind:this={fileDownload} />
|
<a hidden {href} {download} bind:this={fileDownload} />
|
||||||
</article>
|
</article>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { clipboard } from "$lib/actions/clipboard.js";
|
import { clipboard } from "$lib/actions/clipboard.js";
|
||||||
|
import yaml from "yaml";
|
||||||
|
|
||||||
export let data = "Loading...";
|
export let data = {};
|
||||||
export let format;
|
export let serialized = "Loading...";
|
||||||
|
export let format = "json";
|
||||||
|
|
||||||
let copyLabel = "clipboard";
|
let copyLabel = "clipboard";
|
||||||
|
|
||||||
@ -37,6 +46,14 @@
|
|||||||
function handleSave() {
|
function handleSave() {
|
||||||
fileDownload?.click();
|
fileDownload?.click();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const serialize = async (data, format) => {
|
||||||
|
if (format === "json") return JSON.stringify(data, null, 2);
|
||||||
|
|
||||||
|
return yaml.stringify(data);
|
||||||
|
};
|
||||||
|
|
||||||
|
$: serialize(data, format).then((s) => (serialized = s));
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
@ -50,4 +67,15 @@
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
right: 5em;
|
right: 5em;
|
||||||
}
|
}
|
||||||
|
.my-switch {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.my-switch > span {
|
||||||
|
display: inline-block;
|
||||||
|
font-size: var(--font-scale-10);
|
||||||
|
}
|
||||||
|
label {
|
||||||
|
margin: 0px 0.5rem;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
@ -1,4 +1,4 @@
|
|||||||
import { render } from "@testing-library/svelte";
|
import { render, waitFor } from "@testing-library/svelte";
|
||||||
import "@testing-library/jest-dom";
|
import "@testing-library/jest-dom";
|
||||||
|
|
||||||
import Serialized from "./Serialized.svelte";
|
import Serialized from "./Serialized.svelte";
|
||||||
@ -6,9 +6,8 @@ import Serialized from "./Serialized.svelte";
|
|||||||
test("basic", () => {
|
test("basic", () => {
|
||||||
const { getByText } = render(Serialized, {
|
const { getByText } = render(Serialized, {
|
||||||
props: {
|
props: {
|
||||||
data: "hello world",
|
data: { greeting: "hello world" },
|
||||||
format: "json",
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
expect(getByText("hello world")).toBeInTheDocument();
|
waitFor(() => expect(getByText("hello world")).toBeInTheDocument());
|
||||||
});
|
});
|
102
src/routes/(editor)/import/+page.svelte
Normal file
102
src/routes/(editor)/import/+page.svelte
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
<article>
|
||||||
|
<nav>
|
||||||
|
<button class="primary" disabled={error} on:click={handleSet}>set </button>
|
||||||
|
<div class="max" />
|
||||||
|
|
||||||
|
<div class="my-error">
|
||||||
|
{#if error}
|
||||||
|
invalid
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button class="primary" on:click={() => fileInput.click()}
|
||||||
|
><i>upload</i> upload</button
|
||||||
|
>
|
||||||
|
</nav>
|
||||||
|
<div class="support">
|
||||||
|
both <code>json</code> and <code>yaml</code> formats are supported
|
||||||
|
</div>
|
||||||
|
<textarea rows="20" bind:value={stringData} />
|
||||||
|
<input
|
||||||
|
bind:this={fileInput}
|
||||||
|
bind:files
|
||||||
|
type="file"
|
||||||
|
on:change={handleUpload}
|
||||||
|
/>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { clipboard } from "$lib/actions/clipboard.js";
|
||||||
|
import { getContext } from "svelte";
|
||||||
|
import yaml from "yaml";
|
||||||
|
import { goto } from "$app/navigation";
|
||||||
|
|
||||||
|
export let format = "json";
|
||||||
|
|
||||||
|
let fileInput;
|
||||||
|
let files;
|
||||||
|
const handleUpload = async () => {
|
||||||
|
stringData = await files[0].text();
|
||||||
|
};
|
||||||
|
|
||||||
|
const api = getContext("api");
|
||||||
|
|
||||||
|
let shipData = api.svelteStore;
|
||||||
|
|
||||||
|
let stringData = JSON.stringify($shipData, null, 2);
|
||||||
|
|
||||||
|
let serialized = {};
|
||||||
|
let error = false;
|
||||||
|
$: try {
|
||||||
|
error = false;
|
||||||
|
serialized = yaml.parse(stringData);
|
||||||
|
} catch (e) {
|
||||||
|
error = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleSet() {
|
||||||
|
if (await window.confirm("import ship (and clobber the current one)?")) {
|
||||||
|
api?.dispatch?.importShip?.(serialized);
|
||||||
|
goto("/editor");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
article {
|
||||||
|
background-color: var(--primary-container);
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
font-size: var(--font-scale-10);
|
||||||
|
}
|
||||||
|
nav {
|
||||||
|
margin-bottom: 1em;
|
||||||
|
}
|
||||||
|
.my-switch {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.my-switch > span {
|
||||||
|
display: inline-block;
|
||||||
|
font-size: var(--font-scale-10);
|
||||||
|
}
|
||||||
|
label {
|
||||||
|
margin: 0px 0.5rem;
|
||||||
|
}
|
||||||
|
textarea {
|
||||||
|
width: 100%;
|
||||||
|
height: 70vh;
|
||||||
|
}
|
||||||
|
.support {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
.my-error {
|
||||||
|
color: red;
|
||||||
|
font-size: var(--font-scale-11);
|
||||||
|
}
|
||||||
|
input[type="file"] {
|
||||||
|
position: inherit;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
</style>
|
@ -1,32 +0,0 @@
|
|||||||
<nav class="m l left">
|
|
||||||
<!-- set them as active -->
|
|
||||||
<a href="/export/print">
|
|
||||||
<i>print</i>
|
|
||||||
<span>print</span>
|
|
||||||
</a>
|
|
||||||
<a href="/export/json">
|
|
||||||
<i>output</i>
|
|
||||||
<span>json</span>
|
|
||||||
</a>
|
|
||||||
<a href="/export/yaml">
|
|
||||||
<i>output</i>
|
|
||||||
<span>yaml</span>
|
|
||||||
</a>
|
|
||||||
<!-- TODO
|
|
||||||
<a>
|
|
||||||
<i>Quiz</i>
|
|
||||||
<span>See also</span>
|
|
||||||
</a>
|
|
||||||
<a>
|
|
||||||
<i>Format_List_Bulleted</i>
|
|
||||||
<span>Changelog</span>
|
|
||||||
</a>
|
|
||||||
-->
|
|
||||||
</nav>
|
|
||||||
<slot />
|
|
||||||
|
|
||||||
<style>
|
|
||||||
nav {
|
|
||||||
margin-top: 70px;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,6 +0,0 @@
|
|||||||
/** @type {import('./$types').PageLoad} */
|
|
||||||
export function load({ params }) {
|
|
||||||
return {
|
|
||||||
format: params.format,
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
<Serialized data={serializedShip} format={data.format} />
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { getContext } from "svelte";
|
|
||||||
|
|
||||||
import Serialized from "./Serialized.svelte";
|
|
||||||
|
|
||||||
const api = getContext("api");
|
|
||||||
|
|
||||||
let shipData = api.svelteStore;
|
|
||||||
export let data;
|
|
||||||
|
|
||||||
const serialize = async (data, format) => {
|
|
||||||
if (format === "json") return JSON.stringify(data, null, 2);
|
|
||||||
|
|
||||||
return import("yaml").then(({ stringify }) => stringify(data));
|
|
||||||
};
|
|
||||||
|
|
||||||
let serializedShip;
|
|
||||||
$: serialize($shipData, data.format).then((s) => (serializedShip = s));
|
|
||||||
</script>
|
|
@ -4,14 +4,14 @@ import packageJson from "./package.json";
|
|||||||
|
|
||||||
/** @type {import('vite').UserConfig} */
|
/** @type {import('vite').UserConfig} */
|
||||||
const config = {
|
const config = {
|
||||||
plugins: [sveltekit()],
|
plugins: [sveltekit()],
|
||||||
publicDir: "./static",
|
// publicDir: "./static",
|
||||||
ssr: {},
|
ssr: {},
|
||||||
optimizeDeps: {},
|
optimizeDeps: {},
|
||||||
define: {
|
define: {
|
||||||
"import.meta.env.PACKAGE_VERSION": JSON.stringify(packageJson.version),
|
"import.meta.env.PACKAGE_VERSION": JSON.stringify(packageJson.version),
|
||||||
"import.meta.env.HOMEPAGE": JSON.stringify(packageJson.homepage),
|
"import.meta.env.HOMEPAGE": JSON.stringify(packageJson.homepage),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default config;
|
export default config;
|
||||||
|
Loading…
Reference in New Issue
Block a user