Compare commits

..
Author SHA1 Message Date
JimmyandGitHub 25bf63778c feat: use thumbnail in section and links image (#1291)
* feat: use thumbnail for section image

* feat: use thumbnail in links image

* fix typo
2026-03-05 13:57:37 +01:00
JimmyandGitHub a95d0e7c85 refactor: use helper/image in links.html (#1290)
* refactor: use `helper/image` in `links.html`

* fix: check for $image existence before accessing
2026-03-05 13:51:34 +01:00
JimmyandGitHub 12f05571cf refactor: make article-list/compact better for term pages (#1289)
* refactor: rename article-time class to article-footer for consistency

* feat: show the number of subpages in `article-compact` when the page is a term
2026-03-05 13:43:55 +01:00
230a28fa8d feat(widgets): link widget titles to their respective pages (#1277)
- archives.html: Link the "Archives" title to the archives page,
  consistent with how individual year links already work
- taxonomy.html: Change showLink default from false to true so
  tag-cloud and categories widget titles link to their taxonomy
  listing pages by default

Widget titles are the primary affordance users interact with, so
linking them to the full listing page improves navigation. The
showLink param can still be set to false to disable this.

Co-authored-by: delize <[email protected]>
2026-03-05 13:18:32 +01:00
JimmyandGitHub a9a14ce815 feat: hide search results container if no keyword is given (#1288)
feat: hide search results container if no keyword is given and add typing
2026-03-05 12:52:06 +01:00
JimmyandGitHub 0ad02c5c0f refactor: add standardized spacing variables and more style cleanup (#1287)
* refactor: add standardized spacing variables and more style cleanup

* refactor: rename `spacing-xxl` to `spacing-2xl` and introduce `spacing-3xl` for consistent spacing variables.

* refactor: Migrate related content styling to use the `subsection-list` component with updated layout adjustments.

* style: adjust padding values for article list tiles.

* refactor: Introduce shadow variables and dynamic spacing to prevent shadow cutoff in list layouts.

* refactor: relocate dark scheme Mermaid variables within the root scope.
2026-03-05 12:29:48 +01:00
JimmyandGitHub 88468ad84e refactor: cleanup stylesheet (#1286)
* refactor: cleanup stylesheet

* Update assets/scss/partials/article.scss
2026-03-05 10:40:13 +01:00
JimmyandGitHub 3dae60ac7a fix: use IsImageResourceWithMeta to check whether image has width / height attributes (#1285) 2026-03-05 09:23:47 +01:00
25 changed files with 278 additions and 218 deletions
+1 -1
View File
@@ -19,7 +19,7 @@ a {
.section-title { .section-title {
text-transform: uppercase; text-transform: uppercase;
margin-top: 0; margin-top: 0;
margin-bottom: 10px; margin-bottom: var(--spacing-sm);
display: block; display: block;
font-size: 1.6rem; font-size: 1.6rem;
font-weight: bold; font-weight: bold;
+4 -8
View File
@@ -60,14 +60,10 @@
display: flex; display: flex;
flex-direction: row; flex-direction: row;
&.column {
flex-direction: column;
}
&.on-phone--column { &.on-phone--column {
flex-direction: column; flex-direction: column;
@include respond(md) { @include respond(md) {
flex-direction: unset; flex-direction: row;
} }
} }
@@ -93,11 +89,11 @@ main.main {
.main-container { .main-container {
min-height: 100vh; min-height: 100vh;
align-items: flex-start; align-items: flex-start;
padding: 0 15px; padding: 0 var(--container-padding);
gap: var(--section-separation); gap: var(--section-separation);
padding-top: var(--main-top-padding); padding-top: var(--main-top-padding);
@include respond(md) { @include respond(md) {
padding: 0 20px; padding-top: 0;
} }
} }
+5
View File
@@ -0,0 +1,5 @@
@mixin card-style {
background-color: var(--card-background);
box-shadow: var(--shadow-l1);
border-radius: var(--card-border-radius);
}
+29 -50
View File
@@ -7,9 +7,7 @@
article { article {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
background-color: var(--card-background); @include card-style;
box-shadow: var(--shadow-l1);
border-radius: var(--card-border-radius);
overflow: hidden; overflow: hidden;
transition: box-shadow 0.3s ease; transition: box-shadow 0.3s ease;
@@ -21,16 +19,8 @@
.article-image { .article-image {
img { img {
width: 100%; width: 100%;
height: 150px; height: var(--article-image-height);
object-fit: cover; object-fit: cover;
@include respond(md) {
height: 200px;
}
@include respond(xl) {
height: 250px;
}
} }
} }
} }
@@ -41,7 +31,7 @@
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
padding: var(--card-padding); padding: var(--card-padding);
gap: 15px; gap: var(--spacing-md);
} }
.article-title { .article-title {
@@ -59,7 +49,7 @@
color: var(--card-text-color-main); color: var(--card-text-color-main);
&:hover { &:hover {
color: var(--card-text-color-main); opacity: 0.8;
} }
} }
} }
@@ -81,12 +71,12 @@
gap: 8px; gap: 8px;
} }
.article-time, .article-footer,
.article-translations, .article-translations,
.article-header-tags { .article-header-tags {
display: flex; display: flex;
color: var(--card-text-color-tertiary); color: var(--card-text-color-tertiary);
gap: 15px; gap: var(--spacing-md);
svg { svg {
vertical-align: middle; vertical-align: middle;
@@ -105,7 +95,7 @@
& > div { & > div {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
gap: 15px; gap: var(--spacing-md);
} }
} }
@@ -123,7 +113,7 @@
.article-category, .article-category,
.article-tags { .article-tags {
display: flex; display: flex;
gap: 10px; gap: var(--spacing-sm);
flex-wrap: wrap; flex-wrap: wrap;
a { a {
@@ -144,21 +134,15 @@
/* Compact style article list */ /* Compact style article list */
.article-list--compact { .article-list--compact {
border-radius: var(--card-border-radius); @include card-style;
box-shadow: var(--shadow-l1); --image-size: var(--article-compact-image-size);
background-color: var(--card-background);
--image-size: 50px;
@include respond(md) {
--image-size: 60px;
}
article { article {
& > a { & > a {
display: flex; display: flex;
align-items: center; align-items: center;
padding: var(--small-card-padding); padding: var(--small-card-padding);
gap: 15px; gap: var(--spacing-md);
} }
&:not(:last-of-type) { &:not(:last-of-type) {
@@ -169,7 +153,7 @@
flex-grow: 1; flex-grow: 1;
padding: 0; padding: 0;
min-height: var(--image-size); min-height: var(--image-size);
gap: 10px; gap: var(--spacing-sm);
} }
.article-title { .article-title {
@@ -189,7 +173,7 @@
} }
} }
.article-time { .article-footer {
font-size: 1.4rem; font-size: 1.4rem;
} }
@@ -204,14 +188,12 @@
/* Tile style article list */ /* Tile style article list */
.article-list--tile { .article-list--tile {
article { article {
border-radius: var(--card-border-radius);
overflow: hidden;
position: relative; position: relative;
width: 250px; width: var(--article-tile-width);
height: 150px; height: var(--article-tile-height);
box-shadow: var(--shadow-l1); @include card-style;
overflow: hidden;
transition: box-shadow 0.3s ease; transition: box-shadow 0.3s ease;
background-color: var(--card-background);
&:hover { &:hover {
box-shadow: var(--shadow-l2); box-shadow: var(--shadow-l2);
@@ -219,11 +201,11 @@
&.has-image { &.has-image {
.article-details { .article-details {
background-color: rgba(#000, 0.25); background-color: var(--article-tile-overlay-bg);
} }
.article-title { .article-title {
color: #fff; color: var(--article-tile-text-color);
} }
} }
@@ -328,19 +310,19 @@
button { button {
padding: 0.5rem 1rem; padding: 0.5rem 1rem;
background: rgba(255, 255, 255, 0.95); background: var(--mermaid-toolbar-btn-bg);
border: 2px solid #333; border: 2px solid var(--mermaid-toolbar-btn-text);
border-radius: 6px; border-radius: 6px;
cursor: pointer; cursor: pointer;
font-size: 1rem; font-size: 1rem;
font-weight: 600; font-weight: 600;
color: #333; color: var(--mermaid-toolbar-btn-text);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
transition: all 0.2s; transition: all 0.2s;
&:hover { &:hover {
background: #333; background: var(--mermaid-toolbar-btn-text);
color: #fff; color: var(--card-background);
transform: scale(1.05); transform: scale(1.05);
} }
} }
@@ -354,7 +336,7 @@
left: 0; left: 0;
width: 100vw; width: 100vw;
height: 100vh; height: 100vh;
background: rgba(0, 0, 0, 0.95); background: var(--mermaid-modal-bg);
z-index: 9999; z-index: 9999;
&.active { &.active {
@@ -379,14 +361,15 @@
.mermaid-modal-controls button, .mermaid-modal-controls button,
.mermaid-modal-close { .mermaid-modal-close {
padding: 0.5rem 1rem; padding: 0.5rem 1rem;
background: #fff; background: var(--mermaid-modal-btn-bg);
border: none; border: none;
border-radius: 4px; border-radius: 4px;
cursor: pointer; cursor: pointer;
font-size: 0.9rem; font-size: 0.9rem;
color: var(--card-text-color-main);
&:hover { &:hover {
background: #ddd; background: var(--mermaid-modal-btn-hover);
} }
} }
@@ -404,11 +387,7 @@
bottom: 1rem; bottom: 1rem;
border-radius: 8px; border-radius: 8px;
overflow: hidden; overflow: hidden;
background: #fff; background: var(--mermaid-modal-content-bg);
[data-scheme="dark"] & {
background: #1e1e1e;
}
} }
.mermaid-panzoom-container { .mermaid-panzoom-container {
+12 -14
View File
@@ -16,17 +16,17 @@
margin: 0 auto; margin: 0 auto;
background: var(--card-background); background: var(--card-background);
border-radius: var(--card-border-radius); border-radius: var(--card-border-radius);
box-shadow: var(--shadow-l3); box-shadow: var(--shadow-l2);
padding: var(--card-padding); padding: var(--card-padding);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 15px; gap: var(--spacing-md);
@include respond(md) { @include respond(md) {
flex-direction: row; flex-direction: row;
flex-wrap: wrap; flex-wrap: wrap;
align-items: center; align-items: center;
gap: 20px; gap: var(--spacing-lg);
} }
} }
@@ -38,7 +38,7 @@
display: block; display: block;
color: var(--card-text-color-main); color: var(--card-text-color-main);
font-size: 1.6rem; font-size: 1.6rem;
margin-bottom: 5px; margin-bottom: var(--spacing-xs);
} }
p { p {
@@ -51,7 +51,7 @@
.cookie-banner__actions { .cookie-banner__actions {
display: flex; display: flex;
gap: 10px; gap: var(--spacing-sm);
flex-shrink: 0; flex-shrink: 0;
} }
@@ -70,7 +70,6 @@
} }
@include respond(md) { @include respond(md) {
width: auto;
margin-left: auto; margin-left: auto;
align-self: center; align-self: center;
} }
@@ -117,19 +116,19 @@
h3 { h3 {
color: var(--card-text-color-main); color: var(--card-text-color-main);
font-size: 1.6rem; font-size: 1.6rem;
margin: 0 0 15px 0; margin: 0 0 var(--spacing-md) 0;
} }
&__actions { &__actions {
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;
gap: 10px; gap: var(--spacing-sm);
margin-top: 20px; margin-top: var(--spacing-lg);
} }
} }
.cookie-category { .cookie-category {
padding: 15px 0; padding: var(--spacing-md) 0;
border-bottom: 1px solid var(--card-separator-color); border-bottom: 1px solid var(--card-separator-color);
&:last-of-type { &:last-of-type {
@@ -139,7 +138,7 @@
label { label {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 10px; gap: var(--spacing-sm);
cursor: pointer; cursor: pointer;
input[type="checkbox"] { input[type="checkbox"] {
@@ -186,14 +185,13 @@
// Comments placeholder when consent not given // Comments placeholder when consent not given
.consent-placeholder { .consent-placeholder {
background: var(--card-background); @include card-style;
border-radius: var(--card-border-radius);
padding: var(--card-padding); padding: var(--card-padding);
text-align: center; text-align: center;
color: var(--card-text-color-secondary); color: var(--card-text-color-secondary);
font-size: 1.4rem; font-size: 1.4rem;
p { p {
margin: 0 0 15px 0; margin: 0 0 var(--spacing-md) 0;
} }
} }
+3 -3
View File
@@ -1,5 +1,5 @@
footer.site-footer { footer.site-footer {
padding: 20px 0 var(--section-separation) 0; padding: var(--spacing-lg) 0 var(--section-separation) 0;
font-size: 1.4rem; font-size: 1.4rem;
line-height: 1.75; line-height: 1.75;
@@ -9,13 +9,13 @@ footer.site-footer {
height: 3px; height: 3px;
width: 50px; width: 50px;
background: var(--body-text-color); background: var(--body-text-color);
margin-bottom: 20px; margin-bottom: var(--spacing-lg);
} }
.copyright { .copyright {
color: var(--accent-color); color: var(--accent-color);
font-weight: bold; font-weight: bold;
margin-bottom: 5px; margin-bottom: var(--spacing-xs);
} }
.powerby { .powerby {
+14 -38
View File
@@ -111,14 +111,14 @@
} }
li { li {
margin: 15px 0 15px 20px; margin: var(--spacing-md) 0 var(--spacing-md) var(--spacing-lg);
padding: 5px; padding: var(--spacing-xs);
&>ol, &>ol,
&>ul { &>ul {
margin-top: 10px; margin-top: var(--spacing-sm);
padding-left: 10px; padding-left: var(--spacing-sm);
margin-bottom: -5px; margin-bottom: calc(var(--spacing-xs) * -1);
&>li:last-child { &>li:last-child {
margin-bottom: 0; margin-bottom: 0;
@@ -182,7 +182,7 @@
.article-toc { .article-toc {
padding: 0 var(--card-padding); padding: 0 var(--card-padding);
margin-top: 20px; margin-top: var(--spacing-lg);
@include respond(lg) { @include respond(lg) {
display: none; display: none;
@@ -203,7 +203,7 @@
summary { summary {
list-style: none; list-style: none;
padding: 15px 20px; padding: var(--spacing-md) var(--spacing-lg);
cursor: pointer; cursor: pointer;
&::-webkit-details-marker { &::-webkit-details-marker {
@@ -213,7 +213,7 @@
.article-toc-title { .article-toc-title {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 10px; gap: var(--spacing-sm);
text-transform: uppercase; text-transform: uppercase;
font-size: 1.4rem; font-size: 1.4rem;
font-weight: bold; font-weight: bold;
@@ -230,33 +230,6 @@
} }
} }
.related-content {
overflow-x: auto;
padding-bottom: 15px;
&>.flex {
float: left;
}
article {
margin-right: 15px;
flex-shrink: 0;
overflow: hidden;
.article-title {
font-size: 1.8rem;
margin: 0;
}
&.has-image {
.article-details {
padding: 20px;
background: linear-gradient(0deg, rgba(0, 0, 0, 0.25) 0%, rgba(0, 0, 0, 0.75) 100%);
}
}
}
}
.article-content { .article-content {
font-family: var(--article-font-family); font-family: var(--article-font-family);
font-size: var(--article-font-size); font-size: var(--article-font-size);
@@ -313,7 +286,7 @@
position: relative; position: relative;
margin: 1.5em 0; margin: 1.5em 0;
border-inline-start: var(--blockquote-border-size) solid var(--card-separator-color); border-inline-start: var(--blockquote-border-size) solid var(--card-separator-color);
padding: 15px calc(var(--card-padding) - var(--blockquote-border-size)); padding: var(--spacing-md) calc(var(--card-padding) - var(--blockquote-border-size));
background-color: var(--blockquote-background-color); background-color: var(--blockquote-background-color);
.cite { .cite {
@@ -383,7 +356,7 @@
flex-direction: row; flex-direction: row;
justify-content: center; justify-content: center;
margin: 1.5em 0; margin: 1.5em 0;
gap: 10px; gap: var(--spacing-sm);
figure { figure {
margin: 0; margin: 0;
@@ -418,6 +391,10 @@
padding: var(--card-padding); padding: var(--card-padding);
position: relative; position: relative;
pre {
background-color: transparent;
}
&:hover { &:hover {
.copyCodeButton { .copyCodeButton {
opacity: 1; opacity: 1;
@@ -430,7 +407,6 @@
} }
pre { pre {
margin: initial;
padding: 0; padding: 0;
margin: 0; margin: 0;
width: auto; width: auto;
+15 -9
View File
@@ -1,11 +1,9 @@
.section-card { .section-card {
border-radius: var(--card-border-radius); @include card-style;
background-color: var(--card-background);
padding: var(--small-card-padding); padding: var(--small-card-padding);
box-shadow: var(--shadow-l1);
display: flex; display: flex;
align-items: center; align-items: center;
gap: 20px; gap: var(--spacing-lg);
--separation: 15px; --separation: 15px;
@@ -47,16 +45,24 @@
} }
.subsection-list { .subsection-list {
overflow-x: auto; --shadow-overlap-x: calc(var(--shadow-l2-blur) + 4px);
margin-left: -24px; --shadow-overlap-y: calc(var(--shadow-l2-blur) + var(--shadow-l2-y) + 4px);
overflow-x: auto;
/// These values are computed from the shadow of the article-list--tile (which uses shadow-l1 and shadow-l2)
/// so that the shadow is not cut off
margin-left: calc(var(--shadow-overlap-x) * -1);
margin-right: calc(var(--shadow-overlap-x) * -1);
margin-bottom: calc(var(--shadow-overlap-y) * -1);
.article-list--tile { .article-list--tile {
display: flex; display: flex;
padding: 8px 0 34px 24px; padding: var(--spacing-xs) var(--shadow-overlap-x) var(--shadow-overlap-y) var(--shadow-overlap-x);
width: max-content; width: max-content;
gap: var(--spacing-lg);
article { article {
margin-right: 20px;
flex-shrink: 0; flex-shrink: 0;
.article-title { .article-title {
@@ -65,7 +71,7 @@
} }
.article-details { .article-details {
padding: 20px; padding: var(--spacing-lg);
} }
} }
} }
+12 -7
View File
@@ -7,12 +7,12 @@
label { label {
font-size: 1.3rem; font-size: 1.3rem;
top: 10px; top: var(--spacing-sm);
} }
input { input {
font-size: 1.5rem; font-size: 1.5rem;
padding: 30px 20px 15px 20px; padding: var(--spacing-2xl) var(--spacing-lg) var(--spacing-md) var(--spacing-lg);
} }
} }
@@ -23,21 +23,20 @@
label { label {
position: absolute; position: absolute;
top: 15px; top: var(--spacing-md);
inset-inline-start: 20px; inset-inline-start: var(--spacing-lg);
font-size: 1.4rem; font-size: 1.4rem;
color: var(--card-text-color-tertiary); color: var(--card-text-color-tertiary);
} }
input { input {
padding: 40px 20px 20px; padding: 40px 20px 20px;
border-radius: var(--card-border-radius); @include card-style;
background-color: var(--card-background);
box-shadow: var(--shadow-l1);
color: var(--card-text-color-main); color: var(--card-text-color-main);
width: 100%; width: 100%;
border: 0; border: 0;
-webkit-appearance: none; -webkit-appearance: none;
appearance: none;
transition: box-shadow 0.3s ease; transition: box-shadow 0.3s ease;
@@ -79,4 +78,10 @@
} }
} }
}
.search-result {
&.hidden {
display: none;
}
} }
+5 -15
View File
@@ -7,7 +7,7 @@
*/ */
.hamburger { .hamburger {
padding-top: 10px; padding-top: var(--spacing-sm);
display: inline-block; display: inline-block;
cursor: pointer; cursor: pointer;
transition-property: opacity, filter; transition-property: opacity, filter;
@@ -26,16 +26,6 @@
opacity: 0.7; opacity: 0.7;
} }
.hamburger.is-active:hover {
opacity: 0.7;
}
.hamburger.is-active .hamburger-inner,
.hamburger.is-active .hamburger-inner::before,
.hamburger.is-active .hamburger-inner::after {
background-color: #000;
}
.hamburger-box { .hamburger-box {
width: 30px; width: 30px;
height: 24px; height: 24px;
@@ -149,7 +139,7 @@
display: none; display: none;
margin: 0 calc(var(--container-padding) * -1); margin: 0 calc(var(--container-padding) * -1);
padding: 30px 30px; padding: var(--spacing-2xl);
@include respond(xl) { @include respond(xl) {
padding: 15px 0; padding: 15px 0;
@@ -158,10 +148,10 @@
&, &,
.menu-bottom-section ol { .menu-bottom-section ol {
flex-direction: column; flex-direction: column;
gap: 30px; gap: var(--spacing-2xl);
@include respond(xl) { @include respond(xl) {
gap: 25px; gap: var(--spacing-xl);
} }
} }
@@ -230,7 +220,7 @@
margin: 0; margin: 0;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
gap: 10px; gap: var(--spacing-sm);
svg { svg {
width: 24px; width: 24px;
+1 -3
View File
@@ -1,8 +1,6 @@
.pagination { .pagination {
display: flex; display: flex;
background-color: var(--card-background); @include card-style;
box-shadow: var(--shadow-l1);
border-radius: var(--card-border-radius);
overflow: hidden; overflow: hidden;
.page-link { .page-link {
+4 -4
View File
@@ -35,7 +35,7 @@
position: relative; position: relative;
--sidebar-avatar-size: 100px; --sidebar-avatar-size: 100px;
--sidebar-element-separation: 20px; --sidebar-element-separation: var(--spacing-lg);
--emoji-size: 40px; --emoji-size: 40px;
--emoji-font-size: 20px; --emoji-font-size: 20px;
@@ -48,7 +48,7 @@
@include respond(2xl) { @include respond(2xl) {
--sidebar-avatar-size: 120px; --sidebar-avatar-size: 120px;
--sidebar-element-separation: 25px; --sidebar-element-separation: var(--spacing-xl);
--emoji-size: 40px; --emoji-size: 40px;
} }
@@ -67,7 +67,7 @@
} }
.site-meta { .site-meta {
gap: 5px; gap: var(--spacing-xs);
} }
.site-name { .site-name {
@@ -144,7 +144,7 @@
.site-meta { .site-meta {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 10px; gap: var(--spacing-sm);
justify-content: center; justify-content: center;
} }
+5 -8
View File
@@ -4,8 +4,8 @@
.widget-icon { .widget-icon {
svg { svg {
width: 32px; width: var(--widget-icon-size);
height: 32px; height: var(--widget-icon-size);
stroke-width: 1.6; stroke-width: 1.6;
color: var(--body-text-color); color: var(--body-text-color);
} }
@@ -17,11 +17,10 @@
.tagCloud-tags { .tagCloud-tags {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
gap: 10px; gap: var(--spacing-sm);
a { a {
background: var(--card-background); @include card-style;
box-shadow: var(--shadow-l1);
border-radius: var(--tag-border-radius); border-radius: var(--tag-border-radius);
padding: 8px 20px; padding: 8px 20px;
color: var(--card-text-color-main); color: var(--card-text-color-main);
@@ -38,9 +37,7 @@
/* Archives widget */ /* Archives widget */
.widget.archives { .widget.archives {
.widget-archive--list { .widget-archive--list {
border-radius: var(--card-border-radius); @include card-style;
box-shadow: var(--shadow-l1);
background-color: var(--card-background);
} }
.archives-year { .archives-year {
+1
View File
@@ -8,6 +8,7 @@
@import "breakpoints.scss"; @import "breakpoints.scss";
@import "variables.scss"; @import "variables.scss";
@import "mixins.scss";
@import "grid.scss"; @import "grid.scss";
@import "external/normalize.scss"; @import "external/normalize.scss";
+69 -9
View File
@@ -120,9 +120,6 @@
--link-background-opacity: 0.5; --link-background-opacity: 0.5;
--link-background-opacity-hover: 0.7; --link-background-opacity-hover: 0.7;
--pre-background-color: #272822;
--pre-text-color: #f8f8f2;
--code-background-color: rgba(0, 0, 0, 0.12); --code-background-color: rgba(0, 0, 0, 0.12);
--code-text-color: #808080; --code-text-color: #808080;
@@ -147,11 +144,13 @@
* Thanks to https://www.figma.com/community/plugin/744987207861965946/Shadow-picker * Thanks to https://www.figma.com/community/plugin/744987207861965946/Shadow-picker
*/ */
:root { :root {
--shadow-l1: 0px 4px 8px rgba(0, 0, 0, 0.04), 0px 0px 2px rgba(0, 0, 0, 0.06), 0px 0px 1px rgba(0, 0, 0, 0.04); --shadow-l1-y: 4px;
--shadow-l2: 0px 10px 20px rgba(0, 0, 0, 0.04), 0px 2px 6px rgba(0, 0, 0, 0.04), 0px 0px 1px rgba(0, 0, 0, 0.04); --shadow-l1-blur: 8px;
--shadow-l3: 0px 10px 20px rgba(0, 0, 0, 0.04), 0px 2px 6px rgba(0, 0, 0, 0.04), 0px 0px 1px rgba(0, 0, 0, 0.04); --shadow-l2-y: 10px;
--shadow-l4: 0px 24px 32px rgba(0, 0, 0, 0.04), 0px 16px 24px rgba(0, 0, 0, 0.04), 0px 4px 8px rgba(0, 0, 0, 0.04), --shadow-l2-blur: 20px;
0px 0px 1px rgba(0, 0, 0, 0.04);
--shadow-l1: 0px var(--shadow-l1-y) var(--shadow-l1-blur) rgba(0, 0, 0, 0.04), 0px 0px 2px rgba(0, 0, 0, 0.06), 0px 0px 1px rgba(0, 0, 0, 0.04);
--shadow-l2: 0px var(--shadow-l2-y) var(--shadow-l2-blur) rgba(0, 0, 0, 0.04), 0px 2px 6px rgba(0, 0, 0, 0.04), 0px 0px 1px rgba(0, 0, 0, 0.04);
} }
[data-scheme="light"] { [data-scheme="light"] {
@@ -169,5 +168,66 @@
:root { :root {
--menu-icon-separation: 40px; --menu-icon-separation: 40px;
--container-padding: 15px; --container-padding: 15px;
@include respond(md) {
--container-padding: 20px;
}
--widget-separation: var(--section-separation); --widget-separation: var(--section-separation);
}
/* Spacing tokens */
--spacing-xs: 5px;
--spacing-sm: 10px;
--spacing-md: 15px;
--spacing-lg: 20px;
--spacing-xl: 25px;
--spacing-2xl: 30px;
--spacing-3xl: 40px;
/* Article image height variables */
--article-image-height: 150px;
@include respond(md) {
--article-image-height: 200px;
}
@include respond(xl) {
--article-image-height: 250px;
}
/* Mermaid component variables */
--mermaid-toolbar-btn-bg: rgba(255, 255, 255, 0.95);
--mermaid-toolbar-btn-text: #333;
--mermaid-modal-bg: rgba(0, 0, 0, 0.95);
--mermaid-modal-content-bg: #fff;
--mermaid-modal-btn-bg: #fff;
--mermaid-modal-btn-hover: #ddd;
&[data-scheme="dark"] {
--mermaid-toolbar-btn-bg: rgba(0, 0, 0, 0.85);
--mermaid-toolbar-btn-text: #eee;
--mermaid-modal-content-bg: #1e1e1e;
--mermaid-modal-btn-bg: #333;
--mermaid-modal-btn-hover: #444;
}
/* Article compact image size */
--article-compact-image-size: 50px;
@include respond(md) {
--article-compact-image-size: 60px;
}
/* Widget icon size */
--widget-icon-size: 32px;
/* Article list tile variables */
--article-tile-width: 250px;
--article-tile-height: 150px;
--article-tile-overlay-bg: rgba(0, 0, 0, 0.25);
--article-tile-text-color: #fff;
&[data-scheme="dark"] {
--article-tile-overlay-bg: rgba(0, 0, 0, 0.45);
}
}
+38 -23
View File
@@ -26,15 +26,15 @@ const tagsToReplace = {
'…': '&hellip;' '…': '&hellip;'
}; };
function replaceTag(tag) { function replaceTag(tag: string) {
return tagsToReplace[tag] || tag; return (tagsToReplace as Record<string, string>)[tag] || tag;
} }
function replaceHTMLEnt(str) { function replaceHTMLEnt(str: string) {
return str.replace(/[&<>"]/g, replaceTag); return str.replace(/[&<>"]/g, replaceTag);
} }
function escapeRegExp(string) { function escapeRegExp(string: string) {
return string.replace(/[.*+\-?^${}()|[\]\\]/g, '\\$&'); return string.replace(/[.*+\-?^${}()|[\]\\]/g, '\\$&');
} }
@@ -45,13 +45,21 @@ class Search {
private list: HTMLDivElement; private list: HTMLDivElement;
private resultTitle: HTMLHeadElement; private resultTitle: HTMLHeadElement;
private resultTitleTemplate: string; private resultTitleTemplate: string;
private container: HTMLDivElement;
constructor({ form, input, list, resultTitle, resultTitleTemplate }) { constructor({ form, input, list, resultTitle, resultTitleTemplate }: {
form: HTMLFormElement,
input: HTMLInputElement,
list: HTMLDivElement,
resultTitle: HTMLHeadingElement,
resultTitleTemplate: string
}) {
this.form = form; this.form = form;
this.input = input; this.input = input;
this.list = list; this.list = list;
this.resultTitle = resultTitle; this.resultTitle = resultTitle;
this.resultTitleTemplate = resultTitleTemplate; this.resultTitleTemplate = resultTitleTemplate;
this.container = list.parentElement as HTMLDivElement;
/// Check if there's already value in the search input /// Check if there's already value in the search input
if (this.input.value.trim() !== '') { if (this.input.value.trim() !== '') {
@@ -203,16 +211,18 @@ class Search {
const endTime = performance.now(); const endTime = performance.now();
this.resultTitle.innerText = this.generateResultTitle(results.length, ((endTime - startTime) / 1000).toPrecision(1)); this.resultTitle.innerText = this.generateResultTitle(results.length, ((endTime - startTime) / 1000).toPrecision(1));
this.container?.classList.remove('hidden');
} }
private generateResultTitle(resultLen, time) { private generateResultTitle(resultLen: number, time: string) {
return this.resultTitleTemplate.replace("#PAGES_COUNT", resultLen).replace("#TIME_SECONDS", time); return this.resultTitleTemplate.replace("#PAGES_COUNT", resultLen.toString()).replace("#TIME_SECONDS", time);
} }
public async getData() { public async getData() {
if (!this.data) { if (!this.data) {
/// Not fetched yet /// Not fetched yet
const jsonURL = this.form.dataset.json; const jsonURL = this.form.dataset.json as string;
this.data = await fetch(jsonURL).then(res => res.json()); this.data = await fetch(jsonURL).then(res => res.json());
const parser = new DOMParser(); const parser = new DOMParser();
@@ -227,7 +237,7 @@ class Search {
private bindSearchForm() { private bindSearchForm() {
let lastSearch = ''; let lastSearch = '';
const eventHandler = (e) => { const eventHandler = (e: Event) => {
e.preventDefault(); e.preventDefault();
const keywords = this.input.value.trim(); const keywords = this.input.value.trim();
@@ -251,6 +261,7 @@ class Search {
private clear() { private clear() {
this.list.innerHTML = ''; this.list.innerHTML = '';
this.resultTitle.innerText = ''; this.resultTitle.innerText = '';
this.container.classList.add('hidden');
} }
private bindQueryStringChange() { private bindQueryStringChange() {
@@ -261,7 +272,7 @@ class Search {
private handleQueryString() { private handleQueryString() {
const pageURL = new URL(window.location.toString()); const pageURL = new URL(window.location.toString());
const keywords = pageURL.searchParams.get('keyword'); const keywords = pageURL.searchParams.get('keyword') || '';
this.input.value = keywords; this.input.value = keywords;
if (keywords) { if (keywords) {
@@ -291,19 +302,21 @@ class Search {
} }
public static render(item: pageData) { public static render(item: pageData) {
return <article> return (
<a href={item.permalink}> <article>
<div class="article-details"> <a href={item.permalink}>
<h2 class="article-title" dangerouslySetInnerHTML={{ __html: item.title }}></h2> <div class="article-details">
<section class="article-preview" dangerouslySetInnerHTML={{ __html: item.preview }}></section> <h2 class="article-title" dangerouslySetInnerHTML={{ __html: item.title }}></h2>
</div> <section class="article-preview" dangerouslySetInnerHTML={{ __html: item.preview }}></section>
{item.image &&
<div class="article-image">
<img src={item.image} loading="lazy" />
</div> </div>
} {item.image &&
</a> <div class="article-image">
</article>; <img src={item.image} loading="lazy" />
</div>
}
</a>
</article>
);
} }
} }
@@ -316,10 +329,12 @@ declare global {
window.addEventListener('load', () => { window.addEventListener('load', () => {
setTimeout(function () { setTimeout(function () {
const searchForm = document.querySelector('.search-form') as HTMLFormElement, const searchForm = document.querySelector('.search-form') as HTMLFormElement,
searchInput = searchForm.querySelector('input') as HTMLInputElement, searchInput = searchForm?.querySelector('input') as HTMLInputElement,
searchResultList = document.querySelector('.search-result--list') as HTMLDivElement, searchResultList = document.querySelector('.search-result--list') as HTMLDivElement,
searchResultTitle = document.querySelector('.search-result--title') as HTMLHeadingElement; searchResultTitle = document.querySelector('.search-result--title') as HTMLHeadingElement;
if (!searchForm || !searchInput || !searchResultList || !searchResultTitle) return;
new Search({ new Search({
form: searchForm, form: searchForm,
input: searchInput, input: searchInput,
+17 -5
View File
@@ -4,11 +4,23 @@
<h2 class="article-title"> <h2 class="article-title">
{{- .Title -}} {{- .Title -}}
</h2> </h2>
<footer class="article-time">
<time datetime='{{ .Date.Format "2006-01-02T15:04:05Z07:00" }}'> {{- $description := .Params.description -}}
{{- .Date | time.Format (or .Site.Params.dateFormat.published "Jan 02, 2006") -}} {{- $IsTerm := in .Kind "term" -}}
</time> {{- if $IsTerm -}}
</footer> {{- $description = $description | default (T "list.page" (len .Pages)) -}}
{{- end -}}
{{- if or $description (not .Date.IsZero) -}}
<footer class="article-footer">
{{- if not .Date.IsZero -}}
<time datetime="{{ .Date.Format "2006-01-02T15:04:05Z07:00" }}">
{{- .Date | time.Format .Site.Params.dateFormat.published -}}
</time>
{{- else if $description -}}
<span class="article-description">{{- $description -}}</span>
{{ end }}
</footer>
{{- end -}}
</div> </div>
{{- $image := partial "helper/image" (dict "Image" .Params.image "Resources" .Resources) -}} {{- $image := partial "helper/image" (dict "Image" .Params.image "Resources" .Resources) -}}
@@ -32,7 +32,7 @@
{{ $showDate := not $Page.Date.IsZero }} {{ $showDate := not $Page.Date.IsZero }}
{{ $showFooter := or $showDate $showReadingTime }} {{ $showFooter := or $showDate $showReadingTime }}
{{ if $showFooter }} {{ if $showFooter }}
<footer class="article-time"> <footer class="article-footer">
{{ if $showDate }} {{ if $showDate }}
<div> <div>
{{ partial "helper/icon" "date" }} {{ partial "helper/icon" "date" }}
@@ -1,12 +1,12 @@
<div class="article-list--compact links"> <div class="article-list--compact links">
{{ range $i, $link := .Params.links }} {{ range $link := .Params.links }}
<article> <article>
<a href="{{ $link.website }}" target="_blank" rel="noopener"> <a href="{{ $link.website }}" target="_blank" rel="noopener">
<div class="article-details"> <div class="article-details">
<h2 class="article-title"> <h2 class="article-title">
{{- $link.title -}} {{- $link.title -}}
</h2> </h2>
<footer class="article-time"> <footer class="article-footer">
{{ with $link.description }} {{ with $link.description }}
{{ . }} {{ . }}
{{ else }} {{ else }}
@@ -14,14 +14,23 @@
{{ end }} {{ end }}
</footer> </footer>
</div> </div>
{{ with $link.image }} {{- $image := partial "helper/image" (dict "Image" $link.image "Resources" $.Resources) -}}
{{ $permalink := . }} {{- with $image -}}
{{ with ($.Resources.GetMatch (printf "%s" (. | safeURL))) }}
{{ $permalink = .RelPermalink }}
{{ end }}
<div class="article-image"> <div class="article-image">
<img src="{{ $permalink }}" loading="lazy"{{ with $link.alt }} alt="{{ . }}"{{ end }}> {{ partial "helper/thumbnail-image" (dict
"Resource" .Resource
"Width" 60
"Height" 60
"Resize" $.Site.Params.ImageProcessing.Thumbnail.Enabled
"Attributes" (dict
"src" $image.Permalink
"alt" $link.title
"loading" "lazy"
"width" .Width
"height" .Height
)
) }}
</div> </div>
{{ end }} {{ end }}
</a> </a>
@@ -1,9 +1,9 @@
{{ $related := (.Site.RegularPages.Related .) | first 5 }} {{ $related := (.Site.RegularPages.Related .) | first 5 }}
{{ with $related }} {{ with $related }}
<aside class="related-content--wrapper"> <aside>
<h2 class="section-title">{{ T "article.relatedContent" }}</h2> <h2 class="section-title">{{ T "article.relatedContent" }}</h2>
<div class="related-content"> <div class="subsection-list">
<div class="flex article-list--tile"> <div class="article-list--tile">
{{ range . }} {{ range . }}
{{ partial "article-list/tile" (dict "context" . "size" "250x150" "Type" "articleList") }} {{ partial "article-list/tile" (dict "context" . "size" "250x150" "Type" "articleList") }}
{{ end }} {{ end }}
+1 -1
View File
@@ -33,7 +33,7 @@
{{ end }} {{ end }}
{{ with $resource }} {{ with $resource }}
{{ if reflect.IsImageResourceProcessable . }} {{ if reflect.IsImageResourceWithMeta . }}
{{ $result = dict {{ $result = dict
"Resource" $resource "Resource" $resource
"Permalink" $permalink "Permalink" $permalink
+5 -1
View File
@@ -7,7 +7,11 @@
<div class="widget-icon"> <div class="widget-icon">
{{ partial "helper/icon" "infinity" }} {{ partial "helper/icon" "infinity" }}
</div> </div>
<h2 class="widget-title section-title">{{ T "widget.archives.title" }}</h2> <h2 class="widget-title section-title">
<a href="{{ $archivesPage.RelPermalink }}">
{{ T "widget.archives.title" }}
</a>
</h2>
{{ $pages := partial "helper/pages.html" $context.Site.Home }} {{ $pages := partial "helper/pages.html" $context.Site.Home }}
{{ $archives := $pages.GroupByDate "2006" }} {{ $archives := $pages.GroupByDate "2006" }}
+1 -1
View File
@@ -13,7 +13,7 @@
{{- $widgetTitle := .Params.title -}} {{- $widgetTitle := .Params.title -}}
{{- $limit := default 10 .Params.limit -}} {{- $limit := default 10 .Params.limit -}}
{{- $icon := default .Params.taxonomy .Params.icon -}} {{- $icon := default .Params.taxonomy .Params.icon -}}
{{- $showLink := default false .Params.showLink -}} {{- $showLink := default true .Params.showLink -}}
<section class="widget tagCloud"> <section class="widget tagCloud">
<div class="widget-icon"> <div class="widget-icon">
+13 -4
View File
@@ -20,10 +20,19 @@
{{- $image := partial "helper/image" (dict "Image" .Params.image "Resources" .Resources) -}} {{- $image := partial "helper/image" (dict "Image" .Params.image "Resources" .Resources) -}}
{{ if $image }} {{ if $image }}
<div class="section-image"> <div class="section-image">
<img src="{{ $image.Permalink }}" {{ partial "helper/thumbnail-image" (dict
width="{{ $image.Width }}" "Resource" $image.Resource
height="{{ $image.Height }}" "Width" 60
loading="lazy"> "Height" 60
"Resize" .Site.Params.ImageProcessing.Thumbnail.Enabled
"Attributes" (dict
"src" $image.Permalink
"alt" .Title
"loading" "lazy"
"width" $image.Width
"height" $image.Height
)
) }}
</div> </div>
{{ end }} {{ end }}
</div> </div>
+1 -1
View File
@@ -16,7 +16,7 @@
</button> </button>
</form> </form>
<div class="search-result"> <div class="search-result hidden">
<h3 class="search-result--title section-title"></h3> <h3 class="search-result--title section-title"></h3>
<div class="search-result--list article-list--compact"></div> <div class="search-result--list article-list--compact"></div>
</div> </div>