Add support for nostr.build and NIP 98 Auth

This commit is contained in:
Jonathan Staab 2023-08-24 09:13:28 -07:00
parent 969acdd654
commit 581e4df423
4 changed files with 58 additions and 51 deletions

View File

@ -209,11 +209,16 @@
}
export const write = text => {
contenteditable.getInput().focus()
const input = contenteditable.getInput()
input.focus()
const selection = window.getSelection()
const textNode = document.createTextNode(text)
const target = last(input.childNodes) as unknown as Node
const offset = target instanceof Text ? target.wholeText.length : target.childNodes.length
selection.collapse(target, offset)
selection.getRangeAt(0).insertNode(textNode)
selection.collapse(textNode, text.length)

View File

@ -84,7 +84,9 @@
}
const setWordCount = throttle(300, () => {
wordCount = compose.parse().match(/\s+/g)?.length || 0
if (compose) {
wordCount = compose.parse().match(/\s+/g)?.length || 0
}
})
onMount(() => {

View File

@ -173,6 +173,9 @@ export class Builder {
createLabel = (payload: EventOpts) => buildEvent(1985, payload)
createNip98AuthHeader = (tags: string[][]) =>
`Nostr ${btoa(JSON.stringify(buildEvent(27235, {tags})))}`
initialize(engine: Engine) {
this.engine = engine
}

View File

@ -1,12 +1,13 @@
<script lang="ts">
import {identity, pick} from "ramda"
import {identity} from "ramda"
import {Fetch, filterVals} from "hurdak"
import Input from "src/partials/Input.svelte"
import Modal from "src/partials/Modal.svelte"
import Content from "src/partials/Content.svelte"
import Spinner from "src/partials/Spinner.svelte"
import Anchor from "src/partials/Anchor.svelte"
import {listenForFile, stripExifData, blobToFile} from "src/util/html"
import {Settings} from "src/app/engine"
import {Builder} from "src/app/engine"
export let icon = null
export let value = null
@ -15,9 +16,10 @@
export let maxHeight = null
export let onChange = null
let input, listener, quote
const url = "https://nostr.build/api/v2/upload/files"
let input, listener, loading
let files = []
let loading = false
let isOpen = false
$: {
@ -26,45 +28,48 @@
if (inputFiles) {
const opts = filterVals(identity, {maxWidth, maxHeight})
files = await Promise.all(
inputFiles.map(async f => blobToFile(await stripExifData(f, opts)))
)
loading = true
quote = await Fetch.postJson(Settings.dufflepud("upload/quote"), {
uploads: files.map(pick(["size"])),
})
try {
files = await Promise.all(
inputFiles.map(async f => blobToFile(await stripExifData(f, opts)))
)
const body = new FormData()
for (const file of files) {
body.append("file[]", file)
}
const result = await Fetch.fetchJson(url, {
body,
method: "POST",
headers: {
Authorization: Builder.createNip98AuthHeader([
["u", url],
["method", "POST"],
]),
},
})
// Legacy weirdness
for (const {url} of result.data) {
value = url
onChange?.(url)
}
} finally {
isOpen = false
loading = false
}
} else {
files = []
quote = null
}
})
}
}
const accept = async () => {
loading = true
try {
await Promise.all(
quote.uploads.map(async ({id}, idx) => {
const {url} = await Fetch.uploadFile(Settings.dufflepud(`upload/${id}`), files[idx])
value = url
onChange?.(url)
})
)
} finally {
loading = false
}
files = []
quote = null
isOpen = false
}
const decline = () => {
files = []
quote = null
isOpen = false
}
</script>
@ -89,24 +94,16 @@
</div>
</div>
{#if quote}
{#if isOpen}
<Modal mini onEscape={decline}>
<Content>
<h1 class="staatliches text-2xl">Confirm File Upload</h1>
<p>Please accept the following terms:</p>
<p>{quote.terms}</p>
<div class="flex gap-2">
<Anchor theme="button" on:click={decline} {loading}>Decline</Anchor>
<Anchor theme="button-accent" on:click={accept} {loading}>Accept</Anchor>
</div>
</Content>
</Modal>
{:else if isOpen}
<Modal mini onEscape={decline}>
<Content>
<h1 class="staatliches text-2xl">Upload a File</h1>
<p>Click below to select a file to upload.</p>
<input multiple={multi} type="file" bind:this={input} />
{#if loading}
<Spinner delay={0}>Uploading your media...</Spinner>
{:else}
<h1 class="staatliches text-2xl">Upload a File</h1>
<p>Click below to select a file to upload.</p>
<input multiple={multi} type="file" bind:this={input} />
{/if}
</Content>
</Modal>
{/if}