Skip to content

Commit f569b38

Browse files
authored
Merge pull request #180 from stumbo/bs7_citations
Initial attempt to build citation modal dialog box.
2 parents ba057b5 + 298633d commit f569b38

File tree

1 file changed

+114
-0
lines changed

1 file changed

+114
-0
lines changed

layouts/bibliography/single.html

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,23 @@ <h1>{{ .Title }}</h1>
5252
No URL to the document is available.
5353
{{ end }}
5454
<br>
55+
56+
<!-- Citation -->
57+
{{/* Build Zotero API params (group id + item key + style) */}}
58+
{{ $gid := "2914042" }}
59+
60+
{{ $key := .File.TranslationBaseName }}
61+
62+
{{ $style := or site.Params.zotero.style "apa" }}
63+
64+
{{ if and $gid $key }}
65+
<br>
66+
<a href="#" id="citeBtn"
67+
data-gid="{{ $gid }}"
68+
data-key="{{ $key }}"
69+
data-style="{{ $style }}"
70+
>Citation</a>
71+
{{ end }}
5572
</p>
5673
<p>
5774
<strong>Abstract</strong>
@@ -218,4 +235,101 @@ <h1>{{ .Title }}</h1>
218235
{{ .Content }}
219236
</div>
220237
</article>
238+
<!-- Citation modal -->
239+
<div id="citationModal" class="citation-modal" hidden>
240+
<div class="citation-dialog">
241+
<div class="citation-header">
242+
<strong>Citation</strong>
243+
<button type="button" class="citation-close" aria-label="Close">×</button>
244+
</div>
245+
<div class="citation-body">
246+
<div id="citationContent">Loading…</div>
247+
</div>
248+
<div class="citation-actions">
249+
<button type="button" id="copyCitation">Copy</button>
250+
<button type="button" class="citation-close">Close</button>
251+
</div>
252+
</div>
253+
<div class="citation-backdrop"></div>
254+
</div>
255+
256+
<style>
257+
.citation-modal[hidden] { display: none; }
258+
.citation-modal { position: fixed; inset: 0; z-index: 1050; }
259+
.citation-dialog {
260+
position: absolute; top: 10%; left: 50%; transform: translateX(-50%);
261+
max-width: 720px; width: calc(100% - 2rem);
262+
background: #fff; border-radius: 6px; box-shadow: 0 10px 30px rgba(0,0,0,.2);
263+
overflow: hidden;
264+
}
265+
.citation-header { display:flex; justify-content:space-between; align-items:center; padding:.75rem 1rem; border-bottom:1px solid #eee; }
266+
.citation-close { background:none; border:0; font-size:1.25rem; line-height:1; cursor:pointer; }
267+
.citation-body { padding:1rem; max-height:50vh; overflow:auto; }
268+
#citationContent { font-size:1rem; line-height:1.4; }
269+
.citation-actions { display:flex; gap:.5rem; justify-content:flex-end; padding:.75rem 1rem; border-top:1px solid #eee; }
270+
</style>
271+
272+
<script>
273+
(function () {
274+
function openModal() { document.getElementById('citationModal').hidden = false; }
275+
function closeModal() { document.getElementById('citationModal').hidden = true; }
276+
277+
document.addEventListener('click', function (e) {
278+
if (e.target.matches('#citeBtn')) {
279+
e.preventDefault();
280+
const btn = e.target;
281+
const gid = btn.dataset.gid;
282+
const key = btn.dataset.key;
283+
const style = btn.dataset.style || 'apa';
284+
const url = `https://api.zotero.org/groups/${encodeURIComponent(gid)}/items/${encodeURIComponent(key)}?format=bib&style=${encodeURIComponent(style)}&linkwrap=1`;
285+
286+
const box = document.getElementById('citationContent');
287+
box.textContent = 'Loading…';
288+
openModal();
289+
290+
fetch(url, { headers: { 'Accept': 'text/html' }})
291+
.then(r => {
292+
if (!r.ok) throw new Error(`HTTP ${r.status}`);
293+
return r.text();
294+
})
295+
.then(html => {
296+
// API returns HTML (span with formatted citation)
297+
box.innerHTML = html;
298+
})
299+
.catch(err => {
300+
box.textContent = `Failed to load citation (${err})`;
301+
});
302+
}
303+
if (e.target.matches('.citation-close')) {
304+
e.preventDefault();
305+
closeModal();
306+
}
307+
if (e.target.matches('#copyCitation')) {
308+
e.preventDefault();
309+
const el = document.getElementById('citationContent');
310+
const text = el.innerText.trim();
311+
if (navigator.clipboard && window.isSecureContext) {
312+
navigator.clipboard.writeText(text).then(() => {
313+
e.target.textContent = 'Copied';
314+
setTimeout(() => e.target.textContent = 'Copy', 1200);
315+
});
316+
} else {
317+
const ta = document.createElement('textarea');
318+
ta.value = text; document.body.appendChild(ta);
319+
ta.select(); try { document.execCommand('copy'); } catch(e){}
320+
document.body.removeChild(ta);
321+
}
322+
}
323+
});
324+
325+
// Close when clicking backdrop or pressing Escape
326+
document.getElementById('citationModal').addEventListener('click', function (e) {
327+
if (e.target.classList.contains('citation-backdrop')) closeModal();
328+
});
329+
document.addEventListener('keydown', function (e) {
330+
if (e.key === 'Escape') closeModal();
331+
});
332+
})();
333+
</script>
334+
221335
{{ end }}

0 commit comments

Comments
 (0)