Files
llink/js/desktop/src/features/compose/event-compose-step.tsx
T

127 lines
4.0 KiB
TypeScript

import { useCallback, useState } from 'react';
import type { EventProperties } from '@/api/types';
import { metaKey } from '@/lib/platform';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Textarea } from '@/components/ui/textarea';
import { KeyHint } from '@/components/key-hint';
import { toDatetimeLocalValue } from '@/features/particles/event-particle-view';
interface EventComposeStepProps {
onCancel: () => void;
onSubmit: (properties: EventProperties) => void;
}
function nextFullHour(): Date {
const date = new Date();
date.setMinutes(0, 0, 0);
date.setHours(date.getHours() + 1);
return date;
}
const dateInputClass =
'w-full rounded-md border border-white/10 bg-white/5 px-3 py-1.5 text-sm text-white outline-none [color-scheme:dark] focus:border-white/30';
export function EventComposeStep({
onCancel,
onSubmit,
}: EventComposeStepProps) {
const [title, setTitle] = useState('');
const [startAt, setStartAt] = useState(() =>
toDatetimeLocalValue(nextFullHour()),
);
const [endAt, setEndAt] = useState('');
const [notes, setNotes] = useState('');
const handleSubmit = useCallback(() => {
const trimmed = title.trim();
if (!trimmed || !startAt) return;
onSubmit({
title: trimmed,
start_at: new Date(startAt),
...(endAt && { end_at: new Date(endAt) }),
...(notes.trim() && { notes: notes.trim() }),
});
}, [title, startAt, endAt, notes, onSubmit]);
const handleKeyDown = useCallback(
(e: React.KeyboardEvent) => {
if (e.key === 'Escape') {
e.preventDefault();
onCancel();
} else if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) {
e.preventDefault();
handleSubmit();
}
},
[onCancel, handleSubmit],
);
return (
<div
className="absolute inset-0 z-50 flex flex-col bg-black/90 pt-16"
onKeyDown={handleKeyDown}
tabIndex={-1}
>
<div className="mx-auto w-full max-w-sm space-y-4 px-6">
<div>
<Label className="mb-1 text-xs text-white/50">Event</Label>
<Input
type="text"
autoFocus
value={title}
onChange={(e) => setTitle(e.target.value)}
placeholder="What's happening?"
className="border-white/10 bg-white/5 text-white placeholder-white/30 focus-visible:border-white/30 focus-visible:ring-0"
/>
</div>
<div className="flex gap-3">
<div className="flex-1">
<Label className="mb-1 text-xs text-white/50">Starts</Label>
<input
type="datetime-local"
value={startAt}
onChange={(e) => setStartAt(e.target.value)}
className={dateInputClass}
/>
</div>
<div className="flex-1">
<Label className="mb-1 text-xs text-white/50">Ends</Label>
<input
type="datetime-local"
value={endAt}
min={startAt}
onChange={(e) => setEndAt(e.target.value)}
className={dateInputClass}
/>
</div>
</div>
<div>
<Label className="mb-1 text-xs text-white/50">Notes</Label>
<Textarea
value={notes}
onChange={(e) => setNotes(e.target.value)}
placeholder="Optional details…"
className="min-h-20 border-white/10 bg-white/5 text-white placeholder:text-white/30 focus-visible:border-white/30 focus-visible:ring-0 dark:bg-white/5"
/>
</div>
</div>
<div className="absolute bottom-8 left-0 right-0 flex items-center justify-center gap-4 text-sm text-white/50">
<KeyHint keys="Esc" onClick={onCancel} title="Cancel (or press Esc)">
cancel
</KeyHint>
<KeyHint
keys={`${metaKey}+Enter`}
onClick={handleSubmit}
title={`Create event (or press ${metaKey}+Enter)`}
>
create
</KeyHint>
</div>
</div>
);
}