修复移动端目录悬浮球,修复文章页布局,优化画廊

This commit is contained in:
nxxy335top committed 2026-05-21 22:56:57 +08:00
1 parent 788d0cc488
commit 67dc37c308
355 files changed
+1407 -270

No files matched your search

+56
View File
@@ -0,0 +1,56 @@
---
---
<div class="wi-cursor-glow" id="wi-cursor-glow"></div>
<script is:inline>
(function(){
var glowEl = document.getElementById("wi-cursor-glow");
if (!glowEl) return;
var rafId = 0;
document.addEventListener("mousemove", function(e) {
if (rafId) return;
rafId = requestAnimationFrame(function() {
glowEl.style.transform = "translate(calc(" + e.clientX + "px - 50%), calc(" + e.clientY + "px - 50%))";
glowEl.classList.add("wi-cursor-glow--visible");
rafId = 0;
});
}, { passive: true });
document.addEventListener("mouseleave", function() {
glowEl.classList.remove("wi-cursor-glow--visible");
});
})();
</script>
<style>
.wi-cursor-glow {
position: fixed;
top: 0;
left: 0;
width: 400px;
height: 400px;
border-radius: 50%;
background: radial-gradient(
circle,
rgba(212, 118, 78, 0.06) 0%,
transparent 70%
);
pointer-events: none;
z-index: 9999;
opacity: 0;
transition: opacity 0.3s ease;
will-change: transform;
}
.wi-cursor-glow--visible {
opacity: 1;
}
html.dark .wi-cursor-glow {
background: radial-gradient(
circle,
rgba(232, 149, 95, 0.04) 0%,
transparent 70%
);
}
</style>
-74
View File
@@ -1,74 +0,0 @@
<script lang="ts" setup>
import { ref, onMounted, onUnmounted } from "vue";
const glowEl = ref<HTMLElement | null>(null);
const visible = ref(false);
var rafId = 0;
function handleMouseMove(e: MouseEvent) {
if (rafId) return;
rafId = requestAnimationFrame(() => {
if (glowEl.value) {
glowEl.value.style.transform = `translate(calc(${e.clientX}px - 50%), calc(${e.clientY}px - 50%))`;
}
rafId = 0;
});
visible.value = true;
}
function handleMouseLeave() {
visible.value = false;
}
onMounted(() => {
document.addEventListener("mousemove", handleMouseMove, { passive: true });
document.addEventListener("mouseleave", handleMouseLeave);
});
onUnmounted(() => {
document.removeEventListener("mousemove", handleMouseMove);
document.removeEventListener("mouseleave", handleMouseLeave);
if (rafId) cancelAnimationFrame(rafId);
});
</script>
<template>
<div
ref="glowEl"
class="wi-cursor-glow"
:class="{ 'wi-cursor-glow--visible': visible }"
/>
</template>
<style scoped>
.wi-cursor-glow {
position: fixed;
top: 0;
left: 0;
width: 400px;
height: 400px;
border-radius: 50%;
background: radial-gradient(
circle,
rgba(212, 118, 78, 0.06) 0%,
transparent 70%
);
pointer-events: none;
z-index: 9999;
opacity: 0;
transition: opacity 0.3s ease;
will-change: transform;
}
.wi-cursor-glow--visible {
opacity: 1;
}
html.dark .wi-cursor-glow {
background: radial-gradient(
circle,
rgba(232, 149, 95, 0.04) 0%,
transparent 70%
);
}
</style>
+1 -1
View File
@@ -1,5 +1,5 @@
---
const THEME_VERSION = "0.1.0";
const THEME_VERSION = "1.0.0";
const today = new Date();
---
+13 -16
View File
@@ -6,14 +6,10 @@
import 'lightgallery/css/lg-zoom.css';
import 'lightgallery/css/lg-thumbnail.css';
import 'lightgallery/css/lg-fullscreen.css';
import 'lightgallery/css/lg-rotate.css';
import 'lightgallery/css/lg-autoplay.css';
import lightGallery from 'lightgallery';
import lgZoom from 'lightgallery/plugins/zoom';
import lgThumbnail from 'lightgallery/plugins/thumbnail';
import lgFullscreen from 'lightgallery/plugins/fullscreen';
import lgRotate from 'lightgallery/plugins/rotate';
import lgAutoplay from 'lightgallery/plugins/autoplay';
var _initialized = new WeakSet();
@@ -74,7 +70,7 @@
function createLgConfig() {
return {
selector: '.wi-lightgallery-item',
plugins: [lgZoom, lgThumbnail, lgFullscreen, lgRotate, lgAutoplay],
plugins: [lgZoom, lgThumbnail, lgFullscreen],
speed: 280,
mode: 'lg-fade',
licenseKey: '0000-0000-0000-0000',
@@ -89,15 +85,6 @@
showZoomInOutIcons: true,
toggleThumb: true,
allowMediaOverlap: true,
autoplay: true,
slideShowAutoplay: false,
slideShowInterval: 5000,
progressBar: true,
autoplayControls: true,
forceSlideShowAutoplay: false,
rotate: true,
flipHorizontal: false,
flipVertical: false,
mobileSettings: {
controls: true,
showCloseIcon: true,
@@ -272,8 +259,18 @@
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initLightGallery);
document.addEventListener('DOMContentLoaded', function() {
if ('requestIdleCallback' in window) {
requestIdleCallback(initLightGallery, { timeout: 2000 });
} else {
setTimeout(initLightGallery, 200);
}
});
} else {
initLightGallery();
if ('requestIdleCallback' in window) {
requestIdleCallback(initLightGallery, { timeout: 2000 });
} else {
setTimeout(initLightGallery, 200);
}
}
</script>
+8 -5
View File
@@ -1,5 +1,5 @@
---
import ThemeSwitcher from "./ThemeSwitcher.vue";
import ThemeSwitcher from "./ThemeSwitcher.astro";
---
<header class="wi-navbar-wrapper" id="wi-navbar" th:classappend="${theme.config?.navbar?.navbar_style == 'minimal'} ? 'wi-navbar--minimal' : (${theme.config?.navbar?.navbar_style == 'float'} ? 'wi-navbar--float' : 'wi-navbar--glass')">
@@ -10,6 +10,8 @@ import ThemeSwitcher from "./ThemeSwitcher.vue";
th:src="${theme.config?.basic?.logo}"
alt=""
class="wi-navbar__logo"
loading="eager"
decoding="async"
/>
<span
th:if="${#strings.isEmpty(theme.config?.basic?.logo)}"
@@ -42,7 +44,7 @@ import ThemeSwitcher from "./ThemeSwitcher.vue";
<div class="wi-navbar__actions">
<button
th:if="${pluginFinder.available('PluginSearchWidget') and theme.config?.navbar?.navbar_show_search != false}"
class="wi-navbar__action-btn"
class="wi-navbar__action-btn wi-navbar__search-btn"
type="button"
th:aria-label="${theme.config?.basic?.label_search ?: #messages.msg('common.search')}"
onclick="SearchWidget.open()"
@@ -52,7 +54,7 @@ import ThemeSwitcher from "./ThemeSwitcher.vue";
<th:block th:if="${theme.config?.navbar?.navbar_show_theme_switch != false}">
<span th:attr="data-label=${theme.config?.basic?.label_theme_switch ?: #messages.msg('common.themeSwitch')}" style="display:inline-flex">
<ThemeSwitcher client:idle />
<ThemeSwitcher />
</span>
</th:block>
@@ -315,8 +317,9 @@ import ThemeSwitcher from "./ThemeSwitcher.vue";
display: none;
}
.wi-navbar__action-btn[aria-label="Search"] {
display: none;
.wi-navbar__action-btn {
width: 40px;
height: 40px;
}
.wi-navbar__menu-btn {
+31
View File
@@ -0,0 +1,31 @@
---
---
<script is:inline>
(function(){
var enabled = !document.documentElement.classList.contains("wi-no-animations");
if (!enabled) {
document.querySelectorAll(".wi-reveal").forEach(function(el) {
el.classList.add("wi-revealed");
});
return;
}
if (!("IntersectionObserver" in window)) {
document.querySelectorAll(".wi-reveal").forEach(function(el) {
el.classList.add("wi-revealed");
});
return;
}
var observer = new IntersectionObserver(function(entries) {
entries.forEach(function(entry) {
if (entry.isIntersecting) {
entry.target.classList.add("wi-revealed");
observer.unobserve(entry.target);
}
});
}, { threshold: 0.1, rootMargin: "0px 0px -40px 0px" });
document.querySelectorAll(".wi-reveal").forEach(function(el) {
observer.observe(el);
});
})();
</script>
-36
View File
@@ -1,36 +0,0 @@
<script lang="ts" setup>
import { ref, onMounted, onUnmounted } from "vue";
const observer = ref<IntersectionObserver | null>(null);
onMounted(() => {
const animationEnabled = !document.documentElement.classList.contains(
"wi-no-animations"
);
if (!animationEnabled) return;
observer.value = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.classList.add("wi-revealed");
observer.value?.unobserve(entry.target);
}
});
},
{ threshold: 0.1, rootMargin: "0px 0px -40px 0px" }
);
document.querySelectorAll(".wi-reveal").forEach((el) => {
observer.value?.observe(el);
});
});
onUnmounted(() => {
observer.value?.disconnect();
});
</script>
<template>
<slot />
</template>
+93
View File
@@ -0,0 +1,93 @@
---
---
<button
class="theme-toggle"
type="button"
id="wi-theme-toggle"
aria-label="切换主题"
title="切换主题"
>
<svg class="theme-toggle__icon theme-toggle__icon--sun" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="5"></circle>
<line x1="12" y1="1" x2="12" y2="3"></line>
<line x1="12" y1="21" x2="12" y2="23"></line>
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
<line x1="1" y1="12" x2="3" y2="12"></line>
<line x1="21" y1="12" x2="23" y2="12"></line>
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
</svg>
<svg class="theme-toggle__icon theme-toggle__icon--moon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path>
</svg>
</button>
<script is:inline>
(function(){
var btn = document.getElementById("wi-theme-toggle");
if (!btn) return;
var sunIcon = btn.querySelector(".theme-toggle__icon--sun");
var moonIcon = btn.querySelector(".theme-toggle__icon--moon");
var isDark = document.documentElement.classList.contains("dark");
function updateIcons() {
if (isDark) {
sunIcon.style.display = "";
moonIcon.style.display = "none";
} else {
sunIcon.style.display = "none";
moonIcon.style.display = "";
}
}
var labelEl = document.querySelector("[data-label]");
if (labelEl) {
var label = labelEl.getAttribute("data-label") || "切换主题";
btn.setAttribute("aria-label", label);
btn.setAttribute("title", label);
}
updateIcons();
btn.addEventListener("click", function() {
document.documentElement.classList.add("wi-theme-transition");
isDark = !isDark;
document.documentElement.classList.toggle("dark", isDark);
document.documentElement.setAttribute("data-color-scheme", isDark ? "dark" : "light");
localStorage.setItem("wi-theme", isDark ? "dark" : "light");
var tc = document.querySelector('meta[name="theme-color"]');
if (tc) tc.setAttribute("content", isDark ? "#1a1614" : "#faf7f2");
updateIcons();
setTimeout(function() {
document.documentElement.classList.remove("wi-theme-transition");
}, 300);
});
})();
</script>
<style>
.theme-toggle {
display: inline-flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
width: 34px;
height: 34px;
padding: 0;
border: none;
border-radius: 8px;
background: transparent;
color: var(--ink-2);
cursor: pointer;
transition:
background 0.15s ease,
color 0.15s ease;
}
.theme-toggle:hover {
background: var(--bg-raised);
color: var(--ink);
}
</style>
-64
View File
@@ -1,64 +0,0 @@
<script lang="ts" setup>
import { ref, onMounted } from "vue";
import MingcuteMoonLine from "~icons/mingcute/moon-line";
import MingcuteSunLine from "~icons/mingcute/sun-line";
const isDark = ref(false);
const label = ref("切换主题");
onMounted(() => {
isDark.value = document.documentElement.classList.contains("dark");
const parent = document.querySelector("[data-label]");
if (parent) {
label.value = parent.getAttribute("data-label") || "切换主题";
}
});
function toggle() {
document.documentElement.classList.add("wi-theme-transition");
isDark.value = !isDark.value;
document.documentElement.classList.toggle("dark", isDark.value);
localStorage.setItem("wi-theme", isDark.value ? "dark" : "light");
setTimeout(() => {
document.documentElement.classList.remove("wi-theme-transition");
}, 300);
}
</script>
<template>
<button
class="theme-toggle"
type="button"
:aria-label="label"
:title="label"
@click="toggle"
>
<MingcuteSunLine v-if="isDark" />
<MingcuteMoonLine v-else />
</button>
</template>
<style scoped>
.theme-toggle {
display: inline-flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
width: 34px;
height: 34px;
padding: 0;
border: none;
border-radius: 8px;
background: transparent;
color: var(--ink-2);
cursor: pointer;
transition:
background 0.15s ease,
color 0.15s ease;
}
.theme-toggle:hover {
background: var(--bg-raised);
color: var(--ink);
}
</style>