-
-
-
-
+
+
+
diff --git a/src/styles/_animations.scss b/src/styles/_animations.scss
new file mode 100644
index 0000000..3b38711
--- /dev/null
+++ b/src/styles/_animations.scss
@@ -0,0 +1,64 @@
+:root {
+ --ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);
+ --ease-out-quart: cubic-bezier(0.25, 1, 0.5, 1);
+ --ease-in-out-cubic: cubic-bezier(0.65, 0, 0.35, 1);
+
+ --duration-fast: 150ms;
+ --duration-normal: 300ms;
+ --duration-slow: 500ms;
+ --duration-breath: 3s;
+}
+
+@keyframes breathe {
+ 0%,
+ 100% {
+ opacity: 0.4;
+ transform: scale(1);
+ }
+ 50% {
+ opacity: 0.7;
+ transform: scale(1.08);
+ }
+}
+
+@keyframes fadeInUp {
+ from {
+ opacity: 0;
+ transform: translateY(20px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+@keyframes float {
+ 0%,
+ 100% {
+ transform: translateY(0);
+ }
+ 50% {
+ transform: translateY(-6px);
+ }
+}
+
+@keyframes shimmer {
+ 0% {
+ background-position: -200% 0;
+ }
+ 100% {
+ background-position: 200% 0;
+ }
+}
+
+@keyframes scrollHint {
+ 0%,
+ 100% {
+ opacity: 0.4;
+ transform: translateY(0);
+ }
+ 50% {
+ opacity: 1;
+ transform: translateY(8px);
+ }
+}
diff --git a/src/styles/_colors.scss b/src/styles/_colors.scss
new file mode 100644
index 0000000..50ba82f
--- /dev/null
+++ b/src/styles/_colors.scss
@@ -0,0 +1,43 @@
+:root {
+ --bg: #faf7f2;
+ --bg-raised: #f3ede5;
+ --bg-overlay: rgba(250, 247, 242, 0.85);
+ --ink: #2c2420;
+ --ink-2: #7a6e64;
+ --ink-3: #b5a99e;
+ --rule: #e8e0d6;
+ --accent: #d4764e;
+ --accent-hover: #c4613a;
+ --accent-bg: #fdf0e8;
+ --mist-pink: #f0e4de;
+ --sea-salt: #e8e0d6;
+ --caramel: #8b6f5e;
+ --glass-bg: rgba(250, 247, 242, 0.72);
+ --glass-border: rgba(232, 224, 214, 0.5);
+ --shadow-sm: 0 1px 3px rgba(44, 36, 32, 0.06);
+ --shadow-md: 0 4px 16px rgba(44, 36, 32, 0.08);
+ --shadow-lg: 0 8px 32px rgba(44, 36, 32, 0.12);
+ --shadow-glow: 0 0 40px rgba(212, 118, 78, 0.15);
+}
+
+html.dark {
+ --bg: #1a1614;
+ --bg-raised: #242018;
+ --bg-overlay: rgba(26, 22, 20, 0.85);
+ --ink: #ede6de;
+ --ink-2: #9a8e84;
+ --ink-3: #5e544a;
+ --rule: #2e2822;
+ --accent: #e8955f;
+ --accent-hover: #f0a872;
+ --accent-bg: #2a1e16;
+ --mist-pink: #2e2420;
+ --sea-salt: #2e2822;
+ --caramel: #a08878;
+ --glass-bg: rgba(26, 22, 20, 0.72);
+ --glass-border: rgba(46, 40, 34, 0.5);
+ --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.2);
+ --shadow-md: 0 4px 16px rgba(0, 0, 0, 0.25);
+ --shadow-lg: 0 8px 32px rgba(0, 0, 0, 0.35);
+ --shadow-glow: 0 0 40px rgba(232, 149, 95, 0.12);
+}
diff --git a/src/styles/_comment.scss b/src/styles/_comment.scss
new file mode 100644
index 0000000..21e8e2d
--- /dev/null
+++ b/src/styles/_comment.scss
@@ -0,0 +1,210 @@
+@use 'variables' as *;
+
+.halo-comment-widget {
+ background: var(--glass-bg);
+ backdrop-filter: blur(16px);
+ -webkit-backdrop-filter: blur(16px);
+ border: 1px solid var(--glass-border);
+ border-radius: $border-radius-lg;
+ padding: var(--space-md);
+ margin-top: var(--space-xl);
+ width: 100%;
+ max-width: 600px;
+ margin-inline: auto;
+
+ .comment-item {
+ background: var(--bg-raised);
+ border: 1px solid var(--rule);
+ border-radius: $border-radius-md;
+ padding: var(--space-sm);
+ margin-bottom: var(--space-xs);
+ transition:
+ box-shadow var(--duration-normal) var(--ease-out-expo),
+ transform var(--duration-normal) var(--ease-out-expo);
+
+ &:hover {
+ box-shadow: var(--shadow-sm);
+ transform: translateY(-1px);
+ }
+ }
+
+ .comment-reply-item {
+ background: var(--bg);
+ border: 1px solid var(--rule);
+ border-radius: $border-radius-md;
+ padding: var(--space-xs) var(--space-sm);
+ margin-top: var(--space-xs);
+ transition:
+ box-shadow var(--duration-normal) var(--ease-out-expo),
+ transform var(--duration-normal) var(--ease-out-expo);
+
+ &:hover {
+ box-shadow: var(--shadow-sm);
+ transform: translateY(-1px);
+ }
+ }
+
+ .comment-header {
+ display: flex;
+ align-items: center;
+ gap: var(--space-xs);
+ margin-bottom: var(--space-xs);
+ }
+
+ .comment-avatar {
+ width: 24px;
+ height: 24px;
+ border-radius: $border-radius-full;
+ box-shadow: var(--shadow-sm);
+ }
+
+ .comment-author {
+ font-weight: 600;
+ color: var(--ink);
+ font-size: var(--text-xs);
+ }
+
+ .comment-time {
+ font-size: var(--text-xs);
+ color: var(--ink-3);
+ letter-spacing: var(--tracking-wide);
+ }
+
+ .comment-content {
+ font-size: var(--text-sm);
+ line-height: var(--leading-relaxed);
+ color: var(--ink);
+ margin-bottom: var(--space-xs);
+ }
+
+ .comment-form {
+ background: var(--bg-raised);
+ border: 1px solid var(--rule);
+ border-radius: $border-radius-md;
+ padding: var(--space-sm);
+ margin-bottom: var(--space-md);
+ }
+
+ .comment-input,
+ .comment-textarea {
+ width: 100%;
+ padding: var(--space-sm) var(--space-md);
+ background: var(--bg);
+ border: 1px solid var(--rule);
+ border-radius: $border-radius-sm;
+ color: var(--ink);
+ font-family: var(--font-body);
+ font-size: var(--text-sm);
+ transition:
+ border-color var(--duration-fast) var(--ease-out-quart),
+ box-shadow var(--duration-fast) var(--ease-out-quart);
+
+ &:focus {
+ outline: none;
+ border-color: var(--accent);
+ box-shadow: 0 0 0 3px rgba(212, 118, 78, 0.15);
+ }
+
+ &::placeholder {
+ color: var(--ink-3);
+ }
+ }
+
+ .comment-textarea {
+ min-height: 80px;
+ resize: vertical;
+ }
+
+ .comment-button {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ padding: var(--space-sm) var(--space-lg);
+ background: var(--accent);
+ color: var(--bg);
+ border: none;
+ border-radius: $border-radius-sm;
+ font-family: var(--font-body);
+ font-size: var(--text-sm);
+ font-weight: 600;
+ cursor: pointer;
+ transition:
+ background var(--duration-fast) var(--ease-out-quart),
+ transform var(--duration-fast) var(--ease-out-quart),
+ box-shadow var(--duration-fast) var(--ease-out-quart);
+
+ &:hover {
+ background: var(--accent-hover);
+ transform: translateY(-1px);
+ box-shadow: var(--shadow-md);
+ }
+
+ &:active {
+ transform: translateY(0);
+ }
+ }
+
+ .comment-pagination {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ gap: var(--space-md);
+ margin-top: var(--space-lg);
+ }
+
+ .comment-pagination-button {
+ padding: var(--space-xs) var(--space-md);
+ background: var(--bg-raised);
+ border: 1px solid var(--rule);
+ border-radius: $border-radius-sm;
+ color: var(--ink-2);
+ font-size: var(--text-sm);
+ cursor: pointer;
+ transition:
+ border-color var(--duration-fast) var(--ease-out-quart),
+ color var(--duration-fast) var(--ease-out-quart);
+
+ &:hover {
+ border-color: var(--accent);
+ color: var(--accent);
+ }
+ }
+
+ .comment-reply-button {
+ font-size: var(--text-xs);
+ color: var(--ink-3);
+ cursor: pointer;
+ transition: color var(--duration-fast) var(--ease-out-quart);
+
+ &:hover {
+ color: var(--accent);
+ }
+ }
+
+ .comment-smiley-button {
+ background: none;
+ border: none;
+ cursor: pointer;
+ font-size: var(--text-lg);
+ transition: transform var(--duration-fast) var(--ease-out-quart);
+
+ &:hover {
+ transform: scale(1.2);
+ }
+ }
+}
+
+html.dark .halo-comment-widget {
+ .comment-input,
+ .comment-textarea {
+ &:focus {
+ box-shadow: 0 0 0 3px rgba(232, 149, 95, 0.15);
+ }
+ }
+
+ .comment-button {
+ &:hover {
+ box-shadow: var(--shadow-md);
+ }
+ }
+}
diff --git a/src/styles/_lightgallery.scss b/src/styles/_lightgallery.scss
new file mode 100644
index 0000000..1668a59
--- /dev/null
+++ b/src/styles/_lightgallery.scss
@@ -0,0 +1,361 @@
+@use 'variables' as *;
+@use 'mixins' as *;
+
+$lg-backdrop-light: rgba(18, 14, 12, 0.96);
+$lg-backdrop-dark: rgba(10, 8, 6, 0.97);
+$lg-glass-bg-light: rgba(255, 255, 255, 0.08);
+$lg-glass-bg-dark: rgba(255, 255, 255, 0.06);
+$lg-glass-border: rgba(255, 255, 255, 0.06);
+$lg-icon-color-light: rgba(255, 255, 255, 0.7);
+$lg-icon-color-dark: rgba(255, 255, 255, 0.6);
+$lg-icon-hover-bg-light: rgba(255, 255, 255, 0.12);
+$lg-icon-hover-bg-dark: rgba(255, 255, 255, 0.1);
+$lg-toolbar-height: 44px;
+$lg-icon-size: 36px;
+$lg-nav-size: 48px;
+$lg-thumb-height: 100px;
+
+.lg-backdrop {
+ background-color: $lg-backdrop-light;
+}
+
+.lg-toolbar {
+ background: $lg-glass-bg-light;
+ backdrop-filter: blur(24px) saturate(1.2);
+ -webkit-backdrop-filter: blur(24px) saturate(1.2);
+ border-bottom: none;
+ padding: 4px 12px;
+ height: $lg-toolbar-height;
+}
+
+.lg-toolbar .lg-icon {
+ color: $lg-icon-color-light;
+ width: $lg-icon-size;
+ height: $lg-icon-size;
+ font-size: 17px;
+ border-radius: 8px;
+ transition: all 0.2s ease;
+ padding: 0 !important;
+ line-height: $lg-icon-size !important;
+
+ &::before {
+ vertical-align: middle !important;
+ line-height: $lg-icon-size !important;
+ }
+
+ &:hover {
+ color: #fff;
+ background: $lg-icon-hover-bg-light;
+ }
+}
+
+.lg-inner {
+ top: $lg-toolbar-height !important;
+}
+
+.lg-actions .lg-next,
+.lg-actions .lg-prev {
+ background: $lg-glass-bg-light;
+ backdrop-filter: blur(16px) saturate(1.2);
+ -webkit-backdrop-filter: blur(16px) saturate(1.2);
+ color: $lg-icon-color-light;
+ border-radius: 14px;
+ width: $lg-nav-size;
+ height: $lg-nav-size;
+ font-size: 24px;
+ transition: all 0.25s cubic-bezier(0.16, 1, 0.3, 1);
+ border: 1px solid $lg-glass-border;
+
+ &:hover {
+ color: #fff;
+ background: rgba(255, 255, 255, 0.15);
+ border-color: rgba(255, 255, 255, 0.12);
+ transform: scale(1.05);
+ }
+}
+
+.lg-sub-html {
+ background: linear-gradient(to top, rgba(18, 14, 12, 0.8) 0%, transparent 100%);
+ color: rgba(255, 255, 255, 0.85);
+ font-family: var(--font-body);
+ font-size: 13px;
+ letter-spacing: 0.02em;
+ padding: 48px 16px 12px;
+}
+
+.wi-lg-caption {
+ font-size: 13px;
+ color: rgba(255, 255, 255, 0.85);
+ margin-bottom: 6px;
+}
+
+.wi-lg-exif {
+ display: flex;
+ flex-wrap: wrap;
+ align-items: center;
+ gap: 6px 10px;
+}
+
+.wi-lg-exif__camera,
+.wi-lg-exif__lens {
+ font-size: 11px;
+ color: rgba(255, 255, 255, 0.55);
+ letter-spacing: 0.03em;
+}
+
+.wi-lg-exif__params {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 4px;
+}
+
+.wi-lg-exif__aperture,
+.wi-lg-exif__shutter,
+.wi-lg-exif__iso,
+.wi-lg-exif__focal {
+ display: inline-flex;
+ align-items: center;
+ font-size: 10px;
+ font-weight: 500;
+ color: rgba(255, 255, 255, 0.7);
+ background: rgba(255, 255, 255, 0.08);
+ border-radius: 4px;
+ padding: 2px 6px;
+ letter-spacing: 0.04em;
+ font-variant-numeric: tabular-nums;
+ line-height: 1.4;
+}
+
+.lg-thumb-outer {
+ background: rgba(18, 14, 12, 0.85);
+ backdrop-filter: blur(24px) saturate(1.2);
+ -webkit-backdrop-filter: blur(24px) saturate(1.2);
+ border-top: 1px solid $lg-glass-border;
+ padding: 8px 0;
+}
+
+.lg-thumb-item {
+ border-color: transparent;
+ border-radius: 8px;
+ overflow: hidden;
+ border-width: 2px;
+ transition: all 0.25s cubic-bezier(0.16, 1, 0.3, 1);
+ opacity: 0.5;
+ cursor: pointer;
+
+ &.active {
+ border-color: var(--accent) !important;
+ opacity: 1;
+ transform: scale(1.05);
+ }
+
+ &:hover {
+ border-color: rgba(255, 255, 255, 0.3) !important;
+ opacity: 0.85;
+ }
+}
+
+.lg-counter {
+ color: rgba(255, 255, 255, 0.5);
+ font-size: 12px;
+ font-family: var(--font-body);
+ letter-spacing: 0.08em;
+ font-variant-numeric: tabular-nums;
+}
+
+.lg-progress-bar {
+ height: 2px;
+}
+
+.lg-progress-bar .lg-progress {
+ background: linear-gradient(90deg, var(--accent), var(--accent-hover));
+ height: 2px;
+ border-radius: 1px;
+}
+
+.lg-outer .lg-thumb-outer {
+ display: none !important;
+}
+
+.lg-outer.wi-thumb-shown .lg-thumb-outer {
+ display: block !important;
+}
+
+.lg-outer.wi-thumb-shown .lg-inner {
+ bottom: $lg-thumb-height !important;
+}
+
+.lg-outer .lg-item {
+ transition: opacity 0.3s ease, transform 0.3s ease;
+}
+
+.lg-outer .lg-image {
+ transition: opacity 0.25s ease;
+}
+
+.lg-outer .lg-item.lg-complete .lg-image {
+ opacity: 1;
+}
+
+.lg-outer .lg-item .lg-image {
+ opacity: 0;
+}
+
+html.dark {
+ .lg-backdrop {
+ background-color: $lg-backdrop-dark;
+ }
+
+ .lg-toolbar {
+ background: $lg-glass-bg-dark;
+ }
+
+ .lg-toolbar .lg-icon {
+ color: $lg-icon-color-dark;
+
+ &:hover {
+ color: #fff;
+ background: $lg-icon-hover-bg-dark;
+ }
+ }
+
+ .lg-actions .lg-next,
+ .lg-actions .lg-prev {
+ background: $lg-glass-bg-dark;
+ color: $lg-icon-color-dark;
+ border-color: rgba(255, 255, 255, 0.04);
+
+ &:hover {
+ color: #fff;
+ background: rgba(255, 255, 255, 0.12);
+ border-color: rgba(255, 255, 255, 0.08);
+ }
+ }
+
+ .lg-sub-html {
+ background: linear-gradient(to top, rgba(10, 8, 6, 0.85) 0%, transparent 100%);
+ color: rgba(255, 255, 255, 0.75);
+ }
+
+ .lg-thumb-outer {
+ background: rgba(10, 8, 6, 0.88);
+ border-top-color: rgba(255, 255, 255, 0.04);
+ }
+
+ .lg-thumb-item {
+ opacity: 0.4;
+
+ &.active {
+ border-color: var(--accent) !important;
+ opacity: 1;
+ }
+
+ &:hover {
+ border-color: rgba(255, 255, 255, 0.2) !important;
+ opacity: 0.75;
+ }
+ }
+
+ .lg-counter {
+ color: rgba(255, 255, 255, 0.4);
+ }
+
+ .wi-lg-caption {
+ color: rgba(255, 255, 255, 0.75);
+ }
+
+ .wi-lg-exif__camera,
+ .wi-lg-exif__lens {
+ color: rgba(255, 255, 255, 0.45);
+ }
+
+ .wi-lg-exif__aperture,
+ .wi-lg-exif__shutter,
+ .wi-lg-exif__iso,
+ .wi-lg-exif__focal {
+ color: rgba(255, 255, 255, 0.6);
+ background: rgba(255, 255, 255, 0.06);
+ }
+}
+
+@media (max-width: $breakpoint-md) {
+ .lg-toolbar {
+ padding: 2px 8px;
+ height: 40px;
+ }
+
+ .lg-toolbar .lg-icon {
+ width: 32px;
+ height: 32px;
+ font-size: 15px;
+ line-height: 32px !important;
+
+ &::before {
+ line-height: 32px !important;
+ }
+ }
+
+ .lg-inner {
+ top: 40px !important;
+ }
+
+ .lg-actions .lg-next,
+ .lg-actions .lg-prev {
+ width: 40px;
+ height: 40px;
+ font-size: 20px;
+ border-radius: 12px;
+ }
+
+ .lg-sub-html {
+ font-size: 12px;
+ padding: 36px 12px 8px;
+ }
+
+ .wi-lg-caption {
+ font-size: 12px;
+ margin-bottom: 4px;
+ }
+
+ .wi-lg-exif {
+ gap: 4px 8px;
+ }
+
+ .wi-lg-exif__camera,
+ .wi-lg-exif__lens {
+ font-size: 10px;
+ }
+
+ .wi-lg-exif__aperture,
+ .wi-lg-exif__shutter,
+ .wi-lg-exif__iso,
+ .wi-lg-exif__focal {
+ font-size: 9px;
+ padding: 1px 5px;
+ }
+
+ .lg-outer.wi-thumb-shown .lg-inner {
+ bottom: 80px !important;
+ }
+}
+
+@media (max-width: $breakpoint-sm - 1px) {
+ .lg-toolbar .lg-icon {
+ width: 28px;
+ height: 28px;
+ font-size: 14px;
+ line-height: 28px !important;
+
+ &::before {
+ line-height: 28px !important;
+ }
+ }
+
+ .lg-actions .lg-next,
+ .lg-actions .lg-prev {
+ width: 36px;
+ height: 36px;
+ font-size: 18px;
+ border-radius: 10px;
+ }
+}
diff --git a/src/styles/_mixins.scss b/src/styles/_mixins.scss
new file mode 100644
index 0000000..23b1576
--- /dev/null
+++ b/src/styles/_mixins.scss
@@ -0,0 +1,71 @@
+@use 'sass:math';
+@use 'variables' as *;
+
+@mixin glass-effect {
+ background: var(--glass-bg);
+ backdrop-filter: blur(16px);
+ -webkit-backdrop-filter: blur(16px);
+ border: 1px solid var(--glass-border);
+}
+
+@mixin card-hover {
+ transition: transform var(--duration-normal) var(--ease-out-expo),
+ box-shadow var(--duration-normal) var(--ease-out-expo);
+
+ &:hover {
+ transform: translateY(-4px);
+ box-shadow: var(--shadow-lg);
+ }
+}
+
+@mixin responsive-container {
+ width: 100%;
+ max-width: $container-max;
+ margin-inline: auto;
+ padding-inline: clamp(1rem, 3vw, 2rem);
+}
+
+@mixin section-spacing {
+ padding-block: var(--section-spacing);
+}
+
+@mixin focus-visible {
+ &:focus-visible {
+ outline: 2px solid var(--accent);
+ outline-offset: 2px;
+ border-radius: $border-radius-sm;
+ }
+}
+
+@mixin truncate {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+@mixin hide-scrollbar {
+ scrollbar-width: none;
+ -ms-overflow-style: none;
+
+ &::-webkit-scrollbar {
+ display: none;
+ }
+}
+
+@mixin mobile-only {
+ @media (max-width: #{$breakpoint-sm - 1px}) {
+ @content;
+ }
+}
+
+@mixin tablet-up {
+ @media (min-width: $breakpoint-md) {
+ @content;
+ }
+}
+
+@mixin desktop-up {
+ @media (min-width: $breakpoint-lg) {
+ @content;
+ }
+}
diff --git a/src/styles/_search.scss b/src/styles/_search.scss
new file mode 100644
index 0000000..5795404
--- /dev/null
+++ b/src/styles/_search.scss
@@ -0,0 +1,113 @@
+@use 'variables' as *;
+
+.halo-search-widget {
+ .search-modal {
+ background: var(--glass-bg);
+ backdrop-filter: blur(24px);
+ -webkit-backdrop-filter: blur(24px);
+ border: 1px solid var(--glass-border);
+ border-radius: $border-radius-xl;
+ box-shadow: var(--shadow-lg);
+ overflow: hidden;
+ }
+
+ .search-input {
+ width: 100%;
+ padding: var(--space-lg) var(--space-xl);
+ background: transparent;
+ border: none;
+ border-bottom: 1px solid var(--rule);
+ color: var(--ink);
+ font-family: var(--font-body);
+ font-size: var(--text-lg);
+ outline: none;
+ transition: border-color var(--duration-fast) var(--ease-out-quart);
+
+ &::placeholder {
+ color: var(--ink-3);
+ }
+
+ &:focus {
+ border-bottom-color: var(--accent);
+ }
+ }
+
+ .search-result-item {
+ padding: var(--space-md) var(--space-xl);
+ border-bottom: 1px solid var(--rule);
+ cursor: pointer;
+ transition:
+ background var(--duration-fast) var(--ease-out-quart),
+ padding-left var(--duration-fast) var(--ease-out-quart);
+
+ &:hover {
+ background: var(--accent-bg);
+ padding-left: calc(var(--space-xl) + 4px);
+ }
+
+ &:last-child {
+ border-bottom: none;
+ }
+ }
+
+ .search-result-title {
+ font-size: var(--text-md);
+ font-weight: 600;
+ color: var(--ink);
+ margin-bottom: var(--space-xs);
+ }
+
+ .search-result-content {
+ font-size: var(--text-sm);
+ color: var(--ink-2);
+ line-height: var(--leading-relaxed);
+ display: -webkit-box;
+ -webkit-line-clamp: 2;
+ -webkit-box-orient: vertical;
+ overflow: hidden;
+ }
+
+ .search-result-label {
+ font-size: var(--text-xs);
+ color: var(--ink-3);
+ letter-spacing: var(--tracking-wide);
+ }
+
+ .search-empty {
+ padding: var(--space-3xl) var(--space-xl);
+ text-align: center;
+ color: var(--ink-3);
+ font-size: var(--text-sm);
+ }
+
+ .search-hint {
+ font-size: var(--text-xs);
+ color: var(--ink-3);
+ padding: var(--space-sm) var(--space-xl);
+ border-top: 1px solid var(--rule);
+ text-align: center;
+ }
+
+ .search-highlight {
+ color: var(--accent);
+ font-weight: 600;
+ }
+
+ .search-backdrop {
+ background: rgba(44, 36, 32, 0.4);
+ backdrop-filter: blur(4px);
+ -webkit-backdrop-filter: blur(4px);
+ }
+}
+
+html.dark .halo-search-widget {
+ .search-backdrop {
+ background: rgba(0, 0, 0, 0.5);
+ }
+
+ .search-result-item {
+ &:hover {
+ background: var(--accent-bg);
+ }
+ }
+}
diff --git a/src/styles/_spacing.scss b/src/styles/_spacing.scss
new file mode 100644
index 0000000..8b1e6e2
--- /dev/null
+++ b/src/styles/_spacing.scss
@@ -0,0 +1,18 @@
+:root {
+ --space-xs: 0.25rem;
+ --space-sm: 0.5rem;
+ --space-md: 1rem;
+ --space-lg: 1.5rem;
+ --space-xl: 2rem;
+ --space-2xl: 3rem;
+ --space-3xl: 4rem;
+ --space-4xl: 6rem;
+
+ --container-sm: 640px;
+ --container-md: 768px;
+ --container-lg: 1024px;
+ --container-xl: 1200px;
+ --content-max: 800px;
+
+ --section-spacing: clamp(3rem, 2rem + 3vw, 6rem);
+}
diff --git a/src/styles/_typography.scss b/src/styles/_typography.scss
new file mode 100644
index 0000000..cfa7607
--- /dev/null
+++ b/src/styles/_typography.scss
@@ -0,0 +1,86 @@
+:root {
+ --font-sans: 'Noto Serif SC', 'Source Han Serif SC', Georgia, serif;
+ --font-body: 'Noto Sans SC', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
+ --font-mono: 'JetBrains Mono', 'Fira Code', monospace;
+
+ --text-xs: clamp(0.7rem, 0.66rem + 0.2vw, 0.75rem);
+ --text-sm: clamp(0.8rem, 0.76rem + 0.2vw, 0.875rem);
+ --text-base: clamp(0.938rem, 0.89rem + 0.24vw, 1rem);
+ --text-md: clamp(1.05rem, 0.99rem + 0.3vw, 1.125rem);
+ --text-lg: clamp(1.15rem, 1.06rem + 0.45vw, 1.25rem);
+ --text-xl: clamp(1.3rem, 1.16rem + 0.7vw, 1.5rem);
+ --text-2xl: clamp(1.55rem, 1.34rem + 1.05vw, 1.875rem);
+ --text-3xl: clamp(1.85rem, 1.52rem + 1.65vw, 2.25rem);
+ --text-4xl: clamp(2.15rem, 1.7rem + 2.25vw, 3rem);
+ --text-5xl: clamp(2.6rem, 1.9rem + 3.5vw, 3.75rem);
+
+ --leading-none: 1;
+ --leading-tight: 1.2;
+ --leading-snug: 1.35;
+ --leading-normal: 1.6;
+ --leading-relaxed: 1.75;
+ --leading-loose: 2;
+
+ --tracking-tight: -0.02em;
+ --tracking-normal: 0;
+ --tracking-wide: 0.04em;
+ --tracking-wider: 0.08em;
+ --tracking-widest: 0.12em;
+}
+
+/* 分级标题 */
+h1, h2, h3, h4, h5, h6 {
+ font-family: var(--font-sans);
+ font-weight: 700;
+ line-height: var(--leading-tight);
+ letter-spacing: var(--tracking-tight);
+ color: var(--ink);
+ margin-bottom: var(--space-sm);
+}
+
+h1 {
+ font-size: var(--text-4xl);
+ margin-bottom: var(--space-lg);
+}
+
+h2 {
+ font-size: var(--text-3xl);
+ padding-left: var(--space-md);
+ border-left: 3px solid var(--accent);
+ margin-bottom: var(--space-sm);
+}
+
+h3 {
+ font-size: var(--text-2xl);
+ position: relative;
+ padding-left: var(--space-lg);
+
+ &::before {
+ content: "";
+ display: block;
+ position: absolute;
+ left: 0;
+ top: 50%;
+ transform: translateY(-50%);
+ width: 6px;
+ height: 6px;
+ border-radius: 50%;
+ background: var(--accent);
+ opacity: 0.6;
+ }
+}
+
+h4 {
+ font-size: var(--text-xl);
+ color: var(--ink-2);
+}
+
+h5 {
+ font-size: var(--text-lg);
+ color: var(--ink-2);
+}
+
+h6 {
+ font-size: var(--text-base);
+ color: var(--ink-3);
+}
diff --git a/src/styles/_variables.scss b/src/styles/_variables.scss
new file mode 100644
index 0000000..24c8e17
--- /dev/null
+++ b/src/styles/_variables.scss
@@ -0,0 +1,15 @@
+$breakpoint-sm: 640px;
+$breakpoint-md: 768px;
+$breakpoint-lg: 1024px;
+$breakpoint-xl: 1280px;
+
+$container-max: 1200px;
+$content-max: 800px;
+
+$navbar-height: 64px;
+
+$border-radius-sm: 8px;
+$border-radius-md: 12px;
+$border-radius-lg: 16px;
+$border-radius-xl: 24px;
+$border-radius-full: 9999px;
diff --git a/src/styles/global.css b/src/styles/global.css
deleted file mode 100644
index 0626355..0000000
--- a/src/styles/global.css
+++ /dev/null
@@ -1,465 +0,0 @@
-:root {
- --bg: #faf8f5;
- --bg-raised: #f2ede8;
- --ink: #1a1410;
- --ink-2: #7a7068;
- --ink-3: #b5aca2;
- --rule: #ddd8d0;
- --accent: #c2410c;
- --accent-bg: #fff4ed;
- --black: 26, 20, 16;
- --gray: 122, 112, 104;
- --gray-light: 221, 216, 208;
- --gray-dark: 44, 36, 30;
-}
-
-html.dark {
- --bg: #181613;
- --bg-raised: #242018;
- --ink: #ede9e3;
- --ink-2: #9a9088;
- --ink-3: #5e5650;
- --rule: #2e2a24;
- --accent: #f47040;
- --accent-bg: #2a1a0c;
-}
-
-*,
-*::before,
-*::after {
- box-sizing: border-box;
- min-width: 0;
-}
-
-body {
- font-family: ui-sans-serif, sans-serif;
- margin: 0;
- padding: 0;
- background-color: var(--bg);
- color: var(--ink);
- font-size: 17px;
- line-height: 1.75;
- -webkit-font-smoothing: antialiased;
- word-wrap: break-word;
- overflow-wrap: break-word;
-}
-
-main {
- width: 820px;
- max-width: calc(100% - 2.5rem);
- margin: 0 auto;
- padding: 3rem 0 5rem;
-}
-
-h1,
-h2,
-h3,
-h4,
-h5,
-h6 {
- font-family: ui-sans-serif, sans-serif;
- margin: 0 0 0.5em;
- color: var(--ink);
- line-height: 1.2;
- font-weight: 700;
- letter-spacing: -0.01em;
-}
-h1 {
- font-size: 2.4rem;
-}
-h2 {
- font-size: 1.7rem;
-}
-h3 {
- font-size: 1.3rem;
-}
-h4 {
- font-size: 1.1rem;
-}
-h5 {
- font-size: 1rem;
-}
-
-strong,
-b {
- font-weight: 700;
-}
-
-a {
- color: var(--accent);
- text-decoration: underline;
- text-decoration-thickness: 1px;
- text-underline-offset: 0.2em;
-}
-a:hover {
- color: var(--ink);
-}
-
-p {
- margin: 0 0 1em;
-}
-
-textarea {
- width: 100%;
- font-size: 16px;
-}
-input {
- font-size: 16px;
-}
-table {
- display: block;
- width: 100%;
- max-width: 100%;
- overflow-x: auto;
-}
-
-img,
-video,
-iframe,
-embed,
-object {
- max-width: 100%;
- height: auto;
-}
-
-img {
- border-radius: 10px;
-}
-
-code {
- font-size: 0.88em;
- padding: 0.15em 0.4em;
- background: var(--bg-raised);
- border-radius: 4px;
- border: 1px solid var(--rule);
-}
-pre {
- padding: 1.4em 1.6em;
- border-radius: 10px;
- overflow-x: auto;
- background: var(--ink);
- color: #f8f8f2;
-}
-pre > code {
- all: unset;
- font-size: 0.9em;
- color: inherit;
-}
-blockquote {
- margin: 1.5em 0;
- padding: 0.75em 0 0.75em 1.5em;
- border-left: 3px solid var(--accent);
- color: var(--ink-2);
- font-size: 1.1em;
-}
-hr {
- margin: 2.5rem 0;
- border: none;
- border-top: 1px solid var(--rule);
-}
-
-/* ─── Page shell ─────────────────────────────────── */
-
-.page-shell {
- display: grid;
- gap: 2.5rem;
-}
-
-.page-heading {
- padding-bottom: 1.5rem;
- border-bottom: 1px solid var(--rule);
-}
-
-.page-heading h1 {
- margin-bottom: 0.25em;
-}
-
-.page-meta {
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: 0.6rem;
- margin-bottom: 0.6rem;
- color: var(--ink-3);
- font-size: 0.78rem;
- letter-spacing: 0.1em;
- text-transform: uppercase;
-}
-
-.page-content {
- display: grid;
- gap: 2rem;
-}
-
-/* ─── Post feed ──────────────────────────────────── */
-
-.post-feed__list {
- list-style: none;
- margin: 0;
- padding: 0;
-}
-
-.post-feed__item + .post-feed__item {
- border-top: 1px solid var(--rule);
-}
-
-.post-feed__link {
- display: grid;
- grid-template-columns: minmax(0, 1fr) 200px;
- gap: 2rem;
- align-items: start;
- padding: 2rem 0;
- color: inherit;
- text-decoration: none;
-}
-
-.post-feed__item:first-child .post-feed__link {
- padding-top: 0;
-}
-
-.post-feed__body {
- display: flex;
- flex-direction: column;
- gap: 0.55rem;
- align-self: center;
-}
-
-.post-feed__date {
- margin: 0;
- color: var(--ink-3);
- font-size: 0.8rem;
- letter-spacing: 0.1em;
- text-transform: uppercase;
-}
-
-.post-feed__title {
- margin: 0;
- font-size: 1.35rem;
- line-height: 1.3;
- color: var(--ink);
- transition: color 0.15s ease;
-}
-
-.post-feed__excerpt {
- margin: 0;
- color: var(--ink-2);
- font-size: 0.96rem;
- line-height: 1.6;
-}
-
-.post-feed__image {
- display: block;
- width: 100%;
- aspect-ratio: 4 / 3;
- object-fit: cover;
- border-radius: 10px;
- transition: opacity 0.2s ease;
-}
-
-.post-feed__link:hover .post-feed__title {
- color: var(--accent);
-}
-.post-feed__link:hover .post-feed__image {
- opacity: 0.88;
-}
-
-/* ─── Taxonomy list (categories) ─────────────────── */
-
-.taxonomy-list__item {
- display: flex;
- align-items: center;
- justify-content: space-between;
- gap: 1rem;
- padding: 0.55rem 0;
-}
-
-.taxonomy-list__link {
- color: var(--ink);
- font-size: 1.05rem;
- font-weight: 600;
- text-decoration: none;
- transition: color 0.15s ease;
-}
-
-.taxonomy-list__link:hover {
- color: var(--accent);
-}
-
-.taxonomy-list__count {
- display: inline-flex;
- align-items: center;
- padding: 0.2em 0.7em;
- border-radius: 999px;
- background: var(--bg-raised);
- border: 1px solid var(--rule);
- color: var(--ink-2);
- font-size: 0.82rem;
- white-space: nowrap;
-}
-
-/* ─── Tag cloud (badges) ─────────────────────────── */
-
-.tag-cloud {
- display: flex;
- flex-wrap: wrap;
- gap: 0.6rem;
-}
-
-.tag-pill {
- display: inline-flex;
- align-items: center;
- gap: 0.4rem;
- padding: 0.35em 0.85em;
- border-radius: 6px;
- background: var(--bg-raised);
- border: 1px solid var(--rule);
- color: var(--ink-2);
- font-size: 0.88rem;
- text-decoration: none;
- transition:
- background 0.15s ease,
- color 0.15s ease,
- border-color 0.15s ease;
-}
-
-.tag-pill:hover {
- background: var(--accent-bg);
- color: var(--accent);
- border-color: var(--accent);
-}
-
-.tag-pill__count {
- font-size: 0.8em;
- color: var(--ink-3);
-}
-
-/* ─── Archive ────────────────────────────────────── */
-
-.archive-list {
- display: grid;
- gap: 3rem;
-}
-
-.archive-group {
- display: grid;
- grid-template-columns: 80px minmax(0, 1fr);
- gap: 2rem;
-}
-
-.archive-group__year {
- margin: 0;
- font-size: 1.05rem;
- font-weight: 700;
- color: var(--ink-3);
- letter-spacing: -0.01em;
- padding-top: 0.2rem;
-}
-
-.archive-group__items {
- list-style: none;
- margin: 0;
- padding: 0;
-}
-
-.archive-entry {
- display: grid;
- grid-template-columns: 80px minmax(0, 1fr);
- gap: 1rem;
- padding: 0.5rem 0;
-}
-
-.archive-entry__date {
- color: var(--ink-3);
- font-size: 0.85rem;
- padding-top: 0.15rem;
-}
-
-.archive-entry__title {
- margin: 0 0 0.2rem;
- font-size: 1rem;
- font-weight: 600;
-}
-
-.archive-entry__summary {
- margin: 0;
- font-size: 0.9rem;
- color: var(--ink-2);
-}
-
-/* ─── Responsive ─────────────────────────────────── */
-
-@media (max-width: 680px) {
- main {
- max-width: calc(100% - 2rem);
- padding: 2rem 0 4rem;
- }
-
- h1 {
- font-size: 1.9rem;
- }
- h2 {
- font-size: 1.4rem;
- }
-
- .post-feed__link {
- grid-template-columns: 1fr;
- gap: 1rem;
- padding: 1.5rem 0;
- }
-
- .post-feed__image {
- aspect-ratio: 16 / 9;
- order: -1;
- }
-
- .taxonomy-list__item,
- .archive-group,
- .archive-entry {
- grid-template-columns: 1fr;
- }
-
- .archive-group {
- gap: 0.5rem;
- }
-
- .taxonomy-list__item {
- align-items: flex-start;
- flex-direction: column;
- gap: 0.5rem;
- }
-}
-
-/* ─── Pagination ─────────────────────────────────── */
-
-.pagination {
- display: flex;
- align-items: center;
- justify-content: space-between;
- gap: 1rem;
- padding-top: 2rem;
- border-top: 1px solid var(--rule);
- font-size: 0.95rem;
-}
-
-.pagination__prev,
-.pagination__next {
- color: var(--ink-2);
- text-decoration: none;
- transition: color 0.15s ease;
-}
-
-.pagination__prev:hover,
-.pagination__next:hover {
- color: var(--accent);
-}
-
-.pagination__info {
- color: var(--ink-3);
-}
-
-.archive-empty,
-.feed-empty {
- color: var(--ink-3);
- font-size: 0.95rem;
- padding: 2rem 0;
-}
diff --git a/src/styles/main.scss b/src/styles/main.scss
new file mode 100644
index 0000000..b2124c3
--- /dev/null
+++ b/src/styles/main.scss
@@ -0,0 +1,216 @@
+@use 'variables' as *;
+@use 'mixins';
+@use 'colors';
+@use 'typography';
+@use 'spacing';
+@use 'animations';
+@use 'comment';
+@use 'search';
+@use 'lightgallery';
+
+*,
+*::before,
+*::after {
+ box-sizing: border-box;
+ margin: 0;
+ padding: 0;
+ min-width: 0;
+}
+
+html {
+ scroll-behavior: smooth;
+ -webkit-text-size-adjust: 100%;
+ text-size-adjust: 100%;
+ hanging-punctuation: first last;
+}
+
+body {
+ margin: 0;
+ padding: 0;
+ font-family: var(--font-body);
+ font-size: var(--text-base);
+ line-height: var(--leading-normal);
+ color: var(--ink);
+ background-color: var(--bg);
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ word-wrap: break-word;
+ overflow-wrap: break-word;
+ overflow-x: hidden;
+ tab-size: 4;
+}
+
+::selection {
+ background-color: var(--accent);
+ color: var(--bg);
+}
+
+::-webkit-scrollbar {
+ width: 6px;
+ height: 6px;
+}
+
+::-webkit-scrollbar-track {
+ background: transparent;
+}
+
+::-webkit-scrollbar-thumb {
+ background: var(--caramel);
+ border-radius: $border-radius-full;
+}
+
+::-webkit-scrollbar-thumb:hover {
+ background: var(--accent);
+}
+
+a {
+ color: var(--accent);
+ text-decoration: none;
+ transition: color var(--duration-fast) var(--ease-out-quart);
+
+ &:hover {
+ color: var(--accent-hover);
+ }
+
+ @include mixins.focus-visible;
+}
+
+img,
+video,
+svg {
+ display: block;
+ max-width: 100%;
+ height: auto;
+}
+
+img {
+ border-radius: $border-radius-md;
+}
+
+p {
+ margin-block-end: var(--space-md);
+}
+
+blockquote {
+ margin-block: var(--space-lg);
+ padding: var(--space-md) var(--space-lg);
+ border-left: 3px solid var(--accent);
+ color: var(--ink-2);
+ font-size: var(--text-md);
+ line-height: var(--leading-relaxed);
+ background: var(--bg-raised);
+ border-radius: 0 $border-radius-sm $border-radius-sm 0;
+}
+
+pre {
+ padding: var(--space-lg);
+ border-radius: $border-radius-md;
+ overflow-x: auto;
+ background: var(--ink);
+ color: #f8f8f2;
+ font-family: var(--font-mono);
+ font-size: var(--text-sm);
+ line-height: var(--leading-relaxed);
+ tab-size: 2;
+
+ @include mixins.hide-scrollbar;
+}
+
+code {
+ font-family: var(--font-mono);
+ font-size: 0.88em;
+ padding: 0.15em 0.4em;
+ background: var(--bg-raised);
+ border: 1px solid var(--rule);
+ border-radius: $border-radius-sm;
+}
+
+pre > code {
+ all: unset;
+ font-size: 0.9em;
+ color: inherit;
+}
+
+hr {
+ margin-block: var(--space-2xl);
+ border: none;
+ border-top: 1px solid var(--rule);
+}
+
+table {
+ width: 100%;
+ border-collapse: collapse;
+ font-size: var(--text-sm);
+ overflow-x: auto;
+ display: block;
+
+ th,
+ td {
+ padding: var(--space-sm) var(--space-md);
+ border: 1px solid var(--rule);
+ text-align: left;
+ }
+
+ th {
+ background: var(--bg-raised);
+ font-weight: 600;
+ color: var(--ink);
+ }
+
+ td {
+ color: var(--ink-2);
+ }
+}
+
+.wi-container {
+ @include mixins.responsive-container;
+}
+
+.wi-section {
+ @include mixins.section-spacing;
+}
+
+.wi-sr-only {
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ padding: 0;
+ margin: -1px;
+ overflow: hidden;
+ clip: rect(0, 0, 0, 0);
+ white-space: nowrap;
+ border-width: 0;
+}
+
+.wi-main {
+ padding-top: 100px;
+ padding-bottom: 0;
+ position: relative;
+ z-index: 1;
+ background-color: var(--bg);
+}
+
+.wi-main--wide.wi-main--home {
+ padding-top: 0;
+ padding-bottom: 0;
+ padding-inline: 0;
+ background-color: transparent;
+ max-width: 100%;
+ margin: 0;
+ overflow-x: hidden;
+}
+
+.wi-content-wrap {
+ max-width: 800px;
+ margin: 0 auto;
+ padding-inline: clamp(1rem, 3vw, 2rem);
+}
+
+.wi-content-wrap--wide {
+ max-width: 1200px;
+}
+
+.wi-main--wide {
+ max-width: 1400px;
+ margin: 0 auto;
+}
diff --git a/test-like-api.js b/test-like-api.js
new file mode 100644
index 0000000..01527a6
--- /dev/null
+++ b/test-like-api.js
@@ -0,0 +1,8 @@
+(function(){
+ return fetch('/apis/api.halo.run/v1alpha1/posts/5152aea5-c2e8-4717-8bba-2263d46e19d5/likes', {method: 'POST'})
+ .then(function(r){
+ return r.text().then(function(t){
+ return JSON.stringify({status: r.status, body: t.substring(0, 500)});
+ });
+ });
+})()
diff --git a/theme.yaml b/theme.yaml
index b85fae7..af1e751 100644
--- a/theme.yaml
+++ b/theme.yaml
@@ -1,18 +1,30 @@
apiVersion: theme.halo.run/v1alpha1
kind: Theme
metadata:
- name: astro-starter
+ name: warm-island
spec:
- displayName: Astro Starter
+ displayName: WarmIsland 暖屿
author:
- name: Your Name
- website: https://github.com/YourName
- description: A starter theme for Halo.
- logo: https://www.halo.run/logo
- homepage: https://github.com/halo-sigs/theme-astro-starter
- issues: https://github.com/halo-sigs/theme-astro-starter/issues
+ name: WarmIsland
+ website: https://github.com/warm-island
+ description: 一座深夜里温暖、安静、治愈的小岛 — 具有独特气质的生活博客主题
+ logo: /themes/warm-island/assets/logo.png
+ homepage: https://github.com/warm-island/theme-warm-island
+ issues: https://github.com/warm-island/theme-warm-island/issues
+ settingName: "warm-island-setting"
+ configMapName: "warm-island-configMap"
+ customTemplates:
+ page:
+ - name: MessageBoard
+ description: 留言板
+ screenshot:
+ file: page_messageboard.html
+ - name: Equipment
+ description: 装备
+ screenshot:
+ file: equipment.html
version: "1.0.0"
- requires: ">=2.0.0"
+ requires: ">=2.24.0"
license:
- name: "GPL-3.0"
url: "https://www.gnu.org/licenses/gpl-3.0.en.html"
diff --git a/theme.zip b/theme.zip
new file mode 100644
index 0000000..43be12f
Binary files /dev/null and b/theme.zip differ