mirror of
https://github.com/apophenia-news/apophenia.news.git
synced 2026-10-08 21:35:23 +00:00
Add copy article button with full Markdown source
This commit is contained in:
+8
-2
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1598
-1598
File diff suppressed because one or more lines are too long
Vendored
+2
-2
@@ -16,8 +16,8 @@
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
<link rel="alternate" type="application/rss+xml" title="apophenia.news RSS" href="https://apophenia.news/rss.xml" />
|
||||
<script data-goatcounter="https://apophenia.goatcounter.com/count" async src="//gc.zgo.at/count.js"></script>
|
||||
<script type="module" crossorigin src="/assets/main-BzJy2slU.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/main-rN4cgZI2.css">
|
||||
<script type="module" crossorigin src="/assets/main-COWN3pqS.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/main-BVhQ3ewg.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
||||
+8
-2
File diff suppressed because one or more lines are too long
Vendored
+2
-2
@@ -16,8 +16,8 @@
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
<link rel="alternate" type="application/rss+xml" title="apophenia.news RSS" href="https://apophenia.news/rss.xml" />
|
||||
<script data-goatcounter="https://apophenia.goatcounter.com/count" async src="//gc.zgo.at/count.js"></script>
|
||||
<script type="module" crossorigin src="/assets/main-BzJy2slU.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/main-rN4cgZI2.css">
|
||||
<script type="module" crossorigin src="/assets/main-COWN3pqS.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/main-BVhQ3ewg.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
+8
-2
File diff suppressed because one or more lines are too long
Vendored
+2
-2
@@ -16,8 +16,8 @@
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
<link rel="alternate" type="application/rss+xml" title="apophenia.news RSS" href="https://apophenia.news/rss.xml" />
|
||||
<script data-goatcounter="https://apophenia.goatcounter.com/count" async src="//gc.zgo.at/count.js"></script>
|
||||
<script type="module" crossorigin src="/assets/main-BzJy2slU.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/main-rN4cgZI2.css">
|
||||
<script type="module" crossorigin src="/assets/main-COWN3pqS.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/main-BVhQ3ewg.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
||||
+8
-2
File diff suppressed because one or more lines are too long
Vendored
+8
-2
File diff suppressed because one or more lines are too long
+8
-2
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Vendored
+2
-2
@@ -16,8 +16,8 @@
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
<link rel="alternate" type="application/rss+xml" title="apophenia.news RSS" href="https://apophenia.news/rss.xml" />
|
||||
<script data-goatcounter="https://apophenia.goatcounter.com/count" async src="//gc.zgo.at/count.js"></script>
|
||||
<script type="module" crossorigin src="/assets/main-BzJy2slU.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/main-rN4cgZI2.css">
|
||||
<script type="module" crossorigin src="/assets/main-COWN3pqS.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/main-BVhQ3ewg.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
||||
@@ -52,6 +52,7 @@ const run = async () => {
|
||||
articles.push({
|
||||
...data,
|
||||
sourceFile: file,
|
||||
markdown: md,
|
||||
isUnlisted: unlisted.has(data.slug),
|
||||
html: fixInternalLinks(marked.parse(content))
|
||||
});
|
||||
|
||||
@@ -65,6 +65,11 @@ ${shellHead({
|
||||
${nav}
|
||||
<main class="shell py-10">
|
||||
<article class="card overflow-hidden">
|
||||
<div class="flex justify-end px-6 py-3 sm:px-10">
|
||||
<button type="button" data-copy-article class="inline-flex items-center gap-2 rounded-lg border border-zinc-200 bg-white px-3 py-2 text-sm font-medium text-zinc-800 shadow-sm transition hover:bg-zinc-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-indigo-400">
|
||||
<i data-lucide="copy" class="h-4 w-4"></i><span aria-live="polite">Copy article</span>
|
||||
</button>
|
||||
</div>
|
||||
<img src="${article.header_image}" alt="${escapeHtml(article.title)}" class="h-64 w-full object-cover" />
|
||||
<div class="p-6 sm:p-10">
|
||||
<p class="text-xs uppercase tracking-wide text-zinc-500">${fmtDate(article.date)} • ${renderAuthorInline(article.author)}</p>
|
||||
@@ -76,6 +81,7 @@ ${nav}
|
||||
<hr class="my-8 border-zinc-200" />
|
||||
<div class="article-prose">${article.html}</div>
|
||||
</div>
|
||||
<script id="article-markdown" type="application/json">${JSON.stringify(article.markdown).replace(/</g, "\\u003c")}</script>
|
||||
</article>
|
||||
|
||||
${merch}
|
||||
|
||||
+16
@@ -7,6 +7,22 @@ Alpine.start();
|
||||
|
||||
const bootIcons = () => createIcons({ icons });
|
||||
|
||||
const copyArticleButton = document.querySelector("[data-copy-article]");
|
||||
if (copyArticleButton) {
|
||||
let resetTimer;
|
||||
copyArticleButton.addEventListener("click", async () => {
|
||||
const label = copyArticleButton.querySelector("span");
|
||||
clearTimeout(resetTimer);
|
||||
try {
|
||||
await navigator.clipboard.writeText(JSON.parse(document.querySelector("#article-markdown").textContent));
|
||||
label.textContent = "Copied!";
|
||||
} catch {
|
||||
label.textContent = "Copy failed";
|
||||
}
|
||||
resetTimer = setTimeout(() => (label.textContent = "Copy article"), 2500);
|
||||
});
|
||||
}
|
||||
|
||||
if (document.readyState === "loading") {
|
||||
document.addEventListener("DOMContentLoaded", bootIcons);
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user