This commit is contained in:
2026-04-29 19:04:20 +08:00
parent df60e8dd42
commit 07d11a15af
58 changed files with 3937 additions and 520 deletions
+27
View File
@@ -0,0 +1,27 @@
// =============================================================================
// abstracts/_functions.scss
// Pure SCSS helper functions.
// =============================================================================
// Convert px value to rem.
@function rem($px, $base: 16) {
@return #{$px / $base}rem;
}
// Strip units from a value.
@function strip-unit($value) {
@return $value / ($value * 0 + 1);
}
// Fluid type scale using clamp().
// Usage: font-size: fluid-type(16px, 24px);
@function fluid-type($min-size, $max-size, $min-vw: 375px, $max-vw: 1280px) {
$min-rem: rem(strip-unit($min-size));
$max-rem: rem(strip-unit($max-size));
@return clamp(
#{$min-rem},
calc(#{$min-rem} + (#{strip-unit($max-size)} - #{strip-unit($min-size)}) * ((100vw - #{$min-vw}) / (#{strip-unit($max-vw)} - #{strip-unit($min-vw)}))),
#{$max-rem}
);
}
+100
View File
@@ -0,0 +1,100 @@
// =============================================================================
// abstracts/_mixins.scss
// Responsive helpers and reusable patterns.
// =============================================================================
// Bulma-matching breakpoint mixins.
@mixin mobile {
@media screen and (max-width: 768px) { @content; }
}
@mixin tablet {
@media screen and (min-width: 769px) { @content; }
}
@mixin tablet-only {
@media screen and (min-width: 769px) and (max-width: 1023px) { @content; }
}
@mixin desktop {
@media screen and (min-width: 1024px) { @content; }
}
@mixin widescreen {
@media screen and (min-width: 1216px) { @content; }
}
// Truncate text to N lines using -webkit-line-clamp.
@mixin line-clamp($lines: 2) {
display: -webkit-box;
-webkit-line-clamp: $lines;
-webkit-box-orient: vertical;
overflow: hidden;
}
// Visually hidden (accessible).
@mixin visually-hidden {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
// Aspect-ratio box.
@mixin aspect-ratio($w, $h) {
position: relative;
&::before {
content: '';
display: block;
padding-top: percentage($h / $w);
}
> * {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
object-fit: cover;
}
}
// Focus visible ring (WCAG 2.1).
@mixin focus-ring($color: var(--color-primary)) {
&:focus-visible {
outline: 3px solid $color;
outline-offset: 2px;
}
}
// Card elevation with hover lift.
@mixin card-lift {
transition: transform var(--transition-base), box-shadow var(--transition-base);
&:hover {
transform: translateY(-4px);
box-shadow: var(--card-shadow-hover);
}
}
// Skeleton loading shimmer.
@mixin skeleton-shimmer {
background: linear-gradient(
90deg,
var(--color-surface) 25%,
rgba(255, 255, 255, 0.5) 50%,
var(--color-surface) 75%
);
background-size: 200% 100%;
animation: skeleton-shimmer 1.5s infinite;
}
@keyframes skeleton-shimmer {
0% { background-position: 200% 0; }
100% { background-position: -200% 0; }
}
+79
View File
@@ -0,0 +1,79 @@
// =============================================================================
// abstracts/_variables.scss
// CSS Custom Properties + SCSS variables for the 7-1 architecture.
// Bulma 1.x is built on CSS variables, so we map our design tokens here.
// =============================================================================
// --- Colour tokens -----------------------------------------------------------
:root {
--color-primary: #00d1b2;
--color-primary-dark: #00a896;
--color-dark: #363636;
--color-light: #f5f5f5;
--color-white: #ffffff;
--color-danger: #f14668;
--color-warning: #ffe08a;
--color-info: #3e8ed0;
--color-success: #48c78e;
// Semantic surface tokens (flipped in dark mode).
--color-background: #ffffff;
--color-text: #363636;
--color-surface: #f5f5f5;
--color-border: #dbdbdb;
--color-shadow: rgba(0, 0, 0, 0.1);
// Navbar
--navbar-bg: rgba(255, 255, 255, 0.85);
--navbar-shadow: 0 1px 3px rgba(0, 0, 0, 0.08), 0 1px 2px rgba(0, 0, 0, 0.04);
// Card
--card-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
--card-shadow-hover: 0 8px 24px rgba(0, 0, 0, 0.14);
--card-radius: 8px;
// Typography
--font-family-base: 'Noto Sans SC', system-ui, -apple-system, sans-serif;
--font-size-base: 1rem;
--line-height-base: 1.7;
// Spacing scale (mirrors theme.json)
--space-1: 0.25rem;
--space-2: 0.5rem;
--space-3: 1rem;
--space-4: 1.5rem;
--space-5: 2rem;
--space-6: 3rem;
--space-7: 4.5rem;
// Breakpoints (Bulma defaults)
--bp-mobile: 768px;
--bp-tablet: 769px;
--bp-desktop: 1024px;
--bp-widescreen: 1216px;
// Transitions
--transition-base: 0.3s ease;
}
// Dark mode overrides via data-attribute or media query.
[data-theme='dark'],
@media (prefers-color-scheme: dark) {
:root {
--color-background: #1a1a2e;
--color-text: #e0e0e0;
--color-surface: #16213e;
--color-border: #444444;
--color-shadow: rgba(0, 0, 0, 0.4);
--navbar-bg: rgba(26, 26, 46, 0.9);
--card-shadow: 0 2px 8px rgba(0, 0, 0, 0.4);
--card-shadow-hover:0 8px 24px rgba(0, 0, 0, 0.5);
}
}
// SCSS-only convenience aliases (not emitted as CSS).
$primary: #00d1b2 !default;
$primary-dark: #00a896 !default;
$dark: #363636 !default;
$font-base: var(--font-family-base);
$transition: var(--transition-base);