Fix calendar styling
This commit is contained in:
@@ -7,12 +7,12 @@ const DEFAULT_MONTHS_LONG = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
const DEFAULT_THEME = {
|
const DEFAULT_THEME = {
|
||||||
selectedBg: 'rgb(var(--card-rgb))',
|
selectedBorder: 'rgba(var(--text-emphasis-rgb),0.34)',
|
||||||
selectedBorder: 'rgb(var(--border-input-rgb))',
|
|
||||||
selectedText: 'rgb(var(--text-emphasis-rgb))',
|
selectedText: 'rgb(var(--text-emphasis-rgb))',
|
||||||
selectedDot: 'rgb(var(--text-emphasis-rgb))',
|
selectedDot: 'rgb(var(--text-emphasis-rgb))',
|
||||||
|
selectedShadow: '0 0 0 1px rgba(var(--text-emphasis-rgb),0.10)',
|
||||||
bg: 'rgb(var(--app-bg-rgb))',
|
bg: 'rgb(var(--app-bg-rgb))',
|
||||||
border: 'rgb(var(--card-raised-rgb))',
|
border: 'transparent',
|
||||||
text: 'rgb(var(--text-body-soft-rgb))',
|
text: 'rgb(var(--text-body-soft-rgb))',
|
||||||
dimmedBg: 'transparent',
|
dimmedBg: 'transparent',
|
||||||
dimText: 'rgb(var(--text-faint-rgb))',
|
dimText: 'rgb(var(--text-faint-rgb))',
|
||||||
@@ -58,20 +58,6 @@ export function createSwipePopoverCalendarHTML({
|
|||||||
${weekdays.map((d) => `<div>${d}</div>`).join('')}
|
${weekdays.map((d) => `<div>${d}</div>`).join('')}
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
const gripLeft = `
|
|
||||||
<div data-swc-grip aria-hidden="true" style="position:absolute; left:0; top:50%; transform:translateY(-50%); width:0.76rem; height:1rem; pointer-events:none; opacity:0.66;">
|
|
||||||
<span style="position:absolute; left:0; top:50%; transform:translateY(-50%); width:1.5px; height:1.22rem; border-radius:999px; background:rgba(var(--text-faint-rgb),0.84);"></span>
|
|
||||||
<span style="position:absolute; left:0.16rem; top:50%; transform:translateY(-50%); width:1.5px; height:1.0rem; border-radius:999px; background:rgba(var(--text-faint-rgb),0.74);"></span>
|
|
||||||
<span style="position:absolute; left:0.34rem; top:50%; transform:translateY(-50%); width:1.5px; height:0.56rem; border-radius:999px; background:rgba(var(--text-faint-rgb),0.62);"></span>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
const gripRight = `
|
|
||||||
<div data-swc-grip aria-hidden="true" style="position:absolute; right:0; top:50%; transform:translateY(-50%); width:0.76rem; height:1rem; pointer-events:none; opacity:0.66;">
|
|
||||||
<span style="position:absolute; right:0; top:50%; transform:translateY(-50%); width:1.5px; height:1.22rem; border-radius:999px; background:rgba(var(--text-faint-rgb),0.84);"></span>
|
|
||||||
<span style="position:absolute; right:0.16rem; top:50%; transform:translateY(-50%); width:1.5px; height:1.0rem; border-radius:999px; background:rgba(var(--text-faint-rgb),0.74);"></span>
|
|
||||||
<span style="position:absolute; right:0.34rem; top:50%; transform:translateY(-50%); width:1.5px; height:0.56rem; border-radius:999px; background:rgba(var(--text-faint-rgb),0.62);"></span>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
return `
|
return `
|
||||||
<div class="pb-3 px-3 flex items-center justify-end gap-3">
|
<div class="pb-3 px-3 flex items-center justify-end gap-3">
|
||||||
@@ -79,25 +65,19 @@ export function createSwipePopoverCalendarHTML({
|
|||||||
<span id="${idPrefix}-month-label" class="h-full shrink-0 inline-flex min-w-[5.75rem] max-w-[9rem] items-center justify-center px-3 ${monthLabelTextClass}" style="color:rgb(var(--text-body-soft-rgb));"></span>
|
<span id="${idPrefix}-month-label" class="h-full shrink-0 inline-flex min-w-[5.75rem] max-w-[9rem] items-center justify-center px-3 ${monthLabelTextClass}" style="color:rgb(var(--text-body-soft-rgb));"></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="${idPrefix}-viewport" style="overflow:hidden; position:relative; touch-action:pan-y;">
|
<div id="${idPrefix}-viewport" style="overflow:hidden; position:relative; touch-action:pan-y; -webkit-user-select:none; user-select:none; cursor:grab;">
|
||||||
<div id="${idPrefix}-track" style="display:flex; align-items:flex-start; position:relative; will-change:transform;">
|
<div id="${idPrefix}-track" style="display:flex; align-items:flex-start; position:relative; will-change:transform;">
|
||||||
<div class="swc-panel" data-panel="prev" style="flex-shrink:0; pointer-events:none; position:relative; overflow:hidden;">
|
<div class="swc-panel" data-panel="prev" style="flex-shrink:0; pointer-events:none; position:relative; overflow:hidden;">
|
||||||
${weekdayHeader}
|
${weekdayHeader}
|
||||||
<div id="${idPrefix}-prev-grid" class="grid grid-cols-7 gap-1.5"></div>
|
<div id="${idPrefix}-prev-grid" class="grid grid-cols-7 gap-1.5"></div>
|
||||||
${gripLeft}
|
|
||||||
${gripRight}
|
|
||||||
</div>
|
</div>
|
||||||
<div class="swc-panel" data-panel="current" style="flex-shrink:0; position:relative; overflow:hidden;">
|
<div class="swc-panel" data-panel="current" style="flex-shrink:0; position:relative; overflow:hidden;">
|
||||||
${weekdayHeader}
|
${weekdayHeader}
|
||||||
<div id="${idPrefix}-grid" class="grid grid-cols-7 gap-1.5"></div>
|
<div id="${idPrefix}-grid" class="grid grid-cols-7 gap-1.5"></div>
|
||||||
${gripLeft}
|
|
||||||
${gripRight}
|
|
||||||
</div>
|
</div>
|
||||||
<div class="swc-panel" data-panel="next" style="flex-shrink:0; pointer-events:none; position:relative; overflow:hidden;">
|
<div class="swc-panel" data-panel="next" style="flex-shrink:0; pointer-events:none; position:relative; overflow:hidden;">
|
||||||
${weekdayHeader}
|
${weekdayHeader}
|
||||||
<div id="${idPrefix}-next-grid" class="grid grid-cols-7 gap-1.5"></div>
|
<div id="${idPrefix}-next-grid" class="grid grid-cols-7 gap-1.5"></div>
|
||||||
${gripLeft}
|
|
||||||
${gripRight}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -138,50 +118,37 @@ export function initSwipePopoverCalendar({
|
|||||||
const SWIPE_THRESHOLD = 40;
|
const SWIPE_THRESHOLD = 40;
|
||||||
const ANIMATION_MS = 260;
|
const ANIMATION_MS = 260;
|
||||||
|
|
||||||
let viewportWidth = 0;
|
|
||||||
let panelWidth = 0;
|
let panelWidth = 0;
|
||||||
let panelHandle = 0;
|
let panelInset = 0;
|
||||||
let dragHandleWidth = 0;
|
|
||||||
let restOffset = 0;
|
let restOffset = 0;
|
||||||
let animatingNav = false;
|
let animatingNav = false;
|
||||||
|
let pendingRangeStart = null;
|
||||||
|
let suppressClickUntil = 0;
|
||||||
|
|
||||||
const panels = Array.from(track.querySelectorAll('.swc-panel'));
|
const panels = Array.from(track.querySelectorAll('.swc-panel'));
|
||||||
|
|
||||||
const syncGripVisibility = (showAdjacent = false) => {
|
|
||||||
panels.forEach((panel) => {
|
|
||||||
const isCurrent = panel.dataset.panel === 'current';
|
|
||||||
panel.querySelectorAll('[data-swc-grip]').forEach((grip) => {
|
|
||||||
grip.style.opacity = (isCurrent || showAdjacent) ? '0.66' : '0';
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const applyLayout = () => {
|
const applyLayout = () => {
|
||||||
const vw = viewport.clientWidth || viewport.getBoundingClientRect().width;
|
const vw = viewport.clientWidth || viewport.getBoundingClientRect().width;
|
||||||
if (!vw) return;
|
if (!vw) return;
|
||||||
viewportWidth = vw;
|
const computedInset = panelHandlePx == null
|
||||||
const computedHandle = panelHandlePx == null
|
|
||||||
? Math.round(vw * panelHandleRatio)
|
? Math.round(vw * panelHandleRatio)
|
||||||
: panelHandlePx;
|
: panelHandlePx;
|
||||||
panelHandle = Math.max(panelHandleMin, Math.min(panelHandleMax, computedHandle));
|
panelInset = Math.max(panelHandleMin, Math.min(panelHandleMax, computedInset));
|
||||||
dragHandleWidth = panelHandle;
|
|
||||||
panelWidth = vw;
|
panelWidth = vw;
|
||||||
restOffset = -panelWidth;
|
restOffset = -panelWidth;
|
||||||
panels.forEach((panel) => {
|
panels.forEach((panel) => {
|
||||||
panel.style.width = `${panelWidth}px`;
|
panel.style.width = `${panelWidth}px`;
|
||||||
panel.style.boxSizing = 'border-box';
|
panel.style.boxSizing = 'border-box';
|
||||||
panel.style.paddingLeft = `${panelHandle}px`;
|
panel.style.paddingLeft = `${panelInset}px`;
|
||||||
panel.style.paddingRight = `${panelHandle}px`;
|
panel.style.paddingRight = `${panelInset}px`;
|
||||||
});
|
});
|
||||||
track.style.transition = 'none';
|
track.style.transition = 'none';
|
||||||
track.style.transform = `translate3d(${restOffset}px, 0, 0)`;
|
track.style.transform = `translate3d(${restOffset}px, 0, 0)`;
|
||||||
syncGripVisibility(false);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const resetTrackPosition = () => {
|
const resetTrackPosition = () => {
|
||||||
track.style.transition = 'none';
|
track.style.transition = 'none';
|
||||||
track.style.transform = `translate3d(${restOffset}px, 0, 0)`;
|
track.style.transform = `translate3d(${restOffset}px, 0, 0)`;
|
||||||
syncGripVisibility(false);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const setDragTranslate = (dx, ms) => {
|
const setDragTranslate = (dx, ms) => {
|
||||||
@@ -189,6 +156,10 @@ export function initSwipePopoverCalendar({
|
|||||||
track.style.transform = `translate3d(${restOffset + dx}px, 0, 0)`;
|
track.style.transform = `translate3d(${restOffset + dx}px, 0, 0)`;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const snapBack = () => {
|
||||||
|
setDragTranslate(0, ANIMATION_MS);
|
||||||
|
};
|
||||||
|
|
||||||
const getNavigationTarget = (monthDelta) => {
|
const getNavigationTarget = (monthDelta) => {
|
||||||
const anchor = normalizeMonth(getMonthAnchor());
|
const anchor = normalizeMonth(getMonthAnchor());
|
||||||
return startOfMonth(new Date(anchor.getFullYear(), anchor.getMonth() + monthDelta, 1));
|
return startOfMonth(new Date(anchor.getFullYear(), anchor.getMonth() + monthDelta, 1));
|
||||||
@@ -232,20 +203,22 @@ export function initSwipePopoverCalendar({
|
|||||||
let bg;
|
let bg;
|
||||||
let borderColor;
|
let borderColor;
|
||||||
let text;
|
let text;
|
||||||
let borderClass = 'border';
|
let shadow = 'none';
|
||||||
if (isSelected) {
|
let borderClass = 'border-0';
|
||||||
bg = theme.selectedBg;
|
if (dimmed) {
|
||||||
borderColor = theme.selectedBorder;
|
bg = theme.dimmedBg ?? DEFAULT_THEME.dimmedBg;
|
||||||
text = theme.selectedText;
|
|
||||||
} else if (dimmed) {
|
|
||||||
bg = theme.dimmedBg;
|
|
||||||
borderColor = 'transparent';
|
borderColor = 'transparent';
|
||||||
text = theme.dimText;
|
text = theme.dimText || DEFAULT_THEME.dimText;
|
||||||
borderClass = 'border-0';
|
|
||||||
} else {
|
} else {
|
||||||
bg = theme.bg;
|
bg = theme.bg || DEFAULT_THEME.bg;
|
||||||
borderColor = theme.border;
|
borderColor = theme.border || DEFAULT_THEME.border;
|
||||||
text = theme.text;
|
text = theme.text || DEFAULT_THEME.text;
|
||||||
|
}
|
||||||
|
if (isSelected) {
|
||||||
|
borderColor = theme.selectedBorder || DEFAULT_THEME.selectedBorder;
|
||||||
|
text = theme.selectedText || DEFAULT_THEME.selectedText;
|
||||||
|
shadow = theme.selectedShadow || DEFAULT_THEME.selectedShadow;
|
||||||
|
borderClass = 'border';
|
||||||
}
|
}
|
||||||
const opacity = dimmed && !isSelected ? String(theme.dimOpacity ?? 0.58) : '1';
|
const opacity = dimmed && !isSelected ? String(theme.dimOpacity ?? 0.58) : '1';
|
||||||
const dotColor = isSelected ? theme.selectedDot : theme.dot;
|
const dotColor = isSelected ? theme.selectedDot : theme.dot;
|
||||||
@@ -256,7 +229,7 @@ export function initSwipePopoverCalendar({
|
|||||||
return `
|
return `
|
||||||
<${tag} ${attrs}
|
<${tag} ${attrs}
|
||||||
class="mx-auto flex h-[2.05rem] w-full min-w-0 max-w-full items-center justify-center rounded-full ${borderClass}${dayClass} text-xs font-medium leading-tight overflow-hidden"
|
class="mx-auto flex h-[2.05rem] w-full min-w-0 max-w-full items-center justify-center rounded-full ${borderClass}${dayClass} text-xs font-medium leading-tight overflow-hidden"
|
||||||
style="background:${bg}; border-color:${borderColor}; color:${text}; opacity:${opacity}; touch-action:none;">
|
style="background:${bg}; border-color:${borderColor}; color:${text}; opacity:${opacity}; box-shadow:${shadow}; touch-action:pan-y;">
|
||||||
<span class="relative flex h-full w-full flex-col items-center justify-center">
|
<span class="relative flex h-full w-full flex-col items-center justify-center">
|
||||||
<span class="text-[13px] font-semibold leading-none ${showDot ? '-translate-y-[0.18rem]' : ''}">${day.getDate()}</span>
|
<span class="text-[13px] font-semibold leading-none ${showDot ? '-translate-y-[0.18rem]' : ''}">${day.getDate()}</span>
|
||||||
${showDot ? `<span class="absolute left-1/2 w-1 h-1 -translate-x-1/2 rounded-full opacity-75" style="bottom:0.24rem; background:${dotColor};" aria-hidden="true"></span>` : ''}
|
${showDot ? `<span class="absolute left-1/2 w-1 h-1 -translate-x-1/2 rounded-full opacity-75" style="bottom:0.24rem; background:${dotColor};" aria-hidden="true"></span>` : ''}
|
||||||
@@ -268,7 +241,8 @@ export function initSwipePopoverCalendar({
|
|||||||
|
|
||||||
const render = (previewSelection = null) => {
|
const render = (previewSelection = null) => {
|
||||||
const anchor = normalizeMonth(getMonthAnchor());
|
const anchor = normalizeMonth(getMonthAnchor());
|
||||||
const selectedSet = getSelectedSet(previewSelection);
|
const rangePreview = selectionMode === 'range' && pendingRangeStart ? [pendingRangeStart] : null;
|
||||||
|
const selectedSet = getSelectedSet(previewSelection ?? rangePreview);
|
||||||
if (monthLabelEl) monthLabelEl.textContent = monthLabel(anchor, monthsLong);
|
if (monthLabelEl) monthLabelEl.textContent = monthLabel(anchor, monthsLong);
|
||||||
renderMonthGrid(gridEl, anchor, selectedSet);
|
renderMonthGrid(gridEl, anchor, selectedSet);
|
||||||
renderMonthGrid(prevGridEl, new Date(anchor.getFullYear(), anchor.getMonth() - 1, 1), selectedSet);
|
renderMonthGrid(prevGridEl, new Date(anchor.getFullYear(), anchor.getMonth() - 1, 1), selectedSet);
|
||||||
@@ -278,8 +252,7 @@ export function initSwipePopoverCalendar({
|
|||||||
|
|
||||||
const commitNavigation = (monthDelta) => {
|
const commitNavigation = (monthDelta) => {
|
||||||
if (!canNavigate(monthDelta)) {
|
if (!canNavigate(monthDelta)) {
|
||||||
setDragTranslate(0, ANIMATION_MS);
|
snapBack();
|
||||||
setTimeout(() => syncGripVisibility(false), ANIMATION_MS + 20);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
animatingNav = true;
|
animatingNav = true;
|
||||||
@@ -294,49 +267,28 @@ export function initSwipePopoverCalendar({
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (selectionMode === 'range') {
|
if (selectionMode === 'range') {
|
||||||
let dragStart = null;
|
gridEl.addEventListener('click', (e) => {
|
||||||
let dragCurrent = null;
|
|
||||||
let dragging = false;
|
|
||||||
gridEl.addEventListener('pointerdown', (e) => {
|
|
||||||
if (animatingNav) return;
|
|
||||||
const btn = e.target.closest('.swc-day');
|
const btn = e.target.closest('.swc-day');
|
||||||
if (!btn) return;
|
if (!btn) return;
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
dragStart = btn.dataset.dk;
|
const selectedKey = btn.dataset.dk;
|
||||||
dragCurrent = btn.dataset.dk;
|
if (!pendingRangeStart) {
|
||||||
dragging = true;
|
pendingRangeStart = selectedKey;
|
||||||
gridEl.setPointerCapture(e.pointerId);
|
if (typeof onSelectionCommit === 'function') onSelectionCommit([selectedKey]);
|
||||||
render([dragStart]);
|
render([selectedKey]);
|
||||||
});
|
return;
|
||||||
gridEl.addEventListener('pointermove', (e) => {
|
|
||||||
if (!dragging || animatingNav) return;
|
|
||||||
e.preventDefault();
|
|
||||||
const el = document.elementFromPoint(e.clientX, e.clientY);
|
|
||||||
const btn = el?.closest('.swc-day');
|
|
||||||
if (btn?.dataset.dk && btn.dataset.dk !== dragCurrent) {
|
|
||||||
dragCurrent = btn.dataset.dk;
|
|
||||||
render(dayRange(dragStart, dragCurrent));
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
gridEl.addEventListener('pointerup', () => {
|
const range = dayRange(pendingRangeStart, selectedKey);
|
||||||
if (!dragging) return;
|
pendingRangeStart = null;
|
||||||
dragging = false;
|
|
||||||
const range = dayRange(dragStart, dragCurrent);
|
|
||||||
dragStart = null;
|
|
||||||
dragCurrent = null;
|
|
||||||
if (typeof onSelectionCommit === 'function') onSelectionCommit(range);
|
if (typeof onSelectionCommit === 'function') onSelectionCommit(range);
|
||||||
render();
|
render();
|
||||||
});
|
});
|
||||||
gridEl.addEventListener('pointercancel', () => {
|
|
||||||
dragging = false;
|
|
||||||
dragStart = null;
|
|
||||||
dragCurrent = null;
|
|
||||||
render();
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
gridEl.addEventListener('click', (e) => {
|
gridEl.addEventListener('click', (e) => {
|
||||||
const btn = e.target.closest('.swc-day');
|
const btn = e.target.closest('.swc-day');
|
||||||
if (!btn) return;
|
if (!btn) return;
|
||||||
|
e.stopPropagation();
|
||||||
if (typeof onSelectionCommit === 'function') onSelectionCommit(btn.dataset.dk);
|
if (typeof onSelectionCommit === 'function') onSelectionCommit(btn.dataset.dk);
|
||||||
render();
|
render();
|
||||||
});
|
});
|
||||||
@@ -347,22 +299,18 @@ export function initSwipePopoverCalendar({
|
|||||||
let startY = 0;
|
let startY = 0;
|
||||||
let moved = false;
|
let moved = false;
|
||||||
let axis = null;
|
let axis = null;
|
||||||
|
let hasPointerCapture = false;
|
||||||
|
|
||||||
viewport.addEventListener('pointerdown', (e) => {
|
viewport.addEventListener('pointerdown', (e) => {
|
||||||
if (animatingNav || ptrId !== null) return;
|
if (animatingNav || ptrId !== null) return;
|
||||||
if (e.pointerType === 'mouse' && e.button !== 0) return;
|
if (e.pointerType === 'mouse' && e.button !== 0) return;
|
||||||
if (!panelWidth) applyLayout();
|
if (!panelWidth) applyLayout();
|
||||||
const rect = viewport.getBoundingClientRect();
|
|
||||||
const localX = e.clientX - rect.left;
|
|
||||||
const inLeft = localX <= dragHandleWidth;
|
|
||||||
const inRight = localX >= (viewportWidth - dragHandleWidth);
|
|
||||||
if (!inLeft && !inRight) return;
|
|
||||||
ptrId = e.pointerId;
|
ptrId = e.pointerId;
|
||||||
startX = e.clientX;
|
startX = e.clientX;
|
||||||
startY = e.clientY;
|
startY = e.clientY;
|
||||||
moved = false;
|
moved = false;
|
||||||
axis = null;
|
axis = null;
|
||||||
try { viewport.setPointerCapture(e.pointerId); } catch (_) {}
|
hasPointerCapture = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
viewport.addEventListener('pointermove', (e) => {
|
viewport.addEventListener('pointermove', (e) => {
|
||||||
@@ -372,29 +320,52 @@ export function initSwipePopoverCalendar({
|
|||||||
if (!moved && (Math.abs(dx) > MOVE_THRESHOLD || Math.abs(dy) > MOVE_THRESHOLD)) {
|
if (!moved && (Math.abs(dx) > MOVE_THRESHOLD || Math.abs(dy) > MOVE_THRESHOLD)) {
|
||||||
moved = true;
|
moved = true;
|
||||||
axis = Math.abs(dx) >= Math.abs(dy) ? 'x' : 'y';
|
axis = Math.abs(dx) >= Math.abs(dy) ? 'x' : 'y';
|
||||||
if (axis === 'x') syncGripVisibility(true);
|
|
||||||
}
|
}
|
||||||
if (axis === 'x') setDragTranslate(getAllowedDragDx(dx), 0);
|
if (axis === 'x') {
|
||||||
|
e.preventDefault();
|
||||||
|
suppressClickUntil = Date.now() + 450;
|
||||||
|
if (!hasPointerCapture) {
|
||||||
|
try {
|
||||||
|
viewport.setPointerCapture(e.pointerId);
|
||||||
|
hasPointerCapture = true;
|
||||||
|
} catch (_) {}
|
||||||
|
}
|
||||||
|
setDragTranslate(getAllowedDragDx(dx), 0);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const endGesture = (e) => {
|
const endGesture = (e) => {
|
||||||
if (e && e.pointerId !== ptrId) return;
|
if (e && e.pointerId !== ptrId) return;
|
||||||
|
if (e && hasPointerCapture) {
|
||||||
|
try { viewport.releasePointerCapture(e.pointerId); } catch (_) {}
|
||||||
|
}
|
||||||
|
hasPointerCapture = false;
|
||||||
ptrId = null;
|
ptrId = null;
|
||||||
if (!moved || axis !== 'x') return;
|
if (!moved || axis !== 'x') return;
|
||||||
const dx = e ? e.clientX - startX : 0;
|
const dx = e ? e.clientX - startX : 0;
|
||||||
const monthDelta = dx > 0 ? -1 : 1;
|
const monthDelta = dx > 0 ? -1 : 1;
|
||||||
if (Math.abs(dx) >= SWIPE_THRESHOLD && canNavigate(monthDelta)) commitNavigation(monthDelta);
|
if (Math.abs(dx) >= SWIPE_THRESHOLD && canNavigate(monthDelta)) commitNavigation(monthDelta);
|
||||||
else {
|
else {
|
||||||
setDragTranslate(0, ANIMATION_MS);
|
snapBack();
|
||||||
setTimeout(() => syncGripVisibility(false), ANIMATION_MS + 20);
|
|
||||||
}
|
}
|
||||||
moved = false;
|
moved = false;
|
||||||
axis = null;
|
axis = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
viewport.addEventListener('pointerup', endGesture);
|
viewport.addEventListener('click', (e) => {
|
||||||
viewport.addEventListener('pointercancel', endGesture);
|
if (Date.now() > suppressClickUntil) return;
|
||||||
|
suppressClickUntil = 0;
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
}, true);
|
||||||
|
window.addEventListener('pointerup', endGesture);
|
||||||
|
window.addEventListener('pointercancel', endGesture);
|
||||||
window.addEventListener('resize', applyLayout);
|
window.addEventListener('resize', applyLayout);
|
||||||
|
|
||||||
return { render, reapplyLayout: applyLayout, resetTrackPosition };
|
const clearPendingRange = () => {
|
||||||
|
pendingRangeStart = null;
|
||||||
|
render();
|
||||||
|
};
|
||||||
|
|
||||||
|
return { render, reapplyLayout: applyLayout, resetTrackPosition, clearPendingRange };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,10 +86,10 @@ const PANTRY_CALENDAR_THEME = {
|
|||||||
dimmedBg: 'transparent',
|
dimmedBg: 'transparent',
|
||||||
dimmedBorder: 'transparent',
|
dimmedBorder: 'transparent',
|
||||||
dot: 'rgb(var(--text-faint-rgb))',
|
dot: 'rgb(var(--text-faint-rgb))',
|
||||||
selectedBg: 'rgb(var(--card-rgb))',
|
selectedBorder: 'rgba(var(--text-emphasis-rgb),0.34)',
|
||||||
selectedBorder: 'rgb(var(--border-input-rgb))',
|
|
||||||
selectedText: 'rgb(var(--text-emphasis-rgb))',
|
selectedText: 'rgb(var(--text-emphasis-rgb))',
|
||||||
selectedDot: 'rgb(var(--text-emphasis-rgb))',
|
selectedDot: 'rgb(var(--text-emphasis-rgb))',
|
||||||
|
selectedShadow: '0 0 0 1px rgba(var(--text-emphasis-rgb),0.10)',
|
||||||
};
|
};
|
||||||
|
|
||||||
/* ── state ── */
|
/* ── state ── */
|
||||||
|
|||||||
@@ -188,12 +188,12 @@ function initShoppingCalendar() {
|
|||||||
showDot: dateKey(day) === todayKey() && !isSelected,
|
showDot: dateKey(day) === todayKey() && !isSelected,
|
||||||
}),
|
}),
|
||||||
theme: {
|
theme: {
|
||||||
selectedBg: 'rgb(var(--card-rgb))',
|
selectedBorder: 'rgba(var(--text-emphasis-rgb),0.34)',
|
||||||
selectedBorder: 'rgb(var(--border-input-rgb))',
|
|
||||||
selectedText: 'rgb(var(--text-emphasis-rgb))',
|
selectedText: 'rgb(var(--text-emphasis-rgb))',
|
||||||
selectedDot: 'rgb(var(--text-emphasis-rgb))',
|
selectedDot: 'rgb(var(--text-emphasis-rgb))',
|
||||||
|
selectedShadow: '0 0 0 1px rgba(var(--text-emphasis-rgb),0.10)',
|
||||||
bg: 'rgb(var(--app-bg-rgb))',
|
bg: 'rgb(var(--app-bg-rgb))',
|
||||||
border: 'rgb(var(--card-raised-rgb))',
|
border: 'transparent',
|
||||||
text: 'rgb(var(--text-body-soft-rgb))',
|
text: 'rgb(var(--text-body-soft-rgb))',
|
||||||
dimmedBg: 'transparent',
|
dimmedBg: 'transparent',
|
||||||
dimText: CALENDAR_DIM_TEXT,
|
dimText: CALENDAR_DIM_TEXT,
|
||||||
@@ -268,6 +268,7 @@ function closeCalendar() {
|
|||||||
pill.style.background = 'rgb(var(--card-rgb))';
|
pill.style.background = 'rgb(var(--card-rgb))';
|
||||||
pill.style.borderColor = 'rgb(var(--border-card-rgb))';
|
pill.style.borderColor = 'rgb(var(--border-card-rgb))';
|
||||||
}
|
}
|
||||||
|
shoppingCalendar?.clearPendingRange?.();
|
||||||
shoppingCalendar?.resetTrackPosition();
|
shoppingCalendar?.resetTrackPosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user