Merge branch 'move-to-beer'
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 41 KiB |
Before Width: | Height: | Size: 125 KiB After Width: | Height: | Size: 132 KiB |
Before Width: | Height: | Size: 70 KiB After Width: | Height: | Size: 71 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 25 KiB |
@ -1,22 +1,35 @@
|
|||||||
<div class="field">
|
<div class="field label small" class:suffix>
|
||||||
{#if label}
|
|
||||||
<label>{label}</label>
|
|
||||||
{/if}
|
|
||||||
<slot>
|
<slot>
|
||||||
<input type="text" {placeholder} bind:value on:change />
|
<input id={formId} type="text" bind:value on:change />
|
||||||
</slot>
|
</slot>
|
||||||
|
{#if label}
|
||||||
|
<label for={formId} class:active>{label}</label>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { getContext } from "svelte";
|
||||||
|
|
||||||
export let label = "";
|
export let label = "";
|
||||||
export let value = "";
|
export let value = true;
|
||||||
export let placeholder = label;
|
export let placeholder = label;
|
||||||
|
|
||||||
|
export let suffix = false;
|
||||||
|
export let activeLabel = undefined;
|
||||||
|
export let idPrefix = "formId";
|
||||||
|
|
||||||
|
$: active = typeof activeLabel === "boolean" ? activeLabel : value;
|
||||||
|
|
||||||
|
const genUid = getContext("genUid") ?? (() => "genUid missing");
|
||||||
|
|
||||||
|
const formId = genUid(idPrefix);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
div {
|
div {
|
||||||
font-family: var(--main-font-family);
|
font-family: var(--main-font-family);
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
div > :global(*) {
|
div > :global(*) {
|
||||||
margin-left: 1em;
|
margin-left: 1em;
|
||||||
}
|
}
|
||||||
@ -29,4 +42,8 @@
|
|||||||
font-family: Dosis;
|
font-family: Dosis;
|
||||||
color: var(--indigo-dye);
|
color: var(--indigo-dye);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
.field {
|
||||||
|
margin-bottom: 0px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -15,9 +15,12 @@
|
|||||||
grid-column: 1 / span 3 !important;
|
grid-column: 1 / span 3 !important;
|
||||||
align-items: baseline;
|
align-items: baseline;
|
||||||
gap: 1em;
|
gap: 1em;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
background-color: var(--primary-background);
|
||||||
}
|
}
|
||||||
h2 {
|
h2 {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
font-size: var(--font-scale-12);
|
||||||
}
|
}
|
||||||
hr {
|
hr {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
<main>
|
<Identification {...identification} />
|
||||||
<Identification {...identification} />
|
<Propulsion {...propulsion} />
|
||||||
<Propulsion {...propulsion} />
|
<Structure {...structure} />
|
||||||
<Structure {...structure} />
|
<Weaponry {...weaponry} />
|
||||||
<Weaponry {...weaponry} />
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Identification from "./ShipEdit/Identification.svelte";
|
import Identification from "./ShipEdit/Identification.svelte";
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
<div class="identification-row">
|
<div class="identification-row">
|
||||||
<div>
|
<div>
|
||||||
<Field label="ship class" bind:value={shipClass} />
|
<Field label="ship class" bind:value={shipClass} />
|
||||||
<Field label="ship type">
|
<Field suffix>
|
||||||
<select bind:value={shipType}>
|
<select bind:value={shipType}>
|
||||||
{#each shipTypes as name (name)}
|
{#each shipTypes as name (name)}
|
||||||
<option>{name}</option>
|
<option>{name}</option>
|
||||||
{/each}
|
{/each}
|
||||||
</select>
|
</select>
|
||||||
|
<label class="active">ship type</label>
|
||||||
|
<i>arrow_drop_down</i>
|
||||||
</Field>
|
</Field>
|
||||||
</div>
|
</div>
|
||||||
<ShipCost {...reqs} />
|
<ShipCost {...reqs} />
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<div class="mass">
|
<div class="mass">
|
||||||
<Field label="ship tonnage">
|
<Field label="ship tonnage" suffix>
|
||||||
<input class="short" bind:value={mass} type="number" min="10" max="300" />
|
<input bind:value={mass} type="number" min="10" max="300" />
|
||||||
<img class="mass_symbol" src="{base}/mass.svg" alt="mass" />
|
<i>Weight</i>
|
||||||
|
|
||||||
<div class="note" class:warning={!withinBudget}>
|
<div class="note" class:warning={!withinBudget}>
|
||||||
{#if withinBudget}
|
{#if withinBudget}
|
||||||
@ -14,8 +14,9 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="cost">
|
<div class="cost">
|
||||||
<Field label="cost">
|
<Field label="total cost" suffix>
|
||||||
<span class="cost">{cost}</span>
|
<input value={cost} disabled />
|
||||||
|
<i>Paid</i>
|
||||||
</Field>
|
</Field>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -54,10 +55,6 @@
|
|||||||
grid-column: span 3;
|
grid-column: span 3;
|
||||||
justify-content: space-around;
|
justify-content: space-around;
|
||||||
}
|
}
|
||||||
input {
|
|
||||||
width: 5em;
|
|
||||||
display: inline !important;
|
|
||||||
}
|
|
||||||
.mass_symbol {
|
.mass_symbol {
|
||||||
width: 0.75em;
|
width: 0.75em;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
@ -82,8 +79,7 @@
|
|||||||
div.cost {
|
div.cost {
|
||||||
grid-column: 3;
|
grid-column: 3;
|
||||||
}
|
}
|
||||||
span.cost:after {
|
i {
|
||||||
content: "\00A4";
|
top: 65%;
|
||||||
margin-left: 0.5em;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<Field label="thrust rating">
|
<Field label="thrust rating">
|
||||||
<input
|
<input
|
||||||
class="short"
|
class="engine"
|
||||||
type="number"
|
type="number"
|
||||||
bind:value={rating}
|
bind:value={rating}
|
||||||
min="0"
|
min="0"
|
||||||
@ -11,7 +11,10 @@
|
|||||||
/>
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
|
|
||||||
<label><input type="checkbox" bind:checked={advanced} /> advanced</label>
|
<label class="checkbox">
|
||||||
|
<input type="checkbox" bind:checked={advanced} />
|
||||||
|
<span>advanced</span>
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</ShipItem>
|
</ShipItem>
|
||||||
|
|
||||||
@ -29,28 +32,14 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
input.engine {
|
||||||
|
width: 9em;
|
||||||
|
}
|
||||||
div {
|
div {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: end;
|
align-items: end;
|
||||||
}
|
}
|
||||||
label {
|
label {
|
||||||
font-family: var(--main-font-family);
|
|
||||||
margin-left: 2em;
|
margin-left: 2em;
|
||||||
}
|
}
|
||||||
input[type="number"] {
|
|
||||||
width: 5em;
|
|
||||||
}
|
|
||||||
input {
|
|
||||||
margin-bottom: 0px !important;
|
|
||||||
}
|
|
||||||
input:not([type="checkbox"]) {
|
|
||||||
border: 0px;
|
|
||||||
border-bottom: 1px solid var(--indigo-dye);
|
|
||||||
border-radius: 0px;
|
|
||||||
height: calc(
|
|
||||||
1rem * var(--line-height) + var(--form-element-spacing-vertical) * 1
|
|
||||||
);
|
|
||||||
padding: 0 0.5rem;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
<ShipItem {...reqs}>
|
<ShipItem {...reqs}>
|
||||||
<Field label="FTL drive">
|
<div>FTL drive</div>
|
||||||
|
<nav>
|
||||||
{#each ftlTypes 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}
|
<span>{t}</span>
|
||||||
</label>
|
</label>
|
||||||
{/each}
|
{/each}
|
||||||
</Field>
|
</nav>
|
||||||
</ShipItem>
|
</ShipItem>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
@ -33,5 +33,6 @@
|
|||||||
div {
|
div {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 2em;
|
gap: 2em;
|
||||||
|
align-items: baseline;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -1,20 +1,19 @@
|
|||||||
<ShipItem {...reqs}>
|
<ShipItem {...reqs}>
|
||||||
<Field label="streamlining">
|
<div>streamlining</div>
|
||||||
<div>
|
<div class="field middle-align">
|
||||||
<label>
|
<label class="radio">
|
||||||
<input type="radio" bind:group={type} value="none" />
|
<input type="radio" bind:group={type} value="none" />
|
||||||
none</label
|
<span>none</span></label
|
||||||
>
|
>
|
||||||
<label>
|
<label class="radio">
|
||||||
<input type="radio" bind:group={type} value="partial" />
|
<input type="radio" bind:group={type} value="partial" />
|
||||||
partial</label
|
<span>partial</span></label
|
||||||
>
|
>
|
||||||
<label>
|
<label class="radio">
|
||||||
<input type="radio" bind:group={type} value="full" />
|
<input type="radio" bind:group={type} value="full" />
|
||||||
full</label
|
<span>full</span></label
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
</Field>
|
|
||||||
</ShipItem>
|
</ShipItem>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@ -36,6 +35,6 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
label {
|
label {
|
||||||
margin-left: 1em;
|
margin-left: 2em !important;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
<div>
|
<div>
|
||||||
<Field label="">
|
<button class="button small primary" on:click={addWeapon}>add weapon</button>
|
||||||
|
<Field label="" suffix>
|
||||||
<select bind:value={type}>
|
<select bind:value={type}>
|
||||||
{#each weaponTypes as weapon (weapon.type)}
|
{#each weaponTypes as weapon (weapon.type)}
|
||||||
<option value={weapon.type}>{weapon.name}</option>
|
<option value={weapon.type}>{weapon.name}</option>
|
||||||
{/each}
|
{/each}
|
||||||
</select>
|
</select>
|
||||||
|
<i>arrow_drop_down</i>
|
||||||
</Field>
|
</Field>
|
||||||
<button class="button small primary" on:click={addWeapon}>add weapon</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@ -30,6 +31,7 @@
|
|||||||
button {
|
button {
|
||||||
width: inherit;
|
width: inherit;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
margin-right: 2em;
|
||||||
}
|
}
|
||||||
div :global(.field) {
|
div :global(.field) {
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -37,7 +39,8 @@
|
|||||||
}
|
}
|
||||||
div {
|
div {
|
||||||
display: flex;
|
display: flex;
|
||||||
margin-left: 5em;
|
margin-left: 0em;
|
||||||
margin-bottom: 2em;
|
margin-bottom: 2em;
|
||||||
|
align-items: baseline;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -1,20 +1,22 @@
|
|||||||
<label>beam</label>
|
<span>beam</span>
|
||||||
|
|
||||||
<Field label="beam class">
|
<Field label="beam class" suffix>
|
||||||
<select bind:value={weaponClass}>
|
<select bind:value={weaponClass}>
|
||||||
<option value={1}>1</option>
|
<option value={1}>1</option>
|
||||||
<option value={2}>2</option>
|
<option value={2}>2</option>
|
||||||
<option value={3}>3</option>
|
<option value={3}>3</option>
|
||||||
<option value={4}>4</option>
|
<option value={4}>4</option>
|
||||||
</select>
|
</select>
|
||||||
|
<i>arrow_drop_down</i>
|
||||||
</Field>
|
</Field>
|
||||||
|
|
||||||
<Field label="arcs">
|
<Field label="arcs" suffix>
|
||||||
<select bind:value={nbrArcs}>
|
<select bind:value={nbrArcs}>
|
||||||
{#each arc_options[weaponClass] || [] as nbrArcs (nbrArcs)}
|
{#each arc_options[weaponClass] || [] as nbrArcs (nbrArcs)}
|
||||||
<option>{nbrArcs}</option>
|
<option>{nbrArcs}</option>
|
||||||
{/each}
|
{/each}
|
||||||
</select>
|
</select>
|
||||||
|
<i>arrow_drop_down</i>
|
||||||
</Field>
|
</Field>
|
||||||
|
|
||||||
<Arcs selected={arcs} on:clickArc={({ detail }) => setArcs(detail)} />
|
<Arcs selected={arcs} on:clickArc={({ detail }) => setArcs(detail)} />
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<ShipItem {...reqs}>
|
<ShipItem {...reqs}>
|
||||||
<div class="weapon_row">
|
<div class="weapon_row">
|
||||||
<button class="button small red remove" on:click={remove}>remove </button>
|
<a on:click={remove}><i>Delete</i> </a>
|
||||||
|
|
||||||
<svelte:component this={component[type]} {...specs} on:change={update} />
|
<svelte:component this={component[type]} {...specs} on:change={update} />
|
||||||
</div>
|
</div>
|
||||||
|
@ -3,9 +3,12 @@
|
|||||||
|
|
||||||
<div class="reqs">
|
<div class="reqs">
|
||||||
<div class="mass" bind:this={mass_el}>
|
<div class="mass" bind:this={mass_el}>
|
||||||
{mass} <img src="{base}/mass.svg" alt="mass" />
|
{mass} <i>Weight</i>
|
||||||
|
</div>
|
||||||
|
<div class="cost" bind:this={cost_el}>
|
||||||
|
{cost}
|
||||||
|
<i>Paid</i>
|
||||||
</div>
|
</div>
|
||||||
<div class="cost" bind:this={cost_el}>{cost}</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -53,10 +56,6 @@
|
|||||||
img {
|
img {
|
||||||
width: 0.75em;
|
width: 0.75em;
|
||||||
}
|
}
|
||||||
.cost:after {
|
|
||||||
content: "\00A4";
|
|
||||||
margin-left: 0.5em;
|
|
||||||
}
|
|
||||||
.mass img {
|
.mass img {
|
||||||
width: 0.75em;
|
width: 0.75em;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 41 KiB |
Before Width: | Height: | Size: 125 KiB After Width: | Height: | Size: 132 KiB |
Before Width: | Height: | Size: 70 KiB After Width: | Height: | Size: 71 KiB |
17
src/lib/store/uids.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import { writable, get } from "svelte/store";
|
||||||
|
|
||||||
|
export default () => {
|
||||||
|
const store = writable(0);
|
||||||
|
|
||||||
|
const genUid = (prefix = "") => {
|
||||||
|
store.update((x) => x + 1);
|
||||||
|
return prefix.length
|
||||||
|
? [prefix, "" + get(store)].join("-")
|
||||||
|
: "" + get(store);
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
store,
|
||||||
|
genUid,
|
||||||
|
};
|
||||||
|
};
|
8
src/lib/store/uids.test.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import uids from "./uids";
|
||||||
|
|
||||||
|
test("basic", () => {
|
||||||
|
const { genUid } = uids();
|
||||||
|
|
||||||
|
expect(genUid()).toEqual("1");
|
||||||
|
expect(genUid("potato")).toEqual("potato-2");
|
||||||
|
});
|
@ -62,52 +62,6 @@ input.short {
|
|||||||
color: rgb(0, 80, 160);
|
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
input:not([type="checkbox"]):not([type="radio"]) {
|
|
||||||
border: 0px;
|
|
||||||
border-bottom: 1px solid var(--indigo-dye);
|
|
||||||
border-radius: 0px;
|
|
||||||
height: calc(
|
|
||||||
1rem * var(--line-height) + var(--form-element-spacing-vertical) * 1
|
|
||||||
);
|
|
||||||
padding: 0 0.5rem;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 { font-size: var(--font-scale-15); }
|
h1 { font-size: var(--font-scale-15); }
|
||||||
h2 { font-size: var(--font-scale-14); }
|
h2 { font-size: var(--font-scale-14); }
|
||||||
|
@ -5,8 +5,10 @@
|
|||||||
<script>
|
<script>
|
||||||
import { setContext } from "svelte";
|
import { setContext } from "svelte";
|
||||||
|
|
||||||
import { createApi } from "$lib/store/api.ts";
|
import { createApi } from "$lib/store/api.js";
|
||||||
|
import uids from "$lib/store/uids.js";
|
||||||
import Layout from "$lib/components/MainLayout.svelte";
|
import Layout from "$lib/components/MainLayout.svelte";
|
||||||
|
|
||||||
setContext("api", createApi());
|
setContext("api", createApi());
|
||||||
|
setContext("genUid", uids());
|
||||||
</script>
|
</script>
|
||||||
|
@ -17,9 +17,9 @@ test("we can pass a store", async () => {
|
|||||||
|
|
||||||
api.dispatch.updateIdentification({ shipClass: "Bonobo" });
|
api.dispatch.updateIdentification({ shipClass: "Bonobo" });
|
||||||
|
|
||||||
const { getByPlaceholderText } = render(Page, { context });
|
const { getByLabelText } = render(Page, { context });
|
||||||
|
|
||||||
const classInput = getByPlaceholderText("ship class");
|
const classInput = getByLabelText("ship class");
|
||||||
await fireEvent.input(classInput, { target: { value: "Tarzan" } });
|
await fireEvent.input(classInput, { target: { value: "Tarzan" } });
|
||||||
expect(classInput.value).toEqual("Tarzan");
|
expect(classInput.value).toEqual("Tarzan");
|
||||||
|
|
||||||
|