upgrading sveltekit

This commit is contained in:
Yanick Champoux 2023-03-03 18:02:52 -05:00
parent b4a58694d7
commit 0c0351cbb3
20 changed files with 311 additions and 233 deletions

View File

@ -8,15 +8,11 @@
"build": "svelte-kit build", "build": "svelte-kit build",
"preview": "svelte-kit preview", "preview": "svelte-kit preview",
"lint": "prettier --check . && eslint --ignore-path .gitignore .", "lint": "prettier --check . && eslint --ignore-path .gitignore .",
"format": "prettier --write .", "format": "prettier --write ."
"storybook": "storybook-server",
"vitebook:dev": "vitebook dev",
"vitebook:build": "vitebook build",
"vitebook:preview": "vitebook preview"
}, },
"devDependencies": { "devDependencies": {
"@sveltejs/adapter-static": "^1.0.0-next.28", "@sveltejs/adapter-static": "^1.0.0-next.28",
"@sveltejs/kit": "^1.0.0-next.288", "@sveltejs/kit": "^1.10.0",
"@sveltejs/vite-plugin-svelte": "^1.0.0-next.38", "@sveltejs/vite-plugin-svelte": "^1.0.0-next.38",
"@testing-library/svelte": "^3.1.1", "@testing-library/svelte": "^3.1.1",
"@testing-library/user-event": "^13.5.0", "@testing-library/user-event": "^13.5.0",
@ -26,18 +22,13 @@
"prettier": "~2.5.1", "prettier": "~2.5.1",
"prettier-plugin-svelte": "^2.6.0", "prettier-plugin-svelte": "^2.6.0",
"showdown": "^2.0.3", "showdown": "^2.0.3",
"standard-version": "^9.3.2", "svelte": "^3.55.1",
"storybook-builder-vite": "0.1.21",
"svelte": "^3.46.4",
"typescript": "^4.9.5", "typescript": "^4.9.5",
"vitest": "^0.9.3", "vitest": "^0.9.3",
"vitest-svelte-kit": "^0.0.6" "vitest-svelte-kit": "^0.0.6"
}, },
"dependencies": { "dependencies": {
"@reduxjs/toolkit": "^1.9.3", "@reduxjs/toolkit": "^1.9.3",
"@storybook/addon-essentials": "^6.4.19",
"@storybook/addon-svelte-csf": "^1.1.0",
"@storybook/svelte": "^6.4.21",
"@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.0",
"chota": "^0.8.0", "chota": "^0.8.0",
@ -46,13 +37,11 @@
"redux": "^4.1.2", "redux": "^4.1.2",
"remeda": "^1.1.0", "remeda": "^1.1.0",
"reselect": "^4.1.5", "reselect": "^4.1.5",
"rollup-plugin-analyzer": "^4.0.0",
"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",
"updux": "link:/home/yanick/work/javascript/updux-js/", "vite": "^4.1.4"
"webpack": "5"
}, },
"prettier": { "prettier": {
"svelteSortOrder": "options-markup-scripts-styles", "svelteSortOrder": "options-markup-scripts-styles",

View File

@ -1,12 +1,12 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<link rel="icon" href="/favicon.ico" /> <link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
%svelte.head% %sveltekit.head%
</head> </head>
<body> <body>
<div id="svelte">%svelte.body%</div> <div id="svelte">%sveltekit.body%</div>
</body> </body>
</html> </html>

View File

@ -14,23 +14,22 @@
import Section from "$lib/components/Section/index.svelte"; import Section from "$lib/components/Section/index.svelte";
import Field from "$lib/components/Field/index.svelte"; import Field from "$lib/components/Field/index.svelte";
import ShipItem from "$lib/components/ShipItem/index.svelte"; import ShipItem from "$lib/components/ShipItem/index.svelte";
import { squadronTypes } from "$lib/shipDux/carrier.js"; import { squadronTypes } from "$lib/shipDux/carrier";
const types = squadronTypes.map(({ type }) => type); const types = squadronTypes.map(({ type }) => type);
export let id = 1; export let id = 1;
export let type = types[0].type; export let type = types[0].type;
export let reqs= {}; export let reqs = {};
export let { dispatch } = getContext("ship"); export let { dispatch } = getContext("ship");
$: console.log(type) $: console.log(type);
$: dispatch.setSquadronType({type, id}); $: dispatch.setSquadronType({ type, id });
</script> </script>
<style> <style>
select { select {
width: inherit; width: inherit;
} }
</style> </style>

View File

@ -1,18 +1,18 @@
<Field label="weapon type"> <Field label="weapon type">
<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>
<button class="button small primary" on:click={addWeapon} >add weapon</button> <button class="button small primary" on:click={addWeapon}>add weapon</button>
</Field> </Field>
<script> <script>
import { getContext } from "svelte"; import { getContext } from "svelte";
import Field from "../../Field/index.svelte"; import Field from "../../Field/index.svelte";
import { weaponTypes } from '$lib/shipDux/weaponry/weapons.js'; import { weaponTypes } from "$lib/shipDux/weaponry/weapons";
export let ship = getContext("ship"); export let ship = getContext("ship");
@ -22,8 +22,8 @@
</script> </script>
<style> <style>
select { select {
width: inherit; width: inherit;
display: inline-block; display: inline-block;
} }
</style> </style>

View File

@ -2,78 +2,78 @@ import { PayloadAction, createSlice } from "@reduxjs/toolkit";
import { reqs, Reqs } from "./reqs"; import { reqs, Reqs } from "./reqs";
type Squadron = { type Squadron = {
type: string; type: string;
reqs: Reqs; reqs: Reqs;
}; };
const initialState = { const initialState = {
bays: 0, bays: 0,
squadrons: [] as Squadron[], squadrons: [] as Squadron[],
reqs, reqs,
}; };
export const carrierSlice = createSlice({ export const { actions, reducer } = createSlice({
name: "carrier", name: "carrier",
initialState, initialState,
reducers: { reducers: {
setCarrierBays: (state, action: PayloadAction<number>) => { setCarrierBays: (state, action: PayloadAction<number>) => {
state.bays = action.payload; state.bays = action.payload;
state.reqs = calcBaysReqs(action.payload); state.reqs = calcBaysReqs(action.payload);
state.squadrons = adjustSquadrons(action.payload)(state.squadrons); 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),
};
},
}, },
setSquadronType: (
state,
action: PayloadAction<{ type: string; id: number }>
) => {
state.squadrons[action.payload.id - 1] = {
type: action.payload.type,
reqs: squadronReqs(action.payload.type),
};
},
},
}); });
export const squadronTypes = [ export const squadronTypes = [
{ type: "standard", cost: 3 }, { type: "standard", cost: 3 },
{ type: "fast", cost: 4 }, { type: "fast", cost: 4 },
{ type: "heavy", cost: 5 }, { type: "heavy", cost: 5 },
{ type: "interceptor", cost: 3 }, { type: "interceptor", cost: 3 },
{ type: "attack", cost: 4 }, { type: "attack", cost: 4 },
{ type: "long range", cost: 4 }, { type: "long range", cost: 4 },
{ type: "torpedo", cost: 6 }, { type: "torpedo", cost: 6 },
]; ];
function squadronReqs(type: string) { function squadronReqs(type: string) {
return { return {
mass: 6, mass: 6,
cost: 6 * squadronTypes.find((s) => s.type === type)?.cost, cost: 6 * squadronTypes.find((s) => s.type === type)?.cost,
}; };
} }
const adjustSquadrons = (bays) => (squadrons) => { const adjustSquadrons = (bays) => (squadrons) => {
if (squadrons.length > bays) { if (squadrons.length > bays) {
squadrons = squadrons.slice(0, bays); squadrons = squadrons.slice(0, bays);
} }
if (squadrons.length < bays) { if (squadrons.length < bays) {
squadrons = [ squadrons = [
...squadrons, ...squadrons,
..._.times(bays - squadrons.length, () => ({ ..._.times(bays - squadrons.length, () => ({
type: squadronTypes[0].type, type: squadronTypes[0].type,
reqs: { reqs: {
cost: 6 * squadronTypes[0].cost, cost: 6 * squadronTypes[0].cost,
mass: 6, mass: 6,
}, },
})), })),
]; ];
} }
return squadrons; return squadrons;
}; };
function calcBaysReqs(bays) { function calcBaysReqs(bays) {
return { return {
mass: 9 * bays, mass: 9 * bays,
cost: 18 * bays, cost: 18 * bays,
}; };
} }

View File

@ -0,0 +1,10 @@
import { createStore } from "./index.js";
test("basic, initial store", () => {
const store = createStore();
const state = store.getState();
expect(state).toHaveProperty("propulsion.drive.reqs.mass", 0);
expect(state).toHaveProperty("structure.cargo.space", 0);
});

View File

@ -1,3 +1,37 @@
import { combineReducers, configureStore, createSlice } from "@reduxjs/toolkit";
import R from "remeda";
import * as propulsion from "./propulsion";
import * as structure from "./structure";
import * as weaponry from "./weaponry/index.js";
import * as carrier from "./carrier";
const shipSlice = createSlice({
name: "ship",
initialState: {},
reducers: {},
extraReducers(builder) {
builder.addMatcher(
() => true,
combineReducers({
propulsion: propulsion.reducer,
structure: structure.reducer,
weaponry: weaponry.reducer,
carrier: carrier.reducer,
})
);
},
});
export function createStore() {
return configureStore({
reducer: shipSlice.reducer,
});
}
export const actions = shipSlice.actions;
/**
import * as propulsion from "./propulsion/index.js"; import * as propulsion from "./propulsion/index.js";
import * as identification from "./identification.js"; import * as identification from "./identification.js";
import { calculateDriveReqs } from "./propulsion/drive.js"; import { calculateDriveReqs } from "./propulsion/drive.js";
@ -5,7 +39,27 @@ import { ftlReqsReaction } from "./propulsion/ftl.js";
import * as structure from "./structure/index.js"; import * as structure from "./structure/index.js";
import * as carrier from "./carrier.js"; import * as carrier from "./carrier.js";
import * as weaponry from "./weaponry/index.js"; import * as weaponry from "./weaponry/index.js";
import * as shipReqs from "./shipReqs.js";
import { screensReqsReaction } from "./structure/screens.js"; import { screensReqsReaction } from "./structure/screens.js";
import { createSlice } from "@reduxjs/toolkit";
const initialState = {
propulsion: propulsion.initialState,
identification: identification.initialState,
structure: structure.initialState,
carrier: carrier.initialState,
weaponry: weaponry.initialState,
shipReqs: shipReqs.initialState,
}
const shipSlice = createSlice({
name: "ship",
),
});
const dux = new Updux({ const dux = new Updux({
subduxes: { subduxes: {
@ -39,9 +93,6 @@ dux.setMutation("resetShip", () => () => dux.initial);
dux.setMutation("resetLayout", () => resetUITransform); dux.setMutation("resetLayout", () => resetUITransform);
dux.setMutation("setShipMass", (mass) => u({ reqs: { mass } }));
dux.setMutation("setShipReqs", (reqs) => u({ reqs }));
dux.setMutation("setUITransform", ({ system, systemId, translate }) => { dux.setMutation("setUITransform", ({ system, systemId, translate }) => {
const transform = translate const transform = translate
? `translate(${translate[0]}px,${translate[1]}px)` ? `translate(${translate[0]}px,${translate[1]}px)`
@ -104,3 +155,4 @@ dux.addReaction((store) => (state) => {
}); });
export default dux; export default dux;
*/

View File

@ -2,28 +2,28 @@ import { PayloadAction, createSlice } from "@reduxjs/toolkit";
import { reqs, Reqs } from "../reqs"; import { reqs, Reqs } from "../reqs";
type DriveProps = { type DriveProps = {
rating: number; rating: number;
advanced: boolean; advanced: boolean;
}; };
const initialState: DriveProps & { reqs: Reqs } = { export const initialState: DriveProps & { reqs: Reqs } = {
rating: 0, rating: 0,
advanced: false, advanced: false,
reqs, reqs,
}; };
const driveSlice = createSlice({ const driveSlice = createSlice({
initialState, initialState,
name: "drive", name: "drive",
reducers: { reducers: {
setDrive: (state, action: PayloadAction<DriveProps>) => { setDrive: (state, action: PayloadAction<DriveProps>) => {
state.rating = action.payload.rating; state.rating = action.payload.rating;
state.advanced = action.payload.advanced; state.advanced = action.payload.advanced;
},
setDriveReqs: (state, action: PayloadAction<Reqs>) => {
state.reqs = action.payload;
},
}, },
setDriveReqs: (state, action: PayloadAction<Reqs>) => {
state.reqs = action.payload;
},
},
}); });
export const { actions, reducer } = driveSlice; export const { actions, reducer } = driveSlice;

View File

@ -8,40 +8,40 @@ import { reqs, Reqs } from "../reqs.js";
export const ftlTypes = ["none", "standard", "advanced"] as const; export const ftlTypes = ["none", "standard", "advanced"] as const;
type FtlType = typeof ftlTypes[number]; type FtlType = typeof ftlTypes[number];
const initialState = { export const initialState = {
reqs, reqs,
type: "none" as FtlType, type: "none" as FtlType,
}; };
const ftl = createSlice({ const ftl = createSlice({
name: "ftl", name: "ftl",
initialState, initialState,
reducers: { reducers: {
setFtl: (state, { payload }: PayloadAction<FtlType>) => { setFtl: (state, { payload }: PayloadAction<FtlType>) => {
state.type = payload; state.type = payload;
},
setFtlReqs: (state, action: PayloadAction<Reqs>) => {
state.reqs = action.payload;
},
}, },
setFtlReqs: (state, action: PayloadAction<Reqs>) => {
state.reqs = action.payload;
},
},
}); });
export function calcFtlReqs(type: FtlType, shipMass: number): Reqs { export function calcFtlReqs(type: FtlType, shipMass: number): Reqs {
if (type === "none") return { cost: 0, mass: 0 }; if (type === "none") return { cost: 0, mass: 0 };
const mass = Math.ceil(shipMass / 10); const mass = Math.ceil(shipMass / 10);
return { return {
mass, mass,
cost: mass * (type === "advanced" ? 3 : 2), cost: mass * (type === "advanced" ? 3 : 2),
}; };
} }
export const { actions, reducer } = ftl; export const { actions, reducer } = ftl;
// needs to be at the top level // needs to be at the top level
export const ftlReqsReaction = (store) => export const ftlReqsReaction = (store) =>
createSelector( createSelector(
[(ship) => ship.propulsion.ftl.type, (ship) => ship.reqs.mass], [(ship) => ship.propulsion.ftl.type, (ship) => ship.reqs.mass],
(type, shipMass) => store.dispatch.setFtlReqs(calcFtlReqs(type, shipMass)) (type, shipMass) => store.dispatch.setFtlReqs(calcFtlReqs(type, shipMass))
); );

View File

@ -6,3 +6,8 @@ export const reducer = combineReducers({
drive: drive.reducer, drive: drive.reducer,
ftl: ftl.reducer, ftl: ftl.reducer,
}); });
export const initialState = {
drive: drive.initialState,
ftl: ftl.initialState,
};

View File

@ -0,0 +1 @@
import

View File

@ -0,0 +1,24 @@
import { createSlice } from "@reduxjs/toolkit";
import { reqs } from "./reqs";
const initialState = {
usedMass: 0,
mass: 10,
cost: 0,
};
const shipReqs = createSlice({
name: "shipReqs",
initialState,
reducers: {
setShipMass(state, action) {
state.mass = action.payload;
},
setShipReqs(state, action) {
return {
...state,
...action.payload,
};
},
},
});

View File

@ -4,32 +4,34 @@ import { Reqs, reqs } from "../reqs";
type Layer = number; type Layer = number;
const initialState = { const initialState = {
reqs, reqs,
layers: [] as Layer[], layers: [] as Layer[],
}; };
const armor = createSlice({ const armor = createSlice({
name: "armor", name: "armor",
initialState, initialState,
reducers: { reducers: {
setArmorRating: (state, action) => { setArmorRating: (state, action) => {
state.layers[action.payload.layer - 1] = action.payload.rating; state.layers[action.payload.layer - 1] = action.payload.rating;
state.reqs = calcArmorReqs(state.layers); state.reqs = calcArmorReqs(state.layers);
},
setArmorLayers: (state, action: PayloadAction<number>) => {
while (state.layers.length > action.payload) state.layers.pop();
while (state.layers.length < action.payload) state.layers.push(0);
state.reqs = calcArmorReqs(state.layers);
},
}, },
setArmorLayers: (state, action: PayloadAction<number>) => {
while (state.layers.length > action.payload) state.layers.pop();
while (state.layers.length < action.payload) state.layers.push(0);
state.reqs = calcArmorReqs(state.layers);
},
},
}); });
function calcArmorReqs(layers: Layer[]): Reqs { export const { actions, reducer } = armor;
const mass = 2 * layers.reduce((a, b) => a + b, 0);
const cost = 2 * layers.map((v, k) => v * (k + 1)).reduce((a, b) => a + b, 0);
return { function calcArmorReqs(layers: Layer[]): Reqs {
mass, const mass = 2 * layers.reduce((a, b) => a + b, 0);
cost, const cost = 2 * layers.map((v, k) => v * (k + 1)).reduce((a, b) => a + b, 0);
};
return {
mass,
cost,
};
} }

View File

@ -2,33 +2,32 @@ import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { reqs } from "../reqs"; import { reqs } from "../reqs";
const initialState = { const initialState = {
rating: 0, rating: 0,
min: 0, min: 0,
max: 0, max: 0,
reqs, reqs,
}; };
const hull = createSlice({ const hull = createSlice({
name: "hull", name: "hull",
initialState, initialState,
reducers: { reducers: {
setHull: (state, action: PayloadAction<number>) => { setHull: (state, action: PayloadAction<number>) => {
state.rating = action.payload; state.rating = action.payload;
state.reqs = { state.reqs = {
mass: action.payload, mass: action.payload,
cost: 2 * action.payload, cost: 2 * action.payload,
} };
},
setShipMass: (state, action: PayloadAction<number>) => {
const mass = action.payload;
let { rating } = state;
if (rating > mass) state.rating = mass;
state.min = Math.ceil(mass / 10);
if (state.rating < state.min) state.rating = state.min;
state.max = mass;
};
}, },
}, setShipMass: (state, action: PayloadAction<number>) => {
const mass = action.payload;
let { rating } = state;
if (rating > mass) state.rating = mass;
state.min = Math.ceil(mass / 10);
if (state.rating < state.min) state.rating = state.min;
state.max = mass;
},
},
}); });
export const { actions, reducer } = hull; export const { actions, reducer } = hull;

View File

@ -2,20 +2,20 @@ import { combineReducers } from "redux";
import * as R from "remeda"; import * as R from "remeda";
import * as hull from "./hull.js"; import * as hull from "./hull.js";
import * as screens from "./screens.js"; import * as screens from "./screen.js";
import * as cargo from "./cargo.js"; import * as cargo from "./cargo.js";
import * as armor from "./armor.js"; import * as armor from "./armor.js";
import * as streamlining from "./streamlining.js"; import * as streamlining from "./streamlining.js";
export const reducer = combineReducers( export const reducer = combineReducers(
R.mapValues( R.mapValues(
{ {
hull, hull,
screens, screens,
cargo, cargo,
armor, armor,
streamlining, streamlining,
}, },
R.prop("reducer") R.prop("reducer")
) )
); );

View File

@ -1,40 +1,40 @@
import { browser, dev } from "$app/env"; import { browser, dev } from "$app/environment";
import { readable, get, derived } from "svelte/store"; import { readable, get, derived } from "svelte/store";
import { compose, applyMiddleware } from "redux"; import { compose, applyMiddleware } from "redux";
import shipDux from "../shipDux/index.js"; import shipDux from "../shipDux/index";
import { initial } from "lodash"; import { initial } from "lodash";
let composeEnhancers = compose; let composeEnhancers = compose;
if (dev && browser && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) { if (dev && browser && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) {
composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__; composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__;
} }
export default (initialState = undefined) => { export default (initialState = undefined) => {
if (browser) { if (browser) {
const i = localStorage.getItem("ship"); const i = localStorage.getItem("ship");
if (i) initialState = JSON.parse(localStorage.getItem("ship")); if (i) initialState = JSON.parse(localStorage.getItem("ship"));
} }
const duxStore = shipDux.createStore(initialState, (mw) => const duxStore = shipDux.createStore(initialState, (mw) =>
composeEnhancers(applyMiddleware(mw)) composeEnhancers(applyMiddleware(mw))
); );
let previous; let previous;
const state = readable(duxStore.getState(), (set) => { const state = readable(duxStore.getState(), (set) => {
duxStore.subscribe(() => { duxStore.subscribe(() => {
if (previous === duxStore.getState()) return; if (previous === duxStore.getState()) return;
previous = duxStore.getState(); previous = duxStore.getState();
set(previous); set(previous);
if (browser) localStorage.setItem("ship", JSON.stringify(previous)); if (browser) localStorage.setItem("ship", JSON.stringify(previous));
});
}); });
});
return { return {
dispatch: duxStore.dispatch, dispatch: duxStore.dispatch,
state, state,
shipMass: derived(state, (state) => state.reqs.mass), shipMass: derived(state, (state) => state.reqs.mass),
}; };
}; };

View File

@ -3,7 +3,7 @@
<script> <script>
import { setContext } from "svelte"; import { setContext } from "svelte";
import '$lib/style/index.js'; import "$lib/style/index.js";
import shipStore from "$lib/store/ship.js"; import shipStore from "$lib/store/ship.js";
import App from "$lib/components/App.svelte"; import App from "$lib/components/App.svelte";

View File

@ -1,24 +1,8 @@
import adapter from "@sveltejs/adapter-static"; import preprocess from "svelte-preprocess";
import analyze from "rollup-plugin-analyzer";
const dev = process.env.NODE_ENV === "development";
/** @type {import('@sveltejs/kit').Config} */ /** @type {import('@sveltejs/kit').Config} */
export default { const config = {
kit: { preprocess: preprocess(),
adapter: adapter({ fallback: "index.html" }),
paths: { base: dev ? "" : "/aotds-docks" },
vite: {
define: {
"import.meta.env.PACKAGE_VERSION": JSON.stringify(
process.env.npm_package_version
),
},
build: {
rollupOptions: {
plugins: [analyze()],
// external: ['updux','@yanick/updeep']
},
},
},
},
}; };
export default config;

View File

@ -1,4 +1,5 @@
{ {
"extends": "./.svelte-kit/tsconfig.json",
"compilerOptions": { "compilerOptions": {
/* Visit https://aka.ms/tsconfig to read more about this file */ /* Visit https://aka.ms/tsconfig to read more about this file */

12
vite.config.js Normal file
View File

@ -0,0 +1,12 @@
// vite.config.js
import { sveltekit } from "@sveltejs/kit/vite";
/** @type {import('vite').UserConfig} */
const config = {
plugins: [sveltekit()],
ssr: {},
optimizeDeps: {},
};
export default config;