1,960 bytes View directory
1 <script lang="ts">
2 import { Spring } from 'svelte/motion';
3
4 const count = new Spring(0);
5 const offset = $derived(modulo(count.current, 1));
6
7 function modulo(n: number, m: number) {
8 // handle negative numbers
9 return ((n % m) + m) % m;
10 }
11 </script>
13 <div class="counter">
14 <button onclick={() => (count.target -= 1)} aria-label="Decrease the counter by one">
15 <svg aria-hidden="true" viewBox="0 0 1 1">
16 <path d="M0,0.5 L1,0.5" />
17 </svg>
18 </button>
20 <div class="counter-viewport">
21 <div class="counter-digits" style="transform: translate(0, {100 * offset}%)">
22 <strong class="hidden" aria-hidden="true">{Math.floor(count.current + 1)}</strong>
23 <strong>{Math.floor(count.current)}</strong>
24 </div>
25 </div>
27 <button onclick={() => (count.target += 1)} aria-label="Increase the counter by one">
28 <svg aria-hidden="true" viewBox="0 0 1 1">
29 <path d="M0,0.5 L1,0.5 M0.5,0 L0.5,1" />
30 </svg>
31 </button>
32 </div>
34 <style>
35 .counter {
36 display: flex;
37 border-top: 1px solid rgba(0, 0, 0, 0.1);
38 border-bottom: 1px solid rgba(0, 0, 0, 0.1);
39 margin: 1rem 0;
40 }
42 .counter button {
43 width: 2em;
44 padding: 0;
45 display: flex;
46 align-items: center;
47 justify-content: center;
48 border: 0;
49 background-color: transparent;
50 touch-action: manipulation;
51 font-size: 2rem;
52 }
54 .counter button:hover {
55 background-color: var(--color-bg-1);
56 }
58 svg {
59 width: 25%;
60 height: 25%;
61 }
63 path {
64 vector-effect: non-scaling-stroke;
65 stroke-width: 2px;
66 stroke: #444;
67 }
69 .counter-viewport {
70 width: 8em;
71 height: 4em;
72 overflow: hidden;
73 text-align: center;
74 position: relative;
75 }
77 .counter-viewport strong {
78 position: absolute;
79 display: flex;
80 width: 100%;
81 height: 100%;
82 font-weight: 400;
83 color: var(--color-theme-1);
84 font-size: 4rem;
85 align-items: center;
86 justify-content: center;
87 }
89 .counter-digits {
90 position: absolute;
91 width: 100%;
92 height: 100%;
93 }
95 .hidden {
96 top: -100%;
97 user-select: none;
98 }
99 </style>