jekyll-theme-centos 2.52.0.beta.95 → 2.52.0.beta.97

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 514d7cf7b23b5a2233b00dd34553cc9be81540fafc2fef9a3e3bdcd223355140
4
- data.tar.gz: 11d9d4be1415ddf484b5f1c590fab9a79fb26d24a77e49724f93649d6680444f
3
+ metadata.gz: 02c33817b8b756a8de30c5e96c06b4c2defd9c65600ac6a82adce543427c86ec
4
+ data.tar.gz: 9d14e11510ea28e7ac5a29229a190a9d9340a915e10f66d8cbc19e80dbceb0df
5
5
  SHA512:
6
- metadata.gz: ea8fca5a2626aaab45cef3f673115e3a4260f6ff5b9d31e9b436b5bb304413d879df61e586316fb2ff38bf58ceba27c6e99bdd89412b38f17a42f6d4b9cde8bd
7
- data.tar.gz: c8f7a9cfc0ea451c92192656de898a3c2add1219a4ffa08eb4758520b48bbdc59ffe4ce82ed506d46fce7961228d407384524405e7798ee88873b50c4a2253c1
6
+ metadata.gz: 04ce54202918e0da657e661a0a03de681b3c83c1b68240695f7a11a4b910fe797712e024fdfc49d4558ba84f330fa24d6ca43bca61225312b6aa6853c33c683c
7
+ data.tar.gz: c4e526cad99918c56f708a5a0434ce30de714f4adfb3f3ff1a2da0d9b7f1a10231074b20bc5d6c1a6d6f766cff339e7056da3cbd64530dc41d64d2053adf333e
data/_config.yml CHANGED
@@ -174,10 +174,6 @@ with_link_decorator_data:
174
174
  - img
175
175
 
176
176
  with_heading_anchor: true
177
- with_heading_anchor_data:
178
- icon: "fa-solid fa-hashtag"
179
- copy_success_message: "Copied!"
180
- reset_delay: 2000
181
177
 
182
178
  with_minify: true
183
179
  with_minify_data:
data/_data/base/bits.yml CHANGED
@@ -8,7 +8,7 @@
8
8
  Lorem ipsum odor amet, consectetuer adipiscing elit. Varius imperdiet
9
9
  convallis at efficitur in eros. Sagittis morbi scelerisque faucibus
10
10
  conubia consectetur.
11
- screenshot: base/screenshot-1600x1200.webp
11
+ preamble: false
12
12
  finale: "Derivatives:"
13
13
  actions:
14
14
  - name: Action 1
@@ -36,7 +36,6 @@
36
36
  description: |
37
37
  Lorem ipsum odor amet, consectetuer adipiscing elit. Varius imperdiet
38
38
  convallis at efficitur in eros. Sagittis morbi scelerisque faucibus
39
- screenshot: base/screenshot-1600x1200.webp
40
39
  image: centos-symbol.svg
41
40
  actions:
42
41
  - name: Action 1
@@ -56,7 +55,6 @@
56
55
  - Upstream card example 1
57
56
  - name: Downstream example 1-2
58
57
  icon: fa-solid fa-arrow-right
59
- screenshot: base/screenshot-1600x1200.webp
60
58
  type: downstream
61
59
  description: |
62
60
  Lorem ipsum odor amet, consectetuer adipiscing elit. Varius imperdiet
@@ -69,7 +67,6 @@
69
67
  icon_position: end
70
68
  link: "#"
71
69
  - name: Downstream example 1-3
72
- screenshot: base/screenshot-1600x1200.webp
73
70
  type: downstream
74
71
  description: |
75
72
  Lorem ipsum odor amet, consectetuer adipiscing elit. Varius imperdiet
@@ -82,7 +79,6 @@
82
79
  icon_position: end
83
80
  link: "#"
84
81
  - name: Downstream example 1-4
85
- screenshot: base/screenshot-1600x1200.webp
86
82
  type: downstream
87
83
  description: |
88
84
  Lorem ipsum odor amet, consectetuer adipiscing elit. Varius imperdiet
@@ -1,2 +1,4 @@
1
1
  ---
2
- class: col
2
+ class: "container py-3"
3
+ row_class: "row mb-3"
4
+ col_class: col
@@ -1,15 +1,22 @@
1
1
  title: Content Section Configuration
2
2
  description: >-
3
- Schema for configuring the main content display partial. This controls the
4
- rendering and layout of the primary content area on a page.
3
+ Schema for configuring the content component, which owns the <main>
4
+ element in the default layout. This controls the rendering of the entire
5
+ main page body — the announcement, bits, event, breadcrumb, title,
6
+ artwork, and table of contents components nested inside <main>, followed
7
+ by the page's own converted Markdown or HTML content — as well as the
8
+ layout of that content area.
5
9
  type: object
6
10
  properties:
7
11
  with_content:
8
12
  type: boolean
9
13
  default: true
10
14
  description: >-
11
- Enables or disables the rendering of the content section. Set to `true`
12
- (default) to display the content area; set to `false` to hide it entirely.
15
+ Enables or disables the rendering of the <main> element and every
16
+ component nested inside it (announcement, bits, event, breadcrumb,
17
+ title, artwork, toc, and the page's own content). Set to `true`
18
+ (default) to display the main content region; set to `false` to omit
19
+ `<main>` entirely from the rendered page.
13
20
  with_content_data:
14
21
  type: object
15
22
  description: >-
@@ -17,10 +24,29 @@ properties:
17
24
  rendered content section.
18
25
  properties:
19
26
  class:
27
+ type: string
28
+ default: "container py-3"
29
+ description: >-
30
+ Custom Bootstrap class(es) applied to the `<main>` element itself
31
+ — the outermost element owned by this component. Controls the
32
+ outer container behavior (max-width constraint, vertical padding)
33
+ for the entire main page body.
34
+ row_class:
35
+ type: string
36
+ default: "row mb-3"
37
+ description: >-
38
+ Custom Bootstrap class(es) applied to the `div.row` that wraps the
39
+ content section's `div.col` container. This same class is also
40
+ passed to the breadcrumb, title, artwork, and toc components, so
41
+ every row inside `<main>` shares the same spacing.
42
+ col_class:
20
43
  type: string
21
44
  default: col
22
45
  description: >-
23
- A Bootstrap column class used to control the width and responsiveness of the content section container (e.g., `col`, `col-md-10`, `col-lg-8`).
24
- This dictates the column size within the grid system.
46
+ A Bootstrap column class used to control the width and
47
+ responsiveness of the content section's `div.col` container (e.g.,
48
+ `col`, `col-md-10`, `col-lg-8`). This same class is also passed to
49
+ the breadcrumb, title, artwork, and toc components, so the whole
50
+ page moves as one aligned column.
25
51
  additionalProperties: false # Added to restrict unexpected properties in the data object
26
52
  additionalProperties: false
@@ -2,6 +2,7 @@
2
2
  #
3
3
  # site.data.base.footer - Control footer branding.
4
4
  #
5
+ class: "footer small bg-dark text-centos-purple-100 pt-5"
5
6
  brand_image: "centos-whitelogo.svg"
6
7
  brand_image_class: ""
7
8
  brand_image_height: "32"
@@ -20,6 +20,12 @@ properties:
20
20
  defined here (in the page's front matter) override any global `footer`
21
21
  data defined in site-wide `_data` files.
22
22
  properties:
23
+ class:
24
+ type: string
25
+ default: "footer small bg-dark text-centos-purple-100 pt-5"
26
+ description: >-
27
+ Custom Bootstrap class(es) applied to the `<footer>` element
28
+ itself — the outermost element owned by this component.
23
29
  brand_image:
24
30
  type: string
25
31
  default: "centos-whitelogo.svg"
@@ -1,2 +1,2 @@
1
1
  ---
2
- icon: "fa-solid fa-hashtag"
2
+ icon: "heading-anchor-hash pe-1"
@@ -2,8 +2,8 @@
2
2
  title: Heading Anchor Component Configuration
3
3
  description: >
4
4
  Configuration for the first-class heading anchor feature of jekyll-link-decorator.
5
- Each heading (h1–h6) receives a Font Awesome link icon that, when clicked, copies
6
- the full page URL with fragment to the clipboard.
5
+ Each heading (h1–h6) receives a permalink: an anchor with a hover/focus-revealed
6
+ glyph, linking to the heading itself.
7
7
  type: object
8
8
  properties:
9
9
  with_heading_anchor:
@@ -12,26 +12,16 @@ properties:
12
12
  default: true
13
13
  with_heading_anchor_data:
14
14
  type: object
15
- description: Configuration for heading anchor appearance and copy behaviour.
15
+ description: Configuration for heading anchor appearance.
16
16
  properties:
17
17
  icon:
18
18
  type: string
19
- description: Font Awesome icon classes applied to the anchor icon element.
20
- default: "fa-solid fa-hashtag"
19
+ description: >
20
+ CSS classes applied to the anchor's glyph element. Defaults to a plain
21
+ "#" character rendered via the .heading-anchor-hash class.
22
+ default: "heading-anchor-hash pe-1"
21
23
  icon_size:
22
24
  type: string
23
25
  description: Font Awesome size modifier appended after the icon classes.
24
- copy_success_message:
25
- type: string
26
- description: >
27
- Feedback message shown after a successful clipboard copy.
28
- Consumed by heading-anchor.js via data-success-message on the script element.
29
- default: "Copied!"
30
- reset_delay:
31
- type: integer
32
- description: >
33
- Milliseconds to wait before the icon resets to its original state
34
- after a successful copy. Consumed by heading-anchor.js via data-reset-delay.
35
- default: 2000
36
26
  additionalProperties: false
37
27
  additionalProperties: false
data/_data/base/ogp.yml CHANGED
@@ -2,12 +2,10 @@
2
2
  locale: en_US
3
3
  og:
4
4
  type: website
5
- title: true
6
5
  url: true
7
6
  description: true
8
7
  logo: /assets/icons/apple-touch-icon.png
9
8
  image:
10
- url: true
11
9
  alt: The CentOS Project
12
10
  type: image/png
13
11
  width: 1200
@@ -16,9 +14,7 @@ twitter:
16
14
  card: summary_large_image
17
15
  site: "@CentOS"
18
16
  creator: "@CentOS"
19
- title: true
20
17
  url: true
21
18
  description: true
22
19
  image:
23
- url: true
24
20
  alt: The CentOS Project
@@ -26,7 +26,13 @@ properties:
26
26
  title:
27
27
  type: string
28
28
  default: The CentOS Project
29
- description: The title of the content via the `og:title` tag.
29
+ description: >-
30
+ The title of the content via the `og:title` tag. Falls back to
31
+ `page.title` when omitted, then to this default. Set explicitly
32
+ to `false` or an empty string to omit the tag entirely; `true`
33
+ is treated the same as omitting it (kept for backward
34
+ compatibility with this component's own earlier documented
35
+ convention).
30
36
  description:
31
37
  type: string
32
38
  default: ""
@@ -38,13 +44,22 @@ properties:
38
44
  url:
39
45
  type: string
40
46
  format: uri
41
- default: "{{ site.url }}{{ site.baseurl }}/assets/img/centos-social-share.png"
42
- description: The non-secure URL via the `og:image:url` tag.
47
+ default: "/assets/img/centos-social-share.png"
48
+ description: >-
49
+ The non-secure URL via the `og:image:url` tag. Falls back
50
+ to this default (treated as a path relative to
51
+ `site.url + site.baseurl`, same convention as `logo`) when
52
+ omitted; `true` is treated the same as omitted, for
53
+ backward compatibility with this component's own earlier
54
+ documented convention. Set to a real string to override
55
+ with a different image.
43
56
  secure_url:
44
57
  type: string
45
58
  format: uri
46
- default: "{{ site.url }}{{ site.baseurl }}/assets/img/centos-social-share.png"
47
- description: The secure HTTPS URL via the `og:image:secure_url` tag.
59
+ default: "/assets/img/centos-social-share.png"
60
+ description: >-
61
+ The secure HTTPS URL via the `og:image:secure_url` tag.
62
+ Same fallback and `true`-tolerance as `url` above.
48
63
  type:
49
64
  type: string
50
65
  default: image/png
@@ -154,13 +169,17 @@ properties:
154
169
  url:
155
170
  type: string
156
171
  format: uri
157
- default: "{{ site.url }}{{ site.baseurl }}/assets/img/centos-social-share.png"
158
- description: The image URL via the `twitter:image:url` tag.
172
+ default: "/assets/img/centos-social-share.png"
173
+ description: >-
174
+ The image URL via the `twitter:image:url` tag. Same
175
+ fallback and `true`-tolerance as `og.image.url`.
159
176
  secure_url:
160
177
  type: string
161
178
  format: uri
162
- default: "{{ site.url }}{{ site.baseurl }}/assets/img/centos-social-share.png"
163
- description: The secure HTTPS image URL.
179
+ default: "/assets/img/centos-social-share.png"
180
+ description: >-
181
+ The secure HTTPS image URL. Same fallback and
182
+ `true`-tolerance as `og.image.secure_url`.
164
183
  type:
165
184
  type: string
166
185
  default: image/png
@@ -46,11 +46,13 @@ properties:
46
46
  An icon class (e.g., from Font Awesome) to display alongside the heading.
47
47
  visible_on:
48
48
  type: array
49
- default: ["footer"]
50
49
  description: >-
51
50
  Controls where this item is displayed. For the Shortcut component,
52
- this array must contain `"footer"` to be rendered. Other values
53
- (like `"navbar"`) are ignored in this context.
51
+ this array must contain `"footer"` to be rendered there is no
52
+ standalone default for this property here; an item with no
53
+ `visible_on` at all is not shown in the footer (it falls back to
54
+ navbar-visible instead, per the Navbar component's own default).
55
+ Other values (like `"navbar"`) are ignored in this context.
54
56
  items:
55
57
  type: string
56
58
  enum:
@@ -2,6 +2,7 @@
2
2
  #
3
3
  # site.data.base.social - Provides social networks information.
4
4
  #
5
+ preamble: "Follow us:"
5
6
  media:
6
7
  - name: YouTube
7
8
  icon: "fa-brands fa-youtube"
@@ -18,7 +18,13 @@ properties:
18
18
  preamble:
19
19
  type: string
20
20
  default: "Follow us:"
21
- description: "The social media premable. This is, a text introducing the social media buttons."
21
+ description: >-
22
+ The social media premable. This is, a text introducing the social
23
+ media buttons. This default is applied automatically whenever the
24
+ resolved data source omits the property — set it explicitly to
25
+ `false` or an empty string to render no preamble `<p>` at all; the
26
+ icon row's own margin then reclaims the vertical space. Any other
27
+ string value renders as the preamble text.
22
28
  preamble_class:
23
29
  type: string
24
30
  default: "mb-2"
@@ -19,6 +19,9 @@ Optional Inputs:
19
19
  - data: Artwork data object (overrides fallbacks)
20
20
  - column_class: Bootstrap column class for the row wrapper (set by the layout to
21
21
  keep this component aligned with the content column; defaults to "col")
22
+ - row_class: Bootstrap class(es) for the row wrapper (set by the layout to
23
+ keep this component's row aligned with breadcrumb, title, toc, and
24
+ content; defaults to "row mb-3")
22
25
 
23
26
  Data Source Hierarchy (priority):
24
27
  1. include.data
@@ -49,9 +52,10 @@ Data Source Hierarchy (priority):
49
52
  {%- assign artwork_class = with_artwork_data.class | default: with_artwork_schema.class.default %}
50
53
  {%- assign artwork_image_class = with_artwork_data.image_class | default: with_artwork_schema.image_class.default %}
51
54
  {%- assign column_class = include.column_class | default: 'col' %}
55
+ {%- assign row_class = include.row_class | default: 'row mb-3' %}
52
56
 
53
57
  {%- comment %} --- HTML --- {% endcomment %}
54
- <div class="row mb-3">
58
+ <div class="{{ row_class }}">
55
59
  <div class="{{ column_class }}">
56
60
  <div class="{{ artwork_class }}">
57
61
  <div class="{{ artwork_image_class }}" role="img" aria-label="{{ artwork_alt }}"></div>
@@ -25,7 +25,9 @@ Required Inputs (from data objects):
25
25
 
26
26
  Optional Inputs (from data objects):
27
27
  - description, screenshot, icon, image, actions, color
28
- - preamble, finale: Text before/after the upstream card
28
+ - preamble, finale: Text before/after the upstream card; each falls back to
29
+ its own schema-documented default when omitted — set explicitly to `false`
30
+ or an empty string to render neither element instead
29
31
  - class, card_class, preamble_class, finale_class: Custom styling
30
32
  - downstream_style: 'card' (default) or 'accordion'
31
33
  - downstream_limit: accordion style only; caps items shown, omit for
@@ -71,6 +73,14 @@ Data Source Hierarchy (priority order):
71
73
  {%- assign upstream_bit_index_page_url = upstream_bit.index_page_url | default: with_bits_schema.index_page_url.default %}
72
74
  {%- assign upstream_bit_screenshot_class = upstream_bit.screenshot_class | default: with_bits_schema.screenshot_class.default %}
73
75
  {%- assign upstream_bit_actions_class = upstream_bit.actions_class | default: with_bits_schema.actions_class.default %}
76
+ {%- assign upstream_bit_preamble = upstream_bit.preamble %}
77
+ {%- if upstream_bit.preamble == nil %}
78
+ {%- assign upstream_bit_preamble = with_bits_schema.preamble.default %}
79
+ {%- endif %}
80
+ {%- assign upstream_bit_finale = upstream_bit.finale %}
81
+ {%- if upstream_bit.finale == nil %}
82
+ {%- assign upstream_bit_finale = with_bits_schema.finale.default %}
83
+ {%- endif %}
74
84
  {%- assign upstream_bit_btn_class = "btn btn-sm m-1 btn-" | append: upstream_bit_color %}
75
85
  {%- assign upstream_bit_downstream_style = upstream_bit.downstream_style | default: with_bits_schema.downstream_style.default %}
76
86
  {%- assign upstream_bit_downstream_limit = upstream_bit.downstream_limit %}
@@ -79,8 +89,8 @@ Data Source Hierarchy (priority order):
79
89
  <div class="d-flex flex-column{% if upstream_bit_class != "" %} {{ upstream_bit_class }}{% endif %}">
80
90
 
81
91
  {%- comment %} --- Upstream Preamble --- {% endcomment %}
82
- {%- if upstream_bit.preamble %}
83
- <p{% if upstream_bit_preamble_class != "" %} class="{{ upstream_bit_preamble_class }}"{% endif %}>{{ upstream_bit.preamble }}</p>
92
+ {%- if upstream_bit_preamble and upstream_bit_preamble != empty %}
93
+ <p{% if upstream_bit_preamble_class != "" %} class="{{ upstream_bit_preamble_class }}"{% endif %}>{{ upstream_bit_preamble }}</p>
84
94
  {%- endif %}
85
95
 
86
96
  {%- comment %} --- Upstream Card --- {% endcomment %}
@@ -120,9 +130,9 @@ Data Source Hierarchy (priority order):
120
130
  {%- assign show_index_link = true %}
121
131
  {%- endif %}
122
132
 
123
- {%- if upstream_bit.finale %}
133
+ {%- if upstream_bit_finale and upstream_bit_finale != empty %}
124
134
  <div class="d-flex flex-row w-100 justify-content-between align-items-center">
125
- <p class="m-1{% if upstream_bit_finale_class != "" %} {{ upstream_bit_finale_class }}{% endif %}">{{ upstream_bit.finale }}</p>
135
+ <p class="m-1{% if upstream_bit_finale_class != "" %} {{ upstream_bit_finale_class }}{% endif %}">{{ upstream_bit_finale }}</p>
126
136
  {%- if show_index_link %}
127
137
  <div class="m-1">
128
138
  {%- include base/link.html.liquid
@@ -22,6 +22,9 @@ Optional Inputs:
22
22
  - with_breadcrumb_data.arialabel: aria-label for the <nav> element (default: "breadcrumb")
23
23
  - column_class (include param): Bootstrap column class for the row wrapper (set by
24
24
  the layout to keep this component aligned with the content column; defaults to "col")
25
+ - row_class (include param): Bootstrap class(es) for the row wrapper (set by
26
+ the layout to keep this component's row aligned with title, artwork, toc,
27
+ and content; defaults to "row mb-3")
25
28
 
26
29
  Data Source Hierarchy:
27
30
  - with_breadcrumb: include.with_breadcrumb → page.with_breadcrumb
@@ -50,10 +53,11 @@ Data Source Hierarchy:
50
53
  {%- assign detected_locale = page.locale | default: 'en' %}
51
54
 
52
55
  {%- assign column_class = include.column_class | default: 'col' %}
56
+ {%- assign row_class = include.row_class | default: 'row mb-3' %}
53
57
 
54
- <div class="row small mb-3">
58
+ <div class="{{ row_class }}">
55
59
  <div class="{{ column_class }}">
56
- <nav aria-label="{{ with_breadcrumb_data.arialabel | default: with_breadcrumb_schema.arialabel.default | default: 'breadcrumb' }}">
60
+ <nav class="small" aria-label="{{ with_breadcrumb_data.arialabel | default: with_breadcrumb_schema.arialabel.default | default: 'breadcrumb' }}">
57
61
  <ol class="breadcrumb mb-0">
58
62
  {%- comment %} Home link - adjust for locale {%- endcomment %}
59
63
  {%- if detected_locale == 'en' or detected_locale == '' %}
@@ -8,19 +8,49 @@
8
8
  | default: site.data.base.content
9
9
  -%}
10
10
 
11
+ {%- assign content_schema_key = "content_schema" %}
12
+ {%- assign content_schema = include.schema
13
+ | default: site.data[content_schema_key]
14
+ | default: site.data.base[content_schema_key]
15
+ -%}
16
+
17
+ {%- assign class = include.class
18
+ | default: with_content_data.class
19
+ | default: content_schema.properties.with_content_data.properties.class.default
20
+ | default: 'container py-3' -%}
21
+
22
+ {%- assign row_class = include.row_class
23
+ | default: with_content_data.row_class
24
+ | default: content_schema.properties.with_content_data.properties.row_class.default
25
+ | default: 'row mb-3' -%}
26
+
27
+ {%- assign col_class = include.col_class
28
+ | default: with_content_data.col_class
29
+ | default: content_schema.properties.with_content_data.properties.col_class.default
30
+ | default: 'col' -%}
31
+
11
32
  {%- if with_content -%}
12
- {%- assign content_schema_key = "content_schema" %}
13
- {%- assign content_schema = include.schema
14
- | default: site.data[content_schema_key]
15
- | default: site.data.base[content_schema_key]
16
- -%}
17
- {%- assign class = include.column_class
18
- | default: with_content_data.class
19
- | default: content_schema.properties.with_content_data.properties.class.default
20
- | default: 'col' -%}
21
- <div class="row mb-3">
22
- <div class="{{ class }} content">
33
+ <main class="{{ class }}">
34
+
35
+ {%- include base/announcement.html.liquid %}
36
+
37
+ {% include base/bits.html.liquid %}
38
+
39
+ {% include base/event.html.liquid %}
40
+
41
+ {% include base/breadcrumb.html.liquid column_class=col_class row_class=row_class %}
42
+
43
+ {% include base/title.html.liquid column_class=col_class row_class=row_class %}
44
+
45
+ {% include base/artwork.html.liquid column_class=col_class row_class=row_class %}
46
+
47
+ {% include base/toc.html.liquid column_class=col_class row_class=row_class %}
48
+
49
+ <div class="{{ row_class }}">
50
+ <div class="{{ col_class }} content">
23
51
  {{ content }}
24
52
  </div>
25
53
  </div>
54
+
55
+ </main>
26
56
  {%- endif -%}
@@ -10,16 +10,17 @@
10
10
 
11
11
  {%- if with_footer -%}
12
12
 
13
- <footer class="footer small bg-dark text-centos-purple-100 pt-5">
14
-
15
13
  {%- assign with_footer_schema = site.data.base.footer_schema.properties.with_footer_data.properties %}
16
14
 
15
+ {%- assign footer_class = with_footer_data.class | default: with_footer_schema.class.default %}
17
16
  {%- assign footer_brand_image = with_footer_data.brand_image | default: with_footer_schema.brand_image.default %}
18
17
  {%- assign footer_brand_image_class = with_footer_data.brand_image_class | default: with_footer_schema.brand_image_class.default %}
19
18
  {%- assign footer_brand_image_height = with_footer_data.brand_image_height | default: with_footer_schema.brand_image_height.default %}
20
19
  {%- assign footer_brand_manifestation = with_footer_data.brand_manifestation | default: with_footer_schema.brand_manifestation.default %}
21
20
  {%- assign footer_brand_manifestation_class = with_footer_data.brand_manifestation_class | default: with_footer_schema.brand_manifestation_class.default %}
22
21
 
22
+ <footer class="{{ footer_class }}">
23
+
23
24
  <div class="container">
24
25
  <div class="row justify-content-between align-items-start gx-5">
25
26
  <div class="col-sm-12 col-lg-4">
@@ -29,7 +29,6 @@ Optional Inputs:
29
29
  - page.with_breakingnews_data: Array of breaking news items
30
30
  - page.with_backtotop: Include back-to-top button (boolean)
31
31
  - page.with_copyvalue: Include copy-to-clipboard behavior (boolean)
32
- - page.with_heading_anchor: Include heading anchor copy behavior (boolean)
33
32
  - page.theme_color, site.theme_color: Override browser chrome color (default: #A54C93)
34
33
  ================================================================================
35
34
  {% endcomment %}
@@ -141,5 +140,4 @@ Uses CSS custom properties for cleaner, more maintainable dynamic styling.
141
140
  {%- comment %} JavaScript UI behavior components — depend on Bootstrap and FontAwesome SVG+JS {%- endcomment %}
142
141
  {%- include base/backtotop.html.liquid %}
143
142
  {%- include base/copyvalue.html.liquid %}
144
- {%- include base/heading_anchor.html.liquid %}
145
143
  </head>
@@ -10,7 +10,8 @@ Design Logic:
10
10
  - Responsive hamburger menu: collapses on mobile
11
11
  - Dropdown menus: multi-level navigation
12
12
  - Brand image and manifestation text support
13
- - Filtered navitems by visible_on='navbar'
13
+ - Filtered navitems by visible_on='navbar'; an item that omits visible_on
14
+ entirely falls back to being navbar-visible (schema default `["navbar"]`)
14
15
 
15
16
  Required Inputs:
16
17
  - brand_image: Logo image filename
@@ -50,7 +51,7 @@ Data Source Hierarchy (priority):
50
51
  {%- assign navbar_brand_image_height = with_navbar_data.brand_image_height | default: with_navbar_schema.brand_image_height.default %}
51
52
  {%- assign navbar_brand_manifestation = with_navbar_data.brand_manifestation | default: with_navbar_schema.brand_manifestation.default %}
52
53
  {%- assign navbar_brand_manifestation_class = with_navbar_data.brand_manifestation_class | default: with_navbar_schema.brand_manifestation_class.default %}
53
- {%- assign navbar_navitems = with_navbar_data.navitems | where: "visible_on", "navbar" | default: with_navbar_schema.navitems.default %}
54
+ {%- assign navbar_navitems = with_navbar_data.navitems | where_exp: "item", "item.visible_on == nil or item.visible_on contains 'navbar'" | default: with_navbar_schema.navitems.default %}
54
55
 
55
56
  <nav class="navbar bg-dark fixed-top navbar-expand-lg shadow{% if navbar_class != "" %} {{ navbar_class }}{% endif %}" aria-label="{{ include.arialable | default: 'navbar'}}" data-bs-theme="dark">
56
57
  <div class="container">
@@ -24,6 +24,14 @@ Optional Inputs:
24
24
  - page.locale: BCP 47 locale code set by jekyll-l10n on localized pages
25
25
 
26
26
  Data Source Hierarchy:
27
+ - og:title, twitter:title: with_ogp_data[property].title (real string override)
28
+ → page.title → schema default. `true` (this component's own previously
29
+ documented convention) is treated the same as omitted, for backward
30
+ compatibility; `false` or "" suppresses the tag entirely.
31
+ - og:image:url, :secure_url (+ twitter): with_ogp_data[property].image.url/
32
+ .secure_url (real string override) → schema default
33
+ (/assets/img/centos-social-share.png). Same `true`-tolerance as
34
+ title, for the same reason.
27
35
  - og:type: with_ogp_data.og.type → schema default → 'website'
28
36
  - og:site_name: with_ogp_data.og.site_name → site.title
29
37
  - og:logo: with_ogp_data.og.logo → schema default → '/assets/icons/apple-touch-icon.png'
@@ -35,7 +43,6 @@ Data Source Hierarchy:
35
43
  - twitter:card: with_ogp_data.twitter.card → schema default → 'summary_large_image'
36
44
  - twitter:site: with_ogp_data.twitter.site → schema default → '@CentOS'
37
45
  - twitter:creator: with_ogp_data.twitter.creator → schema default → '@CentOS'
38
- - Default image path: /assets/img/centos-social-share.png
39
46
  ================================================================================
40
47
  {% endcomment %}
41
48
 
@@ -89,8 +96,14 @@ Data Source Hierarchy:
89
96
  {%- endif %}
90
97
 
91
98
  {%- comment %} --- Title --- {% endcomment %}
92
- {%- if with_ogp_data[property].title %}
93
- <meta {{ meta_attr }}="{{ property }}:title" content="{{ page.title | escape }}" />
99
+ {%- assign ogp_title_raw = with_ogp_data[property].title %}
100
+ {%- if ogp_title_raw == nil or ogp_title_raw == true %}
101
+ {%- assign ogp_title = page.title | default: with_ogp_schema.og.properties.title.default %}
102
+ {%- else %}
103
+ {%- assign ogp_title = ogp_title_raw %}
104
+ {%- endif %}
105
+ {%- if ogp_title and ogp_title != empty %}
106
+ <meta {{ meta_attr }}="{{ property }}:title" content="{{ ogp_title | escape }}" />
94
107
  {%- endif %}
95
108
 
96
109
  {%- comment %} --- OG type and logo (after title, before url) --- {% endcomment %}
@@ -119,10 +132,24 @@ Data Source Hierarchy:
119
132
  {%- endif %}
120
133
 
121
134
  {%- comment %} --- Image --- {% endcomment %}
135
+ {%- assign ogp_image_url_raw = with_ogp_data[property].image.url %}
136
+ {%- if ogp_image_url_raw == nil or ogp_image_url_raw == true %}
137
+ {%- assign ogp_image_url = with_ogp_og_image_schema.url.default %}
138
+ {%- else %}
139
+ {%- assign ogp_image_url = ogp_image_url_raw %}
140
+ {%- endif %}
141
+
142
+ {%- assign ogp_image_secure_url_raw = with_ogp_data[property].image.secure_url %}
143
+ {%- if ogp_image_secure_url_raw == nil or ogp_image_secure_url_raw == true %}
144
+ {%- assign ogp_image_secure_url = with_ogp_og_image_schema.secure_url.default %}
145
+ {%- else %}
146
+ {%- assign ogp_image_secure_url = ogp_image_secure_url_raw %}
147
+ {%- endif %}
148
+
122
149
  {%- if with_ogp_data[property].image %}
123
- <meta {{ meta_attr }}="{{ property }}:image" content="{{ site.url }}{{ site.baseurl }}/assets/img/centos-social-share.png" />
150
+ <meta {{ meta_attr }}="{{ property }}:image" content="{{ site.url }}{{ site.baseurl }}{{ ogp_image_url }}" />
124
151
  {%- if property == "og" %}
125
- <meta {{ meta_attr }}="{{ property }}:image:secure_url" content="{{ site.url }}{{ site.baseurl }}/assets/img/centos-social-share.png" />
152
+ <meta {{ meta_attr }}="{{ property }}:image:secure_url" content="{{ site.url }}{{ site.baseurl }}{{ ogp_image_secure_url }}" />
126
153
  <meta {{ meta_attr }}="{{ property }}:image:type" content="{{ ogp_image_type }}" />
127
154
  <meta {{ meta_attr }}="{{ property }}:image:width" content="{{ ogp_image_width }}" />
128
155
  <meta {{ meta_attr }}="{{ property }}:image:height" content="{{ ogp_image_height }}" />
@@ -8,7 +8,9 @@ sections of related links in multi-column layout suitable for footer placement.
8
8
  Strategic Design Logic:
9
9
  - Grouped navigation: categories of related links
10
10
  - Column layout: multi-column footer display
11
- - Filtered items: only shows items with visible_on='footer'
11
+ - Filtered items: only shows items with visible_on='footer', required
12
+ explicitly — an item that omits visible_on is not shown here (it defaults
13
+ to navbar-visible instead, per navbar.html.liquid)
12
14
  - Reusable link component: consistent styling
13
15
  - Empty state handling: no output if no items
14
16
  - Category headings: uppercase section titles
@@ -46,7 +48,7 @@ Conditional Logic:
46
48
  | default: site.data.base.navbar
47
49
  %}
48
50
 
49
- {%- assign shortcut_navitems = with_shortcut_data.navitems | where: "visible_on", "footer" %}
51
+ {%- assign shortcut_navitems = with_shortcut_data.navitems | where_exp: "item", "item.visible_on contains 'footer'" %}
50
52
 
51
53
  {%- if with_shortcut -%}
52
54
 
@@ -2,12 +2,13 @@
2
2
  ================================================================================
3
3
  Template: Social Links Component
4
4
  Purpose: Renders a collection of social media and external links as styled
5
- buttons with icons. Includes optional site description header.
5
+ buttons with icons, with an optional preamble line introducing them.
6
6
  ================================================================================
7
7
 
8
- Strategic Design Logic:
8
+ Design Logic:
9
9
  - Multi-level data source hierarchy for flexible configuration
10
- - Site description display for context/branding purposes
10
+ - Optional preamble text and CSS class, and an optional CSS class on the
11
+ container wrapping the icon row, for full presentational customization
11
12
  - Link rendering via reusable link component with icon support
12
13
  - Icon-based visual identification for different platforms
13
14
  - Accessibility-first approach with proper ARIA labels
@@ -21,9 +22,6 @@ Required Fields (per item in the media array):
21
22
  Optional Inputs (from include):
22
23
  - data: Array of social link objects (overrides all fallbacks)
23
24
 
24
- Optional Inputs (from site configuration):
25
- - site.description: Brief site description displayed above social links
26
-
27
25
  Data Source Hierarchy (in priority order):
28
26
  1. include.data - Explicitly passed social link array
29
27
  2. page.with_social_data - Page front matter configuration
@@ -31,7 +29,10 @@ Data Source Hierarchy (in priority order):
31
29
  4. site.data.base.social - Theme default social links
32
30
 
33
31
  Conditional Logic:
34
- - Site description displays only if site.description is defined
32
+ - Preamble <p> falls back to the schema-documented default when omitted
33
+ from the resolved data source; set it explicitly to `false` or an empty
34
+ string to hide it entirely — no element is emitted in its place, so the
35
+ icon row's own margin reclaims the vertical space
35
36
  - Loops through all social links in resolved data source
36
37
  - Each link rendered with consistent button styling
37
38
  ================================================================================
@@ -50,27 +51,33 @@ Conditional Logic:
50
51
  {%- assign with_social_schema = site.data.base.social_schema.properties.with_social_data.properties %}
51
52
 
52
53
  {%- assign social_class = with_social_data.class | default: with_social_schema.class.default %}
53
- {%- assign social_preamble = with_social_data.preamble | default: with_social_schema.preamble.default %}
54
54
  {%- assign social_preamble_class = with_social_data.preamble_class | default: with_social_schema.preamble_class.default %}
55
55
  {%- assign social_media = with_social_data.media | default: with_social_schema.media.default %}
56
56
 
57
+ {%- assign social_preamble = with_social_data.preamble %}
58
+ {%- if with_social_data.preamble == nil %}
59
+ {%- assign social_preamble = with_social_schema.preamble.default %}
60
+ {%- endif %}
61
+
57
62
  {% if with_social %}
58
63
 
59
64
  {%- comment %} === Presentation (Begin) === {% endcomment %}
60
- {%- if social_preamble %}
65
+ {%- if social_preamble and social_preamble != empty %}
61
66
  <p class="{{ social_preamble_class }}">{{ social_preamble }}</p>
62
67
  {%- endif %}
63
68
 
64
- {%- for item in social_media -%}
65
- {%- include base/link.html.liquid
66
- class = "btn btn-outline-primary m-1"
67
- link = item.link
68
- role = "button"
69
- icon = item.icon
70
- aria_label = item.name
71
- data_bs_title = item.name
72
- %}
73
- {%- endfor %}
69
+ <div class="{{ social_class }}">
70
+ {%- for item in social_media -%}
71
+ {%- include base/link.html.liquid
72
+ class = "btn btn-outline-primary m-1"
73
+ link = item.link
74
+ role = "button"
75
+ icon = item.icon
76
+ aria_label = item.name
77
+ data_bs_title = item.name
78
+ %}
79
+ {%- endfor %}
80
+ </div>
74
81
  {%- comment %} === Presentation (End) === {% endcomment %}
75
82
 
76
83
  {% endif %}
@@ -24,6 +24,9 @@ Optional Inputs (from include):
24
24
  - data: Title configuration object
25
25
  - column_class: Bootstrap column class for the row wrapper (set by the layout to
26
26
  keep this component aligned with the content column; defaults to "col")
27
+ - row_class: Bootstrap class(es) for the row wrapper (set by the layout to
28
+ keep this component's row aligned with breadcrumb, artwork, toc, and
29
+ content; defaults to "row mb-3")
27
30
 
28
31
  Data Source Hierarchy (in priority order):
29
32
  1. include.data - Explicitly passed configuration
@@ -57,8 +60,9 @@ Conditional Logic:
57
60
  {%- assign title_lead = with_title_data.title_lead | default: page.title_lead %}
58
61
  {%- assign title_lead_class = with_title_data.title_lead_class | default: with_title_schema.title_lead_class.default %}
59
62
  {%- assign column_class = include.column_class | default: 'col' %}
63
+ {%- assign row_class = include.row_class | default: 'row mb-3' %}
60
64
 
61
- <div class="row mb-3">
65
+ <div class="{{ row_class }}">
62
66
  <div class="{{ column_class }}">
63
67
  <div class="{{ class }}">
64
68
  <p class="{{ title_class }}">{{ title }}</p>
@@ -33,6 +33,9 @@ Optional Inputs (from include):
33
33
  - data: TOC configuration object
34
34
  - column_class: Bootstrap column class for the row wrapper (set by the layout to
35
35
  keep this component aligned with the content column; defaults to "col")
36
+ - row_class: Bootstrap class(es) for the row wrapper (set by the layout to
37
+ keep this component's row aligned with breadcrumb, title, artwork, and
38
+ content; defaults to "row mb-3")
36
39
 
37
40
  Data Source Hierarchy (in priority order):
38
41
  - with_toc: include.with_toc → page.with_toc
@@ -62,11 +65,12 @@ Data Source Hierarchy (in priority order):
62
65
  {%- assign skip_no_ids = with_toc_data.skip_no_ids | default: with_toc_schema["skip_no_ids"].default %}
63
66
  {%- assign flat_toc = with_toc_data.flat_toc | default: with_toc_schema["flat_toc"].default %}
64
67
  {%- assign column_class = include.column_class | default: 'col' %}
68
+ {%- assign row_class = include.row_class | default: 'row mb-3' %}
65
69
 
66
70
  {%- comment %} === Presentation === {% endcomment %}
67
71
 
68
72
  {%- comment %} --- HTML --- {% endcomment %}
69
- <div class="row mb-3">
73
+ <div class="{{ row_class }}">
70
74
  <div class="{{ column_class }}">
71
75
  <div class="accordion shadow-sm" id="pageToc">
72
76
  <div class="accordion-item">
@@ -1,7 +1,7 @@
1
1
  <!doctype html>
2
2
  <html lang="{{ page.lang | default: 'en' }}"{% if page.with_ogp %} prefix="og: https://ogp.me/ns#"{% endif %}>
3
3
  {% include base/head.html.liquid -%}
4
- <body id="top" class="bg-body{% if page.with_navbar %} has-navbar{% endif %}">
4
+ <body id="top" class="{{ page.body_class | default: 'bg-body' }}{% if page.with_navbar %} has-navbar{% endif %}">
5
5
 
6
6
  {% include base/navbar.html.liquid -%}
7
7
 
@@ -9,34 +9,7 @@
9
9
 
10
10
  {% include base/breakingnews.html.liquid -%}
11
11
 
12
- {%- assign with_content_data = page.with_content_data
13
- | default: site.data.content
14
- | default: site.data.base.content
15
- -%}
16
- {%- assign content_schema = site.data.content_schema | default: site.data.base.content_schema -%}
17
- {%- assign content_class = with_content_data.class
18
- | default: content_schema.properties.with_content_data.properties.class.default
19
- | default: 'col' -%}
20
-
21
- <main class="container py-3">
22
-
23
- {%- include base/announcement.html.liquid %}
24
-
25
- {% include base/bits.html.liquid %}
26
-
27
- {% include base/event.html.liquid %}
28
-
29
- {% include base/breadcrumb.html.liquid column_class=content_class %}
30
-
31
- {% include base/title.html.liquid column_class=content_class %}
32
-
33
- {% include base/artwork.html.liquid column_class=content_class %}
34
-
35
- {% include base/toc.html.liquid column_class=content_class %}
36
-
37
- {% include base/content.html.liquid column_class=content_class %}
38
-
39
- </main>
12
+ {% include base/content.html.liquid %}
40
13
 
41
14
  {% include base/footer.html.liquid %}
42
15
  </body>
@@ -281,13 +281,13 @@ main {
281
281
  opacity: 1;
282
282
  transform: translateX(-100%);
283
283
  }
284
- .heading-anchor.is-active {
285
- opacity: 1 !important;
286
- visibility: visible !important;
287
- transform: translateX(-100%) !important;
284
+ // Plain "#" glyph — replaces the Font Awesome icon so this component has no
285
+ // icon-font dependency; font-style reset since it's text, not an icon glyph.
286
+ .heading-anchor-hash {
287
+ font-style: normal;
288
288
  }
289
- .heading-anchor.is-active i {
290
- color: var(--bs-primary);
289
+ .heading-anchor-hash::before {
290
+ content: "#";
291
291
  }
292
292
 
293
293
  // Accordion containers' bottom clearance — same as the headings/figure
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jekyll-theme-centos
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.52.0.beta.95
4
+ version: 2.52.0.beta.97
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alain Reguera Delgado
@@ -358,7 +358,6 @@ files:
358
358
  - _includes/base/fontawesome.html.liquid
359
359
  - _includes/base/footer.html.liquid
360
360
  - _includes/base/head.html.liquid
361
- - _includes/base/heading_anchor.html.liquid
362
361
  - _includes/base/highlight.html.liquid
363
362
  - _includes/base/image.html.liquid
364
363
  - _includes/base/link.html.liquid
@@ -518,7 +517,6 @@ files:
518
517
  - assets/js/base/backtotop.js
519
518
  - assets/js/base/copyvalue.js
520
519
  - assets/js/base/datatable.js
521
- - assets/js/base/heading-anchor.js
522
520
  - assets/js/base/highlight.js
523
521
  - assets/js/base/init-tooltips.js
524
522
  - assets/js/bootstrap.bundle.js
@@ -1,67 +0,0 @@
1
- {% comment %}
2
- ================================================================================
3
- Template: Heading Anchor Component
4
- Purpose: Loads heading-anchor.js which wires click-to-copy behaviour on anchor
5
- icons that jekyll-link-decorator injects inside h1–h6 elements. Clicking an
6
- anchor icon copies the full page URL (origin + pathname + fragment) to the
7
- clipboard, with a transient fa-check icon as visual feedback.
8
-
9
- Recommended Usage (in head.html.liquid):
10
- {%- include base/heading_anchor.html.liquid %}
11
-
12
- The heading anchor icons themselves are injected by the jekyll-link-decorator
13
- Ruby plugin. This include only loads the JavaScript that powers copy behaviour.
14
-
15
- Required Inputs (from HTML elements produced by the plugin):
16
- - class="heading-anchor" : Selector used to attach click handlers
17
- - data-copy-anchor="#id" : Fragment to append to the current page URL
18
-
19
- Optional Inputs (from data objects):
20
- - reset_delay : Milliseconds before icon resets (default from schema)
21
- - copy_success_message : Not consumed by JS directly; available for reference
22
-
23
- Data Source Hierarchy (in priority order):
24
- 1. include.data - Explicitly passed configuration
25
- 2. page.with_heading_anchor_data - Page front matter
26
- 3. site.data.heading_anchor - Site configuration
27
- 4. site.data.base.heading_anchor - Theme defaults
28
-
29
- Dependencies:
30
- jekyll-link-decorator gem, FontAwesome 6+, Clipboard API (modern browsers)
31
- ================================================================================
32
- {% endcomment %}
33
-
34
- {%- assign with_heading_anchor = include.with_heading_anchor
35
- | default: page.with_heading_anchor
36
- | default: site.with_heading_anchor
37
- -%}
38
-
39
- {%- assign with_heading_anchor_data = include.data
40
- | default: page.with_heading_anchor_data
41
- | default: site.data.heading_anchor
42
- | default: site.data.base.heading_anchor
43
- -%}
44
-
45
- {%- assign with_heading_anchor_schema = site.data.base.heading_anchor_schema.properties.with_heading_anchor_data.properties -%}
46
-
47
- {%- if with_heading_anchor -%}
48
-
49
- {%- comment %} === Presentation === {% endcomment %}
50
-
51
- {%- comment %} --- Defaults --- {% endcomment %}
52
- {%- assign heading_anchor_reset_delay = with_heading_anchor_data.reset_delay | default: with_heading_anchor_schema.reset_delay.default -%}
53
- {%- assign heading_anchor_success_message = with_heading_anchor_data.copy_success_message | default: with_heading_anchor_schema.copy_success_message.default -%}
54
-
55
- {%- comment %} --- HTML --- {% endcomment %}
56
- <!-- Load Heading Anchor functionality with configuration via data attributes -->
57
- <script id="centos-heading-anchor"
58
- {%- if with_heading_anchor_data.reset_delay %}
59
- data-reset-delay="{{ heading_anchor_reset_delay }}"
60
- {%- endif %}
61
- {%- if with_heading_anchor_data.copy_success_message %}
62
- data-success-message="{{ heading_anchor_success_message }}"
63
- {%- endif %}
64
- src="{{ site.baseurl }}/assets/js/base/heading-anchor.min.js"
65
- defer></script>
66
-
67
- {%- endif -%}
@@ -1,109 +0,0 @@
1
- // Heading Anchor Component — requires Bootstrap >= 5.3 (tooltip.setContent) and Font Awesome 6+
2
-
3
- document.addEventListener('DOMContentLoaded', () => {
4
- if (typeof bootstrap === 'undefined') {
5
- console.warn('heading-anchor: Bootstrap not available')
6
- return
7
- }
8
-
9
- const DEFAULT_TEXT = 'Copy link'
10
- const scriptEl = document.getElementById('centos-heading-anchor')
11
- const RESET_DELAY = scriptEl?.dataset.resetDelay
12
- ? parseInt(scriptEl.dataset.resetDelay, 10) : 2000
13
- const SUCCESS_TEXT = scriptEl?.dataset.successMessage || 'Copied!'
14
-
15
- // One shared region: multiple regions would cause simultaneous AT announcements per anchor.
16
- let liveRegion = document.getElementById('centos-heading-anchor-live')
17
- if (!liveRegion) {
18
- liveRegion = document.createElement('div')
19
- liveRegion.id = 'centos-heading-anchor-live'
20
- liveRegion.setAttribute('aria-live', 'polite')
21
- liveRegion.setAttribute('aria-atomic', 'true')
22
- liveRegion.className = 'visually-hidden'
23
- document.body.appendChild(liveRegion)
24
- }
25
-
26
- document.querySelectorAll('.heading-anchor[data-copy-anchor]').forEach(anchor => {
27
- // FA SVG+JS replaces <i> with <svg> before this DOMContentLoaded fires.
28
- // Cache innerHTML after FA has processed so it can be restored on reset.
29
- const originalIconHTML = anchor.innerHTML
30
- // Guards blur/mouseenter handlers from collapsing the tooltip during the success window.
31
- let isLocked = false
32
-
33
- const tooltip = new bootstrap.Tooltip(anchor, {
34
- title: DEFAULT_TEXT,
35
- trigger: 'manual', // CSS sets pointer-events:none on hidden anchors, defeating Bootstrap's auto hover/focus triggers.
36
- placement: 'top',
37
- animation: false // Prevents Bootstrap's fade and the CSS opacity transition from desyncing.
38
- })
39
-
40
- const updateUI = (isSuccess) => {
41
- tooltip.setContent({ '.tooltip-inner': isSuccess ? SUCCESS_TEXT : DEFAULT_TEXT })
42
- if (isSuccess) {
43
- // FA SVG+JS mode: <i> has been replaced by <svg>; swap the path to a checkmark.
44
- const svg = anchor.querySelector('svg')
45
- if (svg) {
46
- const path = svg.querySelector('path')
47
- if (path) {
48
- svg.setAttribute('viewBox', '0 0 448 512')
49
- path.setAttribute('d', 'M434.8 70.1c14.3 10.4 17.5 30.4 7.1 44.7l-256 352c-5.5 7.6-14 12.3-23.4 13.1s-18.5-2.7-25.1-9.3l-128-128c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0l101.5 101.5 234-321.7c10.4-14.3 30.4-17.5 44.7-7.1z')
50
- }
51
- } else {
52
- // FA webfont mode: <i> is still in the DOM; toggle classes normally.
53
- const icon = anchor.querySelector('i')
54
- if (icon) { icon.classList.remove('fa-hashtag'); icon.classList.add('fa-check') }
55
- }
56
- } else {
57
- anchor.innerHTML = originalIconHTML
58
- }
59
- anchor.classList.toggle('is-active', isSuccess)
60
- // Empty string on reset prevents AT from re-announcing stale text on DOM inspection.
61
- liveRegion.textContent = isSuccess ? SUCCESS_TEXT : ''
62
- if (isSuccess) tooltip.show()
63
- }
64
-
65
- const handleInteraction = (show) => {
66
- if (!isLocked) show ? tooltip.show() : tooltip.hide()
67
- }
68
-
69
- anchor.addEventListener('mouseenter', () => handleInteraction(true))
70
- anchor.addEventListener('mouseleave', () => handleInteraction(false))
71
- anchor.addEventListener('focus', () => handleInteraction(true))
72
- anchor.addEventListener('blur', () => handleInteraction(false))
73
-
74
- anchor.addEventListener('click', async (e) => {
75
- e.preventDefault()
76
- anchor.closest('h1, h2, h3, h4, h5, h6')?.scrollIntoView()
77
- if (isLocked) return
78
-
79
- if (!navigator.clipboard) {
80
- console.warn('heading-anchor: Clipboard API unavailable')
81
- return
82
- }
83
-
84
- const url = window.location.origin + window.location.pathname + anchor.dataset.copyAnchor
85
-
86
- try {
87
- await navigator.clipboard.writeText(url)
88
- isLocked = true
89
- // isLocked must be true before blur() so the resulting blur event is suppressed
90
- // and does not hide the tooltip before the success state has been rendered.
91
- anchor.blur()
92
- updateUI(true)
93
-
94
- setTimeout(() => {
95
- isLocked = false
96
- updateUI(false)
97
- // mouseleave/blur events fired while isLocked was true were suppressed;
98
- // hide now if the user already moved away during the success window.
99
- if (!anchor.matches(':hover')) tooltip.hide()
100
- }, RESET_DELAY)
101
-
102
- } catch (err) {
103
- console.warn('heading-anchor: clipboard write failed', err)
104
- isLocked = false
105
- anchor.innerHTML = originalIconHTML
106
- }
107
- })
108
- })
109
- })