@rathnasgala/theme 0.0.20 → 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10,19 +10,21 @@
10
10
  {% macro loading(label='Loading') %}<div class="gala-loading" role="status"><span class="gala-loading__indicator" aria-hidden="true"></span><span class="gala-visually-hidden">{{ label }}</span></div>{% endmacro %}
11
11
  {% macro pagination(previous='', next='') %}<nav class="gala-pagination" aria-label="Pagination">{% if previous %}<a href="{{ previous }}" rel="prev">Previous</a>{% endif %}{% if next %}<a href="{{ next }}" rel="next">Next</a>{% endif %}</nav>{% endmacro %}
12
12
  {% macro search(action='/search/') %}<form class="gala-search" action="{{ action }}" role="search"><label for="gala-search-query">Search</label><input id="gala-search-query" name="q" type="search" autocomplete="off"><button type="submit">Search</button></form>{% endmacro %}
13
- {% macro tableOfContents(items) %}<nav class="gala-toc" aria-label="Table of contents"><ol>{% for item in items %}<li><a href="#{{ item.id }}">{{ item.text }}</a></li>{% endfor %}</ol></nav>{% endmacro %}
13
+ {% macro tableOfContents(items) %}<details class="gala-toc" open><summary>On this page</summary><nav aria-label="Table of contents"><ol>{% for item in items %}<li><a href="#{{ item.id }}">{{ item.text }}</a></li>{% endfor %}</ol></nav></details>{% endmacro %}
14
14
  {% macro shareControl(canonicalUrl, targets=[]) %}<section class="gala-share" aria-label="Share this article"><button type="button" data-copy-url="{{ canonicalUrl | escape }}" aria-label="Copy canonical URL">Copy link</button><output class="gala-share__status" aria-live="polite"></output><input class="gala-share__fallback" value="{{ canonicalUrl | escape }}" readonly aria-label="Canonical URL">{% if targets.length %}<ul>{% for target in targets %}<li><a href="{{ target.url | escape }}" rel="noopener noreferrer" aria-label="Share on {{ target.label | escape }}">{{ target.label }}</a></li>{% endfor %}</ul>{% endif %}</section>{% endmacro %}
15
15
  {% macro languageSwitcher(links, currentLanguage) %}{% if links.length > 2 %}<label>Preferred language <select data-language-preference data-navigate-on-selection>{% for link in links %}{% if link.hreflang != "x-default" %}<option value="{{ link.hreflang | escape }}" data-url="{{ link.href | escape }}"{% if link.hreflang == currentLanguage %} selected{% endif %}>{{ link.hreflang }}</option>{% endif %}{% endfor %}</select></label>{% endif %}{% endmacro %}
16
- {% macro engagementSummary(articleId, engagement, apiBaseUrl) %}
17
- <section class="gala-engagement" aria-label="Engagement" data-article-id="{{ articleId | escape }}" data-engagement-url="{{ apiBaseUrl | escape }}/v1/articles/{{ articleId | escape }}/engagement">
18
- {% if engagement.available %}<dl data-engagement-snapshot><div><dt>Reactions</dt><dd>{{ engagement.reactions }}</dd></div><div><dt>Comments</dt><dd>{{ engagement.comments }}</dd></div><div><dt>Views</dt><dd>{{ engagement.views }}</dd></div></dl>{% else %}<p class="gala-engagement__placeholder" role="status">Loading engagement data.</p>{% endif %}
19
- <div data-engagement-live></div>
20
- {# Readers see what they can do before they are asked who they are. Signing in is requested
21
- at the moment of intent, and the intent is replayed once they are back. #}
22
- <section class="gala-engagement-actions" aria-label="Reader actions" data-engagement-actions>
23
- <div class="gala-reaction-actions" role="group" aria-label="React to this article">
24
- {# The six the platform actually stores (io.gala.api.engagement.ReactionType). Offering
25
- any other name renders a button that can only ever fail on the way to the API. #}
16
+ {% macro reactionIcon(value) %}<svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round">{% if value == 'like' %}<path d="M2 9.5a5.5 5.5 0 0 1 9.591-3.676.56.56 0 0 0 .818 0A5.49 5.49 0 0 1 22 9.5c0 2.29-1.5 4-3 5.5l-5.492 5.313a2 2 0 0 1-3 .019L5 15c-1.5-1.5-3-3.2-3-5.5"/>{% elif value == 'insightful' %}<path d="M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5"/><path d="M9 18h6M10 22h4"/>{% elif value == 'celebrate' %}<path d="M5.8 11.3 2 22l10.7-3.79M4 3h.01M22 8h.01M15 2h.01M22 20h.01"/><path d="m22 2-2.24.75a2.9 2.9 0 0 0-1.96 3.12c.1.86-.57 1.63-1.45 1.63h-.38c-.86 0-1.6.6-1.76 1.44L14 10M22 13l-.82-.33c-.86-.34-1.82.2-1.98 1.11-.11.7-.72 1.22-1.43 1.22H17M11 2l.33.82c.34.86-.2 1.82-1.11 1.98C9.52 4.9 9 5.52 9 6.23V7"/><path d="M11 13c1.93 1.93 2.83 4.17 2 5-.83.83-3.07-.07-5-2-1.93-1.93-2.83-4.17-2-5 .83-.83 3.07.07 5 2Z"/>{% elif value == 'funny' %}<path d="M15 10V9M16.472 15a6 6 0 0 1-8.943 0M9 10V9"/><circle cx="12" cy="12" r="10"/>{% elif value == 'mind-blown' %}<path d="M12 18V5M15 13a4.17 4.17 0 0 1-3-4 4.17 4.17 0 0 1-3 4M17.598 6.5A3 3 0 1 0 12 5a3 3 0 1 0-5.598 1.5M17.997 5.125a4 4 0 0 1 2.526 5.77M18 18a4 4 0 0 0 2-7.464M19.967 17.483A4 4 0 1 1 12 18a4 4 0 1 1-7.967-.517M6 18a4 4 0 0 1-2-7.464M6.003 5.125a4 4 0 0 0-2.526 5.77"/>{% else %}<path d="M11 14h2a2 2 0 0 0 0-4h-3c-.6 0-1.1.2-1.4.6L3 16"/><path d="m14.45 13.39 5.05-4.694C20.196 8 21 6.85 21 5.75a2.75 2.75 0 0 0-4.797-1.837.276.276 0 0 1-.406 0A2.75 2.75 0 0 0 11 5.75c0 1.2.802 2.248 1.5 2.946L16 11.95M2 15l6 6"/><path d="m7 20 1.6-1.4c.3-.4.8-.6 1.4-.6h4c1.1 0 2.1-.4 2.8-1.2l4.6-4.4a1 1 0 0 0-2.75-2.91"/>{% endif %}</svg>{% endmacro %}
17
+ {% macro actionRail(canonicalUrl, engagement) %}
18
+ <aside class="gala-action-rail" aria-label="Reader actions">
19
+ <dl class="gala-action-stats" data-action-stats aria-label="Article statistics">
20
+ {% set reactionCount = engagement.reactions if engagement.available else 0 %}{% set commentCount = engagement.comments if engagement.available else 0 %}{% set viewCount = engagement.views if engagement.available else 0 %}
21
+ <div title="{{ reactionCount }} reactions"><dt><svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M20.8 4.6a5.5 5.5 0 0 0-7.8 0L12 5.7l-1.1-1.1a5.5 5.5 0 0 0-7.8 7.8l1.1 1.1L12 21l7.8-7.5 1.1-1.1a5.5 5.5 0 0 0-.1-7.8Z"/></svg><span class="gala-visually-hidden">Reactions</span></dt><dd data-engagement-stat="reactions" data-stat-label="Reactions">{{ reactionCount if reactionCount >= 1000 else '&lt;1K' | safe }}</dd></div>
22
+ <div title="{{ commentCount }} comments"><dt><svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a4 4 0 0 1-4 4H8l-5 3V7a4 4 0 0 1 4-4h10a4 4 0 0 1 4 4Z"/></svg><span class="gala-visually-hidden">Comments</span></dt><dd data-engagement-stat="comments" data-stat-label="Comments">{{ commentCount if commentCount >= 1000 else '&lt;1K' | safe }}</dd></div>
23
+ <div title="{{ viewCount }} views"><dt><svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7S2 12 2 12Z"/><circle cx="12" cy="12" r="3"/></svg><span class="gala-visually-hidden">Views</span></dt><dd data-engagement-stat="views" data-stat-label="Views">{{ viewCount if viewCount >= 1000 else '&lt;1K' | safe }}</dd></div>
24
+ </dl>
25
+ <span class="gala-action-rail__separator gala-action-rail__separator--stats" aria-hidden="true"></span>
26
+ <div class="gala-action-group gala-action-group--reactions" role="group" aria-label="React to this article">
27
+ <div class="gala-reaction-actions">
26
28
  {% for reaction in [
27
29
  { value: 'like', label: 'Like' },
28
30
  { value: 'insightful', label: 'Insightful' },
@@ -30,16 +32,35 @@
30
32
  { value: 'funny', label: 'Funny' },
31
33
  { value: 'mind-blown', label: 'Mind blown' },
32
34
  { value: 'thank-you', label: 'Thank you' }
33
- ] %}<button type="button" data-reaction="{{ reaction.value }}" aria-pressed="false">{{ reaction.label }}</button>{% endfor %}
35
+ ] %}<button type="button" data-reaction="{{ reaction.value }}" aria-label="{{ reaction.label }}" title="{{ reaction.label }}" aria-pressed="false">{{ reactionIcon(reaction.value) }}</button>{% endfor %}
36
+ </div>
37
+ </div>
38
+ <span class="gala-action-rail__separator" aria-hidden="true"></span>
39
+ <div class="gala-action-group gala-action-group--utilities" role="group" aria-label="Reader utilities">
40
+ <div class="gala-utility-actions">
41
+ <button type="button" data-follow-article aria-label="Follow article" title="Follow article" aria-pressed="false"><svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M18 8a6 6 0 0 0-12 0c0 7-3 7-3 9h18c0-2-3-2-3-9M10 21h4"/></svg><span class="gala-visually-hidden" data-follow-label>Follow article</span></button>
42
+ <a href="#comments" aria-label="Comments" title="Comments"><svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a4 4 0 0 1-4 4H8l-5 3V7a4 4 0 0 1 4-4h10a4 4 0 0 1 4 4Z"/></svg></a>
43
+ <div class="gala-share" aria-label="Share this article">
44
+ <button type="button" data-copy-url="{{ canonicalUrl | escape }}" aria-label="Copy link" title="Copy link"><svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg></button>
45
+ <button type="button" data-native-share="{{ canonicalUrl | escape }}" aria-label="Share" title="Share"><svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7"><circle cx="18" cy="5" r="3"/><circle cx="6" cy="12" r="3"/><circle cx="18" cy="19" r="3"/><path d="m8.6 10.5 6.8-4M8.6 13.5l6.8 4"/></svg></button>
46
+ <output class="gala-share__status gala-visually-hidden" aria-live="polite"></output>
47
+ <input class="gala-share__fallback" value="{{ canonicalUrl | escape }}" readonly aria-label="Canonical URL">
48
+ </div>
49
+ </div>
34
50
  </div>
35
- <button type="button" data-follow-article aria-pressed="false">Follow article</button>
36
- </section>
51
+ </aside>
52
+ {% endmacro %}
53
+ {% macro conversation(engagement) %}
54
+ <div id="conversation" class="gala-conversation" aria-label="Article conversation">
55
+ <header class="gala-conversation__header"><h2>Conversation</h2></header>
56
+ {# Readers see what they can do before they are asked who they are. Signing in is requested
57
+ at the moment of intent, and the intent is replayed once they are back. #}
37
58
  {# The conversation is an island: it owns its own state, because a thread five deep with a page
38
59
  cursor, an open reply form and an edit in progress is state, and hand-written DOM kept losing
39
60
  track of it. Nothing here is needed by a search engine — comments have always arrived from the
40
61
  API after load — so rendering them on the client costs nothing the article cares about. #}
41
- <div data-gala-comments></div>
42
- <output data-engagement-status aria-live="polite"></output>
43
- </section>
62
+ <div id="comments" data-gala-comments></div>
63
+ <output class="gala-conversation__status" data-engagement-status aria-live="polite">Loading comments…</output>
64
+ </div>
44
65
  {% endmacro %}
45
66
  {% macro pageFooter(siteName, links=[]) %}<footer class="gala-page-footer"><p>&copy; {{ siteName }}</p>{% if links.length %}<nav aria-label="Footer"><ul>{% for link in links %}<li><a href="{{ link.url }}">{{ link.label }}</a></li>{% endfor %}</ul></nav>{% endif %}</footer>{% endmacro %}
@@ -1,9 +1,10 @@
1
1
  <!doctype html>
2
- <html lang="{{ post.language or site.site.defaultLanguage }}" data-theme="{{ site.design.theme | default('modern') }}" data-layout="{{ site.design.layout }}" data-palette="{{ site.design.palette | default('default') }}" data-mode="{{ site.design.colorMode | default('system') }}"{% if site.accent %} style="--gala-accent-light: {{ site.accent.light }}; --gala-accent-dark: {{ site.accent.dark }}"{% endif %}>
2
+ <html lang="{{ post.language or site.site.defaultLanguage }}" data-theme="{{ site.design.theme | default('modern') }}" data-layout="{{ site.design.layout | default('article-first') }}" data-palette="{{ site.design.palette | default('default') }}" data-mode="{{ site.design.colorMode | default('system') }}">
3
3
  <head>
4
4
  <meta charset="utf-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1">
6
- <script>(function(){try{var m=localStorage.getItem('gala-color-mode');if(m==='light'||m==='dark'||m==='system')document.documentElement.dataset.mode=m}catch(e){}})();</script>
6
+ <meta http-equiv="Content-Security-Policy" content="default-src 'self'; base-uri 'self'; object-src 'none'; script-src 'self' 'sha256-{{ themeBootstrap | sha256Csp }}'{% if seo %} 'sha256-{{ seo.structuredDataJson | sha256Csp }}'{% endif %}; style-src 'self'; img-src 'self' data: https:; connect-src 'self' {{ site.platform.apiBaseUrl or 'https://api.gala67.com' }}; frame-src {{ site.platform.apiBaseUrl or 'https://api.gala67.com' }} https://www.youtube-nocookie.com https://codepen.io; form-action 'self'; upgrade-insecure-requests">
7
+ <script>{{ themeBootstrap | safe }}</script>
7
8
  <title>{{ post.frontmatter.title or title }} · {{ site.site.name }}</title>
8
9
  {% if post %}<link rel="canonical" href="{{ post.canonicalUrl }}">{% endif %}
9
10
  {% for alternate in hreflangLinks %}<link rel="alternate" hreflang="{{ alternate.hreflang }}" href="{{ alternate.href }}">{% endfor %}
@@ -23,20 +24,17 @@
23
24
  {% endif %}
24
25
  {% if post.publicationState == "tombstoned" %}<meta name="robots" content="noindex">{% endif %}
25
26
  <link rel="stylesheet" href="{{ '/assets/theme.css' | url }}">
27
+ <link rel="stylesheet" href="{{ '/assets/accent.css' | url }}">
26
28
  <link rel="stylesheet" href="{{ '/custom.css' | url }}">
27
- <script src="{{ '/assets/theme-mode.js' | url }}" defer></script>
28
- <script src="{{ '/assets/preferences.js' | url }}" defer></script>
29
29
  <link rel="icon" href="{{ '/assets/favicon.svg' | url }}" type="image/svg+xml">
30
- <script src="{{ '/assets/interactions.js' | url }}" defer></script>
31
- <script type="module" src="{{ '/assets/engagement-comments.js' | url }}"></script>
32
- <script src="{{ '/assets/search.js' | url }}" defer></script>
30
+ <script src="{{ '/assets/reader.js' | url }}" defer></script>
33
31
  </head>
34
- <body>
32
+ <body{% if post %} class="gala-page--article"{% endif %}>
33
+ <a class="gala-skip-link" href="#main-content">Skip to content</a>
35
34
  <header class="gala-site-header">
36
- <a class="gala-icon-control" href="{{ '/' | url }}" aria-label="Home" title="Home">
37
- <svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 10.2 12 3.5l9 6.7"/><path d="M5.4 8.9V19a1.4 1.4 0 0 0 1.4 1.4h3.1v-5.1h4.2v5.1h3.1A1.4 1.4 0 0 0 18.6 19V8.9"/></svg>
38
- </a>
35
+ <a class="gala-site-name" href="{{ '/' | url }}" aria-label="Home">{{ site.site.name }}</a>
39
36
  <nav class="gala-site-header__actions" aria-label="Site controls">
37
+ {% if post %}<a class="gala-header-link" href="#article">Article</a><a class="gala-header-link" href="#conversation">Conversation</a>{% endif %}
40
38
  {% if site.contact.enabled %}<a class="gala-icon-control" href="{{ '/contact/' | url }}" aria-label="Contact author" title="Contact">
41
39
  <svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="5.4" width="18" height="13.2" rx="2.2"/><path d="m3.9 7.3 7.2 5.1a1.6 1.6 0 0 0 1.8 0l7.2-5.1"/></svg>
42
40
  </a>{% endif %}
@@ -50,14 +48,25 @@
50
48
  <button class="gala-icon-control" type="button" data-open-dialog="gala-search-dialog" aria-label="Search" title="Search">
51
49
  <svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="7"/><path d="m20.3 20.3-4.4-4.4"/></svg>
52
50
  </button>
53
- <button class="gala-icon-control" type="button" data-open-dialog="gala-account-dialog" data-user-control aria-label="Sign in or view account" title="Account">
51
+ <button class="gala-account-control" type="button" data-open-dialog="gala-account-dialog" data-user-control aria-label="Sign in or view account" title="Account">
54
52
  <svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M19 20.4v-1.7a3.9 3.9 0 0 0-3.9-3.9H8.9A3.9 3.9 0 0 0 5 18.7v1.7"/><circle cx="12" cy="7.6" r="3.9"/></svg>
53
+ <span data-user-label>Sign in</span>
55
54
  </button>
56
55
  </nav>
57
56
  </header>
58
57
  <main id="main-content">{{ content | safe }}</main>
59
58
  <footer class="gala-page-footer">
60
- <p>&copy; {{ site.site.name }}</p>
59
+ <section class="gala-page-footer__identity" aria-label="Publication author">
60
+ {% if site.site.authorProfile.avatarUrl %}<img src="{{ site.site.authorProfile.avatarUrl | escape }}" alt="" width="40" height="40">{% endif %}
61
+ <div class="gala-page-footer__details">
62
+ <p class="gala-page-footer__line">
63
+ {% if site.site.authorProfile.profileUrl %}<a class="gala-page-footer__author" href="{{ site.site.authorProfile.profileUrl | escape }}" rel="author">{{ site.site.authorProfile.displayName }}</a>{% else %}<strong class="gala-page-footer__author">{{ site.site.authorProfile.displayName }}</strong>{% endif %}
64
+ {% if site.site.publisher.name %}<span>Published by {% if site.site.publisher.url %}<a href="{{ site.site.publisher.url | escape }}" rel="publisher">{{ site.site.publisher.name }}</a>{% else %}{{ site.site.publisher.name }}{% endif %}</span>{% endif %}
65
+ <span>&copy; {{ site.site.name }}</span>
66
+ </p>
67
+ {% if site.site.authorProfile.bio %}<p class="gala-page-footer__bio">{{ site.site.authorProfile.bio }}</p>{% endif %}
68
+ </div>
69
+ </section>
61
70
  {# Which repository sent the traffic, which footer the click came from, which language it
62
71
  was read in, and which author owns it. Sites registered before these managed values
63
72
  existed fall back rather than emitting the literal placeholder. #}
@@ -65,21 +74,20 @@
65
74
  {% set galaLinkLanguage = post.language or site.site.defaultLanguage %}
66
75
  {% set galaLinkSource = site.site.repository if site.site.repository and site.site.repository != 'unavailable' else 'gala-site' %}
67
76
  {% set galaLinkOwner = site.site.ownerId if site.site.ownerId and site.site.ownerId != 'unavailable' else site.site.id %}
68
- {% if attributionTier != 'PAID' %}<p><a href="https://gala67.com/?utm_source={{ galaLinkSource | urlencode }}&amp;utm_medium=referral&amp;utm_campaign=built-with-gala&amp;utm_content={{ galaLinkPlacement | urlencode }}&amp;utm_term={{ galaLinkLanguage | urlencode }}&amp;utm_id={{ galaLinkOwner | urlencode }}" rel="external">Built with Gala</a></p>{% endif %}
77
+ <nav aria-label="Publication footer"><ul>
78
+ {% if attributionTier != 'PAID' %}<li><a href="https://gala67.com/?utm_source={{ galaLinkSource | urlencode }}&amp;utm_medium=referral&amp;utm_campaign=powered-by-gala&amp;utm_content={{ galaLinkPlacement | urlencode }}&amp;utm_term={{ galaLinkLanguage | urlencode }}&amp;utm_id={{ galaLinkOwner | urlencode }}" rel="external">Powered by Gala</a></li>{% endif %}
79
+ <li><a href="https://app.gala67.com/s/terms" rel="external">Terms</a></li>
80
+ <li><a href="https://app.gala67.com/s/privacy" rel="external">Privacy</a></li>
81
+ </ul></nav>
69
82
  </footer>
70
83
  <dialog id="gala-settings-dialog" class="gala-dialog" aria-labelledby="gala-settings-title">
71
- <form method="dialog" class="gala-dialog__close"><button type="submit" aria-label="Close settings">Close</button></form>
72
- <h2 id="gala-settings-title">Reader settings</h2>
73
- <section aria-labelledby="gala-dialog-language-setting">
74
- <h3 id="gala-dialog-language-setting">Language preference</h3>
75
- <label>Preferred language
76
- <select data-language-preference>{% for language in languages %}<option value="{{ language | escape }}">{{ language }}</option>{% endfor %}</select>
77
- </label>
78
- </section>
84
+ <header class="gala-dialog__header"><h2 id="gala-settings-title">Reader settings</h2><form method="dialog" class="gala-dialog__close"><button type="submit" aria-label="Close settings">Close</button></form></header>
85
+ <label>Preferred language
86
+ <select data-language-preference>{% for language in languages %}<option value="{{ language | escape }}">{{ language }}</option>{% endfor %}</select>
87
+ </label>
79
88
  </dialog>
80
89
  <dialog id="gala-search-dialog" class="gala-dialog" aria-labelledby="gala-search-title">
81
- <form method="dialog" class="gala-dialog__close"><button type="submit" aria-label="Close search">Close</button></form>
82
- <h2 id="gala-search-title">Search</h2>
90
+ <header class="gala-dialog__header"><h2 id="gala-search-title">Search</h2><form method="dialog" class="gala-dialog__close"><button type="submit" aria-label="Close search">Close</button></form></header>
83
91
  <section data-gala-search data-index-url="{{ '/search-index.json' | url }}">
84
92
  <form class="gala-search" action="{{ '/search/' | url }}" role="search">
85
93
  <label for="gala-dialog-search-query">Search published posts</label>
@@ -89,13 +97,12 @@
89
97
  <p data-search-status role="status" aria-live="polite">Enter a search term.</p>
90
98
  <ol class="gala-search-results" data-search-results></ol>
91
99
  </section>
92
- <p><a href="{{ '/search/' | url }}">Open search page</a></p>
93
100
  </dialog>
94
101
  {% if site.site.id and site.site.id != "unavailable" %}
95
102
  <dialog id="gala-account-dialog" class="gala-dialog gala-account-dialog" aria-labelledby="gala-account-title">
96
103
  <form method="dialog" class="gala-dialog__close"><button type="submit" aria-label="Close account">Close</button></form>
97
104
  <h2 id="gala-account-title" class="gala-visually-hidden">Gala account</h2>
98
- <iframe data-gala-session-frame title="Gala account and sign in" allow="identity-credentials-get" src="{{ site.platform.apiBaseUrl or 'https://api.gala67.com' }}/v1/widget/session?siteId={{ site.site.id | escape }}"></iframe>
105
+ <iframe data-gala-session-frame title="Gala account and sign in" loading="lazy" allow="identity-credentials-get" src="{{ site.platform.apiBaseUrl or 'https://api.gala67.com' }}/v1/widget/session?siteId={{ site.site.id | escape }}"></iframe>
99
106
  </dialog>
100
107
  {% endif %}
101
108
  </body>
@@ -1,12 +1,16 @@
1
1
  ---
2
2
  layout: layouts/base.njk
3
3
  ---
4
- {% from "components/ui.njk" import engagementSummary, languageSwitcher, shareControl, tableOfContents %}
5
- <article>
6
- {% if post.publicationState == "published" %}<h1>{{ post.frontmatter.title }}</h1>{% endif %}
4
+ {% from "components/ui.njk" import actionRail, conversation, languageSwitcher, tableOfContents %}
5
+ <article id="article" class="gala-article">
6
+ {% if post.publicationState == "published" %}<progress class="gala-reading-progress" data-reading-progress max="1" value="0" aria-label="Reading progress"></progress><header class="gala-article-header"><p class="gala-eyebrow">Published {{ post.frontmatter.publishAfterDate }} · {{ post.language }} · {{ readingMinutes }} min read</p><h1>{{ post.frontmatter.title }}</h1>{% set byline = post.frontmatter.author or site.site.author %}{% if byline and byline != "unavailable" and byline != "New Gala Site" and byline != site.site.name %}<p class="gala-byline">By {{ byline }}</p>{% endif %}</header>{% endif %}
7
7
  {% if post.publicationState == "published" %}{{ languageSwitcher(hreflangLinks, post.language) }}{% endif %}
8
- {% if postTableOfContents.length %}{{ tableOfContents(postTableOfContents) }}{% endif %}
9
- {{ content | safe }}
10
- {% if post.publicationState == "published" %}{{ engagementSummary(post.id, engagement, site.platform.apiBaseUrl or "https://api.gala67.com") }}{% endif %}
11
- {% if post.publicationState == "published" %}{{ shareControl(post.canonicalUrl, shareTargets) }}{% endif %}
8
+ {% if post.publicationState == "published" %}<section class="gala-engagement" data-article-id="{{ post.id | escape }}" data-engagement-url="{{ site.platform.apiBaseUrl or 'https://api.gala67.com' }}/v1/articles/{{ post.id | escape }}/engagement">{% endif %}
9
+ <div class="gala-reading-layout">
10
+ {% if postTableOfContents.length %}{{ tableOfContents(postTableOfContents) }}{% else %}<span></span>{% endif %}
11
+ <div class="gala-markdown">{{ content | safe }}</div>
12
+ {% if post.publicationState == "published" %}<div class="gala-article-boundary"><strong>Reader interactions</strong></div><span class="gala-action-dock" data-action-dock aria-hidden="true"></span>{{ actionRail(post.canonicalUrl, engagement) }}{% endif %}
13
+ </div>
14
+ {% if post.publicationState == "published" %}{{ conversation(engagement) }}{% endif %}
15
+ {% if post.publicationState == "published" %}</section>{% endif %}
12
16
  </article>
@@ -0,0 +1,10 @@
1
+ export default class AccentStylesheet {
2
+ data() {
3
+ return { permalink: '/assets/accent.css', eleventyExcludeFromCollections: true };
4
+ }
5
+
6
+ render({ site }) {
7
+ if (!site.accent) return '';
8
+ return `:root{--gala-accent-light:${site.accent.light};--gala-accent-dark:${site.accent.dark}}\n`;
9
+ }
10
+ }