diff --git a/histoire.config.js b/histoire.config.js index 565928e..918b0dc 100644 --- a/histoire.config.js +++ b/histoire.config.js @@ -9,5 +9,5 @@ export default defineConfig({ // Options here }), ], - // setupFile: "./src/histoire.setup.js", + setupFile: "./src/histoire.setup.js", }); diff --git a/package.json b/package.json index 6def57e..7c8c6b4 100644 --- a/package.json +++ b/package.json @@ -26,31 +26,31 @@ "globby": "^13.1.3", "jest-image-snapshot": "^4.5.1", "pixelmatch": "^5.3.0", - "prettier": "~2.5.1", - "prettier-plugin-svelte": "^2.6.0", + "prettier": "~2.8.6", + "prettier-plugin-svelte": "^2.10.0", "showdown": "^2.0.3", - "svelte": "^3.55.1", - "typescript": "^4.9.5", - "vitest": "^0.29.7", - "vitest-svelte-kit": "^0.0.6" + "svelte": "^3.57.0", + "typescript": "^5.0.2", + "vitest": "^0.29.7" }, "dependencies": { "@picocss/pico": "^1.5.7", "@reduxjs/toolkit": "^1.9.3", "@sveltejs/adapter-node": "^1.0.0-next.0", - "@yanick/updeep-remeda": "^2.1.0", + "@yanick/updeep-remeda": "^2.1.1", "chota": "^0.8.0", "effector": "^22.5.2", "histoire": "^0.15.9", + "jsdom": "^21.1.1", "lodash": "^4.17.21", "redux": "^4.1.2", - "remeda": "^1.1.0", + "remeda": "^1.9.1", "reselect": "^4.1.5", "svelte-chota": "^1.8.6", "svelte-knobby": "^0.3.4", "svelte-moveable": "^0.20.0", "ts-action": "^11.0.0", - "vite": "^4.1.4" + "vite": "^4.2.1" }, "prettier": { "svelteSortOrder": "options-markup-scripts-styles", diff --git a/src/lib/store/ship.test.ts b/src/lib/store/ship.test.ts index 634dd6e..3c0ebbe 100644 --- a/src/lib/store/ship.test.ts +++ b/src/lib/store/ship.test.ts @@ -11,4 +11,13 @@ test("misc", () => { 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"); }); diff --git a/src/lib/store/ship.ts b/src/lib/store/ship.ts index 5c91c60..0b01497 100644 --- a/src/lib/store/ship.ts +++ b/src/lib/store/ship.ts @@ -6,6 +6,7 @@ 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"; const shipDux = new Updux({ subduxes: { @@ -17,6 +18,7 @@ const shipDux = new Updux({ drive, }, }), + carrier: carrierDux, }, }); diff --git a/src/lib/store/ship/carrier.ts b/src/lib/store/ship/carrier.ts new file mode 100644 index 0000000..7dfcfcd --- /dev/null +++ b/src/lib/store/ship/carrier.ts @@ -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 initial = { + 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("setNbrCarrierBays"); +const setSquadronType = createPayloadAction( + "setSquadronType", + (id: number, type: string) => ({ id, type }) +); + +export const carrierDux = new Updux({ + initial, + 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", + initialState, + reducers: { + setCarrierBays: (state, action: PayloadAction) => { + 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), + }; + }, + }, +}); + + + + +*/ diff --git a/static/global.css b/static/global.css index 49c533a..2d9a4fb 100644 --- a/static/global.css +++ b/static/global.css @@ -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); --royal-blue-dark: hsla(218, 100%, 16%, 1); @@ -7,83 +29,95 @@ --white: hsla(20, 60%, 99%, 1); --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; padding: 0px; font-size: var(--font-scale-14); -} + } -h2 { + h2 { font-size: var(--font-scale-12); -} + } - -html, body { - position: relative; - width: 100%; - height: 100%; -} - -body { + 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; -} + 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 { + color: rgb(0, 100, 200); + text-decoration: none; + } -a:hover { - text-decoration: underline; -} + a:hover { + text-decoration: underline; + } -a:visited { - color: rgb(0,80,160); -} + a:visited { + color: rgb(0, 80, 160); + } -label { - display: block; -} + 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, + 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:disabled { + color: #ccc; + } -input[type="range"] { - height: 0; -} + input[type="range"] { + 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-bottom: 1px solid var(--indigo-dye); -} - -input:focus, select:focus { - border: 1px solid var(--indigo-dye);; -} - -input.short { - width:5em; -} - + border-radius: 0px; + height: calc( + 1rem * var(--line-height) + var(--form-element-spacing-vertical) * 1 + ); + padding: 0 0.5rem; + text-align: center; + } diff --git a/vitest.config.js b/vitest.config.js index 78214f1..f3fa425 100644 --- a/vitest.config.js +++ b/vitest.config.js @@ -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) => ({ - ...config, - test: { - globals: true, - environment: "jsdom", - }, - })); +export default mergeConfig( + viteConfig, + defineConfig({ + test: { + globals: true, + environment: "jsdom", + }, + }) +);