Compare commits

...

10 commits

Author SHA1 Message Date
Cotes Chung
d51345e297
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
2024-11-08 22:35:18 +08:00
Cotes Chung
2f844978aa
chore: change stale label to inactive 2024-11-08 22:15:31 +08:00
Supreeth Mysore Venkatesh
42dea8ee29
build(deps): update wdm gem version for compatibility (#2028) 2024-11-04 00:45:59 +08:00
Alexander Fuks
86b13c917f
chore: improve feed interoperability (#2024) 2024-11-01 14:39:03 +04:00
Cotes Chung
4ef3cd8efc
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.
2024-10-29 22:56:32 +08:00
Cotes Chung
c7f967529c
ci: skip test for invalid PRs (#2013) 2024-10-26 16:58:07 +08:00
Cotes Chung
74ed06321c
ci: block invalid pull requests (#2010) 2024-10-25 19:48:11 +08:00
Cotes Chung
d4f7f39ece
refactor: simplify sidebar animation 2024-10-22 11:13:06 +08:00
Cotes Chung
c1bd9eb9ee
refactor: reduce duplicate scss 2024-10-20 13:52:42 +08:00
Cotes Chung
6f461132c0
refactor: improve toc popup module 2024-10-19 21:15:31 +08:00
21 changed files with 197 additions and 113 deletions

View file

@ -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

View file

@ -1,17 +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"
- README.md
- LICENSE
pull_request:
paths-ignore:
- ".github/**"
- "!.github/workflows/ci.yml"
- .gitignore
- "docs/**"
- README.md
- LICENSE
jobs:
build:

View file

@ -1,5 +1,11 @@
name: Lint Commit Messages
on: pull_request
on:
push:
branches:
- master
- "hotfix/*"
pull_request:
jobs:
commitlint:

25
.github/workflows/pr-filter.yml vendored Normal file
View file

@ -0,0 +1,25 @@
name: PR Filter
on:
pull_request_target:
types: [opened, reopened]
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
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 }}
script: |
const script = require('.github/workflows/scripts/pr-filter.js');
await script({ github, context, core });

View file

@ -10,6 +10,7 @@ on:
required: true
BUILDER:
required: true
workflow_dispatch:
jobs:
launch:

36
.github/workflows/scripts/pr-filter.js vendored Normal file
View file

@ -0,0 +1,36 @@
function hasTypes(markdown) {
return /## Type of change/.test(markdown) && /-\s\[x\]/i.test(markdown);
}
function hasDescription(markdown) {
return (
/## Description/.test(markdown) &&
!/## Description\s*\n\s*(##|\s*$)/.test(markdown)
);
}
module.exports = async ({ github, context, core }) => {
const pr = context.payload.pull_request;
const body = pr.body === null ? '' : pr.body;
const markdown = body.replace(/<!--[\s\S]*?-->/g, '');
const action = context.payload.action;
const isValid =
markdown !== '' && hasTypes(markdown) && hasDescription(markdown);
if (!isValid) {
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 ${action} an invalid pull request. No worries, we'll close it for you.`
});
core.setFailed('PR content does not meet template requirements.');
}
};

View file

@ -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.

View file

@ -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"]

View file

@ -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]

View file

@ -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();
}

View file

@ -5,7 +5,10 @@ const desktopMode = matchMedia('(min-width: 1200px)');
function refresh(e) {
if (e.matches) {
if (mobile.popupOpened) {
mobile.hidePopup();
}
desktop.refresh();
} else {
mobile.refresh();

View file

@ -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() {

View file

@ -68,7 +68,7 @@ layout: compress
</aside>
</div>
<div id="mask"></div>
<div id="mask" class="d-none position-fixed w-100 h-100 z-1"></div>
{% if site.pwa.enabled %}
{% include_cached notification.html lang=lang %}

View file

@ -100,7 +100,7 @@ tail_includes:
{% if enable_toc %}
<div id="toc-bar" class="d-flex align-items-center justify-content-between invisible">
<span class="label text-truncate">{{ page.title }}</span>
<button type="button" class="toc-trigger btn btn-link me-1">
<button type="button" class="toc-trigger btn me-1">
<i class="fa-solid fa-list-ul fa-fw"></i>
</button>
</div>
@ -113,8 +113,8 @@ tail_includes:
<dialog id="toc-popup" class="p-0">
<div class="header d-flex flex-row align-items-center justify-content-between">
<div class="label text-truncate py-2 ms-4">{{- page.title -}}</div>
<button id="toc-popup-close" type="button" class="btn btn-link">
<i class="fas fa-close fa-fw"></i>
<button id="toc-popup-close" type="button" class="btn mx-1 my-1 opacity-75">
<i class="fas fa-close"></i>
</button>
</div>
<div id="toc-popup-content" class="px-4 py-3 pb-4"></div>

View file

@ -251,8 +251,8 @@ i {
> p {
margin-left: 0.25em;
margin-top: 0;
margin-bottom: 0;
@include mt-mb(0);
}
}
}
@ -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);
@ -769,8 +768,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 +1042,7 @@ search {
a {
font-size: 1.4rem;
line-height: 2.5rem;
line-height: 1.5rem;
&:hover {
@extend %link-hover;
@ -1069,8 +1068,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,23 +1086,11 @@ search {
color: var(--topbar-text-color);
text-align: center;
width: 70%;
overflow: hidden;
text-overflow: ellipsis;
word-break: keep-all;
white-space: nowrap;
}
#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 --- */
@ -1492,8 +1480,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,

View file

@ -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) {
@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 {

View file

@ -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);

View file

@ -63,9 +63,7 @@
}
> a {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
@include text-ellipsis;
}
}
}

View file

@ -74,9 +74,8 @@
> div:first-child {
display: block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
@extend %text-ellipsis;
}
}
}

View file

@ -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);
@ -380,12 +379,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,9 +422,16 @@ header {
}
}
button:focus-visible {
button {
> i {
font-size: 1.25rem;
vertical-align: middle;
}
&:focus-visible {
box-shadow: none;
}
}
ul {
list-style-type: none;
@ -461,20 +468,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;
}
@ -501,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;
@ -526,7 +534,7 @@ header {
max-width: 100%;
}
%btn-share-hovor {
%btn-share-hover {
color: var(--btn-share-hover-color) !important;
}
@ -558,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);
}
}

View file

@ -34,7 +34,7 @@ permalink: /feed.xml
<updated>{{ post.date | date_to_xmlschema }}</updated>
{% endif %}
<id>{{ post_absolute_url }}</id>
<content src="{{ post_absolute_url }}" />
<content type="text/html" src="{{ post_absolute_url }}" />
<author>
<name>{{ post.author | default: site.social.name }}</name>
</author>