').addClass('hide');
- $('body').prepend(this.$overlay);
- }
-
- this.$overlay.addClass('overlay');
- },
- buildHeader: function()
- {
- if (this.opts.header) this.$header.html(this.opts.header);
- },
- load: function(e)
- {
- this.buildModal();
- this.buildOverlay();
- this.buildHeader();
-
- if (this.opts.url) this.buildContent();
- else this.open(e);
- },
- open: function(e)
- {
- if (e) e.preventDefault();
-
- if (this.isOpened())
- {
- return;
- }
-
- if (this.detect.isMobile()) this.opts.width = '96%';
- if (this.opts.overlay) this.$overlay.removeClass('hide');
-
- this.$target.removeClass('hide');
- this.$modal.removeClass('hide');
-
- this.enableEvents();
- this.findActions();
-
- this.resize();
- $(window).on('resize.' + this.namespace, $.proxy(this.resize, this));
-
- if (this.detect.isDesktop()) this.utils.disableBodyScroll();
-
- // enter
- this.$modal.find('input[type=text],input[type=url],input[type=email]').on('keydown.' + this.namespace, $.proxy(this.handleEnter, this));
-
- this.callback('open');
- this.$modal.animation(this.opts.animationOpen, $.proxy(this.onOpened, this));
- },
- close: function(e)
- {
- if (!this.$modal || !this.isOpened())
- {
- return;
- }
-
- if (e)
- {
- if (this.shouldNotBeClosed(e.target))
- {
- return;
- }
-
- e.preventDefault();
- }
-
- this.callback('close');
- this.disableEvents();
-
- this.$modal.animation(this.opts.animationClose, $.proxy(this.onClosed, this));
-
- if (this.opts.overlay) this.$overlay.animation(this.opts.animationClose);
- },
- onOpened: function()
- {
- this.$modal.addClass('open');
- this.callback('opened');
-
- $.modalcurrent = this;
- },
- onClosed: function()
- {
- this.callback('closed');
-
- this.$target.addClass('hide');
- this.$modal.removeClass('open');
-
- if (this.detect.isDesktop()) this.utils.enableBodyScroll();
-
- this.$body.css('height', '');
- $.modalcurrent = null;
- },
- isOpened: function()
- {
- return (this.$modal.hasClass('open'));
- },
- getData: function()
- {
- var formdata = new Kube.FormData(this);
- formdata.set('');
-
- return formdata.get();
- },
- buildContent: function()
- {
- $.ajax({
- url: this.opts.url + '?' + new Date().getTime(),
- cache: false,
- type: 'post',
- data: this.getData(),
- success: $.proxy(function(data)
- {
- this.$body.html(data);
- this.open();
-
- }, this)
- });
- },
- buildWidth: function()
- {
- var width = this.opts.width;
- var top = '2%';
- var bottom = '2%';
- var percent = width.match(/%$/);
-
- if ((parseInt(this.opts.width) > $(window).width()) && !percent)
- {
- width = '96%';
- }
- else if (!percent)
- {
- top = '16px';
- bottom = '16px';
- }
-
- this.$modal.css({ 'width': width, 'margin-top': top, 'margin-bottom': bottom });
-
- },
- buildPosition: function()
- {
- if (this.opts.position !== 'center')
- {
- return;
- }
-
- var windowHeight = $(window).height();
- var height = this.$modal.outerHeight();
- var top = (windowHeight/2 - height/2) + 'px';
-
- if (this.detect.isMobile()) top = '2%';
- else if (height > windowHeight) top = '16px';
-
- this.$modal.css('margin-top', top);
- },
- buildHeight: function()
- {
- var windowHeight = $(window).height();
-
- if (this.opts.maxHeight)
- {
- var padding = parseInt(this.$body.css('padding-top')) + parseInt(this.$body.css('padding-bottom'));
- var margin = parseInt(this.$modal.css('margin-top')) + parseInt(this.$modal.css('margin-bottom'));
- var height = windowHeight - this.$header.innerHeight() - padding - margin;
-
- this.$body.height(height);
- }
- else if (this.opts.height !== false)
- {
- this.$body.css('height', this.opts.height);
- }
-
- var modalHeight = this.$modal.outerHeight();
- if (modalHeight > windowHeight)
- {
- this.opts.animationOpen = 'show';
- this.opts.animationClose = 'hide';
- }
- },
- resize: function()
- {
- this.buildWidth();
- this.buildPosition();
- this.buildHeight();
- },
- enableEvents: function()
- {
- this.$close.on('click.' + this.namespace, $.proxy(this.close, this));
- $(document).on('keyup.' + this.namespace, $.proxy(this.handleEscape, this));
- this.$target.on('click.' + this.namespace, $.proxy(this.close, this));
- },
- disableEvents: function()
- {
- this.$close.off('.' + this.namespace);
- $(document).off('.' + this.namespace);
- this.$target.off('.' + this.namespace);
- $(window).off('.' + this.namespace);
- },
- findActions: function()
- {
- this.$body.find('[data-action="modal-close"]').on('mousedown.' + this.namespace, $.proxy(this.close, this));
- },
- setHeader: function(header)
- {
- this.$header.html(header);
- },
- setContent: function(content)
- {
- this.$body.html(content);
- },
- setWidth: function(width)
- {
- this.opts.width = width;
- this.resize();
- },
- getModal: function()
- {
- return this.$modal;
- },
- getBody: function()
- {
- return this.$body;
- },
- getHeader: function()
- {
- return this.$header;
- },
- handleEnter: function(e)
- {
- if (e.which === 13)
- {
- e.preventDefault();
- this.close(false);
- }
- },
- handleEscape: function(e)
- {
- return (e.which === 27) ? this.close(false) : true;
- },
- shouldNotBeClosed: function(el)
- {
- if ($(el).attr('data-action') === 'modal-close' || el === this.$close[0])
- {
- return false;
- }
- else if ($(el).closest('.modal').length === 0)
- {
- return false;
- }
-
- return true;
- }
- };
-
- // Inheritance
- Kube.Modal.inherits(Kube);
-
- // Plugin
- Kube.Plugin.create('Modal');
- Kube.Plugin.autoload('Modal');
-
-}(Kube));
diff --git a/assets/js/product-selector.js b/assets/js/product-selector.js
index 909b9f5..8ce2f0e 100644
--- a/assets/js/product-selector.js
+++ b/assets/js/product-selector.js
@@ -4,24 +4,19 @@ document.addEventListener('DOMContentLoaded', () => {
'product-selector-button'
);
- if (productSelectorButton === null || productSelectorContent == null) {
- return;
- }
+ if (!productSelectorButton || !productSelectorContent) return;
productSelectorButton.addEventListener('click', () => {
- /* Logic for hiding/showing ONLY when the button is clicked */
- if (productSelectorContent.style.display === 'block') {
- productSelectorContent.style.display = 'none';
- productSelectorButton.classList.remove('remove-bottom-radius');
- } else {
- productSelectorContent.style.display = 'block';
- productSelectorButton.classList.add('remove-bottom-radius');
- }
+ const isVisible = productSelectorContent.style.display === 'block';
+ productSelectorContent.style.display = isVisible ? 'none' : 'block';
+ productSelectorButton.classList.toggle('remove-bottom-radius', !isVisible);
});
window.addEventListener('click', (event) => {
- /* Greedy Logic to hide the product selector when something other than the button is clicked. Assumes everything has an id containing "product-selector" */
- if (!event.target.id.includes('product-selector')) {
+ const isClickInside =
+ productSelectorButton.contains(event.target) ||
+ productSelectorContent.contains(event.target);
+ if (!isClickInside) {
productSelectorContent.style.display = 'none';
productSelectorButton.classList.remove('remove-bottom-radius');
}
diff --git a/assets/js/sidebar.js b/assets/js/sidebar.js
deleted file mode 100644
index 8cbd8ce..0000000
--- a/assets/js/sidebar.js
+++ /dev/null
@@ -1,101 +0,0 @@
-const LOCAL_STORAGE_COLLAPSE_KEY = 'sidebar-collapsed';
-
-function handleInitialCollapse() {
- const collapsed = localStorage.getItem(LOCAL_STORAGE_COLLAPSE_KEY);
-
- if (collapsed === 'true') {
- $('#sidebar-toggle-button').attr({
- 'aria-expanded': 'false',
- title: 'Show sidebar navigation',
- });
- $('.sidenav').css('max-width', '2.4rem');
- $('#sidebar-wrapper').addClass('sidebar-toggle-collapsed');
- $('.content').addClass('sidebar-content-collapsed-width');
- $('.nginx-docs-api-container').addClass('sidebar-redoc-collapsed-width');
- } else {
- $('#sidebar-toggle-button').attr({
- 'aria-expanded': 'true',
- title: 'Hide sidebar navigation',
- });
- $('.sidenav').css('max-width', '100%');
- $('.content').addClass('sidebar-content-collapsed-width');
- $('#sidebar-wrapper').addClass('hide-sidebar-border');
- }
-}
-
-function handleSetCollapse() {
- $('#sidebar-wrapper').addClass('sidebar-toggle-animate');
-
- const collapsed = localStorage.getItem(LOCAL_STORAGE_COLLAPSE_KEY);
-
- if (collapsed === 'false') {
- $('#sidebar-toggle-button').attr({
- 'aria-expanded': 'false',
- title: 'Show sidebar navigation',
- });
- $('#sidebar-wrapper').addClass('sidebar-toggle-collapsed');
- $('.content').addClass('sidebar-content-collapsed-width');
- $('.nginx-docs-api-container').addClass('sidebar-redoc-collapsed-width');
- localStorage.setItem(LOCAL_STORAGE_COLLAPSE_KEY, true);
- } else {
- $('#sidebar-toggle-button').attr({
- 'aria-expanded': 'true',
- title: 'Hide sidebar navigation',
- });
- $('.sidenav').css('max-width', '100%');
- $('#sidebar-wrapper').addClass('hide-sidebar-border');
- $('#sidebar-wrapper').removeClass('sidebar-toggle-collapsed');
- $('.content').removeClass('sidebar-content-collapsed-width');
- $('.nginx-docs-api-container').removeClass('sidebar-redoc-collapsed-width');
- localStorage.setItem(LOCAL_STORAGE_COLLAPSE_KEY, false);
- }
-}
-
-function handleAnimationEnd(event) {
- const collapsed = localStorage.getItem(LOCAL_STORAGE_COLLAPSE_KEY);
- if (collapsed === 'true') {
- $(this).css('max-width', '2.4rem');
- }
-}
-
-// This code makes the sidebar remember which sections has been clicked when using the sidebar
-$(document).ready(() => {
- // sidebar toggle navigation logic
- handleInitialCollapse();
- $('#sidebar-toggle-button').on('click', handleSetCollapse);
- $('.sidenav').on('transitionend', handleAnimationEnd);
-
- $('.sidebar .nginx-toc-link a').each((i, item) => {
- if (item.dataset.menuId === $('.main').data('menuId')) {
- $(item).css('color', '#429345');
- $(item).css('font-weight', '500');
-
- // Remove "collapsed" class and set aria-expanded to "true" for the current item
- $(item).removeClass('collapsed');
- $(item).attr('aria-expanded', 'true');
-
- // Capture data-target value
- const targetId = $(item).data('target');
- if (!targetId) {
- const hrefValue = $(item).attr('href');
- // Add "show" class to the corresponding divs with matching id
- const targetDivs = $("div[id='" + hrefValue.replace('#', '') + "']");
- targetDivs.addClass('show');
- } else {
- $(targetId).addClass('show');
- }
-
- // Expand parents
- $(item)
- .parents('.collapse')
- .each((i, el) => {
- const col = new bootstrap.Collapse(el, {
- toggle: false,
- });
- col.show();
- });
-
- $(item).next('.accordion-body').find('.collapse').addClass('show');
- }
- });
-});
diff --git a/assets/js/site-dropdown.js b/assets/js/site-dropdown.js
index 4d9c9ec..b71e9c3 100644
--- a/assets/js/site-dropdown.js
+++ b/assets/js/site-dropdown.js
@@ -1,17 +1,12 @@
document.addEventListener('DOMContentLoaded', () => {
const dropdownContent = document.getElementById('dropdown-content');
const navbarButton = document.getElementById('navbar-sites-button');
- const chevronIcon = document.getElementById('navbar-sites-button-icon');
navbarButton.addEventListener('click', () => {
- chevronIcon.classList.toggle('rotate-chevron');
-
if (dropdownContent.style.display === 'block') {
dropdownContent.style.display = 'none';
- navbarButton.classList.remove('remove-bottom-radius');
} else {
dropdownContent.style.display = 'block';
- navbarButton.classList.add('remove-bottom-radius');
}
});
@@ -20,14 +15,7 @@ document.addEventListener('DOMContentLoaded', () => {
!event.target.matches('#navbar-sites-button') &&
!event.target.matches('#navbar-sites-button-icon')
) {
- if (
- dropdownContent.style.display !== 'none' &&
- dropdownContent.style.display !== ''
- ) {
- chevronIcon.classList.toggle('rotate-chevron');
- }
dropdownContent.style.display = 'none';
- navbarButton.classList.remove('remove-bottom-radius');
}
});
});
diff --git a/assets/js/tabs.js b/assets/js/tabs.js
new file mode 100644
index 0000000..9e5cf88
--- /dev/null
+++ b/assets/js/tabs.js
@@ -0,0 +1,68 @@
+window.addEventListener('DOMContentLoaded', () => {
+ const tabLists = document.querySelectorAll('.tab-labels');
+
+ tabLists.forEach((tabList) => {
+ const tabs = tabList.querySelectorAll(':scope > li > [role="tab"]');
+
+ let tabFocus = 0;
+ let selectedTab =
+ tabs[0].getAttribute('aria-selected') === 'true' ? tabs[0] : null;
+ tabList.addEventListener('keyup', (e) => {
+ if (e.key === 'Enter' || e.key === ' ') {
+ e.preventDefault();
+ // Reset existing the aria-selected that is true
+ selectedTab.setAttribute('aria-selected', 'false');
+ selectedTab = e.target;
+
+ // Change the tabs
+ changeTabs(e);
+ }
+ });
+
+ tabList.addEventListener('keydown', (e) => {
+ // Prevent page scrolling on space key hit
+ if (e.key === ' ') {
+ e.preventDefault();
+ } else {
+ if (
+ e.key === 'ArrowRight' ||
+ e.key === 'ArrowLeft' ||
+ e.key === 'Home' ||
+ e.key === 'End'
+ ) {
+ tabs[tabFocus].setAttribute('tabindex', -1);
+ selectedTab =
+ tabs[tabFocus].getAttribute('aria-selected') === 'true'
+ ? tabs[tabFocus]
+ : selectedTab;
+ if (e.key === 'ArrowRight') {
+ tabFocus = (tabFocus + 1) % tabs.length;
+ } else if (e.key === 'ArrowLeft') {
+ tabFocus = tabFocus - 1;
+ if (tabFocus < 0) {
+ tabFocus = tabs.length - 1;
+ }
+ } else if (e.key === 'Home') {
+ tabFocus = 0;
+ } else if (e.key === 'End') {
+ tabFocus = tabs.length - 1;
+ }
+
+ tabs[tabFocus].setAttribute('tabindex', 0);
+ tabs[tabFocus].focus();
+ }
+ }
+ });
+ });
+});
+
+function changeTabs(e) {
+ const toggle = document.getElementById(e.target.getAttribute('for'));
+ const label = e.target;
+
+ // Toggle to new content + update Aria attributes
+ if (toggle) {
+ toggle.checked = true;
+ }
+ label.setAttribute('aria-selected', 'true');
+}
diff --git a/biome.json b/biome.json
index 683bcda..2e49c61 100644
--- a/biome.json
+++ b/biome.json
@@ -1,5 +1,5 @@
{
- "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
+ "$schema": "https://biomejs.dev/schemas/2.0.6/schema.json",
"vcs": {
"enabled": true,
"clientKind": "git",
@@ -7,26 +7,21 @@
},
"files": {
"ignoreUnknown": false,
- "ignore": [
- ".vscode/",
- "**/*.min.js",
- "**/*.standalone.js",
- "kube.js",
-
- "**/css/docs-nginx-com/*.css",
- "**/css/inter/*.css",
- "**/fontawesome/*.css",
- "**/static/*.css",
- "**/bootstrap*.css",
- "**/*.min.css",
- "**/coveo.css",
- "**/f5-hugo.css",
- "**/highlight.css",
- "**/*-overrides.css",
-
- "exampleSite",
- "public/*",
- "test-results/*"
+ "includes": [
+ "**",
+ "!**/.vscode/settings.json",
+ "!**/*.min.js",
+ "!**/*.standalone.js",
+ "!**/css/inter/**/*.css",
+ "!**/css/v2/highlight.css",
+ "!**/static/**/*.css",
+ "!**/bootstrap*.css",
+ "!**/*.min.css",
+ "!**/coveo.css",
+ "!**/*-overrides.css",
+ "!**/exampleSite",
+ "!**/public/**/*",
+ "!**/test-results/**/*"
]
},
"formatter": {
@@ -41,13 +36,22 @@
"noForEach": "off"
},
"style": {
- "useTemplate": "off"
- },
- "nursery": {
- "noDuplicateProperties": "error"
+ "useTemplate": "off",
+ "noParameterAssign": "error",
+ "useAsConstAssertion": "error",
+ "useDefaultParameterLast": "error",
+ "useEnumInitializers": "error",
+ "useSelfClosingElements": "error",
+ "useSingleVarDeclarator": "error",
+ "noUnusedTemplateLiteral": "error",
+ "useNumberNamespace": "error",
+ "noInferrableTypes": "error",
+ "noUselessElse": "error"
},
+ "nursery": {},
"suspicious": {
- "noEmptyBlock": "error"
+ "noEmptyBlock": "error",
+ "noDuplicateProperties": "error"
},
"correctness": {
"noUnknownUnit": "error"
diff --git a/exampleSite/content/test-product/_index.md b/exampleSite/content/test-product/_index.md
index df11ae2..a15dff2 100644
--- a/exampleSite/content/test-product/_index.md
+++ b/exampleSite/content/test-product/_index.md
@@ -1,16 +1,41 @@
---
-description: Test pages for nginx-hugo-theme
+# The title is the product name
title: Test pages
weight: 100
+# The URL is the base of the deployed path, becoming "docs.nginx.com//"
+url:
+# The subtitle displays directly underneath the heading of a given page
+nd-subtitle: Test pages for nginx-hugo-theme
+# Indicates that this is a custom landing page
nd-landing-page: true
+# Types have a 1:1 relationship with Hugo archetypes, so you shouldn't need to change this
+nd-content-type: landing-page
+# Intended for internal catalogue and search, case sensitive:
+# Agent, N4Azure, NIC, NIM, NGF, NAP-DOS, NAP-WAF, NGINX One, NGINX+, Solutions, Unit
+nd-product:
---
-{{}}
- {{}}
+
+## About
+[//]: # "These are Markdown comments to guide you through document structure. Remove them as you go, as well as any unnecessary sections."
+[//]: # "Use underscores for _italics_, and double asterisks for **bold**."
+[//]: # "Backticks are for `monospace`, used sparingly and reserved mostly for executable names - they can cause formatting problems. Avoid them in tables: use italics instead."
+
+[//]: # "This initial section introduces the product to a reader: give a short 1-2 sentence summary of what the product does and its value to the reader."
+[//]: # "Name specific functionality it provides: avoid ambiguous descriptions such as 'enables efficiency', focus on what makes it unique."
+
+This is a compilation of all our shortcodes to show how they look, function, respond, and coded.
+
+## Featured Content
+[//]: # "You can add a maximum of three cards: any extra will not display."
+[//]: # "One card will take full width page: two will take half width each. Three will stack like an inverse pyramid."
+[//]: # "Some examples of content could be the latest release note, the most common install path, and a popular new feature."
+
+{{}}
+ {{}}
{{}}
All shortcodes in one page.
{{}}
{{}}
-
Examples for call-out shortcode
{{}}
{{}}
@@ -20,12 +45,12 @@ nd-landing-page: true
{{}}
## Other Content
+[//]: # "You can add any extra content for the page here, such as additional cards, diagrams or text."
-[//]: # "Provide any sort of additional supporting content you may want customers to see as well (e.g. more cards, diagrams, changelogs, etc.)"
-{{}}
+{{}}
{{}}
{{}}
Installing NGINX
{{}}
{{}}
-{{}}
\ No newline at end of file
+{{}}
diff --git a/exampleSite/content/test-product/tables/examples/config-sharing.md b/exampleSite/content/test-product/tables/examples/config-sharing.md
index bcc7ef0..867e0b4 100644
--- a/exampleSite/content/test-product/tables/examples/config-sharing.md
+++ b/exampleSite/content/test-product/tables/examples/config-sharing.md
@@ -18,7 +18,7 @@ EXCLUDE="default.conf"
Use a space or newline character to separate the items in each list:
-{{}}
+{{
}}
| Parameter | Description |
| ------------------------ | -------------------------------------------------------------------------------------|
@@ -26,11 +26,11 @@ Use a space or newline character to separate the items in each list:
| `CONFPATHS` | List of files and directories to distribute from the primary to the peers. |
| `EXCLUDE` | (Optional) List of configuration files on the primary not to distribute to the peers.|
-{{}}
+{{
}}
### Advanced Parameters
-{{}}
+{{
}}
| Parameter | Description | Default |
| ------------------------ | ---------------------------------------------------------------------------------------|-------------------------|
@@ -42,4 +42,4 @@ Use a space or newline character to separate the items in each list:
| `RSYNC` | Location of the `rsync` binary | **/usr/bin/rsync** |
| `SSH` | Location of the `ssh` binary | **/usr/bin/ssh** |
-{{}}
\ No newline at end of file
+{{
}}
\ No newline at end of file
diff --git a/layouts/404.html b/layouts/404.html
index b038511..a50e27c 100644
--- a/layouts/404.html
+++ b/layouts/404.html
@@ -1,25 +1,15 @@
{{ define "main"}}
-
-
-
Page not found
-
-
-
-
-
-
-
-
-
Uh oh! We couldn't find the page you were looking for.
{{- if and (ne .Type "") (ne .Type "none") -}}
{{ .Type }}
{{- end -}}
@@ -24,7 +24,4 @@
-{{- end -}}
-
-{{ $result.Wrapped }}
-
\ No newline at end of file
+{{- end -}}
\ No newline at end of file
diff --git a/layouts/_default/_markup/render-heading.html b/layouts/_default/_markup/render-heading.html
index 4111b89..f1cf469 100644
--- a/layouts/_default/_markup/render-heading.html
+++ b/layouts/_default/_markup/render-heading.html
@@ -1,13 +1,6 @@
-
-
+
{{ if not .IsHome }}
- {{ if not (in .Params.display_breadcrumb "false" ) }}
- {{ partial "breadcrumb" .}}
- {{ end }}
+ {{ if not (in .Params.display_breadcrumb "false" ) }}
+ {{ partial "breadcrumb" .}}
+ {{ end }}
{{ end }}
-
-
+
+ {{ if not .IsHome }}
{{ if not (in .Params.display_breadcrumb "false" ) }}
{{ partial "breadcrumb" .}}
{{ end }}
- {{ end }}
+ {{ end }}
{{ partial "banner" .}}