Aller au contenu

Rendre les modules d’extension utiles

Construire un module d’extension pour StudioCMS est un moyen puissant d’étendre les fonctionnalités de StudioCMS. Il offre une solution simple et flexible pour ajouter de nouvelles fonctionnalités à votre projet StudioCMS. Voici un exemple simple de création et de fonctionnement d’un module d’extension pour StudioCMS.

Pour commencer, vous devez créer un nouveau module d’extension pour StudioCMS. Voici un exemple de structure de fichier pour un module d’extension pour StudioCMS :

  • package.json
  • Répertoiresrc
    • index.ts
    • Répertoireroutes
      • […slug].astro
    • Répertoiredashboard-grid-items
      • MyPluginGridItem.astro

Dans le fichier principal src/index.ts, vous définirez le module d’extension pour StudioCMS. Voici un exemple de définition d’un module d’extension pour StudioCMS incluant une intégration Astro pour créer un blog simple :

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';
// Définir les options du module d’extension et de l’intégration
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
) {
// Résoudre le chemin d’accès au fichier actuel
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
);
// Définir l’intégration Astro
function
function (local function) monIntegration(options: Options): AstroIntegration
monIntegration
(
options: Options
options
:
interface Options
Options
):
(alias) interface AstroIntegration
import AstroIntegration
AstroIntegration
{
const
const route: string
route
= `/${
options: Options
options
?.
Options.route: string
route
|| 'mon-module-extension'}`;
return {
AstroIntegration.name: string

The name of the integration.

name
: 'mon-integration-astro',
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
;
// Injecter la route pour le module d’extension
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
: 'mon-integration-astro',
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;
`,
}
})
}
}
}
}
// Définir le module d’extension pour 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
: 'mon-module-extension',
name: string
name
: "Mon module d'extension",
studiocmsMinimumVersion?: string | undefined
studiocmsMinimumVersion
: '0.1.0',
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) monIntegration(options: Options): AstroIntegration
monIntegration
(
options: Options
options
)); // Facultatif, mais recommandé
},
'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',
}
}
},
// Définir les éléments de la grille pour le tableau de bord
// Voici les éléments qui seront affichés dans le tableau de bord de StudioCMS
// Vous pouvez définir autant d’éléments que vous le souhaitez
// Dans cet exemple, nous définissons un seul élément, qui a une étendue de 2, qui nécessite l’autorisation `editor` et qui injecte un composant Astro qui remplace l’élément personnalisé HTML simple.
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
: 'exemple',
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
: 'Exemple', icon: 'bolt' },
Error ts(2322) ― Type '"bolt"' is not assignable to type '"heroicons:academic-cap" | "heroicons:academic-cap-16-solid" | "heroicons:academic-cap-20-solid" | "heroicons:academic-cap-solid" | "heroicons:adjustments-horizontal" | ... 1293 more ... | undefined'.
body?: {
readonly html: string;
readonly components?: {
readonly [x: string]: string;
} | undefined;
readonly sanitizeOpts?: SanitizeOptions | undefined;
} | undefined
body
: {
// Utilisez toujours du HTML brut sans `-` ni caractères spéciaux dans les balises, ils seront remplacés par le composant Astro et ce HTML ne sera jamais affiché
html: string
html
: '<examplegriditem></examplegriditem>',
components?: {
readonly [x: string]: string;
} | undefined
components
: {
// Injecter le composant Astro pour remplacer l’élément personnalisé HTML brut
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
({
// Définir les liens de navigation frontend pour le module d’extension
// Ceci est utile si vous utilisez les assistants de navigation intégrés de StudioCMS dans votre mise en page,
// comme lors de l’utilisation du module d’extension `@studiocms/blog`.
frontendNavigationLinks?: readonly {
readonly label: string;
readonly href: string;
}[] | undefined
frontendNavigationLinks
: [{
label: string
label
: "Mon module d'extension",
href: string
href
:
options: Options
options
?.
Options.route: string
route
|| 'mon-module-extension' }],
});
},
'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
({
// Lors de la création de pagesTypes, vous pouvez également définir un `pageContentComponent` si votre module d’extension nécessite un éditeur de contenu personnalisé.
// pageTypes: [{ identifier: 'mon-module-extension', label: "Article de blog (Mon module d’extension)", pageContentComponent: resolve('./components/MyContentEditor.astro') }],
// Dans cet exemple, nous pouvons utiliser l’éditeur de contenu par défaut (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
: 'mon-module-extension',
label: string
label
: "Article de blog (Mon module d'extension)" }],
});
}
}
});
}

L’exemple ci-dessus définit un module d’extension pour StudioCMS incluant une intégration Astro et permettant de créer un exemple de blog simple. Le module d’extension inclut une route injectée dans le projet StudioCMS et un élément de grille affiché dans le tableau de bord de StudioCMS.

Pour plus d’informations sur la création d’une intégration Astro, consultez Astro Integration Kit^ et la documentation des intégrations Astro^.

Dans le fichier src/routes/[...slug].astro, vous définirez la route du module d’extension. Voici un exemple de définition d’une route pour le module d’extension. Nous la diviserons en deux parties : la première est le frontmatter (entre les barrières ---), et la seconde est le modèle HTML placé sous la seconde barrière ---.

Frontmatter
import {
const StudioCMSRenderer: any
StudioCMSRenderer
} from 'studiocms:renderer';
import {
const SDKCoreJs: {
AUTH: {
verifyEmail: {
get: (input: string) => Effect<{
readonly id: string;
readonly userId: string;
readonly expiresAt: Date;
readonly token: string;
} | undefined, DBCallbackFailure | DatabaseError, never>;
create: (userId: string) => Effect<{
readonly id: string;
readonly userId: string;
readonly expiresAt: Date;
readonly token: string;
}, DBCallbackFailure | DatabaseError | GeneratorError, never>;
delete: (input: string) => Effect<DeleteResult, DBCallbackFailure | DatabaseError, never>;
};
oAuth: {
create: (input: {
readonly providerUserId: string;
readonly provider: string;
readonly userId: string;
}) => Effect<{
readonly providerUserId: string;
readonly provider: string;
readonly userId: string;
}, DBCallbackFailure | DatabaseError, never>;
delete: (input: {
readonly userId: string;
readonly provider: string;
}) => AuthDeletionResponse;
searchByProviderId: (input: {
readonly providerUserId: string;
readonly userId: string;
}) => Effect<{
readonly providerUserId: string;
readonly provider: string;
readonly userId: string;
} | undefined, DBCallbackFailure | DatabaseError, never>;
searchProvidersForId: (input: {
readonly userId: string;
readonly providerId: string;
}) => Effect<{
readonly providerUserId: string;
readonly provider: string;
readonly userId: string;
} | undefined, DBCallbackFailure | DatabaseError, never>;
};
permission: {
currentStatus: (input: string) => Effect<{
readonly user: string;
readonly rank: "owner" | "admin" | "editor" | "visitor" | "unknown";
} | undefined, DBCallbackFailure | DatabaseError, never>;
};
session: {
create: (input: {
readonly id: string;
readonly userId: string;
readonly expiresAt: string;
}) => Effect<{
readonly id: string;
readonly userId: string;
readonly expiresAt: Date;
}, DBCallbackFailure | DatabaseError, never>;
getById: (input: string) => Effect<{
readonly id: string;
readonly userId: string;
readonly expiresAt: Date;
} | undefined, DBCallbackFailure | DatabaseError, never>;
sessionWithUser: (sessionId: string) => Effect<{
session: {
readonly id: string;
readonly userId: string;
readonly expiresAt: Date;
};
user: {
readonly id: string;
readonly url?: string | null | undefined;
readonly name: string;
readonly email?: string | null | undefined;
readonly avatar?: string | null | undefined;
readonly username: string;
readonly password?: string | null | undefined;
readonly updatedAt: Date;
readonly createdAt: Date;
readonly emailVerified: boolean;
readonly notifications?: string | null | undefined;
};
} | undefined, DBCallbackFailure | DatabaseError, never>;
delete: (input: string) => AuthDeletionResponse;
update: (input: {
readonly id: string;
readonly newDate: Date;
}) => Effect<{
readonly id: string;
readonly userId: string;
readonly expiresAt: Date;
}, DBCallbackFailure | DatabaseError, never>;
};
user: {
create: (userData: {
readonly id: string;
readonly url?: string | null | undefined;
readonly name: string;
readonly email?: string | null | undefined;
readonly avatar?: string | null | undefined;
readonly username: string;
readonly password?: string | null | undefined;
readonly updatedAt: string;
readonly createdAt: string | undefined;
readonly emailVerified: boolean;
readonly notifications?: string | null | undefined;
}, rank: "owner" | "admin" | "editor" | "visitor" | "unknown") => Effect<{
readonly id: string;
readonly ...

VanillaJS Version of the SDKCore. Most internal functions will still contain Effects, you can use runSDK from the 'studiocms:sdk' to run these as normal async functions

@example

import { SDKCoreJs, runSDK } from 'studiocms:sdk';
const pages = await runSDK(SDKCoreJs.GET.pages());

SDKCoreJs
,
const runSDK: <A, E>(effect: Effect<A, E, never>) => Promise<A>

Utility function for running components of the SDKCoreJs

@example

import { SDKCoreJs, runSDK } from 'studiocms:sdk';
const pages = await runSDK(SDKCoreJs.GET.pages());

runSDK
} 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
}`;
}
// 'mon-module-extension' est ici utilisé comme identifiant pour
// le type de page de la définition du module d’extension
const
const pages: CombinedPageData[]
pages
= await
runSDK<CombinedPageData[], DBCallbackFailure | DatabaseError | ParseError | FolderTreeError | CollectorError | PaginateError>(effect: Effect<CombinedPageData[], DBCallbackFailure | DatabaseError | ParseError | FolderTreeError | CollectorError | PaginateError, never>): Promise<CombinedPageData[]>

Alias for runEffect, used to run SDK effects and convert them to plain JavaScript objects.

@parameffect - The Effect to be converted.

@returnsA promise that resolves to the plain JavaScript object representation of the effect's result.

runSDK
(
const SDKCoreJs: {
AUTH: {
verifyEmail: {
get: (input: string) => Effect<{
readonly id: string;
readonly userId: string;
readonly expiresAt: Date;
readonly token: string;
} | undefined, DBCallbackFailure | DatabaseError, never>;
create: (userId: string) => Effect<{
readonly id: string;
readonly userId: string;
readonly expiresAt: Date;
readonly token: string;
}, DBCallbackFailure | DatabaseError | GeneratorError, never>;
delete: (input: string) => Effect<DeleteResult, DBCallbackFailure | DatabaseError, never>;
};
oAuth: {
create: (input: {
readonly providerUserId: string;
readonly provider: string;
readonly userId: string;
}) => Effect<{
readonly providerUserId: string;
readonly provider: string;
readonly userId: string;
}, DBCallbackFailure | DatabaseError, never>;
delete: (input: {
readonly userId: string;
readonly provider: string;
}) => AuthDeletionResponse;
searchByProviderId: (input: {
readonly providerUserId: string;
readonly userId: string;
}) => Effect<{
readonly providerUserId: string;
readonly provider: string;
readonly userId: string;
} | undefined, DBCallbackFailure | DatabaseError, never>;
searchProvidersForId: (input: {
readonly userId: string;
readonly providerId: string;
}) => Effect<{
readonly providerUserId: string;
readonly provider: string;
readonly userId: string;
} | undefined, DBCallbackFailure | DatabaseError, never>;
};
permission: {
currentStatus: (input: string) => Effect<{
readonly user: string;
readonly rank: "owner" | "admin" | "editor" | "visitor" | "unknown";
} | undefined, DBCallbackFailure | DatabaseError, never>;
};
session: {
create: (input: {
readonly id: string;
readonly userId: string;
readonly expiresAt: string;
}) => Effect<{
readonly id: string;
readonly userId: string;
readonly expiresAt: Date;
}, DBCallbackFailure | DatabaseError, never>;
getById: (input: string) => Effect<{
readonly id: string;
readonly userId: string;
readonly expiresAt: Date;
} | undefined, DBCallbackFailure | DatabaseError, never>;
sessionWithUser: (sessionId: string) => Effect<{
session: {
readonly id: string;
readonly userId: string;
readonly expiresAt: Date;
};
user: {
readonly id: string;
readonly url?: string | null | undefined;
readonly name: string;
readonly email?: string | null | undefined;
readonly avatar?: string | null | undefined;
readonly username: string;
readonly password?: string | null | undefined;
readonly updatedAt: Date;
readonly createdAt: Date;
readonly emailVerified: boolean;
readonly notifications?: string | null | undefined;
};
} | undefined, DBCallbackFailure | DatabaseError, never>;
delete: (input: string) => AuthDeletionResponse;
update: (input: {
readonly id: string;
readonly newDate: Date;
}) => Effect<{
readonly id: string;
readonly userId: string;
readonly expiresAt: Date;
}, DBCallbackFailure | DatabaseError, never>;
};
user: {
create: (userData: {
readonly id: string;
readonly url?: string | null | undefined;
readonly name: string;
readonly email?: string | null | undefined;
readonly avatar?: string | null | undefined;
readonly username: string;
readonly password?: string | null | undefined;
readonly updatedAt: string;
readonly createdAt: string | undefined;
readonly emailVerified: boolean;
readonly notifications?: string | null | undefined;
}, rank: "owner" | "admin" | "editor" | "visitor" | "unknown") => Effect<{
readonly id: string;
readonly ...

VanillaJS Version of the SDKCore. Most internal functions will still contain Effects, you can use runSDK from the 'studiocms:sdk' to run these as normal async functions

@example

import { SDKCoreJs, runSDK } from 'studiocms:sdk';
const pages = await runSDK(SDKCoreJs.GET.pages());

SDKCoreJs
.
type GET: {
permissionsLists: {
owners: () => Effect<SingleRank[], UsersError | DBCallbackFailure | DatabaseError, never>;
admins: () => Effect<SingleRank[], UsersError | DBCallbackFailure | DatabaseError, never>;
editors: () => Effect<SingleRank[], UsersError | DBCallbackFailure | DatabaseError, never>;
visitors: () => Effect<SingleRank[], UsersError | DBCallbackFailure | DatabaseError, never>;
all: () => Effect<CombinedRank[], DBCallbackFailure | DatabaseError | UsersError, never>;
};
... 12 more ...;
tags: {
getAll: () => Effect<readonly {
readonly id: number;
readonly name: string;
readonly description: string;
readonly slug: string;
readonly meta: {
readonly [x: string]: unknown;
};
}[], DBCallbackFailure | DatabaseError, never>;
byId: (tagId: number) => Effect<{
readonly id: number;
readonly name: string;
readonly description: string;
readonly slug: string;
readonly meta: {
readonly [x: string]: unknown;
};
} | undefined, DBCallbackFailure | DatabaseError, never>;
bySlug: (slug: string) => Effect<{
readonly id: number;
readonly name: string;
readonly description: string;
readonly slug: string;
readonly meta: {
readonly [x: string]: unknown;
};
} | undefined, DBCallbackFailure | DatabaseError, never>;
};
}
GET
.
packagePages: (packageName: string) => Effect<CombinedPageData[], ParseError | DBCallbackFailure | DatabaseError | FolderTreeError | CollectorError | PaginateError, never> (+1 overload)
packagePages
('mon-module-extension'));
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: CombinedPageData | undefined
page
=
const pages: CombinedPageData[]
pages
.
Array<CombinedPageData>.find(predicate: (value: CombinedPageData, index: number, obj: CombinedPageData[]) => unknown, thisArg?: any): CombinedPageData | undefined (+1 overload)

Returns the value of the first element in the array where predicate is true, and undefined otherwise.

@parampredicate find calls predicate once for each element of the array, in ascending order, until it finds one where predicate returns true. If such an element is found, find immediately returns that element value. Otherwise, find returns undefined.

@paramthisArg If provided, it will be used as the this value for each invocation of predicate. If it is not provided, undefined is used instead.

find
((
page: CombinedPageData
page
) =>
page: CombinedPageData
page
.
slug: string
slug
===
const slug: string | undefined
slug
|| '');
Modèle
{
slug && page ? (
<div>
<h1>{page.title}</h1>
<StudioCMSRenderer content={page.defaultContent?.content || ''} />
</div>
) : (
<div>
<h1>Mon module d’extension</h1>
<ul>
{pages.length > 0 && pages.map((page) => (
<li>
<a href={makeRoute(page.slug)}>{page.title}</a>
</li>
))}
</ul>
</div>
)
}

L’exemple ci-dessus définit une route dynamique^ pour le module d’extension qui affiche une liste d’articles de blog lorsqu’aucun slug n’est fourni et affiche le contenu d’un article de blog lorsqu’un slug est fourni.

Dans le fichier src/dashboard-grid-items/MyPluginGridItem.astro, vous définirez l’élément de grille du module d’extension. Voici un exemple de définition d’un élément de grille pour le module d’extension :

MyPluginGridItem.astro
---
import { SDKCoreJs, runSDK } from 'studiocms:sdk';
// 'mon-module-extension' est ici utilisé comme identifiant pour
// le type de page à partir de la définition du module d’extension
const pages = await runSDK(SDKCoreJs.GET.packagePages('mon-module-extension'));
// Obtenir les 5 pages les plus récemment mises à jour au cours des 30 derniers jours
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>Pages récemment mises à jour</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>

L’exemple ci-dessus définit un élément de grille pour le module d’extension qui affiche les 5 pages les plus récemment mises à jour au cours des 30 derniers jours. Cet élément inclut une liste de liens vers la page de modification de la gestion de contenu pour chaque page.

Section intitulée « Intégration avec les assistants FrontendNavigationLinks »

Si vous souhaitez utiliser les assistants de navigation intégrés de StudioCMS dans votre projet, de la même manière que le fait le module d’extension @studiocms/blog, vous pouvez créer un composant Navigation.astro personnalisé :

Navigation.astro
---
import { frontendNavigation } from 'studiocms:plugin-helpers';
// Définir les props pour le composant Navigation
interface Props {
topLevelLinkCount?: number;
};
// Obtenir le nombre de liens de niveau supérieur à partir des props
const { topLevelLinkCount = 3 } = Astro.props;
// Obtenir la configuration du site et la liste des pages
const config = Astro.locals.siteConfig.data;
// Récupérer le titre du site à partir de la configuration
const { title } = config || { title: 'StudioCMS' };
// Obtenir l’URL du site principal
const {
mainLinks: { baseSiteURL },
} = Astro.locals.routeMap;
// Définir les props de lien pour la navigation
type LinkProps = {
text: string;
href: string;
};
// Définir les liens pour la navigation
const links: LinkProps[] = await frontendNavigation();
---
{/* S’il n’y a pas d’éléments déroulants */}
{ ( 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>
) }
{/* S’il y a des éléments déroulants */}
{ 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>Plus ▼</button>
<div class="dropdown-content">
{ links.slice(topLevelLinkCount).map(({ text, href }) => (
<a {href}>{text}</a>
)) }
</div>
</div>
</div>
) }

L’exemple ci-dessus définit un composant personnalisé Navigation.astro qui utilise les assistants de navigation intégrés de StudioCMS pour créer un menu de navigation pour le projet. Ce composant inclut des liens vers l’URL du site principal, la page d’index et toutes les autres pages configurées pour s’afficher dans la navigation.

Il vous suffit d’ajouter quelques styles et vous disposez d’un menu de navigation entièrement fonctionnel qui fonctionne avec les assistants de navigation intégrés de StudioCMS.