fuc-new/doc/node_modules/vuepress-plugin-md-power/lib/client/composables/demo.js
hellcat 6adbc04d4b 1
2025-10-03 17:17:08 +08:00

146 lines
4.3 KiB
JavaScript

import { computed, getCurrentInstance, onMounted, ref, toValue, useId, watch } from "vue";
import { onClickOutside, useEventListener } from "@vueuse/core";
import { isPlainObject } from "vuepress/shared";
//#region src/client/composables/demo.ts
function useExpand(defaultExpand = true) {
const expanded = ref(defaultExpand);
function toggle() {
expanded.value = !expanded.value;
}
return [expanded, toggle];
}
function useResources(el, config) {
const resources = computed(() => {
const conf = toValue(config);
if (!conf) return [];
return [{
name: "JavaScript",
items: conf.jsLib?.map((url) => ({
name: normalizeName(url),
url
}))
}, {
name: "CSS",
items: conf.cssLib?.map((url) => ({
name: normalizeName(url),
url
}))
}].filter((i) => i.items?.length);
});
function normalizeName(url) {
return url.slice(url.lastIndexOf("/") + 1);
}
const showResources = ref(false);
function toggleResources() {
showResources.value = !showResources.value;
}
onClickOutside(el, () => {
showResources.value = false;
});
return {
resources,
showResources,
toggleResources
};
}
function useFence(fence, config) {
const data = ref({
js: "",
css: "",
html: "",
jsType: "",
cssType: ""
});
onMounted(() => {
if (!fence.value) return;
const conf = toValue(config);
data.value.html = conf?.html ?? "";
const els = Array.from(fence.value.querySelectorAll("div[class*=\"language-\"]"));
for (const el of els) {
const lang = el.className.match(/language-(\w+)/)?.[1] ?? "";
const content = el.querySelector("pre")?.textContent ?? "";
if (lang === "js" || lang === "javascript") {
data.value.js = content;
data.value.jsType = "js";
}
if (lang === "ts" || lang === "typescript") {
data.value.js = content;
data.value.jsType = "ts";
}
if (lang === "css" || lang === "scss" || lang === "less" || lang === "stylus" || lang === "styl") {
data.value.css = content;
data.value.cssType = lang === "styl" ? "stylus" : lang;
}
}
});
return data;
}
function useNormalDemo(draw, title, config) {
const current = getCurrentInstance();
const id = useId();
const isDark = computed(() => current?.appContext.config.globalProperties.$isDark.value);
const height = ref("100px");
onMounted(() => {
if (!draw.value) return;
const iframeDoc = draw.value.contentDocument || draw.value.contentWindow?.document;
if (!iframeDoc) return;
const templateId = `VPDemoNormalDraw${id}`;
useEventListener("message", (event) => {
const data = parseData(event.data);
if (data.type === templateId) height.value = `${data.height + 5}px`;
});
watch([config, title], () => {
iframeDoc.write(createHTMLTemplate(toValue(title) || "Demo", templateId, toValue(config)));
}, { immediate: true });
watch(isDark, () => {
iframeDoc.documentElement.dataset.theme = isDark.value ? "dark" : "light";
}, { immediate: true });
});
return {
id,
height
};
}
function createHTMLTemplate(title, id, config) {
const { cssLib = [], jsLib = [], html, css, script } = config || {};
const stylesheet = cssLib.map((url) => `<link rel="stylesheet" href="${url}">`).join("");
const scripts = jsLib.map((url) => `<script src="${url}"><\/script>`).join("");
return `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>${title}</title>
${stylesheet}${scripts}
<style>${css}</style>
</head>
<body>
${html}
<script>;(function(){${script}})();<\/script>
<script>;(function(){
const height = Math.ceil(document.documentElement.getBoundingClientRect().height)
window.parent?.postMessage({ type: '${id}', height }, '*')
if (typeof window.ResizeObserver === 'undefined')
return
const resizeObserver = new ResizeObserver(entries => {
const height = Math.ceil(document.documentElement.getBoundingClientRect().height)
window.parent?.postMessage({ type: '${id}', height }, '*')
})
resizeObserver.observe(document.documentElement)
})();<\/script>
</body>
</html>`;
}
function parseData(data) {
try {
if (typeof data === "string") return JSON.parse(data);
else if (isPlainObject(data)) return data;
return {};
} catch {
return {};
}
}
//#endregion
export { parseData, useExpand, useFence, useNormalDemo, useResources };