diff --git a/celements-admin-frontend/.npmrc b/celements-admin-frontend/.npmrc new file mode 100644 index 000000000..7e1d4c5fe --- /dev/null +++ b/celements-admin-frontend/.npmrc @@ -0,0 +1,2 @@ +@celements:registry=https://forge.celhosting.ch/api/packages/celements/npm/ +//forge.celhosting.ch/api/packages/celements/npm/:_authToken=${FORGE_TOKEN} diff --git a/celements-admin-frontend/Jenkinsfile.npm b/celements-admin-frontend/Jenkinsfile.npm new file mode 100644 index 000000000..0691f11a0 --- /dev/null +++ b/celements-admin-frontend/Jenkinsfile.npm @@ -0,0 +1,89 @@ +pipeline { + agent { label 'docker' } + options { + disableConcurrentBuilds() + skipDefaultCheckout(true) + timestamps() + } + parameters { + string( + name: 'GIT_REF', + defaultValue: '', + description: 'optional git ref to publish, e.g. commit SHA, branch name, or refs/tags/admin-frontend-v0.1.0' + ) + } + stages { + stage('Checkout') { + steps { + script { + deleteDir() + String gitRef = params.GIT_REF?.trim() + def scmVars = checkout(!gitRef ? scm : [ + $class: 'GitSCM', + branches: [[name: gitRef]], + userRemoteConfigs: scm.userRemoteConfigs + ]) + env.GIT_REV = scmVars.GIT_COMMIT ?: GIT_COMMIT + if (!GIT_REV) error('GIT_COMMIT missing after checkout') + env.GIT_SHA = GIT_REV.take(7) + } + } + } + stage('Prepare Package') { + steps { + dir('celements-admin-frontend') { + script { + String declaredVersion = sh( + script: 'node -p "require(\'./package.json\').version"', + returnStdout: true + ).trim() + boolean snapshot = declaredVersion.toUpperCase().endsWith('-SNAPSHOT') + if (snapshot) { + String baseVersion = declaredVersion.substring( + 0, + declaredVersion.length() - '-SNAPSHOT'.length() + ) + env.PACKAGE_VERSION = + "${baseVersion}-snapshot.${env.BUILD_NUMBER}.${env.GIT_SHA}" + env.NPM_DIST_TAG = 'snapshot' + } else { + String expectedTag = "admin-frontend-v${declaredVersion}" + String releaseTag = sh( + script: "git tag --points-at HEAD --list '${expectedTag}'", + returnStdout: true + ).trim() + if (releaseTag != expectedTag) { + error("release package requires tag ${expectedTag} at HEAD") + } + env.PACKAGE_VERSION = declaredVersion + env.NPM_DIST_TAG = 'latest' + } + sh "npm version --no-git-tag-version '${env.PACKAGE_VERSION}'" + } + } + } + } + stage('Build and Verify') { + steps { + dir('celements-admin-frontend') { + sh 'npm ci' + sh 'npm run build' + sh 'npm pack --dry-run --json' + } + } + } + stage('Publish Package') { + steps { + dir('celements-admin-frontend') { + withCredentials([usernamePassword( + credentialsId: 'forge-credentials', + usernameVariable: 'FORGE_USER', + passwordVariable: 'FORGE_TOKEN' + )]) { + sh './scripts/publish-forge-package.sh' + } + } + } + } + } +} diff --git a/celements-admin-frontend/README.md b/celements-admin-frontend/README.md index 15a0d9923..a24715e53 100644 --- a/celements-admin-frontend/README.md +++ b/celements-admin-frontend/README.md @@ -61,19 +61,21 @@ The container generates `config.js` from its runtime environment. `.env.local` i ## ๐Ÿ“œ Scripts -| Command | Description | -| -------------------- | ----------------------------------------------------------------- | -| `npm run dev` | Start dev server with concurrent type-checking and test watching | -| `npm run build` | Type-check + run tests + build production bundle | -| `npm run preview` | Preview the production build locally | -| `npm run test` | Run unit tests once with Vitest | -| `npm run test-watch` | Run unit tests in watch mode | -| `npm run type-check` | Type-check `.vue` files with `vue-tsc` | -| `npm run lint` | Lint source files with ESLint | -| `npm run lint-fix` | Auto-fix ESLint issues | -| `npm run format` | Check code formatting with Prettier | -| `npm run format-fix` | Auto-fix code formatting with Prettier | -| `npm run pre-commit` | Run type-check, format check and lint (recommended as a git hook) | +| Command | Description | +| ----------------------- | ----------------------------------------------------------------- | +| `npm run dev` | Start dev server with concurrent type-checking and test watching | +| `npm run build` | Type-check + run tests + build production bundle | +| `npm run preview` | Preview the production build locally | +| `npm run test` | Run unit tests once with Vitest | +| `npm run test-watch` | Run unit tests in watch mode | +| `npm run type-check` | Type-check `.vue` files with `vue-tsc` | +| `npm run lint` | Lint source files with ESLint | +| `npm run lint-fix` | Auto-fix ESLint issues | +| `npm run format` | Check code formatting with Prettier | +| `npm run format-fix` | Auto-fix code formatting with Prettier | +| `npm run pre-commit` | Run type-check, format check and lint (recommended as a git hook) | +| `npm run publish:check` | Build and inspect the package without publishing | +| `npm run publish:forge` | Publish an immutable version to the Forge npm registry | --- @@ -97,7 +99,84 @@ src/ โ””โ”€โ”€ main.ts # Standalone development entry ``` -The app exposes a `createCelementsAdminApp()` factory function from `bootstrap.ts` that allows the frontend to be embedded in a host application or run standalone. +The SPA bootstrap owns Vue Router. Shared feature components and islands use the router-independent +application runtime, which creates a separate Pinia instance for every mounted Vue application. + +## Public package API + +The supported `@celements/admin-frontend` entry points are: + +- `@celements/admin-frontend/runtime` for `createCelementsApplication()`. +- `@celements/admin-frontend/page-attachments` for the router-free `PageAttachments` component and + its typed props, selection event, and `attachment-actions` slot contract. +- `@celements/admin-frontend/page-attachments-island` for the guarded + `` custom-element registration. +- `@celements/admin-frontend/styles.css` for downstream Vue applications using the feature component. + +The custom element accepts `space-name`, `doc-name`, `locale`, and `local-dev`. It dispatches the +bubbling `attachment-selection-change` event. Framework packages are peer dependencies so a +downstream application supplies one Vue, Pinia, PrimeVue, vue-i18n, and VueFinder runtime. Vue +Router remains a development dependency for the deployable SPA shell and is not required by the +published feature, island, or runtime entry points. + +`styles.css` is the complete supported stylesheet. It includes the scoped Celements +application/Tailwind styles and the processed VueFinder styles; consumers must not import CSS from +VueFinder or an internal package path separately. + +## Forge npm package + +The `@celements` scope is hosted at: + +```text +https://forge.celhosting.ch/api/packages/celements/npm/ +``` + +The checked-in `.npmrc` maps only the `@celements` scope to Forge. It reads `FORGE_TOKEN`, which +must be an access token with package read access for consumers and package write access for +publication. The npm Jenkins job uses the established `forge-credentials` username/password +credential and exposes its password as `FORGE_TOKEN`. + +Install an immutable package version and its required peers (the example pins release `0.1.0`): + +```sh +export FORGE_TOKEN='' +npm install --save-exact @celements/admin-frontend@0.1.0 \ + vue@^3.5.30 pinia@^3.0.4 primevue@^4.5.4 vue-i18n@^11.3.0 vuefinder@^4.1.1 +``` + +Use only declared package exports: + +```ts +import { PageAttachments } from '@celements/admin-frontend/page-attachments'; +import { registerPageAttachmentsElement } from '@celements/admin-frontend/page-attachments-island'; +import { createCelementsApplication } from '@celements/admin-frontend/runtime'; +import '@celements/admin-frontend/styles.css'; +``` + +`Jenkinsfile` continues to publish only the Docker image. Package publication is a separate Jenkins +job using `Jenkinsfile.npm`: + +- a declared `x.y.z-SNAPSHOT` version becomes the unique immutable + `x.y.z-snapshot..` version and receives the `snapshot` dist-tag; +- a declared release version `x.y.z` must be built from the exact `admin-frontend-vx.y.z` Git tag + and receives the `latest` dist-tag; +- publication checks Forge first and refuses to overwrite an existing package version. + +Repository code cannot create that Jenkins job. CI operations must configure a job whose script +path is `celements-admin-frontend/Jenkinsfile.npm`; until that infrastructure step exists, the +repository has a verifiable publication path but no package is published automatically. + +Build and inspect the publishable package locally without credentials or publication: + +```sh +npm run publish:check +``` + +From a clean, correctly versioned release checkout, the release job ultimately runs: + +```sh +FORGE_TOKEN='' NPM_DIST_TAG=latest npm run publish:forge +``` --- diff --git a/celements-admin-frontend/package-lock.json b/celements-admin-frontend/package-lock.json index 3dc50244f..9742ec163 100644 --- a/celements-admin-frontend/package-lock.json +++ b/celements-admin-frontend/package-lock.json @@ -17,17 +17,11 @@ "findandreplacedomtext": "^0.4.6", "lodash": "^4.17.23", "luxon": "^3.7.2", - "pinia": "^3.0.4", - "primevue": "^4.5.4", "tailwind-merge": "^3.5.0", "tailwindcss-primeui": "^0.6.1", - "vue": "^3.5.30", "vue-dompurify-html": "^5.3.0", - "vue-i18n": "^11.3.0", "vue-matomo": "^4.2.0", - "vue-router": "^5.0.4", "vue3-spinners": "^1.3.3", - "vuefinder": "^4.1.1", "zod": "^4.3.6" }, "devDependencies": { @@ -49,13 +43,26 @@ "eslint-plugin-vue": "^10.8.0", "jsdom": "^29.0.1", "npm-run-all2": "^8.0.4", + "pinia": "^3.0.4", "postcss": "^8.5.8", "prettier": "^3.8.1", + "primevue": "^4.5.4", "tailwindcss": "^4.2.2", "typescript": "~5.9.3", "vite": "^8.0.1", "vitest": "^4.1.0", - "vue-tsc": "^3.2.6" + "vue": "^3.5.30", + "vue-i18n": "^11.3.0", + "vue-router": "^5.0.4", + "vue-tsc": "^3.2.6", + "vuefinder": "^4.1.1" + }, + "peerDependencies": { + "pinia": "^3.0.4", + "primevue": "^4.5.4", + "vue": "^3.5.30", + "vue-i18n": "^11.3.0", + "vuefinder": "^4.1.1" } }, "node_modules/@alloc/quick-lru": { @@ -121,6 +128,7 @@ "version": "7.29.1", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "dev": true, "dependencies": { "@babel/parser": "^7.29.0", "@babel/types": "^7.29.0", @@ -459,6 +467,7 @@ "version": "1.7.5", "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.5.tgz", "integrity": "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==", + "dev": true, "dependencies": { "@floating-ui/utils": "^0.2.11" } @@ -467,6 +476,7 @@ "version": "1.7.6", "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.6.tgz", "integrity": "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==", + "dev": true, "dependencies": { "@floating-ui/core": "^1.7.5", "@floating-ui/utils": "^0.2.11" @@ -475,7 +485,8 @@ "node_modules/@floating-ui/utils": { "version": "0.2.11", "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.11.tgz", - "integrity": "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==" + "integrity": "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==", + "dev": true }, "node_modules/@fortawesome/fontawesome-common-types": { "version": "7.2.0", @@ -581,6 +592,7 @@ "version": "11.4.2", "resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-11.4.2.tgz", "integrity": "sha512-7fpuCcVmeLv2T9qHsARqGvh8xt+sV2fH+Q+gMHFwB/rPXzo85DpbJFKn7dBH1L5p0c2cSh2DW+2h/64EKrISmA==", + "dev": true, "dependencies": { "@intlify/devtools-types": "11.4.2", "@intlify/message-compiler": "11.4.2", @@ -597,6 +609,7 @@ "version": "11.4.2", "resolved": "https://registry.npmjs.org/@intlify/devtools-types/-/devtools-types-11.4.2.tgz", "integrity": "sha512-3u8EN1kB6EMSi96KXs5k7a8y2X2g4+h3X6iwVZU47cP4n+mTuq//WMjG588BzSp/2XQ/dTXo2BLUXX+XS+PNfA==", + "dev": true, "dependencies": { "@intlify/core-base": "11.4.2", "@intlify/shared": "11.4.2" @@ -612,6 +625,7 @@ "version": "11.4.2", "resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-11.4.2.tgz", "integrity": "sha512-a6CDSGSMTGrg0BjD97x8TBYPf7qQMDlZipJ6UDfv/pd4OIym8TMlHu3MsH0bTNnRdAG2D6EFEykIgiQPqvtTkA==", + "dev": true, "dependencies": { "@intlify/shared": "11.4.2", "source-map-js": "^1.0.2" @@ -627,6 +641,7 @@ "version": "11.4.2", "resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-11.4.2.tgz", "integrity": "sha512-NzpHbguRCsOHDwxmlBa9qu/imc+/QWgsYUaK6FZeNC0wK8QfAbhqrktEp/haVzxU1aikH8IX4ytD+mfFEMi/9A==", + "dev": true, "engines": { "node": ">= 16" }, @@ -655,6 +670,7 @@ "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" @@ -664,6 +680,7 @@ "version": "2.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" @@ -673,6 +690,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, "engines": { "node": ">=6.0.0" } @@ -686,6 +704,7 @@ "version": "0.3.31", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -695,6 +714,7 @@ "version": "1.3.3", "resolved": "https://registry.npmjs.org/@nanostores/i18n/-/i18n-1.3.3.tgz", "integrity": "sha512-hwuTKJ+DKCOuszmmOuNfDeA8j86WJWLLzjzE1BYm+mabMcD5JYDnTd0wPMwgGJ+U//ApRaxviRvOtvk50F+RCg==", + "dev": true, "funding": [ { "type": "github", @@ -712,6 +732,7 @@ "version": "1.3.4", "resolved": "https://registry.npmjs.org/@nanostores/persistent/-/persistent-1.3.4.tgz", "integrity": "sha512-fZ42MOredSkqt450XrPxmQ94pSRPTas/rBUVCvEEMCR+rIp8bdo/xoaFFcG2cwpqAzA164PdD6p3D+MXLJYumw==", + "dev": true, "funding": [ { "type": "github", @@ -729,6 +750,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/@nanostores/vue/-/vue-1.1.0.tgz", "integrity": "sha512-14eY8/YA0AbtWkAjk8zHKxbjcuPubF+M7y9afQzg2b5VqRJcashwA0100vprau13BTBSynUmU6ZsU6x03YidjA==", + "dev": true, "funding": [ { "type": "buymeacoffee", @@ -858,6 +880,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/@primeuix/styles/-/styles-2.0.3.tgz", "integrity": "sha512-2ykAB6BaHzR/6TwF8ShpJTsZrid6cVIEBVlookSdvOdmlWuevGu5vWOScgIwqWwlZcvkFYAGR/SUV3OHCTBMdw==", + "dev": true, "dependencies": { "@primeuix/styled": "^0.7.4" } @@ -882,6 +905,7 @@ "version": "4.5.5", "resolved": "https://registry.npmjs.org/@primevue/core/-/core-4.5.5.tgz", "integrity": "sha512-JpkXhq1ddc70JdsC3CC4dM+UbeeWuCW/8DpS9dNBfrOk824TLSlRlMEGFyVKqRMn5WPQvYLiy3xXfLQeNdSqhQ==", + "dev": true, "dependencies": { "@primeuix/styled": "^0.7.4", "@primeuix/utils": "^0.6.2" @@ -897,6 +921,7 @@ "version": "4.5.5", "resolved": "https://registry.npmjs.org/@primevue/icons/-/icons-4.5.5.tgz", "integrity": "sha512-eteOhTdAOXEYE9qW1AOrBBgDxQ2szHJxSkEK1XVdV2TKxGM5FQf03Ovms0VDyZTc16XBIgvwYjXJQS0BPbhPaA==", + "dev": true, "dependencies": { "@primeuix/utils": "^0.6.2", "@primevue/core": "4.5.5" @@ -1419,6 +1444,7 @@ "version": "8.19.4", "resolved": "https://registry.npmjs.org/@tanstack/match-sorter-utils/-/match-sorter-utils-8.19.4.tgz", "integrity": "sha512-Wo1iKt2b9OT7d+YGhvEPD3DXvPv2etTusIMhMUoG7fbhmxcXCtIjJDEygy91Y2JFlwGyjqiBPRozme7UD8hoqg==", + "dev": true, "dependencies": { "remove-accents": "0.5.0" }, @@ -1434,6 +1460,7 @@ "version": "5.100.10", "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.100.10.tgz", "integrity": "sha512-8UR0yJR+GiQ40m3lPhUr0xbfAupe6GSQiksSBSa9SM2NjezFyxXCIA69/lz8cSoNKZLrw1/PktIyQBJcVeMi3w==", + "dev": true, "funding": { "type": "github", "url": "https://github.com/sponsors/tannerlinsley" @@ -1443,6 +1470,7 @@ "version": "5.100.10", "resolved": "https://registry.npmjs.org/@tanstack/vue-query/-/vue-query-5.100.10.tgz", "integrity": "sha512-S1aOmIPQNd5axR2Sw7H8d96EybY3kEZ396KA90e0SGLDYSfd2QgWi7+ItYXRGIDiSjOjlPUnthKDP0mDDBV8Kw==", + "dev": true, "dependencies": { "@tanstack/match-sorter-utils": "^8.19.4", "@tanstack/query-core": "5.100.10", @@ -1466,12 +1494,14 @@ "node_modules/@tanstack/vue-query/node_modules/@vue/devtools-api": { "version": "6.6.4", "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz", - "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==" + "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==", + "dev": true }, "node_modules/@tanstack/vue-query/node_modules/vue-demi": { "version": "0.14.10", "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz", "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", + "dev": true, "hasInstallScript": true, "bin": { "vue-demi-fix": "bin/vue-demi-fix.js", @@ -1496,7 +1526,8 @@ "node_modules/@transloadit/prettier-bytes": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/@transloadit/prettier-bytes/-/prettier-bytes-0.3.5.tgz", - "integrity": "sha512-xF4A3d/ZyX2LJWeQZREZQw+qFX4TGQ8bGVP97OLRt6sPO6T0TNHBFTuRHOJh7RNmYOBmQ9MHxpolD9bXihpuVA==" + "integrity": "sha512-xF4A3d/ZyX2LJWeQZREZQw+qFX4TGQ8bGVP97OLRt6sPO6T0TNHBFTuRHOJh7RNmYOBmQ9MHxpolD9bXihpuVA==", + "dev": true }, "node_modules/@tsconfig/node20": { "version": "20.1.9", @@ -1590,7 +1621,8 @@ "node_modules/@types/retry": { "version": "0.12.2", "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", - "integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==" + "integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==", + "dev": true }, "node_modules/@types/tough-cookie": { "version": "4.0.5", @@ -1844,6 +1876,7 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/@uppy/companion-client/-/companion-client-5.1.1.tgz", "integrity": "sha512-DzrOWTbIZHvtgAFXBMYHk2wD27NjpBSVhY2tEiEIUhPd2CxbFRZjHM/N3HOt3VwZEAP471QWFLlJRWPcIY3A2Q==", + "dev": true, "dependencies": { "@uppy/utils": "^7.1.1", "namespace-emitter": "^2.0.1", @@ -1857,6 +1890,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/@uppy/components/-/components-1.2.0.tgz", "integrity": "sha512-rtIr+77Rw/q5Vw++xazF1dCg2d4A4zT9CV+ZyN8Rsx8xiIr2CxCR4TaHHBy+WeC0b7Mk6yNuJ0wUa34tFJ6pKg==", + "dev": true, "dependencies": { "clsx": "^2.1.1", "dequal": "^2.0.3", @@ -1885,6 +1919,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/@uppy/core/-/core-5.2.0.tgz", "integrity": "sha512-uvfNyz4cnaplt7LYJmEZHuqOuav0tKp4a9WKJIaH6iIj7XiqYvS2J5SEByexAlUFlzefOAyjzj4Ja2dd/8aMrw==", + "dev": true, "dependencies": { "@transloadit/prettier-bytes": "^0.3.4", "@uppy/store-default": "^5.0.0", @@ -1900,6 +1935,7 @@ "version": "5.1.11", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.11.tgz", "integrity": "sha512-v+KEsUv2ps74PaSKv0gHTxTCgMXOIfBEbaqa6w6ISIGC7ZsvHN4N9oJ8d4cmf0n5oTzQz2SLmThbQWhjd/8eKg==", + "dev": true, "funding": [ { "type": "github", @@ -1917,6 +1953,7 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/@uppy/locales/-/locales-5.1.1.tgz", "integrity": "sha512-zSbDU27JzfdssRJoa5/xmGOsrEtS+2Z9j41weaoCa/NoK4wqZzkFNQ0Z44etbTg3PDVFakZVDu/Z+c+vsJCfdQ==", + "dev": true, "dependencies": { "@uppy/utils": "^7.1.5" } @@ -1924,12 +1961,14 @@ "node_modules/@uppy/store-default": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/@uppy/store-default/-/store-default-5.0.0.tgz", - "integrity": "sha512-hQtCSQ1yGiaval/wVYUWquYGDJ+bpQ7e4FhUUAsRQz1x1K+o7NBtjfp63O9I4Ks1WRoKunpkarZ+as09l02cPw==" + "integrity": "sha512-hQtCSQ1yGiaval/wVYUWquYGDJ+bpQ7e4FhUUAsRQz1x1K+o7NBtjfp63O9I4Ks1WRoKunpkarZ+as09l02cPw==", + "dev": true }, "node_modules/@uppy/utils": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@uppy/utils/-/utils-7.2.0.tgz", "integrity": "sha512-6lC246qszMv6bTyl/+QyHwrudgeguWkA94ME1wHn+a6uRAvmtAEaUManIfGqTJfoKvWAiCJqdJPl5xRJjhAloQ==", + "dev": true, "dependencies": { "lodash": "^4.17.23", "preact": "^10.26.10" @@ -1939,6 +1978,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/@uppy/vue/-/vue-3.2.0.tgz", "integrity": "sha512-BZiyUZxpadf3uUp8YzgwRZTIde/m9Ne4ILFygJg7ilFq/Qfb1pBVspG9FJoG23RbOiRuxd4JixwFh0gaFdfL+w==", + "dev": true, "dependencies": { "@uppy/components": "^1.2.0", "preact": "^10.26.10", @@ -1971,6 +2011,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/@uppy/xhr-upload/-/xhr-upload-5.2.0.tgz", "integrity": "sha512-3LV/X5Of6BINnKplP+CwUJ0a4/7cRFfzxwGyXnW+uCrNQHoo09dttcz3begWHejGvzenQHuUnMO3Fxyc71Pryg==", + "dev": true, "dependencies": { "@uppy/companion-client": "^5.1.1", "@uppy/utils": "^7.2.0" @@ -1982,7 +2023,8 @@ "node_modules/@viselect/vanilla": { "version": "3.9.0", "resolved": "https://registry.npmjs.org/@viselect/vanilla/-/vanilla-3.9.0.tgz", - "integrity": "sha512-E9eBgoi/crJ0SlZMAc+Yst7nU324LZ5LLvcXjzWEcrfllscdpTml2OLOKHC7O8Bbz19OybSLv6VexxnjlJrLxQ==" + "integrity": "sha512-E9eBgoi/crJ0SlZMAc+Yst7nU324LZ5LLvcXjzWEcrfllscdpTml2OLOKHC7O8Bbz19OybSLv6VexxnjlJrLxQ==", + "dev": true }, "node_modules/@vitejs/plugin-vue": { "version": "6.0.6", @@ -2171,6 +2213,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@vue-macros/common/-/common-3.1.2.tgz", "integrity": "sha512-h9t4ArDdniO9ekYHAD95t9AZcAbb19lEGK+26iAjUODOIJKmObDNBSe4+6ELQAA3vtYiFPPBtHh7+cQCKi3Dng==", + "dev": true, "dependencies": { "@vue/compiler-sfc": "^3.5.22", "ast-kit": "^2.1.2", @@ -2243,6 +2286,7 @@ "version": "7.7.9", "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-7.7.9.tgz", "integrity": "sha512-kIE8wvwlcZ6TJTbNeU2HQNtaxLx3a84aotTITUuL/4bzfPxzajGBOoqjMhwZJ8L9qFYDU/lAYMEEm11dnZOD6g==", + "dev": true, "dependencies": { "@vue/devtools-kit": "^7.7.9" } @@ -2251,6 +2295,7 @@ "version": "7.7.9", "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.7.9.tgz", "integrity": "sha512-PyQ6odHSgiDVd4hnTP+aDk2X4gl2HmLDfiyEnn3/oV+ckFDuswRs4IbBT7vacMuGdwY/XemxBoh302ctbsptuA==", + "dev": true, "dependencies": { "@vue/devtools-shared": "^7.7.9", "birpc": "^2.3.0", @@ -2265,6 +2310,7 @@ "version": "7.7.9", "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.7.9.tgz", "integrity": "sha512-iWAb0v2WYf0QWmxCGy0seZNDPdO3Sp5+u78ORnyeonS6MT4PC7VPrryX2BpMJrwlDeaZ6BD4vP4XKjK0SZqaeA==", + "dev": true, "dependencies": { "rfdc": "^1.4.1" } @@ -2466,6 +2512,7 @@ "version": "8.16.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "dev": true, "bin": { "acorn": "bin/acorn" }, @@ -2544,6 +2591,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/ast-kit/-/ast-kit-2.2.0.tgz", "integrity": "sha512-m1Q/RaVOnTp9JxPX+F+Zn7IcLYMzM8kZofDImfsKZd8MbR+ikdOzTeztStWqfrqIxZnYWryyI9ePm3NGjnZgGw==", + "dev": true, "dependencies": { "@babel/parser": "^7.28.5", "pathe": "^2.0.3" @@ -2559,6 +2607,7 @@ "version": "0.8.3", "resolved": "https://registry.npmjs.org/ast-walker-scope/-/ast-walker-scope-0.8.3.tgz", "integrity": "sha512-cbdCP0PGOBq0ASG+sjnKIoYkWMKhhz+F/h9pRexUdX2Hd38+WOlBkRKlqkGOSm0YQpcFMQBJeK4WspUAkwsEdg==", + "dev": true, "dependencies": { "@babel/parser": "^7.28.4", "ast-kit": "^2.1.3" @@ -2640,6 +2689,7 @@ "version": "2.9.0", "resolved": "https://registry.npmjs.org/birpc/-/birpc-2.9.0.tgz", "integrity": "sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==", + "dev": true, "funding": { "url": "https://github.com/sponsors/antfu" } @@ -2768,6 +2818,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "dev": true, "dependencies": { "readdirp": "^5.0.0" }, @@ -2781,7 +2832,8 @@ "node_modules/classnames": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", - "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==" + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==", + "dev": true }, "node_modules/cliui": { "version": "8.0.1", @@ -2859,6 +2911,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "dev": true, "engines": { "node": ">=6" } @@ -2922,7 +2975,8 @@ "node_modules/confbox": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.4.tgz", - "integrity": "sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==" + "integrity": "sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==", + "dev": true }, "node_modules/config-chain": { "version": "1.1.13", @@ -2952,6 +3006,7 @@ "version": "4.0.5", "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-4.0.5.tgz", "integrity": "sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==", + "dev": true, "dependencies": { "is-what": "^5.2.0" }, @@ -3022,7 +3077,8 @@ "node_modules/debounce": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", - "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==" + "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==", + "dev": true }, "node_modules/debug": { "version": "4.4.3", @@ -3057,6 +3113,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, "engines": { "node": ">=6" } @@ -3087,7 +3144,8 @@ "node_modules/easy-bem": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/easy-bem/-/easy-bem-1.1.1.tgz", - "integrity": "sha512-GJRqdiy2h+EXy6a8E6R+ubmqUM08BK0FWNq41k24fup6045biQ8NXxoXimiwegMQvFFV3t1emADdGNL1TlS61A==" + "integrity": "sha512-GJRqdiy2h+EXy6a8E6R+ubmqUM08BK0FWNq41k24fup6045biQ8NXxoXimiwegMQvFFV3t1emADdGNL1TlS61A==", + "dev": true }, "node_modules/editorconfig": { "version": "1.0.7", @@ -3461,7 +3519,8 @@ "node_modules/exsolve": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.8.tgz", - "integrity": "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==" + "integrity": "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==", + "dev": true }, "node_modules/fast-deep-equal": { "version": "3.1.3", @@ -3721,7 +3780,8 @@ "node_modules/hookable": { "version": "5.5.3", "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz", - "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==" + "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==", + "dev": true }, "node_modules/html-encoding-sniffer": { "version": "6.0.0", @@ -3793,6 +3853,7 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.3.2.tgz", "integrity": "sha512-PhBY86zaxNZUuWP6h13Vu5oFe0XY6/UlKzQnYFELzGVHygP3MxmvTfYSG7GN3aIab/iWudSMgjSnG9Dq+nHrgA==", + "dev": true, "engines": { "node": ">=16" }, @@ -3819,6 +3880,7 @@ "version": "5.5.0", "resolved": "https://registry.npmjs.org/is-what/-/is-what-5.5.0.tgz", "integrity": "sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw==", + "dev": true, "engines": { "node": ">=18" }, @@ -3939,6 +4001,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, "bin": { "jsesc": "bin/jsesc" }, @@ -3977,6 +4040,7 @@ "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, "bin": { "json5": "lib/cli.js" }, @@ -4269,6 +4333,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-1.1.2.tgz", "integrity": "sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==", + "dev": true, "dependencies": { "mlly": "^1.7.4", "pkg-types": "^2.3.0", @@ -4330,6 +4395,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/magic-string-ast/-/magic-string-ast-1.0.3.tgz", "integrity": "sha512-CvkkH1i81zl7mmb94DsRiFeG9V2fR2JeuK8yDgS8oiZSFa++wWLEgZ5ufEOyLHbvSbD1gTRKv9NdX69Rnvr9JA==", + "dev": true, "dependencies": { "magic-string": "^0.30.19" }, @@ -4381,6 +4447,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/mime-match/-/mime-match-1.0.2.tgz", "integrity": "sha512-VXp/ugGDVh3eCLOBCiHZMYWQaTNUHv2IJrut+yXA6+JbLPXHglHwfS/5A5L0ll+jkCY7fIzRJcH6OIunF+c6Cg==", + "dev": true, "dependencies": { "wildcard": "^1.1.0" } @@ -4412,12 +4479,14 @@ "node_modules/mitt": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", - "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==" + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", + "dev": true }, "node_modules/mlly": { "version": "1.8.2", "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.2.tgz", "integrity": "sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==", + "dev": true, "dependencies": { "acorn": "^8.16.0", "pathe": "^2.0.3", @@ -4428,12 +4497,14 @@ "node_modules/mlly/node_modules/confbox": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", - "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==" + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", + "dev": true }, "node_modules/mlly/node_modules/pkg-types": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", + "dev": true, "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", @@ -4449,12 +4520,14 @@ "node_modules/muggle-string": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz", - "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==" + "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==", + "dev": true }, "node_modules/namespace-emitter": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/namespace-emitter/-/namespace-emitter-2.0.1.tgz", - "integrity": "sha512-N/sMKHniSDJBjfrkbS/tpkPj4RAbvW3mr8UAzvlMHyun93XEm83IAvhWtJVHo+RHn/oO8Job5YN4b+wRjSVp5g==" + "integrity": "sha512-N/sMKHniSDJBjfrkbS/tpkPj4RAbvW3mr8UAzvlMHyun93XEm83IAvhWtJVHo+RHn/oO8Job5YN4b+wRjSVp5g==", + "dev": true }, "node_modules/nanoid": { "version": "3.3.12", @@ -4477,6 +4550,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/nanostores/-/nanostores-1.3.0.tgz", "integrity": "sha512-XPUa/jz+P1oJvN9VBxw4L9MtdFfaH3DAryqPssqhb2kXjmb9npz0dly6rCsgFWOPr4Yg9mTfM3MDZgZZ+7A3lA==", + "dev": true, "funding": [ { "type": "github", @@ -4644,7 +4718,8 @@ "node_modules/overlayscrollbars": { "version": "2.16.0", "resolved": "https://registry.npmjs.org/overlayscrollbars/-/overlayscrollbars-2.16.0.tgz", - "integrity": "sha512-N03oje/q7j93D0aLZtoCdsDSYLmhheSsv8H7oSLE7HhdV9P/bmCURtLV/KbPye7P/bpfyt/obSfDpGUYoJ0OWg==" + "integrity": "sha512-N03oje/q7j93D0aLZtoCdsDSYLmhheSsv8H7oSLE7HhdV9P/bmCURtLV/KbPye7P/bpfyt/obSfDpGUYoJ0OWg==", + "dev": true }, "node_modules/p-limit": { "version": "3.1.0", @@ -4680,6 +4755,7 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-6.2.1.tgz", "integrity": "sha512-hEt02O4hUct5wtwg4H4KcWgDdm+l1bOaEy/hWzd8xtXB9BqxTWBBhb+2ImAtH4Cv4rPjV76xN3Zumqk3k3AhhQ==", + "dev": true, "dependencies": { "@types/retry": "0.12.2", "is-network-error": "^1.0.0", @@ -4776,12 +4852,14 @@ "node_modules/pathe": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==" + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true }, "node_modules/perfect-debounce": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", - "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==" + "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==", + "dev": true }, "node_modules/picocolors": { "version": "1.1.1", @@ -4816,6 +4894,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/pinia/-/pinia-3.0.4.tgz", "integrity": "sha512-l7pqLUFTI/+ESXn6k3nu30ZIzW5E2WZF/LaHJEpoq6ElcLD+wduZoB2kBN19du6K/4FDpPMazY2wJr+IndBtQw==", + "dev": true, "dependencies": { "@vue/devtools-api": "^7.7.7" }, @@ -4836,6 +4915,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.1.tgz", "integrity": "sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg==", + "dev": true, "dependencies": { "confbox": "^0.2.4", "exsolve": "^1.0.8", @@ -4892,6 +4972,7 @@ "version": "10.29.1", "resolved": "https://registry.npmjs.org/preact/-/preact-10.29.1.tgz", "integrity": "sha512-gQCLc/vWroE8lIpleXtdJhTFDogTdZG9AjMUpVkDf2iTCNwYNWA+u16dL41TqUDJO4gm2IgrcMv3uTpjd4Pwmg==", + "dev": true, "funding": { "type": "opencollective", "url": "https://opencollective.com/preact" @@ -4937,6 +5018,7 @@ "version": "6.1.1", "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-6.1.1.tgz", "integrity": "sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ==", + "dev": true, "engines": { "node": "^14.13.1 || >=16.0.0" }, @@ -4948,6 +5030,7 @@ "version": "4.5.5", "resolved": "https://registry.npmjs.org/primevue/-/primevue-4.5.5.tgz", "integrity": "sha512-Kv5REIewCdP806QaoU+4nBXfmpzOGFKkZ9qH4KsL6MjiAQVc4PUzypt8erl4r3Vzh3nr3aWZIxkxYRRsLGiX2A==", + "dev": true, "dependencies": { "@primeuix/styled": "^0.7.4", "@primeuix/styles": "^2.0.3", @@ -4978,6 +5061,7 @@ "version": "0.2.11", "resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.11.tgz", "integrity": "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==", + "dev": true, "funding": [ { "type": "individual", @@ -5026,6 +5110,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", + "dev": true, "engines": { "node": ">= 20.19.0" }, @@ -5037,7 +5122,8 @@ "node_modules/remove-accents": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/remove-accents/-/remove-accents-0.5.0.tgz", - "integrity": "sha512-8g3/Otx1eJaVD12e31UbJj1YzdtVvzH85HV7t+9MJYk/u3XmkOUJ5Ys9wQrf9PCPK8+xn4ymzqYCiZl6QWKn+A==" + "integrity": "sha512-8g3/Otx1eJaVD12e31UbJj1YzdtVvzH85HV7t+9MJYk/u3XmkOUJ5Ys9wQrf9PCPK8+xn4ymzqYCiZl6QWKn+A==", + "dev": true }, "node_modules/require-directory": { "version": "2.1.1", @@ -5061,6 +5147,7 @@ "version": "0.13.1", "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "dev": true, "engines": { "node": ">= 4" } @@ -5078,7 +5165,8 @@ "node_modules/rfdc": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", - "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==" + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true }, "node_modules/rolldown": { "version": "1.0.0", @@ -5166,7 +5254,8 @@ "node_modules/scule": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/scule/-/scule-1.3.0.tgz", - "integrity": "sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==" + "integrity": "sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==", + "dev": true }, "node_modules/semver": { "version": "7.8.0", @@ -5183,7 +5272,8 @@ "node_modules/shallow-equal": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/shallow-equal/-/shallow-equal-3.1.0.tgz", - "integrity": "sha512-pfVOw8QZIXpMbhBWvzBISicvToTiM5WBF1EeAUZDDSb5Dt29yl4AYbyywbJFSEsRUMr7gJaxqCdr4L3tQf9wVg==" + "integrity": "sha512-pfVOw8QZIXpMbhBWvzBISicvToTiM5WBF1EeAUZDDSb5Dt29yl4AYbyywbJFSEsRUMr7gJaxqCdr4L3tQf9wVg==", + "dev": true }, "node_modules/shebang-command": { "version": "2.0.0", @@ -5248,6 +5338,7 @@ "version": "14.0.1", "resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz", "integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==", + "dev": true, "engines": { "node": ">=0.10.0" } @@ -5369,6 +5460,7 @@ "version": "2.2.6", "resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.6.tgz", "integrity": "sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA==", + "dev": true, "dependencies": { "copy-anything": "^4" }, @@ -5466,6 +5558,7 @@ "version": "0.2.16", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", + "dev": true, "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" @@ -5481,6 +5574,7 @@ "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, "engines": { "node": ">=12.0.0" }, @@ -5497,6 +5591,7 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, "engines": { "node": ">=12" }, @@ -5645,7 +5740,8 @@ "node_modules/ufo": { "version": "1.6.4", "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.4.tgz", - "integrity": "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==" + "integrity": "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==", + "dev": true }, "node_modules/undici": { "version": "7.25.0", @@ -5666,6 +5762,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-3.0.0.tgz", "integrity": "sha512-0Mqk3AT2TZCXWKdcoaufeXNukv2mTrEZExeXlHIOZXdqYoHHr4n51pymnwV8x2BOVxwXbK2HLlI7usrqMpycdg==", + "dev": true, "dependencies": { "@jridgewell/remapping": "^2.3.5", "picomatch": "^4.0.3", @@ -5679,6 +5776,7 @@ "version": "0.3.1", "resolved": "https://registry.npmjs.org/unplugin-utils/-/unplugin-utils-0.3.1.tgz", "integrity": "sha512-5lWVjgi6vuHhJ526bI4nlCOmkCIF3nnfXkCMDeMJrtdvxTs6ZFCM8oNufGTsDbKv/tJ/xj8RpvXjRuPBZJuJog==", + "dev": true, "dependencies": { "pathe": "^2.0.3", "picomatch": "^4.0.3" @@ -5694,6 +5792,7 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, "engines": { "node": ">=12" }, @@ -5705,6 +5804,7 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, "engines": { "node": ">=12" }, @@ -5761,6 +5861,7 @@ "version": "19.1.3", "resolved": "https://registry.npmjs.org/vanilla-lazyload/-/vanilla-lazyload-19.1.3.tgz", "integrity": "sha512-bBMERPu2AFJc35krS+8BOhq++c6dRfL6q368lJPnkS5U92fRQagTR3FsNta69/GukfZzDwDEjD5M3U7VuSiCDw==", + "dev": true, "funding": { "type": "individual", "url": "https://ko-fi.com/verlok" @@ -5986,6 +6087,7 @@ "version": "2.8.9", "resolved": "https://registry.npmjs.org/vue-advanced-cropper/-/vue-advanced-cropper-2.8.9.tgz", "integrity": "sha512-1jc5gO674kVGpJKekoaol6ZlwaF5VYDLSBwBOUpViW0IOrrRsyLw6XNszjEqgbavvqinlKNS6Kqlom3B5M72Tw==", + "dev": true, "dependencies": { "classnames": "^2.2.6", "debounce": "^1.2.0", @@ -6055,6 +6157,7 @@ "version": "11.4.2", "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-11.4.2.tgz", "integrity": "sha512-sADDeKXqAGsPX6tK3t3y2ZiMpbVWN12tG+MhTiJ06rVoh58eGtM4wFyw3uWGbVkXByVp9Ne/AP+nSSzI+J9OAQ==", + "dev": true, "dependencies": { "@intlify/core-base": "11.4.2", "@intlify/devtools-types": "11.4.2", @@ -6074,7 +6177,8 @@ "node_modules/vue-i18n/node_modules/@vue/devtools-api": { "version": "6.6.4", "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz", - "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==" + "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==", + "dev": true }, "node_modules/vue-matomo": { "version": "4.2.0", @@ -6089,6 +6193,7 @@ "version": "5.0.6", "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-5.0.6.tgz", "integrity": "sha512-9+kmUTGbKMyW9Asoy98IXXYIzrTMT7JDAdpDDeEkorHvybpUvBI2wsrSM5jFOXrFydpzRFJ9vAh+80DN2PGu9w==", + "dev": true, "dependencies": { "@babel/generator": "^7.28.6", "@vue-macros/common": "^3.1.1", @@ -6133,6 +6238,7 @@ "version": "8.1.2", "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-8.1.2.tgz", "integrity": "sha512-vA0O112YqyDuNA1s7Yb2gCgToQ/OxOWiFDO5ThLCcDy0ldHnSd1dUTaSYhOldbqoNgumE4dxtGAoAaSUKUD1Zg==", + "dev": true, "dependencies": { "@vue/devtools-kit": "^8.1.2" } @@ -6141,6 +6247,7 @@ "version": "8.1.2", "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-8.1.2.tgz", "integrity": "sha512-f75/upc+GCyjXErpgPGz4582ujS0L/adAltGy+tqXMGUJpgAcfGr6CxnnhpZY8BHuMYt6KpbF8uaFrrQG66rGQ==", + "dev": true, "dependencies": { "@vue/devtools-shared": "^8.1.2", "birpc": "^2.6.1", @@ -6151,17 +6258,20 @@ "node_modules/vue-router/node_modules/@vue/devtools-shared": { "version": "8.1.2", "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-8.1.2.tgz", - "integrity": "sha512-X9RyVFYAdkBe4IUf5v48TxBF/6QPmF8CmWrDAjXzfUHrgQ/HGfTC1A6TqgXqZ03ye66l3AD51BAGD69IvKM9sw==" + "integrity": "sha512-X9RyVFYAdkBe4IUf5v48TxBF/6QPmF8CmWrDAjXzfUHrgQ/HGfTC1A6TqgXqZ03ye66l3AD51BAGD69IvKM9sw==", + "dev": true }, "node_modules/vue-router/node_modules/perfect-debounce": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-2.1.0.tgz", - "integrity": "sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==" + "integrity": "sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==", + "dev": true }, "node_modules/vue-router/node_modules/picomatch": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, "engines": { "node": ">=12" }, @@ -6173,6 +6283,7 @@ "version": "2.0.9", "resolved": "https://registry.npmjs.org/vue-sonner/-/vue-sonner-2.0.9.tgz", "integrity": "sha512-i6BokNlNDL93fpzNxN/LZSn6D6MzlO+i3qXt6iVZne3x1k7R46d5HlFB4P8tYydhgqOrRbIZEsnRd3kG7qGXyw==", + "dev": true, "peerDependencies": { "@nuxt/kit": "^4.0.3", "@nuxt/schema": "^4.0.3", @@ -6226,6 +6337,7 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/vuefinder/-/vuefinder-4.1.2.tgz", "integrity": "sha512-qoYdIRKQIrr+MgQlhNDzxVYOpWhNlncFDsS9ol0XL/kqnALr3rF7+W2KbS0GRjzzqyAuNxAJATcN3fRbj+/lsA==", + "dev": true, "dependencies": { "@floating-ui/dom": "^1.7.4", "@nanostores/i18n": "^1.2.2", @@ -6293,7 +6405,8 @@ "node_modules/webpack-virtual-modules": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", - "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==" + "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", + "dev": true }, "node_modules/whatwg-mimetype": { "version": "5.0.0", @@ -6352,7 +6465,8 @@ "node_modules/wildcard": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-1.1.2.tgz", - "integrity": "sha512-DXukZJxpHA8LuotRwL0pP1+rS6CS7FF2qStDDE1C7DDg2rLud2PXRMuEDYIPhgEezwnlHNL4c+N6MfMTjCGTng==" + "integrity": "sha512-DXukZJxpHA8LuotRwL0pP1+rS6CS7FF2qStDDE1C7DDg2rLud2PXRMuEDYIPhgEezwnlHNL4c+N6MfMTjCGTng==", + "dev": true }, "node_modules/word-wrap": { "version": "1.2.5", @@ -6479,6 +6593,7 @@ "version": "2.9.0", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", + "dev": true, "bin": { "yaml": "bin.mjs" }, diff --git a/celements-admin-frontend/package.json b/celements-admin-frontend/package.json index a502f8e3c..9ffb898ab 100644 --- a/celements-admin-frontend/package.json +++ b/celements-admin-frontend/package.json @@ -3,14 +3,40 @@ "version": "0.1.0-SNAPSHOT", "private": false, "type": "module", + "files": [ + "dist" + ], + "publishConfig": { + "registry": "https://forge.celhosting.ch/api/packages/celements/npm/" + }, "exports": { - "./src/*": "./src/*" + ".": { + "types": "./dist/types/public/runtime.d.ts", + "import": "./dist/package/runtime.js" + }, + "./runtime": { + "types": "./dist/types/public/runtime.d.ts", + "import": "./dist/package/runtime.js" + }, + "./page-attachments": { + "types": "./dist/types/public/page-attachments.d.ts", + "import": "./dist/package/page-attachments.js" + }, + "./page-attachments-island": { + "types": "./dist/types/public/page-attachments-island.d.ts", + "import": "./dist/package/page-attachments-island.js" + }, + "./styles.css": "./dist/package/styles.css" }, "scripts": { "dev": "concurrently \"vite\" \"npm:type-check-watch\" \"npm:test-watch\"", - "build": "npm run type-check && npm run test && vite build", + "build": "npm run type-check && npm run build:deployable && npm run build:package && npm run build:types && npm run test:unit", + "build:deployable": "vite build", + "build:package": "vite build --config vite.library.config.ts", + "build:types": "vue-tsc -p tsconfig.app.json --declaration --emitDeclarationOnly --noEmit false --outDir dist/types --composite false", "preview": "vite preview", - "test": "vitest run", + "test": "npm run build:deployable && npm run build:package && npm run build:types && npm run test:unit", + "test:unit": "vitest run", "test-watch": "vitest", "type-check": "vue-tsc --build --force", "type-check-watch": "vue-tsc --build --force --watch --preserveWatchOutput", @@ -18,7 +44,9 @@ "lint-fix": "eslint . --fix", "format": "prettier --check src test", "format-fix": "prettier --write src test", - "pre-commit": "npm run type-check && npm run format && npm run lint" + "pre-commit": "npm run type-check && npm run format && npm run lint", + "publish:check": "npm run build && npm pack --dry-run --json", + "publish:forge": "./scripts/publish-forge-package.sh" }, "dependencies": { "@fortawesome/fontawesome-svg-core": "^7.2.0", @@ -30,19 +58,20 @@ "findandreplacedomtext": "^0.4.6", "lodash": "^4.17.23", "luxon": "^3.7.2", - "pinia": "^3.0.4", - "primevue": "^4.5.4", "tailwind-merge": "^3.5.0", "tailwindcss-primeui": "^0.6.1", - "vue": "^3.5.30", "vue-dompurify-html": "^5.3.0", - "vue-i18n": "^11.3.0", "vue-matomo": "^4.2.0", - "vue-router": "^5.0.4", "vue3-spinners": "^1.3.3", - "vuefinder": "^4.1.1", "zod": "^4.3.6" }, + "peerDependencies": { + "pinia": "^3.0.4", + "primevue": "^4.5.4", + "vue": "^3.5.30", + "vue-i18n": "^11.3.0", + "vuefinder": "^4.1.1" + }, "devDependencies": { "@tailwindcss/postcss": "^4.2.2", "@tsconfig/node20": "^20.1.9", @@ -62,12 +91,18 @@ "eslint-plugin-vue": "^10.8.0", "jsdom": "^29.0.1", "npm-run-all2": "^8.0.4", + "pinia": "^3.0.4", "postcss": "^8.5.8", "prettier": "^3.8.1", + "primevue": "^4.5.4", "tailwindcss": "^4.2.2", "typescript": "~5.9.3", "vite": "^8.0.1", "vitest": "^4.1.0", + "vue": "^3.5.30", + "vue-i18n": "^11.3.0", + "vue-router": "^5.0.4", + "vuefinder": "^4.1.1", "vue-tsc": "^3.2.6" }, "browserslist": [ diff --git a/celements-admin-frontend/postcss.config.js b/celements-admin-frontend/postcss.config.js index 6f51004b1..abafe65a8 100644 --- a/celements-admin-frontend/postcss.config.js +++ b/celements-admin-frontend/postcss.config.js @@ -39,6 +39,93 @@ function conditionalTailwind() { } conditionalTailwind.postcss = true; +const adminScope = ':where(.cel-admin-surface, .cel-admin-teleport)'; +const vueFinderTeleportScope = + ':where(.vuefinder__themer, .vuefinder__modal-layout, [data-sonner-toaster])'; +const globalSelectors = new Set([ + '*', + ':after', + ':before', + '::after', + '::backdrop', + '::before', + '::file-selector-button', +]); +const vueFinderGlobalSelectorAllowlist = [ + /^\.vuefinder(?:\b|__|--)/, + /^\.vf-/, + /^\.vue-(?:advanced-cropper|bounding-box|circle-stencil|draggable-area|handler-wrapper|line-wrapper|preview|rectangle-stencil|simple-handler|simple-line)(?:\b|__|--)/, + /^\.os-/, + /^\.sonner-/, + /^\.uppy-/, + /^\[data-overlayscrollbars/, + /^\[data-sonner-/, + /^:is\(\.vuefinder/, + /^:where\(\.vuefinder/, +]; + +function isExplicitlyNamespacedVueFinderSelector(selector) { + return vueFinderGlobalSelectorAllowlist.some((pattern) => pattern.test(selector)); +} + +function replaceDocumentRoot(selector, scope) { + const directionMatch = selector.match(/^html\[dir=(ltr|rtl)\]/); + if (directionMatch) { + return selector.replace(directionMatch[0], `${scope}:dir(${directionMatch[1]})`); + } + return selector + .replace(/^html(?:\[[^\]]+\])?\s*>\s*body/, scope) + .replace(/^html(?:\[[^\]]+\])?/, scope) + .replace(/^body/, scope); +} + +function scopeSelector(selector, scope) { + if (selector === ':root' || selector === ':host') return scope; + if (/^(?:html|body)(?:\b|\[|:|\s|>)/.test(selector)) { + return replaceDocumentRoot(selector, scope); + } + const descendant = `${scope} ${selector}`; + if (/^[.[:]/.test(selector)) return `${descendant}, ${scope}${selector}`; + return descendant; +} + +function scopeVueFinderSelector(selector) { + return [adminScope, vueFinderTeleportScope] + .map((scope) => scopeSelector(selector, scope)) + .join(', '); +} + +function scopeAdminStyles() { + return { + postcssPlugin: 'scope-celements-admin-styles', + OnceExit(root, helpers) { + const from = helpers?.result?.opts?.from || root?.source?.input?.file || ''; + const isApplicationStyles = from.includes('/src/assets/main.css'); + if (!isApplicationStyles && !from.includes('/node_modules/vuefinder/')) return; + root.walkRules((rule) => { + if (rule.parent?.type === 'atrule' && rule.parent.name.includes('keyframes')) return; + rule.selectors = rule.selectors.map((selector) => { + const trimmed = selector.trim(); + if (isApplicationStyles) { + if (trimmed === ':root' || trimmed === ':host') return adminScope; + if (globalSelectors.has(trimmed)) return `${adminScope} ${trimmed}`; + if ( + !trimmed.includes('.cel-admin-surface') && + !trimmed.includes('.cel-admin-teleport') + ) { + return scopeSelector(trimmed, adminScope); + } + return selector; + } + if (isExplicitlyNamespacedVueFinderSelector(trimmed)) return selector; + return scopeVueFinderSelector(trimmed); + }); + }); + }, + }; +} +scopeAdminStyles.postcss = true; + export default { - plugins: [conditionalTailwind(), autoprefixer()], + plugins: [conditionalTailwind(), scopeAdminStyles(), autoprefixer()], }; diff --git a/celements-admin-frontend/scripts/publish-forge-package.sh b/celements-admin-frontend/scripts/publish-forge-package.sh new file mode 100755 index 000000000..ba780a920 --- /dev/null +++ b/celements-admin-frontend/scripts/publish-forge-package.sh @@ -0,0 +1,34 @@ +#!/bin/sh + +set -eu + +registry='https://forge.celhosting.ch/api/packages/celements/npm/' +package_name=$(node -p "require('./package.json').name") +package_version=$(node -p "require('./package.json').version") +dist_tag=${NPM_DIST_TAG:-latest} + +case "$package_version" in + *-SNAPSHOT) + echo "refusing to publish mutable snapshot version $package_version" >&2 + echo 'set a unique SemVer prerelease version before publishing' >&2 + exit 1 + ;; +esac + +if [ -z "${FORGE_TOKEN:-}" ]; then + echo 'FORGE_TOKEN is required for Forge package publication' >&2 + exit 1 +fi + +view_error=$(mktemp) +trap 'rm -f "$view_error"' EXIT +if npm view "$package_name@$package_version" version --registry "$registry" >/dev/null 2>"$view_error"; then + echo "refusing to overwrite published package $package_name@$package_version" >&2 + exit 1 +fi +if ! grep -q 'E404' "$view_error"; then + cat "$view_error" >&2 + exit 1 +fi + +npm publish --registry "$registry" --tag "$dist_tag" diff --git a/celements-admin-frontend/src/App.vue b/celements-admin-frontend/src/App.vue index 34597bf14..485414a71 100644 --- a/celements-admin-frontend/src/App.vue +++ b/celements-admin-frontend/src/App.vue @@ -1,6 +1,8 @@ diff --git a/celements-admin-frontend/src/features/page-attachments/types.ts b/celements-admin-frontend/src/features/page-attachments/types.ts new file mode 100644 index 000000000..d79753aff --- /dev/null +++ b/celements-admin-frontend/src/features/page-attachments/types.ts @@ -0,0 +1,22 @@ +import type { DirEntry } from 'vuefinder'; + +export interface PageAttachmentsDocument { + spaceName: string; + docName: string; +} + +export interface PageAttachmentsProps extends PageAttachmentsDocument { + locale?: string; +} + +export interface PageAttachmentsActionContext { + document: PageAttachmentsDocument; + path: string; + count: number; + selectedAttachments: readonly DirEntry[]; +} + +export interface PageAttachmentsSelectionDetail { + document: PageAttachmentsDocument; + selectedAttachments: readonly DirEntry[]; +} diff --git a/celements-admin-frontend/src/islands/PageAttachmentsIslandRoot.vue b/celements-admin-frontend/src/islands/PageAttachmentsIslandRoot.vue new file mode 100644 index 000000000..7fac14116 --- /dev/null +++ b/celements-admin-frontend/src/islands/PageAttachmentsIslandRoot.vue @@ -0,0 +1,23 @@ + + + diff --git a/celements-admin-frontend/src/islands/page-attachments-element.ts b/celements-admin-frontend/src/islands/page-attachments-element.ts new file mode 100644 index 000000000..4ffd9e773 --- /dev/null +++ b/celements-admin-frontend/src/islands/page-attachments-element.ts @@ -0,0 +1,83 @@ +import PageAttachmentsIslandRoot from '@/islands/PageAttachmentsIslandRoot.vue'; +import { createCelementsApplication } from '@/runtime/application'; +import type { PageAttachmentsSelectionDetail } from '@/features/page-attachments/types'; + +export const PAGE_ATTACHMENTS_ELEMENT_NAME = 'cel-page-attachments'; + +export class CelPageAttachmentsElement extends HTMLElement { + static observedAttributes = ['space-name', 'doc-name', 'locale', 'local-dev']; + private application: ReturnType | null = null; + + get spaceName() { + return this.getAttribute('space-name') ?? ''; + } + set spaceName(value: string) { + this.setAttribute('space-name', value); + } + get docName() { + return this.getAttribute('doc-name') ?? ''; + } + set docName(value: string) { + this.setAttribute('doc-name', value); + } + get locale() { + return this.getAttribute('locale') ?? undefined; + } + set locale(value: string | undefined) { + if (value == null) this.removeAttribute('locale'); + else this.setAttribute('locale', value); + } + get localDev() { + const value = this.getAttribute('local-dev'); + return value == null ? undefined : value.toLowerCase() !== 'false'; + } + set localDev(value: boolean | undefined) { + if (value == null) this.removeAttribute('local-dev'); + else this.setAttribute('local-dev', String(value)); + } + connectedCallback() { + if (this.application) return; + if (!this.spaceName || !this.docName) return; + this.application = createCelementsApplication( + PageAttachmentsIslandRoot, + { + spaceName: this.spaceName, + docName: this.docName, + locale: this.locale, + onSelectionChange: (detail: PageAttachmentsSelectionDetail) => { + this.dispatchEvent( + new CustomEvent('attachment-selection-change', { + detail, + bubbles: true, + composed: true, + }) + ); + }, + }, + { locale: this.locale, localDev: this.localDev } + ); + this.application.mount(this); + } + disconnectedCallback() { + this.unmount(); + } + attributeChangedCallback(_name: string, oldValue: string | null, newValue: string | null) { + if (!this.isConnected || oldValue === newValue) return; + this.unmount(); + this.connectedCallback(); + } + private unmount() { + if (!this.application) return; + this.application.app.unmount(); + this.application = null; + this.replaceChildren(); + } +} + +export const registerPageAttachmentsElement = ( + registry: CustomElementRegistry = customElements +) => { + if (!registry.get(PAGE_ATTACHMENTS_ELEMENT_NAME)) { + registry.define(PAGE_ATTACHMENTS_ELEMENT_NAME, CelPageAttachmentsElement); + } +}; diff --git a/celements-admin-frontend/src/medialib/api/tagApi.ts b/celements-admin-frontend/src/medialib/api/tagApi.ts index 37a50cb6c..2083db2af 100644 --- a/celements-admin-frontend/src/medialib/api/tagApi.ts +++ b/celements-admin-frontend/src/medialib/api/tagApi.ts @@ -11,8 +11,7 @@ export async function apiFetchTags(): Promise { export async function apiFetchFilesForTag(tagId: string): Promise { const res = await fetch(`${API_BASE}/tags/files?tagId=${encodeURIComponent(tagId)}`); - if (!res.ok) - throw new Error(`GET ${API_BASE}/tags/files?tagId=${tagId} failed: ${res.status}`); + if (!res.ok) throw new Error(`GET ${API_BASE}/tags/files?tagId=${tagId} failed: ${res.status}`); return res.json() as Promise; } diff --git a/celements-admin-frontend/src/medialib/components/TagSidebar.vue b/celements-admin-frontend/src/medialib/components/TagSidebar.vue index de368fbaf..bbf750202 100644 --- a/celements-admin-frontend/src/medialib/components/TagSidebar.vue +++ b/celements-admin-frontend/src/medialib/components/TagSidebar.vue @@ -1,10 +1,10 @@ @@ -182,8 +217,7 @@ function isActive(tag: Tag): boolean { } function fileCountForTag(tag: Tag): number { - return Object.values(tagStore.fileTagMap).filter((tags) => - tags.some((t) => t.id === tag.id), - ).length; + return Object.values(tagStore.fileTagMap).filter((tags) => tags.some((t) => t.id === tag.id)) + .length; } diff --git a/celements-admin-frontend/src/medialib/components/TagStatusBar.vue b/celements-admin-frontend/src/medialib/components/TagStatusBar.vue index b9086ce1b..88c7151c8 100644 --- a/celements-admin-frontend/src/medialib/components/TagStatusBar.vue +++ b/celements-admin-frontend/src/medialib/components/TagStatusBar.vue @@ -1,15 +1,10 @@