feat(widget): 添加时光流逝卡片组件

添加新的侧边栏组件TimeCard,用于显示时间进度信息(日/周/月/年/人生)
同时更新todo列表添加相关视频计划项
This commit is contained in:
二叉树树
2025-12-04 08:33:04 +08:00
parent 67400575f1
commit 1a7f3aab92
3 changed files with 150 additions and 0 deletions

View File

@@ -5,6 +5,7 @@ import Profile from "./Profile.astro";
import Tag from "./Tags.astro";
import DomainSwitcher from "./DomainSwitcher.astro";
import Todo from "./Todo.astro";
import TimeCard from "./TimeCard.astro";
interface Props {
class?: string;
@@ -21,6 +22,7 @@ const className = Astro.props.class;
<DomainSwitcher class="onload-animation" style="animation-delay: 150ms"></DomainSwitcher>
<Tag class="onload-animation" style="animation-delay: 200ms"></Tag>
<Todo class="onload-animation" style="animation-delay: 250ms"></Todo>
<TimeCard class="onload-animation" style="animation-delay: 300ms"></TimeCard>
<!-- 赞助标 -->
<div class="overflow-hidden flex justify-center">
<a href="https://secbit.ai/" target="_blank" rel="noopener noreferrer">
@@ -38,3 +40,4 @@ const className = Astro.props.class;
</div>

View File

@@ -0,0 +1,146 @@
---
import WidgetLayout from "./WidgetLayout.astro";
interface Props {
class?: string;
style?: string;
}
const className = Astro.props.class;
const style = Astro.props.style;
---
<WidgetLayout name="时光流逝" id="time-card" class={className} style={style}>
<div class="flex flex-col gap-3 text-sm">
<div id="current-date-text" class="text-center font-bold text-neutral-700 dark:text-neutral-300 mb-1">
加载中...
</div>
<div class="flex flex-col gap-1">
<div class="flex justify-between items-center text-xs text-neutral-500">
<span>今天已过去</span>
<span id="day-progress-text">0.00000%</span>
</div>
<div class="w-full bg-neutral-200 dark:bg-neutral-700 rounded-full h-2.5 overflow-hidden">
<div id="day-progress-bar" class="h-2.5 rounded-full bg-blue-500 transition-all duration-500" style="width: 0%"></div>
</div>
</div>
<div class="flex flex-col gap-1">
<div class="flex justify-between items-center text-xs text-neutral-500">
<span>本周已过去</span>
<span id="week-progress-text">0.00000%</span>
</div>
<div class="w-full bg-neutral-200 dark:bg-neutral-700 rounded-full h-2.5 overflow-hidden">
<div id="week-progress-bar" class="h-2.5 rounded-full bg-green-500 transition-all duration-500" style="width: 0%"></div>
</div>
</div>
<div class="flex flex-col gap-1">
<div class="flex justify-between items-center text-xs text-neutral-500">
<span>本月已过去</span>
<span id="month-progress-text">0.00000%</span>
</div>
<div class="w-full bg-neutral-200 dark:bg-neutral-700 rounded-full h-2.5 overflow-hidden">
<div id="month-progress-bar" class="h-2.5 rounded-full bg-yellow-500 transition-all duration-500" style="width: 0%"></div>
</div>
</div>
<div class="flex flex-col gap-1">
<div class="flex justify-between items-center text-xs text-neutral-500">
<span>今年已过去</span>
<span id="year-progress-text">0.00000%</span>
</div>
<div class="w-full bg-neutral-200 dark:bg-neutral-700 rounded-full h-2.5 overflow-hidden">
<div id="year-progress-bar" class="h-2.5 rounded-full bg-red-500 transition-all duration-500" style="width: 0%"></div>
</div>
</div>
<div class="flex flex-col gap-1">
<div class="flex justify-between items-center text-xs text-neutral-500">
<span>站长人生已过去</span>
<span id="life-progress-text">0.00000%</span>
</div>
<div class="w-full bg-neutral-200 dark:bg-neutral-700 rounded-full h-2.5 overflow-hidden">
<div id="life-progress-bar" class="h-2.5 rounded-full bg-purple-500 transition-all duration-500" style="width: 0%"></div>
</div>
</div>
</div>
</WidgetLayout>
<script>
function updateTimeCard() {
const now = new Date();
// Update Date Text
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0');
const day = String(now.getDate()).padStart(2, '0');
const weekDays = ['日', '一', '二', '三', '四', '五', '六'];
const weekDay = weekDays[now.getDay()];
const hours = String(now.getHours()).padStart(2, '0');
const minutes = String(now.getMinutes()).padStart(2, '0');
const seconds = String(now.getSeconds()).padStart(2, '0');
const dateText = document.getElementById('current-date-text');
if (dateText) {
dateText.textContent = `今天是 ${year}年${month}月${day}日 星期${weekDay} ${hours}:${minutes}:${seconds}`;
}
// Calculations
const startOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate());
const endOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1);
const dayProgress = (now.getTime() - startOfDay.getTime()) / (endOfDay.getTime() - startOfDay.getTime()) * 100;
const currentDay = now.getDay() || 7; // 1-7 (Mon-Sun), making Sunday 7 for calculation if week starts on Monday, but let's stick to standard 0-6 or adjust based on locale. Let's assume week starts on Monday for "This week passed".
// Actually standard getDay() is 0 (Sun) to 6 (Sat).
// Let's assume Week starts on Monday.
const startOfWeek = new Date(now);
const dayOfWeek = now.getDay(); // 0 (Sun) - 6 (Sat)
const diffToMonday = (dayOfWeek + 6) % 7; // Mon=0, Tue=1, ..., Sun=6
startOfWeek.setDate(now.getDate() - diffToMonday);
startOfWeek.setHours(0, 0, 0, 0);
const endOfWeek = new Date(startOfWeek);
endOfWeek.setDate(startOfWeek.getDate() + 7);
const weekProgress = (now.getTime() - startOfWeek.getTime()) / (endOfWeek.getTime() - startOfWeek.getTime()) * 100;
const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1);
const endOfMonth = new Date(now.getFullYear(), now.getMonth() + 1, 0, 23, 59, 59, 999); // Last day of month
// Actually easiest is start of next month - start of this month
const nextMonth = new Date(now.getFullYear(), now.getMonth() + 1, 1);
const monthProgress = (now.getTime() - startOfMonth.getTime()) / (nextMonth.getTime() - startOfMonth.getTime()) * 100;
const startOfYear = new Date(now.getFullYear(), 0, 1);
const nextYear = new Date(now.getFullYear() + 1, 0, 1);
const yearProgress = (now.getTime() - startOfYear.getTime()) / (nextYear.getTime() - startOfYear.getTime()) * 100;
// Life Progress (Born: 2007-09-20, Expectancy: 80 years)
const birthDate = new Date('2007-09-20T00:00:00');
const deathDate = new Date('2107-09-20T00:00:00'); // 80 years
const lifeProgress = Math.max(0, Math.min(100, (now.getTime() - birthDate.getTime()) / (deathDate.getTime() - birthDate.getTime()) * 100));
// Update DOM
const updateBar = (idPrefix: string, value: number) => {
const textEl = document.getElementById(`${idPrefix}-text`);
const barEl = document.getElementById(`${idPrefix}-bar`);
if (textEl) textEl.textContent = `${value.toFixed(5)}%`;
if (barEl) barEl.style.width = `${value}%`;
};
updateBar('day-progress', dayProgress);
updateBar('week-progress', weekProgress);
updateBar('month-progress', monthProgress);
updateBar('year-progress', yearProgress);
updateBar('life-progress', lifeProgress);
}
// Initial call
updateTimeCard();
// Update every 50ms for smooth effect (or 1s if less precision is fine, but 5 decimal places imply high precision)
setInterval(updateTimeCard, 100);
// Handle view transitions if any
document.addEventListener('astro:page-load', () => {
updateTimeCard();
});
</script>

View File

@@ -9,6 +9,7 @@ export const todoConfig: TodoConfig = {
{ content: "做视频Ventoy+FirPE使用可能不会做", completed: false },
{ content: "做视频Cloudflare 利用Origin Rules 6转4 访问家里云", completed: false },
{ content: "做视频如何使用OBS优雅的录视频", completed: false },
{ content: "做视频:博客时光流逝卡片", completed: false },
{ content: "做视频anuneko.com米哈游AI上手体验", completed: true },
{ content: "完善Bot插件anuneko.com米哈游AI聊天机器人支持pick", completed: true },
{ content: "写文章当anuneko bot插件完善后编写开发文章", completed: true },