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

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,297 @@
import { defineComponent, inject, onUnmounted, provide, reactive } from "vue";
import { useHead } from "#app/composables/head";
const HeadComponentCtxSymbol = Symbol("head-component");
const TagPositionProps = {
/**
* @deprecated Use tagPosition
*/
body: { type: Boolean, default: void 0 },
tagPosition: { type: String }
};
const normalizeProps = (_props) => {
const props = Object.fromEntries(
Object.entries(_props).filter(([_, value]) => value !== void 0)
);
if (typeof props.body !== "undefined") {
props.tagPosition = props.body ? "bodyClose" : "head";
}
if (typeof props.renderPriority !== "undefined") {
props.tagPriority = props.renderPriority;
}
return props;
};
function useHeadComponentCtx() {
return inject(HeadComponentCtxSymbol, createHeadComponentCtx, true);
}
function createHeadComponentCtx() {
const prev = inject(HeadComponentCtxSymbol, null);
if (prev) {
return prev;
}
const input = reactive({});
const entry = useHead(input);
const ctx = { input, entry };
provide(HeadComponentCtxSymbol, ctx);
return ctx;
}
const globalProps = {
accesskey: String,
autocapitalize: String,
autofocus: {
type: Boolean,
default: void 0
},
class: { type: [String, Object, Array], default: void 0 },
contenteditable: {
type: Boolean,
default: void 0
},
contextmenu: String,
dir: String,
draggable: {
type: Boolean,
default: void 0
},
enterkeyhint: String,
exportparts: String,
hidden: {
type: Boolean,
default: void 0
},
id: String,
inputmode: String,
is: String,
itemid: String,
itemprop: String,
itemref: String,
itemscope: String,
itemtype: String,
lang: String,
nonce: String,
part: String,
slot: String,
spellcheck: {
type: Boolean,
default: void 0
},
style: { type: [String, Object, Array], default: void 0 },
tabindex: String,
title: String,
translate: String,
/**
* @deprecated Use tagPriority
*/
renderPriority: [String, Number],
/**
* Unhead prop to modify the priority of the tag.
*/
tagPriority: { type: [String, Number] }
};
export const NoScript = defineComponent({
name: "NoScript",
inheritAttrs: false,
props: {
...globalProps,
...TagPositionProps,
title: String
},
setup(props, { slots }) {
const { input } = useHeadComponentCtx();
input.noscript ||= [];
const idx = input.noscript.push({}) - 1;
onUnmounted(() => input.noscript[idx] = null);
return () => {
const noscript = normalizeProps(props);
const slotVnodes = slots.default?.();
const textContent = [];
if (slotVnodes) {
for (const vnode of slotVnodes) {
if (vnode.children) {
textContent.push(vnode.children);
}
}
}
if (textContent.length > 0) {
noscript.innerHTML = textContent.join("");
}
input.noscript[idx] = noscript;
return null;
};
}
});
export const Link = defineComponent({
name: "Link",
inheritAttrs: false,
props: {
...globalProps,
...TagPositionProps,
as: String,
crossorigin: String,
disabled: Boolean,
fetchpriority: String,
href: String,
hreflang: String,
imagesizes: String,
imagesrcset: String,
integrity: String,
media: String,
prefetch: {
type: Boolean,
default: void 0
},
referrerpolicy: String,
rel: String,
sizes: String,
title: String,
type: String,
/** @deprecated **/
methods: String,
/** @deprecated **/
target: String
},
setup(props) {
const { input } = useHeadComponentCtx();
input.link ||= [];
const idx = input.link.push({}) - 1;
onUnmounted(() => input.link[idx] = null);
return () => {
input.link[idx] = normalizeProps(props);
return null;
};
}
});
export const Base = defineComponent({
name: "Base",
inheritAttrs: false,
props: {
...globalProps,
href: String,
target: String
},
setup(props) {
const { input } = useHeadComponentCtx();
onUnmounted(() => input.base = null);
return () => {
input.base = normalizeProps(props);
return null;
};
}
});
export const Title = defineComponent({
name: "Title",
inheritAttrs: false,
setup(_, { slots }) {
const { input } = useHeadComponentCtx();
onUnmounted(() => input.title = null);
return () => {
const defaultSlot = slots.default?.();
input.title = defaultSlot?.[0]?.children ? String(defaultSlot?.[0]?.children) : void 0;
if (import.meta.dev) {
if (defaultSlot && (defaultSlot.length > 1 || defaultSlot[0] && typeof defaultSlot[0].children !== "string")) {
console.error("<Title> can take only one string in its default slot.");
}
}
return null;
};
}
});
export const Meta = defineComponent({
name: "Meta",
inheritAttrs: false,
props: {
...globalProps,
charset: String,
content: String,
httpEquiv: String,
name: String,
property: String
},
setup(props) {
const { input } = useHeadComponentCtx();
input.meta ||= [];
const idx = input.meta.push({}) - 1;
onUnmounted(() => input.meta[idx] = null);
return () => {
const meta = { "http-equiv": props.httpEquiv, ...normalizeProps(props) };
if ("httpEquiv" in meta) {
delete meta.httpEquiv;
}
input.meta[idx] = meta;
return null;
};
}
});
export const Style = defineComponent({
name: "Style",
inheritAttrs: false,
props: {
...globalProps,
...TagPositionProps,
type: String,
media: String,
nonce: String,
title: String,
/** @deprecated **/
scoped: {
type: Boolean,
default: void 0
}
},
setup(props, { slots }) {
const { input } = useHeadComponentCtx();
input.style ||= [];
const idx = input.style.push({}) - 1;
onUnmounted(() => input.style[idx] = null);
return () => {
const style = normalizeProps(props);
const textContent = slots.default?.()?.[0]?.children;
if (textContent) {
if (import.meta.dev && typeof textContent !== "string") {
console.error("<Style> can only take a string in its default slot.");
}
input.style[idx] = style;
style.textContent = textContent;
}
return null;
};
}
});
export const Head = defineComponent({
name: "Head",
inheritAttrs: false,
setup: (_props, ctx) => {
createHeadComponentCtx();
return () => ctx.slots.default?.();
}
});
export const Html = defineComponent({
name: "Html",
inheritAttrs: false,
props: {
...globalProps,
manifest: String,
version: String,
xmlns: String
},
setup(_props, ctx) {
const { input } = useHeadComponentCtx();
onUnmounted(() => input.htmlAttrs = null);
return () => {
input.htmlAttrs = { ..._props, ...ctx.attrs };
return ctx.slots.default?.();
};
}
});
export const Body = defineComponent({
name: "Body",
inheritAttrs: false,
props: globalProps,
setup(_props, ctx) {
const { input } = useHeadComponentCtx();
onUnmounted(() => input.bodyAttrs = null);
return () => {
input.bodyAttrs = { ..._props, ...ctx.attrs };
return ctx.slots.default?.();
};
}
});

View file

@ -0,0 +1,18 @@
import type { ActiveHeadEntry, UseHeadInput, UseHeadOptions, UseHeadSafeInput, UseSeoMetaInput, VueHeadClient } from '@unhead/vue';
import type { NuxtApp } from '#app/nuxt';
/**
* Injects the head client from the Nuxt context or Vue inject.
*
* In Nuxt v3 this function will not throw an error if the context is missing.
*/
export declare function injectHead(nuxtApp?: NuxtApp): VueHeadClient;
interface NuxtUseHeadOptions extends UseHeadOptions {
nuxt?: NuxtApp;
}
export declare function useHead(input: UseHeadInput, options?: NuxtUseHeadOptions): ActiveHeadEntry<UseHeadInput> | void;
export declare function useHeadSafe(input: UseHeadSafeInput, options?: NuxtUseHeadOptions): ActiveHeadEntry<UseHeadSafeInput> | void;
export declare function useSeoMeta(input: UseSeoMetaInput, options?: NuxtUseHeadOptions): ActiveHeadEntry<UseSeoMetaInput> | void;
export declare function useServerHead(input: UseHeadInput, options?: NuxtUseHeadOptions): ActiveHeadEntry<UseHeadInput> | void;
export declare function useServerHeadSafe(input: UseHeadSafeInput, options?: NuxtUseHeadOptions): ActiveHeadEntry<UseHeadSafeInput> | void;
export declare function useServerSeoMeta(input: UseSeoMetaInput, options?: NuxtUseHeadOptions): ActiveHeadEntry<UseSeoMetaInput> | void;
export {};

View file

@ -0,0 +1,55 @@
import { hasInjectionContext, inject } from "vue";
import {
useHead as headCore,
useHeadSafe as headSafe,
headSymbol,
useSeoMeta as seoMeta,
useServerHead as serverHead,
useServerHeadSafe as serverHeadSafe,
useServerSeoMeta as serverSeoMeta
} from "@unhead/vue";
import { tryUseNuxtApp } from "#app/nuxt";
export function injectHead(nuxtApp) {
const nuxt = nuxtApp || tryUseNuxtApp();
return nuxt?.ssrContext?.head || nuxt?.runWithContext(() => {
if (hasInjectionContext()) {
return inject(headSymbol);
}
});
}
export function useHead(input, options = {}) {
const head = injectHead(options.nuxt);
if (head) {
return headCore(input, { head, ...options });
}
}
export function useHeadSafe(input, options = {}) {
const head = injectHead(options.nuxt);
if (head) {
return headSafe(input, { head, ...options });
}
}
export function useSeoMeta(input, options = {}) {
const head = injectHead(options.nuxt);
if (head) {
return seoMeta(input, { head, ...options });
}
}
export function useServerHead(input, options = {}) {
const head = injectHead(options.nuxt);
if (head) {
return serverHead(input, { head, ...options });
}
}
export function useServerHeadSafe(input, options = {}) {
const head = injectHead(options.nuxt);
if (head) {
return serverHeadSafe(input, { head, ...options });
}
}
export function useServerSeoMeta(input, options = {}) {
const head = injectHead(options.nuxt);
if (head) {
return serverSeoMeta(input, { head, ...options });
}
}

View file

@ -0,0 +1,25 @@
import type { ActiveHeadEntry, UseHeadInput, UseHeadOptions, UseHeadSafeInput, UseSeoMetaInput, VueHeadClient } from '@unhead/vue/types';
import type { NuxtApp } from '#app/nuxt';
/**
* Injects the head client from the Nuxt context or Vue inject.
*/
export declare function injectHead(nuxtApp?: NuxtApp): VueHeadClient;
interface NuxtUseHeadOptions extends UseHeadOptions {
nuxt?: NuxtApp;
}
export declare function useHead(input: UseHeadInput, options?: NuxtUseHeadOptions): ActiveHeadEntry<UseHeadInput>;
export declare function useHeadSafe(input: UseHeadSafeInput, options?: NuxtUseHeadOptions): ActiveHeadEntry<UseHeadSafeInput>;
export declare function useSeoMeta(input: UseSeoMetaInput, options?: NuxtUseHeadOptions): ActiveHeadEntry<UseSeoMetaInput>;
/**
* @deprecated Use `useHead` instead and wrap with `if (import.meta.server)`
*/
export declare function useServerHead(input: UseHeadInput, options?: NuxtUseHeadOptions): ActiveHeadEntry<UseHeadInput>;
/**
* @deprecated Use `useHeadSafe` instead and wrap with `if (import.meta.server)`
*/
export declare function useServerHeadSafe(input: UseHeadSafeInput, options?: NuxtUseHeadOptions): ActiveHeadEntry<UseHeadSafeInput>;
/**
* @deprecated Use `useSeoMeta` instead and wrap with `if (import.meta.server)`
*/
export declare function useServerSeoMeta(input: UseSeoMetaInput, options?: NuxtUseHeadOptions): ActiveHeadEntry<UseSeoMetaInput>;
export {};

View file

@ -0,0 +1,47 @@
import { hasInjectionContext, inject } from "vue";
import {
useHead as headCore,
useHeadSafe as headSafe,
headSymbol,
useSeoMeta as seoMeta,
useServerHead as serverHead,
useServerHeadSafe as serverHeadSafe,
useServerSeoMeta as serverSeoMeta
} from "@unhead/vue";
import { useNuxtApp } from "#app/nuxt";
export function injectHead(nuxtApp) {
const nuxt = nuxtApp || useNuxtApp();
return nuxt.ssrContext?.head || nuxt.runWithContext(() => {
if (hasInjectionContext()) {
const head = inject(headSymbol);
if (!head) {
throw new Error("[nuxt] [unhead] Missing Unhead instance.");
}
return head;
}
});
}
export function useHead(input, options = {}) {
const head = options.head || injectHead(options.nuxt);
return headCore(input, { head, ...options });
}
export function useHeadSafe(input, options = {}) {
const head = options.head || injectHead(options.nuxt);
return headSafe(input, { head, ...options });
}
export function useSeoMeta(input, options = {}) {
const head = options.head || injectHead(options.nuxt);
return seoMeta(input, { head, ...options });
}
export function useServerHead(input, options = {}) {
const head = options.head || injectHead(options.nuxt);
return serverHead(input, { head, ...options });
}
export function useServerHeadSafe(input, options = {}) {
const head = options.head || injectHead(options.nuxt);
return serverHeadSafe(input, { head, ...options });
}
export function useServerSeoMeta(input, options = {}) {
const head = options.head || injectHead(options.nuxt);
return serverSeoMeta(input, { head, ...options });
}

View file

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

View file

@ -0,0 +1,31 @@
import { createHead as createClientHead, renderDOMHead } from "@unhead/vue/client";
import { defineNuxtPlugin } from "#app/nuxt";
import unheadOptions from "#build/unhead-options.mjs";
export default defineNuxtPlugin({
name: "nuxt:head",
enforce: "pre",
setup(nuxtApp) {
const head = import.meta.server ? nuxtApp.ssrContext.head : createClientHead(unheadOptions);
nuxtApp.vueApp.use(head);
if (import.meta.client) {
let pauseDOMUpdates = true;
const syncHead = async () => {
pauseDOMUpdates = false;
await renderDOMHead(head);
};
head.hooks.hook("dom:beforeRender", (context) => {
context.shouldRender = !pauseDOMUpdates;
});
nuxtApp.hooks.hook("page:start", () => {
pauseDOMUpdates = true;
});
nuxtApp.hooks.hook("page:finish", () => {
if (!nuxtApp.isHydrating) {
syncHead();
}
});
nuxtApp.hooks.hook("app:error", syncHead);
nuxtApp.hooks.hook("app:suspense:resolve", syncHead);
}
}
});

View file

@ -0,0 +1,33 @@
import type { UseHeadInput, UseHeadOptions, VueHeadClient } from '@unhead/vue';
export type VueHeadClientPollyFill = VueHeadClient & {
/**
* @deprecated use `resolveTags`
*/
headTags: VueHeadClient['resolveTags'];
/**
* @deprecated use `push`
*/
addEntry: VueHeadClient['push'];
/**
* @deprecated use `push`
*/
addHeadObjs: VueHeadClient['push'];
/**
* @deprecated use `useHead`
*/
addReactiveEntry: (input: UseHeadInput, options?: UseHeadOptions) => (() => void);
/**
* @deprecated Use useHead API.
*/
removeHeadObjs: () => void;
/**
* @deprecated Call hook `entries:resolve` or update an entry
*/
updateDOM: () => void;
/**
* @deprecated Access unhead properties directly.
*/
unhead: VueHeadClient;
};
declare const _default: any;
export default _default;

View file

@ -0,0 +1,29 @@
import { defineNuxtPlugin } from "#app/nuxt";
import { useHead } from "#app/composables/head";
function polyfillAsVueUseHead(head) {
const polyfilled = head;
polyfilled.headTags = head.resolveTags;
polyfilled.addEntry = head.push;
polyfilled.addHeadObjs = head.push;
polyfilled.addReactiveEntry = (input, options) => {
const api = useHead(input, options);
if (api !== void 0) {
return api.dispose;
}
return () => {
};
};
polyfilled.removeHeadObjs = () => {
};
polyfilled.updateDOM = () => {
head.hooks.callHook("entries:updated", head);
};
polyfilled.unhead = head;
return polyfilled;
}
export default defineNuxtPlugin({
name: "nuxt:vueuse-head-polyfill",
setup(nuxtApp) {
polyfillAsVueUseHead(nuxtApp.vueApp._context.provides.usehead);
}
});

View file

@ -0,0 +1,7 @@
export type Props = Readonly<Record<string, any>>;
export type FetchPriority = 'high' | 'low' | 'auto';
export type CrossOrigin = '' | 'anonymous' | 'use-credentials';
export type HTTPEquiv = 'content-security-policy' | 'content-type' | 'default-style' | 'refresh' | 'x-ua-compatible';
export type ReferrerPolicy = '' | 'no-referrer' | 'no-referrer-when-downgrade' | 'same-origin' | 'origin' | 'strict-origin' | 'origin-when-cross-origin' | 'strict-origin-when-cross-origin' | 'unsafe-url';
export type LinkRelationship = 'alternate' | 'author' | 'canonical' | 'dns-prefetch' | 'help' | 'icon' | 'license' | 'manifest' | 'me' | 'modulepreload' | 'next' | 'pingback' | 'preconnect' | 'prefetch' | 'preload' | 'prerender' | 'prev' | 'search' | 'stylesheet' | (string & {});
export type Target = '_blank' | '_self' | '_parent' | '_top' | (string & {});

View file