mirror of
https://github.com/coracle-social/flotilla.git
synced 2025-12-09 18:37:02 +00:00
Add calendar event editing
This commit is contained in:
@@ -4,6 +4,14 @@
|
||||
|
||||
* Add alerts via Anchor
|
||||
|
||||
# 0.2.14
|
||||
|
||||
* Add calendar event editing
|
||||
|
||||
# 0.2.13
|
||||
|
||||
* Fix android keyboard issue
|
||||
|
||||
# 0.2.12
|
||||
|
||||
* Fix keyboard covering chat input
|
||||
|
||||
@@ -345,7 +345,7 @@ progress[value]::-webkit-progress-value {
|
||||
}
|
||||
|
||||
.chat__messages {
|
||||
@apply saib cw fixed top-12 flex h-[calc(100%-6rem)] flex-col-reverse overflow-y-auto overflow-x-hidden md:h-[calc(100%-2.5rem)];
|
||||
@apply saib cw fixed top-12 flex h-[calc(100%-6rem)] flex-col-reverse overflow-y-auto overflow-x-hidden md:h-[calc(100%-3rem)];
|
||||
}
|
||||
|
||||
.chat__compose {
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
<script lang="ts">
|
||||
import type {TrustedEvent} from "@welshman/util"
|
||||
import {pubkey} from "@welshman/app"
|
||||
import Icon from "@lib/components/Icon.svelte"
|
||||
import Button from "@lib/components/Button.svelte"
|
||||
import ReactionSummary from "@app/components/ReactionSummary.svelte"
|
||||
import ThunkStatusOrDeleted from "@app/components/ThunkStatusOrDeleted.svelte"
|
||||
import EventActivity from "@app/components/EventActivity.svelte"
|
||||
import EventActions from "@app/components/EventActions.svelte"
|
||||
import CalendarEventEdit from "@app/components/CalendarEventEdit.svelte"
|
||||
import {publishDelete, publishReaction} from "@app/commands"
|
||||
import {makeCalendarPath} from "@app/routes"
|
||||
import {pushModal} from "@app/modal"
|
||||
|
||||
const {
|
||||
url,
|
||||
@@ -20,6 +24,8 @@
|
||||
|
||||
const path = makeCalendarPath(url, event.id)
|
||||
|
||||
const editEvent = () => pushModal(CalendarEventEdit, {url, event})
|
||||
|
||||
const onReactionClick = (content: string, events: TrustedEvent[]) => {
|
||||
const reaction = events.find(e => e.pubkey === $pubkey)
|
||||
|
||||
@@ -38,6 +44,17 @@
|
||||
{#if showActivity}
|
||||
<EventActivity {url} {path} {event} />
|
||||
{/if}
|
||||
<EventActions {url} {event} noun="Event" />
|
||||
<EventActions {url} {event} noun="Event">
|
||||
{#snippet customActions()}
|
||||
{#if event.pubkey === $pubkey}
|
||||
<li>
|
||||
<Button onclick={editEvent}>
|
||||
<Icon size={4} icon="pen" />
|
||||
Edit Event
|
||||
</Button>
|
||||
</li>
|
||||
{/if}
|
||||
{/snippet}
|
||||
</EventActions>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,164 +1,23 @@
|
||||
<script lang="ts">
|
||||
import {writable} from "svelte/store"
|
||||
import {randomId, HOUR} from "@welshman/lib"
|
||||
import {createEvent, EVENT_TIME} from "@welshman/util"
|
||||
import {publishThunk} from "@welshman/app"
|
||||
import {preventDefault} from "@lib/html"
|
||||
import {daysBetween} from "@lib/util"
|
||||
import Icon from "@lib/components/Icon.svelte"
|
||||
import Field from "@lib/components/Field.svelte"
|
||||
import Button from "@lib/components/Button.svelte"
|
||||
import Spinner from "@lib/components/Spinner.svelte"
|
||||
import ModalHeader from "@lib/components/ModalHeader.svelte"
|
||||
import ModalFooter from "@lib/components/ModalFooter.svelte"
|
||||
import DateTimeInput from "@lib/components/DateTimeInput.svelte"
|
||||
import EditorContent from "@app/editor/EditorContent.svelte"
|
||||
import {PROTECTED, GENERAL, tagRoom} from "@app/state"
|
||||
import {makeEditor} from "@app/editor"
|
||||
import {pushToast} from "@app/toast"
|
||||
import CalendarEventForm from "@app/components/CalendarEventForm.svelte"
|
||||
|
||||
const {url} = $props()
|
||||
|
||||
const uploading = writable(false)
|
||||
|
||||
const back = () => history.back()
|
||||
|
||||
const submit = () => {
|
||||
if ($uploading) return
|
||||
|
||||
if (!title) {
|
||||
return pushToast({
|
||||
theme: "error",
|
||||
message: "Please provide a title.",
|
||||
})
|
||||
}
|
||||
|
||||
if (!start || !end) {
|
||||
return pushToast({
|
||||
theme: "error",
|
||||
message: "Please provide start and end times.",
|
||||
})
|
||||
}
|
||||
|
||||
if (start >= end) {
|
||||
return pushToast({
|
||||
theme: "error",
|
||||
message: "End time must be later than start time.",
|
||||
})
|
||||
}
|
||||
|
||||
const event = createEvent(EVENT_TIME, {
|
||||
content: editor.getText({blockSeparator: "\n"}).trim(),
|
||||
tags: [
|
||||
["d", randomId()],
|
||||
["title", title],
|
||||
["location", location],
|
||||
["start", start.toString()],
|
||||
["end", end.toString()],
|
||||
...daysBetween(start, end).map(D => ["D", D.toString()]),
|
||||
...editor.storage.nostr.getEditorTags(),
|
||||
tagRoom(GENERAL, url),
|
||||
PROTECTED,
|
||||
],
|
||||
})
|
||||
|
||||
pushToast({message: "Your event has been published!"})
|
||||
publishThunk({event, relays: [url]})
|
||||
history.back()
|
||||
type Props = {
|
||||
url: string
|
||||
}
|
||||
|
||||
const editor = makeEditor({submit, uploading})
|
||||
|
||||
let title = $state("")
|
||||
let location = $state("")
|
||||
let start: number | undefined = $state()
|
||||
let end: number | undefined = $state()
|
||||
let endDirty = false
|
||||
|
||||
$effect(() => {
|
||||
if (!endDirty && start) {
|
||||
end = start + HOUR
|
||||
} else if (end) {
|
||||
endDirty = true
|
||||
}
|
||||
})
|
||||
const {url}: Props = $props()
|
||||
</script>
|
||||
|
||||
<form class="column gap-4" onsubmit={preventDefault(submit)}>
|
||||
<ModalHeader>
|
||||
{#snippet title()}
|
||||
<div>Create an Event</div>
|
||||
{/snippet}
|
||||
{#snippet info()}
|
||||
<div>Invite other group members to events online or in real life.</div>
|
||||
{/snippet}
|
||||
</ModalHeader>
|
||||
<Field>
|
||||
{#snippet label()}
|
||||
<p>Title*</p>
|
||||
{/snippet}
|
||||
{#snippet input()}
|
||||
<label class="input input-bordered flex w-full items-center gap-2">
|
||||
<input bind:value={title} class="grow" type="text" />
|
||||
</label>
|
||||
{/snippet}
|
||||
</Field>
|
||||
<Field>
|
||||
{#snippet label()}
|
||||
<p>Summary</p>
|
||||
{/snippet}
|
||||
{#snippet input()}
|
||||
<div class="relative z-feature flex gap-2 border-t border-solid border-base-100 bg-base-100">
|
||||
<div class="input-editor flex-grow overflow-hidden">
|
||||
<EditorContent {editor} />
|
||||
</div>
|
||||
<Button
|
||||
data-tip="Add an image"
|
||||
class="center btn tooltip"
|
||||
onclick={() => editor.chain().selectFiles().run()}>
|
||||
{#if $uploading}
|
||||
<span class="loading loading-spinner loading-xs"></span>
|
||||
{:else}
|
||||
<Icon icon="gallery-send" />
|
||||
{/if}
|
||||
</Button>
|
||||
</div>
|
||||
{/snippet}
|
||||
</Field>
|
||||
<Field>
|
||||
{#snippet label()}
|
||||
Start*
|
||||
{/snippet}
|
||||
{#snippet input()}
|
||||
<DateTimeInput bind:value={start} />
|
||||
{/snippet}
|
||||
</Field>
|
||||
<Field>
|
||||
{#snippet label()}
|
||||
End*
|
||||
{/snippet}
|
||||
{#snippet input()}
|
||||
<DateTimeInput bind:value={end} />
|
||||
{/snippet}
|
||||
</Field>
|
||||
<Field>
|
||||
{#snippet label()}
|
||||
<p>Location (optional)</p>
|
||||
{/snippet}
|
||||
{#snippet input()}
|
||||
<label class="input input-bordered flex w-full items-center gap-2">
|
||||
<Icon icon="map-point" />
|
||||
<input bind:value={location} class="grow" type="text" />
|
||||
</label>
|
||||
{/snippet}
|
||||
</Field>
|
||||
<ModalFooter>
|
||||
<Button class="btn btn-link" onclick={back}>
|
||||
<Icon icon="alt-arrow-left" />
|
||||
Go back
|
||||
</Button>
|
||||
<Button type="submit" class="btn btn-primary" disabled={$uploading}>
|
||||
<Spinner loading={$uploading}>Create Event</Spinner>
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</form>
|
||||
<CalendarEventForm {url}>
|
||||
{#snippet header()}
|
||||
<ModalHeader>
|
||||
{#snippet title()}
|
||||
<div>Create an Event</div>
|
||||
{/snippet}
|
||||
{#snippet info()}
|
||||
<div>Invite other group members to events online or in real life.</div>
|
||||
{/snippet}
|
||||
</ModalHeader>
|
||||
{/snippet}
|
||||
</CalendarEventForm>
|
||||
|
||||
35
src/app/components/CalendarEventEdit.svelte
Normal file
35
src/app/components/CalendarEventEdit.svelte
Normal file
@@ -0,0 +1,35 @@
|
||||
<script lang="ts">
|
||||
import type {TrustedEvent} from "@welshman/util"
|
||||
import {getTagValue} from "@welshman/util"
|
||||
import ModalHeader from "@lib/components/ModalHeader.svelte"
|
||||
import CalendarEventForm from "@app/components/CalendarEventForm.svelte"
|
||||
|
||||
type Props = {
|
||||
url: string
|
||||
event: TrustedEvent
|
||||
}
|
||||
|
||||
const {url, event}: Props = $props()
|
||||
|
||||
const initialValues = {
|
||||
d: getTagValue("d", event.tags)!,
|
||||
title: getTagValue("title", event.tags)!,
|
||||
location: getTagValue("location", event.tags)!,
|
||||
start: parseInt(getTagValue("start", event.tags)!),
|
||||
end: parseInt(getTagValue("end", event.tags)!),
|
||||
content: event.content,
|
||||
}
|
||||
</script>
|
||||
|
||||
<CalendarEventForm {url} {initialValues}>
|
||||
{#snippet header()}
|
||||
<ModalHeader>
|
||||
{#snippet title()}
|
||||
<div>Edit this Event</div>
|
||||
{/snippet}
|
||||
{#snippet info()}
|
||||
<div>Invite other group members to events online or in real life.</div>
|
||||
{/snippet}
|
||||
</ModalHeader>
|
||||
{/snippet}
|
||||
</CalendarEventForm>
|
||||
171
src/app/components/CalendarEventForm.svelte
Normal file
171
src/app/components/CalendarEventForm.svelte
Normal file
@@ -0,0 +1,171 @@
|
||||
<script lang="ts">
|
||||
import type {Snippet} from "svelte"
|
||||
import {writable} from "svelte/store"
|
||||
import {randomId, HOUR} from "@welshman/lib"
|
||||
import {createEvent, EVENT_TIME} from "@welshman/util"
|
||||
import {publishThunk} from "@welshman/app"
|
||||
import {preventDefault} from "@lib/html"
|
||||
import {daysBetween} from "@lib/util"
|
||||
import Icon from "@lib/components/Icon.svelte"
|
||||
import Field from "@lib/components/Field.svelte"
|
||||
import Button from "@lib/components/Button.svelte"
|
||||
import Spinner from "@lib/components/Spinner.svelte"
|
||||
import ModalFooter from "@lib/components/ModalFooter.svelte"
|
||||
import DateTimeInput from "@lib/components/DateTimeInput.svelte"
|
||||
import EditorContent from "@app/editor/EditorContent.svelte"
|
||||
import {PROTECTED, GENERAL, tagRoom} from "@app/state"
|
||||
import {makeEditor} from "@app/editor"
|
||||
import {pushToast} from "@app/toast"
|
||||
|
||||
type Props = {
|
||||
url: string
|
||||
header: Snippet
|
||||
initialValues?: {
|
||||
d: string
|
||||
title: string
|
||||
content: string
|
||||
location: string
|
||||
start: number
|
||||
end: number
|
||||
}
|
||||
}
|
||||
|
||||
const {url, header, initialValues}: Props = $props()
|
||||
|
||||
const uploading = writable(false)
|
||||
|
||||
const back = () => history.back()
|
||||
|
||||
const submit = () => {
|
||||
if ($uploading) return
|
||||
|
||||
if (!title) {
|
||||
return pushToast({
|
||||
theme: "error",
|
||||
message: "Please provide a title.",
|
||||
})
|
||||
}
|
||||
|
||||
if (!start || !end) {
|
||||
return pushToast({
|
||||
theme: "error",
|
||||
message: "Please provide start and end times.",
|
||||
})
|
||||
}
|
||||
|
||||
if (start >= end) {
|
||||
return pushToast({
|
||||
theme: "error",
|
||||
message: "End time must be later than start time.",
|
||||
})
|
||||
}
|
||||
|
||||
const event = createEvent(EVENT_TIME, {
|
||||
content: editor.getText({blockSeparator: "\n"}).trim(),
|
||||
tags: [
|
||||
["d", initialValues?.d || randomId()],
|
||||
["title", title],
|
||||
["location", location],
|
||||
["start", start.toString()],
|
||||
["end", end.toString()],
|
||||
...daysBetween(start, end).map(D => ["D", D.toString()]),
|
||||
...editor.storage.nostr.getEditorTags(),
|
||||
tagRoom(GENERAL, url),
|
||||
PROTECTED,
|
||||
],
|
||||
})
|
||||
|
||||
pushToast({message: "Your event has been saved!"})
|
||||
publishThunk({event, relays: [url]})
|
||||
history.back()
|
||||
}
|
||||
|
||||
const content = initialValues?.content || ""
|
||||
const editor = makeEditor({submit, uploading, content})
|
||||
|
||||
let title = $state(initialValues?.title)
|
||||
let location = $state(initialValues?.location)
|
||||
let start: number | undefined = $state(initialValues?.start)
|
||||
let end: number | undefined = $state(initialValues?.end)
|
||||
let endDirty = Boolean(initialValues?.end)
|
||||
|
||||
$effect(() => {
|
||||
if (!endDirty && start) {
|
||||
end = start + HOUR
|
||||
} else if (end) {
|
||||
endDirty = true
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<form novalidate class="column gap-4" onsubmit={preventDefault(submit)}>
|
||||
{@render header()}
|
||||
<Field>
|
||||
{#snippet label()}
|
||||
<p>Title*</p>
|
||||
{/snippet}
|
||||
{#snippet input()}
|
||||
<label class="input input-bordered flex w-full items-center gap-2">
|
||||
<input bind:value={title} class="grow" type="text" />
|
||||
</label>
|
||||
{/snippet}
|
||||
</Field>
|
||||
<Field>
|
||||
{#snippet label()}
|
||||
<p>Summary</p>
|
||||
{/snippet}
|
||||
{#snippet input()}
|
||||
<div class="relative z-feature flex gap-2 border-t border-solid border-base-100 bg-base-100">
|
||||
<div class="input-editor flex-grow overflow-hidden">
|
||||
<EditorContent {editor} />
|
||||
</div>
|
||||
<Button
|
||||
data-tip="Add an image"
|
||||
class="center btn tooltip"
|
||||
onclick={() => editor.chain().selectFiles().run()}>
|
||||
{#if $uploading}
|
||||
<span class="loading loading-spinner loading-xs"></span>
|
||||
{:else}
|
||||
<Icon icon="gallery-send" />
|
||||
{/if}
|
||||
</Button>
|
||||
</div>
|
||||
{/snippet}
|
||||
</Field>
|
||||
<Field>
|
||||
{#snippet label()}
|
||||
Start*
|
||||
{/snippet}
|
||||
{#snippet input()}
|
||||
<DateTimeInput bind:value={start} />
|
||||
{/snippet}
|
||||
</Field>
|
||||
<Field>
|
||||
{#snippet label()}
|
||||
End*
|
||||
{/snippet}
|
||||
{#snippet input()}
|
||||
<DateTimeInput bind:value={end} />
|
||||
{/snippet}
|
||||
</Field>
|
||||
<Field>
|
||||
{#snippet label()}
|
||||
<p>Location (optional)</p>
|
||||
{/snippet}
|
||||
{#snippet input()}
|
||||
<label class="input input-bordered flex w-full items-center gap-2">
|
||||
<Icon icon="map-point" />
|
||||
<input bind:value={location} class="grow" type="text" />
|
||||
</label>
|
||||
{/snippet}
|
||||
</Field>
|
||||
<ModalFooter>
|
||||
<Button class="btn btn-link" onclick={back}>
|
||||
<Icon icon="alt-arrow-left" />
|
||||
Go back
|
||||
</Button>
|
||||
<Button type="submit" class="btn btn-primary" disabled={$uploading}>
|
||||
<Spinner loading={$uploading}>Save Event</Spinner>
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</form>
|
||||
@@ -18,9 +18,9 @@
|
||||
Posted by <ProfileLink pubkey={event.pubkey} />
|
||||
</span>
|
||||
{#if meta.location}
|
||||
<span class="ellipsize flex items-center gap-1 whitespace-nowrap">
|
||||
<Icon icon="map-point" size={4} />
|
||||
{meta.location}
|
||||
<span class="flex items-start gap-1">
|
||||
<Icon icon="map-point" class="mt-[2px]" size={4} />
|
||||
<span class="break-words">{meta.location}</span>
|
||||
</span>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<script lang="ts">
|
||||
import type {Snippet} from "svelte"
|
||||
import type {Instance} from "tippy.js"
|
||||
import type {NativeEmoji} from "emoji-picker-element/shared"
|
||||
import type {TrustedEvent} from "@welshman/util"
|
||||
@@ -9,15 +10,14 @@
|
||||
import EventMenu from "@app/components/EventMenu.svelte"
|
||||
import {publishReaction} from "@app/commands"
|
||||
|
||||
const {
|
||||
url,
|
||||
noun,
|
||||
event,
|
||||
}: {
|
||||
type Props = {
|
||||
url: string
|
||||
noun: string
|
||||
event: TrustedEvent
|
||||
} = $props()
|
||||
customActions?: Snippet
|
||||
}
|
||||
|
||||
const {url, noun, event, customActions}: Props = $props()
|
||||
|
||||
const showPopover = () => popover?.show()
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
<Tippy
|
||||
bind:popover
|
||||
component={EventMenu}
|
||||
props={{url, noun, event, onClick: hidePopover}}
|
||||
props={{url, noun, event, customActions, onClick: hidePopover}}
|
||||
params={{trigger: "manual", interactive: true}}>
|
||||
<Button class="btn join-item btn-neutral btn-xs" onclick={showPopover}>
|
||||
<Icon icon="menu-dots" size={4} />
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<script lang="ts">
|
||||
import {onMount} from "svelte"
|
||||
import type {Snippet} from "svelte"
|
||||
import type {TrustedEvent} from "@welshman/util"
|
||||
import {COMMENT} from "@welshman/util"
|
||||
import {pubkey} from "@welshman/app"
|
||||
@@ -10,42 +12,34 @@
|
||||
import EventDeleteConfirm from "@app/components/EventDeleteConfirm.svelte"
|
||||
import {pushModal} from "@app/modal"
|
||||
|
||||
const {
|
||||
url,
|
||||
noun,
|
||||
event,
|
||||
onClick,
|
||||
}: {
|
||||
type Props = {
|
||||
url: string
|
||||
noun: string
|
||||
event: TrustedEvent
|
||||
onClick: () => void
|
||||
} = $props()
|
||||
customActions?: Snippet
|
||||
}
|
||||
|
||||
const {url, noun, event, onClick, customActions}: Props = $props()
|
||||
|
||||
const isRoot = event.kind !== COMMENT
|
||||
|
||||
const report = () => {
|
||||
onClick()
|
||||
pushModal(EventReport, {url, event})
|
||||
}
|
||||
const report = () => pushModal(EventReport, {url, event})
|
||||
|
||||
const showInfo = () => {
|
||||
onClick()
|
||||
pushModal(EventInfo, {url, event})
|
||||
}
|
||||
const showInfo = () => pushModal(EventInfo, {url, event})
|
||||
|
||||
const share = () => {
|
||||
onClick()
|
||||
pushModal(EventShare, {url, event})
|
||||
}
|
||||
const share = () => pushModal(EventShare, {url, event})
|
||||
|
||||
const showDelete = () => {
|
||||
onClick()
|
||||
pushModal(EventDeleteConfirm, {url, event})
|
||||
}
|
||||
const showDelete = () => pushModal(EventDeleteConfirm, {url, event})
|
||||
|
||||
let ul: Element
|
||||
|
||||
onMount(() => {
|
||||
ul.addEventListener("click", onClick)
|
||||
})
|
||||
</script>
|
||||
|
||||
<ul class="menu whitespace-nowrap rounded-box bg-base-100 p-2 shadow-xl">
|
||||
<ul class="menu whitespace-nowrap rounded-box bg-base-100 p-2 shadow-xl" bind:this={ul}>
|
||||
{#if isRoot}
|
||||
<li>
|
||||
<Button onclick={share}>
|
||||
@@ -60,6 +54,7 @@
|
||||
{noun} Details
|
||||
</Button>
|
||||
</li>
|
||||
{@render customActions?.()}
|
||||
{#if event.pubkey === $pubkey}
|
||||
<li>
|
||||
<Button onclick={showDelete} class="text-error">
|
||||
|
||||
@@ -23,6 +23,7 @@ import {
|
||||
matchFilters,
|
||||
getTagValues,
|
||||
getTagValue,
|
||||
getAddress,
|
||||
isShareableRelayUrl,
|
||||
} from "@welshman/util"
|
||||
import type {TrustedEvent, Filter, List} from "@welshman/util"
|
||||
@@ -214,6 +215,7 @@ export const makeCalendarFeed = ({
|
||||
|
||||
const insertEvent = (event: TrustedEvent) => {
|
||||
const start = getStart(event)
|
||||
const address = getAddress(event)
|
||||
|
||||
if (isNaN(start) || isNaN(getEnd(event))) return
|
||||
|
||||
@@ -223,7 +225,7 @@ export const makeCalendarFeed = ({
|
||||
if (getStart($events[i]) > start) return insert(i, event, $events)
|
||||
}
|
||||
|
||||
return [...$events, event]
|
||||
return [...$events.filter(e => getAddress(e) !== address), event]
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
const pad = (n: number) => ("00" + String(n)).slice(-2)
|
||||
|
||||
const getTime = (d: Date) => `${pad(d.getHours())}:${minutes}`
|
||||
const getTime = (d: Date, m: string) => `${pad(d.getHours())}:${m}`
|
||||
|
||||
const setTime = (d: Date, time: string) => {
|
||||
const [hours, minutes] = time.split(":").map(x => parseInt(x))
|
||||
@@ -37,15 +37,19 @@
|
||||
time = undefined
|
||||
}
|
||||
|
||||
let date: Date | undefined = $state()
|
||||
let time: string | undefined = $state()
|
||||
let minutes: string = $state("00")
|
||||
const initialDate = value ? secondsToDate(value) : undefined
|
||||
const initialTime = initialDate ? getTime(initialDate, pad(initialDate.getMinutes())) : undefined
|
||||
const initialMinutes = initialTime ? initialTime.slice(-2) : "00"
|
||||
|
||||
let date: Date | undefined = $state(initialDate)
|
||||
let time: string | undefined = $state(initialTime)
|
||||
let minutes: string = $state(initialMinutes)
|
||||
let element: HTMLElement
|
||||
|
||||
// Sync date to time and value
|
||||
$effect(() => {
|
||||
if (date) {
|
||||
time = getTime(date)
|
||||
time = getTime(date, minutes)
|
||||
value = dateToSeconds(date)
|
||||
} else {
|
||||
value = undefined
|
||||
@@ -55,7 +59,7 @@
|
||||
// Sync updates to value to date/time
|
||||
$effect(() => {
|
||||
const derivedDate = value ? secondsToDate(value) : undefined
|
||||
const derivedTime = derivedDate ? getTime(derivedDate) : undefined
|
||||
const derivedTime = derivedDate ? getTime(derivedDate, minutes) : undefined
|
||||
|
||||
date = derivedDate
|
||||
time = derivedTime
|
||||
|
||||
Reference in New Issue
Block a user