mirror of
https://github.com/coracle-social/flotilla.git
synced 2025-12-11 11:27:03 +00:00
Flesh out calendar event cards
This commit is contained in:
49
package-lock.json
generated
49
package-lock.json
generated
@@ -23,12 +23,12 @@
|
|||||||
"@tiptap/extension-text": "^2.6.6",
|
"@tiptap/extension-text": "^2.6.6",
|
||||||
"@tiptap/suggestion": "^2.6.4",
|
"@tiptap/suggestion": "^2.6.4",
|
||||||
"@types/throttle-debounce": "^5.0.2",
|
"@types/throttle-debounce": "^5.0.2",
|
||||||
"@welshman/app": "^0.0.5",
|
"@welshman/app": "^0.0.7",
|
||||||
"@welshman/lib": "^0.0.17",
|
"@welshman/lib": "^0.0.17",
|
||||||
"@welshman/net": "^0.0.22",
|
"@welshman/net": "^0.0.22",
|
||||||
"@welshman/signer": "^0.0.5",
|
"@welshman/signer": "^0.0.5",
|
||||||
"@welshman/store": "^0.0.6",
|
"@welshman/store": "^0.0.7",
|
||||||
"@welshman/util": "^0.0.31",
|
"@welshman/util": "^0.0.33",
|
||||||
"daisyui": "^4.12.10",
|
"daisyui": "^4.12.10",
|
||||||
"date-picker-svelte": "^2.13.0",
|
"date-picker-svelte": "^2.13.0",
|
||||||
"fuse.js": "^7.0.0",
|
"fuse.js": "^7.0.0",
|
||||||
@@ -1655,14 +1655,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@welshman/app": {
|
"node_modules/@welshman/app": {
|
||||||
"version": "0.0.5",
|
"version": "0.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/@welshman/app/-/app-0.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/@welshman/app/-/app-0.0.7.tgz",
|
||||||
"integrity": "sha512-T7iXybwBnFN9E1GWeGQ6ZxvFrQ3EUUWHsZdG3Q+s57YxBDqDkRy+eOtxaDb2EBmgyflheERaggOlzFFTsmUjyA==",
|
"integrity": "sha512-37dTcUDe+6wLhCFClexuJZKCZyGHgGoiFBvm8EL6ig4UHRMRWH2NCeddftScq0gEIl2GVWuq96iCni9COc7nRw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@welshman/lib": "0.0.17",
|
"@welshman/lib": "0.0.17",
|
||||||
"@welshman/net": "0.0.22",
|
"@welshman/net": "0.0.22",
|
||||||
"@welshman/signer": "0.0.5",
|
"@welshman/signer": "0.0.5",
|
||||||
"@welshman/store": "0.0.6",
|
"@welshman/store": "0.0.7",
|
||||||
"@welshman/util": "0.0.31",
|
"@welshman/util": "0.0.31",
|
||||||
"fuse.js": "^7.0.0",
|
"fuse.js": "^7.0.0",
|
||||||
"idb": "^8.0.0",
|
"idb": "^8.0.0",
|
||||||
@@ -1670,6 +1670,15 @@
|
|||||||
"throttle-debounce": "^5.0.2"
|
"throttle-debounce": "^5.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@welshman/app/node_modules/@welshman/util": {
|
||||||
|
"version": "0.0.31",
|
||||||
|
"resolved": "https://registry.npmjs.org/@welshman/util/-/util-0.0.31.tgz",
|
||||||
|
"integrity": "sha512-nUv/Mto6maQx6vbCaZ0HKQRvLYRWqQzPTLsKoxSDX0HkeFP653T6raFx8TvWt+op/qBuuT8sANJactc2/qGoYg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@welshman/lib": "0.0.17",
|
||||||
|
"nostr-tools": "^2.7.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@welshman/lib": {
|
"node_modules/@welshman/lib": {
|
||||||
"version": "0.0.17",
|
"version": "0.0.17",
|
||||||
"resolved": "https://registry.npmjs.org/@welshman/lib/-/lib-0.0.17.tgz",
|
"resolved": "https://registry.npmjs.org/@welshman/lib/-/lib-0.0.17.tgz",
|
||||||
@@ -1693,6 +1702,15 @@
|
|||||||
"ws": "^8.16.0"
|
"ws": "^8.16.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@welshman/net/node_modules/@welshman/util": {
|
||||||
|
"version": "0.0.31",
|
||||||
|
"resolved": "https://registry.npmjs.org/@welshman/util/-/util-0.0.31.tgz",
|
||||||
|
"integrity": "sha512-nUv/Mto6maQx6vbCaZ0HKQRvLYRWqQzPTLsKoxSDX0HkeFP653T6raFx8TvWt+op/qBuuT8sANJactc2/qGoYg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@welshman/lib": "0.0.17",
|
||||||
|
"nostr-tools": "^2.7.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@welshman/signer": {
|
"node_modules/@welshman/signer": {
|
||||||
"version": "0.0.5",
|
"version": "0.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/@welshman/signer/-/signer-0.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/@welshman/signer/-/signer-0.0.5.tgz",
|
||||||
@@ -1725,16 +1743,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@welshman/store": {
|
"node_modules/@welshman/store": {
|
||||||
"version": "0.0.6",
|
"version": "0.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/@welshman/store/-/store-0.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/@welshman/store/-/store-0.0.7.tgz",
|
||||||
"integrity": "sha512-yZDnXcIZ2fcqvK+1W9OTRXJy3IPKE3ykFp5VnUT5bGMSRSTIyHnPO5swsgDLofe5Zswdee0lJTwE5IQBthf0pQ==",
|
"integrity": "sha512-Ltx2RYwMicCeGWBdl3+Wr+pilIdofmNSDKTqgOqtPanOgSarGn7uqZnPzDz9N+P0htg2TDSogg7YkBWf5drhDw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@welshman/lib": "0.0.17",
|
"@welshman/lib": "0.0.17",
|
||||||
"@welshman/util": "0.0.31",
|
"@welshman/util": "0.0.31",
|
||||||
"svelte": "^4.2.18"
|
"svelte": "^4.2.18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@welshman/util": {
|
"node_modules/@welshman/store/node_modules/@welshman/util": {
|
||||||
"version": "0.0.31",
|
"version": "0.0.31",
|
||||||
"resolved": "https://registry.npmjs.org/@welshman/util/-/util-0.0.31.tgz",
|
"resolved": "https://registry.npmjs.org/@welshman/util/-/util-0.0.31.tgz",
|
||||||
"integrity": "sha512-nUv/Mto6maQx6vbCaZ0HKQRvLYRWqQzPTLsKoxSDX0HkeFP653T6raFx8TvWt+op/qBuuT8sANJactc2/qGoYg==",
|
"integrity": "sha512-nUv/Mto6maQx6vbCaZ0HKQRvLYRWqQzPTLsKoxSDX0HkeFP653T6raFx8TvWt+op/qBuuT8sANJactc2/qGoYg==",
|
||||||
@@ -1743,6 +1761,15 @@
|
|||||||
"nostr-tools": "^2.7.2"
|
"nostr-tools": "^2.7.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@welshman/util": {
|
||||||
|
"version": "0.0.33",
|
||||||
|
"resolved": "https://registry.npmjs.org/@welshman/util/-/util-0.0.33.tgz",
|
||||||
|
"integrity": "sha512-dUt6H6Bi3cwhLup7G6MsfZymwX4C/EGvm6X/9KvaoTGZhy9z66lpoa1MebLGOTaQDyMs8nrIckXMp9eAi/c15Q==",
|
||||||
|
"dependencies": {
|
||||||
|
"@welshman/lib": "0.0.17",
|
||||||
|
"nostr-tools": "^2.7.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/acorn": {
|
"node_modules/acorn": {
|
||||||
"version": "8.12.1",
|
"version": "8.12.1",
|
||||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz",
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz",
|
||||||
|
|||||||
@@ -48,12 +48,12 @@
|
|||||||
"@tiptap/extension-text": "^2.6.6",
|
"@tiptap/extension-text": "^2.6.6",
|
||||||
"@tiptap/suggestion": "^2.6.4",
|
"@tiptap/suggestion": "^2.6.4",
|
||||||
"@types/throttle-debounce": "^5.0.2",
|
"@types/throttle-debounce": "^5.0.2",
|
||||||
"@welshman/app": "^0.0.5",
|
|
||||||
"@welshman/lib": "^0.0.17",
|
"@welshman/lib": "^0.0.17",
|
||||||
|
"@welshman/util": "^0.0.33",
|
||||||
|
"@welshman/store": "^0.0.7",
|
||||||
"@welshman/net": "^0.0.22",
|
"@welshman/net": "^0.0.22",
|
||||||
"@welshman/signer": "^0.0.5",
|
"@welshman/signer": "^0.0.5",
|
||||||
"@welshman/store": "^0.0.6",
|
"@welshman/app": "^0.0.7",
|
||||||
"@welshman/util": "^0.0.31",
|
|
||||||
"daisyui": "^4.12.10",
|
"daisyui": "^4.12.10",
|
||||||
"date-picker-svelte": "^2.13.0",
|
"date-picker-svelte": "^2.13.0",
|
||||||
"fuse.js": "^7.0.0",
|
"fuse.js": "^7.0.0",
|
||||||
|
|||||||
@@ -43,7 +43,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.card2 {
|
.card2 {
|
||||||
@apply rounded-box bg-base-100 p-6 text-base-content;
|
@apply rounded-box bg-base-100 p-6 text-base-content overflow-hidden text-ellipsis;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card2.card2-sm {
|
.card2.card2-sm {
|
||||||
@@ -90,6 +90,10 @@
|
|||||||
@apply shadow-[0_20px_25px_-5px_rgb(0,0,0,0.1)_0_8px_10px_-6px_rgb(0,0,0,0.1)];
|
@apply shadow-[0_20px_25px_-5px_rgb(0,0,0,0.1)_0_8px_10px_-6px_rgb(0,0,0,0.1)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.modal-box .z-feature {
|
||||||
|
@apply z-modal-feature;
|
||||||
|
}
|
||||||
|
|
||||||
/* tiptap */
|
/* tiptap */
|
||||||
|
|
||||||
.input-editor, .chat-editor {
|
.input-editor, .chat-editor {
|
||||||
|
|||||||
32
src/app/components/EventCard.svelte
Normal file
32
src/app/components/EventCard.svelte
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import cx from "classnames"
|
||||||
|
import {fromPairs} from "@welshman/lib"
|
||||||
|
import {Tags, getAddress} from "@welshman/util"
|
||||||
|
import {repository, pubkey, secondsToDate, getLocale, formatTimestamp, formatTimestampAsDate, deriveProfileDisplay} from "@welshman/app"
|
||||||
|
import Icon from "@lib/components/Icon.svelte"
|
||||||
|
import Link from "@lib/components/Link.svelte"
|
||||||
|
|
||||||
|
export let event
|
||||||
|
|
||||||
|
const address = getAddress(event)
|
||||||
|
const timeFmt = new Intl.DateTimeFormat(getLocale(), {timeStyle: "short"})
|
||||||
|
const datetimeFmt = new Intl.DateTimeFormat(getLocale(), {dateStyle: "short", timeStyle: "short"})
|
||||||
|
const profileDisplay = deriveProfileDisplay(event.pubkey)
|
||||||
|
|
||||||
|
$: meta = fromPairs(event.tags) as Record<string, string>
|
||||||
|
$: end = parseInt(meta.end)
|
||||||
|
$: start = parseInt(meta.start)
|
||||||
|
$: startDate = secondsToDate(start)
|
||||||
|
$: endDate = secondsToDate(end)
|
||||||
|
$: startDateDisplay = formatTimestampAsDate(start)
|
||||||
|
$: endDateDisplay = formatTimestampAsDate(end)
|
||||||
|
$: isSingleDay = startDateDisplay === endDateDisplay
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="card2 flex justify-between items-center gap-2">
|
||||||
|
<span>{meta.title || meta.name}</span>
|
||||||
|
<div class="flex items-center gap-2 text-sm">
|
||||||
|
<Icon icon="clock-circle" size={4} />
|
||||||
|
{timeFmt.format(startDate)} — {isSingleDay ? timeFmt.format(endDate) : formatTimestamp(end)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -4,21 +4,22 @@
|
|||||||
import {writable} from "svelte/store"
|
import {writable} from "svelte/store"
|
||||||
import {createEditor, type Editor, EditorContent} from "svelte-tiptap"
|
import {createEditor, type Editor, EditorContent} from "svelte-tiptap"
|
||||||
import {NProfileExtension, ImageExtension} from "nostr-editor"
|
import {NProfileExtension, ImageExtension} from "nostr-editor"
|
||||||
|
import {randomId} from "@welshman/lib"
|
||||||
import {createEvent, EVENT_DATE, EVENT_TIME} from "@welshman/util"
|
import {createEvent, EVENT_DATE, EVENT_TIME} from "@welshman/util"
|
||||||
import {publishThunk, makeThunk} from "@welshman/app"
|
import {publishThunk, makeThunk, dateToSeconds} from "@welshman/app"
|
||||||
import {findNodes} from "@lib/tiptap"
|
import {findNodes} from "@lib/tiptap"
|
||||||
import Icon from "@lib/components/Icon.svelte"
|
import Icon from "@lib/components/Icon.svelte"
|
||||||
import Field from "@lib/components/Field.svelte"
|
import Field from "@lib/components/Field.svelte"
|
||||||
import Button from "@lib/components/Button.svelte"
|
import Button from "@lib/components/Button.svelte"
|
||||||
import DateTimeInput from "@lib/components/DateTimeInput.svelte"
|
import DateTimeInput from "@lib/components/DateTimeInput.svelte"
|
||||||
import {makeMention, makeIMeta} from "@app/commands"
|
import {makeMention, makeIMeta} from "@app/commands"
|
||||||
import {getNoteEditorOptions, addFile} from "@app/editor"
|
import {getNoteEditorOptions, addFile, uploadFiles} from "@app/editor"
|
||||||
import {pushModal} from "@app/modal"
|
import {pushModal, clearModal} from "@app/modal"
|
||||||
import {pushToast} from "@app/toast"
|
import {pushToast} from "@app/toast"
|
||||||
|
|
||||||
export let url
|
export let url
|
||||||
|
|
||||||
const next = () => null
|
const submit = () => uploadFiles($editor)
|
||||||
|
|
||||||
const back = () => history.back()
|
const back = () => history.back()
|
||||||
|
|
||||||
@@ -50,12 +51,20 @@
|
|||||||
|
|
||||||
const event = createEvent(kind, {
|
const event = createEvent(kind, {
|
||||||
content: $editor.getText(),
|
content: $editor.getText(),
|
||||||
tags: [["-"], ...mentionTags, ...imetaTags],
|
tags: [
|
||||||
|
["-"],
|
||||||
|
["d", randomId()],
|
||||||
|
["title", title],
|
||||||
|
["location", location],
|
||||||
|
["start", dateToSeconds(start).toString()],
|
||||||
|
["end", dateToSeconds(end).toString()],
|
||||||
|
...mentionTags,
|
||||||
|
...imetaTags,
|
||||||
|
],
|
||||||
})
|
})
|
||||||
|
|
||||||
publishThunk(makeThunk({event, relays: [url]}))
|
publishThunk(makeThunk({event, relays: [url]}))
|
||||||
|
clearModal()
|
||||||
$editor.chain().clearContent().run()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let editor: Readable<Editor>
|
let editor: Readable<Editor>
|
||||||
@@ -71,7 +80,7 @@
|
|||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<form class="column gap-4" on:submit|preventDefault={next}>
|
<form class="column gap-4" on:submit|preventDefault={submit}>
|
||||||
<div class="py-2">
|
<div class="py-2">
|
||||||
<h1 class="heading">Create an Event</h1>
|
<h1 class="heading">Create an Event</h1>
|
||||||
<p class="text-center">Invite other group members to events online or in real life.</p>
|
<p class="text-center">Invite other group members to events online or in real life.</p>
|
||||||
@@ -118,7 +127,7 @@
|
|||||||
<p slot="label">Location (optional)</p>
|
<p slot="label">Location (optional)</p>
|
||||||
<label class="input input-bordered flex w-full items-center gap-2" slot="input">
|
<label class="input input-bordered flex w-full items-center gap-2" slot="input">
|
||||||
<Icon icon="map-point" />
|
<Icon icon="map-point" />
|
||||||
<input bind:value={title} class="grow" type="text" />
|
<input bind:value={location} class="grow" type="text" />
|
||||||
</label>
|
</label>
|
||||||
</Field>
|
</Field>
|
||||||
<div class="flex flex-row items-center justify-between gap-4">
|
<div class="flex flex-row items-center justify-between gap-4">
|
||||||
@@ -127,8 +136,7 @@
|
|||||||
Go back
|
Go back
|
||||||
</Button>
|
</Button>
|
||||||
<Button type="submit" class="btn btn-primary">
|
<Button type="submit" class="btn btn-primary">
|
||||||
Next
|
Create Event
|
||||||
<Icon icon="alt-arrow-right" class="!bg-base-300" />
|
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
4
src/assets/icons/Clock Circle.svg
Normal file
4
src/assets/icons/Clock Circle.svg
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle cx="12" cy="12" r="10" stroke="#1C274C" stroke-width="1.5"/>
|
||||||
|
<path d="M12 8V12L14.5 14.5" stroke="#1C274C" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 286 B |
@@ -20,17 +20,21 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<label class="relative">
|
<Button class="relative" on:click={init}>
|
||||||
<DateInput format="yyyy-MM-dd HH:mm" placeholder="" bind:value />
|
<DateInput
|
||||||
|
format="yyyy-MM-dd HH:mm"
|
||||||
|
timePrecision="minute"
|
||||||
|
placeholder=""
|
||||||
|
bind:value />
|
||||||
<div class="absolute top-0 h-12 right-2 flex gap-2 items-center cursor-pointer">
|
<div class="absolute top-0 h-12 right-2 flex gap-2 items-center cursor-pointer">
|
||||||
{#if value}
|
{#if value}
|
||||||
<Button on:click={clear} class="h-5">
|
<Button on:click={clear} class="h-5">
|
||||||
<Icon icon="close-circle" />
|
<Icon icon="close-circle" />
|
||||||
</Button>
|
</Button>
|
||||||
{:else}
|
{:else}
|
||||||
<Button on:click={init} class="h-5">
|
<Button class="h-5">
|
||||||
<Icon icon="calendar-minimalistic" />
|
<Icon icon="calendar-minimalistic" />
|
||||||
</Button>
|
</Button>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</Button>
|
||||||
|
|||||||
5
src/lib/components/Divider.svelte
Normal file
5
src/lib/components/Divider.svelte
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<div class="flex items-center gap-2 p-2 text-xs opacity-50">
|
||||||
|
<div class="h-px flex-grow bg-base-content opacity-25" />
|
||||||
|
<p><slot /></p>
|
||||||
|
<div class="h-px flex-grow bg-base-content opacity-25" />
|
||||||
|
</div>
|
||||||
@@ -26,6 +26,7 @@
|
|||||||
import ChatRound from "@assets/icons/Chat Round.svg?dataurl"
|
import ChatRound from "@assets/icons/Chat Round.svg?dataurl"
|
||||||
import CheckCircle from "@assets/icons/Check Circle.svg?dataurl"
|
import CheckCircle from "@assets/icons/Check Circle.svg?dataurl"
|
||||||
import ClipboardText from "@assets/icons/Clipboard Text.svg?dataurl"
|
import ClipboardText from "@assets/icons/Clipboard Text.svg?dataurl"
|
||||||
|
import ClockCircle from "@assets/icons/Clock Circle.svg?dataurl"
|
||||||
import CloseCircle from "@assets/icons/Close Circle.svg?dataurl"
|
import CloseCircle from "@assets/icons/Close Circle.svg?dataurl"
|
||||||
import Copy from "@assets/icons/Copy.svg?dataurl"
|
import Copy from "@assets/icons/Copy.svg?dataurl"
|
||||||
import Compass from "@assets/icons/Compass.svg?dataurl"
|
import Compass from "@assets/icons/Compass.svg?dataurl"
|
||||||
@@ -90,6 +91,7 @@
|
|||||||
"chat-round": ChatRound,
|
"chat-round": ChatRound,
|
||||||
"check-circle": CheckCircle,
|
"check-circle": CheckCircle,
|
||||||
"clipboard-text": ClipboardText,
|
"clipboard-text": ClipboardText,
|
||||||
|
"clock-circle": ClockCircle,
|
||||||
"close-circle": CloseCircle,
|
"close-circle": CloseCircle,
|
||||||
copy: Copy,
|
copy: Copy,
|
||||||
compass: Compass,
|
compass: Compass,
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ export const createSuggestions = (options: SuggestionsOptions) =>
|
|||||||
|
|
||||||
popover = tippy("body", {
|
popover = tippy("body", {
|
||||||
getReferenceClientRect: props.clientRect as any,
|
getReferenceClientRect: props.clientRect as any,
|
||||||
appendTo: document.body,
|
appendTo: document.querySelector('dialog[open]') || document.body,
|
||||||
content: target,
|
content: target,
|
||||||
showOnCreate: true,
|
showOnCreate: true,
|
||||||
interactive: true,
|
interactive: true,
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
import {goto} from "$app/navigation"
|
import {goto} from "$app/navigation"
|
||||||
import {browser} from "$app/environment"
|
import {browser} from "$app/environment"
|
||||||
import {sleep} from "@welshman/lib"
|
import {sleep} from "@welshman/lib"
|
||||||
|
import {throttled} from "@welshman/store"
|
||||||
import {
|
import {
|
||||||
relays,
|
relays,
|
||||||
handles,
|
handles,
|
||||||
@@ -22,7 +23,6 @@
|
|||||||
tracker,
|
tracker,
|
||||||
} from "@welshman/app"
|
} from "@welshman/app"
|
||||||
import * as app from "@welshman/app"
|
import * as app from "@welshman/app"
|
||||||
import {createEventStore} from "@welshman/store"
|
|
||||||
import ModalBox from "@lib/components/ModalBox.svelte"
|
import ModalBox from "@lib/components/ModalBox.svelte"
|
||||||
import Toast from "@app/components/Toast.svelte"
|
import Toast from "@app/components/Toast.svelte"
|
||||||
import Landing from "@app/components/Landing.svelte"
|
import Landing from "@app/components/Landing.svelte"
|
||||||
@@ -64,22 +64,13 @@
|
|||||||
|
|
||||||
ready = db
|
ready = db
|
||||||
? Promise.resolve()
|
? Promise.resolve()
|
||||||
: initStorage("flotilla", 3, {
|
: initStorage("flotilla", 4, {
|
||||||
events: {
|
events: storageAdapters.fromRepository(repository, {throttle: 300}),
|
||||||
keyPath: "id",
|
relays: {keyPath: "url", store: throttled(1000, relays)},
|
||||||
store: createEventStore(repository),
|
handles: {keyPath: "nip05", store: throttled(1000, handles)},
|
||||||
},
|
|
||||||
relays: {
|
|
||||||
keyPath: "url",
|
|
||||||
store: relays,
|
|
||||||
},
|
|
||||||
handles: {
|
|
||||||
keyPath: "nip05",
|
|
||||||
store: handles,
|
|
||||||
},
|
|
||||||
publishStatus: storageAdapters.fromObjectStore(publishStatusData),
|
publishStatus: storageAdapters.fromObjectStore(publishStatusData),
|
||||||
freshness: storageAdapters.fromObjectStore(freshness),
|
freshness: storageAdapters.fromObjectStore(freshness, {throttle: 1000}),
|
||||||
plaintext: storageAdapters.fromObjectStore(plaintext),
|
plaintext: storageAdapters.fromObjectStore(plaintext, {throttle: 1000}),
|
||||||
tracker: storageAdapters.fromTracker(tracker),
|
tracker: storageAdapters.fromTracker(tracker),
|
||||||
}).then(() => sleep(300)) // Wait an extra few ms because of repository throttle
|
}).then(() => sleep(300)) // Wait an extra few ms because of repository throttle
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
import Icon from "@lib/components/Icon.svelte"
|
import Icon from "@lib/components/Icon.svelte"
|
||||||
import Button from "@lib/components/Button.svelte"
|
import Button from "@lib/components/Button.svelte"
|
||||||
import Spinner from "@lib/components/Spinner.svelte"
|
import Spinner from "@lib/components/Spinner.svelte"
|
||||||
|
import Divider from "@lib/components/Divider.svelte"
|
||||||
import ChatMessage from "@app/components/ChatMessage.svelte"
|
import ChatMessage from "@app/components/ChatMessage.svelte"
|
||||||
import ChatCompose from "@app/components/ChatCompose.svelte"
|
import ChatCompose from "@app/components/ChatCompose.svelte"
|
||||||
import {userMembership, decodeNRelay, makeChatId, deriveChat} from "@app/state"
|
import {userMembership, decodeNRelay, makeChatId, deriveChat} from "@app/state"
|
||||||
@@ -90,11 +91,7 @@
|
|||||||
<div class="-mt-2 flex flex-grow flex-col-reverse overflow-auto py-2">
|
<div class="-mt-2 flex flex-grow flex-col-reverse overflow-auto py-2">
|
||||||
{#each elements as { type, id, value, showPubkey } (id)}
|
{#each elements as { type, id, value, showPubkey } (id)}
|
||||||
{#if type === "date"}
|
{#if type === "date"}
|
||||||
<div class="flex items-center gap-2 p-2 text-xs opacity-50">
|
<Divider>{value}</Divider>
|
||||||
<div class="h-px flex-grow bg-base-content opacity-25" />
|
|
||||||
<p>{value}</p>
|
|
||||||
<div class="h-px flex-grow bg-base-content opacity-25" />
|
|
||||||
</div>
|
|
||||||
{:else}
|
{:else}
|
||||||
<ChatMessage event={assertEvent(value)} {showPubkey} />
|
<ChatMessage event={assertEvent(value)} {showPubkey} />
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -1,29 +1,39 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {page} from "$app/stores"
|
import {page} from "$app/stores"
|
||||||
|
import {sortBy, last} from '@welshman/lib'
|
||||||
import type {TrustedEvent} from '@welshman/util'
|
import type {TrustedEvent} from '@welshman/util'
|
||||||
|
import {formatTimestampAsDate} from "@welshman/app"
|
||||||
import Icon from "@lib/components/Icon.svelte"
|
import Icon from "@lib/components/Icon.svelte"
|
||||||
import Button from "@lib/components/Button.svelte"
|
import Button from "@lib/components/Button.svelte"
|
||||||
import Spinner from "@lib/components/Spinner.svelte"
|
import Spinner from "@lib/components/Spinner.svelte"
|
||||||
|
import Divider from "@lib/components/Divider.svelte"
|
||||||
|
import EventCard from "@app/components/EventCard.svelte"
|
||||||
import EventCreate from "@app/components/EventCreate.svelte"
|
import EventCreate from "@app/components/EventCreate.svelte"
|
||||||
import {pushModal} from "@app/modal"
|
import {pushModal} from "@app/modal"
|
||||||
import {eventsByUrl, decodeNRelay} from "@app/state"
|
import {eventsByUrl, decodeNRelay} from "@app/state"
|
||||||
|
|
||||||
const url = decodeNRelay($page.params.nrelay)
|
const url = decodeNRelay($page.params.nrelay)
|
||||||
|
|
||||||
const createEvent = () => pushModal(EventCreate)
|
const createEvent = () => pushModal(EventCreate, {url})
|
||||||
|
|
||||||
const getDateDisplay = (event: TrustedEvent, reset: boolean) => {
|
const getStart = (event: TrustedEvent) =>
|
||||||
if (reset) {
|
parseInt(event.tags.find(t => t[0] === 'start')?.[1]!)
|
||||||
prevEvent = undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
return "hi"
|
|
||||||
}
|
|
||||||
|
|
||||||
let prevEvent
|
|
||||||
let loading = true
|
let loading = true
|
||||||
|
|
||||||
$: events = $eventsByUrl.get(url) || []
|
type Item = {
|
||||||
|
event: TrustedEvent
|
||||||
|
dateDisplay?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
$: items = sortBy(getStart, $eventsByUrl.get(url) || [])
|
||||||
|
.reduce<Item[]>((r, event) => {
|
||||||
|
const prevDateDisplay = r.length > 0 ? formatTimestampAsDate(getStart(last(r).event)) : undefined
|
||||||
|
const newDateDisplay = formatTimestampAsDate(getStart(event))
|
||||||
|
const dateDisplay = prevDateDisplay === newDateDisplay ? undefined : newDateDisplay
|
||||||
|
|
||||||
|
return [...r, {event, dateDisplay}]
|
||||||
|
}, [])
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
loading = false
|
loading = false
|
||||||
@@ -40,19 +50,18 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="-mt-2 flex flex-grow flex-col overflow-auto py-2">
|
<div class="flex flex-grow flex-col overflow-auto p-2 gap-2">
|
||||||
{#each events as event, i (event.id)}
|
{#each items as {event, dateDisplay}, i (event.id)}
|
||||||
{@const dateDisplay = getDateDisplay(event, i === 0)}
|
|
||||||
{#if dateDisplay}
|
{#if dateDisplay}
|
||||||
<div>{dateDisplay}</div>
|
<Divider>{dateDisplay}</Divider>
|
||||||
{/if}
|
{/if}
|
||||||
<div>{event.id}</div>
|
<EventCard {event} />
|
||||||
{/each}
|
{/each}
|
||||||
<p class="flex h-10 items-center justify-center py-20">
|
<p class="flex h-10 items-center justify-center py-20">
|
||||||
<Spinner {loading}>
|
<Spinner {loading}>
|
||||||
{#if loading}
|
{#if loading}
|
||||||
Looking for events...
|
Looking for events...
|
||||||
{:else if events.length === 0}
|
{:else if items.length === 0}
|
||||||
No events found.
|
No events found.
|
||||||
{/if}
|
{/if}
|
||||||
</Spinner>
|
</Spinner>
|
||||||
|
|||||||
@@ -12,7 +12,8 @@ export default {
|
|||||||
feature: 3,
|
feature: 3,
|
||||||
popover: 4,
|
popover: 4,
|
||||||
modal: 5,
|
modal: 5,
|
||||||
toast: 6,
|
"modal-feature": 6,
|
||||||
|
toast: 7,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
plugins: [daisyui],
|
plugins: [daisyui],
|
||||||
|
|||||||
Reference in New Issue
Block a user