jekyll-theme-merida 0.0.1
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 +7 -0
- data/README.md +1 -0
- data/_config.yml +50 -0
- data/_data/menu.yaml +16 -0
- data/_data/repos.yaml +21 -0
- data/_data/social.yaml +10 -0
- data/_includes/footer.html +22 -0
- data/_includes/header.html +18 -0
- data/_includes/latest-news.html +18 -0
- data/_includes/latest-posts.html +9 -0
- data/_includes/navbar.html +67 -0
- data/_includes/post-body.html +5 -0
- data/_includes/search-modal.html +43 -0
- data/_layouts/404.html +28 -0
- data/_layouts/about.html +34 -0
- data/_layouts/base.html +21 -0
- data/_layouts/bib.html +65 -0
- data/_layouts/blog.html +46 -0
- data/_layouts/news.html +35 -0
- data/_layouts/post.html +74 -0
- data/_layouts/projects.html +31 -0
- data/_layouts/publications.html +8 -0
- data/assets/css/app.css +213 -0
- data/assets/css/github-dark.css +116 -0
- data/assets/favicon/android-chrome-192x192.png +0 -0
- data/assets/favicon/android-chrome-512x512.png +0 -0
- data/assets/favicon/apple-touch-icon.png +0 -0
- data/assets/favicon/favicon-16x16.png +0 -0
- data/assets/favicon/favicon-32x32.png +0 -0
- data/assets/favicon/favicon.ico +0 -0
- data/assets/favicon/site.webmanifest +1 -0
- data/assets/img/backgrounds/bg-1.jpg +0 -0
- data/assets/img/profile_pic.jpg +0 -0
- data/assets/scripts/copy-code.js +104 -0
- data/assets/scripts/mathjax-config.js +12 -0
- data/assets/scripts/navbar.js +9 -0
- data/assets/scripts/search.js +99 -0
- data/assets/scripts/table-wrapper.js +15 -0
- data/assets/scripts/without-prose.js +9 -0
- metadata +189 -0
data/assets/css/app.css
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
/* Overrides of Tailwind Theme */
|
|
2
|
+
@import url('https://fonts.googleapis.com/css2?family=Source+Sans+3:ital,wght@0,200..900;1,200..900&display=swap');
|
|
3
|
+
@import url('https://fonts.googleapis.com/css2?family=Gilda+Display&display=swap');
|
|
4
|
+
|
|
5
|
+
@import "tailwindcss";
|
|
6
|
+
|
|
7
|
+
@plugin "@tailwindcss/typography";
|
|
8
|
+
|
|
9
|
+
@theme {
|
|
10
|
+
--font-sans: "Source Sans", ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji",
|
|
11
|
+
"Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
|
12
|
+
--font-gilda: "Gilda Display";
|
|
13
|
+
--font-main: var(--font-sans);
|
|
14
|
+
--color-border-main: var(--color-gray-400);
|
|
15
|
+
--color-primary: var(--color-blue-600);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.max-w-theme {
|
|
19
|
+
@apply max-w-6xl;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/* ************************************************************** */
|
|
23
|
+
|
|
24
|
+
/* Styles of basic HTML elements */
|
|
25
|
+
html {
|
|
26
|
+
@apply overflow-y-scroll;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
em:not(li *) {
|
|
30
|
+
@apply block text-center
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
img:has(+ em) {
|
|
34
|
+
@apply mb-0;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
.manual-h1 {
|
|
39
|
+
@apply text-2xl sm:text-4xl md:text-5xl lg:text-6xl;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/* Task List Styling — checkboxes visible, bullets removed, checked items green */
|
|
43
|
+
ul.task-list {
|
|
44
|
+
@apply list-none p-0 m-0 space-y-2;
|
|
45
|
+
/* remove bullets, vertical spacing */
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
ul.task-list li {
|
|
49
|
+
@apply flex items-center;
|
|
50
|
+
/* align checkbox and text */
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
ul.task-list li input[type="checkbox"] {
|
|
54
|
+
@apply mr-2;
|
|
55
|
+
/* spacing between checkbox and text */
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/* Make checked tasks green */
|
|
59
|
+
ul.task-list li input[type="checkbox"]:checked + * {
|
|
60
|
+
@apply text-green-600 font-medium;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.main a {
|
|
64
|
+
@apply text-primary;
|
|
65
|
+
@apply no-underline;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/* All tables except ones inside .highlight */
|
|
69
|
+
|
|
70
|
+
.main table:not(.highlight table) {
|
|
71
|
+
@apply border-collapse border border-gray-200 text-left mb-4 min-w-full;
|
|
72
|
+
|
|
73
|
+
caption {
|
|
74
|
+
@apply text-sm font-semibold mb-2;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
thead {
|
|
78
|
+
@apply bg-gray-100;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
th {
|
|
82
|
+
@apply px-4 py-2 border-b border-gray-300 font-medium text-gray-700;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
td {
|
|
86
|
+
@apply px-4 py-2 border-b border-gray-200 text-gray-600;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
tbody tr:hover {
|
|
90
|
+
@apply bg-gray-50;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/* Optional: for color swatches or inner divs */
|
|
94
|
+
|
|
95
|
+
td div[data-theme] {
|
|
96
|
+
@apply w-12 aspect-square border border-gray-300;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.table-wrapper {
|
|
101
|
+
@apply overflow-x-auto mb-4;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/* ************************************************************** */
|
|
105
|
+
|
|
106
|
+
/* Code Highlighting styles */
|
|
107
|
+
:not(pre) > code {
|
|
108
|
+
@apply text-gray-600;
|
|
109
|
+
@apply bg-blue-50;
|
|
110
|
+
@apply px-1.5;
|
|
111
|
+
@apply py-0.5;
|
|
112
|
+
@apply rounded;
|
|
113
|
+
@apply font-light;
|
|
114
|
+
@apply font-main;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/* ************************************************************** */
|
|
118
|
+
|
|
119
|
+
/* Code Highlighting styles */
|
|
120
|
+
:not(pre) > code {
|
|
121
|
+
@apply text-gray-600;
|
|
122
|
+
@apply bg-blue-50;
|
|
123
|
+
@apply px-1.5;
|
|
124
|
+
@apply py-0.5;
|
|
125
|
+
@apply rounded;
|
|
126
|
+
@apply font-light;
|
|
127
|
+
@apply font-main;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/*
|
|
131
|
+
adds rounded corners, padding syntax and horizontal scroll bar to the code block
|
|
132
|
+
author: epigone707
|
|
133
|
+
*/
|
|
134
|
+
pre.highlight {
|
|
135
|
+
padding: 7px;
|
|
136
|
+
/* cause a scrolling mechanism to be provided for overflowing boxes */
|
|
137
|
+
overflow-x: auto;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
figure.highlight > pre {
|
|
141
|
+
padding: 7px;
|
|
142
|
+
overflow-x: auto;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/* Default highlight spacing */
|
|
146
|
+
.highlight {
|
|
147
|
+
border-radius: 5px;
|
|
148
|
+
@apply mb-2;
|
|
149
|
+
margin-top: 1rem; /* default */
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/* Remove top margin if the highlight's parent is inside highlighter-rouge
|
|
153
|
+
AND the highlighter-rouge div is immediately after a paragraph */
|
|
154
|
+
p + .highlighter-rouge .highlight {
|
|
155
|
+
@apply mt-0;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.rouge-gutter {
|
|
159
|
+
@apply border-r border-gray-300 pr-2;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.rouge-code pre {
|
|
163
|
+
@apply pl-2;
|
|
164
|
+
/* optional: spacing so code doesn’t touch line */
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.language-plaintext.highlighter-rouge {
|
|
168
|
+
position: relative; /* make outer div relative */
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
.language-plaintext.highlighter-rouge pre.highlight {
|
|
172
|
+
position: static; /* remove relative from inner pre */
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/* for making copy button accessible in mobile and tablet */
|
|
176
|
+
.copy-button {
|
|
177
|
+
touch-action: manipulation; /* ensures the tap is recognized */
|
|
178
|
+
z-index: 10; /* above everything */
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/* ************************************************************** */
|
|
182
|
+
|
|
183
|
+
/* Styles for Bibliography */
|
|
184
|
+
.bibliography {
|
|
185
|
+
@apply pl-0!;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.bibliography li {
|
|
189
|
+
@apply list-none!;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/* ************************************************************** */
|
|
193
|
+
|
|
194
|
+
/* Search utility styles */
|
|
195
|
+
|
|
196
|
+
@keyframes modal-overshoot {
|
|
197
|
+
0% {
|
|
198
|
+
transform: scale(0.9);
|
|
199
|
+
opacity: 0;
|
|
200
|
+
}
|
|
201
|
+
70% {
|
|
202
|
+
transform: scale(1.03);
|
|
203
|
+
opacity: 1;
|
|
204
|
+
}
|
|
205
|
+
100% {
|
|
206
|
+
transform: scale(1);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
.modal-animate {
|
|
211
|
+
animation: modal-overshoot 150ms ease-out;
|
|
212
|
+
}
|
|
213
|
+
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
.highlight table td { padding: 5px; }
|
|
2
|
+
.highlight table pre { margin: 0; }
|
|
3
|
+
.highlight, .highlight .w {
|
|
4
|
+
color: #c9d1d9;
|
|
5
|
+
background-color: #161b22;
|
|
6
|
+
}
|
|
7
|
+
.highlight .k, .highlight .kd, .highlight .kn, .highlight .kp, .highlight .kr, .highlight .kt, .highlight .kv {
|
|
8
|
+
color: #ff7b72;
|
|
9
|
+
}
|
|
10
|
+
.highlight .gr {
|
|
11
|
+
color: #f0f6fc;
|
|
12
|
+
}
|
|
13
|
+
.highlight .gd {
|
|
14
|
+
color: #ffdcd7;
|
|
15
|
+
background-color: #67060c;
|
|
16
|
+
}
|
|
17
|
+
.highlight .nb {
|
|
18
|
+
color: #ffa657;
|
|
19
|
+
}
|
|
20
|
+
.highlight .nc {
|
|
21
|
+
color: #ffa657;
|
|
22
|
+
}
|
|
23
|
+
.highlight .no {
|
|
24
|
+
color: #ffa657;
|
|
25
|
+
}
|
|
26
|
+
.highlight .nn {
|
|
27
|
+
color: #ffa657;
|
|
28
|
+
}
|
|
29
|
+
.highlight .sr {
|
|
30
|
+
color: #7ee787;
|
|
31
|
+
}
|
|
32
|
+
.highlight .na {
|
|
33
|
+
color: #7ee787;
|
|
34
|
+
}
|
|
35
|
+
.highlight .nt {
|
|
36
|
+
color: #7ee787;
|
|
37
|
+
}
|
|
38
|
+
.highlight .gi {
|
|
39
|
+
color: #aff5b4;
|
|
40
|
+
background-color: #033a16;
|
|
41
|
+
}
|
|
42
|
+
.highlight .ges {
|
|
43
|
+
font-weight: bold;
|
|
44
|
+
font-style: italic;
|
|
45
|
+
}
|
|
46
|
+
.highlight .kc {
|
|
47
|
+
color: #79c0ff;
|
|
48
|
+
}
|
|
49
|
+
.highlight .l, .highlight .ld, .highlight .m, .highlight .mb, .highlight .mf, .highlight .mh, .highlight .mi, .highlight .il, .highlight .mo, .highlight .mx {
|
|
50
|
+
color: #79c0ff;
|
|
51
|
+
}
|
|
52
|
+
.highlight .sb {
|
|
53
|
+
color: #79c0ff;
|
|
54
|
+
}
|
|
55
|
+
.highlight .bp {
|
|
56
|
+
color: #79c0ff;
|
|
57
|
+
}
|
|
58
|
+
.highlight .ne {
|
|
59
|
+
color: #79c0ff;
|
|
60
|
+
}
|
|
61
|
+
.highlight .nl {
|
|
62
|
+
color: #79c0ff;
|
|
63
|
+
}
|
|
64
|
+
.highlight .py {
|
|
65
|
+
color: #79c0ff;
|
|
66
|
+
}
|
|
67
|
+
.highlight .nv, .highlight .vc, .highlight .vg, .highlight .vi, .highlight .vm {
|
|
68
|
+
color: #79c0ff;
|
|
69
|
+
}
|
|
70
|
+
.highlight .o, .highlight .ow {
|
|
71
|
+
color: #79c0ff;
|
|
72
|
+
}
|
|
73
|
+
.highlight .gh {
|
|
74
|
+
color: #1f6feb;
|
|
75
|
+
font-weight: bold;
|
|
76
|
+
}
|
|
77
|
+
.highlight .gu {
|
|
78
|
+
color: #1f6feb;
|
|
79
|
+
font-weight: bold;
|
|
80
|
+
}
|
|
81
|
+
.highlight .s, .highlight .sa, .highlight .sc, .highlight .dl, .highlight .sd, .highlight .s2, .highlight .se, .highlight .sh, .highlight .sx, .highlight .s1, .highlight .ss {
|
|
82
|
+
color: #a5d6ff;
|
|
83
|
+
}
|
|
84
|
+
.highlight .nd {
|
|
85
|
+
color: #d2a8ff;
|
|
86
|
+
}
|
|
87
|
+
.highlight .nf, .highlight .fm {
|
|
88
|
+
color: #d2a8ff;
|
|
89
|
+
}
|
|
90
|
+
.highlight .err {
|
|
91
|
+
color: #f0f6fc;
|
|
92
|
+
background-color: #8e1519;
|
|
93
|
+
}
|
|
94
|
+
.highlight .c, .highlight .ch, .highlight .cd, .highlight .cm, .highlight .cp, .highlight .cpf, .highlight .c1, .highlight .cs {
|
|
95
|
+
color: #8b949e;
|
|
96
|
+
}
|
|
97
|
+
.highlight .gl {
|
|
98
|
+
color: #8b949e;
|
|
99
|
+
}
|
|
100
|
+
.highlight .gt {
|
|
101
|
+
color: #8b949e;
|
|
102
|
+
}
|
|
103
|
+
.highlight .ni {
|
|
104
|
+
color: #c9d1d9;
|
|
105
|
+
}
|
|
106
|
+
.highlight .si {
|
|
107
|
+
color: #c9d1d9;
|
|
108
|
+
}
|
|
109
|
+
.highlight .ge {
|
|
110
|
+
color: #c9d1d9;
|
|
111
|
+
font-style: italic;
|
|
112
|
+
}
|
|
113
|
+
.highlight .gs {
|
|
114
|
+
color: #c9d1d9;
|
|
115
|
+
font-weight: bold;
|
|
116
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
// Adds a copy button to code blocks.
|
|
2
|
+
// It finds the code blocks and adds a button with capibility to copy the code into clipboard.
|
|
3
|
+
|
|
4
|
+
window.addEventListener("DOMContentLoaded", () => {
|
|
5
|
+
|
|
6
|
+
// Select all relevant code blocks
|
|
7
|
+
document.querySelectorAll(
|
|
8
|
+
"pre:has(table.rouge-table), figure.highlight > pre"
|
|
9
|
+
).forEach(pre => {
|
|
10
|
+
// prevent duplicates
|
|
11
|
+
if (pre.querySelector(":scope > .copy-button")) return;
|
|
12
|
+
|
|
13
|
+
pre.classList.add("relative");
|
|
14
|
+
|
|
15
|
+
const button = document.createElement("button");
|
|
16
|
+
button.type = "button";
|
|
17
|
+
button.textContent = "Copy";
|
|
18
|
+
button.className =
|
|
19
|
+
"copy-button absolute top-2 right-2 px-2 py-1 text-xs " +
|
|
20
|
+
"bg-gray-600 text-white border-white border-1 rounded hover:bg-gray-700 cursor-pointer";
|
|
21
|
+
|
|
22
|
+
pre.appendChild(button);
|
|
23
|
+
|
|
24
|
+
button.addEventListener("click", async () => {
|
|
25
|
+
let text = "";
|
|
26
|
+
|
|
27
|
+
// Case 1 & 2: table inside pre/code
|
|
28
|
+
const table = pre.querySelector("table.rouge-table");
|
|
29
|
+
if (table) {
|
|
30
|
+
const codeCell = table.querySelector("td.code > pre, td.rouge-code > pre");
|
|
31
|
+
if (codeCell) text = codeCell.textContent;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Case 3: plain code inside pre > code
|
|
35
|
+
if (!text) {
|
|
36
|
+
const code = pre.querySelector("code");
|
|
37
|
+
if (code) text = code.textContent;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (!text) return;
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
await navigator.clipboard.writeText(text);
|
|
44
|
+
button.textContent = "Copied!";
|
|
45
|
+
setTimeout(() => (button.textContent = "Copy"), 2000);
|
|
46
|
+
} catch (err) {
|
|
47
|
+
console.error("Failed to copy:", err);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
window.addEventListener("DOMContentLoaded", () => {
|
|
55
|
+
document.querySelectorAll(".bibtex-toggle").forEach(button => {
|
|
56
|
+
button.addEventListener("click", () => {
|
|
57
|
+
const container = button.closest(".bib-entry");
|
|
58
|
+
if (!container) return;
|
|
59
|
+
|
|
60
|
+
const details = container.querySelector(".bibtex-details");
|
|
61
|
+
if (!details) return;
|
|
62
|
+
|
|
63
|
+
details.open = !details.open;
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
// Adds a copy button to BibTeX pre blocks inside details
|
|
69
|
+
window.addEventListener("DOMContentLoaded", () => {
|
|
70
|
+
|
|
71
|
+
// Select all pre blocks inside details (BibTeX)
|
|
72
|
+
document.querySelectorAll("details > pre").forEach(pre => {
|
|
73
|
+
|
|
74
|
+
// Prevent duplicates
|
|
75
|
+
if (pre.querySelector(":scope > .copy-button")) return;
|
|
76
|
+
|
|
77
|
+
pre.classList.add("relative");
|
|
78
|
+
|
|
79
|
+
// Create button
|
|
80
|
+
const button = document.createElement("button");
|
|
81
|
+
button.type = "button";
|
|
82
|
+
button.textContent = "Copy";
|
|
83
|
+
button.className =
|
|
84
|
+
"copy-button absolute top-2 right-2 px-2 py-1 text-xs " +
|
|
85
|
+
"bg-gray-600 text-white border-white border-1 rounded hover:bg-gray-700 cursor-pointer";
|
|
86
|
+
|
|
87
|
+
pre.appendChild(button);
|
|
88
|
+
|
|
89
|
+
// Copy event
|
|
90
|
+
button.addEventListener("click", async () => {
|
|
91
|
+
const text = pre.textContent; // grab all text inside pre
|
|
92
|
+
if (!text) return;
|
|
93
|
+
|
|
94
|
+
try {
|
|
95
|
+
await navigator.clipboard.writeText(text);
|
|
96
|
+
button.textContent = "Copied!";
|
|
97
|
+
setTimeout(() => (button.textContent = "Copy"), 2000);
|
|
98
|
+
} catch (err) {
|
|
99
|
+
console.error("Failed to copy:", err);
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// Opening and closing the sandwich menu
|
|
2
|
+
document.addEventListener("DOMContentLoaded", function () {
|
|
3
|
+
const btn = document.getElementById("menu-btn");
|
|
4
|
+
const menu = document.getElementById("mobile-menu");
|
|
5
|
+
|
|
6
|
+
btn.addEventListener("click", function () {
|
|
7
|
+
menu.classList.toggle("hidden");
|
|
8
|
+
});
|
|
9
|
+
});
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
let pagefind;
|
|
2
|
+
|
|
3
|
+
// Helper: Load Pagefind
|
|
4
|
+
async function initPagefind() {
|
|
5
|
+
const mod = await import("/pagefind/pagefind.js");
|
|
6
|
+
await mod.init();
|
|
7
|
+
return mod;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// Helper: Show Centered Message (Placeholder or No Results)
|
|
11
|
+
function showPlaceholder(container, message = "Start typing to search...") {
|
|
12
|
+
container.classList.remove("space-y-4", "block");
|
|
13
|
+
container.classList.add("flex", "items-center", "justify-center", "h-full");
|
|
14
|
+
container.innerHTML = `<p class="text-sm text-gray-500 text-center">${message}</p>`;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Helper: Render the Search Results
|
|
18
|
+
function renderResults(results, container) {
|
|
19
|
+
container.innerHTML = "";
|
|
20
|
+
|
|
21
|
+
if (results.length === 0) {
|
|
22
|
+
showPlaceholder(container, "No results found.");
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Restore normal top-aligned layout
|
|
27
|
+
container.classList.remove("flex", "items-center", "justify-center", "h-full");
|
|
28
|
+
container.classList.add("space-y-4", "block");
|
|
29
|
+
|
|
30
|
+
results.forEach(result => {
|
|
31
|
+
const el = document.createElement("a");
|
|
32
|
+
el.href = result.url;
|
|
33
|
+
el.className = "block p-2 -mx-2 rounded hover:bg-gray-100 transition-colors";
|
|
34
|
+
el.innerHTML = `
|
|
35
|
+
<h3 class="text-blue-600 font-semibold hover:underline">${result.meta.title || "Untitled"}</h3>
|
|
36
|
+
<p class="text-sm text-gray-600">${result.excerpt}</p>
|
|
37
|
+
`;
|
|
38
|
+
container.appendChild(el);
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// MAIN INITIALIZATION
|
|
43
|
+
document.addEventListener("DOMContentLoaded", async () => {
|
|
44
|
+
// 1. Grab all elements
|
|
45
|
+
const modal = document.getElementById("search-modal");
|
|
46
|
+
const openButtons = document.querySelectorAll(".search-open");
|
|
47
|
+
const input = document.getElementById("search-input");
|
|
48
|
+
const clearBtn = document.getElementById("search-clear");
|
|
49
|
+
const resultsContainer = document.getElementById("search-results");
|
|
50
|
+
|
|
51
|
+
// 2. Initialize Pagefind
|
|
52
|
+
pagefind = await initPagefind();
|
|
53
|
+
|
|
54
|
+
// 3. Modal Toggle Logic
|
|
55
|
+
openButtons.forEach(btn => {
|
|
56
|
+
btn.addEventListener("click", () => {
|
|
57
|
+
modal.classList.remove("hidden");
|
|
58
|
+
input.focus();
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const closeModal = () => modal.classList.add("hidden");
|
|
63
|
+
|
|
64
|
+
modal.addEventListener("click", (e) => {
|
|
65
|
+
if (e.target === modal) closeModal();
|
|
66
|
+
});
|
|
67
|
+
document.addEventListener("keydown", (e) => {
|
|
68
|
+
if (e.key === "Escape") closeModal();
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// 4. Search & Clear Button Logic
|
|
72
|
+
input.addEventListener("input", async (e) => {
|
|
73
|
+
const query = e.target.value.trim();
|
|
74
|
+
|
|
75
|
+
// Toggle "X" button visibility
|
|
76
|
+
clearBtn.classList.toggle("hidden", query === "");
|
|
77
|
+
|
|
78
|
+
if (!query) {
|
|
79
|
+
showPlaceholder(resultsContainer);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Perform Search
|
|
84
|
+
const search = await pagefind.search(query);
|
|
85
|
+
const results = await Promise.all(
|
|
86
|
+
search.results.slice(0, 10).map(r => r.data())
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
renderResults(results, resultsContainer);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
// 5. Clear Button Click
|
|
93
|
+
clearBtn.addEventListener("click", () => {
|
|
94
|
+
input.value = "";
|
|
95
|
+
input.focus();
|
|
96
|
+
clearBtn.classList.add("hidden");
|
|
97
|
+
showPlaceholder(resultsContainer);
|
|
98
|
+
});
|
|
99
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// Wrap tables in a scrollable container to fix right-side gap
|
|
2
|
+
window.addEventListener("DOMContentLoaded", () => {
|
|
3
|
+
document.querySelectorAll(".main table:not(.highlight table)").forEach(table => {
|
|
4
|
+
// skip if already wrapped
|
|
5
|
+
if (table.parentElement.classList.contains("table-wrapper")) return;
|
|
6
|
+
|
|
7
|
+
// create wrapper div
|
|
8
|
+
const wrapper = document.createElement("div");
|
|
9
|
+
wrapper.className = "table-wrapper overflow-x-auto mb-4";
|
|
10
|
+
|
|
11
|
+
// insert wrapper before the table and move table inside
|
|
12
|
+
table.parentNode.insertBefore(wrapper, table);
|
|
13
|
+
wrapper.appendChild(table);
|
|
14
|
+
});
|
|
15
|
+
});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// queries all elements that should not get prose attributes and adds a not-prose class to them.
|
|
2
|
+
// this is for elements who we don't have direct access to them
|
|
3
|
+
document.addEventListener("DOMContentLoaded", function () {
|
|
4
|
+
const preElements = document.querySelectorAll("pre");
|
|
5
|
+
|
|
6
|
+
preElements.forEach(function (pre) {
|
|
7
|
+
pre.classList.add("not-prose");
|
|
8
|
+
});
|
|
9
|
+
});
|