Merge branch 'sky6-store'

This commit is contained in:
Yanick Champoux 2023-01-12 16:42:45 -05:00
commit 41c6cae377
9 changed files with 181 additions and 4 deletions

View File

@ -27,11 +27,13 @@
"svelte": "^3.54.0", "svelte": "^3.54.0",
"svelte-check": "^2.9.2", "svelte-check": "^2.9.2",
"vite": "^4.0.0", "vite": "^4.0.0",
"vitest": "^0.25.3" "vitest": "^0.25.8"
}, },
"type": "module", "type": "module",
"dependencies": { "dependencies": {
"beercss": "^3.0.4", "beercss": "^3.0.4",
"dexie": "^3.2.2",
"fake-indexeddb": "^4.0.1",
"material-dynamic-colors": "^0.1.5" "material-dynamic-colors": "^0.1.5"
} }
} }

View File

@ -4,11 +4,15 @@
<button on:click={newCampaign}>new campaign</button> <button on:click={newCampaign}>new campaign</button>
</header> </header>
{#each campaigns as campaign (campaign.name)} {#each campaigns as campaign (campaign.id)}
<div class="row"> <div class="row">
<i class="light-green-text">south_america</i> <i class="light-green-text">south_america</i>
<div class="max"> <div class="max">
<h6>{campaign.name}</h6> <h6>
<a href={`/campaign/${campaign.id}`}>
{campaign.name}
</a>
</h6>
<p>chapter 2, second battle.</p> <p>chapter 2, second battle.</p>
</div> </div>
<button on:click={deleteCampaign(campaign)} class="none" <button on:click={deleteCampaign(campaign)} class="none"
@ -18,15 +22,48 @@
{/each} {/each}
</article> </article>
<div class="modal" class:active={showNewCampaign}>
<h5>New campaign</h5>
<div>
<div class="field border">
<input
type="text"
bind:value={newCampaignName}
placeholder="Campaign name"
/>
</div>
</div>
<nav class="right-align">
<button class="border" on:click={() => (showNewCampaign = false)}
>Cancel</button
>
<button on:click={saveNewCampaign}>Create</button>
</nav>
</div>
<script> <script>
import { getContext } from 'svelte';
import { goto } from '$app/navigation';
export let campaigns = []; export let campaigns = [];
export let api = getContext('api');
let showNewCampaign = false;
let newCampaignName = '';
async function deleteCampaign({ name, id }) { async function deleteCampaign({ name, id }) {
if (!window.confirm(`delete campaign ${name}?`)) return; if (!window.confirm(`delete campaign ${name}?`)) return;
api.event.deleteCampaign(id);
} }
const newCampaign = () => { const newCampaign = () => {
console.log('TODO'); showNewCampaign = true;
};
const saveNewCampaign = () => {
api.event.addCampaign(newCampaignName);
newCampaignName = '';
showNewCampaign = false;
}; };
</script> </script>
@ -37,4 +74,7 @@
h5 { h5 {
flex: 1; flex: 1;
} }
article {
height: 90vh;
}
</style> </style>

44
src/lib/store/api.js Normal file
View File

@ -0,0 +1,44 @@
import Dexie, { liveQuery } from 'dexie';
import { writable, derived } from 'svelte/store';
const seedCampaign = {
battles: [],
};
export function genApi(options = {}) {
const storage = new Dexie('Campaigns', options.dexie ?? {});
storage.version(1).stores({
campaigns: '++id,name',
});
const campaigns = liveQuery(async () => {
const c = [];
await storage.campaigns
.toCollection()
.each(({ id, name }) => c.push({ id, name }));
return c;
});
const activeCampaignId = writable();
const activeCampaign = derived(activeCampaignId, async (id, set) => {
const x = await storage.campaigns.get({ id });
console.log({ x });
set(x);
});
return {
campaigns,
activeCampaign,
storage,
event: {
addCampaign: (name) =>
storage.campaigns.add({ name, ...seedCampaign }),
deleteCampaign: (id) => storage.campaigns.delete(id),
setActiveCampaign: async (id) => {
activeCampaignId.set(id);
},
},
};
}

28
src/lib/store/api.test.js Normal file
View File

@ -0,0 +1,28 @@
import { test, expect } from 'vitest';
//import { indexedDB, IDBKeyRange } from 'fake-indexeddb';
import 'fake-indexeddb/auto';
import { genApi } from './api.js';
const get = async (store) => new Promise((resolve) => store.subscribe(resolve));
test('create and add and remove campaigns', async () => {
const api = genApi(); //{ dexie: { indexedDB, IDBKeyRange } });
api.event.addCampaign('C1');
api.event.addCampaign('C2');
let result = await get(api.campaigns);
expect(result).toHaveLength(2);
expect(result[0]).toEqual({
id: 1,
name: 'C1',
});
api.event.deleteCampaign(1);
result = await get(api.campaigns);
expect(result).toHaveLength(1);
});

21
src/routes/+layout.svelte Normal file
View File

@ -0,0 +1,21 @@
<Beer />
<main class="center">
<slot />
</main>
<script>
import { genApi } from '$lib/store/api.js';
import { setContext } from 'svelte';
import Beer from '$lib/components/Beer.svelte';
const api = genApi();
setContext('api', api);
</script>
<style>
main {
max-width: 720px;
height: 100vh;
}
</style>

12
src/routes/+page.svelte Normal file
View File

@ -0,0 +1,12 @@
<Campaigns campaigns={$campaigns} />
<script>
import Campaigns from '$lib/components/Campaigns.svelte';
import { getContext } from 'svelte';
const { campaigns } = getContext('api');
</script>
<style>
</style>

View File

@ -0,0 +1,4 @@
export function load({ params }) {
params.campaignId = parseInt(params?.campaignId);
return params;
}

View File

@ -0,0 +1,14 @@
<slot />
<script>
import { getContext } from 'svelte';
export let data;
const api = getContext('api');
api.event.setActiveCampaign(data.campaignId);
</script>
<style>
</style>

View File

@ -0,0 +1,12 @@
<article>
<h5>{$activeCampaign.name}</h5>
<h6>Chapter 1</h6>
</article>
<script>
import { getContext } from 'svelte';
const { activeCampaign } = getContext('api');
$: console.log({ activeCampaign: $activeCampaign });
</script>