+16
src/assets/copy.svg
+16
src/assets/copy.svg
···
1
+
<svg
2
+
xmlns="http://www.w3.org/2000/svg"
3
+
width="24"
4
+
height="24"
5
+
viewBox="0 0 24 24"
6
+
fill="none"
7
+
stroke="currentColor"
8
+
stroke-width="2"
9
+
stroke-linecap="round"
10
+
stroke-linejoin="round"
11
+
class="lucide lucide-copy-icon lucide-copy"
12
+
>
13
+
<title>Copy text</title>
14
+
<rect width="14" height="14" x="8" y="8" rx="2" ry="2" />
15
+
<path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2" />
16
+
</svg>
+116
src/pages/blog/[id].astro
+116
src/pages/blog/[id].astro
···
5
5
import Sun from "@/assets/sun.svg";
6
6
import Moon from "@/assets/moon.svg";
7
7
8
+
import Copy from "@/assets/copy.svg";
9
+
8
10
import { blog } from "@/config";
9
11
const {
10
12
post: { light, dark, rainbow },
···
49
51
<Moon data-mode-dark />
50
52
</button>
51
53
</header>
54
+
52
55
<main style={`--accent: ${colour};`}>
53
56
<div class="content">
54
57
<Content />
···
94
97
button.style.visibility = "visible";
95
98
</script>
96
99
100
+
<template id="code-heading">
101
+
<!-- slots need to be set using set:html
102
+
else it is treated as astro slot -->
103
+
<span class="lang">
104
+
<Fragment set:html={"<slot>Plain Text</slot>"} />
105
+
</span>
106
+
<button id="copy"><Copy /></button>
107
+
108
+
<style>
109
+
.lang {
110
+
color: white;
111
+
}
112
+
113
+
button {
114
+
border: none;
115
+
background-color: #ffffff20;
116
+
117
+
border-radius: 0.5rem;
118
+
padding: 0;
119
+
width: 2.8rem;
120
+
height: 2.8rem;
121
+
122
+
& svg {
123
+
stroke: var(--_dark-typo-body);
124
+
margin: 0.2rem;
125
+
}
126
+
}
127
+
128
+
:host {
129
+
display: flex block;
130
+
justify-content: space-between;
131
+
align-items: center;
132
+
/* gets overridden by * because why not ig */
133
+
padding: 0.5rem !important;
134
+
position: sticky;
135
+
top: 0;
136
+
left: 0;
137
+
background-color: color-mix(
138
+
in oklab,
139
+
var(--_dark-bg-main),
140
+
var(--_dark-bg-secondary)
141
+
);
142
+
user-select: none;
143
+
}
144
+
</style>
145
+
</template>
146
+
147
+
<script>
148
+
class CodeHeading extends HTMLElement {
149
+
contents = "";
150
+
static observedAttributes = ["contents"];
151
+
152
+
template: HTMLTemplateElement;
153
+
content: DocumentFragment;
154
+
shadowRoot: ShadowRoot;
155
+
156
+
constructor() {
157
+
super();
158
+
const template = document.getElementById("code-heading");
159
+
if (!template || !(template instanceof HTMLTemplateElement))
160
+
throw new Error("Could not get #code-heading");
161
+
this.template = template;
162
+
this.content = template.content;
163
+
164
+
this.shadowRoot = this.attachShadow({ mode: "open" });
165
+
this.shadowRoot.appendChild(this.content.cloneNode(true));
166
+
167
+
const copy = this.shadowRoot.getElementById("copy");
168
+
if (!copy) throw new Error("No #copy in #code-heading");
169
+
console.log(copy, this.contents);
170
+
171
+
copy.addEventListener("click", () => {
172
+
navigator.clipboard.writeText(this.contents).catch((e) => {
173
+
console.error("Encountered error copying to clipboard;", e);
174
+
});
175
+
});
176
+
}
177
+
178
+
attributeChangedCallback(name: string, _: any, newV?: string) {
179
+
if (name == "contents") {
180
+
this.contents = newV ?? "";
181
+
}
182
+
}
183
+
}
184
+
185
+
customElements.define("code-heading", CodeHeading);
186
+
187
+
document.querySelectorAll(".astro-code").forEach((code) => {
188
+
if (!(code instanceof HTMLElement)) return;
189
+
190
+
const heading = document.createElement("code-heading");
191
+
console.log(code.innerText);
192
+
heading.setAttribute("contents", code.innerText);
193
+
194
+
const lang = code.dataset["language"];
195
+
if (lang && lang !== "plaintext") {
196
+
const langEl = document.createElement("span");
197
+
langEl.innerText = "." + lang;
198
+
heading.append(langEl);
199
+
}
200
+
201
+
code.prepend(heading);
202
+
});
203
+
</script>
204
+
97
205
<!-- post content styles -->
98
206
<!-- TODO: REFACTOR -->
99
207
<style is:global>
···
293
401
294
402
.astro-code {
295
403
background-color: var(--_dark-bg-secondary) !important;
404
+
margin-block: 1rem;
405
+
padding: 0;
406
+
position: relative;
407
+
408
+
& code {
409
+
display: block;
410
+
padding: 1rem;
411
+
}
296
412
}
297
413
298
414
/* Check lists */