mirror of
https://github.com/hugo-fixit/FixIt.git
synced 2026-08-24 07:18:57 +00:00
refactor(assets): simplify breakpoints and update UnoCSS CLI config
- Refactor SCSS breakpoints to flat min-width values (680/960/1200/1440) with _bp-max helper deriving ranges from adjacent breakpoints - Add 'xs': null to breakpoints map, remove special-case handling - Update responsive image sizes to match exact breakpoint max values - Add print:hidden to UnoCSS safelist as replacement for d-none-print - Move UnoCSS CLI config to cli.entry in uno.config.ts - Rename css:build → unocss, css:dev → unocss:watch - Update documentation (CLAUDE.md, CONTRIBUTING.md, copilot-instructions.md)
This commit is contained in:
@@ -22,10 +22,10 @@ This document defines the detailed coding standards for the FixIt theme project.
|
||||
|
||||
- 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)
|
||||
- Responsive: `sm:` (>=680px), `md:` (>=960px), `lg:` (>=1200px), `xl:` (>=1440px). Use `max-sm:` for xs (<680px)
|
||||
- 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
|
||||
- Run `pnpm unocss` after modifying `uno.config.ts` or templates that use UnoCSS classes
|
||||
|
||||
## TypeScript Coding Standards
|
||||
|
||||
|
||||
@@ -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). UnoCSS utility classes are pre-built to `assets/css/unocss.css` (via `pnpm css:build`), loaded before the main SCSS bundle.
|
||||
- **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 unocss`), 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`.
|
||||
|
||||
@@ -112,10 +112,10 @@ Hugo Pipes processes all assets. The key orchestration is in `_partials/base/ass
|
||||
|
||||
### UnoCSS (`assets/css/unocss.css`)
|
||||
|
||||
- Pre-built utility classes generated by `pnpm css:build` (config: `uno.config.ts`)
|
||||
- Pre-built utility classes generated by `pnpm unocss` (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)
|
||||
- Responsive breakpoints: `sm:` (>=680px), `md:` (>=960px), `lg:` (>=1200px), `xl:` (>=1440px). Use `max-sm:` for xs (<680px)
|
||||
- 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`)
|
||||
|
||||
|
||||
+2
-2
@@ -82,9 +82,9 @@ pnpm gen:lexers
|
||||
pnpm preview
|
||||
|
||||
# Build UnoCSS utility classes (pre-built, committed to repo)
|
||||
pnpm css:build
|
||||
pnpm unocss
|
||||
# Watch mode for UnoCSS (for theme developers)
|
||||
pnpm css:dev
|
||||
pnpm unocss:watch
|
||||
```
|
||||
|
||||
> [!TIP]
|
||||
|
||||
@@ -82,9 +82,12 @@
|
||||
.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){
|
||||
@media print{
|
||||
.print\:hidden{display:none;}
|
||||
}
|
||||
@media (max-width: 679.9px){
|
||||
.max-sm\:hidden{display:none;}
|
||||
}
|
||||
@media (min-width: 681px){
|
||||
@media (min-width: 680px){
|
||||
.sm\:hidden{display:none;}
|
||||
}
|
||||
@@ -1,45 +1,48 @@
|
||||
// Responsive breakpoints matching the project's media query design
|
||||
// ┌──────────────────────────────────────────────────────┐
|
||||
// │ xs │ sm │ md │ lg │ xl │
|
||||
// │ ≤680 │ 681–960 │ 961–1200 │ 1201–1440 │ ≥1441 │
|
||||
// └──────────────────────────────────────────────────────┘
|
||||
// FixIt Responsive breakpoints system design
|
||||
// ┌──────┬───────────┬───────────┬──────────────┐
|
||||
// │ Name │ min-width │ max-width │ Direction │
|
||||
// ├──────┼───────────┼───────────┼──────────────┤
|
||||
// │ xs │ (null) │ 679.9px │ only │
|
||||
// │ sm │ 680px │ 959.9px │ only/up/down │
|
||||
// │ md │ 960px │ 1199.9px │ only/down │
|
||||
// │ lg │ 1200px │ 1439.9px │ only/up │
|
||||
// │ xl │ 1440px │ (null) │ only │
|
||||
// └──────┴───────────┴───────────┴──────────────┘
|
||||
@use "sass:map";
|
||||
@use "sass:list";
|
||||
|
||||
$breakpoints: (
|
||||
'xs': (
|
||||
'min': null,
|
||||
'max': 680.9px,
|
||||
),
|
||||
'sm': (
|
||||
'min': 681px,
|
||||
'max': 960.9px,
|
||||
),
|
||||
'md': (
|
||||
'min': 961px,
|
||||
'max': 1200.9px,
|
||||
),
|
||||
'lg': (
|
||||
'min': 1201px,
|
||||
'max': 1440.9px,
|
||||
),
|
||||
'xl': (
|
||||
'min': 1441px,
|
||||
'max': null,
|
||||
),
|
||||
'xs': null,
|
||||
'sm': 680px,
|
||||
'md': 960px,
|
||||
'lg': 1200px,
|
||||
'xl': 1440px,
|
||||
) !default;
|
||||
|
||||
/// Get the max-width for a breakpoint (0.1px below the next breakpoint).
|
||||
@function _bp-max($name) {
|
||||
// Ordered list of breakpoint names for range derivation
|
||||
$keys: map.keys($breakpoints);
|
||||
$idx: list.index($keys, $name);
|
||||
@if $idx == null or $idx >= list.length($keys) {
|
||||
@return null;
|
||||
}
|
||||
$next: list.nth($keys, $idx + 1);
|
||||
@return map.get($breakpoints, $next) - 0.1px;
|
||||
}
|
||||
|
||||
/// Apply styles within a named media target.
|
||||
/// @param {String} $target - Target name: xs | sm | md | lg | xl | print | reduce-motion
|
||||
/// @param {String} $direction - Range direction: only | up | down [default: only]
|
||||
///
|
||||
/// @example
|
||||
/// // xs: ≤ 680px
|
||||
/// // xs: < 680px
|
||||
/// @include media('xs') { ... }
|
||||
/// // sm: 681px – 960px
|
||||
/// // sm: 680px – 959.9px
|
||||
/// @include media('sm') { ... }
|
||||
/// // md and above: ≥ 961px
|
||||
/// // md and above: ≥ 960px
|
||||
/// @include media('md', 'up') { ... }
|
||||
/// // lg and below: ≤ 1440px
|
||||
/// // lg and below: ≤ 1199.9px
|
||||
/// @include media('lg', 'down') { ... }
|
||||
/// // print media
|
||||
/// @include media('print') { ... }
|
||||
@@ -54,21 +57,13 @@ $breakpoints: (
|
||||
@media screen and (prefers-reduced-motion: reduce) {
|
||||
@content;
|
||||
}
|
||||
} @else {
|
||||
$range: map.get($breakpoints, $target);
|
||||
$min: null;
|
||||
$max: null;
|
||||
} @else if map.has-key($breakpoints, $target) {
|
||||
$min: map.get($breakpoints, $target);
|
||||
$max: _bp-max($target);
|
||||
|
||||
@if $range != null {
|
||||
$min: map.get($range, 'min');
|
||||
$max: map.get($range, 'max');
|
||||
}
|
||||
|
||||
@if $range == null {
|
||||
@warn "Unknown media target `#{$target}`. Expected: xs, sm, md, lg, xl, print, reduce-motion.";
|
||||
} @else if $direction == 'only' {
|
||||
@if $direction == 'only' {
|
||||
@if $min == null {
|
||||
// xs: max-width only, no lower bound
|
||||
// xs: max-width only
|
||||
@media only screen and (max-width: $max) {
|
||||
@content;
|
||||
}
|
||||
@@ -84,7 +79,7 @@ $breakpoints: (
|
||||
}
|
||||
} @else if $direction == 'up' {
|
||||
@if $min == null {
|
||||
// xs-up: no lower bound, always applies
|
||||
// xs-up: always applies
|
||||
@content;
|
||||
} @else {
|
||||
@media only screen and (min-width: $min) {
|
||||
@@ -93,7 +88,7 @@ $breakpoints: (
|
||||
}
|
||||
} @else if $direction == 'down' {
|
||||
@if $max == null {
|
||||
// xl-down: no upper bound, always applies
|
||||
// xl-down: always applies
|
||||
@content;
|
||||
} @else {
|
||||
@media only screen and (max-width: $max) {
|
||||
@@ -103,5 +98,7 @@ $breakpoints: (
|
||||
} @else {
|
||||
@warn "Unknown direction `#{$direction}`. Expected: only, up, down.";
|
||||
}
|
||||
} @else {
|
||||
@warn "Unknown media target `#{$target}`. Expected: xs, sm, md, lg, xl, print, reduce-motion.";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{{- hugo.Store.Set "version" "v1.0.0-mqt0ysyp" -}}
|
||||
{{- hugo.Store.Set "version" "v1.0.0-mqw3lkj1" -}}
|
||||
{{- .Store.Set "this" dict -}}
|
||||
|
||||
{{- partial "init/detection-env.html" . -}}
|
||||
|
||||
@@ -151,7 +151,7 @@
|
||||
(dict "Process" "resize 1200x webp" "descriptor" "1200w")
|
||||
(dict "Process" "resize 1600x webp" "descriptor" "1600w")
|
||||
-}}
|
||||
{{- dict "Src" $image "Title" $.Description "Resources" .Resources "Matches" $matches "Loading" "eager" "Sizes" "(max-width: 680px) 100vw, (max-width: 960px) 80vw, (max-width: 1440px) 56vw, 800px" "OptimConfig" $optim | partial "plugin/image.html" -}}
|
||||
{{- dict "Src" $image "Title" $.Description "Resources" .Resources "Matches" $matches "Loading" "eager" "Sizes" "(max-width: 679.9px) 100vw, (max-width: 959.9px) 80vw, (max-width: 1439.9px) 56vw, 800px" "OptimConfig" $optim | partial "plugin/image.html" -}}
|
||||
</div>
|
||||
{{- end -}}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
(dict "Process" "fill 1200x504 Center webp" "descriptor" "1200w")
|
||||
(dict "Process" "fill 1600x672 Center webp" "descriptor" "1600w")
|
||||
-}}
|
||||
{{- dict "Src" $image "Title" $.Title "Resources" $.Resources "Matches" $matches "Loading" "eager" "Width" "800" "Height" "336" "Sizes" "(max-width: 680px) 100vw, (max-width: 960px) 80vw, (max-width: 1440px) 56vw, 800px" "OptimConfig" $optim "Alt" (printf "Featured image for %v" $.Title) | partial "plugin/image.html" -}}
|
||||
{{- dict "Src" $image "Title" $.Title "Resources" $.Resources "Matches" $matches "Loading" "eager" "Width" "800" "Height" "336" "Sizes" "(max-width: 679.9px) 100vw, (max-width: 959.9px) 80vw, (max-width: 1439.9px) 56vw, 800px" "OptimConfig" $optim "Alt" (printf "Featured image for %v" $.Title) | partial "plugin/image.html" -}}
|
||||
</a>
|
||||
</div>
|
||||
{{- end -}}
|
||||
|
||||
+2
-2
@@ -42,8 +42,8 @@
|
||||
"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",
|
||||
"unocss": "unocss",
|
||||
"unocss:watch": "unocss --watch",
|
||||
"prepare": "simple-git-hooks"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
+15
-5
@@ -17,12 +17,12 @@ export default defineConfig({
|
||||
],
|
||||
theme: {
|
||||
// FixIt responsive breakpoints (min-width, mobile-first)
|
||||
// xs (max-width: 680.9px) use max-sm: prefix in UnoCSS
|
||||
// xs (< 680px) use max-sm: prefix in UnoCSS
|
||||
breakpoints: {
|
||||
sm: '681px',
|
||||
md: '961px',
|
||||
lg: '1201px',
|
||||
xl: '1441px',
|
||||
sm: '680px',
|
||||
md: '960px',
|
||||
lg: '1200px',
|
||||
xl: '1440px',
|
||||
},
|
||||
colors: {
|
||||
primary: 'var(--fi-primary)',
|
||||
@@ -65,6 +65,7 @@ export default defineConfig({
|
||||
// Responsive visibility
|
||||
'sm:hidden',
|
||||
'max-sm:hidden',
|
||||
'print:hidden',
|
||||
// Print page breaks
|
||||
'break-before-page',
|
||||
'break-after-page',
|
||||
@@ -76,4 +77,13 @@ export default defineConfig({
|
||||
'assets/js/**/*.ts',
|
||||
],
|
||||
},
|
||||
// CLI entry for unocss / unocss:watch
|
||||
cli: {
|
||||
entry: [
|
||||
{
|
||||
patterns: ['layouts/**/*.html', 'assets/js/**/*.ts'],
|
||||
outFile: 'assets/css/unocss.css',
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user