secondbrain-py 0.2.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- brain/__init__.py +0 -0
- brain/__main__.py +18 -0
- brain/_capture_command.py +445 -0
- brain/_compose.py +52 -0
- brain/activity.py +206 -0
- brain/ask.py +631 -0
- brain/audio.py +591 -0
- brain/backfill/__init__.py +12 -0
- brain/backfill/search_extras.py +141 -0
- brain/backfill/source_rows.py +101 -0
- brain/bin/__init__.py +1 -0
- brain/bin/_launcher.py +107 -0
- brain/bin/down.py +8 -0
- brain/bin/launchd.py +268 -0
- brain/bin/monitor.py +570 -0
- brain/bin/rebuild.py +8 -0
- brain/bin/status.py +8 -0
- brain/bin/up.py +8 -0
- brain/brief.py +272 -0
- brain/capture.py +49 -0
- brain/chat.py +293 -0
- brain/cli.py +9760 -0
- brain/cli_claude.py +81 -0
- brain/cli_connect.py +285 -0
- brain/cli_demo.py +266 -0
- brain/config.py +1949 -0
- brain/connect.py +925 -0
- brain/db.py +540 -0
- brain/demo/__init__.py +452 -0
- brain/demo/corpus/manifest.json +403 -0
- brain/demo/embedder.py +74 -0
- brain/durations.py +84 -0
- brain/edit_session.py +156 -0
- brain/editor.py +67 -0
- brain/elicit/__init__.py +16 -0
- brain/elicit/detectors.py +250 -0
- brain/elicit/drafter.py +70 -0
- brain/elicit/queue.py +220 -0
- brain/elicit/schema.py +48 -0
- brain/elicit/session.py +445 -0
- brain/embedding_targets.py +54 -0
- brain/embeddings.py +424 -0
- brain/enrichment.py +808 -0
- brain/errors.py +357 -0
- brain/eval/__init__.py +129 -0
- brain/eval/answer_eval.py +281 -0
- brain/eval/baseline.py +265 -0
- brain/eval/concept_extraction.py +378 -0
- brain/eval/corpus.py +152 -0
- brain/eval/errors.py +19 -0
- brain/eval/graph_baseline.py +226 -0
- brain/eval/graph_retrieval.py +202 -0
- brain/eval/graph_runner.py +319 -0
- brain/eval/metrics.py +101 -0
- brain/eval/runner.py +223 -0
- brain/format.py +783 -0
- brain/gaps.py +390 -0
- brain/graph_rag/__init__.py +94 -0
- brain/graph_rag/_retrieval_common.py +113 -0
- brain/graph_rag/aggregates.py +303 -0
- brain/graph_rag/aliases/__init__.py +583 -0
- brain/graph_rag/backends/__init__.py +10 -0
- brain/graph_rag/backends/_age_helpers.py +473 -0
- brain/graph_rag/backends/age.py +782 -0
- brain/graph_rag/backends/base.py +272 -0
- brain/graph_rag/build.py +344 -0
- brain/graph_rag/communities.py +644 -0
- brain/graph_rag/communities_summary.py +437 -0
- brain/graph_rag/concepts.py +202 -0
- brain/graph_rag/cooccur.py +193 -0
- brain/graph_rag/cross_type.py +312 -0
- brain/graph_rag/extract.py +885 -0
- brain/graph_rag/fuse.py +371 -0
- brain/graph_rag/global_.py +412 -0
- brain/graph_rag/grouping.py +372 -0
- brain/graph_rag/person_resolver.py +167 -0
- brain/graph_rag/reconcile.py +792 -0
- brain/graph_rag/relational.py +353 -0
- brain/graph_rag/retrieve.py +526 -0
- brain/graph_rag/router.py +288 -0
- brain/graph_rag/schema.py +320 -0
- brain/graph_rag/sync.py +237 -0
- brain/graph_rag/tenancy.py +43 -0
- brain/graph_rag/themes.py +501 -0
- brain/graph_rag/weighting.py +202 -0
- brain/ingest/__init__.py +1926 -0
- brain/ingest/chunker.py +249 -0
- brain/ingest/docx.py +40 -0
- brain/ingest/gmail.py +621 -0
- brain/ingest/markdown.py +37 -0
- brain/ingest/pdf.py +61 -0
- brain/ingest/stdin.py +22 -0
- brain/ingest/sub_tokens.py +91 -0
- brain/ingest/text.py +16 -0
- brain/interactions.py +205 -0
- brain/maintenance.py +355 -0
- brain/mcp_server.py +3405 -0
- brain/migrations/001_init.sql +43 -0
- brain/migrations/002_qwen3_embedding.sql +17 -0
- brain/migrations/003_vault_model.sql +41 -0
- brain/migrations/004_relax_content_hash_uniqueness.sql +18 -0
- brain/migrations/005_derived_links.sql +67 -0
- brain/migrations/006_dedup_file_by_source_path.sql +25 -0
- brain/migrations/007_email_thread_and_draft.sql +15 -0
- brain/migrations/008_gmail_thread_unique.sql +11 -0
- brain/migrations/009_chunks_weighted_tsv.sql +28 -0
- brain/migrations/010_interactions.sql +30 -0
- brain/migrations/011_documents_summary.sql +23 -0
- brain/migrations/012_graphrag.sql +171 -0
- brain/migrations/013_graphrag_communities.sql +125 -0
- brain/migrations/014_graphrag_community_summary_hash.sql +33 -0
- brain/migrations/015_interactions_graph_targets.sql +89 -0
- brain/migrations/016_index_hygiene.sql +61 -0
- brain/migrations/017_elicit.sql +30 -0
- brain/migrations/018_review_gap_signal_kinds.sql +40 -0
- brain/migrations/019_search_queries.sql +35 -0
- brain/migrations/020_link_suggestions.sql +40 -0
- brain/migrations/021_timeline_doc_date.sql +34 -0
- brain/migrations/022_link_suggestions_undirected.sql +84 -0
- brain/migrations/023_search_queries_fts_count.sql +28 -0
- brain/quartz_overrides/__init__.py +8 -0
- brain/quartz_overrides/quartz/bootstrap-cli.mjs +65 -0
- brain/quartz_overrides/quartz/build.ts +568 -0
- brain/quartz_overrides/quartz/cli/args.js +152 -0
- brain/quartz_overrides/quartz/cli/build_partial_handler.js +544 -0
- brain/quartz_overrides/quartz/cli/handlers.js +636 -0
- brain/quartz_overrides/quartz/components/CommandPalette.tsx +172 -0
- brain/quartz_overrides/quartz/components/Explorer.tsx +198 -0
- brain/quartz_overrides/quartz/components/Footer.tsx +27 -0
- brain/quartz_overrides/quartz/components/Graph.tsx +468 -0
- brain/quartz_overrides/quartz/components/PageTitle.tsx +72 -0
- brain/quartz_overrides/quartz/components/RelatedDocs.tsx +38 -0
- brain/quartz_overrides/quartz/components/Search.tsx +161 -0
- brain/quartz_overrides/quartz/components/SummaryLede.tsx +72 -0
- brain/quartz_overrides/quartz/components/index.ts +92 -0
- brain/quartz_overrides/quartz/components/pages/TagContent.tsx +272 -0
- brain/quartz_overrides/quartz/components/scripts/commandPalette.inline.ts +665 -0
- brain/quartz_overrides/quartz/components/scripts/explorer.inline.ts +768 -0
- brain/quartz_overrides/quartz/components/scripts/graph.inline.ts +2302 -0
- brain/quartz_overrides/quartz/components/scripts/relatedDocs.inline.ts +163 -0
- brain/quartz_overrides/quartz/components/scripts/search.inline.ts +1011 -0
- brain/quartz_overrides/quartz/plugins/emitters/contentIndex.ts +546 -0
- brain/quartz_overrides/quartz/plugins/transformers/codeCopy.ts +94 -0
- brain/quartz_overrides/quartz/plugins/transformers/derivedFenceMark.ts +302 -0
- brain/quartz_overrides/quartz/plugins/transformers/emailThread.ts +148 -0
- brain/quartz_overrides/quartz/plugins/transformers/emptyDoorFilter.ts +213 -0
- brain/quartz_overrides/quartz/plugins/transformers/index.ts +114 -0
- brain/quartz_overrides/quartz/plugins/transformers/linkKindMark.ts +205 -0
- brain/quartz_overrides/quartz/plugins/transformers/linkSourceTag.ts +104 -0
- brain/quartz_overrides/quartz/plugins/transformers/relativeDate.ts +100 -0
- brain/quartz_overrides/quartz/plugins/transformers/reloadSignal.ts +131 -0
- brain/quartz_overrides/quartz/processors/parse.ts +371 -0
- brain/quartz_overrides/quartz/processors/parser_cache.ts +78 -0
- brain/quartz_overrides/quartz/static/brain-logo-dark.png +0 -0
- brain/quartz_overrides/quartz/static/brain-logo-light.png +0 -0
- brain/quartz_overrides/quartz/static/codeCopy.js +196 -0
- brain/quartz_overrides/quartz/static/emailThread.js +334 -0
- brain/quartz_overrides/quartz/static/favicon.ico +0 -0
- brain/quartz_overrides/quartz/static/icon.png +0 -0
- brain/quartz_overrides/quartz/static/linkSourceTag.js +104 -0
- brain/quartz_overrides/quartz/static/relativeDate.js +142 -0
- brain/quartz_overrides/quartz/static/reload.js +168 -0
- brain/quartz_overrides/quartz/styles/brain/_article.scss +252 -0
- brain/quartz_overrides/quartz/styles/brain/_atmosphere.scss +113 -0
- brain/quartz_overrides/quartz/styles/brain/_callouts.scss +180 -0
- brain/quartz_overrides/quartz/styles/brain/_cmdk.scss +7 -0
- brain/quartz_overrides/quartz/styles/brain/_code.scss +208 -0
- brain/quartz_overrides/quartz/styles/brain/_command_palette.scss +369 -0
- brain/quartz_overrides/quartz/styles/brain/_email_thread.scss +228 -0
- brain/quartz_overrides/quartz/styles/brain/_explorer.scss +142 -0
- brain/quartz_overrides/quartz/styles/brain/_home.scss +182 -0
- brain/quartz_overrides/quartz/styles/brain/_links.scss +322 -0
- brain/quartz_overrides/quartz/styles/brain/_marginalia.scss +117 -0
- brain/quartz_overrides/quartz/styles/brain/_motion.scss +175 -0
- brain/quartz_overrides/quartz/styles/brain/_people_hub.scss +100 -0
- brain/quartz_overrides/quartz/styles/brain/_related_docs.scss +137 -0
- brain/quartz_overrides/quartz/styles/brain/_search.scss +252 -0
- brain/quartz_overrides/quartz/styles/brain/_sidebar.scss +468 -0
- brain/quartz_overrides/quartz/styles/brain/_summary_lede.scss +56 -0
- brain/quartz_overrides/quartz/styles/brain/_surface.scss +43 -0
- brain/quartz_overrides/quartz/styles/brain/_tag_content.scss +118 -0
- brain/quartz_overrides/quartz/styles/brain/_tokens.scss +197 -0
- brain/quartz_overrides/quartz/styles/brain/_typography.scss +92 -0
- brain/quartz_overrides/quartz/styles/custom.scss +89 -0
- brain/quartz_overrides/quartz/styles/graph.scss +505 -0
- brain/quartz_overrides/quartz/util/ctx.ts +92 -0
- brain/quartz_overrides/quartz/util/fastpath_manifest.ts +608 -0
- brain/quartz_overrides/quartz/util/path.ts +358 -0
- brain/quartz_overrides/quartz/util/sourceIcons.ts +55 -0
- brain/quartz_overrides/quartz.config.ts +270 -0
- brain/quartz_overrides/quartz.layout.ts +314 -0
- brain/queries.py +1188 -0
- brain/rank_fusion.py +8 -0
- brain/resurface.py +210 -0
- brain/review/__init__.py +26 -0
- brain/review/emit.py +27 -0
- brain/review/queries.py +436 -0
- brain/review/render.py +196 -0
- brain/review/scans.py +355 -0
- brain/review/weekly.py +413 -0
- brain/search.py +704 -0
- brain/set_similarity.py +15 -0
- brain/setup.py +1205 -0
- brain/tags.py +56 -0
- brain/templates/Caddyfile.j2 +9 -0
- brain/templates/__init__.py +1 -0
- brain/templates/bin/__init__.py +1 -0
- brain/templates/bin/_brain-brief-fg.sh +25 -0
- brain/templates/bin/_brain-build-fg.sh +53 -0
- brain/templates/bin/_brain-watcher-fg.sh +65 -0
- brain/templates/bin/brain-down.sh +89 -0
- brain/templates/bin/brain-status.sh +83 -0
- brain/templates/bin/brain-up.sh +221 -0
- brain/templates/docker/age/Dockerfile +79 -0
- brain/templates/docker-compose.stock.yml.j2 +26 -0
- brain/templates/docker-compose.yml.j2 +34 -0
- brain/templates/env.example +190 -0
- brain/templates/launchd/__init__.py +1 -0
- brain/templates/launchd/com.brain.brief.plist.j2 +45 -0
- brain/templates/launchd/com.brain.build.plist.j2 +46 -0
- brain/templates/launchd/com.brain.watcher.plist.j2 +46 -0
- brain/templates/skill/SKILL.md +63 -0
- brain/templates/skill/__init__.py +1 -0
- brain/timeline.py +834 -0
- brain/todo.py +124 -0
- brain/uninstall.py +185 -0
- brain/vault/__init__.py +115 -0
- brain/vault/_atomic.py +25 -0
- brain/vault/daily_index.py +228 -0
- brain/vault/derived_links/__init__.py +50 -0
- brain/vault/derived_links/directory.py +683 -0
- brain/vault/derived_links/fence.py +408 -0
- brain/vault/derived_links/gws.py +64 -0
- brain/vault/derived_links/participants.py +143 -0
- brain/vault/derived_links/pass_runner.py +362 -0
- brain/vault/derived_links/rules.py +137 -0
- brain/vault/export.py +683 -0
- brain/vault/frontmatter.py +165 -0
- brain/vault/graph.py +620 -0
- brain/vault/graph_format.py +388 -0
- brain/vault/link_rewrite.py +235 -0
- brain/vault/links.py +260 -0
- brain/vault/note_builder.py +211 -0
- brain/vault/paths.py +55 -0
- brain/vault/quartz_overlay.py +236 -0
- brain/vault/rename.py +591 -0
- brain/vault/resolver.py +304 -0
- brain/vault/slug.py +127 -0
- brain/vault/sync.py +1513 -0
- brain/vault/sync_summaries.py +264 -0
- brain/vault/templates.py +145 -0
- brain/vault/watch.py +1052 -0
- brain/wiki/__init__.py +6 -0
- brain/wiki/_github_slugger.py +76 -0
- brain/wiki/_person_name.py +314 -0
- brain/wiki/build_homepage.py +541 -0
- brain/wiki/build_partial.py +273 -0
- brain/wiki/build_people.py +934 -0
- brain/wiki/build_related.py +758 -0
- brain/wiki/build_swap.py +585 -0
- brain/wiki/build_watcher.py +975 -0
- brain/wiki/edit_classifier.py +215 -0
- brain/wiki/errors.py +10 -0
- brain/wiki/fastpath_manifest.py +475 -0
- brain/wiki/fastpath_state.py +174 -0
- brain/wiki/install.py +296 -0
- brain/wiki/slug.py +111 -0
- secondbrain_py-0.2.1.dist-info/METADATA +195 -0
- secondbrain_py-0.2.1.dist-info/RECORD +273 -0
- secondbrain_py-0.2.1.dist-info/WHEEL +5 -0
- secondbrain_py-0.2.1.dist-info/entry_points.txt +11 -0
- secondbrain_py-0.2.1.dist-info/licenses/LICENSE +21 -0
- secondbrain_py-0.2.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
// Brain command palette component (Lane C, Cmd/Ctrl-P).
|
|
2
|
+
//
|
|
3
|
+
// This file is a TEMPLATE. It is installed at
|
|
4
|
+
// `<vault>/.quartz/quartz/components/CommandPalette.tsx` by `brain
|
|
5
|
+
// vault render --overlay`. It does NOT compile or run from the brain
|
|
6
|
+
// repo itself; the imports below resolve against the dependencies
|
|
7
|
+
// Quartz pulls into the cloned workspace via `npm install`, not
|
|
8
|
+
// against any package brain ships.
|
|
9
|
+
//
|
|
10
|
+
// Tested against Quartz v4.5.x (April 2026). The component shape
|
|
11
|
+
// mirrors stock Quartz components — see `Graph.tsx` (also a
|
|
12
|
+
// brain-overlayed component) for the canonical pattern. If a future
|
|
13
|
+
// Quartz version restructures `QuartzComponent` / `QuartzComponentProps`,
|
|
14
|
+
// pull the latest reference component from
|
|
15
|
+
// https://github.com/jackyzha0/quartz/blob/v4/quartz/components/
|
|
16
|
+
// and re-apply the brain tweaks below.
|
|
17
|
+
//
|
|
18
|
+
// Strategy — full new component (not an upstream override): nothing
|
|
19
|
+
// in stock Quartz exposes a quick-open palette. We render the palette
|
|
20
|
+
// markup once per page (registered in `quartz.layout.ts` `afterBody`
|
|
21
|
+
// slot — global, ships with every page in the build), then a
|
|
22
|
+
// co-located inline script (`scripts/commandPalette.inline.ts`)
|
|
23
|
+
// owns the open/close lifecycle, source chips, fuzzy search, keyboard
|
|
24
|
+
// handling, and SPA-nav cleanup.
|
|
25
|
+
//
|
|
26
|
+
// brain (Lane C audit fix 2026-05-02): refactored to native
|
|
27
|
+
// `<dialog>` element. Native dialog gives us, for free:
|
|
28
|
+
// * Focus trap inside the modal while open (no manual `Tab` ring
|
|
29
|
+
// management needed).
|
|
30
|
+
// * Native `Escape` close behavior + `cancel` event we can intercept
|
|
31
|
+
// to keep the brain close-animation.
|
|
32
|
+
// * Automatic focus restoration to the previously-focused element
|
|
33
|
+
// on `dialog.close()`.
|
|
34
|
+
// * Native `::backdrop` pseudo-element — replaces the manual
|
|
35
|
+
// `.brain-cmdk-backdrop` div with a CSS-driven scrim that the
|
|
36
|
+
// browser positions above the rest of the page (top of the
|
|
37
|
+
// stacking context, no z-index gymnastics).
|
|
38
|
+
// All four are non-trivial to implement correctly by hand; using the
|
|
39
|
+
// platform primitive removes drift surface.
|
|
40
|
+
//
|
|
41
|
+
// Markup contract — must stay in sync with the selector list in
|
|
42
|
+
// `_command_palette.scss` (Lane C/P5.3 SCSS partial) and the DOM walk inside
|
|
43
|
+
// `commandPalette.inline.ts`. See those two files' top comments.
|
|
44
|
+
//
|
|
45
|
+
// brain (Lane C audit fix 2026-05-02): combobox semantics on the
|
|
46
|
+
// search input. Plain `<input aria-controls=...>` is an a11y no-op;
|
|
47
|
+
// the WAI-ARIA combobox pattern is `role="combobox"` +
|
|
48
|
+
// `aria-expanded` (toggled by the script) + `aria-haspopup="listbox"`
|
|
49
|
+
// + `aria-autocomplete="list"`. Pairs with `aria-activedescendant`
|
|
50
|
+
// (set per-keystroke by the script) so screen readers announce each
|
|
51
|
+
// arrow-key result.
|
|
52
|
+
//
|
|
53
|
+
// Responsibility (CLAUDE.md rule 8): this file owns the Preact
|
|
54
|
+
// component wrapper. Open/close + search logic lives in
|
|
55
|
+
// `scripts/commandPalette.inline.ts`; the visual rules live in
|
|
56
|
+
// `../styles/brain/_command_palette.scss`. Don't let them spill into each
|
|
57
|
+
// other.
|
|
58
|
+
|
|
59
|
+
import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types"
|
|
60
|
+
// @ts-ignore — esbuild-loader resolves .ts to a bundled string; TS doesn't know.
|
|
61
|
+
import script from "./scripts/commandPalette.inline"
|
|
62
|
+
import { SOURCE_ICONS, SOURCE_CHIP_ORDER } from "../util/sourceIcons"
|
|
63
|
+
|
|
64
|
+
const CHIP_VALUES: ReadonlyArray<keyof typeof SOURCE_ICONS> = SOURCE_CHIP_ORDER
|
|
65
|
+
|
|
66
|
+
const CommandPalette: QuartzComponent = (_props: QuartzComponentProps) => {
|
|
67
|
+
// brain: native `<dialog>` element. The script calls `showModal()`
|
|
68
|
+
// to open and `close()` to dismiss; both manage focus + scroll-lock
|
|
69
|
+
// + the `::backdrop` pseudo-element automatically. The `id` is the
|
|
70
|
+
// selector hook used by `commandPalette.inline.ts` and `_command_palette.scss`
|
|
71
|
+
// — don't rename without updating both.
|
|
72
|
+
//
|
|
73
|
+
// brain: `aria-label` on the dialog gives screen readers a name
|
|
74
|
+
// when the dialog opens (replacing the now-unnecessary `role` /
|
|
75
|
+
// `aria-modal` attributes — native dialog provides both).
|
|
76
|
+
return (
|
|
77
|
+
<dialog id="brain-cmdk-root" class="brain-cmdk-root" aria-label="Command palette">
|
|
78
|
+
<div class="brain-cmdk-modal">
|
|
79
|
+
<div class="brain-cmdk-chips" role="group" aria-label="Filter quick open by source">
|
|
80
|
+
<button
|
|
81
|
+
type="button"
|
|
82
|
+
class="brain-cmdk-chip brain-cmdk-chip-all"
|
|
83
|
+
data-brain-source="__all__"
|
|
84
|
+
data-active="true"
|
|
85
|
+
aria-pressed="true"
|
|
86
|
+
>
|
|
87
|
+
All
|
|
88
|
+
</button>
|
|
89
|
+
{CHIP_VALUES.map((value) => (
|
|
90
|
+
<button
|
|
91
|
+
type="button"
|
|
92
|
+
class="brain-cmdk-chip"
|
|
93
|
+
data-brain-source={value}
|
|
94
|
+
data-active="true"
|
|
95
|
+
aria-pressed="true"
|
|
96
|
+
>
|
|
97
|
+
<span class="brain-cmdk-chip-icon" aria-hidden="true">
|
|
98
|
+
{SOURCE_ICONS[value]}
|
|
99
|
+
</span>
|
|
100
|
+
<span class="brain-cmdk-chip-label">{value}</span>
|
|
101
|
+
</button>
|
|
102
|
+
))}
|
|
103
|
+
</div>
|
|
104
|
+
<input
|
|
105
|
+
class="brain-cmdk-input"
|
|
106
|
+
type="text"
|
|
107
|
+
autocomplete="off"
|
|
108
|
+
autocorrect="off"
|
|
109
|
+
spellcheck={false}
|
|
110
|
+
placeholder="Search the wiki…"
|
|
111
|
+
// brain (Lane C audit fix): WAI-ARIA combobox pattern.
|
|
112
|
+
// * role="combobox" tells AT this is a search input that
|
|
113
|
+
// drives an associated popup.
|
|
114
|
+
// * aria-expanded mirrors visibility (set by the script
|
|
115
|
+
// when the dialog opens / closes).
|
|
116
|
+
// * aria-haspopup="listbox" + aria-autocomplete="list"
|
|
117
|
+
// describes the popup shape.
|
|
118
|
+
// * aria-controls links to the listbox by id.
|
|
119
|
+
// * aria-activedescendant (set per-keystroke by the
|
|
120
|
+
// script) points to the currently-selected option's id
|
|
121
|
+
// so AT can announce it on each arrow press without
|
|
122
|
+
// moving DOM focus off the input.
|
|
123
|
+
role="combobox"
|
|
124
|
+
aria-expanded="false"
|
|
125
|
+
aria-haspopup="listbox"
|
|
126
|
+
aria-controls="brain-cmdk-results"
|
|
127
|
+
aria-autocomplete="list"
|
|
128
|
+
aria-label="Search the wiki"
|
|
129
|
+
/>
|
|
130
|
+
{/* brain: results list rendered by the inline script. The
|
|
131
|
+
initial `<ul>` is empty; the script injects `<li
|
|
132
|
+
class="brain-cmdk-result" id="brain-cmdk-result-N">` rows
|
|
133
|
+
from the contentIndex match. Each `<li>` carries the
|
|
134
|
+
stable id the input's `aria-activedescendant` points at. */}
|
|
135
|
+
<ul
|
|
136
|
+
class="brain-cmdk-results"
|
|
137
|
+
id="brain-cmdk-results"
|
|
138
|
+
role="listbox"
|
|
139
|
+
aria-label="Search results"
|
|
140
|
+
></ul>
|
|
141
|
+
<div class="brain-cmdk-empty" hidden>
|
|
142
|
+
No results.
|
|
143
|
+
</div>
|
|
144
|
+
<div class="brain-cmdk-footer" aria-hidden="true">
|
|
145
|
+
<kbd>↑</kbd>
|
|
146
|
+
<kbd>↓</kbd>
|
|
147
|
+
<span>navigate</span>
|
|
148
|
+
<span>·</span>
|
|
149
|
+
<kbd>↵</kbd>
|
|
150
|
+
<span>open</span>
|
|
151
|
+
<span>·</span>
|
|
152
|
+
<kbd>esc</kbd>
|
|
153
|
+
<span>close</span>
|
|
154
|
+
</div>
|
|
155
|
+
</div>
|
|
156
|
+
</dialog>
|
|
157
|
+
)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// brain: wire the inline script. esbuild-loader resolves the
|
|
161
|
+
// `.inline.ts` import to its compiled bundled string at build time;
|
|
162
|
+
// Quartz inlines the string into the page at `</body>` time when
|
|
163
|
+
// `afterDOMLoaded` is set.
|
|
164
|
+
CommandPalette.afterDOMLoaded = script
|
|
165
|
+
|
|
166
|
+
// brain: no component-css here — visuals live in the global
|
|
167
|
+
// `_command_palette.scss`, which is `@use`-imported via `custom.scss`. That
|
|
168
|
+
// ensures the styles ship with EVERY page (not just pages that mount
|
|
169
|
+
// the component), so first-paint of any page already has the modal's
|
|
170
|
+
// resting state (closed `<dialog>`) rendered without flashing.
|
|
171
|
+
|
|
172
|
+
export default (() => CommandPalette) satisfies QuartzComponentConstructor
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
// Brain wiki overlay — quartz/components/Explorer.tsx
|
|
2
|
+
//
|
|
3
|
+
// This file shadows the upstream ``~/brain-vault/.quartz/quartz/components/Explorer.tsx``.
|
|
4
|
+
// All upstream functionality is preserved verbatim. The only change is the
|
|
5
|
+
// replacement of the module-level ``numExplorers`` counter with a slug-derived
|
|
6
|
+
// deterministic ID.
|
|
7
|
+
//
|
|
8
|
+
// Amendment #8 (T4 — Plan B v3):
|
|
9
|
+
// The upstream Explorer uses a module-level counter (``let numExplorers = 0``)
|
|
10
|
+
// to generate unique aria-id attributes: ``explorer-0``, ``explorer-1``, etc.
|
|
11
|
+
// In a full build, the counter increments with render order; in a partial build
|
|
12
|
+
// (fresh Node process), the counter resets to 0. The same slug may therefore
|
|
13
|
+
// produce a different id in the two paths, breaking byte-exact HTML parity and
|
|
14
|
+
// confusing the browser's aria-controls association on page reload.
|
|
15
|
+
//
|
|
16
|
+
// Fix: replace the counter with a slug-derived deterministic id
|
|
17
|
+
// (``explorer-<slug-with-slashes-as-hyphens>``). The id is unique per page
|
|
18
|
+
// (each page renders exactly one Explorer), deterministic across builds, and
|
|
19
|
+
// independent of render order.
|
|
20
|
+
//
|
|
21
|
+
// This overlay applies in BOTH full-build and partial-build paths so both
|
|
22
|
+
// produce the same HTML for the same slug regardless of order or process lifetime.
|
|
23
|
+
|
|
24
|
+
import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types"
|
|
25
|
+
import style from "./styles/explorer.scss"
|
|
26
|
+
|
|
27
|
+
// @ts-ignore
|
|
28
|
+
import script from "./scripts/explorer.inline"
|
|
29
|
+
import { classNames } from "../util/lang"
|
|
30
|
+
import { i18n } from "../i18n"
|
|
31
|
+
import { FileTrieNode } from "../util/fileTrie"
|
|
32
|
+
import OverflowListFactory from "./OverflowList"
|
|
33
|
+
import { concatenateResources } from "../util/resources"
|
|
34
|
+
|
|
35
|
+
type OrderEntries = "sort" | "filter" | "map"
|
|
36
|
+
|
|
37
|
+
export interface Options {
|
|
38
|
+
title?: string
|
|
39
|
+
folderDefaultState: "collapsed" | "open"
|
|
40
|
+
folderClickBehavior: "collapse" | "link"
|
|
41
|
+
useSavedState: boolean
|
|
42
|
+
sortFn: (a: FileTrieNode, b: FileTrieNode) => number
|
|
43
|
+
filterFn: (node: FileTrieNode) => boolean
|
|
44
|
+
mapFn: (node: FileTrieNode) => void
|
|
45
|
+
order: OrderEntries[]
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const defaultOptions: Options = {
|
|
49
|
+
folderDefaultState: "collapsed",
|
|
50
|
+
folderClickBehavior: "link",
|
|
51
|
+
useSavedState: true,
|
|
52
|
+
mapFn: (node) => {
|
|
53
|
+
return node
|
|
54
|
+
},
|
|
55
|
+
sortFn: (a, b) => {
|
|
56
|
+
// Sort order: folders first, then files. Sort folders and files alphabeticall
|
|
57
|
+
if ((!a.isFolder && !b.isFolder) || (a.isFolder && b.isFolder)) {
|
|
58
|
+
// numeric: true: Whether numeric collation should be used, such that "1" < "2" < "10"
|
|
59
|
+
// sensitivity: "base": Only strings that differ in base letters compare as unequal. Examples: a ≠ b, a = á, a = A
|
|
60
|
+
return a.displayName.localeCompare(b.displayName, undefined, {
|
|
61
|
+
numeric: true,
|
|
62
|
+
sensitivity: "base",
|
|
63
|
+
})
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (!a.isFolder && b.isFolder) {
|
|
67
|
+
return 1
|
|
68
|
+
} else {
|
|
69
|
+
return -1
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
filterFn: (node) => node.slugSegment !== "tags",
|
|
73
|
+
order: ["filter", "map", "sort"],
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export type FolderState = {
|
|
77
|
+
path: string
|
|
78
|
+
collapsed: boolean
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// brain overlay (Amendment #8): the upstream numExplorers counter is REMOVED.
|
|
82
|
+
// Each Explorer uses a slug-derived deterministic id instead.
|
|
83
|
+
// See file-level comment for full rationale.
|
|
84
|
+
|
|
85
|
+
export default ((userOpts?: Partial<Options>) => {
|
|
86
|
+
const opts: Options = { ...defaultOptions, ...userOpts }
|
|
87
|
+
const { OverflowList, overflowListAfterDOMLoaded } = OverflowListFactory()
|
|
88
|
+
|
|
89
|
+
// brain overlay (Amendment #8): accept fileData from props and derive a
|
|
90
|
+
// deterministic, slug-based aria-id for the Explorer component.
|
|
91
|
+
// ``/`` → ``-`` so ``COMPANY_REDACTED/AI-adoption`` becomes ``explorer-COMPANY_REDACTED-AI-adoption``.
|
|
92
|
+
const Explorer: QuartzComponent = ({ cfg, fileData, displayClass }: QuartzComponentProps) => {
|
|
93
|
+
// Slug-derived deterministic ID: stable across full-build render order and
|
|
94
|
+
// partial-build fresh processes. Replaces the upstream numExplorers counter.
|
|
95
|
+
const rawSlug = fileData?.slug ?? "root"
|
|
96
|
+
const slugId = rawSlug.replace(/\//g, "-")
|
|
97
|
+
const id = `explorer-${slugId}`
|
|
98
|
+
|
|
99
|
+
return (
|
|
100
|
+
<div
|
|
101
|
+
class={classNames(displayClass, "explorer")}
|
|
102
|
+
data-behavior={opts.folderClickBehavior}
|
|
103
|
+
data-collapsed={opts.folderDefaultState}
|
|
104
|
+
data-savestate={opts.useSavedState}
|
|
105
|
+
data-data-fns={JSON.stringify({
|
|
106
|
+
order: opts.order,
|
|
107
|
+
sortFn: opts.sortFn.toString(),
|
|
108
|
+
filterFn: opts.filterFn.toString(),
|
|
109
|
+
mapFn: opts.mapFn.toString(),
|
|
110
|
+
})}
|
|
111
|
+
>
|
|
112
|
+
<button
|
|
113
|
+
type="button"
|
|
114
|
+
class="explorer-toggle mobile-explorer hide-until-loaded"
|
|
115
|
+
data-mobile={true}
|
|
116
|
+
aria-controls={id}
|
|
117
|
+
>
|
|
118
|
+
<svg
|
|
119
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
120
|
+
width="24"
|
|
121
|
+
height="24"
|
|
122
|
+
viewBox="0 0 24 24"
|
|
123
|
+
stroke-width="2"
|
|
124
|
+
stroke-linecap="round"
|
|
125
|
+
stroke-linejoin="round"
|
|
126
|
+
class="lucide-menu"
|
|
127
|
+
>
|
|
128
|
+
<line x1="4" x2="20" y1="12" y2="12" />
|
|
129
|
+
<line x1="4" x2="20" y1="6" y2="6" />
|
|
130
|
+
<line x1="4" x2="20" y1="18" y2="18" />
|
|
131
|
+
</svg>
|
|
132
|
+
</button>
|
|
133
|
+
<button
|
|
134
|
+
type="button"
|
|
135
|
+
class="title-button explorer-toggle desktop-explorer"
|
|
136
|
+
data-mobile={false}
|
|
137
|
+
aria-expanded={true}
|
|
138
|
+
>
|
|
139
|
+
<h2>{opts.title ?? i18n(cfg.locale).components.explorer.title}</h2>
|
|
140
|
+
<svg
|
|
141
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
142
|
+
width="14"
|
|
143
|
+
height="14"
|
|
144
|
+
viewBox="5 8 14 8"
|
|
145
|
+
fill="none"
|
|
146
|
+
stroke="currentColor"
|
|
147
|
+
stroke-width="2"
|
|
148
|
+
stroke-linecap="round"
|
|
149
|
+
stroke-linejoin="round"
|
|
150
|
+
class="fold"
|
|
151
|
+
>
|
|
152
|
+
<polyline points="6 9 12 15 18 9"></polyline>
|
|
153
|
+
</svg>
|
|
154
|
+
</button>
|
|
155
|
+
<div id={id} class="explorer-content" aria-expanded={false} role="group">
|
|
156
|
+
<OverflowList class="explorer-ul" />
|
|
157
|
+
</div>
|
|
158
|
+
<template id="template-file">
|
|
159
|
+
<li>
|
|
160
|
+
<a href="#"></a>
|
|
161
|
+
</li>
|
|
162
|
+
</template>
|
|
163
|
+
<template id="template-folder">
|
|
164
|
+
<li>
|
|
165
|
+
<div class="folder-container">
|
|
166
|
+
<svg
|
|
167
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
168
|
+
width="12"
|
|
169
|
+
height="12"
|
|
170
|
+
viewBox="5 8 14 8"
|
|
171
|
+
fill="none"
|
|
172
|
+
stroke="currentColor"
|
|
173
|
+
stroke-width="2"
|
|
174
|
+
stroke-linecap="round"
|
|
175
|
+
stroke-linejoin="round"
|
|
176
|
+
class="folder-icon"
|
|
177
|
+
>
|
|
178
|
+
<polyline points="6 9 12 15 18 9"></polyline>
|
|
179
|
+
</svg>
|
|
180
|
+
<div>
|
|
181
|
+
<button class="folder-button">
|
|
182
|
+
<span class="folder-title"></span>
|
|
183
|
+
</button>
|
|
184
|
+
</div>
|
|
185
|
+
</div>
|
|
186
|
+
<div class="folder-outer">
|
|
187
|
+
<ul class="content"></ul>
|
|
188
|
+
</div>
|
|
189
|
+
</li>
|
|
190
|
+
</template>
|
|
191
|
+
</div>
|
|
192
|
+
)
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
Explorer.css = style
|
|
196
|
+
Explorer.afterDOMLoaded = concatenateResources(script, overflowListAfterDOMLoaded)
|
|
197
|
+
return Explorer
|
|
198
|
+
}) satisfies QuartzComponentConstructor
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { QuartzComponent, QuartzComponentConstructor } from "./types"
|
|
2
|
+
|
|
3
|
+
interface Options {
|
|
4
|
+
links: Record<string, string>
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export default ((opts?: Options) => {
|
|
8
|
+
const githubUrl = opts?.links?.GitHub
|
|
9
|
+
|
|
10
|
+
const Footer: QuartzComponent = () => (
|
|
11
|
+
<footer>
|
|
12
|
+
<p>
|
|
13
|
+
Second Brain
|
|
14
|
+
{githubUrl ? (
|
|
15
|
+
<>
|
|
16
|
+
{" "}
|
|
17
|
+
(<a href={githubUrl}>GitHub</a>)
|
|
18
|
+
</>
|
|
19
|
+
) : null}{" "}
|
|
20
|
+
· © 2026 · notes for my future self · powered by{" "}
|
|
21
|
+
<a href="https://quartz.jzhao.xyz/">Quartz</a>
|
|
22
|
+
</p>
|
|
23
|
+
</footer>
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
return Footer
|
|
27
|
+
}) satisfies QuartzComponentConstructor
|