From 1c96feeb4f11c6c47507f807b305aa5936d0d49c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niccol=C3=B2=20Cant=C3=B9?= Date: Fri, 18 Oct 2024 09:05:10 +0200 Subject: [PATCH 01/24] explicit upstream in the variable name --- nginx/default.conf.template | 6 +++--- nginx/maps.conf.template | 25 ++++++++++--------------- 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/nginx/default.conf.template b/nginx/default.conf.template index e03b588..5173715 100644 --- a/nginx/default.conf.template +++ b/nginx/default.conf.template @@ -3,7 +3,7 @@ map $http_upgrade $connection_upgrade { '' close; } -upstream django { +upstream django_upstream { server django:8000; keepalive 64; } @@ -48,7 +48,7 @@ server { } location @proxy { - proxy_pass http://django; + proxy_pass http://django_upstream; proxy_http_version 1.1; proxy_set_header Host $http_host; proxy_set_header Upgrade $http_upgrade; @@ -62,7 +62,7 @@ server { client_body_buffer_size 8000M; client_body_timeout 360; - proxy_pass http://django; + proxy_pass http://django_upstream; proxy_http_version 1.1; proxy_set_header Host $http_host; proxy_set_header Upgrade $http_upgrade; diff --git a/nginx/maps.conf.template b/nginx/maps.conf.template index d9b33c6..55557c3 100644 --- a/nginx/maps.conf.template +++ b/nginx/maps.conf.template @@ -3,17 +3,17 @@ map $http_upgrade $connection_upgrade { '' close; } -upstream django { +upstream django_upstream { server django:8000; keepalive 64; } -upstream maps { +upstream maps_upstream { server maps:80; keepalive 64; } -upstream titiler { +upstream titiler_upstream { server titiler:80; keepalive 64; } @@ -42,6 +42,8 @@ server { proxy_set_header X-NginX-Proxy true; proxy_set_header Cookie $http_cookie; proxy_redirect off; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $connection_upgrade; location /static/ { alias /statics/; @@ -59,19 +61,15 @@ server { } location @proxy { - proxy_pass http://django; + proxy_pass http://django_upstream; proxy_http_version 1.1; proxy_set_header Host $http_host; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection $connection_upgrade; } location /titiler/ { - proxy_pass http://titiler; + proxy_pass http://titiler_upstream; proxy_http_version 1.1; proxy_set_header Host $http_host; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection $connection_upgrade; } location /admin/ { @@ -81,11 +79,9 @@ server { client_body_buffer_size 8000M; client_body_timeout 360; - proxy_pass http://django; + proxy_pass http://django_upstream; proxy_http_version 1.1; proxy_set_header Host $http_host; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection $connection_upgrade; } location /api/ { @@ -95,7 +91,7 @@ server { client_body_buffer_size 8000M; client_body_timeout 360; - proxy_pass http://django; + proxy_pass http://django_upstream; proxy_http_version 1.1; proxy_set_header Host $http_host; proxy_set_header Upgrade $http_upgrade; @@ -103,9 +99,8 @@ server { } location / { - proxy_pass http://maps; + proxy_pass http://maps_upstream; proxy_http_version 1.1; - proxy_set_header Host $http_host; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; } From ea850591919cf5d20733e31bceff8dfedff67eed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niccol=C3=B2=20Cant=C3=B9?= Date: Fri, 18 Oct 2024 09:05:26 +0200 Subject: [PATCH 02/24] fix casing warnings in docker --- Dockerfile | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Dockerfile b/Dockerfile index edb9e5a..44c021a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,30 +1,30 @@ -FROM registry.opensuse.org/opensuse/leap:latest as base +FROM registry.opensuse.org/opensuse/leap:latest AS base RUN --mount=type=cache,target=/var/cache/zypper \ zypper install --no-recommends -y python311 gdal proj WORKDIR /app ENV PYTHONPATH=/app/.venv/lib ENV PATH=$PATH:/app/.venv/bin -FROM scratch as source +FROM scratch AS source WORKDIR /app COPY config config COPY metadata_catalogue metadata_catalogue COPY manage.py . -FROM base as pdm +FROM base AS pdm RUN --mount=type=cache,target=/var/cache/zypper \ zypper install --no-recommends -y python311-pip git RUN python3.11 -m pip install pdm COPY ./pyproject.toml ./pdm.lock . -FROM pdm as production +FROM pdm AS production RUN --mount=type=cache,target=/var/cache/zypper \ zypper install --no-recommends -y gdal-devel gcc gcc-c++ python311-devel RUN pdm add gdal==$(rpm -q --queryformat='%{VERSION}' gdal) RUN --mount=type=cache,target=/root/.cache/pdm \ pdm install -G production -FROM pdm as translation +FROM pdm AS translation RUN --mount=type=cache,target=/var/cache/zypper \ zypper install --no-recommends -y gettext-tools COPY --from=production /app/.venv .venv @@ -34,7 +34,7 @@ RUN DATABASE_URL="" DJANGO_BASE_SCHEMA_URL="" \ DJANGO_SETTINGS_MODULE="config.settings.test" \ pdm run ./manage.py compilemessages -FROM base as django +FROM base AS django COPY --from=production /app . COPY --from=translation /app/locale locale COPY --from=source /app . @@ -42,7 +42,7 @@ RUN mkdir media COPY entrypoint.sh . ENTRYPOINT ["./entrypoint.sh"] -FROM pdm as dev +FROM pdm AS dev COPY --from=django /app/.venv .venv RUN --mount=type=cache,target=/root/.cache/pdm \ pdm install --dev From b7580812048bef681c7469566f147f825901bf71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niccol=C3=B2=20Cant=C3=B9?= Date: Fri, 18 Oct 2024 09:07:06 +0200 Subject: [PATCH 03/24] update project meta --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 1716398..f98155b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -176,8 +176,8 @@ dependencies = [ "django-filter>=24.2", ] requires-python = ">=3.10" -name = "" -version = "" +name = "nina-catalogue" +version = "0.1.0" description = "" authors = [ {name = "Niccolò Cantù", email = "niccolo.cantu@nina.no"}, From eae8a8242a2aaa04919e21aa93d0e5bfab6c986d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niccol=C3=B2=20Cant=C3=B9?= Date: Fri, 18 Oct 2024 11:53:29 +0200 Subject: [PATCH 04/24] fix docker warnings --- bruno/Dockerfile | 4 ++-- docs/Dockerfile | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/bruno/Dockerfile b/bruno/Dockerfile index 5887492..703d8bd 100644 --- a/bruno/Dockerfile +++ b/bruno/Dockerfile @@ -1,8 +1,8 @@ -FROM node:18-bookworm as base +FROM node:18-bookworm AS base RUN npm install -g @usebruno/cli WORKDIR /app -FROM base as deps +FROM base AS deps COPY ./bruno/catalogue/package.json . RUN npm install diff --git a/docs/Dockerfile b/docs/Dockerfile index ac3dacb..d08813f 100644 --- a/docs/Dockerfile +++ b/docs/Dockerfile @@ -1,7 +1,7 @@ FROM rust:1.74-slim-bookworm AS base -FROM base as builder +FROM base AS builder RUN apt-get update && \ apt-get install --no-install-recommends -y \ musl-tools @@ -11,7 +11,7 @@ ARG MDBOOK_VERSION=0.4.36 RUN cargo install mdbook --version "${MDBOOK_VERSION}" --target "${ARC}" -FROM base as dev +FROM base AS dev RUN apt-get update && \ apt-get install --no-install-recommends -y \ musl-tools libssl-dev pkg-config @@ -21,7 +21,7 @@ WORKDIR /book ENTRYPOINT [ "/usr/local/bin/mdbook" ] -FROM dev as build +FROM dev AS build ARG KROKI_ENDPOINT="https://kroki.io/" ENV MDBOOK_PREPROCESSOR__KROKI_PREPROCESSOR__ENDPOINT="${KROKI_ENDPOINT}" COPY src src @@ -30,6 +30,6 @@ COPY book.toml . RUN mdbook build -FROM nginx as prod +FROM nginx AS prod COPY --from=build /book/book/ /var/www/ COPY default.conf.template /etc/nginx/templates/ From ca6bf1462e91e6b67e4257788dd99d4262723883 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niccol=C3=B2=20Cant=C3=B9?= Date: Fri, 18 Oct 2024 13:58:50 +0200 Subject: [PATCH 05/24] add basic ui setup and templates --- .pre-commit-config.yaml | 18 +- Dockerfile | 18 +- config/settings/base.py | 48 +- config/settings/local.py | 21 +- config/settings/test.py | 8 +- config/urls.py | 11 +- docker-compose.yml | 13 +- entrypoint.sh | 7 + .../core/templates/core/app.html | 1 + .../core/templates/core/base.html | 68 + .../templates/core/partials/navigation.html | 20 + .../core/partials/user-dropdown.html | 49 + metadata_catalogue/static/images/logo.png | Bin 0 -> 2974 bytes .../templates/account/account_inactive.html | 11 - .../templates/account/base.html | 14 - .../templates/account/email.html | 78 - .../templates/account/email_confirm.html | 27 - .../templates/account/login.html | 32 - .../templates/account/logout.html | 20 - .../templates/account/password_change.html | 18 - .../templates/account/password_reset.html | 28 - .../account/password_reset_done.html | 17 - .../account/password_reset_from_key.html | 36 - .../account/password_reset_from_key_done.html | 11 - .../templates/account/password_set.html | 21 - .../templates/account/signup.html | 27 - .../templates/account/signup_closed.html | 11 - .../templates/account/verification_sent.html | 13 - .../account/verified_email_required.html | 24 - metadata_catalogue/templates/app.html | 1 + metadata_catalogue/templates/base.html | 130 +- metadata_catalogue/templates/components.yaml | 2 + .../templates/components/action-button.html | 9 + .../templates/core/partials/navigation.html | 20 + metadata_catalogue/templates/pages/about.html | 2 +- metadata_catalogue/templates/pages/home.html | 4 +- metadata_catalogue/theme/__init__.py | 0 metadata_catalogue/theme/apps.py | 5 + .../theme/static_src/.gitignore | 1 + .../theme/static_src/package-lock.json | 1578 +++++++++++++++++ .../theme/static_src/package.json | 29 + .../theme/static_src/postcss.config.js | 7 + .../theme/static_src/src/styles.css | 6 + .../theme/static_src/tailwind.config.js | 71 + metadata_catalogue/users/urls.py | 10 - metadata_catalogue/users/views.py | 43 - nginx/default.conf.template | 12 +- pdm.lock | 128 +- pyproject.toml | 10 + 49 files changed, 2135 insertions(+), 603 deletions(-) create mode 100755 metadata_catalogue/core/templates/core/app.html create mode 100644 metadata_catalogue/core/templates/core/base.html create mode 100755 metadata_catalogue/core/templates/core/partials/navigation.html create mode 100644 metadata_catalogue/core/templates/core/partials/user-dropdown.html create mode 100644 metadata_catalogue/static/images/logo.png delete mode 100644 metadata_catalogue/templates/account/account_inactive.html delete mode 100644 metadata_catalogue/templates/account/base.html delete mode 100644 metadata_catalogue/templates/account/email.html delete mode 100644 metadata_catalogue/templates/account/email_confirm.html delete mode 100644 metadata_catalogue/templates/account/login.html delete mode 100644 metadata_catalogue/templates/account/logout.html delete mode 100644 metadata_catalogue/templates/account/password_change.html delete mode 100644 metadata_catalogue/templates/account/password_reset.html delete mode 100644 metadata_catalogue/templates/account/password_reset_done.html delete mode 100644 metadata_catalogue/templates/account/password_reset_from_key.html delete mode 100644 metadata_catalogue/templates/account/password_reset_from_key_done.html delete mode 100644 metadata_catalogue/templates/account/password_set.html delete mode 100644 metadata_catalogue/templates/account/signup.html delete mode 100644 metadata_catalogue/templates/account/signup_closed.html delete mode 100644 metadata_catalogue/templates/account/verification_sent.html delete mode 100644 metadata_catalogue/templates/account/verified_email_required.html create mode 100644 metadata_catalogue/templates/app.html create mode 100644 metadata_catalogue/templates/components.yaml create mode 100644 metadata_catalogue/templates/components/action-button.html create mode 100644 metadata_catalogue/templates/core/partials/navigation.html create mode 100644 metadata_catalogue/theme/__init__.py create mode 100644 metadata_catalogue/theme/apps.py create mode 100644 metadata_catalogue/theme/static_src/.gitignore create mode 100644 metadata_catalogue/theme/static_src/package-lock.json create mode 100644 metadata_catalogue/theme/static_src/package.json create mode 100644 metadata_catalogue/theme/static_src/postcss.config.js create mode 100644 metadata_catalogue/theme/static_src/src/styles.css create mode 100644 metadata_catalogue/theme/static_src/tailwind.config.js delete mode 100644 metadata_catalogue/users/urls.py delete mode 100644 metadata_catalogue/users/views.py diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 35c4426..a942593 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -29,15 +29,11 @@ repos: - id: pyupgrade args: [--py311-plus] - - repo: https://github.com/psf/black - rev: 23.10.1 + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.3.5 hooks: - - id: black - - - repo: https://github.com/PyCQA/isort - rev: 5.12.0 - hooks: - - id: isort + - id: ruff + - id: ruff-format - repo: https://github.com/Riverside-Healthcare/djLint rev: v1.34.0 @@ -45,6 +41,12 @@ repos: - id: djlint-reformat-django - id: djlint-django + - repo: https://github.com/Yelp/detect-secrets + rev: v1.4.0 + hooks: + - id: detect-secrets + args: [--exclude-files=metadata_catalogue/fixtures/users.json, --exclude-files=config/settings/test.py, --exclude-files=config/settings/local.py] + # sets up .pre-commit-ci.yaml to ensure pre-commit dependencies stay up to date ci: autoupdate_schedule: weekly diff --git a/Dockerfile b/Dockerfile index 44c021a..84ff7ef 100644 --- a/Dockerfile +++ b/Dockerfile @@ -17,6 +17,10 @@ RUN --mount=type=cache,target=/var/cache/zypper \ RUN python3.11 -m pip install pdm COPY ./pyproject.toml ./pdm.lock . +FROM pdm AS pdm-node +RUN --mount=type=cache,target=/var/cache/zypper \ + zypper install --no-recommends -y nodejs20 npm20 + FROM pdm AS production RUN --mount=type=cache,target=/var/cache/zypper \ zypper install --no-recommends -y gdal-devel gcc gcc-c++ python311-devel @@ -34,15 +38,27 @@ RUN DATABASE_URL="" DJANGO_BASE_SCHEMA_URL="" \ DJANGO_SETTINGS_MODULE="config.settings.test" \ pdm run ./manage.py compilemessages +FROM pdm-node AS tailwind +COPY --from=production /app . +COPY --from=translation /app/locale locale +COPY --from=source /app . +RUN DATABASE_URL="" \ +DJANGO_SETTINGS_MODULE="config.settings.test" \ +python manage.py tailwind install +RUN DATABASE_URL="" \ +DJANGO_SETTINGS_MODULE="config.settings.test" \ +python manage.py tailwind build + FROM base AS django COPY --from=production /app . COPY --from=translation /app/locale locale +COPY --from=tailwind /app/metadata_catalogue/theme/static /app/metadata_catalogue/theme/static COPY --from=source /app . RUN mkdir media COPY entrypoint.sh . ENTRYPOINT ["./entrypoint.sh"] -FROM pdm AS dev +FROM pdm-node AS dev COPY --from=django /app/.venv .venv RUN --mount=type=cache,target=/root/.cache/pdm \ pdm install --dev diff --git a/config/settings/base.py b/config/settings/base.py index 9f53cad..99e6e90 100644 --- a/config/settings/base.py +++ b/config/settings/base.py @@ -1,6 +1,7 @@ """ Base settings to build other settings files upon. """ + from pathlib import Path import environ @@ -76,9 +77,12 @@ THIRD_PARTY_APPS = [ "crispy_forms", - "crispy_bootstrap5", + "crispy_tailwind", + "allauth_ui", "allauth", "allauth.account", + "allauth.socialaccount", + "allauth.socialaccount.providers.openid_connect", "django_probes", "health_check", "health_check.db", @@ -97,6 +101,10 @@ "drf_spectacular", "drf_standardized_errors", "django_filters", + "tailwind", + "widget_tweaks", + "slippers", + "fontawesomefree", ] LOCAL_APPS = [ @@ -106,6 +114,7 @@ "metadata_catalogue.datasets.csw", "metadata_catalogue.datasets.geoapi", "metadata_catalogue.maps", + "metadata_catalogue.theme", ] # https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + LOCAL_APPS @@ -126,7 +135,7 @@ # https://docs.djangoproject.com/en/dev/ref/settings/#auth-user-model AUTH_USER_MODEL = "users.User" # https://docs.djangoproject.com/en/dev/ref/settings/#login-redirect-url -LOGIN_REDIRECT_URL = "users:redirect" +LOGIN_REDIRECT_URL = "home" # https://docs.djangoproject.com/en/dev/ref/settings/#login-url LOGIN_URL = "account_login" @@ -142,7 +151,9 @@ ] # https://docs.djangoproject.com/en/dev/ref/settings/#auth-password-validators AUTH_PASSWORD_VALIDATORS = [ - {"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator"}, + { + "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator" + }, {"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator"}, {"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator"}, {"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator"}, @@ -209,6 +220,7 @@ "django.contrib.messages.context_processors.messages", "metadata_catalogue.users.context_processors.allauth_settings", ], + "builtins": ["slippers.templatetags.slippers"], }, } ] @@ -217,8 +229,8 @@ FORM_RENDERER = "django.forms.renderers.TemplatesSetting" # http://django-crispy-forms.readthedocs.io/en/latest/install.html#template-packs -CRISPY_TEMPLATE_PACK = "bootstrap5" -CRISPY_ALLOWED_TEMPLATE_PACKS = "bootstrap5" +CRISPY_TEMPLATE_PACK = "tailwind" +CRISPY_ALLOWED_TEMPLATE_PACKS = "tailwind" # FIXTURES # ------------------------------------------------------------------------------ @@ -305,6 +317,29 @@ # https://django-allauth.readthedocs.io/en/latest/forms.html ACCOUNT_FORMS = {"signup": "metadata_catalogue.users.forms.UserSignupForm"} +ALLAUTH_UI_THEME = "light" + +if SOCIALACCOUNT_ADAPTER := env("SOCIALACCOUNT_ADAPTER", default=None): + SOCIALACCOUNT_ONLY = True + SOCIALACCOUNT_STORE_TOKENS = True + if OIDC_CLIENT_ID := env("OIDC_CLIENT_ID", default=None): + SOCIALACCOUNT_PROVIDERS = { + "openid_connect": { + "APPS": [ + { + "provider_id": env("OIDC_PROVIDER_ID"), + "name": env("OIDC_PROVIDER_NAME"), + "client_id": OIDC_CLIENT_ID, + "secret": env("OIDC_SECRET"), + "settings": { + "server_url": env("OIDC_PROVIDER_URL"), + }, + }, + ] + } + } + + # DJANGO Q Q_CLUSTER = { "name": "viltkamera", @@ -349,6 +384,7 @@ GEOAPI_SETTINGS_CACHE_ENABLED = env.bool("GEOAPI_SETTINGS_CACHE_ENABLED", default=False) CORS_ALLOWED_ORIGINS = env.list("DJANGO_CORS_ALLOWED_ORIGINS", default=[]) +CORS_URLS_REGEX = r"^/api/.*$" CORS_ALLOW_CREDENTIALS = True MAPS_API_KEY = env("MAPS_API_KEY", default=None) @@ -381,3 +417,5 @@ } DRF_STANDARDIZED_ERRORS = {"ENABLE_IN_DEBUG_FOR_UNHANDLED_EXCEPTIONS": True} + +TAILWIND_APP_NAME = "metadata_catalogue.theme" diff --git a/config/settings/local.py b/config/settings/local.py index 86e25d0..fed3149 100644 --- a/config/settings/local.py +++ b/config/settings/local.py @@ -11,9 +11,13 @@ default="iUb7AqZQ5PzH8EeOdXOQgwwvfhbtyQWuziGY8XfG6hAM1KVwH0Ukt8q4nAuKHF5m", ) # https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts -ALLOWED_HOSTS = ["localhost", "0.0.0.0", "127.0.0.1", "django", "django-dev"] + env.list( - "DJANGO_ALLOWED_HOSTS", default=[""] -) +ALLOWED_HOSTS = [ + "localhost", + "0.0.0.0", + "127.0.0.1", + "django", + "django-dev", +] + env.list("DJANGO_ALLOWED_HOSTS", default=[""]) # CACHES # ------------------------------------------------------------------------------ @@ -28,7 +32,9 @@ # EMAIL # ------------------------------------------------------------------------------ # https://docs.djangoproject.com/en/dev/ref/settings/#email-backend -EMAIL_BACKEND = env("DJANGO_EMAIL_BACKEND", default="django.core.mail.backends.console.EmailBackend") +EMAIL_BACKEND = env( + "DJANGO_EMAIL_BACKEND", default="django.core.mail.backends.console.EmailBackend" +) # django-debug-toolbar # ------------------------------------------------------------------------------ @@ -37,9 +43,16 @@ # https://django-debug-toolbar.readthedocs.io/en/latest/installation.html#middleware MIDDLEWARE += ["debug_toolbar.middleware.DebugToolbarMiddleware"] # noqa: F405 # https://django-debug-toolbar.readthedocs.io/en/latest/configuration.html#debug-toolbar-config + + +def show_toolbar(request): + return True + + DEBUG_TOOLBAR_CONFIG = { "DISABLE_PANELS": ["debug_toolbar.panels.redirects.RedirectsPanel"], "SHOW_TEMPLATE_CONTEXT": True, + "SHOW_TOOLBAR_CALLBACK": show_toolbar, } # https://django-debug-toolbar.readthedocs.io/en/latest/installation.html#internal-ips INTERNAL_IPS = ["127.0.0.1", "10.0.2.2"] diff --git a/config/settings/test.py b/config/settings/test.py index 9a54a79..b27f282 100644 --- a/config/settings/test.py +++ b/config/settings/test.py @@ -2,8 +2,12 @@ With these settings, tests run faster. """ +import os + +os.environ["DJANGO_BASE_SCHEMA_URL"] = "" + from .base import * # noqa -from .base import env +from .base import env # noqa: E402 # GENERAL # ------------------------------------------------------------------------------ @@ -32,6 +36,6 @@ # MEDIA # ------------------------------------------------------------------------------ # https://docs.djangoproject.com/en/dev/ref/settings/#media-url -MEDIA_URL = "http://media.testserver" +MEDIA_URL = "http://media.testserver/" # Your stuff... # ------------------------------------------------------------------------------ diff --git a/config/urls.py b/config/urls.py index 7302339..6ac4b72 100644 --- a/config/urls.py +++ b/config/urls.py @@ -1,5 +1,4 @@ from django.conf import settings -from django.conf.urls.static import static from django.contrib import admin from django.urls import include, path from django.views import defaults as default_views @@ -11,16 +10,20 @@ urlpatterns = [ path("", TemplateView.as_view(template_name="pages/home.html"), name="home"), - path("about/", TemplateView.as_view(template_name="pages/about.html"), name="about"), + path( + "about/", TemplateView.as_view(template_name="pages/about.html"), name="about" + ), # Django Admin, use {% url 'admin:index' %} path(settings.ADMIN_URL, admin.site.urls), # User management - path("users/", include("metadata_catalogue.users.urls", namespace="users")), path("accounts/", include("allauth.urls")), path("ht/", include("health_check.urls")), path("csw/", include("metadata_catalogue.datasets.csw.urls")), path("geoapi", landing_page), - path("geoapi/", include("metadata_catalogue.datasets.geoapi.urls", namespace="geoapi")), + path( + "geoapi/", + include("metadata_catalogue.datasets.geoapi.urls", namespace="geoapi"), + ), path("datasets/", include("metadata_catalogue.datasets.urls")), path("api/v1/", include("config.routers")), path("api/", api.urls), diff --git a/docker-compose.yml b/docker-compose.yml index 1f56d7d..4c3f90b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -85,6 +85,15 @@ services: <<: *django-dev-env DJANGO_MIGRATE: 1 + tailwind: + <<: *django-dev + tty: true + stdin_open: true + command: python manage.py tailwind start + environment: + <<: *django-dev-env + DJANGO_TAILWIND: 1 + queue: <<: *django-prod environment: @@ -199,15 +208,11 @@ services: - TITILER_API_CACHECONTROL=no-cache - FORWARDED_ALLOW_IPS=* - TITILER_API_ROOT_PATH=/titiler - ports: - - "8989:80" maps: profiles: - maps image: ghcr.io/ninanor/nina-map-explorer:main - ports: - - "3000:80" volumes: - ./nginx/maps.config.js:/var/www/config.js diff --git a/entrypoint.sh b/entrypoint.sh index 1bdc44e..7bc60ee 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -20,6 +20,13 @@ else python manage.py setup fi +if [[ -z "${DJANGO_TAILWIND}" ]] +then + echo "Skip tailwind" +else + python manage.py tailwind install --no-input +fi + if [[ -z "${DJANGO_COLLECTSTATIC}" ]] then echo "Skip collectstatic" diff --git a/metadata_catalogue/core/templates/core/app.html b/metadata_catalogue/core/templates/core/app.html new file mode 100755 index 0000000..6d50f09 --- /dev/null +++ b/metadata_catalogue/core/templates/core/app.html @@ -0,0 +1 @@ +{% extends 'core/base.html' %} diff --git a/metadata_catalogue/core/templates/core/base.html b/metadata_catalogue/core/templates/core/base.html new file mode 100644 index 0000000..6ff1a57 --- /dev/null +++ b/metadata_catalogue/core/templates/core/base.html @@ -0,0 +1,68 @@ +{% load static i18n tailwind_tags %} + + +{% get_current_language as LANGUAGE_CODE %} + + + + + + {% block title %} + {% endblock title %} + + + + + {% block seo %} + + + {% endblock seo %} + + + + {% tailwind_css %} + {% block css %} + {% endblock css %} + {% block head_javascript %} + {% endblock head_javascript %} + + + {% block body %} +
+ {% include 'core/partials/navigation.html' %} +
+
+ {% if messages %} + {% for message in messages %} +
+
{{ message }}
+
+ +
+
+ {% endfor %} + {% endif %} + {% block content %} + {% endblock content %} +
+
+ + {% endblock body %} + {% block modal %} + {% endblock modal %} + {% block body_javascript %} + + + {% endblock body_javascript %} + + diff --git a/metadata_catalogue/core/templates/core/partials/navigation.html b/metadata_catalogue/core/templates/core/partials/navigation.html new file mode 100755 index 0000000..7eaf792 --- /dev/null +++ b/metadata_catalogue/core/templates/core/partials/navigation.html @@ -0,0 +1,20 @@ +{% load i18n %} + +
+
+ +
+ {% if user.is_authenticated %} + {% include 'core/partials/user-dropdown.html' %} + {% else %} + Login + {% endif %} +
+
+
diff --git a/metadata_catalogue/core/templates/core/partials/user-dropdown.html b/metadata_catalogue/core/templates/core/partials/user-dropdown.html new file mode 100644 index 0000000..63e470b --- /dev/null +++ b/metadata_catalogue/core/templates/core/partials/user-dropdown.html @@ -0,0 +1,49 @@ +{% load i18n %} + +
+ + + + + + +
+ +
+ +
diff --git a/metadata_catalogue/static/images/logo.png b/metadata_catalogue/static/images/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..3f771d8a421c7886ec747e2136693589b83ff6b8 GIT binary patch literal 2974 zcmV;P3t{w$P)}_a_`=AUyJUZe`aSdch8=C_MY#2|9AfXoQnlQ z(6(3Z-NC(Vz)X`_LJ$x++?#`YrLgX0pg=&_xwk^$&t%rUVGaro5LWJOKXJ;=x|cD< z4(??oK_LKzSvZ1%>->Bf4Z(CpID&!$1d7T$nU9$Z2{%v()6U`mMVQzOL#7bx23YiA0wcV>6HtV+y4J6%{C0ax6qZ5g^gUbVWFV zLLt$`Tu8Wqf+Eqy#AX;Wg%LV}xsOl*1#O~BW8DlG6c%xh0m2DHqN}OtG93Bh0NlJ( z1J9S&pavY}>2p)lShwE??t@HpH8#}4hS#5kwNGA$*B6iM0tmF& z=t#&&83Nn0V!`$CYp{RsZokiWmVe50MF?mLUPqw2*!KI?P_ZgO5)4wdy0^lS zFaPd4_t#yOU4SAOOOD+Spdb@npOqH!fIuctW5_6HtNsA!cF<Kx*IXx76~X+(FR0EL62TB z(D%vNVmHE)V?hE%o=TR;Cw)6=fqv1qbvI&Id^EJTwfLPIHD^9--?N+PihG$Uq!L~3 z`ZJI`I!<>ZhQ{@P+JDvX#}S_Y`p%D7kS?B$Fc)GnC~QEPr;tl@^&c=0YTO>(4LNu9 zCL|<|;g4@wI)B=TX~}T3riO{lV1lA=f}M8cNhZ4D;|D-ZW3%ptoNa1@sOT8}_`%+> zexG#=9Y)SXnENo>ee~=dqv%4E5?!~fiMrcy=$yqD@@{Qu_16}27w~x$qCE^4W`bhC z$j1ZvX__5fBgUpcS=D*%uA`|PTKYUefXttedUG!7?3E^_D}n`z!Q*})>!)c~Vo#Vj zg->u{vP+BoytE$Xr=|197zm4dbX1ozS09XIx*~|P53r@qc1Qq1)sC(OnYobp{wdYh ze(^mQOkJ`HqN95K-;I265C)AM*QH$4putR61QirX6KxWdtZKmw3eK6&{u)y9j!`iN zmU*S50jv|2!RUm}%QW7+#Rsms%yLFP23IbB61t~C~{#f?Mc6emoYM7on%l8?^BOaYEec70SgM4ue#uoBs z#L6pIGY1MBnM0-~I~#Xb76@)b^Nucb1DVTL@>KthXyuisy#sE?J_1RTGT`|IT^H9> z*Ve+6w4X@Ui(>Pd|0&cJB@70}g92KvHeuw+nw;}0Tt87;Xw(QqcQVhhh&x(DReoz( zDcBaMT3E$qAZBTbTg}Zbd`GqznYP%$ssErSoG=k~{M!x~Y#*-*6f8Mr5-849?{oR? z@{*_F!-^eJ>ljQkOsH+*SR(1UEG=JWy27N{NA*S5KRfU88*jpvvX6W#q09zE;pUAn zHE)gNjDxw5ZqgKspI+*zKlTqFbz|p@`Ne7|eD`g5F=HvO4a@`tUW*10H(OhzPAdkn zW@N0$2mj3O`aNYEas!m#?`0sa+ykP|?h1!h+-K8?^H`qTU0=?9o8ivGCgnCFu%rw<~coSXr;lrW1Gce=>#_Y94P+nIDA8g)Wh&#bLHg9>4uM_K5 z<1#Rw;?1IpeuG+ISV8+!b<|k4Q2-OW%s_y%=mdllghbbb$i zZ?^uKpEha%2MSmGF4htE%rd@CwRZV*o!rJDExIBv2%s>Ek+La(qF+;p6J4kq?tXn- zwmb%oCg;4$v&maq%V6N`Z(&&fcz)%z+zu~v5smd{;OmA4em%sfg-c*ESC3YUyDb|! zM_sXAWpy^L!yKG%E;kVrR$KCs3QY*Nv7IcqpnTfBr)I4d@vY!)H3ayD8|6ME6J418zOZi(btMQ81Q5Cc1j@rNyv)Dw z7|-D{y50r=0?mD(3X&#Gl^u~Pl4BKEofk|-i9wN_CBTM^OoU>I#cWKqxMlLAJPY_>f#o zpj!;xl&!~im5QlZbb~k6W9IZ!h lM$#gNNidZP^?F1sWY-J|HIFWI{xlO#eq46X zfZ|l;XYj)rvz3b3Rdkp~G?H_Iz!qAjr()OPwdz1Dq=qS|A320Gk?%)FK*NFRZU+Q1 zR@{HC(nM9&CdW$j(mMtCN<@rAtzTqZ2hg|>3nfeBtMs{i%DeS%yWq;1)7=V+V;^jS zG{+*^;wdUR%uN78uNb6d3pLlslwk&M+g)-l#6kfG&5tfz{?ZC)C@bwYeSu6hzHc8j zxfi>R4$C&_XROzF4KD+DWMV0$a!hAY0E7*6Jh~89P~~R51U2uz9duwILm^Ymqh|@V zViN>EUF8Lokkm5Tg?I=?veGb;&<;7*q3A-Cf>*j9UFZb{W=tPnzQVA$gAyRVTDJ!B z3)ZOps+LYICBByl<~(SvfN&jopuB{T9Qjru%PVCbp?`T7;uWKo04!nHqYJ&jIKK8x zAlF@(4G8a&f0fhj6qO?xJIJj?464*GRfGmmYNJDRoG0_LN&(3tb7Pz;MGX}&@^B%{ zp@VSb!_B4u!nN&B(7t0EtXo&42@o1}MXa--sN{Er?B$&fUwkYR1+%0GYM}TYmSk$hw z6t2cbx{wHo097#<{|ID1!*KJeS61 z_eA0t=s#{e#OrqvG;C3#k}cd^r<9v{4+Tal3J^CUT}K7&w3={BybFm4hK^7xNO4~% zxi_>MOzY0Eq96>ck^rD^$iyLN7|7>BEC&6Lu23_(#*vKEMwgil6NT6Hx(=_AVQ@!; za07}M4irbHH%_3WHPRsPQ+=irfg`^eHSw9!H44B#Ozjc?LHm8FnT>C|!T$sp01Ny- UJe4Dd&;S4c07*qoM6N<$g0jVAlmGw# literal 0 HcmV?d00001 diff --git a/metadata_catalogue/templates/account/account_inactive.html b/metadata_catalogue/templates/account/account_inactive.html deleted file mode 100644 index 036adb4..0000000 --- a/metadata_catalogue/templates/account/account_inactive.html +++ /dev/null @@ -1,11 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} - -{% block head_title %} - {% translate "Account Inactive" %} -{% endblock head_title %} -{% block inner %} -

{% translate "Account Inactive" %}

-

{% translate "This account is inactive." %}

-{% endblock inner %} diff --git a/metadata_catalogue/templates/account/base.html b/metadata_catalogue/templates/account/base.html deleted file mode 100644 index 9e20d0d..0000000 --- a/metadata_catalogue/templates/account/base.html +++ /dev/null @@ -1,14 +0,0 @@ -{% extends "base.html" %} - -{% block title %} - {% block head_title %} - {% endblock head_title %} -{% endblock title %} -{% block content %} -
-
- {% block inner %} - {% endblock inner %} -
-
-{% endblock content %} diff --git a/metadata_catalogue/templates/account/email.html b/metadata_catalogue/templates/account/email.html deleted file mode 100644 index 1d2637e..0000000 --- a/metadata_catalogue/templates/account/email.html +++ /dev/null @@ -1,78 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} -{% load crispy_forms_tags %} - -{% block head_title %} - {% translate "Account" %} -{% endblock head_title %} -{% block inner %} -

{% translate "E-mail Addresses" %}

- {% if user.emailaddress_set.all %} -

{% translate "The following e-mail addresses are associated with your account:" %}

- - {% else %} -

- {% translate "Warning:" %} {% translate "You currently do not have any e-mail address set up. You should really add an e-mail address so you can receive notifications, reset your password, etc." %} -

- {% endif %} -

{% translate "Add E-mail Address" %}

-
- {% csrf_token %} - {{ form|crispy }} - -
-{% endblock inner %} -{% block inline_javascript %} - {{ block.super }} - -{% endblock inline_javascript %} diff --git a/metadata_catalogue/templates/account/email_confirm.html b/metadata_catalogue/templates/account/email_confirm.html deleted file mode 100644 index 95ef44f..0000000 --- a/metadata_catalogue/templates/account/email_confirm.html +++ /dev/null @@ -1,27 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} -{% load account %} - -{% block head_title %} - {% translate "Confirm E-mail Address" %} -{% endblock head_title %} -{% block inner %} -

{% translate "Confirm E-mail Address" %}

- {% if confirmation %} - {% user_display confirmation.email_address.user as user_display %} -

- {% blocktranslate with confirmation.email_address.email as email %}Please confirm that {{ email }} is an e-mail address for user {{ user_display }}.{% endblocktranslate %} -

-
- {% csrf_token %} - -
- {% else %} - {% url 'account_email' as email_url %} -

- {% blocktranslate %}This e-mail confirmation link expired or is invalid. Please issue a new e-mail confirmation request.{% endblocktranslate %} -

- {% endif %} -{% endblock inner %} diff --git a/metadata_catalogue/templates/account/login.html b/metadata_catalogue/templates/account/login.html deleted file mode 100644 index 56c261b..0000000 --- a/metadata_catalogue/templates/account/login.html +++ /dev/null @@ -1,32 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} -{% load account %} -{% load crispy_forms_tags %} - -{% block head_title %} - {% translate "Sign In" %} -{% endblock head_title %} -{% block inner %} -

{% translate "Sign In" %}

- {% if ACCOUNT_ALLOW_REGISTRATION %} -

- {% blocktranslate trimmed %} - If you have not created an account yet, then please - sign up first. - {% endblocktranslate %} -

- {% endif %} - -{% endblock inner %} diff --git a/metadata_catalogue/templates/account/logout.html b/metadata_catalogue/templates/account/logout.html deleted file mode 100644 index e314020..0000000 --- a/metadata_catalogue/templates/account/logout.html +++ /dev/null @@ -1,20 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} - -{% block head_title %} - {% translate "Sign Out" %} -{% endblock head_title %} -{% block inner %} -

{% translate "Sign Out" %}

-

{% translate "Are you sure you want to sign out?" %}

-
- {% csrf_token %} - {% if redirect_field_value %} - - {% endif %} - -
-{% endblock inner %} diff --git a/metadata_catalogue/templates/account/password_change.html b/metadata_catalogue/templates/account/password_change.html deleted file mode 100644 index 029aa54..0000000 --- a/metadata_catalogue/templates/account/password_change.html +++ /dev/null @@ -1,18 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} -{% load crispy_forms_tags %} - -{% block head_title %} - {% translate "Change Password" %} -{% endblock head_title %} -{% block inner %} -

{% translate "Change Password" %}

-
- {% csrf_token %} - {{ form|crispy }} - -
-{% endblock inner %} diff --git a/metadata_catalogue/templates/account/password_reset.html b/metadata_catalogue/templates/account/password_reset.html deleted file mode 100644 index ee35e75..0000000 --- a/metadata_catalogue/templates/account/password_reset.html +++ /dev/null @@ -1,28 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} -{% load account %} -{% load crispy_forms_tags %} - -{% block head_title %} - {% translate "Password Reset" %} -{% endblock head_title %} -{% block inner %} -

{% translate "Password Reset" %}

- {% if user.is_authenticated %} - {% include "account/snippets/already_logged_in.html" %} - {% endif %} -

- {% translate "Forgotten your password? Enter your e-mail address below, and we'll send you an e-mail allowing you to reset it." %} -

-
- {% csrf_token %} - {{ form|crispy }} - -
-

{% blocktranslate %}Please contact us if you have any trouble resetting your password.{% endblocktranslate %}

-{% endblock inner %} diff --git a/metadata_catalogue/templates/account/password_reset_done.html b/metadata_catalogue/templates/account/password_reset_done.html deleted file mode 100644 index 8efc4aa..0000000 --- a/metadata_catalogue/templates/account/password_reset_done.html +++ /dev/null @@ -1,17 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} -{% load account %} - -{% block head_title %} - {% translate "Password Reset" %} -{% endblock head_title %} -{% block inner %} -

{% translate "Password Reset" %}

- {% if user.is_authenticated %} - {% include "account/snippets/already_logged_in.html" %} - {% endif %} -

- {% blocktranslate %}We have sent you an e-mail. Please contact us if you do not receive it within a few minutes.{% endblocktranslate %} -

-{% endblock inner %} diff --git a/metadata_catalogue/templates/account/password_reset_from_key.html b/metadata_catalogue/templates/account/password_reset_from_key.html deleted file mode 100644 index b880bf9..0000000 --- a/metadata_catalogue/templates/account/password_reset_from_key.html +++ /dev/null @@ -1,36 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} -{% load crispy_forms_tags %} - -{% block head_title %} - {% translate "Change Password" %} -{% endblock head_title %} -{% block inner %} -

- {% if token_fail %} - {% translate "Bad Token" %} - {% else %} - {% translate "Change Password" %} - {% endif %} -

- {% if token_fail %} - {% url 'account_reset_password' as passwd_reset_url %} -

- {% blocktranslate %}The password reset link was invalid, possibly because it has already been used. Please request a new password reset.{% endblocktranslate %} -

- {% else %} - {% if form %} -
- {% csrf_token %} - {{ form|crispy }} - -
- {% else %} -

{% translate "Your password is now changed." %}

- {% endif %} - {% endif %} -{% endblock inner %} diff --git a/metadata_catalogue/templates/account/password_reset_from_key_done.html b/metadata_catalogue/templates/account/password_reset_from_key_done.html deleted file mode 100644 index 28db548..0000000 --- a/metadata_catalogue/templates/account/password_reset_from_key_done.html +++ /dev/null @@ -1,11 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} - -{% block head_title %} - {% translate "Change Password" %} -{% endblock head_title %} -{% block inner %} -

{% translate "Change Password" %}

-

{% translate "Your password is now changed." %}

-{% endblock inner %} diff --git a/metadata_catalogue/templates/account/password_set.html b/metadata_catalogue/templates/account/password_set.html deleted file mode 100644 index 56fb618..0000000 --- a/metadata_catalogue/templates/account/password_set.html +++ /dev/null @@ -1,21 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} -{% load crispy_forms_tags %} - -{% block head_title %} - {% translate "Set Password" %} -{% endblock head_title %} -{% block inner %} -

{% translate "Set Password" %}

-
- {% csrf_token %} - {{ form|crispy }} - -
-{% endblock inner %} diff --git a/metadata_catalogue/templates/account/signup.html b/metadata_catalogue/templates/account/signup.html deleted file mode 100644 index 04bcbf9..0000000 --- a/metadata_catalogue/templates/account/signup.html +++ /dev/null @@ -1,27 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} -{% load crispy_forms_tags %} - -{% block head_title %} - {% translate "Signup" %} -{% endblock head_title %} -{% block inner %} -

{% translate "Sign Up" %}

-

- {% blocktranslate %}Already have an account? Then please sign in.{% endblocktranslate %} -

- -{% endblock inner %} diff --git a/metadata_catalogue/templates/account/signup_closed.html b/metadata_catalogue/templates/account/signup_closed.html deleted file mode 100644 index 94c4327..0000000 --- a/metadata_catalogue/templates/account/signup_closed.html +++ /dev/null @@ -1,11 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} - -{% block head_title %} - {% translate "Sign Up Closed" %} -{% endblock head_title %} -{% block inner %} -

{% translate "Sign Up Closed" %}

-

{% translate "We are sorry, but the sign up is currently closed." %}

-{% endblock inner %} diff --git a/metadata_catalogue/templates/account/verification_sent.html b/metadata_catalogue/templates/account/verification_sent.html deleted file mode 100644 index de2a33f..0000000 --- a/metadata_catalogue/templates/account/verification_sent.html +++ /dev/null @@ -1,13 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} - -{% block head_title %} - {% translate "Verify Your E-mail Address" %} -{% endblock head_title %} -{% block inner %} -

{% translate "Verify Your E-mail Address" %}

-

- {% blocktranslate %}We have sent an e-mail to you for verification. Follow the link provided to finalize the signup process. Please contact us if you do not receive it within a few minutes.{% endblocktranslate %} -

-{% endblock inner %} diff --git a/metadata_catalogue/templates/account/verified_email_required.html b/metadata_catalogue/templates/account/verified_email_required.html deleted file mode 100644 index aab0877..0000000 --- a/metadata_catalogue/templates/account/verified_email_required.html +++ /dev/null @@ -1,24 +0,0 @@ -{% extends "account/base.html" %} - -{% load i18n %} - -{% block head_title %} - {% translate "Verify Your E-mail Address" %} -{% endblock head_title %} -{% block inner %} -

{% translate "Verify Your E-mail Address" %}

- {% url 'account_email' as email_url %} -

- {% blocktranslate %}This part of the site requires us to verify that -you are who you claim to be. For this purpose, we require that you -verify ownership of your e-mail address. {% endblocktranslate %} -

-

- {% blocktranslate %}We have sent an e-mail to you for -verification. Please click on the link inside this e-mail. Please -contact us if you do not receive it within a few minutes.{% endblocktranslate %} -

-

- {% blocktranslate %}Note: you can still change your e-mail address.{% endblocktranslate %} -

-{% endblock inner %} diff --git a/metadata_catalogue/templates/app.html b/metadata_catalogue/templates/app.html new file mode 100644 index 0000000..21f5da2 --- /dev/null +++ b/metadata_catalogue/templates/app.html @@ -0,0 +1 @@ +{% extends 'base.html' %} diff --git a/metadata_catalogue/templates/base.html b/metadata_catalogue/templates/base.html index 5a588cd..c569f98 100644 --- a/metadata_catalogue/templates/base.html +++ b/metadata_catalogue/templates/base.html @@ -1,122 +1,10 @@ -{% load static i18n %} +{% extends 'core/base.html' %} - -{% get_current_language as LANGUAGE_CODE %} - - - - - - {% block title %} - Metadata Catalogue - {% endblock title %} - - - - - - {% block css %} - - - - - - {% endblock css %} - - {# Placed at the top of the document so pages load faster with defer #} - {% block javascript %} - - - - - - {% endblock javascript %} - - -
- -
-
- {% if messages %} - {% for message in messages %} -
- {{ message }} - -
- {% endfor %} - {% endif %} - {% block content %} -

Use this document as a way to quick start any new project.

- {% endblock content %} -
- - {% block modal %} - {% endblock modal %} - {% block inline_javascript %} - {% comment %} - Script tags with only code, no src (defer by default). To run - with a "defer" so that you run inline code: - - {% endcomment %} - {% endblock inline_javascript %} - - +{% load static %} + +{% block title %} + Catalogue +{% endblock title %} +{% block description %} + NINA Dataset Catalogue +{% endblock description %} diff --git a/metadata_catalogue/templates/components.yaml b/metadata_catalogue/templates/components.yaml new file mode 100644 index 0000000..a540462 --- /dev/null +++ b/metadata_catalogue/templates/components.yaml @@ -0,0 +1,2 @@ +components: + action-button: "components/action-button.html" diff --git a/metadata_catalogue/templates/components/action-button.html b/metadata_catalogue/templates/components/action-button.html new file mode 100644 index 0000000..5300e0c --- /dev/null +++ b/metadata_catalogue/templates/components/action-button.html @@ -0,0 +1,9 @@ +{% load static %} + +{% var submit_text=submit_text|default:"Submit" %} +{% var class=class|default:"bg-secondary text-white" %} +
+ {% csrf_token %} + {% if form %}{{ form }}{% endif %} + +
diff --git a/metadata_catalogue/templates/core/partials/navigation.html b/metadata_catalogue/templates/core/partials/navigation.html new file mode 100644 index 0000000..41ada87 --- /dev/null +++ b/metadata_catalogue/templates/core/partials/navigation.html @@ -0,0 +1,20 @@ +{% load i18n static %} + +
+
+
+ + NINA logo + +
+
+ {% if user.is_authenticated %} + {% include 'core/partials/user-dropdown.html' %} + {% else %} + Login + {% endif %} +
+
+
diff --git a/metadata_catalogue/templates/pages/about.html b/metadata_catalogue/templates/pages/about.html index 94d9808..942cdab 100644 --- a/metadata_catalogue/templates/pages/about.html +++ b/metadata_catalogue/templates/pages/about.html @@ -1 +1 @@ -{% extends "base.html" %} +{% extends "app.html" %} diff --git a/metadata_catalogue/templates/pages/home.html b/metadata_catalogue/templates/pages/home.html index dc39f74..04c4d73 100644 --- a/metadata_catalogue/templates/pages/home.html +++ b/metadata_catalogue/templates/pages/home.html @@ -1,8 +1,8 @@ -{% extends "base.html" %} +{% extends "app.html" %} {% block content %}
-

Services Available

+

Services Available

  • CSW diff --git a/metadata_catalogue/theme/__init__.py b/metadata_catalogue/theme/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/metadata_catalogue/theme/apps.py b/metadata_catalogue/theme/apps.py new file mode 100644 index 0000000..eb6fac1 --- /dev/null +++ b/metadata_catalogue/theme/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class ThemeConfig(AppConfig): + name = "metadata_catalogue.theme" diff --git a/metadata_catalogue/theme/static_src/.gitignore b/metadata_catalogue/theme/static_src/.gitignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/metadata_catalogue/theme/static_src/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/metadata_catalogue/theme/static_src/package-lock.json b/metadata_catalogue/theme/static_src/package-lock.json new file mode 100644 index 0000000..7fab5f1 --- /dev/null +++ b/metadata_catalogue/theme/static_src/package-lock.json @@ -0,0 +1,1578 @@ +{ + "name": "theme", + "version": "3.8.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "theme", + "version": "3.8.0", + "license": "MIT", + "devDependencies": { + "@tailwindcss/aspect-ratio": "^0.4.2", + "@tailwindcss/forms": "^0.5.7", + "@tailwindcss/typography": "^0.5.10", + "cross-env": "^7.0.3", + "daisyui": "^4.12.13", + "postcss": "^8.4.32", + "postcss-import": "^15.1.0", + "postcss-nested": "^6.0.1", + "postcss-simple-vars": "^7.0.1", + "rimraf": "^5.0.5", + "tailwindcss": "^3.4.0" + } + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@tailwindcss/aspect-ratio": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/aspect-ratio/-/aspect-ratio-0.4.2.tgz", + "integrity": "sha512-8QPrypskfBa7QIMuKHg2TA7BqES6vhBrDLOv8Unb6FcFyd3TjKbc6lcmb9UPQHxfl24sXoJ41ux/H7qQQvfaSQ==", + "dev": true, + "peerDependencies": { + "tailwindcss": ">=2.0.0 || >=3.0.0 || >=3.0.0-alpha.1" + } + }, + "node_modules/@tailwindcss/forms": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.7.tgz", + "integrity": "sha512-QE7X69iQI+ZXwldE+rzasvbJiyV/ju1FGHH0Qn2W3FKbuYtqp8LKcy6iSw79fVUT5/Vvf+0XgLCeYVG+UV6hOw==", + "dev": true, + "dependencies": { + "mini-svg-data-uri": "^1.2.3" + }, + "peerDependencies": { + "tailwindcss": ">=3.0.0 || >= 3.0.0-alpha.1" + } + }, + "node_modules/@tailwindcss/typography": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.13.tgz", + "integrity": "sha512-ADGcJ8dX21dVVHIwTRgzrcunY6YY9uSlAHHGVKvkA+vLc5qLwEszvKts40lx7z0qc4clpjclwLeK5rVCV2P/uw==", + "dev": true, + "dependencies": { + "lodash.castarray": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.merge": "^4.6.2", + "postcss-selector-parser": "6.0.10" + }, + "peerDependencies": { + "tailwindcss": ">=3.0.0 || insiders" + } + }, + "node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "dev": true + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/cross-env": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", + "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "bin": { + "cross-env": "src/bin/cross-env.js", + "cross-env-shell": "src/bin/cross-env-shell.js" + }, + "engines": { + "node": ">=10.14", + "npm": ">=6", + "yarn": ">=1" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-selector-tokenizer": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.8.0.tgz", + "integrity": "sha512-Jd6Ig3/pe62/qe5SBPTN8h8LeUg/pT4lLgtavPf7updwwHpvFzxvOQBHYj2LZDMjUnBzgvIUSjRcf6oT5HzHFg==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "fastparse": "^1.1.2" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/culori": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/culori/-/culori-3.3.0.tgz", + "integrity": "sha512-pHJg+jbuFsCjz9iclQBqyL3B2HLCBF71BwVNujUYEvCeQMvV97R59MNK3R2+jgJ3a1fcZgI9B3vYgz8lzr/BFQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/daisyui": { + "version": "4.12.13", + "resolved": "https://registry.npmjs.org/daisyui/-/daisyui-4.12.13.tgz", + "integrity": "sha512-BnXyQoOByUF/7wSdIKubyhXxbtL8gxwY3u2cNMkxGP39TSVJqMmlItqtpY903fQnLI/NokC+bc+ZV+PEPsppPw==", + "dev": true, + "dependencies": { + "css-selector-tokenizer": "^0.8", + "culori": "^3", + "picocolors": "^1", + "postcss-js": "^4" + }, + "engines": { + "node": ">=16.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/daisyui" + } + }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "dev": true + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "dev": true + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fastparse": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz", + "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", + "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/jackspeak": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.3.0.tgz", + "integrity": "sha512-glPiBfKguqA7v8JsXO3iLjJWZ9FV1vNpoI0I9hI9Mnk5yetO9uPLSpiCEmiVijAssv2f54HpvtzvAHfhPieiDQ==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jiti": { + "version": "1.21.3", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.3.tgz", + "integrity": "sha512-uy2bNX5zQ+tESe+TiC7ilGRz8AtRGmnJH55NC5S0nSUjvvvM2hJHmefHErugGXN4pNv4Qx7vLsnNw9qJ9mtIsw==", + "dev": true, + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/lodash.castarray": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz", + "integrity": "sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==", + "dev": true + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lru-cache": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", + "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", + "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "dev": true, + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mini-svg-data-uri": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz", + "integrity": "sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==", + "dev": true, + "bin": { + "mini-svg-data-uri": "cli.js" + } + }, + "node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/picocolors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/postcss": { + "version": "8.4.38", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", + "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.0", + "source-map-js": "^1.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", + "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", + "dev": true, + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-load-config": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", + "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "lilconfig": "^3.0.0", + "yaml": "^2.3.4" + }, + "engines": { + "node": ">= 14" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/postcss-load-config/node_modules/lilconfig": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.1.tgz", + "integrity": "sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/postcss-nested": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz", + "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.11" + }, + "engines": { + "node": ">=12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-nested/node_modules/postcss-selector-parser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.0.tgz", + "integrity": "sha512-UMz42UD0UY0EApS0ZL9o1XnLhSTtvvvLe5Dc2H2O56fvRZi+KulDyf5ctDhhtYJBGKStV2FL1fy6253cmLgqVQ==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-simple-vars": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-simple-vars/-/postcss-simple-vars-7.0.1.tgz", + "integrity": "sha512-5GLLXaS8qmzHMOjVxqkk1TZPf1jMqesiI7qLhnlyERalG0sMbHIbJqrcnrpmZdKCLglHnRHoEBB61RtGTsj++A==", + "dev": true, + "engines": { + "node": ">=14.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.2.1" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dev": true, + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.7.tgz", + "integrity": "sha512-nV6YcJo5wbLW77m+8KjH8aB/7/rxQy9SZ0HY5shnwULfS+9nmTtVXAJET5NdZmCzA4fPI/Hm1wo/Po/4mopOdg==", + "dev": true, + "dependencies": { + "glob": "^10.3.7" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/source-map-js": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/sucrase": { + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", + "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "glob": "^10.3.10", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tailwindcss": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.3.tgz", + "integrity": "sha512-U7sxQk/n397Bmx4JHbJx/iSOOv5G+II3f1kpLpY2QeUv5DcPdcTsYLlusZfq1NthHS1c1cZoyFmmkex1rzke0A==", + "dev": true, + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.0", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.0", + "lilconfig": "^2.1.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.23", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.1", + "postcss-nested": "^6.0.1", + "postcss-selector-parser": "^6.0.11", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tailwindcss/node_modules/postcss-selector-parser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.0.tgz", + "integrity": "sha512-UMz42UD0UY0EApS0ZL9o1XnLhSTtvvvLe5Dc2H2O56fvRZi+KulDyf5ctDhhtYJBGKStV2FL1fy6253cmLgqVQ==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "dev": true + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yaml": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.3.tgz", + "integrity": "sha512-sntgmxj8o7DE7g/Qi60cqpLBA3HG3STcDA0kO+WfB05jEKhZMbY7umNm2rBpQvsmZ16/lPXCJGW2672dgOUkrg==", + "dev": true, + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + } + } +} diff --git a/metadata_catalogue/theme/static_src/package.json b/metadata_catalogue/theme/static_src/package.json new file mode 100644 index 0000000..be7d1e0 --- /dev/null +++ b/metadata_catalogue/theme/static_src/package.json @@ -0,0 +1,29 @@ +{ + "name": "theme", + "version": "3.8.0", + "description": "", + "scripts": { + "start": "npm run dev", + "build": "npm run build:clean && npm run build:tailwind", + "build:clean": "rimraf ../static/css/dist", + "build:tailwind": "cross-env NODE_ENV=production tailwindcss --postcss -i ./src/styles.css -o ../static/css/dist/styles.css --minify", + "dev": "cross-env NODE_ENV=development tailwindcss --postcss -i ./src/styles.css -o ../static/css/dist/styles.css -w", + "tailwindcss": "node ./node_modules/tailwindcss/lib/cli.js" + }, + "keywords": [], + "author": "", + "license": "MIT", + "devDependencies": { + "@tailwindcss/aspect-ratio": "^0.4.2", + "@tailwindcss/forms": "^0.5.7", + "@tailwindcss/typography": "^0.5.10", + "daisyui": "^4.12.13", + "cross-env": "^7.0.3", + "postcss": "^8.4.32", + "postcss-import": "^15.1.0", + "postcss-nested": "^6.0.1", + "postcss-simple-vars": "^7.0.1", + "rimraf": "^5.0.5", + "tailwindcss": "^3.4.0" + } +} diff --git a/metadata_catalogue/theme/static_src/postcss.config.js b/metadata_catalogue/theme/static_src/postcss.config.js new file mode 100644 index 0000000..0b09b34 --- /dev/null +++ b/metadata_catalogue/theme/static_src/postcss.config.js @@ -0,0 +1,7 @@ +module.exports = { + plugins: { + "postcss-import": {}, + "postcss-simple-vars": {}, + "postcss-nested": {} + }, +} diff --git a/metadata_catalogue/theme/static_src/src/styles.css b/metadata_catalogue/theme/static_src/src/styles.css new file mode 100644 index 0000000..2b8091e --- /dev/null +++ b/metadata_catalogue/theme/static_src/src/styles.css @@ -0,0 +1,6 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + + +[x-cloak] { display: none !important; } diff --git a/metadata_catalogue/theme/static_src/tailwind.config.js b/metadata_catalogue/theme/static_src/tailwind.config.js new file mode 100644 index 0000000..94b8c81 --- /dev/null +++ b/metadata_catalogue/theme/static_src/tailwind.config.js @@ -0,0 +1,71 @@ +/** + * This is a minimal config. + * + * If you need the full config, get it from here: + * https://unpkg.com/browse/tailwindcss@latest/stubs/defaultConfig.stub.js + */ + +const colors = require('tailwindcss/colors'); + +module.exports = { + content: [ + /** + * HTML. Paths to Django template files that will contain Tailwind CSS classes. + */ + + /* Templates within theme app (/templates), e.g. base.html. */ + '../templates/**/*.html', + + /* + * Main templates directory of the project (BASE_DIR/templates). + * Adjust the following line to match your project structure. + */ + '../../templates/**/*.html', + + /* + * Templates in other django apps (BASE_DIR//templates). + * Adjust the following line to match your project structure. + */ + '../../**/templates/**/*.html', + + /** + * JS: If you use Tailwind CSS in JavaScript, uncomment the following lines and make sure + * patterns match your project structure. + */ + /* JS 1: Ignore any JavaScript in node_modules folder. */ + '!../../**/node_modules', + /* JS 2: Process all JavaScript files in the project. */ + '../../**/*.js', + '../../**/*.jsx', + + /** + * Python: If you use Tailwind CSS classes in Python, uncomment the following line + * and make sure the pattern below matches your project structure. + */ + '../../**/*.py' + ], + theme: { + extend: { + // colors: { + // primary: "#74A333", + // secondary: "#004C6C" + // } + }, + }, + daisyui: { + themes: [ + "light", + ] + }, + plugins: [ + /** + * '@tailwindcss/forms' is the forms plugin that provides a minimal styling + * for forms. If you don't like it or have own styling for forms, + * comment the line below to disable '@tailwindcss/forms'. + */ + require('@tailwindcss/forms'), + require('@tailwindcss/typography'), + require('@tailwindcss/aspect-ratio'), + require('daisyui'), + ], +} diff --git a/metadata_catalogue/users/urls.py b/metadata_catalogue/users/urls.py deleted file mode 100644 index 4c60330..0000000 --- a/metadata_catalogue/users/urls.py +++ /dev/null @@ -1,10 +0,0 @@ -from django.urls import path - -from metadata_catalogue.users.views import user_detail_view, user_redirect_view, user_update_view - -app_name = "users" -urlpatterns = [ - path("~redirect/", view=user_redirect_view, name="redirect"), - path("~update/", view=user_update_view, name="update"), - path("/", view=user_detail_view, name="detail"), -] diff --git a/metadata_catalogue/users/views.py b/metadata_catalogue/users/views.py deleted file mode 100644 index 23c12e2..0000000 --- a/metadata_catalogue/users/views.py +++ /dev/null @@ -1,43 +0,0 @@ -from django.contrib.auth import get_user_model -from django.contrib.auth.mixins import LoginRequiredMixin -from django.contrib.messages.views import SuccessMessageMixin -from django.urls import reverse -from django.utils.translation import gettext_lazy as _ -from django.views.generic import DetailView, RedirectView, UpdateView - -User = get_user_model() - - -class UserDetailView(LoginRequiredMixin, DetailView): - model = User - slug_field = "id" - slug_url_kwarg = "id" - - -user_detail_view = UserDetailView.as_view() - - -class UserUpdateView(LoginRequiredMixin, SuccessMessageMixin, UpdateView): - model = User - fields = ["email"] - success_message = _("Information successfully updated") - - def get_success_url(self): - assert self.request.user.is_authenticated # for mypy to know that the user is authenticated - return self.request.user.get_absolute_url() - - def get_object(self): - return self.request.user - - -user_update_view = UserUpdateView.as_view() - - -class UserRedirectView(LoginRequiredMixin, RedirectView): - permanent = False - - def get_redirect_url(self): - return reverse("users:detail", kwargs={"pk": self.request.user.pk}) - - -user_redirect_view = UserRedirectView.as_view() diff --git a/nginx/default.conf.template b/nginx/default.conf.template index 5173715..7ac8a59 100644 --- a/nginx/default.conf.template +++ b/nginx/default.conf.template @@ -5,7 +5,6 @@ map $http_upgrade $connection_upgrade { upstream django_upstream { server django:8000; - keepalive 64; } server { @@ -29,7 +28,10 @@ server { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-NginX-Proxy true; + proxy_set_header Host $http_host; proxy_set_header Cookie $http_cookie; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; proxy_redirect off; location /static/ { @@ -49,10 +51,6 @@ server { location @proxy { proxy_pass http://django_upstream; - proxy_http_version 1.1; - proxy_set_header Host $http_host; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection $connection_upgrade; } location / { @@ -63,9 +61,5 @@ server { client_body_timeout 360; proxy_pass http://django_upstream; - proxy_http_version 1.1; - proxy_set_header Host $http_host; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection $connection_upgrade; } } diff --git a/pdm.lock b/pdm.lock index 2ba54d9..277074a 100644 --- a/pdm.lock +++ b/pdm.lock @@ -5,7 +5,7 @@ groups = ["default", "dev", "docs", "production"] strategy = ["cross_platform"] lock_version = "4.4.1" -content_hash = "sha256:1c38612d0de9336a41c4c6072631fe1de1ac4a307c82089f884c32a662fb619e" +content_hash = "sha256:6e2bb6113906b1ca94c0fe8993643aae871a73b0ac4e501eeb2a052acf77639d" [[package]] name = "affine" @@ -549,6 +549,20 @@ files = [ {file = "crispy_bootstrap5-2023.10-py3-none-any.whl", hash = "sha256:9b5a6c9880f37cd32aa678c0d7576ae60b3e502c444c8712e582f8bd91659afb"}, ] +[[package]] +name = "crispy-tailwind" +version = "1.0.3" +requires_python = ">=3.8" +summary = "Tailwind CSS for Django Crispy Forms" +dependencies = [ + "django-crispy-forms>=2.0", + "django>=4.2", +] +files = [ + {file = "crispy-tailwind-1.0.3.tar.gz", hash = "sha256:2bc9f616d406e4b003f25d46fcb0079f1c2522719d97adb107667271d849459a"}, + {file = "crispy_tailwind-1.0.3-py3-none-any.whl", hash = "sha256:31427f66b1c4fd0d6fb040f4197cfb97d104cdbe7641ea2dea940c0057c4db4b"}, +] + [[package]] name = "cryptography" version = "41.0.7" @@ -651,6 +665,19 @@ files = [ {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"}, ] +[[package]] +name = "dj-rest-auth" +version = "6.0.0" +requires_python = ">=3.8" +summary = "Authentication and Registration in Django Rest Framework" +dependencies = [ + "Django<6.0,>=3.2", + "djangorestframework>=3.13.0", +] +files = [ + {file = "dj-rest-auth-6.0.0.tar.gz", hash = "sha256:760b45f3a07cd6182e6a20fe07d0c55230c5f950167df724d7914d0dd8c50133"}, +] + [[package]] name = "django" version = "4.2.8" @@ -682,6 +709,20 @@ files = [ {file = "django-allauth-0.59.0.tar.gz", hash = "sha256:ec19efb80b34d2f18bd831eab9b10b6301f58d1cce9f39af35f497b7e5b0a141"}, ] +[[package]] +name = "django-allauth-ui" +version = "1.5.0" +requires_python = ">=3.8" +summary = "" +dependencies = [ + "django-widget-tweaks<2.0.0,>=1.5.0", + "slippers<0.7.0,>=0.6.2", +] +files = [ + {file = "django_allauth_ui-1.5.0-py3-none-any.whl", hash = "sha256:b0ce47f5bc02a4ad9630632190291a4e14bd66950d19b5e57b096d837080f6e2"}, + {file = "django_allauth_ui-1.5.0.tar.gz", hash = "sha256:9a486308dc790e76dfab5df72f6b7c1ab2c939e067db40a57eeb6597a202b095"}, +] + [[package]] name = "django-appconf" version = "1.0.6" @@ -1023,6 +1064,19 @@ files = [ {file = "django_stubs-4.2.7-py3-none-any.whl", hash = "sha256:4cf4de258fa71adc6f2799e983091b9d46cfc67c6eebc68fe111218c9a62b3b8"}, ] +[[package]] +name = "django-tailwind" +version = "3.8.0" +requires_python = ">=3.10.0,<4.0.0" +summary = "Tailwind CSS Framework for Django projects" +dependencies = [ + "django>=3.2.14", +] +files = [ + {file = "django_tailwind-3.8.0-py3-none-any.whl", hash = "sha256:fa969c5b95d314b173fe2b2ed2cb2c03f2e2c94fdc2c01ff73a993fa159085da"}, + {file = "django_tailwind-3.8.0.tar.gz", hash = "sha256:31c2f4a7879d685c2de0feaf0b63f246200b37337bea4d7dbafb59bc3f10c008"}, +] + [[package]] name = "django-treebeard" version = "4.7" @@ -1036,6 +1090,16 @@ files = [ {file = "django_treebeard-4.7-py3-none-any.whl", hash = "sha256:787117995ff985d98e6c2b241ef6b9d37fe8ff7051cd7535c283616a0b5b2645"}, ] +[[package]] +name = "django-widget-tweaks" +version = "1.5.0" +requires_python = ">=3.8" +summary = "Tweak the form field rendering in templates, not in python-level form definitions." +files = [ + {file = "django-widget-tweaks-1.5.0.tar.gz", hash = "sha256:1c2180681ebb994e922c754804c7ffebbe1245014777ac47897a81f57cc629c7"}, + {file = "django_widget_tweaks-1.5.0-py3-none-any.whl", hash = "sha256:a41b7b2f05bd44d673d11ebd6c09a96f1d013ee98121cb98c384fe84e33b881e"}, +] + [[package]] name = "djangorestframework" version = "3.15.1" @@ -1049,6 +1113,21 @@ files = [ {file = "djangorestframework-3.15.1.tar.gz", hash = "sha256:f88fad74183dfc7144b2756d0d2ac716ea5b4c7c9840995ac3bfd8ec034333c1"}, ] +[[package]] +name = "djangorestframework-simplejwt" +version = "5.3.1" +requires_python = ">=3.8" +summary = "A minimal JSON Web Token authentication plugin for Django REST Framework" +dependencies = [ + "django>=3.2", + "djangorestframework>=3.12", + "pyjwt<3,>=1.7.1", +] +files = [ + {file = "djangorestframework_simplejwt-5.3.1-py3-none-any.whl", hash = "sha256:381bc966aa46913905629d472cd72ad45faa265509764e20ffd440164c88d220"}, + {file = "djangorestframework_simplejwt-5.3.1.tar.gz", hash = "sha256:6c4bd37537440bc439564ebf7d6085e74c5411485197073f508ebdfa34bc9fae"}, +] + [[package]] name = "djlint" version = "1.34.0" @@ -1256,6 +1335,14 @@ files = [ {file = "flask-3.0.0.tar.gz", hash = "sha256:cfadcdb638b609361d29ec22360d6070a77d7463dcb3ab08d2c2f2f168845f58"}, ] +[[package]] +name = "fontawesomefree" +version = "6.6.0" +summary = "Font Awesome Free" +files = [ + {file = "fontawesomefree-6.6.0-py3-none-any.whl", hash = "sha256:599b574431c9bd92ed5fc054d1045a07c42335da36c17884f2b934755eef9089"}, +] + [[package]] name = "frozenlist" version = "1.4.1" @@ -1529,6 +1616,19 @@ files = [ {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, ] +[[package]] +name = "iommi" +version = "7.6.0" +summary = "iommi is a high level framework built on django" +dependencies = [ + "Django>=3.2", + "pyparsing", +] +files = [ + {file = "iommi-7.6.0-py2.py3-none-any.whl", hash = "sha256:4429f4bdd3f6b75b5acc41a9ab0b0de44249c56fcd3655693ef6cb5d7c3d49bb"}, + {file = "iommi-7.6.0.tar.gz", hash = "sha256:832a2c561a9263e1a1069d5a580f533b05b78e318cad22bef6f8ba087011b6d5"}, +] + [[package]] name = "ipdb" version = "0.13.13" @@ -3001,6 +3101,22 @@ files = [ {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] +[[package]] +name = "slippers" +version = "0.6.2" +requires_python = ">=3.8.0" +summary = "Build reusable components in Django without writing a single line of Python." +dependencies = [ + "Django>=3.2", + "PyYAML>=5.4.0", + "typeguard<3.0.0,>=2.13.3", + "typing-extensions>=4.4.0", +] +files = [ + {file = "slippers-0.6.2-py3-none-any.whl", hash = "sha256:739e05f85354becbf0a65daab831eea62557d89e7512042209ab629af4378bca"}, + {file = "slippers-0.6.2.tar.gz", hash = "sha256:4cb555b8822ba0d404e5405723f5d723994022c29046008ee917081031bc0cf1"}, +] + [[package]] name = "snowballstemmer" version = "2.2.0" @@ -3286,6 +3402,16 @@ files = [ {file = "traitlets-5.14.0.tar.gz", hash = "sha256:fcdaa8ac49c04dfa0ed3ee3384ef6dfdb5d6f3741502be247279407679296772"}, ] +[[package]] +name = "typeguard" +version = "2.13.3" +requires_python = ">=3.5.3" +summary = "Run-time type checker for Python" +files = [ + {file = "typeguard-2.13.3-py3-none-any.whl", hash = "sha256:5e3e3be01e887e7eafae5af63d1f36c849aaa94e3a0112097312aabfa16284f1"}, + {file = "typeguard-2.13.3.tar.gz", hash = "sha256:00edaa8da3a133674796cf5ea87d9f4b4c367d77476e185e80251cc13dfbb8c4"}, +] + [[package]] name = "types-python-dateutil" version = "2.8.19.14" diff --git a/pyproject.toml b/pyproject.toml index f98155b..7e57ebe 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -172,8 +172,18 @@ dependencies = [ "django-rest-framework>=0.1.0", "drf-spectacular>=0.27.2", "drf-nested-routers", + "dj-rest-auth", "drf-standardized-errors[openapi]", + "djangorestframework-simplejwt", "django-filter>=24.2", + "iommi", + "fontawesomefree", + "django-allauth", + "slippers", + "crispy-tailwind", + "django-tailwind", + "django-allauth-ui", + "django-widget-tweaks", ] requires-python = ">=3.10" name = "nina-catalogue" From ade9a81c1621ca34fb60d4e9056a1c56dab4a84d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niccol=C3=B2=20Cant=C3=B9?= Date: Mon, 21 Oct 2024 16:49:12 +0200 Subject: [PATCH 06/24] implement create / list / detail for datasets --- config/settings/base.py | 1 + .../core/templates/core/base.html | 4 +- .../templates/core/partials/navigation.html | 2 +- metadata_catalogue/datasets/forms.py | 67 +++++++++ ...t_notes_dataset_source_offline_and_more.py | 24 +++ metadata_catalogue/datasets/models.py | 138 ++++++++++++++---- metadata_catalogue/datasets/tables.py | 30 ++++ metadata_catalogue/datasets/urls.py | 14 +- metadata_catalogue/datasets/views.py | 51 ++++++- metadata_catalogue/templates/app.html | 7 + .../templates/core/partials/navigation.html | 2 +- .../templates/datasets/dataset_detail.html | 21 +++ .../templates/datasets/dataset_form.html | 16 ++ .../templates/datasets/dataset_list.html | 15 ++ metadata_catalogue/templates/pages/home.html | 11 +- .../theme/static_src/src/styles.css | 20 ++- .../theme/static_src/tailwind.config.js | 118 ++++++++------- pyproject.toml | 46 ++---- 18 files changed, 455 insertions(+), 132 deletions(-) create mode 100644 metadata_catalogue/datasets/forms.py create mode 100644 metadata_catalogue/datasets/migrations/0010_dataset_notes_dataset_source_offline_and_more.py create mode 100644 metadata_catalogue/datasets/tables.py create mode 100644 metadata_catalogue/templates/datasets/dataset_detail.html create mode 100644 metadata_catalogue/templates/datasets/dataset_form.html create mode 100644 metadata_catalogue/templates/datasets/dataset_list.html diff --git a/config/settings/base.py b/config/settings/base.py index 99e6e90..b8c2921 100644 --- a/config/settings/base.py +++ b/config/settings/base.py @@ -102,6 +102,7 @@ "drf_standardized_errors", "django_filters", "tailwind", + "django_tables2", "widget_tweaks", "slippers", "fontawesomefree", diff --git a/metadata_catalogue/core/templates/core/base.html b/metadata_catalogue/core/templates/core/base.html index 6ff1a57..a424353 100644 --- a/metadata_catalogue/core/templates/core/base.html +++ b/metadata_catalogue/core/templates/core/base.html @@ -54,8 +54,8 @@ {% endif %} {% block content %} {% endblock content %} - -
+ + {% endblock body %} {% block modal %} diff --git a/metadata_catalogue/core/templates/core/partials/navigation.html b/metadata_catalogue/core/templates/core/partials/navigation.html index 7eaf792..307595d 100755 --- a/metadata_catalogue/core/templates/core/partials/navigation.html +++ b/metadata_catalogue/core/templates/core/partials/navigation.html @@ -1,6 +1,6 @@ {% load i18n %} -
+