@neosjs/vitepress-theme
Version:
NeosJS VitePress theme
140 lines (139 loc) • 3.89 kB
JavaScript
import { useMediaQuery } from "@vueuse/core";
import {
computed,
onMounted,
onUnmounted,
ref,
watch,
watchEffect,
watchPostEffect
} from "vue";
import { inBrowser, isActive } from "../shared.mjs";
import {
hasActiveLink as containsActiveLink,
getSidebar,
getSidebarGroups
} from "../support/sidebar.mjs";
import { useData } from "./data.mjs";
export function useSidebar() {
const { frontmatter, page, theme } = useData();
const is960 = useMediaQuery("(min-width: 960px)");
const isOpen = ref(false);
const _sidebar = computed(() => {
const sidebarConfig = theme.value.sidebar;
const relativePath = page.value.relativePath;
return sidebarConfig ? getSidebar(sidebarConfig, relativePath) : [];
});
const sidebar = ref(_sidebar.value);
watch(_sidebar, (next, prev) => {
if (JSON.stringify(next) !== JSON.stringify(prev))
sidebar.value = _sidebar.value;
});
const hasSidebar = computed(() => {
return frontmatter.value.sidebar !== false && sidebar.value.length > 0 && frontmatter.value.layout !== "home";
});
const hasAside = computed(() => {
if (frontmatter.value.layout === "home") return false;
if (frontmatter.value.aside != null) return !!frontmatter.value.aside;
return theme.value.aside !== false;
});
const leftAside = computed(() => {
if (hasAside) {
return frontmatter.value.aside == null ? theme.value.aside === "left" : frontmatter.value.aside === "left";
}
return false;
});
const isSidebarEnabled = computed(() => hasSidebar.value && is960.value);
const sidebarGroups = computed(() => {
return hasSidebar.value ? getSidebarGroups(sidebar.value) : [];
});
function open() {
isOpen.value = true;
}
function close() {
isOpen.value = false;
}
function toggle() {
isOpen.value ? close() : open();
}
return {
isOpen,
sidebar,
sidebarGroups,
hasSidebar,
hasAside,
leftAside,
isSidebarEnabled,
open,
close,
toggle
};
}
export function useCloseSidebarOnEscape(isOpen, close) {
let triggerElement;
watchEffect(() => {
triggerElement = isOpen.value ? document.activeElement : void 0;
});
onMounted(() => {
inBrowser && window.addEventListener("keyup", onEscape);
});
onUnmounted(() => {
inBrowser && window.removeEventListener("keyup", onEscape);
});
function onEscape(e) {
if (e.key === "Escape" && isOpen.value) {
close();
triggerElement?.focus();
}
}
}
const hashRef = ref(inBrowser ? location.hash : "");
inBrowser && window.addEventListener("hashchange", () => {
hashRef.value = location.hash;
});
export function useSidebarControl(item) {
const { page } = useData();
const collapsed = ref(false);
const collapsible = computed(() => {
return item.value.collapsed != null;
});
const isLink = computed(() => {
return !!item.value.link;
});
const isActiveLink = ref(false);
const updateIsActiveLink = () => {
isActiveLink.value = isActive(page.value.relativePath, item.value.link);
};
watch([page, item, hashRef], updateIsActiveLink);
onMounted(updateIsActiveLink);
const hasActiveLink = computed(() => {
if (isActiveLink.value) {
return true;
}
return item.value.items ? containsActiveLink(page.value.relativePath, item.value.items) : false;
});
const hasChildren = computed(() => {
return !!(item.value.items && item.value.items.length);
});
watchEffect(() => {
collapsed.value = !!(collapsible.value && item.value.collapsed);
});
watchPostEffect(() => {
;
(isActiveLink.value || hasActiveLink.value) && (collapsed.value = false);
});
function toggle() {
if (collapsible.value) {
collapsed.value = !collapsed.value;
}
}
return {
collapsed,
collapsible,
isLink,
isActiveLink,
hasActiveLink,
hasChildren,
toggle
};
}