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.
@@ -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
@@ -12,6 +12,9 @@
12
12
  @import "core/navbar";
13
13
  @import "core/offcanvas-panels";
14
14
 
15
+ // Obsidian-flavoured markdown features (wiki-links, callouts, backlinks, …)
16
+ @import "core/obsidian";
17
+
15
18
  html, body {
16
19
  max-width: 100%;
17
20
  // overflow-x: hidden;
@@ -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
+ }