diff --git a/Makefile b/Makefile index 1b128f1f9..45eaae72a 100644 --- a/Makefile +++ b/Makefile @@ -28,9 +28,6 @@ test: build: ruby-version-check bundle exec jekyll build --config jekyll.yml --profile -serve: - yarn run dev - # Cleans up all temp files in the build. # Run `make clean` locally whenever you're updating dependencies, or to help # troubleshoot build issues. @@ -41,5 +38,11 @@ clean: -rm -rf .jekyll-cache/vite kill-ports: + @echo '[DEPRECATED]: This target is deprecated because the "run" target now correctly handles kill signals, closing these ports automatically.' + @printf " Existing Jekyll Processes on Port 4000 : %s\n" "$$(lsof -ti:4000 | tr '\n' ' ' || echo 'None')" + @printf " Existing Vite Processes on Port 3036 : %s\n" "$$(lsof -ti:3036 | tr '\n' ' ' || echo 'None')" + @echo 'If you still want to terminate these processes, use the "kill-ports-force" target. [WARNING]: If you are using Firefox, this action may unexpectedly kill your browser processes.' + +kill-ports-force: @JEKYLL_PROCESS=$$(lsof -ti:4000) && kill -9 $$JEKYLL_PROCESS || true @VITE_PROCESS=$$(lsof -ti:3036) && kill -9 $$VITE_PROCESS || true diff --git a/Procfile b/Procfile index 4a2b9ed16..653170eaf 100644 --- a/Procfile +++ b/Procfile @@ -1,2 +1,2 @@ -vite: bin/vite dev -jekyll: bin/jekyll-vite wait && bundle exec jekyll serve --livereload --config jekyll-dev.yml +netlify: npx netlify dev +jekyll: bundle exec jekyll serve --livereload --config jekyll-dev.yml diff --git a/app/_assets/javascripts/navbar.js b/app/_assets/javascripts/navbar.js index 3f6ce507c..a46477484 100644 --- a/app/_assets/javascripts/navbar.js +++ b/app/_assets/javascripts/navbar.js @@ -30,9 +30,7 @@ export default class NavBar { } }); - this.sidebarButton.addEventListener('click', (event) => { - this.toggleSidebar(); - }); + this.sidebarButton?.addEventListener('click', () => this.toggleSidebar()); } toggleSidebar(toggle) { diff --git a/app/_assets/javascripts/prism.js b/app/_assets/javascripts/prism.js index e003becc7..2ddb6ed1b 100644 --- a/app/_assets/javascripts/prism.js +++ b/app/_assets/javascripts/prism.js @@ -1,27 +1,33 @@ import Prism from 'prismjs' -import 'prismjs/plugins/line-numbers/prism-line-numbers.min.js' -import 'prismjs/components/prism-bash.min.js' -import 'prismjs/components/prism-systemd.min.js' -import 'prismjs/components/prism-yaml.min.js' -import 'prismjs/components/prism-json.min.js' - -import 'prismjs/plugins/show-language/prism-show-language.min.js' -import 'prismjs/plugins/autoloader/prism-autoloader.min.js' -import 'prismjs/plugins/toolbar/prism-toolbar.min.js' -import 'prismjs/plugins/toolbar/prism-toolbar.min.css' -import "prismjs/plugins/copy-to-clipboard/prism-copy-to-clipboard.min.js"; - -import 'prismjs/themes/prism.min.css' -import "prismjs/themes/prism-tomorrow.min.css"; -import 'prismjs/plugins/line-numbers/prism-line-numbers.min.css' +import 'prismjs/components/prism-bash.js' +import 'prismjs/components/prism-systemd.js' +import 'prismjs/components/prism-yaml.js' +import 'prismjs/components/prism-json.js' +import 'prismjs/plugins/autoloader/prism-autoloader.js' +import 'prismjs/plugins/line-numbers/prism-line-numbers.js' +import 'prismjs/plugins/toolbar/prism-toolbar.js' +import 'prismjs/plugins/copy-to-clipboard/prism-copy-to-clipboard.js' +// styles +import 'prismjs/themes/prism.css' +import 'prismjs/plugins/line-numbers/prism-line-numbers.css' +import 'prismjs/plugins/toolbar/prism-toolbar.css' import '@/styles/prismjs/prism-vs.scss' Prism.highlightAll(); -document.addEventListener('DOMContentLoaded', (event) => { +const icon = ` + + + + + + +Copied! +`; + +document.addEventListener('DOMContentLoaded', () => { document.querySelectorAll('.copy-to-clipboard-button').forEach((elem) => { - let icon = ' '; - elem.innerHTML = icon + 'Copied!'; + elem.innerHTML = icon; }); }); diff --git a/app/_assets/javascripts/sidebar.js b/app/_assets/javascripts/sidebar.js index 7e34d6c44..656197ca1 100644 --- a/app/_assets/javascripts/sidebar.js +++ b/app/_assets/javascripts/sidebar.js @@ -3,7 +3,6 @@ export default class Sidebar { this.elem = document.querySelector('.theme-container:not(.no-sidebar) #sidebar'); if (this.elem !== null) { - this.groups = Array.from( this.elem.querySelectorAll('.sidebar-links li .sidebar-group') ); @@ -56,35 +55,26 @@ export default class Sidebar { expandActiveGroup() { const currentPath = window.location.pathname; const activeLink = this.elem.querySelector(`a[href^='${currentPath}']`); - if (activeLink) { - const topLevelGroup = activeLink.closest(`.sidebar-group.depth-0`); - if (topLevelGroup !== null) { - this.toggleGroup(topLevelGroup); + if (activeLink) { + let currentGroup = activeLink.closest('.sidebar-group'); - const nestedGroup = activeLink.closest(`.sidebar-group.depth-1`); - if (nestedGroup !== null) { - this.toggleGroup(nestedGroup); - nestedGroup.scrollIntoView({ behavior: "smooth", block: "center" }); - } else { - topLevelGroup.scrollIntoView({ behavior: "smooth", block: "center" }); - } + // Traverse up and expand each nested group until reaching the top level + while (currentGroup) { + this.toggleGroup(currentGroup, false); + currentGroup = currentGroup.parentNode.closest('.sidebar-group'); } + + this.elem.querySelector('.sidebar-links')?.scroll({ top: activeLink.offsetTop, behavior: 'smooth' }); } } setActiveLink() { - let currentPath = window.location.pathname; - if (window.location.hash) { - currentPath += window.location.hash; - } + const currentPath = `${window.location.pathname}${window.location.hash || ''}`; + const activeLink = this.elem.querySelector(`a[href='${currentPath}']`); - let activeElement = this.elem - .querySelector(`a[href='${currentPath}']`); - - if (activeElement !== null) { - activeElement.classList - .add('active'); + if (activeLink) { + activeLink.classList.add('active'); } } } diff --git a/app/_assets/styles/custom/components/_sidebar.scss b/app/_assets/styles/custom/components/_sidebar.scss index a3906a984..e2f7bfd06 100644 --- a/app/_assets/styles/custom/components/_sidebar.scss +++ b/app/_assets/styles/custom/components/_sidebar.scss @@ -44,6 +44,12 @@ $sidebar-button-left-spacing: 1.5rem; .nav-links { display: block; } + + .sidebar-top-section { + padding-bottom: 1rem; + background: #fff; + mask-image: linear-gradient(to bottom, #fff 90%, transparent); + } } .sidebar-links { @@ -91,9 +97,16 @@ a.sidebar-link { .sidebar { position: sticky; top: 0; - padding-top: $navbarHeight; bottom: 0; - height: calc(100vh - #{$navbarHeight}); + height: 100vh; + } + + .sidebar .sidebar-top-section { + position: sticky; + top: 0; + z-index: 1; + padding-top: $navbarHeight; + padding-bottom: 3rem; } .theme-container.no-sidebar .sidebar { diff --git a/app/_assets/styles/custom/components/_version-alert.scss b/app/_assets/styles/custom/components/_version-alert.scss index 8bc4a239d..9a10b488f 100644 --- a/app/_assets/styles/custom/components/_version-alert.scss +++ b/app/_assets/styles/custom/components/_version-alert.scss @@ -4,9 +4,9 @@ // This is the component that alerts the user if they are // viewing documentation for an older version, and provides // them with a link to the latest version. -// +// -$version-alert-max-width: 740px; +$version-alert-max-width: $contentWidth; $version-alert-margin: $navbarHeight auto 0 auto; $version-alert-padding: 2rem 2.5rem 0 2rem; $version-alert-title-font-size: 1.5rem; @@ -14,6 +14,7 @@ $version-alert-title-margin: 0; $version-alert-text-margin: 0; $version-alert-inner-padding: 1.5rem; $version-alert-inner-margin: 0; +$version-alert-inner-margin-large: 0 0 0 0.5rem; $version-alert-link-color: $color-5; .version-alert { @@ -24,6 +25,9 @@ $version-alert-link-color: $color-5; .custom-block { padding: $version-alert-inner-padding; margin: $version-alert-inner-margin; + @media (min-width: $MQMobile) { + margin: $version-alert-inner-margin-large; + } a { text-decoration: underline; diff --git a/app/_assets/styles/prismjs/prism-ghcolors.scss b/app/_assets/styles/prismjs/prism-ghcolors.scss deleted file mode 100644 index 4f27f5bb4..000000000 --- a/app/_assets/styles/prismjs/prism-ghcolors.scss +++ /dev/null @@ -1,126 +0,0 @@ -/** - * GHColors theme by Avi Aryan (http://aviaryan.in) - * Inspired by Github syntax coloring - */ - -code[class*="language-"], -pre[class*="language-"] { - color: #393a34; - font-family: "Consolas", "Bitstream Vera Sans Mono", "Courier New", Courier, - monospace; - direction: ltr; - text-align: left; - white-space: pre; - word-spacing: normal; - word-break: normal; - font-size: 0.95em; - line-height: 1.2em; - - -moz-tab-size: 4; - -o-tab-size: 4; - tab-size: 4; - - -webkit-hyphens: none; - -moz-hyphens: none; - -ms-hyphens: none; - hyphens: none; -} - -pre[class*="language-"]::-moz-selection, -pre[class*="language-"] ::-moz-selection, -code[class*="language-"]::-moz-selection, -code[class*="language-"] ::-moz-selection { - background: #b3d4fc; -} - -pre[class*="language-"]::selection, -pre[class*="language-"] ::selection, -code[class*="language-"]::selection, -code[class*="language-"] ::selection { - background: #b3d4fc; -} - -/* Code blocks */ -pre[class*="language-"] { - padding: 1em; - margin: 0.5em 0; - overflow: auto; - border: 1px solid #dddddd; - background-color: white; -} - -:not(pre) > code[class*="language-"], -pre[class*="language-"] { -} - -/* Inline code */ -:not(pre) > code[class*="language-"] { - padding: 0.2em; - padding-top: 1px; - padding-bottom: 1px; - background: #f8f8f8; - border: 1px solid #dddddd; -} - -.token.comment, -.token.prolog, -.token.doctype, -.token.cdata { - color: #999988; - font-style: italic; -} - -.token.namespace { - opacity: 0.7; -} - -.token.string, -.token.attr-value { - color: #e3116c; -} -.token.punctuation, -.token.operator { - color: #393a34; /* no highlight */ -} - -.token.entity, -.token.url, -.token.symbol, -.token.number, -.token.boolean, -.token.variable, -.token.constant, -.token.property, -.token.regex, -.token.inserted { - color: #36acaa; -} - -.token.atrule, -.token.keyword, -.token.attr-name, -.language-autohotkey .token.selector { - color: #00a4db; -} - -.token.function, -.token.deleted, -.language-autohotkey .token.tag { - color: #9a050f; -} - -.token.tag, -.token.selector, -.language-autohotkey .token.keyword { - color: #00009f; -} - -.token.important, -.token.function, -.token.bold { - font-weight: bold; -} - -.token.italic { - font-style: italic; -} diff --git a/app/_assets/styles/prismjs/prism-vs.scss b/app/_assets/styles/prismjs/prism-vs.scss index 5b5462c5a..23981fc36 100644 --- a/app/_assets/styles/prismjs/prism-vs.scss +++ b/app/_assets/styles/prismjs/prism-vs.scss @@ -128,12 +128,12 @@ .token.property, .token.regex, .token.entity { - color: #ff0000; + color: #ff0000; } .token.directive.tag .tag { - background: #ffff00; - color: #393A34; + background: #ffff00; + color: #393A34; } /* overrides color-values for the Line Numbers plugin @@ -154,7 +154,7 @@ */ .line-highlight { background: rgba(193, 222, 241, 0.2); - background: -webkit-linear-gradient(left, rgba(193, 222, 241, 0.2) 70%, rgba(221, 222, 241, 0)); + background: -webkit-linear-gradient(to left, rgba(193, 222, 241, 0.2) 70%, rgba(221, 222, 241, 0)); background: linear-gradient(to right, rgba(193, 222, 241, 0.2) 70%, rgba(221, 222, 241, 0)); } @@ -162,20 +162,33 @@ background: none !important; box-shadow: none !important; - svg { - bottom: 7.5px; - margin-right: 15px; - } - &[data-copy-state='copy'] span:nth-child(2) { display: none; } + &[data-copy-state='copy-success'] span:nth-child(2) { color: #393a34; position: absolute; + top: 15px; + right: 40px; font-size: 13.6px; line-height: 6.8px; - right: 50px; transition: opacity .5s; } + + &:hover span:first-child { + opacity: 0.7; + } } + +div[class*="language-"] { + &::before { + opacity: 1; + transition: opacity .25s ease-in-out; + } + + &:hover::before, &:focus-within::before { + opacity: 0; + transition: opacity .25s ease-in-out; + } +} diff --git a/app/_assets/styles/vuepress-core/code.scss b/app/_assets/styles/vuepress-core/code.scss index dcb23b146..b90661cb4 100644 --- a/app/_assets/styles/vuepress-core/code.scss +++ b/app/_assets/styles/vuepress-core/code.scss @@ -178,6 +178,10 @@ div[class~='language-php']:before { content: 'php'; } +pre[class*='language-'].line-numbers { + padding-left: 4.8em !important; +} + .line-numbers .line-numbers-rows { border: none !important; left: -4.8em !important; diff --git a/app/_assets/styles/vuepress-core/index.scss b/app/_assets/styles/vuepress-core/index.scss index 71517e851..3556aebbe 100644 --- a/app/_assets/styles/vuepress-core/index.scss +++ b/app/_assets/styles/vuepress-core/index.scss @@ -52,6 +52,14 @@ body { @include wrapper; > *:first-child { + margin-top: 2rem; + + @media (min-width: $MQMobile) { + margin-top: 3rem; + } + } + + &:not(.with-alert) > *:first-child { margin-top: $navbarHeight; } @@ -122,7 +130,7 @@ h1, h2, h3, h4, h5, h6 { font-weight: 600; line-height: 1.25; - #{$contentClass}:not(.custom) > & { + #{$contentClass}:not(.custom):not(.with-alert) > & { margin-top: 0.5rem - $navbarHeight; padding-top: $navbarHeight + 1rem; margin-bottom: 0; diff --git a/app/_assets/styles/vuepress-core/page.scss b/app/_assets/styles/vuepress-core/page.scss index 6074b816a..b75bdec69 100644 --- a/app/_assets/styles/vuepress-core/page.scss +++ b/app/_assets/styles/vuepress-core/page.scss @@ -1,6 +1,10 @@ .page { padding-bottom: 2rem; display: block; + + .content__default.with-alert { + padding-top: 0; + } } .page-edit { diff --git a/app/_assets/styles/vuepress-core/sidebar.scss b/app/_assets/styles/vuepress-core/sidebar.scss index 6be9cc5ee..c71171a54 100644 --- a/app/_assets/styles/vuepress-core/sidebar.scss +++ b/app/_assets/styles/vuepress-core/sidebar.scss @@ -23,6 +23,7 @@ } & > .sidebar-links { padding: 1.5rem 0; + margin-top: -3rem; & > li > a.sidebar-link { font-size: 1.1em; @@ -45,6 +46,7 @@ } & > .sidebar-links { padding: 1rem 0; + margin-top: -1rem; } } } diff --git a/app/_includes/sidebar.html b/app/_includes/sidebar.html index c31025847..0f5fda501 100644 --- a/app/_includes/sidebar.html +++ b/app/_includes/sidebar.html @@ -1,7 +1,8 @@ diff --git a/app/_includes/version_alert.html b/app/_includes/version_alert.html index 27d40dd39..6a5891e0f 100644 --- a/app/_includes/version_alert.html +++ b/app/_includes/version_alert.html @@ -4,26 +4,24 @@ {% assign latest_version_path = "docs/" | append: latest_version | append: '/' | append: page_path | append: '.md' %} {% assign latest_page = site.pages | find: 'path', latest_version_path %} -{% if current_version and current_version != site.data.latest_version.release %} -
-
-
-

Careful!

- {% if current_version == 'dev' %} -

You are browsing documentation for the next version of {{ site.title }}. Use this version at your own risk.

- {% else %} -

You are browsing documentation for a version of {{ site.title }} that is not the latest release.

- {% endif %} +{%- if current_version and current_version != site.data.latest_version.release -%} +
+
+

Careful!

+ {% if current_version == 'dev' %} +

You are browsing documentation for the next version of {{ site.title }}. Use this version at your own risk.

+ {% else %} +

You are browsing documentation for a version of {{ site.title }} that is not the latest release.

+ {% endif %} - {% if latest_page != nil %} -

- Go here to browse the documentation for the latest version. -

- {% endif %} - {% if current_version != 'dev' %} -

Looking for even older versions? Learn more.

- {% endif %} -
-
+ {% if latest_page != nil %} +

+ Go here to browse the documentation for the latest version. +

+ {% endif %} + {% if current_version != 'dev' %} +

Looking for even older versions? Learn more.

+ {% endif %}
-{% endif %} +
+{% endif -%} diff --git a/app/_layouts/page.html b/app/_layouts/page.html index 0e5d6e1c4..d7f16a784 100644 --- a/app/_layouts/page.html +++ b/app/_layouts/page.html @@ -1,10 +1,18 @@ --- layout: default --- + +{% capture classes -%} +theme-default-content +content__default +{% if page.version and page.version != site.data.latest_version.release %} with-alert{% endif %} +{% if page.doc %} doc{% endif -%} +{%- endcapture %} +
{% include version_alert.html %} -
+
{% if page.doc %}

{{ page.title }}

{% endif %} diff --git a/bin/jekyll-vite b/bin/jekyll-vite deleted file mode 100755 index 1d5405ca6..000000000 --- a/bin/jekyll-vite +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env ruby -# frozen_string_literal: true - -require 'bundler/setup' -require 'socket' -require 'vite_ruby' - -def wait_for_dev_server(timeout_at:) - while Time.now <= timeout_at - return if ViteRuby.instance.dev_server_running? - - sleep 1 - end - raise "Timeout: vite dev server is not running on #{ ViteRuby.config.host_with_port }" -end - -case cmd = ARGV[0] -when 'wait' - puts 'Waiting for vite dev server to start' - wait_for_dev_server(timeout_at: Time.now + (ENV['VITE_TIMEOUT'] || 10).to_i) -else - raise ArgumentError, "unknown command #{ cmd.inspect }" -end diff --git a/bin/vite b/bin/vite deleted file mode 100755 index 11fb801e6..000000000 --- a/bin/vite +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env ruby -# frozen_string_literal: true - -# -# This file was generated by Bundler. -# -# The application 'vite' is installed as part of a gem, and -# this file is here to facilitate running it. -# - -require "pathname" -ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", - Pathname.new(__FILE__).realpath) - -bundle_binstub = File.expand_path("../bundle", __FILE__) - -if File.file?(bundle_binstub) - if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ - load(bundle_binstub) - else - abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. -Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") - end -end - -require "rubygems" -require "bundler/setup" - -load Gem.bin_path("vite_ruby", "vite") diff --git a/jekyll-dev.yml b/jekyll-dev.yml index c345455d5..49326ae3e 100644 --- a/jekyll-dev.yml +++ b/jekyll-dev.yml @@ -12,6 +12,17 @@ kramdown: disable: true incremental: true +exclude: + - .netlify/ + - .jekyll-cache/ + - Gemfile + - Gemfile.lock + - node_modules/ + # Styles in _assets/styles/ are managed and hot-reloaded by Vite, so Jekyll + # doesn't need to process them. This prevents unnecessary browser refreshes + # triggered by Jekyll + - _assets/styles/ + # Site settings logo: "/assets/images/brand/kuma-logo-new.svg" repo: "https://github.com/kumahq/kuma" diff --git a/netlify.toml b/netlify.toml index 89bc02401..b34df5c81 100644 --- a/netlify.toml +++ b/netlify.toml @@ -10,6 +10,8 @@ JEKYLL_ENV = "preview" [dev] + # netlify automatically figures out and starts the framework, which in our case + # is vite autoLaunch = false targetPort = 4000 diff --git a/package.json b/package.json index 2ecd995d5..6e5be8aef 100644 --- a/package.json +++ b/package.json @@ -2,11 +2,6 @@ "name": "kuma-website", "description": "The website and docs for Kuma.", "author": "Kong Inc.", - "scripts": { - "dev": "netlify dev", - "test": "jest", - "test-coverage": "jest --coverage" - }, "dependencies": { "@kongponents/ktabs": "^0.1.2", "@kongponents/styles": "^0.2.0", diff --git a/vite.config.ts b/vite.config.ts index 7a3e1fe45..67922d588 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -19,8 +19,19 @@ export default defineConfig({ }), ], css: { + devSourcemap: true, preprocessorOptions: { - scss: { additionalData: ["@import '@/styles/custom/config/variables', '@/styles/vuepress-core/config', '@/styles/custom/config/fonts', '@/styles/custom/config/mixins', '@/styles/custom/base/forms';"] }, + scss: { + api: 'modern', + additionalData: [ + '@import', + "'@/styles/custom/config/variables',", + "'@/styles/vuepress-core/config',", + "'@/styles/custom/config/fonts',", + "'@/styles/custom/config/mixins',", + "'@/styles/custom/base/forms';", + ].join(' ') + }, }, }, })