Skip to content

Commit b9cc38f

Browse files
authored
feat: Upgrade Bootstrap to version 5 and support dark mode (#1516)
Signed-off-by: rogerogers <rogers@rogerogers.com>
1 parent 1b09199 commit b9cc38f

69 files changed

Lines changed: 1013 additions & 1656 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

assets/js/base.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ limitations under the License.
1919
'use strict';
2020

2121
$(function() {
22-
$('[data-toggle="tooltip"]').tooltip();
23-
$('[data-toggle="popover"]').popover();
22+
$('[data-bs-toggle="tooltip"]').tooltip();
23+
$('[data-bs-toggle="popover"]').popover();
2424

2525
$('.popover-dismiss').popover({
2626
trigger: 'focus'

assets/js/click-to-copy.js

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
let codeListings = document.querySelectorAll('.highlight > pre');
2+
3+
for (let index = 0; index < codeListings.length; index++) {
4+
const codeSample = codeListings[index].querySelector('code');
5+
if (!codeSample) {
6+
continue;
7+
}
8+
9+
const copyButton = document.createElement('button');
10+
const buttonAttributes = {
11+
type: 'button',
12+
title: 'Copy to clipboard',
13+
'data-bs-toggle': 'tooltip',
14+
'data-bs-placement': 'top',
15+
'data-bs-container': 'body',
16+
};
17+
18+
Object.keys(buttonAttributes).forEach((key) => {
19+
copyButton.setAttribute(key, buttonAttributes[key]);
20+
});
21+
22+
copyButton.classList.add(
23+
'fas',
24+
'fa-copy',
25+
'btn',
26+
'btn-sm',
27+
'td-click-to-copy'
28+
);
29+
const tooltip = new bootstrap.Tooltip(copyButton);
30+
31+
copyButton.onclick = () => {
32+
copyCode(codeSample, copyButton, tooltip);
33+
};
34+
35+
copyButton.onmouseout = () => {
36+
copyButton.setAttribute('data-bs-original-title', 'Copy to clipboard');
37+
tooltip.hide();
38+
};
39+
40+
const buttonDiv = document.createElement('div');
41+
buttonDiv.classList.add('click-to-copy');
42+
buttonDiv.append(copyButton);
43+
codeListings[index].insertBefore(buttonDiv, codeSample);
44+
}
45+
46+
const copyCode = (codeSample, copyButton, tooltip) => {
47+
if (!codeSample) {
48+
return;
49+
}
50+
51+
const isConsoleBlock = codeSample.matches(
52+
"code[data-lang='console'], code.language-console"
53+
);
54+
let text;
55+
56+
if (isConsoleBlock) {
57+
const clone = codeSample.cloneNode(true);
58+
pruneUnselectableElements(codeSample, clone);
59+
text = clone.textContent;
60+
// For each command, strip the space after the prompt and before the
61+
// command:
62+
text = text.replace(/^ /gm, '');
63+
} else {
64+
text = codeSample.textContent;
65+
}
66+
text = text ? text.trim() : '';
67+
68+
if (!navigator.clipboard) {
69+
console.warn('Clipboard API not available (requires HTTPS or localhost)');
70+
return;
71+
}
72+
73+
navigator.clipboard.writeText(text + '\n').then(() => {
74+
copyButton.setAttribute('data-bs-original-title', 'Copied!');
75+
tooltip.show();
76+
}).catch(error => {
77+
console.warn('Failed to copy text to clipboard:', error);
78+
});
79+
};
80+
81+
const pruneUnselectableElements = (sourceNode, cloneNode) => {
82+
const sourceChildren = sourceNode.children;
83+
const cloneChildren = cloneNode.children;
84+
85+
for (let i = sourceChildren.length - 1; i >= 0; i--) {
86+
const sourceChild = sourceChildren[i];
87+
const cloneChild = cloneChildren[i];
88+
const style = window.getComputedStyle(sourceChild);
89+
const unselectable = style.userSelect === 'none';
90+
91+
if (unselectable) {
92+
cloneChild.remove();
93+
continue;
94+
}
95+
96+
pruneUnselectableElements(sourceChild, cloneChild);
97+
}
98+
};

assets/js/dark-mode.js

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/*!
2+
* This is a Docsy-adapted version of https://github.com/twbs/examples/blob/main/color-modes/js/color-modes.js.
3+
*
4+
* Original header:
5+
*
6+
* Color mode toggler for Bootstrap's docs (https://getbootstrap.com/)
7+
* Copyright 2011-2024 The Bootstrap Authors
8+
* Licensed under the Creative Commons Attribution 3.0 Unported License.
9+
*/
10+
11+
(() => {
12+
'use strict'
13+
14+
const themeKey = 'td-color-theme'
15+
const getStoredTheme = () => localStorage.getItem(themeKey)
16+
const setStoredTheme = theme => localStorage.setItem(themeKey, theme)
17+
18+
const getPreferredTheme = () => {
19+
const storedTheme = getStoredTheme()
20+
if (storedTheme) {
21+
return storedTheme
22+
}
23+
24+
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
25+
}
26+
27+
const setTheme = theme => {
28+
if (theme === 'auto') {
29+
document.documentElement.setAttribute('data-bs-theme', (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'))
30+
} else {
31+
document.documentElement.setAttribute('data-bs-theme', theme)
32+
}
33+
}
34+
35+
setTheme(getPreferredTheme())
36+
37+
document.documentElement.removeAttribute('data-theme-init')
38+
39+
const showActiveTheme = (theme, focus = false) => {
40+
const themeSwitcher = document.querySelector('#bd-theme')
41+
42+
if (!themeSwitcher) {
43+
return
44+
}
45+
46+
const themeSwitcherText = document.querySelector('#bd-theme-text')
47+
const activeThemeIcon = document.querySelector('.theme-icon-active use')
48+
const btnToActive = document.querySelector(`[data-bs-theme-value="${theme}"]`)
49+
if (!btnToActive) {
50+
return
51+
}
52+
const svgOfActiveBtn = btnToActive.querySelector('svg use').getAttribute('href')
53+
54+
document.querySelectorAll('[data-bs-theme-value]').forEach(element => {
55+
element.classList.remove('active')
56+
element.setAttribute('aria-pressed', 'false')
57+
})
58+
59+
btnToActive.classList.add('active')
60+
btnToActive.setAttribute('aria-pressed', 'true')
61+
activeThemeIcon.setAttribute('href', svgOfActiveBtn)
62+
if (themeSwitcherText) {
63+
const themeSwitcherLabel = `${themeSwitcherText.textContent} (${btnToActive.dataset.bsThemeValue})`
64+
themeSwitcher.setAttribute('aria-label', themeSwitcherLabel)
65+
}
66+
67+
if (focus) {
68+
themeSwitcher.focus()
69+
}
70+
}
71+
72+
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
73+
const storedTheme = getStoredTheme()
74+
if (storedTheme !== 'light' && storedTheme !== 'dark') {
75+
setTheme(getPreferredTheme())
76+
}
77+
})
78+
79+
window.addEventListener('DOMContentLoaded', () => {
80+
showActiveTheme(getPreferredTheme())
81+
82+
document.querySelectorAll('[data-bs-theme-value]')
83+
.forEach(toggle => {
84+
toggle.addEventListener('click', () => {
85+
const theme = toggle.getAttribute('data-bs-theme-value')
86+
setStoredTheme(theme)
87+
setTheme(theme)
88+
showActiveTheme(theme, true)
89+
})
90+
})
91+
})
92+
})()

assets/js/offline-search.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@
162162
const $entry = $('<div>').addClass('mt-4');
163163

164164
$entry.append(
165-
$('<small>').addClass('d-block text-muted').text(r.ref)
165+
$('<small>').addClass('d-block text-body-secondary').text(r.ref)
166166
);
167167

168168
$entry.append(

assets/scss/_alerts.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
.alert {
44
font-weight: $font-weight-medium;
5-
background: $white;
5+
background: var(--bs-body-bg);
66
color: inherit;
77
border-radius: 0;
88

assets/scss/_boxes.scss

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33

44
// box-variant creates the main style for a colored section used on the site.
55
@mixin box-variant($parent, $color-name, $color-value) {
6-
$text-color: color-yiq($color-value);
7-
$link-color: mix($blue, $text-color, lightness($color-value));
6+
@if type-of($color-value) == 'color' {
7+
$text-color: color-contrast($color-value);
8+
$link-color: mix($blue, $text-color);
89
$link-hover-color: rgba($link-color, 0.5) !default;
910

1011
#{$parent} {
@@ -27,15 +28,24 @@
2728
content: "";
2829
}
2930
}
31+
32+
p > a {
33+
color: $link-color;
34+
35+
&:hover,
36+
&:focus {
37+
color: $link-hover-color;
38+
}
39+
}
3040
}
3141
}
3242

33-
// Improve contrast for the links in paragraphs.
34-
@include link-variant("#{$parent}--#{$color-name} p > a", $link-color, $link-hover-color, false);
35-
3643
@if $enable-gradients {
3744
@include bg-gradient-variant("#{$parent}--1#{$color-name}#{$parent}--gradient", $color-value,true);
3845
}
46+
} @else {
47+
@warn "box-variant: #{$color-value} is not a color, skipping #{$parent}--#{$color-name}";
48+
}
3949
}
4050

4151
// Common min-height modifiers used for boxes.

assets/scss/_chroma-dark.scss

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/* Generated using: hugo gen chromastyles --style=github-dark */
2+
3+
/* Background */ .bg { color:#e6edf3;background-color:#0d1117; }
4+
/* PreWrapper */ .chroma { color:#e6edf3;background-color:#0d1117;-webkit-text-size-adjust:none; }
5+
/* Error */ .chroma .err { color:#f85149 }
6+
/* LineLink */ .chroma .lnlinks { outline:none;text-decoration:none;color:inherit }
7+
/* LineTableTD */ .chroma .lntd { vertical-align:top;padding:0;margin:0;border:0; }
8+
/* LineTable */ .chroma .lntable { border-spacing:0;padding:0;margin:0;border:0; }
9+
/* LineHighlight */ .chroma .hl { background-color:#6e7681 }
10+
/* LineNumbersTable */ .chroma .lnt { white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679 }
11+
/* LineNumbers */ .chroma .ln { white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#6e7681 }
12+
/* Line */ .chroma .line { display:flex; }
13+
/* Keyword */ .chroma .k { color:#ff7b72 }
14+
/* KeywordConstant */ .chroma .kc { color:#79c0ff }
15+
/* KeywordDeclaration */ .chroma .kd { color:#ff7b72 }
16+
/* KeywordNamespace */ .chroma .kn { color:#ff7b72 }
17+
/* KeywordPseudo */ .chroma .kp { color:#79c0ff }
18+
/* KeywordReserved */ .chroma .kr { color:#ff7b72 }
19+
/* KeywordType */ .chroma .kt { color:#ff7b72 }
20+
/* NameClass */ .chroma .nc { color:#f0883e;font-weight:bold }
21+
/* NameConstant */ .chroma .no { color:#79c0ff;font-weight:bold }
22+
/* NameDecorator */ .chroma .nd { color:#d2a8ff;font-weight:bold }
23+
/* NameEntity */ .chroma .ni { color:#ffa657 }
24+
/* NameException */ .chroma .ne { color:#f0883e;font-weight:bold }
25+
/* NameLabel */ .chroma .nl { color:#79c0ff;font-weight:bold }
26+
/* NameNamespace */ .chroma .nn { color:#ff7b72 }
27+
/* NameProperty */ .chroma .py { color:#79c0ff }
28+
/* NameTag */ .chroma .nt { color:#7ee787 }
29+
/* NameVariable */ .chroma .nv { color:#79c0ff }
30+
/* NameVariableClass */ .chroma .vc { color:#79c0ff }
31+
/* NameVariableGlobal */ .chroma .vg { color:#79c0ff }
32+
/* NameVariableInstance */ .chroma .vi { color:#79c0ff }
33+
/* NameVariableMagic */ .chroma .vm { color:#79c0ff }
34+
/* NameFunction */ .chroma .nf { color:#d2a8ff;font-weight:bold }
35+
/* NameFunctionMagic */ .chroma .fm { color:#d2a8ff;font-weight:bold }
36+
/* Literal */ .chroma .l { color:#a5d6ff }
37+
/* LiteralDate */ .chroma .ld { color:#79c0ff }
38+
/* LiteralString */ .chroma .s { color:#a5d6ff }
39+
/* LiteralStringAffix */ .chroma .sa { color:#79c0ff }
40+
/* LiteralStringBacktick */ .chroma .sb { color:#a5d6ff }
41+
/* LiteralStringChar */ .chroma .sc { color:#a5d6ff }
42+
/* LiteralStringDelimiter */ .chroma .dl { color:#79c0ff }
43+
/* LiteralStringDoc */ .chroma .sd { color:#a5d6ff }
44+
/* LiteralStringDouble */ .chroma .s2 { color:#a5d6ff }
45+
/* LiteralStringEscape */ .chroma .se { color:#79c0ff }
46+
/* LiteralStringHeredoc */ .chroma .sh { color:#79c0ff }
47+
/* LiteralStringInterpol */ .chroma .si { color:#a5d6ff }
48+
/* LiteralStringOther */ .chroma .sx { color:#a5d6ff }
49+
/* LiteralStringRegex */ .chroma .sr { color:#79c0ff }
50+
/* LiteralStringSingle */ .chroma .s1 { color:#a5d6ff }
51+
/* LiteralStringSymbol */ .chroma .ss { color:#a5d6ff }
52+
/* LiteralNumber */ .chroma .m { color:#a5d6ff }
53+
/* LiteralNumberBin */ .chroma .mb { color:#a5d6ff }
54+
/* LiteralNumberFloat */ .chroma .mf { color:#a5d6ff }
55+
/* LiteralNumberHex */ .chroma .mh { color:#a5d6ff }
56+
/* LiteralNumberInteger */ .chroma .mi { color:#a5d6ff }
57+
/* LiteralNumberIntegerLong */ .chroma .il { color:#a5d6ff }
58+
/* LiteralNumberOct */ .chroma .mo { color:#a5d6ff }
59+
/* Operator */ .chroma .o { color:#ff7b72;font-weight:bold }
60+
/* OperatorWord */ .chroma .ow { color:#ff7b72;font-weight:bold }
61+
/* Comment */ .chroma .c { color:#8b949e;font-style:italic }
62+
/* CommentHashbang */ .chroma .ch { color:#8b949e;font-style:italic }
63+
/* CommentMultiline */ .chroma .cm { color:#8b949e;font-style:italic }
64+
/* CommentSingle */ .chroma .c1 { color:#8b949e;font-style:italic }
65+
/* CommentSpecial */ .chroma .cs { color:#8b949e;font-weight:bold;font-style:italic }
66+
/* CommentPreproc */ .chroma .cp { color:#8b949e;font-weight:bold;font-style:italic }
67+
/* CommentPreprocFile */ .chroma .cpf { color:#8b949e;font-weight:bold;font-style:italic }
68+
/* GenericDeleted */ .chroma .gd { color:#ffa198;background-color:#490202 }
69+
/* GenericEmph */ .chroma .ge { font-style:italic }
70+
/* GenericError */ .chroma .gr { color:#ffa198 }
71+
/* GenericHeading */ .chroma .gh { color:#79c0ff;font-weight:bold }
72+
/* GenericInserted */ .chroma .gi { color:#56d364;background-color:#0f5323 }
73+
/* GenericOutput */ .chroma .go { color:#8b949e }
74+
/* GenericPrompt */ .chroma .gp { color:#8b949e }
75+
/* GenericStrong */ .chroma .gs { font-weight:bold }
76+
/* GenericSubheading */ .chroma .gu { color:#79c0ff }
77+
/* GenericTraceback */ .chroma .gt { color:#ff7b72 }
78+
/* GenericUnderline */ .chroma .gl { text-decoration:underline }
79+
/* TextWhitespace */ .chroma .w { color:#6e7681 }

0 commit comments

Comments
 (0)