update
This commit is contained in:
@@ -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}
|
||||
);
|
||||
}
|
||||
@@ -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; }
|
||||
}
|
||||
@@ -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);
|
||||
@@ -0,0 +1,56 @@
|
||||
// =============================================================================
|
||||
// base/_reset.scss
|
||||
// Minimal modern reset on top of Bulma's built-in normalisation.
|
||||
// =============================================================================
|
||||
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
text-size-adjust: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--color-background);
|
||||
color: var(--color-text);
|
||||
font-family: var(--font-family-base);
|
||||
font-size: var(--font-size-base);
|
||||
line-height: var(--line-height-base);
|
||||
transition:
|
||||
background-color var(--transition-base),
|
||||
color var(--transition-base);
|
||||
}
|
||||
|
||||
img,
|
||||
video,
|
||||
svg {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--color-primary);
|
||||
text-underline-offset: 0.2em;
|
||||
|
||||
&:hover {
|
||||
color: var(--color-primary-dark);
|
||||
}
|
||||
|
||||
@include focus-ring;
|
||||
}
|
||||
|
||||
button {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
// Remove default list style for navigation lists.
|
||||
nav ul,
|
||||
nav ol {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
// =============================================================================
|
||||
// base/_typography.scss
|
||||
// =============================================================================
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
line-height: 1.3;
|
||||
font-weight: 700;
|
||||
color: var(--color-dark);
|
||||
}
|
||||
|
||||
p {
|
||||
margin-bottom: var(--space-3);
|
||||
}
|
||||
|
||||
code,
|
||||
pre {
|
||||
font-family: 'JetBrains Mono', 'Fira Code', 'Courier New', monospace;
|
||||
font-size: 0.875em;
|
||||
}
|
||||
|
||||
pre {
|
||||
overflow-x: auto;
|
||||
padding: var(--space-3);
|
||||
background: var(--color-surface);
|
||||
border-radius: var(--card-radius);
|
||||
border-left: 4px solid var(--color-primary);
|
||||
|
||||
code {
|
||||
background: transparent;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
blockquote {
|
||||
border-left: 4px solid var(--color-primary);
|
||||
padding-left: var(--space-3);
|
||||
margin-left: 0;
|
||||
color: #6b7280;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.screen-reader-text {
|
||||
@include visually-hidden;
|
||||
|
||||
&:focus {
|
||||
background-color: var(--color-background);
|
||||
clip: auto;
|
||||
height: auto;
|
||||
left: var(--space-3);
|
||||
top: var(--space-3);
|
||||
width: auto;
|
||||
z-index: 100000;
|
||||
padding: var(--space-2) var(--space-3);
|
||||
border: 2px solid var(--color-primary);
|
||||
border-radius: 4px;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
// =============================================================================
|
||||
// components/_button.scss
|
||||
// =============================================================================
|
||||
|
||||
// Extend Bulma's .button with our colour tokens.
|
||||
.button.is-primary {
|
||||
background-color: var(--color-primary);
|
||||
border-color: transparent;
|
||||
color: #fff;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--color-primary-dark);
|
||||
}
|
||||
}
|
||||
|
||||
// Copy-code button on code blocks.
|
||||
.copy-code-btn {
|
||||
position: absolute;
|
||||
top: 0.5rem;
|
||||
right: 0.5rem;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
border-radius: 4px;
|
||||
color: #e0e0e0;
|
||||
font-size: 0.75rem;
|
||||
padding: 0.2rem 0.5rem;
|
||||
cursor: pointer;
|
||||
transition: background var(--transition-base);
|
||||
|
||||
&:hover {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
&.is-copied {
|
||||
color: var(--color-success);
|
||||
border-color: var(--color-success);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
// =============================================================================
|
||||
// components/_card.scss
|
||||
// Post card component.
|
||||
// =============================================================================
|
||||
|
||||
.post-card {
|
||||
border-radius: var(--card-radius);
|
||||
overflow: hidden;
|
||||
background: var(--color-background);
|
||||
border: 1px solid var(--color-border);
|
||||
box-shadow: var(--card-shadow);
|
||||
margin-bottom: var(--space-4);
|
||||
transition:
|
||||
transform var(--transition-base),
|
||||
box-shadow var(--transition-base);
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-4px);
|
||||
box-shadow: var(--card-shadow-hover);
|
||||
}
|
||||
|
||||
// Featured image wrapper.
|
||||
&__image {
|
||||
overflow: hidden;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
transition: transform 0.5s ease;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover &__image img {
|
||||
transform: scale(1.03);
|
||||
}
|
||||
|
||||
// Gradient placeholder when no featured image.
|
||||
&__gradient-placeholder {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(135deg, var(--color-primary), var(--color-info));
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
&__category-initial {
|
||||
font-size: 2.5rem;
|
||||
font-weight: 700;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
// Categories.
|
||||
&__categories {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--space-1);
|
||||
margin-bottom: var(--space-2);
|
||||
}
|
||||
|
||||
&__category-badge {
|
||||
font-size: 0.75rem;
|
||||
text-decoration: none;
|
||||
border-radius: 4px;
|
||||
transition: opacity var(--transition-base);
|
||||
|
||||
&:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
|
||||
// Title.
|
||||
&__title {
|
||||
margin-bottom: var(--space-2) !important;
|
||||
|
||||
a {
|
||||
color: var(--color-text);
|
||||
text-decoration: none;
|
||||
transition: color var(--transition-base);
|
||||
|
||||
&:hover {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Meta row.
|
||||
&__meta {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--space-3);
|
||||
color: #6b7280;
|
||||
font-size: 0.85rem;
|
||||
margin-bottom: var(--space-3) !important;
|
||||
|
||||
a {
|
||||
color: #6b7280;
|
||||
|
||||
&:hover {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
}
|
||||
|
||||
i {
|
||||
margin-right: 0.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
// Footer row.
|
||||
&__footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--space-2);
|
||||
margin-top: var(--space-3);
|
||||
}
|
||||
|
||||
// "Continue reading" button arrow animation.
|
||||
&__read-more {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
text-decoration: none;
|
||||
transition:
|
||||
background-color var(--transition-base),
|
||||
color var(--transition-base);
|
||||
}
|
||||
|
||||
&__read-more-arrow {
|
||||
display: inline-block;
|
||||
transition: transform var(--transition-base);
|
||||
}
|
||||
|
||||
&__read-more:hover &__read-more-arrow {
|
||||
transform: translateX(4px);
|
||||
}
|
||||
|
||||
// Hero variant (sticky posts).
|
||||
&--hero {
|
||||
.post-card__image {
|
||||
max-height: 400px;
|
||||
}
|
||||
|
||||
.post-card__title {
|
||||
font-size: 1.75rem;
|
||||
}
|
||||
}
|
||||
|
||||
// Skeleton loading state.
|
||||
&--loading {
|
||||
pointer-events: none;
|
||||
|
||||
.post-card__image,
|
||||
.post-card__title,
|
||||
.post-card__meta,
|
||||
.post-card__content {
|
||||
border-radius: 4px;
|
||||
@include skeleton-shimmer;
|
||||
color: transparent;
|
||||
}
|
||||
|
||||
.post-card__image {
|
||||
height: 180px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
// =============================================================================
|
||||
// components/_navigation.scss
|
||||
// Bulma navbar customisation + mobile dropdown corrections.
|
||||
// =============================================================================
|
||||
|
||||
// Navbar item links.
|
||||
.navbar-item,
|
||||
.navbar-link {
|
||||
color: var(--color-text);
|
||||
transition: color var(--transition-base), background-color var(--transition-base);
|
||||
|
||||
&:hover,
|
||||
&:focus-visible {
|
||||
background-color: transparent;
|
||||
color: var(--color-primary);
|
||||
}
|
||||
}
|
||||
|
||||
// Dropdown.
|
||||
.navbar-dropdown {
|
||||
background: var(--color-background);
|
||||
border: 1px solid var(--color-border);
|
||||
border-top: none;
|
||||
border-radius: 0 0 8px 8px;
|
||||
box-shadow: var(--card-shadow);
|
||||
|
||||
.navbar-item {
|
||||
padding: 0.5rem 1rem;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--color-surface);
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-divider {
|
||||
background-color: var(--color-border);
|
||||
}
|
||||
}
|
||||
|
||||
// Breadcrumb.
|
||||
.breadcrumb {
|
||||
margin: var(--space-3) 0;
|
||||
font-size: 0.9rem;
|
||||
|
||||
a {
|
||||
color: var(--color-text);
|
||||
text-decoration: none;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
transition: color var(--transition-base);
|
||||
|
||||
&:hover {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
}
|
||||
|
||||
li.is-active a {
|
||||
color: #6b7280;
|
||||
}
|
||||
}
|
||||
|
||||
// Post navigation.
|
||||
.nav-links {
|
||||
.nav-previous,
|
||||
.nav-next {
|
||||
a {
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
text-decoration: none;
|
||||
max-width: 300px;
|
||||
color: var(--color-text);
|
||||
transition: color var(--transition-base);
|
||||
|
||||
&:hover {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.nav-subtitle {
|
||||
font-size: 0.8rem;
|
||||
color: #6b7280;
|
||||
}
|
||||
|
||||
.nav-title {
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
// =============================================================================
|
||||
// components/_toc.scss
|
||||
// Article Table of Contents sidebar widget.
|
||||
// =============================================================================
|
||||
|
||||
.toc {
|
||||
background: var(--color-background);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--card-radius);
|
||||
position: sticky;
|
||||
top: 80px;
|
||||
max-height: calc(100vh - 120px);
|
||||
overflow-y: auto;
|
||||
scrollbar-width: thin;
|
||||
|
||||
.card-header {
|
||||
background: transparent;
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
}
|
||||
|
||||
.card-header-title {
|
||||
font-size: 0.9rem;
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.card-content {
|
||||
padding: var(--space-2);
|
||||
}
|
||||
}
|
||||
|
||||
#toc-list {
|
||||
ol {
|
||||
list-style: decimal;
|
||||
padding-left: var(--space-4);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
li {
|
||||
margin-bottom: var(--space-2);
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--color-text);
|
||||
text-decoration: none;
|
||||
line-height: 1.4;
|
||||
transition: color var(--transition-base);
|
||||
display: block;
|
||||
|
||||
&:hover,
|
||||
&.toc-active {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
&.toc-active {
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
// Second-level (h3).
|
||||
.toc-level-3 {
|
||||
padding-left: var(--space-3);
|
||||
list-style: disc;
|
||||
color: #6b7280;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
// =============================================================================
|
||||
// layout/_footer.scss
|
||||
// =============================================================================
|
||||
|
||||
.site-footer {
|
||||
margin-top: var(--space-6);
|
||||
background-color: var(--color-surface);
|
||||
border-top: 1px solid var(--color-border);
|
||||
padding-top: var(--space-5);
|
||||
}
|
||||
|
||||
.footer-site-name {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 700;
|
||||
margin-bottom: var(--space-2);
|
||||
|
||||
a {
|
||||
color: var(--color-text);
|
||||
text-decoration: none;
|
||||
|
||||
&:hover {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.footer-site-description {
|
||||
color: #6b7280;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.5;
|
||||
margin-bottom: var(--space-3);
|
||||
}
|
||||
|
||||
.footer-menu-list {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
li {
|
||||
margin-bottom: var(--space-2);
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--color-text);
|
||||
text-decoration: none;
|
||||
transition: color var(--transition-base);
|
||||
|
||||
&:hover {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.social-menu-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--space-2);
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
a {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 2.25rem;
|
||||
height: 2.25rem;
|
||||
border-radius: 50%;
|
||||
background-color: var(--color-border);
|
||||
color: var(--color-text);
|
||||
transition:
|
||||
background-color var(--transition-base),
|
||||
color var(--transition-base);
|
||||
|
||||
&:hover {
|
||||
background-color: var(--color-primary);
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.footer-widget-title {
|
||||
font-size: 1rem;
|
||||
font-weight: 700;
|
||||
margin-bottom: var(--space-3);
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.footer-bottom {
|
||||
margin-top: var(--space-5);
|
||||
padding: var(--space-3) 0;
|
||||
border-top: 1px solid var(--color-border);
|
||||
}
|
||||
|
||||
.footer-copyright {
|
||||
color: #6b7280;
|
||||
font-size: 0.875rem;
|
||||
|
||||
a {
|
||||
color: var(--color-text);
|
||||
|
||||
&:hover {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
// =============================================================================
|
||||
// layout/_grid.scss
|
||||
// Site-wide layout helpers.
|
||||
// =============================================================================
|
||||
|
||||
.site-content {
|
||||
padding-top: var(--space-4);
|
||||
padding-bottom: var(--space-6);
|
||||
}
|
||||
|
||||
// Primary content area + sidebar layout.
|
||||
.content-area {
|
||||
@include desktop {
|
||||
display: flex;
|
||||
gap: var(--space-5);
|
||||
|
||||
#main {
|
||||
flex: 1;
|
||||
min-width: 0; // Prevent flex blowout.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Responsive post grid.
|
||||
.posts-grid {
|
||||
margin-bottom: var(--space-4);
|
||||
}
|
||||
|
||||
// Pagination.
|
||||
.posts-pagination {
|
||||
margin-top: var(--space-4);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
.nav-links {
|
||||
display: flex;
|
||||
gap: var(--space-2);
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
a,
|
||||
span {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 2.25rem;
|
||||
height: 2.25rem;
|
||||
padding: 0 var(--space-2);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: 6px;
|
||||
color: var(--color-text);
|
||||
text-decoration: none;
|
||||
transition:
|
||||
background-color var(--transition-base),
|
||||
color var(--transition-base),
|
||||
border-color var(--transition-base);
|
||||
|
||||
&:hover,
|
||||
&.current {
|
||||
background-color: var(--color-primary);
|
||||
color: #fff;
|
||||
border-color: var(--color-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
// =============================================================================
|
||||
// layout/_header.scss
|
||||
// =============================================================================
|
||||
|
||||
.site-navbar {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 100;
|
||||
background-color: var(--navbar-bg);
|
||||
box-shadow: var(--navbar-shadow);
|
||||
backdrop-filter: blur(10px);
|
||||
-webkit-backdrop-filter: blur(10px);
|
||||
transition: box-shadow var(--transition-base), background-color var(--transition-base);
|
||||
|
||||
&.is-scrolled {
|
||||
box-shadow: 0 4px 12px var(--color-shadow);
|
||||
}
|
||||
}
|
||||
|
||||
// Logo area.
|
||||
.navbar-logo {
|
||||
padding: 0.5rem 0.75rem;
|
||||
|
||||
img {
|
||||
max-height: 2.5rem;
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-site-name {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
font-weight: 700;
|
||||
color: var(--color-dark) !important;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.site-title-initial {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
border-radius: 50%;
|
||||
background-color: var(--color-primary);
|
||||
color: #fff;
|
||||
font-weight: 700;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
// Hamburger burger – three-line → X animation.
|
||||
.navbar-burger {
|
||||
background: transparent;
|
||||
border: none;
|
||||
padding: 0.5rem;
|
||||
transition: opacity var(--transition-base);
|
||||
|
||||
span {
|
||||
display: block;
|
||||
width: 1.25rem;
|
||||
height: 2px;
|
||||
background: var(--color-text);
|
||||
margin: 4px 0;
|
||||
transition:
|
||||
transform 0.3s ease,
|
||||
opacity 0.3s ease;
|
||||
transform-origin: center;
|
||||
}
|
||||
|
||||
&.is-active span:nth-child(1) { transform: translateY(6px) rotate(45deg); }
|
||||
&.is-active span:nth-child(2) { opacity: 0; }
|
||||
&.is-active span:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }
|
||||
}
|
||||
|
||||
// Search widget.
|
||||
.navbar-search-wrap {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.navbar-search-toggle {
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: var(--color-text);
|
||||
font-size: 1rem;
|
||||
padding: 0.25rem 0.5rem;
|
||||
transition: color var(--transition-base);
|
||||
|
||||
&:hover {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
@include focus-ring;
|
||||
}
|
||||
|
||||
.navbar-search-form {
|
||||
position: absolute;
|
||||
top: 110%;
|
||||
right: 0;
|
||||
background: var(--color-background);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: 6px;
|
||||
padding: 0.5rem;
|
||||
box-shadow: var(--card-shadow);
|
||||
min-width: 200px;
|
||||
|
||||
.input {
|
||||
border-color: var(--color-border);
|
||||
background: var(--color-background);
|
||||
color: var(--color-text);
|
||||
}
|
||||
}
|
||||
|
||||
// Dark-mode toggle.
|
||||
.theme-toggle {
|
||||
background: transparent;
|
||||
border: none;
|
||||
font-size: 1rem;
|
||||
color: var(--color-text);
|
||||
padding: 0.25rem 0.5rem;
|
||||
transition: color var(--transition-base);
|
||||
line-height: 1;
|
||||
|
||||
&:hover {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
@include focus-ring;
|
||||
}
|
||||
|
||||
// Show only the relevant icon.
|
||||
body:not([data-theme='dark']) .theme-toggle__light-icon { display: none; }
|
||||
[data-theme='dark'] .theme-toggle__dark-icon { display: none; }
|
||||
|
||||
// Back-to-top button.
|
||||
.back-to-top {
|
||||
position: fixed;
|
||||
bottom: 2rem;
|
||||
right: 2rem;
|
||||
z-index: 200;
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
border-radius: 50%;
|
||||
background-color: var(--color-primary);
|
||||
color: #fff;
|
||||
border: none;
|
||||
font-size: 1.25rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: var(--card-shadow);
|
||||
transition:
|
||||
opacity var(--transition-base),
|
||||
transform var(--transition-base),
|
||||
box-shadow var(--transition-base);
|
||||
opacity: 0;
|
||||
transform: translateY(1rem);
|
||||
pointer-events: none;
|
||||
|
||||
&.is-visible {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
box-shadow: var(--card-shadow-hover);
|
||||
}
|
||||
|
||||
@include focus-ring;
|
||||
}
|
||||
|
||||
// Skip link.
|
||||
.skip-link {
|
||||
@include visually-hidden;
|
||||
|
||||
&:focus {
|
||||
position: fixed;
|
||||
top: var(--space-2);
|
||||
left: var(--space-2);
|
||||
z-index: 9999;
|
||||
background: var(--color-primary);
|
||||
color: #fff;
|
||||
padding: var(--space-2) var(--space-3);
|
||||
border-radius: 4px;
|
||||
clip: auto;
|
||||
height: auto;
|
||||
width: auto;
|
||||
font-weight: 700;
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
// =============================================================================
|
||||
// layout/_sidebar.scss
|
||||
// =============================================================================
|
||||
|
||||
.widget-area {
|
||||
.widget {
|
||||
border-radius: var(--card-radius);
|
||||
overflow: hidden;
|
||||
|
||||
.card-content {
|
||||
padding-top: var(--space-3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sticky sidebar on desktop.
|
||||
@include desktop {
|
||||
#secondary.widget-area {
|
||||
position: sticky;
|
||||
top: calc(var(--space-5) + 60px); // 60px = approx navbar height.
|
||||
align-self: flex-start;
|
||||
max-height: calc(100vh - 100px);
|
||||
overflow-y: auto;
|
||||
scrollbar-width: thin;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// =============================================================================
|
||||
// main.scss – CyyWordpress 7-1 SCSS entry point
|
||||
// =============================================================================
|
||||
|
||||
// 1. Abstracts (no CSS output, just variables / mixins / functions)
|
||||
@use 'abstracts/variables';
|
||||
@use 'abstracts/mixins' as *;
|
||||
@use 'abstracts/functions';
|
||||
|
||||
// 2. Third-party framework (selective Bulma import)
|
||||
@use 'vendors/bulma';
|
||||
|
||||
// 3. Base styles
|
||||
@use 'base/reset';
|
||||
@use 'base/typography';
|
||||
|
||||
// 4. Layout shells
|
||||
@use 'layout/grid';
|
||||
@use 'layout/header';
|
||||
@use 'layout/footer';
|
||||
@use 'layout/sidebar';
|
||||
|
||||
// 5. Reusable components
|
||||
@use 'components/card';
|
||||
@use 'components/navigation';
|
||||
@use 'components/button';
|
||||
@use 'components/toc';
|
||||
|
||||
// 6. Page-specific
|
||||
@use 'pages/home';
|
||||
@use 'pages/single';
|
||||
@use 'pages/archive';
|
||||
|
||||
// 7. Themes (dark mode overrides)
|
||||
@use 'themes/dark';
|
||||
@@ -0,0 +1,18 @@
|
||||
// =============================================================================
|
||||
// pages/_archive.scss
|
||||
// =============================================================================
|
||||
|
||||
.archive-header {
|
||||
margin-bottom: var(--space-4);
|
||||
padding-bottom: var(--space-3);
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
|
||||
.page-title {
|
||||
font-size: 1.75rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.archive-description {
|
||||
color: #6b7280;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// =============================================================================
|
||||
// pages/_home.scss
|
||||
// =============================================================================
|
||||
|
||||
.welcome-banner {
|
||||
margin-bottom: var(--space-3);
|
||||
border-radius: var(--card-radius);
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
// =============================================================================
|
||||
// pages/_single.scss
|
||||
// =============================================================================
|
||||
|
||||
// Reading progress bar.
|
||||
.reading-progress {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 3px;
|
||||
z-index: 9999;
|
||||
background: transparent;
|
||||
pointer-events: none;
|
||||
|
||||
&__bar {
|
||||
height: 100%;
|
||||
width: 0;
|
||||
background: var(--color-primary);
|
||||
transition: width 0.1s linear;
|
||||
}
|
||||
}
|
||||
|
||||
// Hero featured image.
|
||||
.single-hero {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
max-height: 450px;
|
||||
overflow: hidden;
|
||||
border-radius: var(--card-radius);
|
||||
margin-bottom: var(--space-4);
|
||||
|
||||
&__image {
|
||||
width: 100%;
|
||||
height: 450px;
|
||||
object-fit: cover;
|
||||
display: block;
|
||||
loading: eager;
|
||||
}
|
||||
|
||||
&__overlay {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: linear-gradient(to top, rgba(0, 0, 0, 0.65) 0%, transparent 60%);
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
padding: var(--space-5);
|
||||
}
|
||||
|
||||
&__title {
|
||||
color: #fff;
|
||||
font-size: clamp(1.5rem, 4vw, 2.5rem);
|
||||
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Single article layout.
|
||||
.single-layout {
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
// Social share.
|
||||
.social-share {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2);
|
||||
flex-wrap: wrap;
|
||||
margin: var(--space-4) 0;
|
||||
padding: var(--space-3);
|
||||
background: var(--color-surface);
|
||||
border-radius: var(--card-radius);
|
||||
border: 1px solid var(--color-border);
|
||||
|
||||
&__label {
|
||||
font-size: 0.875rem;
|
||||
color: #6b7280;
|
||||
}
|
||||
|
||||
&__btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 2.25rem;
|
||||
height: 2.25rem;
|
||||
border-radius: 50%;
|
||||
background: var(--color-border);
|
||||
color: var(--color-text);
|
||||
border: none;
|
||||
font-size: 1rem;
|
||||
text-decoration: none;
|
||||
transition:
|
||||
background-color var(--transition-base),
|
||||
color var(--transition-base);
|
||||
|
||||
&:hover {
|
||||
background-color: var(--color-primary);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
&--weibo:hover { background-color: #e6162d; }
|
||||
&--twitter:hover { background-color: #000; }
|
||||
}
|
||||
}
|
||||
|
||||
// Author bio.
|
||||
.author-bio {
|
||||
margin: var(--space-4) 0;
|
||||
border-radius: var(--card-radius);
|
||||
border: 1px solid var(--color-border);
|
||||
|
||||
.media {
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
&__avatar {
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
&__name {
|
||||
display: block;
|
||||
color: var(--color-text);
|
||||
text-decoration: none;
|
||||
margin-bottom: var(--space-2);
|
||||
|
||||
&:hover { color: var(--color-primary); }
|
||||
}
|
||||
|
||||
&__description {
|
||||
font-size: 0.9rem;
|
||||
color: #6b7280;
|
||||
line-height: 1.6;
|
||||
}
|
||||
}
|
||||
|
||||
// Related posts.
|
||||
.related-posts {
|
||||
margin: var(--space-4) 0;
|
||||
|
||||
&__title {
|
||||
margin-bottom: var(--space-3);
|
||||
}
|
||||
}
|
||||
|
||||
.related-post-card {
|
||||
height: 100%;
|
||||
border-radius: var(--card-radius);
|
||||
border: 1px solid var(--color-border);
|
||||
overflow: hidden;
|
||||
transition:
|
||||
transform var(--transition-base),
|
||||
box-shadow var(--transition-base);
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: var(--card-shadow-hover);
|
||||
}
|
||||
|
||||
&__image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
&__title {
|
||||
display: block;
|
||||
font-size: 0.9rem;
|
||||
font-weight: 600;
|
||||
color: var(--color-text);
|
||||
text-decoration: none;
|
||||
line-height: 1.4;
|
||||
|
||||
&:hover { color: var(--color-primary); }
|
||||
}
|
||||
}
|
||||
|
||||
// Code block copy button wrapper.
|
||||
.entry-content pre,
|
||||
.post-card__content pre {
|
||||
position: relative;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
// =============================================================================
|
||||
// themes/_dark.scss
|
||||
// Dark mode – extra overrides beyond CSS custom properties.
|
||||
// =============================================================================
|
||||
|
||||
[data-theme='dark'],
|
||||
@media (prefers-color-scheme: dark) {
|
||||
// Bulma component overrides.
|
||||
.navbar {
|
||||
background-color: var(--navbar-bg);
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
}
|
||||
|
||||
.card {
|
||||
background-color: var(--color-surface);
|
||||
border-color: var(--color-border);
|
||||
}
|
||||
|
||||
.notification.is-primary {
|
||||
background-color: rgba(0, 209, 178, 0.15);
|
||||
color: #00d1b2;
|
||||
}
|
||||
|
||||
.input,
|
||||
.select select,
|
||||
.textarea {
|
||||
background-color: var(--color-surface);
|
||||
border-color: var(--color-border);
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.footer {
|
||||
background-color: var(--color-surface);
|
||||
}
|
||||
|
||||
// Code blocks.
|
||||
pre,
|
||||
code {
|
||||
background-color: #0d1117;
|
||||
color: #e6edf3;
|
||||
}
|
||||
}
|
||||
Vendored
+10
@@ -0,0 +1,10 @@
|
||||
// =============================================================================
|
||||
// vendors/_bulma.scss
|
||||
// Selective Bulma 1.x import – only import what the theme uses.
|
||||
// Bulma 1.x exposes sass/ subdirectory; each module uses @use.
|
||||
// =============================================================================
|
||||
@use 'bulma/sass' with (
|
||||
$primary: #00d1b2,
|
||||
$dark: #363636,
|
||||
$light: #f5f5f5
|
||||
);
|
||||
Reference in New Issue
Block a user