window.nostr.js 0.3.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/iframe.js +22 -0
- package/dist/iframe.js.map +7 -0
- package/dist/index.html +2 -27
- package/dist/window.nostr.js +15 -9
- package/iframe/build.js +9 -0
- package/iframe/iframe.ts +28 -0
- package/index.html +1 -26
- package/justfile +8 -2
- package/package.json +4 -3
- package/src/App.svelte +105 -54
- package/src/main.ts +8 -8
- package/src/mediaQueryStore.ts +25 -0
- package/tsconfig.json +4 -3
- package/src/mediaQueryStore.js +0 -33
package/iframe/build.js
ADDED
package/iframe/iframe.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const SHARED_BUNKER_KEY = 'wnj:root:sharedBunker'
|
|
2
|
+
|
|
3
|
+
window.onmessage = async (ev: MessageEvent) => {
|
|
4
|
+
const {bunker, getbunker} = ev.data
|
|
5
|
+
|
|
6
|
+
// set the bunker URL
|
|
7
|
+
if (bunker) {
|
|
8
|
+
// we only accept these websites to be setting the bunker URL
|
|
9
|
+
if (
|
|
10
|
+
!ev.origin.startsWith('https://join.the-nostr.org') &&
|
|
11
|
+
!ev.origin.startsWith('http://localhost:6711')
|
|
12
|
+
) {
|
|
13
|
+
return
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (bunker) {
|
|
17
|
+
localStorage.setItem(SHARED_BUNKER_KEY, bunker)
|
|
18
|
+
} else {
|
|
19
|
+
console.error('wnj iframe got an invalid bunker url:', bunker)
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (getbunker) {
|
|
24
|
+
// any website can get the bunker URL if it is set
|
|
25
|
+
const bunker = localStorage.getItem(SHARED_BUNKER_KEY)
|
|
26
|
+
window.parent.postMessage({bunker}, '*') // we reply even if it's undefined so they know
|
|
27
|
+
}
|
|
28
|
+
}
|
package/index.html
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"
|
|
16
16
|
>
|
|
17
17
|
<main>
|
|
18
|
-
<h1>
|
|
18
|
+
<h1>Lorem Ipsum</h1>
|
|
19
19
|
<p>
|
|
20
20
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed et ex dui.
|
|
21
21
|
Donec eu dui sed massa auctor rhoncus. Nunc mollis, metus nec
|
|
@@ -34,31 +34,6 @@
|
|
|
34
34
|
mollis sit amet. Cras sit amet mi sit amet eros convallis pulvinar.
|
|
35
35
|
Donec condimentum condimentum tincidunt.
|
|
36
36
|
</p>
|
|
37
|
-
|
|
38
|
-
<p>
|
|
39
|
-
Suspendisse eu ipsum vel lorem congue mattis in at neque. Phasellus nec
|
|
40
|
-
felis sit amet nibh bibendum tristique a quis urna. Pellentesque laoreet
|
|
41
|
-
porta libero eget pellentesque. Praesent tempor, nisi et efficitur
|
|
42
|
-
cursus, leo nunc ullamcorper ante, quis eleifend velit justo sed enim.
|
|
43
|
-
Maecenas laoreet dictum lorem rhoncus tempus. Integer ipsum augue,
|
|
44
|
-
sagittis a facilisis et, mollis ut ipsum. Proin elementum consectetur
|
|
45
|
-
tincidunt.
|
|
46
|
-
</p>
|
|
47
|
-
|
|
48
|
-
<p>
|
|
49
|
-
Mauris nec mi et quam semper volutpat. Morbi suscipit felis lectus, in
|
|
50
|
-
ornare purus pretium in. Maecenas et ex metus. Ut aliquam, felis vel
|
|
51
|
-
mollis dapibus, tellus velit blandit dui, eu hendrerit tellus magna at
|
|
52
|
-
eros. Donec scelerisque hendrerit auctor. Aenean aliquet sapien
|
|
53
|
-
elementum dui sagittis eleifend. Donec hendrerit odio et dui lacinia
|
|
54
|
-
aliquet. Morbi auctor ultrices dui fringilla elementum. Curabitur
|
|
55
|
-
scelerisque lorem vitae placerat vulputate. Donec vestibulum urna sem,
|
|
56
|
-
at sodales ligula laoreet id. Etiam vehicula, lorem id tincidunt
|
|
57
|
-
sodales, sem odio vehicula ex, vel condimentum quam augue id augue.
|
|
58
|
-
Integer a varius nunc. Mauris rhoncus leo sed facilisis bibendum. Nullam
|
|
59
|
-
consectetur pellentesque vestibulum. Cras hendrerit feugiat orci, in
|
|
60
|
-
molestie risus rutrum ut. Proin dictum nunc at rutrum vehicula.
|
|
61
|
-
</p>
|
|
62
37
|
</main>
|
|
63
38
|
<!-- <script>
|
|
64
39
|
window.wnjParams = {
|
package/justfile
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
export PATH := "./node_modules/.bin:" + env_var('PATH')
|
|
2
|
+
set unstable
|
|
2
3
|
|
|
3
4
|
dev:
|
|
4
|
-
vite
|
|
5
|
+
vite --port 13471
|
|
5
6
|
|
|
6
|
-
build:
|
|
7
|
+
build: wnj iframe
|
|
8
|
+
|
|
9
|
+
wnj:
|
|
7
10
|
vite build
|
|
8
11
|
mv dist/assets/*.js dist/window.nostr.js
|
|
9
12
|
|
|
13
|
+
iframe:
|
|
14
|
+
node ./iframe/build.js
|
|
15
|
+
|
|
10
16
|
demo:
|
|
11
17
|
xdg-open demo/index.html
|
|
12
18
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "window.nostr.js",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/window.nostr.js",
|
|
6
6
|
"devDependencies": {
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
"@tsconfig/svelte": "^5.0.2",
|
|
9
9
|
"@typescript-eslint/eslint-plugin": "^7.0.1",
|
|
10
10
|
"autoprefixer": "^10.4.17",
|
|
11
|
+
"esbuild": "^0.24.0",
|
|
11
12
|
"eslint-config-prettier": "^9.1.0",
|
|
12
13
|
"eslint-plugin-svelte": "^2.35.1",
|
|
13
14
|
"postcss": "^8.4.35",
|
|
@@ -22,7 +23,7 @@
|
|
|
22
23
|
"vite": "^5.1.0"
|
|
23
24
|
},
|
|
24
25
|
"dependencies": {
|
|
25
|
-
"debounce": "
|
|
26
|
-
"nostr-tools": "2.
|
|
26
|
+
"debounce": "2.0.0",
|
|
27
|
+
"nostr-tools": "^2.9.1"
|
|
27
28
|
}
|
|
28
29
|
}
|
package/src/App.svelte
CHANGED
|
@@ -25,12 +25,14 @@
|
|
|
25
25
|
import Spinner from './Spinner.svelte'
|
|
26
26
|
|
|
27
27
|
const mobileMode = mediaQueryStore('only screen and (max-width: 640px)')
|
|
28
|
-
const
|
|
28
|
+
const lskeys = {
|
|
29
29
|
ORIGIN: 'wnj:origin',
|
|
30
30
|
CLIENT_SECRET: 'wnj:clientSecret',
|
|
31
31
|
Y_POS: 'wnj:ypos',
|
|
32
32
|
CALLBACK_TOKEN: 'wnj:callbackToken',
|
|
33
|
-
BUNKER_POINTER: 'wnj:bunkerPointer'
|
|
33
|
+
BUNKER_POINTER: 'wnj:bunkerPointer',
|
|
34
|
+
CACHED_PUBKEY: 'wnj:cachedPubKey',
|
|
35
|
+
IGNORE_IFRAME: 'wnj:ignoreIframe'
|
|
34
36
|
}
|
|
35
37
|
|
|
36
38
|
let myself: HTMLDivElement
|
|
@@ -38,30 +40,27 @@
|
|
|
38
40
|
export let position: 'top' | 'bottom' = 'top'
|
|
39
41
|
$: origin = $mobileMode
|
|
40
42
|
? 'bottom'
|
|
41
|
-
: (localStorage.getItem(
|
|
42
|
-
|
|
43
|
-
| 'bottom'
|
|
44
|
-
| null) || position
|
|
43
|
+
: (localStorage.getItem(lskeys.ORIGIN) as 'top' | 'bottom' | null) ||
|
|
44
|
+
position
|
|
45
45
|
export let startHidden: boolean
|
|
46
46
|
export let compactMode: boolean
|
|
47
47
|
|
|
48
48
|
const win = window as any
|
|
49
49
|
const pool = new SimplePool()
|
|
50
|
+
let useIframe = false
|
|
51
|
+
let iframe: HTMLIFrameElement | undefined
|
|
50
52
|
let bunkerInput: HTMLInputElement
|
|
51
53
|
let bunkerInputValue: string
|
|
52
54
|
let nameInput: HTMLInputElement
|
|
53
55
|
let nameInputValue: string
|
|
54
56
|
let chosenProvider: BunkerProfile | undefined
|
|
55
57
|
let clientSecret: Uint8Array
|
|
56
|
-
const local = localStorage.getItem(
|
|
58
|
+
const local = localStorage.getItem(lskeys.CLIENT_SECRET)
|
|
57
59
|
if (local) {
|
|
58
60
|
clientSecret = hexToBytes(local)
|
|
59
61
|
} else {
|
|
60
62
|
clientSecret = generateSecretKey()
|
|
61
|
-
localStorage.setItem(
|
|
62
|
-
localStorageKeys.CLIENT_SECRET,
|
|
63
|
-
bytesToHex(clientSecret)
|
|
64
|
-
)
|
|
63
|
+
localStorage.setItem(lskeys.CLIENT_SECRET, bytesToHex(clientSecret))
|
|
65
64
|
}
|
|
66
65
|
|
|
67
66
|
let state: 'opened' | 'closed' | 'justopened' | 'justclosed' = 'closed'
|
|
@@ -97,7 +96,7 @@
|
|
|
97
96
|
export let right = 20
|
|
98
97
|
$: ypos = $mobileMode
|
|
99
98
|
? BASE_YPOS
|
|
100
|
-
: parseInt(localStorage.getItem(
|
|
99
|
+
: parseInt(localStorage.getItem(lskeys.Y_POS) || '0') || BASE_YPOS
|
|
101
100
|
let dragStarted = false
|
|
102
101
|
let hasMoved = false
|
|
103
102
|
let insidePosition: number
|
|
@@ -122,7 +121,7 @@
|
|
|
122
121
|
onauth(url: string) {
|
|
123
122
|
if (creating) {
|
|
124
123
|
showAuth = url
|
|
125
|
-
} else if(identity) {
|
|
124
|
+
} else if (identity) {
|
|
126
125
|
showConfirmAction = url
|
|
127
126
|
opened = true
|
|
128
127
|
} else {
|
|
@@ -169,9 +168,8 @@
|
|
|
169
168
|
let windowNostr = {
|
|
170
169
|
isWnj: true,
|
|
171
170
|
async getPublicKey(): Promise<string> {
|
|
172
|
-
if (bunkerPointer) return bunkerPointer.pubkey
|
|
173
171
|
if (!connecting && !connected) open()
|
|
174
|
-
return (await bunker).
|
|
172
|
+
return (await bunker).getPublicKey()
|
|
175
173
|
},
|
|
176
174
|
async signEvent(event: NostrEvent): Promise<VerifiedEvent> {
|
|
177
175
|
try {
|
|
@@ -218,12 +216,22 @@
|
|
|
218
216
|
|
|
219
217
|
onMount(() => {
|
|
220
218
|
if (!bunkerPointer) {
|
|
221
|
-
let data = localStorage.getItem(
|
|
219
|
+
let data = localStorage.getItem(lskeys.BUNKER_POINTER)
|
|
222
220
|
if (data) {
|
|
223
221
|
bunkerPointer = JSON.parse(data)
|
|
224
|
-
// we have a pointer, which means we can get the public key right away
|
|
225
|
-
// but we will only try to connect when any other method is called on window.nostr
|
|
226
222
|
identify()
|
|
223
|
+
|
|
224
|
+
// we must connect here so identify() works because we can't rely on the bunker params to read our pubkey
|
|
225
|
+
// however we may first check if we have it cached locally before doing the expensive connection
|
|
226
|
+
let cachedPubkey = localStorage.getItem(lskeys.CACHED_PUBKEY)
|
|
227
|
+
if (!cachedPubkey) {
|
|
228
|
+
connect()
|
|
229
|
+
}
|
|
230
|
+
} else {
|
|
231
|
+
// when we don't have any bunker data stored, we can still check the iframe for it
|
|
232
|
+
if (!localStorage.getItem(lskeys.IGNORE_IFRAME)) {
|
|
233
|
+
useIframe = true
|
|
234
|
+
}
|
|
227
235
|
}
|
|
228
236
|
}
|
|
229
237
|
|
|
@@ -256,6 +264,21 @@
|
|
|
256
264
|
}
|
|
257
265
|
})
|
|
258
266
|
|
|
267
|
+
function onIframeLoaded() {
|
|
268
|
+
window.addEventListener('message', handleMessage)
|
|
269
|
+
iframe?.contentWindow?.postMessage({getbunker: true}, '*')
|
|
270
|
+
|
|
271
|
+
async function handleMessage(ev: MessageEvent) {
|
|
272
|
+
let {bunker} = ev.data
|
|
273
|
+
if (bunker) {
|
|
274
|
+
bunkerPointer = await parseBunkerInput(bunker)
|
|
275
|
+
identify()
|
|
276
|
+
connect()
|
|
277
|
+
window.removeEventListener('message', handleMessage)
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
259
282
|
function handleClick(ev: MouseEvent) {
|
|
260
283
|
if (Math.abs(ypos - yposStart) > 6 || Date.now() - clickStart > 600) {
|
|
261
284
|
return
|
|
@@ -318,7 +341,9 @@
|
|
|
318
341
|
|
|
319
342
|
async function handleDisconnect(ev: MouseEvent) {
|
|
320
343
|
ev.preventDefault()
|
|
321
|
-
localStorage.removeItem(
|
|
344
|
+
localStorage.removeItem(lskeys.BUNKER_POINTER)
|
|
345
|
+
localStorage.removeItem(lskeys.CACHED_PUBKEY)
|
|
346
|
+
localStorage.setItem(lskeys.IGNORE_IFRAME, '')
|
|
322
347
|
reset()
|
|
323
348
|
}
|
|
324
349
|
|
|
@@ -391,10 +416,7 @@
|
|
|
391
416
|
try {
|
|
392
417
|
await b.connect()
|
|
393
418
|
connected = true
|
|
394
|
-
localStorage.setItem(
|
|
395
|
-
localStorageKeys.BUNKER_POINTER,
|
|
396
|
-
JSON.stringify(bunkerPointer)
|
|
397
|
-
)
|
|
419
|
+
localStorage.setItem(lskeys.BUNKER_POINTER, JSON.stringify(bunkerPointer))
|
|
398
420
|
close()
|
|
399
421
|
resolveBunker(b)
|
|
400
422
|
} catch (err: any) {
|
|
@@ -410,8 +432,16 @@
|
|
|
410
432
|
}
|
|
411
433
|
}
|
|
412
434
|
|
|
413
|
-
|
|
414
|
-
|
|
435
|
+
// identify() is what gives a name and picture to our floating widget
|
|
436
|
+
async function identify() {
|
|
437
|
+
let pubkey = localStorage.getItem(lskeys.CACHED_PUBKEY)
|
|
438
|
+
if (!pubkey) {
|
|
439
|
+
pubkey = await (await bunker).getPublicKey()
|
|
440
|
+
|
|
441
|
+
// store this pubkey here so we don't have to connect and get our pubkey immediately
|
|
442
|
+
// the next time we open this page
|
|
443
|
+
localStorage.setItem(lskeys.CACHED_PUBKEY, pubkey)
|
|
444
|
+
}
|
|
415
445
|
|
|
416
446
|
identity = {
|
|
417
447
|
pubkey: pubkey,
|
|
@@ -434,8 +464,6 @@
|
|
|
434
464
|
identity!.event = evt
|
|
435
465
|
identity!.name = name
|
|
436
466
|
identity!.picture = picture
|
|
437
|
-
onFirstMetadata?.()
|
|
438
|
-
onFirstMetadata = null
|
|
439
467
|
} catch (err) {
|
|
440
468
|
/***/
|
|
441
469
|
}
|
|
@@ -497,8 +525,8 @@
|
|
|
497
525
|
ypos = BASE_YPOS
|
|
498
526
|
}
|
|
499
527
|
|
|
500
|
-
localStorage.setItem(
|
|
501
|
-
localStorage.setItem(
|
|
528
|
+
localStorage.setItem(lskeys.ORIGIN, origin)
|
|
529
|
+
localStorage.setItem(lskeys.Y_POS, ypos.toString())
|
|
502
530
|
}
|
|
503
531
|
}
|
|
504
532
|
</script>
|
|
@@ -532,18 +560,18 @@
|
|
|
532
560
|
>
|
|
533
561
|
<!-- Connecting view ################### -->
|
|
534
562
|
{#if connecting}
|
|
535
|
-
<div class="flex px-2
|
|
563
|
+
<div class="flex items-center px-2">
|
|
536
564
|
Connecting to bunker
|
|
537
565
|
<Spinner />
|
|
538
566
|
</div>
|
|
539
|
-
{:else if !identity
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
567
|
+
{:else if !identity}
|
|
568
|
+
{#if compactMode}
|
|
569
|
+
<div class="w-6 text-center">N</div>
|
|
570
|
+
{:else}
|
|
571
|
+
<div class="flex items-center px-2">Connect with Nostr</div>
|
|
572
|
+
{/if}
|
|
545
573
|
{:else if !compactMode}
|
|
546
|
-
<div class="flex px-2
|
|
574
|
+
<div class="flex items-center px-2">
|
|
547
575
|
{#if identity.picture}
|
|
548
576
|
<img
|
|
549
577
|
src={identity.picture}
|
|
@@ -551,19 +579,17 @@
|
|
|
551
579
|
class="mr-2 h-5 w-5 rounded-full"
|
|
552
580
|
/>
|
|
553
581
|
{:else}
|
|
554
|
-
|
|
582
|
+
<span class="mr-2">☉</span>
|
|
555
583
|
{/if}
|
|
556
|
-
<div
|
|
584
|
+
<div
|
|
585
|
+
class="inline-block max-w-56 overflow-hidden overflow-ellipsis whitespace-nowrap"
|
|
586
|
+
>
|
|
557
587
|
{identity.name ||
|
|
558
588
|
identity.npub.slice(0, 7) + '…' + identity.npub.slice(-4)}
|
|
559
589
|
</div>
|
|
560
590
|
</div>
|
|
561
591
|
{:else}
|
|
562
|
-
<img
|
|
563
|
-
src={identity.picture}
|
|
564
|
-
alt=""
|
|
565
|
-
class="h-6 w-6 rounded-full"
|
|
566
|
-
/>
|
|
592
|
+
<img src={identity.picture} alt="" class="h-6 w-6 rounded-full" />
|
|
567
593
|
{/if}
|
|
568
594
|
</div>
|
|
569
595
|
|
|
@@ -590,40 +616,57 @@
|
|
|
590
616
|
<div class="m-auto w-full">
|
|
591
617
|
<div class="text-center text-lg">Create a Nostr account</div>
|
|
592
618
|
<div class="mt-4 text-center text-sm leading-4">
|
|
593
|
-
Now you a new window will bring you to <strong
|
|
619
|
+
Now you a new window will bring you to <strong
|
|
620
|
+
>{new URL(showAuth).host}</strong
|
|
621
|
+
>
|
|
622
|
+
where the account creation will take place. If nothing happens check
|
|
623
|
+
that if your browser is blocking popups, pleaase.<br />
|
|
594
624
|
After that you will be returned to this page.
|
|
595
625
|
</div>
|
|
596
626
|
<button
|
|
597
627
|
class="mt-4 block w-full cursor-pointer rounded border-0 px-2 py-1 text-lg text-white disabled:cursor-default disabled:bg-neutral-400 disabled:text-neutral-200 bg-{accent}-900 hover:bg-{accent}-950"
|
|
598
|
-
on:click={() => openAuthURLPopup(showAuth)}
|
|
628
|
+
on:click={() => openAuthURLPopup(showAuth)}
|
|
629
|
+
>
|
|
599
630
|
Start account creation »
|
|
600
631
|
</button>
|
|
601
632
|
</div>
|
|
602
|
-
|
|
603
633
|
{:else if showLogin}
|
|
604
634
|
<div class="m-auto w-full">
|
|
605
635
|
<div class="text-center text-lg">Login into a Nostr account</div>
|
|
606
636
|
<div class="mt-4 text-center text-sm leading-4">
|
|
607
|
-
Now you a new window will bring you to <strong
|
|
637
|
+
Now you a new window will bring you to <strong
|
|
638
|
+
>{new URL(showLogin).host}</strong
|
|
639
|
+
>
|
|
640
|
+
where you can login and approve the permissions. If nothing happens check
|
|
641
|
+
that if your browser is blocking popups, pleaase.<br />
|
|
608
642
|
After that you will be returned to this page.
|
|
609
643
|
</div>
|
|
610
644
|
<button
|
|
611
645
|
class="mt-4 block w-full cursor-pointer rounded border-0 px-2 py-1 text-lg text-white disabled:cursor-default disabled:bg-neutral-400 disabled:text-neutral-200 bg-{accent}-900 hover:bg-{accent}-950"
|
|
612
|
-
on:click={() => openAuthURLPopup(showLogin)}
|
|
646
|
+
on:click={() => openAuthURLPopup(showLogin)}
|
|
647
|
+
>
|
|
613
648
|
Login now »
|
|
614
649
|
</button>
|
|
615
650
|
</div>
|
|
616
|
-
|
|
617
|
-
{:else if showConfirmAction}
|
|
651
|
+
{:else if showConfirmAction}
|
|
618
652
|
<div class="m-auto w-full">
|
|
619
|
-
<div class="text-center text-lg">
|
|
653
|
+
<div class="text-center text-lg">
|
|
654
|
+
An action requires your confirmation
|
|
655
|
+
</div>
|
|
620
656
|
<div class="mt-4 text-center text-sm leading-4">
|
|
621
|
-
Now you a new window will bring you to <strong
|
|
657
|
+
Now you a new window will bring you to <strong
|
|
658
|
+
>{new URL(showConfirmAction).host}</strong
|
|
659
|
+
>
|
|
660
|
+
where you can approve the current action. If nothing happens check that
|
|
661
|
+
if your browser is blocking popups, pleaase.<br />
|
|
622
662
|
After that you will be returned to this page.
|
|
623
663
|
</div>
|
|
624
664
|
<button
|
|
625
665
|
class="mt-4 block w-full cursor-pointer rounded border-0 px-2 py-1 text-lg text-white disabled:cursor-default disabled:bg-neutral-400 disabled:text-neutral-200 bg-{accent}-900 hover:bg-{accent}-950"
|
|
626
|
-
on:click={() => {
|
|
666
|
+
on:click={() => {
|
|
667
|
+
openAuthURLPopup(showConfirmAction)
|
|
668
|
+
}}
|
|
669
|
+
>
|
|
627
670
|
Confirm action »
|
|
628
671
|
</button>
|
|
629
672
|
</div>
|
|
@@ -797,3 +840,11 @@
|
|
|
797
840
|
</div>
|
|
798
841
|
{/if}
|
|
799
842
|
</div>
|
|
843
|
+
{#if useIframe}
|
|
844
|
+
<iframe
|
|
845
|
+
title="~"
|
|
846
|
+
bind:this={iframe}
|
|
847
|
+
on:load={onIframeLoaded}
|
|
848
|
+
src="https://the-nostr.org/iframe.html"
|
|
849
|
+
></iframe>
|
|
850
|
+
{/if}
|
package/src/main.ts
CHANGED
|
@@ -37,24 +37,24 @@ const app = new App({
|
|
|
37
37
|
props: {
|
|
38
38
|
accent: win.wnjParams?.accent || 'cyan',
|
|
39
39
|
position: win.wnjParams?.position === 'bottom' ? 'bottom' : 'top',
|
|
40
|
-
startHidden: win.wnjParams?.startHidden
|
|
41
|
-
compactMode: win.wnjParams?.compactMode
|
|
40
|
+
startHidden: win.wnjParams?.startHidden,
|
|
41
|
+
compactMode: win.wnjParams?.compactMode
|
|
42
42
|
}
|
|
43
43
|
})
|
|
44
44
|
|
|
45
|
-
if (!win.wnjParams?.disableOverflowFix){
|
|
45
|
+
if (!win.wnjParams?.disableOverflowFix) {
|
|
46
46
|
// Inject on the host page a style to avoid weird scrolling on the
|
|
47
47
|
// right/bottom on mobile, if the underlying page has some horizontal
|
|
48
48
|
// scrolling
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
const styleElement = document.createElement('style')
|
|
50
|
+
const cssCode = `
|
|
51
51
|
html, body {
|
|
52
52
|
overflow: auto;
|
|
53
53
|
height: 100%;
|
|
54
54
|
}
|
|
55
|
-
|
|
56
|
-
styleElement.innerHTML = cssCode
|
|
57
|
-
document.head.appendChild(styleElement)
|
|
55
|
+
`
|
|
56
|
+
styleElement.innerHTML = cssCode
|
|
57
|
+
document.head.appendChild(styleElement)
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
export default app
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import {writable} from 'svelte/store'
|
|
2
|
+
|
|
3
|
+
export default (mediaQueryString: string) => {
|
|
4
|
+
const {subscribe, set} = writable<boolean>(undefined, () => {
|
|
5
|
+
// start observing media query
|
|
6
|
+
const mql = window.matchMedia(mediaQueryString)
|
|
7
|
+
|
|
8
|
+
// set first media query result to the store
|
|
9
|
+
set(mql.matches)
|
|
10
|
+
|
|
11
|
+
// called when media query state changes
|
|
12
|
+
const onchange = () => set(mql.matches)
|
|
13
|
+
|
|
14
|
+
// listen for changes (need to support old `addListener` interface)
|
|
15
|
+
mql.addEventListener('change', onchange)
|
|
16
|
+
|
|
17
|
+
// when no more listeners
|
|
18
|
+
return () => {
|
|
19
|
+
// stop listening (need to support old `removeListener` interface)
|
|
20
|
+
mql.removeEventListener('change', onchange)
|
|
21
|
+
}
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
return {subscribe}
|
|
25
|
+
}
|
package/tsconfig.json
CHANGED
|
@@ -13,8 +13,9 @@
|
|
|
13
13
|
*/
|
|
14
14
|
"allowJs": true,
|
|
15
15
|
"checkJs": true,
|
|
16
|
-
"isolatedModules": true
|
|
16
|
+
"isolatedModules": true,
|
|
17
|
+
"moduleDetection": "force"
|
|
17
18
|
},
|
|
18
|
-
"include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"],
|
|
19
|
-
"references": [{
|
|
19
|
+
"include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte", "iframe/*.ts"],
|
|
20
|
+
"references": [{"path": "./tsconfig.node.json"}]
|
|
20
21
|
}
|
package/src/mediaQueryStore.js
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import {writable} from 'svelte/store'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Svelte Media Query Store
|
|
5
|
-
* @param mediaQueryString { string }
|
|
6
|
-
*/
|
|
7
|
-
export default mediaQueryString => {
|
|
8
|
-
const {subscribe, set} = writable(undefined, () => {
|
|
9
|
-
// Start observing media query
|
|
10
|
-
let mql = window.matchMedia(mediaQueryString)
|
|
11
|
-
|
|
12
|
-
// Set first media query result to the store
|
|
13
|
-
set(mql.matches)
|
|
14
|
-
|
|
15
|
-
// Called when media query state changes
|
|
16
|
-
const onchange = () => set(mql.matches)
|
|
17
|
-
|
|
18
|
-
// Listen for changes (need to support old `addListener` interface)
|
|
19
|
-
'addEventListener' in mql
|
|
20
|
-
? mql.addEventListener('change', onchange)
|
|
21
|
-
: mql.addListener(onchange)
|
|
22
|
-
|
|
23
|
-
// when no more listeners
|
|
24
|
-
return () => {
|
|
25
|
-
// stop listening (need to support old `removeListener` interface)
|
|
26
|
-
'removeEventListener' in mql
|
|
27
|
-
? mql.removeEventListener('change', onchange)
|
|
28
|
-
: mql.removeListener(onchange)
|
|
29
|
-
}
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
return {subscribe}
|
|
33
|
-
}
|