Refine calendar icon picker
This commit is contained in:
@@ -863,7 +863,7 @@
|
||||
"offset1week": "1 week before",
|
||||
"offset2weeks": "2 weeks before",
|
||||
"offsetCustom": "Custom...",
|
||||
"customAmountLabel": "Amount",
|
||||
"customAmountLabel": "Number",
|
||||
"customUnitLabel": "Unit",
|
||||
"customMinutes": "Minutes",
|
||||
"customHours": "Hours",
|
||||
|
||||
@@ -863,7 +863,7 @@
|
||||
"offset1week": "1 week before",
|
||||
"offset2weeks": "2 weeks before",
|
||||
"offsetCustom": "Custom...",
|
||||
"customAmountLabel": "Amount",
|
||||
"customAmountLabel": "Number",
|
||||
"customUnitLabel": "Unit",
|
||||
"customMinutes": "Minutes",
|
||||
"customHours": "Hours",
|
||||
|
||||
@@ -805,7 +805,7 @@
|
||||
"offset1week": "1 week before",
|
||||
"offset2weeks": "2 weeks before",
|
||||
"offsetCustom": "Custom...",
|
||||
"customAmountLabel": "Amount",
|
||||
"customAmountLabel": "Number",
|
||||
"customUnitLabel": "Unit",
|
||||
"customMinutes": "Minutes",
|
||||
"customHours": "Hours",
|
||||
|
||||
@@ -863,7 +863,7 @@
|
||||
"offset1week": "1 week before",
|
||||
"offset2weeks": "2 weeks before",
|
||||
"offsetCustom": "Custom...",
|
||||
"customAmountLabel": "Amount",
|
||||
"customAmountLabel": "Number",
|
||||
"customUnitLabel": "Unit",
|
||||
"customMinutes": "Minutes",
|
||||
"customHours": "Hours",
|
||||
|
||||
@@ -863,7 +863,7 @@
|
||||
"offset1week": "1 week before",
|
||||
"offset2weeks": "2 weeks before",
|
||||
"offsetCustom": "Custom...",
|
||||
"customAmountLabel": "Amount",
|
||||
"customAmountLabel": "Number",
|
||||
"customUnitLabel": "Unit",
|
||||
"customMinutes": "Minutes",
|
||||
"customHours": "Hours",
|
||||
|
||||
@@ -863,7 +863,7 @@
|
||||
"offset1week": "1 week before",
|
||||
"offset2weeks": "2 weeks before",
|
||||
"offsetCustom": "Custom...",
|
||||
"customAmountLabel": "Amount",
|
||||
"customAmountLabel": "Number",
|
||||
"customUnitLabel": "Unit",
|
||||
"customMinutes": "Minutes",
|
||||
"customHours": "Hours",
|
||||
|
||||
@@ -863,7 +863,7 @@
|
||||
"offset1week": "1 week before",
|
||||
"offset2weeks": "2 weeks before",
|
||||
"offsetCustom": "Custom...",
|
||||
"customAmountLabel": "Amount",
|
||||
"customAmountLabel": "Number",
|
||||
"customUnitLabel": "Unit",
|
||||
"customMinutes": "Minutes",
|
||||
"customHours": "Hours",
|
||||
|
||||
@@ -863,7 +863,7 @@
|
||||
"offset1week": "1 week before",
|
||||
"offset2weeks": "2 weeks before",
|
||||
"offsetCustom": "Custom...",
|
||||
"customAmountLabel": "Amount",
|
||||
"customAmountLabel": "Number",
|
||||
"customUnitLabel": "Unit",
|
||||
"customMinutes": "Minutes",
|
||||
"customHours": "Hours",
|
||||
|
||||
@@ -864,7 +864,7 @@
|
||||
"offset1week": "1 semana antes",
|
||||
"offset2weeks": "2 semanas antes",
|
||||
"offsetCustom": "Personalizado...",
|
||||
"customAmountLabel": "Quantidade",
|
||||
"customAmountLabel": "Número",
|
||||
"customUnitLabel": "Unidade",
|
||||
"customMinutes": "Minutos",
|
||||
"customHours": "Horas",
|
||||
|
||||
@@ -863,7 +863,7 @@
|
||||
"offset1week": "1 week before",
|
||||
"offset2weeks": "2 weeks before",
|
||||
"offsetCustom": "Custom...",
|
||||
"customAmountLabel": "Amount",
|
||||
"customAmountLabel": "Number",
|
||||
"customUnitLabel": "Unit",
|
||||
"customMinutes": "Minutes",
|
||||
"customHours": "Hours",
|
||||
|
||||
@@ -863,7 +863,7 @@
|
||||
"offset1week": "1 week before",
|
||||
"offset2weeks": "2 weeks before",
|
||||
"offsetCustom": "Custom...",
|
||||
"customAmountLabel": "Amount",
|
||||
"customAmountLabel": "Number",
|
||||
"customUnitLabel": "Unit",
|
||||
"customMinutes": "Minutes",
|
||||
"customHours": "Hours",
|
||||
|
||||
@@ -863,7 +863,7 @@
|
||||
"offset1week": "1 week before",
|
||||
"offset2weeks": "2 weeks before",
|
||||
"offsetCustom": "Custom...",
|
||||
"customAmountLabel": "Amount",
|
||||
"customAmountLabel": "Number",
|
||||
"customUnitLabel": "Unit",
|
||||
"customMinutes": "Minutes",
|
||||
"customHours": "Hours",
|
||||
|
||||
@@ -805,7 +805,7 @@
|
||||
"offset1week": "1 week before",
|
||||
"offset2weeks": "2 weeks before",
|
||||
"offsetCustom": "Custom...",
|
||||
"customAmountLabel": "Amount",
|
||||
"customAmountLabel": "Number",
|
||||
"customUnitLabel": "Unit",
|
||||
"customMinutes": "Minutes",
|
||||
"customHours": "Hours",
|
||||
|
||||
@@ -863,7 +863,7 @@
|
||||
"offset1week": "1 week before",
|
||||
"offset2weeks": "2 weeks before",
|
||||
"offsetCustom": "Custom...",
|
||||
"customAmountLabel": "Amount",
|
||||
"customAmountLabel": "Number",
|
||||
"customUnitLabel": "Unit",
|
||||
"customMinutes": "Minutes",
|
||||
"customHours": "Hours",
|
||||
|
||||
@@ -991,6 +991,48 @@ function openEventModal({ mode, event = null, date = null, reminder = null }) {
|
||||
|
||||
bindDateInputs(panel);
|
||||
|
||||
const iconInput = panel.querySelector('#modal-icon');
|
||||
const iconTrigger = panel.querySelector('#modal-icon-trigger');
|
||||
const iconGrid = panel.querySelector('#modal-icon-grid');
|
||||
const selectIcon = (icon) => {
|
||||
const nextIcon = eventIconName(icon);
|
||||
if (iconInput) iconInput.value = nextIcon;
|
||||
if (iconTrigger) {
|
||||
iconTrigger.dataset.icon = nextIcon;
|
||||
const iconEl = iconTrigger.querySelector('[data-lucide]');
|
||||
iconEl?.setAttribute('data-lucide', nextIcon);
|
||||
}
|
||||
iconGrid?.querySelectorAll('.event-icon-picker__option').forEach((btn) => {
|
||||
const active = btn.dataset.icon === nextIcon;
|
||||
btn.classList.toggle('event-icon-picker__option--active', active);
|
||||
btn.setAttribute('aria-checked', active ? 'true' : 'false');
|
||||
});
|
||||
if (window.lucide) lucide.createIcons();
|
||||
};
|
||||
|
||||
iconTrigger?.addEventListener('click', () => {
|
||||
if (!iconGrid) return;
|
||||
iconGrid.hidden = !iconGrid.hidden;
|
||||
iconTrigger.setAttribute('aria-expanded', iconGrid.hidden ? 'false' : 'true');
|
||||
});
|
||||
iconGrid?.addEventListener('click', (e) => {
|
||||
const btn = e.target.closest('.event-icon-picker__option');
|
||||
if (!btn) return;
|
||||
selectIcon(btn.dataset.icon);
|
||||
iconGrid.hidden = true;
|
||||
iconTrigger?.setAttribute('aria-expanded', 'false');
|
||||
iconTrigger?.focus();
|
||||
});
|
||||
document.addEventListener('click', function closeIconPicker(e) {
|
||||
if (!panel.isConnected) {
|
||||
document.removeEventListener('click', closeIconPicker);
|
||||
return;
|
||||
}
|
||||
if (iconGrid?.hidden || iconGrid?.contains(e.target) || iconTrigger?.contains(e.target)) return;
|
||||
iconGrid.hidden = true;
|
||||
iconTrigger?.setAttribute('aria-expanded', 'false');
|
||||
});
|
||||
|
||||
const reminderOffset = panel.querySelector('#modal-reminder-offset');
|
||||
const reminderCustom = panel.querySelector('#modal-reminder-custom');
|
||||
reminderOffset?.addEventListener('change', () => {
|
||||
@@ -1021,8 +1063,16 @@ function buildEventModalContent({ mode, event, date, reminder = null }) {
|
||||
const endTime = isEdit && event.end_datetime && event.end_datetime.length > 10
|
||||
? localTime(event.end_datetime) : '10:00';
|
||||
const selectedIcon = eventIconName(isEdit ? event.icon : 'calendar');
|
||||
const iconOpts = EVENT_ICONS.map((icon) =>
|
||||
`<option value="${icon.value}" ${selectedIcon === icon.value ? 'selected' : ''}>${esc(icon.label)}</option>`
|
||||
const iconButtons = EVENT_ICONS.map((icon) =>
|
||||
`<button type="button"
|
||||
class="event-icon-picker__option ${selectedIcon === icon.value ? 'event-icon-picker__option--active' : ''}"
|
||||
data-icon="${icon.value}"
|
||||
role="radio"
|
||||
aria-checked="${selectedIcon === icon.value ? 'true' : 'false'}"
|
||||
aria-label="${esc(icon.label)}"
|
||||
title="${esc(icon.label)}">
|
||||
<i data-lucide="${icon.value}" aria-hidden="true"></i>
|
||||
</button>`
|
||||
).join('');
|
||||
|
||||
const userOpts = [
|
||||
@@ -1033,16 +1083,28 @@ function buildEventModalContent({ mode, event, date, reminder = null }) {
|
||||
].join('');
|
||||
|
||||
return `
|
||||
<div class="modal-grid modal-grid--event-title">
|
||||
<div class="form-group">
|
||||
<div class="event-title-picker">
|
||||
<div class="form-group event-icon-picker">
|
||||
<label class="form-label" for="modal-icon-trigger">${t('calendar.iconLabel')}</label>
|
||||
<input type="hidden" id="modal-icon" value="${selectedIcon}">
|
||||
<button type="button"
|
||||
class="event-icon-picker__trigger"
|
||||
id="modal-icon-trigger"
|
||||
data-icon="${selectedIcon}"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="false"
|
||||
aria-label="${t('calendar.iconLabel')}">
|
||||
<i data-lucide="${selectedIcon}" aria-hidden="true"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="form-group event-title-picker__title">
|
||||
<label class="form-label" for="modal-title">${t('calendar.titleLabel')}</label>
|
||||
<input type="text" class="form-input" id="modal-title"
|
||||
placeholder="${t('calendar.titlePlaceholder')}" value="${esc(isEdit ? event.title : '')}">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="modal-icon">${t('calendar.iconLabel')}</label>
|
||||
<select class="form-input" id="modal-icon">${iconOpts}</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="event-icon-picker__grid" id="modal-icon-grid" role="radiogroup" aria-label="${t('calendar.iconLabel')}" hidden>
|
||||
${iconButtons}
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
|
||||
@@ -544,14 +544,104 @@
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.modal-grid--event-title {
|
||||
grid-template-columns: minmax(0, 1fr) 160px;
|
||||
.event-title-picker {
|
||||
display: grid;
|
||||
grid-template-columns: 72px minmax(0, 1fr);
|
||||
gap: var(--space-3);
|
||||
align-items: end;
|
||||
}
|
||||
|
||||
.event-icon-picker {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.event-title-picker__title {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.event-icon-picker__trigger {
|
||||
width: 52px;
|
||||
height: 44px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-sm);
|
||||
background: var(--color-surface);
|
||||
color: var(--color-text-primary);
|
||||
cursor: pointer;
|
||||
transition: border-color var(--transition-fast), background-color var(--transition-fast), transform var(--transition-fast);
|
||||
}
|
||||
|
||||
.event-icon-picker__trigger:hover,
|
||||
.event-icon-picker__trigger:focus-visible {
|
||||
border-color: var(--color-accent);
|
||||
background: var(--color-accent-light);
|
||||
}
|
||||
|
||||
.event-icon-picker__trigger:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
.event-icon-picker__trigger i {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
}
|
||||
|
||||
.event-icon-picker__grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(44px, 1fr));
|
||||
gap: var(--space-2);
|
||||
margin: calc(var(--space-2) * -1) 0 var(--space-4) 0;
|
||||
padding: var(--space-3);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-md);
|
||||
background: var(--color-surface-2);
|
||||
}
|
||||
|
||||
.event-icon-picker__grid[hidden] {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.event-icon-picker__option {
|
||||
height: 42px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 1px solid transparent;
|
||||
border-radius: var(--radius-sm);
|
||||
background: var(--color-surface);
|
||||
color: var(--color-text-secondary);
|
||||
cursor: pointer;
|
||||
transition: border-color var(--transition-fast), color var(--transition-fast), background-color var(--transition-fast), transform var(--transition-fast);
|
||||
}
|
||||
|
||||
.event-icon-picker__option:hover,
|
||||
.event-icon-picker__option:focus-visible {
|
||||
color: var(--color-text-primary);
|
||||
border-color: var(--color-border);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.event-icon-picker__option--active {
|
||||
color: var(--color-accent);
|
||||
border-color: var(--color-accent);
|
||||
background: var(--color-accent-light);
|
||||
}
|
||||
|
||||
.event-icon-picker__option i {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.reminder-custom {
|
||||
margin-top: var(--space-3);
|
||||
}
|
||||
|
||||
.reminder-custom[hidden] {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.agenda-event__meta {
|
||||
font-size: var(--text-sm);
|
||||
color: var(--color-text-secondary);
|
||||
@@ -706,7 +796,7 @@
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.modal-grid--event-title {
|
||||
.event-title-picker {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -13,10 +13,10 @@
|
||||
* → bypassCacheUntil (in-memory + Cache API für SW-Restart-Robustheit)
|
||||
*/
|
||||
|
||||
const SHELL_CACHE = 'oikos-shell-v57';
|
||||
const PAGES_CACHE = 'oikos-pages-v52';
|
||||
const LOCALES_CACHE = 'oikos-locales-v4';
|
||||
const ASSETS_CACHE = 'oikos-assets-v52';
|
||||
const SHELL_CACHE = 'oikos-shell-v58';
|
||||
const PAGES_CACHE = 'oikos-pages-v53';
|
||||
const LOCALES_CACHE = 'oikos-locales-v5';
|
||||
const ASSETS_CACHE = 'oikos-assets-v53';
|
||||
const BYPASS_CACHE = 'oikos-bypass-flag';
|
||||
const ALL_CACHES = [SHELL_CACHE, PAGES_CACHE, LOCALES_CACHE, ASSETS_CACHE];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user