-
Notifications
You must be signed in to change notification settings - Fork 11
/
decal.html
895 lines (840 loc) · 33 KB
/
decal.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
<!DOCTYPE html>
<html>
<head>
<script>document.querySelector('html').classList.add(process.platform)</script>
<link rel="stylesheet" href="~@fontsource/open-sans/latin.css">
<style>
@font-face {
font-family: 'overpass-mono';
src: url('~redhat-overpass-font/webfonts/overpass-mono-webfont/overpass-mono-light.woff2') format('woff2');
font-weight: 300;
font-style: normal;
}
@font-face {
font-family: 'overpass-mono';
src: url('~redhat-overpass-font/webfonts/overpass-mono-webfont/overpass-mono-regular.woff2') format('woff2');
font-weight: 400;
font-style: normal;
}
@font-face {
font-family: 'overpass-mono';
src: url('~redhat-overpass-font/webfonts/overpass-mono-webfont/overpass-mono-semibold.woff2') format('woff2');
font-weight: 500;
font-style: normal;
}
@font-face {
font-family: 'overpass-mono';
src: url('~redhat-overpass-font/webfonts/overpass-mono-webfont/overpass-mono-bold.woff2') format('woff2');
font-weight: 600;
font-style: normal;
}
@font-face {
font-family: 'overpass';
src: url('~redhat-overpass-font/webfonts/overpass-webfont/overpass-bold.woff2') format('woff2');
font-weight: 700;
font-style: normal;
}
@font-face {
font-family: 'overpass';
src: url('~redhat-overpass-font/webfonts/overpass-webfont/overpass-regular.woff2') format('woff2');
font-weight: 400;
font-style: normal;
}
body {
user-select: none;
background: #151517;
margin:0;
padding: 0;
border: 0.5px solid rgba(0, 0, 0, 0);
box-sizing: border-box;
border-radius: 8px;
font-family:'overpass-mono';
overflow: hidden;
-webkit-font-smoothing: antialiased;
}
a:visited, a:active, a {
color: #95E6CB;
outline: none;
}
#bar {
background: #151517;
height: 50px;
padding-top: 12px;
padding-right: 8px;
padding-left: 8px;
margin-left: auto;
margin-right: auto;
border-radius: none;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
color: #FFF;
white-space: nowrap;
box-sizing: border-box;
position: relative;
z-index: 2;
width: calc(100vw + 2px);
left: -2px;
top: -2px;
}
#bar > * {
-webkit-app-region: no-drag;
}
#win-ctrl {
display: none;
}
#window-controls {
-webkit-app-region: drag;
padding: 0;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
white-space: nowrap;
position: fixed;
z-index: 100;
width: 100%;
left: 0;
top: 0;
}
pear-ctrl[data-platform=darwin] {
margin-top: 22px;
margin-left: 12px;
}
.dialog pear-ctrl[data-platform=darwin] {
margin-top: -32px;
}
.dialog.darwin #bar {
background: rgba(0, 0, 0, 0);
display: block;
}
</style>
</head>
<body>
<div id="window-controls"><pear-ctrl></pear-ctrl></div>
<style>
/* windows styles, every selector *MUST* be preceded by .win32 */
.win32 #win-ctrl {
float: right;
margin-left: .6em;
margin-top: 0.22em;
border-spacing: 0.3em 0;
}
.win32 #win-ctrl > .win-ctrl {
opacity: 0.8;
height: 24px;
width: 24px;
display: table-cell;
vertical-align: middle;
text-align: center;
}
.win32 #win-ctrl > .win-ctrl:hover {
opacity: 1;
}
.win32 #bar {
width: calc(100vw + 8px);
left: -4px;
}
#win-ctrl.max #win-max {
display: none;
}
#win-ctrl.max #win-restore {
display: table-cell;
}
#win-ctrl #win-restore {
display: none;
}
</style>
<template id="decal-upgrade-to-beta-tmpl">
<style>
h1 {
font-size: 24px;
font-weight: bold;
margin-bottom: 20px;
}
ul {
list-style-type: none;
padding: 0;
font-size: 14px;
}
ul > li {
margin-bottom: 12px;
}
p {
font-size: 14px;
margin-top: 1em;
}
ul > li::before {
content: '✨';
margin-right: 4px;
}
.advise {
line-height: 1.5em;
}
</style>
<div>
<h1>Upgrade Keet to try new features!</h2>
<p> Upgrade from ALPHA to BETA and access awesome new features such as:</p>
<ul>
<li>Create BIG ROOMS with thousands of peers</li>
<li>Message reactions! 🤘🚀😎</li>
<li>Improved performance for large rooms</li>
<li>New moderation features</li>
<li>... and much more!</li>
</ul>
<p class="advise">Note that Keet BETA is not compatible with Keet mobile <2.0<br>You can switch between BETA and ALPHA anytime. No data will be lost!</p>
</div>
</template>
<template id="decal-downgrade-to-alpha-tmpl">
<style>
h1 {
font-size: 24px;
font-weight: bold;
margin-bottom: 20px;
}
p {
font-size: 14px;
margin-top: 1em;
}
</style>
<div>
<h1>Switch Keet back to ALPHA</h1>
<p>Switch from BETA to ALPHA to see your old rooms.</p>
<p>You won't be able to use the new Keet features while you are on ALPHA.</p>
<p>You can switch back to BETA again anytime. No data will be lost!</p>
</div>
</template>
<template id="decal-upgrade-to-beta-button-tmpl">
<style>
#text {
background: linear-gradient(180deg, #00FFCF 0%, #4AA6FF 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
text-fill-color: transparent;
}
svg {
margin-top: 3px;
margin-bottom: -4px;
margin-left: -1px;
margin-right: 2px;
}
</style>
<svg width="19" height="19" viewBox="0 0 19 19" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11.9258 5.62891L11.4688 3.90625L9.74609 3.44922C9.60547 3.37891 9.5 3.23828 9.5 3.0625C9.5 2.92188 9.60547 2.78125 9.74609 2.71094L11.4688 2.21875L11.9258 0.53125C11.9961 0.390625 12.1367 0.25 12.3125 0.25C12.4531 0.25 12.5938 0.390625 12.6641 0.53125L13.1562 2.21875L14.8438 2.71094C14.9844 2.78125 15.125 2.92188 15.125 3.0625C15.125 3.23828 14.9844 3.37891 14.8438 3.44922L13.1562 3.90625L12.6641 5.62891C12.5938 5.76953 12.4531 5.875 12.3125 5.875C12.1367 5.875 11.9961 5.76953 11.9258 5.62891ZM4.54297 12.4492C4.96484 12.8359 5.14062 13.3633 5.03516 13.9258L4.71875 15.8594L6.44141 14.9453C6.93359 14.6992 7.53125 14.6992 8.02344 14.9453L9.74609 15.8594L9.42969 13.9258C9.32422 13.3984 9.5 12.8359 9.92188 12.4492L11.3281 11.043L9.35938 10.7617C8.83203 10.6914 8.33984 10.3398 8.09375 9.84766L7.21484 8.08984L6.37109 9.84766C6.125 10.3398 5.63281 10.6914 5.10547 10.7617L3.13672 11.043L4.54297 12.4492ZM6.47656 5.80469C6.79297 5.17188 7.67188 5.17188 7.98828 5.80469L9.60547 9.10938L13.2617 9.63672C13.9297 9.74219 14.2109 10.5859 13.7188 11.0781L11.082 13.6445L11.7148 17.2656C11.8203 17.9688 11.1172 18.4961 10.4844 18.1797L7.21484 16.457L3.98047 18.1797C3.34766 18.4961 2.64453 17.9688 2.75 17.2656L3.38281 13.6445L0.746094 11.0781C0.253906 10.5859 0.5 9.74219 1.20312 9.63672L4.85938 9.10938L6.47656 5.80469ZM15.5469 8.82812L14.2109 8.44141C14.0703 8.40625 14 8.26562 14 8.125C14 8.01953 14.0703 7.87891 14.2109 7.84375L15.5469 7.45703L15.9336 6.12109C15.9688 5.98047 16.1094 5.875 16.25 5.875C16.3555 5.875 16.4961 5.98047 16.5312 6.12109L16.918 7.45703L18.2539 7.84375C18.3945 7.87891 18.5 8.01953 18.5 8.125C18.5 8.26562 18.3945 8.40625 18.2539 8.44141L16.918 8.82812L16.5312 10.1641C16.4961 10.3047 16.3555 10.375 16.25 10.375C16.1094 10.375 15.9688 10.3047 15.9336 10.1641L15.5469 8.82812Z" fill="url(#paint0_linear_6964_93237)"/>
<defs>
<linearGradient id="paint0_linear_6964_93237" x1="9.5" y1="1" x2="9.5" y2="17" gradientUnits="userSpaceOnUse">
<stop stop-color="#00FFCF"/>
<stop offset="1" stop-color="#4AA6FF"/>
</linearGradient>
</defs>
</svg>
<span id="text">Upgrade to Beta</span>
</template>
<template id="decal-downgrade-to-alpha-button-tmpl">
<style>
#text {
background: linear-gradient(180deg, #00FFCF 0%, #4AA6FF 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
text-fill-color: transparent;
}
svg {
margin-top: 3px;
margin-bottom: -4px;
margin-left: -1px;
margin-right: 2px;
}
</style>
<svg width="19" height="19" viewBox="0 0 19 19" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1 9.21484V8.93359C1.17578 6.12109 3.53125 3.90625 6.34375 3.90625H13.8672L11.9336 1.97266C11.582 1.65625 11.582 1.12891 11.9336 0.777344C12.25 0.460938 12.7773 0.460938 13.1289 0.777344L16.5039 4.15234C16.8203 4.50391 16.8203 5.03125 16.5039 5.34766L13.1289 8.72266C12.7773 9.07422 12.25 9.07422 11.9336 8.72266C11.582 8.40625 11.582 7.87891 11.9336 7.52734L13.8672 5.59375H6.34375C4.41016 5.59375 2.79297 7.10547 2.6875 9.03906V9.32031C2.65234 9.77734 2.23047 10.1289 1.77344 10.0938C1.31641 10.0938 0.964844 9.67188 1 9.21484ZM18.9648 9.32031H19L18.9648 9.60156C18.7891 12.4141 16.4688 14.5938 13.6211 14.5938H6.09766L8.03125 16.5273C8.38281 16.8789 8.38281 17.4062 8.03125 17.7227C7.71484 18.0742 7.1875 18.0742 6.87109 17.7227L3.49609 14.3477C3.14453 14.0312 3.14453 13.5039 3.49609 13.1523L6.87109 9.8125C7.1875 9.46094 7.71484 9.46094 8.03125 9.8125C8.38281 10.1289 8.38281 10.6562 8.03125 10.9727L6.09766 12.9062H13.6211C15.5547 12.9062 17.1719 11.4297 17.2773 9.49609L17.3125 9.21484C17.3125 8.75781 17.7344 8.40625 18.1914 8.40625C18.6484 8.44141 19 8.86328 18.9648 9.32031Z" fill="#26D2E8"/>
</svg>
<span id="text">Switch to Alpha</span>
</template>
<template id="decal-dialog-tmpl">
<style>
#dialog {
width: 500px;
height: 340px;
position: absolute;
top: 40px;
left: 0px;
background-color: #25262C;
padding: 35px;
font-family: "Inter", sans-serif;
z-index: 99;
}
#header {
color: #FFFFFF;
font-size: 18px;
margin-left: 50px;
}
#p1 {
color: #FFFFFF;
margin-top: 30px;
margin-bottom: 5px;
font-size: 14px;
font-weight: 400;
}
#key {
color:#B0D944;
font-size: 14px;
font-weight: 600;
margin-top: 0px;
margin-bottom: 25px;
}
#p2 {
color: #ACB1BB;
font-size: 14px;
font-weight: 400;
}
#p2 > span {
color: #FFFFFF;
font-weight: 600;
}
input {
display: block;
padding: 16px 16px 16px 16px;
border: 2px solid #4A4E56;
color: #5E636D;
background-color: #202126;
width: 90%;
font-size: 14px;
border-radius: 8px;
margin-top: 25px;
outline: none;
}
#cancel, #confirm {
border: 2px solid #4A4E56;
color: #FFFFFF;
font-weight: 600;
background-color: #202126;
border-radius: 8px;
font-size: 16px;
width: 48%;
height: 55px;
}
#confirm.green-confirm, #cancel {
cursor: pointer;
}
#cancel {
margin-right: 2%;
}
#logo {
float: left;
}
#confirm {
background-color: #4A4E56;
color: #8C919D;
}
.green-confirm {
color: #B0D944 !important;
background-color: #222E02 !important;
border: 2px solid #B0D944 !important;
}
#error {
color: #FF6161;
font-size: 12px;
margin-bottom: 30px;
visibility: hidden;
}
.show {
visibility: visible !important;
}
</style>
<div id="dialog">
<svg id="logo" width="36" height="37" viewBox="0 0 36 37" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M17.7632 2.75H19.3421V5.7125H17.7632V2.75Z" fill="#B0D944"/>
<path d="M16.9737 6.65V7.25H15.3947V8H21.7105V7.25H20.1316V6.0875H18.5526V6.65H16.9737Z" fill="#B0D944"/>
<path d="M23.2895 8.375H18.5526V8.9375H13.8158V10.2875H23.2895V8.375Z" fill="#B0D944"/>
<path d="M24.8684 10.6625H18.5526V11.225H12.2368V12.575H24.8684V10.6625Z" fill="#B0D944"/>
<path d="M24.8684 12.95H18.5526V13.5125H12.2368V14.8625H24.8684V12.95Z" fill="#B0D944"/>
<path d="M26.4474 15.2375H18.5526V15.8H10.6579V17.15H26.4474V15.2375Z" fill="#B0D944"/>
<path d="M26.4474 17.525H18.5526V18.0875H10.6579V19.4375H26.4474V17.525Z" fill="#B0D944"/>
<path d="M28.0263 19.8125H18.5526V20.375H9.07895V21.725H28.0263V19.8125Z" fill="#B0D944"/>
<path d="M29.6053 22.1H18.5526V22.6625H7.5V24.0125H29.6053V22.1Z" fill="#B0D944"/>
<path d="M29.6053 24.3875H18.5526V24.95H7.5V26.3H29.6053V24.3875Z" fill="#B0D944"/>
<path d="M29.6053 26.675H18.5526V27.2375H7.5V28.5875H29.6053V26.675Z" fill="#B0D944"/>
<path d="M26.4474 28.9625H18.5526V29.525H10.6579V30.875H26.4474V28.9625Z" fill="#B0D944"/>
<path d="M23.2895 31.25H18.5526V31.8125H13.8158V32.75H23.2895V31.25Z" fill="#B0D944"/>
<path d="M19.5 24.7143L27.75 20L36 24.7143V25.5627C36 30.6414 32.6333 35.1048 27.75 36.5C22.8667 35.1048 19.5 30.6414 19.5 25.5627V24.7143Z" fill="#E44B44"/>
<path d="M27.75 25.1562V29.5562M27.75 32.3062V32.3172" stroke="#391C20" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
<h1 id="header"></h1>
<p id="p1"></p>
<p id="key"></p>
<p id="p2"></p>
<input type="text"></input>
<p id="error">Please, enter TRUST (uppercase) </p>
<button id="cancel">Cancel</button>
<button id="confirm">Confirm</button>
</div>
</template>
<script type="module">
class DecalDialog extends HTMLElement {
constructor () {
super()
const template = document.querySelector('#decal-dialog-tmpl').content
this.root = this.attachShadow({mode: 'open'})
this.root.appendChild(template.cloneNode(true))
this.confirm = this.root.querySelector('#confirm')
this.cancel = this.root.querySelector('#cancel')
this.input = this.root.querySelector('input')
this.error = this.root.querySelector('#error')
this.header = this.root.querySelector('#header')
this.p1 = this.root.querySelector('#p1')
this.p2 = this.root.querySelector('#p2')
this.key = null
this.ipc = null
this.cancel.addEventListener('click', async () => {
await Pear.Window.self.close()
})
}
#update () {
this.header.innerText = this.dataset.header
this.p1.innerText = this.dataset.p1
this.p2.innerHTML = this.dataset.p2
this.input.placeholder = this.dataset.placeholder
}
get options () {
return this.dataset
}
set options (opts) {
Object.assign(this.dataset, opts)
this.#update()
}
setLink (link) {
this.root.querySelector('#key').innerText = link
}
}
class TrustDialog extends DecalDialog {
constructor () {
super()
this.input.addEventListener('keyup', this.#onKeyup.bind(this))
this.confirm.addEventListener('click', this.#onClick.bind(this))
}
async #permit () {
await this.ipc.permit({ key: this.key })
await this.ipc.restart({ id: this.gid })
}
#onKeyup (event) {
const value = event.target.value
if (value === 'TRUST') {
this.confirm.classList.add('green-confirm')
} else {
this.confirm.classList.remove('green-confirm')
}
if (value === 'trust') {
this.error.classList.add('show')
} else {
this.error.classList.remove('show')
}
}
async #onClick () {
if (this.input.value === 'TRUST') await this.#permit()
}
}
class PasswordDialog extends DecalDialog {
constructor () {
super()
this.input.type = 'password'
this.input.addEventListener('keyup', this.#onKeyup.bind(this))
this.confirm.addEventListener('click', this.#onClick.bind(this))
}
async #permit () {
const password = this.input.value
const hypercoreid = window[Symbol.for('hypercore-id-encoding')]
const t = await this.ipc.permit({ key: this.key, password })
await this.ipc.restart({ id: this.gid })
}
#onKeyup (event) {
const value = event.target.value
if (value.length > 0) {
this.confirm.classList.add('green-confirm')
} else {
this.confirm.classList.remove('green-confirm')
}
}
async #onClick () {
if (this.input.value.length > 0) await this.#permit()
}
}
customElements.define('trust-dialog', TrustDialog)
customElements.define('password-dialog', PasswordDialog)
</script>
<div id="bar">
<script type="module">
import constants from './constants.js'
const hypercoreid = window[Symbol.for('hypercore-id-encoding')]
if (Pear.config.key) {
if (hypercoreid.normalize(Pear.config.key) !== hypercoreid.normalize(constants.ALIASES.keet)) {
if (Pear.config.options.platform?.__legacyTitlebar) {
document.getElementById('bar').style.display = 'block'
const winctrl = document.getElementById('window-controls')
const clone = winctrl.cloneNode()
global.winctrl = clone
}
}
}
</script>
<div id="win-ctrl">
<div id="win-min" class="win-ctrl">
<svg width="18" height="2" viewBox="0 0 18 2" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 0.5625C0 0.28125 0.246094 0 0.5625 0H17.4375C17.7188 0 18 0.28125 18 0.5625C18 0.878906 17.7188 1.125 17.4375 1.125H0.5625C0.246094 1.125 0 0.878906 0 0.5625Z" fill="white"/>
</svg>
</div>
<div id="win-max" class="win-ctrl">
<svg width="18" height="17" viewBox="0 0 18 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 2.625C0 1.39453 0.984375 0.375 2.25 0.375H15.75C16.9805 0.375 18 1.39453 18 2.625V13.875C18 15.1406 16.9805 16.125 15.75 16.125H2.25C0.984375 16.125 0 15.1406 0 13.875V2.625ZM1.125 2.625V6H16.875V2.625C16.875 2.02734 16.3477 1.5 15.75 1.5H2.25C1.61719 1.5 1.125 2.02734 1.125 2.625ZM1.125 7.125V13.875C1.125 14.5078 1.61719 15 2.25 15H15.75C16.3477 15 16.875 14.5078 16.875 13.875V7.125H1.125Z" fill="white"/>
</svg>
</div>
<div id="win-restore" class="win-ctrl">
<svg width="18" height="19" viewBox="0 0 18 19" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M15.1875 1.375H7.3125C6.36328 1.375 5.625 2.14844 5.625 3.0625V3.625H4.5V3.0625C4.5 1.51562 5.73047 0.25 7.3125 0.25H15.1875C16.7344 0.25 18 1.51562 18 3.0625V10.9375C18 12.5195 16.7344 13.75 15.1875 13.75H14.625V12.625H15.1875C16.1016 12.625 16.875 11.8867 16.875 10.9375V3.0625C16.875 2.14844 16.1016 1.375 15.1875 1.375ZM11.25 4.75C12.4805 4.75 13.5 5.76953 13.5 7V16C13.5 17.2656 12.4805 18.25 11.25 18.25H2.25C0.984375 18.25 0 17.2656 0 16V7C0 5.76953 0.984375 4.75 2.25 4.75H11.25ZM11.25 5.875H2.25C1.61719 5.875 1.125 6.40234 1.125 7V9.25H12.375V7C12.375 6.40234 11.8477 5.875 11.25 5.875ZM2.25 17.125H11.25C11.8477 17.125 12.375 16.6328 12.375 16V10.375H1.125V16C1.125 16.6328 1.61719 17.125 2.25 17.125Z" fill="white"/>
</svg>
</div>
<div id="win-close" class="win-ctrl">
<svg id="win-close" width="16" height="17" viewBox="0 0 16 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14.8906 0.550781C15.1016 0.339844 15.4883 0.339844 15.6992 0.550781C15.9102 0.761719 15.9102 1.14844 15.6992 1.35938L8.77344 8.25L15.6992 15.1758C15.9102 15.3867 15.9102 15.7734 15.6992 15.9844C15.4883 16.1953 15.1016 16.1953 14.8906 15.9844L8 9.05859L1.07422 15.9844C0.863281 16.1953 0.476562 16.1953 0.265625 15.9844C0.0546875 15.7734 0.0546875 15.3867 0.265625 15.1758L7.19141 8.25L0.265625 1.35938C0.0546875 1.14844 0.0546875 0.761719 0.265625 0.550781C0.476562 0.339844 0.863281 0.339844 1.07422 0.550781L8 7.47656L14.8906 0.550781Z" fill="white"/>
</svg>
</div>
</div>
<script type="module">
document.querySelector('#bar').addEventListener('dblclick', async (evt) => {
if (evt.target !== evt.currentTarget) return
if (await Pear.Window.self.isMaximized()) await Pear.Window.self.restore()
else await Pear.Window.self.maximize()
})
if (process.platform === 'win32') {
document.querySelector('#win-min').addEventListener('click', async () => { await Pear.Window.self.minimize() })
document.querySelector('#win-max').addEventListener('click', async () => {
await Pear.Window.self.maximize()
document.querySelector('#win-ctrl').classList.add('max')
})
document.querySelector('#win-restore').addEventListener('click', async () => {
await Pear.Window.self.restore()
document.querySelector('#win-ctrl').classList.remove('max')
})
}
</script>
</div>
<decal-report>
<span slot="headline"></span>
<span slot="tagline"></span>
<span slot="cta"></span>
<template id="decal-report-tmpl">
<style>
#status {
display: none;
color: white;
padding: 2em;
}
#headline {
font-weight: 800;
font-family: 'overpass';
font-size: 2em;
margin-top: 20vh;
margin-bottom: 0.6em;
}
#tagline {
font-family: 'Open Sans';
font-size: .875em;
font-weight: 400;
margin-bottom: 2em;
}
#cta {
font-family: 'Open Sans';
cursor: pointer;
border-radius: 8px;
height: 44px;
box-sizing: border-box;
display: inline-block;
font-weight: 700;
font-size: 14px;
padding: 28px;
margin-top: 24px;
color: rgba(29, 110, 83, 1);
background: #95E6CB;
backdrop-filter: blur(48px);
width: auto;
line-height: 0;
border: none;
outline: none;
letter-spacing: 0.6px;
}
</style>
<div id="status">
<div id="headline">
<slot name="headline">HEADLINE</slot>
</div>
<div id="tagline">
<slot name="tagline">TAGLINE</slot>
</div>
<button id="cta"><slot name="cta">CTA</slot></button>
</div>
</template>
<script type="module">
customElements.define('decal-report', class extends HTMLElement {
ipc = Pear[Symbol.for('pear.ipc')]
status = null
static get observedAttributes() { return ['show', 'action'] }
attributeChangedCallback(name, prior, value) {
if (name === 'show') {
if (value) this.shadowRoot.querySelector('#status').style.display = 'block'
else this.shadowRoot.querySelector('#status').style.display = ''
}
if (name === 'action') {
const cta = this.shadowRoot.querySelector('#cta')
const code = (value === 'reload') ? 64 : 0
const handler = (value === 'quit' || value === 'reload') ?
() => Pear.exit(code) :
() => {}
cta.addEventListener('click', handler)
}
}
show (type) { this.setAttribute("show", type) }
hide () { this.setAttribute("show", "") }
async subscribe (ipc, loader) {
this.ipc = ipc
for await (const report of ipc.reports()) {
this.status = report
this.gid = Pear.Window.self.id
loader.hide()
const { type, headline, tagline, cta, key, encrypted } = this.status
if (type === 'update' && this.status.version?.force) {
await loader.updating(this.status.version)
continue
}
if (type === 'permissionRequired') {
const permitDialog = encrypted ? document.createElement('password-dialog') : document.createElement('trust-dialog')
const ctrl = document.createElement('pear-ctrl')
ctrl.dataset.maximizable = false
document.documentElement.classList.add('dialog')
document.body.appendChild(ctrl)
const trustOpts = {
header: 'Unknown app',
p1: 'This application has not been run before:',
p2: 'Type <span>TRUST</span> to continue if you know it is safe to open and to prevent showing this dialog again. <span> Only open trusted sources.</span>',
placeholder: 'Type TRUST to confirm'
}
const passwordOpts = {
header: 'Encrypted app',
p1: 'This application is encrypted:',
p2: 'Type the password',
placeholder: 'Password'
}
permitDialog.options = encrypted ? passwordOpts : trustOpts
document.body.appendChild(permitDialog)
const hypercoreid = window[Symbol.for('hypercore-id-encoding')]
const z32 = hypercoreid.encode(key)
permitDialog.setLink(`pear://${z32}`)
permitDialog.key = key
permitDialog.ipc = ipc
await this.ipc.setSize({ id: this.gid, width: 560, height: 450 })
await this.ipc.detachMainView({ id: this.gid })
continue
}
this.querySelector('[slot="headline"]').innerHTML = headline.content
this.querySelector('[slot="tagline"]').innerHTML = tagline.content
this.querySelector('[slot="cta"]').innerHTML = cta.content
this.setAttribute("action", cta.action)
await this.ipc.detachMainView({ id: this.gid })
const winctrl = document.getElementById('windows-controls')
if (!winctrl) {
const div = document.createElement('div')
div.id = 'windows-controls'
div.appendChild(document.createElement('pear-ctrl'))
document.body.prepend(div)
}
this.show(type)
await this.ipc.detachMainView({ id: this.gid })
}
}
constructor () {
super()
this.ipc = Pear[Symbol.for('pear.ipc')]
const template = document.querySelector('#decal-report-tmpl').content
this.attachShadow({mode: 'open'}).appendChild(template.cloneNode(true))
}
})
</script>
</decal-report>
<decal-loader>
<span slot="update-length"></span>
<span slot="when"></span>
<template id="decal-loader-tmpl">
<style>
#loader {
display: none;
}
#loader {
position: absolute;
left: 0;
right: 0;
width: 100%;
text-align: center;
top: 50%;
transform: translateY(-50%);
}
#logo {
animation: beat 1.1s infinite normal;
transform-origin: center;
display: block;
margin: auto;
}
@keyframes beat {
15% {
transform: scale(1.12);
}
30% {
transform: scale(1.0);
}
43% {
transform: scale(1.05);
}
67% {
transform: scale(1.0);
}
}
#update {
display: none;
margin: 0 auto;
margin-bottom: -4em;
color: #fff;
padding: 8px;
position: fixed;
bottom: 0;
left: 0;
font-size: 0.9em;
padding-bottom: 6em;
padding-left: 3em;
width: 50%;
min-width: 600px;
transform: translateY(140%);
}
#update h2 {
margin-bottom: .5rem;
}
#update th {
font-weight: bold;
text-align: left;
}
#update td:first-child {
text-align: right;
}
#update td:nth-child(2) {
text-align: left;
}
</style>
<div id="loader">
<svg id="logo" width="102" height="146" viewBox="0 0 102 146" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_8912_10861)">
<path d="M47.4056 0.838379H54.5943V15.0361H47.4056V0.838379Z" fill="#B0D944"/>
<path d="M43.8113 19.5305V22.406H36.6226V26.0004H65.3774V22.406H58.1887V16.8347H51V19.5305H43.8113Z" fill="#B0D944"/>
<path d="M72.5662 27.7974H51V30.4931H29.4339V36.963H72.5662V27.7974Z" fill="#B0D944"/>
<path d="M79.7548 38.7593H51V41.455H22.2451V47.9249H79.7548V38.7593Z" fill="#B0D944"/>
<path d="M79.7548 49.7219H51V52.4177H22.2451V58.8875H79.7548V49.7219Z" fill="#B0D944"/>
<path d="M86.9436 60.6846H51V63.3803H15.0565V69.8502H86.9436V60.6846Z" fill="#B0D944"/>
<path d="M86.9436 71.6481H51V74.3438H15.0565V80.8137H86.9436V71.6481Z" fill="#B0D944"/>
<path d="M94.1323 82.61H51V85.3058H7.86774V91.7756H94.1323V82.61Z" fill="#B0D944"/>
<path d="M101.321 93.5726H51V96.2684H0.679016V102.738H101.321V93.5726Z" fill="#B0D944"/>
<path d="M101.321 104.536H51V107.232H0.679016V113.702H101.321V104.536Z" fill="#B0D944"/>
<path d="M101.321 115.499H51V118.195H0.679016V124.664H101.321V115.499Z" fill="#B0D944"/>
<path d="M86.9436 126.461H51V129.156H15.0565V135.626H86.9436V126.461Z" fill="#B0D944"/>
<path d="M72.5662 137.424H51V140.12H29.4339V144.613H72.5662V137.424Z" fill="#B0D944"/>
</g>
<defs>
<clipPath id="clip0_8912_10861">
<rect width="100.642" height="145.571" fill="white" transform="translate(0.679016 0.214233)"/>
</clipPath>
</defs>
</svg>
<table id="update">
<tr>
<th colspan="2" style="color: #95E6CB;">Auto Updating to <slot name="update-length"></slot>...</th>
</tr>
<tr id=hint>
<td colspan="2" style="text-align:left!important;text-indent:.2em">Application(s) will restart <slot name="when">after update</slot></th>
</tr>
</table>
</div>
</template>
<script type="module">
customElements.define('decal-loader', class extends HTMLElement {
#updating = false
async updating ({ force, key, length, fork, current }) {
if (!force) return
this.#updating = true
this.querySelector('[slot="update-length"]').innerHTML = length
this.shadowRoot.querySelector('#update').style.display = 'block'
this.show()
await this.ipc.detachMainView({ id: Pear.Window.self.id })
}
show () {
this.shadowRoot.querySelector('#loader').style.display = 'block'
document.getElementById('bar').style.display = 'block'
}
hide () {
this.shadowRoot.querySelector('#loader').style.display = 'none'
document.getElementById('bar').style.display = 'none'
}
async restart () {
let countdown = 3000
while (countdown > 0) {
this.querySelector('[slot="when"]').innerText = `in ${countdown/1000} seconds`
await new Promise((resolve) => setTimeout(resolve, 1000))
countdown -= 1000
}
this.querySelector('[slot="when"]').innerText = 'as of now!'
await this.ipc.restart()
}
async start (ipc, config) {
this.show()
this.ipc = ipc
await ipc.afterViewLoaded({ id: Pear.Window.self.id })
if (this.#updating) return true
this.hide()
const ctrl = document.querySelector('#window-controls pear-ctrl')
ctrl.remove()
document.getElementById('window-controls').remove()
await ctrl.closing
await ipc.attachMainView({ id: Pear.Window.self.id })
}
constructor () {
super()
const template = document.querySelector('#decal-loader-tmpl').content
this.attachShadow({mode: 'open'}).appendChild(template.cloneNode(true))
}
})
</script>
</decal-loader>
<script type="module">
const { message, messages } = Pear
const ipc = Pear[Symbol.for('pear.ipc')]
const loader = document.querySelector('decal-loader')
messages({ type: 'pear/handover' }, () => {
// legacy, ignore
})
const report = document.querySelector('decal-report')
report.subscribe(ipc, loader)
process.on('exit', (code) => {
const actuallyARefresh = code === undefined
if (actuallyARefresh) return
Pear.exit(code)
})
async function start () {
const win32CloseListener = process.platform === 'win32' ? () => Pear.exit(0) : null
if (process.platform === 'win32') document.querySelector('#win-close').addEventListener('click', win32CloseListener)
let config = Pear.config
if (process.platform === 'win32') {
const close = document.querySelector('#win-close')
close.removeEventListener('click', win32CloseListener)
close.addEventListener('click', async () => {
await Pear.Window.self.close()
})
}
const updating = await loader.start(ipc, config)
if (updating) return
}
start().catch(console.error)
</script>
</body>
</html>