初始化

This commit is contained in:
李琦
2026-08-11 19:07:05 +08:00
commit d2aeb13a09
94 changed files with 8704 additions and 0 deletions

View File

@@ -0,0 +1,64 @@
<script setup>
import { computed, ref } from 'vue'
import { useI18n } from 'vue-i18n'
const props = defineProps({ days: { type: Array, default: () => [] }, selected: String })
const emit = defineEmits(['select'])
const { locale } = useI18n()
const hover = ref(null)
const weekMs = 7 * 24 * 60 * 60 * 1000
const matrix = computed(() => {
const end = new Date()
end.setHours(0, 0, 0, 0)
const start = new Date(end)
start.setDate(start.getDate() - 364)
start.setDate(start.getDate() - start.getDay())
const counts = new Map(props.days.map(x => [x.date, Number(x.count || 0)]))
const cells = []
for (let d = new Date(start); d <= end; d.setDate(d.getDate() + 1)) {
const date = d.toISOString().slice(0, 10)
const count = counts.get(date) || 0
cells.push({ date, count, week: Math.floor((d - start) / weekMs), dow: d.getDay(), level: Math.min(4, count === 0 ? 0 : count < 2 ? 1 : count < 5 ? 2 : count < 10 ? 3 : 4) })
}
const labels = []
let lastMonth = -1
for (let d = new Date(start); d <= end; d.setDate(d.getDate() + 7)) {
const m = d.getMonth()
if (m !== lastMonth) {
labels.push({ week: Math.floor((d - start) / weekMs), text: d.toLocaleString(locale.value === 'zh-CN' ? 'zh-CN' : 'en', { month: 'short' }) })
lastMonth = m
}
}
return { cells, labels, weeks: Math.max(53, ...cells.map(x => x.week + 1)) }
})
function pick(cell) {
if (!cell.date) return
emit('select', cell.date === props.selected ? '' : cell.date)
}
</script>
<template>
<div class="heat-grid-wrap" :style="{ '--weeks': matrix.weeks }">
<div class="heat-months">
<span v-for="m in matrix.labels" :key="m.week + m.text" :style="{ gridColumnStart: m.week + 1 }">{{ m.text }}</span>
</div>
<div class="heat-body">
<div class="heat-weekdays"><span>S</span><span>M</span><span>T</span><span>W</span><span>T</span><span>F</span><span>S</span></div>
<div class="heat-grid">
<button
v-for="cell in matrix.cells"
:key="cell.date"
class="heat-cell"
:class="['l' + cell.level, { selected: cell.date === props.selected }]"
:style="{ gridColumnStart: cell.week + 1, gridRowStart: cell.dow + 1 }"
@mouseenter="hover = cell"
@mouseleave="hover = null"
@click="pick(cell)"
/>
</div>
<div v-if="hover" class="heat-tooltip">{{ hover.date }} · {{ hover.count }} {{ locale === 'zh-CN' ? '次提交' : 'commits' }}</div>
</div>
</div>
</template>