feat(assets): integrate UnoCSS for utility classes and presetIcons (#795)

* refactor(assets): integrate UnoCSS for utility classes

- Add UnoCSS with presetWind3 as pre-built CSS (assets/css/unocss.css)
- Add uno.config.ts with theme breakpoints, colors, safelist, and blocklist
- Replace SCSS utility classes with UnoCSS atomic classes:
  - d-none → hidden
  - d-none-desktop → sm:hidden
  - d-none-mobile → max-sm:hidden
  - order-* (safelist)
  - variant-numeric → tabular-nums lining-nums
- Rename .blur to .is-blur to avoid UnoCSS conflict
- Add @unocss-skip comments for SVG path elements to prevent false positives
- Remove redundant _utilities.scss ($orders map) and simplify _common.scss
- Update documentation (CLAUDE.md, CONTRIBUTING.md, copilot-instructions.md)

* refactor(assets): replace 404/offline SCSS with UnoCSS atomic classes

- Replace _404.scss styles with atomic classes on template elements
- Replace _offline.scss styles with atomic classes on template elements
- Keep selectors (id/class) as user customization hooks
- Delete assets/scss/pages/_404.scss and _offline.scss

* refactor(assets): simplify SCSS with UnoCSS atomic classes

- Replace _bilibili.scss with atomic classes (relative, aspect-video, inset-0)
- Replace _version.scss with atomic classes (whitespace-nowrap, align-text-bottom)
- Replace _noscript-warning.scss with atomic classes (bg-danger, fixed, z-200)
- Add semantic z-index shortcuts (z-hide, z-auto, z-base, z-loading, z-sticky, z-fixed)
- Add h1-h6 to UnoCSS blocklist to prevent false positives
- Use Source path for UnoCSS CSS loading to enable Hugo minify

* chore(assets): minor SCSS and template cleanup

* fix(assets): add secondary color to UnoCSS theme config

text-secondary was broken because the secondary color mapping was missing.

* feat(assets): add UnoCSS presetIcons support and z-index shortcuts

- Add presetIcons preset with empty collections (ready for custom icon sets)
- Add @iconify/json and @iconify/utils devDependencies
- Add semantic z-index shortcuts (z-hide, z-auto, z-base, z-loading, z-sticky, z-fixed)
- Add secondary color to UnoCSS theme config

* refactor(assets): replace SVG icons with UnoCSS presetIcons

- Add Lucide and Octicons icon collections to presetIcons config
- Replace arrow-up/down and enter-key SVGs with Lucide icons
- Replace alert icons (info, light-bulb, report, alert, stop) with Octicons
- Delete replaced SVG files from assets/images/icons/
- Keep custom SVGs (csdn, plume, rootme)

* refactor(layouts): redesign 404 and offline pages with UnoCSS

- Replace translate-y-[30vh] with self-stretch flex centering below header
- Remove arbitrary values (text-[3.6rem], text-[1.8rem], etc.)
- Restore @page print styles in _common.scss
- Simplify offline page layout (icon + title + text)
- Fix hardcoded #57606a → text-secondary
This commit is contained in:
Cell
2026-06-27 06:27:12 +08:00
committed by GitHub
parent e30b9db23b
commit 8af8e806d7
60 changed files with 1446 additions and 288 deletions
+3 -1
View File
@@ -18,7 +18,9 @@
"tamasfe.even-better-toml",
"casualjim.gotemplate",
"SomewhatStationery.some-sass",
"gruntfuggly.todo-tree"
"gruntfuggly.todo-tree",
"antfu.unocss",
"antfu.iconify"
]
}
}
+9
View File
@@ -18,6 +18,15 @@ This document defines the detailed coding standards for the FixIt theme project.
- Use SCSS variables for colors — no hardcoded values
- Keep selector nesting shallow
## UnoCSS Guidelines
- Use UnoCSS atomic classes for common utilities (`hidden`, `me-1`, `text-center`, etc.)
- Theme colors: `bg-primary`, `text-success`, `text-danger`, etc. (mapped via `@theme` in `uno.config.ts`)
- Responsive: `sm:` (>=681px), `md:` (>=961px), `lg:` (>=1201px), `xl:` (>=1441px). Use `max-sm:` for xs (<681px)
- Wrap SVG elements with `<!-- @unocss-skip-start -->` / `<!-- @unocss-skip-end -->` to avoid false positives from `d` attribute values
- Dynamically generated classes (e.g., `order-*`) must be added to `safelist` in `uno.config.ts`
- Run `pnpm css:build` after modifying `uno.config.ts` or templates that use UnoCSS classes
## TypeScript Coding Standards
### Architecture
+3 -1
View File
@@ -6,6 +6,8 @@
"tamasfe.even-better-toml",
"casualjim.gotemplate",
"SomewhatStationery.some-sass",
"gruntfuggly.todo-tree"
"gruntfuggly.todo-tree",
"antfu.unocss",
"antfu.iconify"
]
}
+11 -2
View File
@@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
## Project Overview
FixIt is a modern, responsive theme for the Hugo static site generator. Built with Hugo templates, SCSS, and TypeScript.
FixIt is a modern, responsive theme for the Hugo static site generator. Built with Hugo templates, SCSS, UnoCSS, and TypeScript.
## Development Commands
@@ -90,7 +90,7 @@ Cross-module communication uses the shared `eventBus` singleton, not direct modu
Hugo Pipes processes all assets. The key orchestration is in `_partials/base/assets.html`:
- **CSS**: `scss/main.scss` is the entry point importing `core/`, `pages/`, `widgets/`, `custom`. SCSS variables are configured via `hugo:vars` (user-configurable from `[params.appearance]`) and `hugo:vars/internal` (theme system config).
- **CSS**: `scss/main.scss` is the entry point importing `core/`, `pages/`, `widgets/`, `custom`. SCSS variables are configured via `hugo:vars` (user-configurable from `[params.appearance]`) and `hugo:vars/internal` (theme system config). UnoCSS utility classes are pre-built to `assets/css/unocss.css` (via `pnpm css:build`), loaded before the main SCSS bundle.
- **JS**: `_partials/function/js-build.html` wraps `js.Build` with minify-in-production defaults. Hugo's `@params` injection passes config values into TypeScript at build time.
- **Third-party libraries**: Stored in `assets/lib/` (vendored, not npm-managed). Tracked by `librarybot.yml` and updated weekly by the `hugo-fixit/librarybot` GitHub Action. Can be overridden via CDN config in `assets/data/cdn/jsdelivr.yml` or `unpkg.yml`.
@@ -110,6 +110,15 @@ Hugo Pipes processes all assets. The key orchestration is in `_partials/base/ass
- Prefer relative units (rem, em, %) over absolute units
- Keep selector nesting shallow
### UnoCSS (`assets/css/unocss.css`)
- Pre-built utility classes generated by `pnpm css:build` (config: `uno.config.ts`)
- Use atomic classes for common utilities (`hidden`, `me-1`, `text-center`, etc.)
- Theme colors mapped via `@theme`: `bg-primary`, `text-success`, `text-danger`, etc.
- Responsive breakpoints: `sm:` (>=681px), `md:` (>=961px), `lg:` (>=1201px), `xl:` (>=1441px). Use `max-sm:` for xs (<681px)
- Wrap SVG elements with `<!-- @unocss-skip-start -->` / `<!-- @unocss-skip-end -->` to avoid false positives from `d` attribute values
- `safelist` in `uno.config.ts` for dynamically generated classes (e.g., `order-*`, `sm:hidden`)
### TypeScript
- Use ES6 `#` private fields — not TypeScript `private` with `_` prefix
+7
View File
@@ -80,6 +80,11 @@ pnpm gen:lexers
# Preview the built site locally (requires build first)
pnpm preview
# Build UnoCSS utility classes (pre-built, committed to repo)
pnpm css:build
# Watch mode for UnoCSS (for theme developers)
pnpm css:dev
```
> [!TIP]
@@ -111,6 +116,7 @@ FixIt/
│ └── test/ # Test site
├── archetypes/ # Content templates
├── assets/ # Theme assets
│ ├── css/ # UnoCSS pre-built output (unocss.css)
│ ├── images/ # Image assets
│ ├── js/ # JavaScript files
│ ├── lib/ # Third-party libraries
@@ -127,6 +133,7 @@ FixIt/
│ └── versioning/ # Version management (pre-commit)
├── static/ # Static files
├── hugo.toml # Default theme configuration
├── uno.config.ts # UnoCSS configuration
└── package.json # npm scripts and dependencies
```
-5
View File
@@ -17,11 +17,6 @@ _merge = "shallow"
[outputs]
_merge = "shallow"
# -------------------------------------------------------------------------------------
# Taxonomies Configuration
# See: https://gohugo.io/content-management/taxonomies/#configure-taxonomies
# -------------------------------------------------------------------------------------
[taxonomies]
_merge = "shallow"
-5
View File
@@ -33,11 +33,6 @@ _merge = "shallow"
[outputs]
_merge = "shallow"
# -------------------------------------------------------------------------------------
# Taxonomies Configuration
# See: https://gohugo.io/content-management/taxonomies/#configure-taxonomies
# -------------------------------------------------------------------------------------
[taxonomies]
_merge = "shallow"
+90
View File
@@ -0,0 +1,90 @@
/* layer: preflights */
*,::before,::after{--un-rotate:0;--un-rotate-x:0;--un-rotate-y:0;--un-rotate-z:0;--un-scale-x:1;--un-scale-y:1;--un-scale-z:1;--un-skew-x:0;--un-skew-y:0;--un-translate-x:0;--un-translate-y:0;--un-translate-z:0;--un-pan-x: ;--un-pan-y: ;--un-pinch-zoom: ;--un-scroll-snap-strictness:proximity;--un-ordinal: ;--un-slashed-zero: ;--un-numeric-figure: ;--un-numeric-spacing: ;--un-numeric-fraction: ;--un-border-spacing-x:0;--un-border-spacing-y:0;--un-ring-offset-shadow:0 0 rgb(0 0 0 / 0);--un-ring-shadow:0 0 rgb(0 0 0 / 0);--un-shadow-inset: ;--un-shadow:0 0 rgb(0 0 0 / 0);--un-ring-inset: ;--un-ring-offset-width:0px;--un-ring-offset-color:#fff;--un-ring-width:0px;--un-ring-color:rgb(147 197 253 / 0.5);--un-blur: ;--un-brightness: ;--un-contrast: ;--un-drop-shadow: ;--un-grayscale: ;--un-hue-rotate: ;--un-invert: ;--un-saturate: ;--un-sepia: ;--un-backdrop-blur: ;--un-backdrop-brightness: ;--un-backdrop-contrast: ;--un-backdrop-grayscale: ;--un-backdrop-hue-rotate: ;--un-backdrop-invert: ;--un-backdrop-opacity: ;--un-backdrop-saturate: ;--un-backdrop-sepia: ;}::backdrop{--un-rotate:0;--un-rotate-x:0;--un-rotate-y:0;--un-rotate-z:0;--un-scale-x:1;--un-scale-y:1;--un-scale-z:1;--un-skew-x:0;--un-skew-y:0;--un-translate-x:0;--un-translate-y:0;--un-translate-z:0;--un-pan-x: ;--un-pan-y: ;--un-pinch-zoom: ;--un-scroll-snap-strictness:proximity;--un-ordinal: ;--un-slashed-zero: ;--un-numeric-figure: ;--un-numeric-spacing: ;--un-numeric-fraction: ;--un-border-spacing-x:0;--un-border-spacing-y:0;--un-ring-offset-shadow:0 0 rgb(0 0 0 / 0);--un-ring-shadow:0 0 rgb(0 0 0 / 0);--un-shadow-inset: ;--un-shadow:0 0 rgb(0 0 0 / 0);--un-ring-inset: ;--un-ring-offset-width:0px;--un-ring-offset-color:#fff;--un-ring-width:0px;--un-ring-color:rgb(147 197 253 / 0.5);--un-blur: ;--un-brightness: ;--un-contrast: ;--un-drop-shadow: ;--un-grayscale: ;--un-hue-rotate: ;--un-invert: ;--un-saturate: ;--un-sepia: ;--un-backdrop-blur: ;--un-backdrop-brightness: ;--un-backdrop-contrast: ;--un-backdrop-grayscale: ;--un-backdrop-hue-rotate: ;--un-backdrop-invert: ;--un-backdrop-opacity: ;--un-backdrop-saturate: ;--un-backdrop-sepia: ;}
/* layer: icons */
.lucide-arrow-down{--un-icon:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 24 24' display='inline-block' vertical-align='text-bottom' width='1em' height='1em' xmlns='http://www.w3.org/2000/svg' %3E%3Cpath fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M12 5v14m7-7l-7 7l-7-7'/%3E%3C/svg%3E");-webkit-mask:var(--un-icon) no-repeat;mask:var(--un-icon) no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;background-color:currentColor;color:inherit;display:inline-block;vertical-align:text-bottom;width:1em;height:1em;}
.lucide-arrow-up{--un-icon:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 24 24' display='inline-block' vertical-align='text-bottom' width='1em' height='1em' xmlns='http://www.w3.org/2000/svg' %3E%3Cpath fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m5 12l7-7l7 7m-7 7V5'/%3E%3C/svg%3E");-webkit-mask:var(--un-icon) no-repeat;mask:var(--un-icon) no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;background-color:currentColor;color:inherit;display:inline-block;vertical-align:text-bottom;width:1em;height:1em;}
.lucide-corner-down-left{--un-icon:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 24 24' display='inline-block' vertical-align='text-bottom' width='1em' height='1em' xmlns='http://www.w3.org/2000/svg' %3E%3Cg fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2'%3E%3Cpath d='M20 4v7a4 4 0 0 1-4 4H4'/%3E%3Cpath d='m9 10l-5 5l5 5'/%3E%3C/g%3E%3C/svg%3E");-webkit-mask:var(--un-icon) no-repeat;mask:var(--un-icon) no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;background-color:currentColor;color:inherit;display:inline-block;vertical-align:text-bottom;width:1em;height:1em;}
.octicon-alert-16{--un-icon:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 16 16' display='inline-block' vertical-align='text-bottom' width='1em' height='1em' xmlns='http://www.w3.org/2000/svg' %3E%3Cpath fill='currentColor' d='M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0M9 11a1 1 0 1 1-2 0a1 1 0 0 1 2 0'/%3E%3C/svg%3E");-webkit-mask:var(--un-icon) no-repeat;mask:var(--un-icon) no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;background-color:currentColor;color:inherit;display:inline-block;vertical-align:text-bottom;width:1em;height:1em;}
.octicon-info-16{--un-icon:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 16 16' display='inline-block' vertical-align='text-bottom' width='1em' height='1em' xmlns='http://www.w3.org/2000/svg' %3E%3Cpath fill='currentColor' d='M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8m8-6.5a6.5 6.5 0 1 0 0 13a6.5 6.5 0 0 0 0-13M6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75M8 6a1 1 0 1 1 0-2a1 1 0 0 1 0 2'/%3E%3C/svg%3E");-webkit-mask:var(--un-icon) no-repeat;mask:var(--un-icon) no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;background-color:currentColor;color:inherit;display:inline-block;vertical-align:text-bottom;width:1em;height:1em;}
.octicon-light-bulb-16{--un-icon:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 16 16' display='inline-block' vertical-align='text-bottom' width='1em' height='1em' xmlns='http://www.w3.org/2000/svg' %3E%3Cpath fill='currentColor' d='M8 1.5c-2.363 0-4 1.69-4 3.75c0 .984.424 1.625.984 2.304l.214.253c.223.264.47.556.673.848c.284.411.537.896.621 1.49a.75.75 0 0 1-1.484.211c-.04-.282-.163-.547-.37-.847a9 9 0 0 0-.542-.68l-.268-.32C3.201 7.75 2.5 6.766 2.5 5.25C2.5 2.31 4.863 0 8 0s5.5 2.31 5.5 5.25c0 1.516-.701 2.5-1.328 3.259q-.142.172-.268.319c-.207.245-.383.453-.541.681c-.208.3-.33.565-.37.847a.751.751 0 0 1-1.485-.212c.084-.593.337-1.078.621-1.489c.203-.292.45-.584.673-.848l.213-.253c.561-.679.985-1.32.985-2.304c0-2.06-1.637-3.75-4-3.75M5.75 12h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1 0-1.5M6 15.25a.75.75 0 0 1 .75-.75h2.5a.75.75 0 0 1 0 1.5h-2.5a.75.75 0 0 1-.75-.75'/%3E%3C/svg%3E");-webkit-mask:var(--un-icon) no-repeat;mask:var(--un-icon) no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;background-color:currentColor;color:inherit;display:inline-block;vertical-align:text-bottom;width:1em;height:1em;}
.octicon-report-16{--un-icon:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 16 16' display='inline-block' vertical-align='text-bottom' width='1em' height='1em' xmlns='http://www.w3.org/2000/svg' %3E%3Cpath fill='currentColor' d='M0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v9.5A1.75 1.75 0 0 1 14.25 13H8.06l-2.573 2.573A1.458 1.458 0 0 1 3 14.543V13H1.75A1.75 1.75 0 0 1 0 11.25Zm1.75-.25a.25.25 0 0 0-.25.25v9.5c0 .138.112.25.25.25h2a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.75.75 0 0 1 .53-.22h6.5a.25.25 0 0 0 .25-.25v-9.5a.25.25 0 0 0-.25-.25Zm7 2.25v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0M9 9a1 1 0 1 1-2 0a1 1 0 0 1 2 0'/%3E%3C/svg%3E");-webkit-mask:var(--un-icon) no-repeat;mask:var(--un-icon) no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;background-color:currentColor;color:inherit;display:inline-block;vertical-align:text-bottom;width:1em;height:1em;}
.octicon-stop-16{--un-icon:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 16 16' display='inline-block' vertical-align='text-bottom' width='1em' height='1em' xmlns='http://www.w3.org/2000/svg' %3E%3Cpath fill='currentColor' d='M4.47.22A.75.75 0 0 1 5 0h6c.199 0 .389.079.53.22l4.25 4.25c.141.14.22.331.22.53v6a.75.75 0 0 1-.22.53l-4.25 4.25A.75.75 0 0 1 11 16H5a.75.75 0 0 1-.53-.22L.22 11.53A.75.75 0 0 1 0 11V5c0-.199.079-.389.22-.53Zm.84 1.28L1.5 5.31v5.38l3.81 3.81h5.38l3.81-3.81V5.31L10.69 1.5ZM8 4a.75.75 0 0 1 .75.75v3.5a.75.75 0 0 1-1.5 0v-3.5A.75.75 0 0 1 8 4m0 8a1 1 0 1 1 0-2a1 1 0 0 1 0 2'/%3E%3C/svg%3E");-webkit-mask:var(--un-icon) no-repeat;mask:var(--un-icon) no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;background-color:currentColor;color:inherit;display:inline-block;vertical-align:text-bottom;width:1em;height:1em;}
/* layer: shortcuts */
.z-fixed{z-index:200;}
/* layer: default */
.visible{visibility:visible;}
.absolute{position:absolute;}
.fixed{position:fixed;}
.relative{position:relative;}
.sticky{position:sticky;}
.static{position:static;}
.inset-0{inset:0;}
.inset-x-0{left:0;right:0;}
.bottom-0{bottom:0;}
.order-0{order:0;}
.order-1{order:1;}
.order-2{order:2;}
.order-3{order:3;}
.order-4{order:4;}
.order-5{order:5;}
.order-first{order:-9999;}
.order-last{order:9999;}
.mx-auto{margin-left:auto;margin-right:auto;}
.my-4{margin-top:1rem;margin-bottom:1rem;}
.me{margin-inline-end:1rem;}
.me-1{margin-inline-end:0.25rem;}
.me-2{margin-inline-end:0.5rem;}
.ms-1{margin-inline-start:0.25rem;}
.inline{display:inline;}
.block{display:block;}
.contents{display:contents;}
.hidden{display:none;}
.aspect-video{aspect-ratio:16/9;}
.h-\[1\.25em\]{height:1.25em;}
.h-full{height:100%;}
.w-full{width:100%;}
.flex{display:flex;}
.flex-col{flex-direction:column;}
.table{display:table;}
.transform{transform:translateX(var(--un-translate-x)) translateY(var(--un-translate-y)) translateZ(var(--un-translate-z)) rotate(var(--un-rotate)) rotateX(var(--un-rotate-x)) rotateY(var(--un-rotate-y)) rotateZ(var(--un-rotate-z)) skewX(var(--un-skew-x)) skewY(var(--un-skew-y)) scaleX(var(--un-scale-x)) scaleY(var(--un-scale-y)) scaleZ(var(--un-scale-z));}
.resize{resize:both;}
.break-before-page{break-before:page;}
.break-after-page{break-after:page;}
.items-center{align-items:center;}
.self-stretch{align-self:stretch;}
.justify-center{justify-content:center;}
.whitespace-nowrap{white-space:nowrap;}
.b,
.border{border-width:1px;}
.bg-danger{background-color:var(--fi-danger) /* var(--fi-danger) */;}
.px{padding-left:1rem;padding-right:1rem;}
.pl{padding-left:1rem;}
.pt{padding-top:1rem;}
.text-center{text-align:center;}
.indent{text-indent:1.5rem;}
.align-text-bottom{vertical-align:text-bottom;}
.text-3xl{font-size:1.875rem;line-height:2.25rem;}
.text-5xl{font-size:3rem;line-height:1;}
.text-base{font-size:1rem;line-height:1.5rem;}
.text-lg{font-size:1.125rem;line-height:1.75rem;}
.text-danger{color:var(--fi-danger) /* var(--fi-danger) */;}
.text-secondary{color:var(--fi-secondary) /* var(--fi-secondary) */;}
.text-success{color:var(--fi-success) /* var(--fi-success) */;}
.text-white{--un-text-opacity:1;color:rgb(255 255 255 / var(--un-text-opacity)) /* #fff */;}
.font-bold{font-weight:700;}
.capitalize{text-transform:capitalize;}
.lining-nums{--un-numeric-figure:lining-nums;font-variant-numeric:var(--un-ordinal) var(--un-slashed-zero) var(--un-numeric-figure) var(--un-numeric-spacing) var(--un-numeric-fraction);}
.tabular-nums{--un-numeric-spacing:tabular-nums;font-variant-numeric:var(--un-ordinal) var(--un-slashed-zero) var(--un-numeric-figure) var(--un-numeric-spacing) var(--un-numeric-fraction);}
.underline{text-decoration-line:underline;}
.tab{-moz-tab-size:4;-o-tab-size:4;tab-size:4;}
.text-shadow{--un-text-shadow:0 0 1px var(--un-text-shadow-color, rgb(0 0 0 / 0.2)),0 0 1px var(--un-text-shadow-color, rgb(1 0 5 / 0.1));text-shadow:var(--un-text-shadow);}
.text-shadow-md{--un-text-shadow:0 1px 2px var(--un-text-shadow-color, rgb(30 29 39 / 0.19)),1px 2px 4px var(--un-text-shadow-color, rgb(54 64 147 / 0.18));text-shadow:var(--un-text-shadow);}
.opacity-50{opacity:0.5;}
.shadow{--un-shadow:var(--un-shadow-inset) 0 1px 3px 0 var(--un-shadow-color, rgb(0 0 0 / 0.1)),var(--un-shadow-inset) 0 1px 2px -1px var(--un-shadow-color, rgb(0 0 0 / 0.1));box-shadow:var(--un-ring-offset-shadow), var(--un-ring-shadow), var(--un-shadow);}
.blur{--un-blur:blur(8px);filter:var(--un-blur) var(--un-brightness) var(--un-contrast) var(--un-drop-shadow) var(--un-grayscale) var(--un-hue-rotate) var(--un-invert) var(--un-saturate) var(--un-sepia);}
@media (max-width: 680.9px){
.max-sm\:hidden{display:none;}
}
@media (min-width: 681px){
.sm\:hidden{display:none;}
}
-1
View File
@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path d="M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path></svg>

Before

Width:  |  Height:  |  Size: 409 B

-1
View File
@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path></svg>

Before

Width:  |  Height:  |  Size: 354 B

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path d="M8 1.5c-2.363 0-4 1.69-4 3.75 0 .984.424 1.625.984 2.304l.214.253c.223.264.47.556.673.848.284.411.537.896.621 1.49a.75.75 0 0 1-1.484.211c-.04-.282-.163-.547-.37-.847a8.456 8.456 0 0 0-.542-.68c-.084-.1-.173-.205-.268-.32C3.201 7.75 2.5 6.766 2.5 5.25 2.5 2.31 4.863 0 8 0s5.5 2.31 5.5 5.25c0 1.516-.701 2.5-1.328 3.259-.095.115-.184.22-.268.319-.207.245-.383.453-.541.681-.208.3-.33.565-.37.847a.751.751 0 0 1-1.485-.212c.084-.593.337-1.078.621-1.489.203-.292.45-.584.673-.848.075-.088.147-.173.213-.253.561-.679.985-1.32.985-2.304 0-2.06-1.637-3.75-4-3.75ZM5.75 12h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1 0-1.5ZM6 15.25a.75.75 0 0 1 .75-.75h2.5a.75.75 0 0 1 0 1.5h-2.5a.75.75 0 0 1-.75-.75Z"></path></svg>

Before

Width:  |  Height:  |  Size: 800 B

-1
View File
@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path d="M0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v9.5A1.75 1.75 0 0 1 14.25 13H8.06l-2.573 2.573A1.458 1.458 0 0 1 3 14.543V13H1.75A1.75 1.75 0 0 1 0 11.25Zm1.75-.25a.25.25 0 0 0-.25.25v9.5c0 .138.112.25.25.25h2a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h6.5a.25.25 0 0 0 .25-.25v-9.5a.25.25 0 0 0-.25-.25Zm7 2.25v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 9a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path></svg>

Before

Width:  |  Height:  |  Size: 524 B

-1
View File
@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path d="M4.47.22A.749.749 0 0 1 5 0h6c.199 0 .389.079.53.22l4.25 4.25c.141.14.22.331.22.53v6a.749.749 0 0 1-.22.53l-4.25 4.25A.749.749 0 0 1 11 16H5a.749.749 0 0 1-.53-.22L.22 11.53A.749.749 0 0 1 0 11V5c0-.199.079-.389.22-.53Zm.84 1.28L1.5 5.31v5.38l3.81 3.81h5.38l3.81-3.81V5.31L10.69 1.5ZM8 4a.75.75 0 0 1 .75.75v3.5a.75.75 0 0 1-1.5 0v-3.5A.75.75 0 0 1 8 4Zm0 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path></svg>

Before

Width:  |  Height:  |  Size: 493 B

-1
View File
@@ -1 +0,0 @@
<svg width="20" height="20" aria-label="Arrow down" viewBox="0 0 24 24" role="img"><g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.4"><path d="M12 5v14"></path><path d="m19 12-7 7-7-7"></path></g></svg>

Before

Width:  |  Height:  |  Size: 255 B

-1
View File
@@ -1 +0,0 @@
<svg width="20" height="20" aria-label="Arrow up" viewBox="0 0 24 24" role="img"><g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.4"><path d="m5 12 7-7 7 7"></path><path d="M12 19V5"></path></g></svg>

Before

Width:  |  Height:  |  Size: 252 B

-1
View File
@@ -1 +0,0 @@
<svg width="20" height="20" aria-label="Enter key" viewBox="0 0 24 24" role="img"><g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.4"><polyline points="9 10 4 15 9 20"></polyline><path d="M20 4v7a4 4 0 0 1-4 4H4"></path></g></svg>

Before

Width:  |  Height:  |  Size: 282 B

+1 -1
View File
@@ -171,7 +171,7 @@ function isNodeVisuallyActive(node: Element): boolean {
function isRenderContextActive(el: Element): boolean {
if (!el.isConnected)
return false
if (el.closest('[hidden], .d-none, [aria-hidden="true"]'))
if (el.closest('[hidden], .hidden, [aria-hidden="true"]'))
return false
const diagramView = el.closest('.diagram-view')
+1 -1
View File
@@ -377,7 +377,7 @@ export class CodeModule implements CodeService {
// move block to content
$tab.classList.toggle('active', resolvedIndex === index || defaultActiveTab)
$tab.classList.remove('is-collapsed')
$tab.classList.remove('d-none')
$tab.classList.remove('hidden')
$tab.dataset.tabInit = 'true'
$content.appendChild($tab)
})
+1 -1
View File
@@ -35,7 +35,7 @@ export class CoreModule implements CoreService {
/** Toggle the mask element's blur class based on active overlay state. */
syncMaskState() {
document.getElementById('mask')?.classList.toggle('blur', Boolean(this.activeMaskOverlay))
document.getElementById('mask')?.classList.toggle('is-blur', Boolean(this.activeMaskOverlay))
}
/** Open a named mask overlay, closing any previously active one. */
+3 -3
View File
@@ -67,13 +67,13 @@ export class EventsModule implements EventsService {
}
if ($backToTop) {
if (scrollPercent > 1) {
$backToTop.classList.remove('d-none', 'animate__fadeOut')
$backToTop.classList.remove('hidden', 'animate__fadeOut')
animateCSS($backToTop, ['animate__fadeIn'], true)
}
else {
$backToTop.classList.remove('animate__fadeIn')
animateCSS($backToTop, ['animate__fadeOut'], true, () => {
$backToTop.classList.contains('animate__fadeOut') && $backToTop.classList.add('d-none')
$backToTop.classList.contains('animate__fadeOut') && $backToTop.classList.add('hidden')
})
}
$backToTop.style.setProperty('--fi-b2t-progress', scrollPercent.toFixed(2))
@@ -114,7 +114,7 @@ export class EventsModule implements EventsService {
/** Bind mask click to close the active overlay. */
onClickMask() {
document.getElementById('mask')!.addEventListener('click', (e) => {
if (!(e.target as HTMLElement).classList.contains('blur'))
if (!(e.target as HTMLElement).classList.contains('is-blur'))
return
this.core.closeActiveMaskOverlay()
}, false)
+2 -2
View File
@@ -33,7 +33,7 @@ export class MiscModule implements MiscService {
const minutes = Math.floor((totalSeconds % 3600) / 60)
const seconds = totalSeconds % 60
$runTimes.innerHTML = `${days}, ${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`
document.querySelector('.site-time .d-none')?.classList.remove('d-none')
document.querySelector('.site-time .hidden')?.classList.remove('hidden')
}
/** Start the site-time counter with visibility-change pausing. */
@@ -94,7 +94,7 @@ export class MiscModule implements MiscService {
if (document.querySelector('#comments')) {
const $viewCommentsBtn = document.querySelector<HTMLElement>('.view-comments')!
$viewCommentsBtn.classList.remove('d-none')
$viewCommentsBtn.classList.remove('hidden')
$viewCommentsBtn.addEventListener('click', () => {
scrollIntoView('#comments')
}, false)
+3 -3
View File
@@ -181,7 +181,7 @@ export class TocModule implements TocService {
// TOC Drawer Button Visibility
const openButton = document.querySelector<HTMLElement>('#toc-drawer-button')
if (openButton) {
openButton.classList.toggle('d-none', !isTocStatic())
openButton.classList.toggle('hidden', !isTocStatic())
}
this.activeTocId = null
// TOC Static and TOC Dialog
@@ -218,13 +218,13 @@ export class TocModule implements TocService {
const tocHidden = $toc.classList.contains('toc-hidden')
animation.push(tocHidden ? 'animate__fadeIn' : 'animate__fadeOut')
if (tocHidden) {
$tocContentAuto.classList.remove('d-none', 'animate__fadeOut')
$tocContentAuto.classList.remove('hidden', 'animate__fadeOut')
}
else {
$tocContentAuto.classList.remove('animate__fadeIn')
}
animateCSS($tocContentAuto, animation, true, () => {
$tocContentAuto.classList.contains('animate__fadeOut') && $tocContentAuto.classList.add('d-none')
$tocContentAuto.classList.contains('animate__fadeOut') && $tocContentAuto.classList.add('hidden')
})
$toc.classList.toggle('toc-hidden')
}, false)
+1 -82
View File
@@ -3,63 +3,6 @@
/// ==========================================================================
@use "functions" as *;
@use "mixins" as *;
@use "maps" as maps;
.text-truncate {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.text-start {
text-align: left !important;
}
.text-end {
text-align: right !important;
}
.text-center {
text-align: center !important;
}
.d-none {
display: none !important;
}
.ms-1,
.mx-1 {
margin-left: 0.25em !important;
}
.me-1,
.mx-1 {
margin-right: 0.25em !important;
}
.ps-1,
.px-1 {
padding-left: 0.25em !important;
}
.pe-1,
.px-1 {
padding-right: 0.25em !important;
}
@each $color, $value in maps.$theme-colors {
.text-#{$color} {
color: fi-var(#{$color}) !important;
}
}
@each $key, $value in maps.$orders {
.order-#{$key} {
order: #{$value} !important;
}
}
.variant-numeric {
font-variant-numeric: tabular-nums lining-nums;
}
.rounded-full {
@include border-radius(full);
}
.is-fullscreen {
.fa-expand {
@@ -76,34 +19,10 @@
}
}
// print view helper
.page-break-before {
break-before: page;
}
.page-break-after {
break-after: page;
}
@include media('sm', 'up') {
.d-none-desktop {
display: none;
}
}
@include media('xs') {
.d-none-mobile {
display: none !important;
}
}
// print styles
@include media('print') {
@page {
size: A4 portrait;
margin: 1.27cm;
}
.d-none-print {
display: none !important;
}
}
+1 -1
View File
@@ -18,7 +18,7 @@ header {
box-shadow: $header-box-shadow;
}
&.blur {
&.is-blur {
@include scroll-state-query('scroller', 'scroll-state(scrollable: top)', '&') {
background-color: transparent;
backdrop-filter: saturate(1.2) blur(10px);
-1
View File
@@ -2,4 +2,3 @@
@forward 'alert';
@forward 'chroma-lexers';
@forward 'colors';
@forward 'utilities';
-13
View File
@@ -1,13 +0,0 @@
// Utilities
// property order
$orders: (
first: -1,
0: 0,
1: 1,
2: 2,
3: 3,
4: 4,
5: 5,
last: 6,
) !default;
+4 -4
View File
@@ -8,19 +8,19 @@
$breakpoints: (
'xs': (
'min': null,
'max': 680px,
'max': 680.9px,
),
'sm': (
'min': 681px,
'max': 960px,
'max': 960.9px,
),
'md': (
'min': 961px,
'max': 1200px,
'max': 1200.9px,
),
'lg': (
'min': 1201px,
'max': 1440px,
'max': 1440.9px,
),
'xl': (
'min': 1441px,
-6
View File
@@ -1,6 +0,0 @@
#content-404 {
font-size: 1.8rem;
line-height: 3rem;
text-align: center;
translate: 0 30vh;
}
-2
View File
@@ -1,3 +1 @@
@use "shared";
@use "404" as page404;
@use "offline";
-22
View File
@@ -1,22 +0,0 @@
// Offline page styles
#content-offline {
text-align: center;
translate: 0 30vh;
.offline-title {
font-size: 3.6rem;
}
.offline-subtitle {
margin: 0.4rem 0;
font-size: 1rem;
font-weight: normal;
font-style: italic;
line-height: 100%;
color: #57606a;
}
.error-text {
font-size: 1.2rem;
}
}
-6
View File
@@ -23,12 +23,6 @@
line-height: 1;
margin-bottom: 1rem;
color: fi-var(alert-color);
> svg.icon {
width: initial;
height: initial;
margin-right: 0.5rem;
}
}
@each $type, $item in maps.$alert-color-map {
@@ -1,16 +0,0 @@
.single .bilibili {
position: relative;
width: 100%;
height: auto;
aspect-ratio: 16 / 9;
margin: 1rem auto;
text-align: center;
iframe {
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
}
}
@@ -7,8 +7,8 @@
font-size: 0.8rem;
line-height: 1;
margin-block: 0.5rem;
@include border-radius;
transition: box-shadow 0.2s ease;
@include border-radius;
&:hover {
box-shadow: 0 2px 8px light-dark(rgba(0, 0, 0, 0.1), rgba(255, 255, 255, 0.1));
@@ -1,5 +1,4 @@
@use "admonition";
@use "bilibili";
@use "bluesky";
@use "douyin";
@use "cardlink";
@@ -11,4 +10,3 @@
@use "mermaid";
@use "tabs";
@use "timeline";
@use "version";
@@ -1,8 +0,0 @@
.single .version-link {
white-space: nowrap;
img.version {
height: 1.25em;
vertical-align: text-bottom;
}
}
-1
View File
@@ -5,7 +5,6 @@
@use "link-guard";
@use "mask";
@use "search-modal";
@use "noscript-warning";
@use "reading-progress";
@use "scrollbar";
@use "sw-toast";
+1 -1
View File
@@ -10,7 +10,7 @@
height: 100%;
@include z-index(hide);
&.blur {
&.is-blur {
background-color: rgba(0, 0, 0, 0.25);
backdrop-filter: blur(2px);
@include z-index(fixed, -1);
@@ -1,15 +0,0 @@
@use "core/functions" as *;
@use "core/mixins" as *;
.noscript-warning {
background-color: fi-var(danger);
color: white;
font-size: 1rem;
font-weight: bold;
position: fixed;
text-align: center;
left: 0;
bottom: 0;
width: 100%;
@include z-index(fixed);
}
+1
View File
@@ -4,6 +4,7 @@ export default antfu({
typescript: true,
ignores: [
'node_modules/**',
'assets/css/unocss.css',
'assets/lib/**',
'public/**',
'layouts/**/*.json',
+1 -1
View File
@@ -676,7 +676,7 @@ pre = ""
# e.g. "2021-12-18T16:15:22+08:00"
value = ""
# FixIt 0.2.17 | NEW footer lines order, optional values: ["first", 0, 1, 2, 3, 4, 5, "last"]
# FixIt 0.2.17 | NEW footer lines order, optional values: ["first", 0-5, "last"]
[params.footer.order]
powered = 0
copyright = 0
+3 -8
View File
@@ -4,19 +4,14 @@
{{- end -}}
{{- define "content" -}}
<article class="page" id="content-404">
<article class="page text-3xl self-stretch flex flex-col items-center justify-center text-center" id="content-404">
<h1 id="error-emoji"></h1>
<p class="error-text">
{{- T "pageNotFoundText" -}}&nbsp;
<span class="me-2">{{ T "pageNotFoundText" }}</span>
<a href="javascript:void(0);" title="{{ T `back` }}" onclick="window.history.back();">
{{- dict "Class" "fa-regular fa-hand-point-left" | partial "plugin/icon.html" -}}
</a>
</p>
</article>
<script>
(function() {
const emojiArray = ['\\(o_o)/', '(˚Δ˚)b', '(^-^*)', '(≥o≤)', '(^_^)b', '(·_·)','(=\'X\'=)', '(>_<)', '(;-;)'];
document.getElementById('error-emoji').appendChild(document.createTextNode(emojiArray[Math.floor(Math.random() * emojiArray.length)]));
})();
</script>
<script>(() => { const emojiArray = ['\\(o_o)/', '(˚Δ˚)b', '(^-^*)', '(≥o≤)', '(^_^)b', '(·_·)','(=\'X\'=)', '(>_<)', '(;-;)']; document.getElementById('error-emoji').appendChild(document.createTextNode(emojiArray[Math.floor(Math.random() * emojiArray.length)])); })();</script>
{{- end -}}
+2
View File
@@ -92,7 +92,9 @@
{{- end -}}
<span>{{ $title | safeHTML }}</span>
<a href="#{{ .Anchor | safeURL }}" class="heading-mark">
{{- /* @unocss-skip-start */ -}}
<svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg>
{{- /* @unocss-skip-end */ -}}
</a>
</h{{ $markupLevel }}>
{{- /* EOF */ -}}
+3 -3
View File
@@ -61,8 +61,8 @@
<span class="site-time" title='{{ T "footer.siteRunning" }}'>
{{- $siteTimeIcon := printf (cond .Animate "%v animate-icon" "%v") .Icon -}}
{{- dict "Class" $siteTimeIcon | partial "plugin/icon.html" -}}
{{- with .Pre -}}<span class="ms-1 d-none">{{ . }}</span>{{- end -}}
{{- printf `<span class="run-times variant-numeric ms-1">%v</span>` (T "footer.siteRunning") | safeHTML -}}
{{- with .Pre -}}<span class="ms-1 hidden">{{ . }}</span>{{- end -}}
{{- printf `<span class="run-times tabular-nums lining-nums ms-1">%v</span>` (T "footer.siteRunning") | safeHTML -}}
</span>
{{- end -}}
{{- end -}}
@@ -75,7 +75,7 @@
{{- $loading := dict "Class" "fa-solid fa-spinner fa-spin" | partial "plugin/icon.html" -}}
{{- $iconUV := dict "Class" "fa-regular fa-user me-1" | partial "plugin/icon.html" -}}
{{- $iconPV := dict "Class" "fa-regular fa-eye me-1" | partial "plugin/icon.html" -}}
<div class="footer-line visitor{{ with $footerConfig.order.visitor }} order-{{ . }}{{ end }}{{ if not $busuanzi.siteViews }} d-none{{ end }}">
<div class="footer-line visitor{{ with $footerConfig.order.visitor }} order-{{ . }}{{ end }}{{ if not $busuanzi.siteViews }} hidden{{ end }}">
<span id="busuanzi_container_site_uv" title='{{ T "footer.siteUV" }}'>
{{- $iconUV }}<span id="busuanzi_value_site_uv">{{ $loading }}</span>
{{- /* NO_SPACING */ -}}
+4 -1
View File
@@ -10,7 +10,10 @@
{{- $scssVars := partialCached "function/scss-vars.html" . -}}
{{- $fingerprint := .Site.Store.Get "fingerprint" -}}
{{- /* Base CSS (every page) */ -}}
{{- /* UnoCSS utility classes (pre-built) */ -}}
{{- dict "Source" "css/unocss.css" "Minify" hugo.IsProduction "Fingerprint" $fingerprint | partial "plugin/style.html" -}}
{{- /* Main CSS */ -}}
{{- $mainCSS := dict
"Resource" (resources.Get "scss/main.scss")
"ToCSS" (dict "vars" $scssVars)
+2 -2
View File
@@ -2,7 +2,7 @@
{{- $relLangURL := relLangURL "" -}}
{{- /* Desktop header */ -}}
<header class="desktop animate__faster{{ if .Site.Params.header.blur }} blur{{ end }}" id="header-desktop">
<header class="desktop animate__faster{{ if .Site.Params.header.blur }} is-blur{{ end }}" id="header-desktop">
<div class="header-wrapper"{{ if .Site.Params.githubCorner.enable }} data-github-corner="{{ .Site.Params.githubCorner.position }}"{{ end }}>
<div class="header-title">
<a href="{{ $relLangURL }}" title="{{ .Site.Title }}" class="header-title-link">
@@ -151,7 +151,7 @@
</header>
{{- /* Mobile header */ -}}
<header class="mobile animate__faster{{ if .Site.Params.header.blur }} blur{{ end }}" id="header-mobile">
<header class="mobile animate__faster{{ if .Site.Params.header.blur }} is-blur{{ end }}" id="header-mobile">
<div class="header-container">
<div class="header-wrapper">
<div class="header-title">
+8 -8
View File
@@ -6,7 +6,7 @@
<div class="fixed-buttons">
{{- /* back to top button */ -}}
{{- if $backToTop.enable -}}
<button type="button" class="fixed-button back-to-top animate__faster d-none" aria-label="{{ T `baseof.backToTop` }}">
<button type="button" class="fixed-button back-to-top animate__faster hidden" aria-label="{{ T `baseof.backToTop` }}">
{{- dict "Class" "fa-solid fa-arrow-up" | partial "plugin/icon.html" -}}
{{- if $backToTop.scrollpercent -}}
<svg viewBox="0 0 100 100">
@@ -18,13 +18,13 @@
{{- end -}}
{{- /* toc dialog button */ -}}
{{- if .Store.Get "showToc" -}}
<button type="button" id="toc-drawer-button" class="fixed-button toc-drawer-button d-none{{ with $params.password }} encrypted-hidden{{ end }}" aria-label="{{ T `single.contents` }}" aria-controls="toc-dialog" aria-expanded="false">
<button type="button" id="toc-drawer-button" class="fixed-button toc-drawer-button hidden{{ with $params.password }} encrypted-hidden{{ end }}" aria-label="{{ T `single.contents` }}" aria-controls="toc-dialog" aria-expanded="false">
{{- dict "Class" "fa-solid fa-bars" | partial "plugin/icon.html" -}}
</button>
{{- end -}}
{{- /* comment button */ -}}
{{- if $comment.enable -}}
<button type="button" class="fixed-button view-comments d-none" aria-label="{{ T `baseof.viewComments` }}">
<button type="button" class="fixed-button view-comments hidden" aria-label="{{ T `baseof.viewComments` }}">
{{- dict "Class" "fa-solid fa-comment" | partial "plugin/icon.html" -}}
</button>
{{- end -}}
@@ -36,7 +36,7 @@
{{- if $githubCorner.enable -}}
{{- with $githubCorner -}}
{{- $githubImage := `<svg viewBox="0 0 250 250" aria-hidden="true" width="56" height="56"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg>` -}}
{{- $options := dict "Destination" .Permalink "Title" .Title "Content" $githubImage "ExternalIcon" false "Class" (cond (eq .Position "left") "left" "right" | printf "github-corner %v d-none-mobile") "Noreferrer" false -}}
{{- $options := dict "Destination" .Permalink "Title" .Title "Content" $githubImage "ExternalIcon" false "Class" (cond (eq .Position "left") "left" "right" | printf "github-corner %v max-sm:hidden") "Noreferrer" false -}}
{{- partial "plugin/link.html" $options -}}
{{- end -}}
{{- end -}}
@@ -55,12 +55,12 @@
<div class="search-source-footer">
<div class="search-shortcuts">
<span class="search-shortcut">
<kbd>{{ dict "Src" "images/icons/arrow-up.svg" | partial "plugin/icon.html" }}</kbd>
<kbd>{{ dict "Src" "images/icons/arrow-down.svg" | partial "plugin/icon.html" }}</kbd>
<kbd>{{ dict "Class" "lucide-arrow-up" | partial "plugin/icon.html" }}</kbd>
<kbd>{{ dict "Class" "lucide-arrow-down" | partial "plugin/icon.html" }}</kbd>
{{ T "assets.navigate" }}
</span>
<span class="search-shortcut">
<kbd>{{ dict "Src" "images/icons/enter-key.svg" | partial "plugin/icon.html" }}</kbd>
<kbd>{{ dict "Class" "lucide-corner-down-left" | partial "plugin/icon.html" }}</kbd>
{{ T "assets.select" }}
</span>
<span class="search-shortcut">
@@ -147,7 +147,7 @@
{{- end -}}
<noscript>
<div class="noscript-warning">{{ T "baseof.noscript" }}</div>
<div class="noscript-warning bg-danger text-white text-base font-bold fixed text-center inset-x-0 bottom-0 w-full z-fixed">{{ T "baseof.noscript" }}</div>
</noscript>
</div>
{{- /* EOF */ -}}
+1 -1
View File
@@ -42,7 +42,7 @@
{{- with $profile.subtitle -}}
<p class="home-subtitle">
{{- if $profile.typeit -}}
<span class="d-none">{{ . }}</span>
<span class="hidden">{{ . }}</span>
{{- $.Store.Set "hasTyped" true -}}
<span class="typeit"><template>{{ . | safeHTML }}</template></span>
{{- else -}}
+6 -6
View File
@@ -7,11 +7,11 @@
*/ -}}
{{- $iconMap := dict
"note" "images/icons/alerts/info.svg"
"tip" "images/icons/alerts/light-bulb.svg"
"important" "images/icons/alerts/report.svg"
"warning" "images/icons/alerts/alert.svg"
"caution" "images/icons/alerts/stop.svg"
"note" "octicon-info-16 me-2"
"tip" "octicon-light-bulb-16 me-2"
"important" "octicon-report-16 me-2"
"warning" "octicon-alert-16 me-2"
"caution" "octicon-stop-16 me-2"
-}}
{{- $attrs := "" }}
@@ -29,7 +29,7 @@
<div {{ $attrs | safeHTMLAttr }}>
{{- $icon := index $iconMap .Type -}}
<p class="alert-title">
{{- dict "Src" $icon | partial "plugin/icon.html" }}
{{- dict "Class" $icon | partial "plugin/icon.html" }}
{{- or (T (printf "alert.%v" .Type)) (title .Type) -}}
</p>
{{- .Text | safeHTML -}}
@@ -82,7 +82,7 @@
{{- if $isFirst -}}
{{- .Page.Store.Set $groupKey true -}}
{{- else -}}
{{- $targetClass = add $targetClass " d-none" -}}
{{- $targetClass = add $targetClass " hidden" -}}
{{- end -}}
{{- $wrapper =
replace $wrapper
+2
View File
@@ -84,7 +84,9 @@
</span>
</span>
{{- if $ctx.Download -}}
{{- /* @unocss-skip-start */ -}}
<svg class="cl-shortcut-icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" width="64" height="64"><path d="M824.32 473.6c-15.36-2.56-25.6-15.36-25.6-30.72 0-112.64-71.68-217.6-179.2-250.88-148.48-46.08-289.28 38.4-332.8 166.4-2.56 10.24-12.8 17.92-23.04 20.48C143.36 401.92 51.2 509.44 51.2 637.44v2.56c0 115.2 97.28 204.8 209.92 204.8h524.8c102.4-2.56 184.32-84.48 184.32-186.88 2.56-89.6-61.44-163.84-145.92-184.32z m-273.92 225.28c-12.8 12.8-30.72 15.36-46.08 10.24H501.76c-5.12-2.56-10.24-5.12-15.36-10.24L366.08 578.56c-15.36-15.36-15.36-43.52 0-58.88 15.36-15.36 43.52-15.36 58.88 0l51.2 51.2V352.4608c0-23.04 17.92-40.96 40.96-40.96 23.04 0 40.96 17.92 40.96 40.96v218.4192l51.2-51.2c17.92-17.92 43.52-17.92 61.44 0 17.92 15.36 17.92 40.96 0 58.88l-120.32 120.32z" fill="#4FC089"></path></svg>
{{- /* @unocss-skip-end */ -}}
{{- else -}}
{{- with $cardIcon -}}
{{- if (strings.HasPrefix . "fa") -}}
+6 -6
View File
@@ -23,7 +23,7 @@
{{- $href := "" -}}
{{- $integrity := .Integrity -}}
{{- /* Pre-built resource */ -}}
{{- /* Resource (pre-built) */ -}}
{{- with .Resource -}}
{{- $href = .RelPermalink -}}
{{- with .Data.Integrity -}}
@@ -32,11 +32,8 @@
{{- end -}}
{{- /* Source build */ -}}
{{- if not $href -}}
{{- $href = .Source -}}
{{- end -}}
{{- if $href | and (not (urls.Parse $href).Host) | and (not .Resource) -}}
{{- $resource := resources.Get $href -}}
{{- if .Source | and (not .Resource) | and (not (urls.Parse .Source).Host) -}}
{{- $resource := resources.Get .Source -}}
{{- with .Template -}}
{{- $resource = resources.ExecuteAsTemplate . $.Context $resource -}}
{{- end -}}
@@ -56,6 +53,9 @@
{{- $href = $contentResource.RelPermalink -}}
{{- end -}}
{{- /* Fallback to source */ -}}
{{- $href = $href | default .Source -}}
{{- /* Style attributes */ -}}
{{- $attrs := printf `href="%v"` $href -}}
{{- if .Crossorigin -}}
@@ -1,18 +0,0 @@
{{- $params := partial "function/params.html" -}}
{{- if $params.password -}}
{{- $msg := $params.message | default (T "single.encryptedMessage") -}}
{{- $loading := resources.Get "images/loading.svg" | minify -}}
<div class="fixit-decryptor-container">
<img class="fixit-decryptor-loading" src="{{ $loading.RelPermalink }}" alt="decryptor loading" />
<label for="fixit-decryptor-input" title='{{ T "single.password" }}'>
<input type="password" id="fixit-decryptor-input" class="fixit-decryptor-input d-none" placeholder="🔑 {{ $msg }}" />
</label>
<button class="fixit-decryptor-btn d-none">
{{- dict "Class" "fa-solid fa-unlock" | partial "plugin/icon.html" }}{{ T "single.enterBtn" -}}
</button>
<button class="fixit-encryptor-btn d-none">
{{- dict "Class" "fa-solid fa-lock" | partial "plugin/icon.html" }}{{ T "single.encryptyAgain" -}}
</button>
</div>
{{- end -}}
+2 -2
View File
@@ -7,7 +7,7 @@
{{- $danmaku := .Get "danmaku" | default true -}}
{{- $t := .Get "t" | default 0 -}}
<div class="bilibili">
<iframe src="//player.bilibili.com/player.html?bvid={{ $bvid }}&page={{ $p }}&autoplay={{ $autoplay }}&poster={{ $poster }}&muted={{ $muted }}&danmaku={{ $danmaku }}&t={{ $t }}" border="0" framespacing="0" allowfullscreen="true"></iframe>
<div class="bilibili relative w-full aspect-video my-4 mx-auto text-center">
<iframe class="absolute w-full h-full inset-0" src="//player.bilibili.com/player.html?bvid={{ $bvid }}&page={{ $p }}&autoplay={{ $autoplay }}&poster={{ $poster }}&muted={{ $muted }}&danmaku={{ $danmaku }}&t={{ $t }}" border="0" framespacing="0" allowfullscreen="true"></iframe>
</div>
{{- /* EOF */ -}}
+2 -2
View File
@@ -17,7 +17,7 @@
{{- $resource := resources.Get "images/version.template.svg" -}}
{{- $resource = $resource | resources.ExecuteAsTemplate $path (dict "version" $version "label" $label "color" $color "isCJK" $isCJK) | minify -}}
{{- $alt := printf "%v %v | %v" $repoName $version $label -}}
<a href="{{ $url }}" rel="external" target="_blank" class="version-link">
{{- dict "Src" $resource.RelPermalink "Alt" $alt "Class" "version" | partial "plugin/image.html" -}}
<a href="{{ $url }}" rel="external" target="_blank" class="version-link whitespace-nowrap">
{{- dict "Src" $resource.RelPermalink "Alt" $alt "Class" "version h-[1.25em] align-text-bottom" | partial "plugin/image.html" -}}
</a>
{{- /* EOF */ -}}
+7 -10
View File
@@ -4,17 +4,14 @@
{{- end -}}
{{- define "content" -}}
<article class="page" id="content-offline">
<div class="header">
<h1 class="offline-title animate__animated animate__pulse animate__faster">{{- T "offlineTitle" -}}</h1>
<p class="offline-subtitle animate__animated animate__headShake">
<i class="fa-stack fa-xs" aria-hidden="true">
<i class="fa-solid fa-wifi fa-stack-1x" aria-hidden="true"></i>
<i class="fa-solid fa-ban fa-stack-2x" aria-hidden="true"></i>
<article class="page self-stretch flex flex-col items-center justify-center text-center" id="content-offline">
<p class="animate__animated animate__headShake">
<i class="fa-stack fa-4x opacity-50" aria-hidden="true">
<i class="fa-solid fa-wifi fa-stack-1x"></i>
<i class="fa-solid fa-ban fa-stack-2x text-secondary"></i>
</i>
<span>ERROR_INTERNET_DISCONNECTED</span>
</p>
</div>
<p class="error-text">{{- T "offlineText" -}}</p>
<h1 class="offline-title text-5xl text-shadow-md animate__animated animate__pulse animate__infinite">{{- T "offlineTitle" -}}</h1>
<p class="offline-text text-lg">{{- T "offlineText" -}}</p>
</article>
{{- end -}}
+7 -1
View File
@@ -42,11 +42,16 @@
"version": "pnpm -F versioning start prod",
"changelog": "auto-changelog-plus --starting-date 2021-12-18",
"gen:lexers": "pnpm -F chroma-lexers start",
"css:build": "unocss \"layouts/**/*.html\" \"assets/js/**/*.ts\" -o assets/css/unocss.css",
"css:dev": "pnpm css:build --watch",
"prepare": "simple-git-hooks"
},
"devDependencies": {
"@antfu/eslint-config": "^9.0.0",
"@iconify/json": "^2.2.491",
"@iconify/utils": "^3.1.3",
"@types/node": "^25.9.2",
"@unocss/cli": "^66.7.2",
"auto-changelog-plus": "^1.3.0",
"concurrently": "^9.2.1",
"eslint": "^10.4.1",
@@ -55,7 +60,8 @@
"serve": "^14.2.6",
"simple-git-hooks": "^2.13.1",
"tsx": "^4.22.4",
"typescript": "^6.0.3"
"typescript": "^6.0.3",
"unocss": "^66.6.0"
},
"simple-git-hooks": {
"pre-commit": "pnpm -F versioning start dev && pnpm typecheck && pnpm lint-staged"
@@ -82,7 +82,6 @@ export function updateVersion(type: 'dev' | 'prod') {
const toStageFiles: string[] = [
'layouts/_partials/init/index.html',
'package.json',
'package-lock.json',
'pnpm-lock.yaml',
]
toStageFiles.forEach((file) => {
+1163
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -6,5 +6,6 @@ packages:
- apps/*
- packages/*
allowBuilds:
'@parcel/watcher': true
esbuild: true
simple-git-hooks: true
+79
View File
@@ -0,0 +1,79 @@
import { defineConfig, presetIcons, presetWind3 } from 'unocss'
export default defineConfig({
presets: [
presetIcons({
prefix: '',
collections: {
lucide: () => import('@iconify/json/json/lucide.json').then(i => i.default),
octicon: () => import('@iconify/json/json/octicon.json').then(i => i.default),
},
extraProperties: {
'display': 'inline-block',
'vertical-align': 'text-bottom',
},
}),
presetWind3(),
],
theme: {
// FixIt responsive breakpoints (min-width, mobile-first)
// xs (max-width: 680.9px) use max-sm: prefix in UnoCSS
breakpoints: {
sm: '681px',
md: '961px',
lg: '1201px',
xl: '1441px',
},
colors: {
primary: 'var(--fi-primary)',
secondary: 'var(--fi-secondary)',
success: 'var(--fi-success)',
info: 'var(--fi-info)',
warning: 'var(--fi-warning)',
danger: 'var(--fi-danger)',
},
},
// No preflight/reset — FixIt has its own in core/_reboot.scss
preflights: [],
// Semantic z-index shortcuts (mirrors core/mixins/_z-index.scss)
shortcuts: {
'z-hide': 'z--1',
'z-auto': 'z-auto',
'z-base': 'z-1',
'z-loading': 'z-10',
'z-sticky': 'z-100',
'z-fixed': 'z-200',
},
// Block unused or false-positive utilities
blocklist: [
'container',
/^h[1-6]$/,
// Block legacy Font Awesome icons (FA uses CSS font, not SVG)
/^fa-/,
],
// Always generate order utilities (used dynamically in templates)
safelist: [
// For footer lines order, optional values: ["first", 0-5, "last"]
'order-first',
'order-last',
'order-0',
'order-1',
'order-2',
'order-3',
'order-4',
'order-5',
// Responsive visibility
'sm:hidden',
'max-sm:hidden',
// Print page breaks
'break-before-page',
'break-after-page',
],
// Scan Hugo templates for class usage
content: {
filesystem: [
'layouts/**/*.html',
'assets/js/**/*.ts',
],
},
})