Ir al contenido

Haciendo complementos útiles

Crear un complemento para StudioCMS es una forma poderosa de extender la funcionalidad de StudioCMS. Los complementos proporcionan una manera simple y flexible de agregar nuevas características a tu proyecto StudioCMS. A continuación se muestra un ejemplo básico de cómo crear un complemento de StudioCMS y cómo funciona.

Para comenzar, necesitarás crear un nuevo complemento de StudioCMS. A continuación se muestra un ejemplo básico de la estructura de archivos para un complemento de StudioCMS:

  • package.json
  • Directoriosrc
    • index.ts
    • Directorioroutes
      • […slug].astro
    • Directoriodashboard-grid-items
      • MyPluginGridItem.astro

En el archivo principal src/index.ts, definirás el complemento de StudioCMS. A continuación se muestra un ejemplo de cómo definir un complemento de StudioCMS que incluye una Integración Astro para crear un ejemplo simple de blog:

index.ts
import {
function definePlugin(options: StudioCMSPluginDef): StudioCMSPluginDef

Defines a plugin for StudioCMS.

@paramoptions - The configuration options for the plugin.

@returnsThe plugin configuration.

definePlugin
} from 'studiocms/plugins';
import {
(alias) interface AstroIntegration
import AstroIntegration
AstroIntegration
} from 'astro';
import {
const addVirtualImports: HookUtility<"astro:config:setup", [{
name: string;
imports: Imports;
__enableCorePowerDoNotUseOrYouWillBeFired?: boolean;
}], void>

Creates a Vite virtual module and updates the Astro config. Virtual imports are useful for passing things like config options, or data computed within the integration.

@paramparams

@paramoptions

@paramoptions.name

@paramoptions.imports

@seehttps://astro-integration-kit.netlify.app/utilities/add-virtual-imports/

@example

// my-integration/index.ts
import { addVirtualImports } from "astro-integration-kit";
addVirtualImports(params, {
name: 'my-integration',
imports: {
'virtual:my-integration/config': `export default ${ JSON.stringify({foo: "bar"}) }`,
},
});

This is then readable anywhere else in your integration:

// myIntegration/src/component/layout.astro
import config from "virtual:my-integration/config";
console.log(config.foo) // "bar"

addVirtualImports
,
const createResolver: (_base: string) => {
resolve: (...path: Array<string>) => string;
}

Allows resolving paths relatively to the integration folder easily. Call it like this:

@param_base - The location you want to create relative references from. import.meta.url is usually what you'll want.

@seehttps://astro-integration-kit.netlify.app/core/create-resolver/

@example

const { resolve } = createResolver(import.meta.url);
const pluginPath = resolve("./plugin.ts");

This way, you do not have to add your plugin to your package.json exports.

createResolver
} from 'astro-integration-kit';
// Define las opciones para el complemento y la integración
interface
interface Options
Options
{
Options.route: string
route
: string;
}
export function
function studioCMSPageInjector(options: Options): {
readonly identifier: string;
readonly name: string;
readonly studiocmsMinimumVersion?: string | undefined | undefined;
readonly requires?: readonly string[] | undefined;
readonly hooks: {
"studiocms:astro-config"?: ((args: {
readonly logger: AstroIntegrationLogger;
readonly addIntegrations: (args: AstroIntegration | AstroIntegration[]) => Promise<void>;
}) => Promise<void>) | ((args: {
readonly logger: AstroIntegrationLogger;
readonly addIntegrations: (args: AstroIntegration | AstroIntegration[]) => Promise<void>;
}) => void) | undefined;
"studiocms:auth"?: ((args: {
readonly logger: AstroIntegrationLogger;
readonly setAuthService: (args: {
oAuthProvider: {
readonly name: string;
readonly formattedName: string;
readonly svg: string;
readonly endpointPath: string;
readonly requiredEnvVariables?: readonly string[] | undefined;
};
}) => Promise<void>;
}) => Promise<void>) | ((args: {
readonly logger: AstroIntegrationLogger;
readonly setAuthService: (args: {
oAuthProvider: {
readonly name: string;
readonly formattedName: string;
readonly svg: string;
readonly endpointPath: string;
readonly requiredEnvVariables?: readonly string[] | undefined;
};
}) => Promise<void>;
}) => void) | undefined;
"studiocms:dashboard"?: ((args: {
readonly logger: AstroIntegrationLogger;
readonly setDashboard: (args: {
translations: {
[x: string]: {
[x: string]: {
[x: string]: string;
};
};
};
dashboardGridItems?: readonly {
readonly name: string;
readonly span: 1 | 2 | 3;
readonly variant: "default" | "filled";
readonly requiresPermission?: "owner" | "admin" | "editor" | "visitor" | undefined;
readonly header?: {
readonly title: string;
readonly icon?: "heroicons:academic-cap" | "heroicons:academic-cap-16-solid" | "heroicons:academic-cap-20-solid" | "heroicons:academic-cap-solid" | "heroicons:adjustments-horizontal" | "heroicons:adjustments-horizontal-16-solid" | "heroicons:adjustments-horizontal-20-solid" | "heroicons:adjustments-horizontal-solid" | "heroicons:adjustments-vertical" | "heroicons:adjustments-vertical-16-solid" | "heroicons:adjustments-vertical-20-solid" | "heroicons:adjustments-vertical-solid" | "heroicons:archive-box" | "heroicons:archive-box-16-solid" | "heroicons:archive-box-20-solid" | "heroicons:archive-box-arrow-down" | "heroicons:archive-box-arrow-down-16-solid" | "heroicons:archive-box-arrow-down-20-solid" | "heroicons:archive-box-arrow-down-solid" | "heroicons:archive-box-solid" | "heroicons:archive-box-x-mark" | "heroicons:archive-box-x-mark-16-solid" | "heroicons:archive-box-x-mark-20-solid" | "heroicons:archive-box-x-mark-solid" | "heroicons:arrow-down" | "heroicons:arrow-down-16-solid" | "heroicons:arrow-down-20-solid" | "heroicons:arrow-down-circle" | "heroicons:arrow-down-circle-16-solid" | "heroicons:arrow-down-circle-20-solid" | "heroicons:arrow-down-circle-solid" | "heroicons:arrow-down-left" | "heroicons:arrow-down-left-16-solid" | "heroicons:arrow-down-left-20-solid" | "heroicons:arrow-down-left-solid" | "heroicons:arrow-down-on-square" | "heroicons:arrow-down-on-square-16-solid" | "heroicons:arrow-down-on-square-20-solid" | "heroicons:arrow-down-on-square-solid" | "heroicons:arrow-down-on-square-stack" | "heroicons:arrow-down-on-square-stack-16-solid" | "heroicons:arrow-down-on-square-stack-20-solid" | "heroicons:arrow-down-on-square-stack-solid" | "heroicons:arrow-down-right" | "heroicons:arrow-down-right-16-solid" | "heroicons:arrow-down-right-20-solid" | "heroicons:arrow-down-right-solid" | "heroicons:arrow-down-solid" | "heroicons:arrow-down-tray" | "heroicons:arrow-down-tray-16-solid" | "heroicons:arrow-down-tray-20-solid" | "heroicons:arrow-down-tray-solid" | "heroicons:arrow-left" | "heroicons:arrow-left-16-solid" | "heroicons:arrow-left-20-solid" | "heroicons:arrow-left-circle" | "heroicons:arrow-left-circle-16-solid" | "heroicons:arrow-left-circle-20-solid" | "heroicons:arrow-left-circle-solid" | "heroicons:arrow-left-end-on-rectangle" | "heroicons:arrow-left-end-on-rectangle-16-solid" | "heroicons:arrow-left-end-on-rectangle-20-solid" | "heroicons:arrow-left-end-on-rectangle-solid" | "heroicons:arrow-left-on-rectangle" | "heroicons:arrow-left-on-rectangle-20-solid" | "heroicons:arrow-left-on-rectangle-solid" ...
studioCMSPageInjector
(
options: Options
options
:
interface Options
Options
) {
// Resuelve la ruta al archivo actual
const {
const resolve: (...path: Array<string>) => string
resolve
} =
function createResolver(_base: string): {
resolve: (...path: Array<string>) => string;
}

Allows resolving paths relatively to the integration folder easily. Call it like this:

@param_base - The location you want to create relative references from. import.meta.url is usually what you'll want.

@seehttps://astro-integration-kit.netlify.app/core/create-resolver/

@example

const { resolve } = createResolver(import.meta.url);
const pluginPath = resolve("./plugin.ts");

This way, you do not have to add your plugin to your package.json exports.

createResolver
(import.

The type of import.meta.

If you need to declare that a given property exists on import.meta, this type may be augmented via interface merging.

meta
.
ImportMeta.url: string

The absolute file: URL of the module.

This is defined exactly the same as it is in browsers providing the URL of the current module file.

This enables useful patterns such as relative file loading:

import { readFileSync } from 'node:fs';
const buffer = readFileSync(new URL('./data.proto', import.meta.url));

url
);
// Define la integración Astro
function
function (local function) myIntegration(options: Options): AstroIntegration
myIntegration
(
options: Options
options
:
interface Options
Options
):
(alias) interface AstroIntegration
import AstroIntegration
AstroIntegration
{
const
const route: string
route
= `/${
options: Options
options
?.
Options.route: string
route
|| 'my-plugin'}`;
return {
AstroIntegration.name: string

The name of the integration.

name
: 'my-astro-integration',
AstroIntegration.hooks: {
'astro:config:setup'?: (options: {
config: AstroConfig;
command: "dev" | "build" | "preview" | "sync";
isRestart: boolean;
updateConfig: (newConfig: DeepPartial<AstroConfig>) => AstroConfig;
addRenderer: (renderer: AstroRenderer) => void;
addWatchFile: (path: URL | string) => void;
injectScript: (stage: InjectedScriptStage, content: string) => void;
injectRoute: (injectRoute: InjectedRoute) => void;
addClientDirective: (directive: ClientDirectiveConfig) => void;
addDevToolbarApp: (entrypoint: DevToolbarAppEntry) => void;
addMiddleware: (mid: AstroIntegrationMiddleware) => void;
createCodegenDir: () => URL;
logger: AstroIntegrationLogger;
}) => void | Promise<void>;
... 10 more ...;
'astro:routes:resolved'?: (options: {
routes: IntegrationResolvedRoute[];
logger: AstroIntegrationLogger;
}) => void | Promise<void>;
} & Partial<...>

The different hooks available to extend.

hooks
: {
"astro:config:setup": (
params: {
config: AstroConfig;
command: "dev" | "build" | "preview" | "sync";
isRestart: boolean;
updateConfig: (newConfig: DeepPartial<AstroConfig>) => AstroConfig;
addRenderer: (renderer: AstroRenderer) => void;
addWatchFile: (path: URL | string) => void;
injectScript: (stage: InjectedScriptStage, content: string) => void;
injectRoute: (injectRoute: InjectedRoute) => void;
... 4 more ...;
logger: AstroIntegrationLogger;
}
params
) => {
const {
const injectRoute: (injectRoute: InjectedRoute) => void
injectRoute
} =
params: {
config: AstroConfig;
command: "dev" | "build" | "preview" | "sync";
isRestart: boolean;
updateConfig: (newConfig: DeepPartial<AstroConfig>) => AstroConfig;
addRenderer: (renderer: AstroRenderer) => void;
addWatchFile: (path: URL | string) => void;
injectScript: (stage: InjectedScriptStage, content: string) => void;
injectRoute: (injectRoute: InjectedRoute) => void;
... 4 more ...;
logger: AstroIntegrationLogger;
}
params
;
// Inyecta la ruta para el complemento
const injectRoute: (injectRoute: InjectedRoute) => void
injectRoute
({
entrypoint: string | URL
entrypoint
:
const resolve: (...path: Array<string>) => string
resolve
('./routes/[...slug].astro'),
pattern: string
pattern
: `/${
const route: string
route
}/[...slug]`,
prerender?: boolean
prerender
: false,
})
function addVirtualImports(params: {
config: AstroConfig;
command: "dev" | "build" | "preview" | "sync";
isRestart: boolean;
updateConfig: (newConfig: DeepPartial<AstroConfig>) => AstroConfig;
addRenderer: (renderer: AstroRenderer) => void;
addWatchFile: (path: URL | string) => void;
injectScript: (stage: InjectedScriptStage, content: string) => void;
injectRoute: (injectRoute: InjectedRoute) => void;
... 4 more ...;
logger: AstroIntegrationLogger;
}, args_0: {
...;
}): void

Creates a Vite virtual module and updates the Astro config. Virtual imports are useful for passing things like config options, or data computed within the integration.

@paramparams

@paramoptions

@paramoptions.name

@paramoptions.imports

@seehttps://astro-integration-kit.netlify.app/utilities/add-virtual-imports/

@example

// my-integration/index.ts
import { addVirtualImports } from "astro-integration-kit";
addVirtualImports(params, {
name: 'my-integration',
imports: {
'virtual:my-integration/config': `export default ${ JSON.stringify({foo: "bar"}) }`,
},
});

This is then readable anywhere else in your integration:

// myIntegration/src/component/layout.astro
import config from "virtual:my-integration/config";
console.log(config.foo) // "bar"

addVirtualImports
(
params: {
config: AstroConfig;
command: "dev" | "build" | "preview" | "sync";
isRestart: boolean;
updateConfig: (newConfig: DeepPartial<AstroConfig>) => AstroConfig;
addRenderer: (renderer: AstroRenderer) => void;
addWatchFile: (path: URL | string) => void;
injectScript: (stage: InjectedScriptStage, content: string) => void;
injectRoute: (injectRoute: InjectedRoute) => void;
... 4 more ...;
logger: AstroIntegrationLogger;
}
params
, {
name: string
name
: 'my-astro-integration',
imports: Imports
imports
: {
'myplugin:config': `
export const options = ${
var JSON: JSON

An intrinsic object that provides functions to convert JavaScript values to and from the JavaScript Object Notation (JSON) format.

JSON
.
JSON.stringify(value: any, replacer?: (this: any, key: string, value: any) => any, space?: string | number): string (+1 overload)

Converts a JavaScript value to a JavaScript Object Notation (JSON) string.

@paramvalue A JavaScript value, usually an object or array, to be converted.

@paramreplacer A function that transforms the results.

@paramspace Adds indentation, white space, and line break characters to the return-value JSON text to make it easier to read.

@throws{TypeError} If a circular reference or a BigInt value is found.

stringify
({
route: string
route
})};
export default options;
`,
}
})
}
}
}
}
// Define el complemento de StudioCMS
return
function definePlugin(options: StudioCMSPluginDef): StudioCMSPluginDef

Defines a plugin for StudioCMS.

@paramoptions - The configuration options for the plugin.

@returnsThe plugin configuration.

definePlugin
({
identifier: string
identifier
: 'my-plugin',
name: string
name
: 'My Plugin',
hooks: {
"studiocms:astro-config"?: ((args: {
readonly logger: AstroIntegrationLogger;
readonly addIntegrations: (args: AstroIntegration | AstroIntegration[]) => Promise<void>;
}) => Promise<void>) | ((args: {
readonly logger: AstroIntegrationLogger;
readonly addIntegrations: (args: AstroIntegration | AstroIntegration[]) => Promise<void>;
}) => void) | undefined;
... 5 more ...;
"studiocms:sitemap"?: ((args: {
readonly logger: AstroIntegrationLogger;
readonly setSitemap: (args: {
triggerSitemap?: boolean | undefined;
sitemaps?: readonly {
readonly pluginName: string;
readonly sitemapXMLEndpointPath: string;
}[] | undefined;
}) => Promise<void>;
}) => Promise<void>) | ((args: {
readonly logger: AstroIntegrationLogger;
readonly setSitemap: (args: {
triggerSitemap?: boolean | undefined;
sitemaps?: readonly {
readonly pluginName: string;
readonly sitemapXMLEndpointPath: string;
}[] | undefined;
}) => Promise<void>;
}) => void) | undefined;
}
hooks
: {
'studiocms:astro-config': ({
addIntegrations: (args: AstroIntegration | AstroIntegration[]) => Promise<void>
addIntegrations
}) => {
addIntegrations: (args: AstroIntegration | AstroIntegration[]) => Promise<void>
addIntegrations
(
function (local function) myIntegration(options: Options): AstroIntegration
myIntegration
(
options: Options
options
)); // Opcional, pero recomendado
},
'studiocms:dashboard': ({
setDashboard: (args: {
translations: {
[x: string]: {
[x: string]: {
[x: string]: string;
};
};
};
dashboardGridItems?: readonly {
readonly name: string;
readonly span: 1 | 2 | 3;
readonly variant: "default" | "filled";
readonly requiresPermission?: "owner" | "admin" | "editor" | "visitor" | undefined;
readonly header?: {
readonly title: string;
readonly icon?: "heroicons:academic-cap" | "heroicons:academic-cap-16-solid" | "heroicons:academic-cap-20-solid" | "heroicons:academic-cap-solid" | "heroicons:adjustments-horizontal" | "heroicons:adjustments-horizontal-16-solid" | "heroicons:adjustments-horizontal-20-solid" | "heroicons:adjustments-horizontal-solid" | "heroicons:adjustments-vertical" | "heroicons:adjustments-vertical-16-solid" | "heroicons:adjustments-vertical-20-solid" | "heroicons:adjustments-vertical-solid" | "heroicons:archive-box" | "heroicons:archive-box-16-solid" | "heroicons:archive-box-20-solid" | "heroicons:archive-box-arrow-down" | "heroicons:archive-box-arrow-down-16-solid" | "heroicons:archive-box-arrow-down-20-solid" | "heroicons:archive-box-arrow-down-solid" | "heroicons:archive-box-solid" | "heroicons:archive-box-x-mark" | "heroicons:archive-box-x-mark-16-solid" | "heroicons:archive-box-x-mark-20-solid" | "heroicons:archive-box-x-mark-solid" | "heroicons:arrow-down" | "heroicons:arrow-down-16-solid" | "heroicons:arrow-down-20-solid" | "heroicons:arrow-down-circle" | "heroicons:arrow-down-circle-16-solid" | "heroicons:arrow-down-circle-20-solid" | "heroicons:arrow-down-circle-solid" | "heroicons:arrow-down-left" | "heroicons:arrow-down-left-16-solid" | "heroicons:arrow-down-left-20-solid" | "heroicons:arrow-down-left-solid" | "heroicons:arrow-down-on-square" | "heroicons:arrow-down-on-square-16-solid" | "heroicons:arrow-down-on-square-20-solid" | "heroicons:arrow-down-on-square-solid" | "heroicons:arrow-down-on-square-stack" | "heroicons:arrow-down-on-square-stack-16-solid" | "heroicons:arrow-down-on-square-stack-20-solid" | "heroicons:arrow-down-on-square-stack-solid" | "heroicons:arrow-down-right" | "heroicons:arrow-down-right-16-solid" | "heroicons:arrow-down-right-20-solid" | "heroicons:arrow-down-right-solid" | "heroicons:arrow-down-solid" | "heroicons:arrow-down-tray" | "heroicons:arrow-down-tray-16-solid" | "heroicons:arrow-down-tray-20-solid" | "heroicons:arrow-down-tray-solid" | "heroicons:arrow-left" | "heroicons:arrow-left-16-solid" | "heroicons:arrow-left-20-solid" | "heroicons:arrow-left-circle" | "heroicons:arrow-left-circle-16-solid" | "heroicons:arrow-left-circle-20-solid" | "heroicons:arrow-left-circle-solid" | "heroicons:arrow-left-end-on-rectangle" | "heroicons:arrow-left-end-on-rectangle-16-solid" | "heroicons:arrow-left-end-on-rectangle-20-solid" | "heroicons:arrow-left-end-on-rectangle-solid" | "heroicons:arrow-left-on-rectangle" | "heroicons:arrow-left-on-rectangle-20-solid" | "heroicons:arrow-left-on-rectangle-solid" | "heroicons:arrow-left-solid" | "heroicons:arrow-left-start-on-rectangle" | "heroicons:arrow-left-start-on-rectangle-16-solid" | "heroicons:arrow-left-start-on-rectangle-20-solid" | "heroicons:arrow-left-start-on-rectangle-solid" | "heroicons:arrow-long-down" | "heroicons:arrow-long-down-16-solid" | "heroicons:arrow-long-down-20-solid" | "heroicons:arrow-long-down-solid" | "heroicons:arrow-long-left" | "heroicons:arrow-long-left-16-solid" | "heroicons:arrow-long-left-20-solid" | "heroicons:arrow-long-left-solid" | "heroicons:arrow-long-right" | "heroicons:arrow-long-right-16-solid" | "heroicons:arrow-long-right-20-solid" | "heroicons:arrow-long-right-solid" | "heroicons:arrow-long-up" | "heroicons:arrow-long-up-16-solid" | "heroicons:arrow-long-up-20-solid" | "heroicons:arrow-long-up-solid" | "heroicons:arrow-path" | "heroicons:arrow-path-16-solid" | "heroicons:arrow-path-20-solid" | "heroicons:arrow-path-rounded-square" | "heroicons:arrow-path-rounded-square-16-solid" | "heroicons:arrow-path-rounded-square-20-solid" | "heroicons:arrow-path-rounded-square-solid" | "heroicons:arrow-path-solid" | "heroicons:arrow-right" | "heroicons:arrow-right-16-solid" | "heroicons:arrow-right-20-solid" | "heroicons:arrow-right-circle" | "heroicons:arrow-right-circle-16-solid" | "heroicons:arrow-right-circle-20-solid" | "heroicons:arrow-right-circle-solid" | "heroicons:arrow-right-end-on-rectangle" | "heroicons:arrow-right-end-on-rectangle-16-solid" | "heroicons:arrow-right-end-on-rectangle-20-solid" | "heroicons:arrow-right-end-on-rectangle-solid" | "heroicons:arrow-right-on-rectangle" | "heroicons:arrow-right-on-rectangle-20-solid" | "heroicons:arrow-right-on-rectangle-solid" | "heroicons:arrow-right-solid" | "heroicons:arrow-right-start-on-rectangle" | "heroicons:arrow-right-start-on-rectangle-16-solid" | "heroicons:arrow-right-start-on-rectangle-20-solid" | "heroicons:arrow-right-start-on-rectangle-solid" | "heroicons:arrow-small-down" | "heroicons:arrow-small-down-20-solid" ...
setDashboard
}) => {
setDashboard: (args: {
translations: {
[x: string]: {
[x: string]: {
[x: string]: string;
};
};
};
dashboardGridItems?: readonly {
readonly name: string;
readonly span: 1 | 2 | 3;
readonly variant: "default" | "filled";
readonly requiresPermission?: "owner" | "admin" | "editor" | "visitor" | undefined;
readonly header?: {
readonly title: string;
readonly icon?: "heroicons:academic-cap" | "heroicons:academic-cap-16-solid" | "heroicons:academic-cap-20-solid" | "heroicons:academic-cap-solid" | "heroicons:adjustments-horizontal" | "heroicons:adjustments-horizontal-16-solid" | "heroicons:adjustments-horizontal-20-solid" | "heroicons:adjustments-horizontal-solid" | "heroicons:adjustments-vertical" | "heroicons:adjustments-vertical-16-solid" | "heroicons:adjustments-vertical-20-solid" | "heroicons:adjustments-vertical-solid" | "heroicons:archive-box" | "heroicons:archive-box-16-solid" | "heroicons:archive-box-20-solid" | "heroicons:archive-box-arrow-down" | "heroicons:archive-box-arrow-down-16-solid" | "heroicons:archive-box-arrow-down-20-solid" | "heroicons:archive-box-arrow-down-solid" | "heroicons:archive-box-solid" | "heroicons:archive-box-x-mark" | "heroicons:archive-box-x-mark-16-solid" | "heroicons:archive-box-x-mark-20-solid" | "heroicons:archive-box-x-mark-solid" | "heroicons:arrow-down" | "heroicons:arrow-down-16-solid" | "heroicons:arrow-down-20-solid" | "heroicons:arrow-down-circle" | "heroicons:arrow-down-circle-16-solid" | "heroicons:arrow-down-circle-20-solid" | "heroicons:arrow-down-circle-solid" | "heroicons:arrow-down-left" | "heroicons:arrow-down-left-16-solid" | "heroicons:arrow-down-left-20-solid" | "heroicons:arrow-down-left-solid" | "heroicons:arrow-down-on-square" | "heroicons:arrow-down-on-square-16-solid" | "heroicons:arrow-down-on-square-20-solid" | "heroicons:arrow-down-on-square-solid" | "heroicons:arrow-down-on-square-stack" | "heroicons:arrow-down-on-square-stack-16-solid" | "heroicons:arrow-down-on-square-stack-20-solid" | "heroicons:arrow-down-on-square-stack-solid" | "heroicons:arrow-down-right" | "heroicons:arrow-down-right-16-solid" | "heroicons:arrow-down-right-20-solid" | "heroicons:arrow-down-right-solid" | "heroicons:arrow-down-solid" | "heroicons:arrow-down-tray" | "heroicons:arrow-down-tray-16-solid" | "heroicons:arrow-down-tray-20-solid" | "heroicons:arrow-down-tray-solid" | "heroicons:arrow-left" | "heroicons:arrow-left-16-solid" | "heroicons:arrow-left-20-solid" | "heroicons:arrow-left-circle" | "heroicons:arrow-left-circle-16-solid" | "heroicons:arrow-left-circle-20-solid" | "heroicons:arrow-left-circle-solid" | "heroicons:arrow-left-end-on-rectangle" | "heroicons:arrow-left-end-on-rectangle-16-solid" | "heroicons:arrow-left-end-on-rectangle-20-solid" | "heroicons:arrow-left-end-on-rectangle-solid" | "heroicons:arrow-left-on-rectangle" | "heroicons:arrow-left-on-rectangle-20-solid" | "heroicons:arrow-left-on-rectangle-solid" | "heroicons:arrow-left-solid" | "heroicons:arrow-left-start-on-rectangle" | "heroicons:arrow-left-start-on-rectangle-16-solid" | "heroicons:arrow-left-start-on-rectangle-20-solid" | "heroicons:arrow-left-start-on-rectangle-solid" | "heroicons:arrow-long-down" | "heroicons:arrow-long-down-16-solid" | "heroicons:arrow-long-down-20-solid" | "heroicons:arrow-long-down-solid" | "heroicons:arrow-long-left" | "heroicons:arrow-long-left-16-solid" | "heroicons:arrow-long-left-20-solid" | "heroicons:arrow-long-left-solid" | "heroicons:arrow-long-right" | "heroicons:arrow-long-right-16-solid" | "heroicons:arrow-long-right-20-solid" | "heroicons:arrow-long-right-solid" | "heroicons:arrow-long-up" | "heroicons:arrow-long-up-16-solid" | "heroicons:arrow-long-up-20-solid" | "heroicons:arrow-long-up-solid" | "heroicons:arrow-path" | "heroicons:arrow-path-16-solid" | "heroicons:arrow-path-20-solid" | "heroicons:arrow-path-rounded-square" | "heroicons:arrow-path-rounded-square-16-solid" | "heroicons:arrow-path-rounded-square-20-solid" | "heroicons:arrow-path-rounded-square-solid" | "heroicons:arrow-path-solid" | "heroicons:arrow-right" | "heroicons:arrow-right-16-solid" | "heroicons:arrow-right-20-solid" | "heroicons:arrow-right-circle" | "heroicons:arrow-right-circle-16-solid" | "heroicons:arrow-right-circle-20-solid" | "heroicons:arrow-right-circle-solid" | "heroicons:arrow-right-end-on-rectangle" | "heroicons:arrow-right-end-on-rectangle-16-solid" | "heroicons:arrow-right-end-on-rectangle-20-solid" | "heroicons:arrow-right-end-on-rectangle-solid" | "heroicons:arrow-right-on-rectangle" | "heroicons:arrow-right-on-rectangle-20-solid" | "heroicons:arrow-right-on-rectangle-solid" | "heroicons:arrow-right-solid" | "heroicons:arrow-right-start-on-rectangle" | "heroicons:arrow-right-start-on-rectangle-16-solid" | "heroicons:arrow-right-start-on-rectangle-20-solid" | "heroicons:arrow-right-start-on-rectangle-solid" | "heroicons:arrow-small-down" | "heroicons:arrow-small-down-20-solid" ...
setDashboard
({
translations: {
[x: string]: {
[x: string]: {
[x: string]: string;
};
};
}
translations
: {
en: {
example: {
title: string;
'other-text': string;
};
}
en
: {
example: {
title: string;
'other-text': string;
}
example
: {
title: string
title
: 'Example',
'other-text': 'Some other text',
}
},
fr: {
example: {
title: string;
'other-text': string;
};
}
fr
: {
example: {
title: string;
'other-text': string;
}
example
: {
title: string
title
: 'Exemple',
'other-text': 'Un autre texte',
}
}
},
// Define los elementos de la cuadrícula para el dashboard
// Estos son los elementos que se mostrarán en el Dashboard de StudioCMS
// Puedes definir tantos elementos como quieras
// En este ejemplo, estamos definiendo un solo elemento, que tiene un span de 2 y requiere el permiso 'editor' y inyecta un componente Astro que reemplaza el elemento html personalizado.
dashboardGridItems?: readonly {
readonly name: string;
readonly span: 1 | 2 | 3;
readonly variant: "default" | "filled";
readonly requiresPermission?: "owner" | "admin" | "editor" | "visitor" | undefined;
readonly header?: {
readonly title: string;
readonly icon?: "heroicons:academic-cap" | "heroicons:academic-cap-16-solid" | "heroicons:academic-cap-20-solid" | "heroicons:academic-cap-solid" | "heroicons:adjustments-horizontal" | "heroicons:adjustments-horizontal-16-solid" | "heroicons:adjustments-horizontal-20-solid" | "heroicons:adjustments-horizontal-solid" | "heroicons:adjustments-vertical" | "heroicons:adjustments-vertical-16-solid" | "heroicons:adjustments-vertical-20-solid" | "heroicons:adjustments-vertical-solid" | "heroicons:archive-box" | "heroicons:archive-box-16-solid" | "heroicons:archive-box-20-solid" | "heroicons:archive-box-arrow-down" | "heroicons:archive-box-arrow-down-16-solid" | "heroicons:archive-box-arrow-down-20-solid" | "heroicons:archive-box-arrow-down-solid" | "heroicons:archive-box-solid" | "heroicons:archive-box-x-mark" | "heroicons:archive-box-x-mark-16-solid" | "heroicons:archive-box-x-mark-20-solid" | "heroicons:archive-box-x-mark-solid" | "heroicons:arrow-down" | "heroicons:arrow-down-16-solid" | "heroicons:arrow-down-20-solid" | "heroicons:arrow-down-circle" | "heroicons:arrow-down-circle-16-solid" | "heroicons:arrow-down-circle-20-solid" | "heroicons:arrow-down-circle-solid" | "heroicons:arrow-down-left" | "heroicons:arrow-down-left-16-solid" | "heroicons:arrow-down-left-20-solid" | "heroicons:arrow-down-left-solid" | "heroicons:arrow-down-on-square" | "heroicons:arrow-down-on-square-16-solid" | "heroicons:arrow-down-on-square-20-solid" | "heroicons:arrow-down-on-square-solid" | "heroicons:arrow-down-on-square-stack" | "heroicons:arrow-down-on-square-stack-16-solid" | "heroicons:arrow-down-on-square-stack-20-solid" | "heroicons:arrow-down-on-square-stack-solid" | "heroicons:arrow-down-right" | "heroicons:arrow-down-right-16-solid" | "heroicons:arrow-down-right-20-solid" | "heroicons:arrow-down-right-solid" | "heroicons:arrow-down-solid" | "heroicons:arrow-down-tray" | "heroicons:arrow-down-tray-16-solid" | "heroicons:arrow-down-tray-20-solid" | "heroicons:arrow-down-tray-solid" | "heroicons:arrow-left" | "heroicons:arrow-left-16-solid" | "heroicons:arrow-left-20-solid" | "heroicons:arrow-left-circle" | "heroicons:arrow-left-circle-16-solid" | "heroicons:arrow-left-circle-20-solid" | "heroicons:arrow-left-circle-solid" | "heroicons:arrow-left-end-on-rectangle" | "heroicons:arrow-left-end-on-rectangle-16-solid" | "heroicons:arrow-left-end-on-rectangle-20-solid" | "heroicons:arrow-left-end-on-rectangle-solid" | "heroicons:arrow-left-on-rectangle" | "heroicons:arrow-left-on-rectangle-20-solid" | "heroicons:arrow-left-on-rectangle-solid" | "heroicons:arrow-left-solid" | "heroicons:arrow-left-start-on-rectangle" | "heroicons:arrow-left-start-on-rectangle-16-solid" | "heroicons:arrow-left-start-on-rectangle-20-solid" | "heroicons:arrow-left-start-on-rectangle-solid" | "heroicons:arrow-long-down" | "heroicons:arrow-long-down-16-solid" | "heroicons:arrow-long-down-20-solid" | "heroicons:arrow-long-down-solid" | "heroicons:arrow-long-left" | "heroicons:arrow-long-left-16-solid" | "heroicons:arrow-long-left-20-solid" | "heroicons:arrow-long-left-solid" | "heroicons:arrow-long-right" | "heroicons:arrow-long-right-16-solid" | "heroicons:arrow-long-right-20-solid" | "heroicons:arrow-long-right-solid" | "heroicons:arrow-long-up" | "heroicons:arrow-long-up-16-solid" | "heroicons:arrow-long-up-20-solid" | "heroicons:arrow-long-up-solid" | "heroicons:arrow-path" | "heroicons:arrow-path-16-solid" | "heroicons:arrow-path-20-solid" | "heroicons:arrow-path-rounded-square" | "heroicons:arrow-path-rounded-square-16-solid" | "heroicons:arrow-path-rounded-square-20-solid" | "heroicons:arrow-path-rounded-square-solid" | "heroicons:arrow-path-solid" | "heroicons:arrow-right" | "heroicons:arrow-right-16-solid" | "heroicons:arrow-right-20-solid" | "heroicons:arrow-right-circle" | "heroicons:arrow-right-circle-16-solid" | "heroicons:arrow-right-circle-20-solid" | "heroicons:arrow-right-circle-solid" | "heroicons:arrow-right-end-on-rectangle" | "heroicons:arrow-right-end-on-rectangle-16-solid" | "heroicons:arrow-right-end-on-rectangle-20-solid" | "heroicons:arrow-right-end-on-rectangle-solid" | "heroicons:arrow-right-on-rectangle" | "heroicons:arrow-right-on-rectangle-20-solid" | "heroicons:arrow-right-on-rectangle-solid" | "heroicons:arrow-right-solid" | "heroicons:arrow-right-start-on-rectangle" | "heroicons:arrow-right-start-on-rectangle-16-solid" | "heroicons:arrow-right-start-on-rectangle-20-solid" | "heroicons:arrow-right-start-on-rectangle-solid" | "heroicons:arrow-small-down" | "heroicons:arrow-small-down-20-solid" | "heroicons:arrow-small-down-solid" | "heroicons:arrow-small-left" | "heroicons:arrow-small-left-20-solid" | "heroicons:arrow-small-left-solid" | "heroicons:arrow-small-right" ...
dashboardGridItems
: [
{
name: string
name
: 'example',
span: 1 | 2 | 3
span
: 2,
variant: "default" | "filled"
variant
: 'default',
requiresPermission?: "owner" | "admin" | "editor" | "visitor" | undefined
requiresPermission
: 'editor',
header?: {
readonly title: string;
readonly icon?: "heroicons:academic-cap" | "heroicons:academic-cap-16-solid" | "heroicons:academic-cap-20-solid" | "heroicons:academic-cap-solid" | "heroicons:adjustments-horizontal" | "heroicons:adjustments-horizontal-16-solid" | "heroicons:adjustments-horizontal-20-solid" | "heroicons:adjustments-horizontal-solid" | "heroicons:adjustments-vertical" | "heroicons:adjustments-vertical-16-solid" | "heroicons:adjustments-vertical-20-solid" | "heroicons:adjustments-vertical-solid" | "heroicons:archive-box" | "heroicons:archive-box-16-solid" | "heroicons:archive-box-20-solid" | "heroicons:archive-box-arrow-down" | "heroicons:archive-box-arrow-down-16-solid" | "heroicons:archive-box-arrow-down-20-solid" | "heroicons:archive-box-arrow-down-solid" | "heroicons:archive-box-solid" | "heroicons:archive-box-x-mark" | "heroicons:archive-box-x-mark-16-solid" | "heroicons:archive-box-x-mark-20-solid" | "heroicons:archive-box-x-mark-solid" | "heroicons:arrow-down" | "heroicons:arrow-down-16-solid" | "heroicons:arrow-down-20-solid" | "heroicons:arrow-down-circle" | "heroicons:arrow-down-circle-16-solid" | "heroicons:arrow-down-circle-20-solid" | "heroicons:arrow-down-circle-solid" | "heroicons:arrow-down-left" | "heroicons:arrow-down-left-16-solid" | "heroicons:arrow-down-left-20-solid" | "heroicons:arrow-down-left-solid" | "heroicons:arrow-down-on-square" | "heroicons:arrow-down-on-square-16-solid" | "heroicons:arrow-down-on-square-20-solid" | "heroicons:arrow-down-on-square-solid" | "heroicons:arrow-down-on-square-stack" | "heroicons:arrow-down-on-square-stack-16-solid" | "heroicons:arrow-down-on-square-stack-20-solid" | "heroicons:arrow-down-on-square-stack-solid" | "heroicons:arrow-down-right" | "heroicons:arrow-down-right-16-solid" | "heroicons:arrow-down-right-20-solid" | "heroicons:arrow-down-right-solid" | "heroicons:arrow-down-solid" | "heroicons:arrow-down-tray" | "heroicons:arrow-down-tray-16-solid" | "heroicons:arrow-down-tray-20-solid" | "heroicons:arrow-down-tray-solid" | "heroicons:arrow-left" | "heroicons:arrow-left-16-solid" | "heroicons:arrow-left-20-solid" | "heroicons:arrow-left-circle" | "heroicons:arrow-left-circle-16-solid" | "heroicons:arrow-left-circle-20-solid" | "heroicons:arrow-left-circle-solid" | "heroicons:arrow-left-end-on-rectangle" | "heroicons:arrow-left-end-on-rectangle-16-solid" | "heroicons:arrow-left-end-on-rectangle-20-solid" | "heroicons:arrow-left-end-on-rectangle-solid" | "heroicons:arrow-left-on-rectangle" | "heroicons:arrow-left-on-rectangle-20-solid" | "heroicons:arrow-left-on-rectangle-solid" | "heroicons:arrow-left-solid" | "heroicons:arrow-left-start-on-rectangle" | "heroicons:arrow-left-start-on-rectangle-16-solid" | "heroicons:arrow-left-start-on-rectangle-20-solid" | "heroicons:arrow-left-start-on-rectangle-solid" | "heroicons:arrow-long-down" | "heroicons:arrow-long-down-16-solid" | "heroicons:arrow-long-down-20-solid" | "heroicons:arrow-long-down-solid" | "heroicons:arrow-long-left" | "heroicons:arrow-long-left-16-solid" | "heroicons:arrow-long-left-20-solid" | "heroicons:arrow-long-left-solid" | "heroicons:arrow-long-right" | "heroicons:arrow-long-right-16-solid" | "heroicons:arrow-long-right-20-solid" | "heroicons:arrow-long-right-solid" | "heroicons:arrow-long-up" | "heroicons:arrow-long-up-16-solid" | "heroicons:arrow-long-up-20-solid" | "heroicons:arrow-long-up-solid" | "heroicons:arrow-path" | "heroicons:arrow-path-16-solid" | "heroicons:arrow-path-20-solid" | "heroicons:arrow-path-rounded-square" | "heroicons:arrow-path-rounded-square-16-solid" | "heroicons:arrow-path-rounded-square-20-solid" | "heroicons:arrow-path-rounded-square-solid" | "heroicons:arrow-path-solid" | "heroicons:arrow-right" | "heroicons:arrow-right-16-solid" | "heroicons:arrow-right-20-solid" | "heroicons:arrow-right-circle" | "heroicons:arrow-right-circle-16-solid" | "heroicons:arrow-right-circle-20-solid" | "heroicons:arrow-right-circle-solid" | "heroicons:arrow-right-end-on-rectangle" | "heroicons:arrow-right-end-on-rectangle-16-solid" | "heroicons:arrow-right-end-on-rectangle-20-solid" | "heroicons:arrow-right-end-on-rectangle-solid" | "heroicons:arrow-right-on-rectangle" | "heroicons:arrow-right-on-rectangle-20-solid" | "heroicons:arrow-right-on-rectangle-solid" | "heroicons:arrow-right-solid" | "heroicons:arrow-right-start-on-rectangle" | "heroicons:arrow-right-start-on-rectangle-16-solid" | "heroicons:arrow-right-start-on-rectangle-20-solid" | "heroicons:arrow-right-start-on-rectangle-solid" | "heroicons:arrow-small-down" | "heroicons:arrow-small-down-20-solid" | "heroicons:arrow-small-down-solid" | "heroicons:arrow-small-left" | "heroicons:arrow-small-left-20-solid" | "heroicons:arrow-small-left-solid" | "heroicons:arrow-small-right" | "heroicons:arrow-small-right-20-solid" | "heroicons:arrow-small-right-solid" | "heroicons:arrow-small-up" | "heroicons:arrow-small-up-20-solid" | "heroicons:arrow-small-up-solid" | "heroicons:arrow-top-right-on-square" | "heroicons:arrow-top-right-on-square-16-solid" ...
header
: {
title: string
title
: 'Example',
icon?: "heroicons:academic-cap" | "heroicons:academic-cap-16-solid" | "heroicons:academic-cap-20-solid" | "heroicons:academic-cap-solid" | "heroicons:adjustments-horizontal" | "heroicons:adjustments-horizontal-16-solid" | "heroicons:adjustments-horizontal-20-solid" | "heroicons:adjustments-horizontal-solid" | "heroicons:adjustments-vertical" | "heroicons:adjustments-vertical-16-solid" | "heroicons:adjustments-vertical-20-solid" | "heroicons:adjustments-vertical-solid" | "heroicons:archive-box" | "heroicons:archive-box-16-solid" | ... 1284 more ... | undefined
icon
: 'heroicons:bolt' },
body?: {
readonly html: string;
readonly components?: {
readonly [x: string]: string;
} | undefined;
readonly sanitizeOpts?: SanitizeOptions | undefined;
} | undefined
body
: {
// Siempre usa html plano sin `-` o caracteres especiales en las etiquetas, se reemplazarán con el componente Astro y este HTML nunca se renderizará
html: string
html
: '<examplegriditem></examplegriditem>',
components?: {
readonly [x: string]: string;
} | undefined
components
: {
// Inyecta el componente Astro para reemplazar el elemento html personalizado
examplegriditem: string
examplegriditem
:
const resolve: (...path: Array<string>) => string
resolve
('./dashboard-grid-items/MyPluginGridItem.astro')
}
}
}
],
});
},
'studiocms:frontend': ({
setFrontend: (args: {
frontendNavigationLinks?: readonly {
readonly label: string;
readonly href: string;
}[] | undefined;
}) => Promise<void>
setFrontend
}) => {
setFrontend: (args: {
frontendNavigationLinks?: readonly {
readonly label: string;
readonly href: string;
}[] | undefined;
}) => Promise<void>
setFrontend
({
// Define los enlaces de navegación del frontend para el complemento
// Esto es útil si estás usando los ayudantes de navegación de StudioCMS incorporados en tu diseño,
// como cuando usas el complemento `@studiocms/blog`.
frontendNavigationLinks?: readonly {
readonly label: string;
readonly href: string;
}[] | undefined
frontendNavigationLinks
: [{
label: string
label
: 'My Plugin',
href: string
href
:
options: Options
options
?.
Options.route: string
route
|| 'my-plugin' }],
});
},
'studiocms:rendering': ({
setRendering: (args: {
pageTypes?: readonly {
readonly identifier: string;
readonly label: string;
readonly description?: string | undefined;
readonly fields?: readonly ({
readonly name: string;
readonly label: string;
readonly required?: boolean | undefined;
readonly readOnly?: boolean | undefined;
readonly color?: "primary" | "success" | "warning" | "danger" | "info" | "mono" | undefined;
readonly input: "checkbox";
readonly defaultChecked?: boolean | undefined;
readonly size?: "sm" | "md" | "lg" | undefined;
} | {
readonly name: string;
readonly label: string;
readonly required?: boolean | undefined;
readonly readOnly?: boolean | undefined;
readonly placeholder?: string | undefined;
readonly input: "input";
readonly type?: "number" | "text" | "password" | "email" | "tel" | "url" | "search" | undefined;
readonly defaultValue?: string | undefined;
} | {
readonly name: string;
readonly label: string;
readonly required?: boolean | undefined;
readonly readOnly?: boolean | undefined;
readonly placeholder?: string | undefined;
readonly input: "textarea";
readonly defaultValue?: string | undefined;
} | {
readonly name: string;
readonly label: string;
readonly required?: boolean | undefined;
readonly readOnly?: boolean | undefined;
readonly color?: "primary" | "success" | "warning" | "danger" | "info" | "mono" | undefined;
readonly input: "radio";
readonly options: {
readonly value: string;
readonly label: string;
readonly disabled?: boolean | undefined;
}[];
readonly defaultValue?: string | undefined;
readonly direction?: "horizontal" | "vertical" | undefined;
} | {
readonly name: string;
readonly label: string;
readonly required?: boolean | undefined;
readonly readOnly?: boolean | undefined;
readonly color?: "primary" | "success" | "warning" | "danger" | "info" | "mono" | undefined;
readonly input: "select";
readonly options: {
readonly value: string;
readonly label: string;
readonly disabled?: boolean | undefined;
}[];
readonly type?: "search" | "basic" | undefined;
readonly defaultValue?: string | undefined;
} | {
readonly name: string;
readonly label: string;
readonly required?: boolean | undefined;
readonly readOnly?: boolean | undefined;
readonly fields: readonly ({
readonly name: string;
readonly label: string;
readonly required?: boolean | undefined;
readonly readOnly?: boolean | undefined;
readonly color?: "primary" | "success" | "warning" | "danger" | "info" | "mono" | undefined;
readonly input: "checkbox";
readonly defaultChecked?: boolean | undefined;
readonly size?: "sm" | "md" | "lg" | undefined;
} | {
readonly name: string;
readonly label: string;
readonly required?: boolean | undefined;
readonly readOnly?: boolean | undefined;
readonly placeholder?: string | undefined;
readonly input: "input";
readonly type?: "number" | "text" | "password" | "email" | "tel" | "url" | "search" | undefined;
readonly defaultValue?: string | undefined;
} | {
readonly name: string;
readonly label: string;
readonly required?: boolean | undefined;
readonly readOnly?: boolean | undefined;
readonly placeholder?: string | undefined;
readonly input: "textarea";
readonly defaultValue?: string | undefined;
} | {
readonly name: string;
readonly label: string;
readonly required?: boolean | undefined;
readonly readOnly?: boolean | undefined;
readonly color?: "primary" | "success" | "warning" | "danger" | "info" | "mono" | undefined;
readonly input: "radio";
readonly options: {
readonly value: string;
readonly label: string;
readonly disabled?: boolean | undefined;
}[];
readonly defaultValue?: string | undefined;
readonly direction?: "horizontal" | "vertical" | undefined;
} | {
readonly ...
setRendering
}) => {
setRendering: (args: {
pageTypes?: readonly {
readonly identifier: string;
readonly label: string;
readonly description?: string | undefined;
readonly fields?: readonly ({
readonly name: string;
readonly label: string;
readonly required?: boolean | undefined;
readonly readOnly?: boolean | undefined;
readonly color?: "primary" | "success" | "warning" | "danger" | "info" | "mono" | undefined;
readonly input: "checkbox";
readonly defaultChecked?: boolean | undefined;
readonly size?: "sm" | "md" | "lg" | undefined;
} | {
readonly name: string;
readonly label: string;
readonly required?: boolean | undefined;
readonly readOnly?: boolean | undefined;
readonly placeholder?: string | undefined;
readonly input: "input";
readonly type?: "number" | "text" | "password" | "email" | "tel" | "url" | "search" | undefined;
readonly defaultValue?: string | undefined;
} | {
readonly name: string;
readonly label: string;
readonly required?: boolean | undefined;
readonly readOnly?: boolean | undefined;
readonly placeholder?: string | undefined;
readonly input: "textarea";
readonly defaultValue?: string | undefined;
} | {
readonly name: string;
readonly label: string;
readonly required?: boolean | undefined;
readonly readOnly?: boolean | undefined;
readonly color?: "primary" | "success" | "warning" | "danger" | "info" | "mono" | undefined;
readonly input: "radio";
readonly options: {
readonly value: string;
readonly label: string;
readonly disabled?: boolean | undefined;
}[];
readonly defaultValue?: string | undefined;
readonly direction?: "horizontal" | "vertical" | undefined;
} | {
readonly name: string;
readonly label: string;
readonly required?: boolean | undefined;
readonly readOnly?: boolean | undefined;
readonly color?: "primary" | "success" | "warning" | "danger" | "info" | "mono" | undefined;
readonly input: "select";
readonly options: {
readonly value: string;
readonly label: string;
readonly disabled?: boolean | undefined;
}[];
readonly type?: "search" | "basic" | undefined;
readonly defaultValue?: string | undefined;
} | {
readonly name: string;
readonly label: string;
readonly required?: boolean | undefined;
readonly readOnly?: boolean | undefined;
readonly fields: readonly ({
readonly name: string;
readonly label: string;
readonly required?: boolean | undefined;
readonly readOnly?: boolean | undefined;
readonly color?: "primary" | "success" | "warning" | "danger" | "info" | "mono" | undefined;
readonly input: "checkbox";
readonly defaultChecked?: boolean | undefined;
readonly size?: "sm" | "md" | "lg" | undefined;
} | {
readonly name: string;
readonly label: string;
readonly required?: boolean | undefined;
readonly readOnly?: boolean | undefined;
readonly placeholder?: string | undefined;
readonly input: "input";
readonly type?: "number" | "text" | "password" | "email" | "tel" | "url" | "search" | undefined;
readonly defaultValue?: string | undefined;
} | {
readonly name: string;
readonly label: string;
readonly required?: boolean | undefined;
readonly readOnly?: boolean | undefined;
readonly placeholder?: string | undefined;
readonly input: "textarea";
readonly defaultValue?: string | undefined;
} | {
readonly name: string;
readonly label: string;
readonly required?: boolean | undefined;
readonly readOnly?: boolean | undefined;
readonly color?: "primary" | "success" | "warning" | "danger" | "info" | "mono" | undefined;
readonly input: "radio";
readonly options: {
readonly value: string;
readonly label: string;
readonly disabled?: boolean | undefined;
}[];
readonly defaultValue?: string | undefined;
readonly direction?: "horizontal" | "vertical" | undefined;
} | {
readonly ...
setRendering
({
// Cuando creas pageTypes, también puedes definir un `pageContentComponent` si tu complemento requiere un editor de contenido personalizado.
// pageTypes: [{ identifier: 'my-plugin', label: 'Blog Post (My Plugin)', pageContentComponent: resolve('./components/MyContentEditor.astro') }],
// En este ejemplo estamos usando el editor de contenido por defecto (markdown).
pageTypes?: readonly {
readonly identifier: string;
readonly label: string;
readonly description?: string | undefined;
readonly fields?: readonly ({
readonly name: string;
readonly label: string;
readonly required?: boolean | undefined;
readonly readOnly?: boolean | undefined;
readonly color?: "primary" | "success" | "warning" | "danger" | "info" | "mono" | undefined;
readonly input: "checkbox";
readonly defaultChecked?: boolean | undefined;
readonly size?: "sm" | "md" | "lg" | undefined;
} | {
readonly name: string;
readonly label: string;
readonly required?: boolean | undefined;
readonly readOnly?: boolean | undefined;
readonly placeholder?: string | undefined;
readonly input: "input";
readonly type?: "number" | "text" | "password" | "email" | "tel" | "url" | "search" | undefined;
readonly defaultValue?: string | undefined;
} | {
readonly name: string;
readonly label: string;
readonly required?: boolean | undefined;
readonly readOnly?: boolean | undefined;
readonly placeholder?: string | undefined;
readonly input: "textarea";
readonly defaultValue?: string | undefined;
} | {
readonly name: string;
readonly label: string;
readonly required?: boolean | undefined;
readonly readOnly?: boolean | undefined;
readonly color?: "primary" | "success" | "warning" | "danger" | "info" | "mono" | undefined;
readonly input: "radio";
readonly options: {
readonly value: string;
readonly label: string;
readonly disabled?: boolean | undefined;
}[];
readonly defaultValue?: string | undefined;
readonly direction?: "horizontal" | "vertical" | undefined;
} | {
readonly name: string;
readonly label: string;
readonly required?: boolean | undefined;
readonly readOnly?: boolean | undefined;
readonly color?: "primary" | "success" | "warning" | "danger" | "info" | "mono" | undefined;
readonly input: "select";
readonly options: {
readonly value: string;
readonly label: string;
readonly disabled?: boolean | undefined;
}[];
readonly type?: "search" | "basic" | undefined;
readonly defaultValue?: string | undefined;
} | {
readonly name: string;
readonly label: string;
readonly required?: boolean | undefined;
readonly readOnly?: boolean | undefined;
readonly fields: readonly ({
readonly name: string;
readonly label: string;
readonly required?: boolean | undefined;
readonly readOnly?: boolean | undefined;
readonly color?: "primary" | "success" | "warning" | "danger" | "info" | "mono" | undefined;
readonly input: "checkbox";
readonly defaultChecked?: boolean | undefined;
readonly size?: "sm" | "md" | "lg" | undefined;
} | {
readonly name: string;
readonly label: string;
readonly required?: boolean | undefined;
readonly readOnly?: boolean | undefined;
readonly placeholder?: string | undefined;
readonly input: "input";
readonly type?: "number" | "text" | "password" | "email" | "tel" | "url" | "search" | undefined;
readonly defaultValue?: string | undefined;
} | {
readonly name: string;
readonly label: string;
readonly required?: boolean | undefined;
readonly readOnly?: boolean | undefined;
readonly placeholder?: string | undefined;
readonly input: "textarea";
readonly defaultValue?: string | undefined;
} | {
readonly name: string;
readonly label: string;
readonly required?: boolean | undefined;
readonly readOnly?: boolean | undefined;
readonly color?: "primary" | "success" | "warning" | "danger" | "info" | "mono" | undefined;
readonly input: "radio";
readonly options: {
readonly value: string;
readonly label: string;
readonly disabled?: boolean | undefined;
}[];
readonly defaultValue?: string | undefined;
readonly direction?: "horizontal" | "vertical" | undefined;
} | {
readonly name: string;
readonly label: string;
readonly required?: boolean | undefined;
readonly readOnly?: boolean | undefined;
readonly color?: "primary" | "success" | "warning" | "danger" | "info" | "mono" | undefined;
readonly input: "select";
readonly options: {
readonly value: string;
readonly label: string;
readonly ...
pageTypes
: [{
identifier: string
identifier
: 'my-plugin',
label: string
label
: 'Blog Post (My Plugin)' }],
});
}
}
});
}

El ejemplo anterior define un complemento de StudioCMS que incluye una integración Astro para crear un ejemplo simple de blog. El complemento incluye una ruta que se inyecta en el proyecto StudioCMS y un elemento de cuadrícula que se muestra en el panel de control de StudioCMS.

Para más información sobre cómo crear una integración Astro, consulta el Kit de integración de Astro^ y la documentación de integraciones de Astro^.

En el archivo src/routes/[...slug].astro, definirás la ruta para el complemento. A continuación se muestra un ejemplo de cómo definir una ruta para el complemento, lo dividiremos en dos partes, la primera parte es el frontmatter (entre las marcas ---), y la segunda parte es la plantilla HTML que se coloca debajo del segundo ---.

Frontmatter
import {
const StudioCMSRenderer: any
StudioCMSRenderer
} from 'studiocms:renderer';
import
module "studiocms:sdk"
sdk
from 'studiocms:sdk';
import
const config: {
route: string;
}
config
from 'myplugin:config';
const
const makeRoute: (slug: string) => string
makeRoute
= (
slug: string
slug
: string) => {
return `/${
const config: {
route: string;
}
config
.
route: string
route
}/${
slug: string
slug
}`;
}
// 'my-plugin' aquí se usa como identificador para
// el pageType de la definición del complemento
const
const pages: any
pages
= await
module "studiocms:sdk"
sdk
.
any
GET
.
any
packagePages
('my-plugin');
const {
const slug: string | undefined
slug
} =
const Astro: AstroGlobal<Record<string, any>, AstroComponentFactory, Record<string, string | undefined>>
Astro
.
AstroSharedContext<Record<string, any>, Record<string, string | undefined>>.params: Record<string, string | undefined>

An object containing the values of dynamic route segments matched for a request.

In static builds, this will be the params returned by getStaticPaths(). With on-demand rendering, params can be any value matching the path segments in the dynamic route pattern.

Example

import type { APIContext } from "astro"
export function getStaticPaths() {
return [
{ params: { id: '0' }, props: { name: 'Sarah' } },
{ params: { id: '1' }, props: { name: 'Chris' } },
{ params: { id: '2' }, props: { name: 'Fuzzy' } },
];
}
export function GET({ params }: APIContext): Response {
return new Response(`The current id is ${params.id}.`);
}

Astro reference

params
;
const
const page: any
page
=
const pages: any
pages
.
any
find
((
page: any
page
) =>
page: any
page
.
any
slug
===
const slug: string | undefined
slug
|| '');
Template
{
slug && page ? (
<div>
<h1>{page.title}</h1>
<StudioCMSRenderer content={page.defaultContent?.content || ''} />
</div>
) : (
<div>
<h1>Mi complemento</h1>
<ul>
{pages.length > 0 && pages.map((page) => (
<li>
<a href={makeRoute(page.slug)}>{page.title}</a>
</li>
))}
</ul>
</div>
)
}

El ejemplo anterior define una ruta dinámica^ para el complemento que muestra una lista de entradas de blog cuando no se proporciona un slug y muestra el contenido de una entrada de blog cuando se proporciona un slug.

En el archivo src/dashboard-grid-items/MyPluginGridItem.astro, definirás el elemento de cuadrícula para el complemento. A continuación se muestra un ejemplo de cómo definir un elemento de cuadrícula para el complemento:

MyPluginGridItem.astro
---
import { SDKCoreJs, runSDK } from 'studiocms:sdk';
// 'my-plugin' aquí se usa como identificador para
// el pageType de la definición del complemento
const pages = await runSDK(SDKCoreJs.GET.packagePages('my-plugin'));
// Consigue las 5 páginas actualizadas más recientemente de los últimos 30 días
const recentlyUpdatedPages = pages
.filter((page) => {
const now = new Date();
const thirtyDaysAgo = new Date(now.setDate(now.getDate() - 30));
return new Date(page.updatedAt) > thirtyDaysAgo;
})
.sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime())
.slice(0, 5);
---
<div>
<h2>Páginas actualizadas recientemente</h2>
<ul>
{recentlyUpdatedPages.length > 0 && recentlyUpdatedPages.map((page) => (
<li>
<a href={Astro.locals.routeMap.mainLinks.contentManagementEdit + `?edit=${page.id}`}>{page.title}</a>
</li>
))}
</ul>
</div>

El ejemplo anterior define un elemento de cuadrícula para el complemento que muestra las 5 páginas actualizadas más recientemente de los últimos 30 días. El elemento de cuadrícula incluye una lista de enlaces a la página de edición de gestión de contenido para cada página.

Sección titulada «Integrando con los ayudantes (helpers) de FrontendNavigationLinks»

Si deseas usar los ayudantes (helpers) de navegación incorporados de StudioCMS en tu proyecto, similar a como lo hace el complemento @studiocms/blog, puedes crear un componente personalizado Navigation.astro:

Navigation.astro
---
import { frontendNavigation } from 'studiocms:plugin-helpers';
// Define las props para el componente de navegación
interface Props {
topLevelLinkCount?: number;
};
// Consigue el enlace de nivel superior de las props
const { topLevelLinkCount = 3 } = Astro.props;
// Consigue la configuración del sitio y la lista de páginas
const config = Astro.locals.siteConfig.data;
// Consigue el título del sitio de la configuración
const { title } = config || { title: 'StudioCMS' };
// Consigue la URL principal del sitio
const {
mainLinks: { baseSiteURL },
} = Astro.locals.routeMap;
// Define las props de enlace para la navegación
type LinkProps = {
text: string;
href: string;
};
// Define los enlaces para la navegación
const links: LinkProps[] = await frontendNavigation();
---
{/* Si no hay elementos dropdown */}
{ ( links.length < topLevelLinkCount || links.length === topLevelLinkCount ) && (
<div class="navigation">
<div class="title"><a href={baseSiteURL}>{title}</a></div>
<div class="mini-nav">
<button>Menu</button>
<div class="mini-nav-content">
{
links.map(({ text, href }) => (
<a {href}>{text}</a>
))
}
</div>
</div>
{
links.map(({ text, href }) => (
<a class="links" {href}>{text}</a>
))
}
</div>
) }
{/* Si hay elementos dropdown */}
{ links.length > topLevelLinkCount && (
<div class="navigation">
<div class="title"><a href={baseSiteURL}>{title}</a></div>
<div class="mini-nav">
<button>Menu</button>
<div class="mini-nav-content">
{
links.map(({ text, href }) => (
<a {href}>{text}</a>
))
}
</div>
</div>
{
links.slice(0, topLevelLinkCount).map(({ text, href }) => (
<a class="links" {href}>{text}</a>
))
}
<div class="dropdown">
<button>More ▼</button>
<div class="dropdown-content">
{ links.slice(topLevelLinkCount).map(({ text, href }) => (
<a {href}>{text}</a>
)) }
</div>
</div>
</div>
) }

El ejemplo anterior define un componente personalizado Navigation.astro que utiliza los ayudantes de navegación incorporados de StudioCMS para crear un menú de navegación para el proyecto. El componente incluye enlaces a la URL principal del sitio, la página de índice y cualquier otra página que esté configurada para mostrarse en la navegación.

Todo lo que necesitas hacer es agregar algunos estilos, y tendrás un menú de navegación completamente funcional que funciona con los ayudantes de navegación incorporados de StudioCMS.