mirror of
https://github.com/coracle-social/coracle.git
synced 2024-09-29 00:10:52 +00:00
Add typescript
This commit is contained in:
parent
233c4b6ad6
commit
a45ecb61be
BIN
package-lock.json
generated
BIN
package-lock.json
generated
Binary file not shown.
@ -7,7 +7,8 @@
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"lint": "eslint src/*/** --quiet"
|
||||
"lint": "eslint src/*/** --quiet",
|
||||
"check": "svelte-check --tsconfig ./tsconfig.json --threshold error"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/vite-plugin-svelte": "^1.1.0",
|
||||
@ -23,6 +24,7 @@
|
||||
"@bugsnag/js": "^7.18.0",
|
||||
"@fortawesome/fontawesome-free": "^6.2.1",
|
||||
"@noble/secp256k1": "^1.7.0",
|
||||
"@tsconfig/svelte": "^3.0.0",
|
||||
"classnames": "^2.3.2",
|
||||
"compressorjs": "^1.1.1",
|
||||
"dexie": "^3.2.2",
|
||||
@ -31,8 +33,10 @@
|
||||
"hurdak": "github:ConsignCloud/hurdak",
|
||||
"nostr-tools": "^1.1.1",
|
||||
"ramda": "^0.28.0",
|
||||
"svelte-check": "^3.0.3",
|
||||
"svelte-link-preview": "^0.3.3",
|
||||
"svelte-loading-spinners": "^0.3.4",
|
||||
"svelte-preprocess": "^5.0.1",
|
||||
"svelte-routing": "^1.6.0",
|
||||
"svelte-switch": "^0.0.5",
|
||||
"throttle-debounce": "^5.0.0",
|
||||
|
@ -130,7 +130,7 @@
|
||||
document.body.style.position = `fixed`
|
||||
}
|
||||
} else {
|
||||
document.body.style = ''
|
||||
document.body.setAttribute('style', '')
|
||||
window.scrollTo(0, scrollY)
|
||||
}
|
||||
})
|
||||
@ -151,18 +151,18 @@
|
||||
<Route path="/notes/:activeTab" component={Notes} />
|
||||
<Route path="/people/:npub/:activeTab" let:params>
|
||||
{#key params.npub}
|
||||
<Person {...params} />
|
||||
<Person npub={params.npub} activeTab={params.activeTab} />
|
||||
{/key}
|
||||
</Route>
|
||||
<Route path="/chat" component={Chat} />
|
||||
<Route path="/chat/:entity" let:params>
|
||||
{#key params.entity}
|
||||
<ChatRoom {...params} />
|
||||
<ChatRoom entity={params.entity} />
|
||||
{/key}
|
||||
</Route>
|
||||
<Route path="/messages/:entity" let:params>
|
||||
{#key params.entity}
|
||||
<Messages {...params} />
|
||||
<Messages entity={params.entity} />
|
||||
{/key}
|
||||
</Route>
|
||||
<Route path="/keys" component={Keys} />
|
||||
@ -173,7 +173,7 @@
|
||||
<Route path="/logout" component={Logout} />
|
||||
<Route path="/:entity" let:params>
|
||||
{#key params.entity}
|
||||
<Bech32Entity {...params} />
|
||||
<Bech32Entity entity={params.entity} />
|
||||
{/key}
|
||||
</Route>
|
||||
<Route path="*" component={NotFound} />
|
||||
@ -259,10 +259,10 @@
|
||||
border-b border-medium z-10"
|
||||
>
|
||||
<div class="lg:hidden">
|
||||
<i class="fa-solid fa-bars fa-2xl cursor-pointer" bind:this={menuIcon} on:click={toggleMenu} />
|
||||
<button class="fa-solid fa-bars fa-2xl cursor-pointer" bind:this={menuIcon} on:click={toggleMenu} />
|
||||
</div>
|
||||
<Anchor external type="unstyled" href="https://github.com/staab/coracle" class="flex items-center gap-2">
|
||||
<img src="/images/favicon.png" class="w-8" />
|
||||
<img alt="Coracle Logo" src="/images/favicon.png" class="w-8" />
|
||||
<h1 class="staatliches text-3xl">Coracle</h1>
|
||||
</Anchor>
|
||||
{#if $mostRecentAlert > $lastCheckedAlerts || hasNewMessages}
|
||||
@ -272,12 +272,12 @@
|
||||
|
||||
{#if keys.canSign()}
|
||||
<div class="fixed bottom-0 right-0 m-8">
|
||||
<a
|
||||
<button
|
||||
class="rounded-full bg-accent color-white w-16 h-16 flex justify-center
|
||||
items-center border border-dark shadow-2xl cursor-pointer"
|
||||
items-center border border-dark shadow-2xl"
|
||||
on:click={() => modal.set({type: 'note/create'})}>
|
||||
<span class="fa-sold fa-plus fa-2xl" />
|
||||
</a>
|
||||
</button>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
|
@ -31,7 +31,7 @@ export const ready = writable(false)
|
||||
export const people = writable([])
|
||||
|
||||
// Bootstrap our people observable
|
||||
db.people.toArray().then($p => {
|
||||
db.table('people').toArray().then($p => {
|
||||
people.set(createMap('pubkey', $p))
|
||||
ready.set(true)
|
||||
})
|
||||
@ -51,7 +51,7 @@ export const updatePeople = async updates => {
|
||||
people.update($people => ({...$people, ...updates}))
|
||||
|
||||
// Sync to our database
|
||||
await db.people.bulkPut(Object.values(updates))
|
||||
await db.table('people').bulkPut(Object.values(updates))
|
||||
}
|
||||
|
||||
// Hooks
|
||||
@ -126,7 +126,7 @@ const processProfileEvents = async events => {
|
||||
}
|
||||
},
|
||||
default: () => {
|
||||
console.log(`Received unsupported event type ${event.kind}`)
|
||||
console.log(`Received unsupported event type ${e.kind}`)
|
||||
},
|
||||
}),
|
||||
updated_at: now(),
|
||||
@ -155,7 +155,7 @@ const processRoomEvents = async events => {
|
||||
continue
|
||||
}
|
||||
|
||||
const room = await db.rooms.get(roomId)
|
||||
const room = await db.table('rooms').get(roomId)
|
||||
|
||||
// Merge edits but don't let old ones override new ones
|
||||
if (room?.edited_at > e.created_at) {
|
||||
@ -178,7 +178,7 @@ const processRoomEvents = async events => {
|
||||
}
|
||||
}
|
||||
|
||||
await db.rooms.bulkPut(Object.values(updates))
|
||||
await db.table('rooms').bulkPut(Object.values(updates))
|
||||
}
|
||||
|
||||
const processMessages = async events => {
|
||||
@ -187,7 +187,7 @@ const processMessages = async events => {
|
||||
.map(e => ({...e, recipient: Tags.from(e).type("p").values().first()}))
|
||||
|
||||
if (messages.length > 0) {
|
||||
await db.messages.bulkPut(messages)
|
||||
await db.table('messages').bulkPut(messages)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -37,7 +37,7 @@ export const getFollows = pubkey => {
|
||||
return Tags.wrap(person?.petnames || defaults.petnames).values().all()
|
||||
}
|
||||
|
||||
export const getRelays = pubkey => {
|
||||
export const getRelays = (pubkey?: string) => {
|
||||
let relays = getPerson(pubkey)?.relays
|
||||
|
||||
if (!relays?.length) {
|
||||
@ -71,7 +71,7 @@ export const publish = async (relays, event) => {
|
||||
return signedEvent
|
||||
}
|
||||
|
||||
export const load = async (relays, filter, opts) => {
|
||||
export const load = async (relays, filter, opts?) => {
|
||||
const events = await pool.request(relays, filter, opts)
|
||||
|
||||
await processEvents(events)
|
||||
@ -79,7 +79,7 @@ export const load = async (relays, filter, opts) => {
|
||||
return events
|
||||
}
|
||||
|
||||
export const listen = async (relays, filter, onEvent, {shouldProcess = true} = {}) => {
|
||||
export const listen = async (relays, filter, onEvent, {shouldProcess = true}: any = {}) => {
|
||||
const sub = await pool.subscribe(relays, filter)
|
||||
|
||||
sub.onEvent(e => {
|
@ -7,8 +7,8 @@ let signingFunction
|
||||
|
||||
const pubkey = synced('agent/user/pubkey')
|
||||
const privkey = synced('agent/user/privkey')
|
||||
const hasExtension = () => Boolean(window.nostr)
|
||||
const canSign = () => Boolean(hasExtension() || get(privkey))
|
||||
const getExtension = () => (window as {nostr?: any}).nostr
|
||||
const canSign = () => Boolean(getExtension() || get(privkey))
|
||||
|
||||
const setPrivateKey = _privkey => {
|
||||
privkey.set(_privkey)
|
||||
@ -16,9 +16,11 @@ const setPrivateKey = _privkey => {
|
||||
}
|
||||
|
||||
const setPublicKey = _pubkey => {
|
||||
if (window.nostr) {
|
||||
const nostr = getExtension()
|
||||
|
||||
if (nostr) {
|
||||
signingFunction = async event => {
|
||||
const {sig} = await window.nostr.signEvent(event)
|
||||
const {sig} = await nostr.signEvent(event)
|
||||
|
||||
return sig
|
||||
}
|
||||
@ -44,8 +46,9 @@ const sign = async event => {
|
||||
|
||||
const getCrypt = () => {
|
||||
const $privkey = get(privkey)
|
||||
const nostr = getExtension()
|
||||
|
||||
if (!$privkey && !hasExtension()) {
|
||||
if (!$privkey && !nostr) {
|
||||
throw new Error('No encryption method available.')
|
||||
}
|
||||
|
||||
@ -53,13 +56,13 @@ const getCrypt = () => {
|
||||
encrypt: (pubkey, message) => {
|
||||
return $privkey
|
||||
? nip04.encrypt($privkey, pubkey, message)
|
||||
: window.nostr.nip04.encrypt(pubkey, message)
|
||||
: nostr.nip04.encrypt(pubkey, message)
|
||||
},
|
||||
decrypt: async (pubkey, message) => {
|
||||
try {
|
||||
return $privkey
|
||||
? nip04.decrypt($privkey, pubkey, message)
|
||||
: await window.nostr.nip04.decrypt(pubkey, message)
|
||||
: await nostr.nip04.decrypt(pubkey, message)
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
return `<Failed to decrypt message: ${e}>`
|
||||
@ -72,6 +75,6 @@ const getCrypt = () => {
|
||||
setPublicKey(get(pubkey))
|
||||
|
||||
export default {
|
||||
pubkey, privkey, hasExtension, canSign, setPrivateKey, setPublicKey, clear,
|
||||
pubkey, privkey, canSign, setPrivateKey, setPublicKey, clear,
|
||||
sign, getCrypt,
|
||||
}
|
@ -71,7 +71,7 @@ const findConnection = url => find(whereEq({url}), connections)
|
||||
const connect = async url => {
|
||||
const conn = findConnection(url) || new Connection(url)
|
||||
|
||||
await db.relays.put({url})
|
||||
await db.table('relays').put({url})
|
||||
await Promise.race([conn.connect(), sleep(5000)])
|
||||
|
||||
if (conn.status === 'ready') {
|
||||
|
@ -17,7 +17,7 @@ const onChunk = async (relays, pubkey, events) => {
|
||||
const context = await loaders.loadContext(relays, events, {threshold: 2})
|
||||
const notes = threadify(events, context, {muffle: getMuffle()})
|
||||
|
||||
await db.alerts.bulkPut(notes)
|
||||
await db.table('alerts').bulkPut(notes)
|
||||
|
||||
mostRecentAlert.update($t => events.reduce((t, e) => Math.max(t, e.created_at), $t))
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ import loaders from 'src/app/loaders'
|
||||
|
||||
export {toast, modal, settings, alerts, messages, logUsage}
|
||||
|
||||
export const login = async ({privkey, pubkey}, usingExtension = false) => {
|
||||
export const login = async ({privkey, pubkey}: {privkey?: string, pubkey?: string}, usingExtension = false) => {
|
||||
if (privkey) {
|
||||
keys.setPrivateKey(privkey)
|
||||
} else {
|
||||
@ -79,7 +79,7 @@ export const setRelayWriteCondition = async (url, write) => {
|
||||
}
|
||||
}
|
||||
|
||||
export const render = (note, {showEntire = false}) => {
|
||||
export const renderNote = (note, {showEntire = false}) => {
|
||||
const shouldEllipsize = note.content.length > 500 && !showEntire
|
||||
const $people = get(people)
|
||||
const peopleByPubkey = createMap(
|
@ -44,7 +44,7 @@ const loadNetwork = async (relays, pubkey) => {
|
||||
await loadPeople(tags.relays(), tags.values().all())
|
||||
}
|
||||
|
||||
const loadContext = async (relays, notes, {loadParents = false, depth = 0, ...opts} = {}) => {
|
||||
const loadContext = async (relays, notes, {loadParents = false, depth = 0, ...opts}: any = {}) => {
|
||||
notes = ensurePlural(notes)
|
||||
|
||||
if (notes.length === 0) {
|
||||
@ -58,7 +58,7 @@ const loadContext = async (relays, notes, {loadParents = false, depth = 0, ...op
|
||||
const parentTags = uniq(chunk.map(findReply).filter(identity))
|
||||
const parentIds = Tags.wrap(parentTags).values().all()
|
||||
const combinedRelays = uniq(relays.concat(Tags.wrap(parentTags).relays()))
|
||||
const filter = [{kinds: [1, 7], '#e': chunkIds}]
|
||||
const filter = [{kinds: [1, 7], '#e': chunkIds} as {}]
|
||||
|
||||
if (authors.length > 0) {
|
||||
filter.push({kinds: personKinds, authors})
|
@ -25,7 +25,7 @@ const listen = async (relays, pubkey) => {
|
||||
// Reload annotated messages, don't alert about messages to self
|
||||
const messages = reject(
|
||||
e => e.pubkey === e.recipient,
|
||||
await db.messages.toArray()
|
||||
await db.table('messages').toArray()
|
||||
)
|
||||
|
||||
if (messages.length > 0) {
|
||||
|
@ -1,6 +1,7 @@
|
||||
import Bugsnag from "@bugsnag/js"
|
||||
import {prop} from "ramda"
|
||||
import {uuid} from "hurdak/lib/hurdak"
|
||||
import type {Writable} from 'svelte/store'
|
||||
import {navigate} from "svelte-routing"
|
||||
import {nip19} from 'nostr-tools'
|
||||
import {writable, get} from "svelte/store"
|
||||
@ -15,7 +16,11 @@ export const routes = {
|
||||
|
||||
// Toast
|
||||
|
||||
export const toast = writable(null)
|
||||
export interface Toast<T> extends Writable<T> {
|
||||
show(type: string, message: string, timeout?: number): void
|
||||
}
|
||||
|
||||
export const toast = writable(null) as Toast<any>
|
||||
|
||||
toast.show = (type, message, timeout = 5) => {
|
||||
const id = uuid()
|
||||
@ -29,6 +34,7 @@ toast.show = (type, message, timeout = 5) => {
|
||||
}, timeout * 1000)
|
||||
}
|
||||
|
||||
|
||||
// Modals
|
||||
|
||||
export const modal = {
|
@ -9,9 +9,6 @@ Bugsnag.start({
|
||||
|
||||
import App from 'src/App.svelte'
|
||||
|
||||
// Annoying global always fails silently. TODO: figure out an eslint rule instead
|
||||
window.find = null
|
||||
|
||||
const app = new App({
|
||||
target: document.getElementById('app')
|
||||
})
|
||||
|
@ -6,7 +6,7 @@
|
||||
export let invertColors = false
|
||||
</script>
|
||||
|
||||
<li
|
||||
<div
|
||||
on:click
|
||||
in:fly={{y: 20}}
|
||||
class={cx("py-2 px-3 flex flex-col gap-2 text-white", {
|
||||
@ -15,4 +15,4 @@
|
||||
"hover:bg-medium": interactive && invertColors,
|
||||
})}>
|
||||
<slot />
|
||||
</li>
|
||||
</div>
|
||||
|
@ -9,10 +9,10 @@
|
||||
import Anchor from 'src/partials/Anchor.svelte'
|
||||
import Spinner from 'src/partials/Spinner.svelte'
|
||||
import {user, getPerson} from 'src/agent'
|
||||
import {render} from 'src/app'
|
||||
import {renderNote} from 'src/app'
|
||||
|
||||
export let name
|
||||
export let link
|
||||
export let link = null
|
||||
export let about
|
||||
export let picture
|
||||
export let loadMessages
|
||||
@ -42,7 +42,7 @@
|
||||
}
|
||||
|
||||
// flex-col means the first is the last
|
||||
const getLastListItem = () => document.querySelector('ul[name=messages] li')
|
||||
const getLastListItem = () => document.querySelector('ul[class=channel-messages] li')
|
||||
|
||||
const stickToBottom = async (behavior, cb) => {
|
||||
const shouldStick = window.scrollY + window.innerHeight > document.body.scrollHeight - 200
|
||||
@ -123,7 +123,7 @@
|
||||
<div class="flex gap-4 h-full">
|
||||
<div class="relative w-full">
|
||||
<div class="flex flex-col pt-20 pb-28 h-full">
|
||||
<ul class="pb-6 p-4 overflow-auto flex-grow flex flex-col-reverse justify-start" name="messages">
|
||||
<ul class="pb-6 p-4 overflow-auto flex-grow flex flex-col-reverse justify-start channel-messages">
|
||||
{#each annotatedMessages as m (m.id)}
|
||||
<li in:fly={{y: 20}} class="py-1 flex flex-col gap-2">
|
||||
{#if type === 'chat' && m.showPerson}
|
||||
@ -142,7 +142,7 @@
|
||||
'bg-light text-black rounded-br-none': type === 'dm' && m.person.pubkey === $user.pubkey,
|
||||
'bg-dark rounded-bl-none': type === 'dm' && m.person.pubkey !== $user.pubkey,
|
||||
})}>
|
||||
{@html render(m, {showEntire: true})}
|
||||
{@html renderNote(m, {showEntire: true})}
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
@ -157,7 +157,9 @@
|
||||
<div class="fixed z-10 top-16 w-full lg:-ml-56 lg:pl-56 border-b border-solid border-medium bg-dark">
|
||||
<div class="p-4 flex items-start gap-4">
|
||||
<div class="flex items-center gap-4">
|
||||
<i class="fa fa-arrow-left text-2xl cursor-pointer" on:click={() => navigate("/chat")} />
|
||||
<button
|
||||
class="fa fa-arrow-left text-2xl cursor-pointer"
|
||||
on:click={() => navigate("/chat")} />
|
||||
<div
|
||||
class="overflow-hidden w-12 h-12 rounded-full bg-cover bg-center shrink-0 border border-solid border-white"
|
||||
style="background-image: url({picture})" />
|
||||
@ -171,9 +173,9 @@
|
||||
<div class="text-lg font-bold">{name || ''}</div>
|
||||
{/if}
|
||||
{#if editRoom}
|
||||
<small class="cursor-pointer" on:click={editRoom}>
|
||||
<button class="text-sm cursor-pointer" on:click={editRoom}>
|
||||
<i class="fa-solid fa-edit" /> Edit
|
||||
</small>
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
@ -199,12 +201,12 @@
|
||||
on:keypress={onKeyPress}
|
||||
class="w-full p-2 text-white bg-medium
|
||||
placeholder:text-light outline-0 resize-none" />
|
||||
<div
|
||||
<button
|
||||
on:click={send}
|
||||
class="flex flex-col py-8 p-4 justify-center gap-2 border-l border-solid border-dark
|
||||
hover:bg-accent transition-all cursor-pointer text-white ">
|
||||
<i class="fa-solid fa-paper-plane fa-xl" />
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{#if showNewMessages}
|
||||
|
@ -180,13 +180,13 @@
|
||||
{#if suggestions.length > 0}
|
||||
<div class="rounded border border-solid border-medium mt-2" in:fly={{y: 20}}>
|
||||
{#each suggestions as person, i (person.pubkey)}
|
||||
<div
|
||||
<button
|
||||
class="py-2 px-4 cursor-pointer"
|
||||
class:bg-black={index !== i}
|
||||
class:bg-dark={index === i}
|
||||
on:click={() => pickSuggestion(person)}>
|
||||
<Badge inert {person} />
|
||||
</div>
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
|
@ -2,7 +2,7 @@
|
||||
import cx from "classnames"
|
||||
|
||||
export let wrapperClass = ""
|
||||
export let value
|
||||
export let value = ""
|
||||
|
||||
const className = cx(
|
||||
$$props.class,
|
||||
|
@ -24,29 +24,29 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<div
|
||||
<button
|
||||
class="py-2 px-3 flex flex-col gap-2 text-white cursor-pointer transition-all
|
||||
border border-solid border-black hover:border-medium hover:bg-dark"
|
||||
on:click={() => modal.set({type: 'note/detail', note})}>
|
||||
<div class="flex gap-2 items-center justify-between relative">
|
||||
<span class="cursor-pointer" on:click={openPopover}>
|
||||
<button class="cursor-pointer" on:click={openPopover}>
|
||||
{quantify(note.people.length, 'person', 'people')} liked your note.
|
||||
</span>
|
||||
</button>
|
||||
{#if isOpen}
|
||||
<div in:fly={{y: 20}} class="fixed inset-0 z-10" on:click={closePopover} />
|
||||
<div
|
||||
<button in:fly={{y: 20}} class="fixed inset-0 z-10" on:click={closePopover} />
|
||||
<button
|
||||
on:click={killEvent}
|
||||
infly={{y: 20}}
|
||||
in:fly={{y: 20}}
|
||||
class="absolute top-0 mt-8 py-2 px-4 rounded border border-solid border-medium
|
||||
bg-dark grid grid-cols-3 gap-y-2 gap-x-4 z-20">
|
||||
{#each uniqBy(prop('pubkey'), note.people) as person (person.pubkey)}
|
||||
<Badge {person} />
|
||||
{/each}
|
||||
</div>
|
||||
</button>
|
||||
{/if}
|
||||
<p class="text-sm text-light">{formatTimestamp(note.created_at)}</p>
|
||||
</div>
|
||||
<div class="ml-6 text-light">
|
||||
{ellipsize(note.content, 120)}
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
|
@ -12,7 +12,7 @@
|
||||
}} />
|
||||
|
||||
<div class="fixed inset-0 z-10">
|
||||
<div
|
||||
<button
|
||||
class="absolute inset-0 opacity-75 bg-black cursor-pointer"
|
||||
transition:fade
|
||||
on:click={onEscape} />
|
||||
|
@ -1,4 +1,4 @@
|
||||
<script>
|
||||
<script lang="ts">
|
||||
import cx from 'classnames'
|
||||
import extractUrls from 'extract-urls'
|
||||
import {nip19} from 'nostr-tools'
|
||||
@ -9,7 +9,7 @@
|
||||
import {Tags, findReply, findReplyId, displayPerson, isLike} from "src/util/nostr"
|
||||
import Preview from 'src/partials/Preview.svelte'
|
||||
import Anchor from 'src/partials/Anchor.svelte'
|
||||
import {settings, modal, render} from "src/app"
|
||||
import {settings, modal, renderNote} from "src/app"
|
||||
import {formatTimestamp} from 'src/util/misc'
|
||||
import Badge from "src/partials/Badge.svelte"
|
||||
import Compose from "src/partials/Compose.svelte"
|
||||
@ -45,7 +45,9 @@
|
||||
$: flag = find(whereEq({pubkey: $user?.pubkey}), flags)
|
||||
|
||||
const onClick = e => {
|
||||
if (interactive && !['I'].includes(e.target.tagName) && !e.target.closest('a')) {
|
||||
const target = e.target as HTMLElement
|
||||
|
||||
if (interactive && !['I'].includes(target.tagName) && !target.closest('a')) {
|
||||
modal.set({type: 'note/detail', note, relays})
|
||||
}
|
||||
}
|
||||
@ -112,14 +114,18 @@
|
||||
resetReply()
|
||||
}
|
||||
}
|
||||
|
||||
const onBodyClick = e => {
|
||||
const target = e.target as HTMLElement
|
||||
|
||||
if (!target.closest('.fa-reply') && !target.closest('.note-reply')) {
|
||||
resetReply()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:body
|
||||
on:click={e => {
|
||||
if (!e.target.closest('.fa-reply') && !e.target.closest('.note-reply')) {
|
||||
resetReply()
|
||||
}
|
||||
}}
|
||||
on:click={onBodyClick}
|
||||
on:keydown={e => {
|
||||
if (e.key === 'Escape') {
|
||||
resetReply()
|
||||
@ -150,30 +156,28 @@
|
||||
</p>
|
||||
{:else}
|
||||
<div class="text-ellipsis overflow-hidden flex flex-col gap-2">
|
||||
<p>{@html render(note, {showEntire})}</p>
|
||||
<p>{@html renderNote(note, {showEntire})}</p>
|
||||
{#each links.slice(-2) as link}
|
||||
<div>
|
||||
<div class="inline-block" on:click={e => e.stopPropagation()}>
|
||||
<button class="inline-block" on:click={e => e.stopPropagation()}>
|
||||
<Preview endpoint={`${$settings.dufflepudUrl}/link/preview`} url={link} />
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
<div class="flex gap-6 text-light">
|
||||
<div>
|
||||
<i
|
||||
class="fa fa-reply cursor-pointer"
|
||||
on:click={startReply} />
|
||||
<button class="fa fa-reply cursor-pointer" on:click|stopPropagation={startReply} />
|
||||
{note.replies.length}
|
||||
</div>
|
||||
<div class={cx({'text-accent': like})}>
|
||||
<i
|
||||
<button
|
||||
class="fa fa-heart cursor-pointer"
|
||||
on:click={() => like ? deleteReaction(like) : react("+")} />
|
||||
on:click|stopPropagation={() => like ? deleteReaction(like) : react("+")} />
|
||||
{likes.length}
|
||||
</div>
|
||||
<div>
|
||||
<i class="fa fa-flag cursor-pointer" on:click={() => react("-")} />
|
||||
<button class="fa fa-flag cursor-pointer" on:click|stopPropagation={() => react("-")} />
|
||||
{flags.length}
|
||||
</div>
|
||||
</div>
|
||||
@ -185,13 +189,13 @@
|
||||
<div transition:slide class="note-reply">
|
||||
<div class="bg-medium border-medium border border-solid">
|
||||
<Compose bind:this={reply} onSubmit={sendReply}>
|
||||
<div
|
||||
<button
|
||||
slot="addon"
|
||||
on:click={sendReply}
|
||||
class="flex flex-col py-8 p-4 justify-center gap-2 border-l border-solid border-dark
|
||||
hover:bg-accent transition-all cursor-pointer text-white ">
|
||||
<i class="fa fa-paper-plane fa-xl" />
|
||||
</div>
|
||||
</button>
|
||||
</Compose>
|
||||
</div>
|
||||
{#if replyMentions.length > 0}
|
||||
@ -201,7 +205,7 @@
|
||||
</div>
|
||||
{#each replyMentions as p}
|
||||
<div class="inline-block py-1 px-2 mr-1 mb-2 rounded-full border border-solid border-light">
|
||||
<i class="fa fa-times cursor-pointer" on:click|stopPropagation={() => removeMention(p)} />
|
||||
<button class="fa fa-times cursor-pointer" on:click|stopPropagation={() => removeMention(p)} />
|
||||
{displayPerson(getPerson(p, true))}
|
||||
</div>
|
||||
{/each}
|
||||
@ -214,10 +218,10 @@
|
||||
{#if depth > 0}
|
||||
<div class="ml-5 border-l border-solid border-medium">
|
||||
{#if !showEntire && note.replies.length > 3}
|
||||
<div class="ml-5 py-2 text-light cursor-pointer" on:click={onClick}>
|
||||
<button class="ml-5 py-2 text-light cursor-pointer" on:click={onClick}>
|
||||
<i class="fa fa-up-down text-sm pr-2" />
|
||||
Show {quantify(note.replies.length - 3, 'other reply', 'more replies')}
|
||||
</div>
|
||||
</button>
|
||||
{/if}
|
||||
{#each note.replies.slice(showEntire ? 0 : -3) as r (r.id)}
|
||||
<svelte:self showParent={false} note={r} depth={depth - 1} {invertColors} {anchorId} />
|
||||
|
@ -48,12 +48,12 @@
|
||||
|
||||
<Content size="inherit" class="pt-6">
|
||||
{#if newNotes.length > 0}
|
||||
<div
|
||||
<button
|
||||
in:slide
|
||||
class="cursor-pointer text-center underline text-light"
|
||||
on:click={showNewNotes}>
|
||||
Load {quantify(newNotes.length, 'new note')}
|
||||
</div>
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
<div>
|
||||
|
@ -36,7 +36,7 @@
|
||||
href={url}
|
||||
class="rounded border border-solid border-medium flex flex-col bg-white overflow-hidden">
|
||||
{#if preview.image}
|
||||
<img src={preview.image} />
|
||||
<img alt="Link preview" src={preview.image} />
|
||||
<div class="h-px bg-medium" />
|
||||
{/if}
|
||||
{#if preview.title}
|
||||
|
@ -33,7 +33,7 @@
|
||||
})
|
||||
</script>
|
||||
|
||||
<li
|
||||
<button
|
||||
class="flex gap-4 px-4 py-6 cursor-pointer hover:bg-medium transition-all rounded border border-solid border-medium bg-dark"
|
||||
on:click={() => setRoom(room)}
|
||||
in:fly={{y: 20}}>
|
||||
@ -81,4 +81,4 @@
|
||||
</p>
|
||||
{/if}
|
||||
</div>
|
||||
</li>
|
||||
</button>
|
||||
|
@ -3,7 +3,7 @@
|
||||
export let setRoom
|
||||
</script>
|
||||
|
||||
<div
|
||||
<button
|
||||
class="flex gap-4 px-2 py-4 cursor-pointer hover:bg-dark transition-all"
|
||||
on:click={() => setRoom(room.id)}>
|
||||
<div
|
||||
@ -17,4 +17,4 @@
|
||||
</p>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
|
@ -9,14 +9,14 @@
|
||||
<div class="inline-block">
|
||||
<div class="rounded flex border border-solid border-light cursor-pointer">
|
||||
{#each options as option, i}
|
||||
<span
|
||||
<button
|
||||
class={cx("px-4 py-2", {
|
||||
"border-l border-solid border-light": i > 0,
|
||||
"bg-accent": value === option,
|
||||
})}
|
||||
on:click={() => { value = option }}>
|
||||
{option}
|
||||
</span>
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -7,13 +7,13 @@
|
||||
export let setActiveTab
|
||||
</script>
|
||||
|
||||
<ul class="border-b border-solid border-dark flex pt-2" in:fly={{y: 20}}>
|
||||
<div class="border-b border-solid border-dark flex pt-2" in:fly={{y: 20}}>
|
||||
{#each tabs as tab}
|
||||
<li
|
||||
<button
|
||||
class="cursor-pointer hover:border-b border-solid border-medium px-8 py-4"
|
||||
class:border-b={activeTab === tab}
|
||||
on:click={() => setActiveTab(tab)}>
|
||||
{toTitle(tab)}
|
||||
</li>
|
||||
</button>
|
||||
{/each}
|
||||
</ul>
|
||||
</div>
|
||||
|
@ -18,7 +18,7 @@
|
||||
return createScroller(async () => {
|
||||
limit += 10
|
||||
|
||||
const events = await db.alerts.toArray()
|
||||
const events = await db.table('alerts').toArray()
|
||||
const notes = events.filter(e => e.kind === 1)
|
||||
const likes = events.filter(e => e.kind === 7)
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
<script>
|
||||
<script lang="ts">
|
||||
import {objOf} from 'ramda'
|
||||
import {nip19} from 'nostr-tools'
|
||||
import Content from 'src/partials/Content.svelte'
|
||||
@ -7,7 +7,7 @@
|
||||
|
||||
export let entity
|
||||
|
||||
const {type, data} = nip19.decode(entity)
|
||||
const {type, data} = nip19.decode(entity) as {type: string, data: any}
|
||||
const relays = (data.relays || []).map(objOf('url'))
|
||||
</script>
|
||||
|
||||
|
@ -19,8 +19,8 @@
|
||||
const {mostRecentByPubkey} = messages
|
||||
|
||||
const rooms = lq(async () => {
|
||||
const rooms = await db.rooms.where('joined').equals(1).toArray()
|
||||
const messages = await db.messages.toArray()
|
||||
const rooms = await db.table('rooms').where('joined').equals(1).toArray()
|
||||
const messages = await db.table('messages').toArray()
|
||||
const pubkeys = without([$user.pubkey], uniq(messages.flatMap(m => [m.pubkey, m.recipient])))
|
||||
|
||||
await loaders.loadPeople(getRelays(), pubkeys)
|
||||
@ -31,7 +31,7 @@
|
||||
})
|
||||
|
||||
const search = lq(async () => {
|
||||
const rooms = await db.rooms.where('joined').equals(0).toArray()
|
||||
const rooms = await db.table('rooms').where('joined').equals(0).toArray()
|
||||
|
||||
roomsCount = rooms.length
|
||||
|
||||
@ -49,11 +49,11 @@
|
||||
}
|
||||
|
||||
const joinRoom = id => {
|
||||
db.rooms.where('id').equals(id).modify({joined: 1})
|
||||
db.table('rooms').where('id').equals(id).modify({joined: 1})
|
||||
}
|
||||
|
||||
const leaveRoom = id => {
|
||||
db.rooms.where('id').equals(id).modify({joined: 0})
|
||||
db.table('rooms').where('id').equals(id).modify({joined: 0})
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
|
@ -1,4 +1,4 @@
|
||||
<script>
|
||||
<script lang="ts">
|
||||
import {liveQuery} from 'dexie'
|
||||
import {pluck} from 'ramda'
|
||||
import {nip19} from 'nostr-tools'
|
||||
@ -11,8 +11,8 @@
|
||||
|
||||
export let entity
|
||||
|
||||
let {data: roomId} = nip19.decode(entity)
|
||||
let room = liveQuery(() => db.rooms.where('id').equals(roomId).first())
|
||||
let {data: roomId} = nip19.decode(entity) as {data: string}
|
||||
let room = liveQuery(() => db.table('rooms').where('id').equals(roomId).first())
|
||||
|
||||
const getRoomRelays = $room => {
|
||||
let relays = getRelays()
|
||||
@ -26,7 +26,7 @@
|
||||
|
||||
const listenForMessages = async cb => {
|
||||
// Make sure we have our room so we can calculate relays
|
||||
const $room = await db.rooms.where('id').equals(roomId).first()
|
||||
const $room = await db.table('rooms').where('id').equals(roomId).first()
|
||||
const relays = getRoomRelays($room)
|
||||
|
||||
return listen(
|
||||
|
@ -46,7 +46,10 @@
|
||||
<div class="flex flex-col gap-1">
|
||||
<strong>Public Key</strong>
|
||||
<Input disabled value={$pubkey ? nip19.npubEncode($pubkey) : ''}>
|
||||
<i slot="after" class="fa-solid fa-copy cursor-pointer" on:click={() => copyKey('public')} />
|
||||
<button
|
||||
slot="after"
|
||||
class="fa-solid fa-copy cursor-pointer"
|
||||
on:click={() => copyKey('public')} />
|
||||
</Input>
|
||||
<p class="text-sm text-light">
|
||||
Your public key identifies your account. You can share this with people
|
||||
@ -57,7 +60,10 @@
|
||||
<div class="flex flex-col gap-1">
|
||||
<strong>Private Key</strong>
|
||||
<Input disabled type="password" value={nip19.nsecEncode($privkey)}>
|
||||
<i slot="after" class="fa-solid fa-copy cursor-pointer" on:click={() => copyKey('private')} />
|
||||
<button
|
||||
slot="after"
|
||||
class="fa-solid fa-copy cursor-pointer"
|
||||
on:click={() => copyKey('private')} />
|
||||
</Input>
|
||||
<p class="text-sm text-light">
|
||||
Your private key is used to prove your identity by cryptographically signing
|
||||
|
@ -1,4 +1,4 @@
|
||||
<script>
|
||||
<script lang="ts">
|
||||
import {fly} from 'svelte/transition'
|
||||
import Anchor from "src/partials/Anchor.svelte"
|
||||
import Content from "src/partials/Content.svelte"
|
||||
@ -8,8 +8,10 @@
|
||||
const nip07 = "https://github.com/nostr-protocol/nips/blob/master/07.md"
|
||||
|
||||
const autoLogIn = async () => {
|
||||
if (window.nostr) {
|
||||
await login({pubkey: await window.nostr.getPublicKey()}, true)
|
||||
const {nostr} = window as any
|
||||
|
||||
if (nostr) {
|
||||
await login({pubkey: await nostr.getPublicKey()}, true)
|
||||
} else {
|
||||
modal.set({type: 'login/privkey'})
|
||||
}
|
||||
|
@ -21,7 +21,7 @@
|
||||
// Give them a moment to see the state transition. Dexie
|
||||
// also apparently needs some time
|
||||
setTimeout(() => {
|
||||
window.location = '/login'
|
||||
window.location.href = '/login'
|
||||
}, 1000)
|
||||
}
|
||||
</script>
|
||||
|
@ -1,4 +1,4 @@
|
||||
<script>
|
||||
<script lang="ts">
|
||||
import {liveQuery} from 'dexie'
|
||||
import {nip19} from 'nostr-tools'
|
||||
import {sortBy, pluck} from 'ramda'
|
||||
@ -13,8 +13,8 @@
|
||||
export let entity
|
||||
|
||||
let crypt = keys.getCrypt()
|
||||
let {data: pubkey} = nip19.decode(entity)
|
||||
let person = liveQuery(() => db.people.get(pubkey))
|
||||
let {data: pubkey} = nip19.decode(entity) as {data: string}
|
||||
let person = liveQuery(() => db.table('people').get(pubkey))
|
||||
|
||||
messages.lastCheckedByPubkey.update($obj => ({...$obj, [pubkey]: now()}))
|
||||
|
||||
@ -37,15 +37,20 @@
|
||||
batch(300, async events => {
|
||||
// Reload from db since we annotate messages there
|
||||
const messageIds = pluck('id', events.filter(e => e.kind === 4))
|
||||
const messages = await db.messages.where('id').anyOf(messageIds).toArray()
|
||||
const messages = await db.table('messages').where('id').anyOf(messageIds).toArray()
|
||||
|
||||
cb(await decryptMessages(messages))
|
||||
})
|
||||
)
|
||||
|
||||
const loadMessages = async ({until, limit}) => {
|
||||
const fromThem = await db.messages.where('pubkey').equals(pubkey).toArray()
|
||||
const toThem = await db.messages.where('recipient').equals(pubkey).toArray()
|
||||
const a = db.table('messages')
|
||||
const b = a.where('pubkey')
|
||||
const c = b.equals(pubkey)
|
||||
const d = c.toArray()
|
||||
const e = await d
|
||||
const fromThem = await db.table('messages').where('pubkey').equals(pubkey).toArray()
|
||||
const toThem = await db.table('messages').where('recipient').equals(pubkey).toArray()
|
||||
const events = fromThem.concat(toThem).filter(e => e.created_at < until)
|
||||
const messages = sortBy(e => -e.created_at, events).slice(0, limit)
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
<script>
|
||||
<script lang="ts">
|
||||
import {last, find, reject} from 'ramda'
|
||||
import {onMount, onDestroy} from 'svelte'
|
||||
import {nip19} from 'nostr-tools'
|
||||
@ -26,7 +26,7 @@
|
||||
export let relays = null
|
||||
|
||||
let subs = []
|
||||
let pubkey = nip19.decode(npub).data
|
||||
let pubkey = nip19.decode(npub).data as string
|
||||
let following = false
|
||||
let followers = new Set()
|
||||
let followersCount = 0
|
||||
|
@ -1,4 +1,4 @@
|
||||
<script>
|
||||
<script lang="ts">
|
||||
import {onMount} from "svelte"
|
||||
import {fly} from 'svelte/transition'
|
||||
import {navigate} from "svelte-routing"
|
||||
@ -28,7 +28,8 @@
|
||||
values = pick(Object.keys(values), $user)
|
||||
|
||||
document.querySelector('[name=picture]').addEventListener('change', async e => {
|
||||
const [file] = e.target.files
|
||||
const target = e.target as HTMLInputElement
|
||||
const [file] = target.files
|
||||
|
||||
if (file) {
|
||||
const reader = new FileReader()
|
||||
|
@ -24,15 +24,15 @@
|
||||
const {relays} = await res.json()
|
||||
|
||||
for (const url of relays) {
|
||||
db.relays.put({url})
|
||||
db.table('relays').put({url})
|
||||
}
|
||||
}).catch(noop)
|
||||
|
||||
for (const relay of defaults.relays) {
|
||||
db.relays.put(relay)
|
||||
db.table('relays').put(relay)
|
||||
}
|
||||
|
||||
const knownRelays = liveQuery(() => db.relays.toArray())
|
||||
const knownRelays = liveQuery(() => db.table('relays').toArray())
|
||||
|
||||
$: search = fuzzy($knownRelays, {keys: ["name", "description", "url"]})
|
||||
|
||||
@ -93,7 +93,7 @@
|
||||
<i class={url.startsWith('wss') ? "fa fa-lock" : "fa fa-unlock"} />
|
||||
{last(url.split('://'))}
|
||||
</strong>
|
||||
<i class="fa fa-times cursor-pointer" on:click={() => leave(url)}/>
|
||||
<button class="fa fa-times cursor-pointer" on:click={() => leave(url)} />
|
||||
</div>
|
||||
<p class="text-light">
|
||||
{#if status[url] === 'error'}
|
||||
@ -151,9 +151,9 @@
|
||||
<strong>{name || url}</strong>
|
||||
<p class="text-light">{description || ''}</p>
|
||||
</div>
|
||||
<a class="underline cursor-pointer" on:click={() => join(url)}>
|
||||
<button class="underline cursor-pointer" on:click={() => join(url)}>
|
||||
Join
|
||||
</a>
|
||||
</button>
|
||||
</div>
|
||||
{/if}
|
||||
{/each}
|
||||
|
@ -12,7 +12,7 @@ export const copyToClipboard = text => {
|
||||
const result = document.execCommand("copy")
|
||||
|
||||
document.body.removeChild(input)
|
||||
activeElement.focus()
|
||||
;(activeElement as HTMLElement).focus()
|
||||
|
||||
return result
|
||||
}
|
||||
@ -62,7 +62,7 @@ export const killEvent = e => {
|
||||
e.stopImmediatePropagation()
|
||||
}
|
||||
|
||||
export const fromParentOffset = (element, offset) => {
|
||||
export const fromParentOffset = (element, offset): [HTMLElement, number] => {
|
||||
for (const child of element.childNodes) {
|
||||
if (offset <= child.textContent.length) {
|
||||
return [child, offset]
|
||||
@ -70,6 +70,8 @@ export const fromParentOffset = (element, offset) => {
|
||||
|
||||
offset -= child.textContent.length
|
||||
}
|
||||
|
||||
throw new Error("Unable to find parent offset")
|
||||
}
|
||||
|
||||
export const renderContent = content => {
|
@ -73,7 +73,7 @@ export const formatTimestampRelative = ts => {
|
||||
numeric: 'auto',
|
||||
})
|
||||
|
||||
return formatter.format(-delta, unit)
|
||||
return formatter.format(-delta, unit as Intl.RelativeTimeFormatUnit)
|
||||
}
|
||||
|
||||
export const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
|
||||
@ -147,6 +147,8 @@ export const getLastSync = (k, fallback = 0) => {
|
||||
}
|
||||
|
||||
export class Cursor {
|
||||
until: number
|
||||
limit: number
|
||||
constructor(limit = 10) {
|
||||
this.until = now()
|
||||
this.limit = limit
|
@ -1,4 +1,4 @@
|
||||
<script>
|
||||
<script lang="ts">
|
||||
import {onMount} from "svelte"
|
||||
import {fly} from 'svelte/transition'
|
||||
import {stripExifData} from "src/util/html"
|
||||
@ -10,11 +10,12 @@
|
||||
import {toast, modal} from "src/app"
|
||||
import cmd from "src/app/cmd"
|
||||
|
||||
export let room = {}
|
||||
export let room = {name: null, id: null, about: null, picture: null}
|
||||
|
||||
onMount(async () => {
|
||||
document.querySelector('[name=picture]').addEventListener('change', async e => {
|
||||
const [file] = e.target.files
|
||||
const target = e.target as HTMLInputElement
|
||||
const [file] = target.files
|
||||
|
||||
if (file) {
|
||||
const reader = new FileReader()
|
||||
@ -37,7 +38,7 @@
|
||||
? await cmd.updateRoom(getRelays(), room)
|
||||
: await cmd.createRoom(getRelays(), room)
|
||||
|
||||
await db.rooms.where('id').equals(room.id).modify({joined: 1})
|
||||
await db.table('rooms').where('id').equals(room.id).modify({joined: 1})
|
||||
|
||||
toast.show("info", `Your room has been ${room.id ? 'updated' : 'created'}!`)
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
import {onMount} from 'svelte'
|
||||
import {nip19} from 'nostr-tools'
|
||||
import {fly} from 'svelte/transition'
|
||||
import {load} from 'src/agent'
|
||||
import {load, getRelays} from 'src/agent'
|
||||
import {annotate} from 'src/app'
|
||||
import loaders from 'src/app/loaders'
|
||||
import Note from 'src/partials/Note.svelte'
|
||||
@ -10,7 +10,7 @@
|
||||
import Spinner from 'src/partials/Spinner.svelte'
|
||||
|
||||
export let note
|
||||
export let relays
|
||||
export let relays = getRelays()
|
||||
|
||||
let loading = true
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
<script>
|
||||
<script lang="ts">
|
||||
import {nip19} from 'nostr-tools'
|
||||
import Input from 'src/partials/Input.svelte'
|
||||
import Anchor from 'src/partials/Anchor.svelte'
|
||||
@ -10,7 +10,7 @@
|
||||
const nip07 = "https://github.com/nostr-protocol/nips/blob/master/07.md"
|
||||
|
||||
const logIn = async () => {
|
||||
const privkey = nsec.startsWith('nsec') ? nip19.decode(nsec).data : nsec
|
||||
const privkey = (nsec.startsWith('nsec') ? nip19.decode(nsec).data : nsec) as string
|
||||
|
||||
if (!privkey.match(/[a-z0-9]{64}/)) {
|
||||
toast.show("error", "Sorry, but that's an invalid private key.")
|
||||
|
@ -1,4 +1,4 @@
|
||||
<script>
|
||||
<script lang="ts">
|
||||
import {nip19} from 'nostr-tools'
|
||||
import Input from 'src/partials/Input.svelte'
|
||||
import Anchor from 'src/partials/Anchor.svelte'
|
||||
@ -9,7 +9,7 @@
|
||||
let npub = ''
|
||||
|
||||
const logIn = async () => {
|
||||
const pubkey = npub.startsWith('npub') ? nip19.decode(npub).data : npub
|
||||
const pubkey = (npub.startsWith('npub') ? nip19.decode(npub).data : npub) as string
|
||||
|
||||
if (!pubkey.match(/[a-z0-9]{64}/)) {
|
||||
toast.show("error", "Sorry, but that's an invalid public key.")
|
||||
|
@ -1 +1,3 @@
|
||||
|
||||
<script lang="ts">
|
||||
export let q
|
||||
</script>
|
||||
|
@ -1,4 +1,4 @@
|
||||
<script>
|
||||
<script lang="ts">
|
||||
import {nip19, generatePrivateKey} from 'nostr-tools'
|
||||
import {copyToClipboard} from "src/util/html"
|
||||
import Input from 'src/partials/Input.svelte'
|
||||
@ -11,7 +11,7 @@
|
||||
const nip07 = "https://github.com/nostr-protocol/nips/blob/master/07.md"
|
||||
|
||||
const logIn = async () => {
|
||||
await login({privkey: nip19.decode(nsec).data})
|
||||
await login({privkey: nip19.decode(nsec).data as string})
|
||||
}
|
||||
|
||||
const copyKey = () => {
|
||||
@ -31,7 +31,7 @@
|
||||
<div class="flex-grow">
|
||||
<Input disabled placeholder={"•".repeat(63)}>
|
||||
<i slot="before" class="fa fa-key" />
|
||||
<i slot="after" class="cursor-pointer fa fa-copy" on:click={copyKey} />
|
||||
<button slot="after" class="cursor-pointer fa fa-copy" on:click={copyKey} />
|
||||
</Input>
|
||||
</div>
|
||||
<Anchor type="button" on:click={logIn}>Log In</Anchor>
|
||||
|
16
tsconfig.json
Normal file
16
tsconfig.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"extends": "@tsconfig/svelte/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"target": "esnext",
|
||||
"useDefineForClassFields": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"module": "esnext",
|
||||
"resolveJsonModule": true,
|
||||
"baseUrl": ".",
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"isolatedModules": false,
|
||||
"importsNotUsedAsValues": "preserve"
|
||||
},
|
||||
"include": ["src/**/*.d.ts", "src/**/*.ts", "src/**/*.js", "src/**/*.svelte"]
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
import * as path from 'path'
|
||||
import { defineConfig } from 'vite'
|
||||
import sveltePreprocess from 'svelte-preprocess'
|
||||
import { svelte } from '@sveltejs/vite-plugin-svelte'
|
||||
import { nodePolyfills } from 'vite-plugin-node-polyfills'
|
||||
|
||||
@ -17,8 +18,14 @@ export default defineConfig({
|
||||
protocolImports: true,
|
||||
}),
|
||||
svelte({
|
||||
preprocess: sveltePreprocess(),
|
||||
onwarn: (warning, handler) => {
|
||||
if (warning.code.startsWith("a11y-")) return
|
||||
const isA11y = warning.code.startsWith('a11y-')
|
||||
|
||||
if (["a11y-autofocus"].includes(warning.code)) return
|
||||
if (warning.filename.includes("node_modules")) return
|
||||
if (warning.filename.includes("Card.svelte") && isA11y) return
|
||||
|
||||
handler(warning)
|
||||
},
|
||||
}),
|
||||
|
Loading…
Reference in New Issue
Block a user