jekyll-theme-centos 2.52.0.beta.52 → 2.52.0.beta.53

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.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/_data/base/bits_schema.yml +5 -4
  3. data/_data/base/content_schema.yml +1 -1
  4. data/_data/base/footer.yml +9 -0
  5. data/_data/base/footer_schema.yml +55 -0
  6. data/_data/base/heading_anchor.yml +4 -0
  7. data/_data/base/heading_anchor_schema.yml +37 -0
  8. data/_data/base/link_schema.yml +101 -67
  9. data/_data/base/locales_schema.yml +1 -1
  10. data/_data/base/project_schema.yml +8 -4
  11. data/_data/base/title_schema.yml +1 -1
  12. data/_data/base/toc_schema.yml +16 -2
  13. data/_includes/base/announcement.html.liquid +19 -7
  14. data/_includes/base/artwork.html.liquid +18 -6
  15. data/_includes/base/backtotop.html.liquid +20 -6
  16. data/_includes/base/bits.html.liquid +31 -18
  17. data/_includes/base/breadcrumb.html.liquid +7 -1
  18. data/_includes/base/breakingnews.html.liquid +19 -7
  19. data/_includes/base/card.html.liquid +43 -29
  20. data/_includes/base/configuration-variables-nested.html.liquid +1 -1
  21. data/_includes/base/configuration-variables.html.liquid +3 -3
  22. data/_includes/base/copyright.html.liquid +18 -6
  23. data/_includes/base/copyvalue.html.liquid +19 -5
  24. data/_includes/base/datatable.html.liquid +20 -6
  25. data/_includes/base/event.html.liquid +33 -21
  26. data/_includes/base/fontawesome.html.liquid +21 -7
  27. data/_includes/base/footer.html.liquid +36 -29
  28. data/_includes/base/head.html.liquid +60 -68
  29. data/_includes/base/heading_anchor.html.liquid +62 -0
  30. data/_includes/base/highlight.html.liquid +19 -5
  31. data/_includes/base/link.html.liquid +47 -53
  32. data/_includes/base/locales.html.liquid +41 -30
  33. data/_includes/base/navbar.html.liquid +22 -12
  34. data/_includes/base/navindex.html.liquid +14 -2
  35. data/_includes/base/ogp.html.liquid +89 -75
  36. data/_includes/base/project.html.liquid +34 -22
  37. data/_includes/base/script.html.liquid +7 -19
  38. data/_includes/base/shortcut.html.liquid +32 -24
  39. data/_includes/base/social.html.liquid +33 -23
  40. data/_includes/base/sponsors-cards.html.liquid +17 -6
  41. data/_includes/base/sponsors-carousel.html.liquid +21 -8
  42. data/_includes/base/title.html.liquid +21 -10
  43. data/_includes/base/toc.html.liquid +2 -2
  44. data/_layouts/base/default.html +8 -8
  45. data/_sass/base/_customization.scss +47 -0
  46. data/assets/img/base/page-layout-default.png +0 -0
  47. data/assets/img/base/page-layout-default.svg +878 -1241
  48. data/assets/img/base/page-with-backtotop.png +0 -0
  49. data/assets/img/base/page-with-backtotop.svg +800 -573
  50. data/assets/img/base/page-with-copyright.png +0 -0
  51. data/assets/img/base/page-with-copyright.svg +818 -645
  52. data/assets/img/base/page-with-footer.png +0 -0
  53. data/assets/img/base/page-with-footer.svg +1018 -0
  54. data/assets/img/base/page-with-link.png +0 -0
  55. data/assets/img/base/page-with-link.svg +142 -139
  56. data/assets/img/base/page-with-locales.png +0 -0
  57. data/assets/img/base/page-with-locales.svg +795 -577
  58. data/assets/img/base/page-with-shortcut.png +0 -0
  59. data/assets/img/base/page-with-shortcut.svg +796 -569
  60. data/assets/img/base/page-with-social.png +0 -0
  61. data/assets/img/base/page-with-social.svg +811 -673
  62. data/assets/img/base/page-with-sponsors.png +0 -0
  63. data/assets/img/base/page-with-sponsors.svg +795 -568
  64. data/assets/js/base/heading-anchor.js +108 -0
  65. data/assets/js/base/init-tooltips.js +5 -4
  66. metadata +10 -3
  67. data/_data/base/toc_generator_schema.yml +0 -102
  68. /data/_includes/base/{toc_generator.html.liquid → toc-generator.html.liquid} +0 -0
@@ -1,29 +1,36 @@
1
- {%- assign navbar_brand_image = navbar.brand_image | default: schema.brand_image.default %}
2
- {%- assign navbar_brand_image_class = navbar.brand_image_class | default: schema.brand_image_class.default %}
3
- {%- assign navbar_brand_image_height = navbar.brand_image_height | default: schema.brand_image_height.default %}
4
- {%- assign navbar_brand_manifestation = navbar.brand_manifestation | default: schema.brand_manifestation.default %}
5
- {%- assign navbar_brand_manifestation_class = navbar.brand_manifestation_class | default: schema.brand_manifestation_class.default %}
1
+ {%- assign with_footer = include.with_footer
2
+ | default: page.with_footer
3
+ %}
6
4
 
7
- {%- if page.with_footer -%}
5
+ {%- assign with_footer_data = include.data
6
+ | default: page.with_footer_data
7
+ | default: site.data.footer
8
+ | default: site.data.base.partials.footer
9
+ %}
8
10
 
9
- <div class="container">
11
+ {%- assign with_footer_schema = site.data.base.partials.footer_schema.properties.with_footer_data.properties %}
10
12
 
11
- <div class="row justify-content-between align-items-start gx-5">
13
+ {%- assign footer_brand_image = with_footer_data.brand_image | default: with_footer_schema.brand_image.default %}
14
+ {%- assign footer_brand_image_class = with_footer_data.brand_image_class | default: with_footer_schema.brand_image_class.default %}
15
+ {%- assign footer_brand_image_height = with_footer_data.brand_image_height | default: with_footer_schema.brand_image_height.default %}
16
+ {%- assign footer_brand_manifestation = with_footer_data.brand_manifestation | default: with_footer_schema.brand_manifestation.default %}
17
+ {%- assign footer_brand_manifestation_class = with_footer_data.brand_manifestation_class | default: with_footer_schema.brand_manifestation_class.default %}
18
+
19
+ {%- if with_footer -%}
12
20
 
21
+ <div class="container">
22
+ <div class="row justify-content-between align-items-start gx-5">
13
23
  <div class="col-sm-12 col-lg-4">
14
- {%- if navbar_brand_image != "" %}
24
+ {%- if footer_brand_image != "" %}
15
25
  <a class="navbar-brand" href="{{ site.baseurl }}/">
16
-
17
26
  <img
18
- class="d-inline-block align-text-middle me-2{% if navbar_brand_image_class != "" %} {{ navbar_brand_image_class }}{% endif %}"
19
- src="{{ site.baseurl }}/assets/img/{{ navbar_brand_image }}"
20
- height="{{ navbar_brand_image_height }}"
27
+ class="d-inline-block align-text-middle me-2{% if footer_brand_image_class != "" %} {{ footer_brand_image_class }}{% endif %}"
28
+ src="{{ site.baseurl }}/assets/img/{{ footer_brand_image }}"
29
+ height="{{ footer_brand_image_height }}"
21
30
  alt="{{ site.title }}" />
22
-
23
- {%- if navbar_brand_manifestation != "" %}
24
- <span class="d-inline-block align-text-middle fs-6 border-start border-1 border-light opacity-75 ps-3{% if navbar_brand_manifestation_class != "" %} {{ navbar_brand_manifestation_class }}{% endif %}">{{ navbar_brand_manifestation }}</span>
31
+ {%- if footer_brand_manifestation != "" %}
32
+ <span class="d-inline-block align-text-middle fs-6 border-start border-1 border-light opacity-75 ps-3{% if footer_brand_manifestation_class != "" %} {{ footer_brand_manifestation_class }}{% endif %}">{{ footer_brand_manifestation }}</span>
25
33
  {%- endif %}
26
-
27
34
  </a>
28
35
  {%- endif %}
29
36
  {% if site.description %}
@@ -34,29 +41,29 @@
34
41
  </div>
35
42
 
36
43
  {% if page.with_shortcut %}
37
- <div class="col-sm-12 col-lg-5">
38
- {% include base/shortcut.html.liquid %}
39
- </div>
44
+ <div class="col-sm-12 col-lg-5">
45
+ {% include base/shortcut.html.liquid %}
46
+ </div>
40
47
  {% endif %}
41
48
 
42
49
  {% if page.with_locales or page.with_social %}
43
- <div class="col-sm-12 col-lg-3 pb-5">
44
- {% include base/locales.html.liquid %}
45
- {% include base/social.html.liquid %}
46
- </div>
50
+ <div class="col-sm-12 col-lg-3 pb-5">
51
+ {% include base/locales.html.liquid %}
52
+ {% include base/social.html.liquid %}
53
+ </div>
47
54
  {% endif %}
48
55
 
49
56
  </div>
50
57
  </div>
51
58
 
52
59
  {% if page.with_copyright %}
53
- <div class="container">
54
- <div class="row justify-content-between align-items-center py-3">
55
- <div class="col">
56
- {% include base/copyright.html.liquid %}
60
+ <div class="container">
61
+ <div class="row justify-content-between align-items-center py-3">
62
+ <div class="col">
63
+ {% include base/copyright.html.liquid %}
64
+ </div>
57
65
  </div>
58
66
  </div>
59
- </div>
60
67
  {% endif %}
61
68
 
62
69
  {%- endif -%}
@@ -28,74 +28,66 @@ Optional Inputs:
28
28
  {% endcomment %}
29
29
 
30
30
  <head>
31
- {% if page.title == site.title -%}
32
- <title>{{ page.title }}</title>
33
- {% else -%}
34
- <title>{{ page.title }} - {{ site.title }}</title>
35
- {% endif -%}
36
- <meta charset="utf-8" />
37
- <meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no" />
38
- {%- if page.with_ogp == true -%}
39
- {% include base/ogp.html.liquid %}
40
- {%- endif %}
41
- <link rel="icon" href="{{ site.baseurl }}/assets/icons/favicon-16.png" sizes="16x16" />
42
- <link rel="icon" href="{{ site.baseurl }}/assets/icons/favicon-32.png" sizes="32x32" />
43
- <link rel="icon" href="{{ site.baseurl }}/assets/icons/favicon.svg" sizes="any" />
44
- <link rel="apple-touch-icon" href="{{ site.baseurl }}/assets/icons/apple-touch-icon.png" sizes="180x180" />
45
- <link rel="manifest" href="{{ site.baseurl }}/site.webmanifest" />
46
- <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
47
- <link rel="preconnect" href="https://fonts.googleapis.com" />
48
- <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&family=Source+Code+Pro:ital,wght@0,400;0,500;0,700;1,400;1,500;1,700&display=swap" />
49
- <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Source+Code+Pro:ital,wght@0,400;0,500;0,700;1,400;1,500;1,700&display=swap" />
50
- <link rel="stylesheet" href="{{ site.baseurl }}/assets/css/base/stylesheet.min.css" />
51
- {%- comment %}
52
- Dynamic Breaking News Offset CSS
53
- Adjust scroll-margin-top values based on the number of breaking news items.
54
- Uses CSS custom properties for cleaner, more maintainable dynamic styling.
55
- {%- endcomment %}
56
- {%- assign breakingnews = page.with_breakingnews_data | default: site.data.breakingnews | default: site.data.base.breakingnews %}
57
- {%- if page.with_breakingnews == true and breakingnews.size > 0 %}
58
- {%- assign breakingnews_alert_height = 31 %}
59
- {%- assign navbar_height = 42 %}
60
- {%- assign breakingnews_offset = 0 %}
61
- {%- for item in breakingnews %}
62
- {%- if forloop.first %}
63
- {%- assign breakingnews_offset = breakingnews_alert_height | plus: navbar_height %}
64
- {%- else %}
65
- {%- assign breakingnews_offset = breakingnews_offset | plus: breakingnews_alert_height %}
66
- {%- endif %}
67
- {%- endfor %}
68
- {%- assign heading_margin_px = 48 %}
69
- {%- assign heading_scroll_margin_height = breakingnews_offset | plus: heading_margin_px %}
70
- {%- assign accordion_scroll_margin_height = breakingnews_offset %}
71
- <style>
72
- :root {
73
- --calculated-heading-offset: {{ heading_scroll_margin_height }}px;
74
- --calculated-accordion-offset: {{ accordion_scroll_margin_height }}px;
31
+ {% if page.title == site.title -%}
32
+ <title>{{ page.title }}</title>
33
+ {% else -%}
34
+ <title>{{ page.title }} - {{ site.title }}</title>
35
+ {% endif -%}
36
+ <meta charset="utf-8" />
37
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no" />
38
+ {% include base/ogp.html.liquid %}
39
+ <link rel="icon" href="{{ site.baseurl }}/assets/icons/favicon-16.png" sizes="16x16" />
40
+ <link rel="icon" href="{{ site.baseurl }}/assets/icons/favicon-32.png" sizes="32x32" />
41
+ <link rel="icon" href="{{ site.baseurl }}/assets/icons/favicon.svg" sizes="any" />
42
+ <link rel="apple-touch-icon" href="{{ site.baseurl }}/assets/icons/apple-touch-icon.png" sizes="180x180" />
43
+ <link rel="manifest" href="{{ site.baseurl }}/site.webmanifest" />
44
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
45
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
46
+ <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&family=Source+Code+Pro:ital,wght@0,400;0,500;0,700;1,400;1,500;1,700&display=swap" />
47
+ <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Source+Code+Pro:ital,wght@0,400;0,500;0,700;1,400;1,500;1,700&display=swap" />
48
+ <link rel="stylesheet" href="{{ site.baseurl }}/assets/css/base/stylesheet.min.css" />
49
+ {%- comment %}
50
+ Dynamic Breaking News Offset CSS
51
+ Adjust scroll-margin-top values based on the number of breaking news items.
52
+ Uses CSS custom properties for cleaner, more maintainable dynamic styling.
53
+ {%- endcomment %}
54
+ {%- assign breakingnews = page.with_breakingnews_data | default: site.data.breakingnews | default: site.data.base.breakingnews %}
55
+ {%- if page.with_breakingnews == true and breakingnews.size > 0 %}
56
+ {%- assign breakingnews_alert_height = 31 %}
57
+ {%- assign navbar_height = 42 %}
58
+ {%- assign breakingnews_offset = 0 %}
59
+ {%- for item in breakingnews %}
60
+ {%- if forloop.first %}
61
+ {%- assign breakingnews_offset = breakingnews_alert_height | plus: navbar_height %}
62
+ {%- else %}
63
+ {%- assign breakingnews_offset = breakingnews_offset | plus: breakingnews_alert_height %}
64
+ {%- endif %}
65
+ {%- endfor %}
66
+ {%- assign heading_margin_px = 48 %}
67
+ {%- assign heading_scroll_margin_height = breakingnews_offset | plus: heading_margin_px %}
68
+ {%- assign accordion_scroll_margin_height = breakingnews_offset %}
69
+ <style>
70
+ :root {
71
+ --calculated-heading-offset: {{ heading_scroll_margin_height }}px;
72
+ --calculated-accordion-offset: {{ accordion_scroll_margin_height }}px;
73
+ }
74
+ main {
75
+ .content > h1,
76
+ .content > h2,
77
+ .content > h3,
78
+ .content > h4,
79
+ .content > h5,
80
+ .content > h6 {
81
+ scroll-margin-top: calc(var(--calculated-heading-offset) * 1.3) !important;
75
82
  }
76
- main {
77
- .content > h1,
78
- .content > h2,
79
- .content > h3,
80
- .content > h4,
81
- .content > h5,
82
- .content > h6 {
83
- scroll-margin-top: calc(var(--calculated-heading-offset) * 1.3) !important;
84
- }
85
- .content .accordion,
86
- .content .accordion-item {
87
- scroll-margin-top: calc(var(--calculated-accordion-offset) * 1.5) !important;
88
- }
83
+ .content .accordion,
84
+ .content .accordion-item {
85
+ scroll-margin-top: calc(var(--calculated-accordion-offset) * 1.5) !important;
89
86
  }
90
- </style>
91
- {%- endif %}
92
- {% if page.with_fontawesome %}
93
- {% include base/fontawesome.html.liquid type="head" %}
94
- {% endif %}
95
- {% if page.with_highlight %}
96
- {% include base/highlight.html.liquid type="head" %}
97
- {% endif -%}
98
- {% if page.with_datatable %}
99
- {% include base/datatable.html.liquid type="head" %}
100
- {% endif -%}
87
+ }
88
+ </style>
89
+ {%- endif %}
90
+ {% include base/fontawesome.html.liquid type="head" %}
91
+ {% include base/highlight.html.liquid type="head" %}
92
+ {% include base/datatable.html.liquid type="head" %}
101
93
  </head>
@@ -0,0 +1,62 @@
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 partials/script.html.liquid or layout):
10
+ {% include 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
+ data-reset-delay="{{ heading_anchor_reset_delay }}"
59
+ data-success-message="{{ heading_anchor_success_message }}"
60
+ src="{{ site.baseurl }}/assets/js/base/heading-anchor.min.js"></script>
61
+
62
+ {%- endif -%}
@@ -27,12 +27,24 @@ Data Source Hierarchy (priority):
27
27
  ================================================================================
28
28
  {% endcomment %}
29
29
 
30
- {%- assign highlight = include.data | default: page.with_highlight_data | default: site.data.highlight | default: site.data.base.highlight %}
30
+ {%- assign with_highlight = include.with_highlight
31
+ | default: page.with_highlight
32
+ %}
31
33
 
32
- {%- assign highlight_theme = highlight.theme | default: site.data.base.highlight_schema.properties.with_highlight_data.properties.theme.default %}
33
- {%- assign highlight_version = highlight.version | default: site.data.base.highlight_schema.properties.with_highlight_data.properties.version.default %}
34
- {%- assign copy_icon_svg = highlight.copy_button_icons.copy.svg | default: site.data.base.highlight_schema.properties.with_highlight_data.properties.copy_button_icons.properties.copy.properties.svg.default %}
35
- {%- assign success_icon_svg = highlight.copy_button_icons.success.svg | default: site.data.base.highlight_schema.properties.with_highlight_data.properties.copy_button_icons.properties.success.properties.svg.default %}
34
+ {%- assign with_highlight_data = include.data
35
+ | default: page.with_highlight_data
36
+ | default: site.data.highlight
37
+ | default: site.data.base.highlight
38
+ %}
39
+
40
+ {%- assign with_highlight_schema = site.data.base.highlight_schema.properties.with_highlight_data.properties %}
41
+
42
+ {%- if with_highlight %}
43
+
44
+ {%- assign highlight_theme = with_highlight_data.theme | default: with_highlight_schema.theme.default %}
45
+ {%- assign highlight_version = with_highlight_data.version | default: with_highlight_schema.version.default %}
46
+ {%- assign copy_icon_svg = with_highlight_data.copy_button_icons.copy.svg | default: with_highlight_schema.copy_button_icons.properties.copy.properties.svg.default %}
47
+ {%- assign success_icon_svg = with_highlight_data.copy_button_icons.success.svg | default: with_highlight_schema.copy_button_icons.properties.success.properties.svg.default %}
36
48
 
37
49
  {%- capture html_highlight_head %}
38
50
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/{{ highlight_version }}/styles/{{ highlight_theme | replace_first: 'base16-', 'base16/' | default: 'default' }}.min.css" />
@@ -63,3 +75,5 @@ Data Source Hierarchy (priority):
63
75
  {%- when "script" %}
64
76
  {{ html_highlight_script }}
65
77
  {%- endcase %}
78
+
79
+ {%- endif %}
@@ -24,74 +24,63 @@ Optional Inputs:
24
24
  - class: Custom CSS classes to override default styling
25
25
  - aria_label: Accessible label for screen readers
26
26
  - role: ARIA role attribute
27
+ - data_bs_toggle: Bootstrap toggle ('tooltip' or 'popover')
28
+ - data_bs_title: Bootstrap tooltip/popover text content
29
+ - data_bs_content: Bootstrap popover body text (required when data_bs_toggle is 'popover')
30
+ - data_bs_placement: Bootstrap tooltip/popover placement ('top', 'bottom', 'start', 'end')
31
+ - data_bs_trigger: Bootstrap tooltip/popover trigger events
32
+ - data_bs_delay: Bootstrap tooltip/popover show/hide delay (number or JSON)
33
+ - data_bs_html: Allow HTML in tooltip/popover content ('true' or 'false')
34
+ - data_bs_custom_class: Custom CSS class for tooltip/popover element
35
+ - data_bs_offset: Tooltip/popover position offset (comma-separated pair)
27
36
 
28
37
  Security & External Links:
29
38
  - target="_blank" automatically adds rel="noopener noreferrer"
30
- - External cross-domain links with target="_blank" auto-display
31
- fa-solid fa-external-link icon (unless manually overridden)
32
- - See: examples/jekyll/layouts/default/components/link.md
39
+ - External link icon injection is handled by jekyll-link-decorator
33
40
  ================================================================================
34
41
  {% endcomment %}
35
42
 
36
43
  {%- capture html_link -%}
37
44
  {%- comment %} === Data source selection === {% endcomment %}
38
- {%- assign link = include.link | default: nil %}
39
- {%- assign name = include.name | default: nil %}
40
- {%- assign target = include.target | default: nil %}
41
- {%- assign color = include.color | default: "primary" %}
42
- {%- assign role = include.role | default: nil %}
43
- {%- assign icon = include.icon | default: nil %}
44
- {%- assign icon_position = include.icon_position | default: "start" %}
45
- {%- assign class = include.class | default: nil %}
46
- {%- assign aria_label = include.aria_label | default: nil %}
47
- {%- assign data_bs_toggle = include.data_bs_toggle | default: nil %}
48
- {%- assign data_bs_title = include.data_bs_title | default: nil %}
49
- {%- assign data_bs_placement = include.data_bs_placement | default: nil %}
50
- {%- assign anchor = nil %}
51
- {%- assign rel_attr = nil %}
52
- {%- assign is_external_link = false %}
53
- {%- assign auto_icon = nil %}
45
+ {%- assign link = include.link | default: nil %}
46
+ {%- assign name = include.name | default: nil %}
47
+ {%- assign target = include.target | default: nil %}
48
+ {%- assign color = include.color | default: "primary" %}
49
+ {%- assign role = include.role | default: nil %}
50
+ {%- assign icon = include.icon | default: nil %}
51
+ {%- assign icon_position = include.icon_position | default: "start" %}
52
+ {%- assign class = include.class | default: nil %}
53
+ {%- assign aria_label = include.aria_label | default: nil %}
54
+ {%- assign data_bs_toggle = include.data_bs_toggle | default: nil %}
55
+ {%- assign data_bs_title = include.data_bs_title | default: nil %}
56
+ {%- assign data_bs_content = include.data_bs_content | default: nil %}
57
+ {%- assign data_bs_placement = include.data_bs_placement | default: nil %}
58
+ {%- assign data_bs_trigger = include.data_bs_trigger | default: nil %}
59
+ {%- assign data_bs_delay = include.data_bs_delay | default: nil %}
60
+ {%- assign data_bs_html = include.data_bs_html | default: nil %}
61
+ {%- assign data_bs_custom_class = include.data_bs_custom_class | default: nil %}
62
+ {%- assign data_bs_offset = include.data_bs_offset | default: nil %}
63
+ {%- assign anchor = nil %}
64
+ {%- assign rel_attr = nil %}
54
65
 
55
66
  {%- comment %} === Data processing === {% endcomment %}
56
67
  {%- if link != nil -%}
57
- {%- if link contains "https://" or link contains "http://" -%}
68
+ {%- assign link_char1 = link | slice: 0, 1 -%}
69
+ {%- assign link_char2 = link | slice: 0, 2 -%}
70
+ {%- if link contains "://" or link contains "mailto:" or link contains "tel:" or link_char1 == "#" or link_char2 == "//" -%}
58
71
  {%- assign href_value = link %}
59
- {%- assign is_external_link = true %}
60
72
  {%- else -%}
61
73
  {%- assign href_value = site.baseurl | append: link %}
62
74
  {%- endif -%}
63
75
  {%- else -%}
64
76
  {%- assign href_value = site.baseurl %}
65
- {%- assign anchor = name | strip | replace: ' ', '-' | downcase %}
66
- {%- endif -%}
67
-
68
- {%- comment %} === External link icon handling === {% endcomment %}
69
- {%- if is_external_link and target == "_blank" and icon == nil -%}
70
- {%- comment %} Extract domain from link URL (remove protocol) {% endcomment %}
71
- {%- assign link_domain = link | replace: "https://", "" | replace: "http://", "" %}
72
- {%- assign link_domain = link_domain | split: "/" | first %}
73
- {%- assign link_domain = link_domain | split: "?" | first %}
74
- {%- assign link_domain = link_domain | split: "#" | first %}
75
- {%- assign link_domain = link_domain | downcase %}
76
-
77
- {%- comment %} Extract domain from site.url (remove protocol) {% endcomment %}
78
- {%- assign site_domain = site.url | default: site.baseurl | replace: "https://", "" | replace: "http://", "" %}
79
- {%- assign site_domain = site_domain | split: "/" | first %}
80
- {%- assign site_domain = site_domain | split: "?" | first %}
81
- {%- assign site_domain = site_domain | split: "#" | first %}
82
- {%- assign site_domain = site_domain | downcase %}
83
-
84
- {%- comment %} If domains don't match, add external link icon {% endcomment %}
85
- {%- if link_domain != site_domain -%}
86
- {%- assign auto_icon = "fa-solid fa-external-link" %}
87
- {%- assign icon_position = "end" %}
88
- {%- endif -%}
77
+ {%- assign anchor = name | strip | replace: ' ', '-' | remove: '"' | remove: "'" | remove: '?' | remove: '&' | remove: '#' | remove: '/' | downcase %}
89
78
  {%- endif -%}
90
79
 
91
80
  {%- if class != nil -%}
92
81
  {%- assign link_class = class %}
93
82
  {%- else -%}
94
- {%- assign link_class = "link-" | append: color %}
83
+ {%- assign link_class = "link link-" | append: color %}
95
84
  {%- assign link_class = link_class | append: " link-offset-3 link-offset-3-hover link-underline-" %}
96
85
  {%- assign link_class = link_class | append: color %}
97
86
  {%- assign link_class = link_class | append: " link-underline-opacity-0 link-underline-opacity-100-hover" %}
@@ -103,16 +92,15 @@ Security & External Links:
103
92
  {%- endif -%}
104
93
 
105
94
  {%- comment %} --- Link name with optional icon --- {% endcomment %}
106
- {%- comment %} Use manual icon if provided, otherwise use auto_icon if set {% endcomment %}
107
- {%- assign final_icon = icon | default: auto_icon %}
95
+ {%- assign final_icon = icon %}
108
96
  {%- capture link_name -%}
109
97
  {%- if final_icon != nil -%}
110
98
  {%- if name != nil and icon_position == "end" -%}
111
- {{ name }}<i class="{{ final_icon }} ms-1"></i>
99
+ {{ name }}<i class="{{ final_icon }} ms-1" aria-hidden="true"></i>
112
100
  {%- elsif name != nil and icon_position == "start" -%}
113
- <i class="{{ final_icon }} me-1"></i>{{ name }}
101
+ <i class="{{ final_icon }} me-1" aria-hidden="true"></i>{{ name }}
114
102
  {%- else -%}
115
- <i class="{{ final_icon }}"></i>
103
+ <i class="{{ final_icon }}" aria-hidden="true"></i>
116
104
  {%- endif -%}
117
105
  {%- else -%}
118
106
  {{ name }}
@@ -121,7 +109,7 @@ Security & External Links:
121
109
 
122
110
  {%- comment %} --- HTML: Anchor tag with attributes --- {% endcomment %}
123
111
  <a
124
- href="{{ href_value }}{% if anchor != nil %}#{{ anchor }}{% endif %}"
112
+ href="{{ href_value }}{% if anchor != nil and anchor != "" %}#{{ anchor }}{% endif %}"
125
113
  class="{{ link_class }}"
126
114
  {%- if target != nil %} target="{{ target }}"{% endif %}
127
115
  {%- if rel_attr != nil %} rel="{{ rel_attr }}"{% endif %}
@@ -129,7 +117,13 @@ Security & External Links:
129
117
  {%- if aria_label != nil %} aria-label="{{ aria_label }}"{% endif %}
130
118
  {%- if data_bs_toggle != nil %} data-bs-toggle="{{ data_bs_toggle }}"{% endif %}
131
119
  {%- if data_bs_title != nil %} data-bs-title="{{ data_bs_title }}"{% endif %}
132
- {%- if data_bs_placement != nil %} data-bs-placement="{{ data_bs_placement }}"{% endif %}>
120
+ {%- if data_bs_content != nil %} data-bs-content="{{ data_bs_content }}"{% endif %}
121
+ {%- if data_bs_placement != nil %} data-bs-placement="{{ data_bs_placement }}"{% endif %}
122
+ {%- if data_bs_trigger != nil %} data-bs-trigger="{{ data_bs_trigger }}"{% endif %}
123
+ {%- if data_bs_delay != nil %} data-bs-delay="{{ data_bs_delay }}"{% endif %}
124
+ {%- if data_bs_html != nil %} data-bs-html="{{ data_bs_html }}"{% endif %}
125
+ {%- if data_bs_custom_class != nil %} data-bs-custom-class="{{ data_bs_custom_class }}"{% endif %}
126
+ {%- if data_bs_offset != nil %} data-bs-offset="{{ data_bs_offset }}"{% endif %}>
133
127
  {{- link_name | strip_newlines | strip -}}
134
128
  </a>
135
129
  {%- endcapture -%}
@@ -27,41 +27,52 @@ Locale Detection:
27
27
  ================================================================================
28
28
  {% endcomment %}
29
29
 
30
- {%- assign configured_locales = page.with_locales_data.locales | default: empty_array %}
30
+ {%- assign with_locales = include.with_locales
31
+ | default: page.with_locales
32
+ %}
31
33
 
32
- {%- comment %} Build array of all available locales (always include English) {%- endcomment %}
33
- {%- assign all_locales = configured_locales | default: empty_array %}
34
- {%- unless all_locales contains "en" %}
35
- {%- assign all_locales = all_locales | unshift: "en" %}
36
- {%- endunless %}
34
+ {%- assign with_locales_data = include.data
35
+ | default: page.with_locales_data
36
+ | default: site.data.locales
37
+ | default: site.data.base.locales
38
+ %}
37
39
 
38
- {%- comment %} Detect current page locale from URL: /es/..., /fr/..., etc. {%- endcomment %}
39
- {%- assign url_parts = page.url | split: "/" %}
40
- {%- assign current_locale = "en" %}
41
- {%- if url_parts[1] and all_locales contains url_parts[1] %}
42
- {%- assign current_locale = url_parts[1] %}
43
- {%- endif %}
40
+ {%- assign with_locales_schema = site.data.base.locales_schema.properties.with_locales_data.properties %}
41
+
42
+ {%- if with_locales %}
44
43
 
45
- {%- if page.with_locales and configured_locales %}
44
+ {%- comment %} Build array of all available locales (always include English) {%- endcomment %}
45
+ {%- assign all_locales = with_locales_data.locales | default: with_locales_schema.locales.default %}
46
+ {%- unless all_locales contains "en" %}
47
+ {%- assign all_locales = all_locales | unshift: "en" %}
48
+ {%- endunless %}
49
+
50
+ {%- comment %} Detect current page locale from URL: /es/..., /fr/..., etc. {%- endcomment %}
51
+ {%- assign url_parts = page.url | split: "/" %}
52
+ {%- assign current_locale = "en" %}
53
+ {%- if url_parts[1] and all_locales contains url_parts[1] %}
54
+ {%- assign current_locale = url_parts[1] %}
55
+ {%- endif %}
46
56
 
47
57
  <p class="mb-2">Change page language:</p>
48
58
  <div class="dropdown mb-4">
49
- <button class="btn btn-sm btn-outline-primary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false" aria-label="Languages">
50
- <i class="fa-solid fa-language me-1"></i> {{ site.data.base.languages[current_locale] }} ({{ current_locale }})
51
- </button>
52
- <ul class="dropdown-menu">
53
- {%- for locale in all_locales %}
54
- {%- comment %} DEBUG: page.url={{ page.url }}, current_locale={{ current_locale }}, target_locale={{ locale }} {%- endcomment %}
55
- {%- assign locale_url = page.url | switch_locale_url: locale %}
59
+ <button class="btn btn-sm btn-outline-primary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false" aria-label="Languages">
60
+ <i class="fa-solid fa-language me-1"></i> {{ site.data.base.languages[current_locale] }} ({{ current_locale }})
61
+ </button>
62
+ <ul class="dropdown-menu">
63
+ {%- for locale in all_locales %}
64
+ {%- comment %} DEBUG: page.url={{ page.url }}, current_locale={{ current_locale }}, target_locale={{ locale }} {%- endcomment %}
65
+ {%- assign locale_url = page.url | switch_locale_url: locale %}
66
+
67
+ {%- if locale == current_locale %}
68
+ <li class="small"><a class="dropdown-item active" href="{{ site.baseurl }}{{ locale_url }}" aria-current="true">
69
+ {{ site.data.base.languages[locale] }} ({{ locale }}) <i class="fa-solid fa-check ms-3"></i>
70
+ </a></li>
71
+ {%- else %}
72
+ <li class="small"><a class="dropdown-item" href="{{ site.baseurl }}{{ locale_url }}">{{ site.data.base.languages[locale] }} ({{ locale }})</a></li>
73
+ {%- endif %}
74
+ {%- endfor %}
75
+ </ul>
76
+ </div>
56
77
 
57
- {%- if locale == current_locale %}
58
- <li class="small"><a class="dropdown-item active" href="{{ site.baseurl }}{{ locale_url }}" aria-current="true">
59
- {{ site.data.base.languages[locale] }} ({{ locale }}) <i class="fa-solid fa-check ms-3"></i>
60
- </a></li>
61
- {%- else %}
62
- <li class="small"><a class="dropdown-item" href="{{ site.baseurl }}{{ locale_url }}">{{ site.data.base.languages[locale] }} ({{ locale }})</a></li>
63
- {%- endif %}
64
- {%- endfor %}
65
- </ul>
66
- </div>
67
78
  {%- endif %}
@@ -26,21 +26,31 @@ Data Source Hierarchy (priority):
26
26
  1. include.data
27
27
  2. page.with_navbar_data
28
28
  3. site.data.navbar
29
- 4. site.data.base.navbar
29
+ 4. site.data.base.partials.navbar
30
30
  ================================================================================
31
31
  {% endcomment %}
32
32
 
33
- {%- if page.with_navbar -%}
34
- {%- assign navbar = include.data | default: page.with_navbar_data | default: site.data.navbar | default: site.data.base.navbar %}
35
- {%- assign schema = site.data.base.navbar_schema.properties["with_navbar_data"].properties %}
36
-
37
- {%- assign navbar_class = navbar.class | default: schema.class.default %}
38
- {%- assign navbar_brand_image = navbar.brand_image | default: schema.brand_image.default %}
39
- {%- assign navbar_brand_image_class = navbar.brand_image_class | default: schema.brand_image_class.default %}
40
- {%- assign navbar_brand_image_height = navbar.brand_image_height | default: schema.brand_image_height.default %}
41
- {%- assign navbar_brand_manifestation = navbar.brand_manifestation | default: schema.brand_manifestation.default %}
42
- {%- assign navbar_brand_manifestation_class = navbar.brand_manifestation_class | default: schema.brand_manifestation_class.default %}
43
- {%- assign navbar_navitems = navbar.navitems | where: "visible_on", "navbar" | default: schema.navitems.default %}
33
+ {%- assign with_navbar = include.with_navbar
34
+ | default: page.with_navbar
35
+ %}
36
+
37
+ {%- assign with_navbar_data = include.data
38
+ | default: page.with_navbar_data
39
+ | default: site.data.navbar
40
+ | default: site.data.base.partials.navbar
41
+ %}
42
+
43
+ {%- assign with_navbar_schema = site.data.base.partials.navbar_schema.properties.with_navbar_data.properties %}
44
+
45
+ {%- if with_navbar %}
46
+
47
+ {%- assign navbar_class = with_navbar_data.class | default: with_navbar_schema.class.default %}
48
+ {%- assign navbar_brand_image = with_navbar_data.brand_image | default: with_navbar_schema.brand_image.default %}
49
+ {%- assign navbar_brand_image_class = with_navbar_data.brand_image_class | default: with_navbar_schema.brand_image_class.default %}
50
+ {%- assign navbar_brand_image_height = with_navbar_data.brand_image_height | default: with_navbar_schema.brand_image_height.default %}
51
+ {%- assign navbar_brand_manifestation = with_navbar_data.brand_manifestation | default: with_navbar_schema.brand_manifestation.default %}
52
+ {%- 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 %}
44
54
 
45
55
  <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">
46
56
  <div class="container">