From 5909b593abe7241cc2a6eadf235de6739a78c01d Mon Sep 17 00:00:00 2001 From: Jon Staab Date: Wed, 5 Feb 2025 10:47:56 -0800 Subject: [PATCH] Fix bugs, add timehash --- src/app/components/ChannelCompose.svelte | 6 +---- src/app/components/EventCreate.svelte | 13 ++++++--- src/app/editor/EditorContent.svelte | 13 ++++----- src/app/editor/index.ts | 1 + src/lib/components/DateTimeInput.svelte | 26 +++++++----------- src/lib/components/Field.svelte | 20 +++++++------- src/lib/util.ts | 34 ++++++++++++++++++++++++ 7 files changed, 72 insertions(+), 41 deletions(-) diff --git a/src/app/components/ChannelCompose.svelte b/src/app/components/ChannelCompose.svelte index 3bc2aa23..d826c0fd 100644 --- a/src/app/components/ChannelCompose.svelte +++ b/src/app/components/ChannelCompose.svelte @@ -1,5 +1,5 @@
diff --git a/src/app/components/EventCreate.svelte b/src/app/components/EventCreate.svelte index 5cd67da7..7f48a07f 100644 --- a/src/app/components/EventCreate.svelte +++ b/src/app/components/EventCreate.svelte @@ -4,6 +4,7 @@ import {createEvent, EVENT_TIME} from "@welshman/util" import {publishThunk, dateToSeconds} from "@welshman/app" import {preventDefault} from "@lib/html" + import {timeHashesBetween} from "@lib/util" import Icon from "@lib/components/Icon.svelte" import Field from "@lib/components/Field.svelte" import Button from "@lib/components/Button.svelte" @@ -38,14 +39,18 @@ }) } + const startTs = dateToSeconds(start) + const endTs = dateToSeconds(end) + const event = createEvent(EVENT_TIME, { content: editor.getText({blockSeparator: "\n"}).trim(), tags: [ ["d", randomId()], ["title", title], ["location", location], - ["start", dateToSeconds(start).toString()], - ["end", dateToSeconds(end).toString()], + ["start", startTs.toString()], + ["end", endTs.toString()], + ...timeHashesBetween(startTs, endTs).map(T => ["T", T]), ...editor.storage.nostr.getEditorTags(), PROTECTED, ], @@ -106,7 +111,7 @@ {#snippet label()} - Start + Start* {/snippet} {#snippet input()} @@ -114,7 +119,7 @@ {#snippet label()} - End + End* {/snippet} {#snippet input()} diff --git a/src/app/editor/EditorContent.svelte b/src/app/editor/EditorContent.svelte index b02902ce..c6b40d6c 100644 --- a/src/app/editor/EditorContent.svelte +++ b/src/app/editor/EditorContent.svelte @@ -6,16 +6,17 @@ let element: HTMLElement onMount(() => { - if (element) { - element.append(...(Array.from(editor.options.element.childNodes) as any)) - editor.setOptions({element}) - editor.contentElement = element + if (editor.options.element) { + element?.append(editor.options.element) + } + + if (editor.options.autofocus) { + ;(element?.querySelector("[contenteditable]") as HTMLElement)?.focus() } }) onDestroy(() => { - editor.contentElement = null - editor.setOptions({element: null}) + editor.destroy() }) diff --git a/src/app/editor/index.ts b/src/app/editor/index.ts index 1cb5f313..9ba3c742 100644 --- a/src/app/editor/index.ts +++ b/src/app/editor/index.ts @@ -50,6 +50,7 @@ export const makeEditor = ({ new Editor({ content, autofocus, + element: document.createElement("div"), extensions: [ WelshmanExtension.configure({ submit, diff --git a/src/lib/components/DateTimeInput.svelte b/src/lib/components/DateTimeInput.svelte index a207e423..5b84786e 100644 --- a/src/lib/components/DateTimeInput.svelte +++ b/src/lib/components/DateTimeInput.svelte @@ -4,12 +4,10 @@ import Button from "@lib/components/Button.svelte" interface Props { - initialValue?: Date | undefined value?: Date | undefined } - let {initialValue = undefined, value = $bindable(initialValue)}: Props = - $props() + let {value = $bindable()}: Props = $props() const pad = (n: number) => ("00" + String(n)).slice(-2) @@ -29,7 +27,7 @@ return d } - const onChange = () => { + const onchange = () => { if (value) { value = syncTime(value) } @@ -40,38 +38,32 @@ time = "" } - let time = "" + let time = $state("") let element: HTMLElement - $: { + $effect(() => { if (value) { value = syncTime(value) } - } + })
- +
{#if value} - {:else} - {/if}
diff --git a/src/lib/components/Field.svelte b/src/lib/components/Field.svelte index e61d4ac1..4f81e57f 100644 --- a/src/lib/components/Field.svelte +++ b/src/lib/components/Field.svelte @@ -1,24 +1,26 @@
- {#if props.label} + {#if label} {/if} - {@render props.input?.()} - {#if props.info} + {@render input?.()} + {#if info}

- {@render props.info?.()} + {@render info()}

{/if}
diff --git a/src/lib/util.ts b/src/lib/util.ts index 8c9f1bcd..6514a79f 100644 --- a/src/lib/util.ts +++ b/src/lib/util.ts @@ -1,5 +1,6 @@ import {hexToBytes, bytesToHex} from "@noble/hashes/utils" import * as nip19 from "nostr-tools/nip19" +import {HOUR} from "@welshman/lib" export const displayList = (xs: T[], conj = "and", n = 6, locale = "en-US") => { const stringItems = xs.map(String) @@ -24,3 +25,36 @@ export const nsecDecode = (nsec: string) => { return bytesToHex(data) } + +export const timeHash = (seconds: number, precision = 32) => { + const alphabet = "0123456789bcdefghjkmnpqrstuvwxyz" + const uint32 = Math.min(seconds >>> 0, 0xffffffff) + const binary = uint32.toString(2).padStart(32, "0") + const chunks = Math.min(Math.floor(precision / 5), 6) + + let hash = "" + + for (let i = 0; i < chunks * 5; i += 5) { + const chunk = binary.slice(i, i + 5) + const index = parseInt(chunk, 2) + + hash += alphabet[index] + } + + return hash +} + +export const timeHashesBetween = (a: number, b: number) => { + const precisions = [10, 15, 20] + const start = Math.min(a, b) >>> 0 + const end = Math.min(Math.max(a, b) >>> 0, 0xffffffff) + const hashes = new Set() + + for (let seconds = start; seconds <= end; seconds += HOUR) { + for (const precision of precisions) { + hashes.add(timeHash(seconds, precision)) + } + } + + return Array.from(hashes).sort() +}