Skip to content

Commit 48536b3

Browse files
committed
Refactor to use stores, implement views
1 parent 719ed51 commit 48536b3

13 files changed

+393
-171
lines changed

package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@
1616
"svelte-check": "^3.6.7",
1717
"tslib": "^2.6.2",
1818
"typescript": "^5.2.2",
19-
"vite": "^5.2.0"
19+
"vite": "^5.2.0",
20+
"vite-tsconfig-paths": "^4.3.2"
2021
},
2122
"dependencies": {
22-
"vite-tsconfig-paths": "^4.3.2"
2323
}
2424
}

pnpm-lock.yaml

+12-19
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/App.svelte

+5-24
Original file line numberDiff line numberDiff line change
@@ -3,27 +3,6 @@
33
import Filters from "src/components/Filters.svelte";
44
import Overview from "src/components/Overview.svelte";
55
import Details from "src/components/Details.svelte";
6-
import { type HashedConcert, hashConcert } from "src/utils";
7-
import { type FiltersType, satisfies } from "src/lib/filters";
8-
9-
// Initialise list of concerts
10-
import rawConcerts from "src/assets/concerts.json";
11-
const concerts: HashedConcert[] = rawConcerts.map(hashConcert);
12-
13-
// Filter concerts
14-
let filters: FiltersType = {
15-
searchTerm: "",
16-
booleanTagNames: [],
17-
};
18-
let concertsToShow: HashedConcert[];
19-
let selectedConcertHashes: string[] = [];
20-
let selectedConcerts: HashedConcert[];
21-
$: {
22-
concertsToShow = concerts.filter((c) => satisfies(c, filters));
23-
selectedConcerts = concertsToShow.filter((c) =>
24-
selectedConcertHashes.includes(c.hash),
25-
);
26-
}
276
</script>
287

298
<body>
@@ -32,10 +11,10 @@
3211
<Title />
3312
</div>
3413
<div class="bottom">
35-
<Overview concerts={concertsToShow} bind:selectedConcertHashes />
14+
<Overview />
3615
<div class="bottom-right">
37-
<Filters bind:filters />
38-
<Details bind:selectedConcerts />
16+
<Filters />
17+
<Details />
3918
</div>
4019
</div>
4120
</main>
@@ -57,6 +36,7 @@
5736
align-items: center;
5837
5938
width: 80%;
39+
min-height: 100%;
6040
height: 100%;
6141
max-height: 100%;
6242
padding-top: 30px;
@@ -75,6 +55,7 @@
7555
gap: 20px;
7656
width: 100%;
7757
min-height: 0; /* So confusing that this is required */
58+
height: 100%;
7859
max-height: 100%;
7960
}
8061

src/components/ConcertList.svelte

+90
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
<script lang="ts">
2+
import Tags from "src/components/Tags.svelte";
3+
import { type Concert } from "src/lib/bindings/Concert";
4+
import { formatDate, getPriceString } from "src/lib/utils";
5+
import { selectedConcertIndices } from "src/lib/stores";
6+
7+
export let allConcerts: Concert[];
8+
export let shownIndices: number[];
9+
10+
// Event handler when a concert is clicked. The behaviour is chosen to
11+
// provide as intuitive a UI as possible
12+
function selectOrDeselect(event: MouseEvent, idx: number) {
13+
if ($selectedConcertIndices.includes(idx)) {
14+
if (event.shiftKey) {
15+
$selectedConcertIndices = $selectedConcertIndices.filter(
16+
(i) => i !== idx,
17+
);
18+
} else {
19+
if ($selectedConcertIndices.length === 1) {
20+
$selectedConcertIndices = [];
21+
} else {
22+
$selectedConcertIndices = [idx];
23+
}
24+
}
25+
} else {
26+
if (event.shiftKey) {
27+
$selectedConcertIndices = [...$selectedConcertIndices, idx];
28+
} else {
29+
$selectedConcertIndices = [idx];
30+
}
31+
}
32+
}
33+
</script>
34+
35+
<div class="concert-list">
36+
{#each shownIndices as idx}
37+
{@const concert = allConcerts[idx]}
38+
<button
39+
class="concert"
40+
class:active={$selectedConcertIndices.includes(idx)}
41+
on:click={(event) => selectOrDeselect(event, idx)}
42+
>
43+
<Tags {concert} />
44+
<h3>{concert.title}</h3>
45+
{#if concert.subtitle !== null}
46+
<h4>{concert.subtitle}</h4>
47+
{/if}
48+
<p>
49+
{formatDate(new Date(concert.datetime))}
50+
|
51+
{getPriceString(concert)}
52+
</p>
53+
</button>
54+
{/each}
55+
</div>
56+
57+
<style>
58+
.concert-list {
59+
display: flex;
60+
flex-direction: column;
61+
gap: 10px;
62+
width: 100%;
63+
overflow-y: auto;
64+
padding: 0 15px 0 0;
65+
}
66+
67+
.concert {
68+
border: 2px solid #666;
69+
padding: 10px;
70+
border-radius: 5px;
71+
width: calc(100% - 5px); /* Leave some space for scrollbar on some systems */
72+
73+
font-family: inherit;
74+
text-align: left;
75+
cursor: pointer;
76+
77+
transition: border-color 0.3s;
78+
transition: background-color 0.3s;
79+
transition: margin-left 0.3s;
80+
}
81+
82+
.active {
83+
border-color: #a6628f;
84+
background-color: #f5e9f1;
85+
}
86+
87+
.concert > * {
88+
margin: 2px 0;
89+
}
90+
</style>

0 commit comments

Comments
 (0)