diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml
new file mode 100644
index 0000000..7e1663a
--- /dev/null
+++ b/.idea/copyright/profiles_settings.xml
@@ -0,0 +1,7 @@
+
The page is only available on this site and will not be +rendered on the spine.io.
+ +[authoring]: https://github.com/SpineEventEngine/SpineEventEngine.github.io/blob/master/AUTHORING.md diff --git a/_hugo-site/go.mod b/_hugo-site/go.mod new file mode 100644 index 0000000..60f25e8 --- /dev/null +++ b/_hugo-site/go.mod @@ -0,0 +1,5 @@ +module github.com/SpineEventEngine/documentation/_hugo-site + +go 1.22.0 + +require github.com/TeamDev-Ltd/site-commons v0.0.0-20251202150534-a795438915ff // indirect diff --git a/_hugo-site/go.sum b/_hugo-site/go.sum new file mode 100644 index 0000000..44e846e --- /dev/null +++ b/_hugo-site/go.sum @@ -0,0 +1,2 @@ +github.com/TeamDev-Ltd/site-commons v0.0.0-20251202150534-a795438915ff h1:8kjfGJhf6LeS+IlK9NRktxtcv6O/WDneBuQD3QLPGIs= +github.com/TeamDev-Ltd/site-commons v0.0.0-20251202150534-a795438915ff/go.mod h1:atDeksDWBzsIidpW6Ivz2yYHwp2JPa1i1KXIxkctQ3c= diff --git a/_hugo-site/layouts/_default/baseof.html b/_hugo-site/layouts/_default/baseof.html new file mode 100644 index 0000000..4f16f9a --- /dev/null +++ b/_hugo-site/layouts/_default/baseof.html @@ -0,0 +1,15 @@ + + +{{ partial "head/head.html" . }} +{{ $bodyClass := partial "functions/get-body-class.html" . }} + +Also, copies the `href` to clipboard. + */ +export function setupAnchorClick() { + const anchorIconClass = 'anchor-icon'; + const $anchorLinks = $('a[href^="#"]'); + + $anchorLinks.on('click', function() { + const $this = $(this); + const anchor = $this.attr('href'); + + if ($this.hasClass(anchorIconClass)) { + window.location.hash = anchor; + copyToClipboard(window.location.href); + } + }); +} diff --git a/_hugo-theme/assets/js/docs/architecture-diagram.js b/_hugo-theme/assets/js/docs/architecture-diagram.js new file mode 100644 index 0000000..e68c3e6 --- /dev/null +++ b/_hugo-theme/assets/js/docs/architecture-diagram.js @@ -0,0 +1,380 @@ +/* + * Copyright 2025, TeamDev. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * This is a JavaScript file which backs the Spine architecture diagram. + * + * Please see `/docs/1/introduction/architecture.md` for usage. + */ + +$( + /** + * This function is executed upon page load. + * + * Binds the handlers to the events in this HTML page. + */ + function () { + const baseURL = BASE_URL; + + console.log(`baseurl ${baseURL}`) + + /** + * CSS classes used as selectors to manipulate the elements of SVG diagram. + */ + const endUserClass = "end-user"; + const boxCaptionClass = "box-caption"; + const arrowCaptionClass = "arrow-caption"; + const titleCaptionClass = "title-caption"; + const arrowClass = "arrow"; + const pathOnlyClass = "path-only"; + + /** + * CSS classes of the HTML elements on the page. + * @type {string} + */ + let architectureLinkClass = "architecture-link"; + let noSelectClass = "noselect"; + + let useFacingLink = $("#display-user-facing-components"); + let allComponentLink = $("#display-all-components"); + let selectedElementColor = "#8d28e0"; + let selectedCaptionColor = "#fafafa"; + let selectedBodyBgColor = "#e7ecfa"; + let selectedBodyBgCaptionColor = "#505050"; + + const originFillAttr = "origin-fill"; + const originStrokeAttr = "origin-stroke"; + + const fillAttr = "fill"; + const strokeAttr = "stroke"; + const fillOpacityAttr = "fill-opacity"; + const strokeOpacityAttr = "stroke-opacity"; + const pointerEvents = "pointer-events"; + + const textTag = "text"; + const rectTag = "rect"; + const pathTag = "path"; + + function setupLookAndFeel() { + + // Back up the original fill color and color of elements to use in `mouseleave` later. + let contents = $(".diagram-content").find("*"); + for (let index = 0; index < contents.length; index++) { + const item = $(contents[index]); + const elementName = item[0].nodeName.toLowerCase(); + if (textTag === elementName) { + + if (hasClass(item, boxCaptionClass) + || hasClass(item, arrowCaptionClass) + || hasClass(item, titleCaptionClass)) { + item.attr(originFillAttr, item.attr(fillAttr)); + + // Make all TEXTs non-selectable. + item.addClass(noSelectClass); + } + } + if (rectTag === elementName || pathTag === elementName) { + item.attr(originFillAttr, item.attr(fillAttr)); + item.attr(originStrokeAttr, item.attr(strokeAttr)) + } + } + } + + + /** + * Changes opacity of the elements, not marked as "end-user". + * + * The opacity value is expected to be [0; 1] range. + * + * @param textOpacity the opacity to apply to text elements + * @param elementOpacity the opacity to apply "rect" and "path" elements + */ + function fade(textOpacity, elementOpacity) { + let contents = $(".diagram-content").find("*"); + for (let index = 0; index < contents.length; index++) { + const item = $(contents[index]); + if (hasClass(item, endUserClass)) { + continue; + } + const elementName = item[0].nodeName.toLowerCase(); + + if (textTag === elementName) { + + if (hasClass(item, boxCaptionClass) + || hasClass(item, arrowCaptionClass) + || hasClass(item, titleCaptionClass)) { + + item.attr(fillOpacityAttr, textOpacity); + } + } + if (rectTag === elementName) { + item.attr(fillOpacityAttr, elementOpacity); + } + if (pathTag === elementName) { + item.attr(fillOpacityAttr, elementOpacity); + + item.attr(strokeOpacityAttr, elementOpacity); + } + } + } + + /** + * A custom implementation of `jQuery.hasClass()` suitable for SVG elements. + * + * In the jQuery 1.11.2 currently used, SVG elements are not supported + * by `jQuery.hasClass()`. + * + * @param element an element wrapped in jQuery. + * @param className a class name to detect + * @return `true` if such a class name is declared for this element, `false` otherwise. + */ + function hasClass(element, className) { + const firstChild = element[0]; + for (let classIndex = 0; classIndex < firstChild.classList.length; classIndex++) { + if (className === firstChild.classList[classIndex]) { + return true; + } + } + return false; + } + + /** + * Adds a link behavior to an element. + * + * @param linkElement the jQuery object wrapping the DOM element + * @param onClickCallback the callback to set upon 'click' event + */ + function enableLink(linkElement, onClickCallback) { + linkElement + .addClass(architectureLinkClass) + .click(function () { + onClickCallback() + }); + } + + /** + * Disables a link behaviour of an element. + * + * @param linkElement the jQuery object wrapping the DOM element + */ + function disableLink(linkElement) { + linkElement + .removeClass(architectureLinkClass) + .unbind("click"); + } + + function makeClickable(selector, url) { + + $(".g-caption" + selector) + .css("cursor", "pointer") + .attr("pointer-events", "all") + .mouseover(function () { + let matched = $(selector); + + for (let index = 0; index < matched.length; index++) { + const item = $(matched[index]); + const elementName = item[0].nodeName.toLowerCase(); + if(textTag === elementName) { + item.attr(fillAttr, selectedCaptionColor); + } + if (rectTag === elementName || pathTag === elementName) { + item.attr(fillAttr, selectedElementColor); + } + if(hasClass(item, arrowClass)) { + item.attr(strokeAttr, selectedElementColor); + } + if(hasClass(item, pathOnlyClass)) { + item.attr(fillAttr, "none"); + } + } + }) + .mouseout(function () { + let matched = $(selector); + for (let index = 0; index < matched.length; index++) { + const item = $(matched[index]); + const elementName = item[0].nodeName.toLowerCase(); + if (textTag === elementName + || rectTag === elementName + || pathTag === elementName) { + let originFillValue = item.attr(originFillAttr); + item.attr(fillAttr, originFillValue); + } + + if(hasClass(item, arrowClass)) { + let originStrokeValue = item.attr(originStrokeAttr); + item.attr(strokeAttr, originStrokeValue); + } + } + + }) + .click(function () { + document.location.href = baseURL + url; + }); + + $(".g-caption-bounded-context" + selector) + .css("cursor", "pointer") + .attr("pointer-events", "all") + .mouseover(function () { + let matched = $(selector); + + for (let index = 0; index < matched.length; index++) { + const item = $(matched[index]); + const elementName = item[0].nodeName.toLowerCase(); + if(textTag === elementName) { + item.attr(fillAttr, selectedBodyBgCaptionColor); + } + if (rectTag === elementName || pathTag === elementName) { + item.attr(pointerEvents, "none"); + item.attr(fillAttr, selectedBodyBgColor); + } + if(hasClass(item, arrowClass)) { + item.attr(strokeAttr, selectedBodyBgColor); + } + } + }) + .mouseout(function () { + let matched = $(selector); + for (let index = 0; index < matched.length; index++) { + const item = $(matched[index]); + const elementName = item[0].nodeName.toLowerCase(); + if (textTag === elementName + || rectTag === elementName + || pathTag === elementName) { + let originFillValue = item.attr(originFillAttr); + item.attr(fillAttr, originFillValue); + } + + if(hasClass(item, arrowClass)) { + let originStrokeValue = item.attr(originStrokeAttr); + item.attr(strokeAttr, originStrokeValue); + } + } + + }) + .click(function () { + document.location.href = baseURL + url; + }); + + + $(".g-arrow" + selector) + .css("cursor", "pointer") + .attr("pointer-events", "all") + .mouseover(function () { + let matched = $(selector); + + for (let index = 0; index < matched.length; index++) { + const item = $(matched[index]); + const elementName = item[0].nodeName.toLowerCase(); + if (textTag === elementName) { + item.attr(fillAttr, selectedElementColor); + } + if(hasClass(item, arrowClass)) { + item.attr(fillAttr, selectedElementColor); + } + } + }) + .mouseout(function () { + let matched = $(selector); + for (let index = 0; index < matched.length; index++) { + const item = $(matched[index]); + const elementName = item[0].nodeName.toLowerCase(); + if (textTag === elementName) { + let originFillValue = item.attr(originFillAttr); + item.attr(fillAttr, originFillValue); + } + if(hasClass(item, arrowClass)) { + let originFillValue = item.attr(originFillAttr); + item.attr(fillAttr, originFillValue); + } + } + + }) + .click(function () { + document.location.href = baseURL + url; + }); + + } + + /** + * Displays the user-facing components and fades out the rest. + */ + function displayUserFacing() { + fade("0.65", "0.2"); + enableLink(allComponentLink, displayAll); + disableLink(useFacingLink); + } + + /** + * Displays all the Spine components and removes the fading. + */ + function displayAll() { + fade("1", "1"); + + enableLink(useFacingLink, displayUserFacing); + disableLink(allComponentLink); + } + + /** + * Changes the diagram visibility to make it visible on UI. + * + *
This is useful to avoid the diagram from flickering during loading. + * The styles that hide the diagram are in the file `_sass/base/_diagram.scss`. + */ + function changeDiagramVisibility() { + $("#spine-architecture-diagram").css("visibility", "visible"); + } + + setupLookAndFeel(); + displayUserFacing(); + changeDiagramVisibility(); + + // Link items to the corresponding pages. + + // Boxes: + makeClickable(".aggregate", "docs/introduction/concepts#aggregate"); + makeClickable(".bounded-context", "docs/introduction/concepts#bounded-context"); + makeClickable(".pm", "docs/introduction/concepts#process-manager"); + makeClickable(".projection", "docs/introduction/concepts#projection"); + makeClickable(".aggregate-repo", "docs/introduction/concepts#repository"); + makeClickable(".pm-repo", "docs/introduction/concepts#repository"); + makeClickable(".projection-repo", "docs/introduction/concepts#repository"); + makeClickable(".command-bus", "docs/introduction/concepts#command-bus"); + makeClickable(".event-bus", "docs/introduction/concepts#event-bus"); + makeClickable(".aggregate-mirror", "docs/introduction/concepts#aggregate-mirror"); + makeClickable(".command-store", "docs/introduction/concepts#command-store"); + makeClickable(".event-store", "docs/introduction/concepts#event-store"); + makeClickable(".command-service", "docs/introduction/concepts#command-service"); + makeClickable(".query-service", "docs/introduction/concepts#query-service"); + makeClickable(".subscription-service", "docs/introduction/concepts#subscription-service"); + makeClickable(".stand", "docs/introduction/concepts#stand"); + + // Arrows: + makeClickable(".ui-command-service", "docs/introduction/concepts#command"); + makeClickable(".command-service-ui", "docs/introduction/concepts#acknowledgement"); + makeClickable(".event-bus-aggregate-repo", "docs/introduction/concepts#event"); + makeClickable(".integration-events", "docs/introduction/concepts#integration-event"); + } +); diff --git a/_hugo-theme/assets/js/docs/code-theme.js b/_hugo-theme/assets/js/docs/code-theme.js new file mode 100644 index 0000000..65b6960 --- /dev/null +++ b/_hugo-theme/assets/js/docs/code-theme.js @@ -0,0 +1,99 @@ +/* + * Copyright 2025, TeamDev. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +'use strict'; + +import * as params from '@params'; + +/** + * Changes the code theme styles and body class on the toggle click. + * + *
The selected theme will be saved in cookies and the user will be able + * to navigate between pages without selecting the theme again. + * + *
The stylesheet is applied in `layouts/_partials/head/code-theme.html`. + */ +export function initCodeTheme() { + const $body = $('body'); + const $themeCSS = $('#code-theme-css'); + const $themeToggle = $('#code-theme-toggle'); + const $codeBlock = $('div.highlight'); + const themeClass = { + dark: 'dark-code-theme', + light: 'light-code-theme' + } + const toggleClass = { + toggle: 'code-theme-toggle', + dark: 'dark', + light: 'light' + } + const defaultTheme = params.defaultCodeTheme || 'dark'; + let theme = Cookies.get('code-theme') || defaultTheme; + + setTheme(theme); + createToggleIcon(); + + /** + * Creates the theme toggle icon under each code block. + */ + function createToggleIcon() { + if (!$codeBlock) return; + + $codeBlock.each(function () { + const icon = $(``) + $(this).append(icon); + }); + } + + /** + * Updates the theme on the toggle icon click. + */ + $(document).on('click', `.${toggleClass.toggle}`, function () { + const currentHref = $themeCSS.attr('href'); + const lightHref = $themeCSS.data('light'); + const isLight = currentHref === lightHref; + const newTheme = isLight ? 'dark' : 'light'; + + setTheme(newTheme); + Cookies.set('code-theme', newTheme); + }); + + /** + * Sets the provided theme as the body class and changes the CSS URL + * to the corresponding one. + * + * @param {string} theme the code theme to be set + */ + function setTheme(theme) { + $themeCSS.attr('href', $themeCSS.data(theme)); + $body.removeClass(`${themeClass.dark} ${themeClass.light}`) + .addClass(themeClass[theme]); + $themeToggle.removeClass(`${toggleClass.dark} ${toggleClass.light}`) + .addClass(toggleClass[theme]); + } +} diff --git a/_hugo-theme/assets/js/docs/element-max-height.js b/_hugo-theme/assets/js/docs/element-max-height.js new file mode 100644 index 0000000..d8fd530 --- /dev/null +++ b/_hugo-theme/assets/js/docs/element-max-height.js @@ -0,0 +1,88 @@ +/* + * Copyright 2025, TeamDev. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +'use strict'; + +/** + * Sets the `max-height` property to an element with the `.set-max-height` class. + * + *
The `max-height` value is calculated depending on the current window + * height and will be updated on window resize. + */ +export function setElementMaxHeight() { + const $element = $('.set-max-height'); + const $footer = $('.footer'); + const headerHeight = $('#header').length ? $('#header').outerHeight() : 0; + const footerTopPosition = $footer.length ? $footer.position().top : 0; + + if ($element.length) { + updateMaxHeight(); + + $(window).on('resize scroll', function () { + updateMaxHeight(); + }); + } + + /** + * Sets the `max-height` value to the element + * to be sure that it always fits on the page. + */ + function updateMaxHeight() { + const maxHeight = calculateMaxHeight(); + + $element.each(function() { + $(this).css({ + 'overflow': 'auto', + 'max-height': maxHeight + }); + }); + } + + /** + * Calculates the possible element `max-height` based on the window + * and navigation heights. + * + * @return {number} maxHeight the value of the maximum possible height + */ + function calculateMaxHeight() { + const windowHeight = $(window).height(); + const scrollTop = $(window).scrollTop(); + const elementTopMargin = 24; + const elementBottomMargin = 20; + const elementTopPosition = headerHeight + elementTopMargin; + const maxHeight = windowHeight - elementTopPosition - elementBottomMargin; + + if ($footer.length) { + const isFooterVisible = windowHeight + scrollTop > footerTopPosition; + + if (isFooterVisible) { + return footerTopPosition - scrollTop - elementTopPosition - elementBottomMargin; + } + } + + return maxHeight; + } +} diff --git a/_hugo-theme/assets/js/docs/interactive-toc.js b/_hugo-theme/assets/js/docs/interactive-toc.js new file mode 100644 index 0000000..b28d79f --- /dev/null +++ b/_hugo-theme/assets/js/docs/interactive-toc.js @@ -0,0 +1,185 @@ +/* + * Copyright 2025, TeamDev. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Redistribution and use in source and/or binary forms, with or without + * modification, must retain the above copyright notice and the following + * disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +'use strict'; + +/** + * Makes the Hugo TOC items interactive. + * + *
During scrolling, adds the `current` class to the anchor, the heading + * of which is now visible on the page. + * + *
Note, that the TOC element should be wrapped into the `div` with + * the `interactive-toc` class. For example: + * ``` + *
Prevents the default scroll to avoid active item overriding. + */ + $tocItems.on('click', function (e) { + e.preventDefault(); + const $current = $(this); + const anchor = $current.attr('href'); + + disableScroll = true; + $tocItems.removeClass(currentClass); + $current.addClass(currentClass); + window.location.hash = anchor; + + $('html, body').animate( + {scrollTop: $(anchor).offset().top - 80}, + 300, + function () { + disableScroll = false; + } + ); + }); + + /** + * Marks the current TOC item with the `currentClass`. + */ + function markCurrentTocItem() { + if (!anchors) return; + $tocItems.removeClass(currentClass); + const $active = getCurrentTocItem().addClass(currentClass); + scrollToActiveTocItem($active.get(0)); + } + + /** + * Returns the TOC item, heading of which is now visible on the page. + * + * @returns {jQuery|HTMLElement} the current TOC item + */ + function getCurrentTocItem() { + const scrollPosition = window.pageYOffset; + const windowIncrement = 0.14; + let currentAnchor = null; + anchors.each(function() { + let headingPosition = getHeading(this).position().top; + if (headingPosition < scrollPosition + window.innerHeight * windowIncrement) { + currentAnchor = this; + return; + } + }) + return getTocItem(currentAnchor); + } + + /** + * Returns the TOC item corresponding to the provided `anchor`. + * + * @param {String} anchor the anchor of the visible heading + * @returns {*|jQuery|HTMLElement} the TOC item corresponding to the `anchor` + */ + function getTocItem(anchor) { + return $('#TableOfContents a[href=\"' + anchor + '\"]'); + } + + /** + * Returns the heading element corresponding to the provided `anchor`. + * + * @param {String} anchor the anchor of the heading + * @returns {*|jQuery|HTMLElement} the heading element + */ + function getHeading(anchor) { + return $(':header[id=' + anchor.substring(1) + ']'); + } + + /** + * Returns the list of available anchors on the page. + * + * @returns {Array} the list of anchors + */ + function getAnchors() { + if (!anchors) { + anchors = $tocItems.map(function() { + return $(this).attr("href"); + }); + } + return anchors; + } + + /** + * Scrolls the TOC container to the active item. + * + * @param {DOM node} activeElement the active element in the TOC + */ + function scrollToActiveTocItem(activeElement) { + if (!activeElement) return; + + if ($interactiveToc && $interactiveToc[0].contains(activeElement) && !isElementInView(activeElement)) { + if (activeElement !== lastActiveElement) { + activeElement.scrollIntoView({ + block: 'nearest', + inline: 'nearest', + behavior: 'smooth' + }); + lastActiveElement = activeElement; + } + } + } + + /** + * Checks if the element is in view. + * + *
Helps to avoid scroll jumping at the top of the page.
+ *
+ * @param element the element that should be in the view
+ * @return {boolean}
+ */
+ function isElementInView(element) {
+ const rect = element.getBoundingClientRect();
+ return rect.top >= 0 && rect.bottom <= window.innerHeight;
+ }
+}
diff --git a/_hugo-theme/assets/js/docs/sidenav.js b/_hugo-theme/assets/js/docs/sidenav.js
new file mode 100644
index 0000000..a22e49d
--- /dev/null
+++ b/_hugo-theme/assets/js/docs/sidenav.js
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2025, TeamDev. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Redistribution and use in source and/or binary forms, with or without
+ * modification, must retain the above copyright notice and the following
+ * disclaimer.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * Toggles the sidenav on mobile devices.
+ */
+export function initSidenav() {
+ const $body = $('body');
+ const $mobileSidenavToggle = $('#mobile-sidenav-toggle');
+ const $mobileSidenavCloseBtn = $('#close-mobile-sidenav');
+ const mobileSidenavOpenedClass = 'mobile-sidenav-opened';
+
+ $(window).on('resize', function() {
+ hideMobileSidenavOnResize();
+ });
+
+ /**
+ * Shows the mobile sidenav panel on the toggle click.
+ */
+ $mobileSidenavToggle.click(function () {
+ $body.addClass(mobileSidenavOpenedClass);
+ });
+
+ /**
+ * Closes the mobile sidenav panel on the close button click.
+ */
+ $mobileSidenavCloseBtn.click(function () {
+ $body.removeClass(mobileSidenavOpenedClass);
+ });
+
+ /**
+ * Hides the mobile sidenav on window resizing.
+ */
+ function hideMobileSidenavOnResize() {
+ const tabletWidth = 880;
+ const mobileWindow = $(window).width() <= tabletWidth;
+
+ if (!mobileWindow) {
+ $body.removeClass(mobileSidenavOpenedClass);
+ }
+ }
+}
diff --git a/_hugo-theme/assets/docs-common.scss b/_hugo-theme/assets/scss/docs-common.scss
similarity index 93%
rename from _hugo-theme/assets/docs-common.scss
rename to _hugo-theme/assets/scss/docs-common.scss
index 86644c3..f7a639e 100644
--- a/_hugo-theme/assets/docs-common.scss
+++ b/_hugo-theme/assets/scss/docs-common.scss
@@ -30,3 +30,6 @@
@import "docs-common/config";
@import "docs-common/mixins";
@import "docs-common/layout";
+@import "docs-common/code";
+@import "docs-common/snackbar";
+@import "docs-common/anchor-icon";
diff --git a/_hugo-theme/assets/scss/docs-common/_anchor-icon.scss b/_hugo-theme/assets/scss/docs-common/_anchor-icon.scss
new file mode 100644
index 0000000..bb63372
--- /dev/null
+++ b/_hugo-theme/assets/scss/docs-common/_anchor-icon.scss
@@ -0,0 +1,41 @@
+/*!
+ * Copyright 2025, TeamDev. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Redistribution and use in source and/or binary forms, with or without
+ * modification, must retain the above copyright notice and the following
+ * disclaimer.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+$icon-color: #1a96de;
+$icon-opacity: .38;
+$icon-size-s: 24px;
+
+// Common theme styles from the `TeamDev-Ltd/site-commons`.
+@import "../anchor-icon";
+
+.anchor-icon {
+ color: $icon-color !important;
+ font-weight: 700;
+
+ &:after {
+ margin-bottom: 2px;
+ }
+}
diff --git a/_hugo-theme/assets/scss/docs-common/_config.scss b/_hugo-theme/assets/scss/docs-common/_config.scss
index 332688a..1f93e55 100755
--- a/_hugo-theme/assets/scss/docs-common/_config.scss
+++ b/_hugo-theme/assets/scss/docs-common/_config.scss
@@ -26,8 +26,7 @@
// Layout
$layout-max-width: 1260px;
-$custom-side-col-width: 240px;
-$center-col-width: $layout-max-width - $custom-side-col-width - $custom-side-col-width; // 780px;
+$doc-sidenav-mobile-breakpoint: 880px;
// Line heights
$article-line-height: 1.74;
@@ -74,18 +73,5 @@ $icon-size--m : 32px;
$icon-size--l : 40px;
$icon-size--xl : 48px;
-// Width for the element that is inside the custom column in 240px
-// Width equals `custom-column-width` minus `padding` (240px - 15px - 15px = 210px)
-$sticky-el-width: 210px;
-
-// Collapsible item
-$icon-right-offset: 48px;
-
-// Container top offset for pages with a fixed header. For example a page with a single post.
-$page-top-offset: $header-height + 32px;
-$page-top-offset-mobile: $header-height + 16px;
-
// Inputs
$input-border-radius: $border-radius;
-
-$doc-sidenav-mobile-breakpoint: 880px;
diff --git a/_hugo-theme/assets/scss/docs-common/_layout.scss b/_hugo-theme/assets/scss/docs-common/_layout.scss
index 8dc1260..9feb8c4 100644
--- a/_hugo-theme/assets/scss/docs-common/_layout.scss
+++ b/_hugo-theme/assets/scss/docs-common/_layout.scss
@@ -28,6 +28,10 @@
--text-color: #3a3a3a;
}
+html {
+ scroll-padding-top: $header-height;
+}
+
html,
body {
height: 100%;
diff --git a/_hugo-theme/assets/scss/docs-common/_mixins.scss b/_hugo-theme/assets/scss/docs-common/_mixins.scss
index c2d36ac..5bc83b9 100644
--- a/_hugo-theme/assets/scss/docs-common/_mixins.scss
+++ b/_hugo-theme/assets/scss/docs-common/_mixins.scss
@@ -40,7 +40,7 @@ $breakpoints: (
lg-desktop: 1440px
);
-/* Usage: `@include breakpoint(desktop)` */
+// Usage: `@include breakpoint(desktop)`
@mixin breakpoint($deviceWidth) {
@if map-has-key($breakpoints, $deviceWidth) {
$value: map-get($breakpoints, $deviceWidth);
diff --git a/_hugo-theme/assets/scss/docs-common/_snackbar.scss b/_hugo-theme/assets/scss/docs-common/_snackbar.scss
new file mode 100644
index 0000000..a8eb3e4
--- /dev/null
+++ b/_hugo-theme/assets/scss/docs-common/_snackbar.scss
@@ -0,0 +1,30 @@
+/*!
+ * Copyright 2025, TeamDev. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Redistribution and use in source and/or binary forms, with or without
+ * modification, must retain the above copyright notice and the following
+ * disclaimer.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+$dark-color: #232526;
+
+// Common theme styles from the `TeamDev-Ltd/site-commons`.
+@import "../snackbar";
diff --git a/_hugo-theme/assets/scss/docs-common/code/_code-block.scss b/_hugo-theme/assets/scss/docs-common/code/_code-block.scss
new file mode 100644
index 0000000..4fe4d6e
--- /dev/null
+++ b/_hugo-theme/assets/scss/docs-common/code/_code-block.scss
@@ -0,0 +1,86 @@
+/*!
+ * Copyright 2025, TeamDev. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Redistribution and use in source and/or binary forms, with or without
+ * modification, must retain the above copyright notice and the following
+ * disclaimer.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ Extends the `_code.scss` styles.
+
+ The `.code-block` wrapper is available when using the `{{< highlight >}}`
+ shortcode with the file name parameter or with using the `code-tabs`.
+*/
+.code-block {
+ $code-block-background: var(--code-block-background);
+ $header-name-font-size: 12px;
+ $header-bg-color: var(--code-block-background);
+ $header-divider-color: var(--code-block-header-divider-color);
+
+ margin-bottom: 40px;
+ background-color: $code-block-background;
+ border-radius: $code-block-border-radius;
+
+ .code-block-header {
+ position: relative;
+ display: flex;
+ align-items: center;
+ background-color: $header-bg-color;
+ border-radius: $code-block-border-radius $code-block-border-radius 0 0;
+ border-bottom: 1px solid $header-divider-color;
+
+ .file-name {
+ color: var(--code-block-text-color);
+ font-size: $header-name-font-size;
+ font-weight: bold;
+ line-height: 1;
+ padding: 14px $code-block-padding;
+ }
+
+ .copy-code-to-clipboard-icon {
+ background-color: unset;
+ top: 0;
+ }
+ }
+
+ .highlight {
+ margin-bottom: 0;
+
+ pre {
+ border-radius: 0 0 $code-block-border-radius $code-block-border-radius;
+ }
+
+ table tr td {
+ &:first-child {
+ pre {
+ border-top-left-radius: 0;
+ }
+ }
+
+ &:last-child {
+ pre {
+ border-top-right-radius: 0;
+ }
+ }
+ }
+ }
+}
diff --git a/_hugo-theme/assets/scss/docs-common/code/_code-copy-icon.scss b/_hugo-theme/assets/scss/docs-common/code/_code-copy-icon.scss
new file mode 100644
index 0000000..c388f2a
--- /dev/null
+++ b/_hugo-theme/assets/scss/docs-common/code/_code-copy-icon.scss
@@ -0,0 +1,96 @@
+/*!
+ * Copyright 2025, TeamDev. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Redistribution and use in source and/or binary forms, with or without
+ * modification, must retain the above copyright notice and the following
+ * disclaimer.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// The icon is added to the DOM in `assets/js/components/docs/copy-code.js`.
+.copy-code-to-clipboard-icon {
+ $icon-container-size: 40px;
+ $icon-size: 16px;
+ $icon-color: var(--copy-code-icon-color);
+ $icon-color-hover: var(--copy-code-icon-hover-color);
+ $icon-bg-color: var(--code-block-background);
+
+ position: absolute;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: $icon-container-size;
+ height: $icon-container-size;
+ font-size: $icon-size;
+ color: $icon-color;
+ background-color: $icon-bg-color;
+ border-radius: $code-block-border-radius;
+ top: 0;
+ right: 0;
+ transition: color .2s ease-in-out;
+ cursor: pointer;
+
+ &:hover {
+ color: $icon-color-hover
+ }
+
+ $tooltip-top-position: -16px;
+ $tooltip-right-position: -5px;
+
+ + .copy-code-tooltip {
+ position: absolute;
+ visibility: hidden;
+ font-family: $main-font;
+ top: $tooltip-top-position;
+ right: $tooltip-right-position;
+ font-size: 12px;
+ background: rgba(0, 0, 0, .9);
+ color: white;
+ padding: 4px 6px;
+ border-radius: 3px;
+
+ &.show {
+ visibility: visible;
+ animation: tooltipFadeIn .5s, tooltipFadeOut .5s 2.5s;
+ }
+ }
+
+ @keyframes tooltipFadeIn {
+ 0% {
+ top: 0;
+ opacity: 0;
+ }
+ 100% {
+ top: $tooltip-top-position;
+ opacity: 1;
+ }
+ }
+
+ @keyframes tooltipFadeOut {
+ 0% {
+ top: $tooltip-top-position;
+ opacity: 1;
+ }
+ 100% {
+ top: 0;
+ opacity: 0;
+ }
+ }
+}
diff --git a/_hugo-theme/assets/scss/docs-common/code/_code-tabs.scss b/_hugo-theme/assets/scss/docs-common/code/_code-tabs.scss
new file mode 100644
index 0000000..581ca92
--- /dev/null
+++ b/_hugo-theme/assets/scss/docs-common/code/_code-tabs.scss
@@ -0,0 +1,120 @@
+/*!
+ * Copyright 2025, TeamDev. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Redistribution and use in source and/or binary forms, with or without
+ * modification, must retain the above copyright notice and the following
+ * disclaimer.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * The tabs are managed by `assets/js/components/docs/code-tabs.js`.
+ * The layout of tabs depends on the `assets/scss/components/code/_code-block.scss`.
+ */
+.code-tabs {
+ $code-tab-color: var(--code-tab-color);
+ $code-tab-active-color: var(--code-tab-active-color);
+ $code-tab-indicator-color: var(--code-tab-indicator-color);
+ $code-tab-font: var(--main-font);
+ $code-tab-padding: 14px 16px;
+ $border-radius: 3px;
+ $indicator-line-height: 3px;
+ $indicator-line-border-radius: $indicator-line-height/2;
+
+ margin: 20px 0 32px;
+
+ .tabs {
+ position: relative;
+ display: flex;
+
+ .indicator {
+ content: '';
+ position: absolute;
+ display: block;
+ bottom: -1px;
+ min-width: 0;
+ width: 0;
+ height: $indicator-line-height;
+ background: $code-tab-indicator-color;
+ border-radius: $indicator-line-border-radius;
+ will-change: left, width;
+ transition: left .3s ease, width .3s ease;
+ }
+
+ .tab {
+ position: relative;
+ display: inline-block;
+ padding: $code-tab-padding;
+ font-family: $code-tab-font;
+ color: $code-tab-color;
+ font-weight: bold;
+ font-size: 12px;
+ line-height: 1;
+ transition: color .2s ease-in-out;
+ cursor: pointer;
+
+ &.active {
+ color: $code-tab-active-color;
+
+ &.show-static-indicator {
+ &:after {
+ content: '';
+ position: absolute;
+ display: block;
+ left: 0;
+ bottom: -1px;
+ width: 100%;
+ height: $indicator-line-height;
+ background: red;
+ }
+ }
+ }
+ }
+
+ &.one-tab {
+ .indicator {
+ display: none;
+ }
+ }
+ }
+
+ .code-tab-content {
+ p {
+ padding-top: 0 !important;
+ margin-bottom: 8px;
+ }
+ }
+}
+
+.code-tab-content {
+ display: none;
+
+ &.active {
+ display: block;
+ }
+
+ &.inline.active {
+ display: inline-block;
+ }
+
+ p:first-child {
+ padding-top: 0 !important;
+ }
+}
diff --git a/_hugo-theme/assets/scss/docs-common/code/_code-theme-toggle.scss b/_hugo-theme/assets/scss/docs-common/code/_code-theme-toggle.scss
new file mode 100644
index 0000000..81f445e
--- /dev/null
+++ b/_hugo-theme/assets/scss/docs-common/code/_code-theme-toggle.scss
@@ -0,0 +1,64 @@
+/*!
+ * Copyright 2025, TeamDev. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Redistribution and use in source and/or binary forms, with or without
+ * modification, must retain the above copyright notice and the following
+ * disclaimer.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+.highlight {
+ position: relative;
+}
+
+.light-code-theme {
+ .code-theme-toggle {
+ opacity: .26;
+ }
+}
+
+.code-theme-toggle {
+ $toggle-size: 24px;
+ $icon-size: 18px;
+
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ position: absolute;
+ top: calc((#{$toggle-size} + 2px) * -1);
+ right: 0;
+ width: $toggle-size;
+ height: $toggle-size;
+ opacity: .38;
+ transition: opacity .2s ease-in-out;
+ cursor: pointer;
+
+ &:before {
+ content: '';
+ position: absolute;
+ background: url('img/icons/brightness.svg') no-repeat center/cover;
+ width: $icon-size;
+ height: $icon-size;
+ }
+
+ &:hover {
+ opacity: .54;
+ }
+}
diff --git a/_hugo-theme/assets/scss/docs-common/code/_code.scss b/_hugo-theme/assets/scss/docs-common/code/_code.scss
new file mode 100644
index 0000000..91cfd1a
--- /dev/null
+++ b/_hugo-theme/assets/scss/docs-common/code/_code.scss
@@ -0,0 +1,198 @@
+/*!
+ * Copyright 2025, TeamDev. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Redistribution and use in source and/or binary forms, with or without
+ * modification, must retain the above copyright notice and the following
+ * disclaimer.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+:root {
+ --code-background: #ffffff;
+ --code-text-color: inherit;
+ --code-padding: 0;
+}
+
+.dark-code-theme {
+ --code-block-background: #2b2b2b;
+ --code-block-text-color: #a9b7c6;
+ --code-block-box-shadow: unset;
+ --code-block-header-divider-color: rgba(255, 255, 255, .08);
+ --code-block-highlighted-line-bg: #2c3035;
+ --copy-code-icon-color: #{$gray-600};
+ --copy-code-icon-hover-color: rgba(255, 255, 255, .8);
+ --code-tab-color: #{$gray-600};
+ --code-tab-active-color: #f8f8f2;
+ --code-tab-indicator-color: #{$gray-700};
+}
+
+.light-code-theme {
+ --code-block-background: #ffffff;
+ --code-block-text-color: var(--text-color);
+ --code-block-box-shadow: 0 3px 12px 0 rgba(35, 37, 38, .1);
+ --code-block-header-divider-color: rgba(0, 0, 0, .07);
+ --code-block-highlighted-line-bg: #e9f0e9;
+ --copy-code-icon-color: #{$gray-600};
+ --copy-code-icon-hover-color: #{$gray-700};
+ --code-tab-color: #{$gray-600};
+ --code-tab-active-color: var(--text-color);
+ --code-tab-indicator-color: $main-brand-color;
+}
+
+$mono-font-family: $main-mono-font;
+$code-block-font-size: 13px;
+$code-block-line-height: 1.6;
+$code-block-border-radius: 6px;
+$code-block-padding: 16px;
+
+pre,
+code {
+ font-family: $mono-font-family;
+ color: var(--code-text-color);
+}
+
+pre {
+ overflow-x: auto;
+ margin: 0;
+}
+
+code {
+ font-size: 95%;
+ background-color: var(--code-background);
+ padding: var(--code-padding);
+ margin: 0;
+ font-variant-ligatures: none;
+}
+
+/*
+ The default Hugo Highlight.
+ See the usage here https://gohugo.io/content-management/syntax-highlighting/.
+
+ For better customization enable classes in the project `config`:
+ ```
+ [markup.highlight]
+ noClasses = false
+ ```
+*/
+.highlight {
+ position: relative;
+
+ pre {
+ border-radius: $code-block-border-radius;
+ box-shadow: var(--code-block-box-shadow);
+ }
+
+ // The first `div` that wraps ` This diagram shows
+ all server-side components
+ of a cloud application. When developing with Spine, you will be interacting with
+ some of them. {{ . | markdownify }} {{ .Inner | markdownify }}
+ {{ $title | markdownify }}
+ {{ .Inner | markdownify }} {{ .Inner | markdownify }}` or ``.
+ // When classes are enabled the `div` has the `chroma` class.
+ // Needed to make the code scrollable if the line numbers are enabled.
+ > div {
+ overflow-x: auto;
+ }
+
+ code {
+ display: table;
+ width: 100%;
+ padding: $code-block-padding;
+ font-size: $code-block-font-size;
+ line-height: $code-block-line-height;
+ background-color: var(--code-block-background);
+ color: var(--code-block-text-color);
+ border-radius: unset;
+
+ // Fixes iOS font sizing inside code blocks.
+ // Font size is affected while using flexbox for `` tag
+ // inside code on Safari/Chrome iOS.
+ text-size-adjust: 100%;
+ -ms-text-size-adjust: 100%;
+ -moz-text-size-adjust: 100%;
+ -webkit-text-size-adjust: 100%;
+ }
+
+ // Makes highlighted line full-width.
+ .hl {
+ margin: 0 -#{$code-block-padding};
+ padding: 0 $code-block-padding;
+ }
+
+ // Hugo layout with numbered code lines.
+ // The first column is the numbers, the second is the code.
+ // The layout works if `{linenos=table} near the code backticks is specified.
+ table {
+ &.lntable {
+ width: 100%;
+ }
+
+ tr {
+ td {
+ &:first-child {
+ user-select: none;
+
+ pre {
+ overflow: hidden;
+ border-radius: $code-block-border-radius 0 0 $code-block-border-radius;
+
+ code {
+ padding-right: 0;
+ padding-left: 16px;
+
+ span {
+ // Aligns numbers with the highlighted code line.
+ display: flex;
+ }
+ }
+ }
+ }
+
+ &:last-child {
+ // Prevents the first column from expanding arbitrarily.
+ width: 100%;
+
+ pre {
+ border-radius: 0 $code-block-border-radius $code-block-border-radius 0;
+
+ code {
+ padding-left: 0;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+.opaque-hl-lines {
+ .highlight {
+ code {
+ .hl {
+ background: none;
+ }
+
+ .line:not(.hl) {
+ opacity: .3;
+ }
+ }
+ }
+}
+
+.markdown {
+ .highlight {
+ margin-bottom: 40px;
+ }
+}
diff --git a/_hugo-theme/assets/scss/docs-common/code/_index.scss b/_hugo-theme/assets/scss/docs-common/code/_index.scss
new file mode 100644
index 0000000..07ead30
--- /dev/null
+++ b/_hugo-theme/assets/scss/docs-common/code/_index.scss
@@ -0,0 +1,31 @@
+/*!
+ * Copyright 2025, TeamDev. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Redistribution and use in source and/or binary forms, with or without
+ * modification, must retain the above copyright notice and the following
+ * disclaimer.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+@import "code";
+@import "code-block";
+@import "code-tabs";
+@import "code-copy-icon";
+@import "code-theme-toggle";
diff --git a/_hugo-theme/assets/scss/docs.scss b/_hugo-theme/assets/scss/docs.scss
new file mode 100644
index 0000000..4ab6660
--- /dev/null
+++ b/_hugo-theme/assets/scss/docs.scss
@@ -0,0 +1,42 @@
+/*!
+ * Copyright 2025, TeamDev. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Redistribution and use in source and/or binary forms, with or without
+ * modification, must retain the above copyright notice and the following
+ * disclaimer.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+@import "docs/base/colors";
+@import "docs/base/mixins";
+
+@import "docs/modules/layout";
+@import "docs/modules/article-container";
+@import "docs/modules/article-text";
+@import "docs/modules/interactive-toc";
+@import "docs/modules/sidenav";
+@import "docs/modules/next-prev-nav";
+@import "docs/modules/diagram";
+@import "docs/modules/note-block";
+@import "docs/modules/docs-category-card";
+@import "docs/modules/book-card";
+@import "docs/modules/person-card";
+
+@import "docs/pages/resources";
diff --git a/_hugo-theme/assets/scss/docs/base/_colors.scss b/_hugo-theme/assets/scss/docs/base/_colors.scss
new file mode 100644
index 0000000..060782d
--- /dev/null
+++ b/_hugo-theme/assets/scss/docs/base/_colors.scss
@@ -0,0 +1,48 @@
+/*!
+ * Copyright 2025, TeamDev. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Redistribution and use in source and/or binary forms, with or without
+ * modification, must retain the above copyright notice and the following
+ * disclaimer.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// Brand Colors
+$main-brand-color: #1a96de;
+$second-brand-color: #116db4;
+$body-light-gray-color: #f6f8fA;
+$note-bg-color: #e0f2ff;
+$warning-color: #deba32;
+
+// General Colors
+$black: #2e2e2e;
+$text-color: #3a3a3a;
+
+// Grays
+$gray-100: rgba(black, .12);
+$gray-200: rgba(black, .26);
+$gray-300: rgba(black, .38);
+$gray-500: rgba(black, .54);
+$gray-600: rgba(black, .6);
+$gray-700: rgba(black, .7);
+
+// Links
+$link-color: $main-brand-color;
+$link-hover-color: darken($link-color, 10%);
diff --git a/_hugo-theme/assets/scss/docs/base/_mixins.scss b/_hugo-theme/assets/scss/docs/base/_mixins.scss
new file mode 100644
index 0000000..061e30b
--- /dev/null
+++ b/_hugo-theme/assets/scss/docs/base/_mixins.scss
@@ -0,0 +1,66 @@
+// Usage: @include transition(all .3s ease-in-out);
+@mixin transition($args...) {
+ -webkit-transition: $args;
+ -moz-transition: $args;
+ -ms-transition: $args;
+ -o-transition: $args;
+ transition: $args;
+}
+
+// Usage: @include box-shadow(0 10px 20px 0 rgba(black, .12));
+@mixin box-shadow($args...) {
+ -webkit-box-shadow: $args;
+ -moz-box-shadow: $args;
+ -o-box-shadow: $args;
+ box-shadow: $args;
+}
+
+@mixin close-icon {
+ display: inline-block;
+ width: $icon-size--s;
+ height: $icon-size--s;
+ background: url('https://spine.io/img/x-black.svg') no-repeat center/cover;
+ opacity: .26;
+ @include transition(all .3s ease-in-out);
+}
+
+// Ordered and unordered list styles.
+// Usage: `@include list();`
+@mixin list($item-line-height: 1.6) {
+ ol, ul {
+ margin: 0 0 32px 0;
+ line-height: $item-line-height;
+
+ @media (max-width: $tablet) {
+ margin-bottom: 24px;
+ }
+
+ li {
+ margin-left: 18px;
+ margin-top: .6em;
+ padding-left: 6px; // Adds additional space between bullet and text.
+
+ ol, ul {
+ margin-bottom: 32px;
+
+ li {
+ margin-top: .45em;
+ }
+ }
+ }
+ }
+
+ ul {
+ list-style: disc;
+
+ li {
+ ul {
+ list-style: circle;
+ }
+ }
+ }
+
+ ol {
+ list-style: decimal;
+ }
+}
diff --git a/_hugo-theme/assets/scss/docs/modules/_article-container.scss b/_hugo-theme/assets/scss/docs/modules/_article-container.scss
new file mode 100644
index 0000000..31a7aa8
--- /dev/null
+++ b/_hugo-theme/assets/scss/docs/modules/_article-container.scss
@@ -0,0 +1,88 @@
+/*!
+ * Copyright 2025, TeamDev. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Redistribution and use in source and/or binary forms, with or without
+ * modification, must retain the above copyright notice and the following
+ * disclaimer.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+$article-border-color: #e6ecf1;
+$article-container-border: 1px solid $article-border-color;
+$article-side-padding: 56px;
+$article-container-padding: 32px $article-side-padding 40px;
+$article-container-margin-bottom: 32px;
+$article-container-border-radius: 3px;
+$article-container-min-height: 460px;
+
+.article-container {
+ display: flex;
+ flex-direction: column;
+ background-color: white;
+ border: $article-container-border;
+ border-radius: $article-container-border-radius;
+ padding: $article-container-padding;
+ margin-bottom: $article-container-margin-bottom;
+ min-width: 0; // Fixes a bug when `pre` code breaks flex element.
+ min-height: $article-container-min-height;
+
+ @media (max-width: $phone-xlarge) {
+ padding: 0;
+ border: none;
+ }
+
+ // Full-width code block inside articles.
+ // Extends styles provided in `scss/docs-common/code/_index.scss`.
+ --code-block-padding: #{$article-side-padding};
+
+ @media (max-width: $phone-xlarge) {
+ --code-block-padding: 32px;
+ }
+ @media (max-width: $phone-medium) {
+ --code-block-padding: 20px;
+ }
+
+ .highlight {
+ pre {
+ border-radius: 0;
+ margin-right: calc(var(--code-block-padding) * -1);
+ margin-left: calc(var(--code-block-padding) * -1);
+
+ code {
+ padding-right: var(--code-block-padding);
+ padding-left: var(--code-block-padding);
+ }
+ }
+ }
+
+ li {
+ .highlight {
+ pre {
+ border-radius: $code-block-border-radius;
+ margin-left: unset;
+ margin-right: unset;
+
+ code {
+ padding: $code-block-padding;
+ }
+ }
+ }
+ }
+}
diff --git a/_hugo-theme/assets/scss/docs/modules/_article-text.scss b/_hugo-theme/assets/scss/docs/modules/_article-text.scss
new file mode 100644
index 0000000..3f84e27
--- /dev/null
+++ b/_hugo-theme/assets/scss/docs/modules/_article-text.scss
@@ -0,0 +1,267 @@
+/*!
+ * Copyright 2025, TeamDev. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Redistribution and use in source and/or binary forms, with or without
+ * modification, must retain the above copyright notice and the following
+ * disclaimer.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// Please be careful when renaming this class.
+// It is used in the DocSearch configuration in the admin panel.
+.article-text {
+ a:not(.anchor-icon) {
+ text-decoration: none;
+ color: $link-color;
+ font-weight: 400;
+ transition: all .3s ease-in-out;
+
+ &:hover,
+ &:focus {
+ color: $link-hover-color;
+ text-decoration: underline;
+ }
+
+ &.external-link {
+ white-space: nowrap;
+
+ &:after {
+ content: '\2192';
+ font-weight: 300;
+ width: 8px;
+ height: 8px;
+ overflow: hidden;
+ text-align: right;
+ line-height: 6px;
+ text-indent: -11px;
+ opacity: .6;
+ transform: rotate(-45deg);
+ transition: opacity .16s ease-in;
+ vertical-align: super;
+ font-size: smaller;
+ text-decoration: none;
+ display: inline-block;
+ }
+
+ &:hover {
+ &:after {
+ color: $second-brand-color;
+ }
+ }
+ }
+ }
+
+ ol, ul, li {
+ padding: 0;
+ }
+
+ p {
+ margin-bottom: 16px;
+ }
+
+ p, ol, ul {
+ font-family: $main-serif-font;
+ font-size: $article-font-size;
+ line-height: $article-line-height;
+ text-align: justify;
+
+ @media (max-width: $tablet) {
+ font-size: $font-size--s;
+ }
+
+ @media (max-width: $phone-medium) {
+ text-align: left;
+ }
+ }
+
+ p + ul {
+ margin-top: -4px;
+ }
+
+ .lead + h2 {
+ padding-top: 0;
+ }
+
+ h1, h2, h3, h2 {
+ code {
+ font-size: inherit;
+ color: inherit;
+ }
+ }
+
+ h1 + h2 {
+ padding-top: 0;
+ }
+
+ ul + h2,
+ ol + h2 {
+ padding-top: 16px;
+ }
+
+ h2 + h3 {
+ padding-top: 4px;
+ }
+
+ h3 + h4 {
+ margin-top: 12px;
+ }
+
+ ol + h3,
+ ul + h3 {
+ padding-top: 0;
+ }
+
+ ol + h4,
+ ul + h4 {
+ margin-top: 0;
+ }
+
+ img {
+ display: block;
+ width: 100%;
+ margin: 0 auto;
+ padding-bottom: 8px;
+ }
+
+ .img-small {
+ img {
+ width: 70%;
+ }
+ }
+
+ .img-caption {
+ font-family: $main-font;
+ font-size: 14px;
+ color: $gray-500;
+ margin-bottom: 32px;
+ }
+
+ @include list($item-line-height: $article-line-height);
+
+ // Section headlines
+ h1 {
+ font-size: $font-size--xxxl;
+ font-weight: 300;
+ color: rgba(black, .4);
+ line-height: 1.2;
+ padding-top: 16px;
+ margin-bottom: 32px;
+
+ @media (max-width: $phone-xlarge) {
+ margin-bottom: 16px;
+ }
+ }
+
+ h2 {
+ font-size: 1.8rem;
+ font-weight: 700;
+ color: $black;
+ line-height: 1.3;
+ padding-top: 32px;
+ margin-bottom: 12px;
+
+ &.top {
+ padding-top: 8px;
+ }
+ }
+
+ h3 {
+ font-size: 1.25rem;
+ font-weight: 700;
+ color: $black;
+ line-height: 1.4;
+ margin-bottom: 8px;
+ padding-top: 24px;
+ }
+
+ h4 {
+ font-size: $font-size--s;
+ font-weight: 700;
+ color: $black;
+ margin: 32px 0 8px;
+ }
+
+ h5 {
+ font-size: $font-size--s;
+ font-weight: 300;
+ color: $black;
+ }
+
+ h6 {
+ font-size: .9rem;
+ font-weight: 500;
+ color: $black;
+ }
+
+ .highlight {
+ margin: 8px 0 40px;
+ }
+
+ .date {
+ font-family: $main-font;
+ font-size: 14px;
+ color: $gray-500;
+ }
+
+ .lang {
+ font-size: 14px;
+ color: $gray-300;
+ }
+
+ .coming-soon {
+ color: $gray-200;
+ font-weight: 500;
+ padding-bottom: 24px;
+ margin: 0;
+ }
+
+ strong {
+ font-weight: 700;
+ }
+
+ em {
+ font-style: italic;
+ }
+
+ blockquote {
+ border-left: 2px solid #eeeeee;
+ padding: 0 24px 0 10px;
+ margin: 24px 0 32px;
+
+ p {
+ position: relative;
+ padding-left: 32px;
+ font-size: 22px;
+ line-height: 32px;
+ font-style: italic;
+ font-weight: 300;
+ color: rgba($text-color, .64);
+
+ &:before {
+ content: '';
+ position: absolute;
+ left: 0;
+ width: $icon-size--s;
+ height: $icon-size--s;
+ background: url('img/icons/quote.svg') no-repeat center/cover;
+ }
+ }
+ }
+}
diff --git a/_hugo-theme/assets/scss/docs/modules/_book-card.scss b/_hugo-theme/assets/scss/docs/modules/_book-card.scss
new file mode 100644
index 0000000..18aa5bf
--- /dev/null
+++ b/_hugo-theme/assets/scss/docs/modules/_book-card.scss
@@ -0,0 +1,123 @@
+/*!
+ * Copyright 2025, TeamDev. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Redistribution and use in source and/or binary forms, with or without
+ * modification, must retain the above copyright notice and the following
+ * disclaimer.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+.book-card {
+ position: relative;
+ padding-bottom: 32px;
+
+ @media (min-width: $phone-large) {
+ min-height: 240px;
+ padding-bottom: 48px;
+ }
+
+ $book-size: 142px;
+ $book-size-mobile: 60px;
+ $book-shadow:
+ 0 1px 0 0 #d0d0d0,
+ 0 10px 0 -4px #dedede,
+ 0 11px 0 -4px #d0d0d0,
+ 0 11px 20px -4px rgba(black, .16);
+
+ .book {
+ position: absolute;
+ width: $book-size;
+ box-shadow: $book-shadow;
+
+ &:after {
+ content: '';
+ position: absolute;
+ display: block;
+ width: 1px;
+ height: 6px;
+ background: #d0d0d0;
+ bottom: -7px;
+ left: 2px;
+ float: left;
+ transform: skewX(40deg);
+ }
+
+ @media (max-width: $phone-large) {
+ width: $book-size-mobile;
+ }
+
+ img {
+ padding: 0;
+ }
+ }
+
+ .book-info {
+ padding-left: $book-size + 32px;
+
+ @media (max-width: $phone-large) {
+ padding-left: $book-size-mobile + 20px;
+ }
+
+ .book-title {
+ white-space: normal;
+
+ &:after {
+ display: none;
+ }
+
+ &:hover {
+ text-decoration: none;
+
+ h3 {
+ color: $link-color;
+ }
+ }
+
+ .book-subtitle {
+ font-family: $main-font;
+ font-size: 15px;
+ color: $text-color;
+ margin-top: -4px;
+ margin-bottom: 8px;
+ }
+ }
+
+ .author {
+ font-size: 15px;
+ color: $gray-500;
+ margin-bottom: 8px;
+ }
+
+ .description {
+ @media (max-width: $tablet) {
+ text-align: left;
+ }
+ }
+
+ h3 {
+ padding-top: 4px;
+ margin-bottom: 6px;
+
+ @media (max-width: $phone-large) {
+ padding-top: 0;
+ }
+ }
+ }
+}
diff --git a/_hugo-theme/assets/scss/docs/modules/_diagram.scss b/_hugo-theme/assets/scss/docs/modules/_diagram.scss
new file mode 100644
index 0000000..9668f0a
--- /dev/null
+++ b/_hugo-theme/assets/scss/docs/modules/_diagram.scss
@@ -0,0 +1,114 @@
+/*!
+ * Copyright 2025, TeamDev. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Redistribution and use in source and/or binary forms, with or without
+ * modification, must retain the above copyright notice and the following
+ * disclaimer.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+.diagram-box {
+ margin: 24px 0 32px;
+}
+
+// The diagram visibility controls by `js/docs/architecture-diagram.js`.
+#spine-architecture-diagram {
+ visibility: hidden;
+}
+
+.architecture-link {
+ cursor: pointer;
+ color: $link-color;
+ border-bottom:1px dotted $link-color;
+
+ &:hover {
+ color: $link-hover-color;
+ }
+}
+
+.full-screen-preview {
+ font-family: $main-font;
+
+ .preview-header {
+ padding: 24px 24px 16px;
+ border-bottom: 1px solid rgba(0, 0, 0, .12);
+
+ .preview-title {
+ font-size: 1.25rem;
+ font-weight: 700;
+ line-height: 1.4;
+ color: $black;
+ padding: 0;
+ margin: 0;
+ }
+
+ .preview-subtitle {
+ font-size: 15px;
+ color: $text-color;
+ line-height: 1.6;
+ margin: 8px 0 16px;
+ max-width: 500px;
+ }
+
+ .close-btn-wrapper {
+ float: right;
+
+ .close-btn {
+ display: block;
+ cursor: pointer;
+ line-height: 0;
+ padding: 1rem;
+ margin: -14px -1rem -1rem auto; // `-14px` is used to align the icon with the title text.
+
+ .close-icon {
+ @include close-icon;
+ }
+
+ &:hover {
+ .close-icon {
+ opacity: .87;
+ }
+ }
+ }
+ }
+ }
+
+ .preview-body {
+ padding: 24px 24px 56px;
+
+ svg {
+ display: block;
+ margin: 0 auto;
+ max-width: 1424px;
+ }
+ }
+}
+
+p.full-screen-link {
+ margin-bottom: 24px;
+
+ i {
+ margin-right: 8px;
+ }
+
+ span {
+ font-size: 15px;
+ }
+}
diff --git a/_hugo-theme/assets/scss/docs/modules/_docs-category-card.scss b/_hugo-theme/assets/scss/docs/modules/_docs-category-card.scss
new file mode 100644
index 0000000..b5b15d4
--- /dev/null
+++ b/_hugo-theme/assets/scss/docs/modules/_docs-category-card.scss
@@ -0,0 +1,98 @@
+/*!
+ * Copyright 2025, TeamDev. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Redistribution and use in source and/or binary forms, with or without
+ * modification, must retain the above copyright notice and the following
+ * disclaimer.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+.docs-card-container {
+ display: grid;
+ grid-template-columns: repeat(2, minmax(200px, 1fr));
+ gap: 24px;
+ margin-bottom: 24px;
+
+ @media (max-width: $phone-xlarge) {
+ grid-template-columns: 1fr;
+ }
+
+ a:hover {
+ text-decoration: none;
+ }
+}
+
+.docs-category-card {
+ $card-padding: 20px;
+ $card-border-radius: 6px;
+ $card-shadow:
+ 0 -1px 1px 0 rgba(0, 0, 0, .07),
+ 0 2px 4px 0 rgba(35, 37, 38, .12);
+ $card-hover-shadow: 0 6px 12px rgba(0, 0, 0, .12);
+
+ display: flex;
+ padding: $card-padding;
+ box-shadow: $card-shadow;
+ border-radius: $card-border-radius;
+
+ i {
+ font-size: 24px;
+ margin-right: 20px;
+ color: $main-brand-color;
+ }
+
+ &:hover {
+ text-decoration: none;
+ color: inherit;
+ box-shadow: $card-hover-shadow;
+
+ i {
+ color: $main-brand-color;
+ }
+
+ .card-content {
+ .title {
+ color: $link-color;
+ }
+ }
+ }
+
+ .card-content {
+ .title,
+ .description {
+ font-family: $main-font;
+ color: $text-color;
+ text-align: left;
+ line-height: 1.5;
+ }
+
+ .title {
+ font-weight: 700;
+ font-size: 16px;
+ margin-bottom: 4px;
+ }
+
+ .description {
+ font-weight: 400;
+ font-size: 14px;
+ margin: 0;
+ }
+ }
+}
diff --git a/_hugo-theme/assets/scss/docs/modules/_interactive-toc.scss b/_hugo-theme/assets/scss/docs/modules/_interactive-toc.scss
new file mode 100644
index 0000000..ea47ecf
--- /dev/null
+++ b/_hugo-theme/assets/scss/docs/modules/_interactive-toc.scss
@@ -0,0 +1,98 @@
+/*!
+ * Copyright 2025, TeamDev. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Redistribution and use in source and/or binary forms, with or without
+ * modification, must retain the above copyright notice and the following
+ * disclaimer.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+The TOC can be with the left indicator line or without it.
+Manages by adding the corresponding class.
+*/
+
+.interactive-toc {
+ $toc-item-font-size: 12px;
+ $toc-item-color: $gray-700;
+ $toc-item-line-height: 1.5;
+ $toc-item-active-color: $main-brand-color;
+ $toc-item-bottom-space: 12px;
+ $toc-indicator-width: 1px;
+ $toc-indicator-line-color: rgba(0, 0, 0, .12);
+ $toc-indicator-color: $main-brand-color;
+
+ #TableOfContents {
+ margin-bottom: 0;
+ padding-left: 12px;
+
+ ul {
+ list-style: none;
+ margin-bottom: $toc-item-bottom-space;
+
+ li {
+ font-size: $toc-item-font-size;
+ margin-bottom: $toc-item-bottom-space;
+ line-height: $toc-item-line-height;
+
+ a {
+ text-decoration: none;
+ color: $toc-item-color;
+ font-weight: 400;
+ padding-right: 6px;
+
+ &:hover {
+ color: $toc-item-active-color;
+ }
+
+ &.current {
+ color: $toc-item-active-color;
+ font-weight: 600;
+ }
+ }
+
+ ul {
+ margin: $toc-item-bottom-space 0 0 $toc-item-bottom-space;
+ }
+ }
+ }
+ }
+
+ .toc-indicator {
+ display: none;
+ }
+
+ &.with-indicator-line {
+ position: relative;
+
+ #TableOfContents {
+ border-left: $toc-indicator-width solid $toc-indicator-line-color;
+ padding-left: 16px;
+ }
+
+ .toc-indicator {
+ position: absolute;
+ left: 0;
+ width: $toc-indicator-width;
+ background: $toc-indicator-color;
+ transition: top .3s ease;
+ }
+ }
+}
diff --git a/_hugo-theme/assets/scss/docs/modules/_layout.scss b/_hugo-theme/assets/scss/docs/modules/_layout.scss
new file mode 100644
index 0000000..87fc775
--- /dev/null
+++ b/_hugo-theme/assets/scss/docs/modules/_layout.scss
@@ -0,0 +1,116 @@
+/*!
+ * Copyright 2025, TeamDev. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Redistribution and use in source and/or binary forms, with or without
+ * modification, must retain the above copyright notice and the following
+ * disclaimer.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+$doc-sidenav-desktop-width: 200px;
+$doc-sidenav-tablet-width: 200px;
+$doc-toc-width: 220px;
+$doc-sidenav-background: $gray-100;
+
+.docs {
+ background-color: $body-light-gray-color;
+
+ @media (max-width: $phone-xlarge) {
+ background-color: white;
+ }
+
+ .page-content {
+ display: flex;
+ justify-content: center;
+ flex: 1 1 0;
+ padding: 0;
+ margin-top: 0;
+
+ &.with-colored-sidenav {
+ @include breakpoint-min($doc-sidenav-mobile-breakpoint) {
+ background: linear-gradient(90deg, $doc-sidenav-background 0%, white 50%);
+ }
+
+ .content-col {
+ background-color: white;
+ }
+ }
+ }
+
+ .content-holder {
+ width: 100%;
+ }
+
+ .content-columns {
+ padding: 0 15px;
+
+ @media (max-width: $doc-sidenav-mobile-breakpoint) {
+ padding: 0;
+ }
+
+ .doc-sidenav-col,
+ .toc-col {
+ padding: 24px 0 24px;
+ }
+
+ .content-col {
+ display: flex;
+ flex-direction: column;
+ padding: 24px 15px 48px;
+
+ @include breakpoint($doc-sidenav-mobile-breakpoint) {
+ padding: 16px 0 48px;
+ }
+ }
+
+ .article-container {
+ flex-grow: 1;
+ }
+
+ .sticky-col {
+ position: sticky;
+ align-self: start;
+ top: $header-height;
+ }
+ }
+
+ .three-column {
+ position: relative;
+ display: grid;
+ grid-template-columns: $doc-sidenav-desktop-width minmax(0, 1fr) $doc-toc-width;
+ height: 100%;
+
+ @include breakpoint(desktop) {
+ grid-template-columns: $doc-sidenav-tablet-width minmax(0, 1fr);
+
+ .toc-col {
+ display: none;
+ }
+ }
+
+ @include breakpoint($doc-sidenav-mobile-breakpoint) {
+ display: block;
+
+ .doc-sidenav-col {
+ display: none;
+ }
+ }
+ }
+}
diff --git a/_hugo-theme/assets/scss/docs/modules/_next-prev-nav.scss b/_hugo-theme/assets/scss/docs/modules/_next-prev-nav.scss
new file mode 100644
index 0000000..0d59958
--- /dev/null
+++ b/_hugo-theme/assets/scss/docs/modules/_next-prev-nav.scss
@@ -0,0 +1,84 @@
+/*!
+ * Copyright 2025, TeamDev. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Redistribution and use in source and/or binary forms, with or without
+ * modification, must retain the above copyright notice and the following
+ * disclaimer.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+.next-prev-nav {
+ $space-between: 16px;
+ $label-offset: 24px;
+ $font-family: $main-font;
+ $icon-offset: 8px;
+
+ display: flex;
+ padding: 32px 0 16px;
+ margin-top: auto;
+
+ .item {
+ flex: 1 1 auto;
+ width: 50%;
+ margin: 0;
+ padding: 0;
+ }
+
+ .previous {
+ padding-right: $space-between/2;
+ }
+
+ .next {
+ padding-left: $space-between/2;
+ text-align: right;
+ }
+
+ .arrow-link {
+ display: flex;
+ align-items: center;
+
+ &:after,
+ &:before {
+ content: '';
+ display: none;
+ border: solid $main-brand-color;
+ border-width: 0 2px 2px 0;
+ padding: 3px;
+ }
+
+ &.prev {
+ &:before {
+ display: block;
+ transform: rotate(135deg);
+ margin-right: $icon-offset;
+ }
+ }
+
+ &.next {
+ justify-content: flex-end;
+
+ &:after {
+ display: block;
+ transform: rotate(-45deg);
+ margin-left: $icon-offset;
+ }
+ }
+ }
+}
diff --git a/_hugo-theme/assets/scss/docs/modules/_note-block.scss b/_hugo-theme/assets/scss/docs/modules/_note-block.scss
new file mode 100644
index 0000000..8aa4949
--- /dev/null
+++ b/_hugo-theme/assets/scss/docs/modules/_note-block.scss
@@ -0,0 +1,96 @@
+/*!
+ * Copyright 2025, TeamDev. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Redistribution and use in source and/or binary forms, with or without
+ * modification, must retain the above copyright notice and the following
+ * disclaimer.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+.note-block {
+ padding: 12px 24px 13px;
+ color: $black;
+ border-radius: $border-radius-s;
+ margin-bottom: 24px;
+
+ &.note {
+ background-color: $note-bg-color;
+ border-left: 4px solid $main-brand-color;
+ }
+
+ &.warning {
+ background-color: #fffde6;
+ border-left: 4px solid $warning-color;
+ }
+
+ &.lead {
+ padding: 8px 0 0 0;
+ margin-bottom: 32px;
+
+ p {
+ font-family: $main-font;
+ font-size: 18px;
+ font-weight: 300;
+ letter-spacing: .2px;
+ }
+ }
+
+ code {
+ background-color: transparent;
+ padding: 0;
+ }
+
+ p:last-child {
+ margin-bottom: 0;
+ }
+}
+
+/* TODO:2025-12-01:julia.evseeva: Delete the following styles after migrating content. */
+.lead {
+ font-family: $main-font;
+ font-size: 18px;
+ font-weight: 300;
+ letter-spacing: .2px;
+ padding-top: 8px;
+ margin-bottom: 32px;
+ }
+
+.note,
+.warning {
+ padding: 12px 24px 13px;
+ color: $black;
+ border-radius: $border-radius-s;
+ margin-bottom: 24px;
+
+ code {
+ background-color: transparent;
+ padding: 0;
+ }
+}
+
+.note {
+ background-color: $note-bg-color;
+ border-left: 4px solid $main-brand-color;
+}
+
+.warning {
+ background-color: #fffde6;
+ border-left: 4px solid $warning-color;
+}
diff --git a/_hugo-theme/assets/scss/docs/modules/_person-card.scss b/_hugo-theme/assets/scss/docs/modules/_person-card.scss
new file mode 100644
index 0000000..b0b0271
--- /dev/null
+++ b/_hugo-theme/assets/scss/docs/modules/_person-card.scss
@@ -0,0 +1,83 @@
+/*!
+ * Copyright 2025, TeamDev. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Redistribution and use in source and/or binary forms, with or without
+ * modification, must retain the above copyright notice and the following
+ * disclaimer.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+.person-card {
+ $avatar-size: 100px;
+ $avatar-size-mobile: 60px;
+
+ position: relative;
+ padding-bottom: 40px;
+
+ .avatar {
+ position: absolute;
+ padding: 0;
+ width: $avatar-size;
+ height: $avatar-size;
+ border-radius: 50%;
+
+ @media (max-width: $phone-large) {
+ width: $avatar-size-mobile;
+ height: $avatar-size-mobile;
+ }
+ }
+
+ .person-info {
+ padding-left: $avatar-size + 20px;
+
+ @media (max-width: $phone-large) {
+ padding-left: $avatar-size-mobile + 20px;
+ }
+
+ .social-networks {
+ padding-bottom: 14px;
+
+ a {
+ padding-right: 16px;
+
+ &:after {
+ display: none;
+ }
+
+ &:hover {
+ text-decoration: none;
+
+ i {
+ color: $gray-500;
+ }
+ }
+ }
+
+ i {
+ font-size: 18px;
+ color: $gray-200;
+ }
+ }
+
+ h3 {
+ padding-top: 4px;
+ }
+ }
+}
diff --git a/_hugo-theme/assets/scss/docs/modules/_sidenav.scss b/_hugo-theme/assets/scss/docs/modules/_sidenav.scss
new file mode 100755
index 0000000..54188db
--- /dev/null
+++ b/_hugo-theme/assets/scss/docs/modules/_sidenav.scss
@@ -0,0 +1,250 @@
+/*!
+ * Copyright 2025, TeamDev. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Redistribution and use in source and/or binary forms, with or without
+ * modification, must retain the above copyright notice and the following
+ * disclaimer.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+$sidenav-link-top-level-font-size: 14px;
+$sidenav-link-font-size: 13px;
+$sidenav-link-color: rgba(0, 0, 0, .54);
+$sidenav-link-color-active: $black;
+$sidenav-link-chevron-border-size: 1px solid rgba(0, 0, 0, .4);
+$sidenav-link-chevron-border-size-active: 1px solid rgba(0, 0, 0, .7);
+$sidenav-link-chevron-size: 6px;
+$sidenav-first-level-left-padding: 24px;
+$sidenav-second-level-left-padding: calc(#{$sidenav-first-level-left-padding} + 16px);
+$sidenav-third-level-left-padding: calc(#{$sidenav-second-level-left-padding} + 16px);
+$sticky-docs-sidenav-width: $doc-sidenav-desktop-width + $sidenav-first-level-left-padding;
+$divider-color: rgba(0, 0, 0, .08);
+
+$sidenav-holder-padding: 32px 24px 32px 16px;
+$sidenav-title-left-padding: 22px;
+
+.doc-sidenav {
+ margin-left: -$sidenav-first-level-left-padding;
+ width: $sticky-docs-sidenav-width;
+ list-style: none;
+
+ @media(max-width: $tablet-large){
+ margin: 0;
+ width: 100%;
+ max-height: none !important; // Unsets calculated max-height for the sticky element on mobile.
+ }
+
+ li {
+ list-style: none;
+ line-height: 22px;
+ }
+
+ .sidenav-link {
+ position: relative;
+ display: block;
+ text-decoration: none;
+ font-size: $sidenav-link-top-level-font-size;
+ padding: 8px $sidenav-first-level-left-padding;
+ color: $sidenav-link-color;
+ font-weight: 400;
+ cursor: pointer;
+
+ @media (max-width: $tablet-large) {
+ padding: 12px $sidenav-first-level-left-padding;
+ }
+
+ // Tree title with chevron.
+ &.tree-title {
+ color: $sidenav-link-color-active;
+
+ &:before {
+ content: '';
+ position: absolute;
+ display: inline-block;
+ border-right: $sidenav-link-chevron-border-size-active;
+ border-bottom: $sidenav-link-chevron-border-size-active;
+ width: $sidenav-link-chevron-size;
+ height: $sidenav-link-chevron-size;
+ top: 14px;
+ left: 8px;
+ transform: rotate(45deg);
+ transition: all .3s ease-in-out;
+
+ @media (max-width: $tablet-large) {
+ top: 18px;
+ }
+ }
+
+ &.collapsed {
+ color: $sidenav-link-color;
+
+ &:before {
+ border-right: $sidenav-link-chevron-border-size;
+ border-bottom: $sidenav-link-chevron-border-size;
+ top: 15px;
+ transform: rotate(-45deg);
+
+ @media (max-width: $tablet-large) {
+ top: 19px;
+ }
+ }
+ }
+ }
+
+ &:hover {
+ background-color: rgba(0, 0, 0, .03);
+ text-decoration: none;
+ border-radius: $border-radius-s;
+ }
+
+ &.active {
+ color: $sidenav-link-color-active;
+ font-weight: 600;
+ }
+ }
+
+ .subnav {
+ .sidenav-link {
+ font-size: $sidenav-link-font-size;
+ padding-left: $sidenav-second-level-left-padding;
+
+ // Tree title with chevron
+ &.tree-title {
+ &:before {
+ left: calc(#{$sidenav-first-level-left-padding} - 3px);
+ }
+ }
+ }
+
+ .subnav {
+ position: relative;
+
+ // Side nav vertical progress bar
+ &:before {
+ content: '';
+ position: absolute;
+ background: $divider-color;
+ display: block;
+ left: $sidenav-second-level-left-padding;
+ top: 13px;
+ bottom: 13px;
+ width: 2px;
+ }
+
+ .sidenav-link {
+ padding-left: $sidenav-third-level-left-padding;
+
+ &.active {
+ &:before {
+ content: '';
+ position: absolute;
+ background: rgba(0, 0, 0, .6);
+ display: block;
+ width: 2px;
+ height: 20px;
+ top: 9px;
+ left: $sidenav-second-level-left-padding;
+ }
+ }
+ }
+ }
+ }
+}
+
+.mobile-sidenav-header {
+ display: none;
+
+ @media(max-width: $doc-sidenav-mobile-breakpoint) {
+ display: flex;
+ justify-content: flex-end;
+
+ .icon-wrapper {
+ position: fixed;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ top: 16px;
+ right: 16px;
+ width: 48px;
+ height: 48px;
+ background-color: rgba(255, 255, 255, .9);
+ border-radius: 50%;
+ cursor: pointer;
+ transition: background-color .2s ease-in-out;
+ z-index: 1;
+
+ &:hover {
+ background-color: rgba(0, 0, 0, .03);
+ }
+
+ .close-icon {
+ @include close-icon;
+ }
+ }
+ }
+}
+
+.mobile-sidenav-holder {
+ @media(max-width: $doc-sidenav-mobile-breakpoint) {
+ display: none;
+ position: fixed !important;
+ background-color: white;
+ top: 0 !important;
+ left: 0;
+ width: 100%;
+ height: 100vh;
+ padding: $sidenav-holder-padding !important;
+ overflow-x: auto;
+ transition: all .4s ease-in-out;
+ z-index: map_get($z-index, 'side-nav-mobile');
+ }
+}
+
+.mobile-sidenav-opened {
+ @media(max-width: $doc-sidenav-mobile-breakpoint) {
+ overflow: hidden;
+ }
+
+ .mobile-sidenav-holder {
+ display: block !important;
+ }
+}
+
+#mobile-sidenav-toggle {
+ display: none;
+
+ @media(max-width: $doc-sidenav-mobile-breakpoint) {
+ display: block;
+ padding: 0 15px;
+ cursor: pointer;
+ color: $main-brand-color;
+ font-size: 15px;
+ margin: 24px 0 8px;
+
+ @media (max-width: $phone-xlarge) {
+ padding: 0;
+ }
+
+ i {
+ margin-right: 8px;
+ font-size: 16px;
+ }
+ }
+}
diff --git a/_hugo-theme/assets/scss/docs/pages/_resources.scss b/_hugo-theme/assets/scss/docs/pages/_resources.scss
new file mode 100644
index 0000000..9f6f48a
--- /dev/null
+++ b/_hugo-theme/assets/scss/docs/pages/_resources.scss
@@ -0,0 +1,35 @@
+/*!
+ * Copyright 2025, TeamDev. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Redistribution and use in source and/or binary forms, with or without
+ * modification, must retain the above copyright notice and the following
+ * disclaimer.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+.resources {
+ h1 {
+ margin-bottom: 6px;
+ }
+
+ h1 + p {
+ margin-bottom: 48px;
+ }
+}
diff --git a/_hugo-theme/assets/scss/fonts/_index.scss b/_hugo-theme/assets/scss/fonts/_index.scss
index a86af40..44600bb 100644
--- a/_hugo-theme/assets/scss/fonts/_index.scss
+++ b/_hugo-theme/assets/scss/fonts/_index.scss
@@ -24,6 +24,9 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+// Common theme styles from the `TeamDev-Ltd/site-commons`.
+@import "../fonts/icon-font";
+
@import "roboto";
@import "pt-serif";
diff --git a/_hugo-theme/config/_default/hugo.toml b/_hugo-theme/config/_default/hugo.toml
new file mode 100644
index 0000000..8648819
--- /dev/null
+++ b/_hugo-theme/config/_default/hugo.toml
@@ -0,0 +1,6 @@
+[params]
+ defaultCodeTheme = 'dark'
+
+# The third-party libraries from the `site-commons`.
+[params.libs.js_cookie]
+ enabled = true
diff --git a/_hugo-theme/content/docs/1/_index.md b/_hugo-theme/content/docs/1/_index.md
new file mode 100644
index 0000000..6fcdd2e
--- /dev/null
+++ b/_hugo-theme/content/docs/1/_index.md
@@ -0,0 +1,37 @@
+---
+title: Documentation
+headline: Documentation
+---
+
+# Welcome
+
+{{% note-block class="lead" %}}
+Welcome to the Spine developer documentation. This page gives
+the overview of the documentation sections.
+{{% /note-block %}}
+
+## [Quick Start](docs/quick-start/)
+In this section you can learn what it's like to develop with Spine by going
+through the code of the [Hello World]({{% get-site-data "spine.examples" %}}/hello/)
+example.
+
+## [Introduction](docs/introduction/)
+This section gives an overview of the development process, the architecture of
+the Spine-based application, information on DDD concepts implemented by the
+framework and how framework users deal with them.
+
+## [Guides](docs/guides/validation)
+This section provides detailed instructions on the framework use.
+
+## [Client Libraries](docs/client-libs/)
+This section provides language-specific guides for building client-side applications.
+
+## [API Reference](docs/reference/)
+This sections provides links to the generated documentation.
+
+## [Examples](docs/examples/)
+This page is the entry point for learning from the code of
+the [example applications]({{% get-site-data "spine.examples" %}}).
+
+## [DDD Resources](docs/resources/)
+A brief selection of learning materials we recommend to the colleagues in DDD.
diff --git a/_hugo-theme/content/docs/1/introduction/_index.md b/_hugo-theme/content/docs/1/introduction/_index.md
new file mode 100644
index 0000000..7eba104
--- /dev/null
+++ b/_hugo-theme/content/docs/1/introduction/_index.md
@@ -0,0 +1,256 @@
+---
+title: Development Process
+headline: Documentation
+---
+
+# Development Process
+
+{{% note-block class="lead" %}}
+Building a solution based on Spine Event Engine framework is an iterative process
+which consists of the stages described in this document.
+{{% /note-block %}}
+
+## Getting domain knowledge
+
+The purpose of this step is to find out what we're going to build and why.
+Consider using [EventStorming](https://eventstorming.com) or another domain discovery
+approach for grasping the knowledge from the experts.
+
+Most likely that the solution would have several [Bounded Contexts](docs/introduction/concepts#bounded-context).
+For each context developers need to define:
+ * Signals
+ - [Events](docs/introduction/concepts#event)
+ - [Commands](docs/introduction/concepts#command)
+ - [Rejections](docs/introduction/concepts#rejection)
+ * Entities
+ - [Aggregates](docs/introduction/concepts#aggregate)
+ - [Process Managers](docs/introduction/concepts#process-manager)
+ - [Projections](docs/introduction/concepts#projection).
+
+It is likely that some of the bits of this picture would change during the process.
+But the whole team, including domain experts, need to have complete understanding of how the
+business works to avoid “surprises” down the road.
+
+We return to learning the domain when we discover inconsistencies in the model,
+or we need more information about how the business works, or the business wants to develop further
+and we need to update the model.
+
+Once we got enough domain knowledge we proceed to the implementation.
+
+## Implementing a Bounded Context
+
+At this stage we select one of the Bounded Contexts for the implementation.
+Each context is developed separately. In this sense it can be seen as a microservice.
+It would be natural to start implementing the context which initiates the business flow.
+
+### Defining data types
+
+Implementation starts from defining data types of the selected context as Protobuf messages.
+
+The first step is to define entity [IDs](docs/introduction/concepts#identifier). For example:
+```proto
+// The identifier for a task.
+message TaskId {
+ string uuid = 1;
+}
+```
+
+Then commands, events, rejections are defined:
+```proto
+// A command to create a new task.
+message CreateTask {
+ TaskId id = 1;
+ string name = 2 [(required) = true];
+ string description = 3;
+}
+```
+
+```proto
+// A new task has been created.
+message TaskCreated {
+ TaskId task = 1;
+ string name = 2 [(required) = true];
+ string description = 3;
+ UserId who_created = 4 [(required) = true];
+}
+```
+
+Then we define states of entities.
+
+```proto
+message Task {
+ option (entity).kind = AGGREGATE;
+ TaskId id = 1;
+ string name = 2 [(required) = true];
+ string description = 3;
+ UserId owner = 4 [(required) = true];
+ DeveloperId assignee = 5;
+}
+```
+
+[Value Objects](docs/introduction/concepts#value-objects) are added when they
+are needed to describe entities or messages like commands or events.
+
+### Adding business logic
+
+The business logic of a Bounded Context is based on [Entities](docs/introduction#entities).
+They handle messages updating the state in response. Entities like `Aggregate`s and
+`ProcessManager`s can generate events. `ProcessManager`s can also generate new commands.
+`Projection`s only consume events.
+
+Updating the state of the domain model in response to messages and generating new messages is
+the “life” of the domain model. Messages are delivered to entities by [Repositories](docs/introduction#repositories).
+
+#### Entities
+
+During this step we create entity classes and add message handling methods to them.
+Code snippets below show `Aggregate` and `Projection` classes with their handler methods.
+
+```java
+final class TaskAggregate
+ extends Aggregate
Application Architecture
+
+{{- /* Strip trailing newline. */ -}}
diff --git a/_hugo-theme/layouts/_markup/render-link.html b/_hugo-theme/layouts/_markup/render-link.html
new file mode 100644
index 0000000..ecf4176
--- /dev/null
+++ b/_hugo-theme/layouts/_markup/render-link.html
@@ -0,0 +1,25 @@
+{{- $link := .Destination }}
+{{- $isMailto := strings.HasPrefix $link "mailto:" -}}
+{{- $isAbsolute := strings.HasPrefix $link "http" -}}
+{{- $isSamePageAnchor := strings.HasPrefix $link "#" -}}
+
+{{- $skipNofollow := partial "functions/whitelist-checker.html" $link -}}
+{{- $isExternalLink := partial "functions/is-external-link.html" $link -}}
+
+{{- if or $isAbsolute $isSamePageAnchor -}}
+ {{- $link = $link | safeURL -}}
+{{- else if (not $isMailto) }}
+ {{- $link = partial "functions/get-doc-link.html" (dict
+ "link" $link
+ "page" .Page
+ ) -}}
+{{- end -}}
+
+{{ .Text | safeHTML }}
+{{- /* Strip trailing newline. */ -}}
diff --git a/_hugo-theme/layouts/_partials/docs/components/bottom-nav/functions/get-page.html b/_hugo-theme/layouts/_partials/docs/components/bottom-nav/functions/get-page.html
new file mode 100644
index 0000000..ae2d743
--- /dev/null
+++ b/_hugo-theme/layouts/_partials/docs/components/bottom-nav/functions/get-page.html
@@ -0,0 +1,41 @@
+
+
+{{ $page := .page_context }}
+{{ $item := .item_context }}
+
+{{ $currentVersion := partial "functions/get-doc-version.html" $page }}
+{{ $filePath := printf "docs/%s/%s" $currentVersion.short $item.file_path }}
+{{ $pageURL := "" }}
+{{ $pageTitle := $item.page }}
+
+{{ with site.GetPage $filePath }}
+ {{ $pageURL = .RelPermalink }}
+{{ end }}
+
+{{ $pageItem := dict "url" $pageURL "title" $pageTitle }}
+
+{{ return $pageItem }}
diff --git a/_hugo-theme/layouts/_partials/docs/components/bottom-nav/functions/get-pages.html b/_hugo-theme/layouts/_partials/docs/components/bottom-nav/functions/get-pages.html
new file mode 100644
index 0000000..072d123
--- /dev/null
+++ b/_hugo-theme/layouts/_partials/docs/components/bottom-nav/functions/get-pages.html
@@ -0,0 +1,68 @@
+
+
+
+
+{{ $root := .context }}
+{{ $sidenav := .sidenav }}
+{{ $currentURL := .current_url }}
+
+{{ $root.Scratch.Set "bottomNavPages" (slice) }}
+{{ $root.Scratch.Set "bottomNavCurrentIndex" -1 }}
+
+{{ range $sidenav }}
+ {{ template "get-bottom-nav-pages" (dict "root" $root "node" .) }}
+{{ end }}
+
+{{ define "get-bottom-nav-pages" }}
+ {{ $root := .root }}
+ {{ $node := .node }}
+ {{ with $node.children }}
+ {{ range . }}
+ {{ template "get-bottom-nav-pages" (dict "root" $root "node" .) }}
+ {{ end }}
+ {{ else }}
+ {{ if or $node.file_path (eq $node.file_path "") }}
+ {{ $page := partial "docs/components/bottom-nav/functions/get-page.html" (dict
+ "page_context" $root
+ "item_context" $node
+ ) }}
+ {{ if $page.url }}
+ {{ $root.Scratch.Add "bottomNavPages" (slice $page) }}
+ {{ end }}
+ {{ end }}
+ {{ end }}
+{{ end }}
+
+{{ $pages := $root.Scratch.Get "bottomNavPages" }}
+
+{{ range $i, $page := $pages }}
+ {{ if in $currentURL $page.url }}
+ {{ $root.Scratch.Set "bottomNavCurrentIndex" $i }}
+ {{ end }}
+{{ end }}
diff --git a/_hugo-theme/layouts/_partials/docs/components/bottom-nav/next-prev-nav.html b/_hugo-theme/layouts/_partials/docs/components/bottom-nav/next-prev-nav.html
new file mode 100644
index 0000000..9315cc4
--- /dev/null
+++ b/_hugo-theme/layouts/_partials/docs/components/bottom-nav/next-prev-nav.html
@@ -0,0 +1,64 @@
+
+
+{{ $currentURL := .RelPermalink }}
+{{ $currentVersion := partial "functions/get-doc-version.html" . }}
+{{ $versionData := index site.Data.docs $currentVersion.short }}
+
+{{ if $versionData }}
+ {{ $sidenav := $versionData.sidenav }}
+ {{ if $sidenav }}
+ {{ partial "docs/components/bottom-nav/functions/get-pages" (dict
+ "context" .
+ "sidenav" $sidenav
+ "current_url" $currentURL
+ ) }}
+ {{ $pages := .Scratch.Get "bottomNavPages" }}
+ {{ $index := .Scratch.Get "bottomNavCurrentIndex" }}
+
+ {{ end }}
+ {{ .Scratch.Delete "bottomNavPages" }}
+ {{ .Scratch.Delete "bottomNavCurrentIndex" }}
+{{ end }}
diff --git a/_hugo-theme/layouts/_partials/docs/components/content-layout/three-column.html b/_hugo-theme/layouts/_partials/docs/components/content-layout/three-column.html
new file mode 100644
index 0000000..cd3b16a
--- /dev/null
+++ b/_hugo-theme/layouts/_partials/docs/components/content-layout/three-column.html
@@ -0,0 +1,50 @@
+
+
+
+ {{ range $sidenavData.sidenav }}
+ {{ if .children }}
+ {{ partial "docs/components/sidenav/section.html" (dict
+ "page_context" $page
+ "item_context" .
+ ) }}
+ {{ else }}
+ {{ partial "docs/components/sidenav/page.html" (dict
+ "page_context" $page
+ "item_context" .
+ ) }}
+ {{ end }}
+ {{ end }}
+
+ {{ end }}
+{{ end }}
diff --git a/_hugo-theme/layouts/_partials/docs/head/code-theme.html b/_hugo-theme/layouts/_partials/docs/head/code-theme.html
new file mode 100644
index 0000000..f61cd31
--- /dev/null
+++ b/_hugo-theme/layouts/_partials/docs/head/code-theme.html
@@ -0,0 +1,38 @@
+
+
+
+{{ $lightTheme := "code-theme/light.css" }}
+{{ $darkTheme := "code-theme/dark.css" }}
+{{ $defaultCodeTheme := $darkTheme }}
+{{ if eq site.Params.defaultCodeTheme "light" }}
+ {{ $defaultCodeTheme = $lightTheme }}
+{{ end }}
+
diff --git a/_hugo-theme/layouts/_partials/docs/head/icon-font.html b/_hugo-theme/layouts/_partials/docs/head/icon-font.html
new file mode 100644
index 0000000..a01cd0c
--- /dev/null
+++ b/_hugo-theme/layouts/_partials/docs/head/icon-font.html
@@ -0,0 +1,27 @@
+
+
+
diff --git a/_hugo-theme/layouts/_partials/functions/get-body-class.html b/_hugo-theme/layouts/_partials/functions/get-body-class.html
new file mode 100644
index 0000000..51b8b65
--- /dev/null
+++ b/_hugo-theme/layouts/_partials/functions/get-body-class.html
@@ -0,0 +1,53 @@
+
+
+
+
+{{ if eq .Kind "home" }}
+ {{ .Scratch.Set "bodyClass" "home" }}
+{{ else if eq .Kind "404" }}
+ {{ .Scratch.Set "bodyClass" "error-pages" }}
+{{ else if eq .Kind "page" }}
+ {{ if in .Type "/" }}
+ {{ $type := replace .Type "/" " " }}
+ {{ .Scratch.Set "bodyClass" (print " " $type) }}
+ {{ else }}
+ {{ .Scratch.Set "bodyClass" (print " " .Type) }}
+ {{ end }}
+{{ else }}
+ {{ $type := replace .Type "/" " " }}
+ {{ .Scratch.Set "bodyClass" $type }}
+{{ end }}
+
+{{ $bodyClass := .Scratch.Get "bodyClass" }}
+
+{{ with .Params.bodyclass }}
+ {{ $bodyClass = . }}
+{{ end }}
+
+{{ return $bodyClass }}
diff --git a/_hugo-theme/layouts/_partials/functions/get-doc-category.html b/_hugo-theme/layouts/_partials/functions/get-doc-category.html
new file mode 100644
index 0000000..cee4bc2
--- /dev/null
+++ b/_hugo-theme/layouts/_partials/functions/get-doc-category.html
@@ -0,0 +1,39 @@
+
+
+
+
+{{ $filePath := "" }}
+{{ if $.File }}
+ {{ $filePath = .File.Path }}
+{{ end }}
+{{ $pathDir := path.Dir $filePath }}
+{{ $pathBase := path.Base $pathDir }}
+{{ return $pathBase }}
diff --git a/_hugo-theme/layouts/_partials/functions/get-doc-link.html b/_hugo-theme/layouts/_partials/functions/get-doc-link.html
new file mode 100644
index 0000000..61bb6f9
--- /dev/null
+++ b/_hugo-theme/layouts/_partials/functions/get-doc-link.html
@@ -0,0 +1,47 @@
+
+
+
+
+{{ $link := .link }}
+{{ $pageContext := .page }}
+
+{{ $currentVersion := partial "functions/get-doc-version.html" $pageContext }}
+{{ if and (findRE `^/?docs/[^0-9][^ ]*` $link) (not (findRE `^/?docs/[0-9]+(/|$)` $link)) }}
+ {{ $link = replaceRE "docs" $currentVersion.path $link }}
+{{ end -}}
+
+{{ $link = $link | relURL }}
+{{ return $link }}
diff --git a/_hugo-theme/layouts/_partials/functions/get-doc-section.html b/_hugo-theme/layouts/_partials/functions/get-doc-section.html
new file mode 100644
index 0000000..842edac
--- /dev/null
+++ b/_hugo-theme/layouts/_partials/functions/get-doc-section.html
@@ -0,0 +1,39 @@
+
+
+
+
+{{ $segments := slice }}
+{{ if $.File }}
+ {{ $segments = split .File.Path "/" }}
+{{ end }}
+{{ $section := index $segments 2 }}
+{{ return $section }}
diff --git a/_hugo-theme/layouts/_partials/functions/get-doc-version.html b/_hugo-theme/layouts/_partials/functions/get-doc-version.html
new file mode 100644
index 0000000..48ce201
--- /dev/null
+++ b/_hugo-theme/layouts/_partials/functions/get-doc-version.html
@@ -0,0 +1,51 @@
+
+
+
+
+{{ $versions := site.Data.versions }}
+{{ $mainVersion := index (where $versions "is_main" true) 0 }}
+{{ $currentPath := "" }}
+{{ with $.Page.File }}
+ {{ $currentPath = .Path }}
+{{ end }}
+{{ $currentVersion := "" }}
+{{ range $versions }}
+ {{ if in $currentPath (printf "docs/%s/" .short) }}
+ {{ $currentVersion = . }}
+ {{ end }}
+{{ end }}
+{{ if not $currentVersion }}
+ {{ $currentVersion = $mainVersion }}
+{{ end }}
+{{ return $currentVersion }}
diff --git a/_hugo-theme/layouts/_partials/functions/get-full-version-name.html b/_hugo-theme/layouts/_partials/functions/get-full-version-name.html
new file mode 100644
index 0000000..ae750e5
--- /dev/null
+++ b/_hugo-theme/layouts/_partials/functions/get-full-version-name.html
@@ -0,0 +1,40 @@
+
+
+
+{{ $currentVersion := . }}
+{{ $fullName := "" }}
+{{ if $currentVersion.full_i18n_key }}
+ {{ $fullName = i18n $currentVersion.full_i18n_key }}
+{{ else }}
+ {{ $fullName = $currentVersion.full }}
+{{ end }}
+{{ return $fullName }}
diff --git a/_hugo-theme/layouts/_partials/functions/get-sidenav-title.html b/_hugo-theme/layouts/_partials/functions/get-sidenav-title.html
new file mode 100644
index 0000000..50c0491
--- /dev/null
+++ b/_hugo-theme/layouts/_partials/functions/get-sidenav-title.html
@@ -0,0 +1,40 @@
+
+
+
+
+{{ $sidenavTitle := "" }}
+{{ if .Params.sidenav_title }}
+ {{ $sidenavTitle = .Params.sidenav_title }}
+{{ else if .Params.Title }}
+ {{ $sidenavTitle = .Params.Title }}
+{{ else }}
+ {{ $sidenavTitle = "No sidenav_title parameter" }}
+{{ end }}
+{{ return $sidenavTitle }}
diff --git a/_hugo-theme/layouts/_partials/functions/is-external-link.html b/_hugo-theme/layouts/_partials/functions/is-external-link.html
new file mode 100644
index 0000000..0a290e2
--- /dev/null
+++ b/_hugo-theme/layouts/_partials/functions/is-external-link.html
@@ -0,0 +1,32 @@
+
+
+
+
+{{ $link := . }}
+
+{{ $isExternalLink := strings.HasPrefix $link "http" }}
+{{ return $isExternalLink }}
diff --git a/_hugo-theme/layouts/_partials/scripts/body/baseurl.html b/_hugo-theme/layouts/_partials/scripts/body/baseurl.html
new file mode 100644
index 0000000..c9be212
--- /dev/null
+++ b/_hugo-theme/layouts/_partials/scripts/body/baseurl.html
@@ -0,0 +1,36 @@
+
+
+
+
diff --git a/_hugo-theme/layouts/_partials/scripts/head/jquery.html b/_hugo-theme/layouts/_partials/scripts/head/jquery.html
new file mode 100644
index 0000000..5bfb2d5
--- /dev/null
+++ b/_hugo-theme/layouts/_partials/scripts/head/jquery.html
@@ -0,0 +1,4 @@
+
diff --git a/_hugo-theme/layouts/_shortcodes/book-card.html b/_hugo-theme/layouts/_shortcodes/book-card.html
new file mode 100644
index 0000000..66653a8
--- /dev/null
+++ b/_hugo-theme/layouts/_shortcodes/book-card.html
@@ -0,0 +1,44 @@
+{{- /*
+A component that displays the clickable book card.
+
+Parameters:
+ * `image`. The book cover image name. The image should be placed inside `static`.
+ * `title`. The book title.
+ * `subtitle`. An optional book subtitle.
+ * `author`. The book author.
+ * `book_url`. The URL on a store.
+*/ -}}
+
+{{ $image := .Get "image" }}
+{{ $title := .Get "title" }}
+{{ $subtitle := .Get "subtitle" }}
+{{ $author := .Get "author" }}
+{{ $bookURL := .Get "book_url" }}
+
+{{ $image = print "img/docs/resources/books/" $image }}
+
+
+
+
{{ $title | markdownify }}
+ {{ with $subtitle }}
+
+
{{ $name }}
+
+