nuxtseo-shared 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +9 -0
- package/dist/client/composables/rpc.d.mts +21 -0
- package/dist/client/composables/rpc.d.ts +21 -0
- package/dist/client/composables/rpc.mjs +25 -0
- package/dist/client/composables/shiki.d.mts +13 -0
- package/dist/client/composables/shiki.d.ts +13 -0
- package/dist/client/composables/shiki.mjs +39 -0
- package/dist/client/index.d.mts +7 -0
- package/dist/client/index.d.ts +7 -0
- package/dist/client/index.mjs +6 -0
- package/dist/content.d.mts +82 -0
- package/dist/content.d.ts +82 -0
- package/dist/content.mjs +38 -0
- package/dist/devtools.d.mts +14 -0
- package/dist/devtools.d.ts +14 -0
- package/dist/devtools.mjs +46 -0
- package/dist/i18n.d.mts +28 -0
- package/dist/i18n.d.ts +28 -0
- package/dist/i18n.mjs +121 -0
- package/dist/index.d.mts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.mjs +7 -0
- package/dist/kit.d.mts +32 -0
- package/dist/kit.d.ts +32 -0
- package/dist/kit.mjs +91 -0
- package/dist/pro.d.mts +18 -0
- package/dist/pro.d.ts +18 -0
- package/dist/pro.mjs +70 -0
- package/dist/runtime/server/kit.d.mts +7 -0
- package/dist/runtime/server/kit.d.ts +7 -0
- package/dist/runtime/server/kit.mjs +27 -0
- package/package.json +117 -0
- package/src/client/components/NuxtSeoLogo.vue +77 -0
- package/src/client/components/OCodeBlock.vue +28 -0
- package/src/client/components/OSectionBlock.vue +148 -0
package/dist/kit.d.mts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Nuxt } from '@nuxt/schema';
|
|
2
|
+
import { Nitro } from 'nitropack';
|
|
3
|
+
import { NitroConfig } from 'nitropack/types';
|
|
4
|
+
import { NuxtPage, NuxtModule } from 'nuxt/schema';
|
|
5
|
+
|
|
6
|
+
declare function detectTarget(options?: {
|
|
7
|
+
static?: boolean;
|
|
8
|
+
}): string | undefined;
|
|
9
|
+
declare function resolveNitroPreset(nitroConfig?: NitroConfig): string;
|
|
10
|
+
/**
|
|
11
|
+
* Get the user provided options for a Nuxt module.
|
|
12
|
+
*
|
|
13
|
+
* These options may not be the resolved options that the module actually uses.
|
|
14
|
+
*/
|
|
15
|
+
declare function getNuxtModuleOptions(module: string | NuxtModule, nuxt?: Nuxt): Promise<Record<string, any>>;
|
|
16
|
+
declare function isNuxtGenerate(nuxt?: Nuxt): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Generate TypeScript type augmentations for a Nuxt module.
|
|
19
|
+
*/
|
|
20
|
+
declare function extendTypes(module: string, template: (options: {
|
|
21
|
+
typesPath: string;
|
|
22
|
+
}) => string | Promise<string>): void;
|
|
23
|
+
/**
|
|
24
|
+
* Create a promise that resolves when Nuxt pages are resolved.
|
|
25
|
+
*/
|
|
26
|
+
declare function createPagesPromise(nuxt?: Nuxt): Promise<NuxtPage[]>;
|
|
27
|
+
/**
|
|
28
|
+
* Create a promise that resolves when Nitro is initialized.
|
|
29
|
+
*/
|
|
30
|
+
declare function createNitroPromise(nuxt?: Nuxt): Promise<Nitro>;
|
|
31
|
+
|
|
32
|
+
export { createNitroPromise, createPagesPromise, detectTarget, extendTypes, getNuxtModuleOptions, isNuxtGenerate, resolveNitroPreset };
|
package/dist/kit.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Nuxt } from '@nuxt/schema';
|
|
2
|
+
import { Nitro } from 'nitropack';
|
|
3
|
+
import { NitroConfig } from 'nitropack/types';
|
|
4
|
+
import { NuxtPage, NuxtModule } from 'nuxt/schema';
|
|
5
|
+
|
|
6
|
+
declare function detectTarget(options?: {
|
|
7
|
+
static?: boolean;
|
|
8
|
+
}): string | undefined;
|
|
9
|
+
declare function resolveNitroPreset(nitroConfig?: NitroConfig): string;
|
|
10
|
+
/**
|
|
11
|
+
* Get the user provided options for a Nuxt module.
|
|
12
|
+
*
|
|
13
|
+
* These options may not be the resolved options that the module actually uses.
|
|
14
|
+
*/
|
|
15
|
+
declare function getNuxtModuleOptions(module: string | NuxtModule, nuxt?: Nuxt): Promise<Record<string, any>>;
|
|
16
|
+
declare function isNuxtGenerate(nuxt?: Nuxt): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Generate TypeScript type augmentations for a Nuxt module.
|
|
19
|
+
*/
|
|
20
|
+
declare function extendTypes(module: string, template: (options: {
|
|
21
|
+
typesPath: string;
|
|
22
|
+
}) => string | Promise<string>): void;
|
|
23
|
+
/**
|
|
24
|
+
* Create a promise that resolves when Nuxt pages are resolved.
|
|
25
|
+
*/
|
|
26
|
+
declare function createPagesPromise(nuxt?: Nuxt): Promise<NuxtPage[]>;
|
|
27
|
+
/**
|
|
28
|
+
* Create a promise that resolves when Nitro is initialized.
|
|
29
|
+
*/
|
|
30
|
+
declare function createNitroPromise(nuxt?: Nuxt): Promise<Nitro>;
|
|
31
|
+
|
|
32
|
+
export { createNitroPromise, createPagesPromise, detectTarget, extendTypes, getNuxtModuleOptions, isNuxtGenerate, resolveNitroPreset };
|
package/dist/kit.mjs
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { useNuxt, createResolver, addTemplate, loadNuxtModuleInstance, tryUseNuxt } from '@nuxt/kit';
|
|
2
|
+
import { relative } from 'pathe';
|
|
3
|
+
import { provider, env } from 'std-env';
|
|
4
|
+
|
|
5
|
+
const autodetectableProviders = {
|
|
6
|
+
azure_static: "azure",
|
|
7
|
+
cloudflare_pages: "cloudflare-pages",
|
|
8
|
+
netlify: "netlify",
|
|
9
|
+
stormkit: "stormkit",
|
|
10
|
+
vercel: "vercel",
|
|
11
|
+
cleavr: "cleavr",
|
|
12
|
+
stackblitz: "stackblitz"
|
|
13
|
+
};
|
|
14
|
+
const autodetectableStaticProviders = {
|
|
15
|
+
netlify: "netlify-static",
|
|
16
|
+
vercel: "vercel-static"
|
|
17
|
+
};
|
|
18
|
+
function detectTarget(options = {}) {
|
|
19
|
+
return options?.static ? autodetectableStaticProviders[provider] : autodetectableProviders[provider];
|
|
20
|
+
}
|
|
21
|
+
function resolveNitroPreset(nitroConfig) {
|
|
22
|
+
nitroConfig = nitroConfig || tryUseNuxt()?.options?.nitro;
|
|
23
|
+
if (provider === "stackblitz" || provider === "codesandbox")
|
|
24
|
+
return provider;
|
|
25
|
+
let preset;
|
|
26
|
+
if (nitroConfig && nitroConfig?.preset)
|
|
27
|
+
preset = nitroConfig.preset;
|
|
28
|
+
if (!preset)
|
|
29
|
+
preset = env.NITRO_PRESET || env.SERVER_PRESET || detectTarget() || "node-server";
|
|
30
|
+
return preset.replace("_", "-");
|
|
31
|
+
}
|
|
32
|
+
async function getNuxtModuleOptions(module, nuxt = useNuxt()) {
|
|
33
|
+
const moduleMeta = (typeof module === "string" ? { name: module } : await module.getMeta?.()) || {};
|
|
34
|
+
const { nuxtModule } = await loadNuxtModuleInstance(module, nuxt);
|
|
35
|
+
let moduleEntry;
|
|
36
|
+
for (const m of nuxt.options.modules) {
|
|
37
|
+
if (Array.isArray(m) && m.length >= 2) {
|
|
38
|
+
const _module = m[0];
|
|
39
|
+
const _moduleEntryName = typeof _module === "string" ? _module : (await _module.getMeta?.())?.name || "";
|
|
40
|
+
if (_moduleEntryName === moduleMeta.name)
|
|
41
|
+
moduleEntry = m;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
let inlineOptions = {};
|
|
45
|
+
if (moduleEntry)
|
|
46
|
+
inlineOptions = moduleEntry[1];
|
|
47
|
+
if (nuxtModule.getOptions)
|
|
48
|
+
return nuxtModule.getOptions(inlineOptions, nuxt);
|
|
49
|
+
return inlineOptions;
|
|
50
|
+
}
|
|
51
|
+
function isNuxtGenerate(nuxt = useNuxt()) {
|
|
52
|
+
return nuxt.options.nitro.static || nuxt.options._generate || [
|
|
53
|
+
"static",
|
|
54
|
+
"github-pages"
|
|
55
|
+
].includes(resolveNitroPreset(nuxt.options.nitro));
|
|
56
|
+
}
|
|
57
|
+
function extendTypes(module, template) {
|
|
58
|
+
const nuxt = useNuxt();
|
|
59
|
+
const { resolve } = createResolver(import.meta.url);
|
|
60
|
+
addTemplate({
|
|
61
|
+
filename: `module/${module}.d.ts`,
|
|
62
|
+
getContents: async () => {
|
|
63
|
+
const typesPath = relative(resolve(nuxt.options.rootDir, nuxt.options.buildDir, "module"), resolve("runtime/types"));
|
|
64
|
+
const s = await template({ typesPath });
|
|
65
|
+
return `// Generated by ${module}
|
|
66
|
+
${s}
|
|
67
|
+
export {}
|
|
68
|
+
`;
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
nuxt.hooks.hook("prepare:types", ({ references }) => {
|
|
72
|
+
references.push({ path: resolve(nuxt.options.buildDir, `module/${module}.d.ts`) });
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
function createPagesPromise(nuxt = useNuxt()) {
|
|
76
|
+
return new Promise((resolve) => {
|
|
77
|
+
nuxt.hooks.hook("modules:done", () => {
|
|
78
|
+
if (typeof nuxt.options.pages === "boolean" && nuxt.options.pages === false || typeof nuxt.options.pages === "object" && !nuxt.options.pages.enabled) {
|
|
79
|
+
return resolve([]);
|
|
80
|
+
}
|
|
81
|
+
nuxt.hook("pages:resolved", (pages) => resolve(pages));
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
function createNitroPromise(nuxt = useNuxt()) {
|
|
86
|
+
return new Promise((resolve) => {
|
|
87
|
+
nuxt.hooks.hook("nitro:init", (nitro) => resolve(nitro));
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export { createNitroPromise, createPagesPromise, detectTarget, extendTypes, getNuxtModuleOptions, isNuxtGenerate, resolveNitroPreset };
|
package/dist/pro.d.mts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
interface ModuleRegistration {
|
|
2
|
+
name: string;
|
|
3
|
+
version?: string;
|
|
4
|
+
secret?: string;
|
|
5
|
+
features?: Record<string, boolean | string | number>;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Register a Nuxt SEO Pro module for license verification.
|
|
9
|
+
* Uses Nuxt hook so modules don't need to import from each other.
|
|
10
|
+
*
|
|
11
|
+
* Call this in your module setup. Registrations are collected
|
|
12
|
+
* before the single license verification fetch.
|
|
13
|
+
*/
|
|
14
|
+
declare function registerNuxtSeoProModule(registration: ModuleRegistration): void;
|
|
15
|
+
declare function hookNuxtSeoProLicense(): void;
|
|
16
|
+
|
|
17
|
+
export { hookNuxtSeoProLicense, registerNuxtSeoProModule };
|
|
18
|
+
export type { ModuleRegistration };
|
package/dist/pro.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
interface ModuleRegistration {
|
|
2
|
+
name: string;
|
|
3
|
+
version?: string;
|
|
4
|
+
secret?: string;
|
|
5
|
+
features?: Record<string, boolean | string | number>;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Register a Nuxt SEO Pro module for license verification.
|
|
9
|
+
* Uses Nuxt hook so modules don't need to import from each other.
|
|
10
|
+
*
|
|
11
|
+
* Call this in your module setup. Registrations are collected
|
|
12
|
+
* before the single license verification fetch.
|
|
13
|
+
*/
|
|
14
|
+
declare function registerNuxtSeoProModule(registration: ModuleRegistration): void;
|
|
15
|
+
declare function hookNuxtSeoProLicense(): void;
|
|
16
|
+
|
|
17
|
+
export { hookNuxtSeoProLicense, registerNuxtSeoProModule };
|
|
18
|
+
export type { ModuleRegistration };
|
package/dist/pro.mjs
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import * as p from '@clack/prompts';
|
|
2
|
+
import { useLogger, useNuxt } from '@nuxt/kit';
|
|
3
|
+
import { useSiteConfig } from 'nuxt-site-config/kit';
|
|
4
|
+
import { $fetch } from 'ofetch';
|
|
5
|
+
import { isTest, isCI } from 'std-env';
|
|
6
|
+
|
|
7
|
+
const logger = useLogger("nuxt-seo-pro");
|
|
8
|
+
function registerNuxtSeoProModule(registration) {
|
|
9
|
+
const nuxt = useNuxt();
|
|
10
|
+
nuxt._nuxtSeoProModules = nuxt._nuxtSeoProModules || [];
|
|
11
|
+
nuxt._nuxtSeoProModules.push(registration);
|
|
12
|
+
}
|
|
13
|
+
function hookNuxtSeoProLicense() {
|
|
14
|
+
const nuxt = useNuxt();
|
|
15
|
+
const isBuild = !nuxt.options.dev && !nuxt.options._prepare;
|
|
16
|
+
if (isBuild && !nuxt._isNuxtSeoProVerifying) {
|
|
17
|
+
const license = nuxt.options.runtimeConfig.seoProKey || process.env.NUXT_SEO_PRO_KEY;
|
|
18
|
+
if (isTest || process.env.VITEST) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
if (!isCI && !license) {
|
|
22
|
+
p.log.warn("\u26A0\uFE0F Building without license in non-CI environment. A license is required for production builds.");
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
if (!license) {
|
|
26
|
+
p.log.error("\u{1F510} Nuxt SEO Pro license required");
|
|
27
|
+
p.note("Set NUXT_SEO_PRO_KEY or configure via module options.\n\nhttps://nuxtseo.com/pro/dashboard", "Get your license");
|
|
28
|
+
throw new Error("Missing Nuxt SEO Pro license key.");
|
|
29
|
+
}
|
|
30
|
+
nuxt._isNuxtSeoProVerifying = true;
|
|
31
|
+
nuxt.hooks.hook("build:before", async () => {
|
|
32
|
+
p.intro("Nuxt SEO Pro: License Verification");
|
|
33
|
+
const siteConfig = useSiteConfig();
|
|
34
|
+
const spinner = p.spinner();
|
|
35
|
+
spinner.start("\u{1F511} Verifying Nuxt SEO Pro license...");
|
|
36
|
+
const siteUrl = siteConfig.url?.startsWith("http") ? siteConfig.url : void 0;
|
|
37
|
+
const siteName = siteConfig.name || void 0;
|
|
38
|
+
const modules = nuxt._nuxtSeoProModules?.length > 0 ? nuxt._nuxtSeoProModules : void 0;
|
|
39
|
+
const res = await $fetch("https://nuxtseo.com/api/pro/verify", {
|
|
40
|
+
method: "POST",
|
|
41
|
+
body: {
|
|
42
|
+
apiKey: license,
|
|
43
|
+
siteUrl,
|
|
44
|
+
siteName,
|
|
45
|
+
modules
|
|
46
|
+
}
|
|
47
|
+
}).catch((err) => {
|
|
48
|
+
if (err?.response?.status === 401) {
|
|
49
|
+
spinner.error("Invalid API key");
|
|
50
|
+
p.note("Your API key is invalid.\n\nhttps://nuxtseo.com/pro/dashboard", "License Issue");
|
|
51
|
+
throw new Error("Invalid Nuxt SEO Pro API key.");
|
|
52
|
+
}
|
|
53
|
+
if (err?.response?.status === 403) {
|
|
54
|
+
spinner.error("No active subscription");
|
|
55
|
+
p.note("Your subscription has expired or is inactive.\n\nhttps://nuxtseo.com/pro/dashboard", "License Issue");
|
|
56
|
+
throw new Error("No active Nuxt SEO Pro subscription.");
|
|
57
|
+
}
|
|
58
|
+
logger.error(err);
|
|
59
|
+
return null;
|
|
60
|
+
});
|
|
61
|
+
if (!res) {
|
|
62
|
+
spinner.cancel("License verification skipped (network issue)");
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
spinner.stop("License verified \u2713");
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export { hookNuxtSeoProLicense, registerNuxtSeoProModule };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { H3Event } from 'h3';
|
|
2
|
+
import { NitroRouteConfig } from 'nitropack';
|
|
3
|
+
|
|
4
|
+
declare function withoutQuery(path: string): string;
|
|
5
|
+
declare function createNitroRouteRuleMatcher(e?: H3Event): (path: string) => NitroRouteConfig;
|
|
6
|
+
|
|
7
|
+
export { createNitroRouteRuleMatcher, withoutQuery };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { H3Event } from 'h3';
|
|
2
|
+
import { NitroRouteConfig } from 'nitropack';
|
|
3
|
+
|
|
4
|
+
declare function withoutQuery(path: string): string;
|
|
5
|
+
declare function createNitroRouteRuleMatcher(e?: H3Event): (path: string) => NitroRouteConfig;
|
|
6
|
+
|
|
7
|
+
export { createNitroRouteRuleMatcher, withoutQuery };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { defu } from 'defu';
|
|
2
|
+
import { useRuntimeConfig } from 'nitropack/runtime';
|
|
3
|
+
import { toRouteMatcher, createRouter } from 'radix3';
|
|
4
|
+
import { withoutTrailingSlash, parseURL, withoutBase } from 'ufo';
|
|
5
|
+
|
|
6
|
+
function withoutQuery(path) {
|
|
7
|
+
return path.split("?")[0];
|
|
8
|
+
}
|
|
9
|
+
function createNitroRouteRuleMatcher(e) {
|
|
10
|
+
const { nitro, app } = useRuntimeConfig(e);
|
|
11
|
+
const _routeRulesMatcher = toRouteMatcher(
|
|
12
|
+
createRouter({
|
|
13
|
+
routes: Object.fromEntries(
|
|
14
|
+
Object.entries(nitro?.routeRules || {}).map(([path, rules]) => [path === "/" ? path : withoutTrailingSlash(path), rules])
|
|
15
|
+
)
|
|
16
|
+
})
|
|
17
|
+
);
|
|
18
|
+
return (pathOrUrl) => {
|
|
19
|
+
const path = pathOrUrl[0] === "/" ? pathOrUrl : parseURL(pathOrUrl, app.baseURL).pathname;
|
|
20
|
+
const pathWithoutQuery = withoutQuery(path);
|
|
21
|
+
return defu({}, ..._routeRulesMatcher.matchAll(
|
|
22
|
+
withoutBase(pathWithoutQuery === "/" ? pathWithoutQuery : withoutTrailingSlash(pathWithoutQuery), app.baseURL)
|
|
23
|
+
).reverse());
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export { createNitroRouteRuleMatcher, withoutQuery };
|
package/package.json
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "nuxtseo-shared",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"description": "Shared utilities for Nuxt SEO modules.",
|
|
6
|
+
"author": {
|
|
7
|
+
"name": "Harlan Wilton",
|
|
8
|
+
"email": "harlan@harlanzw.com",
|
|
9
|
+
"url": "https://harlanzw.com/"
|
|
10
|
+
},
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./dist/index.d.mts",
|
|
15
|
+
"import": "./dist/index.mjs"
|
|
16
|
+
},
|
|
17
|
+
"./content": {
|
|
18
|
+
"types": "./dist/content.d.mts",
|
|
19
|
+
"import": "./dist/content.mjs"
|
|
20
|
+
},
|
|
21
|
+
"./kit": {
|
|
22
|
+
"types": "./dist/kit.d.mts",
|
|
23
|
+
"import": "./dist/kit.mjs"
|
|
24
|
+
},
|
|
25
|
+
"./devtools": {
|
|
26
|
+
"types": "./dist/devtools.d.mts",
|
|
27
|
+
"import": "./dist/devtools.mjs"
|
|
28
|
+
},
|
|
29
|
+
"./i18n": {
|
|
30
|
+
"types": "./dist/i18n.d.mts",
|
|
31
|
+
"import": "./dist/i18n.mjs"
|
|
32
|
+
},
|
|
33
|
+
"./pro": {
|
|
34
|
+
"types": "./dist/pro.d.mts",
|
|
35
|
+
"import": "./dist/pro.mjs"
|
|
36
|
+
},
|
|
37
|
+
"./runtime/server/kit": {
|
|
38
|
+
"types": "./dist/runtime/server/kit.d.mts",
|
|
39
|
+
"import": "./dist/runtime/server/kit.mjs"
|
|
40
|
+
},
|
|
41
|
+
"./client": {
|
|
42
|
+
"types": "./dist/client/index.d.mts",
|
|
43
|
+
"import": "./dist/client/index.mjs"
|
|
44
|
+
},
|
|
45
|
+
"./client/composables/rpc": {
|
|
46
|
+
"types": "./dist/client/composables/rpc.d.mts",
|
|
47
|
+
"import": "./dist/client/composables/rpc.mjs"
|
|
48
|
+
},
|
|
49
|
+
"./client/composables/shiki": {
|
|
50
|
+
"types": "./dist/client/composables/shiki.d.mts",
|
|
51
|
+
"import": "./dist/client/composables/shiki.mjs"
|
|
52
|
+
},
|
|
53
|
+
"./client/components/OCodeBlock": "./src/client/components/OCodeBlock.vue",
|
|
54
|
+
"./client/components/OSectionBlock": "./src/client/components/OSectionBlock.vue",
|
|
55
|
+
"./client/components/NuxtSeoLogo": "./src/client/components/NuxtSeoLogo.vue"
|
|
56
|
+
},
|
|
57
|
+
"main": "./dist/index.mjs",
|
|
58
|
+
"types": "./dist/index.d.mts",
|
|
59
|
+
"files": [
|
|
60
|
+
"dist",
|
|
61
|
+
"src/client/components"
|
|
62
|
+
],
|
|
63
|
+
"peerDependencies": {
|
|
64
|
+
"@nuxt/schema": "^3.16.0 || ^4.0.0",
|
|
65
|
+
"h3": "^1.15.0",
|
|
66
|
+
"nitropack": "^2.12.0",
|
|
67
|
+
"nuxt": "^3.16.0 || ^4.0.0",
|
|
68
|
+
"nuxt-site-config": "^3.2.0",
|
|
69
|
+
"vue": "^3.5.0",
|
|
70
|
+
"zod": "^3.23.0"
|
|
71
|
+
},
|
|
72
|
+
"peerDependenciesMeta": {
|
|
73
|
+
"h3": {
|
|
74
|
+
"optional": true
|
|
75
|
+
},
|
|
76
|
+
"nitropack": {
|
|
77
|
+
"optional": true
|
|
78
|
+
},
|
|
79
|
+
"nuxt-site-config": {
|
|
80
|
+
"optional": true
|
|
81
|
+
},
|
|
82
|
+
"zod": {
|
|
83
|
+
"optional": true
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
"dependencies": {
|
|
87
|
+
"@clack/prompts": "^0.10.0",
|
|
88
|
+
"@nuxt/devtools-kit": "^2.3.0",
|
|
89
|
+
"@nuxt/kit": "^4.4.2",
|
|
90
|
+
"consola": "^3.4.2",
|
|
91
|
+
"defu": "^6.1.4",
|
|
92
|
+
"ofetch": "^1.4.1",
|
|
93
|
+
"pathe": "^2.0.3",
|
|
94
|
+
"radix3": "^1.1.2",
|
|
95
|
+
"sirv": "^3.0.1",
|
|
96
|
+
"std-env": "^3.9.0",
|
|
97
|
+
"ufo": "^1.6.1"
|
|
98
|
+
},
|
|
99
|
+
"devDependencies": {
|
|
100
|
+
"@nuxt/schema": "^4.4.2",
|
|
101
|
+
"@nuxtjs/i18n": "^10.2.3",
|
|
102
|
+
"@shikijs/langs": "^3.0.0",
|
|
103
|
+
"@shikijs/themes": "^3.0.0",
|
|
104
|
+
"@vueuse/core": "^13.0.0",
|
|
105
|
+
"h3": "^1.15.0",
|
|
106
|
+
"nitropack": "^2.13.1",
|
|
107
|
+
"nuxt-site-config": "^3.2.21",
|
|
108
|
+
"shiki": "^3.0.0",
|
|
109
|
+
"typescript": "^5.9.3",
|
|
110
|
+
"unbuild": "^3.5.0",
|
|
111
|
+
"vue": "^3.5.0"
|
|
112
|
+
},
|
|
113
|
+
"scripts": {
|
|
114
|
+
"build": "unbuild",
|
|
115
|
+
"stub": "unbuild --stub"
|
|
116
|
+
}
|
|
117
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="flex items-center gap-1">
|
|
3
|
+
<svg viewBox="0 0 64 64" class="pop-quick w-7 h-7">
|
|
4
|
+
<defs>
|
|
5
|
+
<linearGradient id="wmLine1" x1="0%" y1="100%" x2="100%" y2="0%">
|
|
6
|
+
<stop offset="0%" stop-color="#22c55e" />
|
|
7
|
+
<stop offset="100%" stop-color="#86efac" />
|
|
8
|
+
</linearGradient>
|
|
9
|
+
<linearGradient id="wmFill1" x1="0%" y1="0%" x2="0%" y2="100%">
|
|
10
|
+
<stop offset="0%" stop-color="#22c55e" stop-opacity="0.6" />
|
|
11
|
+
<stop offset="100%" stop-color="#22c55e" stop-opacity="0" />
|
|
12
|
+
</linearGradient>
|
|
13
|
+
</defs>
|
|
14
|
+
<path
|
|
15
|
+
class="fill"
|
|
16
|
+
d="M8 52 Q20 48 24 36 T40 20 T56 12 L56 56 L8 56 Z"
|
|
17
|
+
fill="url(#wmFill1)"
|
|
18
|
+
/>
|
|
19
|
+
<path
|
|
20
|
+
class="line"
|
|
21
|
+
d="M8 52 Q20 48 24 36 T40 20 T56 12"
|
|
22
|
+
fill="none"
|
|
23
|
+
stroke="url(#wmLine1)"
|
|
24
|
+
stroke-width="4"
|
|
25
|
+
stroke-linecap="round"
|
|
26
|
+
/>
|
|
27
|
+
<circle class="node" cx="56" cy="12" r="6" fill="url(#wmLine1)" />
|
|
28
|
+
</svg>
|
|
29
|
+
<span class="-ml-1 dark:text-white text-black text-lg font-bold tracking-tight slide-right">
|
|
30
|
+
Nuxt<span class="ml-1 text-green-400">SEO</span>
|
|
31
|
+
</span>
|
|
32
|
+
</div>
|
|
33
|
+
</template>
|
|
34
|
+
|
|
35
|
+
<style scoped>
|
|
36
|
+
@keyframes drawLine {
|
|
37
|
+
0% { stroke-dashoffset: 100; }
|
|
38
|
+
100% { stroke-dashoffset: 0; }
|
|
39
|
+
}
|
|
40
|
+
@keyframes revealFill {
|
|
41
|
+
0% { clip-path: inset(0 100% 0 0); }
|
|
42
|
+
100% { clip-path: inset(0 0% 0 0); }
|
|
43
|
+
}
|
|
44
|
+
@keyframes popNode {
|
|
45
|
+
0%, 70% { opacity: 0; transform: scale(0); }
|
|
46
|
+
85% { transform: scale(1.3); opacity: 1; }
|
|
47
|
+
100% { transform: scale(1); opacity: 1; }
|
|
48
|
+
}
|
|
49
|
+
@keyframes slideRight {
|
|
50
|
+
from {
|
|
51
|
+
transform: scale(0.6) translateX(100%);
|
|
52
|
+
opacity: 0;
|
|
53
|
+
}
|
|
54
|
+
to {
|
|
55
|
+
transform: translateX(0);
|
|
56
|
+
opacity: 1;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.pop-quick .line {
|
|
61
|
+
stroke-dasharray: 100;
|
|
62
|
+
stroke-dashoffset: 100;
|
|
63
|
+
animation: drawLine 0.8s ease-out forwards;
|
|
64
|
+
}
|
|
65
|
+
.pop-quick .fill {
|
|
66
|
+
clip-path: inset(0 100% 0 0);
|
|
67
|
+
animation: revealFill 0.4s ease-out forwards;
|
|
68
|
+
}
|
|
69
|
+
.pop-quick .node {
|
|
70
|
+
opacity: 0;
|
|
71
|
+
transform-origin: 56px 12px;
|
|
72
|
+
animation: popNode 0.6s ease-out forwards;
|
|
73
|
+
}
|
|
74
|
+
.slide-right {
|
|
75
|
+
animation: slideRight 400ms cubic-bezier(0.68, -0.55, 0.27, 1.55) forwards;
|
|
76
|
+
}
|
|
77
|
+
</style>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed } from 'vue'
|
|
3
|
+
import { useRenderCodeHighlight } from '../composables/shiki'
|
|
4
|
+
|
|
5
|
+
const props = withDefaults(
|
|
6
|
+
defineProps<{
|
|
7
|
+
code: string
|
|
8
|
+
lang: 'json' | 'xml' | 'js'
|
|
9
|
+
lines?: boolean
|
|
10
|
+
transformRendered?: (code: string) => string
|
|
11
|
+
}>(),
|
|
12
|
+
{
|
|
13
|
+
lines: false,
|
|
14
|
+
},
|
|
15
|
+
)
|
|
16
|
+
const rendered = computed(() => {
|
|
17
|
+
const code = useRenderCodeHighlight(props.code, props.lang)
|
|
18
|
+
return props.transformRendered ? props.transformRendered(code.value || '') : code.value
|
|
19
|
+
})
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<template>
|
|
23
|
+
<pre
|
|
24
|
+
class="code-block p-5"
|
|
25
|
+
:class="lines ? 'code-block-lines' : ''"
|
|
26
|
+
v-html="rendered"
|
|
27
|
+
/>
|
|
28
|
+
</template>
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { useVModel } from '@vueuse/core'
|
|
3
|
+
|
|
4
|
+
const props = withDefaults(
|
|
5
|
+
defineProps<{
|
|
6
|
+
icon?: string
|
|
7
|
+
text?: string
|
|
8
|
+
description?: string
|
|
9
|
+
containerClass?: string
|
|
10
|
+
headerClass?: string
|
|
11
|
+
collapse?: boolean
|
|
12
|
+
open?: boolean
|
|
13
|
+
padding?: boolean | string
|
|
14
|
+
}>(),
|
|
15
|
+
{
|
|
16
|
+
containerClass: '',
|
|
17
|
+
open: true,
|
|
18
|
+
padding: true,
|
|
19
|
+
collapse: true,
|
|
20
|
+
},
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
const open = useVModel(props, 'open')
|
|
24
|
+
function onToggle(e: any) {
|
|
25
|
+
open.value = e.target.open
|
|
26
|
+
}
|
|
27
|
+
</script>
|
|
28
|
+
|
|
29
|
+
<template>
|
|
30
|
+
<details :open="open" class="section-block" @toggle="onToggle">
|
|
31
|
+
<summary class="section-header" :class="collapse ? '' : 'pointer-events-none'">
|
|
32
|
+
<div class="section-title" :class="[open ? '' : 'opacity-60', headerClass]">
|
|
33
|
+
<UIcon v-if="icon" :name="icon" class="section-icon" />
|
|
34
|
+
<div class="flex-1 min-w-0">
|
|
35
|
+
<div class="section-label">
|
|
36
|
+
<slot name="text">
|
|
37
|
+
{{ text }}
|
|
38
|
+
</slot>
|
|
39
|
+
</div>
|
|
40
|
+
<div v-if="description || $slots.description" class="section-description">
|
|
41
|
+
<slot name="description">
|
|
42
|
+
{{ description }}
|
|
43
|
+
</slot>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
<slot name="actions" />
|
|
47
|
+
<UIcon
|
|
48
|
+
v-if="collapse"
|
|
49
|
+
name="carbon:chevron-down"
|
|
50
|
+
class="chevron"
|
|
51
|
+
/>
|
|
52
|
+
</div>
|
|
53
|
+
</summary>
|
|
54
|
+
<div
|
|
55
|
+
class="section-content"
|
|
56
|
+
:class="typeof padding === 'string' ? padding : padding ? 'px-4' : ''"
|
|
57
|
+
>
|
|
58
|
+
<slot name="details" />
|
|
59
|
+
<div :class="containerClass">
|
|
60
|
+
<slot />
|
|
61
|
+
</div>
|
|
62
|
+
<slot name="footer" />
|
|
63
|
+
</div>
|
|
64
|
+
</details>
|
|
65
|
+
</template>
|
|
66
|
+
|
|
67
|
+
<style scoped>
|
|
68
|
+
.section-block {
|
|
69
|
+
border: 1px solid var(--color-border);
|
|
70
|
+
border-radius: var(--radius-lg);
|
|
71
|
+
overflow: hidden;
|
|
72
|
+
background: var(--color-surface-elevated);
|
|
73
|
+
transition: border-color 200ms ease;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.section-block:hover {
|
|
77
|
+
border-color: var(--color-neutral-300);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.dark .section-block:hover {
|
|
81
|
+
border-color: var(--color-neutral-700);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.section-header {
|
|
85
|
+
cursor: pointer;
|
|
86
|
+
user-select: none;
|
|
87
|
+
padding: 0.875rem 1rem;
|
|
88
|
+
transition: background 150ms ease;
|
|
89
|
+
list-style: none;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.section-header::-webkit-details-marker {
|
|
93
|
+
display: none;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.section-header:hover {
|
|
97
|
+
background: var(--color-surface-sunken);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
details[open] .section-header {
|
|
101
|
+
border-bottom: 1px solid var(--color-border);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.section-title {
|
|
105
|
+
display: flex;
|
|
106
|
+
align-items: center;
|
|
107
|
+
gap: 0.625rem;
|
|
108
|
+
transition: opacity 150ms ease;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.section-icon {
|
|
112
|
+
color: var(--color-text-muted);
|
|
113
|
+
font-size: 1.125rem;
|
|
114
|
+
flex-shrink: 0;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.section-label {
|
|
118
|
+
font-size: 0.875rem;
|
|
119
|
+
font-weight: 600;
|
|
120
|
+
color: var(--color-text);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.section-description {
|
|
124
|
+
font-size: 0.75rem;
|
|
125
|
+
color: var(--color-text-muted);
|
|
126
|
+
margin-top: 0.125rem;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.chevron {
|
|
130
|
+
color: var(--color-text-subtle);
|
|
131
|
+
font-size: 0.875rem;
|
|
132
|
+
flex-shrink: 0;
|
|
133
|
+
transition: transform 200ms cubic-bezier(0.22, 1, 0.36, 1);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
details[open] .chevron {
|
|
137
|
+
transform: rotate(180deg);
|
|
138
|
+
color: var(--color-text-muted);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.section-content {
|
|
142
|
+
display: flex;
|
|
143
|
+
flex-direction: column;
|
|
144
|
+
gap: 0.75rem;
|
|
145
|
+
padding: 1rem;
|
|
146
|
+
background: var(--color-surface-sunken);
|
|
147
|
+
}
|
|
148
|
+
</style>
|