Website Structure

This commit is contained in:
supalerk-ar66 2026-01-13 10:46:40 +07:00
parent 62812f2090
commit 71f0676a62
22365 changed files with 4265753 additions and 791 deletions

View file

@ -0,0 +1,2 @@
declare const _default: any;
export default _default;

View file

@ -0,0 +1,56 @@
import { defineNuxtPlugin, useRouter, useState } from "#imports";
import { shallowReactive, watchEffect } from "vue";
import { setupHooksDebug } from "../shared/hooks.js";
export default defineNuxtPlugin((nuxt) => {
if (typeof document === "undefined" || typeof window === "undefined")
return;
try {
if (window.__NUXT_DEVTOOLS_DISABLE__ || window.parent?.__NUXT_DEVTOOLS_DISABLE__)
return;
if (parent && window.self !== parent) {
if (parent.__NUXT_DEVTOOLS_VIEW__ || parent.document.querySelector("#nuxt-devtools-container"))
return;
}
} catch (e) {
console.error("Nuxt DevTools: Failed to check parent window");
console.error(e);
}
const timeMetric = shallowReactive(window.__NUXT_DEVTOOLS_TIME_METRIC__ || {});
Object.defineProperty(window, "__NUXT_DEVTOOLS_TIME_METRIC__", {
value: timeMetric,
enumerable: false,
configurable: true
});
timeMetric.pluginInit = Date.now();
const clientHooks = setupHooksDebug(nuxt.hooks);
const router = useRouter();
nuxt.hook("app:mounted", () => {
timeMetric.appLoad = Date.now();
});
router.beforeEach(() => {
timeMetric.pageStart = Date.now();
});
nuxt.hook("page:finish", () => {
timeMetric.pageEnd = Date.now();
});
const ssrState = useState("__nuxt_devtools__", () => ({}));
watchEffect(() => {
if (ssrState.value.timeSsrStart)
timeMetric.ssrStart = ssrState.value.timeSsrStart;
});
import("./view/client.js").then(async ({ setupDevToolsClient }) => {
await setupDevToolsClient({
nuxt,
clientHooks,
timeMetric,
router
});
const isMac = typeof navigator !== "undefined" && navigator.platform.toLowerCase().includes("mac");
console.log(
`\u2728 %cNuxt DevTools %c Press Shift + ${isMac ? "Option" : "Alt"} + D to open DevTools`,
"color: black; border-radius: 3px 0 0 3px; padding: 2px 2px 1px 10px; background: #00DC82",
"border-radius: 0 3px 3px 0; padding: 2px 10px 1px 2px; background: #00DC8220",
""
);
});
});

View file

@ -0,0 +1,2 @@
declare const _default: any;
export default _default;

View file

@ -0,0 +1,7 @@
import { defineNuxtPlugin, useState } from "#imports";
export default defineNuxtPlugin(() => {
const state = useState("__nuxt_devtools__", () => ({}));
state.value = {
timeSsrStart: Date.now()
};
});

View file

@ -0,0 +1,13 @@
import type { NuxtDevtoolsHostClient } from '@nuxt/devtools/types';
import type { Ref } from 'vue';
import type { Router } from 'vue-router';
declare const clientRef: import("vue").ShallowRef<NuxtDevtoolsHostClient | undefined, NuxtDevtoolsHostClient | undefined>;
export { clientRef as client };
export type ColorScheme = 'dark' | 'light';
export declare function setupDevToolsClient({ nuxt, clientHooks, timeMetric, router, }: {
nuxt: any;
clientHooks: any;
timeMetric: any;
router: Router;
}): Promise<void>;
export declare function useClientColorMode(): Ref<ColorScheme>;

View file

@ -0,0 +1,371 @@
import { useAppConfig, useRuntimeConfig } from "#imports";
import { NuxtDevtoolsFrame, NuxtDevtoolsInspectPanel } from "@nuxt/devtools/webcomponents";
import { setIframeServerContext } from "@vue/devtools-kit";
import { createHooks } from "hookable";
import { debounce } from "perfect-debounce";
import { events as inspectorEvents, hasData as inspectorHasData, state as inspectorState } from "vite-plugin-vue-tracer/client/overlay";
import { computed, markRaw, nextTick, reactive, ref, shallowReactive, shallowRef, toRef, watch } from "vue";
import { initTimelineMetrics } from "../../function-metrics-helpers.js";
import { settings } from "../../settings.js";
import { popupWindow, state } from "./state.js";
const clientRef = shallowRef();
export { clientRef as client };
export async function setupDevToolsClient({
nuxt,
clientHooks,
timeMetric,
router
}) {
let iframe;
let inspector;
const colorMode = useClientColorMode();
const timeline = initTimelineMetrics();
const client = shallowReactive({
nuxt: markRaw(nuxt),
hooks: createHooks(),
inspector: getInspectorInstance(),
getIframe,
syncClient,
devtools: {
toggle() {
if (state.value.open)
client.devtools.close();
else
client.devtools.open();
},
close() {
if (!state.value.open)
return;
state.value.open = false;
if (popupWindow.value) {
try {
popupWindow.value.close();
} catch {
}
popupWindow.value = null;
}
},
open() {
if (state.value.open)
return;
state.value.open = true;
},
async navigate(path) {
if (!state.value.open)
await client.devtools.open();
await client.hooks.callHook("host:action:navigate", path);
},
async reload() {
await client.hooks.callHook("host:action:reload");
}
},
app: {
appConfig: useAppConfig(),
reload() {
location.reload();
},
navigate(path, hard = false) {
if (hard)
location.href = path;
else
router.push(path);
},
colorMode,
frameState: state,
$fetch: globalThis.$fetch
},
metrics: {
clientPlugins: () => window.__NUXT_DEVTOOLS_PLUGINS_METRIC__,
clientHooks: () => Object.values(clientHooks),
clientTimeline: () => timeline,
loading: () => timeMetric
},
revision: ref(0)
});
window.__NUXT_DEVTOOLS_HOST__ = client;
function syncClient() {
if (!client.inspector)
client.inspector = getInspectorInstance();
try {
iframe?.contentWindow?.__NUXT_DEVTOOLS_VIEW__?.setClient(client);
} catch (e) {
console.error("[nuxt-devtools] Failed to connect view", e);
}
return client;
}
function getIframe() {
if (!iframe) {
const runtimeConfig = useRuntimeConfig();
const CLIENT_BASE = "/__nuxt_devtools__/client";
const CLIENT_PATH = `${runtimeConfig.app.baseURL.replace(CLIENT_BASE, "/")}${CLIENT_BASE}`.replace(/\/+/g, "/");
const initialUrl = CLIENT_PATH + state.value.route;
iframe = document.createElement("iframe");
for (const [key, value] of Object.entries(runtimeConfig.app.devtools?.iframeProps || {}))
iframe.setAttribute(key, String(value));
iframe.id = "nuxt-devtools-iframe";
iframe.src = initialUrl;
iframe.onload = async () => {
try {
setIframeServerContext(iframe);
await waitForClientInjection();
client.syncClient();
} catch (e) {
console.error("Nuxt DevTools client injection failed");
console.error(e);
}
};
}
return iframe;
}
function waitForClientInjection(retry = 20, timeout = 300) {
let lastError;
const test = () => {
try {
return !!iframe?.contentWindow?.__NUXT_DEVTOOLS_VIEW__;
} catch (e) {
lastError = e;
}
return false;
};
if (test())
return;
return new Promise((resolve, reject) => {
const interval = setInterval(() => {
if (test()) {
clearInterval(interval);
resolve();
} else if (retry-- <= 0) {
clearInterval(interval);
reject(lastError);
}
}, timeout);
});
}
function getInspectorInstance() {
if (inspector)
return inspector;
const props = reactive({
mouse: { x: 0, y: 0 },
hasParent: false,
matched: void 0
});
const component = new NuxtDevtoolsInspectPanel(reactive({ props }));
document.body.appendChild(component);
Object.assign(component.style, {
zIndex: 999999,
position: "fixed"
});
component.addEventListener("close", () => {
props.matched = void 0;
inspectorState.isEnabled = false;
inspectorState.isVisible = false;
});
component.addEventListener("selectParent", () => {
const parent = inspectorState.main?.getParent();
if (parent) {
inspectorState.main = parent;
props.matched = parent;
nextTick(() => {
props.hasParent = !!inspectorState.main?.getParent();
});
}
});
component.addEventListener("openInEditor", async (e) => {
const url = e?.detail?.[0];
if (url)
await client.hooks.callHook("host:inspector:click", url);
});
inspectorEvents.on("hover", () => {
inspectorState.isFocused = false;
props.hasParent = !!inspectorState.main?.getParent();
});
inspectorEvents.on("disabled", () => {
inspectorState.isVisible = false;
client?.hooks.callHook("host:inspector:close");
});
inspectorEvents.on("enabled", () => {
inspectorState.isVisible = true;
inspectorState.isEnabled = true;
});
inspectorEvents.on("click", async (info, e) => {
inspectorState.isEnabled = false;
inspectorState.isFocused = true;
inspectorState.isVisible = true;
props.matched = info;
props.mouse = { x: e.clientX, y: e.clientY };
});
const isAvailable = ref(inspectorHasData());
if (!isAvailable.value) {
inspectorEvents.on("hover", async () => {
isAvailable.value = inspectorHasData();
});
}
return inspector = markRaw({
isAvailable,
isEnabled: toRef(inspectorState, "isVisible"),
enable: () => {
inspectorState.isVisible = true;
inspectorState.isEnabled = true;
},
disable: () => {
inspectorState.isVisible = false;
inspectorState.isEnabled = false;
},
toggle: () => {
inspectorState.isEnabled = !inspectorState.isEnabled;
inspectorState.isVisible = inspectorState.isEnabled;
}
});
}
setupRouteTracking(timeline, router);
setupReactivity(client, router, timeline);
clientRef.value = client;
const documentPictureInPicture = window.documentPictureInPicture;
if (documentPictureInPicture?.requestWindow) {
client.devtools.popup = async () => {
const iframe2 = getIframe();
if (!iframe2)
return;
const pip = popupWindow.value = await documentPictureInPicture.requestWindow({
width: Math.round(window.innerWidth * state.value.width / 100),
height: Math.round(window.innerHeight * state.value.height / 100)
});
const style = pip.document.createElement("style");
style.innerHTML = `
body {
margin: 0;
padding: 0;
}
iframe {
width: 100vw;
height: 100vh;
border: none;
outline: none;
}
`;
pip.__NUXT_DEVTOOLS_DISABLE__ = true;
pip.__NUXT_DEVTOOLS_IS_POPUP__ = true;
pip.__NUXT__ = window.parent?.__NUXT__ || window.__NUXT__;
pip.document.title = "Nuxt DevTools";
pip.document.head.appendChild(style);
pip.document.body.appendChild(iframe2);
pip.addEventListener("resize", () => {
state.value.width = Math.round(pip.innerWidth / window.innerWidth * 100);
state.value.height = Math.round(pip.innerHeight / window.innerHeight * 100);
});
pip.addEventListener("pagehide", () => {
popupWindow.value = null;
pip.close();
});
};
}
const holder = document.createElement("div");
holder.id = "nuxt-devtools-container";
holder.setAttribute("data-v-inspector-ignore", "true");
document.body.appendChild(holder);
window.addEventListener("keydown", (e) => {
if (e.code === "KeyD" && e.altKey && e.shiftKey)
client.devtools.toggle();
});
const frame = new NuxtDevtoolsFrame(reactive({
client,
settings,
state,
popupWindow
}));
holder.appendChild(frame);
}
export function useClientColorMode() {
const explicitColor = ref();
const systemColor = ref();
const elements = [
document.documentElement,
document.body
];
const ob = new MutationObserver(getExplicitColor);
elements.forEach((el) => {
ob.observe(el, {
attributes: true,
attributeFilter: ["class"]
});
});
const preferDarkQuery = window.matchMedia("(prefers-color-scheme: dark)");
const preferLightQuery = window.matchMedia("(prefers-color-scheme: light)");
preferDarkQuery.addEventListener("change", getSystemColor);
preferLightQuery.addEventListener("change", getSystemColor);
function getExplicitColor() {
let color;
for (const el of elements) {
if (el.classList.contains("dark")) {
color = "dark";
break;
}
if (el.classList.contains("light")) {
color = "light";
break;
}
}
explicitColor.value = color;
}
function getSystemColor() {
if (preferDarkQuery.matches)
systemColor.value = "dark";
else if (preferLightQuery.matches)
systemColor.value = "light";
else
systemColor.value = void 0;
}
getExplicitColor();
getSystemColor();
return computed(() => explicitColor.value || systemColor.value || "light");
}
function setupRouteTracking(timeline, router) {
if (timeline.options.enabled && router?.currentRoute?.value?.path) {
const start = timeline.events[0]?.start || Date.now();
timeline.events.unshift({
type: "route",
from: router.currentRoute.value.path,
to: router.currentRoute.value.path,
start,
end: start
});
}
let lastRouteEvent;
router?.afterEach(() => {
if (lastRouteEvent && !lastRouteEvent?.end)
lastRouteEvent.end = Date.now();
});
router?.beforeEach((to, from) => {
if (!timeline.options.enabled)
return;
lastRouteEvent = {
type: "route",
from: from.path,
to: to.path,
start: Date.now()
};
timeline.events.push(lastRouteEvent);
});
}
function setupReactivity(client, router, timeMetric) {
const refreshReactivity = debounce(() => {
client.hooks.callHook("host:update:reactivity");
}, 100, { trailing: true });
watch(() => [
client.nuxt.payload,
client.app.colorMode.value,
client.metrics.loading(),
timeMetric
], () => {
refreshReactivity();
}, { deep: true });
router?.afterEach(() => {
refreshReactivity();
});
client.nuxt.hook("app:mounted", () => {
refreshReactivity();
});
client.hooks.hook("devtools:navigate", (path) => {
state.value.route = path;
});
}

View file

@ -0,0 +1,3 @@
import type { DevToolsFrameState } from '@nuxt/devtools/types';
export declare const popupWindow: import("vue").ShallowRef<Window | null, Window | null>;
export declare const state: import("vue").Ref<DevToolsFrameState, DevToolsFrameState>;

View file

@ -0,0 +1,14 @@
import { shallowRef } from "vue";
import { useObjectStorage } from "./utils.js";
export const popupWindow = shallowRef(null);
export const state = useObjectStorage("nuxt-devtools-frame-state", {
width: 80,
height: 60,
top: 0,
left: 50,
open: false,
route: "/",
position: "bottom",
closeOnOutsideClick: false,
minimizePanelInactive: 5e3
}, false);

View file

@ -0,0 +1,3 @@
import type { Ref } from 'vue';
export declare function useObjectStorage<T>(key: string, initial: T, listenToStorage?: boolean): Ref<T>;
export declare function useEventListener(target: EventTarget, type: string, listener: any, options?: boolean | AddEventListenerOptions): void;

View file

@ -0,0 +1,32 @@
import { getCurrentScope, onScopeDispose, ref, watch } from "vue";
export function useObjectStorage(key, initial, listenToStorage = true) {
const raw = localStorage.getItem(key);
const data = ref(raw ? JSON.parse(raw) : initial);
for (const key2 in initial) {
if (data.value[key2] === void 0)
data.value[key2] = initial[key2];
}
let updating = false;
let wrote = "";
watch(data, (value) => {
if (updating)
return;
wrote = JSON.stringify(value);
localStorage.setItem(key, wrote);
}, { deep: true, flush: "post" });
if (listenToStorage) {
useEventListener(window, "storage", (e) => {
if (e.key === key && e.newValue && e.newValue !== wrote) {
updating = true;
data.value = JSON.parse(e.newValue);
updating = false;
}
});
}
return data;
}
export function useEventListener(target, type, listener, options) {
target.addEventListener(type, listener, options);
if (getCurrentScope())
onScopeDispose(() => target.removeEventListener(type, listener, options));
}

View file

@ -0,0 +1,2 @@
declare const _default: any;
export default _default;

View file

@ -0,0 +1,4 @@
import { defineNuxtPlugin } from "#imports";
export default defineNuxtPlugin(() => {
import("@vitejs/devtools/client/inject");
});