diff --git a/.gitignore b/.gitignore index 2e095e84..6504043b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,4 @@ /public/ -/hugo/resources/ -/hugo/static/css/ -hugo/static/libs -hugo/static/showcase/ -hugo/static/libs/ -hugo/static/playground/ node_modules/ .DS_Store .hugo_build.lock diff --git a/foundation/.gitignore b/foundation/.gitignore new file mode 100644 index 00000000..b6291f30 --- /dev/null +++ b/foundation/.gitignore @@ -0,0 +1,2 @@ +bundle/ +dist/ diff --git a/foundation/package.json b/foundation/package.json new file mode 100644 index 00000000..93841a4c --- /dev/null +++ b/foundation/package.json @@ -0,0 +1,67 @@ +{ + "name": "langium-website-foundation", + "version": "1.0.0", + "type": "module", + "description": "Bundling complex sources for hugo", + "author": "TypeFox", + "license": "MIT", + "private": true, + "main": "./dist/index.js", + "module": "./dist/index.js", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "default": "./dist/index.js" + }, + "./bundle": { + "types": "./dist/index.d.ts", + "default": "./bundle/monaco-editor-wrapper-bundle/index.js" + } + }, + "typesVersions": { + "*": { + ".": [ + "dist/index" + ], + "bundle": [ + "dist/index" + ] + } + }, + "files": [ + "dist", + "bundle", + "src", + "LICENSE", + "README.md" + ], + "scripts": { + "clean": "shx rm -rf ./bundle ./dist", + "compile": "tsc", + "build:bundle": "vite --config vite.bundle.ts build", + "build": "npm run clean && npm run compile && npm run build:bundle" + }, + "devDependencies": { + "@types/react": "~18.2.28", + "@types/react-dom": "~18.2.13", + "@types/vscode": "~1.82.0", + "typescript": "~5.2.2", + "vite": "~4.4.11" + }, + "dependencies": { + "@codingame/monaco-vscode-keybindings-service-override": "~1.82.5", + "@typefox/monaco-editor-react": "2.3.0-next.3", + "monaco-editor": "~0.43.0", + "monaco-editor-workers": "~0.43.0", + "monaco-editor-wrapper": "~3.3.0-next.3", + "monaco-languageclient": "~6.5.3", + "react": "~18.2.0", + "react-dom": "~18.2.0", + "vscode": "npm:@codingame/monaco-vscode-api@>=1.82.5 <1.83.0", + "vscode-languageserver": "~8.0.2" + }, + "volta": { + "node": "18.18.1", + "npm": "9.9.0" + } +} diff --git a/foundation/src/index.ts b/foundation/src/index.ts new file mode 100644 index 00000000..151921cf --- /dev/null +++ b/foundation/src/index.ts @@ -0,0 +1,17 @@ +import * as monaco from "monaco-editor"; +import getKeybindingsServiceOverride from '@codingame/monaco-vscode-keybindings-service-override'; +import type { MonacoEditorProps } from "@typefox/monaco-editor-react"; +import { MonacoEditorReactComp } from "@typefox/monaco-editor-react"; +import { addMonacoStyles } from 'monaco-editor-wrapper/styles'; + +export * from "monaco-editor-wrapper"; +export type * from "monaco-editor-wrapper"; +export * from "./monaco-editor-wrapper-utils.js"; + +export { + monaco, + MonacoEditorProps, + MonacoEditorReactComp, + addMonacoStyles, + getKeybindingsServiceOverride +} diff --git a/foundation/src/monaco-editor-wrapper-utils.ts b/foundation/src/monaco-editor-wrapper-utils.ts new file mode 100644 index 00000000..fd739bff --- /dev/null +++ b/foundation/src/monaco-editor-wrapper-utils.ts @@ -0,0 +1,176 @@ +import { languages } from "monaco-editor"; +import getKeybindingsServiceOverride from '@codingame/monaco-vscode-keybindings-service-override'; +import { EditorAppConfigClassic, EditorAppConfigExtended, LanguageClientConfig, UserConfig } from "monaco-editor-wrapper"; + +export type WorkerUrl = string; + +/** + * Generalized configuration used with 'getMonacoEditorReactConfig' to generate a working configuration for monaco-editor-react + */ +export interface MonacoReactConfig { + code: string, + languageId: string, + worker: WorkerUrl | Worker, + readonly?: boolean // whether to make the editor readonly or not (by default is false) +} + +/** + * Extended config, specifically for textmate usage + */ +export interface MonacoExtendedReactConfig extends MonacoReactConfig { + textmateGrammar: any; +} + +/** + * Editor config, specifically for monarch grammar usage + */ +export interface MonacoEditorReactConfig extends MonacoReactConfig { + monarchGrammar?: languages.IMonarchLanguage; +} + +/** + * Helper to identify a Extended config, for use with TextMate + */ +function isMonacoExtendedReactConfig(config: unknown): config is MonacoExtendedReactConfig { + return (config as MonacoExtendedReactConfig).textmateGrammar !== undefined; +} + + +/** + * Default language configuration, common to most Langium DSLs + */ +export const defaultLanguageConfig = { + "comments": { + "lineComment": "//", + "blockComment": ["/*", "*/"] + }, + "brackets": [ + ["{", "}"], + ["[", "]"], + ["(", ")"] + ], + "autoClosingPairs": [ + ["{", "}"], + ["[", "]"], + ["(", ")"], + ["\"", "\""], + ["'", "'"] + ], + "surroundingPairs": [ + ["{", "}"], + ["[", "]"], + ["(", ")"], + ["\"", "\""], + ["'", "'"] + ] +}; + +/** + * Generates a UserConfig for a given Langium example, which is then passed to the monaco-editor-react component + * + * @param config A Extended or classic editor config to generate a UserConfig from + * @returns A completed UserConfig + */ +export function createUserConfig(config: MonacoExtendedReactConfig | MonacoEditorReactConfig): UserConfig { + // setup urls for config & grammar + const id = config.languageId; + + // check whether to use extended config (Textmate) or the classic editor config (Monarch) + let editorAppConfig: EditorAppConfigClassic | EditorAppConfigExtended; + const useExtendedConfig = isMonacoExtendedReactConfig(config); + if (useExtendedConfig) { + // setup extension contents + const languageConfigUrl = `/${id}-configuration.json`; + const languageGrammarUrl = `/${id}-grammar.json`; + const extensionContents = new Map(); + extensionContents.set(languageConfigUrl, JSON.stringify(defaultLanguageConfig)); + extensionContents.set(languageGrammarUrl, JSON.stringify(config.textmateGrammar)); + + editorAppConfig = { + $type: 'extended', + languageId: id, + code: config.code, + useDiffEditor: false, + extensions: [{ + config: { + name: id, + publisher: 'TypeFox', + version: '1.0.0', + engines: { + vscode: '*' + }, + contributes: { + languages: [{ + id: id, + extensions: [ `.${id}` ], + configuration: languageConfigUrl + }], + grammars: [{ + language: id, + scopeName: `source.${id}`, + path: languageGrammarUrl + }] + } + }, + filesOrContents: extensionContents, + }], + userConfiguration: { + json: JSON.stringify({ + 'workbench.colorTheme': 'Default Dark Modern', + 'editor.semanticHighlighting.enabled': true, + 'editor.lightbulb.enabled': true, + 'editor.guides.bracketPairsHorizontal': 'active' + }) + } + }; + } else { + editorAppConfig = { + $type: 'classic', + languageId: id, + code: config.code, + useDiffEditor: false, + languageExtensionConfig: { id }, + languageDef: config.monarchGrammar, + editorOptions: { + 'semanticHighlighting.enabled': true, + readOnly: config.readonly, + theme: 'vs-dark' + } + }; + } + + let languageClientConfig: LanguageClientConfig; + if (typeof config.worker === 'string') { + languageClientConfig = { + options: { + $type: 'WorkerConfig', + url: new URL(config.worker, window.location.href), + type: 'module', + name: `${id}-language-server-worker`, + } + }; + } else { + languageClientConfig = { + options: { + $type: 'WorkerDirect', + worker: config.worker + } + }; + } + + // generate user config for langium based language + const userConfig: UserConfig = { + wrapperConfig: { + serviceConfig: { + // only use keyboard service in addition to the default services from monaco-editor-wrapper + userServices: { + ...getKeybindingsServiceOverride() + }, + debugLogging: true + }, + editorAppConfig + }, + languageClientConfig + } + return userConfig; +} diff --git a/foundation/tsconfig.json b/foundation/tsconfig.json new file mode 100644 index 00000000..501bcbcb --- /dev/null +++ b/foundation/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "noImplicitAny": true, + "target": "ES2022", + "module": "Node16", + "moduleResolution": "Node16", + "rootDir": "src", + "outDir": "dist", + "declaration": true, + "declarationDir": "dist" + }, + "include": [ + "src/**/*.ts", + ] +} \ No newline at end of file diff --git a/hugo/vite.bundle-monaco-editor-react.ts b/foundation/vite.bundle.ts similarity index 51% rename from hugo/vite.bundle-monaco-editor-react.ts rename to foundation/vite.bundle.ts index e9043e81..24a35854 100644 --- a/hugo/vite.bundle-monaco-editor-react.ts +++ b/foundation/vite.bundle.ts @@ -4,21 +4,21 @@ import { defineConfig } from 'vite'; const config = defineConfig({ build: { lib: { - entry: resolve(__dirname, './assets/scripts/monaco-editor-react.ts'), - name: 'monaco-editor-react', - fileName: () => 'monaco-editor-react.js', + entry: resolve(__dirname, './src/index.ts'), + name: 'monaco-editor-wrapper-bundle', + fileName: () => 'index.js', formats: ['es'] }, - outDir: resolve(__dirname, 'static/libs/monaco-editor-react'), - assetsDir: resolve(__dirname, 'static/libs/monaco-editor-react/assets'), - emptyOutDir: false, + outDir: resolve(__dirname, 'bundle/monaco-editor-wrapper-bundle'), + assetsDir: resolve(__dirname, 'bundle/monaco-editor-wrapper-bundle/assets'), + emptyOutDir: true, cssCodeSplit: false, commonjsOptions: { strictRequires: true }, rollupOptions: { output: { - name: 'monaco-editor-react', + name: 'monaco-editor-wrapper-bundle', exports: 'named', sourcemap: false, assetFileNames: (assetInfo) => { @@ -28,11 +28,8 @@ const config = defineConfig({ } }, resolve: { - alias: { - path: 'path-browserify' - } - }, - assetsInclude: ['**/*.wasm'] + dedupe: ['monaco-editor', 'vscode'] + } }); -export default config; \ No newline at end of file +export default config; diff --git a/hugo/.gitignore b/hugo/.gitignore new file mode 100644 index 00000000..b9d7b3f1 --- /dev/null +++ b/hugo/.gitignore @@ -0,0 +1,5 @@ +resources/ +static/css/ +static/showcase/ +static/libs/ +static/playground/ diff --git a/hugo/assets/scripts/arithmetics/arithmetics-tools.tsx b/hugo/assets/scripts/arithmetics/arithmetics-tools.tsx index 25941728..9d563e31 100644 --- a/hugo/assets/scripts/arithmetics/arithmetics-tools.tsx +++ b/hugo/assets/scripts/arithmetics/arithmetics-tools.tsx @@ -1,4 +1,4 @@ -import { monaco } from "monaco-editor-wrapper/."; +import { monaco } from "langium-website-foundation/bundle"; import { Pos } from "../langium-utils/langium-ast"; export interface Evaluation { diff --git a/hugo/assets/scripts/arithmetics/arithmetics.tsx b/hugo/assets/scripts/arithmetics/arithmetics.tsx index 89f87589..7786d5fa 100644 --- a/hugo/assets/scripts/arithmetics/arithmetics.tsx +++ b/hugo/assets/scripts/arithmetics/arithmetics.tsx @@ -1,11 +1,11 @@ -import { MonacoEditorReactComp } from "./static/libs/monaco-editor-react/monaco-editor-react.js"; +import { addMonacoStyles, createUserConfig, MonacoEditorReactComp, UserConfig } from "langium-website-foundation/bundle"; import { buildWorkerDefinition } from "monaco-editor-workers"; import React from "react"; import { createRoot } from "react-dom/client"; import { Diagnostic, DocumentChangeResponse } from "../langium-utils/langium-ast"; import { Evaluation, examples, syntaxHighlighting } from "./arithmetics-tools"; -import { UserConfig } from "monaco-editor-wrapper"; -import { createUserConfig } from "../utils"; + +addMonacoStyles('monaco-styles-helper'); buildWorkerDefinition( "../../libs/monaco-editor-workers/workers", diff --git a/hugo/assets/scripts/domainmodel/domainmodel.tsx b/hugo/assets/scripts/domainmodel/domainmodel.tsx index 02fc14f5..4eb7d7fe 100644 --- a/hugo/assets/scripts/domainmodel/domainmodel.tsx +++ b/hugo/assets/scripts/domainmodel/domainmodel.tsx @@ -1,13 +1,13 @@ -import { MonacoEditorReactComp } from "@typefox/monaco-editor-react/bundle"; +import { addMonacoStyles, createUserConfig, MonacoEditorReactComp, UserConfig } from "langium-website-foundation/bundle"; import { buildWorkerDefinition } from "monaco-editor-workers"; import React from "react"; import { createRoot } from "react-dom/client"; import { Diagnostic, DocumentChangeResponse, LangiumAST } from "../langium-utils/langium-ast"; import { DomainModelAstNode, example, getTreeNode, syntaxHighlighting } from "./domainmodel-tools"; -import { UserConfig } from "monaco-editor-wrapper"; -import { createUserConfig } from "../utils"; import D3Tree from "./d3tree"; - + +addMonacoStyles('monaco-styles-helper'); + buildWorkerDefinition( "../../libs/monaco-editor-workers/workers", new URL("", window.location.href).href, diff --git a/hugo/assets/scripts/minilogo/minilogo-tools.ts b/hugo/assets/scripts/minilogo/minilogo-tools.ts index 9978a0e5..b8a1bf3b 100644 --- a/hugo/assets/scripts/minilogo/minilogo-tools.ts +++ b/hugo/assets/scripts/minilogo/minilogo-tools.ts @@ -1,4 +1,4 @@ -import { monaco } from "monaco-editor-wrapper/."; +import { monaco } from "langium-website-foundation/bundle"; export interface Command { name: 'penUp' | 'penDown' | 'move' | 'color'; diff --git a/hugo/assets/scripts/minilogo/minilogo.tsx b/hugo/assets/scripts/minilogo/minilogo.tsx index 25bcdde6..0380dc82 100644 --- a/hugo/assets/scripts/minilogo/minilogo.tsx +++ b/hugo/assets/scripts/minilogo/minilogo.tsx @@ -1,12 +1,12 @@ -import { MonacoEditorReactComp } from "@typefox/monaco-editor-react/bundle"; +import { addMonacoStyles, createUserConfig, MonacoEditorReactComp, UserConfig } from "langium-website-foundation/bundle"; import { buildWorkerDefinition } from "monaco-editor-workers"; import React, { createRef } from "react"; import { createRoot } from "react-dom/client"; import { Diagnostic, DocumentChangeResponse, LangiumAST } from "../langium-utils/langium-ast"; import { ColorArgs, Command, MoveArgs, examples, syntaxHighlighting } from "./minilogo-tools"; import { compressToEncodedURIComponent, decompressFromEncodedURIComponent } from "lz-string"; -import { UserConfig } from "monaco-editor-wrapper"; -import { createUserConfig } from "../utils"; + +addMonacoStyles('monaco-styles-helper'); buildWorkerDefinition( "../../libs/monaco-editor-workers/workers", diff --git a/hugo/assets/scripts/monaco-editor-react.ts b/hugo/assets/scripts/monaco-editor-react.ts deleted file mode 100644 index a92213a9..00000000 --- a/hugo/assets/scripts/monaco-editor-react.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "@typefox/monaco-editor-react"; -import 'vscode/default-extensions/theme-defaults'; diff --git a/hugo/assets/scripts/sql/constants.ts b/hugo/assets/scripts/sql/constants.ts index 92ea8528..4f249c6f 100644 --- a/hugo/assets/scripts/sql/constants.ts +++ b/hugo/assets/scripts/sql/constants.ts @@ -1,4 +1,4 @@ -import { monaco } from "@typefox/monaco-editor-react/."; +import { monaco } from "langium-website-foundation/bundle"; export const syntaxHighlighting: monaco.languages.IMonarchLanguage = { tokenizer: { diff --git a/hugo/assets/scripts/sql/ui.tsx b/hugo/assets/scripts/sql/ui.tsx index b2d339c0..f6a38c96 100644 --- a/hugo/assets/scripts/sql/ui.tsx +++ b/hugo/assets/scripts/sql/ui.tsx @@ -1,4 +1,4 @@ -import { MonacoEditorReactComp } from "./static/libs/monaco-editor-react/monaco-editor-react.js"; +import { addMonacoStyles, createUserConfig, MonacoEditorReactComp, UserConfig } from "langium-website-foundation/bundle"; import { buildWorkerDefinition } from "monaco-editor-workers"; import React from "react"; import { createRoot } from "react-dom/client"; @@ -9,8 +9,8 @@ import { defaultText, syntaxHighlighting, } from "./constants"; -import { UserConfig } from "monaco-editor-wrapper"; -import { createUserConfig } from '../utils'; + +addMonacoStyles('monaco-styles-helper'); buildWorkerDefinition( "../../libs/monaco-editor-workers/workers", diff --git a/hugo/assets/scripts/statemachine/statemachine.tsx b/hugo/assets/scripts/statemachine/statemachine.tsx index a3b1f6b0..fae5c966 100644 --- a/hugo/assets/scripts/statemachine/statemachine.tsx +++ b/hugo/assets/scripts/statemachine/statemachine.tsx @@ -1,13 +1,13 @@ -import { MonacoEditorReactComp } from "./static/libs/monaco-editor-react/monaco-editor-react.js"; +import { addMonacoStyles, createUserConfig, MonacoEditorReactComp, UserConfig } from "langium-website-foundation/bundle"; import { buildWorkerDefinition } from "monaco-editor-workers"; import React from "react"; import { createRoot } from "react-dom/client"; import { Diagnostic, DocumentChangeResponse, LangiumAST } from "../langium-utils/langium-ast"; import { defaultText, StateMachineAstNode, StateMachineState, StateMachineTools } from "./statemachine-tools"; -import { UserConfig } from "monaco-editor-wrapper"; -import { createUserConfig } from '../utils'; import statemachineGrammar from 'langium-statemachine-dsl/syntaxes/statemachine.tmLanguage.json'; +addMonacoStyles('monaco-styles-helper'); + buildWorkerDefinition( "../../libs/monaco-editor-workers/workers", new URL("", window.location.href).href, diff --git a/hugo/assets/scripts/utils.ts b/hugo/assets/scripts/utils.ts deleted file mode 100644 index 442b764b..00000000 --- a/hugo/assets/scripts/utils.ts +++ /dev/null @@ -1,201 +0,0 @@ -import { UserConfig } from "monaco-editor-wrapper"; -import { monaco } from "monaco-editor-wrapper/."; - -export type WorkerUrl = string; - -/** - * Generalized configuration used with 'getMonacoEditorReactConfig' to generate a working configuration for monaco-editor-react - */ -export interface MonacoReactConfig { - code: string, - htmlElement: HTMLElement, - languageId: string, - worker: WorkerUrl | Worker, - readonly?: boolean // whether to make the editor readonly or not (by default is false) -} - -/** - * VSCode API config, specifically for textmate usage - */ -export interface MonacoVSCodeReactConfig extends MonacoReactConfig { - textmateGrammar: any; -} - -/** - * Editor config, specifically for monarch grammar usage - */ -export interface MonacoEditorReactConfig extends MonacoReactConfig { - monarchGrammar?: monaco.languages.IMonarchLanguage; -} - -/** - * Helper to identify a VSCode API config, for use with TextMate - */ -function isMonacoVSCodeReactConfig(config: unknown): config is MonacoVSCodeReactConfig { - return (config as MonacoVSCodeReactConfig).textmateGrammar !== undefined; -} - -/** - * Helper to identify an editor config (classic), for use with Monarch - */ -function isMonacoEditorReactConfig(config: unknown): config is MonacoEditorReactConfig { - return (config as MonacoEditorReactConfig).monarchGrammar !== undefined; -} - -/** - * Default language configuration, common to most Langium DSLs - */ -export const defaultLanguageConfig = { - "comments": { - "lineComment": "//", - "blockComment": ["/*", "*/"] - }, - "brackets": [ - ["{", "}"], - ["[", "]"], - ["(", ")"] - ], - "autoClosingPairs": [ - ["{", "}"], - ["[", "]"], - ["(", ")"], - ["\"", "\""], - ["'", "'"] - ], - "surroundingPairs": [ - ["{", "}"], - ["[", "]"], - ["(", ")"], - ["\"", "\""], - ["'", "'"] - ] -}; - -/** - * Generates a UserConfig for a given Langium example, which is then passed to the monaco-editor-react component - * - * @param config A VSCode API or classic editor config to generate a UserConfig from - * @returns A completed UserConfig - */ -export function createUserConfig(config: MonacoVSCodeReactConfig | MonacoEditorReactConfig): UserConfig { - // setup extension contents - const extensionContents = new Map(); - - // setup urls for config & grammar - const id = config.languageId; - const languageConfigUrl = `/${id}-configuration.json`; - const languageGrammarUrl = `/${id}-grammar.json`; - - // set extension contents - extensionContents.set(languageConfigUrl, JSON.stringify(defaultLanguageConfig)); - - // check whether to use the VSCode API config (TM), or the classic editor config (Monarch) - const useVscodeConfig = isMonacoVSCodeReactConfig(config); - - if (isMonacoVSCodeReactConfig(config)) { - extensionContents.set(languageGrammarUrl, JSON.stringify(config.textmateGrammar)); - } - - // generate langium config - return { - htmlElement: config.htmlElement, - wrapperConfig: { - // have to disable this for Monarch - // generally true otherwise (toggles using monacoVscodeApiConfig / monacoEditorConfig) - useVscodeConfig, - - serviceConfig: { - // the theme service & textmate services are dependent, they need to both be enabled or disabled together - // this explicitly disables the Monarch capabilities - // both are tied to whether we are using the VSCode config as well - enableThemeService: useVscodeConfig, - enableTextmateService: useVscodeConfig, - - enableModelService: true, - configureEditorOrViewsServiceConfig: { - enableViewsService: false, - useDefaultOpenEditorFunction: true - }, - configureConfigurationServiceConfig: { - defaultWorkspaceUri: '/tmp/' - }, - enableKeybindingsService: true, - enableLanguagesService: true, - debugLogging: false - }, - // VSCode config (for TextMate grammars) - monacoVscodeApiConfig: { - extension: { - name: id, - publisher: 'TypeFox', - version: '1.0.0', - engines: { - vscode: '*' - }, - contributes: { - languages: [{ - id, - extensions: [], - aliases: [ - id - ], - configuration: `.${languageConfigUrl}` - }], - grammars: isMonacoVSCodeReactConfig(config) ? [{ - language: id, - scopeName: `source.${id}`, - path: `.${languageGrammarUrl}` - }] : undefined, - keybindings: [{ - key: 'ctrl+p', - command: 'editor.action.quickCommand', - when: 'editorTextFocus' - }, { - key: 'ctrl+shift+c', - command: 'editor.action.commentLine', - when: 'editorTextFocus' - }] - } - }, - extensionFilesOrContents: extensionContents, - userConfiguration: { - json: `{ - "workbench.colorTheme": "Default Dark Modern", - "editor.fontSize": 14, - "editor.lightbulb.enabled": true, - "editor.lineHeight": 20, - "editor.guides.bracketPairsHorizontal": "active", - "editor.lightbulb.enabled": true -}` - } - }, - // Editor config (classic) (for Monarch) - monacoEditorConfig: { - languageExtensionConfig: { - id - }, - languageDef: isMonacoEditorReactConfig(config) ? config.monarchGrammar : undefined - } - }, - editorConfig: { - languageId: id, - code: config.code, - useDiffEditor: false, - automaticLayout: true, - theme: 'vs-dark', - editorOptions: { - readOnly: config.readonly - } - }, - languageClientConfig: { - enabled: true, - useWebSocket: false, - // build a worker config from a worker URL string, or just copy in the entire worker - workerConfigOptions: typeof config.worker === 'string' ? { - url: new URL(config.worker, window.location.href), - type: 'module', - name: `${id}-language-server-worker`, - } : config.worker - } - }; -} diff --git a/hugo/content/playground/_index.html b/hugo/content/playground/_index.html index 8764727d..d005d41b 100644 --- a/hugo/content/playground/_index.html +++ b/hugo/content/playground/_index.html @@ -10,14 +10,14 @@ noMain: true playground: true --- -