jekyll-theme-zer0 1.2.1 → 1.4.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +67 -0
- data/README.md +28 -4
- data/_includes/components/js-cdn.html +12 -1
- data/_includes/content/backlinks.html +107 -0
- data/_includes/content/transclude.html +62 -0
- data/_includes/navigation/local-graph.html +79 -0
- data/_includes/navigation/sidebar-left.html +6 -0
- data/_layouts/default.html +104 -91
- data/_layouts/note.html +7 -1
- data/_plugins/obsidian_links.rb +427 -0
- data/_sass/core/_obsidian.scss +242 -0
- data/_sass/core/_offcanvas-panels.scss +8 -4
- data/_sass/custom.scss +3 -0
- data/assets/data/wiki-index.json +74 -0
- data/assets/js/obsidian-graph.js +475 -0
- data/assets/js/obsidian-local-graph.js +434 -0
- data/assets/js/obsidian-wiki-links.js +358 -0
- data/scripts/README.md +22 -0
- data/scripts/bin/test +62 -0
- data/scripts/bin/validate +596 -0
- data/scripts/lib/README.md +16 -0
- data/scripts/lint-pages +6 -0
- data/scripts/validate +11 -0
- metadata +13 -2
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// _obsidian.scss — Styles for Obsidian-flavoured Markdown features.
|
|
3
|
+
// Imported from _sass/custom.scss.
|
|
4
|
+
//
|
|
5
|
+
// Covers:
|
|
6
|
+
// - Wiki-links (resolved + broken state)
|
|
7
|
+
// - Inline tags
|
|
8
|
+
// - Note transclusion / image embeds
|
|
9
|
+
// - Callout cards beyond what Bootstrap's `.alert` provides
|
|
10
|
+
// - Backlinks panel
|
|
11
|
+
// ============================================================================
|
|
12
|
+
|
|
13
|
+
// --- Wiki-links ------------------------------------------------------------
|
|
14
|
+
.wiki-link {
|
|
15
|
+
text-decoration: none;
|
|
16
|
+
border-bottom: 1px dashed currentColor;
|
|
17
|
+
font-weight: 500;
|
|
18
|
+
|
|
19
|
+
&:hover {
|
|
20
|
+
text-decoration: underline;
|
|
21
|
+
border-bottom-color: transparent;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
&[aria-current="page"] {
|
|
25
|
+
background-color: rgba(var(--bs-primary-rgb), 0.08);
|
|
26
|
+
padding: 0 0.15rem;
|
|
27
|
+
border-radius: 0.2rem;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.wiki-link-broken {
|
|
32
|
+
color: var(--bs-danger);
|
|
33
|
+
border-bottom-style: dotted;
|
|
34
|
+
cursor: help;
|
|
35
|
+
|
|
36
|
+
&:hover {
|
|
37
|
+
color: var(--bs-danger);
|
|
38
|
+
background-color: rgba(var(--bs-danger-rgb), 0.05);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// --- Inline tags -----------------------------------------------------------
|
|
43
|
+
.obsidian-tag {
|
|
44
|
+
display: inline-block;
|
|
45
|
+
padding: 0.05rem 0.45rem;
|
|
46
|
+
margin: 0 0.1rem;
|
|
47
|
+
font-size: 0.85em;
|
|
48
|
+
font-weight: 500;
|
|
49
|
+
color: var(--bs-secondary);
|
|
50
|
+
background-color: rgba(var(--bs-secondary-rgb), 0.1);
|
|
51
|
+
border-radius: 0.5rem;
|
|
52
|
+
text-decoration: none;
|
|
53
|
+
transition: background-color 0.15s ease;
|
|
54
|
+
|
|
55
|
+
&:hover,
|
|
56
|
+
&:focus {
|
|
57
|
+
background-color: rgba(var(--bs-secondary-rgb), 0.2);
|
|
58
|
+
color: var(--bs-primary);
|
|
59
|
+
text-decoration: none;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// --- Embeds (image + note transclusion) -----------------------------------
|
|
64
|
+
.obsidian-embed-image {
|
|
65
|
+
display: block;
|
|
66
|
+
max-width: 100%;
|
|
67
|
+
height: auto;
|
|
68
|
+
margin: 1rem auto;
|
|
69
|
+
border-radius: 0.375rem;
|
|
70
|
+
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.obsidian-embed-note {
|
|
74
|
+
border-left: 3px solid var(--bs-primary);
|
|
75
|
+
|
|
76
|
+
.obsidian-embed-source {
|
|
77
|
+
font-size: 0.875rem;
|
|
78
|
+
color: var(--bs-secondary);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.obsidian-embed-body {
|
|
82
|
+
background-color: rgba(var(--bs-light-rgb), 0.5);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
[data-bs-theme="dark"] & .obsidian-embed-body {
|
|
86
|
+
background-color: rgba(var(--bs-dark-rgb), 0.4);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.obsidian-embed-broken {
|
|
91
|
+
font-size: 0.9rem;
|
|
92
|
+
|
|
93
|
+
code {
|
|
94
|
+
background-color: rgba(0, 0, 0, 0.06);
|
|
95
|
+
padding: 0.1rem 0.3rem;
|
|
96
|
+
border-radius: 0.25rem;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// --- Callouts -------------------------------------------------------------
|
|
101
|
+
.obsidian-callout {
|
|
102
|
+
border-left-width: 4px;
|
|
103
|
+
border-left-style: solid;
|
|
104
|
+
margin: 1.25rem 0;
|
|
105
|
+
padding: 0.85rem 1rem;
|
|
106
|
+
|
|
107
|
+
.obsidian-callout-title {
|
|
108
|
+
font-weight: 600;
|
|
109
|
+
margin-bottom: 0.4rem;
|
|
110
|
+
display: flex;
|
|
111
|
+
align-items: center;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.obsidian-callout-body {
|
|
115
|
+
margin: 0;
|
|
116
|
+
|
|
117
|
+
> :last-child {
|
|
118
|
+
margin-bottom: 0;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
&[data-collapsed="true"] .obsidian-callout-body {
|
|
123
|
+
display: none;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// --- Backlinks panel -------------------------------------------------------
|
|
128
|
+
.obsidian-backlinks {
|
|
129
|
+
.obsidian-backlinks-list {
|
|
130
|
+
margin-bottom: 0;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.obsidian-backlink {
|
|
134
|
+
padding: 0.5rem 0.75rem;
|
|
135
|
+
border-left: 2px solid transparent;
|
|
136
|
+
border-radius: 0 0.25rem 0.25rem 0;
|
|
137
|
+
transition: background-color 0.15s ease, border-color 0.15s ease;
|
|
138
|
+
|
|
139
|
+
&:hover {
|
|
140
|
+
background-color: rgba(var(--bs-primary-rgb), 0.05);
|
|
141
|
+
border-left-color: var(--bs-primary);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.obsidian-backlink-link {
|
|
146
|
+
text-decoration: none;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.obsidian-backlink-excerpt {
|
|
150
|
+
margin-top: 0.2rem;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// ----------------------------------------------------------------------------
|
|
155
|
+
// Local graph side panel — Obsidian-style local graph view.
|
|
156
|
+
// Rendered by _includes/navigation/local-graph.html via assets/js/obsidian-local-graph.js.
|
|
157
|
+
// ----------------------------------------------------------------------------
|
|
158
|
+
.obsidian-local-graph-fab {
|
|
159
|
+
position: fixed;
|
|
160
|
+
left: 1rem;
|
|
161
|
+
bottom: 1rem;
|
|
162
|
+
z-index: 1032;
|
|
163
|
+
|
|
164
|
+
&[hidden] {
|
|
165
|
+
display: none !important;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
.obsidian-local-graph-toggle {
|
|
170
|
+
width: 3.25rem;
|
|
171
|
+
height: 3.25rem;
|
|
172
|
+
display: inline-flex;
|
|
173
|
+
align-items: center;
|
|
174
|
+
justify-content: center;
|
|
175
|
+
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
|
176
|
+
|
|
177
|
+
&:hover,
|
|
178
|
+
&:focus-visible {
|
|
179
|
+
transform: translateY(-1px);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
&:active {
|
|
183
|
+
transform: translateY(0);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.obsidian-local-graph-panel {
|
|
188
|
+
--bs-offcanvas-width: min(28rem, calc(100vw - 1.5rem));
|
|
189
|
+
|
|
190
|
+
&[hidden] {
|
|
191
|
+
display: none !important;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.offcanvas-body {
|
|
195
|
+
display: flex;
|
|
196
|
+
flex-direction: column;
|
|
197
|
+
min-height: 0;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
.obsidian-local-graph-widget {
|
|
202
|
+
display: flex;
|
|
203
|
+
flex: 1 1 auto;
|
|
204
|
+
flex-direction: column;
|
|
205
|
+
min-height: 0;
|
|
206
|
+
|
|
207
|
+
.obsidian-local-graph-meta {
|
|
208
|
+
flex: 0 0 auto;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
#obsidian-local-graph {
|
|
212
|
+
flex: 1 1 auto;
|
|
213
|
+
width: 100%;
|
|
214
|
+
height: min(62vh, 34rem);
|
|
215
|
+
min-height: 22rem;
|
|
216
|
+
border: 1px solid var(--bs-border-color, #dee2e6);
|
|
217
|
+
border-radius: var(--bs-border-radius-lg, 0.5rem);
|
|
218
|
+
background: var(--bs-tertiary-bg, #f8f9fa);
|
|
219
|
+
overflow: hidden;
|
|
220
|
+
position: relative;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.obsidian-local-graph-status {
|
|
224
|
+
min-height: 1.25rem;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
@media (max-width: 575.98px) {
|
|
229
|
+
.obsidian-local-graph-fab {
|
|
230
|
+
left: 0.875rem;
|
|
231
|
+
bottom: 0.875rem;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
.obsidian-local-graph-panel {
|
|
235
|
+
--bs-offcanvas-width: min(100vw, 24rem);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
.obsidian-local-graph-widget #obsidian-local-graph {
|
|
239
|
+
height: 58vh;
|
|
240
|
+
min-height: 18rem;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
@@ -4,13 +4,15 @@
|
|
|
4
4
|
// =============================================================================
|
|
5
5
|
|
|
6
6
|
#bdSidebar .offcanvas-header,
|
|
7
|
-
#tocContents .offcanvas-header
|
|
7
|
+
#tocContents .offcanvas-header,
|
|
8
|
+
#obsidianLocalGraphPanel .offcanvas-header {
|
|
8
9
|
border-bottom: 2px solid var(--bs-border-color);
|
|
9
10
|
padding: 1.25rem 1rem;
|
|
10
11
|
}
|
|
11
12
|
|
|
12
13
|
#bdSidebar .offcanvas-title,
|
|
13
|
-
#tocContents .offcanvas-title
|
|
14
|
+
#tocContents .offcanvas-title,
|
|
15
|
+
#obsidianLocalGraphPanel .offcanvas-title {
|
|
14
16
|
font-size: 1.125rem;
|
|
15
17
|
font-weight: 600;
|
|
16
18
|
color: var(--bs-emphasis-color);
|
|
@@ -19,7 +21,8 @@
|
|
|
19
21
|
|
|
20
22
|
@media (max-width: 991.98px) {
|
|
21
23
|
#bdSidebar .offcanvas-header .btn-close,
|
|
22
|
-
#tocContents .offcanvas-header .btn-close
|
|
24
|
+
#tocContents .offcanvas-header .btn-close,
|
|
25
|
+
#obsidianLocalGraphPanel .offcanvas-header .btn-close {
|
|
23
26
|
width: 48px;
|
|
24
27
|
height: 48px;
|
|
25
28
|
padding: 0;
|
|
@@ -36,7 +39,8 @@
|
|
|
36
39
|
}
|
|
37
40
|
}
|
|
38
41
|
|
|
39
|
-
#tocContents .offcanvas-body
|
|
42
|
+
#tocContents .offcanvas-body,
|
|
43
|
+
#obsidianLocalGraphPanel .offcanvas-body {
|
|
40
44
|
padding: 1rem;
|
|
41
45
|
}
|
|
42
46
|
|
data/_sass/custom.scss
CHANGED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
---
|
|
2
|
+
# Generated wiki-link index for Obsidian-style [[…]] resolution on the
|
|
3
|
+
# rendered site. Consumed by:
|
|
4
|
+
# - assets/js/obsidian-wiki-links.js (client-side fallback used on the
|
|
5
|
+
# GitHub Pages remote_theme build, where _plugins/obsidian_links.rb
|
|
6
|
+
# does not run)
|
|
7
|
+
# - _includes/content/backlinks.html (per-page backlinks panel)
|
|
8
|
+
#
|
|
9
|
+
# Output: assets/data/wiki-index.json
|
|
10
|
+
#
|
|
11
|
+
# Layout: null so Jekyll just renders the body verbatim.
|
|
12
|
+
layout: null
|
|
13
|
+
permalink: /assets/data/wiki-index.json
|
|
14
|
+
sitemap: false
|
|
15
|
+
---
|
|
16
|
+
{%- comment -%}
|
|
17
|
+
Build a flat array of every renderable document with title, basename,
|
|
18
|
+
permalink, collection, tags, and the body's outgoing wiki-link targets.
|
|
19
|
+
The JS resolver normalizes lookup keys to lowercase + collapsed whitespace
|
|
20
|
+
(matching _plugins/obsidian_links.rb#normalize).
|
|
21
|
+
{%- endcomment -%}
|
|
22
|
+
{%- assign all_docs = "" | split: "" -%}
|
|
23
|
+
{%- for collection in site.collections -%}
|
|
24
|
+
{%- for doc in collection.docs -%}
|
|
25
|
+
{%- assign all_docs = all_docs | push: doc -%}
|
|
26
|
+
{%- endfor -%}
|
|
27
|
+
{%- endfor -%}
|
|
28
|
+
{%- for page in site.pages -%}
|
|
29
|
+
{%- if page.output_ext == ".html" and page.url -%}
|
|
30
|
+
{%- assign all_docs = all_docs | push: page -%}
|
|
31
|
+
{%- endif -%}
|
|
32
|
+
{%- endfor -%}
|
|
33
|
+
{
|
|
34
|
+
"generated_at": {{ site.time | date_to_xmlschema | jsonify }},
|
|
35
|
+
"count": {{ all_docs.size | jsonify }},
|
|
36
|
+
"entries": [
|
|
37
|
+
{%- for doc in all_docs -%}
|
|
38
|
+
{%- assign basename = doc.path | split: "/" | last | replace: ".md", "" | replace: ".markdown", "" | replace: ".html", "" -%}
|
|
39
|
+
{%- assign body = doc.content | default: "" | strip_html -%}
|
|
40
|
+
{%- assign body_excerpt = body | strip_newlines | truncate: 240 -%}
|
|
41
|
+
{%- comment -%}
|
|
42
|
+
Extract outgoing wiki-link targets so the graph view
|
|
43
|
+
(assets/js/obsidian-graph.js) can render edges without re-parsing
|
|
44
|
+
every page client-side. We mask `![[…]]` embeds first so they don't
|
|
45
|
+
also get split as `[[…]]`, then split on `[[`, take everything
|
|
46
|
+
before `]]`, and strip the optional `|alias` and `#anchor` parts.
|
|
47
|
+
{%- endcomment -%}
|
|
48
|
+
{%- assign masked = body | replace: "![[", "@@OBSEMBED@@" -%}
|
|
49
|
+
{%- assign chunks = masked | split: "[[" -%}
|
|
50
|
+
{%- assign outgoing = "" | split: "" -%}
|
|
51
|
+
{%- for chunk in chunks offset: 1 -%}
|
|
52
|
+
{%- assign target_raw = chunk | split: "]]" | first -%}
|
|
53
|
+
{%- if target_raw and target_raw != "" -%}
|
|
54
|
+
{%- assign target = target_raw | split: "|" | first | split: "#" | first | split: "^" | first | strip | downcase -%}
|
|
55
|
+
{%- if target != "" and target.size < 200 -%}
|
|
56
|
+
{%- assign outgoing = outgoing | push: target -%}
|
|
57
|
+
{%- endif -%}
|
|
58
|
+
{%- endif -%}
|
|
59
|
+
{%- endfor -%}
|
|
60
|
+
{%- assign outgoing = outgoing | uniq -%}
|
|
61
|
+
{
|
|
62
|
+
"title": {{ doc.title | default: basename | jsonify }},
|
|
63
|
+
"basename": {{ basename | jsonify }},
|
|
64
|
+
"url": {{ doc.url | jsonify }},
|
|
65
|
+
"collection": {{ doc.collection | default: nil | jsonify }},
|
|
66
|
+
"tags": {{ doc.tags | default: empty | jsonify }},
|
|
67
|
+
"categories": {{ doc.categories | default: empty | jsonify }},
|
|
68
|
+
"aliases": {{ doc.aliases | default: empty | jsonify }},
|
|
69
|
+
"outgoing": {{ outgoing | jsonify }},
|
|
70
|
+
"excerpt": {{ body_excerpt | jsonify }}
|
|
71
|
+
}{% unless forloop.last %},{% endunless %}
|
|
72
|
+
{%- endfor -%}
|
|
73
|
+
]
|
|
74
|
+
}
|