+216
-4
src/components/power.svelte
+216
-4
src/components/power.svelte
···
1
1
<script lang="ts">
2
2
import { type Power, type Locked, isUnlocked } from "@/powers";
3
3
import Self from "./power.svelte";
4
-
import { powers } from "@/stores/powers";
4
+
import { powers, mutatePowers } from "@/stores/powers";
5
5
6
6
const { power }: { power: Power | Locked } = $props();
7
7
</script>
8
8
9
-
<div class="wrapper">
9
+
<!-- <div class="wrapper">
10
10
<div
11
-
class={`power ${power.status !== "locked" ? "unlocked" : "locked"} ${power.status === "frozen:selected" || (power.status !== "locked" && $powers.powers.includes(power.name)) ? "selected" : ""}`}
11
+
class={`power ${power.status !== "locked" ? "unlocked" : "locked"} ${power.frozen === "selected" || (power.status !== "locked" && $powers.powers.includes(power.name)) ? "selected" : ""}`}
12
12
>
13
13
<div class="entry">
14
14
{#if isUnlocked(power)}
···
25
25
{/each}
26
26
</dl>
27
27
<p>{power.description}</p>
28
+
{#if power.status !== "frozen:selected" && power.status !== "frozen:unselected"}<button>Unlock</button>
28
29
</div>
29
30
</details>
30
31
{:else}
···
38
39
<Self power={child} />
39
40
{/each}
40
41
</div>
42
+
</div> -->
43
+
44
+
<div class="wrapper">
45
+
<!-- locked power -->
46
+
{#if power.status === "locked"}
47
+
<div class={`power status:${power.status}`}>
48
+
<img src="/locked.png" alt="" />
49
+
<p class="headline noto-serif">Locked</p>
50
+
</div>
51
+
{:else}
52
+
<!-- unlocked power -->
53
+
<button
54
+
class={`power status:${power.status} frozen:${power.frozen} unlocked:${$powers.powers.includes(power.name)}`}
55
+
id="preview"
56
+
popovertarget={`tooltip-${power.name.replace(/\W/g, "_")}`}
57
+
>
58
+
<img {...power.image} />
59
+
<div class="headline noto-serif">{power.name}</div>
60
+
</button>
61
+
<dialog
62
+
class="tooltip"
63
+
id={`tooltip-${power.name.replace(/\W/g, "_")}`}
64
+
popover="auto"
65
+
>
66
+
{#if !power.frozen}
67
+
<button
68
+
class={`unlock-btn ${$powers.powers.includes(power.name) ? "unselect" : "select"}`}
69
+
onclick={() => {
70
+
console.log("clicked", power.name);
71
+
if (!$powers.powers.includes(power.name)) {
72
+
console.log("select");
73
+
mutatePowers((n) => ({
74
+
...n,
75
+
powers: [...n.powers, power.name],
76
+
}));
77
+
} else {
78
+
console.log("deselect");
79
+
mutatePowers((n) => ({
80
+
...n,
81
+
powers: n.powers.filter((p) => p !== power.name),
82
+
}));
83
+
}
84
+
}}
85
+
>
86
+
<div class="unselect-txt">Unselect</div>
87
+
<div class="select-txt">Select</div>
88
+
</button>
89
+
{/if}
90
+
<img {...power.image} />
91
+
<div class="headline noto-serif">{power.name}</div>
92
+
<dl>
93
+
{#each power.meta as meta}
94
+
<dt>{meta.name}</dt>
95
+
<dd>{meta.value}</dd>
96
+
{/each}
97
+
</dl>
98
+
<p>{power.description}</p>
99
+
</dialog>
100
+
{/if}
101
+
<div class="children" style={`--rows: ${power.children.length}`}>
102
+
{#each power.children as child}
103
+
<Self power={child} />
104
+
{/each}
105
+
</div>
41
106
</div>
42
107
43
-
<style>
108
+
<!-- <style>
44
109
/* positions */
45
110
.wrapper {
46
111
display: flex;
···
157
222
}
158
223
}
159
224
}
225
+
}
226
+
</style> -->
227
+
228
+
<style>
229
+
/* colours etc */
230
+
.power {
231
+
&,
232
+
& + .tooltip,
233
+
& + .tooltip > .unlock-btn {
234
+
border-radius: 1rem;
235
+
color: var(--text);
236
+
background-color: hsl(
237
+
from var(--base, var(--background)) h calc(s * 1.5) 16
238
+
);
239
+
border: 0.2rem solid
240
+
hsl(from var(--base, var(--background)) h calc(s * 1.5) 48);
241
+
}
242
+
243
+
&.status\:unlocked,
244
+
&.frozen\:unselected,
245
+
&.unlocked\:false {
246
+
&,
247
+
& + .tooltip {
248
+
--base: var(--red);
249
+
}
250
+
}
251
+
252
+
&.status\:locked {
253
+
--base: var(--gold);
254
+
}
255
+
256
+
&.frozen\:selected,
257
+
&.unlocked\:true {
258
+
&,
259
+
& + .tooltip {
260
+
--base: var(--green);
261
+
}
262
+
}
263
+
}
264
+
265
+
/* typo */
266
+
dl:not(:empty) {
267
+
padding: 0.5rem;
268
+
& dt {
269
+
float: left;
270
+
padding-right: 1rem;
271
+
font-weight: bold;
272
+
273
+
&::after {
274
+
content: ":";
275
+
}
276
+
}
277
+
}
278
+
279
+
dl + p {
280
+
padding: 0.5rem;
281
+
}
282
+
283
+
.headline {
284
+
font-family: "Noto Serif", serif;
285
+
font-optical-sizing: auto;
286
+
font-weight: 600;
287
+
font-style: normal;
288
+
font-variation-settings: "wdth" 100;
289
+
font-size: 2rem;
290
+
}
291
+
292
+
/* looks positions */
293
+
img {
294
+
width: 5rem;
295
+
height: 5rem;
296
+
object-fit: cover;
297
+
border-radius: 2.5rem;
298
+
}
299
+
300
+
.power {
301
+
display: grid;
302
+
grid-template-columns: 5rem 1fr;
303
+
align-items: center;
304
+
gap: 0.5rem;
305
+
padding: 0.5rem;
306
+
text-align: left;
307
+
308
+
&.status\:locked {
309
+
width: 15rem;
310
+
}
311
+
312
+
&.status\:unlocked {
313
+
width: 35rem;
314
+
}
315
+
}
316
+
317
+
.tooltip {
318
+
margin: auto;
319
+
max-width: 65ch;
320
+
321
+
& img {
322
+
width: 4rem;
323
+
height: 4rem;
324
+
margin: 0.5rem;
325
+
float: left;
326
+
}
327
+
328
+
& .headline {
329
+
height: 5rem;
330
+
line-height: 5rem;
331
+
margin-left: 5rem;
332
+
}
333
+
334
+
& .unlock-btn {
335
+
padding-inline: 1rem;
336
+
padding-block: 0.2rem;
337
+
margin: 1rem;
338
+
float: right;
339
+
340
+
display: grid;
341
+
grid-template-areas: "stack";
342
+
343
+
& > * {
344
+
visibility: hidden;
345
+
grid-area: stack;
346
+
}
347
+
348
+
&.select > .select-txt {
349
+
visibility: visible;
350
+
}
351
+
352
+
&.unselect > .unselect-txt {
353
+
visibility: visible;
354
+
}
355
+
}
356
+
}
357
+
358
+
/* child pos stuff */
359
+
.wrapper {
360
+
display: flex;
361
+
align-items: center;
362
+
width: fit-content;
363
+
gap: 1rem;
364
+
}
365
+
366
+
.children {
367
+
width: fit-content;
368
+
height: 100%;
369
+
display: grid;
370
+
gap: 1rem;
371
+
grid-template-rows: repeat(var(--rows), 1fr);
160
372
}
161
373
</style>
+11
-6
src/pages/index.astro
+11
-6
src/pages/index.astro
···
9
9
<Base title="Astral Powers">
10
10
<Fragment slot="head">
11
11
<style>
12
+
@import url("https://fonts.googleapis.com/css2?family=Noto+Serif:ital,wght@0,100..900;1,100..900&display=swap");
13
+
12
14
@media (prefers-color-scheme: light) {
13
15
:root {
14
16
--text: #151314;
15
17
--background: #f3e7ea;
16
-
--primary: #8ac79c;
17
-
--secondary: #d77fab;
18
+
--green: #53f9c7;
19
+
--red: #bb2541;
20
+
--gold: #c59c2b;
18
21
--accent: #cc2e7d;
19
22
}
20
23
}
···
22
25
:root {
23
26
--text: #eceaeb;
24
27
--background: #190d10;
25
-
--primary: #39764b;
26
-
--secondary: #7f2854;
28
+
--green: #06aa79;
29
+
--red: #da4460;
30
+
--gold: #d4aa3b;
27
31
--accent: #d13181;
28
32
}
29
33
}
···
36
40
37
41
#head {
38
42
width: calc(100vw - 2rem);
39
-
height: 3rem;
43
+
height: 4rem;
44
+
margin-bottom: 1rem;
40
45
}
41
46
42
47
#body {
43
48
width: calc(100vw - 2rem);
44
-
height: calc(100vh - 5rem);
49
+
height: calc(100vh - 7rem);
45
50
overflow: auto;
46
51
}
47
52
</style>
+4
-2
src/powers.ts
+4
-2
src/powers.ts
···
1
1
export interface Power {
2
-
status: "unlocked" | "frozen:selected" | "frozen:unselected";
2
+
status: "unlocked";
3
+
frozen?: "selected" | "unselected";
3
4
name: string;
4
5
description: string;
5
6
image: {
···
23
24
}
24
25
25
26
export const powers: Power = {
26
-
status: "frozen:selected",
27
+
status: "unlocked",
28
+
frozen: "selected",
27
29
name: "Eldritch Adaptability",
28
30
description:
29
31
"You become more adaptable to other envirmonents. When entering another world your body automatically adjusts to endure there better. This can include new languages, gills, cultural understanding, and more.",