Add support for QR codes

This commit is contained in:
Jonathan Staab 2023-02-11 14:59:09 -06:00
parent 3d06e7e0b9
commit 3bc99e816d
12 changed files with 119 additions and 31 deletions

1
.gitignore vendored
View File

@ -1,6 +1,7 @@
# Logs
logs
*.log
*.pem
npm-debug.log*
yarn-debug.log*
yarn-error.log*

BIN
package-lock.json generated

Binary file not shown.

View File

@ -23,7 +23,8 @@
"svelte": "^3.52.0",
"tailwindcss": "^3.2.4",
"typescript": "^4.9.5",
"vite": "^3.2.3"
"vite": "^3.2.3",
"vite-plugin-mkcert": "^1.13.0"
},
"dependencies": {
"@bugsnag/js": "^7.18.0",
@ -39,6 +40,7 @@
"localforage-memoryStorageDriver": "^0.9.2",
"nostr-tools": "^1.2.1",
"npm-run-all": "^4.1.5",
"qr-scanner": "^1.4.2",
"qrcode": "^1.5.1",
"ramda": "^0.28.0",
"svelte-check": "^3.0.3",

View File

@ -105,7 +105,7 @@ const processRoomEvents = async events => {
const content = tryJson(() => pick(roomAttrs, JSON.parse(e.content))) as Record<string, any>
const roomId = e.kind === 40 ? e.id : Tags.from(e).type("e").values().first()
if (!roomId) {
if (!roomId || !content) {
continue
}
@ -151,6 +151,7 @@ const processMessages = async events => {
// Routes
const getWeight = type => {
if (type === 'nip05') return 1
if (type === 'kind:10001') return 1
if (type === 'kind:3') return 0.8
if (type === 'kind:2') return 0.5
@ -262,13 +263,12 @@ const verifyNip05 = (pubkey, as) =>
database.people.patch({...person, verified_as: as})
if (result.relays?.length > 0) {
console.log('===== NIP05 VERIFICATION RELAYS', result.relays)
// database.routes.bulkPut(
// createMap('id', result.relays.flatMap(url =>[
// calculateRoute(pubkey, url, 'nip05', 'write', now()),
// calculateRoute(pubkey, url, 'nip05', 'read', now()),
// ]))
// )
database.routes.bulkPut(
createMap('id', result.relays.filter(isRelay).flatMap(url =>[
calculateRoute(pubkey, url, 'nip05', 'write', now()),
calculateRoute(pubkey, url, 'nip05', 'read', now()),
]))
)
}
}
}, noop)

View File

@ -2,7 +2,6 @@
import {objOf} from 'ramda'
import {onMount} from 'svelte'
import {nip19} from 'nostr-tools'
import {navigate} from 'svelte-routing'
import Content from 'src/partials/Content.svelte'
import NoteDetail from 'src/views/NoteDetail.svelte'
import Person from 'src/routes/Person.svelte'
@ -16,7 +15,7 @@
({type, data} = nip19.decode(entity) as {type: string, data: any})
relays = (data.relays || []).map(objOf('url'))
} catch (e) {
navigate('/')
// pass
}
})
</script>
@ -33,5 +32,9 @@
<Person npub={nip19.npubEncode(data.pubkey)} {relays} activeTab="notes" />
{:else if type === "npub"}
<Person npub={entity} activeTab="notes" />
{:else}
<Content size="lg" class="text-center">
<div>Sorry, we weren't able to find {entity}.</div>
</Content>
{/if}

View File

@ -146,7 +146,7 @@
{/if}
{/if}
<Anchor type="button-circle" on:click={share}>
<i class="fa fa-qrcode" />
<i class="fa fa-share-nodes" />
</Anchor>
</div>
</div>

View File

@ -1,26 +1,20 @@
<script>
import Input from "src/partials/Input.svelte"
import {navigate} from 'svelte-routing'
import Content from 'src/partials/Content.svelte'
import Tabs from 'src/partials/Tabs.svelte'
import SearchPeople from 'src/views/SearchPeople.svelte'
import SearchNotes from 'src/views/SearchNotes.svelte'
import Scan from 'src/views/Scan.svelte'
export let activeTab
let q = ''
// const setActiveTab = tab => navigate(`/search/${tab}`)
const setActiveTab = tab => navigate(`/search/${tab}`)
</script>
<Content>
<!--
<Tabs tabs={['people', 'notes']} {activeTab} {setActiveTab} />
-->
<Input bind:value={q} placeholder="Search for people">
<i slot="before" class="fa-solid fa-search" />
</Input>
<Tabs tabs={['people', 'advanced']} {activeTab} {setActiveTab} />
{#if activeTab === 'people'}
<SearchPeople {q} />
{:else if activeTab === 'notes'}
<SearchNotes {q} />
<SearchPeople />
{:else if activeTab === 'advanced'}
<Scan />
{/if}
</Content>

View File

@ -28,4 +28,7 @@
<Input value={nprofile}>
<button slot="after" class="fa fa-copy" on:click={copyKey} />
</Input>
<div class="text-center text-light">
Copy or scan from a nostr app to share this profile.
</div>
</Content>

79
src/views/Scan.svelte Normal file
View File

@ -0,0 +1,79 @@
<script lang="ts">
import QrScanner from 'qr-scanner'
import {onDestroy} from 'svelte'
import {navigate} from 'svelte-routing'
import {waitFor} from 'hurdak/lib/hurdak'
import Content from 'src/partials/Content.svelte'
import Input from 'src/partials/Input.svelte'
import Anchor from 'src/partials/Anchor.svelte'
import Spinner from 'src/partials/Spinner.svelte'
let mode = 'input', video, ready, value, scanner
const onDecode = result => {
console.log(result)
goToEntity(result.data)
}
const goToEntity = entity => {
navigate(`/${entity}`)
}
const setMode = async newMode => {
mode = newMode
if (newMode === 'scan') {
await waitFor(() => video)
scanner = new QrScanner(video, onDecode, {
returnDetailedScanResult: true,
})
await scanner.start()
ready = true
} else if (scanner) {
ready = false
await scanner.stop()
await scanner.destroy()
}
}
onDestroy(async () => {
if (scanner) {
await scanner.stop()
await scanner.destroy()
}
})
</script>
<Content>
{#if mode === 'input'}
<div class="flex gap-2">
<Input placeholder="nprofile..." bind:value={value} wrapperClass="flex-grow" />
<Anchor type="button" on:click={() => goToEntity(value)}>
<i class="fa fa-arrow-right" />
</Anchor>
<Anchor type="button" on:click={() => setMode('scan')}>
<i class="fa fa-camera" />
</Anchor>
</div>
<div class="text-center text-light">
Enter any nostr identifier (npub, nevent, nprofile or note), or click on the
camera icon to scan with your device's camera instead.
</div>
{:else}
{#if !ready}
<Spinner>
Loading your camera...
</Spinner>
{/if}
<video bind:this={video} />
{#if ready}
<Anchor type="unstyled" class="flex gap-2 items-center" on:click={() => setMode('input')}>
<i class="fa fa-arrow-left" />
<span class="underline">Go back</span>
</Anchor>
{/if}
{/if}
</Content>

View File

@ -1,3 +0,0 @@
<script lang="ts">
export let q
</script>

View File

@ -1,11 +1,11 @@
<script>
import {fuzzy} from "src/util/misc"
import Input from "src/partials/Input.svelte"
import PersonInfo from 'src/partials/PersonInfo.svelte'
import {user} from 'src/agent/helpers'
import database from 'src/agent/database'
export let q
let q
let search
database.people.iter({'name:!nil': null}).then(people => {
@ -13,6 +13,10 @@
})
</script>
<Input bind:value={q} placeholder="Search for people">
<i slot="before" class="fa-solid fa-search" />
</Input>
{#each (search ? search(q) : []).slice(0, 30) as person (person.pubkey)}
{#if person.pubkey !== $user.pubkey}
<PersonInfo {person} />

View File

@ -1,10 +1,14 @@
import * as path from 'path'
import { defineConfig } from 'vite'
import mkcert from 'vite-plugin-mkcert'
import sveltePreprocess from 'svelte-preprocess'
import { svelte } from '@sveltejs/vite-plugin-svelte'
import { nodePolyfills } from 'vite-plugin-node-polyfills'
export default defineConfig({
server: {
https: false,
},
build: {
sourcemap: true,
},
@ -14,6 +18,7 @@ export default defineConfig({
}
},
plugins: [
mkcert(),
nodePolyfills({
protocolImports: true,
}),