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
+38
View File
@@ -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);
}
}
+168
View File
@@ -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;
}
}
}
+89
View File
@@ -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;
}
}
+66
View File
@@ -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;
}
}