mirror of
https://github.com/afoim/fuwari.git
synced 2026-01-31 00:53:19 +08:00
feat(侧边栏): 替换待办事项和时光卡片为灵感组件
添加新的灵感组件并移除旧的待办事项和时光卡片功能 更新图标库配置以支持Material Symbols Light 删除不再使用的待办事项相关类型和文件
This commit is contained in:
@@ -72,6 +72,8 @@ export default defineConfig({
|
||||
"fa6-regular": ["*"],
|
||||
"fa6-solid": ["*"],
|
||||
"simple-icons": ["*"],
|
||||
"material-symbols-light": ["*"],
|
||||
"material-symbols": ["*"],
|
||||
},
|
||||
}), svelte(), sitemap(),
|
||||
expressiveCode({
|
||||
|
||||
@@ -69,6 +69,7 @@
|
||||
"devDependencies": {
|
||||
"@astrojs/ts-plugin": "^1.10.4",
|
||||
"@biomejs/biome": "1.9.4",
|
||||
"@iconify-json/material-symbols-light": "^1.2.49",
|
||||
"@rollup/plugin-yaml": "^4.1.2",
|
||||
"@types/markdown-it": "^14.1.2",
|
||||
"@types/mdast": "^4.0.4",
|
||||
|
||||
10
pnpm-lock.yaml
generated
10
pnpm-lock.yaml
generated
@@ -170,6 +170,9 @@ importers:
|
||||
'@biomejs/biome':
|
||||
specifier: 1.9.4
|
||||
version: 1.9.4
|
||||
'@iconify-json/material-symbols-light':
|
||||
specifier: ^1.2.49
|
||||
version: 1.2.49
|
||||
'@rollup/plugin-yaml':
|
||||
specifier: ^4.1.2
|
||||
version: 4.1.2(rollup@2.79.2)
|
||||
@@ -1136,6 +1139,9 @@ packages:
|
||||
'@iconify-json/fa6-solid@1.2.3':
|
||||
resolution: {integrity: sha512-C5o8YJF+ekrS4wRb/6/0SE2KjRyJlCg++IOVC/fineiRinITivsmzFRNW1MQX2xfDZ1T7bxeKxLN6lcaTG3jGA==}
|
||||
|
||||
'@iconify-json/material-symbols-light@1.2.49':
|
||||
resolution: {integrity: sha512-EpKeZ9NifWfU0mfxC7eULjuVtbRdbgg0cNDOlJZucKulC4bTvCcmlNtK5wqsyRICKi4xcfHlSTsmBMiFjF7GOQ==}
|
||||
|
||||
'@iconify-json/material-symbols@1.2.20':
|
||||
resolution: {integrity: sha512-+KqOT+3fD+LC2FbWiV8gd4+JLMiVUtmqrjzpKN1ji7rfMQTwvYJ94RT0WQlmL+vfDNJ5MTRe3rBzzJyvIH/aSg==}
|
||||
|
||||
@@ -6587,6 +6593,10 @@ snapshots:
|
||||
dependencies:
|
||||
'@iconify/types': 2.0.0
|
||||
|
||||
'@iconify-json/material-symbols-light@1.2.49':
|
||||
dependencies:
|
||||
'@iconify/types': 2.0.0
|
||||
|
||||
'@iconify-json/material-symbols@1.2.20':
|
||||
dependencies:
|
||||
'@iconify/types': 2.0.0
|
||||
|
||||
33
src/components/widget/Inspiration.astro
Normal file
33
src/components/widget/Inspiration.astro
Normal file
@@ -0,0 +1,33 @@
|
||||
---
|
||||
import WidgetLayout from "./WidgetLayout.astro";
|
||||
import { Icon } from "astro-icon/components";
|
||||
import inspirationContent from "@/data/inspiration.txt?raw";
|
||||
|
||||
const items = inspirationContent.split('\n').filter(line => line.trim() !== '');
|
||||
|
||||
interface Props {
|
||||
class?: string;
|
||||
style?: string;
|
||||
}
|
||||
const className = Astro.props.class;
|
||||
const style = Astro.props.style;
|
||||
---
|
||||
|
||||
{items.length > 0 && (
|
||||
<WidgetLayout name="灵感一刻" id="inspiration-list" class={className} style={style}>
|
||||
<div class="flex flex-col gap-2">
|
||||
{items.map((item, index) => (
|
||||
<div class="flex items-start gap-2 text-sm text-neutral-700 dark:text-neutral-300">
|
||||
<span class="font-bold text-[var(--primary)] flex-shrink-0 select-none w-5 text-right">{index + 1}.</span>
|
||||
<span class="leading-5">{item}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div class="mt-4 flex justify-center">
|
||||
<a href="https://github.com/afoim/fuwari/blob/main/src/data/inspiration.txt" target="_blank" rel="noopener noreferrer" class="btn-plain rounded-lg h-9 px-4 flex items-center gap-2 text-[var(--primary)] text-sm">
|
||||
<Icon name="material-symbols:edit-square-outline" class="text-lg" />
|
||||
记录新灵感
|
||||
</a>
|
||||
</div>
|
||||
</WidgetLayout>
|
||||
)}
|
||||
@@ -4,8 +4,7 @@ import type { MarkdownHeading } from "astro";
|
||||
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";
|
||||
import Inspiration from "./Inspiration.astro";
|
||||
|
||||
interface Props {
|
||||
class?: string;
|
||||
@@ -21,9 +20,8 @@ const className = Astro.props.class;
|
||||
<div id="sidebar-sticky" class="transition-all duration-700 flex flex-col w-full gap-4 top-4 sticky top-4">
|
||||
<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>
|
||||
<!-- 赞助标 -->
|
||||
<Inspiration class="onload-animation" style="animation-delay: 250ms"></Inspiration>
|
||||
<!-- 赞助标 -->
|
||||
<div class="overflow-hidden flex justify-center">
|
||||
<a href="https://secbit.ai/" target="_blank" rel="noopener noreferrer">
|
||||
<img src="/aff/secbit-banner-1.gif" alt="Secbit" class="w-full max-w-[280px] rounded-lg hover:opacity-90 transition-opacity" />
|
||||
|
||||
@@ -1,169 +0,0 @@
|
||||
---
|
||||
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-4 p-1">
|
||||
<div id="current-date-text" class="text-center text-xs font-bold text-neutral-700 dark:text-neutral-300 tabular-nums tracking-wide">
|
||||
加载中...
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-3 gap-3">
|
||||
<div class="relative aspect-square flex items-center justify-center group cursor-help" id="day-progress-container">
|
||||
<svg class="w-full h-full -rotate-90 transform" viewBox="0 0 100 100">
|
||||
<circle cx="50" cy="50" r="45" stroke="currentColor" stroke-width="8" fill="transparent" class="text-black/5 dark:text-white/5" />
|
||||
<circle id="day-progress-circle" cx="50" cy="50" r="45" stroke="currentColor" stroke-width="8" fill="transparent" stroke-linecap="round" class="text-[var(--primary)] transition-all duration-75 ease-linear" stroke-dasharray="282.743" stroke-dashoffset="282.743" />
|
||||
</svg>
|
||||
<div class="absolute inset-0 flex items-center justify-center flex-col">
|
||||
<span id="day-progress-text" class="text-sm font-bold text-neutral-600 dark:text-neutral-400 tabular-nums">0时</span>
|
||||
<span class="text-[0.6rem] text-neutral-400 dark:text-neutral-500 scale-90 origin-center font-medium">今日</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="relative aspect-square flex items-center justify-center group cursor-help" id="week-progress-container">
|
||||
<svg class="w-full h-full -rotate-90 transform" viewBox="0 0 100 100">
|
||||
<circle cx="50" cy="50" r="45" stroke="currentColor" stroke-width="8" fill="transparent" class="text-black/5 dark:text-white/5" />
|
||||
<circle id="week-progress-circle" cx="50" cy="50" r="45" stroke="currentColor" stroke-width="8" fill="transparent" stroke-linecap="round" class="text-[var(--primary)] transition-all duration-75 ease-linear" stroke-dasharray="282.743" stroke-dashoffset="282.743" />
|
||||
</svg>
|
||||
<div class="absolute inset-0 flex items-center justify-center flex-col">
|
||||
<span id="week-progress-text" class="text-sm font-bold text-neutral-600 dark:text-neutral-400 tabular-nums">星期</span>
|
||||
<span class="text-[0.6rem] text-neutral-400 dark:text-neutral-500 scale-90 origin-center font-medium">本周</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="relative aspect-square flex items-center justify-center group cursor-help" id="month-progress-container">
|
||||
<svg class="w-full h-full -rotate-90 transform" viewBox="0 0 100 100">
|
||||
<circle cx="50" cy="50" r="45" stroke="currentColor" stroke-width="8" fill="transparent" class="text-black/5 dark:text-white/5" />
|
||||
<circle id="month-progress-circle" cx="50" cy="50" r="45" stroke="currentColor" stroke-width="8" fill="transparent" stroke-linecap="round" class="text-[var(--primary)] transition-all duration-75 ease-linear" stroke-dasharray="282.743" stroke-dashoffset="282.743" />
|
||||
</svg>
|
||||
<div class="absolute inset-0 flex items-center justify-center flex-col">
|
||||
<span id="month-progress-text" class="text-sm font-bold text-neutral-600 dark:text-neutral-400 tabular-nums">第0天</span>
|
||||
<span class="text-[0.6rem] text-neutral-400 dark:text-neutral-500 scale-90 origin-center font-medium">本月</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 gap-3">
|
||||
<div class="relative aspect-square flex items-center justify-center group cursor-help" id="year-progress-container">
|
||||
<svg class="w-full h-full -rotate-90 transform" viewBox="0 0 100 100">
|
||||
<circle cx="50" cy="50" r="45" stroke="currentColor" stroke-width="8" fill="transparent" class="text-black/5 dark:text-white/5" />
|
||||
<circle id="year-progress-circle" cx="50" cy="50" r="45" stroke="currentColor" stroke-width="8" fill="transparent" stroke-linecap="round" class="text-[var(--primary)] transition-all duration-75 ease-linear" stroke-dasharray="282.743" stroke-dashoffset="282.743" />
|
||||
</svg>
|
||||
<div class="absolute inset-0 flex items-center justify-center flex-col">
|
||||
<span id="year-progress-text" class="text-xl font-bold text-neutral-600 dark:text-neutral-400 tabular-nums">0月</span>
|
||||
<span class="text-xs text-neutral-400 dark:text-neutral-500 scale-90 origin-center font-medium">今年</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="relative aspect-square flex items-center justify-center group cursor-help" id="life-progress-container">
|
||||
<svg class="w-full h-full -rotate-90 transform" viewBox="0 0 100 100">
|
||||
<circle cx="50" cy="50" r="45" stroke="currentColor" stroke-width="8" fill="transparent" class="text-black/5 dark:text-white/5" />
|
||||
<circle id="life-progress-circle" cx="50" cy="50" r="45" stroke="currentColor" stroke-width="8" fill="transparent" stroke-linecap="round" class="text-[var(--primary)] transition-all duration-75 ease-linear" stroke-dasharray="282.743" stroke-dashoffset="282.743" />
|
||||
</svg>
|
||||
<div class="absolute inset-0 flex items-center justify-center flex-col">
|
||||
<span id="life-progress-text" class="text-xl font-bold text-neutral-600 dark:text-neutral-400 tabular-nums">0岁</span>
|
||||
<span class="text-xs text-neutral-400 dark:text-neutral-500 scale-90 origin-center font-medium">人生</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</WidgetLayout>
|
||||
|
||||
<script>
|
||||
function updateTimeCard() {
|
||||
const now = new Date();
|
||||
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 milliseconds = String(now.getMilliseconds()).padStart(3, '0').slice(0, 1);
|
||||
|
||||
// Update Header
|
||||
const dateText = document.getElementById('current-date-text');
|
||||
if (dateText) {
|
||||
dateText.textContent = `${year}年${month}月${day}日 星期${weekDay} ${hours}:${minutes}:${seconds}.${milliseconds}`;
|
||||
}
|
||||
|
||||
// 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 startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1);
|
||||
const nextMonth = new Date(now.getFullYear(), now.getMonth() + 1, 1);
|
||||
const daysInMonth = (nextMonth.getTime() - startOfMonth.getTime()) / (1000 * 60 * 60 * 24);
|
||||
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;
|
||||
|
||||
const birthDate = new Date('2007-09-20T00:00:00');
|
||||
const deathDate = new Date('2107-09-20T00:00:00'); // 100 years? User code said 80 years but logic was 2107-2007 = 100.
|
||||
// Re-checking previous code: 2007 to 2107 is 100 years. Previous comment said "80 years" but code used 2107. I'll stick to code.
|
||||
const lifeProgress = Math.max(0, Math.min(100, (now.getTime() - birthDate.getTime()) / (deathDate.getTime() - birthDate.getTime()) * 100));
|
||||
|
||||
// Update Rings
|
||||
const updateRing = (idPrefix: string, percent: number, textDisplay: string, tooltipText: string) => {
|
||||
const circle = document.getElementById(`${idPrefix}-circle`);
|
||||
const text = document.getElementById(`${idPrefix}-text`);
|
||||
const container = document.getElementById(`${idPrefix}-container`);
|
||||
|
||||
if (circle) {
|
||||
const r = 45;
|
||||
const c = 2 * Math.PI * r;
|
||||
const offset = c - (percent / 100) * c;
|
||||
circle.style.strokeDashoffset = String(offset);
|
||||
}
|
||||
if (text) {
|
||||
text.textContent = textDisplay;
|
||||
}
|
||||
if (container) {
|
||||
container.title = tooltipText;
|
||||
}
|
||||
};
|
||||
|
||||
// Day: Hours passed
|
||||
updateRing('day-progress', dayProgress, `${now.getHours()}时`, `今天已过去 ${dayProgress.toFixed(4)}%`);
|
||||
|
||||
// Week: Weekday
|
||||
const startOfWeek = new Date(now);
|
||||
const currentDay = now.getDay(); // 0 (Sun) - 6 (Sat)
|
||||
const diffToMonday = (currentDay + 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;
|
||||
|
||||
updateRing('week-progress', weekProgress, `星期${weekDay}`, `本周已过去 ${weekProgress.toFixed(4)}%`);
|
||||
|
||||
// Month: Days passed
|
||||
updateRing('month-progress', monthProgress, `第${now.getDate()}天`, `本月已过去 ${monthProgress.toFixed(4)}%`);
|
||||
|
||||
// Year: Months passed
|
||||
updateRing('year-progress', yearProgress, `${now.getMonth()}月`, `今年已过去 ${yearProgress.toFixed(4)}%`);
|
||||
|
||||
// Life: Years passed
|
||||
const age = now.getFullYear() - 2007; // Approximate
|
||||
updateRing('life-progress', lifeProgress, `${age}岁`, `人生已过去 ${lifeProgress.toFixed(5)}%`);
|
||||
}
|
||||
|
||||
updateTimeCard();
|
||||
setInterval(updateTimeCard, 50);
|
||||
|
||||
document.addEventListener('astro:page-load', () => {
|
||||
updateTimeCard();
|
||||
});
|
||||
</script>
|
||||
@@ -1,35 +0,0 @@
|
||||
---
|
||||
import { todoConfig } from "@/data/todo";
|
||||
import WidgetLayout from "./WidgetLayout.astro";
|
||||
import { Icon } from "astro-icon/components";
|
||||
|
||||
interface Props {
|
||||
class?: string;
|
||||
style?: string;
|
||||
}
|
||||
const className = Astro.props.class;
|
||||
const style = Astro.props.style;
|
||||
---
|
||||
|
||||
{todoConfig.enable && (
|
||||
<WidgetLayout name={todoConfig.title} id="todo-list" class={className} style={style}>
|
||||
<div class="flex flex-col gap-2">
|
||||
{todoConfig.items.map((item) => (
|
||||
<div class="flex items-center gap-2 text-sm text-neutral-700 dark:text-neutral-300">
|
||||
<Icon
|
||||
name={item.completed ? "material-symbols:check-box-outline" : "material-symbols:check-box-outline-blank"}
|
||||
class={`text-lg flex-shrink-0 ${item.completed ? "text-[var(--primary)]" : "text-neutral-400"}`}
|
||||
/>
|
||||
<span class={item.completed ? "line-through opacity-60" : ""}>{item.content}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div class="mt-4 flex justify-center">
|
||||
<a href="https://github.com/afoim/fuwari/tree/main/src/data/todo.ts" target="_blank" rel="noopener noreferrer" class="btn-plain rounded-lg h-9 px-4 flex items-center gap-2 text-[var(--primary)] text-sm">
|
||||
<Icon name="material-symbols:add-task-rounded" class="text-lg" />
|
||||
我要给你加工作!
|
||||
</a>
|
||||
</div>
|
||||
</WidgetLayout>
|
||||
)}
|
||||
|
||||
5
src/data/inspiration.txt
Normal file
5
src/data/inspiration.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
教你用OBS,AV1编码录制
|
||||
教你配置Cloudflare Turnstile
|
||||
博客开发日志
|
||||
OneDrive Index搭建,随时随地存取文件
|
||||
Rybbit网站统计搭建教程
|
||||
@@ -1,20 +0,0 @@
|
||||
import type { TodoConfig } from "@/types/config";
|
||||
|
||||
export const todoConfig: TodoConfig = {
|
||||
enable: true,
|
||||
title: "待办事项",
|
||||
items: [
|
||||
{ content: "为博客添加”待办事项“功能", completed: true },
|
||||
{ content: "做视频:利用STUN在世界各地连接上你的电脑", completed: true },
|
||||
{ content: "做视频:Ventoy+FirPE使用(可能不会做)", completed: false },
|
||||
{ content: "做视频:Cloudflare 利用Origin Rules 6转4 访问家里云", completed: true },
|
||||
{ content: "做视频:如何使用OBS优雅的录视频", completed: false },
|
||||
{ content: "写文章:Umami迁移记录", completed: true },
|
||||
{ content: "自建Umami并从云迁移到自建", completed: true },
|
||||
{ content: "更改文章底下的链接,用正则删去查询(?=xxx)", completed: true },
|
||||
{ content: "做视频:anuneko.com米哈游AI上手体验", completed: true },
|
||||
{ content: "完善Bot插件:anuneko.com米哈游AI聊天机器人(支持pick)", completed: true },
|
||||
{ content: "写文章:当anuneko bot插件完善后,编写开发文章", completed: true },
|
||||
{ content: "更新文章:Serverless,添加Render,Zeabur", completed: true },
|
||||
],
|
||||
};
|
||||
@@ -93,16 +93,7 @@ export type UmamiConfig = {
|
||||
timezone: string;
|
||||
};
|
||||
|
||||
export type TodoItem = {
|
||||
content: string;
|
||||
completed: boolean;
|
||||
};
|
||||
|
||||
export type TodoConfig = {
|
||||
enable: boolean;
|
||||
title: string;
|
||||
items: TodoItem[];
|
||||
};
|
||||
|
||||
export type LIGHT_DARK_MODE =
|
||||
| typeof LIGHT_MODE
|
||||
|
||||
Reference in New Issue
Block a user