From d451e9e5975565f625222e59891cdabaee63ceec Mon Sep 17 00:00:00 2001 From: pajowu Date: Fri, 25 Aug 2023 16:28:07 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Add=20pages=20in=20footer=20&=20abo?= =?UTF-8?q?ut=20page?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/.gitignore | 2 + backend/data/pages/.gitkeep | 0 backend/openapi-schema.yml | 68 ++ backend/pdm.lock | 18 +- backend/pyproject.toml | 1 + backend/transcribee_backend/config.py | 43 +- backend/transcribee_backend/main.py | 2 + backend/transcribee_backend/routers/page.py | 25 + doc/development_setup.md | 21 + frontend/.gitignore | 2 + frontend/package.json | 7 +- frontend/pnpm-lock.yaml | 676 ++++++++++++++++++- frontend/public/.gitkeep | 0 frontend/scripts/generate_licenses.mjs | 50 ++ frontend/src/api.ts | 16 + frontend/src/api/pages.ts | 7 + frontend/src/app.tsx | 10 +- frontend/src/common/footer.tsx | 182 +++++ frontend/src/common/version.tsx | 69 -- frontend/src/common/virtual:git-version.d.ts | 1 + frontend/src/components/app.tsx | 6 +- frontend/src/openapi-schema.ts | 61 ++ frontend/src/pages/about.tsx | 35 + frontend/src/pages/page.tsx | 26 + frontend/tailwind.config.js | 4 +- frontend/vite.config.js | 20 +- 26 files changed, 1259 insertions(+), 93 deletions(-) create mode 100644 backend/data/pages/.gitkeep create mode 100644 backend/transcribee_backend/routers/page.py create mode 100644 frontend/public/.gitkeep create mode 100755 frontend/scripts/generate_licenses.mjs create mode 100644 frontend/src/api/pages.ts create mode 100644 frontend/src/common/footer.tsx delete mode 100644 frontend/src/common/version.tsx create mode 100644 frontend/src/pages/about.tsx create mode 100644 frontend/src/pages/page.tsx diff --git a/backend/.gitignore b/backend/.gitignore index 022626d8..652379ff 100644 --- a/backend/.gitignore +++ b/backend/.gitignore @@ -4,4 +4,6 @@ db.sqlite3 db.sqlite storage/ !storage/.gitkeep +data/ +!data/pages/.gitkeep .pdm.toml diff --git a/backend/data/pages/.gitkeep b/backend/data/pages/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/backend/openapi-schema.yml b/backend/openapi-schema.yml index 24b44562..183eec40 100644 --- a/backend/openapi-schema.yml +++ b/backend/openapi-schema.yml @@ -359,6 +359,22 @@ components: - languages title: ModelConfig type: object + PageConfig: + properties: + footer_position: + title: Footer Position + type: integer + name: + title: Name + type: string + text: + title: Text + type: string + required: + - name + - text + title: PageConfig + type: object PublicConfig: properties: models: @@ -379,6 +395,18 @@ components: - duration title: SetDurationRequest type: object + ShortPageConfig: + properties: + footer_position: + title: Footer Position + type: integer + name: + title: Name + type: string + required: + - name + title: ShortPageConfig + type: object SpeakerIdentificationTask: properties: document_id: @@ -993,6 +1021,46 @@ paths: $ref: '#/components/schemas/HTTPValidationError' description: Validation Error summary: Get Document Tasks + /api/v1/page/: + get: + operationId: get_pages_api_v1_page__get + responses: + '200': + content: + application/json: + schema: + additionalProperties: + $ref: '#/components/schemas/ShortPageConfig' + title: Response Get Pages Api V1 Page Get + type: object + description: Successful Response + summary: Get Pages + /api/v1/page/{page_id}: + get: + operationId: get_page_api_v1_page__page_id__get + parameters: + - in: path + name: page_id + required: true + schema: + title: Page Id + type: string + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/PageConfig' + description: Successful Response + '404': + description: Page not found + '422': + content: + application/json: + schema: + $ref: '#/components/schemas/HTTPValidationError' + description: Validation Error + summary: Get Page /api/v1/tasks/: get: operationId: list_tasks_api_v1_tasks__get diff --git a/backend/pdm.lock b/backend/pdm.lock index b49f7f01..acd413c3 100644 --- a/backend/pdm.lock +++ b/backend/pdm.lock @@ -848,6 +848,14 @@ version = "1.0.0" requires_python = ">=3.8" summary = "Read key-value pairs from a .env file and set them as environment variables" +[[package]] +name = "python-frontmatter" +version = "1.0.0" +summary = "Parse and manage posts with YAML (or other) frontmatter" +dependencies = [ + "PyYAML", +] + [[package]] name = "python-json-logger" version = "2.0.7" @@ -1180,7 +1188,7 @@ summary = "Jupyter interactive widgets for Jupyter Notebook" [metadata] lock_version = "4.1" -content_hash = "sha256:300153dd9fcf222cb4b04159e74282c6cadf8242053996f2c7cbc32313b89dea" +content_hash = "sha256:67a898031d7442a5ed10832a1e85b0d20e45f9906a612dd4c9e63225d7429f40" [metadata.files] "alembic 1.11.1" = [ @@ -1446,6 +1454,7 @@ content_hash = "sha256:300153dd9fcf222cb4b04159e74282c6cadf8242053996f2c7cbc3231 {url = "https://files.pythonhosted.org/packages/cf/58/8acf1b3e91c58313ce5cb67df61001fc9dcd21be4fadb76c1a2d540e09ed/fqdn-1.5.1-py3-none-any.whl", hash = "sha256:3a179af3761e4df6eb2e026ff9e1a3033d3587bf980a0b1b2e1e5d08d7358014"}, ] "greenlet 2.0.2" = [ + {url = "https://files.pythonhosted.org/packages/03/1a/dae7e4abc978e3eff4b8e90e76fb6619ba38d3cabac5f10131880fc03091/greenlet-2.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d4606a527e30548153be1a9f155f4e283d109ffba663a15856089fb55f933e47"}, {url = "https://files.pythonhosted.org/packages/07/ef/6bfa2ea34f76dea02833d66d28ae7cf4729ddab74ee93ee069c7f1d47c4f/greenlet-2.0.2-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:d5508f0b173e6aa47273bdc0a0b5ba055b59662ba7c7ee5119528f466585526b"}, {url = "https://files.pythonhosted.org/packages/08/b1/0615df6393464d6819040124eb7bdff6b682f206a464b4537964819dcab4/greenlet-2.0.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2dd11f291565a81d71dab10b7033395b7a3a5456e637cf997a6f33ebdf06f8db"}, {url = "https://files.pythonhosted.org/packages/09/57/5fdd37939e0989a756a32d0a838409b68d1c5d348115e9c697f42ee4f87d/greenlet-2.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:971ce5e14dc5e73715755d0ca2975ac88cfdaefcaab078a284fea6cfabf866df"}, @@ -1459,8 +1468,10 @@ content_hash = "sha256:300153dd9fcf222cb4b04159e74282c6cadf8242053996f2c7cbc3231 {url = "https://files.pythonhosted.org/packages/1f/42/95800f165d20fb8269fe6a3ac494649718ede074b1d8a78f58ee2ebda27a/greenlet-2.0.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:18e98fb3de7dba1c0a852731c3070cf022d14f0d68b4c87a19cc1016f3bb8b33"}, {url = "https://files.pythonhosted.org/packages/20/28/c93ffaa75f3c907cd010bf44c5c18c7f8f4bb2409146bd67d538163e33b8/greenlet-2.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:1a819eef4b0e0b96bb0d98d797bef17dc1b4a10e8d7446be32d1da33e095dbb8"}, {url = "https://files.pythonhosted.org/packages/29/c4/fe82cb9ff1bffc52a3832e35fa49cce63e5d366808179153ee879ce47cc9/greenlet-2.0.2-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:9d14b83fab60d5e8abe587d51c75b252bcc21683f24699ada8fb275d7712f5a9"}, + {url = "https://files.pythonhosted.org/packages/34/27/ca6f6deccf2bf7dce5c50953d354d22743f9e2bbce36815f31966687a4d1/greenlet-2.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d967650d3f56af314b72df7089d96cda1083a7fc2da05b375d2bc48c82ab3f3c"}, {url = "https://files.pythonhosted.org/packages/37/b9/3ebd606768bee3ef2198fe6d5e7c6c3af42ad3e06b56c1d0a89c56faba2a/greenlet-2.0.2-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:ba2956617f1c42598a308a84c6cf021a90ff3862eddafd20c3333d50f0edb45b"}, {url = "https://files.pythonhosted.org/packages/3a/69/a6d3d7abd0f36438ff5fab52572fd107966939d59ef9b8309263ab89f607/greenlet-2.0.2-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:910841381caba4f744a44bf81bfd573c94e10b3045ee00de0cbf436fe50673a6"}, + {url = "https://files.pythonhosted.org/packages/3f/1a/1a48b85490d93af5c577e6ab4d032ee3fe85c4c6d8656376f28d6d403fb1/greenlet-2.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8512a0c38cfd4e66a858ddd1b17705587900dd760c6003998e9472b77b56d417"}, {url = "https://files.pythonhosted.org/packages/42/d0/285b81442d8552b1ae6a2ff38caeec94ab90507c9740da718189416e8e6e/greenlet-2.0.2-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:bdfea8c661e80d3c1c99ad7c3ff74e6e87184895bbaca6ee8cc61209f8b9b85d"}, {url = "https://files.pythonhosted.org/packages/43/81/e0a656e3a417b172f834ba5a08dde02b55fd249416c1e933d62ffb6734d0/greenlet-2.0.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2780572ec463d44c1d3ae850239508dbeb9fed38e294c68d19a24d925d9223ca"}, {url = "https://files.pythonhosted.org/packages/49/b8/3ee1723978245e6f0c087908689f424876803ec05555400681240ab2ab33/greenlet-2.0.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:be4ed120b52ae4d974aa40215fcdfde9194d63541c7ded40ee12eb4dda57b76b"}, @@ -1471,6 +1482,7 @@ content_hash = "sha256:300153dd9fcf222cb4b04159e74282c6cadf8242053996f2c7cbc3231 {url = "https://files.pythonhosted.org/packages/54/ce/3a589ec27bd5de97707d2a193716bbe412ccbdb1479f0c3f990789c8fa8c/greenlet-2.0.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9c59a2120b55788e800d82dfa99b9e156ff8f2227f07c5e3012a45a399620b7"}, {url = "https://files.pythonhosted.org/packages/57/a8/079c59b8f5406957224f4f4176e9827508d555beba6d8635787d694226d1/greenlet-2.0.2-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:18a7f18b82b52ee85322d7a7874e676f34ab319b9f8cce5de06067384aa8ff43"}, {url = "https://files.pythonhosted.org/packages/5a/30/5eab5cbb99263c7d8305657587381c84da2a71fddb07dd5efbfaeecf7264/greenlet-2.0.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:937e9020b514ceedb9c830c55d5c9872abc90f4b5862f89c0887033ae33c6f73"}, + {url = "https://files.pythonhosted.org/packages/5d/34/d15e394dd41d84e40d1ef421716a939ad8fb65f010be9480f7a3b9e19bcd/greenlet-2.0.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1087300cf9700bbf455b1b97e24db18f2f77b55302a68272c56209d5587c12d1"}, {url = "https://files.pythonhosted.org/packages/6a/3d/77bd8dd7dd0b872eac87f1edf6fcd94d9d7666befb706ae3a08ed25fbea7/greenlet-2.0.2-cp36-cp36m-win32.whl", hash = "sha256:dbfcfc0218093a19c252ca8eb9aee3d29cfdcb586df21049b9d777fd32c14fd9"}, {url = "https://files.pythonhosted.org/packages/6b/2f/1cb3f376df561c95cb61b199676f51251f991699e325a2aa5e12693d10b8/greenlet-2.0.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a1846f1b999e78e13837c93c778dcfc3365902cfb8d1bdb7dd73ead37059f0d0"}, {url = "https://files.pythonhosted.org/packages/6b/cd/84301cdf80360571f6aa77ac096f867ba98094fec2cb93e69c93d996b8f8/greenlet-2.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b0ef99cdbe2b682b9ccbb964743a6aca37905fda5e0452e5ee239b1654d37f2a"}, @@ -2136,6 +2148,10 @@ content_hash = "sha256:300153dd9fcf222cb4b04159e74282c6cadf8242053996f2c7cbc3231 {url = "https://files.pythonhosted.org/packages/31/06/1ef763af20d0572c032fa22882cfbfb005fba6e7300715a37840858c919e/python-dotenv-1.0.0.tar.gz", hash = "sha256:a8df96034aae6d2d50a4ebe8216326c61c3eb64836776504fcca410e5937a3ba"}, {url = "https://files.pythonhosted.org/packages/44/2f/62ea1c8b593f4e093cc1a7768f0d46112107e790c3e478532329e434f00b/python_dotenv-1.0.0-py3-none-any.whl", hash = "sha256:f5971a9226b701070a4bf2c38c89e5a3f0d64de8debda981d1db98583009122a"}, ] +"python-frontmatter 1.0.0" = [ + {url = "https://files.pythonhosted.org/packages/5f/0b/95a67d6efbd26c3de5b05e267ed6dd6f359d761526b618e1395a057ae9fa/python_frontmatter-1.0.0-py3-none-any.whl", hash = "sha256:766ae75f1b301ffc5fe3494339147e0fd80bc3deff3d7590a93991978b579b08"}, + {url = "https://files.pythonhosted.org/packages/dd/17/0614eb78820bd9243ffd1f57c8bd4a86debd644f5a2cef720e07309d307a/python-frontmatter-1.0.0.tar.gz", hash = "sha256:e98152e977225ddafea6f01f40b4b0f1de175766322004c826ca99842d19a7cd"}, +] "python-json-logger 2.0.7" = [ {url = "https://files.pythonhosted.org/packages/35/a6/145655273568ee78a581e734cf35beb9e33a370b29c5d3c8fee3744de29f/python_json_logger-2.0.7-py3-none-any.whl", hash = "sha256:f380b826a991ebbe3de4d897aeec42760035ac760345e57b812938dc8b35e2bd"}, {url = "https://files.pythonhosted.org/packages/4f/da/95963cebfc578dabd323d7263958dfb68898617912bb09327dd30e9c8d13/python-json-logger-2.0.7.tar.gz", hash = "sha256:23e7ec02d34237c5aa1e29a070193a4ea87583bb4e7f8fd06d3de8264c4b2e1c"}, diff --git a/backend/pyproject.toml b/backend/pyproject.toml index 70ff5a70..f97937ad 100644 --- a/backend/pyproject.toml +++ b/backend/pyproject.toml @@ -19,6 +19,7 @@ dependencies = [ "websockets>=10.4", "python-magic>=0.4.27", "transcribee-proto @ file:///${PROJECT_ROOT}/../proto", + "python-frontmatter>=1.0.0", ] requires-python = ">=3.10" readme = "./README.md" diff --git a/backend/transcribee_backend/config.py b/backend/transcribee_backend/config.py index 9a0f15a9..56824764 100644 --- a/backend/transcribee_backend/config.py +++ b/backend/transcribee_backend/config.py @@ -1,8 +1,10 @@ from pathlib import Path -from typing import Dict, List +from typing import Dict, List, Optional -from pydantic import BaseSettings, parse_file_as -from pydantic.main import BaseModel +import frontmatter +from pydantic import BaseModel, BaseSettings, parse_file_as, parse_obj_as + +pages = None class Settings(BaseSettings): @@ -15,6 +17,7 @@ class Settings(BaseSettings): media_url_base = "http://localhost:8000/" model_config_path: Path = Path("data/models.json") + pages_dir: Path = Path("data/pages/") class ModelConfig(BaseModel): @@ -27,10 +30,44 @@ class PublicConfig(BaseModel): models: Dict[str, ModelConfig] +class ShortPageConfig(BaseModel): + name: str + footer_position: Optional[int] + + +class PageConfig(ShortPageConfig): + text: str + + def get_model_config(): return parse_file_as(Dict[str, ModelConfig], settings.model_config_path) +def load_pages_from_disk() -> Dict[str, PageConfig]: + global pages + if pages is None: + pages = {} + if settings.pages_dir.exists(): + for file in settings.pages_dir.glob("*.md"): + page_id = file.stem + page = frontmatter.load(file) + pages[page_id] = PageConfig( + name=page.metadata.get("name", file.stem), + footer_position=page.metadata.get("footer_position"), + text=page.content, + ) + + return pages + + +def get_page_config(): + return load_pages_from_disk() + + +def get_short_page_config() -> Dict[str, ShortPageConfig]: + return parse_obj_as(Dict[str, ShortPageConfig], get_page_config()) + + def get_public_config(): return PublicConfig(models=get_model_config()) diff --git a/backend/transcribee_backend/main.py b/backend/transcribee_backend/main.py index 943126e7..3943fb42 100644 --- a/backend/transcribee_backend/main.py +++ b/backend/transcribee_backend/main.py @@ -8,6 +8,7 @@ from transcribee_backend.helpers.tasks import remove_expired_tokens, timeout_attempts from transcribee_backend.routers.config import config_router from transcribee_backend.routers.document import document_router +from transcribee_backend.routers.page import page_router from transcribee_backend.routers.task import task_router from transcribee_backend.routers.user import user_router @@ -30,6 +31,7 @@ app.include_router(document_router, prefix="/api/v1/documents") app.include_router(task_router, prefix="/api/v1/tasks") app.include_router(config_router, prefix="/api/v1/config") +app.include_router(page_router, prefix="/api/v1/page") @app.get("/") diff --git a/backend/transcribee_backend/routers/page.py b/backend/transcribee_backend/routers/page.py new file mode 100644 index 00000000..0c18e532 --- /dev/null +++ b/backend/transcribee_backend/routers/page.py @@ -0,0 +1,25 @@ +from typing import Dict + +from fastapi import APIRouter, HTTPException + +from transcribee_backend.config import ( + PageConfig, + ShortPageConfig, + get_page_config, + get_short_page_config, +) + +page_router = APIRouter() + + +@page_router.get("/") +def get_pages() -> Dict[str, ShortPageConfig]: + return get_short_page_config() + + +@page_router.get("/{page_id}", responses={404: {"description": "Page not found"}}) +def get_page(page_id: str) -> PageConfig: + pages = get_page_config() + if page_id not in pages: + raise HTTPException(status_code=404) + return pages[page_id] diff --git a/doc/development_setup.md b/doc/development_setup.md index 8a2ead27..ec3f7d3c 100644 --- a/doc/development_setup.md +++ b/doc/development_setup.md @@ -53,6 +53,27 @@ If you do more development on transcribee, you may wish to do the following thin - Install the [`pre-commit`](https://pre-commit.com/) hook so that your changes are automatically linted before you commit them. Run: `pre-commit install` +## Add pages + +`transcribee` contains a minimal page system. +To add pages, add a markdown file to `backend/data/pages`. +If the file contains a frontmatter with the `footer_position` attribute, the page is shown in the footer. +To modify the name shown in the footer, set the `name` attribute in the frontmatter. +Example file named `example.md`: + +```md +--- +footer_position: 1 +name: Example Page +--- + +# Example Page Showing The Page Feature + +Lorem Ipsum Dolor Sit Amet.... +``` + +This page would be available at `/pages/example.md` and shown in the footer with a link labelled `Example Page`. + ## More! There are more specific instructions in the respective readme files of the diff --git a/frontend/.gitignore b/frontend/.gitignore index 3c47994e..ffa3cbb3 100644 --- a/frontend/.gitignore +++ b/frontend/.gitignore @@ -6,3 +6,5 @@ node_modules # typescript *.tsbuildinfo + +public/LICENSES.md diff --git a/frontend/package.json b/frontend/package.json index 65e29512..0e4ae56e 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -3,7 +3,9 @@ "version": "0.1.0", "scripts": { "dev": "vite", - "build": "vite build", + "build": "npm-run-all --continue-on-error build:*", + "build:licenses": "node scripts/generate_licenses.mjs public/LICENSES.md", + "build:vite": "vite build", "preview": "vite preview", "format": "prettier -w 'src/**/*.(ts|tsx)'", "check": "npm-run-all --continue-on-error check:*", @@ -29,6 +31,7 @@ "devDependencies": { "@jest/globals": "^29.5.0", "@tailwindcss/forms": "^0.5.3", + "@tailwindcss/typography": "^0.5.9", "@types/react": "^18.0.28", "@types/react-dom": "^18.0.11", "@types/react-helmet": "^6.1.6", @@ -43,6 +46,7 @@ "favicons": "^7.1.3", "jest": "^29.5.0", "mime-types": "^2.1.35", + "nlf": "^2.1.1", "npm-run-all": "^4.1.5", "openapi-typescript": "^6.2.0", "postcss": "^8.4.21", @@ -69,6 +73,7 @@ "react-icons": "^4.8.0", "react-intersection-observer": "^9.5.2", "react-json-tree": "^0.18.0", + "react-markdown": "^8.0.7", "react-popper": "^2.3.0", "reconnecting-websocket": "^4.4.0", "slate": "^0.94.0", diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index abc7318b..8acb2c08 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -52,6 +52,9 @@ dependencies: react-json-tree: specifier: ^0.18.0 version: 0.18.0(@types/react@18.0.28)(react@18.2.0) + react-markdown: + specifier: ^8.0.7 + version: 8.0.7(@types/react@18.0.28)(react@18.2.0) react-popper: specifier: ^2.3.0 version: 2.3.0(@popperjs/core@2.11.7)(react-dom@18.2.0)(react@18.2.0) @@ -99,6 +102,9 @@ devDependencies: '@tailwindcss/forms': specifier: ^0.5.3 version: 0.5.3(tailwindcss@3.2.7) + '@tailwindcss/typography': + specifier: ^0.5.9 + version: 0.5.9(tailwindcss@3.2.7) '@types/react': specifier: ^18.0.28 version: 18.0.28 @@ -141,6 +147,9 @@ devDependencies: mime-types: specifier: ^2.1.35 version: 2.1.35 + nlf: + specifier: ^2.1.1 + version: 2.1.1 npm-run-all: specifier: ^4.1.5 version: 4.1.5 @@ -1030,6 +1039,11 @@ packages: '@nodelib/fs.scandir': 2.1.5 fastq: 1.15.0 + /@octetstream/promisify@2.0.2: + resolution: {integrity: sha512-7XHoRB61hxsz8lBQrjC1tq/3OEIgpvGWg6DKAdwi7WRzruwkmsdwmOoUXbU4Dtd4RSOMDwed0SkP3y8UlMt1Bg==} + engines: {node: 6.x || >=8.x} + dev: true + /@podlove/html5-audio-driver@2.0.3: resolution: {integrity: sha512-Vo6Uu8USMTcGv9RSXnDs5YDrhYqhy86t0BulOvVWBeoEYfyw/Q502Se9u71tsQN8clCv+9/SQjVYiJAGuHI5/w==} dependencies: @@ -1210,6 +1224,18 @@ packages: tailwindcss: 3.2.7(postcss@8.4.21) dev: true + /@tailwindcss/typography@0.5.9(tailwindcss@3.2.7): + resolution: {integrity: sha512-t8Sg3DyynFysV9f4JDOVISGsjazNb48AeIYQwcL+Bsq5uf4RYL75C1giZ43KISjeDGBaTN3Kxh7Xj/vRSMJUUg==} + peerDependencies: + tailwindcss: '>=3.0.0 || insiders' + dependencies: + lodash.castarray: 4.4.0 + lodash.isplainobject: 4.0.6 + lodash.merge: 4.6.2 + postcss-selector-parser: 6.0.10 + tailwindcss: 3.2.7(postcss@8.4.21) + dev: true + /@types/babel__core@7.20.1: resolution: {integrity: sha512-aACu/U/omhdk15O4Nfb+fHgH/z3QsfQzpnvRZhYhThms83ZnAOZz7zZAWO7mn2yyNQaA4xTO8GLK3uqFU4bYYw==} dependencies: @@ -1247,6 +1273,12 @@ packages: resolution: {integrity: sha512-epMsEE85fi4lfmJUH/89/iV/LI+F5CvNIvmgs5g5jYFPfhO2S/ae8WSsLOKWdwtoaZw9Q2IhJ4tQ5tFCcS/4HA==} dev: true + /@types/debug@4.1.8: + resolution: {integrity: sha512-/vPO1EPOs306Cvhwv7KfVfYvOJqA/S/AXjaHQiJboCZzcNDb+TIJFN9/2C9DZ//ijSKWioNyUxD792QmDJ+HKQ==} + dependencies: + '@types/ms': 0.7.31 + dev: false + /@types/estree@1.0.0: resolution: {integrity: sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==} dev: false @@ -1257,6 +1289,12 @@ packages: '@types/node': 20.2.5 dev: true + /@types/hast@2.3.5: + resolution: {integrity: sha512-SvQi0L/lNpThgPoleH53cdjB3y9zpLlVjRbqB3rH8hx1jiRSBGAhyjV3H+URFjNVRqt2EdYNrbZE5IsGlNfpRg==} + dependencies: + '@types/unist': 2.0.7 + dev: false + /@types/is-hotkey@0.1.7: resolution: {integrity: sha512-yB5C7zcOM7idwYZZ1wKQ3pTfjA9BbvFqRWvKB46GFddxnJtHwi/b9y84ykQtxQPg5qhdpg4Q/kWU3EGoCTmLzQ==} dev: false @@ -1289,6 +1327,16 @@ packages: resolution: {integrity: sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==} dev: false + /@types/mdast@3.0.12: + resolution: {integrity: sha512-DT+iNIRNX884cx0/Q1ja7NyUPpZuv0KPyL5rGNxm1WC1OtHstl7n4Jb7nk+xacNShQMbczJjt8uFzznpp6kYBg==} + dependencies: + '@types/unist': 2.0.7 + dev: false + + /@types/ms@0.7.31: + resolution: {integrity: sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==} + dev: false + /@types/node@20.2.5: resolution: {integrity: sha512-JJulVEQXmiY9Px5axXHeYGLSjhkZEnD+MDPDGbCbIAbMslkKwmygtZFy1X6s/075Yo94sf8GuSlFfPzysQrWZQ==} dev: true @@ -1330,6 +1378,10 @@ packages: resolution: {integrity: sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==} dev: true + /@types/unist@2.0.7: + resolution: {integrity: sha512-cputDpIbFgLUaGQn6Vqg3/YsJwxUwHLO13v3i5ouxT4lat0khip9AEWxtERujXV9wxIB1EyF97BSJFt6vpdI8g==} + dev: false + /@types/wavesurfer.js@6.0.3: resolution: {integrity: sha512-5Sb5s3pEkOmDosaaP1DWp1Unnx8HhVorm5608TIVdT5jCMvJ6eqM19UD8n7DEbJ7rzreS9RqHmzR8TlcdQBvbA==} dependencies: @@ -1554,6 +1606,10 @@ packages: engines: {node: '>=10'} dev: true + /ansicolors@0.3.2: + resolution: {integrity: sha512-QXu7BPrP29VllRxH8GwB7x5iX5qWKAAMLqKQGWTeLWVlNHNOpVMJ91dsxQAIWXpjuW5wqvxu3Jd/nRjrJ+0pqg==} + dev: true + /anymatch@3.1.3: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} @@ -1561,6 +1617,10 @@ packages: normalize-path: 3.0.0 picomatch: 2.3.1 + /archy@1.0.0: + resolution: {integrity: sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==} + dev: true + /arg@5.0.2: resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} @@ -1620,6 +1680,10 @@ packages: get-intrinsic: 1.2.0 dev: true + /asap@2.0.6: + resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} + dev: true + /autoprefixer@10.4.13(postcss@8.4.21): resolution: {integrity: sha512-49vKpMqcZYsJjwotvt4+h/BCjJVnhGwcLpDt5xkcaOG3eLrG/HUYLagrihYsQ+qrIBgIzX1Rw7a6L8I/ZA1Atg==} engines: {node: ^10 || ^12 || >=14} @@ -1717,6 +1781,10 @@ packages: babel-preset-current-node-syntax: 1.0.1(@babel/core@7.22.1) dev: true + /bail@2.0.2: + resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} + dev: false + /balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} dev: true @@ -1847,6 +1915,10 @@ packages: engines: {node: '>=10'} dev: true + /character-entities@2.0.2: + resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} + dev: false + /chokidar@3.5.3: resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} engines: {node: '>= 8.10.0'} @@ -1936,6 +2008,18 @@ packages: color-string: 1.9.1 dev: true + /comma-separated-tokens@2.0.3: + resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} + dev: false + + /commander@2.19.0: + resolution: {integrity: sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==} + dev: true + + /compare-versions@3.4.0: + resolution: {integrity: sha512-tK69D7oNXXqUW3ZNo/z7NXTEz22TCF0pTE+YF9cxvaAM9XnkLo1fV621xCLrRR6aevJlKxExkss0vWqUCUpqdg==} + dev: true + /compute-scroll-into-view@1.0.20: resolution: {integrity: sha512-UCB0ioiyj8CRjtrvaceBLqqhZCVP+1B8+NWQhmdsm0VXOJtobBCf1dBQmebCCo34qZmUwZfIH2MZLqNHazrfjg==} dev: false @@ -1975,6 +2059,7 @@ packages: /cssesc@3.0.0: resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} engines: {node: '>=4'} + hasBin: true /csstype@3.1.1: resolution: {integrity: sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==} @@ -2000,7 +2085,12 @@ packages: optional: true dependencies: ms: 2.1.2 - dev: true + + /decode-named-character-reference@1.0.2: + resolution: {integrity: sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==} + dependencies: + character-entities: 2.0.2 + dev: false /decompress-response@6.0.0: resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} @@ -2038,6 +2128,11 @@ packages: /defined@1.0.1: resolution: {integrity: sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==} + /dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + dev: false + /detect-libc@2.0.1: resolution: {integrity: sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==} engines: {node: '>=8'} @@ -2064,6 +2159,11 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dev: true + /diff@5.1.0: + resolution: {integrity: sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==} + engines: {node: '>=0.3.1'} + dev: false + /dir-glob@3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} @@ -2505,6 +2605,10 @@ packages: jest-util: 29.5.0 dev: true + /extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + dev: false + /fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} dev: true @@ -2674,6 +2778,14 @@ packages: resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} dev: true + /glob-all@3.1.0: + resolution: {integrity: sha512-B61R+opn9HMe8dD170uIn9SP5gGMP+kUmvQXbCZun7h4MB6JKbPAITaR8WU3N2Ry10r/keBCTsz0DE34L+biWg==} + hasBin: true + dependencies: + glob: 7.2.3 + yargs: 1.2.6 + dev: true + /glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -2785,6 +2897,10 @@ packages: dependencies: function-bind: 1.1.1 + /hast-util-whitespace@2.0.1: + resolution: {integrity: sha512-nAxA0v8+vXSBDt3AnRUNjyRIQ0rD+ntpbAp4LnPkumc5M9yUbSMa4XDU9Q6etY4f1Wp4bNgvc1yjiZtsTTrSng==} + dev: false + /hls.js@1.2.8: resolution: {integrity: sha512-vH4b0ATbMEQz7776YBt6kKlRlvuT7RiFfliuxzn6nBlksrEl5HfQxN1Fn5VUNVVt8rws1rKWzpWwXANgCm03rw==} dev: false @@ -2852,6 +2968,10 @@ packages: resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} dev: true + /inline-style-parser@0.1.1: + resolution: {integrity: sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==} + dev: false + /internal-slot@1.0.5: resolution: {integrity: sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==} engines: {node: '>= 0.4'} @@ -2896,6 +3016,11 @@ packages: has-tostringtag: 1.0.0 dev: true + /is-buffer@2.0.5: + resolution: {integrity: sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==} + engines: {node: '>=4'} + dev: false + /is-callable@1.2.7: resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} engines: {node: '>= 0.4'} @@ -2958,6 +3083,11 @@ packages: engines: {node: '>=8'} dev: true + /is-plain-obj@4.1.0: + resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} + engines: {node: '>=12'} + dev: false + /is-plain-object@5.0.0: resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} engines: {node: '>=0.10.0'} @@ -3579,6 +3709,11 @@ packages: engines: {node: '>=6'} dev: true + /kleur@4.1.5: + resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} + engines: {node: '>=6'} + dev: false + /leven@3.1.0: resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} engines: {node: '>=6'} @@ -3624,10 +3759,42 @@ packages: p-locate: 5.0.0 dev: true + /lodash.assign@4.2.0: + resolution: {integrity: sha512-hFuH8TY+Yji7Eja3mGiuAxBqLagejScbG8GbG0j6o9vzn0YL14My+ktnqtZgFTosKymC9/44wP6s7xyuLfnClw==} + dev: true + + /lodash.assignin@4.2.0: + resolution: {integrity: sha512-yX/rx6d/UTVh7sSVWVSIMjfnz95evAgDFdb1ZozC35I9mSFCkmzptOzevxjgbQUsc78NR44LVHWjsoMQXy9FDg==} + dev: true + + /lodash.castarray@4.4.0: + resolution: {integrity: sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==} + dev: true + + /lodash.clone@4.5.0: + resolution: {integrity: sha512-GhrVeweiTD6uTmmn5hV/lzgCQhccwReIVRLHp7LT4SopOjqEZ5BbX8b5WWEtAKasjmy8hR7ZPwsYlxRCku5odg==} + dev: true + + /lodash.clonedeep@4.5.0: + resolution: {integrity: sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==} + dev: true + /lodash.curry@4.1.1: resolution: {integrity: sha512-/u14pXGviLaweY5JI0IUzgzF2J6Ne8INyzAZjImcryjgkZ+ebruBxy2/JaOOkTqScddcYtakjhSaeemV8lR0tA==} dev: false + /lodash.flatten@4.4.0: + resolution: {integrity: sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==} + dev: true + + /lodash.get@4.4.2: + resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==} + dev: true + + /lodash.isplainobject@4.0.6: + resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} + dev: true + /lodash.memoize@4.1.2: resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} dev: true @@ -3636,6 +3803,10 @@ packages: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} dev: true + /lodash.set@4.3.2: + resolution: {integrity: sha512-4hNPN5jlm/N/HLMCO43v8BXKq9Z7QdAGc/VGrRD61w8gN9g/6jF9A4L1pbUgBLCffi0w9VsXfTOij5x8iTyFvg==} + dev: true + /lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} dev: false @@ -3645,6 +3816,13 @@ packages: dependencies: js-tokens: 4.0.0 + /lru-cache@4.1.5: + resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==} + dependencies: + pseudomap: 1.0.2 + yallist: 2.1.2 + dev: true + /lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} dependencies: @@ -3682,6 +3860,52 @@ packages: tmpl: 1.0.5 dev: true + /mdast-util-definitions@5.1.2: + resolution: {integrity: sha512-8SVPMuHqlPME/z3gqVwWY4zVXn8lqKv/pAhC57FuJ40ImXyBpmO5ukh98zB2v7Blql2FiHjHv9LVztSIqjY+MA==} + dependencies: + '@types/mdast': 3.0.12 + '@types/unist': 2.0.7 + unist-util-visit: 4.1.2 + dev: false + + /mdast-util-from-markdown@1.3.1: + resolution: {integrity: sha512-4xTO/M8c82qBcnQc1tgpNtubGUW/Y1tBQ1B0i5CtSoelOLKFYlElIr3bvgREYYO5iRqbMY1YuqZng0GVOI8Qww==} + dependencies: + '@types/mdast': 3.0.12 + '@types/unist': 2.0.7 + decode-named-character-reference: 1.0.2 + mdast-util-to-string: 3.2.0 + micromark: 3.2.0 + micromark-util-decode-numeric-character-reference: 1.1.0 + micromark-util-decode-string: 1.1.0 + micromark-util-normalize-identifier: 1.1.0 + micromark-util-symbol: 1.1.0 + micromark-util-types: 1.1.0 + unist-util-stringify-position: 3.0.3 + uvu: 0.5.6 + transitivePeerDependencies: + - supports-color + dev: false + + /mdast-util-to-hast@12.3.0: + resolution: {integrity: sha512-pits93r8PhnIoU4Vy9bjW39M2jJ6/tdHyja9rrot9uujkN7UTU9SDnE6WNJz/IGyQk3XHX6yNNtrBH6cQzm8Hw==} + dependencies: + '@types/hast': 2.3.5 + '@types/mdast': 3.0.12 + mdast-util-definitions: 5.1.2 + micromark-util-sanitize-uri: 1.2.0 + trim-lines: 3.0.1 + unist-util-generated: 2.0.1 + unist-util-position: 4.0.4 + unist-util-visit: 4.1.2 + dev: false + + /mdast-util-to-string@3.2.0: + resolution: {integrity: sha512-V4Zn/ncyN1QNSqSBxTrMOLpjr+IKdHl2v3KVLoWmDPscP4r9GcCi71gjgvUV1SFSKh92AjAG4peFuBl2/YgCJg==} + dependencies: + '@types/mdast': 3.0.12 + dev: false + /memorystream@0.3.1: resolution: {integrity: sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==} engines: {node: '>= 0.10.0'} @@ -3695,6 +3919,181 @@ packages: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} + /micromark-core-commonmark@1.1.0: + resolution: {integrity: sha512-BgHO1aRbolh2hcrzL2d1La37V0Aoz73ymF8rAcKnohLy93titmv62E0gP8Hrx9PKcKrqCZ1BbLGbP3bEhoXYlw==} + dependencies: + decode-named-character-reference: 1.0.2 + micromark-factory-destination: 1.1.0 + micromark-factory-label: 1.1.0 + micromark-factory-space: 1.1.0 + micromark-factory-title: 1.1.0 + micromark-factory-whitespace: 1.1.0 + micromark-util-character: 1.2.0 + micromark-util-chunked: 1.1.0 + micromark-util-classify-character: 1.1.0 + micromark-util-html-tag-name: 1.2.0 + micromark-util-normalize-identifier: 1.1.0 + micromark-util-resolve-all: 1.1.0 + micromark-util-subtokenize: 1.1.0 + micromark-util-symbol: 1.1.0 + micromark-util-types: 1.1.0 + uvu: 0.5.6 + dev: false + + /micromark-factory-destination@1.1.0: + resolution: {integrity: sha512-XaNDROBgx9SgSChd69pjiGKbV+nfHGDPVYFs5dOoDd7ZnMAE+Cuu91BCpsY8RT2NP9vo/B8pds2VQNCLiu0zhg==} + dependencies: + micromark-util-character: 1.2.0 + micromark-util-symbol: 1.1.0 + micromark-util-types: 1.1.0 + dev: false + + /micromark-factory-label@1.1.0: + resolution: {integrity: sha512-OLtyez4vZo/1NjxGhcpDSbHQ+m0IIGnT8BoPamh+7jVlzLJBH98zzuCoUeMxvM6WsNeh8wx8cKvqLiPHEACn0w==} + dependencies: + micromark-util-character: 1.2.0 + micromark-util-symbol: 1.1.0 + micromark-util-types: 1.1.0 + uvu: 0.5.6 + dev: false + + /micromark-factory-space@1.1.0: + resolution: {integrity: sha512-cRzEj7c0OL4Mw2v6nwzttyOZe8XY/Z8G0rzmWQZTBi/jjwyw/U4uqKtUORXQrR5bAZZnbTI/feRV/R7hc4jQYQ==} + dependencies: + micromark-util-character: 1.2.0 + micromark-util-types: 1.1.0 + dev: false + + /micromark-factory-title@1.1.0: + resolution: {integrity: sha512-J7n9R3vMmgjDOCY8NPw55jiyaQnH5kBdV2/UXCtZIpnHH3P6nHUKaH7XXEYuWwx/xUJcawa8plLBEjMPU24HzQ==} + dependencies: + micromark-factory-space: 1.1.0 + micromark-util-character: 1.2.0 + micromark-util-symbol: 1.1.0 + micromark-util-types: 1.1.0 + dev: false + + /micromark-factory-whitespace@1.1.0: + resolution: {integrity: sha512-v2WlmiymVSp5oMg+1Q0N1Lxmt6pMhIHD457whWM7/GUlEks1hI9xj5w3zbc4uuMKXGisksZk8DzP2UyGbGqNsQ==} + dependencies: + micromark-factory-space: 1.1.0 + micromark-util-character: 1.2.0 + micromark-util-symbol: 1.1.0 + micromark-util-types: 1.1.0 + dev: false + + /micromark-util-character@1.2.0: + resolution: {integrity: sha512-lXraTwcX3yH/vMDaFWCQJP1uIszLVebzUa3ZHdrgxr7KEU/9mL4mVgCpGbyhvNLNlauROiNUq7WN5u7ndbY6xg==} + dependencies: + micromark-util-symbol: 1.1.0 + micromark-util-types: 1.1.0 + dev: false + + /micromark-util-chunked@1.1.0: + resolution: {integrity: sha512-Ye01HXpkZPNcV6FiyoW2fGZDUw4Yc7vT0E9Sad83+bEDiCJ1uXu0S3mr8WLpsz3HaG3x2q0HM6CTuPdcZcluFQ==} + dependencies: + micromark-util-symbol: 1.1.0 + dev: false + + /micromark-util-classify-character@1.1.0: + resolution: {integrity: sha512-SL0wLxtKSnklKSUplok1WQFoGhUdWYKggKUiqhX+Swala+BtptGCu5iPRc+xvzJ4PXE/hwM3FNXsfEVgoZsWbw==} + dependencies: + micromark-util-character: 1.2.0 + micromark-util-symbol: 1.1.0 + micromark-util-types: 1.1.0 + dev: false + + /micromark-util-combine-extensions@1.1.0: + resolution: {integrity: sha512-Q20sp4mfNf9yEqDL50WwuWZHUrCO4fEyeDCnMGmG5Pr0Cz15Uo7KBs6jq+dq0EgX4DPwwrh9m0X+zPV1ypFvUA==} + dependencies: + micromark-util-chunked: 1.1.0 + micromark-util-types: 1.1.0 + dev: false + + /micromark-util-decode-numeric-character-reference@1.1.0: + resolution: {integrity: sha512-m9V0ExGv0jB1OT21mrWcuf4QhP46pH1KkfWy9ZEezqHKAxkj4mPCy3nIH1rkbdMlChLHX531eOrymlwyZIf2iw==} + dependencies: + micromark-util-symbol: 1.1.0 + dev: false + + /micromark-util-decode-string@1.1.0: + resolution: {integrity: sha512-YphLGCK8gM1tG1bd54azwyrQRjCFcmgj2S2GoJDNnh4vYtnL38JS8M4gpxzOPNyHdNEpheyWXCTnnTDY3N+NVQ==} + dependencies: + decode-named-character-reference: 1.0.2 + micromark-util-character: 1.2.0 + micromark-util-decode-numeric-character-reference: 1.1.0 + micromark-util-symbol: 1.1.0 + dev: false + + /micromark-util-encode@1.1.0: + resolution: {integrity: sha512-EuEzTWSTAj9PA5GOAs992GzNh2dGQO52UvAbtSOMvXTxv3Criqb6IOzJUBCmEqrrXSblJIJBbFFv6zPxpreiJw==} + dev: false + + /micromark-util-html-tag-name@1.2.0: + resolution: {integrity: sha512-VTQzcuQgFUD7yYztuQFKXT49KghjtETQ+Wv/zUjGSGBioZnkA4P1XXZPT1FHeJA6RwRXSF47yvJ1tsJdoxwO+Q==} + dev: false + + /micromark-util-normalize-identifier@1.1.0: + resolution: {integrity: sha512-N+w5vhqrBihhjdpM8+5Xsxy71QWqGn7HYNUvch71iV2PM7+E3uWGox1Qp90loa1ephtCxG2ftRV/Conitc6P2Q==} + dependencies: + micromark-util-symbol: 1.1.0 + dev: false + + /micromark-util-resolve-all@1.1.0: + resolution: {integrity: sha512-b/G6BTMSg+bX+xVCshPTPyAu2tmA0E4X98NSR7eIbeC6ycCqCeE7wjfDIgzEbkzdEVJXRtOG4FbEm/uGbCRouA==} + dependencies: + micromark-util-types: 1.1.0 + dev: false + + /micromark-util-sanitize-uri@1.2.0: + resolution: {integrity: sha512-QO4GXv0XZfWey4pYFndLUKEAktKkG5kZTdUNaTAkzbuJxn2tNBOr+QtxR2XpWaMhbImT2dPzyLrPXLlPhph34A==} + dependencies: + micromark-util-character: 1.2.0 + micromark-util-encode: 1.1.0 + micromark-util-symbol: 1.1.0 + dev: false + + /micromark-util-subtokenize@1.1.0: + resolution: {integrity: sha512-kUQHyzRoxvZO2PuLzMt2P/dwVsTiivCK8icYTeR+3WgbuPqfHgPPy7nFKbeqRivBvn/3N3GBiNC+JRTMSxEC7A==} + dependencies: + micromark-util-chunked: 1.1.0 + micromark-util-symbol: 1.1.0 + micromark-util-types: 1.1.0 + uvu: 0.5.6 + dev: false + + /micromark-util-symbol@1.1.0: + resolution: {integrity: sha512-uEjpEYY6KMs1g7QfJ2eX1SQEV+ZT4rUD3UcF6l57acZvLNK7PBZL+ty82Z1qhK1/yXIY4bdx04FKMgR0g4IAag==} + dev: false + + /micromark-util-types@1.1.0: + resolution: {integrity: sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg==} + dev: false + + /micromark@3.2.0: + resolution: {integrity: sha512-uD66tJj54JLYq0De10AhWycZWGQNUvDI55xPgk2sQM5kn1JYlhbCMTtEeT27+vAhW2FBQxLlOmS3pmA7/2z4aA==} + dependencies: + '@types/debug': 4.1.8 + debug: 4.3.4 + decode-named-character-reference: 1.0.2 + micromark-core-commonmark: 1.1.0 + micromark-factory-space: 1.1.0 + micromark-util-character: 1.2.0 + micromark-util-chunked: 1.1.0 + micromark-util-combine-extensions: 1.1.0 + micromark-util-decode-numeric-character-reference: 1.1.0 + micromark-util-encode: 1.1.0 + micromark-util-normalize-identifier: 1.1.0 + micromark-util-resolve-all: 1.1.0 + micromark-util-sanitize-uri: 1.2.0 + micromark-util-subtokenize: 1.1.0 + micromark-util-symbol: 1.1.0 + micromark-util-types: 1.1.0 + uvu: 0.5.6 + transitivePeerDependencies: + - supports-color + dev: false + /micromatch@4.0.5: resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} engines: {node: '>=8.6'} @@ -3734,6 +4133,10 @@ packages: brace-expansion: 1.1.11 dev: true + /minimist@0.1.0: + resolution: {integrity: sha512-wR5Ipl99t0mTGwLjQJnBjrP/O7zBbLZqvA3aw32DmLx+nXHfWctUjzDjnDx09pX1Po86WFQazF9xUzfMea3Cnw==} + dev: true + /minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} @@ -3741,9 +4144,13 @@ packages: resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} dev: true + /mri@1.2.0: + resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} + engines: {node: '>=4'} + dev: false + /ms@2.1.2: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} - dev: true /nanoid@3.3.4: resolution: {integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==} @@ -3765,6 +4172,20 @@ packages: resolution: {integrity: sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==} dev: true + /nlf@2.1.1: + resolution: {integrity: sha512-ysGGIax/WydhF78a5k//FPMt9tVDVLsnuSZqxwuzIfc5waKKc0Y/jz082a81aAayrP1QQNQm5ck+5Kv+jlbU6Q==} + engines: {node: '>=4'} + hasBin: true + dependencies: + archy: 1.0.0 + commander: 2.19.0 + compare-versions: 3.4.0 + glob-all: 3.1.0 + snyk-resolve-deps: 4.0.2 + transitivePeerDependencies: + - supports-color + dev: true + /node-abi@3.45.0: resolution: {integrity: sha512-iwXuFrMAcFVi/ZoZiqq8BzAdsLw9kxDfTC0HMyjXfSL/6CSDAGD5UmR7azrAgWV1zKYq7dUUMj4owusBWKLsiQ==} engines: {node: '>=10'} @@ -4092,6 +4513,14 @@ packages: postcss: 8.4.21 postcss-selector-parser: 6.0.11 + /postcss-selector-parser@6.0.10: + resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==} + engines: {node: '>=4'} + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + dev: true + /postcss-selector-parser@6.0.11: resolution: {integrity: sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==} engines: {node: '>=4'} @@ -4154,6 +4583,19 @@ packages: react-is: 18.2.0 dev: true + /promise-fs@2.1.1: + resolution: {integrity: sha512-43p7e4QzAQ3w6eyN0+gbBL7jXiZFWLWYITg9wIObqkBySu/a5K1EDcQ/S6UyB/bmiZWDA4NjTbcopKLTaKcGSw==} + engines: {node: '>=6'} + dependencies: + '@octetstream/promisify': 2.0.2 + dev: true + + /promise@7.3.1: + resolution: {integrity: sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==} + dependencies: + asap: 2.0.6 + dev: true + /prompts@2.4.2: resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} engines: {node: '>= 6'} @@ -4169,6 +4611,14 @@ packages: object-assign: 4.1.1 react-is: 16.13.1 + /property-information@6.2.0: + resolution: {integrity: sha512-kma4U7AFCTwpqq5twzC1YVIDXSqg6qQK6JN0smOw8fgRy1OkMi0CYSzFmsy6dnqSenamAtj0CyXMUJ1Mf6oROg==} + dev: false + + /pseudomap@1.0.2: + resolution: {integrity: sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==} + dev: true + /pump@3.0.0: resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} dependencies: @@ -4278,7 +4728,6 @@ packages: /react-is@18.2.0: resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} - dev: true /react-json-tree@0.18.0(@types/react@18.0.28)(react@18.2.0): resolution: {integrity: sha512-Qe6HKSXrr++n9Y31nkRJ3XvQMATISpqigH1vEKhLwB56+nk5thTP0ITThpjxY6ZG/ubpVq/aEHIcyLP/OPHxeA==} @@ -4293,6 +4742,33 @@ packages: react-base16-styling: 0.9.1 dev: false + /react-markdown@8.0.7(@types/react@18.0.28)(react@18.2.0): + resolution: {integrity: sha512-bvWbzG4MtOU62XqBx3Xx+zB2raaFFsq4mYiAzfjXJMEz2sixgeAfraA3tvzULF02ZdOMUOKTBFFaZJDDrq+BJQ==} + peerDependencies: + '@types/react': '>=16' + react: '>=16' + dependencies: + '@types/hast': 2.3.5 + '@types/prop-types': 15.7.5 + '@types/react': 18.0.28 + '@types/unist': 2.0.7 + comma-separated-tokens: 2.0.3 + hast-util-whitespace: 2.0.1 + prop-types: 15.8.1 + property-information: 6.2.0 + react: 18.2.0 + react-is: 18.2.0 + remark-parse: 10.0.2 + remark-rehype: 10.1.0 + space-separated-tokens: 2.0.2 + style-to-object: 0.4.2 + unified: 10.1.2 + unist-util-visit: 4.1.2 + vfile: 5.3.7 + transitivePeerDependencies: + - supports-color + dev: false + /react-popper@2.3.0(@popperjs/core@2.11.7)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-e1hj8lL3uM+sgSR4Lxzn5h1GxBlpa4CQz0XLF8kx4MDrDRWY0Ena4c97PUeSX9i5W3UAfDP0z0FXCTQkoXUl3Q==} peerDependencies: @@ -4373,6 +4849,25 @@ packages: engines: {node: '>=8'} dev: true + /remark-parse@10.0.2: + resolution: {integrity: sha512-3ydxgHa/ZQzG8LvC7jTXccARYDcRld3VfcgIIFs7bI6vbRSxJJmzgLEIIoYKyrfhaY+ujuWaf/PJiMZXoiCXgw==} + dependencies: + '@types/mdast': 3.0.12 + mdast-util-from-markdown: 1.3.1 + unified: 10.1.2 + transitivePeerDependencies: + - supports-color + dev: false + + /remark-rehype@10.1.0: + resolution: {integrity: sha512-EFmR5zppdBp0WQeDVZ/b66CWJipB2q2VLNFMabzDSGR66Z2fQii83G5gTBbgGEnEEA0QRussvrFHxk1HWGJskw==} + dependencies: + '@types/hast': 2.3.5 + '@types/mdast': 3.0.12 + mdast-util-to-hast: 12.3.0 + unified: 10.1.2 + dev: false + /require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} @@ -4436,6 +4931,13 @@ packages: dependencies: queue-microtask: 1.2.3 + /sade@1.8.1: + resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} + engines: {node: '>=6'} + dependencies: + mri: 1.2.0 + dev: false + /safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} dev: true @@ -4607,6 +5109,64 @@ packages: tiny-warning: 1.0.3 dev: false + /snyk-module@1.9.1: + resolution: {integrity: sha512-A+CCyBSa4IKok5uEhqT+hV/35RO6APFNLqk9DRRHg7xW2/j//nPX8wTSZUPF8QeRNEk/sX+6df7M1y6PBHGSHA==} + dependencies: + debug: 3.2.7 + hosted-git-info: 2.8.9 + transitivePeerDependencies: + - supports-color + dev: true + + /snyk-resolve-deps@4.0.2: + resolution: {integrity: sha512-nlw62wiWhGOTw3BD3jVIwrUkRR4iNxEkkO4Y/PWs8BsUWseGu1H6QgLesFXJb3qx7ANJ5UbUCJMgV+eL0Lf9cA==} + dependencies: + ansicolors: 0.3.2 + debug: 3.2.7 + lodash.assign: 4.2.0 + lodash.assignin: 4.2.0 + lodash.clone: 4.5.0 + lodash.flatten: 4.4.0 + lodash.get: 4.4.2 + lodash.set: 4.3.2 + lru-cache: 4.1.5 + semver: 5.7.1 + snyk-module: 1.9.1 + snyk-resolve: 1.1.0 + snyk-tree: 1.0.0 + snyk-try-require: 1.3.1 + then-fs: 2.0.0 + transitivePeerDependencies: + - supports-color + dev: true + + /snyk-resolve@1.1.0: + resolution: {integrity: sha512-OZMF8I8TOu0S58Z/OS9mr8jkEzGAPByCsAkrWlcmZgPaE0RsxVKVIFPhbMNy/JlYswgGDYYIEsNw+e0j1FnTrw==} + dependencies: + debug: 4.3.4 + promise-fs: 2.1.1 + transitivePeerDependencies: + - supports-color + dev: true + + /snyk-tree@1.0.0: + resolution: {integrity: sha512-JQezX6eaVi0uNctPcx2Uzy5KA9lpTRRe31n8NI71DIseGvI6OVCfuKjzFptE06h4ZISMey351ICXnHBadBtWdg==} + hasBin: true + dependencies: + archy: 1.0.0 + dev: true + + /snyk-try-require@1.3.1: + resolution: {integrity: sha512-adCnpfCvigiarbADOHuqh82P4aQUlyq6nWzhVmEUly62Q3tnVg4BGtgjYISkaj9GGBmpgVZiJegENBpQr02NsQ==} + dependencies: + debug: 3.2.7 + lodash.clonedeep: 4.5.0 + lru-cache: 4.1.5 + then-fs: 2.0.0 + transitivePeerDependencies: + - supports-color + dev: true + /source-map-js@1.0.2: resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} engines: {node: '>=0.10.0'} @@ -4623,6 +5183,10 @@ packages: engines: {node: '>=0.10.0'} dev: true + /space-separated-tokens@2.0.2: + resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} + dev: false + /spdx-correct@3.1.1: resolution: {integrity: sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==} dependencies: @@ -4761,6 +5325,12 @@ packages: engines: {node: '>=8'} dev: true + /style-to-object@0.4.2: + resolution: {integrity: sha512-1JGpfPB3lo42ZX8cuPrheZbfQ6kqPPnPHlKMyeRYtfKD+0jG+QsXgXN57O/dvJlzlB2elI6dGmrPnl5VPQFPaA==} + dependencies: + inline-style-parser: 0.1.1 + dev: false + /supports-color@5.5.0: resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} engines: {node: '>=4'} @@ -4883,6 +5453,12 @@ packages: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} dev: true + /then-fs@2.0.0: + resolution: {integrity: sha512-5ffcBcU+vFUCYDNi/o507IqjqrTkuGsLVZ1Fp50hwgZRY7ufVFa9jFfTy5uZ2QnSKacKigWKeaXkOqLa4DsjLw==} + dependencies: + promise: 7.3.1 + dev: true + /tiny-invariant@1.0.6: resolution: {integrity: sha512-FOyLWWVjG+aC0UqG76V53yAWdXfH8bO6FNmyZOuUrzDzK8DI3/JRY25UD7+g49JWM1LXwymsKERB+DzI0dTEQA==} dev: false @@ -4906,6 +5482,14 @@ packages: dependencies: is-number: 7.0.0 + /trim-lines@3.0.1: + resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} + dev: false + + /trough@2.1.0: + resolution: {integrity: sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==} + dev: false + /ts-jest@29.1.0(jest@29.5.0)(typescript@5.1.6): resolution: {integrity: sha512-ZhNr7Z4PcYa+JjMl62ir+zPiNJfXJN6E8hSLnaUKhOgqcn8vb3e537cpkd0FuAfRK3sR1LSqM1MOhliXNgOFPA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -5020,6 +5604,55 @@ packages: busboy: 1.6.0 dev: true + /unified@10.1.2: + resolution: {integrity: sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==} + dependencies: + '@types/unist': 2.0.7 + bail: 2.0.2 + extend: 3.0.2 + is-buffer: 2.0.5 + is-plain-obj: 4.1.0 + trough: 2.1.0 + vfile: 5.3.7 + dev: false + + /unist-util-generated@2.0.1: + resolution: {integrity: sha512-qF72kLmPxAw0oN2fwpWIqbXAVyEqUzDHMsbtPvOudIlUzXYFIeQIuxXQCRCFh22B7cixvU0MG7m3MW8FTq/S+A==} + dev: false + + /unist-util-is@5.2.1: + resolution: {integrity: sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw==} + dependencies: + '@types/unist': 2.0.7 + dev: false + + /unist-util-position@4.0.4: + resolution: {integrity: sha512-kUBE91efOWfIVBo8xzh/uZQ7p9ffYRtUbMRZBNFYwf0RK8koUMx6dGUfwylLOKmaT2cs4wSW96QoYUSXAyEtpg==} + dependencies: + '@types/unist': 2.0.7 + dev: false + + /unist-util-stringify-position@3.0.3: + resolution: {integrity: sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==} + dependencies: + '@types/unist': 2.0.7 + dev: false + + /unist-util-visit-parents@5.1.3: + resolution: {integrity: sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg==} + dependencies: + '@types/unist': 2.0.7 + unist-util-is: 5.2.1 + dev: false + + /unist-util-visit@4.1.2: + resolution: {integrity: sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg==} + dependencies: + '@types/unist': 2.0.7 + unist-util-is: 5.2.1 + unist-util-visit-parents: 5.1.3 + dev: false + /update-browserslist-db@1.0.10(browserslist@4.21.5): resolution: {integrity: sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==} hasBin: true @@ -5052,6 +5685,17 @@ packages: resolution: {integrity: sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==} dev: false + /uvu@0.5.6: + resolution: {integrity: sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA==} + engines: {node: '>=8'} + hasBin: true + dependencies: + dequal: 2.0.3 + diff: 5.1.0 + kleur: 4.1.5 + sade: 1.8.1 + dev: false + /v8-to-istanbul@9.1.0: resolution: {integrity: sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==} engines: {node: '>=10.12.0'} @@ -5068,6 +5712,22 @@ packages: spdx-expression-parse: 3.0.1 dev: true + /vfile-message@3.1.4: + resolution: {integrity: sha512-fa0Z6P8HUrQN4BZaX05SIVXic+7kE3b05PWAtPuYP9QLHsLKYR7/AlLW3NtOrpXRLeawpDLMsVkmk5DG0NXgWw==} + dependencies: + '@types/unist': 2.0.7 + unist-util-stringify-position: 3.0.3 + dev: false + + /vfile@5.3.7: + resolution: {integrity: sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g==} + dependencies: + '@types/unist': 2.0.7 + is-buffer: 2.0.5 + unist-util-stringify-position: 3.0.3 + vfile-message: 3.1.4 + dev: false + /vite-plugin-top-level-await@1.3.0(vite@4.1.4): resolution: {integrity: sha512-owIfsgWudMlQODWJSwp0sQB3AZZu3qsMygeBjZy8CyjEk6OB9AGd8lHqmgwrcEqgvy9N58lYxSBLVk3/4ejEiA==} peerDependencies: @@ -5240,6 +5900,10 @@ packages: engines: {node: '>=10'} dev: true + /yallist@2.1.2: + resolution: {integrity: sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==} + dev: true + /yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} dev: true @@ -5257,6 +5921,12 @@ packages: engines: {node: '>=12'} dev: true + /yargs@1.2.6: + resolution: {integrity: sha512-wwBCGnWIeR7M6d7Wmd4NT48TI8jEzRXFzmYGTNpsHZZ9Uu13vj+p6EawS7kGrzBvkX6rF7vYjUrQnwEOI7QOIw==} + dependencies: + minimist: 0.1.0 + dev: true + /yargs@17.7.2: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} diff --git a/frontend/public/.gitkeep b/frontend/public/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/frontend/scripts/generate_licenses.mjs b/frontend/scripts/generate_licenses.mjs new file mode 100755 index 00000000..8b762988 --- /dev/null +++ b/frontend/scripts/generate_licenses.mjs @@ -0,0 +1,50 @@ +import nlf from 'nlf'; +import fs from 'fs'; + +const args = process.argv.slice(2); + +if (args.length < 1 || args.length > 2) { + console.log(`USAGE: ${process.argv[0]} ${process.argv[1]} OUTPUT_FILE [PREAMBLE_FILE]`); + process.exit(-1); +} + +nlf.find({}, function (err, data) { + const license_parts = []; + if (args[1]) { + license_parts.push(fs.readFileSync(args[1])); + } + for (const item of data) { + if (item.name === 'transcribee') { + continue; + } + license_parts.push(`# ${item.name} License`); + + const licenses = item.licenseSources.package.sources + .map((lic) => { + if (lic.url && lic.url !== '(none)') { + return `[${lic.license}](${lic.url})`; + } else { + return lic.license; + } + }) + .join(', '); + + let name; + if (item.repository && item.repository !== '(none)') { + name = `[${item.name}](${item.repository})`; + } else { + name = item.name; + } + + license_parts.push( + `This product contains the ${name} javascript package (Version ${item.version}), which is licensed under the following licenses: ${licenses}`, + ); + + const source_texts = item.licenseSources.license.sources.map( + (item) => `\`\`\`\n${item.text}\`\`\``, + ); + license_parts.push(...source_texts); + } + const total = license_parts.join('\n\n'); + fs.writeFileSync(args[0], total); +}); diff --git a/frontend/src/api.ts b/frontend/src/api.ts index e6549f03..01b27ce4 100644 --- a/frontend/src/api.ts +++ b/frontend/src/api.ts @@ -1,6 +1,7 @@ import { paths } from './openapi-schema'; import { ApiResponse, Fetcher, Middleware } from 'openapi-typescript-fetch'; import useSwr, { SWRConfiguration } from 'swr'; +import { defaultConfig } from 'swr/_internal'; export function getShareToken(): string | null { return new URL(location.href).searchParams.get('share_token'); @@ -54,3 +55,18 @@ export function makeSwrHook( options, ); } + +export function makeRetrySwrHook( + id: string, + fn: (params: P, req?: RequestInit | undefined) => Promise>, +) { + const swrHook = makeSwrHook(id, fn); + return (params: Parameters[0], options?: Partial) => + swrHook(params, { + onErrorRetry: (err, key, config, revalidate, opts) => { + if (err.status === 422) return; + else defaultConfig.onErrorRetry(err, key, config, revalidate, opts); + }, + ...options, + }); +} diff --git a/frontend/src/api/pages.ts b/frontend/src/api/pages.ts new file mode 100644 index 00000000..83a381d9 --- /dev/null +++ b/frontend/src/api/pages.ts @@ -0,0 +1,7 @@ +import { fetcher, makeRetrySwrHook } from '../api'; + +export const getPages = fetcher.path('/api/v1/page/').method('get').create(); +export const getPage = fetcher.path('/api/v1/page/{page_id}').method('get').create(); + +export const useGetPages = makeRetrySwrHook('getPages', getPages); +export const useGetPage = makeRetrySwrHook('getPage', getPage); diff --git a/frontend/src/app.tsx b/frontend/src/app.tsx index d7f3174a..50a786b1 100644 --- a/frontend/src/app.tsx +++ b/frontend/src/app.tsx @@ -11,16 +11,20 @@ import { Helmet } from 'react-helmet'; import { registerCopyHandler } from './utils/copy_text'; import { useAuthData } from './utils/auth'; import { LoadingPage } from './pages/loading'; +import { PagePage } from './pages/page'; +import { AboutPage } from './pages/about'; registerCopyHandler(); +const LOCATIONS_WIHTOUT_AUTH = ['/about']; + export function App() { const routerBase = trimTrailingSlash(import.meta.env.BASE_URL); - const [_location, navigate] = useLocation(); + const [location, navigate] = useLocation(); const { isLoading, isLoggedIn, hasShareToken } = useAuthData(); const isAuthenticated = isLoggedIn || hasShareToken; - if (!isAuthenticated && !isLoading) { + if (!isAuthenticated && !isLoading && !LOCATIONS_WIHTOUT_AUTH.includes(location)) { setTimeout(() => navigate('/login'), 0); } @@ -30,6 +34,8 @@ export function App() { + + {isLoggedIn && ( <> diff --git a/frontend/src/common/footer.tsx b/frontend/src/common/footer.tsx new file mode 100644 index 00000000..b929f21b --- /dev/null +++ b/frontend/src/common/footer.tsx @@ -0,0 +1,182 @@ +import { Tooltip } from '../components/tooltip'; +import './footer'; +// eslint-disable-next-line import/no-unresolved +import version, { Commit } from 'virtual:git-version'; +import { IoMdOpen } from 'react-icons/io'; +import clsx from 'clsx'; +import { Link } from 'wouter'; +import { useGetPages } from '../api/pages'; +import { primitiveWithClassname } from '../styled'; + +function formatDate(date?: string): string { + return date + ? new Date(date).toLocaleString(undefined, { dateStyle: 'short', timeStyle: 'short' }) + : 'UNKNOWN DATE'; +} + +export function CommitPopup({ commit, text }: { commit: Commit; text: string }) { + return ( + + Last commit{' '} + + {commit?.hash?.substring(0, 10)} + {' '} + on {formatDate(commit.date)}. + + } + > + {text} + + ); +} + +export function ShortVersion() { + const lastCommit = version?.lastCommit; + + return ( + <> + Version:{' '} + {lastCommit?.hash && ( + + {lastCommit.hash.substring(0, 10)} + + )}{' '} + ({lastCommit?.countSinceStart || 'unknown'}) + + ); +} + +export function LongVersion() { + return ( + <> + Frontend built on {formatDate(version?.date)}. + {version?.lastCommitOnMain?.countSinceStart ? ( + <> + {' '} + + {version?.branch != 'main' && + version.lastCommit && + version.lastCommit?.countSinceStart && + version.lastCommitOnMain?.countSinceStart && ( + <> + {' '} + +{' '} + + + )} + {version.diffShort && <> + {version.diffShort}} + + ) : ( + version?.lastCommit?.hash && ( + <> + {' '} + Last commit{' '} + {version.lastCommit?.hash && ( + + {version.lastCommit.hash.substring(0, 10)} + + )}{' '} + on {formatDate(version.lastCommit?.date)}. + + ) + )} + + ); +} + +function useFooterPages() { + const { data: pages } = useGetPages({}); + if (pages === undefined) { + return []; + } + return Object.entries(pages) + .map(([k, v]) => ({ id: k, ...v })) + .filter( + (x): x is typeof x & { footer_position: number } => + x.footer_position !== null && x.footer_position !== undefined, + ) + .sort((a, b) => { + if (a.footer_position > b.footer_position) return 1; + if (a.footer_position < b.footer_position) return -1; + return 0; + }); +} + +export function FooterPages() { + const pages = useFooterPages(); + + return ( + <> + {pages.map((x) => ( + + + {x.name} + + + ))} + + ); +} + +const PipeListItem = primitiveWithClassname('li', [ + 'inline py-0 px-2 border-l-[1px] border-inherit', + 'first:border-l-0', +]); + +export function Footer({ className = '' }: { className?: string }) { + return ( +
+
    + + + + + + About + + + +
+
+ ); +} diff --git a/frontend/src/common/version.tsx b/frontend/src/common/version.tsx deleted file mode 100644 index 357cfd08..00000000 --- a/frontend/src/common/version.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import { Tooltip } from '../components/tooltip'; -import './version'; -// eslint-disable-next-line import/no-unresolved -import version, { Commit } from 'virtual:git-version'; -import { IoMdOpen } from 'react-icons/io'; -import clsx from 'clsx'; - -function formatDate(date?: string): string { - return date - ? new Date(date).toLocaleString('de-DE', { dateStyle: 'short', timeStyle: 'short' }) - : 'UNKNOWN DATE'; -} - -export function CommitPopup({ commit, text }: { commit: Commit; text: string }) { - return ( - - Last commit{' '} - - {commit?.hash?.substring(0, 10)} - {' '} - on {formatDate(commit.date)}. - - } - > - {text} - - ); -} - -export function Version({ className = '' }: { className?: string }) { - const lastCommit = version?.lastCommit; - - return ( -
-
- Frontend built on {formatDate(version?.date)}. Last commit{' '} - {lastCommit?.hash && ( - - {lastCommit.hash.substring(0, 10)} - - )}{' '} - on {formatDate(lastCommit?.date)}. -
-
- ); -} diff --git a/frontend/src/common/virtual:git-version.d.ts b/frontend/src/common/virtual:git-version.d.ts index 70471451..11333011 100644 --- a/frontend/src/common/virtual:git-version.d.ts +++ b/frontend/src/common/virtual:git-version.d.ts @@ -9,6 +9,7 @@ declare module 'virtual:git-version' { branch?: string; diffShort?: string; lastCommit?: Commit; + lastCommitOnMain?: Commit; date?: string; } diff --git a/frontend/src/components/app.tsx b/frontend/src/components/app.tsx index af495c78..7e950840 100644 --- a/frontend/src/components/app.tsx +++ b/frontend/src/components/app.tsx @@ -1,5 +1,5 @@ import clsx from 'clsx'; -import { Version } from '../common/version'; +import { Footer } from '../common/footer'; export function AppContainer({ children, @@ -13,7 +13,7 @@ export function AppContainer({ className={clsx('min-h-screen max-w-screen-xl p-6 mx-auto flex flex-col', className)} >
{children}
- +