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/.github/CODEOWNERS b/.github/CODEOWNERS index a5d78339b8..05b9a503d3 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1 @@ -/packages @warm-coolguy @dopenguin @oeninghe-dataport +* @warm-coolguy @dopenguin @oeninghe-dataport diff --git a/.github/workflows/preview.yaml b/.github/workflows/preview.yaml new file mode 100644 index 0000000000..3f6aa4b5ea --- /dev/null +++ b/.github/workflows/preview.yaml @@ -0,0 +1,54 @@ +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@8e8c483db84b4bee98b60c0593521ed34d9990e8 + + - name: Set up Node.js + if: github.event.action != 'closed' + uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f + with: + node-version: 24.12.0 + registry-url: https://registry.npmjs.org/ + + - name: Install documentation build dependencies + run: sudo apt install mkdocs mkdocs-material + + - name: Install NPM dependencies + run: npm ci + + - name: Build preview + run: | + npm run build:ci + npm run preview:build:ci -- --base="./" + + - name: Build documentation + run: | + npm run docs:ci + mv docs-html ./.dist.preview/docs-html + + - name: Deploy preview to GitHub Pages + uses: rossjrw/pr-preview-action@5fd5f8e2f88e735fc3d1151302b32242037e3962 + 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..7ed9068c57 100644 --- a/.github/workflows/publish-packages.yml +++ b/.github/workflows/publish-packages.yml @@ -1,45 +1,35 @@ -name: Publish packages with updated changelog to npmjs.org +name: Publish @polar/polar to NPM registry on: push: - branches: - - main + tags: + - v* jobs: 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@8e8c483db84b4bee98b60c0593521ed34d9990e8 + + - name: Set up Node.js + uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f with: - node-version: 20.16.0 + node-version: 24.12.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 }} + - name: Install dependencies + run: npm ci + + - name: Build package + run: npm run build:ci + + - name: Publish to NPM + run: npm publish --access public env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - - run: node ./scripts/createRelease ${{ env.TAGS }} + + - 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..8b0d420d37 --- /dev/null +++ b/.github/workflows/publish-pages-next.yml @@ -0,0 +1,40 @@ +name: Publish bleeding-edge documentation to gh-pages/next + +on: + push: + branches: + - next + +permissions: + contents: write + +jobs: + deploy: + name: Deploy documentation + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 + + - name: Set up Node.js + uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f + with: + node-version: 24.12.0 + registry-url: https://registry.npmjs.org/ + + - 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@4a3abc783e1a24aeb44c16e869ad83caf6b4cc23 + 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..0445ff3ac8 --- /dev/null +++ b/.github/workflows/run-tests.yaml @@ -0,0 +1,57 @@ +name: Run automated tests +on: push + +jobs: + lint: + name: Linting + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 + + - name: Set up Node.js + uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f + with: + node-version: 24.12.0 + registry-url: https://registry.npmjs.org/ + + - name: Install dependencies and run linter + run: | + npm ci + npm run lint:ci + + test: + name: Unit tests and e2e tests + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 + + - name: Set up Node.js + uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f + with: + node-version: 24.12.0 + registry-url: https://registry.npmjs.org/ + + - name: Install dependencies and run tests + run: | + npm ci + npm run test:ci + + type-check: + name: Type-checking + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 + + - name: Set up Node.js + uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f + with: + node-version: 24.12.0 + registry-url: https://registry.npmjs.org/ + + - name: Install dependencies and run type-checking + run: | + npm ci + 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..6d0e728120 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,7 @@ /public logs/*.log logs +*.patch +!/patches/**/*.patch + +.DS_Store \ No newline at end of file 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..85d00df16b --- /dev/null +++ b/.husky/defaults.json @@ -0,0 +1,10 @@ +{ + "skipPreCommit": false, + "allowDirtyCommit": true, + "lintOnCommit": 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..4ec5a58dda --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,62 @@ +#!/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_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..9e04d1517c --- /dev/null +++ b/.husky/prepareConfig.js @@ -0,0 +1,39 @@ +import { readFileSync, existsSync } 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/.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/LEGALNOTICE.md b/LEGALNOTICE.md index 3c486a5117..2a15c66c66 100644 --- a/LEGALNOTICE.md +++ b/LEGALNOTICE.md @@ -1,3 +1,7 @@ +--- +title: Legal Notice +--- + # Dataport Altenholzer Straße 10-14 diff --git a/README.md b/README.md index e7a6278c61..67597db470 100644 --- a/README.md +++ b/README.md @@ -1,132 +1,4 @@ ![Public Money, Public Value](https://img.shields.io/badge/Public%20Money-Public%20Value-red) [![License: EUPL v1.2](https://img.shields.io/badge/License-EUPL%20v1.2-blue)](https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12) -[![We're on NPM!](https://img.shields.io/badge/npm-%F0%9F%9A%80-green)](https://www.npmjs.com/search?q=%40polar) -

POLAR

- -**Plugins for OpenLAyeRs** is based on the [masterportalAPI](https://bitbucket.org/geowerkstatt-hamburg/masterportalapi) and [OpenLayers](https://openlayers.org/). - -POLAR is ... - -* ... a configurable map client package. -* ... a flexible map client factory. -* ... an extensible library. - -## Quick Start - -Usage without NPM is documented [here](#getting-started-for-developers). - -### Installation (via NPM) - -```bash -npm i @polar/client-generic -``` - -### Embedding POLAR -#### .js -```js -import polar from '@polar/client-generic' - -polar.createMap({ - // a div must have this id - containerId: 'polarstern', - // any service register – this is Hamburg's - services: 'https://geodienste.hamburg.de/services-internet.json', - mapConfiguration: { - // this initially shows Hamburg's city plan - layers: [{ - id: '453', - visibility: true, - type: 'background', - }] - } -}) -``` - -#### .html -```html -
-``` - -See our [documentation page](https://dataport.github.io/polar/) for all features and configuration options included in this modulith client, with running examples. - -## Example clients - -The most common use case for this client is in citizen's application processes regarding public service. - -Other clients with more specific code include the [Denkmalkarte Schleswig-Holstein](https://efi2.schleswig-holstein.de/dish/dish_client/index.html), a memorial map, and the [Meldemichel Hamburg](https://static.hamburg.de/kartenclient/prod/), a map to inspect and create reports regarding damages to public infrastructure. The latter is currently being migrated to the version seen in this repository. - -A more abstract example is the "Snowbox", which is a test environment for developers with many plugins active: - -

-Screenshot example of a possible POLAR client -

- -## Backers and users - -### States of Germany - - - - - - - - - - -
Bremer Wappenzeichen
Freie Hansestadt Bremen
Hamburg-Symbol
Freie und Hansestadt Hamburg
Landessymbol Sachsen-Anhalt
Sachsen-Anhalt
Landessymbol Schleswig-Holstein
Schleswig-Holstein
- -### Government agencies - -* [Senatskanzlei Hamburg](https://www.hamburg.de/senatskanzlei/) -* [Landesamt fΓΌr Denkmalpflege Schleswig-Holstein](https://www.schleswig-holstein.de/DE/landesregierung/ministerien-behoerden/LD/ld_node.html) -* [Dataport AΓΆR](https://www.dataport.de/) - -## Technical concepts - -### Reusability *and* adaptability - -POLAR is built to ease the creation of new map clients. A lot of feature requests in map clients are recurring and can be fulfilled with reusable parts. Then again, many map clients require a _little extra_. - -POLAR is built to serve both worlds. For generic use cases, generic clients are ready-made and usable by configuration. More specific use cases can be matched with special clients that still make use of the plugins and fill in the missing parts. - -POLAR runs both as full page application and as component. The most common usage is as component: Think of it as a form input where the input data is geospatial. - -### Plugin-based approach - -To see our plugins in action, please visit our [documentation page](https://dataport.github.io/polar/) to see running examples. Plugins are designed to be configurable, optional, and replacable. - -|Name|Details| -|-|-| -|[AddressSearch](https://github.com/Dataport/polar/tree/main/packages/plugins/AddressSearch)|Offers a search field and standard search service implementations with API for your own configurable custom search services. For already usable search services, see the documentation of the package. Integration with Reverse Geocoder and Pins possible, or usable as a data source for further processing.| -|[Attributions](https://github.com/Dataport/polar/tree/main/packages/plugins/Attributions)|Shows layer copyright information of visible layers and client.| -|[Draw](https://github.com/Dataport/polar/tree/main/packages/plugins/Draw)|Allows the user to draw various geometries onto the map. The resulting GeoJSON can be forwarded to later processing steps, or be used by the Export plugin to generate screenshots.| -|[Export](https://github.com/Dataport/polar/tree/main/packages/plugins/Export)|Offers screenshot functionality for the user or further processing.| -|[Filter](https://github.com/Dataport/polar/tree/main/packages/plugins/Filter)|Allows users to filter vector layers to content relevant to their interests.| -|[Fullscreen](https://github.com/Dataport/polar/tree/main/packages/plugins/Fullscreen)|User can toggle between integrated and fullscreen view with this plugin.| -|[GeoLocation](https://github.com/Dataport/polar/tree/main/packages/plugins/GeoLocation)|Geolocalizes the user either on user demand or as a background procedure. An icon is shown on the user position on the map.| -|[Gfi](https://github.com/Dataport/polar/tree/main/packages/plugins/Gfi)|Short for "Get Feature Information". Retrieves feature information from a WMS or WFS layer for display or usage by further processing steps. Can be used as feature list viewer for vector layers.| -|[IconMenu](https://github.com/Dataport/polar/tree/main/packages/plugins/IconMenu)|Handles display of visible plugin buttons. Only relevant for programming clients, no direct user feature.| -|[LayerChooser](https://github.com/Dataport/polar/tree/main/packages/plugins/LayerChooser)|Allows choosing a background layer and an arbitrary amount of feature or overlay layers. WMS layers can optionally be filtered by sub-layers by the user.| -|[Legend](https://github.com/Dataport/polar/tree/main/packages/plugins/Legend)|Displays an overview of layer legend images as delivered by the used WMS services. Images can be clicked for large view.| -|[LoadingIndicator](https://github.com/Dataport/polar/tree/main/packages/plugins/LoadingIndicator)|Loading spinner. Only relevant for programming clients, no direct user feature.| -|[PointerPosition](https://github.com/Dataport/polar/tree/main/packages/plugins/PointerPosition)|Displays the current/last pointer position in a coordinate reference system chosen by the user.| -|[Pins](https://github.com/Dataport/polar/tree/main/packages/plugins/Pins)|Pin feature that allows users to set and move pins to indicate a position. Integration with AddressSearch and ReverseGeocoder configurable.| -|[ReverseGeocoder](https://github.com/Dataport/polar/tree/main/packages/plugins/ReverseGeocoder)|Configurable to translate an arbitrary coordinate to an address. Integration with AddressSearch and Pins configurable.| -|[Scale](https://github.com/Dataport/polar/tree/main/packages/plugins/Scale)|Shows current scale as ratio and size indicator.| -|[Toast](https://github.com/Dataport/polar/tree/main/packages/plugins/Toast)|Shows information to the user. Configurable in many plugins to communicate status updates or procedural advice.| -|[Zoom](https://github.com/Dataport/polar/tree/main/packages/plugins/Zoom)|Allows zooming in and out of the client with buttons.| - -## Getting started (for developers) - -For a detailed step-by-step guide, please refer to our comprehensive [Getting Started guide](https://github.com/Dataport/polar/tree/main/gettingStarted.md). - -## Stay In Touch - -- [Contact us via email πŸ“§](mailto:polar@dataport.de) - -made by [Dataport](https://www.dataport.de/) with ❀️ +# POLAR \ No newline at end of file diff --git a/commitlint.config.js b/commitlint.config.js new file mode 100644 index 0000000000..586d4ab114 --- /dev/null +++ b/commitlint.config.js @@ -0,0 +1,19 @@ +import { globSync } from 'node:fs' +import { basename } from 'node:path' + +export default { + extends: ['@commitlint/config-conventional'], + rules: { + 'scope-enum': [ + 2, + 'always', + [ + 'arch', + 'release', + 'core', + ...globSync('src/plugins/*/').map((path) => basename(path)), + ...globSync('examples/*/').map((path) => basename(path)), + ], + ], + }, +} diff --git a/docs/architecture/decisions/ADR-0001.md b/docs/architecture/decisions/ADR-0001.md new file mode 100644 index 0000000000..8166228b14 --- /dev/null +++ b/docs/architecture/decisions/ADR-0001.md @@ -0,0 +1,21 @@ +# We write ADRs from now on + +## Status + +Accepted. + +## Context + +As time goes by, it becomes unclear whether architectural decisions have been made accidentally or on purpose, and, if on purpose, what the motivations were. + +## Decision + +From now on, all greater or debatable architectural decisions shall be denoted as an ADR within this document, like the "example ADR" you are currently reading. The used template is from [here](https://github.com/joelparkerhenderson/architecture-decision-record/tree/main/locales/en/templates/decision-record-template-by-michael-nygard). Also, questions arising about architecture shall be answered in such an ADR format to procude future references. + +If certain points change while not obsoleting the ADR as such, ADRs may be modified later. + +## Consequences + +* (+) Architecture decisions will become more transparent and understandable. +* (+) A truth base is defined and referencable. +* (-) Time needed for documentation. diff --git a/docs/architecture/decisions/ADR-0002.md b/docs/architecture/decisions/ADR-0002.md new file mode 100644 index 0000000000..9dec6f4cbe --- /dev/null +++ b/docs/architecture/decisions/ADR-0002.md @@ -0,0 +1,22 @@ +# Plugin-based architecture + +## Status + +Revoked by ADR 0009. + +## Context + +With recurring requirements, a desire grows to avoid repetition and reuse components. This can be implemented with a plugin-based architecture to create new map clients and have the most common features already done. + +## Decision + +An architecture for the client has been designed that models how we get to re-use functionality without re-writing it while still being open for extensions. The following graphic explains the architecture in further detail. + +![polar-2-architecture](https://github.com/Dataport/polar/assets/108349707/70090841-051c-44a7-8fde-2a9252a5d2ef) + +## Consequences + +* (+) Higher quality of features since multiple parties use them. +* (+) Implement once, use multiple times. +* (+) Parts are easier to exchange/develop, and not all clients are required to update immediately. +* (-) More difficult to understand the codebase. diff --git a/docs/architecture/decisions/ADR-0003.md b/docs/architecture/decisions/ADR-0003.md new file mode 100644 index 0000000000..6a0b51c9e2 --- /dev/null +++ b/docs/architecture/decisions/ADR-0003.md @@ -0,0 +1,17 @@ +# Error toasts have to be dismissed manually + +## Status + +Accepted. + +## Context + +Information relevant for the user is displayed in toasts which close automatically after a custom timeout. + +## Decision + +A timeout set for toasts that contain error messages will be ignored. Such toasts can only be closed manually by clicking the close button. + +## Consequences + +* (+) The user is forced to handle error messages and thus is more aware of errors that occur. diff --git a/docs/architecture/decisions/ADR-0004.md b/docs/architecture/decisions/ADR-0004.md new file mode 100644 index 0000000000..95a9eb0d76 --- /dev/null +++ b/docs/architecture/decisions/ADR-0004.md @@ -0,0 +1,19 @@ +# Vuex mutations have no map side effects + +## Status + +Obsoleted (Vuex is replaced with Pinia). + +## Context + +OL Map interactions are usually side effects by nature, but are not asynchronous. It was unclear whether such changes belong to actions or mutations. + +## Decision + +It has been decided that map side effects do not belong to mutations, but to actions. + +## Consequences + +* (+) Mutations stay clean of side effects. +* (+) On potential extension of such map calls, asynchronous behaviour may be required; in that case, actions are already the correct position. +* (-) This restriction must be manually enforced. diff --git a/docs/architecture/decisions/ADR-0005.md b/docs/architecture/decisions/ADR-0005.md new file mode 100644 index 0000000000..af9d6cccba --- /dev/null +++ b/docs/architecture/decisions/ADR-0005.md @@ -0,0 +1,24 @@ +# Difference between actions, utils and lib-packages + +## Status + +Accepted. + +## Context + +`actions`, `utils` and `lib`-packages can often consist of very similar code. It was not always clear enough where to place certain functionality, which was ultimately up to each developers own preference. + +## Decision + +When deciding on where to place code (when writing or refactoring), the following ordered list should be followed: + +* Does the functionality also change some part of the state? `action` +* Should the functionality be usable outside of an integrated client? `action` +* Does the functionality **not** have state changes, but belongs to a certain `action`? Either locally in the same file as the `action` or in a folder named after the `action` in the path `store/ACTIONNAME` +* Does the functionality **not** have state changes, but be reusable in the plugin / core? `utils` +* Should the functionality be reusable for multiple plugins / the core? `lib`-package + +## Consequences + +* (+) Gives clarity on where specific code fragments should reside. +* (-) This restriction must be manually enforced. diff --git a/docs/architecture/decisions/ADR-0006.md b/docs/architecture/decisions/ADR-0006.md new file mode 100644 index 0000000000..44a58b73e9 --- /dev/null +++ b/docs/architecture/decisions/ADR-0006.md @@ -0,0 +1,20 @@ +# `console` statement standardization + +## Status + +Accepted. + +## Context + +In production environments it may seem unclear if an error or warning message is shown in the console from which part of the application they occurred. + +## Decision + +All `console.warn` and `console.error` messages have to show the application's part in which they are invoked. +We add the location to the console messages at compile-time using Vite. + +## Consequences + +* (+) Errors and warnings can more easily be tracked back to the place in which they occur. +* (+) This restriction is enforced automatically. +* (-) Console messages are more verbose. diff --git a/docs/architecture/decisions/ADR-0007.md b/docs/architecture/decisions/ADR-0007.md new file mode 100644 index 0000000000..ebeb4eb370 --- /dev/null +++ b/docs/architecture/decisions/ADR-0007.md @@ -0,0 +1,19 @@ +# How to expose additional exports of a package + +## Status + +Accepted. + +## Context + +There are multiple ways of exposing additional exports of a package. They can either be exposed in the main file or configured as additional export nodes via rollup and the package.json. + +## Decision + +All exports should be exposed through the main file of the package as additional named exports. + +## Consequences + +* (+) A package consumer does not need to know additional paths to import. +* (+) This pattern is established by most major frameworks. +* (-) This restriction must be manually enforced. diff --git a/docs/architecture/decisions/ADR-0008.md b/docs/architecture/decisions/ADR-0008.md new file mode 100644 index 0000000000..d95510a4dc --- /dev/null +++ b/docs/architecture/decisions/ADR-0008.md @@ -0,0 +1,19 @@ +# Configuration parameters in tables have to be ordered by a) required and b) alphabetically. + +## Status + +Accepted. + +## Context + +If a developer is reading the docs, having the configuration parameters order first by required values then alphabetically makes it easier to find relevant parameters. + +## Decision + +All docs shall be sorted as proposed. + +## Consequences + +* (+) Better readability of documentation. +* (+) Clear placement of new parameters. +* (-) This restriction must be manually enforced. diff --git a/docs/architecture/decisions/ADR-0009.md b/docs/architecture/decisions/ADR-0009.md new file mode 100644 index 0000000000..32de144d24 --- /dev/null +++ b/docs/architecture/decisions/ADR-0009.md @@ -0,0 +1,23 @@ +# Revoke "ADR 0002: Plugin-based architecture" regarding packaging + +## Status + +Accepted. + +## Context + +The current structure uses NPM packages so segment the codebase into reusable parts. These packages have no known outside usage and slow down development in various positions as well as make documentation and changelogs a burden. Instead of a differentiation of core, plugins, and libs, all of these parts shall reside in a single package whilst maintaining the current pluginability feature. This single package shall also offer a default modulith client with all parts readymade for instantiating that can optionally be used. + +If accepted, the original ADR shall gain an additional sentence linking to this ADR regarding this future change, as this won't be executed easily, in a short time, or in a single step. + +## Decision + +We will restructure the architecture as shown in the next big major version. + +## Consequences + +* (+) Easier maintenance (no superfluous changelogs, easier type access, less boilerplate, faster releases). +* (+) Easier to understand the codebase. +* (-) It's not possible to use different versions of packages in the same client, especially old versions. + * (+) We never did this anyway and it may have produced complex fix scenarios (LTS for majors?) that no longer may occur. +* (-) We'll have to introduce technical limitations (architecture checks) regarding imports to prevent the codebase structure from degrading to spaghetti. diff --git a/docs/architecture/decisions/ADR-0010.md b/docs/architecture/decisions/ADR-0010.md new file mode 100644 index 0000000000..d21bbd87be --- /dev/null +++ b/docs/architecture/decisions/ADR-0010.md @@ -0,0 +1,18 @@ +# Manage ADRs with Git + +## Status + +Accepted. + +## Context + +Currently, ADRs are managed in a single GitHub wiki page of POLAR. + +## Decision + +We move the ADRs to the repository in a documentation folder. We write one file per ADR. + +## Consequences + +- (+) Changes to ADRs can more comfortably be tracked via Git. +- (o) There is more overhead in creating and updating ADRs, which may lead to writing less of them. diff --git a/docs/architecture/decisions/ADR-0011.md b/docs/architecture/decisions/ADR-0011.md new file mode 100644 index 0000000000..3fffb35317 --- /dev/null +++ b/docs/architecture/decisions/ADR-0011.md @@ -0,0 +1,28 @@ +# Split customer-specific clients into separate repositories + +## Status + +Accepted. + +## Context + +The new architecture, as introduced by ADR 0009, has a generic NPM package (@polar/polar, which replaces the packages @polar/core, @polar/lib-X, @polar/plugin-X and @polar/client-generic) and several customer-specific clients (@polar/client-X). + +The customer-specific clients are developed because of individual contracts and are (usually) not of major interest for other users. The maintenance of these clients is done primarily for the customers and does not contribute to the project's vision. + +## Decision + +Customer-specific clients (i.e., clients that are not the snowbox or the generic client) are moved to separate repositories (one repository per client). + +The new structure shall ensure that core changes can still be developed against a customer-specific client using HMR. + +## Consequences + +- (+) The repository structure is easier to understand (no monorepo). +- (+) Rules for contributions can be different between core and clients. +- (+) Contributors do not have to deal with customer-specific clients. +- (+) Real-world examples for implementing your own client in your own repository are provided. +- (+) Generating SBOMs is easier. +- (-) Following up with updates needs to be done in different repositories. + - (+) However, SemVer is used and helpers such as renovate exist. +- (o) Documentation of breaking changes including a migration guide is necessary. diff --git a/docs/architecture/index.md b/docs/architecture/index.md new file mode 100644 index 0000000000..456d50f5b6 --- /dev/null +++ b/docs/architecture/index.md @@ -0,0 +1,46 @@ +--- +title: Architecture +--- + +# Architecture documentation + +## User perspective +When using POLAR, it behaves a simple fragment that can be used in any web-based setting. +It may either work standalone, in which case there are only inputs for configuration, or as a part of a process, in which case there are both inputs and outputs for further processing. + +The purpose of POLAR is to handle all geospatial interactions of a user and utilize the decentralized geospatial infrastructure for that end. + +![POLAR architecture as viewn from a user perspective](../assets/polar-outer-architecture.png) + +*Viewn from the outside, POLAR is just a component* + +## Usage examples +POLAR is designed to increase *application efficiency* and *correctness* for the public sector, but may be used in any form process or as a standalone map client. +The provided _visualisations_ ease communication between citizens and administrative staff, allowing them to effectively share the *where*. + +POLAR is already in use for ... + +- ... **citizens** to ... + - communicate parcel data in applications. + - mark their current position for reports. + - read information on water levels, bathing spots, and much other public information. +- ... **officials in charge** to ... + - coordinate city services regarding reports. + - present governmental data to the public. + - manage and update department geospatial data. +- ... **developers** to ... + - heavily reduce implementation time. + - easily use geospatial systems without domain expertise. + - use POLAR as component in low code platforms. + +## Inner architecture +On the inside, POLAR is constructed from many smaller and isolated packages that each encapsulate a specific part of the business logic. +These parts can be mixed and matched, and are easily replacable for situations where further extension would make them overly complicated. + +For client-specific business logic, this can be placed in the very client itself to prevent bloat in other parts of the product. + +All in all, this makes POLAR a versatile map client factory. + +![POLAR architecture of the software itself](../assets/polar-architecture.png) + +*Viewn from the inside, POLAR is a map client factory* diff --git a/pages/assets/iceberg.svg b/docs/assets/iceberg.svg similarity index 100% rename from pages/assets/iceberg.svg rename to docs/assets/iceberg.svg diff --git a/pages/assets/iceberg_icon.svg b/docs/assets/iceberg_icon.svg similarity index 100% rename from pages/assets/iceberg_icon.svg rename to docs/assets/iceberg_icon.svg diff --git a/pages/assets/iframe-resizer/LICENSE b/docs/assets/iframe-resizer/LICENSE similarity index 100% rename from pages/assets/iframe-resizer/LICENSE rename to docs/assets/iframe-resizer/LICENSE diff --git a/pages/assets/iframe-resizer/README.md b/docs/assets/iframe-resizer/README.md similarity index 100% rename from pages/assets/iframe-resizer/README.md rename to docs/assets/iframe-resizer/README.md diff --git a/pages/assets/iframe-resizer/js/iframeResizer.contentWindow.js b/docs/assets/iframe-resizer/js/iframeResizer.contentWindow.js similarity index 100% rename from pages/assets/iframe-resizer/js/iframeResizer.contentWindow.js rename to docs/assets/iframe-resizer/js/iframeResizer.contentWindow.js diff --git a/pages/assets/iframe-resizer/js/iframeResizer.js b/docs/assets/iframe-resizer/js/iframeResizer.js similarity index 100% rename from pages/assets/iframe-resizer/js/iframeResizer.js rename to docs/assets/iframe-resizer/js/iframeResizer.js diff --git a/pages/assets/landessymbole/bremen.svg b/docs/assets/landessymbole/bremen.svg similarity index 100% rename from pages/assets/landessymbole/bremen.svg rename to docs/assets/landessymbole/bremen.svg diff --git a/pages/assets/landessymbole/hamburg.svg b/docs/assets/landessymbole/hamburg.svg similarity index 100% rename from pages/assets/landessymbole/hamburg.svg rename to docs/assets/landessymbole/hamburg.svg diff --git a/pages/assets/landessymbole/sachsen-anhalt.svg b/docs/assets/landessymbole/sachsen-anhalt.svg similarity index 100% rename from pages/assets/landessymbole/sachsen-anhalt.svg rename to docs/assets/landessymbole/sachsen-anhalt.svg diff --git a/pages/assets/landessymbole/schleswig-holstein.svg b/docs/assets/landessymbole/schleswig-holstein.svg similarity index 100% rename from pages/assets/landessymbole/schleswig-holstein.svg rename to docs/assets/landessymbole/schleswig-holstein.svg diff --git a/pages/assets/landessymbole/sources.md b/docs/assets/landessymbole/sources.md similarity index 100% rename from pages/assets/landessymbole/sources.md rename to docs/assets/landessymbole/sources.md diff --git a/pages/assets/manypixels-decentralized.svg b/docs/assets/manypixels-decentralized.svg similarity index 100% rename from pages/assets/manypixels-decentralized.svg rename to docs/assets/manypixels-decentralized.svg diff --git a/pages/assets/manypixels-legal.svg b/docs/assets/manypixels-legal.svg similarity index 100% rename from pages/assets/manypixels-legal.svg rename to docs/assets/manypixels-legal.svg diff --git a/pages/assets/manypixels-map.svg b/docs/assets/manypixels-map.svg similarity index 100% rename from pages/assets/manypixels-map.svg rename to docs/assets/manypixels-map.svg diff --git a/pages/assets/manypixels-mobile.svg b/docs/assets/manypixels-mobile.svg similarity index 100% rename from pages/assets/manypixels-mobile.svg rename to docs/assets/manypixels-mobile.svg diff --git a/pages/assets/manypixels-puzzle.svg b/docs/assets/manypixels-puzzle.svg similarity index 100% rename from pages/assets/manypixels-puzzle.svg rename to docs/assets/manypixels-puzzle.svg diff --git a/pages/assets/maps_pin.jpg b/docs/assets/maps_pin.jpg similarity index 100% rename from pages/assets/maps_pin.jpg rename to docs/assets/maps_pin.jpg diff --git a/pages/assets/polar-architecture.png b/docs/assets/polar-architecture.png similarity index 100% rename from pages/assets/polar-architecture.png rename to docs/assets/polar-architecture.png diff --git a/pages/assets/polar-outer-architecture.png b/docs/assets/polar-outer-architecture.png similarity index 100% rename from pages/assets/polar-outer-architecture.png rename to docs/assets/polar-outer-architecture.png diff --git a/pages/assets/polar_example_screenshot.png b/docs/assets/polar_example_screenshot.png similarity index 100% rename from pages/assets/polar_example_screenshot.png rename to docs/assets/polar_example_screenshot.png diff --git a/pages/assets/productive-users/dataport-logo.svg b/docs/assets/productive-users/dataport-logo.svg similarity index 100% rename from pages/assets/productive-users/dataport-logo.svg rename to docs/assets/productive-users/dataport-logo.svg diff --git a/pages/assets/productive-users/hamburg-logo.svg b/docs/assets/productive-users/hamburg-logo.svg similarity index 100% rename from pages/assets/productive-users/hamburg-logo.svg rename to docs/assets/productive-users/hamburg-logo.svg diff --git a/pages/assets/productive-users/schleswig-holstein-logo.svg b/docs/assets/productive-users/schleswig-holstein-logo.svg similarity index 100% rename from pages/assets/productive-users/schleswig-holstein-logo.svg rename to docs/assets/productive-users/schleswig-holstein-logo.svg diff --git a/pages/assets/productive-users/sources.md b/docs/assets/productive-users/sources.md similarity index 100% rename from pages/assets/productive-users/sources.md rename to docs/assets/productive-users/sources.md diff --git a/pages/assets/sources.md b/docs/assets/sources.md similarity index 100% rename from pages/assets/sources.md rename to docs/assets/sources.md diff --git a/docs/configuration.md b/docs/configuration.md new file mode 100644 index 0000000000..d022a90563 --- /dev/null +++ b/docs/configuration.md @@ -0,0 +1,21 @@ +--- +title: Configuration +--- + +# Configuration +About configuration, integration, and common use cases. + +## Client documentation +For special usecases, there are specialized clients based on POLAR. + +The following specialized clients are managed by the POLAR core team: +- [Style preview documentation β†—](https://dataport.github.io/polar-client-style-preview) + +Not sure where to start? +Use the package @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. + +100 *OpenLayers* + +90 *Vue* + +80 *Vuex* + +80 *TypeScript* + +10 *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..c80710ab3f --- /dev/null +++ b/eslint.config.ts @@ -0,0 +1,207 @@ +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 perfectionist from 'eslint-plugin-perfectionist' +import prettierConfig from 'eslint-plugin-prettier/recommended' +import vue from 'eslint-plugin-vue' +import { defineConfig } from 'eslint/config' + +/** + * POLAR-specific ESLint configuration + */ +const polarConfig = defineConfig({ + plugins: { + perfectionist, + vue, + }, + 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', + 'perfectionist/sort-imports': 'error', + 'vue/html-self-closing': [ + 'error', + { + html: { + void: 'always', + }, + }, + ], + }, +}) + +/** + * 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'], + }, + ], + }, +}) + +/** + * 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/examples/generic/index.html b/examples/generic/index.html new file mode 100644 index 0000000000..9550af4d23 --- /dev/null +++ b/examples/generic/index.html @@ -0,0 +1,66 @@ + + + + Generic POLAR client + + + + + + + + + +

POLAR map client

+ + +

Demo application

+
+
+
+ + diff --git a/examples/generic/index.js b/examples/generic/index.js new file mode 100644 index 0000000000..e8d33e6caa --- /dev/null +++ b/examples/generic/index.js @@ -0,0 +1,176 @@ +import { updateState } from '@polar/polar' +import { createMap } from '@polar/polar/client' +import { toMerged } from 'es-toolkit' + +const basemapId = '23420' +const basemapGreyId = '23421' +const reports = '6059' +const hamburgBorder = '1693' + +let colorScheme = 'light' + +// arbitrary condition for testing +const isEvenId = (mmlid) => Number(mmlid.slice(-1)) % 2 === 0 + +// NOTE: This function is only usable if the layer is clustered +const isReportSelectable = (feature) => + feature + .get('features') + .reduce( + (accumulator, current) => isEvenId(current.get('mmlid')) || accumulator, + false + ) + +const map = await createMap( + 'polarstern', + 'https://geoportal-hamburg.de/lgv-config/services-internet.json', + { + colorScheme, + startCenter: [565874, 5934140], + layers: [ + { + id: basemapId, + visibility: true, + type: 'background', + name: 'Basemap.de (Farbe)', + }, + { + id: basemapGreyId, + type: 'background', + name: 'Basemap.de (Grau)', + maxZoom: 6, + }, + { + id: hamburgBorder, + visibility: true, + hideInMenu: true, + type: 'mask', + name: 'Stadtgrenze Hamburg', + }, + { + id: reports, + type: 'mask', + name: 'Anliegen (MML)', + visibility: false, + }, + ], + layout: 'nineRegions', + checkServiceAvailability: true, + markers: { + layers: [ + { + id: reports, + defaultStyle: { + stroke: '#FFFFFF', + fill: '#005CA9', + }, + hoverStyle: { + stroke: '#46688E', + fill: '#8BA1B8', + }, + selectionStyle: { + stroke: '#FFFFFF', + fill: '#E10019', + }, + unselectableStyle: { + stroke: '#FFFFFF', + fill: '#333333', + }, + isSelectable: isReportSelectable, + }, + ], + clusterClickZoom: true, + }, + scale: { + showScaleSwitcher: true, + }, + addressSearch: { + searchMethods: [ + { + queryParameters: { + searchStreets: true, + searchHouseNumbers: true, + }, + type: 'mpapi', + url: 'https://geodienste.hamburg.de/HH_WFS_GAGES?service=WFS&request=GetFeature&version=2.0.0', + }, + ], + minLength: 3, + waitMs: 300, + focusAfterSearch: true, + groupProperties: { + defaultGroup: { + limitResults: 5, + }, + }, + }, + pins: { + coordinateSources: [{ plugin: 'addressSearch', key: 'chosenAddress' }], + boundary: { + layerId: hamburgBorder, + }, + movable: 'drag', + style: { + fill: '#FF0019', + }, + toZoomLevel: 7, + }, + reverseGeocoder: { + url: 'https://geodienste.hamburg.de/HH_WPS', + coordinateSources: [ + { + plugin: 'pins', + key: 'coordinate', + }, + ], + addressTarget: { + plugin: 'addressSearch', + key: 'selectResult', + }, + zoomTo: 7, + }, + geoLocation: { + checkLocationInitially: false, + keepCentered: false, + showTooltip: true, + zoomLevel: 7, + }, + }, + [ + 'addressSearch', + 'fullscreen', + 'geoLocation', + 'iconMenu', + 'layerChooser', + 'loadingIndicator', + 'pins', + 'reverseGeocoder', + 'scale', + 'toast', + ], + (serviceRegister) => + serviceRegister.map((entry) => + entry.id === reports ? toMerged(entry, { clusterDistance: 20 }) : entry + ) +) + +/* simple language switcher attached for demo purposes; + * language switching is considered a global concern and + * should be handled by the leading application */ +document + .getElementById('language-switcher') + ?.addEventListener('change', (event) => { + const target = event.target + const { value } = target + updateState(map, 'core', 'language', value) + target[0].innerHTML = value === 'en' ? 'English' : 'Englisch' + target[1].innerHTML = value === 'en' ? 'German' : 'Deutsch' + }) + +document + .getElementById('color-scheme-switcher') + ?.addEventListener('click', ({ target }) => { + target.innerHTML = `Switch to ${colorScheme} mode` + colorScheme = colorScheme === 'light' ? 'dark' : 'light' + updateState(map, 'core', 'colorScheme', colorScheme) + }) diff --git a/examples/generic/tsconfig.json b/examples/generic/tsconfig.json new file mode 100644 index 0000000000..4f7e3eb9b4 --- /dev/null +++ b/examples/generic/tsconfig.json @@ -0,0 +1,23 @@ +{ + "extends": [ + "@vue/tsconfig/tsconfig.dom.json", + "@vue/tsconfig/tsconfig.lib.json", + "../../tsconfig.settings.json" + ], + "compilerOptions": { + "types": [ + "vitest/importMeta", + "vitest/jsdom", + "../../src/@types/vite-env.d.ts", + "../../src/@types/i18next.d.ts", + "../../src/@types/pinia.d.ts", + "../../src/@types/shims-masterportalapi.d.ts", + "../../src/@types/virtual-kern-extra-icons.d.ts" + ], + "lib": ["ESNext", "DOM", "DOM.Iterable"], + "paths": { + "@polar/polar": ["../../src/core/index.ts"], + "@polar/polar/client": ["../../src/client.ts"] + } + } +} diff --git a/examples/github-io/App.vue b/examples/github-io/App.vue new file mode 100644 index 0000000000..76d80db4c4 --- /dev/null +++ b/examples/github-io/App.vue @@ -0,0 +1,191 @@ + + + + + + + diff --git a/examples/github-io/components/CtaSection.vue b/examples/github-io/components/CtaSection.vue new file mode 100644 index 0000000000..605cc8d527 --- /dev/null +++ b/examples/github-io/components/CtaSection.vue @@ -0,0 +1,128 @@ + + + + + diff --git a/examples/github-io/components/DevExSection.vue b/examples/github-io/components/DevExSection.vue new file mode 100644 index 0000000000..61ef6af8a7 --- /dev/null +++ b/examples/github-io/components/DevExSection.vue @@ -0,0 +1,299 @@ + + + + + diff --git a/examples/github-io/components/FeaturesSection.vue b/examples/github-io/components/FeaturesSection.vue new file mode 100644 index 0000000000..9b6712d030 --- /dev/null +++ b/examples/github-io/components/FeaturesSection.vue @@ -0,0 +1,34 @@ + + + + + diff --git a/examples/github-io/components/HeroPolarMap.vue b/examples/github-io/components/HeroPolarMap.vue new file mode 100644 index 0000000000..db84539a81 --- /dev/null +++ b/examples/github-io/components/HeroPolarMap.vue @@ -0,0 +1,146 @@ + + + + + diff --git a/examples/github-io/components/HeroSection.vue b/examples/github-io/components/HeroSection.vue new file mode 100644 index 0000000000..b281922c0e --- /dev/null +++ b/examples/github-io/components/HeroSection.vue @@ -0,0 +1,125 @@ + + + + + diff --git a/examples/github-io/components/RoadmapCard.vue b/examples/github-io/components/RoadmapCard.vue new file mode 100644 index 0000000000..ef470250ee --- /dev/null +++ b/examples/github-io/components/RoadmapCard.vue @@ -0,0 +1,186 @@ + + + + + diff --git a/examples/github-io/components/RoadmapPhaseLabel.vue b/examples/github-io/components/RoadmapPhaseLabel.vue new file mode 100644 index 0000000000..2af1ff85e2 --- /dev/null +++ b/examples/github-io/components/RoadmapPhaseLabel.vue @@ -0,0 +1,87 @@ + + + + + diff --git a/examples/github-io/components/RoadmapSection.vue b/examples/github-io/components/RoadmapSection.vue new file mode 100644 index 0000000000..d7facbe9b4 --- /dev/null +++ b/examples/github-io/components/RoadmapSection.vue @@ -0,0 +1,401 @@ + + + + + diff --git a/examples/github-io/components/TheBadge.vue b/examples/github-io/components/TheBadge.vue new file mode 100644 index 0000000000..f3cb17c51f --- /dev/null +++ b/examples/github-io/components/TheBadge.vue @@ -0,0 +1,48 @@ + + + + + diff --git a/examples/github-io/components/TheFooter.vue b/examples/github-io/components/TheFooter.vue new file mode 100644 index 0000000000..8b15fddaf0 --- /dev/null +++ b/examples/github-io/components/TheFooter.vue @@ -0,0 +1,47 @@ + + + + + diff --git a/examples/github-io/components/TheHeader.vue b/examples/github-io/components/TheHeader.vue new file mode 100644 index 0000000000..6a74b6cbea --- /dev/null +++ b/examples/github-io/components/TheHeader.vue @@ -0,0 +1,224 @@ + + + + + diff --git a/examples/github-io/components/UsedBySection.vue b/examples/github-io/components/UsedBySection.vue new file mode 100644 index 0000000000..39b13087e6 --- /dev/null +++ b/examples/github-io/components/UsedBySection.vue @@ -0,0 +1,21 @@ + + + + + diff --git a/examples/github-io/components/UxSection.vue b/examples/github-io/components/UxSection.vue new file mode 100644 index 0000000000..8547c5e9da --- /dev/null +++ b/examples/github-io/components/UxSection.vue @@ -0,0 +1,82 @@ + + + + + diff --git a/examples/github-io/components/VideoSection.vue b/examples/github-io/components/VideoSection.vue new file mode 100644 index 0000000000..60317b1944 --- /dev/null +++ b/examples/github-io/components/VideoSection.vue @@ -0,0 +1,116 @@ +