diff --git a/src/components/CalendarDay.vue b/src/components/CalendarDay.vue
index 4974cab..7032d6a 100644
--- a/src/components/CalendarDay.vue
+++ b/src/components/CalendarDay.vue
@@ -17,16 +17,7 @@ const formattedDate = computed(() => {
{{ formattedDate }}
@@ -43,10 +34,8 @@ const formattedDate = computed(() => {
position: relative;
user-select: none;
display: grid;
- /* Updated grid for centered day number */
grid-template-columns: 1fr;
grid-template-rows: 1fr auto;
- /* Named grid areas */
grid-template-areas:
'day-number'
'holiday-info';
@@ -89,6 +78,26 @@ const formattedDate = computed(() => {
z-index: 15;
pointer-events: none;
}
+
+/* Search highlight animation */
+.cell.search-highlight-flash::after {
+ content: '';
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ width: calc(100% + .2rem);
+ height: calc(100% + .2rem);
+ border-radius: 1rem;
+ background: transparent;
+ border: 0.3em solid var(--strong);
+ z-index: 16;
+ pointer-events: none;
+}
+
+.cell.search-highlight-flash::after { animation: search-highlight-flash 1.5s ease-out forwards; }
+
+@keyframes search-highlight-flash {0%{opacity:0;transform:translate(-50%,-50%) scale(.8);border-width:.1em}15%{opacity:1;transform:translate(-50%,-50%) scale(1.05);border-width:.4em}30%{opacity:1;transform:translate(-50%,-50%) scale(1);border-width:.3em}100%{opacity:0;transform:translate(-50%,-50%) scale(1);border-width:.3em}}
.cell.selected h1.day-number {
opacity: 0.3;
filter: brightness(1.2);
diff --git a/src/components/CalendarView.vue b/src/components/CalendarView.vue
index 9c1a168..bd88005 100644
--- a/src/components/CalendarView.vue
+++ b/src/components/CalendarView.vue
@@ -197,11 +197,24 @@ function measureFromProbe() {
const {
getWeekIndex,
getFirstDayForVirtualWeek,
- goToToday,
handleHeaderYearChange,
scrollToWeekCentered,
} = vwm
+function showDay(input) {
+ const dateStr = input instanceof Date ? toLocalString(input, DEFAULT_TZ) : String(input)
+ const weekIndex = getWeekIndex(fromLocalString(dateStr, DEFAULT_TZ))
+ scrollToWeekCentered(weekIndex, 'nav', true)
+ const diff = Math.abs(weekIndex - centerVisibleWeek.value)
+ const delay = Math.min(800, diff * 40)
+ setTimeout(() => {
+ const el = document.querySelector(`[data-date="${dateStr}"]`)
+ if (!el) return
+ el.classList.add('search-highlight-flash')
+ setTimeout(() => el.classList.remove('search-highlight-flash'), 1500)
+ }, delay)
+}
+
// Reference date for search: center of the current viewport (virtual week at vertical midpoint)
const centerVisibleWeek = computed(() => {
const midRow = (scrollTop.value + viewportHeight.value / 2) / rowHeight.value
@@ -457,26 +470,15 @@ const handleEventClick = (payload) => {
openEditEventDialog(payload)
}
-function scrollToEventStart(startDate, smooth = true) {
- try {
- const dateObj = fromLocalString(startDate, DEFAULT_TZ)
- const weekIndex = getWeekIndex(dateObj)
- scrollToWeekCentered(weekIndex, 'search-jump', smooth)
- } catch {
- /* noop */
+function handleHeaderSearchPreview(r) { if (r) showDay(r.startDate) }
+function handleHeaderSearchActivate(r) {
+ if (!r) return
+ showDay(r.startDate)
+ if (!r._goto && !r._holiday) {
+ const ev = calendarStore.getEventById(r.id)
+ if (ev) openEditEventDialog({ id: ev.id, event: ev })
}
}
-function handleHeaderSearchPreview(result) {
- if (!result) return
- scrollToEventStart(result.startDate, true)
-}
-function handleHeaderSearchActivate(result) {
- if (!result) return
- scrollToEventStart(result.startDate, true)
- // Open edit dialog for the event
- const ev = calendarStore.getEventById(result.id)
- if (ev) openEditEventDialog({ id: ev.id, event: ev })
-}
// Heuristic: rotate month label (180deg) only for predominantly Latin text.
// We explicitly avoid locale detection; rely solely on characters present.
@@ -543,7 +545,7 @@ window.addEventListener('resize', () => {
showDay(calendarStore.today)"
@search-preview="handleHeaderSearchPreview"
@search-activate="handleHeaderSearchActivate"
/>