{{ card.title }}
+{{ card.body }}
+diff --git a/.editorconfig b/.editorconfig
index b765a32789..7cac9019d6 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -1,4 +1,15 @@
-[*.{js,ts,vue,json}]
+[*.{js,ts,vue,json,html,css}]
+indent_style = tab
+trim_trailing_whitespace = true
+insert_final_newline = true
+
+[*.yaml]
+indent_style = space
+indent_size = 2
+trim_trailing_whitespace = true
+insert_final_newline = true
+
+[vue2/*.{js,ts,vue,json}]
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
diff --git a/.env b/.env
new file mode 100644
index 0000000000..e515439aaf
--- /dev/null
+++ b/.env
@@ -0,0 +1 @@
+VITE_DEV_LANDING=""
diff --git a/.eslintignore b/.eslintignore
deleted file mode 100644
index af5fd69a4a..0000000000
--- a/.eslintignore
+++ /dev/null
@@ -1,10 +0,0 @@
-**/build
-**/.cache
-**/coverage
-**/dist
-**/dist-test
-**/docs
-**/node_modules
-**/tests_output
-*.d.ts
-/.nx/
diff --git a/.eslintrc.json b/.eslintrc.json
deleted file mode 100644
index e40cc91b3b..0000000000
--- a/.eslintrc.json
+++ /dev/null
@@ -1,98 +0,0 @@
-{
- "root": true,
- "extends": [
- "eslint:recommended",
- "plugin:@typescript-eslint/eslint-recommended",
- "plugin:@typescript-eslint/recommended",
- "plugin:vue/recommended",
- "standard",
- "plugin:prettier/recommended"
- ],
- "parser": "vue-eslint-parser",
- "parserOptions": {
- "parser": "@typescript-eslint/parser",
- "ecmaVersion": 2021,
- "sourceType": "module",
- "extraFileExtensions": [".vue"]
- },
- "plugins": ["import"],
- "rules": {
- "no-console": ["error", { "allow": ["warn", "error"] }],
- "no-debugger": "error",
- "object-curly-spacing": "error",
- "array-bracket-spacing": "error",
- "no-multi-spaces": "error",
- "vue/multi-word-component-names": "warn",
- "vue/order-in-components": "error",
- "import/order": "error",
- "curly": "error",
- "brace-style": "error",
- "no-else-return": "error",
- "no-lonely-if": "error",
- "require-await": "error",
- "no-extra-parens": "error",
- "func-style": ["error", "declaration", { "allowArrowFunctions": true }],
- "eol-last": "error",
- "no-eval": "error",
- "no-implied-eval": "error",
- "complexity": "warn",
- "max-depth": "warn"
- },
- "ignorePatterns": ["**/node_modules/**/*", "**/dist/**/*"],
- "settings": {
- "import/parsers": {
- "@typescript-eslint/parser": [".ts", ".tsx"]
- },
- "import/resolver": {
- "typescript": {
- "alwaysTryTypes": true
- }
- }
- },
- "overrides": [
- {
- "files": ["**/__tests__/*.{j,t}s?(x)", "**/tests/**/*.spec.{j,t}s?(x)"],
- "env": {
- "jest": true
- },
- "plugins": ["jest"]
- },
- {
- "files": ["packages/**/*.js", "packages/**/*.vue"],
- "env": {
- "browser": true
- },
- "plugins": ["eslint-plugin-vue"]
- },
- {
- "files": ["packages/**/*.ts"],
- "env": {
- "browser": true
- },
- "parserOptions": {
- "parser": "@typescript-eslint/parser",
- "ecmaVersion": 2021,
- "sourceType": "module",
- "project": "./tsconfig.json"
- },
- "plugins": ["eslint-plugin-tsdoc"],
- "rules": {
- "tsdoc/syntax": "warn",
- "no-use-before-define": "off",
- "@typescript-eslint/promise-function-async": "off",
- "@typescript-eslint/naming-convention": [
- "error",
- {
- "selector": ["typeLike"],
- "format": ["PascalCase"]
- },
- {
- "selector": ["memberLike"],
- "format": ["camelCase", "UPPER_CASE", "snake_case"]
- }
- ],
- "@typescript-eslint/consistent-type-definitions": ["error", "interface"]
- }
- }
- ]
-}
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index a5d78339b8..fe7254e199 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -1 +1 @@
-/packages @warm-coolguy @dopenguin @oeninghe-dataport
+* @warm-coolguy @dopenguin @oeninghe-dataport @czirkelbach @raschju
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000000..274455df80
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,29 @@
+version: 2
+updates:
+ - package-ecosystem: github-actions
+ directory: /
+ target-branch: next
+ schedule:
+ interval: weekly
+ open-pull-requests-limit: 20
+ cooldown:
+ default-days: 7
+ commit-message:
+ prefix: chore
+ include: scope
+
+ - package-ecosystem: npm
+ directory: /
+ target-branch: next
+ schedule:
+ interval: weekly
+ open-pull-requests-limit: 20
+ cooldown:
+ default-days: 3
+ exclude:
+ - "@dataport/eslint-config-geodev"
+ - vite-plugin-kern-extra-icons
+ commit-message:
+ prefix: chore
+ include: scope
+ versioning-strategy: increase
diff --git a/.github/workflows/preview.yaml b/.github/workflows/preview.yaml
new file mode 100644
index 0000000000..89181f96f8
--- /dev/null
+++ b/.github/workflows/preview.yaml
@@ -0,0 +1,61 @@
+name: Deploy PR previews
+
+on:
+ pull_request:
+ types:
+ - opened
+ - reopened
+ - synchronize
+ - closed
+
+permissions:
+ contents: write
+ pull-requests: write
+
+concurrency: preview-${{ github.ref }}
+
+jobs:
+ deploy-preview:
+ name: Create deployment preview
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+
+ - name: Set up Node.js
+ if: github.event.action != 'closed'
+ uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
+ with:
+ node-version: 24.15.0
+ registry-url: https://registry.npmjs.org/
+ cache: 'npm'
+
+ - name: Install documentation build dependencies
+ if: github.event.action != 'closed'
+ run: |
+ sudo apt-get update
+ sudo apt-get install -y --no-install-recommends mkdocs mkdocs-material
+
+ - name: Install NPM dependencies
+ if: github.event.action != 'closed'
+ run: npm ci
+
+ - name: Build preview
+ if: github.event.action != 'closed'
+ run: |
+ npm run build:ci
+ npm run preview:build:ci -- --base="./"
+
+ - name: Build documentation
+ if: github.event.action != 'closed'
+ run: |
+ npm run docs:ci
+ mv docs-html ./.dist.preview/docs-html
+
+ - name: Deploy preview to GitHub Pages
+ uses: rossjrw/pr-preview-action@ffa7509e91a3ec8dfc2e5536c4d5c1acdf7a6de9 # v1.8.1
+ with:
+ source-dir: ./.dist.preview/
+ preview-branch: gh-pages
+ qr-code: true
+ wait-for-pages-deployment: false
diff --git a/.github/workflows/publish-packages.yml b/.github/workflows/publish-packages.yml
index 18d7467924..de42858f39 100644
--- a/.github/workflows/publish-packages.yml
+++ b/.github/workflows/publish-packages.yml
@@ -1,45 +1,40 @@
-name: Publish packages with updated changelog to npmjs.org
+name: Publish @polar/polar to NPM registry
on:
push:
- branches:
- - main
+ tags:
+ - v*
+
+permissions:
+ id-token: write
+ contents: write
jobs:
publish:
+ environment: npm-publish
+ name: Publish package @polar/polar
runs-on: ubuntu-latest
- outputs:
- matrix: ${{ steps.matrix.outputs.TAGS }}
steps:
- - uses: actions/checkout@v4
- with:
- ssh-key: ${{ secrets.MAIN_BOT_KEY_PRIVATE }}
- - uses: actions/setup-node@v4
+ - name: Checkout repository
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+
+ - name: Set up Node.js
+ uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
- node-version: 20.16.0
+ node-version: 24.15.0
registry-url: https://registry.npmjs.org/
- - run: npm ci
- - run: |
- RETURN_TAGS=$(node ./scripts/versionPackages)
- echo "TAGS=$RETURN_TAGS" >> $GITHUB_ENV
- env:
- NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- - uses: EndBug/add-and-commit@v9
- with:
- author_name: Dataport Geo Bot
- author_email: polar@dataport.de
- - run: |
- for TAG in ${{ env.TAGS }}
- do
- git config user.name "Dataport Geo Bot"
- git config user.email "polar@dataport.de"
- git tag $TAG
- git push origin $TAG
- echo "Released and tagged $TAG"
- done
- - run: node ./scripts/publishPackages ${{ env.TAGS }}
- env:
- NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- - run: node ./scripts/createRelease ${{ env.TAGS }}
+ cache: 'npm'
+
+ - name: Install dependencies
+ run: npm ci
+
+ - name: Build package
+ run: npm run build:ci
+
+ - name: Publish to NPM
+ run: npm publish --access public --tag latest
+
+ - name: Create GitHub release
+ run: node scripts/create-github-release.ts
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/publish-pages-next.yml b/.github/workflows/publish-pages-next.yml
new file mode 100644
index 0000000000..180022d653
--- /dev/null
+++ b/.github/workflows/publish-pages-next.yml
@@ -0,0 +1,45 @@
+name: Publish bleeding-edge documentation to gh-pages/next
+
+on:
+ push:
+ branches:
+ - next
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
+permissions:
+ contents: write
+
+jobs:
+ deploy:
+ name: Deploy documentation
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+
+ - name: Set up Node.js
+ uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
+ with:
+ node-version: 24.15.0
+ registry-url: https://registry.npmjs.org/
+ cache: 'npm'
+
+ - name: Install documentation build dependencies
+ run: |
+ sudo apt update
+ sudo apt install mkdocs mkdocs-material
+
+ - name: Install NPM dependencies
+ run: npm ci
+
+ - name: Build documentation
+ run: npm run docs:ci
+
+ - name: Deploy documentation to gh-pages/next
+ uses: JamesIves/github-pages-deploy-action@d92aa235d04922e8f08b40ce78cc5442fcfbfa2f # v4.8.0
+ with:
+ folder: docs-html
+ target-folder: next
diff --git a/.github/workflows/publish-pages.yml b/.github/workflows/publish-pages.yml
deleted file mode 100644
index b05866e805..0000000000
--- a/.github/workflows/publish-pages.yml
+++ /dev/null
@@ -1,23 +0,0 @@
-name: Publish pages folder to gh-pages
-
-on:
- push:
- branches:
- - main
-
-jobs:
- deploy:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v4
- - uses: actions/setup-node@v4
- with:
- node-version: 20.16.0
- registry-url: https://registry.npmjs.org/
- - run: npm ci
- - run: npm run pages:build
- - name: Deploy
- uses: peaceiris/actions-gh-pages@v3
- with:
- github_token: ${{ secrets.GITHUB_TOKEN }}
- publish_dir: ./pages
diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml
new file mode 100644
index 0000000000..ce4711c394
--- /dev/null
+++ b/.github/workflows/run-tests.yaml
@@ -0,0 +1,154 @@
+name: Run automated tests
+on: push
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
+jobs:
+ setup:
+ name: Install dependencies
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+
+ - name: Set up Node.js
+ uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
+ with:
+ node-version: 24.15.0
+ registry-url: https://registry.npmjs.org/
+ cache: 'npm'
+
+ - name: Cache node_modules
+ id: node-modules-cache
+ uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
+ with:
+ path: node_modules
+ key: node-modules-${{ runner.os }}-node24.15.0-${{ hashFiles('package-lock.json', 'patches/**') }}
+
+ - name: Install NPM dependencies
+ if: steps.node-modules-cache.outputs.cache-hit != 'true'
+ run: npm ci --prefer-offline --no-audit --no-fund
+
+ lint:
+ name: Linting
+ needs: setup
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+
+ - name: Set up Node.js
+ uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
+ with:
+ node-version: 24.15.0
+ registry-url: https://registry.npmjs.org/
+
+ - name: Restore node_modules
+ id: node-modules-cache
+ uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
+ with:
+ path: node_modules
+ key: node-modules-${{ runner.os }}-node24.15.0-${{ hashFiles('package-lock.json', 'patches/**') }}
+
+ - name: Install NPM dependencies (cache miss fallback)
+ if: steps.node-modules-cache.outputs.cache-hit != 'true'
+ run: npm ci --prefer-offline --no-audit --no-fund
+
+ - name: Restore ESLint cache
+ uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
+ with:
+ path: .eslintcache
+ key: eslint-${{ runner.os }}-${{ github.ref }}-${{ hashFiles('eslint.config.ts') }}-${{ github.sha }}
+ restore-keys: |
+ eslint-${{ runner.os }}-${{ github.ref }}-${{ hashFiles('eslint.config.ts') }}-
+ eslint-${{ runner.os }}-${{ github.ref }}-
+ eslint-${{ runner.os }}-
+
+ - name: Run linter
+ run: npm run lint
+
+ lintcss:
+ name: CSS linting
+ needs: setup
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+
+ - name: Set up Node.js
+ uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
+ with:
+ node-version: 24.15.0
+ registry-url: https://registry.npmjs.org/
+
+ - name: Restore node_modules
+ id: node-modules-cache
+ uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
+ with:
+ path: node_modules
+ key: node-modules-${{ runner.os }}-node24.15.0-${{ hashFiles('package-lock.json', 'patches/**') }}
+
+ - name: Install NPM dependencies (cache miss fallback)
+ if: steps.node-modules-cache.outputs.cache-hit != 'true'
+ run: npm ci --prefer-offline --no-audit --no-fund
+
+ - name: Run CSS linter
+ run: npm run lint:css
+
+ test:
+ name: Unit tests and e2e tests
+ needs: setup
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+
+ - name: Set up Node.js
+ uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
+ with:
+ node-version: 24.15.0
+ registry-url: https://registry.npmjs.org/
+
+ - name: Restore node_modules
+ id: node-modules-cache
+ uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
+ with:
+ path: node_modules
+ key: node-modules-${{ runner.os }}-node24.15.0-${{ hashFiles('package-lock.json', 'patches/**') }}
+
+ - name: Install NPM dependencies (cache miss fallback)
+ if: steps.node-modules-cache.outputs.cache-hit != 'true'
+ run: npm ci --prefer-offline --no-audit --no-fund
+
+ - name: Run tests
+ run: npm run test:ci
+
+ type-check:
+ name: Type-checking
+ needs: setup
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+
+ - name: Set up Node.js
+ uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
+ with:
+ node-version: 24.15.0
+ registry-url: https://registry.npmjs.org/
+
+ - name: Restore node_modules
+ id: node-modules-cache
+ uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
+ with:
+ path: node_modules
+ key: node-modules-${{ runner.os }}-node24.15.0-${{ hashFiles('package-lock.json', 'patches/**') }}
+
+ - name: Install NPM dependencies (cache miss fallback)
+ if: steps.node-modules-cache.outputs.cache-hit != 'true'
+ run: npm ci --prefer-offline --no-audit --no-fund
+
+ - name: Run type-checking
+ run: npm run tsc:ci
diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml
deleted file mode 100644
index 5b82f7bd77..0000000000
--- a/.github/workflows/run-tests.yml
+++ /dev/null
@@ -1,60 +0,0 @@
-name: Run linter, tests and type check
-
-on: push
-
-jobs:
- lint:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v4
- - uses: actions/setup-node@v4
- with:
- node-version: 20.16.0
- registry-url: https://registry.npmjs.org/
- - run: |
- npm ci
- npm run lint:ci
- test:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v2
- - uses: actions/setup-node@v3
- with:
- node-version: 20.16.0
- registry-url: https://registry.npmjs.org/
- - run: |
- npm ci
- npm run test
- teste2e:
- timeout-minutes: 60
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v4
- - uses: actions/setup-node@v4
- with:
- node-version: 20.16.0
- - name: Install dependencies
- run: npm ci
- - name: Build snowbox (started by playwright by itself)
- run: npm run snowbox:build
- - name: Install Playwright Browsers
- run: npx playwright install --with-deps
- - name: Run Playwright tests (common)
- run: npm run test:e2e
- - uses: actions/upload-artifact@v4
- if: ${{ !cancelled() }}
- with:
- name: playwright-report
- path: playwright-report/
- retention-days: 30
- type-check:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v2
- - uses: actions/setup-node@v3
- with:
- node-version: 20.16.0
- registry-url: https://registry.npmjs.org/
- - run: |
- npm ci
- npm run tsc:ci
diff --git a/.gitignore b/.gitignore
index a621e3f338..65c2194693 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,10 +1,19 @@
+node_modules
+.eslintcache
+
+git-hooks.config.json
+
+/docs-html
+.dist.preview
+.vscode/settings.json
+
+# Old gitignore, maybe cleanup when migrated
**/.eslintcache
**/*.tgz
**/.cache
**/coverage
**/dist
**/dist-test
-**/docs
**/node_modules
**/tests_output
**/test-results/
@@ -17,3 +26,6 @@
/public
logs/*.log
logs
+*.patch
+!/patches/**/*.patch
+.DS_Store
diff --git a/.husky/commit-msg b/.husky/commit-msg
new file mode 100644
index 0000000000..4e831e3bbc
--- /dev/null
+++ b/.husky/commit-msg
@@ -0,0 +1,20 @@
+#!/bin/sh
+set -e
+eval `node .husky/prepareConfig.js`
+if [ "$POLAR_SKIP_COMMIT_MSG" = "yes" ]
+then
+ exit 0
+fi
+
+if [ "$POLAR_LINT_COMMIT_MESSAGE" = "yes" ]
+then
+ if ! npx --no -- commitlint --edit $1
+ then
+ echo "Cannot commit: Invalid commit message." >&2
+ echo "Please edit your commit message appropriately." >&2
+ echo >&2
+ echo "If you want to commit anyway, set POLAR_LINT_COMMIT_MESSAGE=no" >&2
+ echo "If you want to skip all commit-msg checks, set POLAR_SKIP_COMMIT_MSG=yes" >&2
+ exit 1
+ fi
+fi
diff --git a/.husky/defaults.json b/.husky/defaults.json
new file mode 100644
index 0000000000..f6cd8c5977
--- /dev/null
+++ b/.husky/defaults.json
@@ -0,0 +1,11 @@
+{
+ "skipPreCommit": false,
+ "allowDirtyCommit": true,
+ "lintOnCommit": false,
+ "lintCssOnCommit": false,
+ "typecheckOnCommit": false,
+ "testOnCommit": false,
+
+ "skipCommitMsg": false,
+ "lintCommitMessage": true
+}
\ No newline at end of file
diff --git a/.husky/install.js b/.husky/install.js
new file mode 100644
index 0000000000..5d9017a822
--- /dev/null
+++ b/.husky/install.js
@@ -0,0 +1,3 @@
+/* eslint-disable no-console */
+const { default: husky } = await import('husky')
+console.info(husky())
diff --git a/.husky/pre-commit b/.husky/pre-commit
new file mode 100755
index 0000000000..8f0af0b549
--- /dev/null
+++ b/.husky/pre-commit
@@ -0,0 +1,75 @@
+#!/bin/sh
+set -e
+eval `node .husky/prepareConfig.js`
+if [ "$POLAR_SKIP_PRE_COMMIT" = "yes" ]
+then
+ exit 0
+fi
+
+if [ "$POLAR_ALLOW_DIRTY_COMMIT" = "no" ]
+then
+ git rev-parse --verify HEAD >/dev/null || exit 1
+ git update-index -q --ignore-submodules --refresh
+
+ if ! git diff-files --quiet --ignore-submodules
+ then
+ echo "Cannot commit: You have unstaged changes." >&2
+ echo "Please stage, stash or drop these changes." >&2
+ echo >&2
+ echo "If you want to commit anyway, set POLAR_ALLOW_DIRTY_COMMIT=yes" >&2
+ echo "If you want to skip all pre-commit checks, set POLAR_SKIP_PRE_COMMIT=yes" >&2
+ exit 1
+ fi
+fi
+
+if [ "$POLAR_LINT_ON_COMMIT" = "yes" ]
+then
+ if ! npm run lint
+ then
+ echo "Cannot commit: Linting failed." >&2
+ echo "Please fix the above error(s)." >&2
+ echo >&2
+ echo "If you want to commit anyway, set POLAR_LINT_ON_COMMIT=no" >&2
+ echo "If you want to skip all pre-commit checks, set POLAR_SKIP_PRE_COMMIT=yes" >&2
+ exit 1
+ fi
+fi
+
+if [ "$POLAR_LINT_CSS_ON_COMMIT" = "yes" ]
+then
+ if ! npm run lint:css
+ then
+ echo "Cannot commit: CSS linting failed." >&2
+ echo "Please fix the above error(s)." >&2
+ echo >&2
+ echo "If you want to commit anyway, set POLAR_LINT_CSS_ON_COMMIT=no" >&2
+ echo "If you want to skip all pre-commit checks, set POLAR_SKIP_PRE_COMMIT=yes" >&2
+ exit 1
+ fi
+fi
+
+if [ "$POLAR_TYPECHECK_ON_COMMIT" = "yes" ]
+then
+ if ! npm run tsc
+ then
+ echo "Cannot commit: Type checking failed." >&2
+ echo "Please fix the above error(s)." >&2
+ echo >&2
+ echo "If you want to commit anyway, set POLAR_TYPECHECK_ON_COMMIT=no" >&2
+ echo "If you want to skip all pre-commit checks, set POLAR_SKIP_PRE_COMMIT=yes" >&2
+ exit 1
+ fi
+fi
+
+if [ "$POLAR_TEST_ON_COMMIT" = "yes" ]
+then
+ if ! npm run test:ci
+ then
+ echo "Cannot commit: Unit testing failed." >&2
+ echo "Please fix the above error(s)." >&2
+ echo >&2
+ echo "If you want to commit anyway, set POLAR_TEST_ON_COMMIT=no" >&2
+ echo "If you want to skip all pre-commit checks, set POLAR_SKIP_PRE_COMMIT=yes" >&2
+ exit 1
+ fi
+fi
diff --git a/.husky/prepareConfig.js b/.husky/prepareConfig.js
new file mode 100644
index 0000000000..2736be2893
--- /dev/null
+++ b/.husky/prepareConfig.js
@@ -0,0 +1,39 @@
+import { existsSync, readFileSync } from 'node:fs'
+
+let config = JSON.parse(readFileSync('.husky/defaults.json').toString())
+if (existsSync('git-hooks.config.json')) {
+ config = {
+ ...config,
+ ...JSON.parse(readFileSync('git-hooks.config.json').toString()),
+ }
+}
+
+function formatKey(key) {
+ return (
+ 'POLAR_' + key.replace(/[A-Z]/g, (m) => '_' + m.toLowerCase()).toUpperCase()
+ )
+}
+
+function getEnvValue(key) {
+ if (!process.env[key]) {
+ return null
+ }
+ const envValue = process.env[key]
+ if (['yes', 'YES', 'true', 'TRUE', '1', 'on', 'ON'].includes(envValue)) {
+ return true
+ } else if (
+ ['no', 'NO', 'false', 'FALSE', '0', 'off', 'OFF'].includes(envValue)
+ ) {
+ return false
+ }
+ process.stderr.write(
+ `Expected either "yes" or "no" for ${key}, got ${JSON.stringify(envValue)}`
+ )
+ process.exit(1)
+}
+
+Object.entries(config).forEach(([key, value]) => {
+ const formattedKey = formatKey(key)
+ const effectiveValue = getEnvValue(formattedKey) ?? value
+ process.stdout.write(`${formattedKey}=${effectiveValue ? 'yes' : 'no'}\n`)
+})
diff --git a/.npmrc b/.npmrc
index 2d610958c4..ec9e05d8a7 100644
--- a/.npmrc
+++ b/.npmrc
@@ -1,2 +1 @@
-legacy-peer-deps=true
-registry=https://registry.npmjs.org
+min-release-age=3
diff --git a/.prettierrc b/.prettierrc
index f95f035357..7173af6d3d 100644
--- a/.prettierrc
+++ b/.prettierrc
@@ -1,7 +1,8 @@
{
- "semi": false,
- "trailingComma": "es5",
- "singleQuote": true,
- "printWidth": 80,
- "tabWidth": 2
+ "semi": false,
+ "trailingComma": "es5",
+ "singleQuote": true,
+ "printWidth": 80,
+ "tabWidth": 2,
+ "useTabs": true
}
diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000000..c860112bdb
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,29 @@
+{
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "name": "Run development server",
+ "type": "node",
+ "request": "launch",
+ "cwd": "${workspaceFolder}",
+ "runtimeExecutable": "npm",
+ "runtimeArgs": ["run", "dev"]
+ },
+ {
+ "name": "Run production server",
+ "type": "node",
+ "request": "launch",
+ "cwd": "${workspaceFolder}",
+ "runtimeExecutable": "npm",
+ "runtimeArgs": ["run", "preview"]
+ },
+ {
+ "name": "Generate docs",
+ "type": "node",
+ "request": "launch",
+ "cwd": "${workspaceFolder}",
+ "runtimeExecutable": "npm",
+ "runtimeArgs": ["run", "docs"]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/@types/i18next.d.ts b/@types/i18next.d.ts
deleted file mode 100644
index 858cf654b7..0000000000
--- a/@types/i18next.d.ts
+++ /dev/null
@@ -1,88 +0,0 @@
-import 'i18next'
-
-// // // core/plugins // // //
-
-import { resourcesDe as resourcesDeCore } from '@polar/core/src/locales'
-import { resourcesDe as resourcesDeAddressSearch } from '@polar/plugin-address-search/src/locales'
-import { resourcesDe as resourcesDeAttributions } from '@polar/plugin-attributions/src/locales'
-import { resourcesDe as resourcesDeDraw } from '@polar/plugin-draw/src/locales'
-import { resourcesDe as resourcesDeExport } from '@polar/plugin-export/src/locales'
-import { resourcesDe as resourcesDeFilter } from '@polar/plugin-filter/src/locales'
-import { resourcesDe as resourcesDeFullscreen } from '@polar/plugin-fullscreen/src/locales'
-import { resourcesDe as resourcesDeGeoLocation } from '@polar/plugin-geo-location/src/locales'
-import { resourcesDe as resourcesDeGfi } from '@polar/plugin-gfi/src/locales'
-import { resourcesDe as resourcesDeIconMenu } from '@polar/plugin-icon-menu/src/locales'
-import { resourcesDe as resourcesDeLayerChooser } from '@polar/plugin-layer-chooser/src/locales'
-import { resourcesDe as resourcesDeLegend } from '@polar/plugin-legend/src/locales'
-import { resourcesDe as resourcesDeLoadingIndicator } from '@polar/plugin-loading-indicator/src/locales'
-import { resourcesDe as resourcesDePointerPosition } from '@polar/plugin-pointer-position/src/locales'
-import { resourcesDe as resourcesDePins } from '@polar/plugin-pins/src/locales'
-import { resourcesDe as resourcesDeScale } from '@polar/plugin-scale/src/locales'
-import { resourcesDe as resourcesDeToast } from '@polar/plugin-toast/src/locales'
-import { resourcesDe as resourcesDeZoom } from '@polar/plugin-zoom/src/locales'
-
-// // // clients // // //
-
-import { dishDe } from '@polar/client-dish/src/locales'
-import { dishExportMapDe } from '@polar/client-dish/src/plugins/DishExportMap/locales'
-import { dishHeaderDe } from '@polar/client-dish/src/plugins/Header/locales'
-import { dishModalDe } from '@polar/client-dish/src/plugins/Modal/locales'
-import { meldemichelDe } from '@polar/client-meldemichel/src/locales'
-import { meldemichelDe as meldemichelAfmButtonDe } from '@polar/client-meldemichel/src/plugins/AfmButton/locales'
-import { snowboxDe } from '@polar/client-snowbox/src/locales'
-import { textLocatorDe } from '@polar/client-text-locator/src/locales'
-import { textLocatorDe as textLocatorHeaderDe } from '@polar/client-text-locator/src/plugins/Header/locales'
-import { geometrySearchDe } from '@polar/client-text-locator/src/plugins/GeometrySearch/locales'
-
-// // // resources // // //
-
-const resources = {
- common: {
- ...resourcesDeCore,
- dish: dishDe,
- meldemichel: meldemichelDe,
- snowbox: snowboxDe,
- textLocator: textLocatorDe,
- plugins: {
- addressSearch: resourcesDeAddressSearch.plugins.addressSearch,
- attributions: resourcesDeAttributions.plugins.attributions,
- dish: {
- ...dishExportMapDe,
- ...dishHeaderDe,
- ...dishModalDe
- },
- draw: resourcesDeDraw.plugins.draw,
- export: resourcesDeExport.plugins.export,
- filter: resourcesDeFilter.plugins.filter,
- fullscreen: resourcesDeFullscreen.plugins.fullscreen,
- geoLocation: resourcesDeGeoLocation.plugins.geoLocation,
- // geometrySearch is from textLocator
- geometrySearch: {
- ...geometrySearchDe
- },
- gfi: resourcesDeGfi.plugins.gfi,
- iconMenu: resourcesDeIconMenu.plugins.iconMenu,
- layerChooser: resourcesDeLayerChooser.plugins.layerChooser,
- legend: resourcesDeLegend.plugins.legend,
- loadingIndicator: resourcesDeLoadingIndicator.plugins.loadingIndicator,
- meldemichel: {
- ...meldemichelAfmButtonDe
- },
- pointerPosition: resourcesDePointerPosition.plugins.pointerPosition,
- pins: resourcesDePins.plugins.pins,
- scale: resourcesDeScale.plugins.scale,
- textLocator: {
- ...textLocatorHeaderDe
- },
- toast: resourcesDeToast.plugins.toast,
- zoom: resourcesDeZoom.plugins.zoom,
- }
- }
-} as const
-
-declare module 'i18next' {
- interface CustomTypeOptions {
- defaultNS: "common"
- resources: typeof resources
- }
-}
diff --git a/@types/vue-shims/index.d.ts b/@types/vue-shims/index.d.ts
deleted file mode 100644
index c57cce794e..0000000000
--- a/@types/vue-shims/index.d.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-///
-
-
Freie Hansestadt Bremen |
- Freie und Hansestadt Hamburg |
-
Sachsen-Anhalt |
- Schleswig-Holstein |
-
@polar/polar and its documentation for an unspecialized client _including all plugins_.
+
+## Usage pattern
+All clients come with instructions documented above. However, they all mostly share how their integration works. Overall, these parts are required:
+
+- *TODO*
+
diff --git a/docs/contact.md b/docs/contact.md
new file mode 100644
index 0000000000..138bb4415b
--- /dev/null
+++ b/docs/contact.md
@@ -0,0 +1,6 @@
+---
+title: Contact
+---
+
+# Contact
+Mail us at polar@dataport.de
diff --git a/docs/development.md b/docs/development.md
new file mode 100644
index 0000000000..c023334849
--- /dev/null
+++ b/docs/development.md
@@ -0,0 +1,35 @@
+---
+title: Development
+---
+
+# Development
+
+Hint:
+Developing yourself is optional.
+POLAR supplies ready-made clients for many use cases, and you may commission us to write additional features.
+
+## Where to code
+POLAR clients run everywhere.
+To develop plugins and clients anew, a certain setup is required.
+To avoid redoing it, it is advised to create additional plugins and clients in a fork of the project.
+
+There are no further requirements.
+If you aim to merge back, please contact us before starting to put in work.
+
+TODO: Update this section, especially for clients
+
+## Required skills
+Depending on what exactly you plan to write anew, the required skills may vary.
+POLAR is a purely front-end solution and as such general knowledge about web development is advisable.
+
+We are especially writing the client with the following libraries, to which additional knowledge is helpful for contributions.
+
+ *OpenLayers*
+
+ *Vue*
+
+ *Vuex*
+
+ *TypeScript*
+
+ *SCSS*
diff --git a/docs/index.md b/docs/index.md
new file mode 100644
index 0000000000..5aad09f527
--- /dev/null
+++ b/docs/index.md
@@ -0,0 +1,11 @@
+---
+title: Introduction
+---
+
+# What is POLAR?
+
+POLAR is ...
+
+* ... a configurable map client package.
+* ... a flexible map client factory.
+* ... an extensible library.
diff --git a/docs/legal-notice.md b/docs/legal-notice.md
new file mode 120000
index 0000000000..a4ef2b2e5a
--- /dev/null
+++ b/docs/legal-notice.md
@@ -0,0 +1 @@
+../LEGALNOTICE.md
\ No newline at end of file
diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md
new file mode 100644
index 0000000000..d784b755f5
--- /dev/null
+++ b/docs/troubleshooting.md
@@ -0,0 +1,9 @@
+---
+title: Troubleshooting
+---
+
+## Common pitfalls
+
+### Map is not displayed
+
+- For Safari on iPadOS: Are the options "Advanced tracking protections" and "blocking of all cookies" enabled? If so, disable them and try again.
\ No newline at end of file
diff --git a/eslint.config.ts b/eslint.config.ts
new file mode 100644
index 0000000000..edd4ccbdd7
--- /dev/null
+++ b/eslint.config.ts
@@ -0,0 +1,243 @@
+import mainConfig from '@dataport/eslint-config-geodev'
+import browserConfig from '@dataport/eslint-config-geodev/browser'
+import htmlConfig from '@dataport/eslint-config-geodev/html'
+import jsonConfig from '@dataport/eslint-config-geodev/json'
+import markdownConfig from '@dataport/eslint-config-geodev/markdown'
+import tsConfig from '@dataport/eslint-config-geodev/typescript'
+import vueConfig from '@dataport/eslint-config-geodev/vue'
+import importPlugin from 'eslint-plugin-import'
+import perfectionist from 'eslint-plugin-perfectionist'
+import prettierConfig from 'eslint-plugin-prettier/recommended'
+import vue from 'eslint-plugin-vue'
+import { defineConfig } from 'eslint/config'
+
+import local from './eslintRules/index.js'
+
+/**
+ * POLAR-specific ESLint configuration
+ */
+const polarConfig = defineConfig({
+ plugins: {
+ import: importPlugin,
+ perfectionist,
+ vue,
+ local,
+ },
+ rules: {
+ 'prettier/prettier': 'error',
+
+ // Re-enable rules that are disabled by prettier but do not collide
+ curly: ['error', 'all'],
+
+ // POLAR-specific rules
+ 'no-warning-comments': 'warn',
+ 'no-void': 'off',
+ '@stylistic/lines-around-comment': [
+ 'error',
+ {
+ beforeBlockComment: true,
+ allowBlockStart: true,
+ allowObjectStart: true,
+ allowArrayStart: true,
+ allowClassStart: true,
+ allowEnumStart: true,
+ allowInterfaceStart: true,
+ allowModuleStart: true,
+ allowTypeStart: true,
+ },
+ ],
+ 'import-x/order': 'off',
+ 'import/consistent-type-specifier-style': ['error', 'prefer-top-level'],
+ 'perfectionist/sort-imports': [
+ 'error',
+ {
+ groups: [
+ 'type-import',
+ { newlinesBetween: 0 },
+ 'type-internal',
+ { newlinesBetween: 0 },
+ 'type-parent',
+ { newlinesBetween: 0 },
+ 'type-sibling',
+ { newlinesBetween: 0 },
+ 'type-index',
+ ['value-builtin', 'value-external'],
+ 'value-internal',
+ ['value-parent', 'value-sibling', 'value-index'],
+ 'ts-equals-import',
+ 'unknown',
+ ],
+ },
+ ],
+ 'perfectionist/sort-named-imports': 'error',
+ 'vue/html-self-closing': [
+ 'error',
+ {
+ html: {
+ void: 'always',
+ },
+ },
+ ],
+ 'local/import-style': 'error',
+ },
+})
+
+/**
+ * POLAR-specific TypeScript ESLint configuration
+ */
+const polarTsConfig = defineConfig({
+ rules: {
+ // Relaxed rules
+ '@typescript-eslint/no-unsafe-argument': 'off',
+ '@typescript-eslint/no-unsafe-assignment': 'off',
+ '@typescript-eslint/no-unsafe-call': 'off',
+ '@typescript-eslint/no-unsafe-member-access': 'off',
+ '@typescript-eslint/no-unsafe-return': 'off',
+ '@typescript-eslint/restrict-template-expressions': [
+ 'error',
+ {
+ allowAny: true,
+ allowNumber: true,
+ },
+ ],
+
+ // POLAR-specific rules
+ 'perfectionist/sort-interfaces': [
+ 'error',
+ {
+ type: 'natural',
+ groups: ['required-member', 'unknown'],
+ },
+ ],
+ '@typescript-eslint/consistent-type-imports': [
+ 'error',
+ {
+ disallowTypeAnnotations: true,
+ fixStyle: 'separate-type-imports',
+ prefer: 'type-imports',
+ },
+ ],
+ },
+})
+
+/**
+ * POLAR-specific Vue ESLint configuration
+ */
+const polarVueConfig = defineConfig({
+ rules: {
+ // POLAR-specific rules
+ 'vue/no-empty-component-block': 'error',
+ 'vue/block-order': [
+ 'error',
+ {
+ order: ['template', 'script', 'style'],
+ },
+ ],
+ 'vue/block-lang': [
+ 'error',
+ {
+ template: {
+ allowNoLang: true,
+ },
+ script: {
+ lang: 'ts',
+ },
+ style: {
+ allowNoLang: true,
+ },
+ },
+ ],
+ 'vue/component-api-style': ['error', ['script-setup', 'composition']],
+ 'vue/require-default-export': 'error',
+ 'vue/enforce-style-attribute': ['error', { allow: ['scoped'] }],
+ },
+})
+
+/**
+ * POLAR-specific HTML ESLint configuration
+ */
+const polarHtmlConfig = defineConfig({
+ rules: {
+ // POLAR-specific rules
+ '@html-eslint/require-closing-tags': ['error', { selfClosing: 'always' }],
+ '@html-eslint/no-extra-spacing-attrs': [
+ 'error',
+ { enforceBeforeSelfClose: true },
+ ],
+ },
+})
+
+export default defineConfig([
+ {
+ ignores: [
+ 'vue2/',
+ 'node_modules/',
+ 'docs/assets/',
+ 'docs-html/',
+ '.vscode/',
+ '**/dist/**',
+ '**/.dist.preview/**',
+
+ // Legacy list
+ '**/build',
+ '**/.cache',
+ '**/coverage',
+ '**/tests_output',
+ '*.d.ts',
+ '.nx/',
+ ],
+ },
+ {
+ files: ['**/*.js', '**/*.mjs', '**/*.cjs'],
+ extends: [mainConfig, browserConfig, prettierConfig, polarConfig],
+ },
+ {
+ files: ['**/*.ts'],
+ extends: [
+ mainConfig,
+ browserConfig,
+ tsConfig,
+ prettierConfig,
+ polarConfig,
+ polarTsConfig,
+ ],
+ },
+ {
+ files: ['**/eslint.config.ts'],
+ rules: {
+ '@typescript-eslint/naming-convention': 'off',
+ },
+ },
+ {
+ files: ['**/*.vue'],
+ extends: [
+ mainConfig,
+ browserConfig,
+ tsConfig,
+ vueConfig,
+ prettierConfig,
+ polarConfig,
+ polarTsConfig,
+ polarVueConfig,
+ ],
+ },
+ {
+ files: ['**/examples/**/*.vue'],
+ rules: {
+ 'vue/enforce-style-attribute': ['error', { allow: ['scoped', 'module'] }],
+ },
+ },
+ {
+ files: ['**/*.json'],
+ ignores: ['package-lock.json'],
+ extends: [jsonConfig],
+ },
+ {
+ files: ['**/*.md'],
+ extends: [markdownConfig],
+ },
+ {
+ files: ['**/*.html'],
+ extends: [htmlConfig, polarHtmlConfig],
+ },
+])
diff --git a/eslintRules/import-style.ts b/eslintRules/import-style.ts
new file mode 100644
index 0000000000..a376175c2d
--- /dev/null
+++ b/eslintRules/import-style.ts
@@ -0,0 +1,201 @@
+import type { Rule } from 'eslint'
+
+import path from 'node:path'
+
+/**
+ * Returns the context key for a path that is already relative to srcRoot.
+ *
+ * Contexts:
+ * - "core" → src/core/**
+ * - "plugins/+ Join the growing community of developers and public administrations + using POLAR to deliver modern, accessible map experiences. +
+ ++ Get started in minutes with POLAR's intuitive API. Our framework is + designed to make complex mapping tasks simple while giving you full + control when you need it. +
++ POLAR combines cutting-edge technology with ease of use, giving you the + tools to create exceptional map-based applications. +
+{{ title }}
+{{ body }}
++ We're continuously improving POLAR. Here's what we've shipped and + what's coming next. +
++ POLAR is designed with user experience at its core, ensuring your + mapping applications are accessible, responsive, and delightful to + use. +
+{{ card.body }}
++ 2024 we gave a small talk at FOSSGIS about ... +
+This is a minimal test page. Stage services are used.
-Developer playground.
-- Please mind you have to generate it locally first with `npm run docs:snowbox`, or use the public version here. -
-In this example, the map client is used as an element on a website.
- -- This illustrates which kind of data can be retrieved from the map client. -
-Current zoom level:
-GFI information:
-PIN coordinates:
-- Address search result: -
- -- Drawing: -
- -- Drawing revision: -
- -
- Map export:
-
-
Developer playground.
-- Please mind you have to generate it locally first with `npm run docs:snowbox`, or use the public version here. -
-In this example, the map client is used as an element on a website.
- -- This illustrates which kind of data can be retrieved from the map client. -
-Current zoom level:
-GFI information:
-PIN coordinates:
-- Address search result: -
- -- Drawing: -
- -- Drawing revision: -
- -
- Map export:
-
-