mirror of
https://github.com/afoim/fuwari.git
synced 2026-01-31 09:03:18 +08:00
feat(widget): 添加时光流逝卡片组件
添加新的侧边栏组件TimeCard,用于显示时间进度信息(日/周/月/年/人生) 同时更新todo列表添加相关视频计划项
This commit is contained in:
@@ -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>
|
||||
|
||||
|
||||
|
||||
|
||||
146
src/components/widget/TimeCard.astro
Normal file
146
src/components/widget/TimeCard.astro
Normal 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>
|
||||
|
||||
@@ -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 },
|
||||
|
||||
Reference in New Issue
Block a user