顯示具有 Obsidian 標籤的文章。 顯示所有文章
顯示具有 Obsidian 標籤的文章。 顯示所有文章

2025/08/08

Python | 調整 dropbox中 obsidian & logseq共用journal folder中 檔名規則出入

 #!/usr/bin/env python3

# -*- coding: utf-8 -*-


import re

import sys

import argparse

from pathlib import Path

from datetime import date


# ===== 工具:月份與序數 =====

MONTHS_FULL = [

    "January","February","March","April","May","June",

    "July","August","September","October","November","December"

]

MONTHS_ABBR = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]

MONTH_TO_NUM = {m:i+1 for i,m in enumerate(MONTHS_FULL)}

ABBR_TO_NUM  = {m:i+1 for i,m in enumerate(MONTHS_ABBR)}

NUM_TO_MONTH = {i+1:m for i,m in enumerate(MONTHS_FULL)}


def ordinal(n: int) -> str:

    if 11 <= (n % 100) <= 13:

        suffix = "th"

    else:

        suffix = {1:"st",2:"nd",3:"rd"}.get(n % 10, "th")

    return f"{n}{suffix}"


def canonical_stem(d: date) -> str:

    # 目標:MMMM do, yyyy(注意 do 小寫)

    return f"{NUM_TO_MONTH[d.month]} {ordinal(d.day)}, {d.year}"


# ===== 解析各種日期字串(給 [[...]] 正規化用) =====

def parse_date_token(s: str):

    s = s.strip()


    m = re.match(rf"^\s*({'|'.join(MONTHS_FULL)})\s+(\d{{1,2}})(?:st|nd|rd|th)?,\s*(\d{{4}})\s*$", s, flags=re.IGNORECASE)

    if m:

        month = MONTH_TO_NUM[m.group(1).capitalize()]

        day = int(m.group(2)); year = int(m.group(3))

        try: return date(year, month, day)

        except ValueError: return None


    m = re.match(rf"^\s*({'|'.join(MONTHS_ABBR)})\.?\s+(\d{{1,2}})(?:st|nd|rd|th)?,\s*(\d{{4}})\s*$", s, flags=re.IGNORECASE)

    if m:

        month = ABBR_TO_NUM[m.group(1).capitalize()]

        day = int(m.group(2)); year = int(m.group(3))

        try: return date(year, month, day)

        except ValueError: return None


    m = re.match(r"^\s*(\d{4})[._/\-](\d{1,2})[._/\-](\d{1,2})\s*$", s)

    if m:

        y, mo, d = map(int, m.groups())

        try: return date(y, mo, d)

        except ValueError: return None


    return None


# ===== 連結正規化 [[日期]] → [[MMMM do, yyyy]] =====

REF_PATTERN = re.compile(r"\[\[\s*([^\]\|#]+?)\s*\]\]")


def rewrite_date_page_refs(text: str):

    replaced = 0

    def _repl(m):

        nonlocal replaced

        inner = m.group(1)

        d = parse_date_token(inner)

        if d:

            replaced += 1

            return f"[[{canonical_stem(d)}]]"

        return m.group(0)

    new_text = REF_PATTERN.sub(_repl, text)

    return new_text, replaced


# ===== 安全重新命名(加 merged 前綴時避免撞名) =====

def prefixed_unique_path(p: Path, prefix="merged ") -> Path:

    target = p.with_name(prefix + p.name)

    if not target.exists():

        return target

    stem, suf = target.stem, target.suffix

    i = 1

    while True:

        c = target.with_name(f"{stem} ({i}){suf}")

        if not c.exists():

            return c

        i += 1


# ===== 解析檔名取得日期 =====

def parse_date_from_stem(stem: str):

    s = stem.strip()


    m = re.match(rf"^({'|'.join(MONTHS_FULL)})\s+(\d{{1,2}})(?:st|nd|rd|th)?,\s*(\d{{4}})$", s)

    if m:

        month = MONTH_TO_NUM[m.group(1)]

        day = int(m.group(2)); year = int(m.group(3))

        try:

            d = date(year, month, day)

            style = "canonical" if re.search(r"(st|nd|rd|th),", s) else "long_month"

            return d, style

        except ValueError:

            return None


    m = re.match(rf"^({'|'.join(MONTHS_ABBR)})\.?\s+(\d{{1,2}})(?:st|nd|rd|th)?,\s*(\d{{4}})$", s, flags=re.IGNORECASE)

    if m:

        month = ABBR_TO_NUM[m.group(1).capitalize()]

        day = int(m.group(2)); year = int(m.group(3))

        try: return date(year, month, day), "abbr_month"

        except ValueError: return None


    m = re.match(r"^(\d{4})[._-](\d{1,2})[._-](\d{1,2})$", s)

    if m:

        y, mo, d = map(int, m.groups())

        try: return date(y, mo, d), "iso"

        except ValueError: return None


    return None


# ===== 檔案讀寫 =====

def read_text(path: Path) -> str:

    return path.read_text(encoding="utf-8", errors="ignore")


def write_text(path: Path, text: str):

    path.write_text(text, encoding="utf-8")


def append_transformed(src: Path, dest: Path) -> tuple[int,int]:

    raw = read_text(src)

    fixed, replaced = rewrite_date_page_refs(raw)

    with dest.open("a", encoding="utf-8") as f:

        if dest.exists() and dest.stat().st_size > 0:

            f.write("\n")

        f.write(fixed)

        if not fixed.endswith("\n"):

            f.write("\n")

    return len(fixed), replaced


def rewrite_links_in_file(path: Path) -> int:

    raw = read_text(path)

    fixed, replaced = rewrite_date_page_refs(raw)

    if replaced > 0:

        write_text(path, fixed)

    return replaced


# ===== 掃描候選 =====

def find_candidates(root: Path):

    """

    掃描 root 下的 .md(不遞迴,跳過 'merged ' 開頭)

    回傳 { date: { 'canonical': Path|None, 'sources': [Path,...] } }

    """

    mapping = {}

    for p in root.glob("*.md"):

        if p.name.lower().startswith("merged "):

            continue

        parsed = parse_date_from_stem(p.stem)

        if not parsed:

            continue

        d, style = parsed

        bucket = mapping.setdefault(d, {"canonical": None, "sources": []})

        if style == "canonical":

            bucket["canonical"] = p

        else:

            bucket["sources"].append(p)

    # 保留所有有關聯的日期(包含只有 canonical 的,稍後用邏輯過濾「不需處理」的)

    return mapping


def process_dates(root: Path, mapping: dict, limit: int, dry_run: bool):

    if not mapping:

        print("沒有可處理的日期檔。")

        return


    dates_sorted = sorted(mapping.keys(), reverse=True)


    # 僅選擇「需要處理」的日期:

    # - 有 sources(需要合併),或

    # - 沒有 canonical(只有 1 個或多個來源 → 需要改名或合併)

    # 會跳過:已是 canonical 且沒有 sources(代表已正確,屬 no-op)

    work_dates = [d for d in dates_sorted if not (mapping[d]["canonical"] and not mapping[d]["sources"])]


    if not work_dates:

        print("找不到需要處理的日期(最新的都已是 MMMM do, yyyy 且無重複)。")

        return


    selected = work_dates[:limit]


    print("日期狀態(由新到舊):")

    for d in dates_sorted:

        info = mapping[d]

        if info["canonical"] and not info["sources"]:

            status = "OK 已是 MMMM do, yyyy(跳過)"

        elif info["canonical"] and info["sources"]:

            status = f"合併 {len(info['sources'])} 來源"

        elif not info["canonical"] and len(info["sources"]) == 1:

            status = "改名為 MMMM do, yyyy"

        else:

            status = f"合併 {len(info['sources'])} 來源(並建立目標)"

        tag = " ← 將處理" if d in selected else ""

        print(f"- {d.isoformat()}:{status}{tag}")


    for d in selected:

        info = mapping[d]

        target = info["canonical"] if info["canonical"] else root / f"{canonical_stem(d)}.md"

        will_create = (info["canonical"] is None) and (not target.exists())

        sources_sorted = sorted(info["sources"], key=lambda p: p.name.lower())


        print(f"\n=== {d.isoformat()} ===")


        # 單一來源且尚未存在目標 → 直接改名(不加 merged)

        if info["canonical"] is None and len(sources_sorted) == 1 and will_create:

            src = sources_sorted[0]

            print(f"[SINGLE] 僅有來源:{src.name}")

            if dry_run:

                print(f"  [REWRITE] 將在檔內正規化 [[日期]] → [[{canonical_stem(d)}]]")

                print(f"  [RENAME]  '{src.name}'  →  '{target.name}'")

            else:

                replaced = rewrite_links_in_file(src)

                if replaced:

                    print(f"  [REWRITE] 已正規化 {replaced} 處 [[日期]]")

                src.rename(target)

                print(f"  [RENAMED] '{src.name}'  →  '{target.name}'")

                # 保險:對新檔再跑一次正規化

                replaced_t = rewrite_links_in_file(target)

                if replaced_t:

                    print(f"  [TARGET REWRITE] {target.name} 內正規化 {replaced_t} 處 [[日期]]")

            continue


        # 其他情境:存在目標或有多來源 → 合併 + 來源加 merged 前綴

        if will_create:

            print(f"[TARGET] {target.name}(將建立)")

        else:

            print(f"[TARGET] {target.name}")


        planned = []

        for src in sources_sorted:

            new_path = prefixed_unique_path(src)  # merged ...

            planned.append((src, new_path))


        if dry_run:

            print(f"  [TARGET REWRITE] 將正規化 {target.name} 內的 [[日期]](若存在)")

            for src, new_path in planned:

                print(f"  [COPY]   '{src.name}'  →  '{target.name}'(先正規化連結)")

                print(f"  [RENAME] '{src.name}'  →  '{new_path.name}'")

            continue


        if will_create:

            target.write_text("", encoding="utf-8")

            print(f"[CREATE TARGET] 已建立:{target.name}")


        replaced_t = rewrite_links_in_file(target)

        if replaced_t:

            print(f"  [TARGET REWRITE] {target.name} 內正規化 {replaced_t} 處 [[日期]]")


        total_chars = 0

        total_refs  = 0

        for src, new_path in planned:

            appended_len, replaced_refs = append_transformed(src, target)

            total_chars += appended_len

            total_refs  += replaced_refs

            print(f"  [COPIED]  '{src.name}'  →  '{target.name}'  (+{appended_len} chars, fixed {replaced_refs} refs)")

            src.rename(new_path)

            print(f"  [RENAMED] '{src.name}'  →  '{new_path.name}'")


        print(f"[SUMMARY] 合併 {len(planned)} 個來源,總附加 ~{total_chars} 字元、正規化 {total_refs} 個 [[日期]] → {target.name}")


    print(f"\n完成!此次處理日期數量:{len(selected)}。")


def main():

    ap = argparse.ArgumentParser(description="合併/正規化日記到 MMMM do, yyyy;跳過已是正確格式且無重複的最新日期。")

    ap.add_argument("root", nargs="?", default=".", help="要處理的資料夾(預設:目前資料夾)")

    ap.add_argument("-n","--limit", type=int, default=1000, help="一次處理的『日期數量』(預設:1;可改 10 或 1000)")

    ap.add_argument("--dry-run", action="store_true", help="僅列出將進行的動作,不修改檔案")

    args = ap.parse_args()


    root = Path(args.root).expanduser().resolve()

    if not root.exists():

        print(f"找不到資料夾:{root}")

        sys.exit(1)


    mapping = find_candidates(root)

    process_dates(root, mapping, limit=args.limit, dry_run=args.dry_run)


if __name__ == "__main__":

    main()


2025/08/04

如何同時使用 Logseq 與 Obsidian?

🎯 核心觀念

先釐清你的需求

在開始使用 Logseq 或 Obsidian 前,應先問自己:「我到底想用這些工具達成什麼目標?」
如果還沒釐清需求,很可能會陷入「有了解決方案,卻沒找到問題」的情境。

🔄 可以雙軌並行,互補使用

你可以根據各自的優勢與不足來決定使用場景:

  • 主觀使用法:用你喜歡的那一套工具去做那件事。

  • 客觀使用法:用一個工具來補足另一個的不足之處。


💡 使用情境與分工建議

使用工具 建議用途
Logseq 區塊式筆記、任務管理、每日筆記、間隔重複學習、Zotero / PDF 整合、以 Journal 為主導的「每日輸入流」
Obsidian 跨檔案筆記整理、大型專案或研究、視覺化連結地圖、更強大的自訂排版與插件、Readwise 整合、跨平台同步

⚠️ 注意事項:兩者之間的相容性

Logseq 與 Obsidian 都使用 Markdown,但:

  • Markdown 格式略有差異,某些語法、屬性或資料夾結構在兩邊可能顯示不一樣。

  • 使用相同資料夾時,可能導致顯示異常或格式錯亂

  • 解法:依照規範進行設定與資料夾規劃


🔧 讓 Obsidian 和 Logseq 協同工作的建議設定

📁 檔案與資料夾結構建議

功能 建議設定
筆記存放位置 /pages 資料夾(兩邊通用)
附件存放位置 /assets 資料夾
每日筆記格式 Logseq 和 Obsidian 都設定為 MMMM do, YYYY(如:August 4th, 2025)
每日筆記位置 /journals 資料夾
連結格式 在 Obsidian 中:關閉 Wikilinks、使用相對路徑
任務管理 建立一頁 [[logseq tasks]],可用查詢語法過濾 DOING 等狀態

🔌 推薦插件(Obsidian 專用)

插件 功能
obsidian-plugin-logseq 讓 Obsidian 更好地預覽 Logseq 的 Markdown
obsseq 協助從 Logseq 遷移至 Obsidian
obsidian-logseq-compat 增進 Obsidian 與 Logseq 的視覺相容性
Template.Obs 一個模板庫,適合整合兩者使用

✅ 實作技巧與小撇步

  • /assets 建立附件資料夾,快速儲存與引用圖片和檔案

  • 在 Obsidian 中使用「Outliner」、「Zoom」等插件強化大綱結構(但手機版可能需停用)

  • 用相同資料夾作為 Obsidian Vault 與 Logseq 的工作空間,便於雙向同步


🎓 結論建議

  • 雙軌並行是可行的,但你需要設定好一致的命名規則與檔案結構。

  • 開始使用後,實際操作比看影片或建議更能幫你釐清偏好。

  • 最終選擇不在於哪個工具比較好,而是你在哪個環境中思考與寫作最順手。


2025/05/14

🧠 🎮 Obsidian RPG × 任務反思整合系統設計方案

 太棒了!Obsidian 是個高度彈性、模組化強的筆記系統,非常適合你這種偏好自訂語法結構、RPG 化人生管理、反思導向的使用者。現在我來幫你重新設計一套完整的 Obsidian 系統架構,可 取代 Roam(知識/筆記)與 Notion(反思/追蹤),並保留 Outlook + Apple Calendar 做排程。


🧠 🎮 Obsidian RPG × 任務反思整合系統設計方案


🎯 你的核心需求回顧(解題目標)

項目 需求 / 使用模式
📒 知識筆記與任務連結 Roam 做會議記錄、知識標籤管理
✅ RPG 架構反思與追蹤 Notion 管 Role → Purpose → Game → Task
📆 排程與提醒 Outlook(工作)、Apple Calendar(家庭)
🧘 每日反思 & 行動聚焦 Roam 模板反思、每日 MIT
📈 低維護的儀表板與回顧流程 Notion 的 Review Note + 自動平均分數計算

⚒️ Obsidian 替代方案概述

原系統 Obsidian 替代方式
Roam Daily Note + Templater + Tags + Dataview
Notion RPG 架構 → 轉為 YAML metadata + Dataview
行事曆 延續使用 Outlook & Apple Calendar,同步至 Daily Note

📁 Vault 結構設計(資料夾架構)

📂 journals/         → 繼續每日筆記(由 Calendar 或 Periodic Notes 控管)
📂 pages/
├── 🎭 roles/         → e.g. Creator.md, Parent.md
├── 🎯 purposes/      → e.g. share-ideas.md
├── 🎮 games/         → e.g. Blogging.md
├── 🧠 zettels/        → 雜項知識、反思、外部輸入筆記
📂 Templates/        → daily.md, game.md, weekly-review.md

🧩 命名標準建議(強化搜尋與 Dataview 分類)

類型命名範例開頭 YAML 中加上
Roleroles/Creator.mdtype: role
Purposepurposes/share-ideas.mdtype: purpose
Gamegames/Blogging.mdtype: game
Zettel/Notezettels/Zettelkasten.md可省略

🧠 加值小技巧:善用 _- 命名結構

  • 使用 -:當標題有空格,例如 share-ideas.md(利於網頁型連結)

  • 使用 _:當你需要資料夾排序時(如 _Templates/ 排最上)


📌 技術套件與外掛需求

外掛 用途
Templater 自動生成每日筆記 / Game 模板
Dataview 建立 Game 分數平均、未回顧列表、RPG 儀表板
Calendar 檢視 Daily Note(非與 Outlook 衝突)
Tasks 支援 checklist 與 due date 管理
Periodic Notes(選配) 自動生成週/月/年回顧
Day Planner / Kanban(選配) 可嵌入時間區塊或視覺進度條

以下是你提供內容的改寫版本,語句更清晰、邏輯更一致,格式也更易於直接用於 Obsidian Vault 系統建構與維護。


🧱 系統筆記內容設計(Obsidian)


1️⃣ 🎭 Roles / Purposes / Games:以 YAML 為結構核心,透過 Dataview 自動整理與追蹤

📄 games/Blogging.md 範例

---
type: game
title: Blogging
purpose: share-ideas
roles: [Creator]
score: 8
last-reviewed: 2024-05-10
visible: true
---

🔁 Review Notes

  • 2024-05-10:發文穩定,想再挑戰日更

  • 2024-04-27:寫太慢,推文品質佳但量太少

📎 Related Tasks

  • Draft AI and storytelling essay ⏳ 2024-05-16

  • Review article by David Perell

📌 Dataview 查詢語句:找出需回顧的 Game

table score, last-reviewed
from "games"
where visible = true
sort last-reviewed asc

📄 purposes/share-ideas.md 範例

---
type: purpose
roles: [Creator, SupportiveColleague]
avg-score: 6.5
---

🎮 對應遊戲

  • [[games/Blogging]]

  • [[games/Public Speaking]]

📌 說明筆記

寫作讓我整理思緒,分享想法是一種輸出型學習方式。


2️⃣ 🗓 journals/2024-05-14.md — 每日筆記模板

---
tags: [daily]
date: 2024-05-14
---

📅 Daily Reflection

🔺 今日最重要任務(MIT)

  • #MIT Draft newsletter

  • #MIT Finish onboarding deck

  • #MIT Review woodworking plan

💭 自我反思

  • Gratitude

  • Mood / Energy

  • Emotional Garbage

  • Stoic Check:我是否讓無法控制的事影響了我?

  • Future Self:理想中的我會給今天的自己什麼建議?

🔍 聚焦角色 / 目標 / 遊戲

  • Game:: [[games/Blogging]]

  • Purpose:: [[purposes/share-ideas]]

  • Role:: [[roles/Creator]]

🔁 附加筆記

  • 會議記錄:[[Meeting 2024-05-14]]

  • 思緒備忘:

✅ 使用 [Templater] 外掛可自動每日生成,搭配 Calendar 與 Tasks 外掛整合任務視覺化


3️⃣ 🔁 weekly-reviews/2024-W20.md — 週回顧筆記模板

---
type: weekly-review
week: 2024-W20
---

🧭 Weekly RPG Review

✅ 本週表現最佳的 Game

  • [[games/Blogging]]:score:: 8(發文節奏穩定)

  • [[games/Parenting]]:score:: 7(週末陪伴時間足夠)

❗️需特別關注

table score, last-reviewed
from "games"
where score < 5
sort score asc

💬 自我問答

  • 哪個 Purpose 本週被忽略了?

  • 有沒有哪個 Role 長期未出場?

  • 下週可以嘗試一個什麼小實驗?


4️⃣ 🧠 pages/ 裡的筆記(取代 Roam 的 block-style 筆記)

你可以繼續使用 Roam 的語法風格與命名邏輯,但結合 Obsidian 的雙向連結與標籤系統,例如:

# Zettelkasten-style Notes

## [[KeyTerm]]: Atomic Notes  
小而完整的知識單位,方便組裝與引用。

## #Claim  
Most note-taking systems collapse because of poor link hygiene.

## #ToResearch  
- 比較 PARA vs P.A.I.R  
- 閱讀 David Perell 對寫作系統的建議

📊 RPG 儀表板整合頁面(建議儲存為 pages/RPG Dashboard.md

## 🎮 所有 Game 狀態
table score, last-reviewed
from "games"
where visible = true
sort last-reviewed asc

## 🎯 Purpose 平均分數
table avg-score
from "purposes"
sort avg-score asc

## 🎭 Role 目前狀態
table avg-score
from "roles"
sort avg-score asc

📌 這份設計支援你現有的資料夾與命名邏輯,不需改動結構,只需:

  • 加入 type: 進 YAML

  • 用資料夾分類 / 命名標準自動歸位

  • 使用 Dataview 查詢 + Templater 插入模板完成自動化反思 / 儀表板


太好了!這是為你的系統(RPG + Review + Daily Notes)量身打造的:


📊 Dataview 語法對照手冊 for Obsidian RPG 系統

🔧 支援你的 RolesPurposesGames、每日筆記與週回顧
✅ 可直接貼入 Obsidian 使用,支援 YAML-based metadata


🧱 資料前提設定(YAML 基本範例)

你應在每個 RPG 物件檔案開頭加入以下欄位,供 Dataview 抓取:

📄 games/Blogging.md

---
type: game
title: Blogging
purpose: share-ideas
roles: [Creator]
score: 8
last-reviewed: 2024-05-14
visible: true
---

📄 purposes/share-ideas.md

---
type: purpose
roles: [Creator, SupportiveColleague]
avg-score: 6.5
---

📚 查詢語法總表(直接貼用)


🎮 1️⃣ Game 類別查詢

▶ 所有正在玩的 Game(visible: true

table score, last-reviewed
from "games"
where type = "game" and visible = true
sort last-reviewed asc

▶ 最近沒更新的 Game(超過 14 天)

table score, last-reviewed
from "games"
where type = "game" and visible = true and date(last-reviewed) <= date(today) - dur(14 days)
sort last-reviewed asc

▶ 分數較低的 Game(score < 6)

table score, last-reviewed
from "games"
where type = "game" and score < 6
sort score asc

▶ 每個 Game 對應的 Purpose / Roles

table purpose, roles
from "games"
where type = "game"
sort score desc

🎯 2️⃣ Purpose 類別查詢

▶ 所有 Purpose 的平均分數(你可手動更新 avg-score)

table avg-score as "Avg Score", roles
from "purposes"
where type = "purpose"
sort avg-score asc

▶ 哪些 Purpose 關聯最多遊戲(需建立反向連結)

(需在每個 Game 裡有 purpose: xxx 並用 [[purposes/xxx]] 連回)

table length(rows) as "Games Count"
group by purpose

🎭 3️⃣ Role 類別查詢(若你有建立 roles/Creator.md 這類)

▶ 各角色的平均分數(由你手動填 avg-score)

table avg-score as "Avg Score"
from "roles"
where type = "role"
sort avg-score asc

🗓 4️⃣ 每日筆記中任務標記查詢(如 #MIT)

▶ 本週最重要任務(每日筆記標有 #MIT)

table file.link as "Date", text
from "journals"
where contains(text, "#MIT")
sort file.name desc

▶ 所有 MIT 任務 + 所屬遊戲(需使用 Game:: [[Blogging]] 格式)

table Game, text
from "journals"
where contains(text, "#MIT")

🔁 5️⃣ 每週 / 每月回顧中關鍵資訊查詢

▶ 所有 Weekly Review 的記錄(自訂 type: weekly-review

table week
from "weekly-reviews"
where type = "weekly-review"
sort week desc

🧭 6️⃣ RPG Overview 儀表板建議結構(合併使用)

## 🎮 Active Games
```dataview
table score, last-reviewed
from "games"
where visible = true
sort last-reviewed asc

## 🎯 Purposes by Score
```dataview
table avg-score, roles
from "purposes"
where type = "purpose"
sort avg-score asc

## 🎭 Roles Overview
```dataview
table avg-score
from "roles"
where type = "role"
sort avg-score asc

🛠 常用語法備註

用法 意義
from "資料夾" 限定來源
where visible = true 篩選欄位
sort xxx asc/desc 排序
date(x) 把文字變成日期格式供運算
dur(14 days) 時間差距
contains(text, "#MIT") 搜尋文本是否含特定詞

✅ 使用建議

  • 所有 .md 檔放進固定資料夾(games/、purposes/、roles/)

  • 加入 type:score:last-reviewed: 等欄位在 YAML

  • 儀表板頁面建一個 RPG Dashboard.md,貼入上述組合即可使用


若你想要我:

  • 幫你建好 dashboard.md + 所有查詢都套上框架

  • 提供範例 Game/Purpose/Role .md 檔案

  • 或打包一份 Starter Vault


2022/05/16

tagging, bi directional linking & markdown

 

在GTD還流行的年代,當時的概念是每個itme都要寫上一些metadata

- status: in progress, deferred, someday maybe

- location: @office, @home, @commute

- time: @morning, @phone, @writing

- person: w/Amy, w/Kevin...

當這些不夠用的時候,還要另外加上tag,當時David Allen說某個週末做一次review,可以更有效率,但我一直都有兩個疑問

1. 我覺得為了維護這些資料反而需要花費更多時間

2. 這個系統讓我壓力更大

3. 我不認為GTD可以Scale,當有更多成員,複雜性更高的時候,應該就會爆炸

當時有許多有趣的工具應該都是為了維護越來越複雜的metadata而衍生出來

- theBrain https://www.thebrain.com/ 可以連結文件彼此之間的概念,到現在還是很優秀,但費用對我來說依舊沒有動力投資

- XMind 跟iThought我後來選了iThought,因為買斷對我來說感覺還是比較舒服,iThoughs作者英國光頭的形象也讓我比較有親切感。MindMap畫到一個程度,總是不容易再回去連結到其他的概念,Roam Research這些後來的工具讓使用者在觀念之間跳來跳去容易多了。Mindoomo, MindMeister, MindNode, Coggle, SimpleMind, MindManager, Visual Understanding Environment, Mind42, bubbl.us, 

- Tinderbox 另外一個想學沒學好的工具,我像是松鼠一樣蒐集了許多想要閱讀的清單,閱讀的速度跟不上蒐集的速度。還好現在有Speechify可以幫助我多讀一點東西。

不論如何,GTD在過去二十年依舊幫助我許多,改變了我安排決定事情的優先順序的習慣,到現在甚至改變了我手寫筆記的習慣,我也這樣請小孩子寫自己的筆記&日記。

  • ? 問題 >> ?該怎麼做
  • [ ]   該做的事情 >>[ ] 閱讀第二課
  • 想法 >> 可以用在肉桂麵包
  • -> 流程順序 >> 清洗 -> 烹飪 -> 上菜
  • # 標籤 >> #猴子 #自然課
  • @ context & location
  • - 條列項目 >>
    • - 物品一
    • -事件二 

另外一個有趣的事情是,為了要釐清這些metadata之間的關聯性,有很長一段時間我想要建立一個立體的tag關聯性整理界面,一個3D的網狀架構,讓概念之間彼此連結,並且用節點之間的距離,來換算關聯性跟權重,我想參考星狀資料結構,搭配Google Earth的界面來讓使用者(其實是我自己)來整理腦子的想法。這個概念太模糊,我就沒有能力可以實現。

後來的WikiNode, WikiLink都有了knowledge graph的技術,Roam Research, Obsidian, LogSeq等都有自動視覺化顯示概念關係的工具,我之前想要達到的目的,使用bi directional linking甚至比視覺抓取方式更有效率。

感謝世界上這麼多傑出聰明的人們,許多困難我還在掙扎的時候,他們就實做出比我能想像到更好的工具出來給我們用了:)