diff --git a/app.py b/app.py
index ac57e04..e33982a 100644
--- a/app.py
+++ b/app.py
@@ -9,7 +9,7 @@ from comics_data import (
COMICS, COMIC_NAME, COPYRIGHT_NAME, SITE_URL, FULL_WIDTH_DEFAULT, PLAIN_DEFAULT, LOGO_IMAGE, LOGO_MODE,
HEADER_IMAGE, FOOTER_IMAGE, BANNER_IMAGE, COMPACT_FOOTER, ARCHIVE_FULL_WIDTH, SECTIONS_ENABLED,
USE_COMIC_NAV_ICONS, USE_HEADER_NAV_ICONS, USE_FOOTER_SOCIAL_ICONS, NEWSLETTER_ENABLED,
- SOCIAL_INSTAGRAM, SOCIAL_YOUTUBE, SOCIAL_EMAIL, API_SPEC_LINK, EMBED_ENABLED
+ SOCIAL_INSTAGRAM, SOCIAL_YOUTUBE, SOCIAL_EMAIL, API_SPEC_LINK, EMBED_ENABLED, PERMALINK_ENABLED
)
import markdown
@@ -50,7 +50,8 @@ def inject_global_settings():
'social_youtube': SOCIAL_YOUTUBE,
'social_email': SOCIAL_EMAIL,
'api_spec_link': API_SPEC_LINK,
- 'embed_enabled': EMBED_ENABLED
+ 'embed_enabled': EMBED_ENABLED,
+ 'permalink_enabled': PERMALINK_ENABLED
}
diff --git a/comics_data.py b/comics_data.py
index 6ad43b1..a79b804 100644
--- a/comics_data.py
+++ b/comics_data.py
@@ -89,6 +89,10 @@ API_SPEC_LINK = None # Set to 'openapi.yml' to enable
# When enabled, users can get embed codes to display comics on other websites
EMBED_ENABLED = True
+# Global setting: Set to True to enable permalink copy button
+# When enabled, users can easily copy a direct link to the current comic
+PERMALINK_ENABLED = True
+
COMICS = [
{
'number': 1,
diff --git a/static/css/style.css b/static/css/style.css
index 1466b01..053baf2 100644
--- a/static/css/style.css
+++ b/static/css/style.css
@@ -1070,13 +1070,45 @@ footer.compact-footer .footer-section:not(:last-child)::after {
}
/* ============================================================
- EMBED FEATURE STYLES
+ SHARE/EMBED FEATURE STYLES
============================================================ */
-/* Embed button section */
-.comic-embed-section {
+/* Share section (contains permalink and embed buttons) */
+.comic-share-section {
margin-top: var(--space-lg);
text-align: center;
+ display: flex;
+ justify-content: center;
+ gap: var(--space-md);
+ flex-wrap: wrap;
+}
+
+/* Permalink button */
+.btn-permalink {
+ padding: var(--space-sm) var(--space-lg);
+ background-color: var(--color-background);
+ border: var(--border-width-thin) solid var(--color-border);
+ color: var(--color-text);
+ font-family: var(--font-family);
+ font-size: var(--font-size-md);
+ cursor: pointer;
+ text-transform: uppercase;
+ letter-spacing: var(--letter-spacing-tight);
+ transition: background-color var(--transition-speed);
+}
+
+.btn-permalink:hover {
+ background-color: var(--color-hover-bg);
+}
+
+.btn-permalink:focus {
+ outline: 3px solid var(--color-primary);
+ outline-offset: 2px;
+}
+
+.btn-permalink.copied {
+ background-color: var(--color-primary);
+ color: var(--color-background);
}
/* Embed button */
diff --git a/static/js/permalink.js b/static/js/permalink.js
new file mode 100644
index 0000000..862b5a1
--- /dev/null
+++ b/static/js/permalink.js
@@ -0,0 +1,84 @@
+// Permalink functionality for Sunday Comics
+// Handles copying comic permalinks to clipboard
+
+(function() {
+ 'use strict';
+
+ const permalinkButton = document.getElementById('permalink-button');
+
+ if (!permalinkButton) {
+ // Permalink feature not enabled or button not found
+ return;
+ }
+
+ // Get the site URL from the page
+ const siteUrl = document.body.getAttribute('data-site-url') || window.location.origin;
+
+ // Copy permalink when button is clicked
+ permalinkButton.addEventListener('click', function() {
+ const comicNumber = this.getAttribute('data-comic-number');
+ if (!comicNumber) return;
+
+ // Generate permalink URL
+ const permalink = `${siteUrl}/comic/${comicNumber}`;
+
+ // Copy to clipboard
+ copyToClipboard(permalink);
+ });
+
+ // Copy text to clipboard
+ function copyToClipboard(text) {
+ // Modern clipboard API
+ if (navigator.clipboard && navigator.clipboard.writeText) {
+ navigator.clipboard.writeText(text).then(function() {
+ showCopyFeedback();
+ }).catch(function() {
+ // Fallback for older browsers
+ fallbackCopy(text);
+ });
+ } else {
+ // Fallback for older browsers
+ fallbackCopy(text);
+ }
+ }
+
+ // Fallback copy method for older browsers
+ function fallbackCopy(text) {
+ // Create temporary textarea
+ const textarea = document.createElement('textarea');
+ textarea.value = text;
+ textarea.style.position = 'fixed';
+ textarea.style.opacity = '0';
+ document.body.appendChild(textarea);
+ textarea.focus();
+ textarea.select();
+
+ try {
+ document.execCommand('copy');
+ showCopyFeedback();
+ } catch (err) {
+ alert('Failed to copy. Please copy manually: ' + text);
+ }
+
+ document.body.removeChild(textarea);
+ }
+
+ // Show visual feedback that the permalink was copied
+ function showCopyFeedback() {
+ const originalText = permalinkButton.textContent;
+ permalinkButton.textContent = 'Copied!';
+ permalinkButton.classList.add('copied');
+
+ setTimeout(function() {
+ permalinkButton.textContent = originalText;
+ permalinkButton.classList.remove('copied');
+ }, 2000);
+ }
+
+ // Update permalink button when comic changes via client-side navigation
+ window.addEventListener('comicUpdated', function(event) {
+ if (event.detail && event.detail.comicNumber && permalinkButton) {
+ permalinkButton.setAttribute('data-comic-number', event.detail.comicNumber);
+ }
+ });
+})();
diff --git a/templates/base.html b/templates/base.html
index 5587f6b..607698f 100644
--- a/templates/base.html
+++ b/templates/base.html
@@ -207,6 +207,9 @@
{% if embed_enabled %}
{% endif %}
+ {% if permalink_enabled %}
+
+ {% endif %}
{% block extra_js %}{% endblock %}