408 lines
12 KiB
JavaScript
408 lines
12 KiB
JavaScript
// src/composables/clientData.ts
|
|
import { inject } from "vue";
|
|
var clientDataSymbol = Symbol(
|
|
__VUEPRESS_DEV__ ? "clientData" : ""
|
|
);
|
|
var useClientData = () => {
|
|
const clientData = inject(clientDataSymbol);
|
|
if (!clientData) {
|
|
throw new Error("useClientData() is called without provider.");
|
|
}
|
|
return clientData;
|
|
};
|
|
|
|
// src/composables/clientDataUtils.ts
|
|
var useLayouts = () => useClientData().layouts;
|
|
var usePageComponent = () => useClientData().pageComponent;
|
|
var usePageData = () => useClientData().pageData;
|
|
var usePageFrontmatter = () => useClientData().pageFrontmatter;
|
|
var usePageHead = () => useClientData().pageHead;
|
|
var usePageLang = () => useClientData().pageLang;
|
|
var usePageLayout = () => useClientData().pageLayout;
|
|
var useRedirects = () => useClientData().redirects;
|
|
var useRouteLocale = () => useClientData().routeLocale;
|
|
var useRoutePath = () => useClientData().routePath;
|
|
var useRoutes = () => useClientData().routes;
|
|
var useSiteData = () => useClientData().siteData;
|
|
var useSiteLocaleData = () => useClientData().siteLocaleData;
|
|
|
|
// src/composables/updateHead.ts
|
|
import { inject as inject2 } from "vue";
|
|
var updateHeadSymbol = Symbol(
|
|
__VUEPRESS_DEV__ ? "updateHead" : ""
|
|
);
|
|
var useUpdateHead = () => {
|
|
const updateHead = inject2(updateHeadSymbol);
|
|
if (!updateHead) {
|
|
throw new Error("useUpdateHead() is called without provider.");
|
|
}
|
|
return updateHead;
|
|
};
|
|
|
|
// src/router/resolveRoutePath.ts
|
|
import { normalizeRoutePath } from "@vuepress/shared";
|
|
|
|
// src/internal/routes.ts
|
|
import {
|
|
redirects as redirectsRaw,
|
|
routes as routesRaw
|
|
} from "@internal/routes";
|
|
import { shallowRef } from "vue";
|
|
var redirects = shallowRef(redirectsRaw);
|
|
var routes = shallowRef(routesRaw);
|
|
if (__VUEPRESS_DEV__ && (import.meta.webpackHot || import.meta.hot)) {
|
|
__VUE_HMR_RUNTIME__.updateRedirects = (data) => {
|
|
redirects.value = data;
|
|
};
|
|
__VUE_HMR_RUNTIME__.updateRoutes = (data) => {
|
|
routes.value = data;
|
|
};
|
|
}
|
|
|
|
// src/router/resolveRoutePath.ts
|
|
var resolveRoutePath = (pathname, currentPath) => {
|
|
const normalizedRoutePath = normalizeRoutePath(pathname, currentPath);
|
|
if (routes.value[normalizedRoutePath]) return normalizedRoutePath;
|
|
const encodedRoutePath = encodeURI(normalizedRoutePath);
|
|
if (routes.value[encodedRoutePath]) {
|
|
return encodedRoutePath;
|
|
}
|
|
const redirectedRoutePath = redirects.value[normalizedRoutePath] || redirects.value[encodedRoutePath];
|
|
if (redirectedRoutePath) {
|
|
return redirectedRoutePath;
|
|
}
|
|
return normalizedRoutePath;
|
|
};
|
|
|
|
// src/router/resolveRoute.ts
|
|
import { splitPath } from "@vuepress/shared";
|
|
var resolveRoute = (path, currentPath) => {
|
|
const { pathname, hashAndQueries } = splitPath(path);
|
|
const routePath = resolveRoutePath(pathname, currentPath);
|
|
const routeFullPath = routePath + hashAndQueries;
|
|
if (!routes.value[routePath]) {
|
|
return {
|
|
...routes.value["/404.html"],
|
|
path: routeFullPath,
|
|
notFound: true
|
|
};
|
|
}
|
|
return {
|
|
...routes.value[routePath],
|
|
path: routeFullPath,
|
|
notFound: false
|
|
};
|
|
};
|
|
|
|
// src/router/resolveRouteFullPath.ts
|
|
import { splitPath as splitPath2 } from "@vuepress/shared";
|
|
var resolveRouteFullPath = (path, currentPath) => {
|
|
const { pathname, hashAndQueries } = splitPath2(path);
|
|
return resolveRoutePath(pathname, currentPath) + hashAndQueries;
|
|
};
|
|
|
|
// src/router/index.ts
|
|
import { useRoute, useRouter } from "vue-router";
|
|
|
|
// src/components/RouteLink.ts
|
|
import { computed, defineComponent, h } from "vue";
|
|
import { useRoute as useRoute2, useRouter as useRouter2 } from "vue-router";
|
|
var guardEvent = (event) => {
|
|
if (event.metaKey || event.altKey || event.ctrlKey || event.shiftKey) return;
|
|
if (event.defaultPrevented) return;
|
|
if (event.button !== void 0 && event.button !== 0) return;
|
|
if (event.currentTarget) {
|
|
const target = event.currentTarget.getAttribute("target");
|
|
if (target?.match(/\b_blank\b/i)) return;
|
|
}
|
|
event.preventDefault();
|
|
return true;
|
|
};
|
|
var RouteLink = defineComponent({
|
|
name: "RouteLink",
|
|
props: {
|
|
/**
|
|
* The route path to link to
|
|
*/
|
|
to: {
|
|
type: String,
|
|
required: true
|
|
},
|
|
/**
|
|
* Whether the link is active to have an active class
|
|
*
|
|
* Notice that the active status is not automatically determined according to the current route.
|
|
*/
|
|
active: Boolean,
|
|
/**
|
|
* The class to add when the link is active
|
|
*/
|
|
activeClass: {
|
|
type: String,
|
|
default: "route-link-active"
|
|
}
|
|
},
|
|
slots: Object,
|
|
setup(props, { slots }) {
|
|
const router = useRouter2();
|
|
const route = useRoute2();
|
|
const path = computed(
|
|
() => props.to.startsWith("#") || props.to.startsWith("?") ? props.to : `${__VUEPRESS_BASE__}${resolveRouteFullPath(props.to, route.path).substring(1)}`
|
|
);
|
|
return () => h(
|
|
"a",
|
|
{
|
|
class: ["route-link", { [props.activeClass]: props.active }],
|
|
href: path.value,
|
|
onClick: (event = {}) => {
|
|
if (guardEvent(event)) {
|
|
router.push(props.to).catch();
|
|
}
|
|
}
|
|
},
|
|
slots.default?.()
|
|
);
|
|
}
|
|
});
|
|
|
|
// src/components/AutoLink.ts
|
|
import { isLinkWithProtocol } from "@vuepress/shared";
|
|
import { computed as computed2, defineComponent as defineComponent2, h as h2, toRef } from "vue";
|
|
import { useRoute as useRoute3 } from "vue-router";
|
|
var AutoLink = defineComponent2({
|
|
name: "AutoLink",
|
|
props: {
|
|
config: {
|
|
type: Object,
|
|
required: true
|
|
}
|
|
},
|
|
slots: Object,
|
|
setup(props, { slots }) {
|
|
const config = toRef(props, "config");
|
|
const route = useRoute3();
|
|
const siteData = useSiteData();
|
|
const withProtocol = computed2(() => isLinkWithProtocol(config.value.link));
|
|
const linkTarget = computed2(
|
|
() => config.value.target || (withProtocol.value ? "_blank" : void 0)
|
|
);
|
|
const isBlankTarget = computed2(() => linkTarget.value === "_blank");
|
|
const isInternal = computed2(
|
|
() => !withProtocol.value && !isBlankTarget.value
|
|
);
|
|
const linkRel = computed2(
|
|
() => config.value.rel || (isBlankTarget.value ? "noopener noreferrer" : null)
|
|
);
|
|
const linkAriaLabel = computed2(
|
|
() => config.value.ariaLabel ?? config.value.text
|
|
);
|
|
const shouldBeActiveInSubpath = computed2(() => {
|
|
if (config.value.exact) return false;
|
|
const localePaths = Object.keys(siteData.value.locales);
|
|
return localePaths.length ? (
|
|
// Check all the locales
|
|
localePaths.every((key) => key !== config.value.link)
|
|
) : (
|
|
// Check root
|
|
config.value.link !== "/"
|
|
);
|
|
});
|
|
const isActive = computed2(() => {
|
|
if (!isInternal.value) return false;
|
|
if (config.value.activeMatch) {
|
|
return (config.value.activeMatch instanceof RegExp ? config.value.activeMatch : new RegExp(config.value.activeMatch, "u")).test(route.path);
|
|
}
|
|
if (shouldBeActiveInSubpath.value) {
|
|
return route.path.startsWith(config.value.link);
|
|
}
|
|
return route.path === config.value.link;
|
|
});
|
|
return () => {
|
|
const { before, after, default: defaultSlot } = slots;
|
|
const content = defaultSlot?.(config.value) || [
|
|
before?.(config.value),
|
|
config.value.text,
|
|
after?.(config.value)
|
|
];
|
|
return isInternal.value ? h2(
|
|
RouteLink,
|
|
{
|
|
"class": "auto-link",
|
|
"to": config.value.link,
|
|
"active": isActive.value,
|
|
"aria-label": linkAriaLabel.value
|
|
},
|
|
() => content
|
|
) : h2(
|
|
"a",
|
|
{
|
|
"class": "auto-link external-link",
|
|
"href": config.value.link,
|
|
"aria-label": linkAriaLabel.value,
|
|
"rel": linkRel.value,
|
|
"target": linkTarget.value
|
|
},
|
|
content
|
|
);
|
|
};
|
|
}
|
|
});
|
|
|
|
// src/components/ClientOnly.ts
|
|
import { defineComponent as defineComponent3, onMounted, ref } from "vue";
|
|
var ClientOnly = defineComponent3({
|
|
name: "ClientOnly",
|
|
setup(_, ctx) {
|
|
const isMounted = ref(false);
|
|
onMounted(() => {
|
|
isMounted.value = true;
|
|
});
|
|
return () => isMounted.value ? ctx.slots.default?.() : null;
|
|
}
|
|
});
|
|
|
|
// src/components/Content.ts
|
|
import { computed as computed3, defineAsyncComponent, defineComponent as defineComponent4, h as h3 } from "vue";
|
|
var Content = defineComponent4({
|
|
// eslint-disable-next-line vue/no-reserved-component-names
|
|
name: "Content",
|
|
props: {
|
|
path: {
|
|
type: String,
|
|
required: false,
|
|
default: ""
|
|
}
|
|
},
|
|
setup(props) {
|
|
const pageComponent = usePageComponent();
|
|
const ContentComponent = computed3(() => {
|
|
if (!props.path) return pageComponent.value;
|
|
const route = resolveRoute(props.path);
|
|
return defineAsyncComponent(() => route.loader().then(({ comp }) => comp));
|
|
});
|
|
return () => h3(ContentComponent.value);
|
|
}
|
|
});
|
|
|
|
// src/resolvers.ts
|
|
import { dedupeHead, isString, resolveLocalePath } from "@vuepress/shared";
|
|
import { reactive } from "vue";
|
|
|
|
// src/constants.ts
|
|
var LAYOUT_NAME_DEFAULT = "Layout";
|
|
var LANG_DEFAULT = "en-US";
|
|
|
|
// src/resolvers.ts
|
|
var resolvers = reactive({
|
|
/**
|
|
* Resolve layouts component map
|
|
*/
|
|
resolveLayouts: (clientConfigs) => clientConfigs.reduce(
|
|
(prev, item) => ({
|
|
...prev,
|
|
...item.layouts
|
|
}),
|
|
{}
|
|
),
|
|
/**
|
|
* Merge the head config in frontmatter and site locale
|
|
*
|
|
* Frontmatter should take priority over site locale
|
|
*/
|
|
resolvePageHead: (pageHeadTitle, pageFrontmatter, siteLocaleDate) => {
|
|
const description = isString(pageFrontmatter.description) ? pageFrontmatter.description : siteLocaleDate.description;
|
|
const head = [
|
|
...Array.isArray(pageFrontmatter.head) ? pageFrontmatter.head : [],
|
|
...siteLocaleDate.head,
|
|
["title", {}, pageHeadTitle],
|
|
["meta", { name: "description", content: description }]
|
|
];
|
|
return dedupeHead(head);
|
|
},
|
|
/**
|
|
* Resolve the content of page head title
|
|
*
|
|
* It would be used as the content of the `<title>` tag
|
|
*/
|
|
resolvePageHeadTitle: (pageData, siteLocaleDate) => [pageData.title, siteLocaleDate.title].filter((item) => !!item).join(" | "),
|
|
/**
|
|
* Resolve page language from page data
|
|
*
|
|
* It would be used as the `lang` attribute of `<html>` tag
|
|
*/
|
|
resolvePageLang: (pageData, siteLocaleData) => pageData.lang || siteLocaleData.lang || LANG_DEFAULT,
|
|
/**
|
|
* Resolve layout component of current page
|
|
*/
|
|
resolvePageLayout: (pageData, layouts) => {
|
|
const layoutName = isString(pageData.frontmatter.layout) ? pageData.frontmatter.layout : LAYOUT_NAME_DEFAULT;
|
|
if (!layouts[layoutName]) {
|
|
throw new Error(`[vuepress] Cannot resolve layout: ${layoutName}`);
|
|
}
|
|
return layouts[layoutName];
|
|
},
|
|
/**
|
|
* Resolve locale path according to route path and locales config
|
|
*/
|
|
resolveRouteLocale: (locales, routePath) => resolveLocalePath(locales, decodeURI(routePath)),
|
|
/**
|
|
* Resolve site data for specific locale
|
|
*
|
|
* It would merge the locales fields to the root fields
|
|
*/
|
|
resolveSiteLocaleData: ({ base, locales, ...siteData }, routeLocale) => ({
|
|
...siteData,
|
|
...locales[routeLocale],
|
|
head: [
|
|
// when merging head, the locales head should be placed before root head
|
|
// to get higher priority
|
|
...locales[routeLocale]?.head ?? [],
|
|
...siteData.head ?? []
|
|
]
|
|
})
|
|
});
|
|
|
|
// src/utils/defineClientConfig.ts
|
|
var defineClientConfig = (clientConfig = {}) => clientConfig;
|
|
|
|
// src/utils/withBase.ts
|
|
import { isLinkHttp, removeLeadingSlash } from "@vuepress/shared";
|
|
var withBase = (url) => {
|
|
if (isLinkHttp(url)) return url;
|
|
return `${__VUEPRESS_BASE__}${removeLeadingSlash(url)}`;
|
|
};
|
|
|
|
export {
|
|
clientDataSymbol,
|
|
useClientData,
|
|
useLayouts,
|
|
usePageComponent,
|
|
usePageData,
|
|
usePageFrontmatter,
|
|
usePageHead,
|
|
usePageLang,
|
|
usePageLayout,
|
|
useRedirects,
|
|
useRouteLocale,
|
|
useRoutePath,
|
|
useRoutes,
|
|
useSiteData,
|
|
useSiteLocaleData,
|
|
updateHeadSymbol,
|
|
useUpdateHead,
|
|
redirects,
|
|
routes,
|
|
resolveRoutePath,
|
|
resolveRoute,
|
|
resolveRouteFullPath,
|
|
useRoute,
|
|
useRouter,
|
|
RouteLink,
|
|
AutoLink,
|
|
ClientOnly,
|
|
Content,
|
|
resolvers,
|
|
defineClientConfig,
|
|
withBase
|
|
};
|