diff --git a/package-lock.json b/package-lock.json index a9ec7e5..2028e5c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -41,6 +41,7 @@ "mongodb": "^6.17.0", "multiple-scripts-tmux": "^1.0.4", "nodemon": "^3.0.1", + "normalize-diacritics": "^5.0.0", "nyc": "^17.1.0", "object-path": "^0.11.8", "qs": "^6.12.0", @@ -9894,6 +9895,22 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/normalize-diacritics": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/normalize-diacritics/-/normalize-diacritics-5.0.0.tgz", + "integrity": "sha512-t6czCJOpbAtckN1wCC2qPWnO3GQvNANb9bcUNbiOLEqojVuP31+ELIs5KhEG8jyz0TH7iD9BWxWz8O3ic2/rMQ==", + "hasInstallScript": true, + "dependencies": { + "tslib": "^2.4.0" + }, + "engines": { + "node": ">= 14.x", + "npm": ">= 6.x" + }, + "funding": { + "url": "https://github.com/motss/lit-ntml?sponsor=1" + } + }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -14003,6 +14020,11 @@ "node": ">=0.3.1" } }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" + }, "node_modules/tsscmp": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz", @@ -22372,6 +22394,14 @@ "abbrev": "^2.0.0" } }, + "normalize-diacritics": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/normalize-diacritics/-/normalize-diacritics-5.0.0.tgz", + "integrity": "sha512-t6czCJOpbAtckN1wCC2qPWnO3GQvNANb9bcUNbiOLEqojVuP31+ELIs5KhEG8jyz0TH7iD9BWxWz8O3ic2/rMQ==", + "requires": { + "tslib": "^2.4.0" + } + }, "normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -25333,6 +25363,11 @@ } } }, + "tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" + }, "tsscmp": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz", diff --git a/package.json b/package.json index 438cbc8..2f399da 100644 --- a/package.json +++ b/package.json @@ -120,6 +120,7 @@ "mongodb": "^6.17.0", "multiple-scripts-tmux": "^1.0.4", "nodemon": "^3.0.1", + "normalize-diacritics": "^5.0.0", "nyc": "^17.1.0", "object-path": "^0.11.8", "qs": "^6.12.0", diff --git a/src/back/routes/common/tabs/tabs.tsx b/src/back/routes/common/tabs/tabs.tsx index bbecad2..0f6890d 100644 --- a/src/back/routes/common/tabs/tabs.tsx +++ b/src/back/routes/common/tabs/tabs.tsx @@ -1,5 +1,6 @@ import type { FlatTemplatable } from "tempstream"; import { TempstreamJSX } from "tempstream"; +import { normalizeSync as normalize } from "normalize-diacritics"; const ids = (function* () { let i = 0; @@ -11,6 +12,14 @@ const ids = (function* () { } })(); +const normalizeId = (id: string) => { + const normalized = normalize(id); + const hyphened = normalized.replace(/[^\w-]/g, "-"); + const squashedHyphens = hyphened.replace(/-+/g, "-"); + + return squashedHyphens; +}; + export function tabs({ tabs, default_tab, @@ -29,18 +38,24 @@ export function tabs({ active_navbar_tab_style?: string; }) { const tab_section_id = ids.next().value; + + const tabsNormalizedIds = tabs.map((tab) => ({ + ...tab, + id: normalizeId(tab.id), + })); + return (
{tab_bar || ( )} - {tabs.map(({ id, content }) => { + {tabsNormalizedIds.map(({ id, content }) => { const tab_id = `tabs__${tab_section_id}__tab__${id}`; return (
diff --git a/src/front/controllers.ts b/src/front/controllers.ts index 3bb7af3..11519b8 100644 --- a/src/front/controllers.ts +++ b/src/front/controllers.ts @@ -49,9 +49,6 @@ application.register("submit-on-input", SubmitOnInput); import { default as Toast } from "./../../node_modules/@sealcode/jdd-editor/src/controllers/toast.stimulus.js"; application.register("toast", Toast); -import { default as PasswordGenerateButton } from "./../../node_modules/@sealcode/sealgen/src/controllers/password-generate-button.stimulus.js"; -application.register("password-generate-button", PasswordGenerateButton); - import { default as Monaco } from "./../../node_modules/@sealcode/monaco-wrapper/src/controllers/monaco.stimulus.js"; application.register("monaco", Monaco);