feat: 月预览自定义悬停 tooltip, 月/周预览添加回到今日按钮

- MonthPreview: 用自定义 tooltip 替代原生 title 属性, 鼠标悬停事件
  即时显示详细信息 (标题/时间/地点/描述), 固定在右下角避免遮挡
- MonthPreview/WeekPreview: 工具栏新增回到今日按钮, 一键跳转回当天
- useCalendar: 新增 goToToday() action, 重置 previewDate 为今天
This commit is contained in:
zikai
2026-07-22 04:29:46 +00:00
parent 1c6ecf9d86
commit b49dbd46eb
3 changed files with 62 additions and 10 deletions

View File

@@ -1,5 +1,5 @@
<script setup>
import { computed } from 'vue'
import { ref, computed } from 'vue'
import { useCalendar } from '../composables/useCalendar.js'
import { expandOccurrences } from '../lib/recur.js'
import { eventColor } from '../lib/colors.js'
@@ -8,11 +8,14 @@ import {
} from '../lib/date.js'
import { DOW } from '../lib/weekday.js'
const { state, prevMonth, nextMonth } = useCalendar()
const { state, prevMonth, nextMonth, goToToday } = useCalendar()
// 表头: 周一~周日
const headers = DOW.slice(1).concat(DOW[0])
// 自定义 tooltip 状态
const hoverEvent = ref(null)
// 当前预览月的年月标签
const monthLabel = computed(function () {
const parts = parseISODate(startOfMonth(state.previewDate))
@@ -62,12 +65,12 @@ function colorStyle(uid) {
}
}
function tooltip(ev) {
const parts = [ev.summary || '(无标题)']
parts.push(ev.dtstartTime + ' - ' + ev.dtendTime)
if (ev.location) parts.push('地点: ' + ev.location)
if (ev.description) parts.push('描述: ' + ev.description)
return parts.join('\n')
function showTooltip(ev) {
hoverEvent.value = ev
}
function hideTooltip() {
hoverEvent.value = null
}
</script>
@@ -77,6 +80,7 @@ function tooltip(ev) {
<button class="nav-btn" @click="prevMonth">上个月</button>
<span class="month-label">{{ monthLabel }}</span>
<button class="nav-btn" @click="nextMonth">下个月</button>
<button class="nav-btn today-btn" @click="goToToday">回到今日</button>
</div>
<div class="month-grid">
<div v-for="h in headers" :key="h" class="grid-header">{{ h }}</div>
@@ -96,13 +100,21 @@ function tooltip(ev) {
:key="occ.event.uid + occ.date"
class="event-chip"
:style="colorStyle(occ.event.uid)"
:title="tooltip(occ.event)"
@mouseenter="showTooltip(occ.event)"
@mouseleave="hideTooltip"
>
{{ occ.event.summary || '(无标题)' }}
</div>
</div>
</div>
</div>
<!-- 自定义 tooltip -->
<div v-if="hoverEvent" class="event-tooltip" @mouseenter="showTooltip(hoverEvent)" @mouseleave="hideTooltip">
<div class="tooltip-title">{{ hoverEvent.summary || '(无标题)' }}</div>
<div class="tooltip-row">时间: {{ hoverEvent.dtstartTime }} - {{ hoverEvent.dtendTime }}</div>
<div v-if="hoverEvent.location" class="tooltip-row">地点: {{ hoverEvent.location }}</div>
<div v-if="hoverEvent.description" class="tooltip-desc">{{ hoverEvent.description }}</div>
</div>
</div>
</template>
@@ -112,6 +124,7 @@ function tooltip(ev) {
height: 100%;
display: flex;
flex-direction: column;
position: relative;
}
.preview-toolbar {
display: flex;
@@ -130,6 +143,8 @@ function tooltip(ev) {
color: #2c3e50;
}
.nav-btn:hover { background: #ecf0f1; }
.today-btn { border-color: #3498db; color: #3498db; font-weight: 600; }
.today-btn:hover { background: #eaf4fc; }
.month-label {
font-size: 16px;
font-weight: 600;
@@ -200,4 +215,33 @@ function tooltip(ev) {
text-overflow: ellipsis;
cursor: default;
}
.event-tooltip {
position: fixed;
bottom: 16px;
right: 16px;
max-width: 320px;
background: #fff;
border: 1px solid #d5dbdb;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
padding: 12px 16px;
z-index: 100;
font-size: 13px;
}
.tooltip-title {
font-size: 14px;
font-weight: 700;
color: #2c3e50;
margin-bottom: 6px;
}
.tooltip-row {
color: #34495e;
margin-bottom: 3px;
}
.tooltip-desc {
color: #7f8c8d;
margin-top: 6px;
white-space: pre-wrap;
word-break: break-all;
}
</style>

View File

@@ -8,7 +8,7 @@ import {
} from '../lib/date.js'
import { DOW } from '../lib/weekday.js'
const { state, prevWeek, nextWeek } = useCalendar()
const { state, prevWeek, nextWeek, goToToday } = useCalendar()
const HOUR_HEIGHT = 48 // 每小时像素高度
const headers = DOW.slice(1).concat(DOW[0]) // 周一..周日
@@ -113,6 +113,7 @@ function tooltip(ev) {
<button class="nav-btn" @click="prevWeek">上一周</button>
<span class="week-label">{{ weekLabel }}</span>
<button class="nav-btn" @click="nextWeek">下一周</button>
<button class="nav-btn today-btn" @click="goToToday">回到今日</button>
</div>
<div class="week-grid-wrapper">
<div class="week-grid">
@@ -177,6 +178,8 @@ function tooltip(ev) {
color: #2c3e50;
}
.nav-btn:hover { background: #ecf0f1; }
.today-btn { border-color: #3498db; color: #3498db; font-weight: 600; }
.today-btn:hover { background: #eaf4fc; }
.week-label {
font-size: 16px;
font-weight: 600;

View File

@@ -174,6 +174,10 @@ function nextWeek() {
state.previewDate = addDays(state.previewDate, 7)
}
function goToToday() {
state.previewDate = todayISO()
}
// ------------------------------------------------------------------ //
// 计算属性
// ------------------------------------------------------------------ //
@@ -211,5 +215,6 @@ export function useCalendar() {
nextMonth,
prevWeek,
nextWeek,
goToToday,
}
}