Merge branch 'streamlining-2' into redux-toolbox
This commit is contained in:
commit
add30bb666
@ -9,5 +9,5 @@ export default defineConfig({
|
|||||||
// Options here
|
// Options here
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
// setupFile: "./src/histoire.setup.js",
|
setupFile: "./src/histoire.setup.js",
|
||||||
});
|
});
|
||||||
|
18
package.json
18
package.json
@ -26,31 +26,31 @@
|
|||||||
"globby": "^13.1.3",
|
"globby": "^13.1.3",
|
||||||
"jest-image-snapshot": "^4.5.1",
|
"jest-image-snapshot": "^4.5.1",
|
||||||
"pixelmatch": "^5.3.0",
|
"pixelmatch": "^5.3.0",
|
||||||
"prettier": "~2.5.1",
|
"prettier": "~2.8.6",
|
||||||
"prettier-plugin-svelte": "^2.6.0",
|
"prettier-plugin-svelte": "^2.10.0",
|
||||||
"showdown": "^2.0.3",
|
"showdown": "^2.0.3",
|
||||||
"svelte": "^3.55.1",
|
"svelte": "^3.57.0",
|
||||||
"typescript": "^4.9.5",
|
"typescript": "^5.0.2",
|
||||||
"vitest": "^0.29.7",
|
"vitest": "^0.29.7"
|
||||||
"vitest-svelte-kit": "^0.0.6"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@picocss/pico": "^1.5.7",
|
"@picocss/pico": "^1.5.7",
|
||||||
"@reduxjs/toolkit": "^1.9.3",
|
"@reduxjs/toolkit": "^1.9.3",
|
||||||
"@sveltejs/adapter-node": "^1.0.0-next.0",
|
"@sveltejs/adapter-node": "^1.0.0-next.0",
|
||||||
"@yanick/updeep-remeda": "^2.1.0",
|
"@yanick/updeep-remeda": "^2.1.1",
|
||||||
"chota": "^0.8.0",
|
"chota": "^0.8.0",
|
||||||
"effector": "^22.5.2",
|
"effector": "^22.5.2",
|
||||||
"histoire": "^0.15.9",
|
"histoire": "^0.15.9",
|
||||||
|
"jsdom": "^21.1.1",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"redux": "^4.1.2",
|
"redux": "^4.1.2",
|
||||||
"remeda": "^1.1.0",
|
"remeda": "^1.9.1",
|
||||||
"reselect": "^4.1.5",
|
"reselect": "^4.1.5",
|
||||||
"svelte-chota": "^1.8.6",
|
"svelte-chota": "^1.8.6",
|
||||||
"svelte-knobby": "^0.3.4",
|
"svelte-knobby": "^0.3.4",
|
||||||
"svelte-moveable": "^0.20.0",
|
"svelte-moveable": "^0.20.0",
|
||||||
"ts-action": "^11.0.0",
|
"ts-action": "^11.0.0",
|
||||||
"vite": "^4.1.4"
|
"vite": "^4.2.1"
|
||||||
},
|
},
|
||||||
"prettier": {
|
"prettier": {
|
||||||
"svelteSortOrder": "options-markup-scripts-styles",
|
"svelteSortOrder": "options-markup-scripts-styles",
|
||||||
|
@ -1 +1,3 @@
|
|||||||
import "./lib/style/index.js";
|
//import "./lib/style/index.js";
|
||||||
|
import "@picocss/pico";
|
||||||
|
import "../static/global.css";
|
||||||
|
@ -1,118 +0,0 @@
|
|||||||
<script>
|
|
||||||
import "@picocss/pico";
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style global>
|
|
||||||
@font-face {
|
|
||||||
font-family: "Faktos";
|
|
||||||
font-style: normal;
|
|
||||||
src: url(/fonts/Faktos.ttf) format("truetype");
|
|
||||||
}
|
|
||||||
@font-face {
|
|
||||||
font-family: "Dosis";
|
|
||||||
src: url(/fonts/dosis/Dosis-VariableFont_wght.ttf) format("truetype");
|
|
||||||
}
|
|
||||||
|
|
||||||
:root {
|
|
||||||
--main-font-family: "Dosis", -apple-system, BlinkMacSystemFont, "Segoe UI",
|
|
||||||
Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
|
|
||||||
--font-family: "Dosis", -apple-system, BlinkMacSystemFont, "Segoe UI",
|
|
||||||
Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
|
|
||||||
|
|
||||||
--font-scale-9: 0.75rem;
|
|
||||||
--font-scale-10: 1em;
|
|
||||||
--font-scale-11: 1.333rem;
|
|
||||||
--font-scale-12: 1.777rem;
|
|
||||||
--font-scale-13: 2.369rem;
|
|
||||||
--font-scale-14: 3.157rem;
|
|
||||||
--font-scale-15: 4.209rem;
|
|
||||||
|
|
||||||
--oxford-blue: hsla(226, 60%, 10%, 1);
|
|
||||||
--royal-blue-dark: hsla(218, 100%, 16%, 1);
|
|
||||||
--indigo-dye: hsla(209, 95%, 24%, 1);
|
|
||||||
--cg-blue: hsla(193, 80%, 35%, 1);
|
|
||||||
--white: hsla(20, 60%, 99%, 1);
|
|
||||||
|
|
||||||
--main-width: 60em;
|
|
||||||
}
|
|
||||||
|
|
||||||
input.short {
|
|
||||||
width: 5em !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
small {
|
|
||||||
font-size: var(--font-scale-9);
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
margin: 0px;
|
|
||||||
padding: 0px;
|
|
||||||
font-size: var(--font-scale-14);
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
font-size: var(--font-scale-12);
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
position: relative;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
background-color: var(--white);
|
|
||||||
color: #333;
|
|
||||||
margin: 0;
|
|
||||||
padding: 8px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
font-family: "Dosis", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
|
|
||||||
Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: rgb(0, 100, 200);
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:visited {
|
|
||||||
color: rgb(0, 80, 160);
|
|
||||||
}
|
|
||||||
|
|
||||||
label {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
input,
|
|
||||||
button,
|
|
||||||
select,
|
|
||||||
textarea {
|
|
||||||
font-family: inherit;
|
|
||||||
font-size: inherit;
|
|
||||||
padding: 0.4em;
|
|
||||||
margin: 0 0 0.5em 0;
|
|
||||||
box-sizing: border-box;
|
|
||||||
border: 1px solid #ccc;
|
|
||||||
border-radius: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
input:disabled {
|
|
||||||
color: #ccc;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type="range"] {
|
|
||||||
height: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* input, */
|
|
||||||
/* select { */
|
|
||||||
/* border: 0px; */
|
|
||||||
/* border-bottom: 1px solid var(--indigo-dye); */
|
|
||||||
/* } */
|
|
||||||
|
|
||||||
input:focus,
|
|
||||||
select:focus {
|
|
||||||
border: 1px solid var(--indigo-dye);
|
|
||||||
}
|
|
||||||
</style>
|
|
18
src/lib/components/ShipEdit.story.svelte
Normal file
18
src/lib/components/ShipEdit.story.svelte
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<Hst.Story>
|
||||||
|
<ShipEdit {...ship} />
|
||||||
|
</Hst.Story>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { setContext } from "svelte";
|
||||||
|
import ShipEdit from "./ShipEdit.svelte";
|
||||||
|
import { createApi } from "$lib/store/api";
|
||||||
|
|
||||||
|
export let Hst;
|
||||||
|
|
||||||
|
const api = createApi();
|
||||||
|
setContext("api", api);
|
||||||
|
|
||||||
|
let ship = api.getState();
|
||||||
|
|
||||||
|
api.subscribe(() => (ship = api.getState()));
|
||||||
|
</script>
|
24
src/lib/components/ShipEdit.svelte
Normal file
24
src/lib/components/ShipEdit.svelte
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<main>
|
||||||
|
<Identification {...identification} />
|
||||||
|
<Propulsion {...propulsion} />
|
||||||
|
<Structure {...structure} />
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Identification from "./ShipEdit/Identification.svelte";
|
||||||
|
import Propulsion from "./ShipEdit/Propulsion.svelte";
|
||||||
|
import shipDux from "$lib/store/ship";
|
||||||
|
import Structure from "./ShipEdit/Structure.svelte";
|
||||||
|
|
||||||
|
export let identification = {};
|
||||||
|
export let propulsion = {};
|
||||||
|
export let structure = {};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
main {
|
||||||
|
width: var(--main-width);
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
}
|
||||||
|
</style>
|
@ -1,5 +1,4 @@
|
|||||||
<ShipItem {...reqs}>
|
<ShipItem {...reqs}>
|
||||||
<!--
|
|
||||||
<Field label={`squadron ${id}`}>
|
<Field label={`squadron ${id}`}>
|
||||||
<select bind:value={type}>
|
<select bind:value={type}>
|
||||||
{#each types as type (type)}
|
{#each types as type (type)}
|
||||||
@ -7,7 +6,6 @@
|
|||||||
{/each}
|
{/each}
|
||||||
</select>
|
</select>
|
||||||
</Field>
|
</Field>
|
||||||
-->
|
|
||||||
</ShipItem>
|
</ShipItem>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
17
src/lib/components/ShipEdit/Identification.story.svelte
Normal file
17
src/lib/components/ShipEdit/Identification.story.svelte
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<Hst.Story title="ShipEdit/Identification">
|
||||||
|
<Identification
|
||||||
|
shipClass="Demeter"
|
||||||
|
shipType="Destroyer"
|
||||||
|
isCarrier={false}
|
||||||
|
reqs={{
|
||||||
|
cost: 12,
|
||||||
|
mass: 13,
|
||||||
|
usedMass: 9,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Hst.Story>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
export let Hst;
|
||||||
|
import Identification from "./Identification.svelte";
|
||||||
|
</script>
|
53
src/lib/components/ShipEdit/Identification.svelte
Normal file
53
src/lib/components/ShipEdit/Identification.svelte
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
<div class="identification-row">
|
||||||
|
<div>
|
||||||
|
<Field label="ship class" bind:value={shipClass} />
|
||||||
|
<Field label="ship type">
|
||||||
|
<select bind:value={shipType}>
|
||||||
|
{#each shipTypes as name (name)}
|
||||||
|
<option>{name}</option>
|
||||||
|
{/each}
|
||||||
|
</select>
|
||||||
|
</Field>
|
||||||
|
</div>
|
||||||
|
<ShipCost {...reqs} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { getContext } from "svelte";
|
||||||
|
|
||||||
|
import Field from "$lib/components/Field.svelte";
|
||||||
|
import { candidateShipTypes } from "./Identification/shipTypes.js";
|
||||||
|
import ShipCost from "./Identification/ShipCost.svelte";
|
||||||
|
|
||||||
|
export let shipClass = "";
|
||||||
|
export let shipType = "";
|
||||||
|
export let isCarrier = false;
|
||||||
|
export let reqs = {};
|
||||||
|
|
||||||
|
export let api = getContext("api");
|
||||||
|
|
||||||
|
$: shipTypes = candidateShipTypes(reqs.mass, isCarrier).map(
|
||||||
|
({ name }) => name
|
||||||
|
);
|
||||||
|
|
||||||
|
$: if (shipTypes.length > 0 && !shipTypes.includes(shipType))
|
||||||
|
shipType = shipTypes[0];
|
||||||
|
|
||||||
|
$: api?.dispatch?.updateIdentification?.({ shipType, shipClass });
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
div {
|
||||||
|
display: flex;
|
||||||
|
align-items: end;
|
||||||
|
gap: 2em;
|
||||||
|
}
|
||||||
|
.identification-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.identification-row :global(> *:first-child) {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
</style>
|
@ -1,22 +0,0 @@
|
|||||||
<Meta title="ShipEdit/Identification" component={Identification} argTypes={{}} />
|
|
||||||
|
|
||||||
<Story name="Primary" args={{}} />
|
|
||||||
|
|
||||||
<Template let:args>
|
|
||||||
<div style="width: 50em">
|
|
||||||
<Identification {...args} />
|
|
||||||
</div>
|
|
||||||
</Template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { Meta, Template, Story } from "@storybook/addon-svelte-csf";
|
|
||||||
import { action } from "@storybook/addon-actions";
|
|
||||||
|
|
||||||
import { setContext } from "svelte";
|
|
||||||
|
|
||||||
import Identification from "./index.svelte";
|
|
||||||
|
|
||||||
setContext("ship", {
|
|
||||||
dispatch: (type, detail) => action(type)(detail),
|
|
||||||
});
|
|
||||||
</script>
|
|
@ -22,18 +22,20 @@
|
|||||||
<script>
|
<script>
|
||||||
import { base } from "$app/paths";
|
import { base } from "$app/paths";
|
||||||
import { getContext } from "svelte";
|
import { getContext } from "svelte";
|
||||||
import Field from "$lib/components/Field/index.svelte";
|
import Field from "$lib/components/Field.svelte";
|
||||||
|
|
||||||
export let ship = getContext("ship");
|
export let api = getContext("api");
|
||||||
|
|
||||||
export let mass = 10;
|
export let mass = 10;
|
||||||
export let cost = 10;
|
export let cost = 10;
|
||||||
export let usedMass = 5;
|
export let usedMass = 10;
|
||||||
|
|
||||||
$: massUnused = mass - usedMass;
|
$: massUnused = mass - usedMass;
|
||||||
$: withinBudget = massUnused >= 0;
|
$: withinBudget = massUnused >= 0;
|
||||||
|
|
||||||
$: ship.dispatch(ship.actions.setShipMass(mass));
|
$: api?.dispatch?.updateIdentification?.({
|
||||||
|
reqs: { mass },
|
||||||
|
});
|
||||||
|
|
||||||
/* const change_tonnage = ({ target: { value } }) => */
|
/* const change_tonnage = ({ target: { value } }) => */
|
||||||
/* ship.dispatch(ship.actions.set_ship_mass(parseInt(value))); */
|
/* ship.dispatch(ship.actions.set_ship_mass(parseInt(value))); */
|
@ -1,40 +0,0 @@
|
|||||||
<div>
|
|
||||||
<Field label="ship class" bind:value={shipClass} />
|
|
||||||
<Field label="ship type">
|
|
||||||
<select bind:value={shipType}>
|
|
||||||
{#each shipTypes as name (name)}
|
|
||||||
<option>{name}</option>
|
|
||||||
{/each}
|
|
||||||
</select>
|
|
||||||
</Field>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { getContext } from "svelte";
|
|
||||||
|
|
||||||
import Field from "$lib/components/Field/index.svelte";
|
|
||||||
import { candidateShipTypes } from "./shipTypes.js";
|
|
||||||
|
|
||||||
export let shipClass = "";
|
|
||||||
export let shipType = "";
|
|
||||||
export let mass = 10;
|
|
||||||
export let isCarrier = false;
|
|
||||||
|
|
||||||
const ship = getContext("ship");
|
|
||||||
|
|
||||||
$: shipTypes = candidateShipTypes(mass, isCarrier).map(({ name }) => name);
|
|
||||||
|
|
||||||
$: if (shipTypes.length > 0 && !shipTypes.includes(shipType))
|
|
||||||
shipType = shipTypes[0];
|
|
||||||
|
|
||||||
$: ship.dispatch(ship.actions.setShipType(shipType));
|
|
||||||
$: ship.dispatch(ship.actions.setShipClass(shipClass));
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
div {
|
|
||||||
display: flex;
|
|
||||||
align-items: end;
|
|
||||||
gap: 2em;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,6 +1,6 @@
|
|||||||
<Section label="propulsion">
|
<Section label="propulsion">
|
||||||
<Drive {...propulsion.drive} />
|
<Drive {...drive} />
|
||||||
<Ftl {...propulsion.ftl} />
|
<Ftl {...ftl} />
|
||||||
</Section>
|
</Section>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
@ -8,8 +8,6 @@
|
|||||||
import Drive from "./Propulsion/Engine.svelte";
|
import Drive from "./Propulsion/Engine.svelte";
|
||||||
import Ftl from "./Propulsion/Ftl.svelte";
|
import Ftl from "./Propulsion/Ftl.svelte";
|
||||||
|
|
||||||
export let propulsion = {
|
export let drive = {};
|
||||||
drive: {},
|
export let ftl = {};
|
||||||
ftl: {},
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
@ -13,5 +13,4 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
import Engine from "./Engine.svelte";
|
import Engine from "./Engine.svelte";
|
||||||
import "$lib/components/GlobalStyle.svelte";
|
|
||||||
</script>
|
</script>
|
||||||
|
@ -25,7 +25,8 @@
|
|||||||
export let rating = 0;
|
export let rating = 0;
|
||||||
export let api = getContext("api");
|
export let api = getContext("api");
|
||||||
|
|
||||||
$: api?.dispatch?.setEngine({ rating, advanced });
|
console.log(api?.dispatch?.setDrive);
|
||||||
|
$: api?.dispatch?.setDrive?.({ rating, advanced });
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
@ -13,5 +13,4 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
import Ftl from "./Ftl.svelte";
|
import Ftl from "./Ftl.svelte";
|
||||||
import "$lib/components/GlobalStyle.svelte";
|
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<ShipItem {...reqs}>
|
<ShipItem {...reqs}>
|
||||||
<Field label="FTL drive">
|
<Field label="FTL drive">
|
||||||
{#each types as t (t)}
|
{#each ftlTypes as t (t)}
|
||||||
<label
|
<label
|
||||||
><input type="radio" bind:group={type} value={t} />
|
><input type="radio" bind:group={type} value={t} />
|
||||||
{t}
|
{t}
|
||||||
@ -15,13 +15,13 @@
|
|||||||
import ShipItem from "$lib/components/ShipItem.svelte";
|
import ShipItem from "$lib/components/ShipItem.svelte";
|
||||||
import Field from "$lib/components/Field.svelte";
|
import Field from "$lib/components/Field.svelte";
|
||||||
|
|
||||||
|
import { ftlTypes } from "$lib/store/ship/propulsion/ftl";
|
||||||
|
|
||||||
export let type = "none";
|
export let type = "none";
|
||||||
export let reqs = { mass: 0, cost: 0 };
|
export let reqs = { mass: 0, cost: 0 };
|
||||||
export let api = getContext("api");
|
export let api = getContext("api");
|
||||||
|
|
||||||
const types = ["none", "standard", "advanced"];
|
$: api?.dispatch.setFtlType?.(type);
|
||||||
|
|
||||||
$: api?.dispatch.setFtl(type);
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
10
src/lib/components/ShipEdit/Structure.svelte
Normal file
10
src/lib/components/ShipEdit/Structure.svelte
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<Section label="structure">
|
||||||
|
<Streamlining {...streamlining} />
|
||||||
|
</Section>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import Section from "$lib/components/Section.svelte";
|
||||||
|
import Streamlining from "./Structure/Streamlining.svelte";
|
||||||
|
|
||||||
|
export let streamlining = {};
|
||||||
|
</script>
|
@ -18,17 +18,17 @@
|
|||||||
</ShipItem>
|
</ShipItem>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import ShipItem from "$lib/components/ShipItem/index.svelte";
|
import ShipItem from "$lib/components/ShipItem.svelte";
|
||||||
import Field from "$lib/components/Field/index.svelte";
|
import Field from "$lib/components/Field.svelte";
|
||||||
|
|
||||||
import { getContext } from "svelte";
|
import { getContext } from "svelte";
|
||||||
|
|
||||||
export let type = "none";
|
export let type = "none";
|
||||||
export let reqs = {};
|
export let reqs = {};
|
||||||
|
|
||||||
export let {dispatch, shipMass} = getContext("ship");
|
export let api = getContext("api");
|
||||||
|
|
||||||
$: dispatch.setStreamlining({type, shipMass: $shipMass});
|
$: api?.dispatch?.setStreamlining?.(type);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { PayloadAction, createSlice } from "@reduxjs/toolkit";
|
import { createSlice } from "@reduxjs/toolkit";
|
||||||
import { reqs, Reqs } from "./reqs";
|
import { reqs, type Reqs } from "./reqs";
|
||||||
|
|
||||||
type Squadron = {
|
type Squadron = {
|
||||||
type: string;
|
type: string;
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
import { createSlice, type PayloadAction } from "@reduxjs/toolkit";
|
||||||
import { Updux } from "updux";
|
|
||||||
import u from "updeep";
|
import u from "updeep";
|
||||||
|
|
||||||
import { Reqs, reqs } from "./reqs.js";
|
import { type Reqs, reqs } from "./reqs.js";
|
||||||
|
|
||||||
const initialState = {
|
const initialState = {
|
||||||
rating: 1,
|
rating: 1,
|
||||||
|
@ -41,10 +41,4 @@ export const calculateDriveReqs = (store) =>
|
|||||||
store.dispatch.setDriveReqs(calcDriveReqs(ship_mass, rating, advanced))
|
store.dispatch.setDriveReqs(calcDriveReqs(ship_mass, rating, advanced))
|
||||||
);
|
);
|
||||||
|
|
||||||
export function calcDriveReqs(shipMass, rating, advanced = false) {
|
|
||||||
const mass = Math.ceil(rating * 0.05 * shipMass);
|
|
||||||
const cost = mass * (advanced ? 3 : 2);
|
|
||||||
|
|
||||||
return { mass, cost };
|
|
||||||
}
|
|
||||||
*/
|
*/
|
||||||
|
@ -5,14 +5,6 @@ import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
|||||||
|
|
||||||
import { reqs, Reqs } from "../reqs.js";
|
import { reqs, Reqs } from "../reqs.js";
|
||||||
|
|
||||||
export const ftlTypes = ["none", "standard", "advanced"] as const;
|
|
||||||
type FtlType = typeof ftlTypes[number];
|
|
||||||
|
|
||||||
export const initialState = {
|
|
||||||
reqs,
|
|
||||||
type: "none" as FtlType,
|
|
||||||
};
|
|
||||||
|
|
||||||
const ftl = createSlice({
|
const ftl = createSlice({
|
||||||
name: "ftl",
|
name: "ftl",
|
||||||
initialState,
|
initialState,
|
||||||
@ -26,22 +18,4 @@ const ftl = createSlice({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export function calcFtlReqs(type: FtlType, shipMass: number): Reqs {
|
|
||||||
if (type === "none") return { cost: 0, mass: 0 };
|
|
||||||
|
|
||||||
const mass = Math.ceil(shipMass / 10);
|
|
||||||
|
|
||||||
return {
|
|
||||||
mass,
|
|
||||||
cost: mass * (type === "advanced" ? 3 : 2),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export const { actions, reducer } = ftl;
|
export const { actions, reducer } = ftl;
|
||||||
|
|
||||||
// needs to be at the top level
|
|
||||||
export const ftlReqsReaction = (store) =>
|
|
||||||
createSelector(
|
|
||||||
[(ship) => ship.propulsion.ftl.type, (ship) => ship.reqs.mass],
|
|
||||||
(type, shipMass) => store.dispatch.setFtlReqs(calcFtlReqs(type, shipMass))
|
|
||||||
);
|
|
||||||
|
9
src/lib/store/api.ts
Normal file
9
src/lib/store/api.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import ship from "./ship";
|
||||||
|
|
||||||
|
export type Api = ReturnType<typeof ship.createStore>;
|
||||||
|
|
||||||
|
export const createApi = () => {
|
||||||
|
const api = ship.createStore();
|
||||||
|
console.log(api);
|
||||||
|
return api;
|
||||||
|
};
|
32
src/lib/store/ship.test.ts
Normal file
32
src/lib/store/ship.test.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import { test, expect } from "vitest";
|
||||||
|
import ship from "./ship";
|
||||||
|
|
||||||
|
test("kicking the tires", () => {
|
||||||
|
const store = ship.createStore();
|
||||||
|
console.log(store.getState());
|
||||||
|
console.log(store.getState.getStreamlining());
|
||||||
|
store.dispatch.setFtlType("standard");
|
||||||
|
|
||||||
|
expect(store.getState().propulsion.ftl.reqs.mass).toEqual(1);
|
||||||
|
expect(store.getState().identification.reqs.usedMass).toEqual(1);
|
||||||
|
|
||||||
|
store.dispatch.setDrive({ rating: 3, advanced: true });
|
||||||
|
|
||||||
|
expect(store.getState().propulsion.drive.reqs).toEqual({ mass: 2, cost: 6 });
|
||||||
|
|
||||||
|
store.dispatch.setNbrCarrierBays(1);
|
||||||
|
expect(store.getState().carrier.nbrBays).toEqual(1);
|
||||||
|
store.dispatch.setNbrCarrierBays(2);
|
||||||
|
expect(store.getState().carrier.nbrBays).toEqual(2);
|
||||||
|
|
||||||
|
store.dispatch.setSquadronType(2, "fast");
|
||||||
|
|
||||||
|
expect(store.getState().carrier.squadrons[1]).toHaveProperty("type", "fast");
|
||||||
|
|
||||||
|
expect(store.getState.isCarrier()).toBe(true);
|
||||||
|
|
||||||
|
store.dispatch.setStreamlining("partial");
|
||||||
|
|
||||||
|
expect(store.getState.getStreamlining()).toBe("partial");
|
||||||
|
expect(store.selectors.getStreamlining(store.getState())).toBe("partial");
|
||||||
|
});
|
84
src/lib/store/ship.ts
Normal file
84
src/lib/store/ship.ts
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
import { createSelector } from "@reduxjs/toolkit";
|
||||||
|
import Updux from "updux";
|
||||||
|
import * as R from "remeda";
|
||||||
|
|
||||||
|
import identification from "./ship/identification";
|
||||||
|
import ftl, { calcFtlReqs } from "./ship/propulsion/ftl";
|
||||||
|
import drive from "./ship/propulsion/drive";
|
||||||
|
import { calcDriveReqs } from "$lib/shipDux/engine";
|
||||||
|
import { carrierDux } from "./ship/carrier";
|
||||||
|
import { streamliningDux as streamlining } from "./ship/structure/streamlining";
|
||||||
|
import { calcStreamliningReqs } from "./ship/structure/rules";
|
||||||
|
|
||||||
|
const shipDux = new Updux({
|
||||||
|
subduxes: {
|
||||||
|
identification,
|
||||||
|
structure: new Updux({
|
||||||
|
initialState: {},
|
||||||
|
subduxes: {
|
||||||
|
streamlining,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
propulsion: new Updux({
|
||||||
|
initialState: {},
|
||||||
|
subduxes: {
|
||||||
|
ftl,
|
||||||
|
drive,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
carrier: carrierDux,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
shipDux.addReaction((api) =>
|
||||||
|
createSelector(
|
||||||
|
api.selectors.getFtlType,
|
||||||
|
api.selectors.getShipMass,
|
||||||
|
(type, mass) => api.dispatch.setFtlReqs(calcFtlReqs(type, mass))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
shipDux.addReaction((api) => (state) => {
|
||||||
|
let cost = 0;
|
||||||
|
let mass = 0;
|
||||||
|
|
||||||
|
let subsystems = R.values(R.omit(state, ["identification"]));
|
||||||
|
|
||||||
|
while (subsystems.length > 0) {
|
||||||
|
const subsystem = subsystems.shift();
|
||||||
|
if (typeof subsystem !== "object") continue;
|
||||||
|
|
||||||
|
if (subsystem.reqs) {
|
||||||
|
cost += subsystem.reqs.cost;
|
||||||
|
mass += subsystem.reqs.mass;
|
||||||
|
}
|
||||||
|
|
||||||
|
subsystems.push(...Object.values(subsystem));
|
||||||
|
}
|
||||||
|
|
||||||
|
api.dispatch.setShipReqs({ cost, usedMass: mass });
|
||||||
|
});
|
||||||
|
|
||||||
|
shipDux.addReaction((api) =>
|
||||||
|
createSelector(
|
||||||
|
api.selectors.getShipMass,
|
||||||
|
(state) => state.propulsion.drive.rating,
|
||||||
|
(state) => state.propulsion.drive.advanced,
|
||||||
|
(mass, rating, advanced) =>
|
||||||
|
api.dispatch.setDriveReqs(calcDriveReqs(mass, rating, advanced))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
shipDux.addReaction((api) =>
|
||||||
|
createSelector(
|
||||||
|
// (state) => state,
|
||||||
|
api.selectors.getShipMass,
|
||||||
|
api.selectors.getStreamlining,
|
||||||
|
(mass, type) => {
|
||||||
|
console.log("AH!", mass, type);
|
||||||
|
api.dispatch.setStreamliningReqs(calcStreamliningReqs(type, mass));
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
export default shipDux;
|
118
src/lib/store/ship/carrier.ts
Normal file
118
src/lib/store/ship/carrier.ts
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
import Updux, { createPayloadAction } from "updux";
|
||||||
|
import u from "@yanick/updeep-remeda";
|
||||||
|
import { reqs, type Reqs } from "$lib/shipDux/reqs";
|
||||||
|
|
||||||
|
type Squadron = {
|
||||||
|
type: string;
|
||||||
|
reqs: Reqs;
|
||||||
|
};
|
||||||
|
|
||||||
|
const initialState = {
|
||||||
|
nbrBays: 0,
|
||||||
|
squadrons: [] as Squadron[],
|
||||||
|
reqs,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const squadronTypes = [
|
||||||
|
{ type: "standard", cost: 3 },
|
||||||
|
{ type: "fast", cost: 4 },
|
||||||
|
{ type: "heavy", cost: 5 },
|
||||||
|
{ type: "interceptor", cost: 3 },
|
||||||
|
{ type: "attack", cost: 4 },
|
||||||
|
{ type: "long range", cost: 4 },
|
||||||
|
{ type: "torpedo", cost: 6 },
|
||||||
|
];
|
||||||
|
|
||||||
|
const setNbrCarrierBays = createPayloadAction<number>("setNbrCarrierBays");
|
||||||
|
const setSquadronType = createPayloadAction(
|
||||||
|
"setSquadronType",
|
||||||
|
(id: number, type: string) => ({ id, type })
|
||||||
|
);
|
||||||
|
|
||||||
|
export const carrierDux = new Updux({
|
||||||
|
initialState,
|
||||||
|
actions: { setNbrCarrierBays, setSquadronType },
|
||||||
|
});
|
||||||
|
|
||||||
|
function calcBaysReqs(bays) {
|
||||||
|
return {
|
||||||
|
mass: 9 * bays,
|
||||||
|
cost: 18 * bays,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const adjustSquadrons = (bays: number) => (squadrons) => {
|
||||||
|
if (squadrons.length === bays) return squadrons;
|
||||||
|
|
||||||
|
if (squadrons.length > bays) {
|
||||||
|
return squadrons.slice(0, bays);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
...squadrons,
|
||||||
|
...Array.from({ length: bays - squadrons.length })
|
||||||
|
.fill({
|
||||||
|
type: squadronTypes[0].type,
|
||||||
|
reqs: {
|
||||||
|
cost: 6 * squadronTypes[0].cost,
|
||||||
|
mass: 6,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.map((s, i) => ({ ...s, id: squadrons.length + i + 1 })),
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
carrierDux.addMutation(setNbrCarrierBays, (nbrBays) =>
|
||||||
|
u({
|
||||||
|
nbrBays,
|
||||||
|
reqs: calcBaysReqs(nbrBays),
|
||||||
|
squadrons: adjustSquadrons(nbrBays),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
carrierDux.addMutation(setSquadronType, ({ id, type }) => {
|
||||||
|
return u({
|
||||||
|
squadrons: u.map(
|
||||||
|
u.if(u.matches({ id }), (state) => {
|
||||||
|
return u(state, {
|
||||||
|
type,
|
||||||
|
reqs: squadronReqs(type),
|
||||||
|
});
|
||||||
|
})
|
||||||
|
),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function squadronReqs(type: string) {
|
||||||
|
return {
|
||||||
|
mass: 6,
|
||||||
|
cost: 6 * squadronTypes.find((s) => s.type === type)?.cost,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
export const { actions, reducer } = createSlice({
|
||||||
|
name: "carrier",
|
||||||
|
initialStateState,
|
||||||
|
reducers: {
|
||||||
|
setCarrierBays: (state, action: PayloadAction<number>) => {
|
||||||
|
state.bays = action.payload;
|
||||||
|
state.reqs = calcBaysReqs(action.payload);
|
||||||
|
state.squadrons = adjustSquadrons(action.payload)(state.squadrons);
|
||||||
|
},
|
||||||
|
setSquadronType: (
|
||||||
|
state,
|
||||||
|
action: PayloadAction<{ type: string; id: number }>
|
||||||
|
) => {
|
||||||
|
state.squadrons[action.payload.id - 1] = {
|
||||||
|
type: action.payload.type,
|
||||||
|
reqs: squadronReqs(action.payload.type),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
44
src/lib/store/ship/identification.ts
Normal file
44
src/lib/store/ship/identification.ts
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import Updux, { createAction, withPayload } from "updux";
|
||||||
|
import u from "@yanick/updeep-remeda";
|
||||||
|
import * as R from "remeda";
|
||||||
|
import { carrierDux } from "./carrier";
|
||||||
|
|
||||||
|
const initialState = {
|
||||||
|
shipType: "",
|
||||||
|
shipClass: "",
|
||||||
|
isCarrier: false,
|
||||||
|
reqs: {
|
||||||
|
mass: 10,
|
||||||
|
cost: 0,
|
||||||
|
usedMass: 0,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const setShipClass = createAction("setShipClass", withPayload<string>());
|
||||||
|
const updateIdentification = createAction("updateIdentification");
|
||||||
|
const setShipReqs = createAction("setShipReqs", withPayload());
|
||||||
|
|
||||||
|
export const dux = new Updux({
|
||||||
|
initialState,
|
||||||
|
actions: {
|
||||||
|
setShipClass,
|
||||||
|
updateIdentification,
|
||||||
|
setShipReqs,
|
||||||
|
},
|
||||||
|
selectors: {
|
||||||
|
getShipMass: (state) => state.reqs.mass,
|
||||||
|
isCarrier: ({ isCarrier }) => isCarrier,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
dux.addMutation(setShipClass, (shipClass) => u({ shipClass }));
|
||||||
|
dux.addMutation(updateIdentification, (update) => u(update));
|
||||||
|
dux.addMutation(setShipReqs, (reqs) => u({ reqs }));
|
||||||
|
|
||||||
|
dux.addMutation(carrierDux.actions.setNbrCarrierBays, (nbrBays) =>
|
||||||
|
u({
|
||||||
|
isCarrier: nbrBays > 0,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
export default dux;
|
38
src/lib/store/ship/propulsion/drive.ts
Normal file
38
src/lib/store/ship/propulsion/drive.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import { reqs, type Reqs } from "$lib/shipDux/reqs";
|
||||||
|
import Updux, { createPayloadAction } from "updux";
|
||||||
|
import u from "@yanick/updeep-remeda";
|
||||||
|
|
||||||
|
type DriveProps = {
|
||||||
|
rating: number;
|
||||||
|
advanced: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
const initialState: DriveProps & { reqs: Reqs } = {
|
||||||
|
rating: 0,
|
||||||
|
advanced: false,
|
||||||
|
reqs,
|
||||||
|
};
|
||||||
|
|
||||||
|
const setDrive = createPayloadAction<DriveProps>("setDrive");
|
||||||
|
const setDriveReqs = createPayloadAction<Reqs>("setDriveReqs");
|
||||||
|
|
||||||
|
const dux = new Updux({
|
||||||
|
initialState,
|
||||||
|
actions: { setDrive, setDriveReqs },
|
||||||
|
});
|
||||||
|
|
||||||
|
export default dux;
|
||||||
|
|
||||||
|
dux.addMutation(setDrive, (change) => u(change));
|
||||||
|
dux.addMutation(setDriveReqs, (reqs) => u({ reqs }));
|
||||||
|
|
||||||
|
export function calcDriveReqs(
|
||||||
|
shipMass: number,
|
||||||
|
rating: number,
|
||||||
|
advanced = false
|
||||||
|
) {
|
||||||
|
const mass = Math.ceil(rating * 0.05 * shipMass);
|
||||||
|
const cost = mass * (advanced ? 3 : 2);
|
||||||
|
|
||||||
|
return { mass, cost };
|
||||||
|
}
|
40
src/lib/store/ship/propulsion/ftl.ts
Normal file
40
src/lib/store/ship/propulsion/ftl.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import { reqs, type Reqs } from "$lib/shipDux/reqs";
|
||||||
|
import Updux, { createAction, withPayload } from "updux";
|
||||||
|
import u from "@yanick/updeep-remeda";
|
||||||
|
import * as R from "remeda";
|
||||||
|
|
||||||
|
export const ftlTypes = ["none", "standard", "advanced"] as const;
|
||||||
|
|
||||||
|
type FtlType = typeof ftlTypes[number];
|
||||||
|
|
||||||
|
export const initialState = {
|
||||||
|
reqs,
|
||||||
|
type: "none" as FtlType,
|
||||||
|
};
|
||||||
|
|
||||||
|
const setFtlType = createAction("setFtlType", withPayload<FtlType>());
|
||||||
|
const setFtlReqs = createAction("setFtlReqs", withPayload<Reqs>());
|
||||||
|
|
||||||
|
const dux = new Updux({
|
||||||
|
initialState,
|
||||||
|
actions: { setFtlType, setFtlReqs },
|
||||||
|
selectors: {
|
||||||
|
getFtlType: R.prop<any, any>("type"),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
dux.addMutation(setFtlType, (type) => u({ type }));
|
||||||
|
dux.addMutation(setFtlReqs, (reqs) => u({ reqs }));
|
||||||
|
|
||||||
|
export default dux;
|
||||||
|
|
||||||
|
export function calcFtlReqs(type: FtlType, shipMass: number): Reqs {
|
||||||
|
if (type === "none") return { cost: 0, mass: 0 };
|
||||||
|
|
||||||
|
const mass = Math.ceil(shipMass / 10);
|
||||||
|
|
||||||
|
return {
|
||||||
|
mass,
|
||||||
|
cost: mass * (type === "advanced" ? 3 : 2),
|
||||||
|
};
|
||||||
|
}
|
9
src/lib/store/ship/structure/rules.ts
Normal file
9
src/lib/store/ship/structure/rules.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
export type Streamlining = "none" | "partial" | "full";
|
||||||
|
|
||||||
|
export function calcStreamliningReqs(type: Streamlining, shipMass: number) {
|
||||||
|
const mass = Math.ceil(
|
||||||
|
(shipMass * (type === "none" ? 0 : type === "partial" ? 5 : 10)) / 100
|
||||||
|
);
|
||||||
|
|
||||||
|
return { mass, cost: 2 * mass };
|
||||||
|
}
|
26
src/lib/store/ship/structure/streamlining.ts
Normal file
26
src/lib/store/ship/structure/streamlining.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import { reqs } from "$lib/shipDux/reqs";
|
||||||
|
import Updux, { createPayloadAction } from "updux";
|
||||||
|
import type { Streamlining } from "./rules";
|
||||||
|
import u from "@yanick/updeep-remeda";
|
||||||
|
|
||||||
|
const initialState = {
|
||||||
|
type: "none" as Streamlining,
|
||||||
|
reqs,
|
||||||
|
};
|
||||||
|
|
||||||
|
const setStreamlining = createPayloadAction<Streamlining>("setStreamlining");
|
||||||
|
const setStreamliningReqs = createPayloadAction("setStreamliningReqs");
|
||||||
|
|
||||||
|
export const streamliningDux = new Updux({
|
||||||
|
initialState,
|
||||||
|
actions: { setStreamlining, setStreamliningReqs },
|
||||||
|
selectors: {
|
||||||
|
getStreamlining: (state) => {
|
||||||
|
return state?.type;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
streamliningDux.addMutation(setStreamlining, (type) => u({ type }));
|
||||||
|
|
||||||
|
streamliningDux.addMutation(setStreamliningReqs, (reqs) => u({ reqs }));
|
@ -1,4 +1,26 @@
|
|||||||
:root {
|
@font-face {
|
||||||
|
font-family: "Faktos";
|
||||||
|
font-style: normal;
|
||||||
|
src: url(/fonts/Faktos.ttf) format("truetype");
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: "Dosis";
|
||||||
|
src: url(/fonts/dosis/Dosis-VariableFont_wght.ttf) format("truetype");
|
||||||
|
}
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--main-font-family: "Dosis", -apple-system, BlinkMacSystemFont, "Segoe UI",
|
||||||
|
Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
|
||||||
|
--font-family: "Dosis", -apple-system, BlinkMacSystemFont, "Segoe UI",
|
||||||
|
Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
|
||||||
|
|
||||||
|
--font-scale-9: 0.75rem;
|
||||||
|
--font-scale-10: 1em;
|
||||||
|
--font-scale-11: 1.333rem;
|
||||||
|
--font-scale-12: 1.777rem;
|
||||||
|
--font-scale-13: 2.369rem;
|
||||||
|
--font-scale-14: 3.157rem;
|
||||||
|
--font-scale-15: 4.209rem;
|
||||||
|
|
||||||
--oxford-blue: hsla(226, 60%, 10%, 1);
|
--oxford-blue: hsla(226, 60%, 10%, 1);
|
||||||
--royal-blue-dark: hsla(218, 100%, 16%, 1);
|
--royal-blue-dark: hsla(218, 100%, 16%, 1);
|
||||||
@ -7,54 +29,60 @@
|
|||||||
--white: hsla(20, 60%, 99%, 1);
|
--white: hsla(20, 60%, 99%, 1);
|
||||||
|
|
||||||
--main-width: 60em;
|
--main-width: 60em;
|
||||||
}
|
}
|
||||||
|
|
||||||
small {font-size: var(--font-scale-9); }
|
input.short {
|
||||||
|
width: 5em !important;
|
||||||
|
}
|
||||||
|
|
||||||
h1 {
|
small {
|
||||||
|
font-size: var(--font-scale-9);
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
font-size: var(--font-scale-14);
|
font-size: var(--font-scale-14);
|
||||||
}
|
}
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
font-size: var(--font-scale-12);
|
font-size: var(--font-scale-12);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
html, body {
|
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
background-color: var(--white);
|
background-color: var(--white);
|
||||||
color: #333;
|
color: #333;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
font-family: "Dosis", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
|
font-family: "Dosis", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
|
||||||
}
|
Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
color: rgb(0,100,200);
|
color: rgb(0, 100, 200);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
a:hover {
|
a:hover {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
a:visited {
|
a:visited {
|
||||||
color: rgb(0,80,160);
|
color: rgb(0, 80, 160);
|
||||||
}
|
}
|
||||||
|
|
||||||
label {
|
label {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
input, button, select, textarea {
|
input,
|
||||||
|
button,
|
||||||
|
select,
|
||||||
|
textarea {
|
||||||
font-family: inherit;
|
font-family: inherit;
|
||||||
font-size: inherit;
|
font-size: inherit;
|
||||||
padding: 0.4em;
|
padding: 0.4em;
|
||||||
@ -62,28 +90,34 @@ input, button, select, textarea {
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
border: 1px solid #ccc;
|
border: 1px solid #ccc;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
input:disabled {
|
input:disabled {
|
||||||
color: #ccc;
|
color: #ccc;
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type="range"] {
|
input[type="range"] {
|
||||||
height: 0;
|
height: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---- inputs --- */
|
/* input, */
|
||||||
|
/* select { */
|
||||||
|
/* border: 0px; */
|
||||||
|
/* border-bottom: 1px solid var(--indigo-dye); */
|
||||||
|
/* } */
|
||||||
|
|
||||||
input, select {
|
input:focus,
|
||||||
|
select:focus {
|
||||||
|
border: 1px solid var(--indigo-dye);
|
||||||
|
}
|
||||||
|
|
||||||
|
input:not([type="checkbox"]):not([type="radio"]) {
|
||||||
border: 0px;
|
border: 0px;
|
||||||
border-bottom: 1px solid var(--indigo-dye);
|
border-bottom: 1px solid var(--indigo-dye);
|
||||||
}
|
border-radius: 0px;
|
||||||
|
height: calc(
|
||||||
input:focus, select:focus {
|
1rem * var(--line-height) + var(--form-element-spacing-vertical) * 1
|
||||||
border: 1px solid var(--indigo-dye);;
|
);
|
||||||
}
|
padding: 0 0.5rem;
|
||||||
|
text-align: center;
|
||||||
input.short {
|
}
|
||||||
width:5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
import { extractFromSvelteConfig } from "vitest-svelte-kit";
|
import { mergeConfig } from "vite";
|
||||||
|
import { defineConfig } from "vitest/config";
|
||||||
|
import viteConfig from "./vite.config.js";
|
||||||
|
|
||||||
export default extractFromSvelteConfig().then((config) => ({
|
export default mergeConfig(
|
||||||
...config,
|
viteConfig,
|
||||||
|
defineConfig({
|
||||||
test: {
|
test: {
|
||||||
globals: true,
|
globals: true,
|
||||||
environment: "jsdom",
|
environment: "jsdom",
|
||||||
},
|
},
|
||||||
}));
|
})
|
||||||
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user