update menu actions

This commit is contained in:
ClovertaTheTrilobita 2026-04-19 02:20:01 +03:00
parent 2f48907035
commit b10aec8d15

View file

@ -10,12 +10,7 @@ interface Props {
} }
const { headings = [] } = Astro.props; const { headings = [] } = Astro.props;
// 只取 h2 / h3博客目录最常见
const tocHeadings = headings.filter((h) => h.depth === 2 || h.depth === 3); const tocHeadings = headings.filter((h) => h.depth === 2 || h.depth === 3);
// 手机端按钮里显示的“目录: 第一节、xxxxx”
const mobilePreview = tocHeadings[0]?.text ?? "本文目录";
--- ---
{ {
@ -79,24 +74,16 @@ const mobilePreview = tocHeadings[0]?.text ?? "本文目录";
) )
} }
<script is:inline> <style is:global>
(() => { :where(h1, h2, h3, h4, h5, h6) {
const btn = document.querySelector(".post-menu-mobile-toggle"); scroll-margin-top: 4rem;
const panel = document.querySelector("#post-menu-panel"); }
</style>
if (!btn || !panel) return;
btn.addEventListener("click", () => {
const expanded = btn.getAttribute("aria-expanded") === "true";
btn.setAttribute("aria-expanded", String(!expanded));
panel.classList.toggle("is-open", !expanded);
});
})();
</script>
<style> <style>
.post-menu { .post-menu {
box-sizing: border-box; box-sizing: border-box;
border: 1px solid gray;
} }
.post-menu-title { .post-menu-title {
@ -109,6 +96,7 @@ const mobilePreview = tocHeadings[0]?.text ?? "本文目录";
list-style: none; list-style: none;
margin: 0; margin: 0;
padding: 0; padding: 0;
font-size: 0.9rem;
} }
.post-menu-item { .post-menu-item {
@ -135,7 +123,7 @@ const mobilePreview = tocHeadings[0]?.text ?? "本文目录";
display: none; display: none;
} }
@media (min-width: 1200px) { @media (min-width: 1300px) {
.post-menu { .post-menu {
--menu-width: 180px; --menu-width: 180px;
position: fixed; position: fixed;
@ -149,7 +137,7 @@ const mobilePreview = tocHeadings[0]?.text ?? "本文目录";
} }
} }
@media (max-width: 1199px) { @media (max-width: 1299px) {
.post-menu-mobile-toggle { .post-menu-mobile-toggle {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
@ -159,15 +147,14 @@ const mobilePreview = tocHeadings[0]?.text ?? "本文目录";
right: 0.8rem; right: 0.8rem;
z-index: 30; z-index: 30;
max-width: min(78vw, 22rem); max-width: min(78vw, 22rem);
padding: 0.45rem 0.75rem; padding: 0.6rem 0.75rem;
border: 1.5px solid rgba(123, 169, 255, 0.55); border: 1.5px solid rgba(123, 169, 255, 0.55);
border-radius: 999px; border-radius: 999px;
background: rgba(249, 242, 237, 0.92); background: rgba(249, 242, 237, 0.92);
backdrop-filter: blur(6px); backdrop-filter: blur(6px);
color: inherit; color: inherit;
font-size: 0.8rem; font-size: 0.85rem;
cursor: pointer; cursor: pointer;
opacity: 0; opacity: 0;
transform: translateY(calc(-100% - 0.6rem)); transform: translateY(calc(-100% - 0.6rem));
pointer-events: none; pointer-events: none;
@ -191,10 +178,13 @@ const mobilePreview = tocHeadings[0]?.text ?? "本文目录";
} }
.post-menu-mobile-preview { .post-menu-mobile-preview {
display: inline-block;
width: 10rem;
/* height: 1rem; */
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
max-width: 14rem; text-align: left;
} }
.post-menu { .post-menu {
@ -208,7 +198,6 @@ const mobilePreview = tocHeadings[0]?.text ?? "本文目录";
overflow: auto; overflow: auto;
padding: 0.9rem 1rem; padding: 0.9rem 1rem;
border: 1.5px solid rgba(128, 128, 128, 0.55); border: 1.5px solid rgba(128, 128, 128, 0.55);
/* border-radius: 1rem; */
background: rgba(255, 255, 255, 0.96); background: rgba(255, 255, 255, 0.96);
backdrop-filter: blur(8px); backdrop-filter: blur(8px);
box-shadow: 0 6px 24px rgba(0, 0, 0, 0.08); box-shadow: 0 6px 24px rgba(0, 0, 0, 0.08);
@ -231,6 +220,8 @@ const mobilePreview = tocHeadings[0]?.text ?? "本文目录";
); );
if (!btn || !panel || !preview || headingLinks.length === 0) return; if (!btn || !panel || !preview || headingLinks.length === 0) return;
if (btn.dataset.bound === "true") return;
btn.dataset.bound = "true";
const defaultText = const defaultText =
preview.getAttribute("data-default-text") || "本文目录"; preview.getAttribute("data-default-text") || "本文目录";
@ -260,16 +251,27 @@ const mobilePreview = tocHeadings[0]?.text ?? "本文目录";
const closeMenu = () => { const closeMenu = () => {
panel.classList.remove("is-open"); panel.classList.remove("is-open");
btn.setAttribute("aria-expanded", "false"); btn.setAttribute("aria-expanded", "false");
document.addEventListener("click", (e) => {
const target = e.target;
if (!(target instanceof Node)) return;
const clickedInsidePanel = panel.contains(target);
const clickedButton = btn.contains(target);
if (!clickedInsidePanel && !clickedButton) {
closeMenu();
}
});
}; };
const updateVisibility = () => { const updateVisibility = () => {
if (window.innerWidth > 1199) { if (window.innerWidth >= 1200) {
btn.classList.remove("is-visible"); btn.classList.remove("is-visible");
closeMenu(); closeMenu();
return; return;
} }
const shouldShow = window.scrollY > 300; const shouldShow = window.scrollY > 80;
btn.classList.toggle("is-visible", shouldShow); btn.classList.toggle("is-visible", shouldShow);
if (!shouldShow) { if (!shouldShow) {
@ -278,7 +280,7 @@ const mobilePreview = tocHeadings[0]?.text ?? "本文目录";
}; };
const updateCurrentHeading = () => { const updateCurrentHeading = () => {
if (window.innerWidth > 1099) return; if (window.innerWidth >= 1200) return;
headingItems = getHeadingElements(); headingItems = getHeadingElements();
@ -312,9 +314,26 @@ const mobilePreview = tocHeadings[0]?.text ?? "本文目录";
panel.addEventListener("click", (e) => { panel.addEventListener("click", (e) => {
const target = e.target; const target = e.target;
if (target instanceof Element && target.closest("a")) { if (!(target instanceof Element)) return;
closeMenu();
} const link = target.closest("a[data-heading-link]");
if (!link) return;
const href = link.getAttribute("href");
if (!href || !href.startsWith("#")) return;
const el = document.getElementById(href.slice(1));
if (!el) return;
e.preventDefault();
el.scrollIntoView({
behavior: "smooth",
block: "start",
});
history.replaceState(null, "", href);
closeMenu();
}); });
const onScroll = () => { const onScroll = () => {