| | --- |
| | interface Props { |
| | citationText: string; |
| | bibtex: string; |
| | licence?: string; |
| | doi?: string; |
| | acknowledgements?: string; |
| | } |
| | const { citationText, bibtex, licence, doi, acknowledgements } = Astro.props as Props; |
| | --- |
| | <footer class="footer"> |
| | <div class="footer-inner"> |
| | <section class="citation-block"> |
| | <h3>Citation</h3> |
| | <p>For attribution, cite this work as</p> |
| | <pre class="citation short">{citationText}</pre> |
| | |
| | <p>BibTeX citation</p> |
| | <pre class="citation long">{bibtex}</pre> |
| | </section> |
| | {acknowledgements && ( |
| | <section class="acknowledgements-block"> |
| | <h3>Acknowledgements</h3> |
| | <p set:html={acknowledgements}></p> |
| | </section> |
| | )} |
| | {doi && ( |
| | <section class="doi-block"> |
| | <h3>DOI</h3> |
| | <p><a href={`https://doi.org/${doi}`} target="_blank" rel="noopener noreferrer">{doi}</a></p> |
| | </section> |
| | )} |
| | {licence && ( |
| | <section class="reuse-block"> |
| | <h3>Reuse</h3> |
| | <p set:html={licence}></p> |
| | </section> |
| | )} |
| | <section class="references-block"> |
| | <slot /> |
| | </section> |
| | </div> |
| | </footer> |
| |
|
| |
|
| | <script is:inline> |
| | (() => { |
| | const getFooter = () => document.currentScript?.closest('footer') || document.querySelector('footer.footer'); |
| | const footer = getFooter(); |
| | if (!footer) return; |
| | const target = footer.querySelector('.references-block'); |
| | if (!target) return; |
| | |
| | const contentRoot = document.querySelector('section.content-grid main') || document.querySelector('main') || document.body; |
| | |
| | const ensureHeading = (text) => { |
| | const exists = Array.from(target.children).some((c) => c.tagName === 'H3' && c.textContent.trim().toLowerCase() === text.toLowerCase()); |
| | if (!exists) { |
| | const h = document.createElement('h3'); |
| | h.textContent = text; |
| | target.appendChild(h); |
| | } |
| | }; |
| | |
| | const moveIntoFooter = (element, headingText) => { |
| | if (!element) return false; |
| | |
| | const firstHeading = element.querySelector(':scope > h1, :scope > h2, :scope > h3'); |
| | if (firstHeading) { |
| | const txt = (firstHeading.textContent || '').trim().toLowerCase(); |
| | const targetTxt = headingText.trim().toLowerCase(); |
| | if (txt === targetTxt || txt.includes('reference') || txt.includes('bibliograph')) { |
| | firstHeading.remove(); |
| | } |
| | } |
| | ensureHeading(headingText); |
| | target.appendChild(element); |
| | return true; |
| | }; |
| | const run = () => { |
| | const findFirstOutsideFooter = (selectors) => { |
| | for (const sel of selectors) { |
| | const el = contentRoot.querySelector(sel); |
| | if (el && !footer.contains(el)) return el; |
| | } |
| | return null; |
| | }; |
| | |
| | const referencesEl = findFirstOutsideFooter(['#references', '.references', '.bibliography']); |
| | const footnotesEl = findFirstOutsideFooter(['.footnotes']); |
| | |
| | const movedRefs = moveIntoFooter(referencesEl, 'References'); |
| | const movedNotes = moveIntoFooter(footnotesEl, 'Footnotes'); |
| | return movedRefs || movedNotes; |
| | }; |
| | |
| | |
| | const done = run(); |
| | if (!done) { |
| | const onReady = () => run(); |
| | if (document.readyState === 'loading') { |
| | document.addEventListener('DOMContentLoaded', onReady, { once: true }); |
| | } else { |
| | setTimeout(onReady, 0); |
| | } |
| | } |
| | |
| | |
| | |
| | })(); |
| | </script> |
| | |
| | |
| | <style is:global> |
| | .footer { |
| | contain: layout style; |
| | font-size: 0.8em; |
| | line-height: 1.7em; |
| | margin-top: 60px; |
| | margin-bottom: 0; |
| | border-top: 1px solid rgba(0, 0, 0, 0.1); |
| | color: rgba(0, 0, 0, 0.5); |
| | } |
| | |
| | .footer-inner { |
| | max-width: 1280px; |
| | margin: 0 auto; |
| | padding: 60px 16px 48px; |
| | display: grid; |
| | grid-template-columns: 220px minmax(0, 680px) 260px; |
| | gap: 32px; |
| | align-items: start; |
| | } |
| | |
| | |
| | .citation-block, |
| | .acknowledgements-block, |
| | .references-block, |
| | .reuse-block, |
| | .doi-block { |
| | display: contents; |
| | } |
| | |
| | .citation-block > h3, |
| | .acknowledgements-block > h3, |
| | .references-block > h3, |
| | .reuse-block > h3, |
| | .doi-block > h3 { |
| | grid-column: 1; |
| | font-size: 15px; |
| | margin: 0; |
| | text-align: right; |
| | padding-right: 30px; |
| | } |
| | |
| | .citation-block > :not(h3), |
| | .acknowledgements-block > :not(h3), |
| | .references-block > :not(h3), |
| | .reuse-block > :not(h3), |
| | .doi-block > :not(h3) { |
| | grid-column: 2; |
| | } |
| | |
| | |
| | .citation-block h3 { |
| | margin: 0 0 8px; |
| | } |
| | |
| | .citation-block h4 { |
| | margin: 16px 0 8px; |
| | font-size: 14px; |
| | text-transform: uppercase; |
| | color: var(--muted-color); |
| | } |
| | |
| | .citation-block p, |
| | .acknowledgements-block p, |
| | .reuse-block p, |
| | .doi-block p, |
| | .footnotes ol, |
| | .footnotes ol p, |
| | .references { |
| | margin-top: 0; |
| | } |
| | |
| | |
| | .citation { |
| | font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; |
| | font-size: 11px; |
| | line-height: 15px; |
| | border-left: 1px solid rgba(0, 0, 0, 0.1); |
| | padding-left: 18px; |
| | border: 1px solid rgba(0,0,0,0.1); |
| | background: rgba(0, 0, 0, 0.02); |
| | padding: 10px 18px; |
| | border-radius: 3px; |
| | color: rgba(150, 150, 150, 1); |
| | overflow: hidden; |
| | margin-top: -12px; |
| | white-space: pre-wrap; |
| | word-wrap: break-word; |
| | } |
| | |
| | .citation a { |
| | color: rgba(0, 0, 0, 0.6); |
| | text-decoration: underline; |
| | } |
| | |
| | .citation.short { |
| | margin-top: -4px; |
| | } |
| | |
| | .references-block h3 { |
| | margin: 0; |
| | } |
| | |
| | |
| | .references-block ol { |
| | padding: 0 0 0 15px; |
| | } |
| | |
| | @media (min-width: 768px) { |
| | .references-block ol { |
| | padding: 0 0 0 30px; |
| | margin-left: -30px; |
| | } |
| | } |
| | |
| | .references-block li { |
| | margin-bottom: 1em; |
| | } |
| | |
| | .references-block a { |
| | color: var(--text-color); |
| | } |
| | |
| | [data-theme="dark"] .footer { border-top-color: rgba(255,255,255,.15); color: rgba(200,200,200,.8); } |
| | [data-theme="dark"] .citation { background: rgba(255,255,255,0.04); border-color: rgba(255,255,255,.15); color: rgba(200,200,200,1); } |
| | [data-theme="dark"] .citation a { color: rgba(255,255,255,0.75); } |
| | |
| | |
| | |
| | .footer a { |
| | color: var(--primary-color); |
| | border-bottom: 1px solid var(--link-underline); |
| | text-decoration: none; |
| | } |
| | .footer a:hover { |
| | color: var(--primary-color-hover); |
| | border-bottom-color: var(--link-underline-hover); |
| | } |
| | [data-theme="dark"] .footer a { |
| | color: var(--primary-color); |
| | } |
| | </style> |
| | |