WIP: February 2026 event improvements and calendar refactor #1
@ -74,6 +74,8 @@
|
||||
|
||||
--outline-width-md: 1.5px;
|
||||
|
||||
--background-image-scrollbar: linear-gradient(to bottom, rgba(255, 255, 255, 0), rgba(255, 255, 255, 1));
|
||||
|
||||
--radius-xs: 0.25rem;
|
||||
--radius-sm: 0.375rem;
|
||||
--radius-md: 0.6667rem;
|
||||
|
||||
@ -30,6 +30,17 @@ details {
|
||||
}
|
||||
}
|
||||
|
||||
/* simple variant */
|
||||
&.details--simple
|
||||
{
|
||||
summary {
|
||||
&::before,
|
||||
&::after {
|
||||
content: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&[open] {
|
||||
summary::after {
|
||||
@apply rotate-180;
|
||||
|
||||
@ -4,3 +4,17 @@
|
||||
background-image: var(--event-map);
|
||||
width: calc(100% + 3rem);
|
||||
}
|
||||
|
||||
/* event form fields */
|
||||
#event-form {
|
||||
@apply flex flex-col gap-4 pt-6;
|
||||
|
||||
.event-field {
|
||||
display: grid;
|
||||
grid-template-columns: 3rem auto;
|
||||
|
||||
.event-field-icon {
|
||||
@apply pt-2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -178,6 +178,13 @@ article.settings {
|
||||
h3 + .input-row {
|
||||
@apply mt-6;
|
||||
}
|
||||
.input-rows {
|
||||
@apply flex flex-col gap-3;
|
||||
|
||||
.input-row + .input-row {
|
||||
@apply mt-0;
|
||||
}
|
||||
}
|
||||
@container style(--can-scroll: 1) {
|
||||
.input-row--actions {
|
||||
@apply !border-black;
|
||||
|
||||
@ -22,7 +22,7 @@ dialog {
|
||||
max-height: calc(100dvh - 5rem);
|
||||
width: 91.666667%;
|
||||
max-width: 36rem;
|
||||
transition: translate 150ms cubic-bezier(0,0,.2,1);
|
||||
transition: translate 150ms ease-in-out;
|
||||
box-shadow: 0 1.5rem 4rem -0.5rem rgba(0, 0, 0, 0.4);
|
||||
|
||||
/* close button */
|
||||
@ -54,11 +54,17 @@ dialog {
|
||||
|
||||
/* main content wrapper */
|
||||
section.modal-body {
|
||||
@apply flex flex-col px-6 pb-8;
|
||||
@apply flex flex-col px-6 pb-8 overflow-y-auto;
|
||||
|
||||
&.no-margin {
|
||||
@apply p-0;
|
||||
}
|
||||
|
||||
/* overlay gradient to signal scrollability */
|
||||
&::after {
|
||||
@apply h-8 w-full absolute bottom-20 left-0 bg-scrollbar;
|
||||
content: '';
|
||||
}
|
||||
}
|
||||
|
||||
/* standard form with 1rem gap between rows */
|
||||
@ -73,7 +79,7 @@ dialog {
|
||||
|
||||
/* footer */
|
||||
footer {
|
||||
@apply sticky bottom-0 bg-white px-6 py-4 border-t-md border-gray-300 flex justify-between;
|
||||
@apply sticky bottom-0 bg-white px-6 h-20 border-t-md border-gray-300 flex items-center justify-between;
|
||||
}
|
||||
|
||||
/* event modal with a map */
|
||||
@ -139,9 +145,10 @@ dialog {
|
||||
|
||||
/* extra container over the backdrop below the modal */
|
||||
#modal-aside {
|
||||
@apply w-11/12 max-w-3xl justify-self-center px-4 h-0;
|
||||
@apply flex flex-row justify-between items-start gap-2 translate-y-4;
|
||||
@apply opacity-0 invisible;
|
||||
@apply justify-self-center pl-4 h-0 flex flex-row justify-between items-start gap-2;
|
||||
@apply translate-y-4 opacity-0 invisible;
|
||||
width: 91.666667%;
|
||||
max-width: 36rem;
|
||||
pointer-events: none;
|
||||
transition:
|
||||
translate 250ms ease-in-out,
|
||||
|
||||
@ -464,6 +464,28 @@ function initNaturalEventParser(root = document) {
|
||||
return null;
|
||||
};
|
||||
|
||||
const isAtTimeCandidate = (candidate) => {
|
||||
const normalized = String(candidate || '')
|
||||
.trim()
|
||||
.toLowerCase()
|
||||
.replace(/\./g, '');
|
||||
|
||||
if (normalized === '') return false;
|
||||
if (normalized === 'noon' || normalized === 'midnight') return true;
|
||||
|
||||
// 1-2 digit + a|p|am|pm (with/without space), e.g. 3p, 3 p, 3pm, 3 pm
|
||||
if (/^\d{1,2}\s*(a|p|am|pm)$/.test(normalized)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// h:mm / hh:mm with optional a|p|am|pm, or plain 24-hour format (e.g. 15:30)
|
||||
if (/^\d{1,2}:\d{2}(?:\s*(a|p|am|pm))?$/.test(normalized)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
const parseTimeToken = (text) => {
|
||||
const lowered = text.toLowerCase();
|
||||
const noonIndex = lowered.indexOf(' at noon');
|
||||
@ -476,18 +498,20 @@ function initNaturalEventParser(root = document) {
|
||||
return { hours: 0, minutes: 0, index: midnightIndex };
|
||||
}
|
||||
|
||||
const match = text.match(/\bat\s+(\d{1,2})(?::(\d{2}))?\s*(am|pm)?\b/i);
|
||||
const match = text.match(/\bat\s+(\d{1,2})(?::(\d{2}))?\s*(am|pm|a|p)?\b/i);
|
||||
if (!match) return null;
|
||||
|
||||
let hours = parseInt(match[1], 10);
|
||||
const minutes = parseInt(match[2] || '0', 10);
|
||||
const meridiem = (match[3] || '').toLowerCase();
|
||||
const meridiem = (match[3] || '').toLowerCase().replace(/\./g, '');
|
||||
|
||||
if (Number.isNaN(hours) || Number.isNaN(minutes)) return null;
|
||||
if (minutes < 0 || minutes > 59) return null;
|
||||
|
||||
if (meridiem) {
|
||||
if (hours === 12 && meridiem === 'am') hours = 0;
|
||||
if (hours < 12 && meridiem === 'pm') hours += 12;
|
||||
if (hours < 1 || hours > 12) return null;
|
||||
if (hours === 12 && meridiem.startsWith('a')) hours = 0;
|
||||
if (hours < 12 && meridiem.startsWith('p')) hours += 12;
|
||||
} else if (hours > 23) {
|
||||
return null;
|
||||
}
|
||||
@ -646,9 +670,26 @@ function initNaturalEventParser(root = document) {
|
||||
const index = lower.lastIndexOf(' at ');
|
||||
if (index === -1) return null;
|
||||
|
||||
const candidate = text.slice(index + 4).trim().replace(/[.,;]+$/, '');
|
||||
let candidate = text.slice(index + 4).trim().replace(/[.,;]+$/, '');
|
||||
if (!candidate) return null;
|
||||
if (/^\d{1,2}(?::\d{2})?\s*(am|pm)?\b/i.test(candidate)) return null;
|
||||
|
||||
// If the phrase ends with a dangling "at", trim it first.
|
||||
// Example: "... at 11am at" -> candidate "11am"
|
||||
candidate = candidate.replace(/\s+at\s*$/i, '').trim();
|
||||
if (!candidate) return null;
|
||||
|
||||
// If the extracted candidate starts with a time token, strip it.
|
||||
// Example: "11am at Pediatric Alliance" -> "Pediatric Alliance"
|
||||
const leadingTimeMatch = candidate.match(/^(?:\d{1,2}(?::\d{2})?\s*(?:a|p|am|pm)|\d{1,2}:\d{2}|noon|midnight)\b/i);
|
||||
if (leadingTimeMatch) {
|
||||
candidate = candidate
|
||||
.slice(leadingTimeMatch[0].length)
|
||||
.replace(/^\s*at\s*/i, '')
|
||||
.trim();
|
||||
}
|
||||
|
||||
if (!candidate) return null;
|
||||
if (isAtTimeCandidate(candidate)) return null;
|
||||
if (/\bfor\s+\d+\s*(minutes?|mins?|hours?|hrs?)\b/i.test(candidate)) return null;
|
||||
|
||||
return candidate;
|
||||
@ -857,8 +898,15 @@ function initNaturalEventParser(root = document) {
|
||||
titleInput.value = parsed.title;
|
||||
}
|
||||
|
||||
if (parsed.location && locationInput) {
|
||||
locationInput.value = parsed.location;
|
||||
if (locationInput) {
|
||||
if (parsed.location) {
|
||||
locationInput.value = parsed.location;
|
||||
input.dataset.nlLocationApplied = '1';
|
||||
} else if (input.dataset.nlLocationApplied === '1') {
|
||||
// Clear stale parser-written values (e.g. interim "at 3" while typing "at 3pm")
|
||||
locationInput.value = '';
|
||||
input.dataset.nlLocationApplied = '0';
|
||||
}
|
||||
}
|
||||
|
||||
const existingStart = startInput.type === 'date'
|
||||
@ -1395,4 +1443,3 @@ export function handleEventModalAfterSwap(target) {
|
||||
target.closest('dialog')?.showModal();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
1
resources/svg/icons/calendar-clock.svg
Normal file
1
resources/svg/icons/calendar-clock.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M16 14v2.2l1.6 1"/><path d="M16 2v4"/><path d="M21 7.5V6a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h3.5"/><path d="M3 10h5"/><path d="M8 2v4"/><circle cx="16" cy="16" r="6"/></svg>
|
||||
|
After Width: | Height: | Size: 375 B |
1
resources/svg/icons/description.svg
Normal file
1
resources/svg/icons/description.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 5H3"/><path d="M15 12H3"/><path d="M17 19H3"/></svg>
|
||||
|
After Width: | Height: | Size: 247 B |
@ -1,4 +1,4 @@
|
||||
<x-modal.content modal-class="modal--wide modal--square modal--event">
|
||||
<x-modal.content modal-class="modal--event">
|
||||
<x-modal.title class="input">
|
||||
@if ($event->exists)
|
||||
<h2>{{ __('Edit event details') }}</h2>
|
||||
@ -14,7 +14,7 @@
|
||||
/>
|
||||
@endif
|
||||
</x-modal.title>
|
||||
<x-modal.body class="no-margin">
|
||||
<x-modal.body>
|
||||
@include('event.partials.form', [
|
||||
'calendar' => $calendar,
|
||||
'event' => $event,
|
||||
|
||||
@ -11,417 +11,407 @@
|
||||
@method('PUT')
|
||||
@endif
|
||||
|
||||
<div class="tab-panels" data-tabs>
|
||||
<menu class="tabs tabs--vertical" role="tablist" aria-orientation="vertical">
|
||||
<li id="tab-details" role="tab" aria-controls="tab-details" aria-selected="true">
|
||||
<x-button type="button">
|
||||
<x-icon-info-circle width="20" />
|
||||
<span>Details</span>
|
||||
</x-button>
|
||||
</li>
|
||||
<li id="tab-repeat" role="tab" aria-controls="tab-repeat" aria-selected="false">
|
||||
<x-button type="button">
|
||||
<x-icon-repeat width="20" />
|
||||
<span>Repeat</span>
|
||||
</x-button>
|
||||
</li>
|
||||
<li id="tab-attendees" role="tab" aria-controls="tab-attendees" aria-selected="false">
|
||||
<x-button type="button">
|
||||
<x-icon-user-circle width="20" />
|
||||
<span>Guests</span>
|
||||
</x-button>
|
||||
</li>
|
||||
<li id="tab-description" role="tab" aria-controls="tab-description" aria-selected="false">
|
||||
<x-button type="button">
|
||||
<x-icon-user-circle width="20" />
|
||||
<span>Description</span>
|
||||
</x-button>
|
||||
</li>
|
||||
</menu>
|
||||
<div class="panels">
|
||||
<div id="tab-details" role="tabpanel" aria-labelledby="tab-btn-details">
|
||||
{{-- Calendar --}}
|
||||
<div class="input-row input-row--1">
|
||||
<div class="input-cell">
|
||||
<x-input.label for="calendar_uri" :value="__('common.calendar')" />
|
||||
{{-- Title --}}
|
||||
<div class="event-field">
|
||||
<div class="event-field-icon"><!-- empty --></div>
|
||||
<div class="input-row input-row--1">
|
||||
<div class="input-cell">
|
||||
<x-input.text
|
||||
id="title"
|
||||
name="title"
|
||||
type="text"
|
||||
:value="old('title', $event->meta?->title ?? '')"
|
||||
placeholder="Event title..."
|
||||
required
|
||||
:autofocus="$event->exists"
|
||||
/>
|
||||
<x-input.error class="mt-2" :messages="$errors->get('title')" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="relative" data-calendar-picker>
|
||||
<input type="hidden" id="calendar_uri" name="calendar_uri" value="{{ $selectedCalendarUri ?? '' }}" data-calendar-picker-input>
|
||||
{{-- Calendar --}}
|
||||
<div class="event-field">
|
||||
<div class="event-field-icon">
|
||||
<x-icon-calendar />
|
||||
</div>
|
||||
<div class="input-row input-row--1">
|
||||
<div class="input-cell">
|
||||
<div class="relative" data-calendar-picker>
|
||||
<input type="hidden" id="calendar_uri" name="calendar_uri" value="{{ $selectedCalendarUri ?? '' }}" data-calendar-picker-input>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="button button--secondary w-full justify-between"
|
||||
data-calendar-picker-toggle
|
||||
aria-expanded="false"
|
||||
>
|
||||
<span class="inline-flex items-center gap-2">
|
||||
<span class="inline-block h-3 w-3 rounded-full" data-calendar-picker-color style="background-color: {{ $selectedCalendarColor ?? '#64748b' }}"></span>
|
||||
<span data-calendar-picker-label>{{ $selectedCalendarName ?? __('common.calendar') }}</span>
|
||||
</span>
|
||||
<x-icon-chevron-down width="18" />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="button button--secondary w-full justify-between"
|
||||
data-calendar-picker-toggle
|
||||
aria-expanded="false"
|
||||
>
|
||||
<span class="inline-flex items-center gap-2">
|
||||
<span class="inline-block h-3 w-3 rounded-full" data-calendar-picker-color style="background-color: {{ $selectedCalendarColor ?? '#64748b' }}"></span>
|
||||
<span data-calendar-picker-label>{{ $selectedCalendarName ?? __('common.calendar') }}</span>
|
||||
</span>
|
||||
<x-icon-chevron-down width="18" />
|
||||
</button>
|
||||
|
||||
<div class="absolute z-20 mt-2 w-full rounded-md border-md border-secondary bg-white shadow-sm hidden" data-calendar-picker-menu>
|
||||
<ul class="list-none p-1 m-0 flex flex-col gap-1">
|
||||
@foreach (($calendarPickerOptions ?? []) as $option)
|
||||
<li>
|
||||
<button
|
||||
type="button"
|
||||
class="button button--tertiary w-full justify-start"
|
||||
data-calendar-picker-option
|
||||
data-calendar-picker-uri="{{ $option['uri'] }}"
|
||||
data-calendar-picker-name="{{ $option['name'] }}"
|
||||
data-calendar-picker-color="{{ $option['color'] }}"
|
||||
>
|
||||
<span class="inline-block h-3 w-3 rounded-full" style="background-color: {{ $option['color'] }}"></span>
|
||||
<span>{{ $option['name'] }}</span>
|
||||
</button>
|
||||
</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Title --}}
|
||||
<div class="input-row input-row--1">
|
||||
<div class="input-cell">
|
||||
<x-input.label for="title" :value="__('Title')" />
|
||||
<x-input.text
|
||||
id="title"
|
||||
name="title"
|
||||
type="text"
|
||||
:value="old('title', $event->meta?->title ?? '')"
|
||||
required
|
||||
:autofocus="$event->exists"
|
||||
/>
|
||||
<x-input.error class="mt-2" :messages="$errors->get('title')" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Description --}}
|
||||
<div class="input-row input-row--1">
|
||||
<div class="input-cell">
|
||||
<x-input.label for="description" :value="__('Description')" />
|
||||
<x-input.textarea
|
||||
id="description"
|
||||
name="description"
|
||||
rows="3">{{ old('description', $event->meta?->description ?? '') }}</x-input.textarea>
|
||||
<x-input.error :messages="$errors->get('description')" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Location --}}
|
||||
<div class="input-row input-row--1">
|
||||
<div class="input-cell">
|
||||
<x-input.label for="location" :value="__('Location')" />
|
||||
<x-input.text
|
||||
id="location"
|
||||
name="location"
|
||||
:value="old('location', $event->meta?->location ?? '')"
|
||||
{{-- live suggestions via htmx --}}
|
||||
hx-get="{{ route('location.suggest') }}"
|
||||
hx-trigger="keyup changed delay:300ms"
|
||||
hx-target="#location-suggestions"
|
||||
hx-swap="innerHTML"
|
||||
/>
|
||||
<x-input.error :messages="$errors->get('location')" />
|
||||
|
||||
{{-- suggestion dropdown target --}}
|
||||
<div id="location-suggestions" class="relative z-20"></div>
|
||||
{{-- hidden fields (filled when user clicks a suggestion; handy for step #2) --}}
|
||||
<input type="hidden" id="loc_display_name" name="loc_display_name" />
|
||||
<input type="hidden" id="loc_place_name" name="loc_place_name" />
|
||||
<input type="hidden" id="loc_street" name="loc_street" />
|
||||
<input type="hidden" id="loc_city" name="loc_city" />
|
||||
<input type="hidden" id="loc_state" name="loc_state" />
|
||||
<input type="hidden" id="loc_postal" name="loc_postal" />
|
||||
<input type="hidden" id="loc_country" name="loc_country" />
|
||||
<input type="hidden" id="loc_lat" name="loc_lat" />
|
||||
<input type="hidden" id="loc_lon" name="loc_lon" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Start / End --}}
|
||||
<div class="input-row input-row--1-1">
|
||||
<div class="input-cell">
|
||||
<x-input.label for="start_at" :value="__('Starts')" />
|
||||
<x-input.text
|
||||
id="start_at"
|
||||
name="start_at"
|
||||
type="datetime-local"
|
||||
:value="old('start_at', $start)"
|
||||
data-event-start
|
||||
required
|
||||
/>
|
||||
<x-input.error :messages="$errors->get('start_at')" />
|
||||
</div>
|
||||
<div class="input-cell">
|
||||
<x-input.label for="end_at" :value="__('Ends')" />
|
||||
<x-input.text
|
||||
id="end_at"
|
||||
name="end_at"
|
||||
type="datetime-local"
|
||||
:value="old('end_at', $end)"
|
||||
data-event-end
|
||||
required
|
||||
/>
|
||||
<x-input.error :messages="$errors->get('end_at')" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- All-day --}}
|
||||
<div class="input-row input-row--1">
|
||||
<div class="input-cell">
|
||||
<x-input.checkbox-label
|
||||
label="{{ __('All day event') }}"
|
||||
id="all_day"
|
||||
name="all_day"
|
||||
value="1"
|
||||
data-all-day-toggle
|
||||
:checked="(bool) old('all_day', $event->meta?->all_day)"
|
||||
/>
|
||||
<div class="absolute z-20 mt-2 w-full rounded-md border-md border-secondary bg-white shadow-sm hidden" data-calendar-picker-menu>
|
||||
<ul class="list-none p-1 m-0 flex flex-col gap-1">
|
||||
@foreach (($calendarPickerOptions ?? []) as $option)
|
||||
<li>
|
||||
<button
|
||||
type="button"
|
||||
class="button button--tertiary w-full justify-start"
|
||||
data-calendar-picker-option
|
||||
data-calendar-picker-uri="{{ $option['uri'] }}"
|
||||
data-calendar-picker-name="{{ $option['name'] }}"
|
||||
data-calendar-picker-color="{{ $option['color'] }}"
|
||||
>
|
||||
<span class="inline-block h-3 w-3 rounded-full" style="background-color: {{ $option['color'] }}"></span>
|
||||
<span>{{ $option['name'] }}</span>
|
||||
</button>
|
||||
</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- recurrence --}}
|
||||
<div id="tab-repeat" role="tabpanel" aria-labelledby="tab-btn-repeat" hidden>
|
||||
<div class="input-row input-row--1">
|
||||
<div class="input-cell">
|
||||
<div class="mt-3">
|
||||
<x-input.label for="repeat_frequency" :value="__('calendar.event.recurrence.frequency')" />
|
||||
<x-input.select
|
||||
id="repeat_frequency"
|
||||
name="repeat_frequency"
|
||||
:options="$rruleOptions"
|
||||
:selected="$repeatFrequency"
|
||||
:placeholder="__('calendar.event.recurrence.none')"
|
||||
data-recurrence-frequency
|
||||
{{-- Location --}}
|
||||
<div class="event-field">
|
||||
<div class="event-field-icon">
|
||||
<x-icon-pin />
|
||||
</div>
|
||||
<div class="input-row input-row--1">
|
||||
<div class="input-cell">
|
||||
<x-input.text
|
||||
id="location"
|
||||
name="location"
|
||||
:value="old('location', $event->meta?->location ?? '')"
|
||||
placeholder="Location..."
|
||||
{{-- live suggestions via htmx --}}
|
||||
hx-get="{{ route('location.suggest') }}"
|
||||
hx-trigger="keyup changed delay:300ms"
|
||||
hx-target="#location-suggestions"
|
||||
hx-swap="innerHTML"
|
||||
/>
|
||||
<x-input.error :messages="$errors->get('location')" />
|
||||
|
||||
{{-- suggestion dropdown target --}}
|
||||
<div id="location-suggestions" class="relative z-20"></div>
|
||||
{{-- hidden fields (filled when user clicks a suggestion; handy for step #2) --}}
|
||||
<input type="hidden" id="loc_display_name" name="loc_display_name" />
|
||||
<input type="hidden" id="loc_place_name" name="loc_place_name" />
|
||||
<input type="hidden" id="loc_street" name="loc_street" />
|
||||
<input type="hidden" id="loc_city" name="loc_city" />
|
||||
<input type="hidden" id="loc_state" name="loc_state" />
|
||||
<input type="hidden" id="loc_postal" name="loc_postal" />
|
||||
<input type="hidden" id="loc_country" name="loc_country" />
|
||||
<input type="hidden" id="loc_lat" name="loc_lat" />
|
||||
<input type="hidden" id="loc_lon" name="loc_lon" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Start / End --}}
|
||||
<div class="event-field">
|
||||
<div class="event-field-icon">
|
||||
<x-icon-calendar-clock />
|
||||
</div>
|
||||
<div class="input-rows">
|
||||
<div class="input-row input-row--1-1">
|
||||
<div class="input-cell">
|
||||
<x-input.text
|
||||
id="start_at"
|
||||
name="start_at"
|
||||
type="datetime-local"
|
||||
:value="old('start_at', $start)"
|
||||
data-event-start
|
||||
required
|
||||
aria-label="Start date and time"
|
||||
/>
|
||||
<x-input.error :messages="$errors->get('start_at')" />
|
||||
</div>
|
||||
<div class="input-cell">
|
||||
<x-input.text
|
||||
id="end_at"
|
||||
name="end_at"
|
||||
type="datetime-local"
|
||||
:value="old('end_at', $end)"
|
||||
data-event-end
|
||||
required
|
||||
aria-label="End date and time"
|
||||
/>
|
||||
<x-input.error :messages="$errors->get('end_at')" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-row input-row--1">
|
||||
<div class="input-cell ml-2px">
|
||||
<x-input.checkbox-label
|
||||
label="{{ __('All day event') }}"
|
||||
id="all_day"
|
||||
name="all_day"
|
||||
value="1"
|
||||
data-all-day-toggle
|
||||
:checked="(bool) old('all_day', $event->meta?->all_day)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- recurrence --}}
|
||||
<div class="event-field">
|
||||
<div class="event-field-icon">
|
||||
<x-icon-repeat />
|
||||
</div>
|
||||
<div class="input-row input-row--1">
|
||||
<div class="input-cell">
|
||||
<x-input.select
|
||||
id="repeat_frequency"
|
||||
name="repeat_frequency"
|
||||
:options="$rruleOptions"
|
||||
:selected="$repeatFrequency"
|
||||
:placeholder="__('calendar.event.recurrence.none')"
|
||||
data-recurrence-frequency
|
||||
/>
|
||||
<x-input.error :messages="$errors->get('repeat_frequency')" />
|
||||
|
||||
<div class="mt-3 {{ $repeatFrequency === '' ? 'hidden' : '' }}" data-recurrence-interval>
|
||||
<x-input.label for="repeat_interval" :value="__('calendar.event.recurrence.every')" />
|
||||
<div class="flex items-center gap-2">
|
||||
<x-input.text
|
||||
id="repeat_interval"
|
||||
name="repeat_interval"
|
||||
type="number"
|
||||
min="1"
|
||||
max="365"
|
||||
:value="$repeatInterval"
|
||||
/>
|
||||
<span class="text-sm text-gray-600" data-recurrence-unit></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 {{ $repeatFrequency !== 'weekly' ? 'hidden' : '' }}" data-recurrence-section="weekly">
|
||||
<p class="text-sm text-gray-600">{{ __('calendar.event.recurrence.on_days') }}</p>
|
||||
<div class="flex flex-wrap gap-2 mt-2">
|
||||
@foreach ($weekdayOptions as $code => $label)
|
||||
<label class="inline-flex items-center gap-2 text-sm">
|
||||
<x-input.checkbox
|
||||
name="repeat_weekdays[]"
|
||||
value="{{ $code }}"
|
||||
:checked="in_array($code, (array) $repeatWeekdays, true)"
|
||||
/>
|
||||
<span title="{{ $weekdayLong[$code] ?? $code }}">{{ $label }}</span>
|
||||
</label>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 {{ $repeatFrequency !== 'monthly' ? 'hidden' : '' }}" data-recurrence-section="monthly">
|
||||
<div class="flex flex-col gap-3">
|
||||
<div class="flex items-center gap-4">
|
||||
<x-input.radio-label
|
||||
id="repeat_monthly_mode_days"
|
||||
name="repeat_monthly_mode"
|
||||
value="days"
|
||||
label="{{ __('calendar.event.recurrence.on_days') }}"
|
||||
:checked="$repeatMonthMode === 'days'"
|
||||
data-monthly-mode
|
||||
/>
|
||||
<x-input.error :messages="$errors->get('repeat_frequency')" />
|
||||
<x-input.radio-label
|
||||
id="repeat_monthly_mode_weekday"
|
||||
name="repeat_monthly_mode"
|
||||
value="weekday"
|
||||
label="{{ __('calendar.event.recurrence.on_the') }}"
|
||||
:checked="$repeatMonthMode === 'weekday'"
|
||||
data-monthly-mode
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="mt-3 {{ $repeatFrequency === '' ? 'hidden' : '' }}" data-recurrence-interval>
|
||||
<x-input.label for="repeat_interval" :value="__('calendar.event.recurrence.every')" />
|
||||
<div class="flex items-center gap-2">
|
||||
<x-input.text
|
||||
id="repeat_interval"
|
||||
name="repeat_interval"
|
||||
type="number"
|
||||
min="1"
|
||||
max="365"
|
||||
:value="$repeatInterval"
|
||||
<div class="grid grid-cols-7 gap-2 {{ $repeatMonthMode !== 'days' ? 'hidden' : '' }}" data-monthly-days>
|
||||
@for ($day = 1; $day <= 31; $day++)
|
||||
<label class="inline-flex items-center gap-2 text-xs">
|
||||
<x-input.checkbox
|
||||
name="repeat_month_days[]"
|
||||
value="{{ $day }}"
|
||||
:checked="in_array($day, (array) $repeatMonthDays)"
|
||||
/>
|
||||
<span class="text-sm text-gray-600" data-recurrence-unit></span>
|
||||
</div>
|
||||
</div>
|
||||
<span>{{ $day }}</span>
|
||||
</label>
|
||||
@endfor
|
||||
</div>
|
||||
|
||||
<div class="mt-4 {{ $repeatFrequency !== 'weekly' ? 'hidden' : '' }}" data-recurrence-section="weekly">
|
||||
<p class="text-sm text-gray-600">{{ __('calendar.event.recurrence.on_days') }}</p>
|
||||
<div class="flex flex-wrap gap-2 mt-2">
|
||||
@foreach ($weekdayOptions as $code => $label)
|
||||
<label class="inline-flex items-center gap-2 text-sm">
|
||||
<x-input.checkbox
|
||||
name="repeat_weekdays[]"
|
||||
value="{{ $code }}"
|
||||
:checked="in_array($code, (array) $repeatWeekdays, true)"
|
||||
/>
|
||||
<span title="{{ $weekdayLong[$code] ?? $code }}">{{ $label }}</span>
|
||||
</label>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 {{ $repeatFrequency !== 'monthly' ? 'hidden' : '' }}" data-recurrence-section="monthly">
|
||||
<div class="flex flex-col gap-3">
|
||||
<div class="flex items-center gap-4">
|
||||
<x-input.radio-label
|
||||
id="repeat_monthly_mode_days"
|
||||
name="repeat_monthly_mode"
|
||||
value="days"
|
||||
label="{{ __('calendar.event.recurrence.on_days') }}"
|
||||
:checked="$repeatMonthMode === 'days'"
|
||||
data-monthly-mode
|
||||
/>
|
||||
<x-input.radio-label
|
||||
id="repeat_monthly_mode_weekday"
|
||||
name="repeat_monthly_mode"
|
||||
value="weekday"
|
||||
label="{{ __('calendar.event.recurrence.on_the') }}"
|
||||
:checked="$repeatMonthMode === 'weekday'"
|
||||
data-monthly-mode
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-7 gap-2 {{ $repeatMonthMode !== 'days' ? 'hidden' : '' }}" data-monthly-days>
|
||||
@for ($day = 1; $day <= 31; $day++)
|
||||
<label class="inline-flex items-center gap-2 text-xs">
|
||||
<x-input.checkbox
|
||||
name="repeat_month_days[]"
|
||||
value="{{ $day }}"
|
||||
:checked="in_array($day, (array) $repeatMonthDays)"
|
||||
/>
|
||||
<span>{{ $day }}</span>
|
||||
</label>
|
||||
@endfor
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-3 {{ $repeatMonthMode !== 'weekday' ? 'hidden' : '' }}" data-monthly-weekday>
|
||||
<x-input.select
|
||||
id="repeat_month_week"
|
||||
name="repeat_month_week"
|
||||
:options="[
|
||||
'first' => __('calendar.event.recurrence.week_order.first'),
|
||||
'second' => __('calendar.event.recurrence.week_order.second'),
|
||||
'third' => __('calendar.event.recurrence.week_order.third'),
|
||||
'fourth' => __('calendar.event.recurrence.week_order.fourth'),
|
||||
'last' => __('calendar.event.recurrence.week_order.last'),
|
||||
]"
|
||||
:selected="$repeatMonthWeek"
|
||||
/>
|
||||
<x-input.select
|
||||
id="repeat_month_weekday"
|
||||
name="repeat_month_weekday"
|
||||
:options="$weekdayLong"
|
||||
:selected="$repeatMonthWeekday"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 text-sm text-gray-600 {{ $repeatFrequency !== 'yearly' ? 'hidden' : '' }}" data-recurrence-section="yearly">
|
||||
{{ __('calendar.event.recurrence.yearly_hint') }}
|
||||
</div>
|
||||
<div class="flex items-center gap-3 {{ $repeatMonthMode !== 'weekday' ? 'hidden' : '' }}" data-monthly-weekday>
|
||||
<x-input.select
|
||||
id="repeat_month_week"
|
||||
name="repeat_month_week"
|
||||
:options="[
|
||||
'first' => __('calendar.event.recurrence.week_order.first'),
|
||||
'second' => __('calendar.event.recurrence.week_order.second'),
|
||||
'third' => __('calendar.event.recurrence.week_order.third'),
|
||||
'fourth' => __('calendar.event.recurrence.week_order.fourth'),
|
||||
'last' => __('calendar.event.recurrence.week_order.last'),
|
||||
]"
|
||||
:selected="$repeatMonthWeek"
|
||||
/>
|
||||
<x-input.select
|
||||
id="repeat_month_weekday"
|
||||
name="repeat_month_weekday"
|
||||
:options="$weekdayLong"
|
||||
:selected="$repeatMonthWeekday"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- attendees --}}
|
||||
<div id="tab-attendees" role="tabpanel" aria-labelledby="tab-btn-attendees" hidden>
|
||||
<div class="input-row input-row--1">
|
||||
<div class="input-cell">
|
||||
<input type="hidden" name="attendees_present" value="1">
|
||||
|
||||
<div class="flex flex-col gap-3" data-attendees data-next-index="{{ count($attendees ?? []) }}">
|
||||
<div class="flex flex-col gap-2">
|
||||
<x-input.label for="attendee_lookup" :value="__('calendar.event.attendees.add')" />
|
||||
<p class="text-sm text-gray-600">{{ __('calendar.event.attendees.help') }}</p>
|
||||
<div class="flex items-center gap-2">
|
||||
<x-input.text
|
||||
id="attendee_lookup"
|
||||
name="attendee"
|
||||
type="text"
|
||||
placeholder="{{ __('calendar.event.attendees.search_placeholder') }}"
|
||||
data-attendee-lookup
|
||||
hx-get="{{ route('attendee.suggest') }}"
|
||||
hx-trigger="keyup changed delay:250ms"
|
||||
hx-target="#attendee-suggestions"
|
||||
hx-swap="innerHTML"
|
||||
/>
|
||||
<x-button type="button" variant="tertiary" data-attendee-add-manual>
|
||||
{{ __('calendar.event.attendees.add_button') }}
|
||||
</x-button>
|
||||
</div>
|
||||
<div id="attendee-suggestions"></div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-3" data-attendees-list>
|
||||
@foreach (($attendees ?? []) as $index => $attendee)
|
||||
<div class="attendee-row rounded-lg border border-gray-200 p-3 flex flex-col gap-3" data-attendee-row>
|
||||
<input type="hidden" name="attendees[{{ $index }}][attendee_uri]" value="{{ $attendee['attendee_uri'] ?? '' }}" data-attendee-uri>
|
||||
<input type="hidden" name="attendees[{{ $index }}][email]" value="{{ $attendee['email'] ?? '' }}" data-attendee-email>
|
||||
<input type="hidden" name="attendees[{{ $index }}][name]" value="{{ $attendee['name'] ?? '' }}" data-attendee-name>
|
||||
<input type="hidden" name="attendees[{{ $index }}][role]" value="{{ !empty($attendee['optional']) ? 'OPT-PARTICIPANT' : 'REQ-PARTICIPANT' }}" data-attendee-role>
|
||||
<input type="hidden" name="attendees[{{ $index }}][partstat]" value="NEEDS-ACTION">
|
||||
<input type="hidden" name="attendees[{{ $index }}][cutype]" value="INDIVIDUAL">
|
||||
<input type="hidden" name="attendees[{{ $index }}][is_organizer]" value="0">
|
||||
|
||||
<div class="flex items-center justify-between gap-3">
|
||||
<div class="flex flex-col">
|
||||
<strong data-attendee-display>
|
||||
{{ ($attendee['name'] ?? '') !== '' ? ($attendee['name'] . ' <' . ($attendee['email'] ?? '') . '>') : ($attendee['email'] ?? '') }}
|
||||
</strong>
|
||||
<span class="text-xs text-emerald-700 {{ !empty($attendee['verified']) ? '' : 'hidden' }}" data-attendee-verified>
|
||||
{{ __('calendar.event.attendees.verified') }}
|
||||
</span>
|
||||
</div>
|
||||
<button type="button" class="button button--tertiary" data-attendee-remove>
|
||||
<x-icon-x width="18" />
|
||||
<span class="sr-only">{{ __('calendar.event.attendees.remove') }}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-4">
|
||||
<label class="inline-flex items-center gap-2 text-sm">
|
||||
<input type="hidden" name="attendees[{{ $index }}][optional]" value="0">
|
||||
<x-input.checkbox
|
||||
name="attendees[{{ $index }}][optional]"
|
||||
value="1"
|
||||
:checked="(bool) ($attendee['optional'] ?? false)"
|
||||
data-attendee-optional
|
||||
/>
|
||||
<span>{{ __('calendar.event.attendees.optional') }}</span>
|
||||
</label>
|
||||
|
||||
<label class="inline-flex items-center gap-2 text-sm">
|
||||
<input type="hidden" name="attendees[{{ $index }}][rsvp]" value="0">
|
||||
<x-input.checkbox
|
||||
name="attendees[{{ $index }}][rsvp]"
|
||||
value="1"
|
||||
:checked="(bool) ($attendee['rsvp'] ?? true)"
|
||||
/>
|
||||
<span>{{ __('calendar.event.attendees.rsvp') }}</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
<template data-attendee-template>
|
||||
<div class="attendee-row rounded-lg border border-gray-200 p-3 flex flex-col gap-3" data-attendee-row>
|
||||
<input type="hidden" name="attendees[__INDEX__][attendee_uri]" value="" data-attendee-uri>
|
||||
<input type="hidden" name="attendees[__INDEX__][email]" value="" data-attendee-email>
|
||||
<input type="hidden" name="attendees[__INDEX__][name]" value="" data-attendee-name>
|
||||
<input type="hidden" name="attendees[__INDEX__][role]" value="REQ-PARTICIPANT" data-attendee-role>
|
||||
<input type="hidden" name="attendees[__INDEX__][partstat]" value="NEEDS-ACTION">
|
||||
<input type="hidden" name="attendees[__INDEX__][cutype]" value="INDIVIDUAL">
|
||||
<input type="hidden" name="attendees[__INDEX__][is_organizer]" value="0">
|
||||
|
||||
<div class="flex items-center justify-between gap-3">
|
||||
<div class="flex flex-col">
|
||||
<strong data-attendee-display></strong>
|
||||
<span class="text-xs text-emerald-700 hidden" data-attendee-verified>
|
||||
{{ __('calendar.event.attendees.verified') }}
|
||||
</span>
|
||||
</div>
|
||||
<button type="button" class="button button--tertiary" data-attendee-remove>
|
||||
<x-icon-x width="18" />
|
||||
<span class="sr-only">{{ __('calendar.event.attendees.remove') }}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-4">
|
||||
<label class="inline-flex items-center gap-2 text-sm">
|
||||
<input type="hidden" name="attendees[__INDEX__][optional]" value="0">
|
||||
<input name="attendees[__INDEX__][optional]" type="checkbox" value="1" data-attendee-optional>
|
||||
<span>{{ __('calendar.event.attendees.optional') }}</span>
|
||||
</label>
|
||||
|
||||
<label class="inline-flex items-center gap-2 text-sm">
|
||||
<input type="hidden" name="attendees[__INDEX__][rsvp]" value="0">
|
||||
<input name="attendees[__INDEX__][rsvp]" type="checkbox" value="1" checked>
|
||||
<span>{{ __('calendar.event.attendees.rsvp') }}</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-4 text-sm text-gray-600 {{ $repeatFrequency !== 'yearly' ? 'hidden' : '' }}" data-recurrence-section="yearly">
|
||||
{{ __('calendar.event.recurrence.yearly_hint') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- attendees --}}
|
||||
<div class="event-field">
|
||||
<div class="event-field-icon">
|
||||
<x-icon-user-circle />
|
||||
</div>
|
||||
<div class="input-row input-row--1">
|
||||
<div class="input-cell">
|
||||
<input type="hidden" name="attendees_present" value="1">
|
||||
|
||||
<div class="flex flex-col gap-3" data-attendees data-next-index="{{ count($attendees ?? []) }}">
|
||||
<div class="flex flex-col gap-2">
|
||||
<x-input.label for="attendee_lookup" :value="__('calendar.event.attendees.add')" />
|
||||
<p class="text-sm text-gray-600">{{ __('calendar.event.attendees.help') }}</p>
|
||||
<div class="flex items-center gap-2">
|
||||
<x-input.text
|
||||
id="attendee_lookup"
|
||||
name="attendee"
|
||||
type="text"
|
||||
placeholder="{{ __('calendar.event.attendees.search_placeholder') }}"
|
||||
data-attendee-lookup
|
||||
hx-get="{{ route('attendee.suggest') }}"
|
||||
hx-trigger="keyup changed delay:250ms"
|
||||
hx-target="#attendee-suggestions"
|
||||
hx-swap="innerHTML"
|
||||
/>
|
||||
<x-button type="button" variant="tertiary" data-attendee-add-manual>
|
||||
{{ __('calendar.event.attendees.add_button') }}
|
||||
</x-button>
|
||||
</div>
|
||||
<div id="attendee-suggestions"></div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-3" data-attendees-list>
|
||||
@foreach (($attendees ?? []) as $index => $attendee)
|
||||
<div class="attendee-row rounded-lg border border-gray-200 p-3 flex flex-col gap-3" data-attendee-row>
|
||||
<input type="hidden" name="attendees[{{ $index }}][attendee_uri]" value="{{ $attendee['attendee_uri'] ?? '' }}" data-attendee-uri>
|
||||
<input type="hidden" name="attendees[{{ $index }}][email]" value="{{ $attendee['email'] ?? '' }}" data-attendee-email>
|
||||
<input type="hidden" name="attendees[{{ $index }}][name]" value="{{ $attendee['name'] ?? '' }}" data-attendee-name>
|
||||
<input type="hidden" name="attendees[{{ $index }}][role]" value="{{ !empty($attendee['optional']) ? 'OPT-PARTICIPANT' : 'REQ-PARTICIPANT' }}" data-attendee-role>
|
||||
<input type="hidden" name="attendees[{{ $index }}][partstat]" value="NEEDS-ACTION">
|
||||
<input type="hidden" name="attendees[{{ $index }}][cutype]" value="INDIVIDUAL">
|
||||
<input type="hidden" name="attendees[{{ $index }}][is_organizer]" value="0">
|
||||
|
||||
<div class="flex items-center justify-between gap-3">
|
||||
<div class="flex flex-col">
|
||||
<strong data-attendee-display>
|
||||
{{ ($attendee['name'] ?? '') !== '' ? ($attendee['name'] . ' <' . ($attendee['email'] ?? '') . '>') : ($attendee['email'] ?? '') }}
|
||||
</strong>
|
||||
<span class="text-xs text-emerald-700 {{ !empty($attendee['verified']) ? '' : 'hidden' }}" data-attendee-verified>
|
||||
{{ __('calendar.event.attendees.verified') }}
|
||||
</span>
|
||||
</div>
|
||||
<button type="button" class="button button--tertiary" data-attendee-remove>
|
||||
<x-icon-x width="18" />
|
||||
<span class="sr-only">{{ __('calendar.event.attendees.remove') }}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-4">
|
||||
<label class="inline-flex items-center gap-2 text-sm">
|
||||
<input type="hidden" name="attendees[{{ $index }}][optional]" value="0">
|
||||
<x-input.checkbox
|
||||
name="attendees[{{ $index }}][optional]"
|
||||
value="1"
|
||||
:checked="(bool) ($attendee['optional'] ?? false)"
|
||||
data-attendee-optional
|
||||
/>
|
||||
<span>{{ __('calendar.event.attendees.optional') }}</span>
|
||||
</label>
|
||||
|
||||
<label class="inline-flex items-center gap-2 text-sm">
|
||||
<input type="hidden" name="attendees[{{ $index }}][rsvp]" value="0">
|
||||
<x-input.checkbox
|
||||
name="attendees[{{ $index }}][rsvp]"
|
||||
value="1"
|
||||
:checked="(bool) ($attendee['rsvp'] ?? true)"
|
||||
/>
|
||||
<span>{{ __('calendar.event.attendees.rsvp') }}</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
<template data-attendee-template>
|
||||
<div class="attendee-row rounded-lg border border-gray-200 p-3 flex flex-col gap-3" data-attendee-row>
|
||||
<input type="hidden" name="attendees[__INDEX__][attendee_uri]" value="" data-attendee-uri>
|
||||
<input type="hidden" name="attendees[__INDEX__][email]" value="" data-attendee-email>
|
||||
<input type="hidden" name="attendees[__INDEX__][name]" value="" data-attendee-name>
|
||||
<input type="hidden" name="attendees[__INDEX__][role]" value="REQ-PARTICIPANT" data-attendee-role>
|
||||
<input type="hidden" name="attendees[__INDEX__][partstat]" value="NEEDS-ACTION">
|
||||
<input type="hidden" name="attendees[__INDEX__][cutype]" value="INDIVIDUAL">
|
||||
<input type="hidden" name="attendees[__INDEX__][is_organizer]" value="0">
|
||||
|
||||
<div class="flex items-center justify-between gap-3">
|
||||
<div class="flex flex-col">
|
||||
<strong data-attendee-display></strong>
|
||||
<span class="text-xs text-emerald-700 hidden" data-attendee-verified>
|
||||
{{ __('calendar.event.attendees.verified') }}
|
||||
</span>
|
||||
</div>
|
||||
<button type="button" class="button button--tertiary" data-attendee-remove>
|
||||
<x-icon-x width="18" />
|
||||
<span class="sr-only">{{ __('calendar.event.attendees.remove') }}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-4">
|
||||
<label class="inline-flex items-center gap-2 text-sm">
|
||||
<input type="hidden" name="attendees[__INDEX__][optional]" value="0">
|
||||
<input name="attendees[__INDEX__][optional]" type="checkbox" value="1" data-attendee-optional>
|
||||
<span>{{ __('calendar.event.attendees.optional') }}</span>
|
||||
</label>
|
||||
|
||||
<label class="inline-flex items-center gap-2 text-sm">
|
||||
<input type="hidden" name="attendees[__INDEX__][rsvp]" value="0">
|
||||
<input name="attendees[__INDEX__][rsvp]" type="checkbox" value="1" checked>
|
||||
<span>{{ __('calendar.event.attendees.rsvp') }}</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Description --}}
|
||||
<div class="event-field">
|
||||
<div class="event-field-icon">
|
||||
<x-icon-description />
|
||||
</div>
|
||||
<div class="input-row input-row--1">
|
||||
<div class="input-cell">
|
||||
<x-input.textarea
|
||||
id="description"
|
||||
name="description"
|
||||
placeholder="Description..."
|
||||
rows="3">{{ old('description', $event->meta?->description ?? '') }}</x-input.textarea>
|
||||
<x-input.error :messages="$errors->get('description')" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user