Skip to content

Commit 551b30e

Browse files
committed
feat: add toggle
1 parent ea44350 commit 551b30e

File tree

2 files changed

+298
-11
lines changed

2 files changed

+298
-11
lines changed

packages/invoice-dashboard/src/lib/view-requests.svelte

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
// Components
88
import Copy from "@requestnetwork/shared-components/copy.svelte";
99
import Dropdown from "@requestnetwork/shared-components/dropdown.svelte";
10+
import Switch from "@requestnetwork/shared-components/switch.svelte";
1011
import Input from "@requestnetwork/shared-components/input.svelte";
1112
import PoweredBy from "@requestnetwork/shared-components/powered-by.svelte";
1213
import Toaster from "@requestnetwork/shared-components/sonner.svelte";
@@ -49,6 +50,10 @@
4950
export let wagmiConfig: WagmiConfig;
5051
export let requestNetwork: RequestNetwork | null | undefined;
5152
export let currencies: CurrencyTypes.CurrencyInput[] = [];
53+
export let isDecryptionSwitchedOn: boolean;
54+
export let switchOnDecryption: (option: boolean) => void | undefined;
55+
56+
let sliderValue = isDecryptionSwitchedOn ? "on" : "off";
5257
5358
let signer: `0x${string}` | undefined;
5459
let activeConfig = config ? config : defaultConfig;
@@ -383,6 +388,18 @@
383388
const handleRemoveSelectedRequest = () => {
384389
activeRequest = undefined;
385390
};
391+
392+
393+
$: sliderValue, getRequests();
394+
395+
$: {
396+
if(sliderValue === 'on') {
397+
switchOnDecryption(true);
398+
} else {
399+
switchOnDecryption(false);
400+
}
401+
}
402+
386403
</script>
387404

388405
<div
@@ -411,17 +428,23 @@
411428
</li>
412429
</ul>
413430
</div>
414-
<div style="display: flex; flex-direction: column; gap: 10px;">
431+
<div style="display: flex; flex-direction: column;">
415432
<div class="search-wrapper">
416-
<Input
417-
placeholder="Search..."
418-
width="w-[300px]"
419-
handleInput={handleSearchChange}
420-
>
421-
<div slot="icon">
422-
<Search />
433+
<div class="search-wrapper" style="gap: 10px;">
434+
<Input
435+
placeholder="Search..."
436+
width="w-[300px]"
437+
handleInput={handleSearchChange}
438+
>
439+
<div slot="icon">
440+
<Search />
441+
</div>
442+
</Input>
443+
<div class="width: fit-content;">
444+
<Switch bind:value={sliderValue} label="Show encrypted requests" fontSize={14} design="slider" />
423445
</div>
424-
</Input>
446+
</div>
447+
425448
<Dropdown
426449
config={activeConfig}
427450
type="checkbox"
@@ -578,7 +601,7 @@
578601
</tr>
579602
</thead>
580603
<tbody>
581-
{#if processedRequests.length > 0}
604+
{#if !loading && processedRequests.length > 0}
582605
{#each processedRequests as request}
583606
<tr class="row" on:click={(e) => handleRequestSelect(e, request)}>
584607
{#if columns.issuedAt}
@@ -686,7 +709,9 @@
686709
</tr>
687710
{/each}
688711
{:else}
689-
<DashboardSkeleton />
712+
{#if loading}
713+
<DashboardSkeleton />
714+
{/if}
690715
{/if}
691716
</tbody>
692717
</table>

shared/components/switch.svelte

Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
1+
<script>
2+
// based on suggestions from:
3+
// Inclusive Components by Heydon Pickering https://inclusive-components.design/toggle-button/
4+
// On Designing and Building Toggle Switches by Sara Soueidan https://www.sarasoueidan.com/blog/toggle-switch-design/
5+
// and this example by Scott O'hara https://codepen.io/scottohara/pen/zLZwNv
6+
7+
8+
export let label;
9+
export let design = 'inner label'
10+
export let options = [];
11+
export let fontSize = 16;
12+
export let value = 'off';
13+
14+
let checked = value === 'on' ? true : false;
15+
16+
17+
const uniqueID = Math.floor(Math.random() * 100)
18+
19+
function handleClick(event){
20+
const target = event.target
21+
22+
const state = target.getAttribute('aria-checked')
23+
24+
checked = state === 'true' ? false : true
25+
26+
value = checked === true ? 'on' : 'off'
27+
}
28+
29+
const slugify = (str = "") =>
30+
str.toLowerCase().replace(/ /g, "-").replace(/\./g, "");
31+
32+
</script>
33+
34+
{#if design == 'inner'}
35+
<div class="s s--inner">
36+
<span id={`switch-${uniqueID}`}>{label}</span>
37+
<button
38+
role="switch"
39+
aria-checked={checked}
40+
aria-labelledby={`switch-${uniqueID}`}
41+
on:click={handleClick}>
42+
<span>on</span>
43+
<span>off</span>
44+
</button>
45+
</div>
46+
{:else if design == 'slider'}
47+
<div class="s s--slider" style="font-size:{fontSize}px">
48+
<span id={`switch-${uniqueID}`}>{label}</span>
49+
<button
50+
role="switch"
51+
aria-checked={checked}
52+
aria-labelledby={`switch-${uniqueID}`}
53+
on:click={handleClick}>
54+
</button>
55+
</div>
56+
{:else}
57+
<div class="s s--multi">
58+
<div role='radiogroup'
59+
class="group-container"
60+
aria-labelledby={`label-${uniqueID}`}
61+
style="font-size:{fontSize}px"
62+
id={`group-${uniqueID}`}>
63+
<div class='legend' id={`label-${uniqueID}`}>{label}</div>
64+
{#each options as option}
65+
<input type="radio" id={`${option}-${uniqueID}`} value={option} bind:group={value}>
66+
<label for={`${option}-${uniqueID}`}>
67+
{option}
68+
</label>
69+
{/each}
70+
</div>
71+
</div>
72+
73+
{/if}
74+
75+
<style>
76+
/* Inner Design Option */
77+
.s--inner button {
78+
padding: 0.5em;
79+
background-color: #fff;
80+
border: 1px solid #ccc;
81+
}
82+
[role='switch'][aria-checked='true'] :first-child,
83+
[role='switch'][aria-checked='false'] :last-child {
84+
display: none;
85+
color: #fff;
86+
}
87+
88+
.s--inner button span {
89+
user-select: none;
90+
pointer-events:none;
91+
padding: 0.25em;
92+
}
93+
94+
.s--inner button:focus {
95+
outline: #0bb489 solid 1px;
96+
}
97+
98+
/* Slider Design Option */
99+
100+
.s--slider {
101+
display: flex;
102+
align-items: center;
103+
}
104+
105+
.s--slider button {
106+
width: 3em;
107+
height: 1.6em;
108+
position: relative;
109+
margin: 0 0 0 0.5em;
110+
background: #ccc;
111+
border: none;
112+
}
113+
114+
.s--slider button::before {
115+
content: '';
116+
position: absolute;
117+
width: 1.3em;
118+
height: 1.3em;
119+
background: #fff;
120+
top: 0.13em;
121+
right: 1.5em;
122+
transition: transform 0.3s;
123+
}
124+
125+
.s--slider button[aria-checked='true']{
126+
background-color: #0bb489
127+
}
128+
129+
.s--slider button[aria-checked='true']::before{
130+
transform: translateX(1.3em);
131+
transition: transform 0.3s;
132+
}
133+
134+
.s--slider button:focus {
135+
box-shadow: 0 0px 0px 1px #0bb489;
136+
}
137+
138+
/* Multi Design Option */
139+
140+
/* Based on suggestions from Sara Soueidan https://www.sarasoueidan.com/blog/toggle-switch-design/
141+
and this example from Scott O'hara https://codepen.io/scottohara/pen/zLZwNv */
142+
143+
.s--multi .group-container {
144+
border: none;
145+
padding: 0;
146+
white-space: nowrap;
147+
}
148+
149+
/* .s--multi legend {
150+
font-size: 2px;
151+
opacity: 0;
152+
position: absolute;
153+
} */
154+
155+
.s--multi label {
156+
display: inline-block;
157+
line-height: 1.6;
158+
position: relative;
159+
z-index: 2;
160+
}
161+
162+
.s--multi input {
163+
opacity: 0;
164+
position: absolute;
165+
}
166+
167+
.s--multi label:first-of-type {
168+
padding-right: 5em;
169+
}
170+
171+
.s--multi label:last-child {
172+
margin-left: -5em;
173+
padding-left: 5em;
174+
}
175+
176+
.s--multi:focus-within label:first-of-type:after {
177+
box-shadow: 0 0px 8px #0bb489;
178+
border-radius: 1.5em;
179+
}
180+
181+
182+
183+
/* making the switch UI. */
184+
.s--multi label:first-of-type:before,
185+
.s--multi label:first-of-type:after {
186+
content: "";
187+
height: 1.25em;
188+
overflow: hidden;
189+
pointer-events: none;
190+
position: absolute;
191+
vertical-align: middle;
192+
}
193+
194+
.s--multi label:first-of-type:before {
195+
border-radius: 100%;
196+
z-index: 2;
197+
position: absolute;
198+
width: 1.2em;
199+
height: 1.2em;
200+
background: #fff;
201+
top: 0.2em;
202+
right: 1.2em;
203+
transition: transform 0.3s;
204+
}
205+
206+
.s--multi label:first-of-type:after {
207+
background: #0bb489;
208+
border-radius: 1em;
209+
margin: 0 1em;
210+
transition: background .2s ease-in-out;
211+
width: 3em;
212+
height: 1.6em;
213+
}
214+
215+
.s--multi input:first-of-type:checked ~ label:first-of-type:after {
216+
background: #ccc;
217+
}
218+
219+
.s--multi input:first-of-type:checked ~ label:first-of-type:before {
220+
transform: translateX(-1.4em);
221+
}
222+
223+
.s--multi input:last-of-type:checked ~ label:last-of-type {
224+
z-index: 1;
225+
}
226+
227+
.s--multi input:focus {
228+
box-shadow: 0 0px 8px #0bb489;
229+
border-radius: 1.5em;
230+
}
231+
232+
/* gravy */
233+
234+
/* Inner Design Option */
235+
[role='switch'][aria-checked='true'] :first-child,
236+
[role='switch'][aria-checked='false'] :last-child {
237+
border-radius: 0.25em;
238+
background: #0bb489;
239+
display: inline-block;
240+
}
241+
242+
.s--inner button:focus {
243+
box-shadow: 0 0px 8px #0bb489;
244+
border-radius: 0.1em;
245+
}
246+
247+
/* Slider Design Option */
248+
.s--slider button {
249+
border-radius: 1.5em;
250+
}
251+
252+
.s--slider button::before {
253+
border-radius: 100%;
254+
}
255+
256+
.s--slider button:focus {
257+
box-shadow: 0 0px 8px #0bb489;
258+
border-radius: 1.5em;
259+
}
260+
261+
262+
</style>

0 commit comments

Comments
 (0)