├── .DS_Store
├── Bullet Journal模版文件分享.zip
├── Minimalism Challenge Calender
├── Minimalism Game Calendar.md
├── minimalism_items.md
├── 挑战日历使用说明.md
└── 极简挑战物品记录表及评分规则.md
├── README.md
├── bujo_calender_views V1.0.zip
└── bujo_calender_views V1.0
├── .DS_Store
├── calendar.css
├── markdown文件
├── .DS_Store
├── 周视图.md
├── 日视图.md
├── 月视图.md
└── 视图合集.md
├── 使用指南.md
├── 使用指南.pdf
├── 视图blue_dark_v1.0.png
├── 视图blue_light_v1.0.png
├── 视图green_dark_v1.0.png
└── 视图green_lignt_v1.0.png
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YuriWg/Obsidian_Templates/1cbeab148121cfbd320b2fdf08ae89b527e23e1f/.DS_Store
--------------------------------------------------------------------------------
/Bullet Journal模版文件分享.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YuriWg/Obsidian_Templates/1cbeab148121cfbd320b2fdf08ae89b527e23e1f/Bullet Journal模版文件分享.zip
--------------------------------------------------------------------------------
/Minimalism Challenge Calender/Minimalism Game Calendar.md:
--------------------------------------------------------------------------------
1 | ---
2 | created: 2025-03-01T22:09:00
3 | updated: 2025-03-19T10:35
4 | challenge_month: 3
5 | life_stage: 0.8
6 | ---
7 | ```dataviewjs
8 | // 在最外层添加背景容器
9 | const mainContainer = document.createElement('div');
10 | mainContainer.style.cssText = `
11 | background: linear-gradient(135deg, #f5f5f5 0%, #fafafa 100%);
12 | border-radius: 0px;
13 | padding: 40px;
14 | margin: 20px 0;
15 | `;
16 |
17 | // 生成30天极简主义游戏的日历
18 | const currentDate = new Date();
19 | const challengeMonth = this.challenge_month;
20 | const currentYear = currentDate.getFullYear();
21 |
22 | // 添加环形进度条SVG生成函数
23 | function generateProgressRing(score) {
24 | const radius = 15;
25 | const circumference = 2 * Math.PI * radius;
26 | const progress = (score / 100) * circumference;
27 | const dashOffset = circumference - progress;
28 |
29 | return `
30 | `;
52 | }
53 |
54 | // 添加处理方式映射
55 | const disposalMethods = {
56 | 0: { label: "立即处理", icon: "🗑️"},
57 | 20: { label: "推荐舍弃", icon: "📤"},
58 | 40: { label: "灵活处理", icon: "🔄"},
59 | 60: { label: "建议保留", icon: "📥"},
60 | 80: { label: "必须保留", icon: "📦"}
61 | };
62 |
63 | // 获取处理方式
64 | function getDisposalMethod(score) {
65 | const thresholds = Object.keys(disposalMethods)
66 | .map(Number)
67 | .sort((a, b) => b - a);
68 |
69 | for (const threshold of thresholds) {
70 | if (score >= threshold) {
71 | return disposalMethods[threshold];
72 | }
73 | }
74 | return disposalMethods[0];
75 | }
76 |
77 | try {
78 | // 1. 直接读取文件内容
79 | const filePath = '0_Bullet Journal/Monthly Challenge/2025 Mar 30天极简主义挑战/minimalism_items.md';
80 | const content = await dv.io.load(filePath);
81 |
82 | if (!content) {
83 | throw new Error('无法读取文件内容');
84 | }
85 |
86 | // 2. 定位JSON数据
87 | const startIndex = content.indexOf('[{');
88 | const endIndex = content.lastIndexOf('}]') + 2;
89 |
90 | if (startIndex === -1 || endIndex <= 1) {
91 | throw new Error('未找到有效的JSON数据');
92 | }
93 |
94 | const jsonString = content.slice(startIndex, endIndex);
95 | const rawData = JSON.parse(jsonString);
96 | const itemCategories = {
97 | "衣物": {color: "#B4846C", icon: "🧣", order: 1},
98 | "日用品": {color: "#A7B89D", icon: "🧴", order: 2},
99 | "食物": {color: "#E1A692", icon: "🍕", order: 3},
100 | "电子产品": {color: "#7895B2", icon: "📱", order: 4},
101 | "文具": {color: "#BBAB8C", icon: "✏️", order: 5},
102 | "书籍": {color: "#E5BA73", icon: "📖", order: 6},
103 | "装饰品": {color: "#C17C74", icon: "🎀", order: 7},
104 | "其它": {color: "#939B9F", icon: "🫙", order: 8},
105 | "default": {color: "#e8e8e8", icon: "📎", order: 9}
106 | };
107 |
108 |
109 | // 导出颜色映射
110 | const setcolors = Object.fromEntries(
111 | Object.entries(itemCategories).map(([key, value]) => [key, value.color])
112 | );
113 |
114 | // 导出图标映射
115 | const categoryIcons = Object.fromEntries(
116 | Object.entries(itemCategories).map(([key, value]) => [key, value.icon])
117 | );
118 |
119 | function getCategoryColor(category) {
120 | return itemCategories[category]?.color || itemCategories.default.color;
121 | }
122 |
123 | function getCategoryIcon(category) {
124 | return itemCategories[category]?.icon || itemCategories.default.icon;
125 | }
126 |
127 | function getSortedCategories() {
128 | return Object.entries(itemCategories)
129 | .sort((a, b) => a[1].order - b[1].order)
130 | .map(([key]) => key);
131 | }
132 |
133 | // 3. 从JSON数据中提取表格数据
134 | const tableData = rawData.map(row => ({
135 | date: row.日期.replace(/-/g, ''),
136 | item: row.物品,
137 | category: row.分类 || 'default',
138 | freq: Number(row['使用频率']) || 0,
139 | necessity: Number(row['必要性']) || 0,
140 | irreplace: Number(row['不可替代性']) || 0,
141 | space: Number(row['空间负担']) || 0,
142 | multifunction: Number(row['多功能性']) || 0,
143 | emotion: Number(row['情感价值']) || 0,
144 | maintenance: Number(row['维护费用']) || 0,
145 | cost: Number(row['获取成本']) || 0
146 | }));
147 |
148 | // 添加生活阶段系数的计算函数
149 | function getLifeStageMultiplier(stage) {
150 | const multipliers = {
151 | 1: 0.8,
152 | 2: 1.0,
153 | 3: 1.3
154 | };
155 | return multipliers[stage] || 1.0;
156 | }
157 |
158 | // 修改计算得分函数
159 | function calculateScore(item) {
160 | const scores = [
161 | item.freq,
162 | item.necessity,
163 | item.irreplace,
164 | item.space,
165 | item.multifunction,
166 | item.emotion,
167 | item.maintenance,
168 | item.cost
169 | ];
170 |
171 | const baseScore = scores.reduce((sum, score) => sum + score, 0);
172 | const lifeStageMultiplier = getLifeStageMultiplier(dv.current().life_stage);
173 | const finalScore = baseScore * lifeStageMultiplier;
174 |
175 | return Math.min(100, Math.max(0, finalScore));
176 | }
177 |
178 | // 添加月度统计面板
179 | const monthStats = tableData.reduce((stats, item) => {
180 | const score = calculateScore(item);
181 | stats.totalScore += score;
182 | stats.itemCount++;
183 | stats.categories[item.category] = (stats.categories[item.category] || 0) + 1;
184 | return stats;
185 | }, { totalScore: 0, itemCount: 0, categories: {} });
186 |
187 | // 修改统计面板的风格和内容
188 | const statsPanel = document.createElement('div');
189 | statsPanel.style.cssText = `
190 | display: flex;
191 | flex-direction: column;
192 | gap: 15px;
193 | margin: 20px 0;
194 | padding: 20px;
195 | `;
196 |
197 | // 更新统计面板的HTML结构
198 | statsPanel.innerHTML = `
199 |
206 |
212 |
221 | 📦
222 |
223 |
224 |
${monthStats.itemCount}
230 |
待处理物品
234 |
235 |
236 |
237 |
248 | ${Object.entries(monthStats.categories)
249 | .sort((a, b) => {
250 | const orderA = itemCategories[a[0]]?.order || 999;
251 | const orderB = itemCategories[b[0]]?.order || 999;
252 | return orderA - orderB;
253 | })
254 | .map(([category, count]) => `
255 |
267 |
${categoryIcons[category] || categoryIcons.default}
270 |
275 | ${category}
279 | ${count}
284 |
285 |
286 | `).join('')}
287 |
288 |
289 | `;
290 |
291 | // 修改得分指导说明部分
292 | const scoreGuide = document.createElement('div');
293 | scoreGuide.style.cssText = `
294 | position: relative;
295 | padding: 8px;
296 | border-radius: 12px;
297 | font-size: 0.9em;
298 | margin-bottom: -15px;
299 | `;
300 |
301 | // 更新得分指导的HTML结构
302 | scoreGuide.innerHTML = `
303 |
312 | ${[
313 | {score: '80-100', label: '必须保留', icon: "🗂️"},
314 | {score: '60-79', label: '建议保留', icon: "📥"},
315 | {score: '40-59', label: '灵活处理', icon: "🔄"},
316 | {score: '20-39', label: '推荐舍弃', icon: "📤"},
317 | {score: '0-19', label: '立即处理', icon: "🗑️"}
318 | ].map(item => `
319 |
327 |
333 | ${item.icon}
334 | ${item.score}
335 | ${item.label}
336 |
337 | `).join('')}
338 |
339 |
348 | `;
349 |
350 | statsPanel.appendChild(scoreGuide);
351 |
352 | // 生成表格布局
353 | let table = ``;
359 |
360 | const totalDays = 30;
361 |
362 | for (let day = 1; day <= totalDays; day++) {
363 | const dateStr = `2025${String(3).padStart(2,'0')}${String(day).padStart(2,'0')}`;
364 | const dayRecord = tableData.find(item => item.date === dateStr);
365 | const dayLabel = `Day ${day}`;
366 |
367 | let itemInfo = dayRecord ? `
368 |
378 |
${dayLabel}
388 |
${dayRecord.item}
399 |
411 |
${categoryIcons[dayRecord.category]}
417 |
426 | ${Math.round(calculateScore(dayRecord))}
430 | ${getDisposalMethod(calculateScore(dayRecord)).icon}
431 |
432 |
433 |
` : '';
434 |
435 | const content = dayRecord ? `
436 |
${itemInfo}` : `
447 |
${dayLabel}
`;
454 |
455 | table += `
456 |
${content}
`;
471 | }
472 | table += `
`;
473 |
474 | // 修改主容器的添加顺序
475 | mainContainer.innerHTML = `
476 | 30 Days
486 | Minimalism Game
496 | `;
497 |
498 | mainContainer.appendChild(statsPanel);
499 |
500 | const tableContainer = document.createElement('div');
501 | tableContainer.innerHTML = table;
502 | tableContainer.style.cssText = `
503 | width: 100%;
504 | //max-width: 1000px;
505 | margin: 30px 0px;
506 | padding: 0;
507 | `;
508 |
509 | mainContainer.appendChild(tableContainer);
510 | dv.container.appendChild(mainContainer);
511 |
512 | } catch (error) {
513 | console.error('数据处理错误:', error);
514 | dv.paragraph(`❌ 数据加载失败: ${error.message}`);
515 | }
516 | ```
--------------------------------------------------------------------------------
/Minimalism Challenge Calender/minimalism_items.md:
--------------------------------------------------------------------------------
1 | ---
2 | created: 2025-03-12T18:50
3 | updated: 2025-03-19T10:35
4 | life_stage: 1
5 | ---
6 |
7 | [{"日期":"2025-03-01","物品":"一个草莓熊支架","分类":"装饰品","使用频率":0,"必要性":8,"不可替代性":3,"空间负担":20,"多功能性":3,"情感价值":0,"维护费用":5,"获取成本":0},{"日期":"2025-03-02","物品":"一些明信片","分类":"文具","使用频率":0,"必要性":0,"不可替代性":3,"空间负担":20,"多功能性":0,"情感价值":5,"维护费用":5,"获取成本":0}]
--------------------------------------------------------------------------------
/Minimalism Challenge Calender/挑战日历使用说明.md:
--------------------------------------------------------------------------------
1 | ---
2 | created: 2025-03-19T10:42
3 | updated: 2025-03-19T11:00
4 | ---
5 |
6 | # 30天极简主义挑战日历使用说明
7 |
8 | ## 1. 前置条件
9 | - 确保已安装并启用Dataview插件,并开启dataviewJS相关功能
10 | 
11 |
12 | - 确保`minimalism_items.md`文件存在并包含有效的JSON数据,安装JSON table插件可一键实现markdown表格与JSON格式间的相互转换
13 |
14 | ## 2. 文件读取
15 | 当前文件读取路径设置如下:
16 | ```
17 | 0_Bullet Journal/
18 | └── Monthly Challenge/
19 | └── 2025 Mar 30天极简主义挑战/
20 | ├── Minimalism Game Calendar.md # 本日历文件
21 | └── minimalism_items.md # 物品数据文件
22 | ```
23 | 需根据自己的路径调整的,找到如图代码位置,将filePath改为自己的文件路径即可
24 | 
25 |
26 | ## 3. 必要属性设置
27 | 在日历文件的YAML frontmatter中设置:
28 | ```yaml
29 | challenge_month: 3 # 挑战月份(1-12)
30 | life_stage: 1 # 生活阶段(1-3,分别对应不同系数0.8;1.0;1.3)
31 | ```
32 |
33 | ## 4. 数据格式要求
34 | [[minimalism_items.md]] 文件需包含以下格式的JSON数据:
35 | ```json
36 | [
37 | {
38 | "日期": "2025-03-01",
39 | "物品": "旧T恤",
40 | "分类": "衣物",
41 | "使用频率": 20,
42 | "必要性": 30,
43 | "不可替代性": 10,
44 | "空间负担": 40,
45 | "多功能性": 5,
46 | "情感价值": 15,
47 | "维护费用": 5,
48 | "获取成本": 10
49 | },
50 | // ...更多物品数据
51 | ]
52 | ```
53 |
54 | ## 5. 评分规则
55 | _详细见文档:[[极简挑战物品记录表及评分规则.md]]_
56 | - 综合评分 = (各项评分之和) × 生活阶段系数
57 | - 评分范围:0-100分
58 | - 处理建议:
59 | - 80-100分:必须保留
60 | - 60-79分:建议保留
61 | - 40-59分:灵活处理
62 | - 20-39分:推荐舍弃
63 | - 0-19分:立即处理
64 |
--------------------------------------------------------------------------------
/Minimalism Challenge Calender/极简挑战物品记录表及评分规则.md:
--------------------------------------------------------------------------------
1 | ---
2 | tags:
3 | - type/note
4 | - theme/life/minimalism
5 | - theme/challenge
6 | aliases:
7 | lead: 一份用于记录和评估个人物品价值的极简主义挑战表格,帮助系统化地整理和优化个人物品。
8 | visual: "![[image.jpg]]"
9 | template_type: Note
10 | updated: 2025-03-19T10:33
11 | created: 2025-03-06T11:09
12 | ---
13 |
14 |
15 | > [!Summary]
16 | > `= this.lead`
17 |
18 | ## 物品记录表格
19 |
20 | | date | item | catogory | freq | necessity | irreplace | space | multifunction | emotion | maintenance | cost |
21 | | :--------: | :-------------------: | :------: | :--------------------------: | :---------------------------: | :----------------------------: | :-----------------------------: | :-------------------------: | :-----------------------------: | :--------------------------: | :----------------------------: |
22 | | | *权重* | | *25%* | *15%* | *10%* | *20%* | *5%* | *15%* | *5%* | *5%* |
23 | | | *评分标准*
*(100x权重)* | | *每天用:25
每周用:18
半年未用:0* | *生存必需:15
提升质量:8
可有可无:0* | *特殊定制:10
普通替代品:3
随处可买:0* | *小体积高效用:20
中等:10
大件低效用:0* | *三用以上:5
双用途:3
单一功能:0* | *重大回忆载体:15
普通纪念品:8
无意义:0* | *无需维护:5
定期保养:3
持续耗材:1* | *限量版/绝版:5
高价购入:3
平价易得:0* |
24 | | 2025-03-01 | 一个草莓熊支架 | 装饰品 | 0 | 8 | 3 | 10 | 3 | 0 | 5 | 0 |
25 | | 2025-03-02 | 一些明信片 | 文具 | 0 | 0 | 3 | 10 | 0 | 5 | 5 | 0 |
26 | | 2025-03-03 | | | | | | | | | | |
27 | | 2025-03-04 | | | | | | | | | | |
28 | | 2025-03-05 | | | | | | | | | | |
29 | | 2025-03-06 | | | | | | | | | | |
30 | | 2025-03-07 | | | | | | | | | | |
31 | | 2025-03-08 | | | | | | | | | | |
32 | | 2025-03-09 | | | | | | | | | | |
33 | | 2025-03-10 | | | | | | | | | | |
34 | | 2025-03-11 | | | | | | | | | | |
35 | | 2025-03-12 | | | | | | | | | | |
36 | | 2025-03-13 | | | | | | | | | | |
37 | | 2025-03-14 | | | | | | | | | | |
38 | | 2025-03-15 | | | | | | | | | | |
39 | | 2025-03-16 | | | | | | | | | | |
40 | | 2025-03-17 | | | | | | | | | | |
41 | | 2025-03-18 | | | | | | | | | | |
42 | | 2025-03-19 | | | | | | | | | | |
43 | | 2025-03-20 | | | | | | | | | | |
44 | | 2025-03-21 | | | | | | | | | | |
45 | | 2025-03-22 | | | | | | | | | | |
46 | | 2025-03-23 | | | | | | | | | | |
47 | | 2025-03-24 | | | | | | | | | | |
48 | | 2025-03-25 | | | | | | | | | | |
49 | | 2025-03-26 | | | | | | | | | | |
50 | | 2025-03-27 | | | | | | | | | | |
51 | | 2025-03-28 | | | | | | | | | | |
52 | | 2025-03-29 | | | | | | | | | | |
53 | | 2025-03-30 | | | | | | | | | | |
54 | | 2025-03-31 | | | | | | | | | | |
55 |
56 | ---
57 | #### 日常物品舍弃评分规则
58 | (总分 = 各维度得分 × 生活阶段系数)
59 |
60 | | 评分维度 | 评分项 | 权重 | 评分标准 | 示例物品得分 |
61 | | :-------: | :---: | :-: | :----------------------------: | :-----------------: |
62 | | **功能性价值** | 使用频率 | 25% | 每天用(25)\| 每周用(15)\| 半年未用(0) | 牙刷(10)\| 帐篷(2) |
63 | | | 核心必要性 | 15% | 生存必需(15)\| 提升质量(8)\| 可有可无(0) | 药品(15)\| 香薰机(8) |
64 | | | 不可替代性 | 10% | 特殊定制(10)\| 普通替代品(3)\| 随处可买(0) | 义齿(10)\| 玻璃杯(0) |
65 | | **空间效率** | 占用体积 | 20% | 小体积高效用(20)\| 中等(10)\| 大件低效用(0) | 折叠伞(20)\| 沙发(5) |
66 | | | 多功能性 | 5% | 三用以上(5)\| 双用途(3)\| 单一功能(0) | 瑞士军刀(5)\| 擀面杖(0) |
67 | | **情感价值** | 纪念意义 | 15% | 重大回忆载体(15)\| 普通纪念品(8)\| 无意义(0) | 结婚戒指(15)\| 旅游明信片(3) |
68 | | **经济成本** | 维护费用 | 5% | 无需维护(5)\| 定期保养(3)\| 持续耗材(1) | 铸铁锅(3)\| 空气净化器滤芯(1) |
69 | | | 获取成本 | 5% | 限量版/绝版(5)\| 高价购入(3)\| 平价易得(0) | 绝版书(5)\| 超市碗碟(0) |
70 |
71 | #### 动态调整规则
72 | 1. **生活阶段系数**
73 | - 搬家/换季:总分 × 0.8(强化精简)
74 | - 稳定居住:总分 × 1.0
75 | - 空间充裕:总分 × 1.3(允许保留)
76 |
77 | 2. **职业/爱好修正**
78 | - 厨师保留专业刀具 +15%
79 | - 摄影师保留相机设备 +20%
80 | - 普通职员办公用品 +5%
81 |
82 | #### 决策阈值
83 |
84 | | **总分范围** | **行动建议** | **执行策略** |
85 | | -------- | -------- | ------------- |
86 | | 80-100 | **必须保留** | 设置专用收纳区 |
87 | | 60-79 | **建议保留** | 6个月观察期,定期复评 |
88 | | 40-59 | **灵活处理** | 转赠/二手出售/暂存储物间 |
89 | | 20-39 | **推荐舍弃** | 拍照留念后处理 |
90 | | 0-19 | **立即处理** | 直接回收/捐赠 |
91 |
92 | #### **风险对冲设计**
93 | 1. **暂存机制**
94 | - 设置「犹豫箱」:暂存3个月后再最终决定
95 | - 重要文件/照片:数字化备份后处理实体
96 |
97 | 2. **后悔防护**
98 | - 建立「舍弃日志」:记录物品信息和处理方式
99 | - 高价物品:优先二手平台寄售而非直接丢弃
100 |
101 | #### **示例计算**
102 | **物品:** 冬季厚外套(稳定居住期,普通职员)
103 | - 功能性:8(每周用) + 10(保暖必需) + 0(可替代) = **18**
104 | - 空间效率:5(大体积) + 0(单一功能) = **5**
105 | - 情感价值:0(无纪念) = **0**
106 | - 经济成本:3(需干洗) + 0(平价) = **3**
107 | - **原始总分**:18+5+0+3 = **26**
108 | - **动态调整**:26 × 1.0(稳定期) = **26**
109 | - **决策**:推荐舍弃(拍照留念后捐赠)
110 |
111 | **物品:** 老式机械手表(父亲遗物,稳定期)
112 | - 功能性:2(半年未用) + 3(非必需) + 10(不可替代) = **15**
113 | - 空间效率:8(小体积) + 0(单一功能) = **8**
114 | - 情感价值:10(重大回忆) + 5(定制刻字) = **15**
115 | - 经济成本:5(无需维护) + 5(绝版) = **10**
116 | - **总分**:15+8+15+10 = **48** → 调整后48 → **灵活处理**
117 | - **最终决策**:保留并放入纪念品收藏柜
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ### 资料包说明
2 | #### 往期资料
3 | - 完整的Daily Log和Weekly Log: [Daily & Weekly Log模版](https://github.com/YuriWg/Obsidian_Templates/blob/main/Bullet%20Journal%E6%A8%A1%E7%89%88%E6%96%87%E4%BB%B6%E5%88%86%E4%BA%AB.zip)
4 | - 日、周、月打卡视图模版: [打卡小工具](https://github.com/YuriWg/Obsidian_Templates/tree/main/bujo_calender_views%20V1.0)
5 | #### 本次更新
6 | - 月度挑战日历模版: [30天极简主义挑战日历](https://github.com/YuriWg/Obsidian_Templates/tree/main/Minimalism%20Challenge%20Calender)
7 |
8 | 
9 |
--------------------------------------------------------------------------------
/bujo_calender_views V1.0.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YuriWg/Obsidian_Templates/1cbeab148121cfbd320b2fdf08ae89b527e23e1f/bujo_calender_views V1.0.zip
--------------------------------------------------------------------------------
/bujo_calender_views V1.0/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YuriWg/Obsidian_Templates/1cbeab148121cfbd320b2fdf08ae89b527e23e1f/bujo_calender_views V1.0/.DS_Store
--------------------------------------------------------------------------------
/bujo_calender_views V1.0/calendar.css:
--------------------------------------------------------------------------------
1 | /* 日历容器样式 */
2 | .calendar-container {
3 | background-color: hsla(var(--interactive-accent-hsl), 0.05);
4 | border-radius: 12px;
5 | padding: 1.2rem;
6 | text-align: left;
7 | color: var(--text-normal);
8 | box-shadow: 0 2px 8px rgba(0,0,0,0.05);
9 | }
10 |
11 | /* 周数标题 */
12 | .calendar-week-title {
13 | color: var(--interactive-accent);
14 | font-weight: 800;
15 | font-size: 1.5em;
16 | margin-bottom: 1rem;
17 | margin-top: 1rem;
18 | margin-left: 2rem;
19 | }
20 |
21 | /* 分割线 */
22 | .calendar-divider {
23 | height: 1px;
24 | background: hsla(var(--interactive-accent-hsl), .1);
25 | margin: 0px 20px;
26 | }
27 |
28 | /* 日历网格 */
29 | .calendar-grid {
30 | display: grid;
31 | grid-template-columns: repeat(7, minmax(0, 1fr));
32 | gap: 0.2em;
33 | padding: 0em 1em;
34 | }
35 |
36 | /* 星期标题 */
37 | .weekday-header {
38 | text-align: center;
39 | font-weight: bold;
40 | font-size: 15px;
41 | color: var(--interactive-accent);
42 | padding-top: 1em;
43 | }
44 |
45 | /* 日期单元格基础样式 */
46 | .date-cell {
47 | text-align: center;
48 | border-radius: 20px;
49 | font-size: 15px;
50 | display: flex;
51 | justify-content: center;
52 | align-items: center;
53 | color: var(--text-muted);
54 | margin-left: 0 0.2em;
55 | min-width: 2em;
56 | }
57 |
58 | /* 当前日期高亮 */
59 | .date-cell-current {
60 | background-color: var(--interactive-accent);
61 | color: white;
62 | font-weight: bold;
63 | padding: 0.5em 1em;
64 | margin: 1em 0.8em;
65 | }
66 |
67 | /* 有日记的日期样式 */
68 | .date-cell-has-note {
69 | background-color: hsla(var(--interactive-accent-hsl), 0.3);
70 | }
71 |
72 | /* 引用区块容器 */
73 | .quote-container {
74 | border-top: 1px solid hsla(var(--interactive-accent-hsl), 0.1);
75 | margin-top: 0.5em;
76 | padding-top: 2em;
77 | padding-bottom: 1.2em;
78 | font-size: 1em;
79 | color: var(--interactive-accent);
80 | position: relative;
81 | font-weight: bold;
82 | line-height: 2;
83 | margin-left: 20px;
84 | margin-right: 20px;
85 | }
86 |
87 | /* 引用图标 */
88 | .quote-icon {
89 | position: absolute;
90 | left: 0px;
91 | top: -5px;
92 | font-size: 24px;
93 | color: var(--interactive-accent);
94 | opacity: 1;
95 | }
96 |
97 | /* 周视图容器 */
98 | .week-view-container {
99 | display: flex;
100 | flex-direction: row;
101 | gap: 1rem;
102 | margin: 1em 0;
103 | }
104 |
105 | .week-view-container .calendar-grid {
106 | display: grid;
107 | grid-template-columns: repeat(7, 2.5em);
108 | gap: 0.5em;
109 | padding: 1.5em;
110 | margin: 0em 1em;
111 | justify-content: center;
112 | }
113 |
114 | .week-view-container .date-cell {
115 | width: 2.5em;
116 | height: 2.5em;
117 | display: flex;
118 | justify-content: center;
119 | align-items: center;
120 | border-radius: 50%;
121 | font-size: 0.9em;
122 | color: var(--text-normal);
123 | margin: 0;
124 | padding: 0;
125 | }
126 |
127 | .week-view-container .date-cell.date-cell-current {
128 | background-color: var(--interactive-accent);
129 | color: white !important;
130 | font-weight: bold;
131 | box-shadow: 0 2px 4px rgba(0,0,0,0.1);
132 | }
133 |
134 | .week-view-container .date-cell.date-cell-empty {
135 | background-color: hsla(var(--interactive-accent-hsl), 0.1);
136 | border: 1px solid var(--interactive-accent);
137 | color: var(--text-normal);
138 | }
139 |
140 | .week-view-container .date-cell.date-cell-other {
141 | color: var(--text-muted);
142 | opacity: 0.5;
143 | }
144 |
145 | .week-view-container .weekday-header {
146 | text-align: center;
147 | font-weight: bold;
148 | font-size: 15px;
149 | color: var(--interactive-accent);
150 | padding-top: 0em;
151 | padding-bottom: 1em;
152 | }
153 |
154 | /* 月历部分 */
155 | .month-calendar {
156 | flex: 1;
157 | background-color: hsla(var(--interactive-accent-hsl), 0.05);
158 | border-radius: 12px;
159 | padding: 1.2rem;
160 | box-shadow: 0 2px 8px rgba(0,0,0,0.05);
161 | }
162 |
163 | .month-calendar-title {
164 | color: var(--interactive-accent);
165 | font-weight: 800;
166 | font-size: 1.5em;
167 | margin-top: 1.5rem;
168 | margin-bottom: 0.8rem;
169 | text-align: center;
170 | }
171 |
172 | /* 习惯跟踪部分 */
173 | .habit-tracker {
174 | display: flex;
175 | background-color: hsla(var(--interactive-accent-hsl), 0.05);
176 | border-radius: 12px;
177 | padding: 1.2rem;
178 | height: 350px;
179 | box-shadow: 0 2px 8px rgba(0,0,0,0.05);
180 | flex: 2;
181 | overflow: hidden;
182 | }
183 |
184 | .habit-grid {
185 | display: grid;
186 | grid-template-columns: minmax(100px, 1fr) repeat(7, minmax(1.5rem, 1fr));
187 | gap: 4px;
188 | width: 100%;
189 | text-align: center;
190 | }
191 |
192 | .habit-day-name {
193 | font-weight: bold;
194 | color: var(--interactive-accent);
195 | font-size: 1.1em;
196 | padding: 4px 0;
197 | }
198 |
199 | .habit-name {
200 | text-align: left;
201 | padding: 4px 8px;
202 | font-weight: 500;
203 | }
204 |
205 | .habit-status {
206 | width: 1.5rem;
207 | height: 1.5rem;
208 | margin: 2px auto;
209 | display: flex;
210 | align-items: center;
211 | justify-content: center;
212 | border-radius: 50%;
213 | }
214 |
215 | .habit-status-done {
216 | background-color: var(--interactive-accent);
217 | box-shadow: 0 2px 6px rgba(var(--interactive-accent-rgb), 0.5);
218 | }
219 |
220 | .habit-status-empty {
221 | background-color: hsla(var(--interactive-accent-hsl), 0.1);
222 | border: 1.5px dotted hsla(var(--interactive-accent-hsl), 0.8);
223 | }
224 |
225 | .habit-status-mood {
226 | background-color: hsla(var(--interactive-accent-hsl), 0.1);
227 | border: 1.5px dotted hsla(var(--interactive-accent-hsl), 0.8);
228 | font-size: 1.5rem;
229 | color: var(--interactive-accent);
230 | }
231 |
232 | /* 月视图专用样式 */
233 | .month-view-container {
234 | display: flex;
235 | flex-direction: column;
236 | gap: 1rem;
237 | margin: 1em 0;
238 | }
239 |
240 | /* 年度概览部分 */
241 | .year-overview {
242 | background-color: hsla(var(--interactive-accent-hsl), 0.05);
243 | border-radius: 12px;
244 | padding: 2rem;
245 | margin-bottom: 0;
246 | box-shadow: 0 2px 8px rgba(0,0,0,0.05);
247 | }
248 |
249 | .year-title {
250 | color: var(--interactive-accent);
251 | font-weight: 800;
252 | font-size: 2em;
253 | margin-left: 0.5rem;
254 | margin-bottom: 1rem;
255 | }
256 |
257 | .year-subtitle {
258 | font-size: 0.5em;
259 | color: hsla(var(--interactive-accent-hsl), 1);
260 | }
261 |
262 | .months-container {
263 | display: flex;
264 | gap: 1rem;
265 | overflow-x: auto;
266 | padding: 0 2px 2px;
267 | scrollbar-width: thin;
268 | }
269 |
270 | .month-button {
271 | flex: 100%;
272 | height: 2rem;
273 | border-radius: 50px;
274 | display: flex;
275 | align-items: center;
276 | justify-content: center;
277 | margin-top: 1rem;
278 | font-weight: lighter;
279 | color: var(--text-muted);
280 | transition: all 0.2s ease;
281 | background: hsla(var(--interactive-accent-hsl), 0.05);
282 | border: 1px solid hsla(var(--interactive-accent-hsl), 0.5);
283 | font-size: 1rem;
284 | cursor: pointer;
285 | }
286 |
287 | .month-button.current {
288 | background: var(--interactive-accent);
289 | color: white;
290 | transform: scale(1);
291 | box-shadow: 0 4px 12px rgba(var(--interactive-accent-rgb), 0.3);
292 | }
293 |
294 | .month-button.has-note {
295 | background: hsla(var(--interactive-accent-hsl), 0.2);
296 | border-color: var(--interactive-accent);
297 | }
298 |
299 | /* 月度跟踪网格 */
300 | .month-tracker {
301 | display: grid;
302 | grid-template-columns: minmax(90px, 1fr) repeat(31, minmax(1.5rem, 1fr)) minmax(50px, 0.5fr);
303 | gap: 4px;
304 | width: 100%;
305 | max-width: 100%;
306 | text-align: center;
307 | padding: 20px;
308 | background-color: hsla(var(--interactive-accent-hsl), 0.05);
309 | border-radius: 5px;
310 | overflow-x: auto;
311 | scrollbar-width: thin;
312 | -webkit-overflow-scrolling: touch;
313 | }
314 |
--------------------------------------------------------------------------------
/bujo_calender_views V1.0/markdown文件/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YuriWg/Obsidian_Templates/1cbeab148121cfbd320b2fdf08ae89b527e23e1f/bujo_calender_views V1.0/markdown文件/.DS_Store
--------------------------------------------------------------------------------
/bujo_calender_views V1.0/markdown文件/周视图.md:
--------------------------------------------------------------------------------
1 | ---
2 | created: 2025-03-01T10:25:00
3 | updated: 2025-03-01T13:11
4 | cssclasses:
5 | - week-view
6 | - calendar-views
7 | ---
8 | ```dataviewjs
9 | // 日期相关函数
10 | function formatDate(date) {
11 | return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
12 | }
13 |
14 | function getWeekRange(baseDate) {
15 | const dayOfWeek = (baseDate.getDay() + 6) % 7;
16 | const startDate = new Date(baseDate);
17 | startDate.setDate(baseDate.getDate() - dayOfWeek);
18 | const endDate = new Date(startDate);
19 | endDate.setDate(startDate.getDate() + 6);
20 | return { startDate, endDate };
21 | }
22 |
23 | // 优化日期处理函数
24 | function getDateInfo(date) {
25 | return {
26 | year: date.getFullYear(),
27 | month: date.getMonth(),
28 | day: date.getDate(),
29 | weekday: (date.getDay() + 6) % 7
30 | };
31 | }
32 |
33 | // 简化页面查询逻辑
34 | function getPageForDate(dateStr) {
35 | return dv.pages('"0_Bullet Journal/Daily Notes"')
36 | .where(p => p.file.name.startsWith(dateStr))
37 | .first();
38 | }
39 |
40 | // 修改容器类名,使用共享样式
41 | let combinedHTML = '';
42 |
43 | try {
44 | const baseDate = dv.current().created ? new Date(dv.current().created) : new Date();
45 | const { startDate, endDate } = getWeekRange(baseDate);
46 | const currentYear = startDate.getFullYear();
47 | const currentMonth = startDate.getMonth();
48 | const currentWeek = Math.ceil((baseDate - new Date(baseDate.getFullYear(), 0, 1)) / (1000 * 60 * 60 * 24 * 7));
49 |
50 | // 生成月历HTML
51 | combinedHTML += `
52 |
53 |
54 | ${currentYear} ${["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"][currentMonth]} W${currentWeek}
55 |
56 |
57 | ${generateWeekGrid(startDate, endDate)}
58 |
59 |
60 | `;
61 |
62 | // 生成习惯跟踪器HTML
63 | combinedHTML += `
64 |
65 | ${generateHabitTracker(startDate, endDate)}
66 |
67 | `;
68 |
69 | } catch (e) {
70 | console.error("Error in week view:", e);
71 | combinedHTML += '
Error generating week view
';
72 | }
73 |
74 | combinedHTML += '
';
75 | dv.paragraph(combinedHTML);
76 |
77 | // 辅助函数
78 | function generateWeekGrid(startDate, endDate) {
79 | const dateInfo = getDateInfo(startDate);
80 | let gridHTML = '';
81 |
82 | // 添加星期标题
83 | ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"].forEach(day => {
84 | gridHTML += ``;
85 | });
86 |
87 | // 重置时间部分,只比较日期
88 | startDate.setHours(0, 0, 0, 0);
89 | endDate.setHours(0, 0, 0, 0);
90 |
91 | // 获取当前月的信息
92 | const currentYear = startDate.getFullYear();
93 | const currentMonth = startDate.getMonth();
94 | const firstDay = new Date(currentYear, currentMonth, 1);
95 | const lastDay = new Date(currentYear, currentMonth + 1, 0);
96 | const firstDayWeek = (firstDay.getDay() + 6) % 7;
97 | const prevMonthDays = new Date(currentYear, currentMonth, 0).getDate();
98 |
99 | // 添加上月末尾日期
100 | for (let i = 0; i < firstDayWeek; i++) {
101 | const date = new Date(currentYear, currentMonth - 1, prevMonthDays - firstDayWeek + i + 1);
102 | const isCurrentWeek = date >= startDate && date <= endDate;
103 |
104 | gridHTML += `
105 |
106 | ${prevMonthDays - firstDayWeek + i + 1}
107 |
`;
108 | }
109 |
110 | // 添加本月日期
111 | for (let i = 1; i <= lastDay.getDate(); i++) {
112 | const currentDate = new Date(currentYear, currentMonth, i);
113 | currentDate.setHours(0, 0, 0, 0);
114 | const dateStr = formatDate(currentDate);
115 | const weekDay = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'][currentDate.getDay()];
116 | // 修改:查找方式改为精确匹配日期前缀
117 | const pages = dv.pages()
118 | .where(p => p.file.name.startsWith(dateStr))
119 | .values;
120 | const page = pages.length > 0;
121 |
122 | const isCurrentWeek = currentDate >= startDate && currentDate <= endDate;
123 |
124 | gridHTML += `
125 |
126 | ${i}
127 |
`;
128 | }
129 |
130 | // 添加下月开始日期
131 | const lastDayWeek = (lastDay.getDay() + 6) % 7;
132 | for (let i = 1; i <= 6 - lastDayWeek; i++) {
133 | const nextDate = new Date(currentYear, currentMonth + 1, i);
134 | nextDate.setHours(0, 0, 0, 0);
135 | const dateStr = formatDate(nextDate);
136 | // 修改:对下月日期也使用相同的查找逻辑
137 | const pages = dv.pages()
138 | .where(p => p.file.name.startsWith(dateStr))
139 | .values;
140 | const page = pages.length > 0;
141 |
142 | const isCurrentWeek = nextDate >= startDate && nextDate <= endDate;
143 |
144 | gridHTML += `
145 |
146 | ${i}
147 |
`;
148 | }
149 |
150 | return gridHTML;
151 | }
152 |
153 | function generateHabitTracker(startDate, endDate) {
154 | const habits = ['🧘 拉伸', '📓 日记', '💻 笔记', '🏃 慢跑', '📖 阅读', '🤔 Stoic', '💢 心情'];
155 | const moodEmojiMap = {
156 | '-5': '😱', '-4': '😖', '-3': '😟', '-2': '😔', '-1': '😕',
157 | '0': '😐', '1': '🙂', '2': '😊', '3': '😄', '4': '🥰', '5': '😇'
158 | };
159 |
160 | let trackerHTML = `
161 |
162 |
163 | ${["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"].map(day =>
164 | `
${day}
`
165 | ).join('')}`;
166 |
167 | habits.forEach(habit => {
168 | trackerHTML += `
${habit}
`;
169 |
170 | for (let i = 0; i < 7; i++) {
171 | const currentDate = new Date(startDate);
172 | currentDate.setDate(startDate.getDate() + i);
173 | const dateStr = formatDate(currentDate);
174 | const page = getPageForDate(dateStr);
175 |
176 | const status = page ? {
177 | '🧘 拉伸': page.stretch || false,
178 | '📓 日记': page.journal || false,
179 | '💻 笔记': page.notes || false,
180 | '🏃 慢跑': page.running || false,
181 | '📖 阅读': page.reading || false,
182 | '🤔 Stoic': page.stoic || "",
183 | '💢 心情': page.mood ?? null
184 | }[habit] : null;
185 |
186 | const isMood = habit === '💢 心情';
187 |
188 | trackerHTML += `
189 |
190 |
194 | ${isMood ? (status !== null ? moodEmojiMap[status] : '') : (status ? '✓' : '')}
195 |
196 |
`;
197 | }
198 | });
199 |
200 | trackerHTML += '
';
201 | return trackerHTML;
202 | }
--------------------------------------------------------------------------------
/bujo_calender_views V1.0/markdown文件/日视图.md:
--------------------------------------------------------------------------------
1 | ---
2 | created: 2025-03-01T10:23
3 | updated: 2025-03-01T13:23
4 | cssclasses:
5 | - calendar-views
6 | ---
7 | ```dataviewjs
8 | // 获取当前页面的日期(支持文件名和created属性)
9 | const getPageDate = () => {
10 | // 尝试从文件名获取日期
11 | const fileName = dv.current().file.name.split(" ")[0];
12 | const dateMatch = fileName.match(/^\d{4}-\d{2}-\d{2}$/);
13 |
14 | if (dateMatch) {
15 | const [year, month, day] = fileName.split("-").map(Number);
16 | return new Date(year, month - 1, day);
17 | }
18 |
19 | // 如果文件名不是日期格式,使用created属性
20 | return new Date(dv.current().created);
21 | };
22 |
23 | const currentDate = getPageDate();
24 | const [year, month, day] = [
25 | currentDate.getFullYear(),
26 | currentDate.getMonth() + 1,
27 | currentDate.getDate()
28 | ];
29 |
30 | // 计算本周日期
31 | const currentDayOfWeek = (currentDate.getDay() + 6) % 7;
32 | const weekStart = new Date(currentDate);
33 | weekStart.setDate(currentDate.getDate() - currentDayOfWeek);
34 | const weekEnd = new Date(currentDate);
35 | weekEnd.setDate(currentDate.getDate() + (6 - currentDayOfWeek));
36 |
37 | // 修改日期格式化函数
38 | const formatDateStr = (date) => {
39 | const y = date.getFullYear();
40 | const m = String(date.getMonth() + 1).padStart(2, '0');
41 | const d = String(date.getDate()).padStart(2, '0');
42 | return `${y}-${m}-${d}`;
43 | };
44 |
45 | // 简化周数计算
46 | const getWeekInfo = (date) => {
47 | const firstDayOfYear = new Date(date.getFullYear(), 0, 1);
48 | const pastDaysOfYear = (date - firstDayOfYear) / 86400000;
49 | return {
50 | week: 2 + Math.floor((pastDaysOfYear + firstDayOfYear.getDay() + 1) / 7),
51 | year: date.getFullYear()
52 | };
53 | };
54 |
55 | // 获取 ISO 周数
56 | const getISOWeek = (date) => {
57 | const target = new Date(date.valueOf());
58 | const dayNr = (date.getDay() + 6) % 7;
59 | target.setDate(target.getDate() - dayNr + 3);
60 | const jan4 = new Date(target.getFullYear(), 0, 4);
61 | const dayDiff = (target - jan4) / 86400000;
62 | return 2 + Math.floor(dayDiff / 7);
63 | };
64 |
65 | // 格式化标题
66 | const weekNumber = getISOWeek(currentDate);
67 | const formattedWeek = `${year} W${weekNumber}`;
68 |
69 | // 修改容器类名
70 | let calendarHTML = `
`;
71 | calendarHTML += `
${formattedWeek}
`;
72 | calendarHTML += `
`;
73 | calendarHTML += `
`;
74 |
75 | // 添加星期标题
76 | ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"].forEach(day => {
77 | calendarHTML += ``;
78 | });
79 |
80 | // 填充日期
81 | for (let i = 0; i < 7; i++) {
82 | const date = new Date(weekStart);
83 | date.setDate(weekStart.getDate() + i);
84 | const dateStr = formatDateStr(date);
85 | const page = dv.page(dateStr);
86 |
87 | let cellClasses = ["date-cell"];
88 | if (date.toDateString() === currentDate.toDateString()) {
89 | cellClasses.push("date-cell-current");
90 | } else if (page) {
91 | cellClasses.push("date-cell-has-note");
92 | }
93 |
94 | calendarHTML += `
${date.getDate()}
`;
95 | }
96 |
97 | calendarHTML += `
`; // 结束 calendar-grid
98 |
99 | // 将引用区块移到日历网格外部
100 | //calendarHTML += `
`;
101 | calendarHTML += `
102 |
❝
103 | ${dv.current().quote ?
104 | String(dv.current().quote)
105 | .replace(/^"+|"+$/g, '')
106 | .replace(/(\[\[.*?\]\])|(.*\.md\|?)/g, (match) => {
107 | const parts = match.split('|');
108 | return parts.length > 1 ? parts.pop() : parts[0];
109 | })
110 | .replace(/\]\]/g, '') :
111 | '
浊水变澄清,全在自流中。————种田山头火'}
112 |
`;
113 |
114 | calendarHTML += `
`; // 结束 calendar-container
115 |
116 | dv.paragraph(calendarHTML);
117 |
118 |
--------------------------------------------------------------------------------
/bujo_calender_views V1.0/markdown文件/月视图.md:
--------------------------------------------------------------------------------
1 | ---
2 | created: 2025-02-28T10:28:00
3 | updated: 2025-03-01T12:47
4 | cssclasses:
5 | - month-view
6 | - calendar-views
7 | ---
8 | ```dataviewjs
9 | // 移除内联样式定义
10 | const mainContainerStyle = ``;
11 | const containerStyle = ``;
12 |
13 | // 初始化容器
14 | let combinedHTML = '
';
15 |
16 | // 获取当前年份和月份
17 | const currentYear = new Date().getFullYear();
18 | const currentMonth = new Date(dv.current().created).getMonth()+1;
19 |
20 | // 年度概览部分
21 | let yearCalendarHTML = `
22 |
23 |
24 | ${currentYear}
25 | 正确的开始,微小的长进,然后持续。
26 |
27 |
`;
28 |
29 | // 生成月份按钮
30 | for (let month = 1; month <= 12; month++) {
31 | const monthStart = dv.date(`${currentYear}-${String(month).padStart(2,'0')}-01`);
32 | const monthName = monthStart.toFormat('MMM');
33 | const hasMonthlyNote = dv.page(`Monthly/${currentYear}-${String(month).padStart(2,'0')}`);
34 |
35 | const classes = [
36 | 'month-button',
37 | month === currentMonth ? 'current' : '',
38 | hasMonthlyNote ? 'has-note' : ''
39 | ].filter(Boolean).join(' ');
40 |
41 | yearCalendarHTML += `
42 |
44 | ${monthName}
45 |
`;
46 | }
47 |
48 | yearCalendarHTML += '
';
49 |
50 | // 创建标题和网格布局
51 | let habitHTML = `
52 |
53 |
54 | `;
55 | // 确保日期框架稳定生成
56 | const buildCalendarGrid = () => {
57 | // 获取当前月份(动态)
58 | const currentDate = dv.date(dv.current().created);
59 | const monthStart = currentDate.startOf('month');
60 | const daysInMonth = currentDate.daysInMonth;
61 |
62 | // 核心框架生成
63 | let habitHTML = `
64 |
78 |
79 | `;
80 |
81 | // 生成日期列(强制生成空框架)
82 | Array.from({length: daysInMonth}).forEach((_, index) => {
83 | habitHTML += `
${index +1}
`;
84 | });
85 | habitHTML += `
`; //统计列
86 |
87 | // 定义习惯列表
88 | const habits = ['🧘 拉伸', '📓 日记', '💻 笔记', '🏃 慢跑', '📖 阅读', '🤔 Stoic', '💢 心情'];
89 |
90 | // 获取数据(带空值保护)
91 | const safeGetPages = () => {
92 | try {
93 | return dv.pages('"0_Bullet Journal/Daily Notes"')
94 | .where(p => p?.file?.name?.startsWith(monthStart.toFormat('yyyy-MM')))
95 | .sort(p => p.file.name, 'asc') || [];
96 | } catch {
97 | return [];
98 | }
99 | };
100 | const pages = safeGetPages();
101 |
102 | const moodEmojiMap = {
103 | [-5]: '😱', [-4]: '😖', [-3]: '😟', [-2]: '😔', [-1]: '😕',
104 | 0: '😐', 1: '🙂', 2: '😊', 3: '😄', 4: '🥰', 5: '😇'
105 | };
106 |
107 | // 简化习惯状态获取逻辑
108 | const getHabitState = (page, habit) => {
109 | const stateMap = {
110 | '🧘 拉伸': 'stretch',
111 | '📓 日记': 'journal',
112 | '💻 笔记': 'notes',
113 | '🏃 慢跑': 'running',
114 | '📖 阅读': 'reading',
115 | '🤔 Stoic': 'stoic',
116 | '💢 心情': 'mood'
117 | };
118 | return page?.[stateMap[habit]] ?? null;
119 | };
120 |
121 | // 构建习惯行
122 | habits.forEach(habit => {
123 | let habitCount = 0;
124 | let moodSum = 0;
125 | let moodCount = 0;
126 |
127 | habitHTML += `
${habit}
`;
128 |
129 | for (let day = 1; day <= daysInMonth; day++) {
130 | const currentDate = monthStart.plus({days: day-1});
131 | const page = pages.find(p =>
132 | dv.date(p?.file?.name?.split(" ")[0])?.toISODate() === currentDate.toISODate()
133 | ) || {};
134 |
135 | // 安全获取习惯状态
136 | const habitState = getHabitState(page, habit);
137 |
138 | // 更新统计值部分
139 | if (habit === '💢 心情') {
140 | if (habitState !== null) {
141 | moodSum += habitState;
142 | moodCount++;
143 | }
144 | } else if (habit === '🤔 Stoic') {
145 | if (page.file && habitState && habitState.trim() !== '') {
146 | habitCount++;
147 | }
148 | } else {
149 | if (page.file && habitState === true) {
150 | habitCount++;
151 | }
152 | }
153 |
154 | // 在渲染单元格时使用简化的逻辑
155 | const getCellStyle = (habit, state) => `
156 | width: 1.5rem;
157 | height: 1.5rem;
158 | background-color: ${habit === '💢 心情'
159 | ? 'var(--background-modifier-hover)'
160 | : (state ? 'var(--interactive-accent)' : 'var(--background-modifier-hover)')};
161 | border: 1.5px dotted ${habit === '💢 心情'
162 | ? 'var(--interactive-accent)'
163 | : (state ? 'transparent' : 'var(--interactive-accent)')};
164 | `;
165 |
166 | // 渲染单元格(强制最小显示)
167 | habitHTML += `
168 |
169 |
174 | ${habit === '💢 心情' ? (moodEmojiMap[habitState] || '') : (habitState ? '✓' : '')}
175 |
176 |
`;
177 | }
178 |
179 | const statValue = habit === '💢 心情'
180 | ? moodCount > 0
181 | ? moodEmojiMap[Math.round(moodSum / moodCount)]
182 | : '-'
183 | : `${Math.round((habitCount / daysInMonth) * 100)}%`; // 所有习惯都使用整月天数
184 |
185 | habitHTML += `
186 |
198 | ${statValue}
199 |
200 | `;
201 | });
202 |
203 | return habitHTML + '
';
204 | }
205 |
206 | // 最终输出
207 | //dv.paragraph(buildCalendarGrid());
208 | // 闭合容器
209 | habitHTML += `
`;
210 |
211 | // 组合输出
212 | combinedHTML += yearCalendarHTML;
213 | combinedHTML += buildCalendarGrid();
214 | combinedHTML += '
';
215 |
216 | // 最终渲染
217 | dv.paragraph(combinedHTML);
218 | ```
--------------------------------------------------------------------------------
/bujo_calender_views V1.0/markdown文件/视图合集.md:
--------------------------------------------------------------------------------
1 | ---
2 | created: 2025-02-28T09:16:00
3 | updated: 2025-03-01T13:14
4 | ---
5 | ### 日视图
6 | ```dataviewjs
7 | // 获取当前页面的日期(支持文件名和created属性)
8 | const getPageDate = () => {
9 | // 尝试从文件名获取日期
10 | const fileName = dv.current().file.name.split(" ")[0];
11 | const dateMatch = fileName.match(/^\d{4}-\d{2}-\d{2}$/);
12 |
13 | if (dateMatch) {
14 | const [year, month, day] = fileName.split("-").map(Number);
15 | return new Date(year, month - 1, day);
16 | }
17 |
18 | // 如果文件名不是日期格式,使用created属性
19 | return new Date(dv.current().created);
20 | };
21 |
22 | const currentDate = getPageDate();
23 | const [year, month, day] = [
24 | currentDate.getFullYear(),
25 | currentDate.getMonth() + 1,
26 | currentDate.getDate()
27 | ];
28 |
29 | // 计算本周日期
30 | const currentDayOfWeek = (currentDate.getDay() + 6) % 7;
31 | const weekStart = new Date(currentDate);
32 | weekStart.setDate(currentDate.getDate() - currentDayOfWeek);
33 | const weekEnd = new Date(currentDate);
34 | weekEnd.setDate(currentDate.getDate() + (6 - currentDayOfWeek));
35 |
36 | // 修改日期格式化函数
37 | const formatDateStr = (date) => {
38 | const y = date.getFullYear();
39 | const m = String(date.getMonth() + 1).padStart(2, '0');
40 | const d = String(date.getDate()).padStart(2, '0');
41 | return `${y}-${m}-${d}`;
42 | };
43 |
44 | // 简化周数计算
45 | const getWeekInfo = (date) => {
46 | const firstDayOfYear = new Date(date.getFullYear(), 0, 1);
47 | const pastDaysOfYear = (date - firstDayOfYear) / 86400000;
48 | return {
49 | week: 2 + Math.floor((pastDaysOfYear + firstDayOfYear.getDay() + 1) / 7),
50 | year: date.getFullYear()
51 | };
52 | };
53 |
54 | // 获取 ISO 周数
55 | const getISOWeek = (date) => {
56 | const target = new Date(date.valueOf());
57 | const dayNr = (date.getDay() + 6) % 7;
58 | target.setDate(target.getDate() - dayNr + 3);
59 | const jan4 = new Date(target.getFullYear(), 0, 4);
60 | const dayDiff = (target - jan4) / 86400000;
61 | return 2 + Math.floor(dayDiff / 7);
62 | };
63 |
64 | // 格式化标题
65 | const weekNumber = getISOWeek(currentDate);
66 | const formattedWeek = `${year} W${weekNumber}`;
67 |
68 | // 修改容器类名
69 | let calendarHTML = ``;
70 | calendarHTML += `
${formattedWeek}
`;
71 | calendarHTML += `
`;
72 | calendarHTML += `
`;
73 |
74 | // 添加星期标题
75 | ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"].forEach(day => {
76 | calendarHTML += ``;
77 | });
78 |
79 | // 填充日期
80 | for (let i = 0; i < 7; i++) {
81 | const date = new Date(weekStart);
82 | date.setDate(weekStart.getDate() + i);
83 | const dateStr = formatDateStr(date);
84 | const page = dv.page(dateStr);
85 |
86 | let cellClasses = ["date-cell"];
87 | if (date.toDateString() === currentDate.toDateString()) {
88 | cellClasses.push("date-cell-current");
89 | } else if (page) {
90 | cellClasses.push("date-cell-has-note");
91 | }
92 |
93 | calendarHTML += `
${date.getDate()}
`;
94 | }
95 |
96 | calendarHTML += `
`; // 结束 calendar-grid
97 |
98 | // 将引用区块移到日历网格外部
99 | //calendarHTML += `
`;
100 | calendarHTML += `
101 |
❝
102 | ${dv.current().quote ?
103 | String(dv.current().quote)
104 | .replace(/^"+|"+$/g, '')
105 | .replace(/(\[\[.*?\]\])|(.*\.md\|?)/g, (match) => {
106 | const parts = match.split('|');
107 | return parts.length > 1 ? parts.pop() : parts[0];
108 | })
109 | .replace(/\]\]/g, '') :
110 | '
浊水变澄清,全在自流中。————种田山头火'}
111 |
`;
112 |
113 | calendarHTML += `
`; // 结束 calendar-container
114 |
115 | dv.paragraph(calendarHTML);
116 |
117 | ```
118 |
119 | ### 周视图
120 | ```dataviewjs
121 | // 日期相关函数
122 | function formatDate(date) {
123 | return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
124 | }
125 |
126 | function getWeekRange(baseDate) {
127 | const dayOfWeek = (baseDate.getDay() + 6) % 7;
128 | const startDate = new Date(baseDate);
129 | startDate.setDate(baseDate.getDate() - dayOfWeek);
130 | const endDate = new Date(startDate);
131 | endDate.setDate(startDate.getDate() + 6);
132 | return { startDate, endDate };
133 | }
134 |
135 | // 优化日期处理函数
136 | function getDateInfo(date) {
137 | return {
138 | year: date.getFullYear(),
139 | month: date.getMonth(),
140 | day: date.getDate(),
141 | weekday: (date.getDay() + 6) % 7
142 | };
143 | }
144 |
145 | // 简化页面查询逻辑
146 | function getPageForDate(dateStr) {
147 | return dv.pages('"0_Bullet Journal/Daily Notes"')
148 | .where(p => p.file.name.startsWith(dateStr))
149 | .first();
150 | }
151 |
152 | // 修改容器类名,使用共享样式
153 | let combinedHTML = '';
154 |
155 | try {
156 | const baseDate = dv.current().created ? new Date(dv.current().created) : new Date();
157 | const { startDate, endDate } = getWeekRange(baseDate);
158 | const currentYear = startDate.getFullYear();
159 | const currentMonth = startDate.getMonth();
160 | const currentWeek = Math.ceil((baseDate - new Date(baseDate.getFullYear(), 0, 1)) / (1000 * 60 * 60 * 24 * 7));
161 |
162 | // 生成月历HTML
163 | combinedHTML += `
164 |
165 |
166 | ${currentYear} ${["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"][currentMonth]} W${currentWeek}
167 |
168 |
169 | ${generateWeekGrid(startDate, endDate)}
170 |
171 |
172 | `;
173 |
174 | // 生成习惯跟踪器HTML
175 | combinedHTML += `
176 |
177 | ${generateHabitTracker(startDate, endDate)}
178 |
179 | `;
180 |
181 | } catch (e) {
182 | console.error("Error in week view:", e);
183 | combinedHTML += '
Error generating week view
';
184 | }
185 |
186 | combinedHTML += '
';
187 | dv.paragraph(combinedHTML);
188 |
189 | // 辅助函数
190 | function generateWeekGrid(startDate, endDate) {
191 | const dateInfo = getDateInfo(startDate);
192 | let gridHTML = '';
193 |
194 | // 添加星期标题
195 | ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"].forEach(day => {
196 | gridHTML += ``;
197 | });
198 |
199 | // 重置时间部分,只比较日期
200 | startDate.setHours(0, 0, 0, 0);
201 | endDate.setHours(0, 0, 0, 0);
202 |
203 | // 获取当前月的信息
204 | const currentYear = startDate.getFullYear();
205 | const currentMonth = startDate.getMonth();
206 | const firstDay = new Date(currentYear, currentMonth, 1);
207 | const lastDay = new Date(currentYear, currentMonth + 1, 0);
208 | const firstDayWeek = (firstDay.getDay() + 6) % 7;
209 | const prevMonthDays = new Date(currentYear, currentMonth, 0).getDate();
210 |
211 | // 添加上月末尾日期
212 | for (let i = 0; i < firstDayWeek; i++) {
213 | const date = new Date(currentYear, currentMonth - 1, prevMonthDays - firstDayWeek + i + 1);
214 | const isCurrentWeek = date >= startDate && date <= endDate;
215 |
216 | gridHTML += `
217 |
218 | ${prevMonthDays - firstDayWeek + i + 1}
219 |
`;
220 | }
221 |
222 | // 添加本月日期
223 | for (let i = 1; i <= lastDay.getDate(); i++) {
224 | const currentDate = new Date(currentYear, currentMonth, i);
225 | currentDate.setHours(0, 0, 0, 0);
226 | const dateStr = formatDate(currentDate);
227 | const weekDay = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'][currentDate.getDay()];
228 | // 修改:查找方式改为精确匹配日期前缀
229 | const pages = dv.pages()
230 | .where(p => p.file.name.startsWith(dateStr))
231 | .values;
232 | const page = pages.length > 0;
233 |
234 | const isCurrentWeek = currentDate >= startDate && currentDate <= endDate;
235 |
236 | gridHTML += `
237 |
238 | ${i}
239 |
`;
240 | }
241 |
242 | // 添加下月开始日期
243 | const lastDayWeek = (lastDay.getDay() + 6) % 7;
244 | for (let i = 1; i <= 6 - lastDayWeek; i++) {
245 | const nextDate = new Date(currentYear, currentMonth + 1, i);
246 | nextDate.setHours(0, 0, 0, 0);
247 | const dateStr = formatDate(nextDate);
248 | // 修改:对下月日期也使用相同的查找逻辑
249 | const pages = dv.pages()
250 | .where(p => p.file.name.startsWith(dateStr))
251 | .values;
252 | const page = pages.length > 0;
253 |
254 | const isCurrentWeek = nextDate >= startDate && nextDate <= endDate;
255 |
256 | gridHTML += `
257 |
258 | ${i}
259 |
`;
260 | }
261 |
262 | return gridHTML;
263 | }
264 |
265 | function generateHabitTracker(startDate, endDate) {
266 | const habits = ['🧘 拉伸', '📓 日记', '💻 笔记', '🏃 慢跑', '📖 阅读', '🤔 Stoic', '💢 心情'];
267 | const moodEmojiMap = {
268 | '-5': '😱', '-4': '😖', '-3': '😟', '-2': '😔', '-1': '😕',
269 | '0': '😐', '1': '🙂', '2': '😊', '3': '😄', '4': '🥰', '5': '😇'
270 | };
271 |
272 | let trackerHTML = `
273 |
274 |
275 | ${["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"].map(day =>
276 | `
${day}
`
277 | ).join('')}`;
278 |
279 | habits.forEach(habit => {
280 | trackerHTML += `
${habit}
`;
281 |
282 | for (let i = 0; i < 7; i++) {
283 | const currentDate = new Date(startDate);
284 | currentDate.setDate(startDate.getDate() + i);
285 | const dateStr = formatDate(currentDate);
286 | const page = getPageForDate(dateStr);
287 |
288 | const status = page ? {
289 | '🧘 拉伸': page.stretch || false,
290 | '📓 日记': page.journal || false,
291 | '💻 笔记': page.notes || false,
292 | '🏃 慢跑': page.running || false,
293 | '📖 阅读': page.reading || false,
294 | '🤔 Stoic': page.stoic || "",
295 | '💢 心情': page.mood ?? null
296 | }[habit] : null;
297 |
298 | const isMood = habit === '💢 心情';
299 |
300 | trackerHTML += `
301 |
302 |
306 | ${isMood ? (status !== null ? moodEmojiMap[status] : '') : (status ? '✓' : '')}
307 |
308 |
`;
309 | }
310 | });
311 |
312 | trackerHTML += '
';
313 | return trackerHTML;
314 | }
315 | ```
316 |
317 |
318 | ### 月视图
319 |
320 | ```dataviewjs
321 | // 移除内联样式定义
322 | const mainContainerStyle = ``;
323 | const containerStyle = ``;
324 |
325 | // 初始化容器
326 | let combinedHTML = '
';
327 |
328 | // 获取当前年份和月份
329 | const currentYear = new Date().getFullYear();
330 | const currentMonth = new Date(dv.current().created).getMonth()+1;
331 |
332 | // 年度概览部分
333 | let yearCalendarHTML = `
334 |
335 |
336 | ${currentYear}
337 | 正确的开始,微小的长进,然后持续。
338 |
339 |
`;
340 |
341 | // 生成月份按钮
342 | for (let month = 1; month <= 12; month++) {
343 | const monthStart = dv.date(`${currentYear}-${String(month).padStart(2,'0')}-01`);
344 | const monthName = monthStart.toFormat('MMM');
345 | const hasMonthlyNote = dv.page(`Monthly/${currentYear}-${String(month).padStart(2,'0')}`);
346 |
347 | const classes = [
348 | 'month-button',
349 | month === currentMonth ? 'current' : '',
350 | hasMonthlyNote ? 'has-note' : ''
351 | ].filter(Boolean).join(' ');
352 |
353 | yearCalendarHTML += `
354 |
356 | ${monthName}
357 |
`;
358 | }
359 |
360 | yearCalendarHTML += '
';
361 |
362 | // 创建标题和网格布局
363 | let habitHTML = `
364 |
365 |
366 | `;
367 | // 确保日期框架稳定生成
368 | const buildCalendarGrid = () => {
369 | // 获取当前月份(动态)
370 | const currentDate = dv.date(dv.current().created);
371 | const monthStart = currentDate.startOf('month');
372 | const daysInMonth = currentDate.daysInMonth;
373 |
374 | // 核心框架生成
375 | let habitHTML = `
376 |
390 |
391 | `;
392 |
393 | // 生成日期列(强制生成空框架)
394 | Array.from({length: daysInMonth}).forEach((_, index) => {
395 | habitHTML += `
${index +1}
`;
396 | });
397 | habitHTML += `
`; //统计列
398 |
399 | // 定义习惯列表
400 | const habits = ['🧘 拉伸', '📓 日记', '💻 笔记', '🏃 慢跑', '📖 阅读', '🤔 Stoic', '💢 心情'];
401 |
402 | // 获取数据(带空值保护)
403 | const safeGetPages = () => {
404 | try {
405 | return dv.pages('"0_Bullet Journal/Daily Notes"')
406 | .where(p => p?.file?.name?.startsWith(monthStart.toFormat('yyyy-MM')))
407 | .sort(p => p.file.name, 'asc') || [];
408 | } catch {
409 | return [];
410 | }
411 | };
412 | const pages = safeGetPages();
413 |
414 | const moodEmojiMap = {
415 | [-5]: '😱', [-4]: '😖', [-3]: '😟', [-2]: '😔', [-1]: '😕',
416 | 0: '😐', 1: '🙂', 2: '😊', 3: '😄', 4: '🥰', 5: '😇'
417 | };
418 |
419 | // 简化习惯状态获取逻辑
420 | const getHabitState = (page, habit) => {
421 | const stateMap = {
422 | '🧘 拉伸': 'stretch',
423 | '📓 日记': 'journal',
424 | '💻 笔记': 'notes',
425 | '🏃 慢跑': 'running',
426 | '📖 阅读': 'reading',
427 | '🤔 Stoic': 'stoic',
428 | '💢 心情': 'mood'
429 | };
430 | return page?.[stateMap[habit]] ?? null;
431 | };
432 |
433 | // 构建习惯行
434 | habits.forEach(habit => {
435 | let habitCount = 0;
436 | let moodSum = 0;
437 | let moodCount = 0;
438 |
439 | habitHTML += `
${habit}
`;
440 |
441 | for (let day = 1; day <= daysInMonth; day++) {
442 | const currentDate = monthStart.plus({days: day-1});
443 | const page = pages.find(p =>
444 | dv.date(p?.file?.name?.split(" ")[0])?.toISODate() === currentDate.toISODate()
445 | ) || {};
446 |
447 | // 安全获取习惯状态
448 | const habitState = getHabitState(page, habit);
449 |
450 | // 更新统计值部分
451 | if (habit === '💢 心情') {
452 | if (habitState !== null) {
453 | moodSum += habitState;
454 | moodCount++;
455 | }
456 | } else if (habit === '🤔 Stoic') {
457 | if (page.file && habitState && habitState.trim() !== '') {
458 | habitCount++;
459 | }
460 | } else {
461 | if (page.file && habitState === true) {
462 | habitCount++;
463 | }
464 | }
465 |
466 | // 在渲染单元格时使用简化的逻辑
467 | const getCellStyle = (habit, state) => `
468 | width: 1.5rem;
469 | height: 1.5rem;
470 | background-color: ${habit === '💢 心情'
471 | ? 'var(--background-modifier-hover)'
472 | : (state ? 'var(--interactive-accent)' : 'var(--background-modifier-hover)')};
473 | border: 1.5px dotted ${habit === '💢 心情'
474 | ? 'var(--interactive-accent)'
475 | : (state ? 'transparent' : 'var(--interactive-accent)')};
476 | `;
477 |
478 | // 渲染单元格(强制最小显示)
479 | habitHTML += `
480 |
481 |
486 | ${habit === '💢 心情' ? (moodEmojiMap[habitState] || '') : (habitState ? '✓' : '')}
487 |
488 |
`;
489 | }
490 |
491 | const statValue = habit === '💢 心情'
492 | ? moodCount > 0
493 | ? moodEmojiMap[Math.round(moodSum / moodCount)]
494 | : '-'
495 | : `${Math.round((habitCount / daysInMonth) * 100)}%`; // 所有习惯都使用整月天数
496 |
497 | habitHTML += `
498 |
510 | ${statValue}
511 |
512 | `;
513 | });
514 |
515 | return habitHTML + '
';
516 | }
517 |
518 | // 最终输出
519 | //dv.paragraph(buildCalendarGrid());
520 | // 闭合容器
521 | habitHTML += `
`;
522 |
523 | // 组合输出
524 | combinedHTML += yearCalendarHTML;
525 | combinedHTML += buildCalendarGrid();
526 | combinedHTML += '
';
527 |
528 | // 最终渲染
529 | dv.paragraph(combinedHTML);
530 | ```
531 |
532 |
--------------------------------------------------------------------------------
/bujo_calender_views V1.0/使用指南.md:
--------------------------------------------------------------------------------
1 | ---
2 | created: 2025-03-01T12:23
3 | updated: 2025-03-01T12:36
4 | ---
5 | # 个人知识库视图系统使用指南 📖
6 |
7 | ## 1. 系统概述
8 |
9 | 这是一套为 Obsidian 设计的视图系统,包含日视图、周视图和月视图三个层级,帮助你更好地管理和展示个人知识与习惯追踪数据。
10 |
11 | ## 2. 安装步骤
12 |
13 | 1. 将 `calendar.css` 文件复制到 `.obsidian/snippets` 目录下
14 | 2. 在 Obsidian 设置中启用该 CSS 片段:
15 | - 打开设置 (Settings)
16 | - 进入外观 (Appearance)
17 | - 找到 CSS 片段 (CSS snippets)
18 | - 刷新并启用 `calendar.css`
19 | 3. 复制 `视图v1.0.md` 文件到你的知识库中
20 |
21 | ## 3. 视图说明
22 |
23 | ### 3.1 日视图功能
24 | - 显示当前周的日历
25 | - 高亮显示当前日期
26 | - 显示每日格言(需在日记中添加 `quote` 字段)
27 | - 标记已创建日记的日期
28 |
29 | ### 3.2 周视图功能
30 | - 显示当月日历,高亮当前周
31 | - 习惯追踪器,包含以下项目:
32 | - 🧘 拉伸
33 | - 📓 日记
34 | - 💻 笔记
35 | - 🏃 慢跑
36 | - 📖 阅读
37 | - 🤔 Stoic
38 | - 💢 心情
39 |
40 | ### 3.3 月视图功能
41 | - 年度概览(显示所有月份)
42 | - 当月习惯详细追踪
43 | - 自动计算习惯完成率
44 | - 心情平均值统计
45 |
46 | ## 4. 使用方法
47 |
48 | ### 4.1 创建日记文件
49 | - 文件名格式:`YYYY-MM-DD`
50 | - 需包含以下 YAML frontmatter:
51 | ```yaml
52 | ---
53 | quote: "每日格言" # 可选
54 | stretch: true/false # 拉伸记录
55 | journal: true/false # 日记记录
56 | notes: true/false # 笔记记录
57 | running: true/false # 慢跑记录
58 | reading: true/false # 阅读记录
59 | stoic: "内容" # Stoic 思考
60 | mood: -5到5的数值 # 心情值
61 | ---
62 | ```
63 |
64 | ### 4.2 心情值对应表
65 | ```
66 | -5: 😱 极度焦虑
67 | -4: 😖 非常难过
68 | -3: 😟 难过
69 | -2: 😔 有点难过
70 | -1: 😕 不太好
71 | 0: 😐 一般
72 | 1: 🙂 还行
73 | 2: 😊 不错
74 | 3: 😄 开心
75 | 4: 🥰 很开心
76 | 5: 😇 极度开心
77 | ```
78 |
79 | ## 5. 注意事项
80 |
81 | 1. 确保你的 Obsidian 版本支持 DataviewJS
82 | 2. 日记文件需要按照指定格式命名和存储
83 | 3. YAML frontmatter 中的字段名称需要完全匹配
84 | 4. 心情值必须在 -5 到 5 的范围内
85 |
86 | ## 6. 自定义建议
87 |
88 | 1. 可以根据需要修改 `calendar.css` 中的颜色和样式
89 | 2. 可以在习惯追踪器中添加或删除项目
90 | 3. 可以调整视图的显示效果以适应个人偏好
91 |
92 | ## 7. 问题排查
93 |
94 | 如果视图显示不正常,请检查:
95 | 1. CSS 片段是否正确启用
96 | 2. 日记文件格式是否正确
97 | 3. YAML frontmatter 是否包含所需字段
98 | 4. Dataview 插件是否正常运行
99 |
100 | ## 8. 系统优化说明
101 |
102 | ### 8.1 整体架构优化
103 | - CSS样式完全分离:所有样式都统一在 `calendar.css` 中管理
104 | - 统一容器类名:使用 `calendar-container` 实现样式共享
105 | - 代码结构优化:提高可维护性和扩展性
106 | - 统一设计语言:保持视觉风格一致性
107 |
108 | ### 8.2 日视图优化
109 | - 改进日期获取逻辑:支持从文件名和created属性获取日期
110 | - 优化周数计算:采用 ISO 周数标准
111 | - 改进引用区块:优化显示位置和样式
112 | - 增强日期单元格:提供更好的视觉反馈
113 |
114 | ### 8.3 周视图优化
115 | - 改进日期范围计算
116 | - 优化习惯追踪器显示
117 | - 提升页面查询性能
118 | - 添加错误处理机制
119 | - 支持跨月份周视图
120 |
121 | ### 8.4 月视图优化
122 | - 添加年度概览功能
123 | - 改进月份按钮交互
124 | - 优化习惯统计算法
125 | - 改进数据可视化展示
126 | - 增加月度数据分析
127 |
128 | ### 8.5 功能增强
129 | - 完善心情追踪系统
130 | - 使用表情符号直观显示
131 | - 优化统计算法
132 | - 添加习惯完成率统计
133 | - 优化 Stoic 思考记录
134 | - 增加数据验证机制
135 |
136 | ### 8.6 性能优化
137 | - 优化数据查询逻辑
138 | - 减少DOM操作
139 | - 改进日期计算方法
140 | - 添加空值保护机制
141 |
142 | ### 8.7 用户体验优化
143 | - 统一视觉设计
144 | - 改进响应式布局
145 | - 优化移动端适配
146 | - 增强交互反馈
147 |
148 | ## 9. 更新日志
149 |
150 | 当前版本:v1.1
151 | - 优化系统架构
152 | - 改进性能表现
153 | - 增强用户体验
154 | - 完善文档说明
155 |
--------------------------------------------------------------------------------
/bujo_calender_views V1.0/使用指南.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YuriWg/Obsidian_Templates/1cbeab148121cfbd320b2fdf08ae89b527e23e1f/bujo_calender_views V1.0/使用指南.pdf
--------------------------------------------------------------------------------
/bujo_calender_views V1.0/视图blue_dark_v1.0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YuriWg/Obsidian_Templates/1cbeab148121cfbd320b2fdf08ae89b527e23e1f/bujo_calender_views V1.0/视图blue_dark_v1.0.png
--------------------------------------------------------------------------------
/bujo_calender_views V1.0/视图blue_light_v1.0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YuriWg/Obsidian_Templates/1cbeab148121cfbd320b2fdf08ae89b527e23e1f/bujo_calender_views V1.0/视图blue_light_v1.0.png
--------------------------------------------------------------------------------
/bujo_calender_views V1.0/视图green_dark_v1.0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YuriWg/Obsidian_Templates/1cbeab148121cfbd320b2fdf08ae89b527e23e1f/bujo_calender_views V1.0/视图green_dark_v1.0.png
--------------------------------------------------------------------------------
/bujo_calender_views V1.0/视图green_lignt_v1.0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YuriWg/Obsidian_Templates/1cbeab148121cfbd320b2fdf08ae89b527e23e1f/bujo_calender_views V1.0/视图green_lignt_v1.0.png
--------------------------------------------------------------------------------