From e6b87d28111457cbc2f497866b71d8a2d00e35bc Mon Sep 17 00:00:00 2001 From: Alexander Fuks Date: Tue, 24 Sep 2024 04:21:34 +0400 Subject: [PATCH 01/21] chore: remove `h1` element from site title (#1960) --- _includes/sidebar.html | 4 +--- _sass/addon/commons.scss | 12 +++++------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/_includes/sidebar.html b/_includes/sidebar.html index 4f0bb8c..569585f 100644 --- a/_includes/sidebar.html +++ b/_includes/sidebar.html @@ -11,9 +11,7 @@ {%- endif -%} -

- {{ site.title }} -

+ {{ site.title }}

{{ site.tagline }}

diff --git a/_sass/addon/commons.scss b/_sass/addon/commons.scss index 465cb08..e2a0e61 100644 --- a/_sass/addon/commons.scss +++ b/_sass/addon/commons.scss @@ -738,6 +738,9 @@ $btn-mb: 0.5rem; } .site-title { + @extend %clickable-transition; + @extend %sidebar-link-hover; + font-family: inherit; font-weight: 900; font-size: 1.75rem; @@ -745,13 +748,8 @@ $btn-mb: 0.5rem; letter-spacing: 0.25px; margin-top: 1.25rem; margin-bottom: 0.5rem; - - a { - @extend %clickable-transition; - @extend %sidebar-link-hover; - - color: var(--site-title-color); - } + width: fit-content; + color: var(--site-title-color); } .site-subtitle { From 93f616b25d7ed6c4f090c50c8663f8c1f59947f4 Mon Sep 17 00:00:00 2001 From: Cotes Chung <11371340+cotes2020@users.noreply.github.com> Date: Thu, 26 Sep 2024 22:30:56 +0800 Subject: [PATCH 02/21] fix: pagination error when pinned posts exceed the page size (#1965) --- _layouts/home.html | 45 ++++++++++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/_layouts/home.html b/_layouts/home.html index e44efe8..451e391 100644 --- a/_layouts/home.html +++ b/_layouts/home.html @@ -5,38 +5,45 @@ refactor: true {% include lang.html %} -{% assign pinned = site.posts | where: 'pin', 'true' %} -{% assign default = site.posts | where_exp: 'item', 'item.pin != true and item.hidden != true' %} +{% assign all_pinned = site.posts | where: 'pin', 'true' %} +{% assign all_normal = site.posts | where_exp: 'item', 'item.pin != true and item.hidden != true' %} {% assign posts = '' | split: '' %} - + -{% assign offset = paginator.page | minus: 1 | times: paginator.per_page %} -{% assign pinned_num = pinned.size | minus: offset %} +{% assign visible_start = paginator.page | minus: 1 | times: paginator.per_page %} +{% assign visible_end = visible_start | plus: paginator.per_page %} -{% if pinned_num > 0 %} - {% for i in (offset..pinned.size) limit: pinned_num %} - {% assign posts = posts | push: pinned[i] %} +{% if all_pinned.size > visible_start %} + {% if all_pinned.size > visible_end %} + {% assign pinned_size = paginator.per_page %} + {% else %} + {% assign pinned_size = all_pinned.size | minus: visible_start %} + {% endif %} + + {% for i in (visible_start..all_pinned.size) limit: pinned_size %} + {% assign posts = posts | push: all_pinned[i] %} {% endfor %} {% else %} - {% assign pinned_num = 0 %} + {% assign pinned_size = 0 %} {% endif %} - + -{% assign default_beg = offset | minus: pinned.size %} +{% assign normal_size = paginator.posts | size | minus: pinned_size %} -{% if default_beg < 0 %} - {% assign default_beg = 0 %} -{% endif %} +{% if normal_size > 0 %} + {% if pinned_size > 0 %} + {% assign normal_start = 0 %} + {% else %} + {% assign normal_start = visible_start | minus: all_pinned.size %} + {% endif %} -{% assign default_num = paginator.posts | size | minus: pinned_num %} -{% assign default_end = default_beg | plus: default_num | minus: 1 %} + {% assign normal_end = normal_start | plus: normal_size | minus: 1 %} -{% if default_num > 0 %} - {% for i in (default_beg..default_end) %} - {% assign posts = posts | push: default[i] %} + {% for i in (normal_start..normal_end) %} + {% assign posts = posts | push: all_normal[i] %} {% endfor %} {% endif %} From 740bd84c51cbb929438ea538ddc942f97d1c1431 Mon Sep 17 00:00:00 2001 From: Bence Boros <39780892+borosbence@users.noreply.github.com> Date: Tue, 1 Oct 2024 17:19:39 +0200 Subject: [PATCH 03/21] chore(i18n): update hungarian translation (#1976) --- _data/locales/hu-HU.yml | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/_data/locales/hu-HU.yml b/_data/locales/hu-HU.yml index 53d88e9..be3a31b 100644 --- a/_data/locales/hu-HU.yml +++ b/_data/locales/hu-HU.yml @@ -14,24 +14,23 @@ tabs: categories: Kategóriák tags: Címkék archives: Archívum - about: Rólam + about: Bemutatkozás # the text displayed in the search bar & search results search: hint: keresés cancel: Mégse - no_results: Oops! Nincs találat a keresésre. + no_results: Hoppá! Nincs találat a keresésre. panel: lastmod: Legutóbb frissítve trending_tags: Népszerű Címkék toc: Tartalom - links: Blog linkek copyright: # Shown at the bottom of the post license: - template: A bejegyzés :LICENSE_NAME licenccel rendelkezik. + template: A bejegyzést a szerző :LICENSE_NAME licenc alatt engedélyezte. name: CC BY 4.0 link: https://creativecommons.org/licenses/by/4.0/ @@ -42,7 +41,7 @@ copyright: Creative Commons Attribution 4.0 International (CC BY 4.0) licenccel rendelkeznek, hacsak másképp nincs jelezve. -meta: Készítve :PLATFORM motorral :THEME témával +meta: Készítve :THEME témával a :PLATFORM platformra. not_found: statement: Sajnáljuk, az URL-t rosszul helyeztük el, vagy valami nem létezőre mutat. @@ -73,7 +72,21 @@ post: title: Link másolása succeed: Link sikeresen másolva! +# Date time format. +# See: , +df: + post: + strftime: "%Y. %B. %e." + dayjs: "YYYY. MMMM D." + archives: + strftime: "%B" + dayjs: "MMM" + # categories page categories: - category_measure: kategória - post_measure: bejegyzés + category_measure: + singular: kategória + plural: kategória + post_measure: + singular: bejegyzés + plural: bejegyzés From 8a064a5e5a95cd22aa654f7c80da09d107262508 Mon Sep 17 00:00:00 2001 From: Alexander Fuks Date: Fri, 11 Oct 2024 18:32:10 +0400 Subject: [PATCH 04/21] feat: show toc on mobile screens (#1964) --- _includes/toc-status.html | 10 + _includes/toc.html | 9 +- _javascript/modules/components/toc.js | 39 +++- .../modules/components/toc/toc-desktop.js | 22 ++ .../modules/components/toc/toc-mobile.js | 117 ++++++++++ _javascript/modules/plugins.js | 2 +- _javascript/post.js | 7 +- _layouts/post.html | 28 ++- _sass/addon/commons.scss | 4 +- _sass/addon/module.scss | 7 + _sass/colors/typography-dark.scss | 2 +- _sass/colors/typography-light.scss | 2 +- _sass/layout/post.scss | 209 ++++++++++++++++++ 13 files changed, 429 insertions(+), 29 deletions(-) create mode 100644 _includes/toc-status.html create mode 100644 _javascript/modules/components/toc/toc-desktop.js create mode 100644 _javascript/modules/components/toc/toc-mobile.js diff --git a/_includes/toc-status.html b/_includes/toc-status.html new file mode 100644 index 0000000..4b71cae --- /dev/null +++ b/_includes/toc-status.html @@ -0,0 +1,10 @@ +{% comment %} + Determine TOC state and return it through variable "enable_toc" +{% endcomment %} + +{% assign enable_toc = false %} +{% if site.toc and page.toc %} + {% if page.content contains ' +

{{- site.data.locales[include.lang].panel.toc -}}

diff --git a/_javascript/modules/components/toc.js b/_javascript/modules/components/toc.js index 56ce26f..765336a 100644 --- a/_javascript/modules/components/toc.js +++ b/_javascript/modules/components/toc.js @@ -1,15 +1,30 @@ -export function toc() { - if (document.querySelector('main h2, main h3')) { - // see: https://github.com/tscanlin/tocbot#usage - tocbot.init({ - tocSelector: '#toc', - contentSelector: '.content', - ignoreSelector: '[data-toc-skip]', - headingSelector: 'h2, h3, h4', - orderedList: false, - scrollSmooth: false - }); +import { TocMobile as mobile } from './toc/toc-mobile'; +import { TocDesktop as desktop } from './toc/toc-desktop'; - document.getElementById('toc-wrapper').classList.remove('d-none'); +const desktopMode = matchMedia('(min-width: 1200px)'); + +function refresh(e) { + if (e.matches) { + mobile.hidePopup(); + desktop.refresh(); + } else { + mobile.refresh(); } } + +function init() { + if (document.querySelector('main>article[data-toc="true"]') === null) { + return; + } + + // Avoid create multiple instances of Tocbot. Ref: + if (desktopMode.matches) { + desktop.init(); + } else { + mobile.init(); + } + + desktopMode.onchange = refresh; +} + +export { init as initToc }; diff --git a/_javascript/modules/components/toc/toc-desktop.js b/_javascript/modules/components/toc/toc-desktop.js new file mode 100644 index 0000000..5021a72 --- /dev/null +++ b/_javascript/modules/components/toc/toc-desktop.js @@ -0,0 +1,22 @@ +export class TocDesktop { + /* Tocbot options Ref: https://github.com/tscanlin/tocbot#usage */ + static options = { + tocSelector: '#toc', + contentSelector: '.content', + ignoreSelector: '[data-toc-skip]', + headingSelector: 'h2, h3, h4', + orderedList: false, + scrollSmooth: false, + headingsOffset: 16 * 2 // 2rem + }; + + static refresh() { + tocbot.refresh(this.options); + } + + static init() { + if (document.getElementById('toc-wrapper')) { + tocbot.init(this.options); + } + } +} diff --git a/_javascript/modules/components/toc/toc-mobile.js b/_javascript/modules/components/toc/toc-mobile.js new file mode 100644 index 0000000..48b372d --- /dev/null +++ b/_javascript/modules/components/toc/toc-mobile.js @@ -0,0 +1,117 @@ +/** + * TOC button, topbar and popup for mobile devices + */ + +const $tocBar = document.getElementById('toc-bar'); +const $soloTrigger = document.getElementById('toc-solo-trigger'); +const $triggers = document.getElementsByClassName('toc-trigger'); +const $popup = document.getElementById('toc-popup'); +const $btnClose = document.getElementById('toc-popup-close'); + +const SCROLL_LOCK = 'overflow-hidden'; +const CLOSING = 'closing'; + +export class TocMobile { + static invisible = true; + static barHeight = 16 * 3; // 3rem + + static options = { + tocSelector: '#toc-popup-content', + contentSelector: '.content', + ignoreSelector: '[data-toc-skip]', + headingSelector: 'h2, h3, h4', + orderedList: false, + scrollSmooth: false, + collapseDepth: 4, + headingsOffset: this.barHeight + }; + + static initBar() { + const observer = new IntersectionObserver( + (entries) => { + entries.forEach((entry) => { + $tocBar.classList.toggle('invisible', entry.isIntersecting); + }); + }, + { rootMargin: `-${this.barHeight}px 0px 0px 0px` } + ); + + observer.observe($soloTrigger); + this.invisible = false; + } + + static listenAnchors() { + const $anchors = document.getElementsByClassName('toc-link'); + [...$anchors].forEach((anchor) => { + anchor.onclick = this.hidePopup; + }); + } + + static refresh() { + if (this.invisible) { + this.initComponents(); + } + tocbot.refresh(this.options); + this.listenAnchors(); + } + + static showPopup() { + TocMobile.lockScroll(true); + $popup.showModal(); + const activeItem = $popup.querySelector('li.is-active-li'); + activeItem.scrollIntoView({ block: 'center' }); + } + + static hidePopup() { + if (!$popup.open) { + return; + } + + $popup.toggleAttribute(CLOSING); + + $popup.addEventListener( + 'animationend', + () => { + $popup.toggleAttribute(CLOSING); + $popup.close(); + }, + { once: true } + ); + + TocMobile.lockScroll(false); + } + + static lockScroll(enable) { + document.documentElement.classList.toggle(SCROLL_LOCK, enable); + document.body.classList.toggle(SCROLL_LOCK, enable); + } + + static clickBackdrop(event) { + const rect = event.target.getBoundingClientRect(); + if ( + event.clientX < rect.left || + event.clientX > rect.right || + event.clientY < rect.top || + event.clientY > rect.bottom + ) { + TocMobile.hidePopup(); + } + } + + static initComponents() { + this.initBar(); + + [...$triggers].forEach((trigger) => { + trigger.onclick = this.showPopup; + }); + + $popup.onclick = this.clickBackdrop; + $btnClose.onclick = $popup.oncancel = this.hidePopup; + } + + static init() { + tocbot.init(this.options); + this.listenAnchors(); + this.initComponents(); + } +} diff --git a/_javascript/modules/plugins.js b/_javascript/modules/plugins.js index fb892e2..cc95c1b 100644 --- a/_javascript/modules/plugins.js +++ b/_javascript/modules/plugins.js @@ -3,4 +3,4 @@ export { initClipboard } from './components/clipboard'; export { loadImg } from './components/img-loading'; export { imgPopup } from './components/img-popup'; export { initLocaleDatetime } from './components/locale-datetime'; -export { toc } from './components/toc'; +export { initToc } from './components/toc'; diff --git a/_javascript/post.js b/_javascript/post.js index 9340f05..1c616ec 100644 --- a/_javascript/post.js +++ b/_javascript/post.js @@ -1,14 +1,15 @@ -import { basic, initSidebar, initTopbar } from './modules/layouts'; +import { basic, initTopbar, initSidebar } from './modules/layouts'; + import { loadImg, imgPopup, initLocaleDatetime, initClipboard, - toc + initToc } from './modules/plugins'; loadImg(); -toc(); +initToc(); imgPopup(); initSidebar(); initLocaleDatetime(); diff --git a/_layouts/post.html b/_layouts/post.html index f17ceea..bcc133f 100644 --- a/_layouts/post.html +++ b/_layouts/post.html @@ -11,7 +11,9 @@ tail_includes: {% include lang.html %} -
+{% include toc-status.html %} + +

{{ page.title }}

{% if page.description %} @@ -95,6 +97,30 @@ tail_includes:
+ {% if enable_toc %} + + + + + +
+
{{- page.title -}}
+ +
+
+
+ {% endif %} +
{{ content }}
diff --git a/_sass/addon/commons.scss b/_sass/addon/commons.scss index e2a0e61..e332f21 100644 --- a/_sass/addon/commons.scss +++ b/_sass/addon/commons.scss @@ -908,9 +908,7 @@ $btn-mb: 0.5rem; } #topbar { - button i { - color: #999999; - } + @extend %btn-color; #breadcrumb { font-size: 1rem; diff --git a/_sass/addon/module.scss b/_sass/addon/module.scss index 42db4e2..34ac67b 100644 --- a/_sass/addon/module.scss +++ b/_sass/addon/module.scss @@ -8,6 +8,7 @@ color: var(--heading-color); font-weight: 400; font-family: $font-family-heading; + scroll-margin-top: 3.5rem; } %anchor { @@ -134,6 +135,12 @@ } } +%btn-color { + button i { + color: #999999; + } +} + /* ---------- scss mixin --------- */ @mixin mt-mb($value) { diff --git a/_sass/colors/typography-dark.scss b/_sass/colors/typography-dark.scss index 12427ec..664c936 100644 --- a/_sass/colors/typography-dark.scss +++ b/_sass/colors/typography-dark.scss @@ -22,7 +22,6 @@ --btn-border-color: #2e2f31; --btn-backtotop-color: var(--text-color); --btn-backtotop-border-color: #212122; - --btn-box-shadow: var(--main-bg); --card-header-bg: #292929; --checkbox-color: rgb(118, 120, 121); --checkbox-checked-color: var(--link-color); @@ -60,6 +59,7 @@ /* Posts */ --toc-highlight: rgb(116, 178, 243); + --toc-popup-border-color: #373737; --tag-hover: rgb(43, 56, 62); --tb-odd-bg: #252526; /* odd rows of the posts' table */ --tb-even-bg: rgb(31, 31, 34); /* even rows of the posts' table */ diff --git a/_sass/colors/typography-light.scss b/_sass/colors/typography-light.scss index 7800074..b6fc561 100644 --- a/_sass/colors/typography-light.scss +++ b/_sass/colors/typography-light.scss @@ -22,7 +22,6 @@ --btn-border-color: #e9ecef; --btn-backtotop-color: #686868; --btn-backtotop-border-color: #f1f1f1; - --btn-box-shadow: #eaeaea; --checkbox-color: #c5c5c5; --checkbox-checked-color: #07a8f7; --img-bg: radial-gradient( @@ -63,6 +62,7 @@ /* Posts */ --toc-highlight: #0550ae; + --toc-popup-border-color: lightgray; --btn-share-color: gray; --btn-share-hover-color: #0d6efd; --card-bg: white; diff --git a/_sass/layout/post.scss b/_sass/layout/post.scss index 815db93..be72700 100644 --- a/_sass/layout/post.scss +++ b/_sass/layout/post.scss @@ -228,6 +228,7 @@ header { } } +/* TOC panel */ #toc-wrapper { border-left: 1px solid rgba(158, 158, 158, 0.17); position: -webkit-sticky; @@ -290,6 +291,201 @@ header { } } +/* --- TOC button, bar and popup in mobile/tablet --- */ + +#toc-bar { + position: -webkit-sticky; + position: sticky; + top: 0; + z-index: 1; + margin: 0 -1rem; + height: $topbar-height; + background: var(--main-bg); + border-bottom: 1px solid var(--main-border-color); + transition: all 0.2s ease-in-out; + + @extend %btn-color; + + .label { + @extend %heading; + + margin-left: 0.25rem; + padding: 0 0.75rem; + color: inherit; + } + + &.invisible { + top: -$topbar-height; + transition: none; + } +} + +#toc-solo-trigger { + color: var(--text-muted-color); + border-color: var(--btn-border-color); + border-radius: $radius-lg; + + .label { + font-size: 1rem; + font-family: $font-family-heading; + } + + &:hover { + box-shadow: none; + background: none; + } +} + +@mixin slide-in { + from { + opacity: 0.7; + transform: translateY(-$topbar-height); + } + + to { + opacity: 1; + transform: translateY(0); + } +} + +@mixin slide-out { + 0% { + transform: translateY(0); + opacity: 1; + } + + 100% { + transform: translateY(-$topbar-height); + opacity: 0; + } +} + +@-webkit-keyframes slide-in { + @include slide-in; +} + +@keyframes slide-in { + @include slide-in; +} + +@-webkit-keyframes slide-out { + @include slide-out; +} + +@keyframes slide-out { + @include slide-out; +} + +#toc-popup { + $slide-in: slide-in 0.3s ease-out; + $slide-out: slide-out 0.3s ease-out; + $curtain-height: 2rem; + + border-color: var(--toc-popup-border-color); + border-width: 1px; + border-radius: $radius-lg; + color: var(--text-color); + background: var(--main-bg); + margin-top: $topbar-height; + min-width: 20rem; + font-size: 1.05rem; + + @media all and (min-width: 576px) { + max-width: 32rem; + } + + &[open] { + -webkit-animation: $slide-in; + animation: $slide-in; + } + + &[closing] { + -webkit-animation: $slide-out; + animation: $slide-out; + } + + @media all and (min-width: 850px) { + left: $sidebar-width; + } + + .header { + @extend %btn-color; + + position: -webkit-sticky; + position: sticky; + top: 0; + background-color: inherit; + border-bottom: 1px solid var(--main-border-color); + + .label { + font-family: $font-family-heading; + } + } + + button:focus-visible { + box-shadow: none; + } + + ul { + list-style-type: none; + padding-left: 0; + + li { + ul, + & + li { + margin-top: 0.25rem; + } + + a { + display: flex; + line-height: 1.5; + padding: 0.375rem 0; + padding-right: 1.125rem; + + &.toc-link::before { + display: none; + } + } + } + } + + @for $i from 2 through 4 { + .node-name--H#{$i} { + padding-left: 1.125rem * ($i - 1); + } + } + + .is-active-link { + color: var(--toc-highlight) !important; + font-weight: 600; + } + + &::-webkit-backdrop { + -webkit-backdrop-filter: blur(5px); + backdrop-filter: blur(5px); + } + + &::backdrop { + -webkit-backdrop-filter: blur(5px); + backdrop-filter: blur(5px); + } + + &::after { + display: flex; + content: ''; + position: relative; + background: linear-gradient(transparent, var(--main-bg) 70%); + height: $curtain-height; + } + + #toc-popup-content { + overflow: auto; + max-height: calc(100vh - 4 * $topbar-height); + font-family: $font-family-heading; + margin-bottom: -$curtain-height; + } +} + /* --- Related Posts --- */ #related-posts { @@ -368,3 +564,16 @@ header { margin-right: -0.5rem; } } + +@media all and (min-width: 1200px) { + h2, + h3, + h4 { + scroll-margin-top: 2rem; + } + + #toc-bar, + #toc-solo-trigger { + display: none !important; + } +} From 03e302cbf68cc502a2b6bef0726186a0b3ef321c Mon Sep 17 00:00:00 2001 From: Alexander Fuks Date: Sun, 13 Oct 2024 21:16:25 +0400 Subject: [PATCH 05/21] chore: close toc-popup gracefully with Esc key (#1990) --- _javascript/modules/components/toc/toc-mobile.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/_javascript/modules/components/toc/toc-mobile.js b/_javascript/modules/components/toc/toc-mobile.js index 48b372d..8d717dd 100644 --- a/_javascript/modules/components/toc/toc-mobile.js +++ b/_javascript/modules/components/toc/toc-mobile.js @@ -62,7 +62,11 @@ export class TocMobile { activeItem.scrollIntoView({ block: 'center' }); } - static hidePopup() { + static hidePopup(event) { + if (event?.type === 'cancel') { + event.preventDefault(); + } + if (!$popup.open) { return; } From 6f461132c00c7f7d557e0b865530bb256c1fe5be Mon Sep 17 00:00:00 2001 From: Cotes Chung <11371340+cotes2020@users.noreply.github.com> Date: Sat, 19 Oct 2024 21:13:21 +0800 Subject: [PATCH 06/21] refactor: improve toc popup module --- _javascript/modules/components/toc.js | 5 +- .../modules/components/toc/toc-mobile.js | 48 ++++++++++--------- _layouts/post.html | 6 +-- _sass/layout/post.scss | 24 ++++++---- 4 files changed, 49 insertions(+), 34 deletions(-) diff --git a/_javascript/modules/components/toc.js b/_javascript/modules/components/toc.js index 765336a..e9086ee 100644 --- a/_javascript/modules/components/toc.js +++ b/_javascript/modules/components/toc.js @@ -5,7 +5,10 @@ const desktopMode = matchMedia('(min-width: 1200px)'); function refresh(e) { if (e.matches) { - mobile.hidePopup(); + if (mobile.popupOpened) { + mobile.hidePopup(); + } + desktop.refresh(); } else { mobile.refresh(); diff --git a/_javascript/modules/components/toc/toc-mobile.js b/_javascript/modules/components/toc/toc-mobile.js index 8d717dd..20e24a7 100644 --- a/_javascript/modules/components/toc/toc-mobile.js +++ b/_javascript/modules/components/toc/toc-mobile.js @@ -12,8 +12,8 @@ const SCROLL_LOCK = 'overflow-hidden'; const CLOSING = 'closing'; export class TocMobile { - static invisible = true; - static barHeight = 16 * 3; // 3rem + static #invisible = true; + static #barHeight = 16 * 3; // 3rem static options = { tocSelector: '#toc-popup-content', @@ -23,7 +23,7 @@ export class TocMobile { orderedList: false, scrollSmooth: false, collapseDepth: 4, - headingsOffset: this.barHeight + headingsOffset: this.#barHeight }; static initBar() { @@ -33,44 +33,40 @@ export class TocMobile { $tocBar.classList.toggle('invisible', entry.isIntersecting); }); }, - { rootMargin: `-${this.barHeight}px 0px 0px 0px` } + { rootMargin: `-${this.#barHeight}px 0px 0px 0px` } ); observer.observe($soloTrigger); - this.invisible = false; + this.#invisible = false; } static listenAnchors() { const $anchors = document.getElementsByClassName('toc-link'); [...$anchors].forEach((anchor) => { - anchor.onclick = this.hidePopup; + anchor.onclick = () => this.hidePopup(); }); } static refresh() { - if (this.invisible) { + if (this.#invisible) { this.initComponents(); } tocbot.refresh(this.options); this.listenAnchors(); } + static get popupOpened() { + return $popup.open; + } + static showPopup() { - TocMobile.lockScroll(true); + this.lockScroll(true); $popup.showModal(); const activeItem = $popup.querySelector('li.is-active-li'); activeItem.scrollIntoView({ block: 'center' }); } - static hidePopup(event) { - if (event?.type === 'cancel') { - event.preventDefault(); - } - - if (!$popup.open) { - return; - } - + static hidePopup() { $popup.toggleAttribute(CLOSING); $popup.addEventListener( @@ -82,7 +78,7 @@ export class TocMobile { { once: true } ); - TocMobile.lockScroll(false); + this.lockScroll(false); } static lockScroll(enable) { @@ -91,6 +87,10 @@ export class TocMobile { } static clickBackdrop(event) { + if ($popup.hasAttribute(CLOSING)) { + return; + } + const rect = event.target.getBoundingClientRect(); if ( event.clientX < rect.left || @@ -98,7 +98,7 @@ export class TocMobile { event.clientY < rect.top || event.clientY > rect.bottom ) { - TocMobile.hidePopup(); + this.hidePopup(); } } @@ -106,11 +106,15 @@ export class TocMobile { this.initBar(); [...$triggers].forEach((trigger) => { - trigger.onclick = this.showPopup; + trigger.onclick = () => this.showPopup(); }); - $popup.onclick = this.clickBackdrop; - $btnClose.onclick = $popup.oncancel = this.hidePopup; + $popup.onclick = (e) => this.clickBackdrop(e); + $btnClose.onclick = () => this.hidePopup(); + $popup.oncancel = (e) => { + e.preventDefault(); + this.hidePopup(); + }; } static init() { diff --git a/_layouts/post.html b/_layouts/post.html index bcc133f..6a2deff 100644 --- a/_layouts/post.html +++ b/_layouts/post.html @@ -100,7 +100,7 @@ tail_includes: {% if enable_toc %} @@ -113,8 +113,8 @@ tail_includes:
{{- page.title -}}
-
diff --git a/_sass/layout/post.scss b/_sass/layout/post.scss index be72700..01021f3 100644 --- a/_sass/layout/post.scss +++ b/_sass/layout/post.scss @@ -380,12 +380,13 @@ header { $slide-in: slide-in 0.3s ease-out; $slide-out: slide-out 0.3s ease-out; $curtain-height: 2rem; + $backdrop: blur(5px); border-color: var(--toc-popup-border-color); border-width: 1px; border-radius: $radius-lg; color: var(--text-color); - background: var(--main-bg); + background: var(--card-bg); margin-top: $topbar-height; min-width: 20rem; font-size: 1.05rem; @@ -422,8 +423,15 @@ header { } } - button:focus-visible { - box-shadow: none; + button { + > i { + font-size: 1.25rem; + vertical-align: middle; + } + + &:focus-visible { + box-shadow: none; + } } ul { @@ -461,20 +469,20 @@ header { } &::-webkit-backdrop { - -webkit-backdrop-filter: blur(5px); - backdrop-filter: blur(5px); + -webkit-backdrop-filter: $backdrop; + backdrop-filter: $backdrop; } &::backdrop { - -webkit-backdrop-filter: blur(5px); - backdrop-filter: blur(5px); + -webkit-backdrop-filter: $backdrop; + backdrop-filter: $backdrop; } &::after { display: flex; content: ''; position: relative; - background: linear-gradient(transparent, var(--main-bg) 70%); + background: linear-gradient(transparent, var(--card-bg) 70%); height: $curtain-height; } From c1bd9eb9eece4cf3b7e76d750bcc4108aec63361 Mon Sep 17 00:00:00 2001 From: Cotes Chung <11371340+cotes2020@users.noreply.github.com> Date: Sun, 20 Oct 2024 13:47:54 +0800 Subject: [PATCH 07/21] refactor: reduce duplicate scss --- _sass/addon/commons.scss | 22 ++++++++++------------ _sass/addon/module.scss | 21 ++++++++++++++++++--- _sass/layout/archives.scss | 5 ++--- _sass/layout/category-tag.scss | 4 +--- _sass/layout/home.scss | 5 ++--- _sass/layout/post.scss | 26 ++++++++++++-------------- 6 files changed, 45 insertions(+), 38 deletions(-) diff --git a/_sass/addon/commons.scss b/_sass/addon/commons.scss index e332f21..2bf99b8 100644 --- a/_sass/addon/commons.scss +++ b/_sass/addon/commons.scss @@ -251,8 +251,8 @@ i { > p { margin-left: 0.25em; - margin-top: 0; - margin-bottom: 0; + + @include mt-mb(0); } } } @@ -769,8 +769,8 @@ $btn-mb: 0.5rem; li.nav-item { opacity: 0.9; width: 100%; - padding-left: 1.5rem; - padding-right: 1.5rem; + + @include pl-pr(1.5rem); a.nav-link { @include pt-pb(0.6rem); @@ -1043,7 +1043,7 @@ search { a { font-size: 1.4rem; - line-height: 2.5rem; + line-height: 1.5rem; &:hover { @extend %link-hover; @@ -1069,8 +1069,9 @@ search { } > p { - overflow: hidden; - text-overflow: ellipsis; + @extend %text-ellipsis; + + white-space: break-spaces; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; @@ -1086,10 +1087,7 @@ search { color: var(--topbar-text-color); text-align: center; width: 70%; - overflow: hidden; - text-overflow: ellipsis; word-break: keep-all; - white-space: nowrap; } #mask { @@ -1492,8 +1490,8 @@ search { #main-wrapper > .container { max-width: $main-content-max-width; - padding-left: 1.75rem !important; - padding-right: 1.75rem !important; + + @include pl-pr(1.75rem, true); } main.col-12, diff --git a/_sass/addon/module.scss b/_sass/addon/module.scss index 34ac67b..1dfb735 100644 --- a/_sass/addon/module.scss +++ b/_sass/addon/module.scss @@ -112,6 +112,16 @@ -webkit-box-orient: vertical; } +@mixin text-ellipsis { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +%text-ellipsis { + @include text-ellipsis; +} + %text-highlight { color: var(--text-muted-highlight-color); font-weight: 600; @@ -158,9 +168,14 @@ padding-bottom: $val; } -@mixin pl-pr($val) { - padding-left: $val; - padding-right: $val; +@mixin pl-pr($val, $important: false) { + @if $important { + padding-left: $val !important; + padding-right: $val !important; + } @else { + padding-left: $val; + padding-right: $val; + } } @mixin placeholder { diff --git a/_sass/layout/archives.scss b/_sass/layout/archives.scss index 3a2e86b..fd1979b 100644 --- a/_sass/layout/archives.scss +++ b/_sass/layout/archives.scss @@ -58,9 +58,8 @@ li { font-size: 1.1rem; line-height: 3rem; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; + + @extend %text-ellipsis; &:nth-child(odd) { background-color: var(--main-bg, #ffffff); diff --git a/_sass/layout/category-tag.scss b/_sass/layout/category-tag.scss index 9e43a91..fe7d99c 100644 --- a/_sass/layout/category-tag.scss +++ b/_sass/layout/category-tag.scss @@ -63,9 +63,7 @@ } > a { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; + @include text-ellipsis; } } } diff --git a/_sass/layout/home.scss b/_sass/layout/home.scss index 0d95d7b..7fff3ba 100644 --- a/_sass/layout/home.scss +++ b/_sass/layout/home.scss @@ -74,9 +74,8 @@ > div:first-child { display: block; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; + + @extend %text-ellipsis; } } } diff --git a/_sass/layout/post.scss b/_sass/layout/post.scss index 01021f3..b66e906 100644 --- a/_sass/layout/post.scss +++ b/_sass/layout/post.scss @@ -1,6 +1,6 @@ -/* - Post-specific style -*/ +/** + * Post-specific styles + */ %btn-post-nav { width: 50%; @@ -97,7 +97,7 @@ header { &:hover { i { - @extend %btn-share-hovor; + @extend %btn-share-hover; } } } @@ -258,9 +258,8 @@ header { .toc-link { display: block; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; + + @extend %text-ellipsis; &:hover { color: var(--toc-highlight); @@ -509,10 +508,11 @@ header { } p { + @extend %text-ellipsis; + font-size: 0.9rem; margin-bottom: 0.5rem; - overflow: hidden; - text-overflow: ellipsis; + white-space: break-spaces; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; @@ -534,7 +534,7 @@ header { max-width: 100%; } -%btn-share-hovor { +%btn-share-hover { color: var(--btn-share-hover-color) !important; } @@ -566,10 +566,8 @@ header { /* Hide SideBar and TOC */ @media all and (max-width: 849px) { .post-navigation { - padding-left: 0; - padding-right: 0; - margin-left: -0.5rem; - margin-right: -0.5rem; + @include pl-pr(0); + @include ml-mr(-0.5rem); } } From d4f7f39ece2d8feaca963b8bfba331268b28811e Mon Sep 17 00:00:00 2001 From: Cotes Chung <11371340+cotes2020@users.noreply.github.com> Date: Tue, 22 Oct 2024 10:42:07 +0800 Subject: [PATCH 08/21] refactor: simplify sidebar animation --- _javascript/modules/components/sidebar.js | 23 +++++++++-------------- _layouts/default.html | 2 +- _sass/addon/commons.scss | 10 ---------- 3 files changed, 10 insertions(+), 25 deletions(-) diff --git a/_javascript/modules/components/sidebar.js b/_javascript/modules/components/sidebar.js index 6b562d8..aed759e 100644 --- a/_javascript/modules/components/sidebar.js +++ b/_javascript/modules/components/sidebar.js @@ -2,26 +2,21 @@ * Expand or close the sidebar in mobile screens. */ -const ATTR_DISPLAY = 'sidebar-display'; +const $sidebar = document.getElementById('sidebar'); +const $trigger = document.getElementById('sidebar-trigger'); +const $mask = document.getElementById('mask'); class SidebarUtil { - static isExpanded = false; + static #isExpanded = false; static toggle() { - if (SidebarUtil.isExpanded === false) { - document.body.setAttribute(ATTR_DISPLAY, ''); - } else { - document.body.removeAttribute(ATTR_DISPLAY); - } - - SidebarUtil.isExpanded = !SidebarUtil.isExpanded; + this.#isExpanded = !this.#isExpanded; + document.body.toggleAttribute('sidebar-display', this.#isExpanded); + $sidebar.classList.toggle('z-2', this.#isExpanded); + $mask.classList.toggle('d-none', !this.#isExpanded); } } export function sidebarExpand() { - document - .getElementById('sidebar-trigger') - .addEventListener('click', SidebarUtil.toggle); - - document.getElementById('mask').addEventListener('click', SidebarUtil.toggle); + $trigger.onclick = $mask.onclick = () => SidebarUtil.toggle(); } diff --git a/_layouts/default.html b/_layouts/default.html index ea438fe..1590ef6 100644 --- a/_layouts/default.html +++ b/_layouts/default.html @@ -68,7 +68,7 @@ layout: compress -
+
{% if site.pwa.enabled %} {% include_cached notification.html lang=lang %} diff --git a/_sass/addon/commons.scss b/_sass/addon/commons.scss index 2bf99b8..5e8acea 100644 --- a/_sass/addon/commons.scss +++ b/_sass/addon/commons.scss @@ -688,7 +688,6 @@ $btn-mb: 0.5rem; height: 100%; overflow-y: auto; width: $sidebar-width; - z-index: 99; background: var(--sidebar-bg); border-right: 1px solid var(--sidebar-border-color); @@ -1091,16 +1090,7 @@ search { } #mask { - display: none; - position: fixed; inset: 0 0 0 0; - height: 100%; - width: 100%; - z-index: 1; - - @at-root [#{$sidebar-display}] & { - display: block !important; - } } /* --- basic wrappers --- */ From 74ed06321c1730dc788af3306b80a0f1739510d4 Mon Sep 17 00:00:00 2001 From: Cotes Chung <11371340+cotes2020@users.noreply.github.com> Date: Fri, 25 Oct 2024 19:48:11 +0800 Subject: [PATCH 09/21] ci: block invalid pull requests (#2010) --- .github/workflows/pr-filter.yml | 22 ++++++++++++++ .github/workflows/scripts/pr-filter.js | 40 ++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 .github/workflows/pr-filter.yml create mode 100644 .github/workflows/scripts/pr-filter.js diff --git a/.github/workflows/pr-filter.yml b/.github/workflows/pr-filter.yml new file mode 100644 index 0000000..b6bcd00 --- /dev/null +++ b/.github/workflows/pr-filter.yml @@ -0,0 +1,22 @@ +name: Block Invalid PR + +on: + pull_request_target: + types: [opened, reopened, edited] + +jobs: + check-template: + runs-on: ubuntu-latest + permissions: + pull-requests: write + steps: + - name: Checkout Code + uses: actions/checkout@v4 + + - name: Check PR Content + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const script = require('.github/workflows/scripts/pr-filter.js'); + await script({ github, context }); diff --git a/.github/workflows/scripts/pr-filter.js b/.github/workflows/scripts/pr-filter.js new file mode 100644 index 0000000..e720630 --- /dev/null +++ b/.github/workflows/scripts/pr-filter.js @@ -0,0 +1,40 @@ +function noTypes(markdown) { + if (/## Type of change/.test(markdown) && /- \[x\]/i.test(markdown)) { + return false; + } + return true; +} + +function noDescription(markdown) { + return ( + /## Description/.test(markdown) === false || + /## Description\s*\n\s*## \w+/.test(markdown) || + /## Description\s*\n\s*$/.test(markdown) + ); +} + +module.exports = async ({ github, context }) => { + const pr = context.payload.pull_request; + + if (pr.labels.length > 0) { + // Skip if the PR is already labeled (typically created by a deps-bot.) + return; + } + + const body = pr.body === null ? '' : pr.body.trim(); + const markdown = body.replace(//g, ''); + + if (body === '' || noTypes(markdown) || noDescription(markdown)) { + await github.rest.pulls.update({ + ...context.repo, + pull_number: pr.number, + state: 'closed' + }); + + await github.rest.issues.createComment({ + ...context.repo, + issue_number: pr.number, + body: "Oops, it seems you've submitted an invalid pull request. No worries, we'll close it for you." + }); + } +}; From c7f967529c294f9622f142470406f2be43ea4d35 Mon Sep 17 00:00:00 2001 From: Cotes Chung <11371340+cotes2020@users.noreply.github.com> Date: Sat, 26 Oct 2024 16:58:07 +0800 Subject: [PATCH 10/21] ci: skip test for invalid PRs (#2013) --- .github/workflows/ci.yml | 7 +++++- .github/workflows/commitlint.yml | 3 ++- .github/workflows/pr-filter.yml | 17 +++++++++++--- .github/workflows/scripts/pr-filter.js | 31 ++++++++++++-------------- 4 files changed, 36 insertions(+), 22 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 50a158b..f909b7e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,4 +1,5 @@ name: "CI" + on: push: branches: @@ -11,7 +12,7 @@ on: - "docs/**" - "README.md" - "LICENSE" - pull_request: + workflow_call: jobs: build: @@ -43,3 +44,7 @@ jobs: - name: Test Site run: bash tools/test.sh + + check-commit: + needs: build + uses: ./.github/workflows/commitlint.yml diff --git a/.github/workflows/commitlint.yml b/.github/workflows/commitlint.yml index c9c48c3..ac8726f 100644 --- a/.github/workflows/commitlint.yml +++ b/.github/workflows/commitlint.yml @@ -1,5 +1,6 @@ name: Lint Commit Messages -on: pull_request + +on: workflow_call jobs: commitlint: diff --git a/.github/workflows/pr-filter.yml b/.github/workflows/pr-filter.yml index b6bcd00..fe393a2 100644 --- a/.github/workflows/pr-filter.yml +++ b/.github/workflows/pr-filter.yml @@ -1,22 +1,33 @@ -name: Block Invalid PR +name: PR Filter on: pull_request_target: - types: [opened, reopened, edited] + types: [opened, reopened] jobs: check-template: runs-on: ubuntu-latest permissions: pull-requests: write + steps: - name: Checkout Code uses: actions/checkout@v4 - name: Check PR Content + id: intercept uses: actions/github-script@v7 with: github-token: ${{ secrets.GITHUB_TOKEN }} + result-encoding: string script: | const script = require('.github/workflows/scripts/pr-filter.js'); - await script({ github, context }); + return await script({ github, context }); + + - name: Abort due to invalid PR + if: ${{ steps.intercept.outputs.result != 'true' }} + run: exit 1 + + test: + needs: check-template + uses: ./.github/workflows/ci.yml diff --git a/.github/workflows/scripts/pr-filter.js b/.github/workflows/scripts/pr-filter.js index e720630..f4190dd 100644 --- a/.github/workflows/scripts/pr-filter.js +++ b/.github/workflows/scripts/pr-filter.js @@ -1,30 +1,25 @@ -function noTypes(markdown) { - if (/## Type of change/.test(markdown) && /- \[x\]/i.test(markdown)) { - return false; - } - return true; +function hasTypes(markdown) { + return /## Type of change/.test(markdown) && /-\s*\[x\]/i.test(markdown); } -function noDescription(markdown) { +function hasDescription(markdown) { return ( - /## Description/.test(markdown) === false || - /## Description\s*\n\s*## \w+/.test(markdown) || - /## Description\s*\n\s*$/.test(markdown) + /## Description/.test(markdown) && + !/## Description\s*\n\s*(##|\s*$)/.test(markdown) ); } module.exports = async ({ github, context }) => { const pr = context.payload.pull_request; - - if (pr.labels.length > 0) { - // Skip if the PR is already labeled (typically created by a deps-bot.) - return; - } - const body = pr.body === null ? '' : pr.body.trim(); const markdown = body.replace(//g, ''); + const action = context.payload.action; - if (body === '' || noTypes(markdown) || noDescription(markdown)) { + const isValid = + pr.labels.length > 0 || // PR create by Dependabot would have labels + (markdown !== '' && hasTypes(markdown) && hasDescription(markdown)); + + if (!isValid) { await github.rest.pulls.update({ ...context.repo, pull_number: pr.number, @@ -34,7 +29,9 @@ module.exports = async ({ github, context }) => { await github.rest.issues.createComment({ ...context.repo, issue_number: pr.number, - body: "Oops, it seems you've submitted an invalid pull request. No worries, we'll close it for you." + body: `Oops, it seems you've ${action} an invalid pull request. No worries, we'll close it for you.` }); } + + return isValid; }; From 4ef3cd8efc90518cc56b4e92306f81aa36feee70 Mon Sep 17 00:00:00 2001 From: Cotes Chung <11371340+cotes2020@users.noreply.github.com> Date: Tue, 29 Oct 2024 22:56:32 +0800 Subject: [PATCH 11/21] ci: improve workflow triggers (#2017) - Unchain commit-lint and CI - Even if a commit does not meet the CI path filter, it still needs to lint the commit message. - Unchain PR filter and CI - The CI workflow needs to be triggered when the commits in a pull request are modified. - Allow manual publishing - Sometimes `semantic-release` will error out due to commit messages referencing discussions, but this does not affect the final RubyGems/GitHub Release. In such cases, manual triggering of the publish process is needed to complete the remaining publishing steps. --- .github/workflows/cd.yml | 7 +++---- .github/workflows/ci.yml | 25 ++++++++++++++----------- .github/workflows/commitlint.yml | 7 ++++++- .github/workflows/pr-filter.yml | 11 +---------- .github/workflows/publish.yml | 1 + .github/workflows/scripts/pr-filter.js | 10 +++++----- .github/workflows/style-lint.yml | 6 ++++-- 7 files changed, 34 insertions(+), 33 deletions(-) diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 4f2da0e..c665f75 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -2,13 +2,12 @@ name: CD on: push: - branches: - - production - tags-ignore: - - "**" + branches: [production] + tags-ignore: ["**"] jobs: release: + if: ${{ ! startsWith(github.event.head_commit.message, 'chore(release)') }} permissions: contents: write issues: write diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f909b7e..31b8786 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,18 +1,25 @@ -name: "CI" +name: CI on: push: branches: - - "master" - - "hotfix/**" + - master + - "hotfix/*" paths-ignore: - ".github/**" - "!.github/workflows/ci.yml" - - ".gitignore" + - .gitignore - "docs/**" - - "README.md" - - "LICENSE" - workflow_call: + - README.md + - LICENSE + pull_request: + paths-ignore: + - ".github/**" + - "!.github/workflows/ci.yml" + - .gitignore + - "docs/**" + - README.md + - LICENSE jobs: build: @@ -44,7 +51,3 @@ jobs: - name: Test Site run: bash tools/test.sh - - check-commit: - needs: build - uses: ./.github/workflows/commitlint.yml diff --git a/.github/workflows/commitlint.yml b/.github/workflows/commitlint.yml index ac8726f..58f1a3f 100644 --- a/.github/workflows/commitlint.yml +++ b/.github/workflows/commitlint.yml @@ -1,6 +1,11 @@ name: Lint Commit Messages -on: workflow_call +on: + push: + branches: + - master + - "hotfix/*" + pull_request: jobs: commitlint: diff --git a/.github/workflows/pr-filter.yml b/.github/workflows/pr-filter.yml index fe393a2..42e1d64 100644 --- a/.github/workflows/pr-filter.yml +++ b/.github/workflows/pr-filter.yml @@ -19,15 +19,6 @@ jobs: uses: actions/github-script@v7 with: github-token: ${{ secrets.GITHUB_TOKEN }} - result-encoding: string script: | const script = require('.github/workflows/scripts/pr-filter.js'); - return await script({ github, context }); - - - name: Abort due to invalid PR - if: ${{ steps.intercept.outputs.result != 'true' }} - run: exit 1 - - test: - needs: check-template - uses: ./.github/workflows/ci.yml + await script({ github, context, core }); diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 99114ea..b0f9713 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -10,6 +10,7 @@ on: required: true BUILDER: required: true + workflow_dispatch: jobs: launch: diff --git a/.github/workflows/scripts/pr-filter.js b/.github/workflows/scripts/pr-filter.js index f4190dd..9724201 100644 --- a/.github/workflows/scripts/pr-filter.js +++ b/.github/workflows/scripts/pr-filter.js @@ -1,5 +1,5 @@ function hasTypes(markdown) { - return /## Type of change/.test(markdown) && /-\s*\[x\]/i.test(markdown); + return /## Type of change/.test(markdown) && /-\s\[x\]/i.test(markdown); } function hasDescription(markdown) { @@ -9,9 +9,9 @@ function hasDescription(markdown) { ); } -module.exports = async ({ github, context }) => { +module.exports = async ({ github, context, core }) => { const pr = context.payload.pull_request; - const body = pr.body === null ? '' : pr.body.trim(); + const body = pr.body === null ? '' : pr.body; const markdown = body.replace(//g, ''); const action = context.payload.action; @@ -31,7 +31,7 @@ module.exports = async ({ github, context }) => { issue_number: pr.number, body: `Oops, it seems you've ${action} an invalid pull request. No worries, we'll close it for you.` }); - } - return isValid; + core.setFailed('PR content does not meet template requirements.'); + } }; diff --git a/.github/workflows/style-lint.yml b/.github/workflows/style-lint.yml index f84f3bc..5cb38a7 100644 --- a/.github/workflows/style-lint.yml +++ b/.github/workflows/style-lint.yml @@ -1,8 +1,10 @@ -name: "Style Lint" +name: Style Lint on: push: - branches: ["master", "hotfix/**"] + branches: + - master + - "hotfix/*" paths: ["_sass/**/*.scss"] pull_request: paths: ["_sass/**/*.scss"] From 86b13c917f8f9477b10766fb621cbe987c025203 Mon Sep 17 00:00:00 2001 From: Alexander Fuks Date: Fri, 1 Nov 2024 14:39:03 +0400 Subject: [PATCH 12/21] chore: improve feed interoperability (#2024) --- assets/feed.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/feed.xml b/assets/feed.xml index 0ab20e3..d2aad4d 100644 --- a/assets/feed.xml +++ b/assets/feed.xml @@ -34,7 +34,7 @@ permalink: /feed.xml {{ post.date | date_to_xmlschema }} {% endif %} {{ post_absolute_url }} - + {{ post.author | default: site.social.name }} From 42dea8ee2986ee609ca6f2643a03bd29bd5456a3 Mon Sep 17 00:00:00 2001 From: Supreeth Mysore Venkatesh Date: Sun, 3 Nov 2024 17:45:59 +0100 Subject: [PATCH 13/21] build(deps): update `wdm` gem version for compatibility (#2028) --- Gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index 66f9337..e541574 100644 --- a/Gemfile +++ b/Gemfile @@ -11,4 +11,4 @@ platforms :mingw, :x64_mingw, :mswin, :jruby do gem "tzinfo-data" end -gem "wdm", "~> 0.1.1", :platforms => [:mingw, :x64_mingw, :mswin] +gem "wdm", "~> 0.2.0", :platforms => [:mingw, :x64_mingw, :mswin] From 2f844978aac587a8631c16d6907f24a8af6035a3 Mon Sep 17 00:00:00 2001 From: Cotes Chung <11371340+cotes2020@users.noreply.github.com> Date: Fri, 8 Nov 2024 22:15:31 +0800 Subject: [PATCH 14/21] chore: change stale label to `inactive` --- .github/workflows/stale.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index bcf425a..4f6e91c 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -9,7 +9,7 @@ permissions: pull-requests: write env: - STALE_LABEL: stale + STALE_LABEL: inactive EXEMPT_LABELS: "pending,planning,in progress" MESSAGE: > This conversation has been automatically marked as stale because it has not had recent activity. From d51345e29754ba92a0c2fd6534bbd248ff298331 Mon Sep 17 00:00:00 2001 From: Cotes Chung <11371340+cotes2020@users.noreply.github.com> Date: Fri, 8 Nov 2024 22:35:18 +0800 Subject: [PATCH 15/21] ci: reduce unnecessary pr-filter runs (#2033) - Checking the repository of the PR is more effective than checking the label to identify bot-initiated PRs - This change also allows more flexible PR body definitions for developers with write access to the repository --- .github/workflows/pr-filter.yml | 1 + .github/workflows/scripts/pr-filter.js | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pr-filter.yml b/.github/workflows/pr-filter.yml index 42e1d64..8e9a18b 100644 --- a/.github/workflows/pr-filter.yml +++ b/.github/workflows/pr-filter.yml @@ -6,6 +6,7 @@ on: jobs: check-template: + if: github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name runs-on: ubuntu-latest permissions: pull-requests: write diff --git a/.github/workflows/scripts/pr-filter.js b/.github/workflows/scripts/pr-filter.js index 9724201..03f50dc 100644 --- a/.github/workflows/scripts/pr-filter.js +++ b/.github/workflows/scripts/pr-filter.js @@ -16,8 +16,7 @@ module.exports = async ({ github, context, core }) => { const action = context.payload.action; const isValid = - pr.labels.length > 0 || // PR create by Dependabot would have labels - (markdown !== '' && hasTypes(markdown) && hasDescription(markdown)); + markdown !== '' && hasTypes(markdown) && hasDescription(markdown); if (!isValid) { await github.rest.pulls.update({ From 65f960c31a734b5306a8b919040c3aae9b783efd Mon Sep 17 00:00:00 2001 From: Cotes Chung <11371340+cotes2020@users.noreply.github.com> Date: Sat, 16 Nov 2024 22:49:55 +0800 Subject: [PATCH 16/21] perf: speed up page rendering and jekyll build process (#2034) - Ensure inline scripts execute after the DOM has fully loaded. - Use Rollup to bundle the theme-mode and Mermaid scripts, reducing the number of Jekyll include snippets. --- _includes/analytics/cloudflare.html | 1 - _includes/analytics/fathom.html | 5 +- _includes/analytics/google.html | 2 +- _includes/analytics/matomo.html | 13 +- _includes/{comments.html => comment.html} | 0 _includes/comments/disqus.html | 63 ++++---- _includes/comments/giscus.html | 44 ++---- _includes/comments/utterances.html | 65 ++++----- _includes/head.html | 25 +++- _includes/js-selector.html | 29 +--- _includes/jsdelivr-combine.html | 8 +- _includes/mermaid.html | 62 -------- _includes/mode-toggle.html | 116 --------------- _includes/search-loader.html | 42 +++--- _javascript/categories.js | 2 +- _javascript/home.js | 2 +- _javascript/misc.js | 2 +- .../modules/{plugins.js => components.js} | 4 + _javascript/modules/components/img-popup.js | 16 +-- _javascript/modules/components/mermaid.js | 60 ++++++++ _javascript/modules/components/mode-toggle.js | 15 ++ .../modules/components/mode-watcher.js | 14 -- _javascript/modules/components/sidebar.js | 22 --- _javascript/modules/layouts/basic.js | 4 +- _javascript/modules/layouts/sidebar.js | 20 ++- _javascript/modules/theme.js | 135 ++++++++++++++++++ _javascript/page.js | 8 +- _javascript/post.js | 6 +- _layouts/default.html | 8 +- _layouts/post.html | 3 +- _sass/layout/post.scss | 1 + package.json | 1 + rollup.config.js | 19 ++- 33 files changed, 410 insertions(+), 407 deletions(-) rename _includes/{comments.html => comment.html} (100%) delete mode 100644 _includes/mermaid.html delete mode 100644 _includes/mode-toggle.html rename _javascript/modules/{plugins.js => components.js} (60%) create mode 100644 _javascript/modules/components/mermaid.js create mode 100644 _javascript/modules/components/mode-toggle.js delete mode 100644 _javascript/modules/components/mode-watcher.js delete mode 100644 _javascript/modules/components/sidebar.js create mode 100644 _javascript/modules/theme.js diff --git a/_includes/analytics/cloudflare.html b/_includes/analytics/cloudflare.html index 1eeb1a9..9faa11e 100644 --- a/_includes/analytics/cloudflare.html +++ b/_includes/analytics/cloudflare.html @@ -4,4 +4,3 @@ src="https://static.cloudflareinsights.com/beacon.min.js" data-cf-beacon='{"token": "{{ site.analytics.cloudflare.id }}"}' > - diff --git a/_includes/analytics/fathom.html b/_includes/analytics/fathom.html index 4b603d3..216bb14 100644 --- a/_includes/analytics/fathom.html +++ b/_includes/analytics/fathom.html @@ -2,6 +2,5 @@ - + defer +> diff --git a/_includes/analytics/google.html b/_includes/analytics/google.html index d0aac65..dfe4828 100644 --- a/_includes/analytics/google.html +++ b/_includes/analytics/google.html @@ -1,7 +1,7 @@ - diff --git a/_includes/comments.html b/_includes/comment.html similarity index 100% rename from _includes/comments.html rename to _includes/comment.html diff --git a/_includes/comments/disqus.html b/_includes/comments/disqus.html index 2b889a4..fd12a3c 100644 --- a/_includes/comments/disqus.html +++ b/_includes/comments/disqus.html @@ -1,38 +1,25 @@ - - -
-

Comments powered by Disqus.

-
- - diff --git a/_includes/comments/giscus.html b/_includes/comments/giscus.html index f9becfe..8058472 100644 --- a/_includes/comments/giscus.html +++ b/_includes/comments/giscus.html @@ -1,21 +1,8 @@ - - - diff --git a/_includes/head.html b/_includes/head.html index af3acdb..310f52e 100644 --- a/_includes/head.html +++ b/_includes/head.html @@ -97,11 +97,32 @@ {% endif %} - + {% unless site.theme_mode %} - {% include mode-toggle.html %} + {% endunless %} + {% include js-selector.html lang=lang %} + + {% if jekyll.environment == 'production' %} + + {% if site.pwa.enabled %} + + {% endif %} + + + {% for analytics in site.analytics %} + {% capture str %}{{ analytics }}{% endcapture %} + {% assign platform = str | split: '{' | first %} + {% if site.analytics[platform].id and site.analytics[platform].id != empty %} + {% include analytics/{{ platform }}.html %} + {% endif %} + {% endfor %} + {% endif %} + {% include metadata-hook.html %} diff --git a/_includes/js-selector.html b/_includes/js-selector.html index 4d77d06..fd4acca 100644 --- a/_includes/js-selector.html +++ b/_includes/js-selector.html @@ -62,12 +62,12 @@ {% capture script %}/assets/js/dist/{{ js }}.min.js{% endcapture %} - + {% if page.math %} - - + + {% endif %} @@ -84,26 +84,3 @@ {% endcase %} {% endif %} {% endif %} - -{% if page.mermaid %} - {% include mermaid.html %} -{% endif %} - -{% if jekyll.environment == 'production' %} - - {% if site.pwa.enabled %} - - {% endif %} - - - {% for analytics in site.analytics %} - {% capture str %}{{ analytics }}{% endcapture %} - {% assign type = str | split: '{' | first %} - {% if site.analytics[type].id and site.analytics[type].id != empty %} - {% include analytics/{{ type }}.html %} - {% endif %} - {% endfor %} -{% endif %} diff --git a/_includes/jsdelivr-combine.html b/_includes/jsdelivr-combine.html index cffa699..0611213 100644 --- a/_includes/jsdelivr-combine.html +++ b/_includes/jsdelivr-combine.html @@ -1,6 +1,6 @@ {% assign urls = include.urls | split: ',' %} -{% assign combined_urls = nil %} +{% assign combined_urls = null %} {% assign domain = 'https://cdn.jsdelivr.net/' %} @@ -15,12 +15,12 @@ {% endif %} {% elsif url contains '//' %} - + {% else %} - + {% endif %} {% endfor %} {% if combined_urls %} - + {% endif %} diff --git a/_includes/mermaid.html b/_includes/mermaid.html deleted file mode 100644 index a3a83ed..0000000 --- a/_includes/mermaid.html +++ /dev/null @@ -1,62 +0,0 @@ - - diff --git a/_includes/mode-toggle.html b/_includes/mode-toggle.html deleted file mode 100644 index 113ec37..0000000 --- a/_includes/mode-toggle.html +++ /dev/null @@ -1,116 +0,0 @@ - - - diff --git a/_includes/search-loader.html b/_includes/search-loader.html index 2582580..7fd065d 100644 --- a/_includes/search-loader.html +++ b/_includes/search-loader.html @@ -19,29 +19,31 @@ {% capture not_found %}

{{ site.data.locales[include.lang].search.no_results }}

{% endcapture %} diff --git a/_javascript/categories.js b/_javascript/categories.js index 15d8251..ce87d67 100644 --- a/_javascript/categories.js +++ b/_javascript/categories.js @@ -1,5 +1,5 @@ import { basic, initSidebar, initTopbar } from './modules/layouts'; -import { categoryCollapse } from './modules/plugins'; +import { categoryCollapse } from './modules/components'; basic(); initSidebar(); diff --git a/_javascript/home.js b/_javascript/home.js index ef22cb9..7f628a1 100644 --- a/_javascript/home.js +++ b/_javascript/home.js @@ -1,5 +1,5 @@ import { basic, initSidebar, initTopbar } from './modules/layouts'; -import { initLocaleDatetime, loadImg } from './modules/plugins'; +import { initLocaleDatetime, loadImg } from './modules/components'; loadImg(); initLocaleDatetime(); diff --git a/_javascript/misc.js b/_javascript/misc.js index 52b4043..37130da 100644 --- a/_javascript/misc.js +++ b/_javascript/misc.js @@ -1,5 +1,5 @@ import { basic, initSidebar, initTopbar } from './modules/layouts'; -import { initLocaleDatetime } from './modules/plugins'; +import { initLocaleDatetime } from './modules/components'; initSidebar(); initTopbar(); diff --git a/_javascript/modules/plugins.js b/_javascript/modules/components.js similarity index 60% rename from _javascript/modules/plugins.js rename to _javascript/modules/components.js index cc95c1b..95791a6 100644 --- a/_javascript/modules/plugins.js +++ b/_javascript/modules/components.js @@ -4,3 +4,7 @@ export { loadImg } from './components/img-loading'; export { imgPopup } from './components/img-popup'; export { initLocaleDatetime } from './components/locale-datetime'; export { initToc } from './components/toc'; +export { loadMermaid } from './components/mermaid'; +export { modeWatcher } from './components/mode-toggle'; +export { back2top } from './components/back-to-top'; +export { loadTooptip } from './components/tooltip-loader'; diff --git a/_javascript/modules/components/img-popup.js b/_javascript/modules/components/img-popup.js index ac12043..420a226 100644 --- a/_javascript/modules/components/img-popup.js +++ b/_javascript/modules/components/img-popup.js @@ -4,7 +4,6 @@ * Dependencies: https://github.com/biati-digital/glightbox */ -const html = document.documentElement; const lightImages = '.popup:not(.dark)'; const darkImages = '.popup:not(.light)'; let selector = lightImages; @@ -33,26 +32,17 @@ export function imgPopup() { document.querySelector('.popup.dark') === null ); - if ( - (html.hasAttribute('data-mode') && - html.getAttribute('data-mode') === 'dark') || - (!html.hasAttribute('data-mode') && - window.matchMedia('(prefers-color-scheme: dark)').matches) - ) { + if (Theme.visualState === Theme.DARK) { selector = darkImages; } let current = GLightbox({ selector: `${selector}` }); - if (hasDualImages && document.getElementById('mode-toggle')) { + if (hasDualImages && Theme.switchable) { let reverse = null; window.addEventListener('message', (event) => { - if ( - event.source === window && - event.data && - event.data.direction === ModeToggle.ID - ) { + if (event.source === window && event.data && event.data.id === Theme.ID) { updateImages(current, reverse); } }); diff --git a/_javascript/modules/components/mermaid.js b/_javascript/modules/components/mermaid.js new file mode 100644 index 0000000..2b4759f --- /dev/null +++ b/_javascript/modules/components/mermaid.js @@ -0,0 +1,60 @@ +/** + * Mermaid-js loader + */ + +const MERMAID = 'mermaid'; +const themeMapper = Theme.getThemeMapper('default', 'dark'); + +function refreshTheme(event) { + if (event.source === window && event.data && event.data.id === Theme.ID) { + // Re-render the SVG › + const mermaidList = document.getElementsByClassName(MERMAID); + + [...mermaidList].forEach((elem) => { + const svgCode = elem.previousSibling.children.item(0).innerHTML; + elem.textContent = svgCode; + elem.removeAttribute('data-processed'); + }); + + const newTheme = themeMapper[Theme.visualState]; + + mermaid.initialize({ theme: newTheme }); + mermaid.init(null, `.${MERMAID}`); + } +} + +function setNode(elem) { + const svgCode = elem.textContent; + const backup = elem.parentElement; + backup.classList.add('d-none'); + // Create mermaid node + const mermaid = document.createElement('pre'); + mermaid.classList.add(MERMAID); + const text = document.createTextNode(svgCode); + mermaid.appendChild(text); + backup.after(mermaid); +} + +export function loadMermaid() { + if ( + typeof mermaid === 'undefined' || + typeof mermaid.initialize !== 'function' + ) { + return; + } + + const initTheme = themeMapper[Theme.visualState]; + + let mermaidConf = { + theme: initTheme + }; + + const basicList = document.getElementsByClassName('language-mermaid'); + [...basicList].forEach(setNode); + + mermaid.initialize(mermaidConf); + + if (Theme.switchable) { + window.addEventListener('message', refreshTheme); + } +} diff --git a/_javascript/modules/components/mode-toggle.js b/_javascript/modules/components/mode-toggle.js new file mode 100644 index 0000000..455ff0a --- /dev/null +++ b/_javascript/modules/components/mode-toggle.js @@ -0,0 +1,15 @@ +/** + * Add listener for theme mode toggle + */ + +const $toggle = document.getElementById('mode-toggle'); + +export function modeWatcher() { + if (!$toggle) { + return; + } + + $toggle.addEventListener('click', () => { + Theme.flip(); + }); +} diff --git a/_javascript/modules/components/mode-watcher.js b/_javascript/modules/components/mode-watcher.js deleted file mode 100644 index 9eecd09..0000000 --- a/_javascript/modules/components/mode-watcher.js +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Add listener for theme mode toggle - */ -const toggle = document.getElementById('mode-toggle'); - -export function modeWatcher() { - if (!toggle) { - return; - } - - toggle.addEventListener('click', () => { - modeToggle.flipMode(); - }); -} diff --git a/_javascript/modules/components/sidebar.js b/_javascript/modules/components/sidebar.js deleted file mode 100644 index aed759e..0000000 --- a/_javascript/modules/components/sidebar.js +++ /dev/null @@ -1,22 +0,0 @@ -/** - * Expand or close the sidebar in mobile screens. - */ - -const $sidebar = document.getElementById('sidebar'); -const $trigger = document.getElementById('sidebar-trigger'); -const $mask = document.getElementById('mask'); - -class SidebarUtil { - static #isExpanded = false; - - static toggle() { - this.#isExpanded = !this.#isExpanded; - document.body.toggleAttribute('sidebar-display', this.#isExpanded); - $sidebar.classList.toggle('z-2', this.#isExpanded); - $mask.classList.toggle('d-none', !this.#isExpanded); - } -} - -export function sidebarExpand() { - $trigger.onclick = $mask.onclick = () => SidebarUtil.toggle(); -} diff --git a/_javascript/modules/layouts/basic.js b/_javascript/modules/layouts/basic.js index fb36a8b..b8eddf6 100644 --- a/_javascript/modules/layouts/basic.js +++ b/_javascript/modules/layouts/basic.js @@ -1,7 +1,7 @@ -import { back2top } from '../components/back-to-top'; -import { loadTooptip } from '../components/tooltip-loader'; +import { back2top, loadTooptip, modeWatcher } from '../components'; export function basic() { + modeWatcher(); back2top(); loadTooptip(); } diff --git a/_javascript/modules/layouts/sidebar.js b/_javascript/modules/layouts/sidebar.js index 8795693..bbf5e7d 100644 --- a/_javascript/modules/layouts/sidebar.js +++ b/_javascript/modules/layouts/sidebar.js @@ -1,7 +1,19 @@ -import { modeWatcher } from '../components/mode-watcher'; -import { sidebarExpand } from '../components/sidebar'; +const ATTR_DISPLAY = 'sidebar-display'; +const $sidebar = document.getElementById('sidebar'); +const $trigger = document.getElementById('sidebar-trigger'); +const $mask = document.getElementById('mask'); + +class SidebarUtil { + static #isExpanded = false; + + static toggle() { + this.#isExpanded = !this.#isExpanded; + document.body.toggleAttribute(ATTR_DISPLAY, this.#isExpanded); + $sidebar.classList.toggle('z-2', this.#isExpanded); + $mask.classList.toggle('d-none', !this.#isExpanded); + } +} export function initSidebar() { - modeWatcher(); - sidebarExpand(); + $trigger.onclick = $mask.onclick = () => SidebarUtil.toggle(); } diff --git a/_javascript/modules/theme.js b/_javascript/modules/theme.js new file mode 100644 index 0000000..f9ebf20 --- /dev/null +++ b/_javascript/modules/theme.js @@ -0,0 +1,135 @@ +/** + * Theme management class + * + * To reduce flickering during page load, this script should be loaded synchronously. + */ +class Theme { + static #modeKey = 'mode'; + static #modeAttr = 'data-mode'; + static #darkMedia = window.matchMedia('(prefers-color-scheme: dark)'); + static switchable = !document.documentElement.hasAttribute(this.#modeAttr); + + static get DARK() { + return 'dark'; + } + + static get LIGHT() { + return 'light'; + } + + /** + * @returns {string} Theme mode identifier + */ + static get ID() { + return 'theme-mode'; + } + + /** + * Gets the current visual state of the theme. + * + * @returns {string} The current visual state, either the mode if it exists, + * or the system dark mode state ('dark' or 'light'). + */ + static get visualState() { + if (this.#hasMode) { + return this.#mode; + } else { + return this.#sysDark ? this.DARK : this.LIGHT; + } + } + + static get #mode() { + return sessionStorage.getItem(this.#modeKey); + } + + static get #isDarkMode() { + return this.#mode === this.DARK; + } + + static get #hasMode() { + return this.#mode !== null; + } + + static get #sysDark() { + return this.#darkMedia.matches; + } + + /** + * Maps theme modes to provided values + * @param {string} light Value for light mode + * @param {string} dark Value for dark mode + * @returns {Object} Mapped values + */ + static getThemeMapper(light, dark) { + return { + [this.LIGHT]: light, + [this.DARK]: dark + }; + } + + /** + * Initializes the theme based on system preferences or stored mode + */ + static init() { + if (!this.switchable) { + return; + } + + this.#darkMedia.addEventListener('change', () => { + const lastMode = this.#mode; + this.#clearMode(); + + if (lastMode !== this.visualState) { + this.#notify(); + } + }); + + if (!this.#hasMode) { + return; + } + + if (this.#isDarkMode) { + this.#setDark(); + } else { + this.#setLight(); + } + } + + /** + * Flips the current theme mode + */ + static flip() { + if (this.#hasMode) { + this.#clearMode(); + } else { + this.#sysDark ? this.#setLight() : this.#setDark(); + } + this.#notify(); + } + + static #setDark() { + document.documentElement.setAttribute(this.#modeAttr, this.DARK); + sessionStorage.setItem(this.#modeKey, this.DARK); + } + + static #setLight() { + document.documentElement.setAttribute(this.#modeAttr, this.LIGHT); + sessionStorage.setItem(this.#modeKey, this.LIGHT); + } + + static #clearMode() { + document.documentElement.removeAttribute(this.#modeAttr); + sessionStorage.removeItem(this.#modeKey); + } + + /** + * Notifies other plugins that the theme mode has changed + */ + static #notify() { + window.postMessage({ id: this.ID }, '*'); + } +} + +Theme.init(); + +export default Theme; diff --git a/_javascript/page.js b/_javascript/page.js index 76e8ce9..4b03b79 100644 --- a/_javascript/page.js +++ b/_javascript/page.js @@ -1,9 +1,15 @@ import { basic, initSidebar, initTopbar } from './modules/layouts'; -import { loadImg, imgPopup, initClipboard } from './modules/plugins'; +import { + loadImg, + imgPopup, + initClipboard, + loadMermaid +} from './modules/components'; loadImg(); imgPopup(); initSidebar(); initTopbar(); initClipboard(); +loadMermaid(); basic(); diff --git a/_javascript/post.js b/_javascript/post.js index 1c616ec..dc472b4 100644 --- a/_javascript/post.js +++ b/_javascript/post.js @@ -5,8 +5,9 @@ import { imgPopup, initLocaleDatetime, initClipboard, - initToc -} from './modules/plugins'; + initToc, + loadMermaid +} from './modules/components'; loadImg(); initToc(); @@ -15,4 +16,5 @@ initSidebar(); initLocaleDatetime(); initClipboard(); initTopbar(); +loadMermaid(); basic(); diff --git a/_layouts/default.html b/_layouts/default.html index 1590ef6..c83c561 100644 --- a/_layouts/default.html +++ b/_layouts/default.html @@ -74,8 +74,12 @@ layout: compress {% include_cached notification.html lang=lang %} {% endif %} - - {% include js-selector.html lang=lang %} + + + {% for _include in layout.script_includes %} + {% assign _include_path = _include | append: '.html' %} + {% include {{ _include_path }} %} + {% endfor %} {% include_cached search-loader.html lang=lang %} diff --git a/_layouts/post.html b/_layouts/post.html index 6a2deff..c8c21ef 100644 --- a/_layouts/post.html +++ b/_layouts/post.html @@ -6,7 +6,8 @@ panel_includes: tail_includes: - related-posts - post-nav - - comments +script_includes: + - comment --- {% include lang.html %} diff --git a/_sass/layout/post.scss b/_sass/layout/post.scss index b66e906..891479e 100644 --- a/_sass/layout/post.scss +++ b/_sass/layout/post.scss @@ -532,6 +532,7 @@ header { .utterances { max-width: 100%; + min-height: 269px; } %btn-share-hover { diff --git a/package.json b/package.json index f93e76b..3447784 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "devDependencies": { "@babel/core": "^7.25.2", "@babel/plugin-transform-class-properties": "^7.25.4", + "@babel/plugin-transform-private-methods": "^7.25.7", "@babel/preset-env": "^7.25.4", "@commitlint/cli": "^19.5.0", "@commitlint/config-conventional": "^19.5.0", diff --git a/rollup.config.js b/rollup.config.js index 19ba4da..3a1ae29 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -34,24 +34,32 @@ function insertFrontmatter() { }; } -function build(filename, { src = SRC_DEFAULT, jekyll = false } = {}) { +function build( + filename, + { src = SRC_DEFAULT, jekyll = false, outputName = null } = {} +) { + const input = `${src}/${filename}.js`; + return { - input: `${src}/${filename}.js`, + input, output: { file: `${DIST}/${filename}.min.js`, format: 'iife', - name: 'Chirpy', + ...(outputName !== null && { name: outputName }), banner, sourcemap: !isProd && !jekyll }, watch: { - include: `${src}/**` + include: input }, plugins: [ babel({ babelHelpers: 'bundled', presets: ['@babel/env'], - plugins: ['@babel/plugin-transform-class-properties'] + plugins: [ + '@babel/plugin-transform-class-properties', + '@babel/plugin-transform-private-methods' + ] }), nodeResolve(), isProd && terser(), @@ -69,6 +77,7 @@ export default [ build('page'), build('post'), build('misc'), + build('theme', { src: `${SRC_DEFAULT}/modules`, outputName: 'Theme' }), build('app', { src: SRC_PWA, jekyll: true }), build('sw', { src: SRC_PWA, jekyll: true }) ]; From c69914effc1f222d2b31d2ed14d1efda90575c9f Mon Sep 17 00:00:00 2001 From: Cotes Chung <11371340+cotes2020@users.noreply.github.com> Date: Sun, 24 Nov 2024 02:08:13 +0800 Subject: [PATCH 17/21] ci: avoid repeated runs of stylelint (#2057) --- .github/workflows/style-lint.yml | 25 ----------------------- .stylelintrc.json | 30 +++++++++++++++++++++++++++ package.json | 35 -------------------------------- 3 files changed, 30 insertions(+), 60 deletions(-) delete mode 100644 .github/workflows/style-lint.yml create mode 100644 .stylelintrc.json diff --git a/.github/workflows/style-lint.yml b/.github/workflows/style-lint.yml deleted file mode 100644 index 5cb38a7..0000000 --- a/.github/workflows/style-lint.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: Style Lint - -on: - push: - branches: - - master - - "hotfix/*" - paths: ["_sass/**/*.scss"] - pull_request: - paths: ["_sass/**/*.scss"] - -jobs: - stylelint: - runs-on: ubuntu-latest - - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup Node - uses: actions/setup-node@v4 - with: - node-version: lts/* - - run: npm i - - run: npm test diff --git a/.stylelintrc.json b/.stylelintrc.json new file mode 100644 index 0000000..57dd7d6 --- /dev/null +++ b/.stylelintrc.json @@ -0,0 +1,30 @@ +{ + "extends": "stylelint-config-standard-scss", + "rules": { + "no-descending-specificity": null, + "shorthand-property-no-redundant-values": null, + "at-rule-no-vendor-prefix": null, + "property-no-vendor-prefix": null, + "selector-no-vendor-prefix": null, + "value-no-vendor-prefix": null, + "color-function-notation": "legacy", + "alpha-value-notation": "number", + "selector-not-notation": "simple", + "color-hex-length": "long", + "declaration-block-single-line-max-declarations": 3, + "scss/operator-no-newline-after": null, + "rule-empty-line-before": [ + "always", + { + "ignore": ["after-comment", "first-nested"] + } + ], + "value-keyword-case": [ + "lower", + { + "ignoreProperties": ["/^\\$/"] + } + ], + "media-feature-range-notation": "prefix" + } +} diff --git a/package.json b/package.json index 3447784..d6beea0 100644 --- a/package.json +++ b/package.json @@ -68,41 +68,6 @@ ] } }, - "stylelint": { - "extends": "stylelint-config-standard-scss", - "rules": { - "no-descending-specificity": null, - "shorthand-property-no-redundant-values": null, - "at-rule-no-vendor-prefix": null, - "property-no-vendor-prefix": null, - "selector-no-vendor-prefix": null, - "value-no-vendor-prefix": null, - "color-function-notation": "legacy", - "alpha-value-notation": "number", - "selector-not-notation": "simple", - "color-hex-length": "long", - "declaration-block-single-line-max-declarations": 3, - "scss/operator-no-newline-after": null, - "rule-empty-line-before": [ - "always", - { - "ignore": [ - "after-comment", - "first-nested" - ] - } - ], - "value-keyword-case": [ - "lower", - { - "ignoreProperties": [ - "/^\\$/" - ] - } - ], - "media-feature-range-notation": "prefix" - } - }, "release": { "branches": [ "production" From 35c794cf5896565430389f35c660b88a93cebb17 Mon Sep 17 00:00:00 2001 From: Cotes Chung <11371340+cotes2020@users.noreply.github.com> Date: Mon, 25 Nov 2024 00:05:28 +0800 Subject: [PATCH 18/21] perf: modular sass architecture (#2052) - Modularized the Sass architecture to enhance code maintainability and reduce the output file size - Replaced deprecated `@import` with `@use` / `@forward` --- .gitignore | 2 +- .stylelintrc.json | 1 + _includes/head.html | 2 +- _posts/2019-08-09-getting-started.md | 2 - _sass/abstracts/_breakpoints.scss | 73 + _sass/abstracts/_index.scss | 4 + _sass/abstracts/_mixins.scss | 80 + .../_placeholders.scss} | 83 +- .../_variables.scss} | 4 - _sass/addon/commons.scss | 1526 ----------------- _sass/base/_base.scss | 476 +++++ _sass/base/_index.scss | 4 + _sass/base/_reset.scss | 41 + .../{addon/syntax.scss => base/_syntax.scss} | 131 +- _sass/base/_typography.scss | 266 +++ _sass/colors/syntax-dark.scss | 164 -- _sass/colors/syntax-light.scss | 210 --- _sass/colors/typography-light.scss | 112 -- _sass/components/_buttons.scss | 51 + _sass/components/_index.scss | 2 + _sass/components/_popups.scss | 172 ++ _sass/layout/_footer.scss | 36 + _sass/layout/_index.scss | 4 + _sass/layout/_panel.scss | 66 + _sass/layout/_sidebar.scss | 258 +++ _sass/layout/_topbar.scss | 86 + _sass/main.bundle.scss | 4 +- _sass/main.scss | 17 +- .../archives.scss => pages/_archives.scss} | 23 +- .../_categories.scss} | 11 +- .../_category-tag.scss} | 29 +- _sass/{layout/home.scss => pages/_home.scss} | 119 +- _sass/pages/_index.scss | 7 + _sass/{layout/post.scss => pages/_post.scss} | 219 +-- _sass/pages/_search.scss | 184 ++ _sass/{layout/tags.scss => pages/_tags.scss} | 10 +- .../_dark.scss} | 168 +- _sass/themes/_light.scss | 313 ++++ _sass/variables-hook.scss | 3 - assets/css/jekyll-theme-chirpy.scss | 2 +- package.json | 2 +- purgecss.config.js | 23 - purgecss.js | 30 + tools/init.sh | 3 +- tools/release.sh | 2 +- 45 files changed, 2523 insertions(+), 2502 deletions(-) create mode 100644 _sass/abstracts/_breakpoints.scss create mode 100644 _sass/abstracts/_index.scss create mode 100644 _sass/abstracts/_mixins.scss rename _sass/{addon/module.scss => abstracts/_placeholders.scss} (59%) rename _sass/{addon/variables.scss => abstracts/_variables.scss} (96%) delete mode 100644 _sass/addon/commons.scss create mode 100644 _sass/base/_base.scss create mode 100644 _sass/base/_index.scss create mode 100644 _sass/base/_reset.scss rename _sass/{addon/syntax.scss => base/_syntax.scss} (74%) create mode 100644 _sass/base/_typography.scss delete mode 100644 _sass/colors/syntax-dark.scss delete mode 100644 _sass/colors/syntax-light.scss delete mode 100644 _sass/colors/typography-light.scss create mode 100644 _sass/components/_buttons.scss create mode 100644 _sass/components/_index.scss create mode 100644 _sass/components/_popups.scss create mode 100644 _sass/layout/_footer.scss create mode 100644 _sass/layout/_index.scss create mode 100644 _sass/layout/_panel.scss create mode 100644 _sass/layout/_sidebar.scss create mode 100644 _sass/layout/_topbar.scss rename _sass/{layout/archives.scss => pages/_archives.scss} (95%) rename _sass/{layout/categories.scss => pages/_categories.scss} (87%) rename _sass/{layout/category-tag.scss => pages/_category-tag.scss} (79%) rename _sass/{layout/home.scss => pages/_home.scss} (73%) create mode 100644 _sass/pages/_index.scss rename _sass/{layout/post.scss => pages/_post.scss} (67%) create mode 100644 _sass/pages/_search.scss rename _sass/{layout/tags.scss => pages/_tags.scss} (71%) rename _sass/{colors/typography-dark.scss => themes/_dark.scss} (62%) create mode 100644 _sass/themes/_light.scss delete mode 100644 _sass/variables-hook.scss delete mode 100644 purgecss.config.js create mode 100644 purgecss.js diff --git a/.gitignore b/.gitignore index 0082d90..7dd7cef 100644 --- a/.gitignore +++ b/.gitignore @@ -23,5 +23,5 @@ package-lock.json !.vscode/tasks.json # Misc -_sass/dist +_sass/vendors assets/js/dist diff --git a/.stylelintrc.json b/.stylelintrc.json index 57dd7d6..b890290 100644 --- a/.stylelintrc.json +++ b/.stylelintrc.json @@ -1,4 +1,5 @@ { + "ignoreFiles": ["_sass/vendors/**"], "extends": "stylelint-config-standard-scss", "rules": { "no-descending-specificity": null, diff --git a/_includes/head.html b/_includes/head.html index 310f52e..011187c 100644 --- a/_includes/head.html +++ b/_includes/head.html @@ -70,7 +70,7 @@ {% unless jekyll.environment == 'production' %} - + {% endunless %} diff --git a/_posts/2019-08-09-getting-started.md b/_posts/2019-08-09-getting-started.md index 3b41a3c..2681126 100644 --- a/_posts/2019-08-09-getting-started.md +++ b/_posts/2019-08-09-getting-started.md @@ -93,8 +93,6 @@ Social contact options are displayed at the bottom of the sidebar. You can enabl To customize the stylesheet, copy the theme's `assets/css/jekyll-theme-chirpy.scss`{: .filepath} file to the same path in your Jekyll site, and add your custom styles at the end of the file. -Starting with version `6.2.0`, if you want to overwrite the SASS variables defined in `_sass/addon/variables.scss`{: .filepath}, copy the main SASS file `_sass/main.scss`{: .filepath} to the `_sass`{: .filepath} directory in your site's source, then create a new file `_sass/variables-hook.scss`{: .filepath} and assign your new values there. - ### Customizing Static Assets Static assets configuration was introduced in version `5.1.0`. The CDN of the static assets is defined in `_data/origin/cors.yml`{: .filepath }. You can replace some of them based on the network conditions in the region where your website is published. diff --git a/_sass/abstracts/_breakpoints.scss b/_sass/abstracts/_breakpoints.scss new file mode 100644 index 0000000..e40cefe --- /dev/null +++ b/_sass/abstracts/_breakpoints.scss @@ -0,0 +1,73 @@ +@use 'sass:map'; + +$-breakpoints: ( + // 1 column + sm: 576px, + md: 768px, + // 2 columns + lg: 850px, + // 3 columns + xl: 1200px, + xxl: 1400px, + xxxl: 1650px +); + +@function get($breakpoint) { + @return map.get($-breakpoints, $breakpoint); +} + +/* Less than the given width */ +@mixin lt($width) { + @media all and (max-width: calc(#{$width} - 1px)) { + @content; + } +} + +/* Less than or equal to the given width */ +@mixin lte($width) { + @media all and (max-width: $width) { + @content; + } +} + +@mixin sm { + @media all and (min-width: get(sm)) { + @content; + } +} + +@mixin md { + @media all and (min-width: get(md)) { + @content; + } +} + +@mixin lg { + @media all and (min-width: get(lg)) { + @content; + } +} + +@mixin xl { + @media all and (min-width: get(xl)) { + @content; + } +} + +@mixin xxl { + @media all and (min-width: get(xxl)) { + @content; + } +} + +@mixin xxxl { + @media all and (min-width: get(xxxl)) { + @content; + } +} + +@mixin between($min, $max) { + @media all and (min-width: $min) and (max-width: $max) { + @content; + } +} diff --git a/_sass/abstracts/_index.scss b/_sass/abstracts/_index.scss new file mode 100644 index 0000000..6c9e21c --- /dev/null +++ b/_sass/abstracts/_index.scss @@ -0,0 +1,4 @@ +@forward 'variables'; +@forward 'mixins'; +@forward 'placeholders'; +@forward 'breakpoints'; diff --git a/_sass/abstracts/_mixins.scss b/_sass/abstracts/_mixins.scss new file mode 100644 index 0000000..c5eeee3 --- /dev/null +++ b/_sass/abstracts/_mixins.scss @@ -0,0 +1,80 @@ +@mixin text-ellipsis { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +@mixin mt-mb($value) { + margin-top: $value; + margin-bottom: $value; +} + +@mixin ml-mr($value) { + margin-left: $value; + margin-right: $value; +} + +@mixin pt-pb($val) { + padding-top: $val; + padding-bottom: $val; +} + +@mixin pl-pr($val, $important: false) { + @if $important { + padding-left: $val !important; + padding-right: $val !important; + } @else { + padding-left: $val; + padding-right: $val; + } +} + +@mixin placeholder { + color: var(--text-muted-color) !important; +} + +@mixin placeholder-focus { + opacity: 0.6; +} + +@mixin label($font-size: 1rem, $font-weight: 600, $color: var(--label-color)) { + color: $color; + font-size: $font-size; + font-weight: $font-weight; +} + +@mixin align-center { + position: relative; + left: 50%; + transform: translateX(-50%); +} + +@mixin prompt($type, $fa-content, $fa-style: 'solid', $rotate: 0) { + &.prompt-#{$type} { + background-color: var(--prompt-#{$type}-bg); + + &::before { + content: $fa-content; + color: var(--prompt-#{$type}-icon-color); + font: var(--fa-font-#{$fa-style}); + + @if $rotate != 0 { + transform: rotate(#{$rotate}deg); + } + } + } +} + +@mixin slide($append: null) { + $basic: transform 0.4s ease; + + @if $append { + transition: $basic, $append; + } @else { + transition: $basic; + } +} + +@mixin max-w-100 { + max-width: 100%; +} diff --git a/_sass/addon/module.scss b/_sass/abstracts/_placeholders.scss similarity index 59% rename from _sass/addon/module.scss rename to _sass/abstracts/_placeholders.scss index 1dfb735..e4c1bb0 100644 --- a/_sass/addon/module.scss +++ b/_sass/abstracts/_placeholders.scss @@ -1,13 +1,10 @@ -/* -* Mainly scss modules, only imported to `assets/css/main.scss` -*/ - -/* ---------- scss placeholder --------- */ +@use 'variables' as v; +@use 'mixins' as mx; %heading { color: var(--heading-color); font-weight: 400; - font-family: $font-family-heading; + font-family: v.$font-family-heading; scroll-margin-top: 3.5rem; } @@ -82,7 +79,7 @@ } %rounded { - border-radius: $radius-lg; + border-radius: v.$radius-lg; } %img-caption { @@ -112,14 +109,8 @@ -webkit-box-orient: vertical; } -@mixin text-ellipsis { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - %text-ellipsis { - @include text-ellipsis; + @include mx.text-ellipsis; } %text-highlight { @@ -151,65 +142,15 @@ } } -/* ---------- scss mixin --------- */ - -@mixin mt-mb($value) { - margin-top: $value; - margin-bottom: $value; +%code-snippet-bg { + background-color: var(--highlight-bg-color); } -@mixin ml-mr($value) { - margin-left: $value; - margin-right: $value; +%code-snippet-padding { + padding-left: 1rem; + padding-right: 1.5rem; } -@mixin pt-pb($val) { - padding-top: $val; - padding-bottom: $val; -} - -@mixin pl-pr($val, $important: false) { - @if $important { - padding-left: $val !important; - padding-right: $val !important; - } @else { - padding-left: $val; - padding-right: $val; - } -} - -@mixin placeholder { - color: var(--text-muted-color) !important; -} - -@mixin placeholder-focus { - opacity: 0.6; -} - -@mixin label($font-size: 1rem, $font-weight: 600, $color: var(--label-color)) { - color: $color; - font-size: $font-size; - font-weight: $font-weight; -} - -@mixin align-center { - position: relative; - left: 50%; - transform: translateX(-50%); -} - -@mixin prompt($type, $fa-content, $fa-style: 'solid', $rotate: 0) { - &.prompt-#{$type} { - background-color: var(--prompt-#{$type}-bg); - - &::before { - content: $fa-content; - color: var(--prompt-#{$type}-icon-color); - font: var(--fa-font-#{$fa-style}); - - @if $rotate != 0 { - transform: rotate(#{$rotate}deg); - } - } - } +%max-w-100 { + max-width: 100%; } diff --git a/_sass/addon/variables.scss b/_sass/abstracts/_variables.scss similarity index 96% rename from _sass/addon/variables.scss rename to _sass/abstracts/_variables.scss index 1d51cb1..0194e40 100644 --- a/_sass/addon/variables.scss +++ b/_sass/abstracts/_variables.scss @@ -1,7 +1,3 @@ -/* - * The SCSS variables - */ - /* sidebar */ $sidebar-width: 260px !default; /* the basic width */ diff --git a/_sass/addon/commons.scss b/_sass/addon/commons.scss deleted file mode 100644 index 5e8acea..0000000 --- a/_sass/addon/commons.scss +++ /dev/null @@ -1,1526 +0,0 @@ -/* The common styles */ - -html { - font-size: 16px; - - @media (prefers-color-scheme: light) { - &:not([data-mode]), - &[data-mode='light'] { - @include light-scheme; - } - - &[data-mode='dark'] { - @include dark-scheme; - } - } - - @media (prefers-color-scheme: dark) { - &:not([data-mode]), - &[data-mode='dark'] { - @include dark-scheme; - } - - &[data-mode='light'] { - @include light-scheme; - } - } -} - -body { - background: var(--main-bg); - padding: env(safe-area-inset-top) env(safe-area-inset-right) - env(safe-area-inset-bottom) env(safe-area-inset-left); - color: var(--text-color); - -webkit-font-smoothing: antialiased; - font-family: $font-family-base; -} - -/* --- Typography --- */ - -@for $i from 1 through 5 { - h#{$i} { - @extend %heading; - - @if $i > 1 { - @extend %anchor; - } - - @if $i < 5 { - $size-factor: 0.25rem; - - @if $i > 1 { - $size-factor: 0.18rem; - - main & { - @if $i == 2 { - margin: 2.5rem 0 1.25rem; - } @else { - margin: 2rem 0 1rem; - } - } - } - - & { - font-size: 1rem + (5 - $i) * $size-factor; - } - } @else { - font-size: 1.05rem; - } - } -} - -a { - @extend %link-color; - - text-decoration: none; -} - -img { - max-width: 100%; - height: auto; - transition: all 0.35s ease-in-out; - - .blur & { - $blur: 20px; - - -webkit-filter: blur($blur); - filter: blur($blur); - } -} - -blockquote { - border-left: 0.125rem solid var(--blockquote-border-color); - padding-left: 1rem; - color: var(--blockquote-text-color); - margin-top: 0.5rem; - - > p:last-child { - margin-bottom: 0; - } - - &[class^='prompt-'] { - border-left: 0; - position: relative; - padding: 1rem 1rem 1rem 3rem; - color: var(--prompt-text-color); - - @extend %rounded; - - &::before { - text-align: center; - width: 3rem; - position: absolute; - left: 0.25rem; - margin-top: 0.4rem; - text-rendering: auto; - -webkit-font-smoothing: antialiased; - } - } - - @include prompt('tip', '\f0eb', $fa-style: 'regular'); - @include prompt('info', '\f06a', $rotate: 180); - @include prompt('warning', '\f06a'); - @include prompt('danger', '\f071'); -} - -kbd { - font-family: Lato, sans-serif; - display: inline-block; - vertical-align: middle; - line-height: 1.3rem; - min-width: 1.75rem; - text-align: center; - margin: 0 0.3rem; - padding-top: 0.1rem; - color: var(--kbd-text-color); - background-color: var(--kbd-bg-color); - border-radius: $radius-sm; - border: solid 1px var(--kbd-wrap-color); - box-shadow: inset 0 -2px 0 var(--kbd-wrap-color); -} - -hr { - border-color: var(--main-border-color); - opacity: 1; -} - -footer { - background-color: var(--main-bg); - height: $footer-height; - border-top: 1px solid var(--main-border-color); - - @extend %text-xs; - - a { - @extend %text-highlight; - - &:hover { - @extend %link-hover; - } - } - - em { - @extend %text-highlight; - } - - p { - text-align: center; - margin-bottom: 0; - } -} - -/* fontawesome icons */ -i { - &.far, - &.fas { - @extend %no-cursor; - } -} - -/* --- Panels --- */ - -.access { - top: 2rem; - transition: top 0.2s ease-in-out; - margin-top: 3rem; - margin-bottom: 4rem; - - &:only-child { - position: -webkit-sticky; - position: sticky; - } - - > section { - padding-left: 1rem; - border-left: 1px solid var(--main-border-color); - - &:not(:last-child) { - margin-bottom: 4rem; - } - } - - .content { - font-size: 0.9rem; - } -} - -#panel-wrapper { - /* the headings */ - .panel-heading { - font-family: inherit; - line-height: inherit; - - @include label(inherit); - } - - .post-tag { - line-height: 1.05rem; - font-size: 0.85rem; - border-radius: 0.8rem; - padding: 0.3rem 0.5rem; - margin: 0 0.35rem 0.5rem 0; - - &:hover { - transition: all 0.3s ease-in; - } - } -} - -#access-lastmod { - a { - color: inherit; - - &:hover { - @extend %link-hover; - } - - @extend %no-bottom-border; - } -} - -.footnotes > ol { - padding-left: 2rem; - margin-top: 0.5rem; - - > li { - &:not(:last-child) { - margin-bottom: 0.3rem; - } - - @extend %sup-fn-target; - - > p { - margin-left: 0.25em; - - @include mt-mb(0); - } - } -} - -.footnote { - @at-root a#{&} { - @include ml-mr(1px); - @include pl-pr(2px); - - border-bottom-style: none !important; - } -} - -sup { - @extend %sup-fn-target; -} - -.reversefootnote { - @at-root a#{&} { - font-size: 0.6rem; - line-height: 1; - position: relative; - bottom: 0.25em; - margin-left: 0.25em; - border-bottom-style: none !important; - } -} - -/* --- Begin of Markdown table style --- */ - -/* it will be created by Liquid */ -.table-wrapper { - overflow-x: auto; - margin-bottom: 1.5rem; - - > table { - min-width: 100%; - overflow-x: auto; - border-spacing: 0; - - thead { - border-bottom: solid 2px rgba(210, 215, 217, 0.75); - - th { - @extend %table-cell; - } - } - - tbody { - tr { - border-bottom: 1px solid var(--tb-border-color); - - &:nth-child(2n) { - background-color: var(--tb-even-bg); - } - - &:nth-child(2n + 1) { - background-color: var(--tb-odd-bg); - } - - td { - @extend %table-cell; - } - } - } /* tbody */ - } /* table */ -} - -/* --- post --- */ - -.preview-img { - aspect-ratio: 40 / 21; - width: 100%; - height: 100%; - overflow: hidden; - - @extend %rounded; - - &:not(.no-bg) { - background: var(--img-bg); - } - - img { - height: 100%; - -o-object-fit: cover; - object-fit: cover; - - @extend %rounded; - - @at-root #post-list & { - width: 100%; - } - } -} - -.post-preview { - @extend %rounded; - - border: 0; - background: var(--card-bg); - box-shadow: var(--card-shadow); - - &::before { - @extend %rounded; - - content: ''; - width: 100%; - height: 100%; - position: absolute; - background-color: var(--card-hovor-bg); - opacity: 0; - transition: opacity 0.35s ease-in-out; - } - - &:hover { - &::before { - opacity: 0.3; - } - } -} - -main { - line-height: 1.75; - - h1 { - margin-top: 2rem; - } - - p { - > a.popup { - &:not(.normal):not(.left):not(.right) { - @include align-center; - } - } - } - - .categories, - #tags, - #archives { - a:not(:hover) { - @extend %no-bottom-border; - } - } -} - -.post-meta { - @extend %text-sm; - - a { - &:not([class]):hover { - @extend %link-hover; - } - } - - em { - @extend %normal-font-style; - } -} - -.content { - font-size: 1.08rem; - margin-top: 2rem; - overflow-wrap: break-word; - - a { - &.popup { - @extend %no-cursor; - @extend %img-caption; - @include mt-mb(0.5rem); - - cursor: zoom-in; - } - - &:not(.img-link) { - @extend %link-underline; - - &:hover { - @extend %link-hover; - } - } - } - - ol, - ul { - &:not([class]), - &.task-list { - -webkit-padding-start: 1.75rem; - padding-inline-start: 1.75rem; - - li { - margin: 0.25rem 0; - padding-left: 0.25rem; - } - - ol, - ul { - -webkit-padding-start: 1.25rem; - padding-inline-start: 1.25rem; - margin: 0.5rem 0; - } - } - } - - ul.task-list { - -webkit-padding-start: 1.25rem; - padding-inline-start: 1.25rem; - - li { - list-style-type: none; - padding-left: 0; - - /* checkbox icon */ - > i { - width: 2rem; - margin-left: -1.25rem; - color: var(--checkbox-color); - - &.checked { - color: var(--checkbox-checked-color); - } - } - - ul { - -webkit-padding-start: 1.75rem; - padding-inline-start: 1.75rem; - } - } - - input[type='checkbox'] { - margin: 0 0.5rem 0.2rem -1.3rem; - vertical-align: middle; - } - } /* ul */ - - dl > dd { - margin-left: 1rem; - } - - ::marker { - color: var(--text-muted-color); - } -} /* .content */ - -.tag:hover { - @extend %tag-hover; -} - -.post-tag { - display: inline-block; - min-width: 2rem; - text-align: center; - border-radius: 0.5rem; - border: 1px solid var(--btn-border-color); - padding: 0 0.4rem; - color: var(--text-muted-color); - line-height: 1.3rem; - - &:not(:last-child) { - margin-right: 0.2rem; - } -} - -.rounded-10 { - border-radius: 10px !important; -} - -.img-link { - color: transparent; - display: inline-flex; -} - -.shimmer { - overflow: hidden; - position: relative; - background: var(--img-bg); - - &::before { - content: ''; - position: absolute; - background: var(--shimmer-bg); - height: 100%; - width: 100%; - -webkit-animation: shimmer 1.3s infinite; - animation: shimmer 1.3s infinite; - } - - @-webkit-keyframes shimmer { - 0% { - transform: translateX(-100%); - } - - 100% { - transform: translateX(100%); - } - } - - @keyframes shimmer { - 0% { - transform: translateX(-100%); - } - - 100% { - transform: translateX(100%); - } - } -} - -.embed-video { - width: 100%; - height: 100%; - margin-bottom: 1rem; - aspect-ratio: 16 / 9; - - @extend %rounded; - - &.twitch { - aspect-ratio: 310 / 189; - } - - &.file { - display: block; - width: auto; - height: auto; - max-width: 100%; - max-height: 100%; - margin: auto; - margin-bottom: 0; - } - - @extend %img-caption; -} - -.embed-audio { - width: 100%; - display: block; - - @extend %img-caption; -} - -/* --- buttons --- */ -.btn-lang { - border: 1px solid !important; - padding: 1px 3px; - border-radius: 3px; - color: var(--link-color); - - &:focus { - box-shadow: none; - } -} - -/* --- Effects classes --- */ - -.flex-grow-1 { - flex-grow: 1 !important; -} - -.btn-box-shadow { - box-shadow: var(--card-shadow); -} - -/* overwrite bootstrap muted */ -.text-muted { - color: var(--text-muted-color) !important; -} - -/* Overwrite bootstrap tooltip */ -.tooltip-inner { - font-size: 0.7rem; - max-width: 220px; - text-align: left; -} - -/* Overwrite bootstrap outline button */ -.btn.btn-outline-primary { - &:not(.disabled):hover { - border-color: #007bff !important; - } -} - -.disabled { - color: rgb(206, 196, 196); - pointer-events: auto; - cursor: not-allowed; -} - -.hide-border-bottom { - border-bottom: none !important; -} - -.input-focus { - box-shadow: none; - border-color: var(--input-focus-border-color) !important; - background: center !important; - transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out; -} - -.left { - float: left; - margin: 0.75rem 1rem 1rem 0; -} - -.right { - float: right; - margin: 0.75rem 0 1rem 1rem; -} - -/* --- Overriding --- */ - -/* mermaid */ -.mermaid { - text-align: center; -} - -/* MathJax */ -mjx-container { - overflow-y: hidden; - min-width: auto !important; -} - -/* --- sidebar layout --- */ - -$sidebar-display: 'sidebar-display'; -$btn-border-width: 3px; -$btn-mb: 0.5rem; - -#sidebar { - @include pl-pr(0); - - position: fixed; - top: 0; - left: 0; - height: 100%; - overflow-y: auto; - width: $sidebar-width; - background: var(--sidebar-bg); - border-right: 1px solid var(--sidebar-border-color); - - /* Hide scrollbar for IE, Edge and Firefox */ - -ms-overflow-style: none; /* IE and Edge */ - scrollbar-width: none; /* Firefox */ - - /* Hide scrollbar for Chrome, Safari and Opera */ - &::-webkit-scrollbar { - display: none; - } - - %sidebar-link-hover { - &:hover { - color: var(--sidebar-active-color); - } - } - - a { - @extend %sidebar-links; - } - - #avatar { - display: block; - width: 7rem; - height: 7rem; - overflow: hidden; - box-shadow: var(--avatar-border-color) 0 0 0 2px; - transform: translateZ(0); /* fixed the zoom in Safari */ - - img { - transition: transform 0.5s; - - &:hover { - transform: scale(1.2); - } - } - } - - .profile-wrapper { - @include mt-mb(2.5rem); - @extend %clickable-transition; - - padding-left: 2.5rem; - padding-right: 1.25rem; - width: 100%; - } - - .site-title { - @extend %clickable-transition; - @extend %sidebar-link-hover; - - font-family: inherit; - font-weight: 900; - font-size: 1.75rem; - line-height: 1.2; - letter-spacing: 0.25px; - margin-top: 1.25rem; - margin-bottom: 0.5rem; - width: fit-content; - color: var(--site-title-color); - } - - .site-subtitle { - font-size: 95%; - color: var(--site-subtitle-color); - margin-top: 0.25rem; - word-spacing: 1px; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - } - - ul { - margin-bottom: 2rem; - - li.nav-item { - opacity: 0.9; - width: 100%; - - @include pl-pr(1.5rem); - - a.nav-link { - @include pt-pb(0.6rem); - - display: flex; - align-items: center; - border-radius: 0.75rem; - font-weight: 600; - - &:hover { - background-color: var(--sidebar-hover-bg); - } - - i { - font-size: 95%; - opacity: 0.8; - margin-right: 1.5rem; - } - - span { - font-size: 90%; - letter-spacing: 0.2px; - } - } - - &.active { - .nav-link { - color: var(--sidebar-active-color); - background-color: var(--sidebar-hover-bg); - - span { - opacity: 1; - } - } - } - - &:not(:first-child) { - margin-top: 0.25rem; - } - } - } - - .sidebar-bottom { - padding-left: 2rem; - padding-right: 1rem; - margin-bottom: 1.5rem; - - $btn-size: 1.75rem; - - %button { - width: $btn-size; - height: $btn-size; - margin-bottom: $btn-mb; // multi line gap - border-radius: 50%; - color: var(--sidebar-btn-color); - background-color: var(--sidebar-btn-bg); - text-align: center; - display: flex; - align-items: center; - justify-content: center; - - &:not(:focus-visible) { - box-shadow: var(--sidebar-border-color) 0 0 0 1px; - } - - &:hover { - background-color: var(--sidebar-hover-bg); - } - } - - a { - @extend %button; - @extend %sidebar-link-hover; - @extend %clickable-transition; - - &:not(:last-child) { - margin-right: $sb-btn-gap; - } - } - - i { - line-height: $btn-size; - } - - #mode-toggle { - @extend %button; - @extend %sidebar-links; - @extend %sidebar-link-hover; - } - - .icon-border { - @extend %no-cursor; - @include ml-mr(calc(($sb-btn-gap - $btn-border-width) / 2)); - - background-color: var(--sidebar-btn-color); - content: ''; - width: $btn-border-width; - height: $btn-border-width; - border-radius: 50%; - margin-bottom: $btn-mb; - } - } /* .sidebar-bottom */ -} /* #sidebar */ - -@media (hover: hover) { - #sidebar ul > li:last-child::after { - transition: top 0.5s ease; - } - - .nav-link { - transition: background-color 0.3s ease-in-out; - } - - .post-preview { - transition: background-color 0.35s ease-in-out; - } -} - -#search-result-wrapper { - display: none; - height: 100%; - width: 100%; - overflow: auto; - - .content { - margin-top: 2rem; - } -} - -/* --- top-bar --- */ - -#topbar-wrapper { - height: $topbar-height; - background-color: var(--topbar-bg); -} - -#topbar { - @extend %btn-color; - - #breadcrumb { - font-size: 1rem; - color: var(--text-muted-color); - padding-left: 0.5rem; - - a:hover { - @extend %link-hover; - } - - span { - &:not(:last-child) { - &::after { - content: '›'; - padding: 0 0.3rem; - } - } - } - } -} /* #topbar */ - -::-webkit-input-placeholder { - @include placeholder; -} - -::-moz-placeholder { - @include placeholder; -} - -:-ms-input-placeholder { - @include placeholder; -} - -::-ms-input-placeholder { - @include placeholder; -} - -::placeholder { - @include placeholder; -} - -:focus::-webkit-input-placeholder { - @include placeholder-focus; -} - -:focus::-moz-placeholder { - @include placeholder-focus; -} - -:focus:-ms-input-placeholder { - @include placeholder-focus; -} - -:focus::-ms-input-placeholder { - @include placeholder-focus; -} - -:focus::placeholder { - @include placeholder-focus; -} - -search { - display: flex; - width: 100%; - border-radius: 1rem; - border: 1px solid var(--search-border-color); - background: var(--main-bg); - padding: 0 0.5rem; - - i { - z-index: 2; - font-size: 0.9rem; - color: var(--search-icon-color); - } -} - -#sidebar-trigger, -#search-trigger { - display: none; -} - -/* 'Cancel' link */ -#search-cancel { - color: var(--link-color); - display: none; - white-space: nowrap; - - @extend %cursor-pointer; -} - -#search-input { - background: center; - border: 0; - border-radius: 0; - padding: 0.18rem 0.3rem; - color: var(--text-color); - height: auto; - - &:focus { - box-shadow: none; - } -} - -#search-hints { - padding: 0 1rem; - - h4 { - margin-bottom: 1.5rem; - } - - .post-tag { - display: inline-block; - line-height: 1rem; - font-size: 1rem; - background: var(--search-tag-bg); - border: none; - padding: 0.5rem; - margin: 0 1.25rem 1rem 0; - - &::before { - content: '#'; - color: var(--text-muted-color); - padding-right: 0.2rem; - } - - @extend %link-color; - } -} - -#search-results { - padding-bottom: 3rem; - - a { - font-size: 1.4rem; - line-height: 1.5rem; - - &:hover { - @extend %link-hover; - } - - @extend %link-color; - @extend %no-bottom-border; - @extend %heading; - } - - > article { - width: 100%; - - &:not(:last-child) { - margin-bottom: 1rem; - } - - /* icons */ - i { - color: #818182; - margin-right: 0.15rem; - font-size: 80%; - } - - > p { - @extend %text-ellipsis; - - white-space: break-spaces; - display: -webkit-box; - -webkit-line-clamp: 3; - -webkit-box-orient: vertical; - } - } -} /* #search-results */ - -#topbar-title { - display: none; - font-size: 1.1rem; - font-weight: 600; - font-family: sans-serif; - color: var(--topbar-text-color); - text-align: center; - width: 70%; - word-break: keep-all; -} - -#mask { - inset: 0 0 0 0; -} - -/* --- basic wrappers --- */ - -#main-wrapper { - position: relative; - - @include pl-pr(0); - - > .container { - min-height: 100vh; - } -} - -#topbar-wrapper.row, -#main-wrapper > .container > .row, -#search-result-wrapper > .row { - @include ml-mr(0); -} - -#tail-wrapper { - > :not(script) { - margin-top: 3rem; - } -} - -/* --- button back-to-top --- */ - -#back-to-top { - visibility: hidden; - opacity: 0; - z-index: 1; - cursor: pointer; - position: fixed; - right: 1rem; - bottom: calc($footer-height-large - $back2top-size / 2); - background: var(--button-bg); - color: var(--btn-backtotop-color); - padding: 0; - width: $back2top-size; - height: $back2top-size; - border-radius: 50%; - border: 1px solid var(--btn-backtotop-border-color); - transition: opacity 0.5s ease-in-out, transform 0.2s ease-out; - - &:hover { - transform: translate3d(0, -5px, 0); - -webkit-transform: translate3d(0, -5px, 0); - } - - i { - line-height: $back2top-size; - position: relative; - bottom: 2px; - } - - &.show { - opacity: 1; - visibility: visible; - } -} - -#notification { - @-webkit-keyframes popup { - from { - opacity: 0; - bottom: 0; - } - } - - @keyframes popup { - from { - opacity: 0; - bottom: 0; - } - } - - .toast-header { - background: none; - border-bottom: none; - color: inherit; - } - - .toast-body { - font-family: Lato, sans-serif; - line-height: 1.25rem; - - button { - font-size: 90%; - min-width: 4rem; - } - } - - &.toast { - &.show { - display: block; - min-width: 20rem; - border-radius: 0.5rem; - -webkit-backdrop-filter: blur(10px); - backdrop-filter: blur(10px); - background-color: rgba(255, 255, 255, 0.5); - color: #1b1b1eba; - position: fixed; - left: 50%; - bottom: 20%; - transform: translateX(-50%); - -webkit-animation: popup 0.8s; - animation: popup 0.8s; - } - } -} - -/* - Responsive Design: - - {sidebar, content, panel} >= 1200px screen width - {sidebar, content} >= 850px screen width - {content} <= 849px screen width - -*/ - -@media all and (max-width: 576px) { - main { - .content { - > blockquote[class^='prompt-'] { - @include ml-mr(-1rem); - - border-radius: 0; - max-width: none; - } - } - } - - #avatar { - width: 5rem; - height: 5rem; - } -} - -@media all and (max-width: 768px) { - %full-width { - max-width: 100%; - } - - #topbar { - @extend %full-width; - } - - #main-wrapper > .container { - @extend %full-width; - @include pl-pr(0); - } -} - -/* hide sidebar and panel */ -@media all and (max-width: 849px) { - @mixin slide($append: null) { - $basic: transform 0.4s ease; - - @if $append { - transition: $basic, $append; - } @else { - transition: $basic; - } - } - - footer { - @include slide; - - height: $footer-height-large; - padding: 1.5rem 0; - } - - [#{$sidebar-display}] { - #sidebar { - transform: translateX(0); - } - - #main-wrapper { - transform: translateX($sidebar-width); - } - - #back-to-top { - visibility: hidden; - } - } - - #sidebar { - @include slide; - - transform: translateX(-$sidebar-width); /* hide */ - -webkit-transform: translateX(-$sidebar-width); - } - - #main-wrapper { - @include slide; - } - - #topbar, - #main-wrapper > .container { - max-width: 100%; - } - - #search-result-wrapper { - width: 100%; - } - - #breadcrumb, - search { - display: none; - } - - #topbar-wrapper { - @include slide(top 0.2s ease); - - left: 0; - } - - main, - #panel-wrapper { - margin-top: 0; - } - - #topbar-title, - #sidebar-trigger, - #search-trigger { - display: block; - } - - #search-result-wrapper .content { - letter-spacing: 0; - } - - #tags { - justify-content: center !important; - } - - h1.dynamic-title { - display: none; - - ~ .content { - margin-top: 2.5rem; - } - } -} /* max-width: 849px */ - -/* Sidebar is visible */ -@media all and (min-width: 850px) { - /* Solved jumping scrollbar */ - html { - overflow-y: scroll; - } - - #main-wrapper { - margin-left: $sidebar-width; - } - - #sidebar { - .profile-wrapper { - margin-top: 3rem; - } - } - - #search-hints { - display: none; - } - - search { - max-width: $search-max-width; - } - - #search-result-wrapper { - max-width: $main-content-max-width; - justify-content: start !important; - } - - main { - h1 { - margin-top: 3rem; - } - } - - div.content .table-wrapper > table { - min-width: 70%; - } - - /* button 'back-to-Top' position */ - #back-to-top { - right: 5%; - bottom: calc($footer-height - $back2top-size / 2); - } - - #topbar-title { - text-align: left; - } -} - -/* Pad horizontal */ -@media all and (min-width: 992px) and (max-width: 1199px) { - #main-wrapper > .container .col-lg-11 { - flex: 0 0 96%; - max-width: 96%; - } -} - -/* Compact icons in sidebar & panel hidden */ -@media all and (min-width: 850px) and (max-width: 1199px) { - #search-results > div { - max-width: 700px; - } - - #breadcrumb { - width: 65%; - overflow: hidden; - text-overflow: ellipsis; - word-break: keep-all; - white-space: nowrap; - } -} - -/* panel hidden */ -@media all and (max-width: 1199px) { - #panel-wrapper { - display: none; - } - - #main-wrapper > .container > div.row { - justify-content: center !important; - } -} - -/* --- desktop mode, both sidebar and panel are visible --- */ - -@media all and (min-width: 1200px) { - search { - margin-right: 4rem; - } - - #search-input { - transition: all 0.3s ease-in-out; - } - - #search-results > article { - width: 45%; - - &:nth-child(odd) { - margin-right: 1.5rem; - } - - &:nth-child(even) { - margin-left: 1.5rem; - } - - &:last-child:nth-child(odd) { - position: relative; - right: 24.3%; - } - } - - .content { - font-size: 1.03rem; - } -} - -@media all and (min-width: 1400px) { - #back-to-top { - right: calc((100vw - $sidebar-width - 1140px) / 2 + 3rem); - } -} - -@media all and (min-width: 1650px) { - $icon-gap: 1rem; - - #main-wrapper { - margin-left: $sidebar-width-large; - } - - #topbar-wrapper { - left: $sidebar-width-large; - } - - search { - margin-right: calc( - $main-content-max-width / 4 - $search-max-width - 0.75rem - ); - } - - #main-wrapper > .container { - max-width: $main-content-max-width; - - @include pl-pr(1.75rem, true); - } - - main.col-12, - #tail-wrapper { - padding-right: 4.5rem !important; - } - - #back-to-top { - right: calc( - (100vw - $sidebar-width-large - $main-content-max-width) / 2 + 2rem - ); - } - - #sidebar { - width: $sidebar-width-large; - - .profile-wrapper { - margin-top: 3.5rem; - margin-bottom: 2.5rem; - padding-left: 3.5rem; - } - - ul { - li.nav-item { - @include pl-pr(2.75rem); - } - } - - .sidebar-bottom { - padding-left: 2.75rem; - margin-bottom: 1.75rem; - - a:not(:last-child) { - margin-right: $sb-btn-gap-lg; - } - - .icon-border { - @include ml-mr(calc(($sb-btn-gap-lg - $btn-border-width) / 2)); - } - } - } -} /* min-width: 1650px */ diff --git a/_sass/base/_base.scss b/_sass/base/_base.scss new file mode 100644 index 0000000..19f153b --- /dev/null +++ b/_sass/base/_base.scss @@ -0,0 +1,476 @@ +@use '../abstracts/variables' as v; +@use '../abstracts/breakpoints' as bp; +@use '../abstracts/mixins' as mx; +@use '../abstracts/placeholders'; +@use '../themes/light'; +@use '../themes/dark'; + +:root { + font-size: 16px; +} + +html { + @media (prefers-color-scheme: light) { + &:not([data-mode]), + &[data-mode='light'] { + @include light.styles; + } + + &[data-mode='dark'] { + @include dark.styles; + } + } + + @media (prefers-color-scheme: dark) { + &:not([data-mode]), + &[data-mode='dark'] { + @include dark.styles; + } + + &[data-mode='light'] { + @include light.styles; + } + } + + @include bp.lg { + overflow-y: scroll; + } +} + +body { + background: var(--main-bg); + padding: env(safe-area-inset-top) env(safe-area-inset-right) + env(safe-area-inset-bottom) env(safe-area-inset-left); + color: var(--text-color); + -webkit-font-smoothing: antialiased; + font-family: v.$font-family-base; +} + +h1.dynamic-title { + @include bp.lt(bp.get(lg)) { + display: none; + + ~ .content { + margin-top: 2.5rem; + } + } +} + +main { + &.col-12 { + @include bp.xxxl { + padding-right: 4.5rem !important; + } + } +} + +.preview-img { + aspect-ratio: 40 / 21; + width: 100%; + height: 100%; + overflow: hidden; + + @extend %rounded; + + &:not(.no-bg) { + background: var(--img-bg); + } + + img { + height: 100%; + -o-object-fit: cover; + object-fit: cover; + + @extend %rounded; + + @at-root #post-list & { + width: 100%; + } + } +} + +.post-preview { + @extend %rounded; + + border: 0; + background: var(--card-bg); + box-shadow: var(--card-shadow); + + &::before { + @extend %rounded; + + content: ''; + width: 100%; + height: 100%; + position: absolute; + background-color: var(--card-hovor-bg); + opacity: 0; + transition: opacity 0.35s ease-in-out; + } + + &:hover { + &::before { + opacity: 0.3; + } + } +} + +.post-meta { + @extend %text-sm; + + a { + &:not([class]):hover { + @extend %link-hover; + } + } + + em { + @extend %normal-font-style; + } +} + +.content { + font-size: 1.08rem; + margin-top: 2rem; + overflow-wrap: break-word; + + @include bp.xl { + font-size: 1.03rem; + } + + a { + &.popup { + @extend %no-cursor; + @extend %img-caption; + @include mx.mt-mb(0.5rem); + + cursor: zoom-in; + } + + &:not(.img-link) { + @extend %link-underline; + + &:hover { + @extend %link-hover; + } + } + } + + ol, + ul { + &:not([class]), + &.task-list { + -webkit-padding-start: 1.75rem; + padding-inline-start: 1.75rem; + + li { + margin: 0.25rem 0; + padding-left: 0.25rem; + } + + ol, + ul { + -webkit-padding-start: 1.25rem; + padding-inline-start: 1.25rem; + margin: 0.5rem 0; + } + } + } + + ul.task-list { + -webkit-padding-start: 1.25rem; + padding-inline-start: 1.25rem; + + li { + list-style-type: none; + padding-left: 0; + + /* checkbox icon */ + > i { + width: 2rem; + margin-left: -1.25rem; + color: var(--checkbox-color); + + &.checked { + color: var(--checkbox-checked-color); + } + } + + ul { + -webkit-padding-start: 1.75rem; + padding-inline-start: 1.75rem; + } + } + + input[type='checkbox'] { + margin: 0 0.5rem 0.2rem -1.3rem; + vertical-align: middle; + } + } /* ul */ + + dl > dd { + margin-left: 1rem; + } + + ::marker { + color: var(--text-muted-color); + } + + .table-wrapper > table { + @include bp.lg { + min-width: 70%; + } + } +} /* .content */ + +.tag:hover { + @extend %tag-hover; +} + +.post-tag { + display: inline-block; + min-width: 2rem; + text-align: center; + border-radius: 0.5rem; + border: 1px solid var(--btn-border-color); + padding: 0 0.4rem; + color: var(--text-muted-color); + line-height: 1.3rem; + + &:not(:last-child) { + margin-right: 0.2rem; + } +} + +.rounded-10 { + border-radius: 10px !important; +} + +.img-link { + color: transparent; + display: inline-flex; +} + +.shimmer { + overflow: hidden; + position: relative; + background: var(--img-bg); + + &::before { + content: ''; + position: absolute; + background: var(--shimmer-bg); + height: 100%; + width: 100%; + -webkit-animation: shimmer 1.3s infinite; + animation: shimmer 1.3s infinite; + } + + @-webkit-keyframes shimmer { + 0% { + transform: translateX(-100%); + } + + 100% { + transform: translateX(100%); + } + } + + @keyframes shimmer { + 0% { + transform: translateX(-100%); + } + + 100% { + transform: translateX(100%); + } + } +} + +.embed-video { + width: 100%; + height: 100%; + margin-bottom: 1rem; + aspect-ratio: 16 / 9; + + @extend %rounded; + + &.twitch { + aspect-ratio: 310 / 189; + } + + &.file { + display: block; + width: auto; + height: auto; + max-width: 100%; + max-height: 100%; + margin: auto; + margin-bottom: 0; + } + + @extend %img-caption; +} + +.embed-audio { + width: 100%; + display: block; + + @extend %img-caption; +} + +/* --- Effects classes --- */ + +.flex-grow-1 { + flex-grow: 1 !important; +} + +.btn-box-shadow { + box-shadow: var(--card-shadow); +} + +/* overwrite bootstrap muted */ +.text-muted { + color: var(--text-muted-color) !important; +} + +/* Overwrite bootstrap tooltip */ +.tooltip-inner { + font-size: 0.7rem; + max-width: 220px; + text-align: left; +} + +/* Overwrite bootstrap outline button */ +.btn.btn-outline-primary { + &:not(.disabled):hover { + border-color: #007bff !important; + } +} + +.disabled { + color: rgb(206, 196, 196); + pointer-events: auto; + cursor: not-allowed; +} + +.hide-border-bottom { + border-bottom: none !important; +} + +.input-focus { + box-shadow: none; + border-color: var(--input-focus-border-color) !important; + background: center !important; + transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out; +} + +.left { + float: left; + margin: 0.75rem 1rem 1rem 0; +} + +.right { + float: right; + margin: 0.75rem 0 1rem 1rem; +} + +/* --- Overriding --- */ + +/* mermaid */ +.mermaid { + text-align: center; +} + +/* MathJax */ +mjx-container { + overflow-y: hidden; + min-width: auto !important; +} + +@media (hover: hover) { + #sidebar ul > li:last-child::after { + transition: top 0.5s ease; + } + + .nav-link { + transition: background-color 0.3s ease-in-out; + } + + .post-preview { + transition: background-color 0.35s ease-in-out; + } +} + +#mask { + inset: 0 0 0 0; +} + +#main-wrapper { + position: relative; + + @include mx.pl-pr(0); + + @include bp.lt(bp.get(lg)) { + @include mx.slide; + } + + @include bp.lg { + margin-left: v.$sidebar-width; + } + + @include bp.xxxl { + margin-left: v.$sidebar-width-large; + } + + > .container { + min-height: 100vh; + + @include bp.lte(bp.get(md)) { + @include mx.max-w-100; + @include mx.pl-pr(0); + } + + @include bp.lt(bp.get(lg)) { + max-width: 100%; + } + + /* Pad horizontal */ + @include bp.between(992px, calc(#{bp.get(xl)} - 1px)) { + .col-lg-11 { + flex: 0 0 96%; + max-width: 96%; + } + } + + @include bp.lt(bp.get(xl)) { + > .row { + justify-content: center !important; + } + } + + @include bp.xxxl { + max-width: v.$main-content-max-width; + + @include mx.pl-pr(1.75rem, true); + } + } +} + +/* --- basic wrappers --- */ + +#topbar-wrapper.row, +#main-wrapper > .container > .row, +#search-result-wrapper > .row { + @include mx.ml-mr(0); +} + +#tail-wrapper { + @include bp.xxxl { + padding-right: 4.5rem !important; + } + + > :not(script) { + margin-top: 3rem; + } +} diff --git a/_sass/base/_index.scss b/_sass/base/_index.scss new file mode 100644 index 0000000..611d28f --- /dev/null +++ b/_sass/base/_index.scss @@ -0,0 +1,4 @@ +@forward 'reset'; +@forward 'base'; +@forward 'typography'; +@forward 'syntax'; diff --git a/_sass/base/_reset.scss b/_sass/base/_reset.scss new file mode 100644 index 0000000..1e5a629 --- /dev/null +++ b/_sass/base/_reset.scss @@ -0,0 +1,41 @@ +@use '../abstracts/mixins' as *; + +::-webkit-input-placeholder { + @include placeholder; +} + +::-moz-placeholder { + @include placeholder; +} + +:-ms-input-placeholder { + @include placeholder; +} + +::-ms-input-placeholder { + @include placeholder; +} + +::placeholder { + @include placeholder; +} + +:focus::-webkit-input-placeholder { + @include placeholder-focus; +} + +:focus::-moz-placeholder { + @include placeholder-focus; +} + +:focus:-ms-input-placeholder { + @include placeholder-focus; +} + +:focus::-ms-input-placeholder { + @include placeholder-focus; +} + +:focus::placeholder { + @include placeholder-focus; +} diff --git a/_sass/addon/syntax.scss b/_sass/base/_syntax.scss similarity index 74% rename from _sass/addon/syntax.scss rename to _sass/base/_syntax.scss index 6bd7b40..69924fc 100644 --- a/_sass/addon/syntax.scss +++ b/_sass/base/_syntax.scss @@ -1,44 +1,7 @@ -/* -* The syntax highlight. -*/ - -@import 'colors/syntax-light'; -@import 'colors/syntax-dark'; - -html { - @media (prefers-color-scheme: light) { - &:not([data-mode]), - &[data-mode='light'] { - @include light-syntax; - } - - &[data-mode='dark'] { - @include dark-syntax; - } - } - - @media (prefers-color-scheme: dark) { - &:not([data-mode]), - &[data-mode='dark'] { - @include dark-syntax; - } - - &[data-mode='light'] { - @include light-syntax; - } - } -} - -/* -- code snippets -- */ - -%code-snippet-bg { - background-color: var(--highlight-bg-color); -} - -%code-snippet-padding { - padding-left: 1rem; - padding-right: 1.5rem; -} +@use '../abstracts/variables' as v; +@use '../abstracts/breakpoints' as bp; +@use '../abstracts/mixins' as mx; +@use '../abstracts/placeholders'; .highlighter-rouge { color: var(--highlighter-rouge-color); @@ -59,7 +22,7 @@ html { pre { margin-bottom: 0; - font-size: $code-font-size; + font-size: v.$code-font-size; line-height: 1.4rem; word-wrap: normal; /* Fixed Safari overflow-x */ } @@ -101,10 +64,10 @@ code { color: var(--code-color); &.highlighter-rouge { - font-size: $code-font-size; + font-size: v.$code-font-size; padding: 3px 5px; word-break: break-word; - border-radius: $radius-sm; + border-radius: v.$radius-sm; background-color: var(--inline-code-bg); } @@ -150,9 +113,42 @@ div[class^='language-'] { box-shadow: var(--language-border-color) 0 0 0 1px; .content > & { - @include ml-mr(-1rem); + @include mx.ml-mr(-1rem); border-radius: 0; + + @include bp.sm { + @include mx.ml-mr(0); + + border-radius: v.$radius-lg; + } + } + + .code-header { + @include bp.sm { + @include mx.ml-mr(0); + + $dot-margin: 1rem; + + &::before { + content: ''; + display: inline-block; + margin-left: $dot-margin; + width: v.$code-dot-size; + height: v.$code-dot-size; + border-radius: 50%; + background-color: var(--code-header-muted-color); + box-shadow: (v.$code-dot-size + v.$code-dot-gap) 0 0 + var(--code-header-muted-color), + (v.$code-dot-size + v.$code-dot-gap) * 2 0 0 + var(--code-header-muted-color); + } + + span { + // center the text of label + margin-left: calc(($dot-margin + v.$code-dot-size) / 2 * -1); + } + } } .highlight { @@ -184,18 +180,18 @@ div { display: flex; justify-content: space-between; align-items: center; - height: $code-header-height; + height: v.$code-header-height; margin-left: 0.75rem; margin-right: 0.25rem; /* the label block */ span { - line-height: $code-header-height; + line-height: v.$code-header-height; /* label icon */ i { font-size: 1rem; - width: $code-icon-width; + width: v.$code-icon-width; color: var(--code-header-icon-color); &.small { @@ -223,8 +219,8 @@ div { @extend %rounded; border: 1px solid transparent; - height: $code-header-height; - width: $code-header-height; + height: v.$code-header-height; + width: v.$code-header-height; padding: 0; background-color: inherit; @@ -255,38 +251,3 @@ div { } } } - -@media all and (min-width: 576px) { - div[class^='language-'] { - .content > & { - @include ml-mr(0); - - border-radius: $radius-lg; - } - - .code-header { - @include ml-mr(0); - - $dot-margin: 1rem; - - &::before { - content: ''; - display: inline-block; - margin-left: $dot-margin; - width: $code-dot-size; - height: $code-dot-size; - border-radius: 50%; - background-color: var(--code-header-muted-color); - box-shadow: ($code-dot-size + $code-dot-gap) 0 0 - var(--code-header-muted-color), - ($code-dot-size + $code-dot-gap) * 2 0 0 - var(--code-header-muted-color); - } - - span { - // center the text of label - margin-left: calc(($dot-margin + $code-dot-size) / 2 * -1); - } - } - } -} diff --git a/_sass/base/_typography.scss b/_sass/base/_typography.scss new file mode 100644 index 0000000..4cf3964 --- /dev/null +++ b/_sass/base/_typography.scss @@ -0,0 +1,266 @@ +@use '../abstracts/variables' as v; +@use '../abstracts/breakpoints' as bp; +@use '../abstracts/mixins' as mx; +@use '../abstracts/placeholders'; + +@for $i from 1 through 5 { + h#{$i} { + @extend %heading; + + @if $i > 1 { + @extend %anchor; + } + + @if $i < 5 { + $size-factor: 0.25rem; + + @if $i > 1 { + $size-factor: 0.18rem; + + main & { + @if $i == 2 { + margin: 2.5rem 0 1.25rem; + } @else { + margin: 2rem 0 1rem; + } + } + } + + & { + font-size: 1rem + (5 - $i) * $size-factor; + } + } @else { + font-size: 1.05rem; + } + } +} + +a { + @extend %link-color; + + text-decoration: none; +} + +img { + max-width: 100%; + height: auto; + transition: all 0.35s ease-in-out; + + .blur & { + $blur: 20px; + + -webkit-filter: blur($blur); + filter: blur($blur); + } +} + +blockquote { + border-left: 0.125rem solid var(--blockquote-border-color); + padding-left: 1rem; + color: var(--blockquote-text-color); + margin-top: 0.5rem; + + > p:last-child { + margin-bottom: 0; + } + + &[class^='prompt-'] { + border-left: 0; + position: relative; + padding: 1rem 1rem 1rem 3rem; + color: var(--prompt-text-color); + + @extend %rounded; + + &::before { + text-align: center; + width: 3rem; + position: absolute; + left: 0.25rem; + margin-top: 0.4rem; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + } + } + + @include mx.prompt('tip', '\f0eb', $fa-style: 'regular'); + @include mx.prompt('info', '\f06a', $rotate: 180); + @include mx.prompt('warning', '\f06a'); + @include mx.prompt('danger', '\f071'); +} + +kbd { + font-family: Lato, sans-serif; + display: inline-block; + vertical-align: middle; + line-height: 1.3rem; + min-width: 1.75rem; + text-align: center; + margin: 0 0.3rem; + padding-top: 0.1rem; + color: var(--kbd-text-color); + background-color: var(--kbd-bg-color); + border-radius: v.$radius-sm; + border: solid 1px var(--kbd-wrap-color); + box-shadow: inset 0 -2px 0 var(--kbd-wrap-color); +} + +hr { + border-color: var(--main-border-color); + opacity: 1; +} + +footer { + background-color: var(--main-bg); + height: v.$footer-height; + border-top: 1px solid var(--main-border-color); + + @extend %text-xs; + + a { + @extend %text-highlight; + + &:hover { + @extend %link-hover; + } + } + + em { + @extend %text-highlight; + } + + p { + text-align: center; + margin-bottom: 0; + } +} + +/* fontawesome icons */ +i { + &.far, + &.fas { + @extend %no-cursor; + } +} + +sup { + @extend %sup-fn-target; +} + +main { + line-height: 1.75; + + h1 { + margin-top: 2rem; + + @include bp.lg { + margin-top: 3rem; + } + } + + p { + > a.popup { + &:not(.normal):not(.left):not(.right) { + @include mx.align-center; + } + } + } + + .categories, + #tags, + #archives { + a:not(:hover) { + @extend %no-bottom-border; + } + } + + @include bp.lte(bp.get(sm)) { + .content { + > blockquote[class^='prompt-'] { + @include mx.ml-mr(-1rem); + + border-radius: 0; + max-width: none; + } + } + } +} + +.footnotes > ol { + padding-left: 2rem; + margin-top: 0.5rem; + + > li { + &:not(:last-child) { + margin-bottom: 0.3rem; + } + + @extend %sup-fn-target; + + > p { + margin-left: 0.25em; + + @include mx.mt-mb(0); + } + } +} + +.footnote { + @at-root a#{&} { + @include mx.ml-mr(1px); + @include mx.pl-pr(2px); + + border-bottom-style: none !important; + } +} + +.reversefootnote { + @at-root a#{&} { + font-size: 0.6rem; + line-height: 1; + position: relative; + bottom: 0.25em; + margin-left: 0.25em; + border-bottom-style: none !important; + } +} + +/* --- Begin of Markdown table style --- */ + +/* it will be created by Liquid */ +.table-wrapper { + overflow-x: auto; + margin-bottom: 1.5rem; + + > table { + min-width: 100%; + overflow-x: auto; + border-spacing: 0; + + thead { + border-bottom: solid 2px rgba(210, 215, 217, 0.75); + + th { + @extend %table-cell; + } + } + + tbody { + tr { + border-bottom: 1px solid var(--tb-border-color); + + &:nth-child(2n) { + background-color: var(--tb-even-bg); + } + + &:nth-child(2n + 1) { + background-color: var(--tb-odd-bg); + } + + td { + @extend %table-cell; + } + } + } /* tbody */ + } /* table */ +} diff --git a/_sass/colors/syntax-dark.scss b/_sass/colors/syntax-dark.scss deleted file mode 100644 index eb92204..0000000 --- a/_sass/colors/syntax-dark.scss +++ /dev/null @@ -1,164 +0,0 @@ -/* - * The syntax dark mode styles. - */ - -@mixin dark-syntax { - --language-border-color: #2d2d2d; - --highlight-bg-color: #151515; - --highlighter-rouge-color: #c9def1; - --highlight-lineno-color: #808080; - --inline-code-bg: rgba(255, 255, 255, 0.05); - --code-color: #b0b0b0; - --code-header-text-color: #6a6a6a; - --code-header-muted-color: #353535; - --code-header-icon-color: #565656; - --clipboard-checked-color: #2bcc2b; - --filepath-text-color: #cacaca; - - .highlight .gp { - color: #87939d; - } - - /* --- Syntax highlight theme from `rougify style base16.dark` --- */ - - .highlight table td { - padding: 5px; - } - - .highlight table pre { - margin: 0; - } - - .highlight, - .highlight .w { - color: #d0d0d0; - background-color: #151515; - } - - .highlight .err { - color: #151515; - background-color: #ac4142; - } - - .highlight .c, - .highlight .ch, - .highlight .cd, - .highlight .cm, - .highlight .cpf, - .highlight .c1, - .highlight .cs { - color: #848484; - } - - .highlight .cp { - color: #f4bf75; - } - - .highlight .nt { - color: #f4bf75; - } - - .highlight .o, - .highlight .ow { - color: #d0d0d0; - } - - .highlight .p, - .highlight .pi { - color: #d0d0d0; - } - - .highlight .gi { - color: #90a959; - } - - .highlight .gd { - color: #f08a8b; - background-color: #320000; - } - - .highlight .gh { - color: #6a9fb5; - background-color: #151515; - font-weight: bold; - } - - .highlight .k, - .highlight .kn, - .highlight .kp, - .highlight .kr, - .highlight .kv { - color: #aa759f; - } - - .highlight .kc { - color: #d28445; - } - - .highlight .kt { - color: #d28445; - } - - .highlight .kd { - color: #d28445; - } - - .highlight .s, - .highlight .sb, - .highlight .sc, - .highlight .dl, - .highlight .sd, - .highlight .s2, - .highlight .sh, - .highlight .sx, - .highlight .s1 { - color: #90a959; - } - - .highlight .sa { - color: #aa759f; - } - - .highlight .sr { - color: #75b5aa; - } - - .highlight .si { - color: #b76d45; - } - - .highlight .se { - color: #b76d45; - } - - .highlight .nn { - color: #f4bf75; - } - - .highlight .nc { - color: #f4bf75; - } - - .highlight .no { - color: #f4bf75; - } - - .highlight .na { - color: #6a9fb5; - } - - .highlight .m, - .highlight .mb, - .highlight .mf, - .highlight .mh, - .highlight .mi, - .highlight .il, - .highlight .mo, - .highlight .mx { - color: #90a959; - } - - .highlight .ss { - color: #90a959; - } -} diff --git a/_sass/colors/syntax-light.scss b/_sass/colors/syntax-light.scss deleted file mode 100644 index 76aa669..0000000 --- a/_sass/colors/syntax-light.scss +++ /dev/null @@ -1,210 +0,0 @@ -/* - * The syntax light mode code snippet colors. - */ - -@mixin light-syntax { - /* --- custom light colors --- */ - --language-border-color: #ececec; - --highlight-bg-color: #f6f8fa; - --highlighter-rouge-color: #3f596f; - --highlight-lineno-color: #9e9e9e; - --inline-code-bg: rgba(25, 25, 28, 0.05); - --code-color: #3a3a3a; - --code-header-text-color: #a3a3a3; - --code-header-muted-color: #e5e5e5; - --code-header-icon-color: #c9c8c8; - --clipboard-checked-color: #43c743; - - /* --- Syntax highlight theme from `rougify style github` --- */ - - .highlight table td { - padding: 5px; - } - - .highlight table pre { - margin: 0; - } - - .highlight, - .highlight .w { - color: #24292f; - background-color: #f6f8fa; - } - - .highlight .k, - .highlight .kd, - .highlight .kn, - .highlight .kp, - .highlight .kr, - .highlight .kt, - .highlight .kv { - color: #cf222e; - } - - .highlight .gr { - color: #f6f8fa; - } - - .highlight .gd { - color: #82071e; - background-color: #ffebe9; - } - - .highlight .nb { - color: #953800; - } - - .highlight .nc { - color: #953800; - } - - .highlight .no { - color: #953800; - } - - .highlight .nn { - color: #953800; - } - - .highlight .sr { - color: #116329; - } - - .highlight .na { - color: #116329; - } - - .highlight .nt { - color: #116329; - } - - .highlight .gi { - color: #116329; - background-color: #dafbe1; - } - - .highlight .kc { - color: #0550ae; - } - - .highlight .l, - .highlight .ld, - .highlight .m, - .highlight .mb, - .highlight .mf, - .highlight .mh, - .highlight .mi, - .highlight .il, - .highlight .mo, - .highlight .mx { - color: #0550ae; - } - - .highlight .sb { - color: #0550ae; - } - - .highlight .bp { - color: #0550ae; - } - - .highlight .ne { - color: #0550ae; - } - - .highlight .nl { - color: #0550ae; - } - - .highlight .py { - color: #0550ae; - } - - .highlight .nv, - .highlight .vc, - .highlight .vg, - .highlight .vi, - .highlight .vm { - color: #0550ae; - } - - .highlight .o, - .highlight .ow { - color: #0550ae; - } - - .highlight .gh { - color: #0550ae; - font-weight: bold; - } - - .highlight .gu { - color: #0550ae; - font-weight: bold; - } - - .highlight .s, - .highlight .sa, - .highlight .sc, - .highlight .dl, - .highlight .sd, - .highlight .s2, - .highlight .se, - .highlight .sh, - .highlight .sx, - .highlight .s1, - .highlight .ss { - color: #0a3069; - } - - .highlight .nd { - color: #8250df; - } - - .highlight .nf, - .highlight .fm { - color: #8250df; - } - - .highlight .err { - color: #f6f8fa; - background-color: #82071e; - } - - .highlight .c, - .highlight .ch, - .highlight .cd, - .highlight .cm, - .highlight .cp, - .highlight .cpf, - .highlight .c1, - .highlight .cs { - color: #68717a; - } - - .highlight .gl { - color: #68717a; - } - - .highlight .gt { - color: #68717a; - } - - .highlight .ni { - color: #24292f; - } - - .highlight .si { - color: #24292f; - } - - .highlight .ge { - color: #24292f; - font-style: italic; - } - - .highlight .gs { - color: #24292f; - font-weight: bold; - } -} /* light-syntax */ diff --git a/_sass/colors/typography-light.scss b/_sass/colors/typography-light.scss deleted file mode 100644 index b6fc561..0000000 --- a/_sass/colors/typography-light.scss +++ /dev/null @@ -1,112 +0,0 @@ -/* - * The syntax light mode typography colors - */ - -@mixin light-scheme { - /* Framework color */ - --main-bg: white; - --mask-bg: #c1c3c5; - --main-border-color: #f3f3f3; - - /* Common color */ - --text-color: #34343c; - --text-muted-color: #757575; - --text-muted-highlight-color: inherit; - --heading-color: #2a2a2a; - --label-color: #585858; - --blockquote-border-color: #eeeeee; - --blockquote-text-color: #757575; - --link-color: #0056b2; - --link-underline-color: #dee2e6; - --button-bg: #ffffff; - --btn-border-color: #e9ecef; - --btn-backtotop-color: #686868; - --btn-backtotop-border-color: #f1f1f1; - --checkbox-color: #c5c5c5; - --checkbox-checked-color: #07a8f7; - --img-bg: radial-gradient( - circle, - rgb(255, 255, 255) 0%, - rgb(239, 239, 239) 100% - ); - --shimmer-bg: linear-gradient( - 90deg, - rgba(250, 250, 250, 0) 0%, - rgba(232, 230, 230, 1) 50%, - rgba(250, 250, 250, 0) 100% - ); - - /* Sidebar */ - --site-title-color: rgb(113, 113, 113); - --site-subtitle-color: #717171; - --sidebar-bg: #f6f8fa; - --sidebar-border-color: #efefef; - --sidebar-muted-color: #545454; - --sidebar-active-color: #1d1d1d; - --sidebar-hover-bg: rgb(223, 233, 241, 0.64); - --sidebar-btn-bg: white; - --sidebar-btn-color: #8e8e8e; - --avatar-border-color: white; - - /* Topbar */ - --topbar-bg: rgb(255, 255, 255, 0.7); - --topbar-text-color: rgb(78, 78, 78); - --search-border-color: rgb(240, 240, 240); - --search-icon-color: #c2c6cc; - --input-focus-border-color: #b8b8b8; - - /* Home page */ - --post-list-text-color: dimgray; - --btn-patinator-text-color: #555555; - --btn-paginator-hover-color: var(--sidebar-bg); - - /* Posts */ - --toc-highlight: #0550ae; - --toc-popup-border-color: lightgray; - --btn-share-color: gray; - --btn-share-hover-color: #0d6efd; - --card-bg: white; - --card-hovor-bg: #e2e2e2; - --card-shadow: rgb(104, 104, 104, 0.05) 0 2px 6px 0, - rgba(211, 209, 209, 0.15) 0 0 0 1px; - --footnote-target-bg: lightcyan; - --tb-odd-bg: #fbfcfd; - --tb-border-color: #eaeaea; - --dash-color: silver; - --kbd-wrap-color: #bdbdbd; - --kbd-text-color: var(--text-color); - --kbd-bg-color: white; - --prompt-text-color: rgb(46, 46, 46, 0.77); - --prompt-tip-bg: rgb(123, 247, 144, 0.2); - --prompt-tip-icon-color: #03b303; - --prompt-info-bg: #e1f5fe; - --prompt-info-icon-color: #0070cb; - --prompt-warning-bg: rgb(255, 243, 205); - --prompt-warning-icon-color: #ef9c03; - --prompt-danger-bg: rgb(248, 215, 218, 0.56); - --prompt-danger-icon-color: #df3c30; - - /* Tags */ - --tag-border: #dee2e6; - --tag-shadow: var(--btn-border-color); - --tag-hover: rgb(222, 226, 230); - --search-tag-bg: #f8f9fa; - - /* Categories */ - --categories-border: rgba(0, 0, 0, 0.125); - --categories-hover-bg: var(--btn-border-color); - --categories-icon-hover-color: darkslategray; - - /* Archive */ - --timeline-color: rgba(0, 0, 0, 0.075); - --timeline-node-bg: #c2c6cc; - --timeline-year-dot-color: #ffffff; - - [class^='prompt-'] { - --link-underline-color: rgb(219, 216, 216); - } - - .dark { - display: none; - } -} /* light-scheme */ diff --git a/_sass/components/_buttons.scss b/_sass/components/_buttons.scss new file mode 100644 index 0000000..bd7363e --- /dev/null +++ b/_sass/components/_buttons.scss @@ -0,0 +1,51 @@ +@use '../abstracts/variables' as v; +@use '../abstracts/breakpoints' as bp; + +#back-to-top { + visibility: hidden; + opacity: 0; + z-index: 1; + cursor: pointer; + position: fixed; + right: 1rem; + bottom: calc(v.$footer-height-large - v.$back2top-size / 2); + background: var(--button-bg); + color: var(--btn-backtotop-color); + padding: 0; + width: v.$back2top-size; + height: v.$back2top-size; + border-radius: 50%; + border: 1px solid var(--btn-backtotop-border-color); + transition: opacity 0.5s ease-in-out, transform 0.2s ease-out; + + @include bp.lg { + right: 5%; + bottom: calc(v.$footer-height - v.$back2top-size / 2); + } + + @include bp.xxl { + right: calc((100vw - v.$sidebar-width - 1140px) / 2 + 3rem); + } + + @include bp.xxxl { + right: calc( + (100vw - v.$sidebar-width-large - v.$main-content-max-width) / 2 + 2rem + ); + } + + &:hover { + transform: translate3d(0, -5px, 0); + -webkit-transform: translate3d(0, -5px, 0); + } + + i { + line-height: v.$back2top-size; + position: relative; + bottom: 2px; + } + + &.show { + opacity: 1; + visibility: visible; + } +} diff --git a/_sass/components/_index.scss b/_sass/components/_index.scss new file mode 100644 index 0000000..ffbb908 --- /dev/null +++ b/_sass/components/_index.scss @@ -0,0 +1,2 @@ +@forward 'buttons'; +@forward 'popups'; diff --git a/_sass/components/_popups.scss b/_sass/components/_popups.scss new file mode 100644 index 0000000..ca3e2fc --- /dev/null +++ b/_sass/components/_popups.scss @@ -0,0 +1,172 @@ +@use '../abstracts/variables' as v; +@use '../abstracts/breakpoints' as bp; +@use '../abstracts/placeholders'; + +/* PWA update popup */ +#notification { + @-webkit-keyframes popup { + from { + opacity: 0; + bottom: 0; + } + } + + @keyframes popup { + from { + opacity: 0; + bottom: 0; + } + } + + .toast-header { + background: none; + border-bottom: none; + color: inherit; + } + + .toast-body { + font-family: Lato, sans-serif; + line-height: 1.25rem; + + button { + font-size: 90%; + min-width: 4rem; + } + } + + &.toast { + &.show { + display: block; + min-width: 20rem; + border-radius: 0.5rem; + -webkit-backdrop-filter: blur(10px); + backdrop-filter: blur(10px); + background-color: rgba(255, 255, 255, 0.5); + color: #1b1b1eba; + position: fixed; + left: 50%; + bottom: 20%; + transform: translateX(-50%); + -webkit-animation: popup 0.8s; + animation: popup 0.8s; + } + } +} + +#toc-popup { + $slide-in: slide-in 0.3s ease-out; + $slide-out: slide-out 0.3s ease-out; + $curtain-height: 2rem; + $backdrop: blur(5px); + + border-color: var(--toc-popup-border-color); + border-width: 1px; + border-radius: v.$radius-lg; + color: var(--text-color); + background: var(--card-bg); + margin-top: v.$topbar-height; + min-width: 20rem; + font-size: 1.05rem; + + @include bp.sm { + max-width: 32rem; + } + + &[open] { + -webkit-animation: $slide-in; + animation: $slide-in; + } + + &[closing] { + -webkit-animation: $slide-out; + animation: $slide-out; + } + + @include bp.lg { + left: v.$sidebar-width; + } + + .header { + @extend %btn-color; + + position: -webkit-sticky; + position: sticky; + top: 0; + background-color: inherit; + border-bottom: 1px solid var(--main-border-color); + + .label { + font-family: v.$font-family-heading; + } + } + + button { + > i { + font-size: 1.25rem; + vertical-align: middle; + } + + &:focus-visible { + box-shadow: none; + } + } + + ul { + list-style-type: none; + padding-left: 0; + + li { + ul, + & + li { + margin-top: 0.25rem; + } + + a { + display: flex; + line-height: 1.5; + padding: 0.375rem 0; + padding-right: 1.125rem; + + &.toc-link::before { + display: none; + } + } + } + } + + @for $i from 2 through 4 { + .node-name--H#{$i} { + padding-left: 1.125rem * ($i - 1); + } + } + + .is-active-link { + color: var(--toc-highlight) !important; + font-weight: 600; + } + + &::-webkit-backdrop { + -webkit-backdrop-filter: $backdrop; + backdrop-filter: $backdrop; + } + + &::backdrop { + -webkit-backdrop-filter: $backdrop; + backdrop-filter: $backdrop; + } + + &::after { + display: flex; + content: ''; + position: relative; + background: linear-gradient(transparent, var(--card-bg) 70%); + height: $curtain-height; + } + + #toc-popup-content { + overflow: auto; + max-height: calc(100vh - 4 * v.$topbar-height); + font-family: v.$font-family-heading; + margin-bottom: -$curtain-height; + } +} diff --git a/_sass/layout/_footer.scss b/_sass/layout/_footer.scss new file mode 100644 index 0000000..fd49ea0 --- /dev/null +++ b/_sass/layout/_footer.scss @@ -0,0 +1,36 @@ +@use '../abstracts/breakpoints' as bp; +@use '../abstracts/variables' as v; +@use '../abstracts/mixins' as mx; +@use '../abstracts/placeholders'; + +footer { + background-color: var(--main-bg); + height: v.$footer-height; + border-top: 1px solid var(--main-border-color); + + @extend %text-xs; + + @include bp.lt(bp.get(lg)) { + @include mx.slide; + + height: v.$footer-height-large; + padding: 1.5rem 0; + } + + a { + @extend %text-highlight; + + &:hover { + @extend %link-hover; + } + } + + em { + @extend %text-highlight; + } + + p { + text-align: center; + margin-bottom: 0; + } +} diff --git a/_sass/layout/_index.scss b/_sass/layout/_index.scss new file mode 100644 index 0000000..fa75daf --- /dev/null +++ b/_sass/layout/_index.scss @@ -0,0 +1,4 @@ +@forward 'sidebar'; +@forward 'topbar'; +@forward 'panel'; +@forward 'footer'; diff --git a/_sass/layout/_panel.scss b/_sass/layout/_panel.scss new file mode 100644 index 0000000..bb5c2bc --- /dev/null +++ b/_sass/layout/_panel.scss @@ -0,0 +1,66 @@ +@use '../abstracts/breakpoints' as bp; +@use '../abstracts/mixins' as mx; +@use '../abstracts/placeholders'; + +.access { + top: 2rem; + transition: top 0.2s ease-in-out; + margin-top: 3rem; + margin-bottom: 4rem; + + &:only-child { + position: -webkit-sticky; + position: sticky; + } + + > section { + padding-left: 1rem; + border-left: 1px solid var(--main-border-color); + + &:not(:last-child) { + margin-bottom: 4rem; + } + } + + .content { + font-size: 0.9rem; + } +} + +#panel-wrapper { + /* the headings */ + .panel-heading { + font-family: inherit; + line-height: inherit; + + @include mx.label(inherit); + } + + .post-tag { + line-height: 1.05rem; + font-size: 0.85rem; + border-radius: 0.8rem; + padding: 0.3rem 0.5rem; + margin: 0 0.35rem 0.5rem 0; + + &:hover { + transition: all 0.3s ease-in; + } + } + + @include bp.lt(bp.get(xl)) { + display: none; + } +} + +#access-lastmod { + a { + color: inherit; + + &:hover { + @extend %link-hover; + } + + @extend %no-bottom-border; + } +} diff --git a/_sass/layout/_sidebar.scss b/_sass/layout/_sidebar.scss new file mode 100644 index 0000000..eaad470 --- /dev/null +++ b/_sass/layout/_sidebar.scss @@ -0,0 +1,258 @@ +@use '../abstracts/variables' as v; +@use '../abstracts/mixins' as mx; +@use '../abstracts/breakpoints' as bp; +@use '../abstracts/placeholders'; + +$btn-border-width: 3px; +$btn-mb: 0.5rem; +$sidebar-display: 'sidebar-display'; /* the attribute for sidebar display */ + +#sidebar { + @include mx.pl-pr(0); + + position: fixed; + top: 0; + left: 0; + height: 100%; + overflow-y: auto; + width: v.$sidebar-width; + background: var(--sidebar-bg); + border-right: 1px solid var(--sidebar-border-color); + + /* Hide scrollbar for IE, Edge and Firefox */ + -ms-overflow-style: none; /* IE and Edge */ + scrollbar-width: none; /* Firefox */ + + /* Hide scrollbar for Chrome, Safari and Opera */ + &::-webkit-scrollbar { + display: none; + } + + @include bp.lt(bp.get(lg)) { + @include mx.slide; + + transform: translateX(-#{v.$sidebar-width}); /* hide */ + -webkit-transform: translateX(-#{v.$sidebar-width}); + + [#{$sidebar-display}] & { + transform: translateX(0); + } + } + + @include bp.xxxl { + width: v.$sidebar-width-large; + } + + %sidebar-link-hover { + &:hover { + color: var(--sidebar-active-color); + } + } + + a { + @extend %sidebar-links; + } + + #avatar { + display: block; + width: 6.5rem; + height: 6.5rem; + overflow: hidden; + box-shadow: var(--avatar-border-color) 0 0 0 2px; + transform: translateZ(0); /* fixed the zoom in Safari */ + + @include bp.sm { + width: 7rem; + height: 7rem; + } + + img { + transition: transform 0.5s; + + &:hover { + transform: scale(1.2); + } + } + } + + .profile-wrapper { + @include mx.mt-mb(2.5rem); + @extend %clickable-transition; + + padding-left: 2.5rem; + padding-right: 1.25rem; + width: 100%; + + @include bp.lg { + margin-top: 3rem; + } + + @include bp.xxxl { + margin-top: 3.5rem; + margin-bottom: 2.5rem; + padding-left: 3.5rem; + } + } + + .site-title { + @extend %clickable-transition; + @extend %sidebar-link-hover; + + font-family: inherit; + font-weight: 900; + font-size: 1.75rem; + line-height: 1.2; + letter-spacing: 0.25px; + margin-top: 1.25rem; + margin-bottom: 0.5rem; + width: fit-content; + color: var(--site-title-color); + } + + .site-subtitle { + font-size: 95%; + color: var(--site-subtitle-color); + margin-top: 0.25rem; + word-spacing: 1px; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + } + + ul { + margin-bottom: 2rem; + + li.nav-item { + opacity: 0.9; + width: 100%; + + @include mx.pl-pr(1.5rem); + + @include bp.xxxl { + @include mx.pl-pr(2.75rem); + } + + a.nav-link { + @include mx.pt-pb(0.6rem); + + display: flex; + align-items: center; + border-radius: 0.75rem; + font-weight: 600; + + &:hover { + background-color: var(--sidebar-hover-bg); + } + + i { + font-size: 95%; + opacity: 0.8; + margin-right: 1.5rem; + } + + span { + font-size: 90%; + letter-spacing: 0.2px; + } + } + + &.active { + .nav-link { + color: var(--sidebar-active-color); + background-color: var(--sidebar-hover-bg); + + span { + opacity: 1; + } + } + } + + &:not(:first-child) { + margin-top: 0.25rem; + } + } + } + + .sidebar-bottom { + padding-left: 2rem; + padding-right: 1rem; + margin-bottom: 1.5rem; + + @include bp.xxxl { + padding-left: 2.75rem; + margin-bottom: 1.75rem; + } + + $btn-size: 1.75rem; + + %button { + width: $btn-size; + height: $btn-size; + margin-bottom: $btn-mb; // multi line gap + border-radius: 50%; + color: var(--sidebar-btn-color); + background-color: var(--sidebar-btn-bg); + text-align: center; + display: flex; + align-items: center; + justify-content: center; + + &:not(:focus-visible) { + box-shadow: var(--sidebar-border-color) 0 0 0 1px; + } + + &:hover { + background-color: var(--sidebar-hover-bg); + } + } + + a { + @extend %button; + @extend %sidebar-link-hover; + @extend %clickable-transition; + + &:not(:last-child) { + margin-right: v.$sb-btn-gap; + + @include bp.xxxl { + margin-right: v.$sb-btn-gap-lg; + } + } + } + + i { + line-height: $btn-size; + } + + #mode-toggle { + @extend %button; + @extend %sidebar-links; + @extend %sidebar-link-hover; + } + + .icon-border { + @extend %no-cursor; + @include mx.ml-mr(calc((v.$sb-btn-gap - $btn-border-width) / 2)); + + background-color: var(--sidebar-btn-color); + content: ''; + width: $btn-border-width; + height: $btn-border-width; + border-radius: 50%; + margin-bottom: $btn-mb; + + @include bp.xxxl { + @include mx.ml-mr(calc((v.$sb-btn-gap-lg - $btn-border-width) / 2)); + } + } + } /* .sidebar-bottom */ +} /* #sidebar */ + +[#{$sidebar-display}] { + #main-wrapper { + @include bp.lt(bp.get(lg)) { + transform: translateX(v.$sidebar-width); + } + } +} diff --git a/_sass/layout/_topbar.scss b/_sass/layout/_topbar.scss new file mode 100644 index 0000000..eb0aea9 --- /dev/null +++ b/_sass/layout/_topbar.scss @@ -0,0 +1,86 @@ +@use '../abstracts/variables' as v; +@use '../abstracts/mixins' as mx; +@use '../abstracts/breakpoints' as bp; +@use '../abstracts/placeholders'; + +#topbar-wrapper { + height: v.$topbar-height; + background-color: var(--topbar-bg); + + @include bp.lt(bp.get(lg)) { + @include mx.slide(top 0.2s ease); + + left: 0; + } +} + +#topbar { + @extend %btn-color; + + #breadcrumb { + font-size: 1rem; + color: var(--text-muted-color); + padding-left: 0.5rem; + + a:hover { + @extend %link-hover; + } + + span { + &:not(:last-child) { + &::after { + content: '›'; + padding: 0 0.3rem; + } + } + } + + @include bp.lt(bp.get(lg)) { + display: none; + } + + @include bp.between(bp.get(lg), calc(#{bp.get(xl)} - 1px)) { + width: 65%; + overflow: hidden; + text-overflow: ellipsis; + word-break: keep-all; + white-space: nowrap; + } + } + + @include bp.lte(bp.get(md)) { + @include mx.max-w-100; + } + + @include bp.lt(bp.get(lg)) { + max-width: 100%; + } +} + +#topbar-title { + display: none; + font-size: 1.1rem; + font-weight: 600; + font-family: sans-serif; + color: var(--topbar-text-color); + text-align: center; + width: 70%; + word-break: keep-all; + + @include bp.lt(bp.get(lg)) { + display: block; + } + + @include bp.lg { + text-align: left; + } +} + +#sidebar-trigger, +#search-trigger { + display: none; + + @include bp.lt(bp.get(lg)) { + display: block; + } +} diff --git a/_sass/main.bundle.scss b/_sass/main.bundle.scss index 52e893f..5d84f93 100644 --- a/_sass/main.bundle.scss +++ b/_sass/main.bundle.scss @@ -1,2 +1,2 @@ -@import 'dist/bootstrap'; -@import 'main'; +@use 'vendors/bootstrap'; +@use 'main'; diff --git a/_sass/main.scss b/_sass/main.scss index 1c2311d..3bbb70d 100644 --- a/_sass/main.scss +++ b/_sass/main.scss @@ -1,13 +1,4 @@ -@import 'colors/typography-light'; -@import 'colors/typography-dark'; -@import 'addon/variables'; -@import 'variables-hook'; -@import 'addon/module'; -@import 'addon/syntax'; -@import 'addon/commons'; -@import 'layout/home'; -@import 'layout/post'; -@import 'layout/tags'; -@import 'layout/archives'; -@import 'layout/categories'; -@import 'layout/category-tag'; +@forward 'base'; +@forward 'components'; +@forward 'layout'; +@forward 'pages'; diff --git a/_sass/layout/archives.scss b/_sass/pages/_archives.scss similarity index 95% rename from _sass/layout/archives.scss rename to _sass/pages/_archives.scss index fd1979b..86e77a8 100644 --- a/_sass/layout/archives.scss +++ b/_sass/pages/_archives.scss @@ -1,10 +1,17 @@ -/* - Style for Archives -*/ +@use '../abstracts/breakpoints' as bp; +@use '../abstracts/placeholders'; #archives { letter-spacing: 0.03rem; + @include bp.lt(bp.get(sm)) { + margin-top: -1rem; + + ul { + letter-spacing: 0; + } + } + $timeline-width: 4px; %timeline { @@ -131,13 +138,3 @@ } } } /* #archives */ - -@media all and (max-width: 576px) { - #archives { - margin-top: -1rem; - - ul { - letter-spacing: 0; - } - } -} diff --git a/_sass/layout/categories.scss b/_sass/pages/_categories.scss similarity index 87% rename from _sass/layout/categories.scss rename to _sass/pages/_categories.scss index f12b963..64a2df5 100644 --- a/_sass/layout/categories.scss +++ b/_sass/pages/_categories.scss @@ -1,8 +1,7 @@ -/* - Style for Tab Categories -*/ +@use '../abstracts/variables' as v; +@use '../abstracts/placeholders'; -%category-icon-color { +%-category-icon-color { color: gray; } @@ -16,7 +15,7 @@ } .card-header { - $radius: calc($radius-lg - 1px); + $radius: calc(v.$radius-lg - 1px); padding: 0.75rem; border-radius: $radius; @@ -29,7 +28,7 @@ } i { - @extend %category-icon-color; + @extend %-category-icon-color; font-size: 86%; /* fontawesome icons */ } diff --git a/_sass/layout/category-tag.scss b/_sass/pages/_category-tag.scss similarity index 79% rename from _sass/layout/category-tag.scss rename to _sass/pages/_category-tag.scss index fe7d99c..0a82712 100644 --- a/_sass/layout/category-tag.scss +++ b/_sass/pages/_category-tag.scss @@ -1,6 +1,6 @@ -/* - Style for page Category and Tag -*/ +@use '../abstracts/breakpoints' as bp; +@use '../abstracts/mixins' as mx; +@use '../abstracts/placeholders'; .dash { margin: 0 0.5rem 0.6rem 0.5rem; @@ -24,6 +24,10 @@ position: relative; top: 0.6rem; margin-right: 0.5rem; + + @include bp.lt(bp.get(sm)) { + margin: 0 0.5rem; + } } /* post's title */ @@ -31,6 +35,10 @@ @extend %no-bottom-border; font-size: 1.1rem; + + @include bp.lt(bp.get(sm)) { + @include mx.text-ellipsis; + } } } } @@ -53,18 +61,3 @@ margin-bottom: -1px; /* Avoid jumping */ } } - -@media all and (max-width: 576px) { - #page-category, - #page-tag { - ul > li { - &::before { - margin: 0 0.5rem; - } - - > a { - @include text-ellipsis; - } - } - } -} diff --git a/_sass/layout/home.scss b/_sass/pages/_home.scss similarity index 73% rename from _sass/layout/home.scss rename to _sass/pages/_home.scss index 7fff3ba..7a4bbf9 100644 --- a/_sass/layout/home.scss +++ b/_sass/pages/_home.scss @@ -1,10 +1,14 @@ -/* - Style for Homepage -*/ +@use '../abstracts/variables' as v; +@use '../abstracts/breakpoints' as bp; +@use '../abstracts/placeholders'; #post-list { margin-top: 2rem; + @include bp.lg { + margin-top: 2.5rem; + } + .card-wrapper { &:hover { text-decoration: none; @@ -20,7 +24,11 @@ background: none; %img-radius { - border-radius: $radius-lg $radius-lg 0 0; + border-radius: v.$radius-lg v.$radius-lg 0 0; + + @include bp.md { + border-radius: 0 v.$radius-lg v.$radius-lg 0; + } } .preview-img { @@ -35,6 +43,10 @@ height: 100%; padding: 1rem; + @include bp.md { + padding: 1.75rem 1.75rem 1.25rem; + } + .card-title { @extend %text-clip; @@ -46,14 +58,20 @@ color: var(--text-muted-color) !important; } - .card-text.content { - @extend %muted; + .card-text { + @include bp.md { + display: inherit !important; + } - p { - @extend %text-clip; + &.content { + @extend %muted; - line-height: 1.5; - margin: 0; + p { + @extend %text-clip; + + line-height: 1.5; + margin: 0; + } } } @@ -63,6 +81,10 @@ i { &:not(:first-child) { margin-left: 1.5rem; + + @include bp.md { + margin-left: 1.75rem; + } } } @@ -87,11 +109,28 @@ font-family: Lato, sans-serif; justify-content: space-evenly; + @include bp.lg { + font-size: 0.85rem; + justify-content: center; + } + a:hover { text-decoration: none; } .page-item { + @include bp.lt(bp.get(lg)) { + &:not(:first-child):not(:last-child) { + display: none; + } + } + + @include bp.lg { + &:not(:last-child) { + margin-right: 0.7rem; + } + } + .page-link { color: var(--btn-patinator-text-color); padding: 0 0.6rem; @@ -125,64 +164,10 @@ } } } /* .page-item */ -} /* .pagination */ -/* Tablet */ -@media all and (min-width: 768px) { - %img-radius { - border-radius: 0 $radius-lg $radius-lg 0; - } - - #post-list { - .card { - .card-body { - padding: 1.75rem 1.75rem 1.25rem 1.75rem; - - .card-text { - display: inherit !important; - } - - .post-meta { - i { - &:not(:first-child) { - margin-left: 1.75rem; - } - } - } - } - } - } -} - -/* Hide SideBar and TOC */ -@media all and (max-width: 830px) { - .pagination { - .page-item { - &:not(:first-child):not(:last-child) { - display: none; - } - } - } -} - -/* Sidebar is visible */ -@media all and (min-width: 831px) { - #post-list { - margin-top: 2.5rem; - } - - .pagination { - font-size: 0.85rem; - justify-content: center; - - .page-item { - &:not(:last-child) { - margin-right: 0.7rem; - } - } - - .page-index { + .page-index { + @include bp.lg { display: none; } - } /* .pagination */ + } } diff --git a/_sass/pages/_index.scss b/_sass/pages/_index.scss new file mode 100644 index 0000000..74e9ea6 --- /dev/null +++ b/_sass/pages/_index.scss @@ -0,0 +1,7 @@ +@forward 'search'; +@forward 'home'; +@forward 'post'; +@forward 'categories'; +@forward 'tags'; +@forward 'archives'; +@forward 'category-tag'; diff --git a/_sass/layout/post.scss b/_sass/pages/_post.scss similarity index 67% rename from _sass/layout/post.scss rename to _sass/pages/_post.scss index 891479e..d789050 100644 --- a/_sass/layout/post.scss +++ b/_sass/pages/_post.scss @@ -1,14 +1,15 @@ -/** - * Post-specific styles - */ +@use '../abstracts/variables' as v; +@use '../abstracts/breakpoints' as bp; +@use '../abstracts/mixins' as mx; +@use '../abstracts/placeholders'; -%btn-post-nav { +%-btn-post-nav { width: 50%; position: relative; border-color: var(--btn-border-color); } -@mixin dot($pl: 0.25rem, $pr: 0.25rem) { +@mixin -dot($pl: 0.25rem, $pr: 0.25rem) { content: '\2022'; padding-left: $pl; padding-right: $pr; @@ -24,7 +25,7 @@ header { .post-meta { span + span::before { - @include dot; + @include -dot; } em, @@ -113,9 +114,20 @@ header { } /* .share-wrapper */ } +.post-tail-bottom { + @include bp.lte(bp.get(sm)) { + flex-wrap: wrap-reverse !important; + + > div:first-child { + width: 100%; + margin-top: 1rem; + } + } +} + .share-mastodon { /* See: https://github.com/justinribeiro/share-to-mastodon#properties */ - --wc-stm-font-family: $font-family-base; + --wc-stm-font-family: v.$font-family-base; --wc-stm-dialog-background-color: var(--card-bg); --wc-stm-form-button-border: 1px solid var(--btn-border-color); --wc-stm-form-submit-background-color: var(--sidebar-btn-bg); @@ -139,8 +151,13 @@ header { } .post-navigation { + @include bp.lt(bp.get(lg)) { + @include mx.pl-pr(0); + @include mx.ml-mr(-0.5rem); + } + .btn { - @extend %btn-post-nav; + @extend %-btn-post-nav; &:not(:hover) { color: var(--link-color); @@ -153,7 +170,7 @@ header { } &.disabled { - @extend %btn-post-nav; + @extend %-btn-post-nav; pointer-events: auto; cursor: not-allowed; @@ -173,12 +190,12 @@ header { } &:first-child { - border-radius: $radius-lg 0 0 $radius-lg; + border-radius: v.$radius-lg 0 0 v.$radius-lg; left: 0.5px; } &:last-child { - border-radius: 0 $radius-lg $radius-lg 0; + border-radius: 0 v.$radius-lg v.$radius-lg 0; right: 0.5px; } } @@ -298,23 +315,27 @@ header { top: 0; z-index: 1; margin: 0 -1rem; - height: $topbar-height; + height: v.$topbar-height; background: var(--main-bg); border-bottom: 1px solid var(--main-border-color); transition: all 0.2s ease-in-out; @extend %btn-color; + @include bp.xl { + display: none !important; + } + .label { @extend %heading; - margin-left: 0.25rem; + margin-left: 0.375rem; padding: 0 0.75rem; color: inherit; } &.invisible { - top: -$topbar-height; + top: -#{v.$topbar-height}; transition: none; } } @@ -322,11 +343,15 @@ header { #toc-solo-trigger { color: var(--text-muted-color); border-color: var(--btn-border-color); - border-radius: $radius-lg; + border-radius: v.$radius-lg; + + @include bp.xl { + display: none !important; + } .label { font-size: 1rem; - font-family: $font-family-heading; + font-family: v.$font-family-heading; } &:hover { @@ -338,7 +363,7 @@ header { @mixin slide-in { from { opacity: 0.7; - transform: translateY(-$topbar-height); + transform: translateY(-#{v.$topbar-height}); } to { @@ -354,7 +379,7 @@ header { } 100% { - transform: translateY(-$topbar-height); + transform: translateY(-#{v.$topbar-height}); opacity: 0; } } @@ -375,129 +400,11 @@ header { @include slide-out; } -#toc-popup { - $slide-in: slide-in 0.3s ease-out; - $slide-out: slide-out 0.3s ease-out; - $curtain-height: 2rem; - $backdrop: blur(5px); - - border-color: var(--toc-popup-border-color); - border-width: 1px; - border-radius: $radius-lg; - color: var(--text-color); - background: var(--card-bg); - margin-top: $topbar-height; - min-width: 20rem; - font-size: 1.05rem; - - @media all and (min-width: 576px) { - max-width: 32rem; - } - - &[open] { - -webkit-animation: $slide-in; - animation: $slide-in; - } - - &[closing] { - -webkit-animation: $slide-out; - animation: $slide-out; - } - - @media all and (min-width: 850px) { - left: $sidebar-width; - } - - .header { - @extend %btn-color; - - position: -webkit-sticky; - position: sticky; - top: 0; - background-color: inherit; - border-bottom: 1px solid var(--main-border-color); - - .label { - font-family: $font-family-heading; - } - } - - button { - > i { - font-size: 1.25rem; - vertical-align: middle; - } - - &:focus-visible { - box-shadow: none; - } - } - - ul { - list-style-type: none; - padding-left: 0; - - li { - ul, - & + li { - margin-top: 0.25rem; - } - - a { - display: flex; - line-height: 1.5; - padding: 0.375rem 0; - padding-right: 1.125rem; - - &.toc-link::before { - display: none; - } - } - } - } - - @for $i from 2 through 4 { - .node-name--H#{$i} { - padding-left: 1.125rem * ($i - 1); - } - } - - .is-active-link { - color: var(--toc-highlight) !important; - font-weight: 600; - } - - &::-webkit-backdrop { - -webkit-backdrop-filter: $backdrop; - backdrop-filter: $backdrop; - } - - &::backdrop { - -webkit-backdrop-filter: $backdrop; - backdrop-filter: $backdrop; - } - - &::after { - display: flex; - content: ''; - position: relative; - background: linear-gradient(transparent, var(--card-bg) 70%); - height: $curtain-height; - } - - #toc-popup-content { - overflow: auto; - max-height: calc(100vh - 4 * $topbar-height); - font-family: $font-family-heading; - margin-bottom: -$curtain-height; - } -} - /* --- Related Posts --- */ #related-posts { > h3 { - @include label(1.1rem, 600); + @include mx.label(1.1rem, 600); } time { @@ -540,47 +447,23 @@ header { } .share-label { - @include label(inherit, 400, inherit); + @include mx.label(inherit, 400, inherit); &::after { content: ':'; } } -@media all and (max-width: 576px) { - .post-tail-bottom { - flex-wrap: wrap-reverse !important; - - > div:first-child { - width: 100%; - margin-top: 1rem; - } - } -} - -@media all and (max-width: 768px) { - .content > p > img { +.content > p > img { + @include bp.lte(bp.get(md)) { max-width: calc(100% + 1rem); } } -/* Hide SideBar and TOC */ -@media all and (max-width: 849px) { - .post-navigation { - @include pl-pr(0); - @include ml-mr(-0.5rem); - } -} - -@media all and (min-width: 1200px) { - h2, - h3, - h4 { +h2, +h3, +h4 { + @include bp.xl { scroll-margin-top: 2rem; } - - #toc-bar, - #toc-solo-trigger { - display: none !important; - } } diff --git a/_sass/pages/_search.scss b/_sass/pages/_search.scss new file mode 100644 index 0000000..dfb044e --- /dev/null +++ b/_sass/pages/_search.scss @@ -0,0 +1,184 @@ +@use '../abstracts/breakpoints' as bp; +@use '../abstracts/variables' as v; +@use '../abstracts/placeholders'; + +search { + display: flex; + width: 100%; + border-radius: 1rem; + border: 1px solid var(--search-border-color); + background: var(--main-bg); + padding: 0 0.5rem; + + i { + z-index: 2; + font-size: 0.9rem; + color: var(--search-icon-color); + } + + @include bp.lt(bp.get(lg)) { + display: none; + } + + @include bp.lg { + max-width: v.$search-max-width; + } + + @include bp.xl { + margin-right: 4rem; + } + + @include bp.xxxl { + margin-right: calc( + v.$main-content-max-width / 4 - v.$search-max-width - 0.75rem + ); + } +} + +#search-result-wrapper { + display: none; + height: 100%; + width: 100%; + overflow: auto; + + .content { + margin-top: 2rem; + } + + @include bp.lt(bp.get(lg)) { + width: 100%; + + .content { + letter-spacing: 0; + } + } + + @include bp.lg { + max-width: v.$main-content-max-width; + justify-content: start !important; + } +} + +#search-results { + padding-bottom: 3rem; + + @include bp.between(bp.get(lg), calc(#{bp.get(xl)} - 1px)) { + > div { + max-width: 700px; + } + } + + a { + font-size: 1.4rem; + line-height: 1.5rem; + + &:hover { + @extend %link-hover; + } + + @extend %link-color; + @extend %no-bottom-border; + @extend %heading; + } + + > article { + width: 100%; + + &:not(:last-child) { + margin-bottom: 1rem; + } + + @include bp.xl { + width: 45%; + + &:nth-child(odd) { + margin-right: 1.5rem; + } + + &:nth-child(even) { + margin-left: 1.5rem; + } + + &:last-child:nth-child(odd) { + position: relative; + right: 24.3%; + } + } + + h2 { + line-height: 2.5rem; + } + + /* icons */ + i { + color: #818182; + margin-right: 0.15rem; + font-size: 80%; + } + + > p { + @extend %text-ellipsis; + + white-space: break-spaces; + display: -webkit-box; + -webkit-line-clamp: 3; + -webkit-box-orient: vertical; + } + } +} + +/* 'Cancel' link */ +#search-cancel { + color: var(--link-color); + display: none; + white-space: nowrap; + + @extend %cursor-pointer; +} + +#search-input { + background: center; + border: 0; + border-radius: 0; + padding: 0.18rem 0.3rem; + color: var(--text-color); + height: auto; + + &:focus { + box-shadow: none; + } + + @include bp.xl { + transition: all 0.3s ease-in-out; + } +} + +#search-hints { + padding: 0 1rem; + + @include bp.lg { + display: none; + } + + h4 { + margin-bottom: 1.5rem; + } + + .post-tag { + display: inline-block; + line-height: 1rem; + font-size: 1rem; + background: var(--search-tag-bg); + border: none; + padding: 0.5rem; + margin: 0 1.25rem 1rem 0; + + &::before { + content: '#'; + color: var(--text-muted-color); + padding-right: 0.2rem; + } + + @extend %link-color; + } +} diff --git a/_sass/layout/tags.scss b/_sass/pages/_tags.scss similarity index 71% rename from _sass/layout/tags.scss rename to _sass/pages/_tags.scss index 4cf5d3b..d22f20d 100644 --- a/_sass/layout/tags.scss +++ b/_sass/pages/_tags.scss @@ -1,6 +1,4 @@ -/* - Styles for Tab Tags -*/ +@use '../abstracts/breakpoints' as bp; .tag { border-radius: 0.7em; @@ -17,3 +15,9 @@ font-family: Oswald, sans-serif; } } + +#tags { + @include bp.lt(bp.get(lg)) { + justify-content: center !important; + } +} diff --git a/_sass/colors/typography-dark.scss b/_sass/themes/_dark.scss similarity index 62% rename from _sass/colors/typography-dark.scss rename to _sass/themes/_dark.scss index 664c936..8c2f6ea 100644 --- a/_sass/colors/typography-dark.scss +++ b/_sass/themes/_dark.scss @@ -1,8 +1,6 @@ -/* - * The main dark mode styles - */ +@mixin styles { + color-scheme: dark; -@mixin dark-scheme { /* Framework color */ --main-bg: rgb(27, 27, 30); --mask-bg: rgb(68, 69, 70); @@ -100,7 +98,18 @@ --timeline-color: rgb(63, 65, 68); --timeline-year-dot-color: var(--timeline-color); - color-scheme: dark; + /* Code highlight colors */ + --language-border-color: #2d2d2d; + --highlight-bg-color: #151515; + --highlighter-rouge-color: #c9def1; + --highlight-lineno-color: #808080; + --inline-code-bg: rgba(255, 255, 255, 0.05); + --code-color: #b0b0b0; + --code-header-text-color: #6a6a6a; + --code-header-muted-color: #353535; + --code-header-icon-color: #565656; + --clipboard-checked-color: #2bcc2b; + --filepath-text-color: #cacaca; .light { display: none; @@ -144,4 +153,151 @@ #disqus_thread { color-scheme: none; } -} /* dark-scheme */ + + /* --- Syntax highlight theme from `rougify style base16.dark` --- */ + + .highlight .gp { + color: #87939d; + } + + .highlight table td { + padding: 5px; + } + + .highlight table pre { + margin: 0; + } + + .highlight, + .highlight .w { + color: #d0d0d0; + background-color: #151515; + } + + .highlight .err { + color: #151515; + background-color: #ac4142; + } + + .highlight .c, + .highlight .ch, + .highlight .cd, + .highlight .cm, + .highlight .cpf, + .highlight .c1, + .highlight .cs { + color: #848484; + } + + .highlight .cp { + color: #f4bf75; + } + + .highlight .nt { + color: #f4bf75; + } + + .highlight .o, + .highlight .ow { + color: #d0d0d0; + } + + .highlight .p, + .highlight .pi { + color: #d0d0d0; + } + + .highlight .gi { + color: #90a959; + } + + .highlight .gd { + color: #f08a8b; + background-color: #320000; + } + + .highlight .gh { + color: #6a9fb5; + background-color: #151515; + font-weight: bold; + } + + .highlight .k, + .highlight .kn, + .highlight .kp, + .highlight .kr, + .highlight .kv { + color: #aa759f; + } + + .highlight .kc { + color: #d28445; + } + + .highlight .kt { + color: #d28445; + } + + .highlight .kd { + color: #d28445; + } + + .highlight .s, + .highlight .sb, + .highlight .sc, + .highlight .dl, + .highlight .sd, + .highlight .s2, + .highlight .sh, + .highlight .sx, + .highlight .s1 { + color: #90a959; + } + + .highlight .sa { + color: #aa759f; + } + + .highlight .sr { + color: #75b5aa; + } + + .highlight .si { + color: #b76d45; + } + + .highlight .se { + color: #b76d45; + } + + .highlight .nn { + color: #f4bf75; + } + + .highlight .nc { + color: #f4bf75; + } + + .highlight .no { + color: #f4bf75; + } + + .highlight .na { + color: #6a9fb5; + } + + .highlight .m, + .highlight .mb, + .highlight .mf, + .highlight .mh, + .highlight .mi, + .highlight .il, + .highlight .mo, + .highlight .mx { + color: #90a959; + } + + .highlight .ss { + color: #90a959; + } +} diff --git a/_sass/themes/_light.scss b/_sass/themes/_light.scss new file mode 100644 index 0000000..14c3962 --- /dev/null +++ b/_sass/themes/_light.scss @@ -0,0 +1,313 @@ +@mixin styles { + /* Framework color */ + --main-bg: white; + --mask-bg: #c1c3c5; + --main-border-color: #f3f3f3; + + /* Common color */ + --text-color: #34343c; + --text-muted-color: #757575; + --text-muted-highlight-color: inherit; + --heading-color: #2a2a2a; + --label-color: #585858; + --blockquote-border-color: #eeeeee; + --blockquote-text-color: #757575; + --link-color: #0056b2; + --link-underline-color: #dee2e6; + --button-bg: #ffffff; + --btn-border-color: #e9ecef; + --btn-backtotop-color: #686868; + --btn-backtotop-border-color: #f1f1f1; + --checkbox-color: #c5c5c5; + --checkbox-checked-color: #07a8f7; + --img-bg: radial-gradient( + circle, + rgb(255, 255, 255) 0%, + rgb(239, 239, 239) 100% + ); + --shimmer-bg: linear-gradient( + 90deg, + rgba(250, 250, 250, 0) 0%, + rgba(232, 230, 230, 1) 50%, + rgba(250, 250, 250, 0) 100% + ); + + /* Sidebar */ + --site-title-color: rgb(113, 113, 113); + --site-subtitle-color: #717171; + --sidebar-bg: #f6f8fa; + --sidebar-border-color: #efefef; + --sidebar-muted-color: #545454; + --sidebar-active-color: #1d1d1d; + --sidebar-hover-bg: rgb(223, 233, 241, 0.64); + --sidebar-btn-bg: white; + --sidebar-btn-color: #8e8e8e; + --avatar-border-color: white; + + /* Topbar */ + --topbar-bg: rgb(255, 255, 255, 0.7); + --topbar-text-color: rgb(78, 78, 78); + --search-border-color: rgb(240, 240, 240); + --search-icon-color: #c2c6cc; + --input-focus-border-color: #b8b8b8; + + /* Home page */ + --post-list-text-color: dimgray; + --btn-patinator-text-color: #555555; + --btn-paginator-hover-color: var(--sidebar-bg); + + /* Posts */ + --toc-highlight: #0550ae; + --toc-popup-border-color: lightgray; + --btn-share-color: gray; + --btn-share-hover-color: #0d6efd; + --card-bg: white; + --card-hovor-bg: #e2e2e2; + --card-shadow: rgb(104, 104, 104, 0.05) 0 2px 6px 0, + rgba(211, 209, 209, 0.15) 0 0 0 1px; + --footnote-target-bg: lightcyan; + --tb-odd-bg: #fbfcfd; + --tb-border-color: #eaeaea; + --dash-color: silver; + --kbd-wrap-color: #bdbdbd; + --kbd-text-color: var(--text-color); + --kbd-bg-color: white; + --prompt-text-color: rgb(46, 46, 46, 0.77); + --prompt-tip-bg: rgb(123, 247, 144, 0.2); + --prompt-tip-icon-color: #03b303; + --prompt-info-bg: #e1f5fe; + --prompt-info-icon-color: #0070cb; + --prompt-warning-bg: rgb(255, 243, 205); + --prompt-warning-icon-color: #ef9c03; + --prompt-danger-bg: rgb(248, 215, 218, 0.56); + --prompt-danger-icon-color: #df3c30; + + /* Tags */ + --tag-border: #dee2e6; + --tag-shadow: var(--btn-border-color); + --tag-hover: rgb(222, 226, 230); + --search-tag-bg: #f8f9fa; + + /* Categories */ + --categories-border: rgba(0, 0, 0, 0.125); + --categories-hover-bg: var(--btn-border-color); + --categories-icon-hover-color: darkslategray; + + /* Archive */ + --timeline-color: rgba(0, 0, 0, 0.075); + --timeline-node-bg: #c2c6cc; + --timeline-year-dot-color: #ffffff; + + /* --- Custom code light mode colors --- */ + --language-border-color: #ececec; + --highlight-bg-color: #f6f8fa; + --highlighter-rouge-color: #3f596f; + --highlight-lineno-color: #9e9e9e; + --inline-code-bg: rgba(25, 25, 28, 0.05); + --code-color: #3a3a3a; + --code-header-text-color: #a3a3a3; + --code-header-muted-color: #e5e5e5; + --code-header-icon-color: #c9c8c8; + --clipboard-checked-color: #43c743; + + [class^='prompt-'] { + --link-underline-color: rgb(219, 216, 216); + } + + .dark { + display: none; + } + + /* --- Syntax highlight theme from `rougify style github` --- */ + + .highlight table td { + padding: 5px; + } + + .highlight table pre { + margin: 0; + } + + .highlight, + .highlight .w { + color: #24292f; + background-color: #f6f8fa; + } + + .highlight .k, + .highlight .kd, + .highlight .kn, + .highlight .kp, + .highlight .kr, + .highlight .kt, + .highlight .kv { + color: #cf222e; + } + + .highlight .gr { + color: #f6f8fa; + } + + .highlight .gd { + color: #82071e; + background-color: #ffebe9; + } + + .highlight .nb { + color: #953800; + } + + .highlight .nc { + color: #953800; + } + + .highlight .no { + color: #953800; + } + + .highlight .nn { + color: #953800; + } + + .highlight .sr { + color: #116329; + } + + .highlight .na { + color: #116329; + } + + .highlight .nt { + color: #116329; + } + + .highlight .gi { + color: #116329; + background-color: #dafbe1; + } + + .highlight .kc { + color: #0550ae; + } + + .highlight .l, + .highlight .ld, + .highlight .m, + .highlight .mb, + .highlight .mf, + .highlight .mh, + .highlight .mi, + .highlight .il, + .highlight .mo, + .highlight .mx { + color: #0550ae; + } + + .highlight .sb { + color: #0550ae; + } + + .highlight .bp { + color: #0550ae; + } + + .highlight .ne { + color: #0550ae; + } + + .highlight .nl { + color: #0550ae; + } + + .highlight .py { + color: #0550ae; + } + + .highlight .nv, + .highlight .vc, + .highlight .vg, + .highlight .vi, + .highlight .vm { + color: #0550ae; + } + + .highlight .o, + .highlight .ow { + color: #0550ae; + } + + .highlight .gh { + color: #0550ae; + font-weight: bold; + } + + .highlight .gu { + color: #0550ae; + font-weight: bold; + } + + .highlight .s, + .highlight .sa, + .highlight .sc, + .highlight .dl, + .highlight .sd, + .highlight .s2, + .highlight .se, + .highlight .sh, + .highlight .sx, + .highlight .s1, + .highlight .ss { + color: #0a3069; + } + + .highlight .nd { + color: #8250df; + } + + .highlight .nf, + .highlight .fm { + color: #8250df; + } + + .highlight .err { + color: #f6f8fa; + background-color: #82071e; + } + + .highlight .c, + .highlight .ch, + .highlight .cd, + .highlight .cm, + .highlight .cp, + .highlight .cpf, + .highlight .c1, + .highlight .cs { + color: #68717a; + } + + .highlight .gl { + color: #68717a; + } + + .highlight .gt { + color: #68717a; + } + + .highlight .ni { + color: #24292f; + } + + .highlight .si { + color: #24292f; + } + + .highlight .ge { + color: #24292f; + font-style: italic; + } + + .highlight .gs { + color: #24292f; + font-weight: bold; + } +} diff --git a/_sass/variables-hook.scss b/_sass/variables-hook.scss deleted file mode 100644 index f27e0eb..0000000 --- a/_sass/variables-hook.scss +++ /dev/null @@ -1,3 +0,0 @@ -/* - Appending custom SCSS variables will override the default ones in `_sass/addon/variables.scsss` -*/ diff --git a/assets/css/jekyll-theme-chirpy.scss b/assets/css/jekyll-theme-chirpy.scss index d20545b..7ff89bf 100644 --- a/assets/css/jekyll-theme-chirpy.scss +++ b/assets/css/jekyll-theme-chirpy.scss @@ -1,7 +1,7 @@ --- --- -@import 'main +@use 'main {%- if jekyll.environment == 'production' -%} .bundle {%- endif -%} diff --git a/package.json b/package.json index d6beea0..aa83ee7 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "homepage": "https://github.com/cotes2020/jekyll-theme-chirpy/", "scripts": { "build": "concurrently npm:build:*", - "build:css": "purgecss -c purgecss.config.js", + "build:css": "node purgecss.js", "build:js": "rollup -c --bundleConfigAsCjs --environment BUILD:production", "watch:js": "rollup -c --bundleConfigAsCjs -w", "lint:scss": "stylelint _sass/**/*.scss", diff --git a/purgecss.config.js b/purgecss.config.js deleted file mode 100644 index de370de..0000000 --- a/purgecss.config.js +++ /dev/null @@ -1,23 +0,0 @@ -const fs = require('fs'); -const DIST_PATH = '_sass/dist'; - -fs.rm(DIST_PATH, { recursive: true, force: true }, (err) => { - if (err) { - throw err; - } - - fs.mkdirSync(DIST_PATH); -}); - -module.exports = { - content: ['_includes/**/*.html', '_layouts/**/*.html', '_javascript/**/*.js'], - css: ['node_modules/bootstrap/dist/css/bootstrap.min.css'], - keyframes: true, - variables: true, - output: `${DIST_PATH}/bootstrap.css`, - // The `safelist` should be changed appropriately for future development - safelist: { - standard: [/^collaps/, /^w-/, 'shadow', 'border', 'kbd'], - greedy: [/^col-/, /tooltip/] - } -}; diff --git a/purgecss.js b/purgecss.js new file mode 100644 index 0000000..ad42db2 --- /dev/null +++ b/purgecss.js @@ -0,0 +1,30 @@ +const fs = require('fs').promises; +const { PurgeCSS } = require('purgecss'); +const DIST_PATH = '_sass/vendors'; +const output = `${DIST_PATH}/_bootstrap.scss`; + +const config = { + content: ['_includes/**/*.html', '_layouts/**/*.html', '_javascript/**/*.js'], + css: ['node_modules/bootstrap/dist/css/bootstrap.min.css'], + keyframes: true, + variables: true, + // The `safelist` should be changed appropriately for future development + safelist: { + standard: [/^collaps/, /^w-/, 'shadow', 'border', 'kbd'], + greedy: [/^col-/, /tooltip/] + } +}; + +function main() { + fs.rm(DIST_PATH, { recursive: true, force: true }) + .then(() => fs.mkdir(DIST_PATH)) + .then(() => new PurgeCSS().purge(config)) + .then((result) => { + return fs.writeFile(output, result[0].css); + }) + .catch((err) => { + console.error('Error during PurgeCSS process:', err); + }); +} + +main(); diff --git a/tools/init.sh b/tools/init.sh index 2ad72ab..d710182 100755 --- a/tools/init.sh +++ b/tools/init.sh @@ -92,7 +92,8 @@ init_files() { npm i && npm run build # track the CSS/JS output - _sedi "/.*\/dist$/d" .gitignore + _sedi "/^_sass\/vendors/d" .gitignore + _sedi "/^assets\/js\/dist/d" .gitignore } commit() { diff --git a/tools/release.sh b/tools/release.sh index 522c892..36ca88a 100755 --- a/tools/release.sh +++ b/tools/release.sh @@ -15,7 +15,7 @@ NODE_SPEC="package.json" CHANGELOG="docs/CHANGELOG.md" CONFIG="_config.yml" -CSS_DIST="_sass/dist" +CSS_DIST="_sass/vendors" JS_DIST="assets/js/dist" FILES=( From 5756b8fc2636071de9bf7a137fec1dec811a9043 Mon Sep 17 00:00:00 2001 From: Cotes Chung <11371340+cotes2020@users.noreply.github.com> Date: Mon, 25 Nov 2024 00:18:06 +0800 Subject: [PATCH 19/21] build(deps-dev): upgrade dependencies Close #2058 --- package.json | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/package.json b/package.json index aa83ee7..36f77e5 100644 --- a/package.json +++ b/package.json @@ -28,25 +28,25 @@ "bootstrap": "^5.3.3" }, "devDependencies": { - "@babel/core": "^7.25.2", - "@babel/plugin-transform-class-properties": "^7.25.4", - "@babel/plugin-transform-private-methods": "^7.25.7", - "@babel/preset-env": "^7.25.4", - "@commitlint/cli": "^19.5.0", - "@commitlint/config-conventional": "^19.5.0", + "@babel/core": "^7.26.0", + "@babel/plugin-transform-class-properties": "^7.25.9", + "@babel/plugin-transform-private-methods": "^7.25.9", + "@babel/preset-env": "^7.26.0", + "@commitlint/cli": "^19.6.0", + "@commitlint/config-conventional": "^19.6.0", "@rollup/plugin-babel": "^6.0.4", - "@rollup/plugin-node-resolve": "^15.2.3", + "@rollup/plugin-node-resolve": "^15.3.0", "@rollup/plugin-terser": "^0.4.4", "@semantic-release/changelog": "^6.0.3", "@semantic-release/exec": "^6.0.3", "@semantic-release/git": "^10.0.1", - "concurrently": "^9.0.1", + "concurrently": "^9.1.0", "conventional-changelog-conventionalcommits": "^8.0.0", - "husky": "^9.1.6", - "purgecss": "^6.0.0", - "rollup": "^4.21.3", - "semantic-release": "^24.1.1", - "stylelint": "^16.9.0", + "husky": "^9.1.7", + "purgecss": "^7.0.2", + "rollup": "^4.27.4", + "semantic-release": "^24.2.0", + "stylelint": "^16.10.0", "stylelint-config-standard-scss": "^13.1.0" }, "prettier": { From 11647697bbacb84df6171a0ac7947a0e4fdef5da Mon Sep 17 00:00:00 2001 From: Cotes Chung <11371340+cotes2020@users.noreply.github.com> Date: Mon, 25 Nov 2024 03:55:11 +0800 Subject: [PATCH 20/21] build(deps): update dependencies version --- _data/origin/cors.yml | 8 ++++---- assets/lib | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/_data/origin/cors.yml b/_data/origin/cors.yml index afdb3d9..e9bb4eb 100644 --- a/_data/origin/cors.yml +++ b/_data/origin/cors.yml @@ -20,17 +20,17 @@ webfonts: https://fonts.googleapis.com/css2?family=Lato:wght@300;400&family=Sour # Libraries toc: - css: https://cdn.jsdelivr.net/npm/tocbot@4.29.0/dist/tocbot.min.css - js: https://cdn.jsdelivr.net/npm/tocbot@4.29.0/dist/tocbot.min.js + css: https://cdn.jsdelivr.net/npm/tocbot@4.32.2/dist/tocbot.min.css + js: https://cdn.jsdelivr.net/npm/tocbot@4.32.2/dist/tocbot.min.js fontawesome: - css: https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.6.0/css/all.min.css + css: https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.7.1/css/all.min.css search: js: https://cdn.jsdelivr.net/npm/simple-jekyll-search@1.10.0/dest/simple-jekyll-search.min.js mermaid: - js: https://cdn.jsdelivr.net/npm/mermaid@11.0.2/dist/mermaid.min.js + js: https://cdn.jsdelivr.net/npm/mermaid@11.4.0/dist/mermaid.min.js dayjs: js: diff --git a/assets/lib b/assets/lib index a231bc7..b9e18a1 160000 --- a/assets/lib +++ b/assets/lib @@ -1 +1 @@ -Subproject commit a231bc7e2c67198e604950cb2be9147a0b2020c0 +Subproject commit b9e18a1510e3be5de250ed34205da318b76474e0 From 5265b039741555943f9a6f0451287aefb6810f28 Mon Sep 17 00:00:00 2001 From: Cotes Chung <11371340+cotes2020@users.noreply.github.com> Date: Thu, 28 Nov 2024 02:58:25 +0800 Subject: [PATCH 21/21] feat: support vertical scrolling for toc in desktop mode (#2064) --- _includes/toc.html | 5 +-- _layouts/default.html | 2 +- _sass/abstracts/_placeholders.scss | 4 +++ _sass/layout/_panel.scss | 14 ++++++--- _sass/pages/_post.scss | 49 +++++++++++++++++++++++++++--- 5 files changed, 61 insertions(+), 13 deletions(-) diff --git a/_includes/toc.html b/_includes/toc.html index 49c8f90..883bf13 100644 --- a/_includes/toc.html +++ b/_includes/toc.html @@ -1,8 +1,9 @@ {% include toc-status.html %} {% if enable_toc %} -
-

{{- site.data.locales[include.lang].panel.toc -}}

+
+
+

{{- site.data.locales[include.lang].panel.toc -}}

{% endif %} diff --git a/_layouts/default.html b/_layouts/default.html index c83c561..a55bfef 100644 --- a/_layouts/default.html +++ b/_layouts/default.html @@ -33,7 +33,7 @@ layout: compress -