From 8b9e5144f7af3bb0578d80ed619dd0743d0d5f0f Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 24 Jul 2024 11:22:02 +0200 Subject: Adding upstream version 5.3.3+dfsg. Signed-off-by: Daniel Baumann --- .cspell.json | 1 + .eslintrc.json | 4 +- .github/workflows/browserstack.yml | 6 +- .github/workflows/bundlewatch.yml | 6 +- .github/workflows/calibreapp-image-actions.yml | 10 +- .github/workflows/codeql.yml | 8 +- .github/workflows/cspell.yml | 4 +- .github/workflows/css.yml | 6 +- .github/workflows/docs.yml | 6 +- .github/workflows/js.yml | 7 +- .github/workflows/lint.yml | 6 +- .github/workflows/node-sass.yml | 6 +- .github/workflows/release-notes.yml | 2 +- LICENSE | 2 +- README.md | 14 +- build/banner.js | 15 - build/banner.mjs | 20 + build/build-plugins.js | 103 - build/build-plugins.mjs | 105 + build/change-version.js | 101 - build/change-version.mjs | 113 + build/generate-sri.js | 63 - build/generate-sri.mjs | 64 + build/postcss.config.js | 19 - build/postcss.config.mjs | 17 + build/rollup.config.js | 57 - build/rollup.config.mjs | 59 + build/vnu-jar.js | 61 - build/vnu-jar.mjs | 59 + build/zip-examples.js | 98 - build/zip-examples.mjs | 101 + hugo.yml | 26 +- js/src/base-component.js | 2 +- js/src/dom/selector-engine.js | 2 +- js/src/modal.js | 4 +- js/src/scrollspy.js | 4 +- js/src/tab.js | 2 +- js/src/tooltip.js | 4 +- js/src/util/backdrop.js | 4 +- js/src/util/sanitizer.js | 3 + js/tests/unit/carousel.spec.js | 4 +- js/tests/unit/dom/selector-engine.spec.js | 24 + js/tests/unit/dropdown.spec.js | 4 +- js/tests/unit/modal.spec.js | 33 +- js/tests/unit/offcanvas.spec.js | 4 +- js/tests/unit/scrollspy.spec.js | 4 +- js/tests/unit/tab.spec.js | 4 +- js/tests/unit/toast.spec.js | 4 +- js/tests/unit/tooltip.spec.js | 4 +- js/tests/visual/modal.html | 34 +- nuget/bootstrap.nuspec | 2 +- nuget/bootstrap.png | Bin 6421 -> 6420 bytes nuget/bootstrap.sass.nuspec | 2 +- package-lock.json | 7947 +++++++++++--------- package.js | 2 +- package.json | 92 +- scss/_accordion.scss | 22 +- scss/_buttons.scss | 11 +- scss/_carousel.scss | 12 +- scss/_modal.scss | 1 - scss/_offcanvas.scss | 5 +- scss/_reboot.scss | 1 + scss/_root.scss | 3 + scss/_tables.scss | 2 +- scss/_utilities.scss | 6 +- scss/_variables-dark.scss | 2 + scss/_variables.scss | 38 +- scss/forms/_form-check.scss | 3 +- scss/mixins/_banner.scss | 4 +- scss/mixins/_forms.scss | 14 +- scss/mixins/_grid.scss | 4 +- .../_auto-import-of-variables-dark.test.scss | 7 + scss/tests/mixins/_utilities.test.scss | 2 +- site/assets/js/application.js | 2 +- site/assets/js/code-examples.js | 2 +- site/assets/js/snippets.js | 2 +- site/assets/scss/_component-examples.scss | 4 + site/assets/scss/_navbar.scss | 2 +- site/assets/scss/_scrolling.scss | 3 + site/assets/scss/_sidebar.scss | 2 +- site/assets/scss/docs.scss | 2 +- site/content/docs/5.3/components/accordion.md | 6 +- site/content/docs/5.3/components/alerts.md | 4 +- site/content/docs/5.3/components/badge.md | 12 +- site/content/docs/5.3/components/card.md | 2 +- site/content/docs/5.3/components/list-group.md | 14 +- site/content/docs/5.3/components/modal.md | 2 +- site/content/docs/5.3/components/offcanvas.md | 3 +- site/content/docs/5.3/components/popovers.md | 4 +- site/content/docs/5.3/content/reboot.md | 2 +- site/content/docs/5.3/content/tables.md | 2 +- site/content/docs/5.3/customize/color.md | 672 +- site/content/docs/5.3/customize/sass.md | 17 +- site/content/docs/5.3/examples/blog-rtl/index.html | 6 +- site/content/docs/5.3/examples/blog/blog.css | 2 +- site/content/docs/5.3/examples/blog/blog.rtl.css | 2 +- site/content/docs/5.3/examples/blog/index.html | 6 +- .../docs/5.3/examples/cheatsheet-rtl/index.html | 6 +- .../docs/5.3/examples/cheatsheet/index.html | 6 +- .../docs/5.3/examples/dashboard-rtl/index.html | 6 +- .../content/docs/5.3/examples/dashboard/index.html | 6 +- .../5.3/examples/features/unsplash-photo-1.jpg | Bin 10451 -> 10433 bytes .../5.3/examples/features/unsplash-photo-2.jpg | Bin 113018 -> 113000 bytes .../5.3/examples/features/unsplash-photo-3.jpg | Bin 40607 -> 40589 bytes .../docs/5.3/examples/heroes/bootstrap-docs.png | Bin 371399 -> 369528 bytes site/content/docs/5.3/examples/product/index.html | 6 +- .../docs/5.3/examples/starter-template/index.html | 2 +- site/content/docs/5.3/forms/checks-radios.md | 2 +- site/content/docs/5.3/getting-started/download.md | 18 + .../docs/5.3/getting-started/introduction.md | 13 +- .../content/docs/5.3/getting-started/javascript.md | 3 +- site/content/docs/5.3/getting-started/parcel.md | 6 +- site/content/docs/5.3/getting-started/vite.md | 12 +- site/content/docs/5.3/getting-started/webpack.md | 6 +- site/content/docs/5.3/helpers/stacks.md | 2 +- site/content/docs/5.3/layout/gutters.md | 2 +- site/content/docs/5.3/migration.md | 185 +- site/content/docs/5.3/utilities/background.md | 7 +- site/content/docs/5.3/utilities/position.md | 2 +- site/content/docs/5.3/utilities/text.md | 2 +- site/content/docs/versions.md | 2 +- site/data/docs-versions.yml | 2 +- site/layouts/_default/examples.html | 11 +- site/layouts/partials/docs-navbar.html | 6 +- site/layouts/partials/home/get-started.html | 6 +- site/layouts/shortcodes/example.html | 14 +- .../5.3/assets/brand/bootstrap-logo-shadow.png | Bin 48625 -> 46112 bytes .../static/docs/5.3/assets/img/bootstrap-icons.png | Bin 40798 -> 40346 bytes .../5.3/assets/img/bootstrap-themes-collage.png | Bin 74442 -> 74428 bytes .../5.3/assets/img/bootstrap-themes-collage@2x.png | Bin 244640 -> 243991 bytes .../docs/5.3/assets/img/examples/album-rtl.png | Bin 6391 -> 6384 bytes .../docs/5.3/assets/img/examples/album-rtl@2x.png | Bin 15347 -> 15342 bytes site/static/docs/5.3/assets/img/examples/album.png | Bin 10678 -> 10667 bytes .../docs/5.3/assets/img/examples/album@2x.png | Bin 25026 -> 24904 bytes .../docs/5.3/assets/img/examples/badges@2x.png | Bin 14798 -> 14232 bytes .../5.3/assets/img/examples/breadcrumbs@2x.png | Bin 6028 -> 6025 bytes .../docs/5.3/assets/img/examples/buttons.png | Bin 4545 -> 4493 bytes .../docs/5.3/assets/img/examples/buttons@2x.png | Bin 9994 -> 9827 bytes .../docs/5.3/assets/img/examples/carousel-rtl.png | Bin 10344 -> 10242 bytes .../5.3/assets/img/examples/carousel-rtl@2x.png | Bin 24460 -> 24414 bytes .../docs/5.3/assets/img/examples/carousel.png | Bin 13219 -> 13170 bytes .../docs/5.3/assets/img/examples/carousel@2x.png | Bin 31320 -> 31271 bytes .../5.3/assets/img/examples/dashboard-rtl@2x.png | Bin 19399 -> 19363 bytes .../docs/5.3/assets/img/examples/footers.png | Bin 4297 -> 4295 bytes .../docs/5.3/assets/img/examples/headers.png | Bin 5196 -> 5180 bytes .../docs/5.3/assets/img/examples/headers@2x.png | Bin 12639 -> 12565 bytes .../docs/5.3/assets/img/examples/list-groups.png | Bin 7134 -> 7114 bytes .../docs/5.3/assets/img/examples/masonry.png | Bin 15253 -> 15234 bytes .../docs/5.3/assets/img/examples/masonry@2x.png | Bin 37705 -> 37617 bytes .../docs/5.3/assets/img/examples/navbar-bottom.png | Bin 4819 -> 4747 bytes .../5.3/assets/img/examples/navbar-bottom@2x.png | Bin 11666 -> 11588 bytes .../docs/5.3/assets/img/examples/navbar-fixed.png | Bin 5876 -> 5864 bytes .../5.3/assets/img/examples/navbar-fixed@2x.png | Bin 13979 -> 13971 bytes .../docs/5.3/assets/img/examples/navbar-static.png | Bin 6541 -> 6540 bytes .../5.3/assets/img/examples/navbars-offcanvas.png | Bin 6850 -> 6819 bytes .../assets/img/examples/navbars-offcanvas@2x.png | Bin 16965 -> 16913 bytes .../docs/5.3/assets/img/examples/navbars.png | Bin 12965 -> 12963 bytes .../5.3/assets/img/examples/offcanvas-navbar.png | Bin 9691 -> 9673 bytes .../assets/img/examples/offcanvas-navbar@2x.png | Bin 23975 -> 23926 bytes .../assets/img/examples/sticky-footer-navbar.png | Bin 6966 -> 6891 bytes .../img/examples/sticky-footer-navbar@2x.png | Bin 15744 -> 15720 bytes .../docs/5.3/assets/img/examples/sticky-footer.png | Bin 4279 -> 4278 bytes .../5.3/assets/img/favicons/apple-touch-icon.png | Bin 7650 -> 7488 bytes .../docs/5.3/assets/img/favicons/favicon-32x32.png | Bin 1156 -> 1152 bytes .../5.3/assets/img/guides/parcel-dev-server.png | Bin 13933 -> 13690 bytes .../docs/5.3/assets/img/guides/vite-dev-server.png | Bin 13584 -> 13265 bytes .../5.3/assets/img/guides/webpack-dev-server.png | Bin 14197 -> 13999 bytes site/static/docs/5.3/assets/img/parcel.png | Bin 6003 -> 6001 bytes site/static/docs/5.3/assets/js/color-modes.js | 6 +- 169 files changed, 5717 insertions(+), 4892 deletions(-) delete mode 100644 build/banner.js create mode 100644 build/banner.mjs delete mode 100644 build/build-plugins.js create mode 100644 build/build-plugins.mjs delete mode 100644 build/change-version.js create mode 100644 build/change-version.mjs delete mode 100644 build/generate-sri.js create mode 100644 build/generate-sri.mjs delete mode 100644 build/postcss.config.js create mode 100644 build/postcss.config.mjs delete mode 100644 build/rollup.config.js create mode 100644 build/rollup.config.mjs delete mode 100644 build/vnu-jar.js create mode 100644 build/vnu-jar.mjs delete mode 100644 build/zip-examples.js create mode 100644 build/zip-examples.mjs create mode 100644 scss/tests/mixins/_auto-import-of-variables-dark.test.scss diff --git a/.cspell.json b/.cspell.json index e477ef8..484af2a 100644 --- a/.cspell.json +++ b/.cspell.json @@ -40,6 +40,7 @@ "dropright", "dropstart", "dropup", + "dgst", "errorf", "favicon", "favicons", diff --git a/.eslintrc.json b/.eslintrc.json index 055acc7..2efe773 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -51,6 +51,7 @@ "SwitchCase": 1 } ], + "logical-assignment-operators": "off", "max-params": [ "warn", 5 @@ -75,6 +76,7 @@ "error", "after" ], + "prefer-object-has-own": "off", "prefer-template": "error", "semi": [ "error", @@ -108,7 +110,7 @@ "node": true }, "parserOptions": { - "sourceType": "script" + "sourceType": "module" }, "rules": { "no-console": "off", diff --git a/.github/workflows/browserstack.yml b/.github/workflows/browserstack.yml index e545d62..a53c233 100644 --- a/.github/workflows/browserstack.yml +++ b/.github/workflows/browserstack.yml @@ -9,7 +9,7 @@ on: env: FORCE_COLOR: 2 - NODE: 18 + NODE: 20 permissions: contents: read @@ -22,12 +22,12 @@ jobs: steps: - name: Clone repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: persist-credentials: false - name: Set up Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: "${{ env.NODE }}" cache: npm diff --git a/.github/workflows/bundlewatch.yml b/.github/workflows/bundlewatch.yml index c02a37e..99ba060 100644 --- a/.github/workflows/bundlewatch.yml +++ b/.github/workflows/bundlewatch.yml @@ -9,7 +9,7 @@ on: env: FORCE_COLOR: 2 - NODE: 18 + NODE: 20 permissions: contents: read @@ -20,12 +20,12 @@ jobs: steps: - name: Clone repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: persist-credentials: false - name: Set up Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: "${{ env.NODE }}" cache: npm diff --git a/.github/workflows/calibreapp-image-actions.yml b/.github/workflows/calibreapp-image-actions.yml index 21df1f6..08987b3 100644 --- a/.github/workflows/calibreapp-image-actions.yml +++ b/.github/workflows/calibreapp-image-actions.yml @@ -8,15 +8,21 @@ on: - '**.png' - '**.webp' +permissions: + contents: read + jobs: build: # Only run on Pull Requests within the same repository, and not from forks. if: github.event.pull_request.head.repo.full_name == github.repository name: calibreapp/image-actions runs-on: ubuntu-latest + permissions: + # allow calibreapp/image-actions to update PRs + pull-requests: write steps: - - name: Checkout Repo - uses: actions/checkout@v3 + - name: Clone repository + uses: actions/checkout@v4 with: persist-credentials: false diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index b1780ee..dd7f6e7 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -24,21 +24,21 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: persist-credentials: false - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 with: config-file: ./.github/codeql/codeql-config.yml languages: "javascript" queries: +security-and-quality - name: Autobuild - uses: github/codeql-action/autobuild@v2 + uses: github/codeql-action/autobuild@v3 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 with: category: "/language:javascript" diff --git a/.github/workflows/cspell.yml b/.github/workflows/cspell.yml index 11788e3..c671fde 100644 --- a/.github/workflows/cspell.yml +++ b/.github/workflows/cspell.yml @@ -23,12 +23,12 @@ jobs: steps: - name: Clone repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: persist-credentials: false - name: Run cspell - uses: streetsidesoftware/cspell-action@v2 + uses: streetsidesoftware/cspell-action@v5 with: config: ".cspell.json" files: "**/*.md" diff --git a/.github/workflows/css.yml b/.github/workflows/css.yml index 66112a9..52e93e2 100644 --- a/.github/workflows/css.yml +++ b/.github/workflows/css.yml @@ -9,7 +9,7 @@ on: env: FORCE_COLOR: 2 - NODE: 18 + NODE: 20 permissions: contents: read @@ -20,12 +20,12 @@ jobs: steps: - name: Clone repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: persist-credentials: false - name: Set up Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: "${{ env.NODE }}" cache: npm diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 2a684f6..0822205 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -9,7 +9,7 @@ on: env: FORCE_COLOR: 2 - NODE: 18 + NODE: 20 permissions: contents: read @@ -20,12 +20,12 @@ jobs: steps: - name: Clone repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: persist-credentials: false - name: Set up Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: "${{ env.NODE }}" cache: npm diff --git a/.github/workflows/js.yml b/.github/workflows/js.yml index 805b1b7..1b672aa 100644 --- a/.github/workflows/js.yml +++ b/.github/workflows/js.yml @@ -9,7 +9,7 @@ on: env: FORCE_COLOR: 2 - NODE: 18 + NODE: 20 permissions: contents: read @@ -25,12 +25,12 @@ jobs: steps: - name: Clone repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: persist-credentials: false - name: Set up Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ env.NODE }} cache: npm @@ -46,6 +46,7 @@ jobs: - name: Run Coveralls uses: coverallsapp/github-action@v2 + if: ${{ !github.event.repository.fork }} with: github-token: "${{ secrets.GITHUB_TOKEN }}" path-to-lcov: "./js/coverage/lcov.info" diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index fd62b41..213f9ec 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -9,7 +9,7 @@ on: env: FORCE_COLOR: 2 - NODE: 18 + NODE: 20 permissions: contents: read @@ -20,12 +20,12 @@ jobs: steps: - name: Clone repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: persist-credentials: false - name: Set up Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: "${{ env.NODE }}" cache: npm diff --git a/.github/workflows/node-sass.yml b/.github/workflows/node-sass.yml index c558e44..493cc35 100644 --- a/.github/workflows/node-sass.yml +++ b/.github/workflows/node-sass.yml @@ -9,7 +9,7 @@ on: env: FORCE_COLOR: 2 - NODE: 18 + NODE: 20 permissions: contents: read @@ -20,12 +20,12 @@ jobs: steps: - name: Clone repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: persist-credentials: false - name: Set up Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: "${{ env.NODE }}" diff --git a/.github/workflows/release-notes.yml b/.github/workflows/release-notes.yml index f620dd3..813956a 100644 --- a/.github/workflows/release-notes.yml +++ b/.github/workflows/release-notes.yml @@ -18,6 +18,6 @@ jobs: runs-on: ubuntu-latest if: github.repository == 'twbs/bootstrap' steps: - - uses: release-drafter/release-drafter@v5 + - uses: release-drafter/release-drafter@v6 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/LICENSE b/LICENSE index 6633b55..2a703f5 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2011-2023 The Bootstrap Authors +Copyright (c) 2011-2024 The Bootstrap Authors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index c08d4cb..cb51a56 100644 --- a/README.md +++ b/README.md @@ -46,11 +46,11 @@ Our default branch is for development of our Bootstrap 5 release. Head to the [` Several quick start options are available: -- [Download the latest release](https://github.com/twbs/bootstrap/archive/v5.3.1.zip) +- [Download the latest release](https://github.com/twbs/bootstrap/archive/v5.3.3.zip) - Clone the repo: `git clone https://github.com/twbs/bootstrap.git` -- Install with [npm](https://www.npmjs.com/): `npm install bootstrap@v5.3.1` -- Install with [yarn](https://yarnpkg.com/): `yarn add bootstrap@v5.3.1` -- Install with [Composer](https://getcomposer.org/): `composer require twbs/bootstrap:5.3.1` +- Install with [npm](https://www.npmjs.com/): `npm install bootstrap@v5.3.3` +- Install with [yarn](https://yarnpkg.com/): `yarn add bootstrap@v5.3.3` +- Install with [Composer](https://getcomposer.org/): `composer require twbs/bootstrap:5.3.3` - Install with [NuGet](https://www.nuget.org/): CSS: `Install-Package bootstrap` Sass: `Install-Package bootstrap.sass` Read the [Getting started page](https://getbootstrap.com/docs/5.3/getting-started/introduction/) for information on the framework contents, templates, examples, and more. @@ -69,7 +69,6 @@ Read the [Getting started page](https://getbootstrap.com/docs/5.3/getting-starte [![CSS Brotli size](https://img.badgesize.io/twbs/bootstrap/main/dist/css/bootstrap.min.css?compression=brotli&label=CSS%20Brotli%20size)](https://github.com/twbs/bootstrap/blob/main/dist/css/bootstrap.min.css) [![JS gzip size](https://img.badgesize.io/twbs/bootstrap/main/dist/js/bootstrap.min.js?compression=gzip&label=JS%20gzip%20size)](https://github.com/twbs/bootstrap/blob/main/dist/js/bootstrap.min.js) [![JS Brotli size](https://img.badgesize.io/twbs/bootstrap/main/dist/js/bootstrap.min.js?compression=brotli&label=JS%20Brotli%20size)](https://github.com/twbs/bootstrap/blob/main/dist/js/bootstrap.min.js) -[![BrowserStack Status](https://www.browserstack.com/automate/badge.svg?badge_key=SkxZcStBeExEdVJqQ2hWYnlWckpkNmNEY213SFp6WHFETWk2bGFuY3pCbz0tLXhqbHJsVlZhQnRBdEpod3NLSDMzaHc9PQ==--3d0b75245708616eb93113221beece33e680b229)](https://www.browserstack.com/automate/public-build/SkxZcStBeExEdVJqQ2hWYnlWckpkNmNEY213SFp6WHFETWk2bGFuY3pCbz0tLXhqbHJsVlZhQnRBdEpod3NLSDMzaHc9PQ==--3d0b75245708616eb93113221beece33e680b229) [![Backers on Open Collective](https://img.shields.io/opencollective/backers/bootstrap?logo=opencollective&logoColor=fff)](#backers) [![Sponsors on Open Collective](https://img.shields.io/opencollective/sponsors/bootstrap?logo=opencollective&logoColor=fff)](#sponsors) @@ -177,7 +176,8 @@ Get updates on Bootstrap's development and chat with the project maintainers and - Follow [@getbootstrap on Twitter](https://twitter.com/getbootstrap). - Read and subscribe to [The Official Bootstrap Blog](https://blog.getbootstrap.com/). -- Ask and explore [our GitHub Discussions](https://github.com/twbs/bootstrap/discussions). +- Ask questions and explore [our GitHub Discussions](https://github.com/twbs/bootstrap/discussions). +- Discuss, ask questions, and more on [the community Discord](https://discord.gg/bZUvakRU3M) or [Bootstrap subreddit](https://reddit.com/r/bootstrap). - Chat with fellow Bootstrappers in IRC. On the `irc.libera.chat` server, in the `#bootstrap` channel. - Implementation help may be found at Stack Overflow (tagged [`bootstrap-5`](https://stackoverflow.com/questions/tagged/bootstrap-5)). - Developers should use the keyword `bootstrap` on packages which modify or add to the functionality of Bootstrap when distributing through [npm](https://www.npmjs.com/browse/keyword/bootstrap) or similar delivery mechanisms for maximum discoverability. @@ -243,4 +243,4 @@ Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com ## Copyright and license -Code and documentation copyright 2011–2023 the [Bootstrap Authors](https://github.com/twbs/bootstrap/graphs/contributors). Code released under the [MIT License](https://github.com/twbs/bootstrap/blob/main/LICENSE). Docs released under [Creative Commons](https://creativecommons.org/licenses/by/3.0/). +Code and documentation copyright 2011–2024 the [Bootstrap Authors](https://github.com/twbs/bootstrap/graphs/contributors). Code released under the [MIT License](https://github.com/twbs/bootstrap/blob/main/LICENSE). Docs released under [Creative Commons](https://creativecommons.org/licenses/by/3.0/). diff --git a/build/banner.js b/build/banner.js deleted file mode 100644 index a022f1c..0000000 --- a/build/banner.js +++ /dev/null @@ -1,15 +0,0 @@ -'use strict' - -const pkg = require('../package.json') - -const year = new Date().getFullYear() - -function getBanner(pluginFilename) { - return `/*! - * Bootstrap${pluginFilename ? ` ${pluginFilename}` : ''} v${pkg.version} (${pkg.homepage}) - * Copyright 2011-${year} ${pkg.author} - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) - */` -} - -module.exports = getBanner diff --git a/build/banner.mjs b/build/banner.mjs new file mode 100644 index 0000000..3fea93c --- /dev/null +++ b/build/banner.mjs @@ -0,0 +1,20 @@ +import fs from 'node:fs/promises' +import path from 'node:path' +import { fileURLToPath } from 'node:url' + +const __dirname = path.dirname(fileURLToPath(import.meta.url)) + +const pkgJson = path.join(__dirname, '../package.json') +const pkg = JSON.parse(await fs.readFile(pkgJson, 'utf8')) + +const year = new Date().getFullYear() + +function getBanner(pluginFilename) { + return `/*! + * Bootstrap${pluginFilename ? ` ${pluginFilename}` : ''} v${pkg.version} (${pkg.homepage}) + * Copyright 2011-${year} ${pkg.author} + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */` +} + +export default getBanner diff --git a/build/build-plugins.js b/build/build-plugins.js deleted file mode 100644 index b2833a3..0000000 --- a/build/build-plugins.js +++ /dev/null @@ -1,103 +0,0 @@ -#!/usr/bin/env node - -/*! - * Script to build our plugins to use them separately. - * Copyright 2020-2023 The Bootstrap Authors - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) - */ - -'use strict' - -const path = require('node:path') -const rollup = require('rollup') -const globby = require('globby') -const { babel } = require('@rollup/plugin-babel') -const banner = require('./banner.js') - -const sourcePath = path.resolve(__dirname, '../js/src/').replace(/\\/g, '/') -const jsFiles = globby.sync(`${sourcePath}/**/*.js`) - -// Array which holds the resolved plugins -const resolvedPlugins = [] - -// Trims the "js" extension and uppercases => first letter, hyphens, backslashes & slashes -const filenameToEntity = filename => filename.replace('.js', '') - .replace(/(?:^|-|\/|\\)[a-z]/g, str => str.slice(-1).toUpperCase()) - -for (const file of jsFiles) { - resolvedPlugins.push({ - src: file, - dist: file.replace('src', 'dist'), - fileName: path.basename(file), - className: filenameToEntity(path.basename(file)) - // safeClassName: filenameToEntity(path.relative(sourcePath, file)) - }) -} - -const build = async plugin => { - const globals = {} - - const bundle = await rollup.rollup({ - input: plugin.src, - plugins: [ - babel({ - // Only transpile our source code - exclude: 'node_modules/**', - // Include the helpers in each file, at most one copy of each - babelHelpers: 'bundled' - }) - ], - external(source) { - // Pattern to identify local files - const pattern = /^(\.{1,2})\// - - // It's not a local file, e.g a Node.js package - if (!pattern.test(source)) { - globals[source] = source - return true - } - - const usedPlugin = resolvedPlugins.find(plugin => { - return plugin.src.includes(source.replace(pattern, '')) - }) - - if (!usedPlugin) { - throw new Error(`Source ${source} is not mapped!`) - } - - // We can change `Index` with `UtilIndex` etc if we use - // `safeClassName` instead of `className` everywhere - globals[path.normalize(usedPlugin.src)] = usedPlugin.className - return true - } - }) - - await bundle.write({ - banner: banner(plugin.fileName), - format: 'umd', - name: plugin.className, - sourcemap: true, - globals, - generatedCode: 'es2015', - file: plugin.dist - }) - - console.log(`Built ${plugin.className}`) -} - -(async () => { - try { - const basename = path.basename(__filename) - const timeLabel = `[${basename}] finished` - - console.log('Building individual plugins...') - console.time(timeLabel) - - await Promise.all(Object.values(resolvedPlugins).map(plugin => build(plugin))) - - console.timeEnd(timeLabel) - } catch (error) { - console.error(error) - process.exit(1) - } -})() diff --git a/build/build-plugins.mjs b/build/build-plugins.mjs new file mode 100644 index 0000000..252b4b4 --- /dev/null +++ b/build/build-plugins.mjs @@ -0,0 +1,105 @@ +#!/usr/bin/env node + +/*! + * Script to build our plugins to use them separately. + * Copyright 2020-2024 The Bootstrap Authors + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */ + +import path from 'node:path' +import { fileURLToPath } from 'node:url' +import { babel } from '@rollup/plugin-babel' +import globby from 'globby' +import { rollup } from 'rollup' +import banner from './banner.mjs' + +const __filename = fileURLToPath(import.meta.url) +const __dirname = path.dirname(fileURLToPath(import.meta.url)) + +const sourcePath = path.resolve(__dirname, '../js/src/').replace(/\\/g, '/') +const jsFiles = globby.sync(`${sourcePath}/**/*.js`) + +// Array which holds the resolved plugins +const resolvedPlugins = [] + +// Trims the "js" extension and uppercases => first letter, hyphens, backslashes & slashes +const filenameToEntity = filename => filename.replace('.js', '') + .replace(/(?:^|-|\/|\\)[a-z]/g, str => str.slice(-1).toUpperCase()) + +for (const file of jsFiles) { + resolvedPlugins.push({ + src: file, + dist: file.replace('src', 'dist'), + fileName: path.basename(file), + className: filenameToEntity(path.basename(file)) + // safeClassName: filenameToEntity(path.relative(sourcePath, file)) + }) +} + +const build = async plugin => { + const globals = {} + + const bundle = await rollup({ + input: plugin.src, + plugins: [ + babel({ + // Only transpile our source code + exclude: 'node_modules/**', + // Include the helpers in each file, at most one copy of each + babelHelpers: 'bundled' + }) + ], + external(source) { + // Pattern to identify local files + const pattern = /^(\.{1,2})\// + + // It's not a local file, e.g a Node.js package + if (!pattern.test(source)) { + globals[source] = source + return true + } + + const usedPlugin = resolvedPlugins.find(plugin => { + return plugin.src.includes(source.replace(pattern, '')) + }) + + if (!usedPlugin) { + throw new Error(`Source ${source} is not mapped!`) + } + + // We can change `Index` with `UtilIndex` etc if we use + // `safeClassName` instead of `className` everywhere + globals[path.normalize(usedPlugin.src)] = usedPlugin.className + return true + } + }) + + await bundle.write({ + banner: banner(plugin.fileName), + format: 'umd', + name: plugin.className, + sourcemap: true, + globals, + generatedCode: 'es2015', + file: plugin.dist + }) + + console.log(`Built ${plugin.className}`) +} + +(async () => { + try { + const basename = path.basename(__filename) + const timeLabel = `[${basename}] finished` + + console.log('Building individual plugins...') + console.time(timeLabel) + + await Promise.all(Object.values(resolvedPlugins).map(plugin => build(plugin))) + + console.timeEnd(timeLabel) + } catch (error) { + console.error(error) + process.exit(1) + } +})() diff --git a/build/change-version.js b/build/change-version.js deleted file mode 100644 index 9685df5..0000000 --- a/build/change-version.js +++ /dev/null @@ -1,101 +0,0 @@ -#!/usr/bin/env node - -/*! - * Script to update version number references in the project. - * Copyright 2017-2023 The Bootstrap Authors - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) - */ - -'use strict' - -const fs = require('node:fs').promises -const path = require('node:path') -const globby = require('globby') - -const VERBOSE = process.argv.includes('--verbose') -const DRY_RUN = process.argv.includes('--dry') || process.argv.includes('--dry-run') - -// These are the filetypes we only care about replacing the version -const GLOB = [ - '**/*.{css,html,js,json,md,scss,txt,yml}' -] -const GLOBBY_OPTIONS = { - cwd: path.join(__dirname, '..'), - gitignore: true -} - -// Blame TC39... https://github.com/benjamingr/RegExp.escape/issues/37 -function regExpQuote(string) { - return string.replace(/[$()*+-.?[\\\]^{|}]/g, '\\$&') -} - -function regExpQuoteReplacement(string) { - return string.replace(/\$/g, '$$') -} - -async function replaceRecursively(file, oldVersion, newVersion) { - const originalString = await fs.readFile(file, 'utf8') - const newString = originalString - .replace( - new RegExp(regExpQuote(oldVersion), 'g'), - regExpQuoteReplacement(newVersion) - ) - // Also replace the version used by the rubygem, - // which is using periods (`.`) instead of hyphens (`-`) - .replace( - new RegExp(regExpQuote(oldVersion.replace(/-/g, '.')), 'g'), - regExpQuoteReplacement(newVersion.replace(/-/g, '.')) - ) - - // No need to move any further if the strings are identical - if (originalString === newString) { - return - } - - if (VERBOSE) { - console.log(`FILE: ${file}`) - } - - if (DRY_RUN) { - return - } - - await fs.writeFile(file, newString, 'utf8') -} - -function showUsage(args) { - console.error('USAGE: change-version old_version new_version [--verbose] [--dry[-run]]') - console.error('Got arguments:', args) - process.exit(1) -} - -async function main(args) { - let [oldVersion, newVersion] = args - - if (!oldVersion || !newVersion) { - showUsage(args) - } - - // Strip any leading `v` from arguments because - // otherwise we will end up with duplicate `v`s - [oldVersion, newVersion] = [oldVersion, newVersion].map(arg => { - return arg.startsWith('v') ? arg.slice(1) : arg - }) - - if (oldVersion === newVersion) { - showUsage(args) - } - - try { - const files = await globby(GLOB, GLOBBY_OPTIONS) - - await Promise.all( - files.map(file => replaceRecursively(file, oldVersion, newVersion)) - ) - } catch (error) { - console.error(error) - process.exit(1) - } -} - -main(process.argv.slice(2)) diff --git a/build/change-version.mjs b/build/change-version.mjs new file mode 100644 index 0000000..30cfcc4 --- /dev/null +++ b/build/change-version.mjs @@ -0,0 +1,113 @@ +#!/usr/bin/env node + +/*! + * Script to update version number references in the project. + * Copyright 2017-2024 The Bootstrap Authors + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */ + +import { execFile } from 'node:child_process' +import fs from 'node:fs/promises' +import process from 'node:process' + +const VERBOSE = process.argv.includes('--verbose') +const DRY_RUN = process.argv.includes('--dry') || process.argv.includes('--dry-run') + +// These are the files we only care about replacing the version +const FILES = [ + 'README.md', + 'hugo.yml', + 'js/src/base-component.js', + 'package.js', + 'scss/mixins/_banner.scss', + 'site/data/docs-versions.yml' +] + +// Blame TC39... https://github.com/benjamingr/RegExp.escape/issues/37 +function regExpQuote(string) { + return string.replace(/[$()*+-.?[\\\]^{|}]/g, '\\$&') +} + +function regExpQuoteReplacement(string) { + return string.replace(/\$/g, '$$') +} + +async function replaceRecursively(file, oldVersion, newVersion) { + const originalString = await fs.readFile(file, 'utf8') + const newString = originalString + .replace( + new RegExp(regExpQuote(oldVersion), 'g'), + regExpQuoteReplacement(newVersion) + ) + // Also replace the version used by the rubygem, + // which is using periods (`.`) instead of hyphens (`-`) + .replace( + new RegExp(regExpQuote(oldVersion.replace(/-/g, '.')), 'g'), + regExpQuoteReplacement(newVersion.replace(/-/g, '.')) + ) + + // No need to move any further if the strings are identical + if (originalString === newString) { + return + } + + if (VERBOSE) { + console.log(`Found ${oldVersion} in ${file}`) + } + + if (DRY_RUN) { + return + } + + await fs.writeFile(file, newString, 'utf8') +} + +function bumpNpmVersion(newVersion) { + if (DRY_RUN) { + return + } + + execFile('npm', ['version', newVersion, '--no-git-tag'], { shell: true }, error => { + if (error) { + console.error(error) + process.exit(1) + } + }) +} + +function showUsage(args) { + console.error('USAGE: change-version old_version new_version [--verbose] [--dry[-run]]') + console.error('Got arguments:', args) + process.exit(1) +} + +async function main(args) { + let [oldVersion, newVersion] = args + + if (!oldVersion || !newVersion) { + showUsage(args) + } + + // Strip any leading `v` from arguments because + // otherwise we will end up with duplicate `v`s + [oldVersion, newVersion] = [oldVersion, newVersion].map(arg => { + return arg.startsWith('v') ? arg.slice(1) : arg + }) + + if (oldVersion === newVersion) { + showUsage(args) + } + + bumpNpmVersion(newVersion) + + try { + await Promise.all( + FILES.map(file => replaceRecursively(file, oldVersion, newVersion)) + ) + } catch (error) { + console.error(error) + process.exit(1) + } +} + +main(process.argv.slice(2)) diff --git a/build/generate-sri.js b/build/generate-sri.js deleted file mode 100644 index 2e22924..0000000 --- a/build/generate-sri.js +++ /dev/null @@ -1,63 +0,0 @@ -#!/usr/bin/env node - -/*! - * Script to generate SRI hashes for use in our docs. - * Remember to use the same vendor files as the CDN ones, - * otherwise the hashes won't match! - * - * Copyright 2017-2023 The Bootstrap Authors - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) - */ - -'use strict' - -const crypto = require('node:crypto') -const fs = require('node:fs') -const path = require('node:path') -const sh = require('shelljs') - -sh.config.fatal = true - -const configFile = path.join(__dirname, '../hugo.yml') - -// Array of objects which holds the files to generate SRI hashes for. -// `file` is the path from the root folder -// `configPropertyName` is the hugo.yml variable's name of the file -const files = [ - { - file: 'dist/css/bootstrap.min.css', - configPropertyName: 'css_hash' - }, - { - file: 'dist/css/bootstrap.rtl.min.css', - configPropertyName: 'css_rtl_hash' - }, - { - file: 'dist/js/bootstrap.min.js', - configPropertyName: 'js_hash' - }, - { - file: 'dist/js/bootstrap.bundle.min.js', - configPropertyName: 'js_bundle_hash' - }, - { - file: 'node_modules/@popperjs/core/dist/umd/popper.min.js', - configPropertyName: 'popper_hash' - } -] - -for (const { file, configPropertyName } of files) { - fs.readFile(file, 'utf8', (error, data) => { - if (error) { - throw error - } - - const algo = 'sha384' - const hash = crypto.createHash(algo).update(data, 'utf8').digest('base64') - const integrity = `${algo}-${hash}` - - console.log(`${configPropertyName}: ${integrity}`) - - sh.sed('-i', new RegExp(`^(\\s+${configPropertyName}:\\s+["'])\\S*(["'])`), `$1${integrity}$2`, configFile) - }) -} diff --git a/build/generate-sri.mjs b/build/generate-sri.mjs new file mode 100644 index 0000000..384e8f4 --- /dev/null +++ b/build/generate-sri.mjs @@ -0,0 +1,64 @@ +#!/usr/bin/env node + +/*! + * Script to generate SRI hashes for use in our docs. + * Remember to use the same vendor files as the CDN ones, + * otherwise the hashes won't match! + * + * Copyright 2017-2024 The Bootstrap Authors + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */ + +import crypto from 'node:crypto' +import fs from 'node:fs' +import path from 'node:path' +import { fileURLToPath } from 'node:url' +import sh from 'shelljs' + +const __dirname = path.dirname(fileURLToPath(import.meta.url)) + +sh.config.fatal = true + +const configFile = path.join(__dirname, '../hugo.yml') + +// Array of objects which holds the files to generate SRI hashes for. +// `file` is the path from the root folder +// `configPropertyName` is the hugo.yml variable's name of the file +const files = [ + { + file: 'dist/css/bootstrap.min.css', + configPropertyName: 'css_hash' + }, + { + file: 'dist/css/bootstrap.rtl.min.css', + configPropertyName: 'css_rtl_hash' + }, + { + file: 'dist/js/bootstrap.min.js', + configPropertyName: 'js_hash' + }, + { + file: 'dist/js/bootstrap.bundle.min.js', + configPropertyName: 'js_bundle_hash' + }, + { + file: 'node_modules/@popperjs/core/dist/umd/popper.min.js', + configPropertyName: 'popper_hash' + } +] + +for (const { file, configPropertyName } of files) { + fs.readFile(file, 'utf8', (error, data) => { + if (error) { + throw error + } + + const algorithm = 'sha384' + const hash = crypto.createHash(algorithm).update(data, 'utf8').digest('base64') + const integrity = `${algorithm}-${hash}` + + console.log(`${configPropertyName}: ${integrity}`) + + sh.sed('-i', new RegExp(`^(\\s+${configPropertyName}:\\s+["'])\\S*(["'])`), `$1${integrity}$2`, configFile) + }) +} diff --git a/build/postcss.config.js b/build/postcss.config.js deleted file mode 100644 index 7f8186d..0000000 --- a/build/postcss.config.js +++ /dev/null @@ -1,19 +0,0 @@ -'use strict' - -const mapConfig = { - inline: false, - annotation: true, - sourcesContent: true -} - -module.exports = context => { - return { - map: context.file.dirname.includes('examples') ? false : mapConfig, - plugins: { - autoprefixer: { - cascade: false - }, - rtlcss: context.env === 'RTL' - } - } -} diff --git a/build/postcss.config.mjs b/build/postcss.config.mjs new file mode 100644 index 0000000..7717cfc --- /dev/null +++ b/build/postcss.config.mjs @@ -0,0 +1,17 @@ +const mapConfig = { + inline: false, + annotation: true, + sourcesContent: true +} + +export default context => { + return { + map: context.file.dirname.includes('examples') ? false : mapConfig, + plugins: { + autoprefixer: { + cascade: false + }, + rtlcss: context.env === 'RTL' + } + } +} diff --git a/build/rollup.config.js b/build/rollup.config.js deleted file mode 100644 index f01918e..0000000 --- a/build/rollup.config.js +++ /dev/null @@ -1,57 +0,0 @@ -'use strict' - -const path = require('node:path') -const { babel } = require('@rollup/plugin-babel') -const { nodeResolve } = require('@rollup/plugin-node-resolve') -const replace = require('@rollup/plugin-replace') -const banner = require('./banner.js') - -const BUNDLE = process.env.BUNDLE === 'true' -const ESM = process.env.ESM === 'true' - -let fileDestination = `bootstrap${ESM ? '.esm' : ''}` -const external = ['@popperjs/core'] -const plugins = [ - babel({ - // Only transpile our source code - exclude: 'node_modules/**', - // Include the helpers in the bundle, at most one copy of each - babelHelpers: 'bundled' - }) -] -const globals = { - '@popperjs/core': 'Popper' -} - -if (BUNDLE) { - fileDestination += '.bundle' - // Remove last entry in external array to bundle Popper - external.pop() - delete globals['@popperjs/core'] - plugins.push( - replace({ - 'process.env.NODE_ENV': '"production"', - preventAssignment: true - }), - nodeResolve() - ) -} - -const rollupConfig = { - input: path.resolve(__dirname, `../js/index.${ESM ? 'esm' : 'umd'}.js`), - output: { - banner: banner(), - file: path.resolve(__dirname, `../dist/js/${fileDestination}.js`), - format: ESM ? 'esm' : 'umd', - globals, - generatedCode: 'es2015' - }, - external, - plugins -} - -if (!ESM) { - rollupConfig.output.name = 'bootstrap' -} - -module.exports = rollupConfig diff --git a/build/rollup.config.mjs b/build/rollup.config.mjs new file mode 100644 index 0000000..dd6c7d1 --- /dev/null +++ b/build/rollup.config.mjs @@ -0,0 +1,59 @@ +import path from 'node:path' +import process from 'node:process' +import { fileURLToPath } from 'node:url' +import { babel } from '@rollup/plugin-babel' +import { nodeResolve } from '@rollup/plugin-node-resolve' +import replace from '@rollup/plugin-replace' +import banner from './banner.mjs' + +const __dirname = path.dirname(fileURLToPath(import.meta.url)) + +const BUNDLE = process.env.BUNDLE === 'true' +const ESM = process.env.ESM === 'true' + +let destinationFile = `bootstrap${ESM ? '.esm' : ''}` +const external = ['@popperjs/core'] +const plugins = [ + babel({ + // Only transpile our source code + exclude: 'node_modules/**', + // Include the helpers in the bundle, at most one copy of each + babelHelpers: 'bundled' + }) +] +const globals = { + '@popperjs/core': 'Popper' +} + +if (BUNDLE) { + destinationFile += '.bundle' + // Remove last entry in external array to bundle Popper + external.pop() + delete globals['@popperjs/core'] + plugins.push( + replace({ + 'process.env.NODE_ENV': '"production"', + preventAssignment: true + }), + nodeResolve() + ) +} + +const rollupConfig = { + input: path.resolve(__dirname, `../js/index.${ESM ? 'esm' : 'umd'}.js`), + output: { + banner: banner(), + file: path.resolve(__dirname, `../dist/js/${destinationFile}.js`), + format: ESM ? 'esm' : 'umd', + globals, + generatedCode: 'es2015' + }, + external, + plugins +} + +if (!ESM) { + rollupConfig.output.name = 'bootstrap' +} + +export default rollupConfig diff --git a/build/vnu-jar.js b/build/vnu-jar.js deleted file mode 100644 index 22956cb..0000000 --- a/build/vnu-jar.js +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/env node - -/*! - * Script to run vnu-jar if Java is available. - * Copyright 2017-2023 The Bootstrap Authors - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) - */ - -'use strict' - -const { execFile, spawn } = require('node:child_process') -const vnu = require('vnu-jar') - -execFile('java', ['-version'], (error, stdout, stderr) => { - if (error) { - console.error('Skipping vnu-jar test; Java is probably missing.') - console.error(error) - return - } - - console.log('Running vnu-jar validation...') - - const is32bitJava = !/64-Bit/.test(stderr) - - // vnu-jar accepts multiple ignores joined with a `|`. - // Also note that the ignores are string regular expressions. - const ignores = [ - // "autocomplete" is included in
diff --git a/site/content/docs/5.3/utilities/text.md b/site/content/docs/5.3/utilities/text.md index 95fe06b..68b516a 100644 --- a/site/content/docs/5.3/utilities/text.md +++ b/site/content/docs/5.3/utilities/text.md @@ -31,7 +31,7 @@ Note that we don't provide utility classes for justified text. While, aesthetica Wrap text with a `.text-wrap` class. {{< example >}} -{{ end }} diff --git a/site/data/docs-versions.yml b/site/data/docs-versions.yml index 1d41c42..a924dd2 100644 --- a/site/data/docs-versions.yml +++ b/site/data/docs-versions.yml @@ -48,7 +48,7 @@ - group: v5.x baseurl: "https://getbootstrap.com/docs" - description: "Current major release. Last update was v5.3.1." + description: "Current major release. Last update was v5.3.3." versions: - "5.0" - "5.1" diff --git a/site/layouts/_default/examples.html b/site/layouts/_default/examples.html index 11759a2..e99c697 100644 --- a/site/layouts/_default/examples.html +++ b/site/layouts/_default/examples.html @@ -89,9 +89,14 @@ --bs-btn-active-bg: #5a23c8; --bs-btn-active-border-color: #5a23c8; } + .bd-mode-toggle { z-index: 1500; } + + .bd-mode-toggle .dropdown-menu .active .bi { + display: block !important; + } {{ range .Page.Params.extra_css }} @@ -129,21 +134,21 @@