Merge branch 'battle-result'

This commit is contained in:
Yanick Champoux 2023-01-13 12:51:05 -05:00
commit 834b317b2f
13 changed files with 367 additions and 59 deletions

View File

@ -2,5 +2,6 @@ import { defineConfig } from 'histoire';
import { HstSvelte } from '@histoire/plugin-svelte'; import { HstSvelte } from '@histoire/plugin-svelte';
export default defineConfig({ export default defineConfig({
setupFile: '/src/histoire.setup.js',
plugins: [HstSvelte()], plugins: [HstSvelte()],
}); });

1
src/histoire.setup.js Normal file
View File

@ -0,0 +1 @@
//global?.__SVELTEKIT_APP_VERSION_POLL_INTERVAL__ = 1000;

View File

@ -1,5 +0,0 @@
<script>
import 'beercss';
</script>
; // import 'material-dynamic-colors';

View File

@ -0,0 +1,25 @@
<Beer />
<Hst.Story>
<Battle {status} />
<svelte:fragment slot="controls">
<Hst.Select
bind:value={status}
title="status"
options={Object.fromEntries(statuses.map((s) => [s, s]))}
/>
<Hst.Number bind:value={wave} title="wave" />
</svelte:fragment>
</Hst.Story>
<script>
/** @type any */
export let Hst;
import Beer from './Beer.svelte';
import Battle from './Battle.svelte';
let status = 'upcoming';
let wave = '1';
let statuses = ['upcoming', 'prep', 'ongoing', 'won', 'lost'];
</script>

View File

@ -0,0 +1,124 @@
<h5><a href={`#/campaign/${params.campaignId}`}>{$activeCampaign?.name}</a></h5>
<h6>Chapter {chapter}, battle {chapterBattle} -- {status}</h6>
<dl>
{#if status === 'ongoing'}
<dt>wave</dt>
<dd>{wave === 2 ? 'second' : 'first'}</dd>
{/if}
<dt>city</dt>
<dd>{city}</dd>
<dt>scenario</dt>
<dd>{scenario}</dd>
<dt>character</dt>
<dd>{character}</dd>
<dt>difficulty</dt>
<dd>
<div class="field border">
<input
type="number"
step="0.5"
value={difficulty}
on:change={({ target: { value } }) =>
event.setBattleDifficulty(params.battleId, value)}
/>
</div>
<!--
<Stars
on:change={(e) => (difficulty = e.target.value)}
config={{
readOnly: false, //status !== 'preparation',
countStars: 5,
score: difficulty,
showScore: false,
starConfig: {
size: 15,
fillColor: '#F9ED4F',
strokeColor: '#BB8511',
unfilledColor: '#FFF',
strokeUnfilledColor: '#000',
},
range: { min: 0, max: 5, step: 0.5 },
}}
/>
{difficulty}
-->
</dd>
</dl>
{#if status === 'upcoming'}
<button>Start battle</button>
{:else if status === 'ongoing'}
<button on:click={battleVerdict('won')}>Battle won</button>
<button on:click={battleVerdict('lost')}>Battle lost</button>
{/if}
<script>
import { getContext } from 'svelte';
import Stars from '@ernane/svelte-star-rating';
export let params;
const { activeCampaign, event } = getContext('api');
event.setActiveCampaign(params.campaignId);
$: battles = $activeCampaign?.battles;
$: battle = battles && battles[params.battleId - 1];
$: console.log($activeCampaign);
$: scenario = battle?.scenario;
$: status = battle?.status;
$: wave = battle?.wave;
$: difficulty = battle?.difficulty ?? 0;
$: character = battle?.character;
$: city = battle?.city;
$: console.log(battle);
let chapter = 1 + parseInt(params.battleId / 2);
let chapterBattle = params.battleId % 2;
const battleVerdict = (verdict) =>
event.setBattleVerdict(params.battleId, verdict);
// $: event.setBattleDifficulty(params.battleId, difficulty);
</script>
<style>
article {
width: 500px;
}
header {
display: flex;
align-items: baseline;
}
h5 {
flex: 1;
}
h6 {
font-style: italic;
font-size: 1.25rem;
}
dl {
width: 100%;
display: grid;
grid-template-columns: 8em auto;
grid-row-gap: 0.75em;
font-size: 1.25rem;
}
dt {
text-align: right;
padding-right: 2em;
}
dd {
display: flex;
}
article :global(.stars-container) {
justify-content: left !important;
margin-right: 1em;
}
input {
width: 5em;
}
</style>

View File

@ -0,0 +1,64 @@
<article>
{#if $activeCampaign}
<h5>{$activeCampaign.name}</h5>
<h6>Chapter 1</h6>
<Battle {...battles[0]} {campaignId} chapter={1} chapterBattle={1} />
<div class="medium-divider" />
<Battle {...battles[1]} {campaignId} chapter={1} chapterBattle={2} />
<div class="medium-divider" {campaignId} />
<h6>Chapter 2</h6>
<Battle {...battles[2]} {campaignId} chapter={2} chapterBattle={1} />
<div class="medium-divider" />
<Battle {...battles[3]} {campaignId} chapter={2} chapterBattle={2} />
<div class="medium-divider" />
<h6>Chapter 3</h6>
<Battle {...battles[4]} {campaignId} chapter={3} chapterBattle={1} />
<div class="medium-divider" />
<Battle {...battles[5]} {campaignId} chapter={3} chapterBattle={2} />
<div class="medium-divider" />
<h6>Chapter 4</h6>
<Battle {...battles[6]} {campaignId} chapter={4} chapterBattle={1} />
<div class="medium-divider" />
<Battle {...battles[7]} {campaignId} chapter={4} chapterBattle={2} />
<div class="medium-divider" />
<Battle {...battles[8]} {campaignId} chapter={4} chapterBattle={3} />
<div class="medium-divider" />
<Battle {...battles[9]} {campaignId} chapter={4} chapterBattle={4} />
<div class="medium-divider" />
<Battle {...battles[10]} {campaignId} chapter={4} chapterBattle={5} />
<div class="medium-divider" />
<Battle {...battles[11]} {campaignId} chapter={4} chapterBattle={6} />
<div class="medium-divider" />
{/if}
</article>
<script>
import * as R from 'remeda';
import Battle from './Campaign/Battle.svelte';
import { getContext } from 'svelte';
export let params;
const api = getContext('api');
api.event.setActiveCampaign(params.campaignId);
const { activeCampaign } = getContext('api');
$: battles = $activeCampaign?.battles ?? [];
$: while (battles.length <= 12) battles.push({ notYet: true });
const campaignId = params.campaignId;
$: byChapter = R.pipe(
$activeCampaign?.battles ?? [],
R.groupBy(({ id }) => R.clamp(1 + parseInt(id / 2), { max: 4 })),
);
$: console.log(byChapter);
</script>
<style>
</style>

View File

@ -0,0 +1,24 @@
<div class="row">
<p>
{#if notYet}
???
{:else}
<a href={`#/campaign/${campaignId}/battle/${id}`}>
Battle of {city}</a
><span>, {status}</span>
{/if}
</p>
</div>
<script>
export let city = '';
export let status = '';
export let id = 0;
export let notYet = false;
export let campaignId;
export let chapter;
export let chapterBattle;
</script>
<style>
</style>

View File

@ -5,9 +5,21 @@
</Hst.Story> </Hst.Story>
<script> <script>
import { setContext } from 'svelte';
export let Hst; export let Hst;
import Beer from './Beer.svelte'; import Beer from './Beer.svelte';
import Campaigns from './Campaigns.svelte'; import Campaigns from './Campaigns.svelte';
import { genApi } from '$lib/store/api.js';
global.__SVELTEKIT_APP_VERSION_POLL_INTERVAL__ = 1000;
const campaigns = [{ name: 'Earth 613' }]; const campaigns = [{ name: 'Earth 613' }];
setContext(
'api',
genApi({
local: campaigns,
}),
);
</script> </script>

View File

@ -4,12 +4,12 @@
<button on:click={newCampaign}>new campaign</button> <button on:click={newCampaign}>new campaign</button>
</header> </header>
{#each campaigns as campaign (campaign.id)} {#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> <h6>
<a href={`/campaign/${campaign.id}`}> <a href={`#/campaign/${campaign._id}`}>
{campaign.name} {campaign.name}
</a> </a>
</h6> </h6>
@ -50,10 +50,11 @@
<script> <script>
import * as R from 'remeda'; import * as R from 'remeda';
import { getContext } from 'svelte'; import { getContext } from 'svelte';
import { goto } from '$app/navigation'; // import { goto } from '$app/navigation';
const goto = () => {};
export let campaigns = [];
export let api = getContext('api'); export let api = getContext('api');
export let campaigns = api?.campaigns;
let showNewCampaign = false; let showNewCampaign = false;
let newCampaignName = ''; let newCampaignName = '';

View File

@ -1,47 +1,124 @@
import PouchDB from 'pouchdb-browser';
import * as R from 'remeda'; import * as R from 'remeda';
import Dexie, { liveQuery } from 'dexie'; import Dexie, { liveQuery } from 'dexie';
import { writable, derived } from 'svelte/store'; import { writable, derived, get } from 'svelte/store';
import { genNextBattle } from './genNextBattle.js'; import { genNextBattle } from './genNextBattle.js';
import u from '@yanick/updeep-remeda';
const seedCampaign = { const seedCampaign = {
battles: [], battles: [],
}; };
export function genApi(options = {}) { export function genApi(options = {}) {
const storage = new Dexie('Campaigns', options.dexie ?? {}); const pouchdb = new PouchDB(
'Campaigns',
options.local
? {
adapter: 'memory',
}
: {},
);
storage.version(1).stores({ const campaignsCore = writable([]);
campaigns: '++id,name',
pouchdb
.allDocs({ include_docs: true })
.then((r) => r.rows.map(({ id, doc }) => [id, doc]))
.then(Object.fromEntries)
.then(campaignsCore.set);
pouchdb
.changes({ since: 'now', live: true, include_docs: true })
.on('change', (change) => {
console.log({ change });
if (change.deleted) {
campaignsCore.update(u.skip(change.id));
} else {
campaignsCore.update(u.updateIn(change.id, change.doc));
}
}); });
const campaigns = writable([]); const campaigns = derived(campaignsCore, Object.values);
storage.campaigns.toArray().then((c) => campaigns.set(c)); campaigns.subscribe((c) => console.log(c));
const activeCampaignId = writable(); const addCampaign = (name) =>
pouchdb.post({
name,
...seedCampaign,
battles: [{ id: 1, ...genNextBattle() }],
});
const activeCampaignId = writable(0);
const setActiveCampaign = activeCampaignId.set;
const activeCampaign = derived( const activeCampaign = derived(
[activeCampaignId, campaigns], [campaignsCore, activeCampaignId],
async ([id, campaigns], set) => { ([$c, $id]) => $c[$id],
const x = campaigns.find((c) => c.id === id);
set(x);
},
); );
const setBattleDifficulty = (battleId, difficulty) => {
pouchdb
.put(
u.updateIn(get(activeCampaign), `battles.${battleId - 1}`, {
difficulty,
}),
)
.catch((e) => console.error(e));
};
const setBattleVerdict = (battleId, status) => {
let campaign = get(activeCampaign);
campaign = u.updateIn(campaign, `battles.${battleId - 1}`, {
status,
});
campaign = u(campaign, {
battles: (battles) => [
...battles,
u(genNextBattle(campaign.battles), {
id: battles.length + 1,
}),
],
});
pouchdb.put(campaign).catch((e) => console.error(e));
};
return { return {
campaigns, campaigns,
activeCampaign, activeCampaign,
storage,
event: { event: {
addCampaign,
setActiveCampaign,
setBattleVerdict,
setBattleDifficulty,
},
};
/*
const activeCampaign = writeable();
addCampaign: (name) => addCampaign: (name) =>
storage.campaigns.add({ storage.campaigns.add({
name, name,
...seedCampaign, ...seedCampaign,
battles: [genNextBattle()], battles: [{ id: 1, ...genNextBattle() }],
}),
return {
campaigns,
event: {
,
addCampaign: (name) =>
storage.campaigns.add({
name,
...seedCampaign,
battles: [{ id: 1, ...genNextBattle() }],
}), }),
deleteCampaign: (id) => storage.campaigns.delete(id), deleteCampaign: (id) => storage.campaigns.delete(id),
setActiveCampaign: async (id) => {
activeCampaignId.set(id);
},
}, },
}; };
*/
} }

View File

@ -23,6 +23,6 @@ export function genNextBattle(battles = []) {
), ),
); );
return { scenario, character, city, status: 'upcoming' }; return { scenario, character, city, status: 'ongoing', wave: 1 };
} }
} }

View File

@ -1 +0,0 @@
export const ssr = false;

View File

@ -1,15 +0,0 @@
<article>
{#if $activeCampaign}
<h5>{$activeCampaign.name}</h5>
<h6>Chapter 1</h6>
<ul>
<li>Battle of New York, ongoing</li>
</ul>
{/if}
</article>
<script>
import { getContext } from 'svelte';
const { activeCampaign } = getContext('api');
</script>