this repo has no description
1---
2interface Props {
3 immutable?: true;
4}
5---
6
7<script>
8 import Powers, { type powerObj } from "../../lib/powers";
9
10 class HTMLPointsMeterElement extends HTMLElement {
11 dec: HTMLButtonElement;
12 inc: HTMLButtonElement;
13 meter: HTMLMeterElement;
14 count: HTMLElement;
15 max: HTMLElement;
16
17 constructor() {
18 super();
19 const dec = this.querySelector("button[data-dec]");
20 const inc = this.querySelector("button[data-inc]");
21 const meter = this.querySelector("meter");
22 const count = this.querySelector("span.count");
23 const max = this.querySelector("span.max");
24
25 if (
26 !(
27 dec instanceof HTMLButtonElement &&
28 inc instanceof HTMLButtonElement &&
29 meter instanceof HTMLMeterElement &&
30 count instanceof HTMLElement &&
31 max instanceof HTMLElement
32 )
33 ) {
34 throw "Elements not set correctly";
35 }
36
37 this.dec = dec;
38 this.inc = inc;
39 this.meter = meter;
40 this.count = count;
41 this.max = max;
42
43 Powers.subscribe(this.handleState.bind(this));
44
45 this.dec.addEventListener("click", async () => {
46 this.max.innerText = "...";
47 this.dec.disabled = true;
48
49 await Powers.setKey("points", Powers.get().points - 1).catch((e) =>
50 console.warn(e),
51 );
52
53 this.dec.disabled =
54 !(Powers.get().points - 1 >= 0) ||
55 !(Powers.get().points - 1 >= Powers.get().powers.length) ||
56 this.getAttribute("disabled") !== null;
57 });
58
59 this.inc.addEventListener("click", async () => {
60 this.max.innerText = "...";
61 this.inc.disabled = true;
62 await Powers.setKey("points", Powers.get().points + 1).catch((e) =>
63 console.warn(e),
64 );
65
66 this.inc.disabled = this.getAttribute("disabled") !== null;
67 });
68 }
69
70 handleState(_val: Readonly<powerObj> | null) {
71 const val = _val ? _val : { powers: [""], points: 1 };
72 this.meter.value = val.powers.length;
73 this.meter.max = val.points;
74 this.count.innerText = val.powers.length + "";
75 this.max.innerText = val.points + "";
76
77 this.dec.disabled =
78 !(val.points - 1 >= 0) ||
79 !(val.points - 1 >= val.powers.length) ||
80 this.getAttribute("disabled") !== null;
81 }
82 }
83
84 customElements.define("points-meter", HTMLPointsMeterElement);
85</script>
86
87<points-meter disabled={Astro.props.immutable}>
88 <button aria-label="decrement" data-dec disabled={Astro.props.immutable}
89 >-</button
90 >
91 <meter></meter>
92 <span class="total"
93 ><span class="count"></span>/<span class="max"></span></span
94 >
95 <button aria-label="increment" data-inc disabled={Astro.props.immutable}
96 >+</button
97 >
98</points-meter>
99
100<style>
101 points-meter {
102 background-color: color-mix(
103 in oklch,
104 100% var(--background),
105 10% var(--text)
106 );
107 border: 5px solid var(--text);
108 border-radius: 10px;
109 padding: 1em;
110 z-index: 99;
111
112 display: grid;
113 gap: 1em;
114 grid-template: "dec meter inc" 1fr / 1fr 3fr 1fr;
115 max-width: 100%;
116 width: 400px;
117
118 button {
119 background-color: inherit;
120 border: 3px solid;
121 border-color: inherit;
122 border-radius: inherit;
123
124 &[disabled],
125 &:active {
126 opacity: 0.7;
127 }
128 }
129
130 .total {
131 width: min-content;
132 padding: 0.2em 1em;
133 margin: auto;
134 z-index: 99;
135
136 background: var(--background);
137 border: 1px solid;
138 border-color: inherit;
139 border-radius: 0.5em;
140 }
141
142 meter {
143 appearance: none;
144 width: 100%;
145 height: 3rem;
146 background: var(--background);
147 border-radius: 10px;
148 overflow: clip;
149
150 &::-webkit-meter-bar {
151 background: inherit;
152 height: 3rem;
153 }
154
155 &::-moz-meter-bar {
156 background: var(--green);
157 }
158
159 &::-webkit-meter-optimum-value {
160 background: var(--green);
161 height: 100%;
162 }
163 }
164
165 button[data-dec] {
166 grid-area: dec;
167 }
168
169 button[data-inc] {
170 grid-area: inc;
171 }
172
173 meter,
174 .total {
175 grid-area: meter;
176 }
177 }
178</style>