Compare commits
32 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fb2850d4fb | |||
| 87597b7701 | |||
| ae64b7764d | |||
| ed58fa228e | |||
| 8ceed77081 | |||
| d2ba54ec3a | |||
| 3416e2bdf1 | |||
| d952815932 | |||
| cde64ed80a | |||
| cfd88d0469 | |||
| 5e45fec296 | |||
| 393e7a06e2 | |||
| f1af87baf8 | |||
| f851ef2d85 | |||
| 252ab6a586 | |||
| cf2a02c8de | |||
| d87a2ed4eb | |||
| c9d053d1c0 | |||
| b5f0f06ea3 | |||
| 36b0ff9f63 | |||
| 7a383957a7 | |||
| b5630359ee | |||
| 310154815b | |||
| 2733785016 | |||
| 99ba414d88 | |||
| 41631b5b70 | |||
| 6ca654bf1a | |||
| 074585337b | |||
| f1b398e1ae | |||
| d1f73f18cd | |||
| 3f2d84bf62 | |||
| 7b9c362d38 |
@@ -8,27 +8,37 @@ and this project adheres to
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## Added
|
||||
## [3.3.0] - 2025-05-06
|
||||
|
||||
### Added
|
||||
|
||||
- ✨(backend) add endpoint checking media status #984
|
||||
- ✨(backend) allow setting session cookie age via env var #977
|
||||
- ✨(backend) allow theme customnization using a configuration file #948
|
||||
- ✨ Add a custom callout block to the editor #892
|
||||
- ✨(frontend) Add a custom callout block to the editor #892
|
||||
- 🚩(frontend) version MIT only #911
|
||||
- ✨(backend) integrate maleware_detection from django-lasuite #936
|
||||
- 🏗️(frontend) Footer configurable #959
|
||||
- 🩺(CI) add lint spell mistakes #954
|
||||
- ✨(frontend) create generic theme #792
|
||||
- 🛂(frontend) block edition to not connected users #945
|
||||
- 🚸(frontend) Let loader during upload analyze #984
|
||||
- 🚩(frontend) feature flag on blocking edition #997
|
||||
|
||||
## Changed
|
||||
### Changed
|
||||
|
||||
- 📝(frontend) Update documentation
|
||||
- ✅(frontend) Improve tests coverage
|
||||
- 📝(frontend) Update documentation #949
|
||||
- ✅(frontend) Improve tests coverage #949
|
||||
- ⬆️(docker) upgrade backend image to python 3.13 #973
|
||||
- ⬆️(docker) upgrade node images to alpine 3.21
|
||||
- ⬆️(docker) upgrade node images to alpine 3.21 #973
|
||||
|
||||
### Fixed
|
||||
- 🐛(y-provider) increase JSON size limits for transcription conversion #989
|
||||
|
||||
### Removed
|
||||
|
||||
- 🔥(back) remove footer endpoint
|
||||
- 🔥(back) remove footer endpoint #948
|
||||
|
||||
|
||||
## [3.2.1] - 2025-05-06
|
||||
|
||||
@@ -580,7 +590,8 @@ and this project adheres to
|
||||
- ✨(frontend) Coming Soon page (#67)
|
||||
- 🚀 Impress, project to manage your documents easily and collaboratively.
|
||||
|
||||
[unreleased]: https://github.com/numerique-gouv/impress/compare/v3.2.1...main
|
||||
[unreleased]: https://github.com/numerique-gouv/impress/compare/v3.3.0...main
|
||||
[v3.3.0]: https://github.com/numerique-gouv/impress/releases/v3.3.0
|
||||
[v3.2.1]: https://github.com/numerique-gouv/impress/releases/v3.2.1
|
||||
[v3.2.0]: https://github.com/numerique-gouv/impress/releases/v3.2.0
|
||||
[v3.1.0]: https://github.com/numerique-gouv/impress/releases/v3.1.0
|
||||
|
||||
@@ -57,7 +57,7 @@ Available methods: Helm chart, Nix package
|
||||
|
||||
In the works: Docker Compose, YunoHost
|
||||
|
||||
⚠️ For some advanced features (ex: Export as PDF) Docs relies on XL packages from BlockNote. These are licenced under AGPL-3.0 and are not MIT compatible. You can perfectly use Docs without these packages by setting the environment variable `PUBLISH_AS_MIT` to true. That way you'll build an image of the application without the features that are not MIT compatible. Read the [environment variables documentation](/docs/docs/env.md) for more information.
|
||||
⚠️ For some advanced features (ex: Export as PDF) Docs relies on XL packages from BlockNote. These are licenced under AGPL-3.0 and are not MIT compatible. You can perfectly use Docs without these packages by setting the environment variable `PUBLISH_AS_MIT` to true. That way you'll build an image of the application without the features that are not MIT compatible. Read the [environment variables documentation](/docs/env.md) for more information.
|
||||
|
||||
## Getting started 🔧
|
||||
|
||||
|
||||
@@ -16,6 +16,15 @@ the following command inside your docker container:
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [3.3.0] - 2025-05-22
|
||||
|
||||
⚠️ For some advanced features (ex: Export as PDF) Docs relies on XL packages from BlockNote. These are licenced under AGPL-3.0 and are not MIT compatible. You can perfectly use Docs without these packages by setting the environment variable `PUBLISH_AS_MIT` to true. That way you'll build an image of the application without the features that are not MIT compatible. Read the [environment variables documentation](/docs/docs/env.md) for more information.
|
||||
|
||||
The footer is now configurable from a customization file. To override the default one, you can
|
||||
use the `THEME_CUSTOMIZATION_FILE_PATH` environment variable to point to your customization file.
|
||||
The customization file must be a JSON file and must follow the rules described in the
|
||||
[theming documentation](docs/theming.md).
|
||||
|
||||
## [3.0.0] - 2025-03-28
|
||||
|
||||
We are not using the nginx auth request anymore to access the collaboration server (`yProvider`)
|
||||
|
||||
|
After Width: | Height: | Size: 19 KiB |
@@ -47,6 +47,7 @@ These are the environment variables you can set for the `impress-backend` contai
|
||||
| COLLABORATION_API_URL | collaboration api host | |
|
||||
| COLLABORATION_SERVER_SECRET | collaboration api secret | |
|
||||
| COLLABORATION_WS_URL | collaboration websocket url | |
|
||||
| COLLABORATION_WS_NOT_CONNECTED_READY_ONLY | Users not connected to the collaboration server cannot edit | false |
|
||||
| FRONTEND_CSS_URL | To add a external css file to the app | |
|
||||
| FRONTEND_HOMEPAGE_FEATURE_ENABLED | frontend feature flag to display the homepage | false |
|
||||
| FRONTEND_THEME | frontend theme to use | |
|
||||
|
||||
@@ -30,4 +30,27 @@ body {
|
||||
|
||||
Then, set the `FRONTEND_CSS_URL` environment variable to the URL of your custom CSS file. Once you've done this, our application will load your custom CSS file and apply the styles, changing the background color to the custom color you specified.
|
||||
|
||||
----
|
||||
|
||||
# **Footer Configuration** 📝
|
||||
|
||||
The footer is configurable from the theme customization file.
|
||||
|
||||
### Settings 🔧
|
||||
|
||||
```shellscript
|
||||
THEME_CUSTOMIZATION_FILE_PATH=<path>
|
||||
```
|
||||
|
||||
### Example of JSON
|
||||
|
||||
The json must follow some rules: https://github.com/suitenumerique/docs/blob/main/src/helm/env.d/dev/configuration/theme/demo.json
|
||||
|
||||
`footer.default` is the fallback if the language is not supported.
|
||||
|
||||
---
|
||||
Below is a visual example of a configured footer ⬇️:
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
@@ -61,6 +61,3 @@ COLLABORATION_BACKEND_BASE_URL=http://app-dev:8000
|
||||
COLLABORATION_SERVER_ORIGIN=http://localhost:3000
|
||||
COLLABORATION_SERVER_SECRET=my-secret
|
||||
COLLABORATION_WS_URL=ws://localhost:4444/collaboration/ws/
|
||||
|
||||
# Frontend
|
||||
FRONTEND_THEME=default
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
# For the CI job test-e2e
|
||||
SUSTAINED_THROTTLE_RATES="200/hour"
|
||||
BURST_THROTTLE_RATES="200/minute"
|
||||
DJANGO_SERVER_TO_SERVER_API_TOKENS=test-e2e
|
||||
SUSTAINED_THROTTLE_RATES="200/hour"
|
||||
Y_PROVIDER_API_KEY=yprovider-api-key
|
||||
Y_PROVIDER_API_BASE_URL=http://y-provider:4444/api/
|
||||
THEME_CUSTOMIZATION_FILE_PATH="" #force theme_customization to be empty
|
||||
@@ -4,7 +4,7 @@
|
||||
import json
|
||||
import logging
|
||||
import uuid
|
||||
from urllib.parse import unquote, urlparse
|
||||
from urllib.parse import unquote, urlencode, urlparse
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.postgres.aggregates import ArrayAgg
|
||||
@@ -18,6 +18,7 @@ from django.db import models as db
|
||||
from django.db.models.expressions import RawSQL
|
||||
from django.db.models.functions import Left, Length
|
||||
from django.http import Http404, StreamingHttpResponse
|
||||
from django.urls import reverse
|
||||
from django.utils.text import capfirst, slugify
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
@@ -1193,8 +1194,16 @@ class DocumentViewSet(
|
||||
|
||||
malware_detection.analyse_file(key, document_id=document.id)
|
||||
|
||||
url = reverse(
|
||||
"documents-media-check",
|
||||
kwargs={"pk": document.id},
|
||||
)
|
||||
parameters = urlencode({"key": key})
|
||||
|
||||
return drf.response.Response(
|
||||
{"file": f"{settings.MEDIA_URL:s}{key:s}"},
|
||||
{
|
||||
"file": f"{url:s}?{parameters:s}",
|
||||
},
|
||||
status=drf.status.HTTP_201_CREATED,
|
||||
)
|
||||
|
||||
@@ -1279,7 +1288,10 @@ class DocumentViewSet(
|
||||
# Check if the attachment is ready
|
||||
s3_client = default_storage.connection.meta.client
|
||||
bucket_name = default_storage.bucket_name
|
||||
head_resp = s3_client.head_object(Bucket=bucket_name, Key=key)
|
||||
try:
|
||||
head_resp = s3_client.head_object(Bucket=bucket_name, Key=key)
|
||||
except ClientError as err:
|
||||
raise drf.exceptions.PermissionDenied() from err
|
||||
metadata = head_resp.get("Metadata", {})
|
||||
# In order to be compatible with existing upload without `status` metadata,
|
||||
# we consider them as ready.
|
||||
@@ -1294,6 +1306,50 @@ class DocumentViewSet(
|
||||
|
||||
return drf.response.Response("authorized", headers=request.headers, status=200)
|
||||
|
||||
@drf.decorators.action(detail=True, methods=["get"], url_path="media-check")
|
||||
def media_check(self, request, *args, **kwargs):
|
||||
"""
|
||||
Check if the media is ready to be served.
|
||||
"""
|
||||
document = self.get_object()
|
||||
|
||||
key = request.query_params.get("key")
|
||||
if not key:
|
||||
return drf.response.Response(
|
||||
{"detail": "Missing 'key' query parameter"},
|
||||
status=drf.status.HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
|
||||
if key not in document.attachments:
|
||||
return drf.response.Response(
|
||||
{"detail": "Attachment missing"},
|
||||
status=drf.status.HTTP_404_NOT_FOUND,
|
||||
)
|
||||
|
||||
# Check if the attachment is ready
|
||||
s3_client = default_storage.connection.meta.client
|
||||
bucket_name = default_storage.bucket_name
|
||||
try:
|
||||
head_resp = s3_client.head_object(Bucket=bucket_name, Key=key)
|
||||
except ClientError as err:
|
||||
logger.error("Client Error fetching file %s metadata: %s", key, err)
|
||||
return drf.response.Response(
|
||||
{"detail": "Media not found"},
|
||||
status=drf.status.HTTP_404_NOT_FOUND,
|
||||
)
|
||||
metadata = head_resp.get("Metadata", {})
|
||||
|
||||
body = {
|
||||
"status": metadata.get("status", enums.DocumentAttachmentStatus.PROCESSING),
|
||||
}
|
||||
if metadata.get("status") == enums.DocumentAttachmentStatus.READY:
|
||||
body = {
|
||||
"status": enums.DocumentAttachmentStatus.READY,
|
||||
"file": f"{settings.MEDIA_URL:s}{key:s}",
|
||||
}
|
||||
|
||||
return drf.response.Response(body, status=drf.status.HTTP_200_OK)
|
||||
|
||||
@drf.decorators.action(
|
||||
detail=True,
|
||||
methods=["post"],
|
||||
@@ -1729,6 +1785,7 @@ class ConfigView(drf.views.APIView):
|
||||
array_settings = [
|
||||
"AI_FEATURE_ENABLED",
|
||||
"COLLABORATION_WS_URL",
|
||||
"COLLABORATION_WS_NOT_CONNECTED_READY_ONLY",
|
||||
"CRISP_WEBSITE_ID",
|
||||
"ENVIRONMENT",
|
||||
"FRONTEND_CSS_URL",
|
||||
|
||||
@@ -835,6 +835,7 @@ class Document(MP_Node, BaseModel):
|
||||
"ai_transform": ai_access,
|
||||
"ai_translate": ai_access,
|
||||
"attachment_upload": can_update,
|
||||
"media_check": can_get,
|
||||
"children_list": can_get,
|
||||
"children_create": can_update and user.is_authenticated,
|
||||
"collaboration_auth": can_get,
|
||||
|
||||
@@ -5,6 +5,7 @@ Test file uploads API endpoint for users in impress's core app.
|
||||
import re
|
||||
import uuid
|
||||
from unittest import mock
|
||||
from urllib.parse import parse_qs, urlparse
|
||||
|
||||
from django.core.files.storage import default_storage
|
||||
from django.core.files.uploadedfile import SimpleUploadedFile
|
||||
@@ -66,8 +67,12 @@ def test_api_documents_attachment_upload_anonymous_success():
|
||||
|
||||
assert response.status_code == 201
|
||||
|
||||
pattern = re.compile(rf"^/media/{document.id!s}/attachments/(.*)\.png")
|
||||
file_path = response.json()["file"]
|
||||
pattern = re.compile(rf"^{document.id!s}/attachments/(.*)\.png")
|
||||
url_parsed = urlparse(response.json()["file"])
|
||||
assert url_parsed.path == f"/api/v1.0/documents/{document.id!s}/media-check/"
|
||||
query = parse_qs(url_parsed.query)
|
||||
assert query["key"][0] is not None
|
||||
file_path = query["key"][0]
|
||||
match = pattern.search(file_path)
|
||||
file_id = match.group(1)
|
||||
# Validate that file_id is a valid UUID
|
||||
@@ -148,8 +153,13 @@ def test_api_documents_attachment_upload_authenticated_success(reach, role):
|
||||
|
||||
assert response.status_code == 201
|
||||
|
||||
pattern = re.compile(rf"^/media/{document.id!s}/attachments/(.*)\.png")
|
||||
match = pattern.search(response.json()["file"])
|
||||
pattern = re.compile(rf"^{document.id!s}/attachments/(.*)\.png")
|
||||
url_parsed = urlparse(response.json()["file"])
|
||||
assert url_parsed.path == f"/api/v1.0/documents/{document.id!s}/media-check/"
|
||||
query = parse_qs(url_parsed.query)
|
||||
assert query["key"][0] is not None
|
||||
file_path = query["key"][0]
|
||||
match = pattern.search(file_path)
|
||||
file_id = match.group(1)
|
||||
|
||||
mock_analyse_file.assert_called_once_with(
|
||||
@@ -224,8 +234,12 @@ def test_api_documents_attachment_upload_success(via, role, mock_user_teams):
|
||||
|
||||
assert response.status_code == 201
|
||||
|
||||
file_path = response.json()["file"]
|
||||
pattern = re.compile(rf"^/media/{document.id!s}/attachments/(.*)\.png")
|
||||
pattern = re.compile(rf"^{document.id!s}/attachments/(.*)\.png")
|
||||
url_parsed = urlparse(response.json()["file"])
|
||||
assert url_parsed.path == f"/api/v1.0/documents/{document.id!s}/media-check/"
|
||||
query = parse_qs(url_parsed.query)
|
||||
assert query["key"][0] is not None
|
||||
file_path = query["key"][0]
|
||||
match = pattern.search(file_path)
|
||||
file_id = match.group(1)
|
||||
|
||||
@@ -320,8 +334,13 @@ def test_api_documents_attachment_upload_fix_extension(
|
||||
|
||||
assert response.status_code == 201
|
||||
|
||||
file_path = response.json()["file"]
|
||||
pattern = re.compile(rf"^/media/{document.id!s}/attachments/(.*)\.{extension:s}")
|
||||
pattern = re.compile(rf"^{document.id!s}/attachments/(.*)\.{extension:s}")
|
||||
url_parsed = urlparse(response.json()["file"])
|
||||
assert url_parsed.path == f"/api/v1.0/documents/{document.id!s}/media-check/"
|
||||
query = parse_qs(url_parsed.query)
|
||||
assert query["key"][0] is not None
|
||||
file_path = query["key"][0]
|
||||
|
||||
match = pattern.search(file_path)
|
||||
file_id = match.group(1)
|
||||
|
||||
@@ -386,8 +405,12 @@ def test_api_documents_attachment_upload_unsafe():
|
||||
|
||||
assert response.status_code == 201
|
||||
|
||||
file_path = response.json()["file"]
|
||||
pattern = re.compile(rf"^/media/{document.id!s}/attachments/(.*)\.exe")
|
||||
pattern = re.compile(rf"^{document.id!s}/attachments/(.*)\.exe")
|
||||
url_parsed = urlparse(response.json()["file"])
|
||||
assert url_parsed.path == f"/api/v1.0/documents/{document.id!s}/media-check/"
|
||||
query = parse_qs(url_parsed.query)
|
||||
assert query["key"][0] is not None
|
||||
file_path = query["key"][0]
|
||||
match = pattern.search(file_path)
|
||||
file_id = match.group(1)
|
||||
|
||||
|
||||
@@ -0,0 +1,244 @@
|
||||
"""Test the "media_check" endpoint."""
|
||||
|
||||
from io import BytesIO
|
||||
from uuid import uuid4
|
||||
|
||||
from django.core.files.storage import default_storage
|
||||
|
||||
import pytest
|
||||
from rest_framework.test import APIClient
|
||||
|
||||
from core import factories
|
||||
from core.enums import DocumentAttachmentStatus
|
||||
from core.tests.conftest import TEAM, USER, VIA
|
||||
|
||||
pytestmark = pytest.mark.django_db
|
||||
|
||||
|
||||
def test_api_documents_media_check_unknown_document():
|
||||
"""
|
||||
The "media_check" endpoint should return a 404 error if the document does not exist.
|
||||
"""
|
||||
client = APIClient()
|
||||
response = client.get(f"/api/v1.0/documents/{uuid4()!s}media-check/")
|
||||
assert response.status_code == 404
|
||||
|
||||
|
||||
def test_api_documents_media_check_missing_key():
|
||||
"""
|
||||
The "media_check" endpoint should return a 404 error if the key is missing.
|
||||
"""
|
||||
user = factories.UserFactory()
|
||||
|
||||
client = APIClient()
|
||||
client.force_login(user=user)
|
||||
|
||||
document = factories.DocumentFactory(users=[user])
|
||||
|
||||
response = client.get(f"/api/v1.0/documents/{document.id!s}/media-check/")
|
||||
assert response.status_code == 400
|
||||
assert response.json() == {"detail": "Missing 'key' query parameter"}
|
||||
|
||||
|
||||
def test_api_documents_media_check_key_parameter_not_related_to_document():
|
||||
"""
|
||||
The "media_check" endpoint should return a 404 error if the key is not related to the document.
|
||||
"""
|
||||
user = factories.UserFactory()
|
||||
|
||||
client = APIClient()
|
||||
client.force_login(user=user)
|
||||
|
||||
document = factories.DocumentFactory(users=[user])
|
||||
|
||||
response = client.get(
|
||||
f"/api/v1.0/documents/{document.id!s}/media-check/",
|
||||
{"key": f"{document.id!s}/attachments/unknown.jpg"},
|
||||
)
|
||||
assert response.status_code == 404
|
||||
assert response.json() == {"detail": "Attachment missing"}
|
||||
|
||||
|
||||
def test_api_documents_media_check_anonymous_public_document():
|
||||
"""
|
||||
The "media_check" endpoint should return a 200 status code if the document is public.
|
||||
"""
|
||||
document = factories.DocumentFactory(link_reach="public")
|
||||
|
||||
filename = f"{uuid4()!s}.jpg"
|
||||
key = f"{document.id!s}/attachments/{filename:s}"
|
||||
default_storage.connection.meta.client.put_object(
|
||||
Bucket=default_storage.bucket_name,
|
||||
Key=key,
|
||||
Body=BytesIO(b"my prose"),
|
||||
ContentType="text/plain",
|
||||
Metadata={"status": DocumentAttachmentStatus.PROCESSING},
|
||||
)
|
||||
document.attachments = [key]
|
||||
document.save(update_fields=["attachments"])
|
||||
|
||||
client = APIClient()
|
||||
|
||||
response = client.get(
|
||||
f"/api/v1.0/documents/{document.id!s}/media-check/", {"key": key}
|
||||
)
|
||||
assert response.status_code == 200
|
||||
assert response.json() == {"status": DocumentAttachmentStatus.PROCESSING}
|
||||
|
||||
|
||||
def test_api_documents_media_check_anonymous_public_document_ready():
|
||||
"""
|
||||
The "media_check" endpoint should return a 200 status code if the document is public.
|
||||
"""
|
||||
document = factories.DocumentFactory(link_reach="public")
|
||||
|
||||
filename = f"{uuid4()!s}.jpg"
|
||||
key = f"{document.id!s}/attachments/{filename:s}"
|
||||
default_storage.connection.meta.client.put_object(
|
||||
Bucket=default_storage.bucket_name,
|
||||
Key=key,
|
||||
Body=BytesIO(b"my prose"),
|
||||
ContentType="text/plain",
|
||||
Metadata={"status": DocumentAttachmentStatus.READY},
|
||||
)
|
||||
document.attachments = [key]
|
||||
document.save(update_fields=["attachments"])
|
||||
|
||||
client = APIClient()
|
||||
|
||||
response = client.get(
|
||||
f"/api/v1.0/documents/{document.id!s}/media-check/", {"key": key}
|
||||
)
|
||||
assert response.status_code == 200
|
||||
assert response.json() == {
|
||||
"status": DocumentAttachmentStatus.READY,
|
||||
"file": f"/media/{key:s}",
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.parametrize("link_reach", ["restricted", "authenticated"])
|
||||
def test_api_documents_media_check_anonymous_non_public_document(link_reach):
|
||||
"""
|
||||
The "media_check" endpoint should return a 403 error if the document is not public.
|
||||
"""
|
||||
document = factories.DocumentFactory(link_reach=link_reach)
|
||||
|
||||
client = APIClient()
|
||||
|
||||
response = client.get(f"/api/v1.0/documents/{document.id!s}/media-check/")
|
||||
assert response.status_code == 401
|
||||
|
||||
|
||||
def test_api_documents_media_check_connected_document():
|
||||
"""
|
||||
The "media_check" endpoint should return a 200 status code for a user connected
|
||||
checking for a document with link_reach authenticated.
|
||||
"""
|
||||
document = factories.DocumentFactory(link_reach="authenticated")
|
||||
|
||||
filename = f"{uuid4()!s}.jpg"
|
||||
key = f"{document.id!s}/attachments/{filename:s}"
|
||||
default_storage.connection.meta.client.put_object(
|
||||
Bucket=default_storage.bucket_name,
|
||||
Key=key,
|
||||
Body=BytesIO(b"my prose"),
|
||||
ContentType="text/plain",
|
||||
Metadata={"status": DocumentAttachmentStatus.READY},
|
||||
)
|
||||
document.attachments = [key]
|
||||
document.save(update_fields=["attachments"])
|
||||
|
||||
user = factories.UserFactory()
|
||||
client = APIClient()
|
||||
client.force_login(user=user)
|
||||
|
||||
response = client.get(
|
||||
f"/api/v1.0/documents/{document.id!s}/media-check/", {"key": key}
|
||||
)
|
||||
assert response.status_code == 200
|
||||
assert response.json() == {
|
||||
"status": DocumentAttachmentStatus.READY,
|
||||
"file": f"/media/{key:s}",
|
||||
}
|
||||
|
||||
|
||||
def test_api_documents_media_check_connected_document_media_not_related():
|
||||
"""
|
||||
The "media_check" endpoint should return a 404 error if the key is not related to the document.
|
||||
"""
|
||||
document = factories.DocumentFactory(link_reach="authenticated")
|
||||
|
||||
filename = f"{uuid4()!s}.jpg"
|
||||
key = f"{document.id!s}/attachments/{filename:s}"
|
||||
|
||||
user = factories.UserFactory()
|
||||
client = APIClient()
|
||||
client.force_login(user=user)
|
||||
|
||||
response = client.get(
|
||||
f"/api/v1.0/documents/{document.id!s}/media-check/", {"key": key}
|
||||
)
|
||||
assert response.status_code == 404
|
||||
assert response.json() == {"detail": "Attachment missing"}
|
||||
|
||||
|
||||
def test_api_documents_media_check_media_missing_on_storage():
|
||||
"""
|
||||
The "media_check" endpoint should return a 404 error if the media is missing on storage.
|
||||
"""
|
||||
document = factories.DocumentFactory(link_reach="authenticated")
|
||||
|
||||
filename = f"{uuid4()!s}.jpg"
|
||||
key = f"{document.id!s}/attachments/{filename:s}"
|
||||
|
||||
document.attachments = [key]
|
||||
document.save(update_fields=["attachments"])
|
||||
|
||||
user = factories.UserFactory()
|
||||
client = APIClient()
|
||||
client.force_login(user=user)
|
||||
|
||||
response = client.get(
|
||||
f"/api/v1.0/documents/{document.id!s}/media-check/", {"key": key}
|
||||
)
|
||||
assert response.status_code == 404
|
||||
assert response.json() == {"detail": "Media not found"}
|
||||
|
||||
|
||||
@pytest.mark.parametrize("via", VIA)
|
||||
def test_api_documents_media_check_restricted_document(via, mock_user_teams):
|
||||
"""
|
||||
The "media_check" endpoint should return a 200 status code if the document is restricted and
|
||||
the user has access to it.
|
||||
"""
|
||||
document = factories.DocumentFactory(link_reach="restricted")
|
||||
filename = f"{uuid4()!s}.jpg"
|
||||
key = f"{document.id!s}/attachments/{filename:s}"
|
||||
default_storage.connection.meta.client.put_object(
|
||||
Bucket=default_storage.bucket_name,
|
||||
Key=key,
|
||||
Body=BytesIO(b"my prose"),
|
||||
ContentType="text/plain",
|
||||
Metadata={"status": DocumentAttachmentStatus.READY},
|
||||
)
|
||||
document.attachments = [key]
|
||||
document.save(update_fields=["attachments"])
|
||||
|
||||
user = factories.UserFactory()
|
||||
client = APIClient()
|
||||
client.force_login(user=user)
|
||||
|
||||
if via == USER:
|
||||
factories.UserDocumentAccessFactory(document=document, user=user)
|
||||
elif via == TEAM:
|
||||
mock_user_teams.return_value = ["lasuite", "unknown"]
|
||||
factories.TeamDocumentAccessFactory(document=document, team="lasuite")
|
||||
|
||||
response = client.get(
|
||||
f"/api/v1.0/documents/{document.id!s}/media-check/", {"key": key}
|
||||
)
|
||||
assert response.status_code == 200
|
||||
assert response.json() == {
|
||||
"status": DocumentAttachmentStatus.READY,
|
||||
"file": f"/media/{key:s}",
|
||||
}
|
||||
@@ -48,6 +48,7 @@ def test_api_documents_retrieve_anonymous_public_standalone():
|
||||
"restricted": ["reader", "editor"],
|
||||
},
|
||||
"media_auth": True,
|
||||
"media_check": True,
|
||||
"move": False,
|
||||
"partial_update": document.link_role == "editor",
|
||||
"restore": False,
|
||||
@@ -111,6 +112,7 @@ def test_api_documents_retrieve_anonymous_public_parent():
|
||||
"link_configuration": False,
|
||||
"link_select_options": models.LinkReachChoices.get_select_options(links),
|
||||
"media_auth": True,
|
||||
"media_check": True,
|
||||
"move": False,
|
||||
"partial_update": grand_parent.link_role == "editor",
|
||||
"restore": False,
|
||||
@@ -210,6 +212,7 @@ def test_api_documents_retrieve_authenticated_unrelated_public_or_authenticated(
|
||||
"restricted": ["reader", "editor"],
|
||||
},
|
||||
"media_auth": True,
|
||||
"media_check": True,
|
||||
"move": False,
|
||||
"partial_update": document.link_role == "editor",
|
||||
"restore": False,
|
||||
@@ -279,8 +282,9 @@ def test_api_documents_retrieve_authenticated_public_or_authenticated_parent(rea
|
||||
"invite_owner": False,
|
||||
"link_configuration": False,
|
||||
"link_select_options": models.LinkReachChoices.get_select_options(links),
|
||||
"move": False,
|
||||
"media_auth": True,
|
||||
"media_check": True,
|
||||
"move": False,
|
||||
"partial_update": grand_parent.link_role == "editor",
|
||||
"restore": False,
|
||||
"retrieve": True,
|
||||
@@ -460,6 +464,7 @@ def test_api_documents_retrieve_authenticated_related_parent():
|
||||
"link_configuration": access.role in ["administrator", "owner"],
|
||||
"link_select_options": models.LinkReachChoices.get_select_options(links),
|
||||
"media_auth": True,
|
||||
"media_check": True,
|
||||
"move": access.role in ["administrator", "owner"],
|
||||
"partial_update": access.role != "reader",
|
||||
"restore": access.role == "owner",
|
||||
|
||||
@@ -91,6 +91,7 @@ def test_api_documents_trashbin_format():
|
||||
"restricted": ["reader", "editor"],
|
||||
},
|
||||
"media_auth": True,
|
||||
"media_check": True,
|
||||
"move": False, # Can't move a deleted document
|
||||
"partial_update": True,
|
||||
"restore": True,
|
||||
|
||||
@@ -20,6 +20,7 @@ pytestmark = pytest.mark.django_db
|
||||
@override_settings(
|
||||
AI_FEATURE_ENABLED=False,
|
||||
COLLABORATION_WS_URL="http://testcollab/",
|
||||
COLLABORATION_WS_NOT_CONNECTED_READY_ONLY=True,
|
||||
CRISP_WEBSITE_ID="123",
|
||||
FRONTEND_CSS_URL="http://testcss/",
|
||||
FRONTEND_THEME="test-theme",
|
||||
@@ -41,6 +42,7 @@ def test_api_config(is_authenticated):
|
||||
assert response.status_code == HTTP_200_OK
|
||||
assert response.json() == {
|
||||
"COLLABORATION_WS_URL": "http://testcollab/",
|
||||
"COLLABORATION_WS_NOT_CONNECTED_READY_ONLY": True,
|
||||
"CRISP_WEBSITE_ID": "123",
|
||||
"ENVIRONMENT": "test",
|
||||
"FRONTEND_CSS_URL": "http://testcss/",
|
||||
|
||||
@@ -165,6 +165,7 @@ def test_models_documents_get_abilities_forbidden(
|
||||
"favorite": False,
|
||||
"invite_owner": False,
|
||||
"media_auth": False,
|
||||
"media_check": False,
|
||||
"move": False,
|
||||
"link_configuration": False,
|
||||
"link_select_options": {
|
||||
@@ -231,6 +232,7 @@ def test_models_documents_get_abilities_reader(
|
||||
"restricted": ["reader", "editor"],
|
||||
},
|
||||
"media_auth": True,
|
||||
"media_check": True,
|
||||
"move": False,
|
||||
"partial_update": False,
|
||||
"restore": False,
|
||||
@@ -293,6 +295,7 @@ def test_models_documents_get_abilities_editor(
|
||||
"restricted": ["reader", "editor"],
|
||||
},
|
||||
"media_auth": True,
|
||||
"media_check": True,
|
||||
"move": False,
|
||||
"partial_update": True,
|
||||
"restore": False,
|
||||
@@ -344,6 +347,7 @@ def test_models_documents_get_abilities_owner(django_assert_num_queries):
|
||||
"restricted": ["reader", "editor"],
|
||||
},
|
||||
"media_auth": True,
|
||||
"media_check": True,
|
||||
"move": True,
|
||||
"partial_update": True,
|
||||
"restore": True,
|
||||
@@ -392,6 +396,7 @@ def test_models_documents_get_abilities_administrator(django_assert_num_queries)
|
||||
"restricted": ["reader", "editor"],
|
||||
},
|
||||
"media_auth": True,
|
||||
"media_check": True,
|
||||
"move": True,
|
||||
"partial_update": True,
|
||||
"restore": False,
|
||||
@@ -443,6 +448,7 @@ def test_models_documents_get_abilities_editor_user(django_assert_num_queries):
|
||||
"restricted": ["reader", "editor"],
|
||||
},
|
||||
"media_auth": True,
|
||||
"media_check": True,
|
||||
"move": False,
|
||||
"partial_update": True,
|
||||
"restore": False,
|
||||
@@ -501,6 +507,7 @@ def test_models_documents_get_abilities_reader_user(
|
||||
"restricted": ["reader", "editor"],
|
||||
},
|
||||
"media_auth": True,
|
||||
"media_check": True,
|
||||
"move": False,
|
||||
"partial_update": access_from_link,
|
||||
"restore": False,
|
||||
@@ -557,6 +564,7 @@ def test_models_documents_get_abilities_preset_role(django_assert_num_queries):
|
||||
"restricted": ["reader", "editor"],
|
||||
},
|
||||
"media_auth": True,
|
||||
"media_check": True,
|
||||
"move": False,
|
||||
"partial_update": False,
|
||||
"restore": False,
|
||||
|
||||
@@ -1,124 +1,129 @@
|
||||
{
|
||||
"footer": {
|
||||
"default": {
|
||||
"externalLinks": [
|
||||
{
|
||||
"label": "Github",
|
||||
"href": "https://github.com/suitenumerique/docs/"
|
||||
},
|
||||
{
|
||||
"label": "DINUM",
|
||||
"href": "https://www.numerique.gouv.fr/dinum/"
|
||||
},
|
||||
{
|
||||
"label": "ZenDiS",
|
||||
"href": "https://zendis.de/"
|
||||
},
|
||||
{
|
||||
"label": "BlockNote.js",
|
||||
"href": "https://www.blocknotejs.org/"
|
||||
}
|
||||
],
|
||||
"bottomInformation": {
|
||||
"label": "Unless otherwise stated, all content on this site is under",
|
||||
"link": {
|
||||
"label": "licence etalab-2.0",
|
||||
"href": "https://github.com/etalab/licence-ouverte/blob/master/LO.md"
|
||||
}
|
||||
}
|
||||
"footer": {
|
||||
"default": {
|
||||
"logo": {
|
||||
"src": "/assets/icon-docs.svg",
|
||||
"width": "54px",
|
||||
"alt": "Docs Logo",
|
||||
"withTitle": true
|
||||
},
|
||||
"en": {
|
||||
"legalLinks": [
|
||||
{
|
||||
"label": "Legal Notice",
|
||||
"href": "#"
|
||||
},
|
||||
{
|
||||
"label": "Personal data and cookies",
|
||||
"href": "#"
|
||||
},
|
||||
{
|
||||
"label": "Accessibility",
|
||||
"href": "#"
|
||||
}
|
||||
],
|
||||
"bottomInformation": {
|
||||
"label": "Unless otherwise stated, all content on this site is under",
|
||||
"link": {
|
||||
"label": "licence MIT",
|
||||
"href": "https://github.com/suitenumerique/docs/blob/main/LICENSE"
|
||||
}
|
||||
"externalLinks": [
|
||||
{
|
||||
"label": "Github",
|
||||
"href": "https://github.com/suitenumerique/docs/"
|
||||
},
|
||||
{
|
||||
"label": "DINUM",
|
||||
"href": "https://www.numerique.gouv.fr/dinum/"
|
||||
},
|
||||
{
|
||||
"label": "ZenDiS",
|
||||
"href": "https://zendis.de/"
|
||||
},
|
||||
{
|
||||
"label": "BlockNote.js",
|
||||
"href": "https://www.blocknotejs.org/"
|
||||
}
|
||||
},
|
||||
"fr": {
|
||||
"legalLinks": [
|
||||
{
|
||||
"label": "Mentions légales",
|
||||
"href": "#"
|
||||
},
|
||||
{
|
||||
"label": "Données personnelles et cookies",
|
||||
"href": "#"
|
||||
},
|
||||
{
|
||||
"label": "Accessibilité",
|
||||
"href": "#"
|
||||
}
|
||||
],
|
||||
"bottomInformation": {
|
||||
"label": "Sauf mention contraire, tout le contenu de ce site est sous",
|
||||
"link": {
|
||||
"label": "licence MIT",
|
||||
"href": "https://github.com/suitenumerique/docs/blob/main/LICENSE"
|
||||
}
|
||||
],
|
||||
"bottomInformation": {
|
||||
"label": "Unless otherwise stated, all content on this site is under",
|
||||
"link": {
|
||||
"label": "licence etalab-2.0",
|
||||
"href": "https://github.com/etalab/licence-ouverte/blob/master/LO.md"
|
||||
}
|
||||
},
|
||||
"de": {
|
||||
"legalLinks": [
|
||||
{
|
||||
"label": "Impressum",
|
||||
"href": "#"
|
||||
},
|
||||
{
|
||||
"label": "Personenbezogene Daten und Cookies",
|
||||
"href": "#"
|
||||
},
|
||||
{
|
||||
"label": "Barrierefreiheit",
|
||||
"href": "#"
|
||||
}
|
||||
],
|
||||
"bottomInformation": {
|
||||
"label": "Sofern nicht anders angegeben, steht der gesamte Inhalt dieser Website unter",
|
||||
"link": {
|
||||
"label": "licence MIT",
|
||||
"href": "https://github.com/suitenumerique/docs/blob/main/LICENSE"
|
||||
}
|
||||
}
|
||||
},
|
||||
"en": {
|
||||
"legalLinks": [
|
||||
{
|
||||
"label": "Legal Notice",
|
||||
"href": "#"
|
||||
},
|
||||
{
|
||||
"label": "Personal data and cookies",
|
||||
"href": "#"
|
||||
},
|
||||
{
|
||||
"label": "Accessibility",
|
||||
"href": "#"
|
||||
}
|
||||
},
|
||||
"nl": {
|
||||
"legalLinks": [
|
||||
{
|
||||
"label": "Wettelijke bepalingen",
|
||||
"href": "#"
|
||||
},
|
||||
{
|
||||
"label": "Persoonlijke gegevens en cookies",
|
||||
"href": "#"
|
||||
},
|
||||
{
|
||||
"label": "Toegankelijkheid",
|
||||
"href": "#"
|
||||
}
|
||||
],
|
||||
"bottomInformation": {
|
||||
"label": "Tenzij anders vermeld, is alle inhoud van deze site ondergebracht onder",
|
||||
"link": {
|
||||
"label": "licence MIT",
|
||||
"href": "https://github.com/suitenumerique/docs/blob/main/LICENSE"
|
||||
}
|
||||
],
|
||||
"bottomInformation": {
|
||||
"label": "Unless otherwise stated, all content on this site is under",
|
||||
"link": {
|
||||
"label": "licence MIT",
|
||||
"href": "https://github.com/suitenumerique/docs/blob/main/LICENSE"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fr": {
|
||||
"legalLinks": [
|
||||
{
|
||||
"label": "Mentions légales",
|
||||
"href": "#"
|
||||
},
|
||||
{
|
||||
"label": "Données personnelles et cookies",
|
||||
"href": "#"
|
||||
},
|
||||
{
|
||||
"label": "Accessibilité",
|
||||
"href": "#"
|
||||
}
|
||||
],
|
||||
"bottomInformation": {
|
||||
"label": "Sauf mention contraire, tout le contenu de ce site est sous",
|
||||
"link": {
|
||||
"label": "licence MIT",
|
||||
"href": "https://github.com/suitenumerique/docs/blob/main/LICENSE"
|
||||
}
|
||||
}
|
||||
},
|
||||
"de": {
|
||||
"legalLinks": [
|
||||
{
|
||||
"label": "Impressum",
|
||||
"href": "#"
|
||||
},
|
||||
{
|
||||
"label": "Personenbezogene Daten und Cookies",
|
||||
"href": "#"
|
||||
},
|
||||
{
|
||||
"label": "Barrierefreiheit",
|
||||
"href": "#"
|
||||
}
|
||||
],
|
||||
"bottomInformation": {
|
||||
"label": "Sofern nicht anders angegeben, steht der gesamte Inhalt dieser Website unter",
|
||||
"link": {
|
||||
"label": "licence MIT",
|
||||
"href": "https://github.com/suitenumerique/docs/blob/main/LICENSE"
|
||||
}
|
||||
}
|
||||
},
|
||||
"nl": {
|
||||
"legalLinks": [
|
||||
{
|
||||
"label": "Wettelijke bepalingen",
|
||||
"href": "#"
|
||||
},
|
||||
{
|
||||
"label": "Persoonlijke gegevens en cookies",
|
||||
"href": "#"
|
||||
},
|
||||
{
|
||||
"label": "Toegankelijkheid",
|
||||
"href": "#"
|
||||
}
|
||||
],
|
||||
"bottomInformation": {
|
||||
"label": "Tenzij anders vermeld, is alle inhoud van deze site ondergebracht onder",
|
||||
"link": {
|
||||
"label": "licence MIT",
|
||||
"href": "https://github.com/suitenumerique/docs/blob/main/LICENSE"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -413,6 +413,11 @@ class Base(Configuration):
|
||||
COLLABORATION_WS_URL = values.Value(
|
||||
None, environ_name="COLLABORATION_WS_URL", environ_prefix=None
|
||||
)
|
||||
COLLABORATION_WS_NOT_CONNECTED_READY_ONLY = values.BooleanValue(
|
||||
False,
|
||||
environ_name="COLLABORATION_WS_NOT_CONNECTED_READY_ONLY",
|
||||
environ_prefix=None,
|
||||
)
|
||||
|
||||
# Frontend
|
||||
FRONTEND_THEME = values.Value(
|
||||
@@ -679,6 +684,15 @@ class Base(Configuration):
|
||||
),
|
||||
"propagate": False,
|
||||
},
|
||||
"docs.security": {
|
||||
"handlers": ["console"],
|
||||
"level": values.Value(
|
||||
"INFO",
|
||||
environ_name="LOGGING_LEVEL_LOGGERS_SECURITY",
|
||||
environ_prefix=None,
|
||||
),
|
||||
"propagate": False,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: lasuite-docs\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-04-29 11:48+0000\n"
|
||||
"PO-Revision-Date: 2025-05-05 07:07\n"
|
||||
"POT-Creation-Date: 2025-05-22 12:09+0000\n"
|
||||
"PO-Revision-Date: 2025-05-22 14:16\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Breton\n"
|
||||
"Language: br_FR\n"
|
||||
@@ -66,32 +66,32 @@ msgstr "Doare korf"
|
||||
msgid "Format"
|
||||
msgstr "Stumm"
|
||||
|
||||
#: build/lib/core/api/viewsets.py:966 core/api/viewsets.py:966
|
||||
#: build/lib/core/api/viewsets.py:967 core/api/viewsets.py:967
|
||||
#, python-brace-format
|
||||
msgid "copy of {title}"
|
||||
msgstr "eilenn {title}"
|
||||
|
||||
#: build/lib/core/enums.py:35 core/enums.py:35
|
||||
#: build/lib/core/enums.py:36 core/enums.py:36
|
||||
msgid "First child"
|
||||
msgstr "Bugel kentañ"
|
||||
|
||||
#: build/lib/core/enums.py:36 core/enums.py:36
|
||||
#: build/lib/core/enums.py:37 core/enums.py:37
|
||||
msgid "Last child"
|
||||
msgstr "Bugel diwezhañ"
|
||||
|
||||
#: build/lib/core/enums.py:37 core/enums.py:37
|
||||
#: build/lib/core/enums.py:38 core/enums.py:38
|
||||
msgid "First sibling"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/enums.py:38 core/enums.py:38
|
||||
#: build/lib/core/enums.py:39 core/enums.py:39
|
||||
msgid "Last sibling"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/enums.py:39 core/enums.py:39
|
||||
#: build/lib/core/enums.py:40 core/enums.py:40
|
||||
msgid "Left"
|
||||
msgstr "Kleiz"
|
||||
|
||||
#: build/lib/core/enums.py:40 core/enums.py:40
|
||||
#: build/lib/core/enums.py:41 core/enums.py:41
|
||||
msgid "Right"
|
||||
msgstr "Dehoù"
|
||||
|
||||
@@ -225,8 +225,8 @@ msgstr "implijer"
|
||||
msgid "users"
|
||||
msgstr "implijerien"
|
||||
|
||||
#: build/lib/core/models.py:470 build/lib/core/models.py:1154
|
||||
#: core/models.py:470 core/models.py:1154
|
||||
#: build/lib/core/models.py:470 build/lib/core/models.py:1155
|
||||
#: core/models.py:470 core/models.py:1155
|
||||
msgid "title"
|
||||
msgstr "titl"
|
||||
|
||||
@@ -242,128 +242,128 @@ msgstr ""
|
||||
msgid "Documents"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:532 build/lib/core/models.py:872 core/models.py:532
|
||||
#: core/models.py:872
|
||||
#: build/lib/core/models.py:532 build/lib/core/models.py:873 core/models.py:532
|
||||
#: core/models.py:873
|
||||
msgid "Untitled Document"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:907 core/models.py:907
|
||||
#: build/lib/core/models.py:908 core/models.py:908
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you!"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:911 core/models.py:911
|
||||
#: build/lib/core/models.py:912 core/models.py:912
|
||||
#, python-brace-format
|
||||
msgid "{name} invited you with the role \"{role}\" on the following document:"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:917 core/models.py:917
|
||||
#: build/lib/core/models.py:918 core/models.py:918
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you: {title}"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1015 core/models.py:1015
|
||||
#: build/lib/core/models.py:1016 core/models.py:1016
|
||||
msgid "Document/user link trace"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1016 core/models.py:1016
|
||||
#: build/lib/core/models.py:1017 core/models.py:1017
|
||||
msgid "Document/user link traces"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1022 core/models.py:1022
|
||||
#: build/lib/core/models.py:1023 core/models.py:1023
|
||||
msgid "A link trace already exists for this document/user."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1045 core/models.py:1045
|
||||
#: build/lib/core/models.py:1046 core/models.py:1046
|
||||
msgid "Document favorite"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1046 core/models.py:1046
|
||||
#: build/lib/core/models.py:1047 core/models.py:1047
|
||||
msgid "Document favorites"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1052 core/models.py:1052
|
||||
#: build/lib/core/models.py:1053 core/models.py:1053
|
||||
msgid "This document is already targeted by a favorite relation instance for the same user."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1074 core/models.py:1074
|
||||
#: build/lib/core/models.py:1075 core/models.py:1075
|
||||
msgid "Document/user relation"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1075 core/models.py:1075
|
||||
#: build/lib/core/models.py:1076 core/models.py:1076
|
||||
msgid "Document/user relations"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1081 core/models.py:1081
|
||||
#: build/lib/core/models.py:1082 core/models.py:1082
|
||||
msgid "This user is already in this document."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1087 core/models.py:1087
|
||||
#: build/lib/core/models.py:1088 core/models.py:1088
|
||||
msgid "This team is already in this document."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1093 build/lib/core/models.py:1241
|
||||
#: core/models.py:1093 core/models.py:1241
|
||||
#: build/lib/core/models.py:1094 build/lib/core/models.py:1242
|
||||
#: core/models.py:1094 core/models.py:1242
|
||||
msgid "Either user or team must be set, not both."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1155 core/models.py:1155
|
||||
#: build/lib/core/models.py:1156 core/models.py:1156
|
||||
msgid "description"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1156 core/models.py:1156
|
||||
#: build/lib/core/models.py:1157 core/models.py:1157
|
||||
msgid "code"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1157 core/models.py:1157
|
||||
#: build/lib/core/models.py:1158 core/models.py:1158
|
||||
msgid "css"
|
||||
msgstr "css"
|
||||
|
||||
#: build/lib/core/models.py:1159 core/models.py:1159
|
||||
#: build/lib/core/models.py:1160 core/models.py:1160
|
||||
msgid "public"
|
||||
msgstr "publik"
|
||||
|
||||
#: build/lib/core/models.py:1161 core/models.py:1161
|
||||
#: build/lib/core/models.py:1162 core/models.py:1162
|
||||
msgid "Whether this template is public for anyone to use."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1167 core/models.py:1167
|
||||
#: build/lib/core/models.py:1168 core/models.py:1168
|
||||
msgid "Template"
|
||||
msgstr "Patrom"
|
||||
|
||||
#: build/lib/core/models.py:1168 core/models.py:1168
|
||||
#: build/lib/core/models.py:1169 core/models.py:1169
|
||||
msgid "Templates"
|
||||
msgstr "Patromoù"
|
||||
|
||||
#: build/lib/core/models.py:1222 core/models.py:1222
|
||||
#: build/lib/core/models.py:1223 core/models.py:1223
|
||||
msgid "Template/user relation"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1223 core/models.py:1223
|
||||
#: build/lib/core/models.py:1224 core/models.py:1224
|
||||
msgid "Template/user relations"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1229 core/models.py:1229
|
||||
#: build/lib/core/models.py:1230 core/models.py:1230
|
||||
msgid "This user is already in this template."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1235 core/models.py:1235
|
||||
#: build/lib/core/models.py:1236 core/models.py:1236
|
||||
msgid "This team is already in this template."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1258 core/models.py:1258
|
||||
#: build/lib/core/models.py:1259 core/models.py:1259
|
||||
msgid "email address"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1277 core/models.py:1277
|
||||
#: build/lib/core/models.py:1278 core/models.py:1278
|
||||
msgid "Document invitation"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1278 core/models.py:1278
|
||||
#: build/lib/core/models.py:1279 core/models.py:1279
|
||||
msgid "Document invitations"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1298 core/models.py:1298
|
||||
#: build/lib/core/models.py:1299 core/models.py:1299
|
||||
msgid "This email is already associated to a registered user."
|
||||
msgstr ""
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: lasuite-docs\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-04-29 11:48+0000\n"
|
||||
"PO-Revision-Date: 2025-05-05 07:07\n"
|
||||
"POT-Creation-Date: 2025-05-22 12:09+0000\n"
|
||||
"PO-Revision-Date: 2025-05-22 14:16\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: German\n"
|
||||
"Language: de_DE\n"
|
||||
@@ -66,32 +66,32 @@ msgstr "Typ"
|
||||
msgid "Format"
|
||||
msgstr "Format"
|
||||
|
||||
#: build/lib/core/api/viewsets.py:966 core/api/viewsets.py:966
|
||||
#: build/lib/core/api/viewsets.py:967 core/api/viewsets.py:967
|
||||
#, python-brace-format
|
||||
msgid "copy of {title}"
|
||||
msgstr "Kopie von {title}"
|
||||
|
||||
#: build/lib/core/enums.py:35 core/enums.py:35
|
||||
#: build/lib/core/enums.py:36 core/enums.py:36
|
||||
msgid "First child"
|
||||
msgstr "Erstes Unterelement"
|
||||
|
||||
#: build/lib/core/enums.py:36 core/enums.py:36
|
||||
#: build/lib/core/enums.py:37 core/enums.py:37
|
||||
msgid "Last child"
|
||||
msgstr "Letztes Unterelement"
|
||||
|
||||
#: build/lib/core/enums.py:37 core/enums.py:37
|
||||
#: build/lib/core/enums.py:38 core/enums.py:38
|
||||
msgid "First sibling"
|
||||
msgstr "Erstes Nebenelement"
|
||||
|
||||
#: build/lib/core/enums.py:38 core/enums.py:38
|
||||
#: build/lib/core/enums.py:39 core/enums.py:39
|
||||
msgid "Last sibling"
|
||||
msgstr "Letztes Nebenelement"
|
||||
|
||||
#: build/lib/core/enums.py:39 core/enums.py:39
|
||||
#: build/lib/core/enums.py:40 core/enums.py:40
|
||||
msgid "Left"
|
||||
msgstr "Links"
|
||||
|
||||
#: build/lib/core/enums.py:40 core/enums.py:40
|
||||
#: build/lib/core/enums.py:41 core/enums.py:41
|
||||
msgid "Right"
|
||||
msgstr "Rechts"
|
||||
|
||||
@@ -225,8 +225,8 @@ msgstr "Benutzer"
|
||||
msgid "users"
|
||||
msgstr "Benutzer"
|
||||
|
||||
#: build/lib/core/models.py:470 build/lib/core/models.py:1154
|
||||
#: core/models.py:470 core/models.py:1154
|
||||
#: build/lib/core/models.py:470 build/lib/core/models.py:1155
|
||||
#: core/models.py:470 core/models.py:1155
|
||||
msgid "title"
|
||||
msgstr "Titel"
|
||||
|
||||
@@ -242,128 +242,128 @@ msgstr "Dokument"
|
||||
msgid "Documents"
|
||||
msgstr "Dokumente"
|
||||
|
||||
#: build/lib/core/models.py:532 build/lib/core/models.py:872 core/models.py:532
|
||||
#: core/models.py:872
|
||||
#: build/lib/core/models.py:532 build/lib/core/models.py:873 core/models.py:532
|
||||
#: core/models.py:873
|
||||
msgid "Untitled Document"
|
||||
msgstr "Unbenanntes Dokument"
|
||||
|
||||
#: build/lib/core/models.py:907 core/models.py:907
|
||||
#: build/lib/core/models.py:908 core/models.py:908
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you!"
|
||||
msgstr "{name} hat ein Dokument mit Ihnen geteilt!"
|
||||
|
||||
#: build/lib/core/models.py:911 core/models.py:911
|
||||
#: build/lib/core/models.py:912 core/models.py:912
|
||||
#, python-brace-format
|
||||
msgid "{name} invited you with the role \"{role}\" on the following document:"
|
||||
msgstr "{name} hat Sie mit der Rolle \"{role}\" zu folgendem Dokument eingeladen:"
|
||||
|
||||
#: build/lib/core/models.py:917 core/models.py:917
|
||||
#: build/lib/core/models.py:918 core/models.py:918
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you: {title}"
|
||||
msgstr "{name} hat ein Dokument mit Ihnen geteilt: {title}"
|
||||
|
||||
#: build/lib/core/models.py:1015 core/models.py:1015
|
||||
#: build/lib/core/models.py:1016 core/models.py:1016
|
||||
msgid "Document/user link trace"
|
||||
msgstr "Dokument/Benutzer Linkverfolgung"
|
||||
|
||||
#: build/lib/core/models.py:1016 core/models.py:1016
|
||||
#: build/lib/core/models.py:1017 core/models.py:1017
|
||||
msgid "Document/user link traces"
|
||||
msgstr "Dokument/Benutzer Linkverfolgung"
|
||||
|
||||
#: build/lib/core/models.py:1022 core/models.py:1022
|
||||
#: build/lib/core/models.py:1023 core/models.py:1023
|
||||
msgid "A link trace already exists for this document/user."
|
||||
msgstr "Für dieses Dokument/ diesen Benutzer ist bereits eine Linkverfolgung vorhanden."
|
||||
|
||||
#: build/lib/core/models.py:1045 core/models.py:1045
|
||||
#: build/lib/core/models.py:1046 core/models.py:1046
|
||||
msgid "Document favorite"
|
||||
msgstr "Dokumentenfavorit"
|
||||
|
||||
#: build/lib/core/models.py:1046 core/models.py:1046
|
||||
#: build/lib/core/models.py:1047 core/models.py:1047
|
||||
msgid "Document favorites"
|
||||
msgstr "Dokumentfavoriten"
|
||||
|
||||
#: build/lib/core/models.py:1052 core/models.py:1052
|
||||
#: build/lib/core/models.py:1053 core/models.py:1053
|
||||
msgid "This document is already targeted by a favorite relation instance for the same user."
|
||||
msgstr "Dieses Dokument ist bereits durch den gleichen Benutzer favorisiert worden."
|
||||
|
||||
#: build/lib/core/models.py:1074 core/models.py:1074
|
||||
#: build/lib/core/models.py:1075 core/models.py:1075
|
||||
msgid "Document/user relation"
|
||||
msgstr "Dokument/Benutzerbeziehung"
|
||||
|
||||
#: build/lib/core/models.py:1075 core/models.py:1075
|
||||
#: build/lib/core/models.py:1076 core/models.py:1076
|
||||
msgid "Document/user relations"
|
||||
msgstr "Dokument/Benutzerbeziehungen"
|
||||
|
||||
#: build/lib/core/models.py:1081 core/models.py:1081
|
||||
#: build/lib/core/models.py:1082 core/models.py:1082
|
||||
msgid "This user is already in this document."
|
||||
msgstr "Dieser Benutzer befindet sich bereits in diesem Dokument."
|
||||
|
||||
#: build/lib/core/models.py:1087 core/models.py:1087
|
||||
#: build/lib/core/models.py:1088 core/models.py:1088
|
||||
msgid "This team is already in this document."
|
||||
msgstr "Dieses Team befindet sich bereits in diesem Dokument."
|
||||
|
||||
#: build/lib/core/models.py:1093 build/lib/core/models.py:1241
|
||||
#: core/models.py:1093 core/models.py:1241
|
||||
#: build/lib/core/models.py:1094 build/lib/core/models.py:1242
|
||||
#: core/models.py:1094 core/models.py:1242
|
||||
msgid "Either user or team must be set, not both."
|
||||
msgstr "Benutzer oder Team müssen gesetzt werden, nicht beides."
|
||||
|
||||
#: build/lib/core/models.py:1155 core/models.py:1155
|
||||
#: build/lib/core/models.py:1156 core/models.py:1156
|
||||
msgid "description"
|
||||
msgstr "Beschreibung"
|
||||
|
||||
#: build/lib/core/models.py:1156 core/models.py:1156
|
||||
#: build/lib/core/models.py:1157 core/models.py:1157
|
||||
msgid "code"
|
||||
msgstr "Code"
|
||||
|
||||
#: build/lib/core/models.py:1157 core/models.py:1157
|
||||
#: build/lib/core/models.py:1158 core/models.py:1158
|
||||
msgid "css"
|
||||
msgstr "CSS"
|
||||
|
||||
#: build/lib/core/models.py:1159 core/models.py:1159
|
||||
#: build/lib/core/models.py:1160 core/models.py:1160
|
||||
msgid "public"
|
||||
msgstr "öffentlich"
|
||||
|
||||
#: build/lib/core/models.py:1161 core/models.py:1161
|
||||
#: build/lib/core/models.py:1162 core/models.py:1162
|
||||
msgid "Whether this template is public for anyone to use."
|
||||
msgstr "Ob diese Vorlage für jedermann öffentlich ist."
|
||||
|
||||
#: build/lib/core/models.py:1167 core/models.py:1167
|
||||
#: build/lib/core/models.py:1168 core/models.py:1168
|
||||
msgid "Template"
|
||||
msgstr "Vorlage"
|
||||
|
||||
#: build/lib/core/models.py:1168 core/models.py:1168
|
||||
#: build/lib/core/models.py:1169 core/models.py:1169
|
||||
msgid "Templates"
|
||||
msgstr "Vorlagen"
|
||||
|
||||
#: build/lib/core/models.py:1222 core/models.py:1222
|
||||
#: build/lib/core/models.py:1223 core/models.py:1223
|
||||
msgid "Template/user relation"
|
||||
msgstr "Vorlage/Benutzer-Beziehung"
|
||||
|
||||
#: build/lib/core/models.py:1223 core/models.py:1223
|
||||
#: build/lib/core/models.py:1224 core/models.py:1224
|
||||
msgid "Template/user relations"
|
||||
msgstr "Vorlage/Benutzerbeziehungen"
|
||||
|
||||
#: build/lib/core/models.py:1229 core/models.py:1229
|
||||
#: build/lib/core/models.py:1230 core/models.py:1230
|
||||
msgid "This user is already in this template."
|
||||
msgstr "Dieser Benutzer ist bereits in dieser Vorlage."
|
||||
|
||||
#: build/lib/core/models.py:1235 core/models.py:1235
|
||||
#: build/lib/core/models.py:1236 core/models.py:1236
|
||||
msgid "This team is already in this template."
|
||||
msgstr "Dieses Team ist bereits in diesem Template."
|
||||
|
||||
#: build/lib/core/models.py:1258 core/models.py:1258
|
||||
#: build/lib/core/models.py:1259 core/models.py:1259
|
||||
msgid "email address"
|
||||
msgstr "E-Mail-Adresse"
|
||||
|
||||
#: build/lib/core/models.py:1277 core/models.py:1277
|
||||
#: build/lib/core/models.py:1278 core/models.py:1278
|
||||
msgid "Document invitation"
|
||||
msgstr "Einladung zum Dokument"
|
||||
|
||||
#: build/lib/core/models.py:1278 core/models.py:1278
|
||||
#: build/lib/core/models.py:1279 core/models.py:1279
|
||||
msgid "Document invitations"
|
||||
msgstr "Dokumenteinladungen"
|
||||
|
||||
#: build/lib/core/models.py:1298 core/models.py:1298
|
||||
#: build/lib/core/models.py:1299 core/models.py:1299
|
||||
msgid "This email is already associated to a registered user."
|
||||
msgstr "Diese E-Mail ist bereits einem registrierten Benutzer zugeordnet."
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: lasuite-docs\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-04-29 11:48+0000\n"
|
||||
"PO-Revision-Date: 2025-05-05 07:07\n"
|
||||
"POT-Creation-Date: 2025-05-22 12:09+0000\n"
|
||||
"PO-Revision-Date: 2025-05-22 14:16\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: English\n"
|
||||
"Language: en_US\n"
|
||||
@@ -66,32 +66,32 @@ msgstr ""
|
||||
msgid "Format"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/api/viewsets.py:966 core/api/viewsets.py:966
|
||||
#: build/lib/core/api/viewsets.py:967 core/api/viewsets.py:967
|
||||
#, python-brace-format
|
||||
msgid "copy of {title}"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/enums.py:35 core/enums.py:35
|
||||
#: build/lib/core/enums.py:36 core/enums.py:36
|
||||
msgid "First child"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/enums.py:36 core/enums.py:36
|
||||
#: build/lib/core/enums.py:37 core/enums.py:37
|
||||
msgid "Last child"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/enums.py:37 core/enums.py:37
|
||||
#: build/lib/core/enums.py:38 core/enums.py:38
|
||||
msgid "First sibling"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/enums.py:38 core/enums.py:38
|
||||
#: build/lib/core/enums.py:39 core/enums.py:39
|
||||
msgid "Last sibling"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/enums.py:39 core/enums.py:39
|
||||
#: build/lib/core/enums.py:40 core/enums.py:40
|
||||
msgid "Left"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/enums.py:40 core/enums.py:40
|
||||
#: build/lib/core/enums.py:41 core/enums.py:41
|
||||
msgid "Right"
|
||||
msgstr ""
|
||||
|
||||
@@ -225,8 +225,8 @@ msgstr ""
|
||||
msgid "users"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:470 build/lib/core/models.py:1154
|
||||
#: core/models.py:470 core/models.py:1154
|
||||
#: build/lib/core/models.py:470 build/lib/core/models.py:1155
|
||||
#: core/models.py:470 core/models.py:1155
|
||||
msgid "title"
|
||||
msgstr ""
|
||||
|
||||
@@ -242,128 +242,128 @@ msgstr ""
|
||||
msgid "Documents"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:532 build/lib/core/models.py:872 core/models.py:532
|
||||
#: core/models.py:872
|
||||
#: build/lib/core/models.py:532 build/lib/core/models.py:873 core/models.py:532
|
||||
#: core/models.py:873
|
||||
msgid "Untitled Document"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:907 core/models.py:907
|
||||
#: build/lib/core/models.py:908 core/models.py:908
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you!"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:911 core/models.py:911
|
||||
#: build/lib/core/models.py:912 core/models.py:912
|
||||
#, python-brace-format
|
||||
msgid "{name} invited you with the role \"{role}\" on the following document:"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:917 core/models.py:917
|
||||
#: build/lib/core/models.py:918 core/models.py:918
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you: {title}"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1015 core/models.py:1015
|
||||
#: build/lib/core/models.py:1016 core/models.py:1016
|
||||
msgid "Document/user link trace"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1016 core/models.py:1016
|
||||
#: build/lib/core/models.py:1017 core/models.py:1017
|
||||
msgid "Document/user link traces"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1022 core/models.py:1022
|
||||
#: build/lib/core/models.py:1023 core/models.py:1023
|
||||
msgid "A link trace already exists for this document/user."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1045 core/models.py:1045
|
||||
#: build/lib/core/models.py:1046 core/models.py:1046
|
||||
msgid "Document favorite"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1046 core/models.py:1046
|
||||
#: build/lib/core/models.py:1047 core/models.py:1047
|
||||
msgid "Document favorites"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1052 core/models.py:1052
|
||||
#: build/lib/core/models.py:1053 core/models.py:1053
|
||||
msgid "This document is already targeted by a favorite relation instance for the same user."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1074 core/models.py:1074
|
||||
#: build/lib/core/models.py:1075 core/models.py:1075
|
||||
msgid "Document/user relation"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1075 core/models.py:1075
|
||||
#: build/lib/core/models.py:1076 core/models.py:1076
|
||||
msgid "Document/user relations"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1081 core/models.py:1081
|
||||
#: build/lib/core/models.py:1082 core/models.py:1082
|
||||
msgid "This user is already in this document."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1087 core/models.py:1087
|
||||
#: build/lib/core/models.py:1088 core/models.py:1088
|
||||
msgid "This team is already in this document."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1093 build/lib/core/models.py:1241
|
||||
#: core/models.py:1093 core/models.py:1241
|
||||
#: build/lib/core/models.py:1094 build/lib/core/models.py:1242
|
||||
#: core/models.py:1094 core/models.py:1242
|
||||
msgid "Either user or team must be set, not both."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1155 core/models.py:1155
|
||||
#: build/lib/core/models.py:1156 core/models.py:1156
|
||||
msgid "description"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1156 core/models.py:1156
|
||||
#: build/lib/core/models.py:1157 core/models.py:1157
|
||||
msgid "code"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1157 core/models.py:1157
|
||||
#: build/lib/core/models.py:1158 core/models.py:1158
|
||||
msgid "css"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1159 core/models.py:1159
|
||||
#: build/lib/core/models.py:1160 core/models.py:1160
|
||||
msgid "public"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1161 core/models.py:1161
|
||||
#: build/lib/core/models.py:1162 core/models.py:1162
|
||||
msgid "Whether this template is public for anyone to use."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1167 core/models.py:1167
|
||||
#: build/lib/core/models.py:1168 core/models.py:1168
|
||||
msgid "Template"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1168 core/models.py:1168
|
||||
#: build/lib/core/models.py:1169 core/models.py:1169
|
||||
msgid "Templates"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1222 core/models.py:1222
|
||||
#: build/lib/core/models.py:1223 core/models.py:1223
|
||||
msgid "Template/user relation"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1223 core/models.py:1223
|
||||
#: build/lib/core/models.py:1224 core/models.py:1224
|
||||
msgid "Template/user relations"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1229 core/models.py:1229
|
||||
#: build/lib/core/models.py:1230 core/models.py:1230
|
||||
msgid "This user is already in this template."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1235 core/models.py:1235
|
||||
#: build/lib/core/models.py:1236 core/models.py:1236
|
||||
msgid "This team is already in this template."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1258 core/models.py:1258
|
||||
#: build/lib/core/models.py:1259 core/models.py:1259
|
||||
msgid "email address"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1277 core/models.py:1277
|
||||
#: build/lib/core/models.py:1278 core/models.py:1278
|
||||
msgid "Document invitation"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1278 core/models.py:1278
|
||||
#: build/lib/core/models.py:1279 core/models.py:1279
|
||||
msgid "Document invitations"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1298 core/models.py:1298
|
||||
#: build/lib/core/models.py:1299 core/models.py:1299
|
||||
msgid "This email is already associated to a registered user."
|
||||
msgstr ""
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: lasuite-docs\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-04-29 11:48+0000\n"
|
||||
"PO-Revision-Date: 2025-05-05 07:07\n"
|
||||
"POT-Creation-Date: 2025-05-22 12:09+0000\n"
|
||||
"PO-Revision-Date: 2025-05-22 14:16\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Spanish\n"
|
||||
"Language: es_ES\n"
|
||||
@@ -66,32 +66,32 @@ msgstr "Tipo de Cuerpo"
|
||||
msgid "Format"
|
||||
msgstr "Formato"
|
||||
|
||||
#: build/lib/core/api/viewsets.py:966 core/api/viewsets.py:966
|
||||
#: build/lib/core/api/viewsets.py:967 core/api/viewsets.py:967
|
||||
#, python-brace-format
|
||||
msgid "copy of {title}"
|
||||
msgstr "copia de {title}"
|
||||
|
||||
#: build/lib/core/enums.py:35 core/enums.py:35
|
||||
#: build/lib/core/enums.py:36 core/enums.py:36
|
||||
msgid "First child"
|
||||
msgstr "Primer nodo"
|
||||
|
||||
#: build/lib/core/enums.py:36 core/enums.py:36
|
||||
#: build/lib/core/enums.py:37 core/enums.py:37
|
||||
msgid "Last child"
|
||||
msgstr "Último nodo"
|
||||
|
||||
#: build/lib/core/enums.py:37 core/enums.py:37
|
||||
#: build/lib/core/enums.py:38 core/enums.py:38
|
||||
msgid "First sibling"
|
||||
msgstr "Primera relación"
|
||||
|
||||
#: build/lib/core/enums.py:38 core/enums.py:38
|
||||
#: build/lib/core/enums.py:39 core/enums.py:39
|
||||
msgid "Last sibling"
|
||||
msgstr "Última relación"
|
||||
|
||||
#: build/lib/core/enums.py:39 core/enums.py:39
|
||||
#: build/lib/core/enums.py:40 core/enums.py:40
|
||||
msgid "Left"
|
||||
msgstr "Izquierda"
|
||||
|
||||
#: build/lib/core/enums.py:40 core/enums.py:40
|
||||
#: build/lib/core/enums.py:41 core/enums.py:41
|
||||
msgid "Right"
|
||||
msgstr "Derecha"
|
||||
|
||||
@@ -225,8 +225,8 @@ msgstr "usuario"
|
||||
msgid "users"
|
||||
msgstr "usuarios"
|
||||
|
||||
#: build/lib/core/models.py:470 build/lib/core/models.py:1154
|
||||
#: core/models.py:470 core/models.py:1154
|
||||
#: build/lib/core/models.py:470 build/lib/core/models.py:1155
|
||||
#: core/models.py:470 core/models.py:1155
|
||||
msgid "title"
|
||||
msgstr "título"
|
||||
|
||||
@@ -242,128 +242,128 @@ msgstr "Documento"
|
||||
msgid "Documents"
|
||||
msgstr "Documentos"
|
||||
|
||||
#: build/lib/core/models.py:532 build/lib/core/models.py:872 core/models.py:532
|
||||
#: core/models.py:872
|
||||
#: build/lib/core/models.py:532 build/lib/core/models.py:873 core/models.py:532
|
||||
#: core/models.py:873
|
||||
msgid "Untitled Document"
|
||||
msgstr "Documento sin título"
|
||||
|
||||
#: build/lib/core/models.py:907 core/models.py:907
|
||||
#: build/lib/core/models.py:908 core/models.py:908
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you!"
|
||||
msgstr "¡{name} ha compartido un documento contigo!"
|
||||
|
||||
#: build/lib/core/models.py:911 core/models.py:911
|
||||
#: build/lib/core/models.py:912 core/models.py:912
|
||||
#, python-brace-format
|
||||
msgid "{name} invited you with the role \"{role}\" on the following document:"
|
||||
msgstr "Te ha invitado {name} al siguiente documento con el rol \"{role}\" :"
|
||||
|
||||
#: build/lib/core/models.py:917 core/models.py:917
|
||||
#: build/lib/core/models.py:918 core/models.py:918
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you: {title}"
|
||||
msgstr "{name} ha compartido un documento contigo: {title}"
|
||||
|
||||
#: build/lib/core/models.py:1015 core/models.py:1015
|
||||
#: build/lib/core/models.py:1016 core/models.py:1016
|
||||
msgid "Document/user link trace"
|
||||
msgstr "Traza del enlace de documento/usuario"
|
||||
|
||||
#: build/lib/core/models.py:1016 core/models.py:1016
|
||||
#: build/lib/core/models.py:1017 core/models.py:1017
|
||||
msgid "Document/user link traces"
|
||||
msgstr "Trazas del enlace de documento/usuario"
|
||||
|
||||
#: build/lib/core/models.py:1022 core/models.py:1022
|
||||
#: build/lib/core/models.py:1023 core/models.py:1023
|
||||
msgid "A link trace already exists for this document/user."
|
||||
msgstr "Ya existe una traza de enlace para este documento/usuario."
|
||||
|
||||
#: build/lib/core/models.py:1045 core/models.py:1045
|
||||
#: build/lib/core/models.py:1046 core/models.py:1046
|
||||
msgid "Document favorite"
|
||||
msgstr "Documento favorito"
|
||||
|
||||
#: build/lib/core/models.py:1046 core/models.py:1046
|
||||
#: build/lib/core/models.py:1047 core/models.py:1047
|
||||
msgid "Document favorites"
|
||||
msgstr "Documentos favoritos"
|
||||
|
||||
#: build/lib/core/models.py:1052 core/models.py:1052
|
||||
#: build/lib/core/models.py:1053 core/models.py:1053
|
||||
msgid "This document is already targeted by a favorite relation instance for the same user."
|
||||
msgstr "Este documento ya ha sido marcado como favorito por el usuario."
|
||||
|
||||
#: build/lib/core/models.py:1074 core/models.py:1074
|
||||
#: build/lib/core/models.py:1075 core/models.py:1075
|
||||
msgid "Document/user relation"
|
||||
msgstr "Relación documento/usuario"
|
||||
|
||||
#: build/lib/core/models.py:1075 core/models.py:1075
|
||||
#: build/lib/core/models.py:1076 core/models.py:1076
|
||||
msgid "Document/user relations"
|
||||
msgstr "Relaciones documento/usuario"
|
||||
|
||||
#: build/lib/core/models.py:1081 core/models.py:1081
|
||||
#: build/lib/core/models.py:1082 core/models.py:1082
|
||||
msgid "This user is already in this document."
|
||||
msgstr "Este usuario ya forma parte del documento."
|
||||
|
||||
#: build/lib/core/models.py:1087 core/models.py:1087
|
||||
#: build/lib/core/models.py:1088 core/models.py:1088
|
||||
msgid "This team is already in this document."
|
||||
msgstr "Este equipo ya forma parte del documento."
|
||||
|
||||
#: build/lib/core/models.py:1093 build/lib/core/models.py:1241
|
||||
#: core/models.py:1093 core/models.py:1241
|
||||
#: build/lib/core/models.py:1094 build/lib/core/models.py:1242
|
||||
#: core/models.py:1094 core/models.py:1242
|
||||
msgid "Either user or team must be set, not both."
|
||||
msgstr "Debe establecerse un usuario o un equipo, no ambos."
|
||||
|
||||
#: build/lib/core/models.py:1155 core/models.py:1155
|
||||
#: build/lib/core/models.py:1156 core/models.py:1156
|
||||
msgid "description"
|
||||
msgstr "descripción"
|
||||
|
||||
#: build/lib/core/models.py:1156 core/models.py:1156
|
||||
#: build/lib/core/models.py:1157 core/models.py:1157
|
||||
msgid "code"
|
||||
msgstr "código"
|
||||
|
||||
#: build/lib/core/models.py:1157 core/models.py:1157
|
||||
#: build/lib/core/models.py:1158 core/models.py:1158
|
||||
msgid "css"
|
||||
msgstr "css"
|
||||
|
||||
#: build/lib/core/models.py:1159 core/models.py:1159
|
||||
#: build/lib/core/models.py:1160 core/models.py:1160
|
||||
msgid "public"
|
||||
msgstr "público"
|
||||
|
||||
#: build/lib/core/models.py:1161 core/models.py:1161
|
||||
#: build/lib/core/models.py:1162 core/models.py:1162
|
||||
msgid "Whether this template is public for anyone to use."
|
||||
msgstr "Si esta plantilla es pública para que cualquiera la utilice."
|
||||
|
||||
#: build/lib/core/models.py:1167 core/models.py:1167
|
||||
#: build/lib/core/models.py:1168 core/models.py:1168
|
||||
msgid "Template"
|
||||
msgstr "Plantilla"
|
||||
|
||||
#: build/lib/core/models.py:1168 core/models.py:1168
|
||||
#: build/lib/core/models.py:1169 core/models.py:1169
|
||||
msgid "Templates"
|
||||
msgstr "Plantillas"
|
||||
|
||||
#: build/lib/core/models.py:1222 core/models.py:1222
|
||||
#: build/lib/core/models.py:1223 core/models.py:1223
|
||||
msgid "Template/user relation"
|
||||
msgstr "Relación plantilla/usuario"
|
||||
|
||||
#: build/lib/core/models.py:1223 core/models.py:1223
|
||||
#: build/lib/core/models.py:1224 core/models.py:1224
|
||||
msgid "Template/user relations"
|
||||
msgstr "Relaciones plantilla/usuario"
|
||||
|
||||
#: build/lib/core/models.py:1229 core/models.py:1229
|
||||
#: build/lib/core/models.py:1230 core/models.py:1230
|
||||
msgid "This user is already in this template."
|
||||
msgstr "Este usuario ya forma parte de la plantilla."
|
||||
|
||||
#: build/lib/core/models.py:1235 core/models.py:1235
|
||||
#: build/lib/core/models.py:1236 core/models.py:1236
|
||||
msgid "This team is already in this template."
|
||||
msgstr "Este equipo ya se encuentra en esta plantilla."
|
||||
|
||||
#: build/lib/core/models.py:1258 core/models.py:1258
|
||||
#: build/lib/core/models.py:1259 core/models.py:1259
|
||||
msgid "email address"
|
||||
msgstr "dirección de correo electrónico"
|
||||
|
||||
#: build/lib/core/models.py:1277 core/models.py:1277
|
||||
#: build/lib/core/models.py:1278 core/models.py:1278
|
||||
msgid "Document invitation"
|
||||
msgstr "Invitación al documento"
|
||||
|
||||
#: build/lib/core/models.py:1278 core/models.py:1278
|
||||
#: build/lib/core/models.py:1279 core/models.py:1279
|
||||
msgid "Document invitations"
|
||||
msgstr "Invitaciones a documentos"
|
||||
|
||||
#: build/lib/core/models.py:1298 core/models.py:1298
|
||||
#: build/lib/core/models.py:1299 core/models.py:1299
|
||||
msgid "This email is already associated to a registered user."
|
||||
msgstr "Este correo electrónico está asociado a un usuario registrado."
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: lasuite-docs\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-04-29 11:48+0000\n"
|
||||
"PO-Revision-Date: 2025-05-05 09:05\n"
|
||||
"POT-Creation-Date: 2025-05-22 12:09+0000\n"
|
||||
"PO-Revision-Date: 2025-05-22 14:16\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: French\n"
|
||||
"Language: fr_FR\n"
|
||||
@@ -66,32 +66,32 @@ msgstr "Type de corps"
|
||||
msgid "Format"
|
||||
msgstr "Format"
|
||||
|
||||
#: build/lib/core/api/viewsets.py:966 core/api/viewsets.py:966
|
||||
#: build/lib/core/api/viewsets.py:967 core/api/viewsets.py:967
|
||||
#, python-brace-format
|
||||
msgid "copy of {title}"
|
||||
msgstr "copie de {title}"
|
||||
|
||||
#: build/lib/core/enums.py:35 core/enums.py:35
|
||||
#: build/lib/core/enums.py:36 core/enums.py:36
|
||||
msgid "First child"
|
||||
msgstr "Premier enfant"
|
||||
|
||||
#: build/lib/core/enums.py:36 core/enums.py:36
|
||||
#: build/lib/core/enums.py:37 core/enums.py:37
|
||||
msgid "Last child"
|
||||
msgstr "Dernier enfant"
|
||||
|
||||
#: build/lib/core/enums.py:37 core/enums.py:37
|
||||
#: build/lib/core/enums.py:38 core/enums.py:38
|
||||
msgid "First sibling"
|
||||
msgstr "Premier frère ou sœur"
|
||||
|
||||
#: build/lib/core/enums.py:38 core/enums.py:38
|
||||
#: build/lib/core/enums.py:39 core/enums.py:39
|
||||
msgid "Last sibling"
|
||||
msgstr "Dernière relation"
|
||||
|
||||
#: build/lib/core/enums.py:39 core/enums.py:39
|
||||
#: build/lib/core/enums.py:40 core/enums.py:40
|
||||
msgid "Left"
|
||||
msgstr "Gauche"
|
||||
|
||||
#: build/lib/core/enums.py:40 core/enums.py:40
|
||||
#: build/lib/core/enums.py:41 core/enums.py:41
|
||||
msgid "Right"
|
||||
msgstr "Droite"
|
||||
|
||||
@@ -225,8 +225,8 @@ msgstr "utilisateur"
|
||||
msgid "users"
|
||||
msgstr "utilisateurs"
|
||||
|
||||
#: build/lib/core/models.py:470 build/lib/core/models.py:1154
|
||||
#: core/models.py:470 core/models.py:1154
|
||||
#: build/lib/core/models.py:470 build/lib/core/models.py:1155
|
||||
#: core/models.py:470 core/models.py:1155
|
||||
msgid "title"
|
||||
msgstr "titre"
|
||||
|
||||
@@ -242,128 +242,128 @@ msgstr "Document"
|
||||
msgid "Documents"
|
||||
msgstr "Documents"
|
||||
|
||||
#: build/lib/core/models.py:532 build/lib/core/models.py:872 core/models.py:532
|
||||
#: core/models.py:872
|
||||
#: build/lib/core/models.py:532 build/lib/core/models.py:873 core/models.py:532
|
||||
#: core/models.py:873
|
||||
msgid "Untitled Document"
|
||||
msgstr "Document sans titre"
|
||||
|
||||
#: build/lib/core/models.py:907 core/models.py:907
|
||||
#: build/lib/core/models.py:908 core/models.py:908
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you!"
|
||||
msgstr "{name} a partagé un document avec vous!"
|
||||
|
||||
#: build/lib/core/models.py:911 core/models.py:911
|
||||
#: build/lib/core/models.py:912 core/models.py:912
|
||||
#, python-brace-format
|
||||
msgid "{name} invited you with the role \"{role}\" on the following document:"
|
||||
msgstr "{name} vous a invité avec le rôle \"{role}\" sur le document suivant :"
|
||||
|
||||
#: build/lib/core/models.py:917 core/models.py:917
|
||||
#: build/lib/core/models.py:918 core/models.py:918
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you: {title}"
|
||||
msgstr "{name} a partagé un document avec vous : {title}"
|
||||
|
||||
#: build/lib/core/models.py:1015 core/models.py:1015
|
||||
#: build/lib/core/models.py:1016 core/models.py:1016
|
||||
msgid "Document/user link trace"
|
||||
msgstr "Trace du lien document/utilisateur"
|
||||
|
||||
#: build/lib/core/models.py:1016 core/models.py:1016
|
||||
#: build/lib/core/models.py:1017 core/models.py:1017
|
||||
msgid "Document/user link traces"
|
||||
msgstr "Traces du lien document/utilisateur"
|
||||
|
||||
#: build/lib/core/models.py:1022 core/models.py:1022
|
||||
#: build/lib/core/models.py:1023 core/models.py:1023
|
||||
msgid "A link trace already exists for this document/user."
|
||||
msgstr "Une trace de lien existe déjà pour ce document/utilisateur."
|
||||
|
||||
#: build/lib/core/models.py:1045 core/models.py:1045
|
||||
#: build/lib/core/models.py:1046 core/models.py:1046
|
||||
msgid "Document favorite"
|
||||
msgstr "Document favori"
|
||||
|
||||
#: build/lib/core/models.py:1046 core/models.py:1046
|
||||
#: build/lib/core/models.py:1047 core/models.py:1047
|
||||
msgid "Document favorites"
|
||||
msgstr "Documents favoris"
|
||||
|
||||
#: build/lib/core/models.py:1052 core/models.py:1052
|
||||
#: build/lib/core/models.py:1053 core/models.py:1053
|
||||
msgid "This document is already targeted by a favorite relation instance for the same user."
|
||||
msgstr "Ce document est déjà un favori de cet utilisateur."
|
||||
|
||||
#: build/lib/core/models.py:1074 core/models.py:1074
|
||||
#: build/lib/core/models.py:1075 core/models.py:1075
|
||||
msgid "Document/user relation"
|
||||
msgstr "Relation document/utilisateur"
|
||||
|
||||
#: build/lib/core/models.py:1075 core/models.py:1075
|
||||
#: build/lib/core/models.py:1076 core/models.py:1076
|
||||
msgid "Document/user relations"
|
||||
msgstr "Relations document/utilisateur"
|
||||
|
||||
#: build/lib/core/models.py:1081 core/models.py:1081
|
||||
#: build/lib/core/models.py:1082 core/models.py:1082
|
||||
msgid "This user is already in this document."
|
||||
msgstr "Cet utilisateur est déjà dans ce document."
|
||||
|
||||
#: build/lib/core/models.py:1087 core/models.py:1087
|
||||
#: build/lib/core/models.py:1088 core/models.py:1088
|
||||
msgid "This team is already in this document."
|
||||
msgstr "Cette équipe est déjà dans ce document."
|
||||
|
||||
#: build/lib/core/models.py:1093 build/lib/core/models.py:1241
|
||||
#: core/models.py:1093 core/models.py:1241
|
||||
#: build/lib/core/models.py:1094 build/lib/core/models.py:1242
|
||||
#: core/models.py:1094 core/models.py:1242
|
||||
msgid "Either user or team must be set, not both."
|
||||
msgstr "L'utilisateur ou l'équipe doivent être définis, pas les deux."
|
||||
|
||||
#: build/lib/core/models.py:1155 core/models.py:1155
|
||||
#: build/lib/core/models.py:1156 core/models.py:1156
|
||||
msgid "description"
|
||||
msgstr "description"
|
||||
|
||||
#: build/lib/core/models.py:1156 core/models.py:1156
|
||||
#: build/lib/core/models.py:1157 core/models.py:1157
|
||||
msgid "code"
|
||||
msgstr "code"
|
||||
|
||||
#: build/lib/core/models.py:1157 core/models.py:1157
|
||||
#: build/lib/core/models.py:1158 core/models.py:1158
|
||||
msgid "css"
|
||||
msgstr "CSS"
|
||||
|
||||
#: build/lib/core/models.py:1159 core/models.py:1159
|
||||
#: build/lib/core/models.py:1160 core/models.py:1160
|
||||
msgid "public"
|
||||
msgstr "public"
|
||||
|
||||
#: build/lib/core/models.py:1161 core/models.py:1161
|
||||
#: build/lib/core/models.py:1162 core/models.py:1162
|
||||
msgid "Whether this template is public for anyone to use."
|
||||
msgstr "Si ce modèle est public, utilisable par n'importe qui."
|
||||
|
||||
#: build/lib/core/models.py:1167 core/models.py:1167
|
||||
#: build/lib/core/models.py:1168 core/models.py:1168
|
||||
msgid "Template"
|
||||
msgstr "Modèle"
|
||||
|
||||
#: build/lib/core/models.py:1168 core/models.py:1168
|
||||
#: build/lib/core/models.py:1169 core/models.py:1169
|
||||
msgid "Templates"
|
||||
msgstr "Modèles"
|
||||
|
||||
#: build/lib/core/models.py:1222 core/models.py:1222
|
||||
#: build/lib/core/models.py:1223 core/models.py:1223
|
||||
msgid "Template/user relation"
|
||||
msgstr "Relation modèle/utilisateur"
|
||||
|
||||
#: build/lib/core/models.py:1223 core/models.py:1223
|
||||
#: build/lib/core/models.py:1224 core/models.py:1224
|
||||
msgid "Template/user relations"
|
||||
msgstr "Relations modèle/utilisateur"
|
||||
|
||||
#: build/lib/core/models.py:1229 core/models.py:1229
|
||||
#: build/lib/core/models.py:1230 core/models.py:1230
|
||||
msgid "This user is already in this template."
|
||||
msgstr "Cet utilisateur est déjà dans ce modèle."
|
||||
|
||||
#: build/lib/core/models.py:1235 core/models.py:1235
|
||||
#: build/lib/core/models.py:1236 core/models.py:1236
|
||||
msgid "This team is already in this template."
|
||||
msgstr "Cette équipe est déjà modèle."
|
||||
|
||||
#: build/lib/core/models.py:1258 core/models.py:1258
|
||||
#: build/lib/core/models.py:1259 core/models.py:1259
|
||||
msgid "email address"
|
||||
msgstr "adresse e-mail"
|
||||
|
||||
#: build/lib/core/models.py:1277 core/models.py:1277
|
||||
#: build/lib/core/models.py:1278 core/models.py:1278
|
||||
msgid "Document invitation"
|
||||
msgstr "Invitation à un document"
|
||||
|
||||
#: build/lib/core/models.py:1278 core/models.py:1278
|
||||
#: build/lib/core/models.py:1279 core/models.py:1279
|
||||
msgid "Document invitations"
|
||||
msgstr "Invitations à un document"
|
||||
|
||||
#: build/lib/core/models.py:1298 core/models.py:1298
|
||||
#: build/lib/core/models.py:1299 core/models.py:1299
|
||||
msgid "This email is already associated to a registered user."
|
||||
msgstr "Cette adresse email est déjà associée à un utilisateur inscrit."
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: lasuite-docs\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-04-29 11:48+0000\n"
|
||||
"PO-Revision-Date: 2025-05-05 07:07\n"
|
||||
"POT-Creation-Date: 2025-05-22 12:09+0000\n"
|
||||
"PO-Revision-Date: 2025-05-22 14:16\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Italian\n"
|
||||
"Language: it_IT\n"
|
||||
@@ -66,32 +66,32 @@ msgstr ""
|
||||
msgid "Format"
|
||||
msgstr "Formato"
|
||||
|
||||
#: build/lib/core/api/viewsets.py:966 core/api/viewsets.py:966
|
||||
#: build/lib/core/api/viewsets.py:967 core/api/viewsets.py:967
|
||||
#, python-brace-format
|
||||
msgid "copy of {title}"
|
||||
msgstr "copia di {title}"
|
||||
|
||||
#: build/lib/core/enums.py:35 core/enums.py:35
|
||||
#: build/lib/core/enums.py:36 core/enums.py:36
|
||||
msgid "First child"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/enums.py:36 core/enums.py:36
|
||||
#: build/lib/core/enums.py:37 core/enums.py:37
|
||||
msgid "Last child"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/enums.py:37 core/enums.py:37
|
||||
#: build/lib/core/enums.py:38 core/enums.py:38
|
||||
msgid "First sibling"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/enums.py:38 core/enums.py:38
|
||||
#: build/lib/core/enums.py:39 core/enums.py:39
|
||||
msgid "Last sibling"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/enums.py:39 core/enums.py:39
|
||||
#: build/lib/core/enums.py:40 core/enums.py:40
|
||||
msgid "Left"
|
||||
msgstr "Sinistra"
|
||||
|
||||
#: build/lib/core/enums.py:40 core/enums.py:40
|
||||
#: build/lib/core/enums.py:41 core/enums.py:41
|
||||
msgid "Right"
|
||||
msgstr "Destra"
|
||||
|
||||
@@ -225,8 +225,8 @@ msgstr "utente"
|
||||
msgid "users"
|
||||
msgstr "utenti"
|
||||
|
||||
#: build/lib/core/models.py:470 build/lib/core/models.py:1154
|
||||
#: core/models.py:470 core/models.py:1154
|
||||
#: build/lib/core/models.py:470 build/lib/core/models.py:1155
|
||||
#: core/models.py:470 core/models.py:1155
|
||||
msgid "title"
|
||||
msgstr "titolo"
|
||||
|
||||
@@ -242,128 +242,128 @@ msgstr "Documento"
|
||||
msgid "Documents"
|
||||
msgstr "Documenti"
|
||||
|
||||
#: build/lib/core/models.py:532 build/lib/core/models.py:872 core/models.py:532
|
||||
#: core/models.py:872
|
||||
#: build/lib/core/models.py:532 build/lib/core/models.py:873 core/models.py:532
|
||||
#: core/models.py:873
|
||||
msgid "Untitled Document"
|
||||
msgstr "Documento senza titolo"
|
||||
|
||||
#: build/lib/core/models.py:907 core/models.py:907
|
||||
#: build/lib/core/models.py:908 core/models.py:908
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you!"
|
||||
msgstr "{name} ha condiviso un documento con te!"
|
||||
|
||||
#: build/lib/core/models.py:911 core/models.py:911
|
||||
#: build/lib/core/models.py:912 core/models.py:912
|
||||
#, python-brace-format
|
||||
msgid "{name} invited you with the role \"{role}\" on the following document:"
|
||||
msgstr "{name} ti ha invitato con il ruolo \"{role}\" nel seguente documento:"
|
||||
|
||||
#: build/lib/core/models.py:917 core/models.py:917
|
||||
#: build/lib/core/models.py:918 core/models.py:918
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you: {title}"
|
||||
msgstr "{name} ha condiviso un documento con te: {title}"
|
||||
|
||||
#: build/lib/core/models.py:1015 core/models.py:1015
|
||||
#: build/lib/core/models.py:1016 core/models.py:1016
|
||||
msgid "Document/user link trace"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1016 core/models.py:1016
|
||||
#: build/lib/core/models.py:1017 core/models.py:1017
|
||||
msgid "Document/user link traces"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1022 core/models.py:1022
|
||||
#: build/lib/core/models.py:1023 core/models.py:1023
|
||||
msgid "A link trace already exists for this document/user."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1045 core/models.py:1045
|
||||
#: build/lib/core/models.py:1046 core/models.py:1046
|
||||
msgid "Document favorite"
|
||||
msgstr "Documento preferito"
|
||||
|
||||
#: build/lib/core/models.py:1046 core/models.py:1046
|
||||
#: build/lib/core/models.py:1047 core/models.py:1047
|
||||
msgid "Document favorites"
|
||||
msgstr "Documenti preferiti"
|
||||
|
||||
#: build/lib/core/models.py:1052 core/models.py:1052
|
||||
#: build/lib/core/models.py:1053 core/models.py:1053
|
||||
msgid "This document is already targeted by a favorite relation instance for the same user."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1074 core/models.py:1074
|
||||
#: build/lib/core/models.py:1075 core/models.py:1075
|
||||
msgid "Document/user relation"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1075 core/models.py:1075
|
||||
#: build/lib/core/models.py:1076 core/models.py:1076
|
||||
msgid "Document/user relations"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1081 core/models.py:1081
|
||||
#: build/lib/core/models.py:1082 core/models.py:1082
|
||||
msgid "This user is already in this document."
|
||||
msgstr "Questo utente è già presente in questo documento."
|
||||
|
||||
#: build/lib/core/models.py:1087 core/models.py:1087
|
||||
#: build/lib/core/models.py:1088 core/models.py:1088
|
||||
msgid "This team is already in this document."
|
||||
msgstr "Questo team è già presente in questo documento."
|
||||
|
||||
#: build/lib/core/models.py:1093 build/lib/core/models.py:1241
|
||||
#: core/models.py:1093 core/models.py:1241
|
||||
#: build/lib/core/models.py:1094 build/lib/core/models.py:1242
|
||||
#: core/models.py:1094 core/models.py:1242
|
||||
msgid "Either user or team must be set, not both."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1155 core/models.py:1155
|
||||
#: build/lib/core/models.py:1156 core/models.py:1156
|
||||
msgid "description"
|
||||
msgstr "descrizione"
|
||||
|
||||
#: build/lib/core/models.py:1156 core/models.py:1156
|
||||
#: build/lib/core/models.py:1157 core/models.py:1157
|
||||
msgid "code"
|
||||
msgstr "code"
|
||||
|
||||
#: build/lib/core/models.py:1157 core/models.py:1157
|
||||
#: build/lib/core/models.py:1158 core/models.py:1158
|
||||
msgid "css"
|
||||
msgstr "css"
|
||||
|
||||
#: build/lib/core/models.py:1159 core/models.py:1159
|
||||
#: build/lib/core/models.py:1160 core/models.py:1160
|
||||
msgid "public"
|
||||
msgstr "pubblico"
|
||||
|
||||
#: build/lib/core/models.py:1161 core/models.py:1161
|
||||
#: build/lib/core/models.py:1162 core/models.py:1162
|
||||
msgid "Whether this template is public for anyone to use."
|
||||
msgstr "Indica se questo modello è pubblico per chiunque."
|
||||
|
||||
#: build/lib/core/models.py:1167 core/models.py:1167
|
||||
#: build/lib/core/models.py:1168 core/models.py:1168
|
||||
msgid "Template"
|
||||
msgstr "Modello"
|
||||
|
||||
#: build/lib/core/models.py:1168 core/models.py:1168
|
||||
#: build/lib/core/models.py:1169 core/models.py:1169
|
||||
msgid "Templates"
|
||||
msgstr "Modelli"
|
||||
|
||||
#: build/lib/core/models.py:1222 core/models.py:1222
|
||||
#: build/lib/core/models.py:1223 core/models.py:1223
|
||||
msgid "Template/user relation"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1223 core/models.py:1223
|
||||
#: build/lib/core/models.py:1224 core/models.py:1224
|
||||
msgid "Template/user relations"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1229 core/models.py:1229
|
||||
#: build/lib/core/models.py:1230 core/models.py:1230
|
||||
msgid "This user is already in this template."
|
||||
msgstr "Questo utente è già in questo modello."
|
||||
|
||||
#: build/lib/core/models.py:1235 core/models.py:1235
|
||||
#: build/lib/core/models.py:1236 core/models.py:1236
|
||||
msgid "This team is already in this template."
|
||||
msgstr "Questo team è già in questo modello."
|
||||
|
||||
#: build/lib/core/models.py:1258 core/models.py:1258
|
||||
#: build/lib/core/models.py:1259 core/models.py:1259
|
||||
msgid "email address"
|
||||
msgstr "indirizzo e-mail"
|
||||
|
||||
#: build/lib/core/models.py:1277 core/models.py:1277
|
||||
#: build/lib/core/models.py:1278 core/models.py:1278
|
||||
msgid "Document invitation"
|
||||
msgstr "Invito al documento"
|
||||
|
||||
#: build/lib/core/models.py:1278 core/models.py:1278
|
||||
#: build/lib/core/models.py:1279 core/models.py:1279
|
||||
msgid "Document invitations"
|
||||
msgstr "Inviti al documento"
|
||||
|
||||
#: build/lib/core/models.py:1298 core/models.py:1298
|
||||
#: build/lib/core/models.py:1299 core/models.py:1299
|
||||
msgid "This email is already associated to a registered user."
|
||||
msgstr "Questa email è già associata a un utente registrato."
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: lasuite-docs\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-04-29 11:48+0000\n"
|
||||
"PO-Revision-Date: 2025-05-05 07:07\n"
|
||||
"POT-Creation-Date: 2025-05-22 12:09+0000\n"
|
||||
"PO-Revision-Date: 2025-05-22 14:16\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Dutch\n"
|
||||
"Language: nl_NL\n"
|
||||
@@ -66,32 +66,32 @@ msgstr "Text type"
|
||||
msgid "Format"
|
||||
msgstr "Formaat"
|
||||
|
||||
#: build/lib/core/api/viewsets.py:966 core/api/viewsets.py:966
|
||||
#: build/lib/core/api/viewsets.py:967 core/api/viewsets.py:967
|
||||
#, python-brace-format
|
||||
msgid "copy of {title}"
|
||||
msgstr "kopie van {title}"
|
||||
|
||||
#: build/lib/core/enums.py:35 core/enums.py:35
|
||||
#: build/lib/core/enums.py:36 core/enums.py:36
|
||||
msgid "First child"
|
||||
msgstr "Eerste node"
|
||||
|
||||
#: build/lib/core/enums.py:36 core/enums.py:36
|
||||
#: build/lib/core/enums.py:37 core/enums.py:37
|
||||
msgid "Last child"
|
||||
msgstr "Laatste node"
|
||||
|
||||
#: build/lib/core/enums.py:37 core/enums.py:37
|
||||
#: build/lib/core/enums.py:38 core/enums.py:38
|
||||
msgid "First sibling"
|
||||
msgstr "Eerste naaste"
|
||||
|
||||
#: build/lib/core/enums.py:38 core/enums.py:38
|
||||
#: build/lib/core/enums.py:39 core/enums.py:39
|
||||
msgid "Last sibling"
|
||||
msgstr "Laatste naaste"
|
||||
|
||||
#: build/lib/core/enums.py:39 core/enums.py:39
|
||||
#: build/lib/core/enums.py:40 core/enums.py:40
|
||||
msgid "Left"
|
||||
msgstr "Links"
|
||||
|
||||
#: build/lib/core/enums.py:40 core/enums.py:40
|
||||
#: build/lib/core/enums.py:41 core/enums.py:41
|
||||
msgid "Right"
|
||||
msgstr "Rechts"
|
||||
|
||||
@@ -225,8 +225,8 @@ msgstr "gebruiker"
|
||||
msgid "users"
|
||||
msgstr "gebruikers"
|
||||
|
||||
#: build/lib/core/models.py:470 build/lib/core/models.py:1154
|
||||
#: core/models.py:470 core/models.py:1154
|
||||
#: build/lib/core/models.py:470 build/lib/core/models.py:1155
|
||||
#: core/models.py:470 core/models.py:1155
|
||||
msgid "title"
|
||||
msgstr "titel"
|
||||
|
||||
@@ -242,128 +242,128 @@ msgstr "Document"
|
||||
msgid "Documents"
|
||||
msgstr "Documenten"
|
||||
|
||||
#: build/lib/core/models.py:532 build/lib/core/models.py:872 core/models.py:532
|
||||
#: core/models.py:872
|
||||
#: build/lib/core/models.py:532 build/lib/core/models.py:873 core/models.py:532
|
||||
#: core/models.py:873
|
||||
msgid "Untitled Document"
|
||||
msgstr "Naamloos Document"
|
||||
|
||||
#: build/lib/core/models.py:907 core/models.py:907
|
||||
#: build/lib/core/models.py:908 core/models.py:908
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you!"
|
||||
msgstr "{name} heeft een document met gedeeld!"
|
||||
|
||||
#: build/lib/core/models.py:911 core/models.py:911
|
||||
#: build/lib/core/models.py:912 core/models.py:912
|
||||
#, python-brace-format
|
||||
msgid "{name} invited you with the role \"{role}\" on the following document:"
|
||||
msgstr "{name} heeft u uitgenodigd met de rol \"{role}\" op het volgende document:"
|
||||
|
||||
#: build/lib/core/models.py:917 core/models.py:917
|
||||
#: build/lib/core/models.py:918 core/models.py:918
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you: {title}"
|
||||
msgstr "{name} heeft een document met u gedeeld: {title}"
|
||||
|
||||
#: build/lib/core/models.py:1015 core/models.py:1015
|
||||
#: build/lib/core/models.py:1016 core/models.py:1016
|
||||
msgid "Document/user link trace"
|
||||
msgstr "Document/gebruiker url"
|
||||
|
||||
#: build/lib/core/models.py:1016 core/models.py:1016
|
||||
#: build/lib/core/models.py:1017 core/models.py:1017
|
||||
msgid "Document/user link traces"
|
||||
msgstr "Document/gebruiker url"
|
||||
|
||||
#: build/lib/core/models.py:1022 core/models.py:1022
|
||||
#: build/lib/core/models.py:1023 core/models.py:1023
|
||||
msgid "A link trace already exists for this document/user."
|
||||
msgstr "Een url bestaat al voor dit document/deze gebruiker."
|
||||
|
||||
#: build/lib/core/models.py:1045 core/models.py:1045
|
||||
#: build/lib/core/models.py:1046 core/models.py:1046
|
||||
msgid "Document favorite"
|
||||
msgstr "Document favoriet"
|
||||
|
||||
#: build/lib/core/models.py:1046 core/models.py:1046
|
||||
#: build/lib/core/models.py:1047 core/models.py:1047
|
||||
msgid "Document favorites"
|
||||
msgstr "Document favorieten"
|
||||
|
||||
#: build/lib/core/models.py:1052 core/models.py:1052
|
||||
#: build/lib/core/models.py:1053 core/models.py:1053
|
||||
msgid "This document is already targeted by a favorite relation instance for the same user."
|
||||
msgstr "Dit document is al in gebruik als favoriete door dezelfde gebruiker."
|
||||
|
||||
#: build/lib/core/models.py:1074 core/models.py:1074
|
||||
#: build/lib/core/models.py:1075 core/models.py:1075
|
||||
msgid "Document/user relation"
|
||||
msgstr "Document/gebruiker relatie"
|
||||
|
||||
#: build/lib/core/models.py:1075 core/models.py:1075
|
||||
#: build/lib/core/models.py:1076 core/models.py:1076
|
||||
msgid "Document/user relations"
|
||||
msgstr "Document/gebruiker relaties"
|
||||
|
||||
#: build/lib/core/models.py:1081 core/models.py:1081
|
||||
#: build/lib/core/models.py:1082 core/models.py:1082
|
||||
msgid "This user is already in this document."
|
||||
msgstr "De gebruiker is al in dit document."
|
||||
|
||||
#: build/lib/core/models.py:1087 core/models.py:1087
|
||||
#: build/lib/core/models.py:1088 core/models.py:1088
|
||||
msgid "This team is already in this document."
|
||||
msgstr "Het team is al in dit document."
|
||||
|
||||
#: build/lib/core/models.py:1093 build/lib/core/models.py:1241
|
||||
#: core/models.py:1093 core/models.py:1241
|
||||
#: build/lib/core/models.py:1094 build/lib/core/models.py:1242
|
||||
#: core/models.py:1094 core/models.py:1242
|
||||
msgid "Either user or team must be set, not both."
|
||||
msgstr "Een gebruiker of team moet gekozen worden, maar niet beide."
|
||||
|
||||
#: build/lib/core/models.py:1155 core/models.py:1155
|
||||
#: build/lib/core/models.py:1156 core/models.py:1156
|
||||
msgid "description"
|
||||
msgstr "omschrijving"
|
||||
|
||||
#: build/lib/core/models.py:1156 core/models.py:1156
|
||||
#: build/lib/core/models.py:1157 core/models.py:1157
|
||||
msgid "code"
|
||||
msgstr "code"
|
||||
|
||||
#: build/lib/core/models.py:1157 core/models.py:1157
|
||||
#: build/lib/core/models.py:1158 core/models.py:1158
|
||||
msgid "css"
|
||||
msgstr "css"
|
||||
|
||||
#: build/lib/core/models.py:1159 core/models.py:1159
|
||||
#: build/lib/core/models.py:1160 core/models.py:1160
|
||||
msgid "public"
|
||||
msgstr "publiek"
|
||||
|
||||
#: build/lib/core/models.py:1161 core/models.py:1161
|
||||
#: build/lib/core/models.py:1162 core/models.py:1162
|
||||
msgid "Whether this template is public for anyone to use."
|
||||
msgstr "Of dit template als publiek is en door iedereen te gebruiken is."
|
||||
|
||||
#: build/lib/core/models.py:1167 core/models.py:1167
|
||||
#: build/lib/core/models.py:1168 core/models.py:1168
|
||||
msgid "Template"
|
||||
msgstr "Template"
|
||||
|
||||
#: build/lib/core/models.py:1168 core/models.py:1168
|
||||
#: build/lib/core/models.py:1169 core/models.py:1169
|
||||
msgid "Templates"
|
||||
msgstr "Templates"
|
||||
|
||||
#: build/lib/core/models.py:1222 core/models.py:1222
|
||||
#: build/lib/core/models.py:1223 core/models.py:1223
|
||||
msgid "Template/user relation"
|
||||
msgstr "Template/gebruiker relatie"
|
||||
|
||||
#: build/lib/core/models.py:1223 core/models.py:1223
|
||||
#: build/lib/core/models.py:1224 core/models.py:1224
|
||||
msgid "Template/user relations"
|
||||
msgstr "Template/gebruiker relaties"
|
||||
|
||||
#: build/lib/core/models.py:1229 core/models.py:1229
|
||||
#: build/lib/core/models.py:1230 core/models.py:1230
|
||||
msgid "This user is already in this template."
|
||||
msgstr "De gebruiker bestaat al in dit template."
|
||||
|
||||
#: build/lib/core/models.py:1235 core/models.py:1235
|
||||
#: build/lib/core/models.py:1236 core/models.py:1236
|
||||
msgid "This team is already in this template."
|
||||
msgstr "Het team bestaat al in dit template."
|
||||
|
||||
#: build/lib/core/models.py:1258 core/models.py:1258
|
||||
#: build/lib/core/models.py:1259 core/models.py:1259
|
||||
msgid "email address"
|
||||
msgstr "email adres"
|
||||
|
||||
#: build/lib/core/models.py:1277 core/models.py:1277
|
||||
#: build/lib/core/models.py:1278 core/models.py:1278
|
||||
msgid "Document invitation"
|
||||
msgstr "Document uitnodiging"
|
||||
|
||||
#: build/lib/core/models.py:1278 core/models.py:1278
|
||||
#: build/lib/core/models.py:1279 core/models.py:1279
|
||||
msgid "Document invitations"
|
||||
msgstr "Document uitnodigingen"
|
||||
|
||||
#: build/lib/core/models.py:1298 core/models.py:1298
|
||||
#: build/lib/core/models.py:1299 core/models.py:1299
|
||||
msgid "This email is already associated to a registered user."
|
||||
msgstr "Deze email is al geassocieerd met een geregistreerde gebruiker."
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: lasuite-docs\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-04-29 11:48+0000\n"
|
||||
"PO-Revision-Date: 2025-05-05 07:07\n"
|
||||
"POT-Creation-Date: 2025-05-22 12:09+0000\n"
|
||||
"PO-Revision-Date: 2025-05-22 14:16\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Portuguese\n"
|
||||
"Language: pt_PT\n"
|
||||
@@ -66,32 +66,32 @@ msgstr ""
|
||||
msgid "Format"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/api/viewsets.py:966 core/api/viewsets.py:966
|
||||
#: build/lib/core/api/viewsets.py:967 core/api/viewsets.py:967
|
||||
#, python-brace-format
|
||||
msgid "copy of {title}"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/enums.py:35 core/enums.py:35
|
||||
#: build/lib/core/enums.py:36 core/enums.py:36
|
||||
msgid "First child"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/enums.py:36 core/enums.py:36
|
||||
#: build/lib/core/enums.py:37 core/enums.py:37
|
||||
msgid "Last child"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/enums.py:37 core/enums.py:37
|
||||
#: build/lib/core/enums.py:38 core/enums.py:38
|
||||
msgid "First sibling"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/enums.py:38 core/enums.py:38
|
||||
#: build/lib/core/enums.py:39 core/enums.py:39
|
||||
msgid "Last sibling"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/enums.py:39 core/enums.py:39
|
||||
#: build/lib/core/enums.py:40 core/enums.py:40
|
||||
msgid "Left"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/enums.py:40 core/enums.py:40
|
||||
#: build/lib/core/enums.py:41 core/enums.py:41
|
||||
msgid "Right"
|
||||
msgstr ""
|
||||
|
||||
@@ -225,8 +225,8 @@ msgstr ""
|
||||
msgid "users"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:470 build/lib/core/models.py:1154
|
||||
#: core/models.py:470 core/models.py:1154
|
||||
#: build/lib/core/models.py:470 build/lib/core/models.py:1155
|
||||
#: core/models.py:470 core/models.py:1155
|
||||
msgid "title"
|
||||
msgstr ""
|
||||
|
||||
@@ -242,128 +242,128 @@ msgstr ""
|
||||
msgid "Documents"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:532 build/lib/core/models.py:872 core/models.py:532
|
||||
#: core/models.py:872
|
||||
#: build/lib/core/models.py:532 build/lib/core/models.py:873 core/models.py:532
|
||||
#: core/models.py:873
|
||||
msgid "Untitled Document"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:907 core/models.py:907
|
||||
#: build/lib/core/models.py:908 core/models.py:908
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you!"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:911 core/models.py:911
|
||||
#: build/lib/core/models.py:912 core/models.py:912
|
||||
#, python-brace-format
|
||||
msgid "{name} invited you with the role \"{role}\" on the following document:"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:917 core/models.py:917
|
||||
#: build/lib/core/models.py:918 core/models.py:918
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you: {title}"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1015 core/models.py:1015
|
||||
#: build/lib/core/models.py:1016 core/models.py:1016
|
||||
msgid "Document/user link trace"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1016 core/models.py:1016
|
||||
#: build/lib/core/models.py:1017 core/models.py:1017
|
||||
msgid "Document/user link traces"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1022 core/models.py:1022
|
||||
#: build/lib/core/models.py:1023 core/models.py:1023
|
||||
msgid "A link trace already exists for this document/user."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1045 core/models.py:1045
|
||||
#: build/lib/core/models.py:1046 core/models.py:1046
|
||||
msgid "Document favorite"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1046 core/models.py:1046
|
||||
#: build/lib/core/models.py:1047 core/models.py:1047
|
||||
msgid "Document favorites"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1052 core/models.py:1052
|
||||
#: build/lib/core/models.py:1053 core/models.py:1053
|
||||
msgid "This document is already targeted by a favorite relation instance for the same user."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1074 core/models.py:1074
|
||||
#: build/lib/core/models.py:1075 core/models.py:1075
|
||||
msgid "Document/user relation"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1075 core/models.py:1075
|
||||
#: build/lib/core/models.py:1076 core/models.py:1076
|
||||
msgid "Document/user relations"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1081 core/models.py:1081
|
||||
#: build/lib/core/models.py:1082 core/models.py:1082
|
||||
msgid "This user is already in this document."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1087 core/models.py:1087
|
||||
#: build/lib/core/models.py:1088 core/models.py:1088
|
||||
msgid "This team is already in this document."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1093 build/lib/core/models.py:1241
|
||||
#: core/models.py:1093 core/models.py:1241
|
||||
#: build/lib/core/models.py:1094 build/lib/core/models.py:1242
|
||||
#: core/models.py:1094 core/models.py:1242
|
||||
msgid "Either user or team must be set, not both."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1155 core/models.py:1155
|
||||
#: build/lib/core/models.py:1156 core/models.py:1156
|
||||
msgid "description"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1156 core/models.py:1156
|
||||
#: build/lib/core/models.py:1157 core/models.py:1157
|
||||
msgid "code"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1157 core/models.py:1157
|
||||
#: build/lib/core/models.py:1158 core/models.py:1158
|
||||
msgid "css"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1159 core/models.py:1159
|
||||
#: build/lib/core/models.py:1160 core/models.py:1160
|
||||
msgid "public"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1161 core/models.py:1161
|
||||
#: build/lib/core/models.py:1162 core/models.py:1162
|
||||
msgid "Whether this template is public for anyone to use."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1167 core/models.py:1167
|
||||
#: build/lib/core/models.py:1168 core/models.py:1168
|
||||
msgid "Template"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1168 core/models.py:1168
|
||||
#: build/lib/core/models.py:1169 core/models.py:1169
|
||||
msgid "Templates"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1222 core/models.py:1222
|
||||
#: build/lib/core/models.py:1223 core/models.py:1223
|
||||
msgid "Template/user relation"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1223 core/models.py:1223
|
||||
#: build/lib/core/models.py:1224 core/models.py:1224
|
||||
msgid "Template/user relations"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1229 core/models.py:1229
|
||||
#: build/lib/core/models.py:1230 core/models.py:1230
|
||||
msgid "This user is already in this template."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1235 core/models.py:1235
|
||||
#: build/lib/core/models.py:1236 core/models.py:1236
|
||||
msgid "This team is already in this template."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1258 core/models.py:1258
|
||||
#: build/lib/core/models.py:1259 core/models.py:1259
|
||||
msgid "email address"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1277 core/models.py:1277
|
||||
#: build/lib/core/models.py:1278 core/models.py:1278
|
||||
msgid "Document invitation"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1278 core/models.py:1278
|
||||
#: build/lib/core/models.py:1279 core/models.py:1279
|
||||
msgid "Document invitations"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1298 core/models.py:1298
|
||||
#: build/lib/core/models.py:1299 core/models.py:1299
|
||||
msgid "This email is already associated to a registered user."
|
||||
msgstr ""
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: lasuite-docs\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-04-29 11:48+0000\n"
|
||||
"PO-Revision-Date: 2025-05-05 07:07\n"
|
||||
"POT-Creation-Date: 2025-05-22 12:09+0000\n"
|
||||
"PO-Revision-Date: 2025-05-22 14:16\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Slovenian\n"
|
||||
"Language: sl_SI\n"
|
||||
@@ -66,32 +66,32 @@ msgstr "Vrsta telesa"
|
||||
msgid "Format"
|
||||
msgstr "Oblika"
|
||||
|
||||
#: build/lib/core/api/viewsets.py:966 core/api/viewsets.py:966
|
||||
#: build/lib/core/api/viewsets.py:967 core/api/viewsets.py:967
|
||||
#, python-brace-format
|
||||
msgid "copy of {title}"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/enums.py:35 core/enums.py:35
|
||||
#: build/lib/core/enums.py:36 core/enums.py:36
|
||||
msgid "First child"
|
||||
msgstr "Prvi otrok"
|
||||
|
||||
#: build/lib/core/enums.py:36 core/enums.py:36
|
||||
#: build/lib/core/enums.py:37 core/enums.py:37
|
||||
msgid "Last child"
|
||||
msgstr "Zadnji otrok"
|
||||
|
||||
#: build/lib/core/enums.py:37 core/enums.py:37
|
||||
#: build/lib/core/enums.py:38 core/enums.py:38
|
||||
msgid "First sibling"
|
||||
msgstr "Prvi brat in sestra"
|
||||
|
||||
#: build/lib/core/enums.py:38 core/enums.py:38
|
||||
#: build/lib/core/enums.py:39 core/enums.py:39
|
||||
msgid "Last sibling"
|
||||
msgstr "Zadnji brat in sestra"
|
||||
|
||||
#: build/lib/core/enums.py:39 core/enums.py:39
|
||||
#: build/lib/core/enums.py:40 core/enums.py:40
|
||||
msgid "Left"
|
||||
msgstr "Levo"
|
||||
|
||||
#: build/lib/core/enums.py:40 core/enums.py:40
|
||||
#: build/lib/core/enums.py:41 core/enums.py:41
|
||||
msgid "Right"
|
||||
msgstr "Desno"
|
||||
|
||||
@@ -225,8 +225,8 @@ msgstr "uporabnik"
|
||||
msgid "users"
|
||||
msgstr "uporabniki"
|
||||
|
||||
#: build/lib/core/models.py:470 build/lib/core/models.py:1154
|
||||
#: core/models.py:470 core/models.py:1154
|
||||
#: build/lib/core/models.py:470 build/lib/core/models.py:1155
|
||||
#: core/models.py:470 core/models.py:1155
|
||||
msgid "title"
|
||||
msgstr "naslov"
|
||||
|
||||
@@ -242,128 +242,128 @@ msgstr "Dokument"
|
||||
msgid "Documents"
|
||||
msgstr "Dokumenti"
|
||||
|
||||
#: build/lib/core/models.py:532 build/lib/core/models.py:872 core/models.py:532
|
||||
#: core/models.py:872
|
||||
#: build/lib/core/models.py:532 build/lib/core/models.py:873 core/models.py:532
|
||||
#: core/models.py:873
|
||||
msgid "Untitled Document"
|
||||
msgstr "Dokument brez naslova"
|
||||
|
||||
#: build/lib/core/models.py:907 core/models.py:907
|
||||
#: build/lib/core/models.py:908 core/models.py:908
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you!"
|
||||
msgstr "{name} je delil dokument z vami!"
|
||||
|
||||
#: build/lib/core/models.py:911 core/models.py:911
|
||||
#: build/lib/core/models.py:912 core/models.py:912
|
||||
#, python-brace-format
|
||||
msgid "{name} invited you with the role \"{role}\" on the following document:"
|
||||
msgstr "{name} vas je povabil z vlogo \"{role}\" na naslednjem dokumentu:"
|
||||
|
||||
#: build/lib/core/models.py:917 core/models.py:917
|
||||
#: build/lib/core/models.py:918 core/models.py:918
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you: {title}"
|
||||
msgstr "{name} je delil dokument z vami: {title}"
|
||||
|
||||
#: build/lib/core/models.py:1015 core/models.py:1015
|
||||
#: build/lib/core/models.py:1016 core/models.py:1016
|
||||
msgid "Document/user link trace"
|
||||
msgstr "Dokument/sled povezave uporabnika"
|
||||
|
||||
#: build/lib/core/models.py:1016 core/models.py:1016
|
||||
#: build/lib/core/models.py:1017 core/models.py:1017
|
||||
msgid "Document/user link traces"
|
||||
msgstr "Sledi povezav dokumenta/uporabnika"
|
||||
|
||||
#: build/lib/core/models.py:1022 core/models.py:1022
|
||||
#: build/lib/core/models.py:1023 core/models.py:1023
|
||||
msgid "A link trace already exists for this document/user."
|
||||
msgstr "Za ta dokument/uporabnika že obstaja sled povezave."
|
||||
|
||||
#: build/lib/core/models.py:1045 core/models.py:1045
|
||||
#: build/lib/core/models.py:1046 core/models.py:1046
|
||||
msgid "Document favorite"
|
||||
msgstr "Priljubljeni dokument"
|
||||
|
||||
#: build/lib/core/models.py:1046 core/models.py:1046
|
||||
#: build/lib/core/models.py:1047 core/models.py:1047
|
||||
msgid "Document favorites"
|
||||
msgstr "Priljubljeni dokumenti"
|
||||
|
||||
#: build/lib/core/models.py:1052 core/models.py:1052
|
||||
#: build/lib/core/models.py:1053 core/models.py:1053
|
||||
msgid "This document is already targeted by a favorite relation instance for the same user."
|
||||
msgstr "Ta dokument je že ciljno usmerjen s priljubljenim primerkom relacije za istega uporabnika."
|
||||
|
||||
#: build/lib/core/models.py:1074 core/models.py:1074
|
||||
#: build/lib/core/models.py:1075 core/models.py:1075
|
||||
msgid "Document/user relation"
|
||||
msgstr "Odnos dokument/uporabnik"
|
||||
|
||||
#: build/lib/core/models.py:1075 core/models.py:1075
|
||||
#: build/lib/core/models.py:1076 core/models.py:1076
|
||||
msgid "Document/user relations"
|
||||
msgstr "Odnosi dokument/uporabnik"
|
||||
|
||||
#: build/lib/core/models.py:1081 core/models.py:1081
|
||||
#: build/lib/core/models.py:1082 core/models.py:1082
|
||||
msgid "This user is already in this document."
|
||||
msgstr "Ta uporabnik je že v tem dokumentu."
|
||||
|
||||
#: build/lib/core/models.py:1087 core/models.py:1087
|
||||
#: build/lib/core/models.py:1088 core/models.py:1088
|
||||
msgid "This team is already in this document."
|
||||
msgstr "Ta ekipa je že v tem dokumentu."
|
||||
|
||||
#: build/lib/core/models.py:1093 build/lib/core/models.py:1241
|
||||
#: core/models.py:1093 core/models.py:1241
|
||||
#: build/lib/core/models.py:1094 build/lib/core/models.py:1242
|
||||
#: core/models.py:1094 core/models.py:1242
|
||||
msgid "Either user or team must be set, not both."
|
||||
msgstr "Nastaviti je treba bodisi uporabnika ali ekipo, a ne obojega."
|
||||
|
||||
#: build/lib/core/models.py:1155 core/models.py:1155
|
||||
#: build/lib/core/models.py:1156 core/models.py:1156
|
||||
msgid "description"
|
||||
msgstr "opis"
|
||||
|
||||
#: build/lib/core/models.py:1156 core/models.py:1156
|
||||
#: build/lib/core/models.py:1157 core/models.py:1157
|
||||
msgid "code"
|
||||
msgstr "koda"
|
||||
|
||||
#: build/lib/core/models.py:1157 core/models.py:1157
|
||||
#: build/lib/core/models.py:1158 core/models.py:1158
|
||||
msgid "css"
|
||||
msgstr "css"
|
||||
|
||||
#: build/lib/core/models.py:1159 core/models.py:1159
|
||||
#: build/lib/core/models.py:1160 core/models.py:1160
|
||||
msgid "public"
|
||||
msgstr "javno"
|
||||
|
||||
#: build/lib/core/models.py:1161 core/models.py:1161
|
||||
#: build/lib/core/models.py:1162 core/models.py:1162
|
||||
msgid "Whether this template is public for anyone to use."
|
||||
msgstr "Ali je ta predloga javna za uporabo."
|
||||
|
||||
#: build/lib/core/models.py:1167 core/models.py:1167
|
||||
#: build/lib/core/models.py:1168 core/models.py:1168
|
||||
msgid "Template"
|
||||
msgstr "Predloga"
|
||||
|
||||
#: build/lib/core/models.py:1168 core/models.py:1168
|
||||
#: build/lib/core/models.py:1169 core/models.py:1169
|
||||
msgid "Templates"
|
||||
msgstr "Predloge"
|
||||
|
||||
#: build/lib/core/models.py:1222 core/models.py:1222
|
||||
#: build/lib/core/models.py:1223 core/models.py:1223
|
||||
msgid "Template/user relation"
|
||||
msgstr "Odnos predloga/uporabnik"
|
||||
|
||||
#: build/lib/core/models.py:1223 core/models.py:1223
|
||||
#: build/lib/core/models.py:1224 core/models.py:1224
|
||||
msgid "Template/user relations"
|
||||
msgstr "Odnosi med predlogo in uporabnikom"
|
||||
|
||||
#: build/lib/core/models.py:1229 core/models.py:1229
|
||||
#: build/lib/core/models.py:1230 core/models.py:1230
|
||||
msgid "This user is already in this template."
|
||||
msgstr "Ta uporabnik je že v tej predlogi."
|
||||
|
||||
#: build/lib/core/models.py:1235 core/models.py:1235
|
||||
#: build/lib/core/models.py:1236 core/models.py:1236
|
||||
msgid "This team is already in this template."
|
||||
msgstr "Ta ekipa je že v tej predlogi."
|
||||
|
||||
#: build/lib/core/models.py:1258 core/models.py:1258
|
||||
#: build/lib/core/models.py:1259 core/models.py:1259
|
||||
msgid "email address"
|
||||
msgstr "elektronski naslov"
|
||||
|
||||
#: build/lib/core/models.py:1277 core/models.py:1277
|
||||
#: build/lib/core/models.py:1278 core/models.py:1278
|
||||
msgid "Document invitation"
|
||||
msgstr "Vabilo na dokument"
|
||||
|
||||
#: build/lib/core/models.py:1278 core/models.py:1278
|
||||
#: build/lib/core/models.py:1279 core/models.py:1279
|
||||
msgid "Document invitations"
|
||||
msgstr "Vabila na dokument"
|
||||
|
||||
#: build/lib/core/models.py:1298 core/models.py:1298
|
||||
#: build/lib/core/models.py:1299 core/models.py:1299
|
||||
msgid "This email is already associated to a registered user."
|
||||
msgstr "Ta e-poštni naslov je že povezan z registriranim uporabnikom."
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: lasuite-docs\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-04-29 11:48+0000\n"
|
||||
"PO-Revision-Date: 2025-05-05 07:07\n"
|
||||
"POT-Creation-Date: 2025-05-22 12:09+0000\n"
|
||||
"PO-Revision-Date: 2025-05-22 14:16\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Swedish\n"
|
||||
"Language: sv_SE\n"
|
||||
@@ -66,32 +66,32 @@ msgstr ""
|
||||
msgid "Format"
|
||||
msgstr "Format"
|
||||
|
||||
#: build/lib/core/api/viewsets.py:966 core/api/viewsets.py:966
|
||||
#: build/lib/core/api/viewsets.py:967 core/api/viewsets.py:967
|
||||
#, python-brace-format
|
||||
msgid "copy of {title}"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/enums.py:35 core/enums.py:35
|
||||
#: build/lib/core/enums.py:36 core/enums.py:36
|
||||
msgid "First child"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/enums.py:36 core/enums.py:36
|
||||
#: build/lib/core/enums.py:37 core/enums.py:37
|
||||
msgid "Last child"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/enums.py:37 core/enums.py:37
|
||||
#: build/lib/core/enums.py:38 core/enums.py:38
|
||||
msgid "First sibling"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/enums.py:38 core/enums.py:38
|
||||
#: build/lib/core/enums.py:39 core/enums.py:39
|
||||
msgid "Last sibling"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/enums.py:39 core/enums.py:39
|
||||
#: build/lib/core/enums.py:40 core/enums.py:40
|
||||
msgid "Left"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/enums.py:40 core/enums.py:40
|
||||
#: build/lib/core/enums.py:41 core/enums.py:41
|
||||
msgid "Right"
|
||||
msgstr ""
|
||||
|
||||
@@ -225,8 +225,8 @@ msgstr ""
|
||||
msgid "users"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:470 build/lib/core/models.py:1154
|
||||
#: core/models.py:470 core/models.py:1154
|
||||
#: build/lib/core/models.py:470 build/lib/core/models.py:1155
|
||||
#: core/models.py:470 core/models.py:1155
|
||||
msgid "title"
|
||||
msgstr ""
|
||||
|
||||
@@ -242,128 +242,128 @@ msgstr ""
|
||||
msgid "Documents"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:532 build/lib/core/models.py:872 core/models.py:532
|
||||
#: core/models.py:872
|
||||
#: build/lib/core/models.py:532 build/lib/core/models.py:873 core/models.py:532
|
||||
#: core/models.py:873
|
||||
msgid "Untitled Document"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:907 core/models.py:907
|
||||
#: build/lib/core/models.py:908 core/models.py:908
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you!"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:911 core/models.py:911
|
||||
#: build/lib/core/models.py:912 core/models.py:912
|
||||
#, python-brace-format
|
||||
msgid "{name} invited you with the role \"{role}\" on the following document:"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:917 core/models.py:917
|
||||
#: build/lib/core/models.py:918 core/models.py:918
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you: {title}"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1015 core/models.py:1015
|
||||
#: build/lib/core/models.py:1016 core/models.py:1016
|
||||
msgid "Document/user link trace"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1016 core/models.py:1016
|
||||
#: build/lib/core/models.py:1017 core/models.py:1017
|
||||
msgid "Document/user link traces"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1022 core/models.py:1022
|
||||
#: build/lib/core/models.py:1023 core/models.py:1023
|
||||
msgid "A link trace already exists for this document/user."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1045 core/models.py:1045
|
||||
#: build/lib/core/models.py:1046 core/models.py:1046
|
||||
msgid "Document favorite"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1046 core/models.py:1046
|
||||
#: build/lib/core/models.py:1047 core/models.py:1047
|
||||
msgid "Document favorites"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1052 core/models.py:1052
|
||||
#: build/lib/core/models.py:1053 core/models.py:1053
|
||||
msgid "This document is already targeted by a favorite relation instance for the same user."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1074 core/models.py:1074
|
||||
#: build/lib/core/models.py:1075 core/models.py:1075
|
||||
msgid "Document/user relation"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1075 core/models.py:1075
|
||||
#: build/lib/core/models.py:1076 core/models.py:1076
|
||||
msgid "Document/user relations"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1081 core/models.py:1081
|
||||
#: build/lib/core/models.py:1082 core/models.py:1082
|
||||
msgid "This user is already in this document."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1087 core/models.py:1087
|
||||
#: build/lib/core/models.py:1088 core/models.py:1088
|
||||
msgid "This team is already in this document."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1093 build/lib/core/models.py:1241
|
||||
#: core/models.py:1093 core/models.py:1241
|
||||
#: build/lib/core/models.py:1094 build/lib/core/models.py:1242
|
||||
#: core/models.py:1094 core/models.py:1242
|
||||
msgid "Either user or team must be set, not both."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1155 core/models.py:1155
|
||||
#: build/lib/core/models.py:1156 core/models.py:1156
|
||||
msgid "description"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1156 core/models.py:1156
|
||||
#: build/lib/core/models.py:1157 core/models.py:1157
|
||||
msgid "code"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1157 core/models.py:1157
|
||||
#: build/lib/core/models.py:1158 core/models.py:1158
|
||||
msgid "css"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1159 core/models.py:1159
|
||||
#: build/lib/core/models.py:1160 core/models.py:1160
|
||||
msgid "public"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1161 core/models.py:1161
|
||||
#: build/lib/core/models.py:1162 core/models.py:1162
|
||||
msgid "Whether this template is public for anyone to use."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1167 core/models.py:1167
|
||||
#: build/lib/core/models.py:1168 core/models.py:1168
|
||||
msgid "Template"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1168 core/models.py:1168
|
||||
#: build/lib/core/models.py:1169 core/models.py:1169
|
||||
msgid "Templates"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1222 core/models.py:1222
|
||||
#: build/lib/core/models.py:1223 core/models.py:1223
|
||||
msgid "Template/user relation"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1223 core/models.py:1223
|
||||
#: build/lib/core/models.py:1224 core/models.py:1224
|
||||
msgid "Template/user relations"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1229 core/models.py:1229
|
||||
#: build/lib/core/models.py:1230 core/models.py:1230
|
||||
msgid "This user is already in this template."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1235 core/models.py:1235
|
||||
#: build/lib/core/models.py:1236 core/models.py:1236
|
||||
msgid "This team is already in this template."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1258 core/models.py:1258
|
||||
#: build/lib/core/models.py:1259 core/models.py:1259
|
||||
msgid "email address"
|
||||
msgstr "e-postadress"
|
||||
|
||||
#: build/lib/core/models.py:1277 core/models.py:1277
|
||||
#: build/lib/core/models.py:1278 core/models.py:1278
|
||||
msgid "Document invitation"
|
||||
msgstr "Bjud in dokument"
|
||||
|
||||
#: build/lib/core/models.py:1278 core/models.py:1278
|
||||
#: build/lib/core/models.py:1279 core/models.py:1279
|
||||
msgid "Document invitations"
|
||||
msgstr "Inbjudningar dokument"
|
||||
|
||||
#: build/lib/core/models.py:1298 core/models.py:1298
|
||||
#: build/lib/core/models.py:1299 core/models.py:1299
|
||||
msgid "This email is already associated to a registered user."
|
||||
msgstr "Denna e-postadress är redan associerad med en registrerad användare."
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: lasuite-docs\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-04-29 11:48+0000\n"
|
||||
"PO-Revision-Date: 2025-05-05 07:07\n"
|
||||
"POT-Creation-Date: 2025-05-22 12:09+0000\n"
|
||||
"PO-Revision-Date: 2025-05-22 14:16\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Turkish\n"
|
||||
"Language: tr_TR\n"
|
||||
@@ -66,32 +66,32 @@ msgstr ""
|
||||
msgid "Format"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/api/viewsets.py:966 core/api/viewsets.py:966
|
||||
#: build/lib/core/api/viewsets.py:967 core/api/viewsets.py:967
|
||||
#, python-brace-format
|
||||
msgid "copy of {title}"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/enums.py:35 core/enums.py:35
|
||||
#: build/lib/core/enums.py:36 core/enums.py:36
|
||||
msgid "First child"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/enums.py:36 core/enums.py:36
|
||||
#: build/lib/core/enums.py:37 core/enums.py:37
|
||||
msgid "Last child"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/enums.py:37 core/enums.py:37
|
||||
#: build/lib/core/enums.py:38 core/enums.py:38
|
||||
msgid "First sibling"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/enums.py:38 core/enums.py:38
|
||||
#: build/lib/core/enums.py:39 core/enums.py:39
|
||||
msgid "Last sibling"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/enums.py:39 core/enums.py:39
|
||||
#: build/lib/core/enums.py:40 core/enums.py:40
|
||||
msgid "Left"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/enums.py:40 core/enums.py:40
|
||||
#: build/lib/core/enums.py:41 core/enums.py:41
|
||||
msgid "Right"
|
||||
msgstr ""
|
||||
|
||||
@@ -225,8 +225,8 @@ msgstr ""
|
||||
msgid "users"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:470 build/lib/core/models.py:1154
|
||||
#: core/models.py:470 core/models.py:1154
|
||||
#: build/lib/core/models.py:470 build/lib/core/models.py:1155
|
||||
#: core/models.py:470 core/models.py:1155
|
||||
msgid "title"
|
||||
msgstr ""
|
||||
|
||||
@@ -242,128 +242,128 @@ msgstr ""
|
||||
msgid "Documents"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:532 build/lib/core/models.py:872 core/models.py:532
|
||||
#: core/models.py:872
|
||||
#: build/lib/core/models.py:532 build/lib/core/models.py:873 core/models.py:532
|
||||
#: core/models.py:873
|
||||
msgid "Untitled Document"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:907 core/models.py:907
|
||||
#: build/lib/core/models.py:908 core/models.py:908
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you!"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:911 core/models.py:911
|
||||
#: build/lib/core/models.py:912 core/models.py:912
|
||||
#, python-brace-format
|
||||
msgid "{name} invited you with the role \"{role}\" on the following document:"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:917 core/models.py:917
|
||||
#: build/lib/core/models.py:918 core/models.py:918
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you: {title}"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1015 core/models.py:1015
|
||||
#: build/lib/core/models.py:1016 core/models.py:1016
|
||||
msgid "Document/user link trace"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1016 core/models.py:1016
|
||||
#: build/lib/core/models.py:1017 core/models.py:1017
|
||||
msgid "Document/user link traces"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1022 core/models.py:1022
|
||||
#: build/lib/core/models.py:1023 core/models.py:1023
|
||||
msgid "A link trace already exists for this document/user."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1045 core/models.py:1045
|
||||
#: build/lib/core/models.py:1046 core/models.py:1046
|
||||
msgid "Document favorite"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1046 core/models.py:1046
|
||||
#: build/lib/core/models.py:1047 core/models.py:1047
|
||||
msgid "Document favorites"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1052 core/models.py:1052
|
||||
#: build/lib/core/models.py:1053 core/models.py:1053
|
||||
msgid "This document is already targeted by a favorite relation instance for the same user."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1074 core/models.py:1074
|
||||
#: build/lib/core/models.py:1075 core/models.py:1075
|
||||
msgid "Document/user relation"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1075 core/models.py:1075
|
||||
#: build/lib/core/models.py:1076 core/models.py:1076
|
||||
msgid "Document/user relations"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1081 core/models.py:1081
|
||||
#: build/lib/core/models.py:1082 core/models.py:1082
|
||||
msgid "This user is already in this document."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1087 core/models.py:1087
|
||||
#: build/lib/core/models.py:1088 core/models.py:1088
|
||||
msgid "This team is already in this document."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1093 build/lib/core/models.py:1241
|
||||
#: core/models.py:1093 core/models.py:1241
|
||||
#: build/lib/core/models.py:1094 build/lib/core/models.py:1242
|
||||
#: core/models.py:1094 core/models.py:1242
|
||||
msgid "Either user or team must be set, not both."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1155 core/models.py:1155
|
||||
#: build/lib/core/models.py:1156 core/models.py:1156
|
||||
msgid "description"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1156 core/models.py:1156
|
||||
#: build/lib/core/models.py:1157 core/models.py:1157
|
||||
msgid "code"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1157 core/models.py:1157
|
||||
#: build/lib/core/models.py:1158 core/models.py:1158
|
||||
msgid "css"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1159 core/models.py:1159
|
||||
#: build/lib/core/models.py:1160 core/models.py:1160
|
||||
msgid "public"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1161 core/models.py:1161
|
||||
#: build/lib/core/models.py:1162 core/models.py:1162
|
||||
msgid "Whether this template is public for anyone to use."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1167 core/models.py:1167
|
||||
#: build/lib/core/models.py:1168 core/models.py:1168
|
||||
msgid "Template"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1168 core/models.py:1168
|
||||
#: build/lib/core/models.py:1169 core/models.py:1169
|
||||
msgid "Templates"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1222 core/models.py:1222
|
||||
#: build/lib/core/models.py:1223 core/models.py:1223
|
||||
msgid "Template/user relation"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1223 core/models.py:1223
|
||||
#: build/lib/core/models.py:1224 core/models.py:1224
|
||||
msgid "Template/user relations"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1229 core/models.py:1229
|
||||
#: build/lib/core/models.py:1230 core/models.py:1230
|
||||
msgid "This user is already in this template."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1235 core/models.py:1235
|
||||
#: build/lib/core/models.py:1236 core/models.py:1236
|
||||
msgid "This team is already in this template."
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1258 core/models.py:1258
|
||||
#: build/lib/core/models.py:1259 core/models.py:1259
|
||||
msgid "email address"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1277 core/models.py:1277
|
||||
#: build/lib/core/models.py:1278 core/models.py:1278
|
||||
msgid "Document invitation"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1278 core/models.py:1278
|
||||
#: build/lib/core/models.py:1279 core/models.py:1279
|
||||
msgid "Document invitations"
|
||||
msgstr ""
|
||||
|
||||
#: build/lib/core/models.py:1298 core/models.py:1298
|
||||
#: build/lib/core/models.py:1299 core/models.py:1299
|
||||
msgid "This email is already associated to a registered user."
|
||||
msgstr ""
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: lasuite-docs\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-04-29 11:48+0000\n"
|
||||
"PO-Revision-Date: 2025-05-05 07:07\n"
|
||||
"POT-Creation-Date: 2025-05-22 12:09+0000\n"
|
||||
"PO-Revision-Date: 2025-05-22 14:16\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Chinese Simplified\n"
|
||||
"Language: zh_CN\n"
|
||||
@@ -66,32 +66,32 @@ msgstr "正文类型"
|
||||
msgid "Format"
|
||||
msgstr "格式"
|
||||
|
||||
#: build/lib/core/api/viewsets.py:966 core/api/viewsets.py:966
|
||||
#: build/lib/core/api/viewsets.py:967 core/api/viewsets.py:967
|
||||
#, python-brace-format
|
||||
msgid "copy of {title}"
|
||||
msgstr "{title} 的副本"
|
||||
|
||||
#: build/lib/core/enums.py:35 core/enums.py:35
|
||||
#: build/lib/core/enums.py:36 core/enums.py:36
|
||||
msgid "First child"
|
||||
msgstr "第一个子项"
|
||||
|
||||
#: build/lib/core/enums.py:36 core/enums.py:36
|
||||
#: build/lib/core/enums.py:37 core/enums.py:37
|
||||
msgid "Last child"
|
||||
msgstr "最后一个子项"
|
||||
|
||||
#: build/lib/core/enums.py:37 core/enums.py:37
|
||||
#: build/lib/core/enums.py:38 core/enums.py:38
|
||||
msgid "First sibling"
|
||||
msgstr "第一个同级项"
|
||||
|
||||
#: build/lib/core/enums.py:38 core/enums.py:38
|
||||
#: build/lib/core/enums.py:39 core/enums.py:39
|
||||
msgid "Last sibling"
|
||||
msgstr "最后一个同级项"
|
||||
|
||||
#: build/lib/core/enums.py:39 core/enums.py:39
|
||||
#: build/lib/core/enums.py:40 core/enums.py:40
|
||||
msgid "Left"
|
||||
msgstr "左"
|
||||
|
||||
#: build/lib/core/enums.py:40 core/enums.py:40
|
||||
#: build/lib/core/enums.py:41 core/enums.py:41
|
||||
msgid "Right"
|
||||
msgstr "右"
|
||||
|
||||
@@ -225,8 +225,8 @@ msgstr "用户"
|
||||
msgid "users"
|
||||
msgstr "个用户"
|
||||
|
||||
#: build/lib/core/models.py:470 build/lib/core/models.py:1154
|
||||
#: core/models.py:470 core/models.py:1154
|
||||
#: build/lib/core/models.py:470 build/lib/core/models.py:1155
|
||||
#: core/models.py:470 core/models.py:1155
|
||||
msgid "title"
|
||||
msgstr "标题"
|
||||
|
||||
@@ -242,128 +242,128 @@ msgstr "文档"
|
||||
msgid "Documents"
|
||||
msgstr "个文档"
|
||||
|
||||
#: build/lib/core/models.py:532 build/lib/core/models.py:872 core/models.py:532
|
||||
#: core/models.py:872
|
||||
#: build/lib/core/models.py:532 build/lib/core/models.py:873 core/models.py:532
|
||||
#: core/models.py:873
|
||||
msgid "Untitled Document"
|
||||
msgstr "未命名文档"
|
||||
|
||||
#: build/lib/core/models.py:907 core/models.py:907
|
||||
#: build/lib/core/models.py:908 core/models.py:908
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you!"
|
||||
msgstr "{name} 与您共享了一个文档!"
|
||||
|
||||
#: build/lib/core/models.py:911 core/models.py:911
|
||||
#: build/lib/core/models.py:912 core/models.py:912
|
||||
#, python-brace-format
|
||||
msgid "{name} invited you with the role \"{role}\" on the following document:"
|
||||
msgstr "{name} 邀请您以“{role}”角色访问以下文档:"
|
||||
|
||||
#: build/lib/core/models.py:917 core/models.py:917
|
||||
#: build/lib/core/models.py:918 core/models.py:918
|
||||
#, python-brace-format
|
||||
msgid "{name} shared a document with you: {title}"
|
||||
msgstr "{name} 与您共享了一个文档:{title}"
|
||||
|
||||
#: build/lib/core/models.py:1015 core/models.py:1015
|
||||
#: build/lib/core/models.py:1016 core/models.py:1016
|
||||
msgid "Document/user link trace"
|
||||
msgstr "文档/用户链接跟踪"
|
||||
|
||||
#: build/lib/core/models.py:1016 core/models.py:1016
|
||||
#: build/lib/core/models.py:1017 core/models.py:1017
|
||||
msgid "Document/user link traces"
|
||||
msgstr "个文档/用户链接跟踪"
|
||||
|
||||
#: build/lib/core/models.py:1022 core/models.py:1022
|
||||
#: build/lib/core/models.py:1023 core/models.py:1023
|
||||
msgid "A link trace already exists for this document/user."
|
||||
msgstr "此文档/用户的链接跟踪已存在。"
|
||||
|
||||
#: build/lib/core/models.py:1045 core/models.py:1045
|
||||
#: build/lib/core/models.py:1046 core/models.py:1046
|
||||
msgid "Document favorite"
|
||||
msgstr "文档收藏"
|
||||
|
||||
#: build/lib/core/models.py:1046 core/models.py:1046
|
||||
#: build/lib/core/models.py:1047 core/models.py:1047
|
||||
msgid "Document favorites"
|
||||
msgstr "文档收藏夹"
|
||||
|
||||
#: build/lib/core/models.py:1052 core/models.py:1052
|
||||
#: build/lib/core/models.py:1053 core/models.py:1053
|
||||
msgid "This document is already targeted by a favorite relation instance for the same user."
|
||||
msgstr "该文档已被同一用户的收藏关系实例关联。"
|
||||
|
||||
#: build/lib/core/models.py:1074 core/models.py:1074
|
||||
#: build/lib/core/models.py:1075 core/models.py:1075
|
||||
msgid "Document/user relation"
|
||||
msgstr "文档/用户关系"
|
||||
|
||||
#: build/lib/core/models.py:1075 core/models.py:1075
|
||||
#: build/lib/core/models.py:1076 core/models.py:1076
|
||||
msgid "Document/user relations"
|
||||
msgstr "文档/用户关系集"
|
||||
|
||||
#: build/lib/core/models.py:1081 core/models.py:1081
|
||||
#: build/lib/core/models.py:1082 core/models.py:1082
|
||||
msgid "This user is already in this document."
|
||||
msgstr "该用户已在此文档中。"
|
||||
|
||||
#: build/lib/core/models.py:1087 core/models.py:1087
|
||||
#: build/lib/core/models.py:1088 core/models.py:1088
|
||||
msgid "This team is already in this document."
|
||||
msgstr "该团队已在此文档中。"
|
||||
|
||||
#: build/lib/core/models.py:1093 build/lib/core/models.py:1241
|
||||
#: core/models.py:1093 core/models.py:1241
|
||||
#: build/lib/core/models.py:1094 build/lib/core/models.py:1242
|
||||
#: core/models.py:1094 core/models.py:1242
|
||||
msgid "Either user or team must be set, not both."
|
||||
msgstr "必须设置用户或团队之一,不能同时设置两者。"
|
||||
|
||||
#: build/lib/core/models.py:1155 core/models.py:1155
|
||||
#: build/lib/core/models.py:1156 core/models.py:1156
|
||||
msgid "description"
|
||||
msgstr "说明"
|
||||
|
||||
#: build/lib/core/models.py:1156 core/models.py:1156
|
||||
#: build/lib/core/models.py:1157 core/models.py:1157
|
||||
msgid "code"
|
||||
msgstr "代码"
|
||||
|
||||
#: build/lib/core/models.py:1157 core/models.py:1157
|
||||
#: build/lib/core/models.py:1158 core/models.py:1158
|
||||
msgid "css"
|
||||
msgstr "css"
|
||||
|
||||
#: build/lib/core/models.py:1159 core/models.py:1159
|
||||
#: build/lib/core/models.py:1160 core/models.py:1160
|
||||
msgid "public"
|
||||
msgstr "公开"
|
||||
|
||||
#: build/lib/core/models.py:1161 core/models.py:1161
|
||||
#: build/lib/core/models.py:1162 core/models.py:1162
|
||||
msgid "Whether this template is public for anyone to use."
|
||||
msgstr "该模板是否公开供任何人使用。"
|
||||
|
||||
#: build/lib/core/models.py:1167 core/models.py:1167
|
||||
#: build/lib/core/models.py:1168 core/models.py:1168
|
||||
msgid "Template"
|
||||
msgstr "模板"
|
||||
|
||||
#: build/lib/core/models.py:1168 core/models.py:1168
|
||||
#: build/lib/core/models.py:1169 core/models.py:1169
|
||||
msgid "Templates"
|
||||
msgstr "模板"
|
||||
|
||||
#: build/lib/core/models.py:1222 core/models.py:1222
|
||||
#: build/lib/core/models.py:1223 core/models.py:1223
|
||||
msgid "Template/user relation"
|
||||
msgstr "模板/用户关系"
|
||||
|
||||
#: build/lib/core/models.py:1223 core/models.py:1223
|
||||
#: build/lib/core/models.py:1224 core/models.py:1224
|
||||
msgid "Template/user relations"
|
||||
msgstr "模板/用户关系集"
|
||||
|
||||
#: build/lib/core/models.py:1229 core/models.py:1229
|
||||
#: build/lib/core/models.py:1230 core/models.py:1230
|
||||
msgid "This user is already in this template."
|
||||
msgstr "该用户已在此模板中。"
|
||||
|
||||
#: build/lib/core/models.py:1235 core/models.py:1235
|
||||
#: build/lib/core/models.py:1236 core/models.py:1236
|
||||
msgid "This team is already in this template."
|
||||
msgstr "该团队已在此模板中。"
|
||||
|
||||
#: build/lib/core/models.py:1258 core/models.py:1258
|
||||
#: build/lib/core/models.py:1259 core/models.py:1259
|
||||
msgid "email address"
|
||||
msgstr "电子邮件地址"
|
||||
|
||||
#: build/lib/core/models.py:1277 core/models.py:1277
|
||||
#: build/lib/core/models.py:1278 core/models.py:1278
|
||||
msgid "Document invitation"
|
||||
msgstr "文档邀请"
|
||||
|
||||
#: build/lib/core/models.py:1278 core/models.py:1278
|
||||
#: build/lib/core/models.py:1279 core/models.py:1279
|
||||
msgid "Document invitations"
|
||||
msgstr "文档邀请"
|
||||
|
||||
#: build/lib/core/models.py:1298 core/models.py:1298
|
||||
#: build/lib/core/models.py:1299 core/models.py:1299
|
||||
msgid "This email is already associated to a registered user."
|
||||
msgstr "此电子邮件已经与现有注册用户关联。"
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "impress"
|
||||
version = "3.2.1"
|
||||
version = "3.3.0"
|
||||
authors = [{ "name" = "DINUM", "email" = "dev@mail.numerique.gouv.fr" }]
|
||||
classifiers = [
|
||||
"Development Status :: 5 - Production/Stable",
|
||||
@@ -26,14 +26,14 @@ readme = "README.md"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = [
|
||||
"beautifulsoup4==4.13.4",
|
||||
"boto3==1.38.18",
|
||||
"boto3==1.38.27",
|
||||
"Brotli==1.1.0",
|
||||
"celery[redis]==5.5.2",
|
||||
"celery[redis]==5.5.3",
|
||||
"django-configurations==2.5.1",
|
||||
"django-cors-headers==4.7.0",
|
||||
"django-countries==7.6.1",
|
||||
"django-filter==25.1",
|
||||
"django-lasuite[all]==0.0.8",
|
||||
"django-lasuite[all]==0.0.9",
|
||||
"django-parler==2.3",
|
||||
"django-redis==5.4.0",
|
||||
"django-storages[s3]==1.14.6",
|
||||
@@ -46,19 +46,19 @@ dependencies = [
|
||||
"easy_thumbnails==2.10",
|
||||
"factory_boy==3.3.3",
|
||||
"gunicorn==23.0.0",
|
||||
"jsonschema==4.23.0",
|
||||
"jsonschema==4.24.0",
|
||||
"lxml==5.4.0",
|
||||
"markdown==3.8",
|
||||
"mozilla-django-oidc==4.0.1",
|
||||
"nested-multipart-parser==1.5.0",
|
||||
"openai==1.79.0",
|
||||
"openai==1.82.1",
|
||||
"psycopg[binary]==3.2.9",
|
||||
"pycrdt==0.12.19",
|
||||
"pycrdt==0.12.20",
|
||||
"PyJWT==2.10.1",
|
||||
"python-magic==0.4.27",
|
||||
"redis<6.0.0",
|
||||
"requests==2.32.3",
|
||||
"sentry-sdk==2.28.0",
|
||||
"sentry-sdk==2.29.1",
|
||||
"whitenoise==6.9.0",
|
||||
]
|
||||
|
||||
@@ -72,10 +72,10 @@ dependencies = [
|
||||
dev = [
|
||||
"django-extensions==4.1",
|
||||
"django-test-migrations==1.5.0",
|
||||
"drf-spectacular-sidecar==2025.5.1",
|
||||
"freezegun==1.5.1",
|
||||
"drf-spectacular-sidecar==2025.6.1",
|
||||
"freezegun==1.5.2",
|
||||
"ipdb==0.13.13",
|
||||
"ipython==9.2.0",
|
||||
"ipython==9.3.0",
|
||||
"pyfakefs==5.8.0",
|
||||
"pylint-django==2.6.1",
|
||||
"pylint==3.3.7",
|
||||
@@ -83,10 +83,10 @@ dev = [
|
||||
"pytest-django==4.11.1",
|
||||
"pytest==8.3.5",
|
||||
"pytest-icdiff==0.9",
|
||||
"pytest-xdist==3.6.1",
|
||||
"pytest-xdist==3.7.0",
|
||||
"responses==0.25.7",
|
||||
"ruff==0.11.10",
|
||||
"types-requests==2.32.0.20250515",
|
||||
"ruff==0.11.12",
|
||||
"types-requests==2.32.0.20250602",
|
||||
]
|
||||
|
||||
[tool.setuptools]
|
||||
|
||||
@@ -50,19 +50,7 @@ ENV NEXT_PUBLIC_PUBLISH_AS_MIT=${PUBLISH_AS_MIT}
|
||||
RUN yarn build
|
||||
|
||||
# ---- Front-end image ----
|
||||
FROM nginxinc/nginx-unprivileged:1.27-alpine AS frontend-production
|
||||
|
||||
# Remove the upgrade part once nginx has published
|
||||
# a new image that fixes the CVE related to libxml2
|
||||
ARG UID=101
|
||||
USER root
|
||||
|
||||
# Upgrade system packages to install security updates
|
||||
RUN apk update && \
|
||||
apk upgrade && \
|
||||
rm -rf /var/cache/apk/*
|
||||
|
||||
USER $UID
|
||||
FROM nginxinc/nginx-unprivileged:alpine3.21 AS frontend-production
|
||||
|
||||
# Un-privileged user running the application
|
||||
ARG DOCKER_USER
|
||||
|
||||
@@ -10,8 +10,6 @@ test.beforeEach(async ({ page }) => {
|
||||
|
||||
test.describe('404', () => {
|
||||
test('Checks all the elements are visible', async ({ page }) => {
|
||||
await expect(page.getByLabel('Image 404')).toBeVisible();
|
||||
await expect(page.getByText('Ouch')).toBeVisible();
|
||||
await expect(
|
||||
page.getByText(
|
||||
'It seems that the page you are looking for does not exist or cannot be displayed correctly.',
|
||||
|
||||
@@ -4,10 +4,11 @@ export const CONFIG = {
|
||||
AI_FEATURE_ENABLED: true,
|
||||
CRISP_WEBSITE_ID: null,
|
||||
COLLABORATION_WS_URL: 'ws://localhost:4444/collaboration/ws/',
|
||||
COLLABORATION_WS_NOT_CONNECTED_READY_ONLY: false,
|
||||
ENVIRONMENT: 'development',
|
||||
FRONTEND_CSS_URL: null,
|
||||
FRONTEND_HOMEPAGE_FEATURE_ENABLED: true,
|
||||
FRONTEND_THEME: 'default',
|
||||
FRONTEND_THEME: null,
|
||||
MEDIA_BASE_URL: 'http://localhost:8083',
|
||||
LANGUAGES: [
|
||||
['en-us', 'English'],
|
||||
@@ -20,7 +21,25 @@ export const CONFIG = {
|
||||
POSTHOG_KEY: {},
|
||||
SENTRY_DSN: null,
|
||||
theme_customization: {},
|
||||
};
|
||||
} as const;
|
||||
|
||||
export const overrideConfig = async (
|
||||
page: Page,
|
||||
newConfig: { [K in keyof typeof CONFIG]?: unknown },
|
||||
) =>
|
||||
await page.route('**/api/v1.0/config/', async (route) => {
|
||||
const request = route.request();
|
||||
if (request.method().includes('GET')) {
|
||||
await route.fulfill({
|
||||
json: {
|
||||
...CONFIG,
|
||||
...newConfig,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
await route.continue();
|
||||
}
|
||||
});
|
||||
|
||||
export const keyCloakSignIn = async (
|
||||
page: Page,
|
||||
@@ -28,10 +47,7 @@ export const keyCloakSignIn = async (
|
||||
fromHome: boolean = true,
|
||||
) => {
|
||||
if (fromHome) {
|
||||
await page
|
||||
.getByRole('button', { name: 'Proconnect Login' })
|
||||
.first()
|
||||
.click();
|
||||
await page.getByRole('button', { name: 'Start Writing' }).first().click();
|
||||
}
|
||||
|
||||
const login = `user-e2e-${browserName}`;
|
||||
@@ -91,9 +107,16 @@ export const createDoc = async (
|
||||
};
|
||||
|
||||
export const verifyDocName = async (page: Page, docName: string) => {
|
||||
const input = page.getByRole('textbox', { name: 'doc title input' });
|
||||
await expect(
|
||||
page.getByLabel('It is the card information about the document.'),
|
||||
).toBeVisible({
|
||||
timeout: 10000,
|
||||
});
|
||||
|
||||
try {
|
||||
await expect(input).toHaveText(docName);
|
||||
await expect(
|
||||
page.getByRole('textbox', { name: 'doc title input' }),
|
||||
).toHaveText(docName);
|
||||
} catch {
|
||||
await expect(page.getByRole('heading', { name: docName })).toBeVisible();
|
||||
}
|
||||
|
||||
@@ -2,38 +2,14 @@ import path from 'path';
|
||||
|
||||
import { expect, test } from '@playwright/test';
|
||||
|
||||
import { CONFIG, createDoc } from './common';
|
||||
import { CONFIG, createDoc, overrideConfig } from './common';
|
||||
|
||||
test.describe('Config', () => {
|
||||
test('it checks the config api is called', async ({ page }) => {
|
||||
const responsePromise = page.waitForResponse(
|
||||
(response) =>
|
||||
response.url().includes('/config/') && response.status() === 200,
|
||||
);
|
||||
|
||||
await page.goto('/');
|
||||
|
||||
const response = await responsePromise;
|
||||
expect(response.ok()).toBeTruthy();
|
||||
|
||||
expect(await response.json()).toStrictEqual(CONFIG);
|
||||
});
|
||||
|
||||
test('it checks that sentry is trying to init from config endpoint', async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.route('**/api/v1.0/config/', async (route) => {
|
||||
const request = route.request();
|
||||
if (request.method().includes('GET')) {
|
||||
await route.fulfill({
|
||||
json: {
|
||||
...CONFIG,
|
||||
SENTRY_DSN: 'https://sentry.io/123',
|
||||
},
|
||||
});
|
||||
} else {
|
||||
await route.continue();
|
||||
}
|
||||
await overrideConfig(page, {
|
||||
SENTRY_DSN: 'https://sentry.io/123',
|
||||
});
|
||||
|
||||
const invalidMsg = 'Invalid Sentry Dsn: https://sentry.io/123';
|
||||
@@ -98,18 +74,8 @@ test.describe('Config', () => {
|
||||
page,
|
||||
browserName,
|
||||
}) => {
|
||||
await page.route('**/api/v1.0/config/', async (route) => {
|
||||
const request = route.request();
|
||||
if (request.method().includes('GET')) {
|
||||
await route.fulfill({
|
||||
json: {
|
||||
...CONFIG,
|
||||
AI_FEATURE_ENABLED: false,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
await route.continue();
|
||||
}
|
||||
await overrideConfig(page, {
|
||||
AI_FEATURE_ENABLED: false,
|
||||
});
|
||||
|
||||
await page.goto('/');
|
||||
@@ -129,18 +95,8 @@ test.describe('Config', () => {
|
||||
test('it checks that Crisp is trying to init from config endpoint', async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.route('**/api/v1.0/config/', async (route) => {
|
||||
const request = route.request();
|
||||
if (request.method().includes('GET')) {
|
||||
await route.fulfill({
|
||||
json: {
|
||||
...CONFIG,
|
||||
CRISP_WEBSITE_ID: '1234',
|
||||
},
|
||||
});
|
||||
} else {
|
||||
await route.continue();
|
||||
}
|
||||
await overrideConfig(page, {
|
||||
CRISP_WEBSITE_ID: '1234',
|
||||
});
|
||||
|
||||
await page.goto('/');
|
||||
@@ -151,18 +107,8 @@ test.describe('Config', () => {
|
||||
});
|
||||
|
||||
test('it checks FRONTEND_CSS_URL config', async ({ page }) => {
|
||||
await page.route('**/api/v1.0/config/', async (route) => {
|
||||
const request = route.request();
|
||||
if (request.method().includes('GET')) {
|
||||
await route.fulfill({
|
||||
json: {
|
||||
...CONFIG,
|
||||
FRONTEND_CSS_URL: 'http://localhost:123465/css/style.css',
|
||||
},
|
||||
});
|
||||
} else {
|
||||
await route.continue();
|
||||
}
|
||||
await overrideConfig(page, {
|
||||
FRONTEND_CSS_URL: 'http://localhost:123465/css/style.css',
|
||||
});
|
||||
|
||||
await page.goto('/');
|
||||
@@ -178,9 +124,7 @@ test.describe('Config', () => {
|
||||
test.describe('Config: Not loggued', () => {
|
||||
test.use({ storageState: { cookies: [], origins: [] } });
|
||||
|
||||
test('it checks that theme is configured from config endpoint', async ({
|
||||
page,
|
||||
}) => {
|
||||
test('it checks the config api is called', async ({ page }) => {
|
||||
const responsePromise = page.waitForResponse(
|
||||
(response) =>
|
||||
response.url().includes('/config/') && response.status() === 200,
|
||||
@@ -191,11 +135,25 @@ test.describe('Config: Not loggued', () => {
|
||||
const response = await responsePromise;
|
||||
expect(response.ok()).toBeTruthy();
|
||||
|
||||
const jsonResponse = await response.json();
|
||||
expect(jsonResponse.FRONTEND_THEME).toStrictEqual('default');
|
||||
const json = (await response.json()) as typeof CONFIG;
|
||||
const { theme_customization, ...configApi } = json;
|
||||
expect(theme_customization).toBeDefined();
|
||||
const { theme_customization: _, ...CONFIG_LEFT } = CONFIG;
|
||||
|
||||
const footer = page.locator('footer').first();
|
||||
expect(configApi).toStrictEqual(CONFIG_LEFT);
|
||||
});
|
||||
|
||||
test('it checks that theme is configured from config endpoint', async ({
|
||||
page,
|
||||
}) => {
|
||||
await overrideConfig(page, {
|
||||
FRONTEND_THEME: 'dsfr',
|
||||
});
|
||||
|
||||
await page.goto('/');
|
||||
|
||||
const header = page.locator('header').first();
|
||||
// alt 'Gouvernement Logo' comes from the theme
|
||||
await expect(footer.getByAltText('Gouvernement Logo')).toBeVisible();
|
||||
await expect(header.getByAltText('Gouvernement Logo')).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -425,6 +425,10 @@ test.describe('Doc Editor', () => {
|
||||
const downloadPromise = page.waitForEvent('download', (download) => {
|
||||
return download.suggestedFilename().includes(`html`);
|
||||
});
|
||||
const responseCheckPromise = page.waitForResponse(
|
||||
(response) =>
|
||||
response.url().includes('media-check') && response.status() === 200,
|
||||
);
|
||||
|
||||
await verifyDocName(page, randomDoc);
|
||||
|
||||
@@ -439,6 +443,8 @@ test.describe('Doc Editor', () => {
|
||||
const fileChooser = await fileChooserPromise;
|
||||
await fileChooser.setFiles(path.join(__dirname, 'assets/test.html'));
|
||||
|
||||
await responseCheckPromise;
|
||||
|
||||
await page.locator('.bn-block-content[data-name="test.html"]').click();
|
||||
await page.getByRole('button', { name: 'Download file' }).click();
|
||||
|
||||
@@ -455,6 +461,51 @@ test.describe('Doc Editor', () => {
|
||||
expect(svgBuffer.toString()).toContain('Hello svg');
|
||||
});
|
||||
|
||||
test('it analyzes uploads', async ({ page, browserName }) => {
|
||||
const [randomDoc] = await createDoc(page, 'doc-editor', browserName, 1);
|
||||
|
||||
let requestCount = 0;
|
||||
await page.route(
|
||||
/.*\/documents\/.*\/media-check\/\?key=.*/,
|
||||
async (route) => {
|
||||
const request = route.request();
|
||||
if (request.method().includes('GET')) {
|
||||
await route.fulfill({
|
||||
json: {
|
||||
status: requestCount ? 'ready' : 'processing',
|
||||
file: '/anything.html',
|
||||
},
|
||||
});
|
||||
|
||||
requestCount++;
|
||||
} else {
|
||||
await route.continue();
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
const fileChooserPromise = page.waitForEvent('filechooser');
|
||||
|
||||
await verifyDocName(page, randomDoc);
|
||||
|
||||
const editor = page.locator('.ProseMirror.bn-editor');
|
||||
|
||||
await editor.click();
|
||||
await editor.locator('.bn-block-outer').last().fill('/');
|
||||
await page.getByText('Embedded file').click();
|
||||
await page.getByText('Upload file').click();
|
||||
|
||||
const fileChooser = await fileChooserPromise;
|
||||
await fileChooser.setFiles(path.join(__dirname, 'assets/test.html'));
|
||||
|
||||
await expect(editor.getByText('Analyzing file...')).toBeVisible();
|
||||
// The retry takes a few seconds
|
||||
await expect(editor.getByText('test.html')).toBeVisible({
|
||||
timeout: 7000,
|
||||
});
|
||||
await expect(editor.getByText('Analyzing file...')).toBeHidden();
|
||||
});
|
||||
|
||||
test('it checks block editing when not connected to collab server', async ({
|
||||
page,
|
||||
}) => {
|
||||
@@ -465,6 +516,7 @@ test.describe('Doc Editor', () => {
|
||||
json: {
|
||||
...CONFIG,
|
||||
COLLABORATION_WS_URL: 'ws://localhost:5555/collaboration/ws/',
|
||||
COLLABORATION_WS_NOT_CONNECTED_READY_ONLY: true,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
|
||||
@@ -208,7 +208,6 @@ test.describe('Documents filters', () => {
|
||||
|
||||
// Initial state
|
||||
await expect(allDocs).toBeVisible();
|
||||
await expect(allDocs).toHaveCSS('background-color', 'rgb(238, 238, 238)');
|
||||
await expect(allDocs).toHaveAttribute('aria-selected', 'true');
|
||||
|
||||
await expect(myDocs).toBeVisible();
|
||||
|
||||
@@ -101,6 +101,8 @@ test.describe('Doc Visibility: Restricted', () => {
|
||||
page,
|
||||
browserName,
|
||||
}) => {
|
||||
test.slow();
|
||||
|
||||
await page.goto('/');
|
||||
await keyCloakSignIn(page, browserName);
|
||||
|
||||
@@ -121,14 +123,16 @@ test.describe('Doc Visibility: Restricted', () => {
|
||||
await keyCloakSignIn(page, otherBrowser!);
|
||||
|
||||
await expect(
|
||||
page.getByRole('link', { name: 'Docs Logo Docs BETA' }),
|
||||
page.getByRole('link', { name: 'Docs Logo Docs' }),
|
||||
).toBeVisible();
|
||||
|
||||
await page.goto(urlDoc);
|
||||
|
||||
await expect(
|
||||
page.getByText('You do not have permission to view this document.'),
|
||||
).toBeVisible();
|
||||
).toBeVisible({
|
||||
timeout: 10000,
|
||||
});
|
||||
});
|
||||
|
||||
test('A doc is accessible when member.', async ({ page, browserName }) => {
|
||||
@@ -173,7 +177,7 @@ test.describe('Doc Visibility: Restricted', () => {
|
||||
await keyCloakSignIn(page, otherBrowser!);
|
||||
|
||||
await expect(
|
||||
page.getByRole('link', { name: 'Docs Logo Docs BETA' }),
|
||||
page.getByRole('link', { name: 'Docs Logo Docs' }),
|
||||
).toBeVisible();
|
||||
|
||||
await page.goto(urlDoc);
|
||||
@@ -430,7 +434,7 @@ test.describe('Doc Visibility: Authenticated', () => {
|
||||
await keyCloakSignIn(page, otherBrowser!);
|
||||
|
||||
await expect(
|
||||
page.getByRole('link', { name: 'Docs Logo Docs BETA' }),
|
||||
page.getByRole('link', { name: 'Docs Logo Docs' }),
|
||||
).toBeVisible();
|
||||
|
||||
await page.goto(urlDoc);
|
||||
@@ -490,7 +494,7 @@ test.describe('Doc Visibility: Authenticated', () => {
|
||||
await keyCloakSignIn(page, otherBrowser!);
|
||||
|
||||
await expect(
|
||||
page.getByRole('link', { name: 'Docs Logo Docs BETA' }),
|
||||
page.getByRole('link', { name: 'Docs Logo Docs' }),
|
||||
).toBeVisible();
|
||||
|
||||
await page.goto(urlDoc);
|
||||
|
||||
@@ -1,14 +1,115 @@
|
||||
import { expect, test } from '@playwright/test';
|
||||
|
||||
import { overrideConfig } from './common';
|
||||
|
||||
test.describe('Footer', () => {
|
||||
test.use({ storageState: { cookies: [], origins: [] } });
|
||||
|
||||
test('checks the footer is not displayed if no config', async ({ page }) => {
|
||||
await overrideConfig(page, {
|
||||
theme_customization: {},
|
||||
});
|
||||
|
||||
await page.goto('/');
|
||||
await expect(page.locator('footer')).toBeHidden();
|
||||
});
|
||||
|
||||
test('checks all the elements are visible', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
const footer = page.locator('footer').first();
|
||||
|
||||
await expect(footer.getByAltText('Docs Logo')).toBeVisible();
|
||||
await expect(footer.getByRole('heading', { name: 'Docs' })).toBeVisible();
|
||||
|
||||
await expect(footer.getByRole('link', { name: 'Github' })).toBeVisible();
|
||||
await expect(footer.getByRole('link', { name: 'DINUM' })).toBeVisible();
|
||||
await expect(footer.getByRole('link', { name: 'ZenDiS' })).toBeVisible();
|
||||
|
||||
await expect(
|
||||
footer.getByRole('link', { name: 'BlockNote.js' }),
|
||||
).toBeVisible();
|
||||
await expect(
|
||||
footer.getByRole('link', { name: 'Legal Notice' }),
|
||||
).toBeVisible();
|
||||
await expect(
|
||||
footer.getByRole('link', { name: 'Personal data and cookies' }),
|
||||
).toBeVisible();
|
||||
await expect(
|
||||
footer.getByRole('link', { name: 'Accessibility' }),
|
||||
).toBeVisible();
|
||||
|
||||
await expect(
|
||||
footer.getByText(
|
||||
'Unless otherwise stated, all content on this site is under licence',
|
||||
),
|
||||
).toBeVisible();
|
||||
|
||||
// Check the translation
|
||||
const header = page.locator('header').first();
|
||||
await header.getByRole('button').getByText('English').click();
|
||||
await page.getByLabel('Français').click();
|
||||
|
||||
await expect(
|
||||
page.locator('footer').getByText('Mentions légales'),
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
test('checks the footer is correctly overrided', async ({ page }) => {
|
||||
await overrideConfig(page, {
|
||||
FRONTEND_THEME: 'dsfr',
|
||||
theme_customization: {
|
||||
footer: {
|
||||
default: {
|
||||
logo: {
|
||||
src: '/assets/logo-gouv.svg',
|
||||
width: '220px',
|
||||
alt: 'Gouvernement Logo',
|
||||
},
|
||||
externalLinks: [
|
||||
{
|
||||
label: 'legifrance.gouv.fr',
|
||||
href: '#',
|
||||
},
|
||||
{
|
||||
label: 'info.gouv.fr',
|
||||
href: '#',
|
||||
},
|
||||
],
|
||||
legalLinks: [
|
||||
{
|
||||
label: 'Legal link',
|
||||
href: '#',
|
||||
},
|
||||
],
|
||||
bottomInformation: {
|
||||
label: 'Some bottom information text',
|
||||
link: {
|
||||
label: 'a custom label',
|
||||
href: '#',
|
||||
},
|
||||
},
|
||||
},
|
||||
fr: {
|
||||
bottomInformation: {
|
||||
label: "Text d'information en bas de page en français",
|
||||
link: {
|
||||
label: 'un label personnalisé',
|
||||
href: '#',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await page.goto('/');
|
||||
const footer = page.locator('footer').first();
|
||||
|
||||
await expect(footer.getByAltText('Gouvernement Logo')).toBeVisible();
|
||||
|
||||
await expect(footer.getByRole('heading', { name: 'Docs' })).toBeHidden();
|
||||
await expect(footer.getByText('BETA')).toBeHidden();
|
||||
|
||||
await expect(
|
||||
footer.getByRole('link', { name: 'legifrance.gouv.fr' }),
|
||||
).toBeVisible();
|
||||
@@ -18,53 +119,30 @@ test.describe('Footer', () => {
|
||||
).toBeVisible();
|
||||
|
||||
await expect(
|
||||
footer.getByRole('link', { name: 'service-public.fr' }),
|
||||
footer.getByRole('link', { name: 'Legal link' }),
|
||||
).toBeVisible();
|
||||
|
||||
await expect(
|
||||
footer.getByRole('link', { name: 'data.gouv.fr' }),
|
||||
footer.getByText('Some bottom information text'),
|
||||
).toBeVisible();
|
||||
|
||||
await expect(
|
||||
footer.getByRole('link', { name: 'Legal Notice' }),
|
||||
footer.getByRole('link', { name: 'a custom label' }),
|
||||
).toBeVisible();
|
||||
|
||||
// Check the translation
|
||||
const header = page.locator('header').first();
|
||||
await header.getByRole('button').getByText('English').click();
|
||||
await page.getByLabel('Français').click();
|
||||
|
||||
await expect(
|
||||
page
|
||||
.locator('footer')
|
||||
.getByText("Text d'information en bas de page en français"),
|
||||
).toBeVisible();
|
||||
|
||||
await expect(
|
||||
footer.getByRole('link', { name: 'Personal data and cookies' }),
|
||||
).toBeVisible();
|
||||
|
||||
await expect(
|
||||
footer.getByRole('link', { name: 'Accessibility' }),
|
||||
).toBeVisible();
|
||||
|
||||
await expect(
|
||||
footer.getByText(
|
||||
'Unless otherwise stated, all content on this site is under licence',
|
||||
),
|
||||
footer.getByRole('link', { name: 'un label personnalisé' }),
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
const legalPages = [
|
||||
{ name: 'Legal Notice', url: '/legal-notice/' },
|
||||
{ name: 'Personal data and cookies', url: '/personal-data-cookies/' },
|
||||
{ name: 'Accessibility', url: '/accessibility/' },
|
||||
];
|
||||
for (const { name, url } of legalPages) {
|
||||
test(`checks ${name} page`, async ({ page }) => {
|
||||
await page.goto('/');
|
||||
|
||||
const footer = page.locator('footer').first();
|
||||
await footer.getByRole('link', { name }).click();
|
||||
|
||||
await expect(
|
||||
page
|
||||
.getByRole('heading', {
|
||||
name,
|
||||
})
|
||||
.first(),
|
||||
).toBeVisible();
|
||||
|
||||
await expect(page).toHaveURL(url);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,20 +1,39 @@
|
||||
import { expect, test } from '@playwright/test';
|
||||
|
||||
import { expectLoginPage, keyCloakSignIn } from './common';
|
||||
import { expectLoginPage, keyCloakSignIn, overrideConfig } from './common';
|
||||
|
||||
test.describe('Header', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/');
|
||||
});
|
||||
|
||||
test('checks all the elements are visible', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
|
||||
const header = page.locator('header').first();
|
||||
|
||||
await expect(header.getByLabel('Docs Logo')).toBeVisible();
|
||||
await expect(header.locator('h2').getByText('Docs')).toHaveCSS(
|
||||
'color',
|
||||
'rgb(0, 0, 145)',
|
||||
'font-family',
|
||||
/Roboto/i,
|
||||
);
|
||||
|
||||
await expect(
|
||||
header.getByRole('button', {
|
||||
name: 'Logout',
|
||||
}),
|
||||
).toBeVisible();
|
||||
|
||||
await expect(header.getByText('English')).toBeVisible();
|
||||
});
|
||||
|
||||
test('checks all the elements are visible with DSFR theme', async ({
|
||||
page,
|
||||
}) => {
|
||||
await overrideConfig(page, {
|
||||
FRONTEND_THEME: 'dsfr',
|
||||
});
|
||||
await page.goto('/');
|
||||
|
||||
const header = page.locator('header').first();
|
||||
|
||||
await expect(header.getByLabel('Docs Logo')).toBeVisible();
|
||||
await expect(header.locator('h2').getByText('Docs')).toHaveCSS(
|
||||
'font-family',
|
||||
/Marianne/i,
|
||||
@@ -36,6 +55,11 @@ test.describe('Header', () => {
|
||||
});
|
||||
|
||||
test('checks La Gauffre interaction', async ({ page }) => {
|
||||
await overrideConfig(page, {
|
||||
FRONTEND_THEME: 'dsfr',
|
||||
});
|
||||
await page.goto('/');
|
||||
|
||||
const header = page.locator('header').first();
|
||||
|
||||
await expect(
|
||||
@@ -68,11 +92,13 @@ test.describe('Header', () => {
|
||||
test.describe('Header mobile', () => {
|
||||
test.use({ viewport: { width: 500, height: 1200 } });
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/');
|
||||
});
|
||||
test('it checks the header when mobile with DSFR theme', async ({ page }) => {
|
||||
await overrideConfig(page, {
|
||||
FRONTEND_THEME: 'dsfr',
|
||||
});
|
||||
|
||||
await page.goto('/');
|
||||
|
||||
test('it checks the header when mobile', async ({ page }) => {
|
||||
const header = page.locator('header').first();
|
||||
|
||||
await expect(header.getByLabel('Open the header menu')).toBeVisible();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { expect, test } from '@playwright/test';
|
||||
|
||||
import { CONFIG } from './common';
|
||||
import { overrideConfig } from './common';
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/docs/');
|
||||
@@ -9,6 +9,62 @@ test.beforeEach(async ({ page }) => {
|
||||
test.describe('Home page', () => {
|
||||
test.use({ storageState: { cookies: [], origins: [] } });
|
||||
test('checks all the elements are visible', async ({ page }) => {
|
||||
await page.goto('/docs/');
|
||||
|
||||
// Check header content
|
||||
const header = page.locator('header').first();
|
||||
const footer = page.locator('footer').first();
|
||||
await expect(header).toBeVisible();
|
||||
await expect(
|
||||
header.getByRole('button', { name: /Language/ }),
|
||||
).toBeVisible();
|
||||
await expect(header.getByRole('img', { name: 'Docs logo' })).toBeVisible();
|
||||
await expect(header.getByRole('heading', { name: 'Docs' })).toBeVisible();
|
||||
|
||||
// Check the titles
|
||||
const h2 = page.locator('h2');
|
||||
await expect(h2.getByText('Govs ❤️ Open Source.')).toBeVisible();
|
||||
await expect(
|
||||
h2.getByText('Collaborative writing, Simplified.'),
|
||||
).toBeVisible();
|
||||
await expect(
|
||||
h2.getByText('An uncompromising writing experience.'),
|
||||
).toBeVisible();
|
||||
await expect(
|
||||
h2.getByText('Simple and secure collaboration.'),
|
||||
).toBeVisible();
|
||||
await expect(h2.getByText('Flexible export.')).toBeVisible();
|
||||
await expect(
|
||||
h2.getByText('A new way to organize knowledge.'),
|
||||
).toBeVisible();
|
||||
await expect(
|
||||
page.getByRole('button', { name: 'Start Writing' }),
|
||||
).toBeVisible();
|
||||
|
||||
await expect(footer).toBeVisible();
|
||||
});
|
||||
|
||||
test('checks all the elements are visible with dsfr theme', async ({
|
||||
page,
|
||||
}) => {
|
||||
await overrideConfig(page, {
|
||||
FRONTEND_THEME: 'dsfr',
|
||||
theme_customization: {
|
||||
footer: {
|
||||
default: {
|
||||
externalLinks: [
|
||||
{
|
||||
label: 'legifrance.gouv.fr',
|
||||
href: '#',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await page.goto('/docs/');
|
||||
|
||||
// Check header content
|
||||
const header = page.locator('header').first();
|
||||
const footer = page.locator('footer').first();
|
||||
@@ -54,18 +110,8 @@ test.describe('Home page', () => {
|
||||
});
|
||||
|
||||
test('it checks the homepage feature flag', async ({ page }) => {
|
||||
await page.route('**/api/v1.0/config/', async (route) => {
|
||||
const request = route.request();
|
||||
if (request.method().includes('GET')) {
|
||||
await route.fulfill({
|
||||
json: {
|
||||
...CONFIG,
|
||||
FRONTEND_HOMEPAGE_FEATURE_ENABLED: false,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
await route.continue();
|
||||
}
|
||||
await overrideConfig(page, {
|
||||
FRONTEND_HOMEPAGE_FEATURE_ENABLED: false,
|
||||
});
|
||||
|
||||
await page.goto('/');
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "app-e2e",
|
||||
"version": "3.2.1",
|
||||
"version": "3.3.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"lint": "eslint . --ext .ts",
|
||||
|
||||
@@ -3,6 +3,8 @@ import { cunninghamConfig as tokens } from '@gouvfr-lasuite/ui-kit';
|
||||
const customColors = {
|
||||
'primary-action': '#1212FF',
|
||||
'primary-bg': '#FAFAFA',
|
||||
'primary-focus': '#0A76F6',
|
||||
'secondary-icon': 'var(--c--theme--colors--primary-text)',
|
||||
'blue-400': '#7AB1E8',
|
||||
'blue-500': '#417DC4',
|
||||
'blue-600': '#3558A2',
|
||||
@@ -35,19 +37,18 @@ const customColors = {
|
||||
'yellow-600': '#66673D',
|
||||
};
|
||||
|
||||
tokens.themes.default.theme.colors = {
|
||||
...tokens.themes.default.theme.colors,
|
||||
...customColors,
|
||||
};
|
||||
|
||||
tokens.themes.default.theme = {
|
||||
...tokens.themes.default.theme,
|
||||
...{
|
||||
logo: {
|
||||
src: '/assets/logo-gouv.svg',
|
||||
widthHeader: '110px',
|
||||
widthFooter: '220px',
|
||||
alt: 'Gouvernement Logo',
|
||||
src: '',
|
||||
alt: '',
|
||||
widthHeader: '',
|
||||
widthFooter: '',
|
||||
},
|
||||
colors: {
|
||||
...tokens.themes.default.theme.colors,
|
||||
...customColors,
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -55,13 +56,201 @@ tokens.themes.default.theme = {
|
||||
tokens.themes.default.components = {
|
||||
...tokens.themes.default.components,
|
||||
...{
|
||||
'la-gauffre': {
|
||||
activated: true,
|
||||
},
|
||||
'home-proconnect': {
|
||||
activated: true,
|
||||
'la-gaufre': false,
|
||||
'home-proconnect': false,
|
||||
beta: false,
|
||||
'image-system-filter': '',
|
||||
favicon: {
|
||||
ico: '/assets/favicon-light.ico',
|
||||
'png-light': '/assets/favicon-light.png',
|
||||
'png-dark': '/assets/favicon-dark.png',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default tokens;
|
||||
const dsfrTheme = {
|
||||
dsfr: {
|
||||
theme: {
|
||||
colors: {
|
||||
'secondary-icon': '#C9191E',
|
||||
},
|
||||
logo: {
|
||||
src: '/assets/logo-gouv.svg',
|
||||
widthHeader: '110px',
|
||||
widthFooter: '220px',
|
||||
alt: 'Gouvernement Logo',
|
||||
},
|
||||
},
|
||||
components: {
|
||||
'la-gaufre': true,
|
||||
'home-proconnect': true,
|
||||
beta: true,
|
||||
favicon: {
|
||||
ico: '/assets/favicon-dsfr.ico',
|
||||
'png-light': '/assets/favicon-dsfr.png',
|
||||
'png-dark': '/assets/favicon-dark-dsfr.png',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const genericTheme = {
|
||||
generic: {
|
||||
theme: {
|
||||
colors: {
|
||||
'primary-action': '#206EBD',
|
||||
'primary-focus': '#1E64BF',
|
||||
'primary-text': '#2E2C28',
|
||||
'primary-050': '#F8F8F7',
|
||||
'primary-100': '#F0EFEC',
|
||||
'primary-150': '#F4F4FD',
|
||||
'primary-200': '#E8E7E4',
|
||||
'primary-300': '#CFCDC9',
|
||||
'primary-400': '#979592',
|
||||
'primary-500': '#82807D',
|
||||
'primary-600': '#3F3D39',
|
||||
'primary-700': '#2E2C28',
|
||||
'primary-800': '#302E29',
|
||||
'primary-900': '#282622',
|
||||
'primary-950': '#201F1C',
|
||||
'secondary-text': '#fff',
|
||||
'secondary-50': '#F4F7FA',
|
||||
'secondary-100': '#D7E3EE',
|
||||
'secondary-200': '#B8CCE1',
|
||||
'secondary-300': '#99B4D3',
|
||||
'secondary-400': '#7595BE',
|
||||
'secondary-500': '#5874A0',
|
||||
'secondary-600': '#3A5383',
|
||||
'secondary-700': '#1E3462',
|
||||
'secondary-800': '#091B41',
|
||||
'secondary-900': '#08183B',
|
||||
'secondary-950': '#071636',
|
||||
'greyscale-text': '#3C3B38',
|
||||
'greyscale-000': '#fff',
|
||||
'greyscale-050': '#F8F7F7',
|
||||
'greyscale-100': '#F3F3F2',
|
||||
'greyscale-200': '#ECEBEA',
|
||||
'greyscale-250': '#E4E3E2',
|
||||
'greyscale-300': '#D3D2CF',
|
||||
'greyscale-350': '#eee',
|
||||
'greyscale-400': '#96948E',
|
||||
'greyscale-500': '#817E77',
|
||||
'greyscale-600': '#6A6862',
|
||||
'greyscale-700': '#3C3B38',
|
||||
'greyscale-750': '#383632',
|
||||
'greyscale-800': '#2D2B27',
|
||||
'greyscale-900': '#262522',
|
||||
'greyscale-950': '#201F1C',
|
||||
'greyscale-1000': '#181714',
|
||||
'success-text': '#234935',
|
||||
'success-50': '#F3FBF5',
|
||||
'success-100': '#E4F7EA',
|
||||
'success-200': '#CAEED4',
|
||||
'success-300': '#A0E0B5',
|
||||
'success-400': '#6CC88C',
|
||||
'success-500': '#6CC88C',
|
||||
'success-600': '#358D5C',
|
||||
'success-700': '#2D704B',
|
||||
'success-800': '#28583F',
|
||||
'success-900': '#234935',
|
||||
'success-950': '#0F281B',
|
||||
'info-text': '#212445',
|
||||
'info-50': '#F2F6FB',
|
||||
'info-100': '#E2E9F5',
|
||||
'info-200': '#CCD8EE',
|
||||
'info-300': '#A9C0E3',
|
||||
'info-400': '#809DD4',
|
||||
'info-500': '#617BC7',
|
||||
'info-600': '#4A5CBF',
|
||||
'info-700': '#3E49B2',
|
||||
'info-800': '#353C8F',
|
||||
'info-900': '#303771',
|
||||
'info-950': '#212445',
|
||||
'warning-text': '#D97C3A',
|
||||
'warning-50': '#FDF7F1',
|
||||
'warning-100': '#FBEDDC',
|
||||
'warning-200': '#F5D9B9',
|
||||
'warning-300': '#EDBE8C',
|
||||
'warning-400': '#E2985C',
|
||||
'warning-500': '#D97C3A',
|
||||
'warning-600': '#C96330',
|
||||
'warning-700': '#A34B32',
|
||||
'warning-800': '#813B2C',
|
||||
'warning-900': '#693327',
|
||||
'warning-950': '#381713',
|
||||
'danger-action': '#C0182A',
|
||||
'danger-text': '#FFF',
|
||||
'danger-050': '#FDF5F4',
|
||||
'danger-100': '#FBEBE8',
|
||||
'danger-200': '#F9E0DC',
|
||||
'danger-300': '#F3C3BD',
|
||||
'danger-400': '#E26552',
|
||||
'danger-500': '#C91F00',
|
||||
'danger-600': '#A71901',
|
||||
'danger-700': '#562C2B',
|
||||
'danger-800': '#392425',
|
||||
'danger-900': '#311F20',
|
||||
'danger-950': '#2A191A',
|
||||
'blue-400': '#8BAECC',
|
||||
'blue-500': '#567AA2',
|
||||
'blue-600': '#455784',
|
||||
'brown-400': '#E4C090',
|
||||
'brown-500': '#BA9977',
|
||||
'brown-600': '#735C45',
|
||||
'cyan-400': '#5CBEC9',
|
||||
'cyan-500': '#43A1B3',
|
||||
'cyan-600': '#39809B',
|
||||
'gold-400': '#ECBF50',
|
||||
'gold-500': '#DFA038',
|
||||
'gold-600': '#C17B31',
|
||||
'green-400': '#5DBD9A',
|
||||
'green-500': '#3AA183',
|
||||
'green-600': '#2A816D',
|
||||
'olive-400': '#AFD662',
|
||||
'olive-500': '#90BB4B',
|
||||
'olive-600': '#6E9441',
|
||||
'orange-400': '#E2985C',
|
||||
'orange-500': '#D97C3A',
|
||||
'orange-600': '#C96330',
|
||||
'pink-400': '#BE8FC8',
|
||||
'pink-500': '#A563B1',
|
||||
'pink-600': '#8B44A5',
|
||||
'purple-400': '#BE8FC8',
|
||||
'purple-500': '#A563B1',
|
||||
'purple-600': '#8B44A5',
|
||||
'yellow-400': '#EDC947',
|
||||
'yellow-500': '#DBB13A',
|
||||
'yellow-600': '#B88A34',
|
||||
},
|
||||
font: {
|
||||
families: {
|
||||
base: 'Inter, Roboto Flex Variable, sans-serif',
|
||||
accent: 'Inter, Roboto Flex Variable, sans-serif',
|
||||
},
|
||||
},
|
||||
},
|
||||
components: {
|
||||
button: {
|
||||
primary: {
|
||||
background: {
|
||||
'color-hover': 'var(--c--theme--colors--primary-focus)',
|
||||
'color-active': 'var(--c--theme--colors--primary-focus)',
|
||||
'color-focus': 'var(--c--theme--colors--primary-focus)',
|
||||
},
|
||||
},
|
||||
},
|
||||
'image-system-filter': 'saturate(0.2)',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const docsTokens = {
|
||||
...tokens,
|
||||
themes: {
|
||||
...tokens.themes,
|
||||
...dsfrTheme,
|
||||
...genericTheme,
|
||||
},
|
||||
};
|
||||
|
||||
export default docsTokens;
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "app-impress",
|
||||
"version": "3.2.1",
|
||||
"version": "3.3.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "prettier --check . && yarn stylelint && next build",
|
||||
"build:ci": "cp .env.development .env.local && yarn build",
|
||||
"build-theme": "cunningham -g css,ts -o src/cunningham --utility-classes && yarn prettier",
|
||||
"build-theme": "cunningham -g css,ts -o src/cunningham --utility-classes && yarn prettier && yarn stylelint --fix",
|
||||
"start": "npx -y serve@latest out",
|
||||
"lint": "tsc --noEmit && next lint",
|
||||
"prettier": "prettier --write .",
|
||||
@@ -16,56 +16,57 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@ag-media/react-pdf-table": "2.0.3",
|
||||
"@blocknote/code-block": "0.30.0",
|
||||
"@blocknote/core": "0.30.0",
|
||||
"@blocknote/mantine": "0.30.0",
|
||||
"@blocknote/react": "0.30.0",
|
||||
"@blocknote/xl-docx-exporter": "0.30.0",
|
||||
"@blocknote/xl-pdf-exporter": "0.30.0",
|
||||
"@blocknote/code-block": "0.31.1",
|
||||
"@blocknote/core": "0.31.1",
|
||||
"@blocknote/mantine": "0.31.1",
|
||||
"@blocknote/react": "0.31.1",
|
||||
"@blocknote/xl-docx-exporter": "0.31.1",
|
||||
"@blocknote/xl-pdf-exporter": "0.31.1",
|
||||
"@emoji-mart/data": "1.2.1",
|
||||
"@emoji-mart/react": "1.1.1",
|
||||
"@fontsource/material-icons": "5.2.5",
|
||||
"@gouvfr-lasuite/integration": "1.0.3",
|
||||
"@gouvfr-lasuite/ui-kit": "0.6.0",
|
||||
"@gouvfr-lasuite/ui-kit": "0.7.0",
|
||||
"@hocuspocus/provider": "2.15.2",
|
||||
"@openfun/cunningham-react": "3.1.0",
|
||||
"@react-pdf/renderer": "4.3.0",
|
||||
"@sentry/nextjs": "9.19.0",
|
||||
"@tanstack/react-query": "5.76.1",
|
||||
"@sentry/nextjs": "9.22.0",
|
||||
"@tanstack/react-query": "5.77.1",
|
||||
"canvg": "4.0.3",
|
||||
"clsx": "2.1.1",
|
||||
"cmdk": "1.1.1",
|
||||
"crisp-sdk-web": "1.0.25",
|
||||
"docx": "9.5.0",
|
||||
"emoji-mart": "5.6.0",
|
||||
"i18next": "25.1.3",
|
||||
"i18next": "25.2.1",
|
||||
"i18next-browser-languagedetector": "8.1.0",
|
||||
"idb": "8.0.3",
|
||||
"lodash": "4.17.21",
|
||||
"luxon": "3.6.1",
|
||||
"next": "15.3.2",
|
||||
"posthog-js": "1.242.2",
|
||||
"posthog-js": "1.246.0",
|
||||
"react": "*",
|
||||
"react-aria-components": "1.8.0",
|
||||
"react-aria-components": "1.9.0",
|
||||
"react-dom": "*",
|
||||
"react-i18next": "15.5.1",
|
||||
"react-i18next": "15.5.2",
|
||||
"react-intersection-observer": "9.16.0",
|
||||
"react-select": "5.10.1",
|
||||
"styled-components": "6.1.18",
|
||||
"tldraw": "3.13.1",
|
||||
"use-debounce": "10.0.4",
|
||||
"y-protocols": "1.0.6",
|
||||
"yjs": "*",
|
||||
"zustand": "5.0.4"
|
||||
"zustand": "5.0.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@svgr/webpack": "8.1.0",
|
||||
"@tanstack/react-query-devtools": "5.76.1",
|
||||
"@tanstack/react-query-devtools": "5.77.1",
|
||||
"@testing-library/dom": "10.4.0",
|
||||
"@testing-library/jest-dom": "6.6.3",
|
||||
"@testing-library/react": "16.3.0",
|
||||
"@testing-library/user-event": "14.6.1",
|
||||
"@types/jest": "29.5.14",
|
||||
"@types/lodash": "4.17.16",
|
||||
"@types/lodash": "4.17.17",
|
||||
"@types/luxon": "3.6.2",
|
||||
"@types/node": "*",
|
||||
"@types/react": "*",
|
||||
@@ -82,7 +83,7 @@
|
||||
"stylelint-config-standard": "38.0.0",
|
||||
"stylelint-prettier": "5.0.3",
|
||||
"typescript": "*",
|
||||
"webpack": "5.99.8",
|
||||
"webpack": "5.99.9",
|
||||
"workbox-webpack-plugin": "7.1.0"
|
||||
}
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 992 B After Width: | Height: | Size: 992 B |
|
After Width: | Height: | Size: 5.3 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
@@ -0,0 +1,12 @@
|
||||
<svg viewBox="0 0 32 33" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M21.6305 29.5812C22.7983 29.2538 23.9166 28.6562 24.6505 27.6003C25.3749 26.5663 25.5789 25.2547 25.5789 23.9925V5.50099C25.5789 5.17358 25.5611 4.84557 25.5216 4.52148C26.1016 4.74961 26.5486 5.12658 26.8626 5.65239C27.2331 6.25024 27.4184 7.03757 27.4184 8.01435V26.7964C27.4184 28.1184 27.0942 29.1078 26.4458 29.7646C25.7974 30.4214 24.8207 30.7498 23.5155 30.7498H16.4209C16.5889 30.7204 16.7574 30.6901 16.9262 30.659C18.4067 30.3944 19.9713 30.0354 21.6185 29.5846L21.6305 29.5812Z"
|
||||
fill="#C9191E"
|
||||
/>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M4.58203 26.405V7.5977C4.58203 6.45251 4.88938 5.58519 5.50408 4.99575C6.1272 4.40631 6.95242 4.08212 7.97972 4.02318C9.49542 3.93055 10.9311 3.80425 12.2868 3.64425C13.6425 3.47584 14.9393 3.28217 16.1771 3.06324C17.4234 2.8443 18.6359 2.60011 19.8148 2.33065C21.0274 2.04435 21.9578 2.1875 22.6062 2.7601C23.2546 3.33269 23.5788 4.24632 23.5788 5.50099V23.9925C23.5788 25.0956 23.3893 25.9166 23.0104 26.4555C22.6315 27.0029 21.9915 27.4028 21.0905 27.6554C19.4906 28.0933 17.9833 28.4386 16.5687 28.6912C15.154 28.9522 13.7731 29.1501 12.4258 29.2848C11.0785 29.4196 9.69751 29.5248 8.28286 29.6006C7.11241 29.668 6.20299 29.4238 5.5546 28.868C4.90622 28.3207 4.58203 27.4997 4.58203 26.405ZM9.20865 11.0124C11.0635 10.8944 12.7632 10.7131 14.3075 10.4683C14.6822 10.4072 15.0564 10.3436 15.4291 10.2776C15.8192 10.2085 16.1013 9.86859 16.1013 9.47337C16.1013 8.96154 15.638 8.57609 15.135 8.66189C14.846 8.71118 14.5555 8.75909 14.2635 8.80562C12.7346 9.04923 11.0452 9.22998 9.19523 9.3477C8.91819 9.36558 8.69776 9.45188 8.55608 9.62391C8.42209 9.78661 8.35645 9.98229 8.35645 10.2053C8.35645 10.4321 8.43296 10.6295 8.58568 10.7918L8.58783 10.7939C8.75336 10.9595 8.96369 11.0311 9.20865 11.0124ZM9.20801 15.206C11.0631 15.088 12.763 14.9066 14.3075 14.6619C15.8588 14.4089 17.3936 14.1138 18.9112 13.7766C19.2191 13.7081 19.4498 13.6003 19.5652 13.433C19.6786 13.2721 19.7347 13.0876 19.7347 12.8832C19.7347 12.6526 19.6469 12.454 19.476 12.2926C19.2921 12.1189 19.0348 12.0784 18.7304 12.1411L18.7285 12.1415C17.2823 12.4694 15.794 12.7553 14.2635 12.9992C12.7346 13.2428 11.0452 13.4235 9.19523 13.5413C8.91819 13.5591 8.69776 13.6454 8.55608 13.8175C8.42276 13.9794 8.35645 14.1705 8.35645 14.3863C8.35645 14.6203 8.43209 14.8223 8.58558 14.9854L8.59 14.9896C8.75499 15.1449 8.96316 15.2155 9.20551 15.2062L9.20801 15.206ZM9.20847 19.3994C11.0634 19.2729 12.7631 19.0874 14.3075 18.8427C15.8589 18.5982 17.3934 18.3073 18.9112 17.97C19.2199 17.9014 19.4508 17.7891 19.566 17.6127C19.6783 17.4529 19.7347 17.2733 19.7347 17.0766C19.7347 16.8461 19.6469 16.6474 19.476 16.4861C19.2921 16.3123 19.0348 16.2718 18.7304 16.3345L18.729 16.3348C17.2827 16.6543 15.7942 16.9361 14.2635 17.18C12.7345 17.4236 11.045 17.6086 9.19495 17.7347C8.91804 17.7526 8.69771 17.8389 8.55608 18.0109C8.42276 18.1728 8.35645 18.3639 8.35645 18.5797C8.35645 18.8137 8.43209 19.0158 8.58558 19.1789L8.59 19.183C8.75499 19.3383 8.96316 19.4089 9.20551 19.3996L9.20847 19.3994ZM14.3075 23.007C12.7632 23.2518 11.0635 23.4331 9.20867 23.5512C8.9637 23.5698 8.75337 23.4982 8.58783 23.3326L8.58572 23.3305C8.433 23.1682 8.35645 22.9708 8.35645 22.7441C8.35645 22.521 8.42209 22.3253 8.55608 22.1626C8.69776 21.9906 8.91827 21.9043 9.19531 21.8864C11.0453 21.7687 12.7346 21.588 14.2635 21.3443C14.5555 21.2978 14.846 21.2499 15.135 21.2006C15.638 21.1148 16.1013 21.5003 16.1013 22.0121C16.1013 22.4073 15.8192 22.7472 15.4291 22.8163C15.0564 22.8823 14.6822 22.9459 14.3075 23.007Z"
|
||||
fill="#000091"
|
||||
/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.6 KiB |
@@ -1,12 +1,12 @@
|
||||
<svg viewBox="0 0 32 33" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M21.6305 29.5812C22.7983 29.2538 23.9166 28.6562 24.6505 27.6003C25.3749 26.5663 25.5789 25.2547 25.5789 23.9925V5.50099C25.5789 5.17358 25.5611 4.84557 25.5216 4.52148C26.1016 4.74961 26.5486 5.12658 26.8626 5.65239C27.2331 6.25024 27.4184 7.03757 27.4184 8.01435V26.7964C27.4184 28.1184 27.0942 29.1078 26.4458 29.7646C25.7974 30.4214 24.8207 30.7498 23.5155 30.7498H16.4209C16.5889 30.7204 16.7574 30.6901 16.9262 30.659C18.4067 30.3944 19.9713 30.0354 21.6185 29.5846L21.6305 29.5812Z"
|
||||
fill="#C9191E"
|
||||
fill="var(--c--theme--colors--secondary-icon)"
|
||||
/>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M4.58203 26.405V7.5977C4.58203 6.45251 4.88938 5.58519 5.50408 4.99575C6.1272 4.40631 6.95242 4.08212 7.97972 4.02318C9.49542 3.93055 10.9311 3.80425 12.2868 3.64425C13.6425 3.47584 14.9393 3.28217 16.1771 3.06324C17.4234 2.8443 18.6359 2.60011 19.8148 2.33065C21.0274 2.04435 21.9578 2.1875 22.6062 2.7601C23.2546 3.33269 23.5788 4.24632 23.5788 5.50099V23.9925C23.5788 25.0956 23.3893 25.9166 23.0104 26.4555C22.6315 27.0029 21.9915 27.4028 21.0905 27.6554C19.4906 28.0933 17.9833 28.4386 16.5687 28.6912C15.154 28.9522 13.7731 29.1501 12.4258 29.2848C11.0785 29.4196 9.69751 29.5248 8.28286 29.6006C7.11241 29.668 6.20299 29.4238 5.5546 28.868C4.90622 28.3207 4.58203 27.4997 4.58203 26.405ZM9.20865 11.0124C11.0635 10.8944 12.7632 10.7131 14.3075 10.4683C14.6822 10.4072 15.0564 10.3436 15.4291 10.2776C15.8192 10.2085 16.1013 9.86859 16.1013 9.47337C16.1013 8.96154 15.638 8.57609 15.135 8.66189C14.846 8.71118 14.5555 8.75909 14.2635 8.80562C12.7346 9.04923 11.0452 9.22998 9.19523 9.3477C8.91819 9.36558 8.69776 9.45188 8.55608 9.62391C8.42209 9.78661 8.35645 9.98229 8.35645 10.2053C8.35645 10.4321 8.43296 10.6295 8.58568 10.7918L8.58783 10.7939C8.75336 10.9595 8.96369 11.0311 9.20865 11.0124ZM9.20801 15.206C11.0631 15.088 12.763 14.9066 14.3075 14.6619C15.8588 14.4089 17.3936 14.1138 18.9112 13.7766C19.2191 13.7081 19.4498 13.6003 19.5652 13.433C19.6786 13.2721 19.7347 13.0876 19.7347 12.8832C19.7347 12.6526 19.6469 12.454 19.476 12.2926C19.2921 12.1189 19.0348 12.0784 18.7304 12.1411L18.7285 12.1415C17.2823 12.4694 15.794 12.7553 14.2635 12.9992C12.7346 13.2428 11.0452 13.4235 9.19523 13.5413C8.91819 13.5591 8.69776 13.6454 8.55608 13.8175C8.42276 13.9794 8.35645 14.1705 8.35645 14.3863C8.35645 14.6203 8.43209 14.8223 8.58558 14.9854L8.59 14.9896C8.75499 15.1449 8.96316 15.2155 9.20551 15.2062L9.20801 15.206ZM9.20847 19.3994C11.0634 19.2729 12.7631 19.0874 14.3075 18.8427C15.8589 18.5982 17.3934 18.3073 18.9112 17.97C19.2199 17.9014 19.4508 17.7891 19.566 17.6127C19.6783 17.4529 19.7347 17.2733 19.7347 17.0766C19.7347 16.8461 19.6469 16.6474 19.476 16.4861C19.2921 16.3123 19.0348 16.2718 18.7304 16.3345L18.729 16.3348C17.2827 16.6543 15.7942 16.9361 14.2635 17.18C12.7345 17.4236 11.045 17.6086 9.19495 17.7347C8.91804 17.7526 8.69771 17.8389 8.55608 18.0109C8.42276 18.1728 8.35645 18.3639 8.35645 18.5797C8.35645 18.8137 8.43209 19.0158 8.58558 19.1789L8.59 19.183C8.75499 19.3383 8.96316 19.4089 9.20551 19.3996L9.20847 19.3994ZM14.3075 23.007C12.7632 23.2518 11.0635 23.4331 9.20867 23.5512C8.9637 23.5698 8.75337 23.4982 8.58783 23.3326L8.58572 23.3305C8.433 23.1682 8.35645 22.9708 8.35645 22.7441C8.35645 22.521 8.42209 22.3253 8.55608 22.1626C8.69776 21.9906 8.91827 21.9043 9.19531 21.8864C11.0453 21.7687 12.7346 21.588 14.2635 21.3443C14.5555 21.2978 14.846 21.2499 15.135 21.2006C15.638 21.1148 16.1013 21.5003 16.1013 22.0121C16.1013 22.4073 15.8192 22.7472 15.4291 22.8163C15.0564 22.8823 14.6822 22.9459 14.3075 23.007Z"
|
||||
fill="#000091"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.6 KiB |
@@ -6,7 +6,9 @@ import {
|
||||
useState,
|
||||
} from 'react';
|
||||
import { Button, Popover } from 'react-aria-components';
|
||||
import styled from 'styled-components';
|
||||
import styled, { css } from 'styled-components';
|
||||
|
||||
import { useCunninghamTheme } from '@/cunningham';
|
||||
|
||||
import { BoxProps } from './Box';
|
||||
|
||||
@@ -27,11 +29,9 @@ const StyledButton = styled(Button)<StyledButtonProps>`
|
||||
background: none;
|
||||
outline: none;
|
||||
transition: all 0.2s ease-in-out;
|
||||
font-family: Marianne, Arial, serif;
|
||||
font-weight: 500;
|
||||
font-size: 0.938rem;
|
||||
padding: 0;
|
||||
text-wrap: nowrap;
|
||||
${({ $css }) => $css};
|
||||
`;
|
||||
|
||||
@@ -51,6 +51,8 @@ export const DropButton = ({
|
||||
children,
|
||||
label,
|
||||
}: PropsWithChildren<DropButtonProps>) => {
|
||||
const { themeTokens } = useCunninghamTheme();
|
||||
const font = themeTokens['font']?.['families']['base'];
|
||||
const [isLocalOpen, setIsLocalOpen] = useState(isOpen);
|
||||
|
||||
const triggerRef = useRef(null);
|
||||
@@ -70,7 +72,10 @@ export const DropButton = ({
|
||||
ref={triggerRef}
|
||||
onPress={() => onOpenChangeHandler(true)}
|
||||
aria-label={label}
|
||||
$css={buttonCss}
|
||||
$css={css`
|
||||
font-family: ${font};
|
||||
${buttonCss};
|
||||
`}
|
||||
className="--docs--drop-button"
|
||||
>
|
||||
{button}
|
||||
|
||||
@@ -2,11 +2,17 @@ import { useQuery } from '@tanstack/react-query';
|
||||
|
||||
import { APIError, errorCauses, fetchAPI } from '@/api';
|
||||
import { Theme } from '@/cunningham/';
|
||||
import { FooterType } from '@/features/footer';
|
||||
import { PostHogConf } from '@/services';
|
||||
|
||||
interface ThemeCustomization {
|
||||
footer?: FooterType;
|
||||
}
|
||||
|
||||
interface ConfigResponse {
|
||||
AI_FEATURE_ENABLED?: boolean;
|
||||
COLLABORATION_WS_URL?: string;
|
||||
COLLABORATION_WS_NOT_CONNECTED_READY_ONLY?: boolean;
|
||||
CRISP_WEBSITE_ID?: string;
|
||||
ENVIRONMENT: string;
|
||||
FRONTEND_CSS_URL?: string;
|
||||
@@ -17,6 +23,7 @@ interface ConfigResponse {
|
||||
MEDIA_BASE_URL?: string;
|
||||
POSTHOG_KEY?: PostHogConf;
|
||||
SENTRY_DSN?: string;
|
||||
theme_customization?: ThemeCustomization;
|
||||
}
|
||||
|
||||
const LOCAL_STORAGE_KEY = 'docs_config';
|
||||
|
||||
@@ -2,8 +2,12 @@ import { useCunninghamTheme } from '../useCunninghamTheme';
|
||||
|
||||
describe('<useCunninghamTheme />', () => {
|
||||
it('has the logo correctly set', () => {
|
||||
const { themeTokens, setTheme } = useCunninghamTheme.getState();
|
||||
setTheme('default');
|
||||
expect(useCunninghamTheme.getState().themeTokens.logo?.src).toBe('');
|
||||
|
||||
// Change theme
|
||||
useCunninghamTheme.getState().setTheme('dsfr');
|
||||
|
||||
const { themeTokens } = useCunninghamTheme.getState();
|
||||
const logo = themeTokens.logo;
|
||||
expect(logo?.src).toBe('/assets/logo-gouv.svg');
|
||||
expect(logo?.widthHeader).toBe('110px');
|
||||
|
||||
@@ -43,3 +43,36 @@
|
||||
.c__tooltip {
|
||||
padding: 4px 6px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Image System
|
||||
*/
|
||||
.c__image-system-filter {
|
||||
filter: var(--c--components--image-system-filter);
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: Inter;
|
||||
font-style: italic;
|
||||
font-weight: 100 900;
|
||||
font-display: swap;
|
||||
src: url('https://fonts.gstatic.com/s/inter/v18/UcCm3FwrK3iLTcvnUwQT9g.woff2')
|
||||
format('woff2');
|
||||
unicode-range:
|
||||
U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
|
||||
U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212,
|
||||
U+2215, U+FEFF, U+FFFD;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: Inter;
|
||||
font-style: normal;
|
||||
font-weight: 100 900;
|
||||
font-display: swap;
|
||||
src: url('https://fonts.gstatic.com/s/inter/v18/UcCo3FwrK3iLTcviYwY.woff2')
|
||||
format('woff2');
|
||||
unicode-range:
|
||||
U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
|
||||
U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212,
|
||||
U+2215, U+FEFF, U+FFFD;
|
||||
}
|
||||
|
||||
@@ -92,6 +92,8 @@
|
||||
--c--theme--colors--rose-500: #e18b76;
|
||||
--c--theme--colors--primary-action: #1212ff;
|
||||
--c--theme--colors--primary-bg: #fafafa;
|
||||
--c--theme--colors--primary-focus: #0a76f6;
|
||||
--c--theme--colors--secondary-icon: var(--c--theme--colors--primary-text);
|
||||
--c--theme--colors--blue-400: #7ab1e8;
|
||||
--c--theme--colors--blue-600: #3558a2;
|
||||
--c--theme--colors--brown-400: #e6be92;
|
||||
@@ -190,10 +192,10 @@
|
||||
--c--theme--breakpoints--xxs: 320px;
|
||||
--c--theme--breakpoints--mobile: 768px;
|
||||
--c--theme--breakpoints--tablet: 1024px;
|
||||
--c--theme--logo--src: /assets/logo-gouv.svg;
|
||||
--c--theme--logo--widthheader: 110px;
|
||||
--c--theme--logo--widthfooter: 220px;
|
||||
--c--theme--logo--alt: gouvernement logo;
|
||||
--c--theme--logo--src: ;
|
||||
--c--theme--logo--alt: ;
|
||||
--c--theme--logo--widthheader: ;
|
||||
--c--theme--logo--widthfooter: ;
|
||||
--c--components--modal--width-small: 342px;
|
||||
--c--components--tooltip--padding: 4px 8px;
|
||||
--c--components--tooltip--background-color: var(
|
||||
@@ -485,8 +487,13 @@
|
||||
--c--theme--colors--info-100
|
||||
);
|
||||
--c--components--badge--info--color: var(--c--theme--colors--info-600);
|
||||
--c--components--la-gauffre--activated: true;
|
||||
--c--components--home-proconnect--activated: true;
|
||||
--c--components--la-gaufre: false;
|
||||
--c--components--home-proconnect: false;
|
||||
--c--components--beta: false;
|
||||
--c--components--image-system-filter: ;
|
||||
--c--components--favicon--ico: /assets/favicon-light.ico;
|
||||
--c--components--favicon--png-light: /assets/favicon-light.png;
|
||||
--c--components--favicon--png-dark: /assets/favicon-dark.png;
|
||||
}
|
||||
|
||||
.cunningham-theme--dark {
|
||||
@@ -538,6 +545,158 @@
|
||||
--c--theme--colors--danger-900: #9d6666;
|
||||
}
|
||||
|
||||
.cunningham-theme--dsfr {
|
||||
--c--theme--colors--secondary-icon: #c9191e;
|
||||
--c--theme--logo--src: /assets/logo-gouv.svg;
|
||||
--c--theme--logo--widthHeader: 110px;
|
||||
--c--theme--logo--widthFooter: 220px;
|
||||
--c--theme--logo--alt: gouvernement logo;
|
||||
--c--components--la-gaufre: true;
|
||||
--c--components--home-proconnect: true;
|
||||
--c--components--beta: true;
|
||||
--c--components--favicon--ico: /assets/favicon-dsfr.ico;
|
||||
--c--components--favicon--png-light: /assets/favicon-dsfr.png;
|
||||
--c--components--favicon--png-dark: /assets/favicon-dark-dsfr.png;
|
||||
}
|
||||
|
||||
.cunningham-theme--generic {
|
||||
--c--theme--colors--primary-action: #206ebd;
|
||||
--c--theme--colors--primary-focus: #1e64bf;
|
||||
--c--theme--colors--primary-text: #2e2c28;
|
||||
--c--theme--colors--primary-050: #f8f8f7;
|
||||
--c--theme--colors--primary-100: #f0efec;
|
||||
--c--theme--colors--primary-150: #f4f4fd;
|
||||
--c--theme--colors--primary-200: #e8e7e4;
|
||||
--c--theme--colors--primary-300: #cfcdc9;
|
||||
--c--theme--colors--primary-400: #979592;
|
||||
--c--theme--colors--primary-500: #82807d;
|
||||
--c--theme--colors--primary-600: #3f3d39;
|
||||
--c--theme--colors--primary-700: #2e2c28;
|
||||
--c--theme--colors--primary-800: #302e29;
|
||||
--c--theme--colors--primary-900: #282622;
|
||||
--c--theme--colors--primary-950: #201f1c;
|
||||
--c--theme--colors--secondary-text: #fff;
|
||||
--c--theme--colors--secondary-50: #f4f7fa;
|
||||
--c--theme--colors--secondary-100: #d7e3ee;
|
||||
--c--theme--colors--secondary-200: #b8cce1;
|
||||
--c--theme--colors--secondary-300: #99b4d3;
|
||||
--c--theme--colors--secondary-400: #7595be;
|
||||
--c--theme--colors--secondary-500: #5874a0;
|
||||
--c--theme--colors--secondary-600: #3a5383;
|
||||
--c--theme--colors--secondary-700: #1e3462;
|
||||
--c--theme--colors--secondary-800: #091b41;
|
||||
--c--theme--colors--secondary-900: #08183b;
|
||||
--c--theme--colors--secondary-950: #071636;
|
||||
--c--theme--colors--greyscale-text: #3c3b38;
|
||||
--c--theme--colors--greyscale-000: #fff;
|
||||
--c--theme--colors--greyscale-050: #f8f7f7;
|
||||
--c--theme--colors--greyscale-100: #f3f3f2;
|
||||
--c--theme--colors--greyscale-200: #ecebea;
|
||||
--c--theme--colors--greyscale-250: #e4e3e2;
|
||||
--c--theme--colors--greyscale-300: #d3d2cf;
|
||||
--c--theme--colors--greyscale-350: #eee;
|
||||
--c--theme--colors--greyscale-400: #96948e;
|
||||
--c--theme--colors--greyscale-500: #817e77;
|
||||
--c--theme--colors--greyscale-600: #6a6862;
|
||||
--c--theme--colors--greyscale-700: #3c3b38;
|
||||
--c--theme--colors--greyscale-750: #383632;
|
||||
--c--theme--colors--greyscale-800: #2d2b27;
|
||||
--c--theme--colors--greyscale-900: #262522;
|
||||
--c--theme--colors--greyscale-950: #201f1c;
|
||||
--c--theme--colors--greyscale-1000: #181714;
|
||||
--c--theme--colors--success-text: #234935;
|
||||
--c--theme--colors--success-50: #f3fbf5;
|
||||
--c--theme--colors--success-100: #e4f7ea;
|
||||
--c--theme--colors--success-200: #caeed4;
|
||||
--c--theme--colors--success-300: #a0e0b5;
|
||||
--c--theme--colors--success-400: #6cc88c;
|
||||
--c--theme--colors--success-500: #6cc88c;
|
||||
--c--theme--colors--success-600: #358d5c;
|
||||
--c--theme--colors--success-700: #2d704b;
|
||||
--c--theme--colors--success-800: #28583f;
|
||||
--c--theme--colors--success-900: #234935;
|
||||
--c--theme--colors--success-950: #0f281b;
|
||||
--c--theme--colors--info-text: #212445;
|
||||
--c--theme--colors--info-50: #f2f6fb;
|
||||
--c--theme--colors--info-100: #e2e9f5;
|
||||
--c--theme--colors--info-200: #ccd8ee;
|
||||
--c--theme--colors--info-300: #a9c0e3;
|
||||
--c--theme--colors--info-400: #809dd4;
|
||||
--c--theme--colors--info-500: #617bc7;
|
||||
--c--theme--colors--info-600: #4a5cbf;
|
||||
--c--theme--colors--info-700: #3e49b2;
|
||||
--c--theme--colors--info-800: #353c8f;
|
||||
--c--theme--colors--info-900: #303771;
|
||||
--c--theme--colors--info-950: #212445;
|
||||
--c--theme--colors--warning-text: #d97c3a;
|
||||
--c--theme--colors--warning-50: #fdf7f1;
|
||||
--c--theme--colors--warning-100: #fbeddc;
|
||||
--c--theme--colors--warning-200: #f5d9b9;
|
||||
--c--theme--colors--warning-300: #edbe8c;
|
||||
--c--theme--colors--warning-400: #e2985c;
|
||||
--c--theme--colors--warning-500: #d97c3a;
|
||||
--c--theme--colors--warning-600: #c96330;
|
||||
--c--theme--colors--warning-700: #a34b32;
|
||||
--c--theme--colors--warning-800: #813b2c;
|
||||
--c--theme--colors--warning-900: #693327;
|
||||
--c--theme--colors--warning-950: #381713;
|
||||
--c--theme--colors--danger-action: #c0182a;
|
||||
--c--theme--colors--danger-text: #fff;
|
||||
--c--theme--colors--danger-050: #fdf5f4;
|
||||
--c--theme--colors--danger-100: #fbebe8;
|
||||
--c--theme--colors--danger-200: #f9e0dc;
|
||||
--c--theme--colors--danger-300: #f3c3bd;
|
||||
--c--theme--colors--danger-400: #e26552;
|
||||
--c--theme--colors--danger-500: #c91f00;
|
||||
--c--theme--colors--danger-600: #a71901;
|
||||
--c--theme--colors--danger-700: #562c2b;
|
||||
--c--theme--colors--danger-800: #392425;
|
||||
--c--theme--colors--danger-900: #311f20;
|
||||
--c--theme--colors--danger-950: #2a191a;
|
||||
--c--theme--colors--blue-400: #8baecc;
|
||||
--c--theme--colors--blue-500: #567aa2;
|
||||
--c--theme--colors--blue-600: #455784;
|
||||
--c--theme--colors--brown-400: #e4c090;
|
||||
--c--theme--colors--brown-500: #ba9977;
|
||||
--c--theme--colors--brown-600: #735c45;
|
||||
--c--theme--colors--cyan-400: #5cbec9;
|
||||
--c--theme--colors--cyan-500: #43a1b3;
|
||||
--c--theme--colors--cyan-600: #39809b;
|
||||
--c--theme--colors--gold-400: #ecbf50;
|
||||
--c--theme--colors--gold-500: #dfa038;
|
||||
--c--theme--colors--gold-600: #c17b31;
|
||||
--c--theme--colors--green-400: #5dbd9a;
|
||||
--c--theme--colors--green-500: #3aa183;
|
||||
--c--theme--colors--green-600: #2a816d;
|
||||
--c--theme--colors--olive-400: #afd662;
|
||||
--c--theme--colors--olive-500: #90bb4b;
|
||||
--c--theme--colors--olive-600: #6e9441;
|
||||
--c--theme--colors--orange-400: #e2985c;
|
||||
--c--theme--colors--orange-500: #d97c3a;
|
||||
--c--theme--colors--orange-600: #c96330;
|
||||
--c--theme--colors--pink-400: #be8fc8;
|
||||
--c--theme--colors--pink-500: #a563b1;
|
||||
--c--theme--colors--pink-600: #8b44a5;
|
||||
--c--theme--colors--purple-400: #be8fc8;
|
||||
--c--theme--colors--purple-500: #a563b1;
|
||||
--c--theme--colors--purple-600: #8b44a5;
|
||||
--c--theme--colors--yellow-400: #edc947;
|
||||
--c--theme--colors--yellow-500: #dbb13a;
|
||||
--c--theme--colors--yellow-600: #b88a34;
|
||||
--c--theme--font--families--base: inter, roboto flex variable, sans-serif;
|
||||
--c--theme--font--families--accent: inter, roboto flex variable, sans-serif;
|
||||
--c--components--button--primary--background--color-hover: var(
|
||||
--c--theme--colors--primary-focus
|
||||
);
|
||||
--c--components--button--primary--background--color-active: var(
|
||||
--c--theme--colors--primary-focus
|
||||
);
|
||||
--c--components--button--primary--background--color-focus: var(
|
||||
--c--theme--colors--primary-focus
|
||||
);
|
||||
--c--components--image-system-filter: saturate(0.2);
|
||||
}
|
||||
|
||||
.clr-secondary-text {
|
||||
color: var(--c--theme--colors--secondary-text);
|
||||
}
|
||||
@@ -910,6 +1069,14 @@
|
||||
color: var(--c--theme--colors--primary-bg);
|
||||
}
|
||||
|
||||
.clr-primary-focus {
|
||||
color: var(--c--theme--colors--primary-focus);
|
||||
}
|
||||
|
||||
.clr-secondary-icon {
|
||||
color: var(--c--theme--colors--secondary-icon);
|
||||
}
|
||||
|
||||
.clr-blue-400 {
|
||||
color: var(--c--theme--colors--blue-400);
|
||||
}
|
||||
@@ -1366,6 +1533,14 @@
|
||||
background-color: var(--c--theme--colors--primary-bg);
|
||||
}
|
||||
|
||||
.bg-primary-focus {
|
||||
background-color: var(--c--theme--colors--primary-focus);
|
||||
}
|
||||
|
||||
.bg-secondary-icon {
|
||||
background-color: var(--c--theme--colors--secondary-icon);
|
||||
}
|
||||
|
||||
.bg-blue-400 {
|
||||
background-color: var(--c--theme--colors--blue-400);
|
||||
}
|
||||
|
||||
@@ -96,6 +96,8 @@ export const tokens = {
|
||||
'rose-500': '#E18B76',
|
||||
'primary-action': '#1212FF',
|
||||
'primary-bg': '#FAFAFA',
|
||||
'primary-focus': '#0A76F6',
|
||||
'secondary-icon': 'var(--c--theme--colors--primary-text)',
|
||||
'blue-400': '#7AB1E8',
|
||||
'blue-600': '#3558A2',
|
||||
'brown-400': '#E6BE92',
|
||||
@@ -208,12 +210,7 @@ export const tokens = {
|
||||
mobile: '768px',
|
||||
tablet: '1024px',
|
||||
},
|
||||
logo: {
|
||||
src: '/assets/logo-gouv.svg',
|
||||
widthHeader: '110px',
|
||||
widthFooter: '220px',
|
||||
alt: 'Gouvernement Logo',
|
||||
},
|
||||
logo: { src: '', alt: '', widthHeader: '', widthFooter: '' },
|
||||
},
|
||||
components: {
|
||||
modal: { 'width-small': '342px' },
|
||||
@@ -366,8 +363,15 @@ export const tokens = {
|
||||
warning: { 'background-color': '#fff4f3', color: '#b34000' },
|
||||
info: { 'background-color': '#E8EDFF', color: '#0063CB' },
|
||||
},
|
||||
'la-gauffre': { activated: true },
|
||||
'home-proconnect': { activated: true },
|
||||
'la-gaufre': false,
|
||||
'home-proconnect': false,
|
||||
beta: false,
|
||||
'image-system-filter': '',
|
||||
favicon: {
|
||||
ico: '/assets/favicon-light.ico',
|
||||
'png-light': '/assets/favicon-light.png',
|
||||
'png-dark': '/assets/favicon-dark.png',
|
||||
},
|
||||
},
|
||||
},
|
||||
dark: {
|
||||
@@ -422,5 +426,173 @@ export const tokens = {
|
||||
},
|
||||
},
|
||||
},
|
||||
dsfr: {
|
||||
theme: {
|
||||
colors: { 'secondary-icon': '#C9191E' },
|
||||
logo: {
|
||||
src: '/assets/logo-gouv.svg',
|
||||
widthHeader: '110px',
|
||||
widthFooter: '220px',
|
||||
alt: 'Gouvernement Logo',
|
||||
},
|
||||
},
|
||||
components: {
|
||||
'la-gaufre': true,
|
||||
'home-proconnect': true,
|
||||
beta: true,
|
||||
favicon: {
|
||||
ico: '/assets/favicon-dsfr.ico',
|
||||
'png-light': '/assets/favicon-dsfr.png',
|
||||
'png-dark': '/assets/favicon-dark-dsfr.png',
|
||||
},
|
||||
},
|
||||
},
|
||||
generic: {
|
||||
theme: {
|
||||
colors: {
|
||||
'primary-action': '#206EBD',
|
||||
'primary-focus': '#1E64BF',
|
||||
'primary-text': '#2E2C28',
|
||||
'primary-050': '#F8F8F7',
|
||||
'primary-100': '#F0EFEC',
|
||||
'primary-150': '#F4F4FD',
|
||||
'primary-200': '#E8E7E4',
|
||||
'primary-300': '#CFCDC9',
|
||||
'primary-400': '#979592',
|
||||
'primary-500': '#82807D',
|
||||
'primary-600': '#3F3D39',
|
||||
'primary-700': '#2E2C28',
|
||||
'primary-800': '#302E29',
|
||||
'primary-900': '#282622',
|
||||
'primary-950': '#201F1C',
|
||||
'secondary-text': '#fff',
|
||||
'secondary-50': '#F4F7FA',
|
||||
'secondary-100': '#D7E3EE',
|
||||
'secondary-200': '#B8CCE1',
|
||||
'secondary-300': '#99B4D3',
|
||||
'secondary-400': '#7595BE',
|
||||
'secondary-500': '#5874A0',
|
||||
'secondary-600': '#3A5383',
|
||||
'secondary-700': '#1E3462',
|
||||
'secondary-800': '#091B41',
|
||||
'secondary-900': '#08183B',
|
||||
'secondary-950': '#071636',
|
||||
'greyscale-text': '#3C3B38',
|
||||
'greyscale-000': '#fff',
|
||||
'greyscale-050': '#F8F7F7',
|
||||
'greyscale-100': '#F3F3F2',
|
||||
'greyscale-200': '#ECEBEA',
|
||||
'greyscale-250': '#E4E3E2',
|
||||
'greyscale-300': '#D3D2CF',
|
||||
'greyscale-350': '#eee',
|
||||
'greyscale-400': '#96948E',
|
||||
'greyscale-500': '#817E77',
|
||||
'greyscale-600': '#6A6862',
|
||||
'greyscale-700': '#3C3B38',
|
||||
'greyscale-750': '#383632',
|
||||
'greyscale-800': '#2D2B27',
|
||||
'greyscale-900': '#262522',
|
||||
'greyscale-950': '#201F1C',
|
||||
'greyscale-1000': '#181714',
|
||||
'success-text': '#234935',
|
||||
'success-50': '#F3FBF5',
|
||||
'success-100': '#E4F7EA',
|
||||
'success-200': '#CAEED4',
|
||||
'success-300': '#A0E0B5',
|
||||
'success-400': '#6CC88C',
|
||||
'success-500': '#6CC88C',
|
||||
'success-600': '#358D5C',
|
||||
'success-700': '#2D704B',
|
||||
'success-800': '#28583F',
|
||||
'success-900': '#234935',
|
||||
'success-950': '#0F281B',
|
||||
'info-text': '#212445',
|
||||
'info-50': '#F2F6FB',
|
||||
'info-100': '#E2E9F5',
|
||||
'info-200': '#CCD8EE',
|
||||
'info-300': '#A9C0E3',
|
||||
'info-400': '#809DD4',
|
||||
'info-500': '#617BC7',
|
||||
'info-600': '#4A5CBF',
|
||||
'info-700': '#3E49B2',
|
||||
'info-800': '#353C8F',
|
||||
'info-900': '#303771',
|
||||
'info-950': '#212445',
|
||||
'warning-text': '#D97C3A',
|
||||
'warning-50': '#FDF7F1',
|
||||
'warning-100': '#FBEDDC',
|
||||
'warning-200': '#F5D9B9',
|
||||
'warning-300': '#EDBE8C',
|
||||
'warning-400': '#E2985C',
|
||||
'warning-500': '#D97C3A',
|
||||
'warning-600': '#C96330',
|
||||
'warning-700': '#A34B32',
|
||||
'warning-800': '#813B2C',
|
||||
'warning-900': '#693327',
|
||||
'warning-950': '#381713',
|
||||
'danger-action': '#C0182A',
|
||||
'danger-text': '#FFF',
|
||||
'danger-050': '#FDF5F4',
|
||||
'danger-100': '#FBEBE8',
|
||||
'danger-200': '#F9E0DC',
|
||||
'danger-300': '#F3C3BD',
|
||||
'danger-400': '#E26552',
|
||||
'danger-500': '#C91F00',
|
||||
'danger-600': '#A71901',
|
||||
'danger-700': '#562C2B',
|
||||
'danger-800': '#392425',
|
||||
'danger-900': '#311F20',
|
||||
'danger-950': '#2A191A',
|
||||
'blue-400': '#8BAECC',
|
||||
'blue-500': '#567AA2',
|
||||
'blue-600': '#455784',
|
||||
'brown-400': '#E4C090',
|
||||
'brown-500': '#BA9977',
|
||||
'brown-600': '#735C45',
|
||||
'cyan-400': '#5CBEC9',
|
||||
'cyan-500': '#43A1B3',
|
||||
'cyan-600': '#39809B',
|
||||
'gold-400': '#ECBF50',
|
||||
'gold-500': '#DFA038',
|
||||
'gold-600': '#C17B31',
|
||||
'green-400': '#5DBD9A',
|
||||
'green-500': '#3AA183',
|
||||
'green-600': '#2A816D',
|
||||
'olive-400': '#AFD662',
|
||||
'olive-500': '#90BB4B',
|
||||
'olive-600': '#6E9441',
|
||||
'orange-400': '#E2985C',
|
||||
'orange-500': '#D97C3A',
|
||||
'orange-600': '#C96330',
|
||||
'pink-400': '#BE8FC8',
|
||||
'pink-500': '#A563B1',
|
||||
'pink-600': '#8B44A5',
|
||||
'purple-400': '#BE8FC8',
|
||||
'purple-500': '#A563B1',
|
||||
'purple-600': '#8B44A5',
|
||||
'yellow-400': '#EDC947',
|
||||
'yellow-500': '#DBB13A',
|
||||
'yellow-600': '#B88A34',
|
||||
},
|
||||
font: {
|
||||
families: {
|
||||
base: 'Inter, Roboto Flex Variable, sans-serif',
|
||||
accent: 'Inter, Roboto Flex Variable, sans-serif',
|
||||
},
|
||||
},
|
||||
},
|
||||
components: {
|
||||
button: {
|
||||
primary: {
|
||||
background: {
|
||||
'color-hover': 'var(--c--theme--colors--primary-focus)',
|
||||
'color-active': 'var(--c--theme--colors--primary-focus)',
|
||||
'color-focus': 'var(--c--theme--colors--primary-focus)',
|
||||
},
|
||||
},
|
||||
},
|
||||
'image-system-filter': 'saturate(0.2)',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -12,30 +12,32 @@ type ComponentTokens = Tokens['components'];
|
||||
export type Theme = keyof typeof tokens.themes;
|
||||
|
||||
interface ThemeStore {
|
||||
theme: Theme;
|
||||
setTheme: (theme: Theme) => void;
|
||||
themeTokens: Partial<Tokens['theme']>;
|
||||
colorsTokens: Partial<ColorsTokens>;
|
||||
fontSizesTokens: Partial<FontSizesTokens>;
|
||||
spacingsTokens: Partial<SpacingsTokens>;
|
||||
componentTokens: ComponentTokens;
|
||||
currentTokens: Partial<Tokens>;
|
||||
fontSizesTokens: Partial<FontSizesTokens>;
|
||||
setTheme: (theme: Theme) => void;
|
||||
spacingsTokens: Partial<SpacingsTokens>;
|
||||
theme: Theme;
|
||||
themeTokens: Partial<Tokens['theme']>;
|
||||
}
|
||||
|
||||
const getMergedTokens = (theme: Theme) => {
|
||||
return merge({}, tokens.themes['default'], tokens.themes[theme]);
|
||||
};
|
||||
|
||||
const DEFAULT_THEME: Theme = 'default';
|
||||
const DEFAULT_THEME: Theme = 'generic';
|
||||
const defaultTokens = getMergedTokens(DEFAULT_THEME);
|
||||
|
||||
const initialState: ThemeStore = {
|
||||
theme: DEFAULT_THEME,
|
||||
setTheme: () => {},
|
||||
themeTokens: defaultTokens.theme,
|
||||
colorsTokens: defaultTokens.theme.colors,
|
||||
componentTokens: defaultTokens.components,
|
||||
spacingsTokens: defaultTokens.theme.spacings,
|
||||
currentTokens: tokens.themes[DEFAULT_THEME] as Partial<Tokens>,
|
||||
fontSizesTokens: defaultTokens.theme.font.sizes,
|
||||
setTheme: () => {},
|
||||
spacingsTokens: defaultTokens.theme.spacings,
|
||||
theme: DEFAULT_THEME,
|
||||
themeTokens: defaultTokens.theme,
|
||||
};
|
||||
|
||||
export const useCunninghamTheme = create<ThemeStore>((set) => ({
|
||||
@@ -44,12 +46,13 @@ export const useCunninghamTheme = create<ThemeStore>((set) => ({
|
||||
const newTokens = getMergedTokens(theme);
|
||||
|
||||
set({
|
||||
theme,
|
||||
themeTokens: newTokens.theme,
|
||||
colorsTokens: newTokens.theme.colors,
|
||||
componentTokens: newTokens.components,
|
||||
spacingsTokens: newTokens.theme.spacings,
|
||||
currentTokens: tokens.themes[theme] as Partial<Tokens>,
|
||||
fontSizesTokens: newTokens.theme.font.sizes,
|
||||
spacingsTokens: newTokens.theme.spacings,
|
||||
theme,
|
||||
themeTokens: newTokens.theme,
|
||||
});
|
||||
},
|
||||
}));
|
||||
|
||||
@@ -13,7 +13,13 @@ declare module '*.svg' {
|
||||
}
|
||||
|
||||
declare module '*.svg?url' {
|
||||
const content: string;
|
||||
const content: {
|
||||
src: string;
|
||||
width: number;
|
||||
height: number;
|
||||
blurWidth: number;
|
||||
blurHeight: number;
|
||||
};
|
||||
export default content;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import { APIError, errorCauses } from '@/api';
|
||||
|
||||
interface CheckDocMediaStatusResponse {
|
||||
file?: string;
|
||||
status: 'processing' | 'ready';
|
||||
}
|
||||
|
||||
interface CheckDocMediaStatus {
|
||||
urlMedia: string;
|
||||
}
|
||||
|
||||
export const checkDocMediaStatus = async ({
|
||||
urlMedia,
|
||||
}: CheckDocMediaStatus): Promise<CheckDocMediaStatusResponse> => {
|
||||
const response = await fetch(urlMedia, {
|
||||
credentials: 'include',
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new APIError(
|
||||
'Failed to check the media status',
|
||||
await errorCauses(response),
|
||||
);
|
||||
}
|
||||
|
||||
return response.json() as Promise<CheckDocMediaStatusResponse>;
|
||||
};
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from './checkDocMediaStatus';
|
||||
export * from './useCreateDocUpload';
|
||||
export * from './useDocAITransform';
|
||||
export * from './useDocAITranslate';
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="#3b82f6"
|
||||
stroke-width="2.5"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="analyzing-spinner"
|
||||
>
|
||||
<circle cx="12" cy="12" r="10" opacity="0.2"></circle>
|
||||
<path d="M12 2a10 10 0 0 1 10 10" opacity="0.8">
|
||||
<animateTransform
|
||||
attributeName="transform"
|
||||
type="rotate"
|
||||
from="0 12 12"
|
||||
to="360 12 12"
|
||||
dur="1s"
|
||||
repeatCount="indefinite"
|
||||
calcMode="spline"
|
||||
keySplines="0.42 0 0.58 1"
|
||||
keyTimes="0;1"
|
||||
/>
|
||||
</path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 598 B |
@@ -0,0 +1,17 @@
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
fill="#FFA500"
|
||||
>
|
||||
<path
|
||||
d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"
|
||||
></path>
|
||||
<line x1="12" y1="9" x2="12" y2="13"></line>
|
||||
<line x1="12" y1="17" x2="12.01" y2="17"></line>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 425 B |
@@ -18,16 +18,17 @@ import { Box, TextErrors } from '@/components';
|
||||
import { Doc, useIsCollaborativeEditable } from '@/docs/doc-management';
|
||||
import { useAuth } from '@/features/auth';
|
||||
|
||||
import { useUploadFile } from '../hook';
|
||||
import { useHeadings } from '../hook/useHeadings';
|
||||
import { useHeadings, useUploadFile, useUploadStatus } from '../hook/';
|
||||
import useSaveDoc from '../hook/useSaveDoc';
|
||||
import { useEditorStore } from '../stores';
|
||||
import { cssEditor } from '../styles';
|
||||
import { DocsBlockNoteEditor } from '../types';
|
||||
import { randomColor } from '../utils';
|
||||
|
||||
import { BlockNoteSuggestionMenu } from './BlockNoteSuggestionMenu';
|
||||
import { BlockNoteToolbar } from './BlockNoteToolBar/BlockNoteToolbar';
|
||||
import { CalloutBlock, DividerBlock } from './custom-blocks';
|
||||
import { DrawBlock } from './custom-blocks/DrawBlock';
|
||||
|
||||
export const blockNoteSchema = withPageBreak(
|
||||
BlockNoteSchema.create({
|
||||
@@ -35,6 +36,7 @@ export const blockNoteSchema = withPageBreak(
|
||||
...defaultBlockSpecs,
|
||||
callout: CalloutBlock,
|
||||
divider: DividerBlock,
|
||||
draw: DrawBlock,
|
||||
},
|
||||
}),
|
||||
);
|
||||
@@ -63,7 +65,7 @@ export const BlockNoteEditor = ({ doc, provider }: BlockNoteEditorProps) => {
|
||||
: user?.full_name || user?.email || t('Anonymous');
|
||||
const showCursorLabels: 'always' | 'activity' | (string & {}) = 'activity';
|
||||
|
||||
const editor = useCreateBlockNote(
|
||||
const editor: DocsBlockNoteEditor = useCreateBlockNote(
|
||||
{
|
||||
codeBlock,
|
||||
collaboration: {
|
||||
@@ -127,7 +129,9 @@ export const BlockNoteEditor = ({ doc, provider }: BlockNoteEditorProps) => {
|
||||
},
|
||||
[collabName, lang, provider, uploadFile],
|
||||
);
|
||||
|
||||
useHeadings(editor);
|
||||
useUploadStatus(editor);
|
||||
|
||||
useEffect(() => {
|
||||
setEditor(editor);
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
getCalloutReactSlashMenuItems,
|
||||
getDividerReactSlashMenuItems,
|
||||
} from './custom-blocks';
|
||||
import { getDrawReactSlashMenuItems } from './custom-blocks/DrawBlock';
|
||||
|
||||
export const BlockNoteSuggestionMenu = () => {
|
||||
const editor = useBlockNoteEditor<DocsBlockSchema>();
|
||||
@@ -30,6 +31,7 @@ export const BlockNoteSuggestionMenu = () => {
|
||||
getPageBreakReactSlashMenuItems(editor),
|
||||
getCalloutReactSlashMenuItems(editor, t, basicBlocksName),
|
||||
getDividerReactSlashMenuItems(editor, t, basicBlocksName),
|
||||
getDrawReactSlashMenuItems(editor, t, basicBlocksName),
|
||||
),
|
||||
query,
|
||||
),
|
||||
|
||||
@@ -32,7 +32,6 @@ export const ModalConfirmDownloadUnsafe = ({
|
||||
aria-label={t('Download')}
|
||||
color="danger"
|
||||
onClick={() => {
|
||||
console.log('onClick');
|
||||
if (onConfirm) {
|
||||
void onConfirm();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,341 @@
|
||||
/* eslint-disable react-hooks/rules-of-hooks */
|
||||
import {
|
||||
ReactRendererProps,
|
||||
defaultProps,
|
||||
insertOrUpdateBlock,
|
||||
} from '@blocknote/core';
|
||||
import { BlockTypeSelectItem, createReactBlockSpec } from '@blocknote/react';
|
||||
import { TFunction } from 'i18next';
|
||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import {
|
||||
Editor,
|
||||
TLEventMapHandler,
|
||||
TLStore,
|
||||
Tldraw,
|
||||
getSnapshot,
|
||||
loadSnapshot,
|
||||
} from 'tldraw';
|
||||
import 'tldraw/tldraw.css';
|
||||
|
||||
import { Box, Icon } from '@/components';
|
||||
|
||||
import { DocsBlockNoteEditor } from '../../types';
|
||||
|
||||
import _ from 'lodash';
|
||||
|
||||
import { clear } from 'console';
|
||||
|
||||
/**
|
||||
* ----------------------------------------------------------------------------------
|
||||
* Collaborative **Draw** block – backed by a Y‑js document synced through
|
||||
* `@hocuspocus/provider` (see `useProviderStore`).
|
||||
* ----------------------------------------------------------------------------------
|
||||
*
|
||||
* Each Draw block owns its own Y‑Doc, identified by `roomId` (persisted in `propSchema`).
|
||||
* The block serialises a base‑64‑encoded Y‑js update (`drawingData`) so newcomers see
|
||||
* the latest snapshot _immediately_, without waiting for the websocket connection.
|
||||
*/
|
||||
export const DrawBlock = createReactBlockSpec(
|
||||
{
|
||||
type: 'draw',
|
||||
propSchema: {
|
||||
textAlignment: defaultProps.textAlignment,
|
||||
backgroundColor: defaultProps.backgroundColor,
|
||||
roomId: { default: `drawing-${Date.now()}` },
|
||||
drawingData: { default: '' },
|
||||
changeHistory: { default: '' },
|
||||
lastChange: { default: '' },
|
||||
increment: { default: 0 }, // Increment to force re-rendering
|
||||
},
|
||||
content: 'inline',
|
||||
},
|
||||
{
|
||||
render: ({ block, editor: editorBN }) => {
|
||||
const [editor, setEditor] = useState<Editor>();
|
||||
|
||||
const setAppToState = useCallback((editor: Editor) => {
|
||||
setEditor(editor);
|
||||
}, []);
|
||||
|
||||
const timeoutId = useRef<NodeJS.Timeout | null>(null);
|
||||
|
||||
const [storeEvents, setStoreEvents] = useState<string[]>([]);
|
||||
console.log('Loading saved drawing data');
|
||||
|
||||
useEffect(() => {
|
||||
if (block.props.drawingData && editor) {
|
||||
console.log('DDData');
|
||||
try {
|
||||
const drawingData = JSON.parse(block.props.drawingData);
|
||||
//const drawingData = block.props.drawingData;
|
||||
|
||||
// Update: Using the non-deprecated method to load the snapshot
|
||||
// Instead of editor.store.loadSnapshot(drawingData)
|
||||
loadSnapshot(editor.store, drawingData);
|
||||
|
||||
console.log('Successfully loaded drawing data');
|
||||
} catch (error) {
|
||||
console.error('Failed to load drawing data:', error);
|
||||
}
|
||||
}
|
||||
}, [block.props.drawingData, editor]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!editor) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Load saved drawing data if available
|
||||
|
||||
function logChangeEvent(eventInfo: string, changeData: any = null) {
|
||||
console.log(eventInfo);
|
||||
|
||||
// Get current properties
|
||||
// const currentProps = { ...block.props };
|
||||
|
||||
// // Get current changeHistory or initialize empty array
|
||||
// const currentHistory = Array.isArray(currentProps.changeHistory)
|
||||
// ? currentProps.changeHistory
|
||||
// : [];
|
||||
|
||||
// // Create a change record with timestamp
|
||||
// const changeRecord = {
|
||||
// timestamp: new Date().toISOString(),
|
||||
// event: eventInfo,
|
||||
// data: changeData,
|
||||
// };
|
||||
|
||||
// // Create new props object with all updated values
|
||||
// const updatedProps = {
|
||||
// ...currentProps,
|
||||
// changeHistory: [...currentHistory, changeRecord],
|
||||
// lastChange: changeRecord,
|
||||
// };
|
||||
|
||||
// // Add drawingData if available
|
||||
// if (changeData?.drawingData) {
|
||||
// updatedProps.drawingData = changeData.drawingData;
|
||||
// }
|
||||
|
||||
// Update the block with the new props
|
||||
// console.log('Updating block with props:', updatedProps);
|
||||
|
||||
// //editorBN.updateBlock(block, { props: updatedProps });
|
||||
|
||||
// if (timeoutId.current) {
|
||||
// clearTimeout(timeoutId.current);
|
||||
// }
|
||||
// timeoutId.current = setTimeout(() => {
|
||||
// editorBN.updateBlock(block, {
|
||||
// props: updatedProps,
|
||||
// });
|
||||
// }, 300);
|
||||
if (!editor) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (timeoutId.current) {
|
||||
clearTimeout(timeoutId.current);
|
||||
}
|
||||
timeoutId.current = setTimeout(() => {
|
||||
const snapshot = getSnapshot(editor.store);
|
||||
//const snapshot = JSON.stringify(editor.store.serialize());
|
||||
|
||||
console.log('Captured drawing snapshot:', snapshot);
|
||||
|
||||
// Only update drawingData property to avoid multiple updates
|
||||
const currentProps = { ...block.props };
|
||||
|
||||
editorBN.updateBlock(block, {
|
||||
props: {
|
||||
drawingData: JSON.stringify(snapshot),
|
||||
increment: currentProps.increment + 1, // Increment to force re-rendering
|
||||
},
|
||||
});
|
||||
}, 300);
|
||||
|
||||
//setStoreEvents((events) => [...events, eventInfo]);
|
||||
}
|
||||
|
||||
//[1]
|
||||
const handleChangeEvent: TLEventMapHandler<'change'> = (change) => {
|
||||
// Added
|
||||
for (const record of Object.values(change.changes.added)) {
|
||||
if (record.typeName === 'shape') {
|
||||
logChangeEvent(`created shape (${record.type})`, {
|
||||
action: 'created',
|
||||
shapeType: record.type,
|
||||
shape: record,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Updated
|
||||
for (const [from, to] of Object.values(change.changes.updated)) {
|
||||
if (
|
||||
from.typeName === 'instance' &&
|
||||
to.typeName === 'instance' &&
|
||||
from.currentPageId !== to.currentPageId
|
||||
) {
|
||||
logChangeEvent(
|
||||
`changed page (${from.currentPageId}, ${to.currentPageId})`,
|
||||
{
|
||||
action: 'changedPage',
|
||||
fromPageId: from.currentPageId,
|
||||
toPageId: to.currentPageId,
|
||||
},
|
||||
);
|
||||
} else if (
|
||||
from.id.startsWith('shape') &&
|
||||
to.id.startsWith('shape')
|
||||
) {
|
||||
let diff = _.reduce(
|
||||
from,
|
||||
(result: any[], value, key: string) =>
|
||||
_.isEqual(value, to[key])
|
||||
? result
|
||||
: result.concat([key, to[key]]),
|
||||
[],
|
||||
);
|
||||
const diffObj = {};
|
||||
|
||||
if (diff?.[0] === 'props') {
|
||||
diff = _.reduce(
|
||||
from.props,
|
||||
(result: any[], value, key) =>
|
||||
_.isEqual(value, to.props[key])
|
||||
? result
|
||||
: result.concat([key, to.props[key]]),
|
||||
[],
|
||||
);
|
||||
|
||||
// Convert diff array to object for better storage
|
||||
for (let i = 0; i < diff.length; i += 2) {
|
||||
diffObj[diff[i]] = diff[i + 1];
|
||||
}
|
||||
}
|
||||
|
||||
logChangeEvent(`updated shape (${JSON.stringify(diff)})`, {
|
||||
action: 'updated',
|
||||
shapeId: from.id,
|
||||
changes: diffObj,
|
||||
from: from,
|
||||
to: to,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Removed
|
||||
for (const record of Object.values(change.changes.removed)) {
|
||||
if (record.typeName === 'shape') {
|
||||
logChangeEvent(`deleted shape (${record.type})`, {
|
||||
action: 'deleted',
|
||||
shapeType: record.type,
|
||||
shape: record,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Store the entire drawing state periodically when changes occur
|
||||
// if (
|
||||
// Object.keys(change.changes.added).length > 0 ||
|
||||
// Object.keys(change.changes.updated).length > 0 ||
|
||||
// Object.keys(change.changes.removed).length > 0
|
||||
// ) {
|
||||
// // Capture the current drawing state if available
|
||||
// if (editor.store) {
|
||||
// try {
|
||||
// // Update: Using the non-deprecated method to get the snapshot
|
||||
// // Instead of
|
||||
// //
|
||||
// const snapshot = getSnapshot(editor.store);
|
||||
// //const snapshot = JSON.stringify(editor.store.serialize());
|
||||
|
||||
// console.log('Captured drawing snapshot:', snapshot);
|
||||
|
||||
// // Only update drawingData property to avoid multiple updates
|
||||
// const currentProps = { ...block.props };
|
||||
|
||||
// if (timeoutId.current) {
|
||||
// clearTimeout(timeoutId.current);
|
||||
// }
|
||||
// timeoutId.current = setTimeout(() => {
|
||||
// editorBN.updateBlock(block, {
|
||||
// props: {
|
||||
// ...currentProps,
|
||||
// drawingData: snapshot,
|
||||
// },
|
||||
// });
|
||||
// }, 300);
|
||||
|
||||
// console.log('Drawing snapshot updated');
|
||||
// } catch (error) {
|
||||
// console.error('Failed to capture drawing snapshot:', error);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
};
|
||||
|
||||
// [2]
|
||||
const cleanupFunction = editor.store.listen(handleChangeEvent, {
|
||||
source: 'user',
|
||||
scope: 'all',
|
||||
});
|
||||
|
||||
return () => {
|
||||
cleanupFunction();
|
||||
};
|
||||
}, [block, editor, editorBN]);
|
||||
|
||||
return (
|
||||
<Box style={{ width: '100%', height: 300 }}>
|
||||
{/*
|
||||
* We deliberately pass the TL‑store directly. TLDraw will observe the
|
||||
* changes – including those coming over the wire – and re‑render.
|
||||
*/}
|
||||
<Tldraw onMount={setAppToState} />
|
||||
</Box>
|
||||
);
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* Slash‑menu helper → inserts a new collaborative draw block with a unique `roomId`.
|
||||
*/
|
||||
export const getDrawReactSlashMenuItems = (
|
||||
editor: DocsBlockNoteEditor,
|
||||
t: TFunction<'translation', undefined>,
|
||||
group: string,
|
||||
) => [
|
||||
{
|
||||
title: t('Draw'),
|
||||
onItemClick: () => {
|
||||
insertOrUpdateBlock(editor, {
|
||||
type: 'draw',
|
||||
props: {
|
||||
roomId: `drawing-${Date.now()}`,
|
||||
drawingData: null,
|
||||
changeHistory: [],
|
||||
lastChange: null,
|
||||
},
|
||||
});
|
||||
},
|
||||
aliases: ['draw'],
|
||||
group,
|
||||
icon: <Icon iconName="draw" $size="18px" />,
|
||||
subtext: t('Add a collaborative canvas'),
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* Formatting‑toolbar item so users can transform an existing block into a Draw block.
|
||||
*/
|
||||
export const getDrawFormattingToolbarItems = (
|
||||
t: TFunction<'translation', undefined>,
|
||||
): BlockTypeSelectItem => ({
|
||||
name: t('Draw'),
|
||||
type: 'draw',
|
||||
icon: () => <Icon iconName="lightbulb" $size="16px" />,
|
||||
isSelected: (block) => block.type === 'draw',
|
||||
});
|
||||
@@ -1,2 +1,3 @@
|
||||
export * from './useHeadings';
|
||||
export * from './useSaveDoc';
|
||||
export * from './useUploadFile';
|
||||
|
||||
@@ -1,11 +1,85 @@
|
||||
import { useCallback } from 'react';
|
||||
import { useCallback, useEffect, useRef } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { backendUrl } from '@/api';
|
||||
import { useMediaUrl } from '@/core/config';
|
||||
import { sleep } from '@/utils';
|
||||
|
||||
import { useCreateDocAttachment } from '../api';
|
||||
import { checkDocMediaStatus, useCreateDocAttachment } from '../api';
|
||||
import Loader from '../assets/loader.svg?url';
|
||||
import Warning from '../assets/warning.svg?url';
|
||||
import { DocsBlockNoteEditor } from '../types';
|
||||
|
||||
/**
|
||||
* Upload file can be analyzed on the server side,
|
||||
* we had this function to wait for the analysis to be done
|
||||
* before returning the file url. It will keep the loader
|
||||
* on the upload button until the analysis is done.
|
||||
* @param url
|
||||
* @returns Promise<CheckDocMediaStatusResponse> status_code
|
||||
* @description Waits for the upload to be analyzed by checking the status of the file.
|
||||
*/
|
||||
const loopCheckDocMediaStatus = async (url: string) => {
|
||||
const SLEEP_TIME = 5000;
|
||||
const response = await checkDocMediaStatus({
|
||||
urlMedia: url,
|
||||
});
|
||||
|
||||
if (response.status === 'ready') {
|
||||
return response;
|
||||
} else {
|
||||
await sleep(SLEEP_TIME);
|
||||
return await loopCheckDocMediaStatus(url);
|
||||
}
|
||||
};
|
||||
|
||||
const informationStatus = (src: string, text: string) => {
|
||||
const loadingContainer = document.createElement('div');
|
||||
loadingContainer.style.display = 'flex';
|
||||
loadingContainer.style.alignItems = 'center';
|
||||
loadingContainer.style.justifyContent = 'left';
|
||||
loadingContainer.style.padding = '10px';
|
||||
loadingContainer.style.color = '#666';
|
||||
loadingContainer.className =
|
||||
'bn-visual-media bn-audio bn-file-name-with-icon';
|
||||
|
||||
// Create an image element for the SVG
|
||||
const imgElement = document.createElement('img');
|
||||
imgElement.src = src;
|
||||
|
||||
// Create a text span
|
||||
const textSpan = document.createElement('span');
|
||||
textSpan.textContent = text;
|
||||
textSpan.style.marginLeft = '8px';
|
||||
textSpan.style.verticalAlign = 'middle';
|
||||
imgElement.style.animation = 'spin 1.5s linear infinite';
|
||||
|
||||
// Add the spinner and text to the container
|
||||
loadingContainer.appendChild(imgElement);
|
||||
loadingContainer.appendChild(textSpan);
|
||||
|
||||
return loadingContainer;
|
||||
};
|
||||
|
||||
const replaceUploadContent = (blockId: string, elementReplace: HTMLElement) => {
|
||||
const blockEl = document.body.querySelector(
|
||||
`.bn-block[data-id="${blockId}"]`,
|
||||
);
|
||||
|
||||
blockEl
|
||||
?.querySelector('.bn-visual-media-wrapper .bn-visual-media')
|
||||
?.replaceWith(elementReplace);
|
||||
|
||||
blockEl
|
||||
?.querySelector('.bn-file-block-content-wrapper .bn-audio')
|
||||
?.replaceWith(elementReplace);
|
||||
|
||||
blockEl
|
||||
?.querySelector('.bn-file-block-content-wrapper .bn-file-name-with-icon')
|
||||
?.replaceWith(elementReplace);
|
||||
};
|
||||
|
||||
export const useUploadFile = (docId: string) => {
|
||||
const mediaUrl = useMediaUrl();
|
||||
const {
|
||||
mutateAsync: createDocAttachment,
|
||||
isError: isErrorAttachment,
|
||||
@@ -22,9 +96,9 @@ export const useUploadFile = (docId: string) => {
|
||||
body,
|
||||
});
|
||||
|
||||
return `${mediaUrl}${ret.file}`;
|
||||
return `${backendUrl()}${ret.file}`;
|
||||
},
|
||||
[createDocAttachment, docId, mediaUrl],
|
||||
[createDocAttachment, docId],
|
||||
);
|
||||
|
||||
return {
|
||||
@@ -33,3 +107,101 @@ export const useUploadFile = (docId: string) => {
|
||||
errorAttachment,
|
||||
};
|
||||
};
|
||||
|
||||
export const useUploadStatus = (editor: DocsBlockNoteEditor) => {
|
||||
const ANALYZE_URL = 'media-check';
|
||||
const { t } = useTranslation();
|
||||
const mediaUrl = useMediaUrl();
|
||||
const timeoutIds = useRef<Record<string, NodeJS.Timeout>>({});
|
||||
|
||||
const blockAnalyzeProcess = useCallback(
|
||||
(editor: DocsBlockNoteEditor, blockId: string, url: string) => {
|
||||
if (timeoutIds.current[url]) {
|
||||
clearTimeout(timeoutIds.current[url]);
|
||||
}
|
||||
|
||||
// Delay to let the time to the dom to be rendered
|
||||
const timoutId = setTimeout(() => {
|
||||
replaceUploadContent(
|
||||
blockId,
|
||||
informationStatus(Loader.src, t('Analyzing file...')),
|
||||
);
|
||||
|
||||
loopCheckDocMediaStatus(url)
|
||||
.then((response) => {
|
||||
const block = editor.getBlock(blockId);
|
||||
if (!block) {
|
||||
return;
|
||||
}
|
||||
|
||||
block.props = {
|
||||
...block.props,
|
||||
url: `${mediaUrl}${response.file}`,
|
||||
};
|
||||
|
||||
editor.updateBlock(blockId, block);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Error analyzing file:', error);
|
||||
|
||||
replaceUploadContent(
|
||||
blockId,
|
||||
informationStatus(
|
||||
Warning.src,
|
||||
t('The antivirus has detected an anomaly in your file.'),
|
||||
),
|
||||
);
|
||||
});
|
||||
}, 250);
|
||||
|
||||
timeoutIds.current[url] = timoutId;
|
||||
},
|
||||
[t, mediaUrl],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const blocksAnalyze = editor?.document.filter(
|
||||
(block) => 'url' in block.props && block.props.url.includes(ANALYZE_URL),
|
||||
);
|
||||
|
||||
if (!blocksAnalyze?.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
blocksAnalyze.forEach((block) => {
|
||||
if (!('url' in block.props)) {
|
||||
return;
|
||||
}
|
||||
|
||||
blockAnalyzeProcess(editor, block.id, block.props.url);
|
||||
});
|
||||
}, [blockAnalyzeProcess, editor]);
|
||||
|
||||
useEffect(() => {
|
||||
editor.onChange((_, context) => {
|
||||
const blocksChanges = context.getChanges();
|
||||
|
||||
if (!blocksChanges.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const blockChanges = blocksChanges[0];
|
||||
|
||||
if (
|
||||
blockChanges.source.type !== 'local' ||
|
||||
blockChanges.type !== 'update' ||
|
||||
!('url' in blockChanges.block.props) ||
|
||||
('url' in blockChanges.block.props &&
|
||||
!blockChanges.block.props.url.includes(ANALYZE_URL))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
blockAnalyzeProcess(
|
||||
editor,
|
||||
blockChanges.block.id,
|
||||
blockChanges.block.props.url,
|
||||
);
|
||||
});
|
||||
}, [blockAnalyzeProcess, mediaUrl, editor, t]);
|
||||
};
|
||||
|
||||
@@ -29,7 +29,7 @@ export const AlertNetwork = () => {
|
||||
border: 1px solid var(--c--theme--colors--warning-300);
|
||||
`}
|
||||
>
|
||||
<Box $direction="row" $gap={spacingsTokens['2xs']}>
|
||||
<Box $direction="row" $gap={spacingsTokens['2xs']} $align="center">
|
||||
<Icon iconName="mobiledata_off" $theme="warning" $variation="600" />
|
||||
<Text $theme="warning" $variation="600" $weight={500}>
|
||||
{t('Your network do not allow you to edit')}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import { useConfig } from '@/core';
|
||||
import { useIsOffline } from '@/features/service-worker';
|
||||
|
||||
import { useProviderStore } from '../stores';
|
||||
@@ -7,6 +8,7 @@ import { Doc, LinkReach } from '../types';
|
||||
|
||||
export const useIsCollaborativeEditable = (doc: Doc) => {
|
||||
const { isConnected } = useProviderStore();
|
||||
const { data: conf } = useConfig();
|
||||
|
||||
const docIsPublic = doc.link_reach === LinkReach.PUBLIC;
|
||||
const docIsAuth = doc.link_reach === LinkReach.AUTHENTICATED;
|
||||
@@ -37,6 +39,13 @@ export const useIsCollaborativeEditable = (doc: Doc) => {
|
||||
return () => clearTimeout(timer);
|
||||
}, [isConnected, isOffline, isShared]);
|
||||
|
||||
if (!conf?.COLLABORATION_WS_NOT_CONNECTED_READY_ONLY) {
|
||||
return {
|
||||
isEditable: true,
|
||||
isLoading: false,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
isEditable,
|
||||
isLoading,
|
||||
|
||||
@@ -87,6 +87,7 @@ export const DocSearchModal = ({ ...modalProps }: DocSearchModalProps) => {
|
||||
$justify="center"
|
||||
>
|
||||
<Image
|
||||
className="c__image-system-filter"
|
||||
width={320}
|
||||
src={EmptySearchIcon}
|
||||
alt={t('No active search')}
|
||||
|
||||
@@ -1,51 +1,138 @@
|
||||
<svg
|
||||
width="32"
|
||||
height="36"
|
||||
viewBox="0 0 32 36"
|
||||
width="33"
|
||||
height="33"
|
||||
viewBox="0 0 33 33"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<rect
|
||||
x="2.01394"
|
||||
y="1.23611"
|
||||
width="25.9722"
|
||||
height="33.5278"
|
||||
rx="3.54167"
|
||||
fill="white"
|
||||
/>
|
||||
<rect
|
||||
x="2.01394"
|
||||
y="1.23611"
|
||||
width="25.9722"
|
||||
height="33.5278"
|
||||
rx="3.54167"
|
||||
stroke="#E3E3FD"
|
||||
stroke-width="0.472222"
|
||||
/>
|
||||
<path
|
||||
d="M6.5 8.55554H15"
|
||||
stroke="#6A6AF4"
|
||||
stroke-width="1.88889"
|
||||
stroke-linecap="round"
|
||||
/>
|
||||
<path
|
||||
d="M6.5 11.3889H23.5M6.5 14.2222H23.5M6.5 17.0556H23.5M6.5 19.8889H23.5M6.5 22.7222H20.6667"
|
||||
stroke="#CACAFB"
|
||||
stroke-width="1.88889"
|
||||
stroke-linecap="round"
|
||||
/>
|
||||
<rect x="7" y="10" width="16" height="16" rx="8" fill="#6A6AF4" />
|
||||
<rect
|
||||
x="7"
|
||||
y="10"
|
||||
width="16"
|
||||
height="16"
|
||||
rx="8"
|
||||
stroke="white"
|
||||
stroke-width="1.5"
|
||||
/>
|
||||
<path
|
||||
d="M16.8 18L18 19.2V20.1H15.45V22.95L15 23.4L14.55 22.95V20.1H12V19.2L13.2 18V14.7H12.6V13.8H17.4V14.7H16.8V18Z"
|
||||
fill="white"
|
||||
/>
|
||||
<g clip-path="url(#clip0_3236_2932)">
|
||||
<g clip-path="url(#clip1_3236_2932)">
|
||||
<rect x="4.5" y="0.5" width="24" height="32" rx="3.55556" fill="white" />
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M8.08374 7.7623C8.08374 7.27138 8.48171 6.87341 8.97263 6.87341H16.9726C17.4635 6.87341 17.8615 7.27138 17.8615 7.7623C17.8615 8.25322 17.4635 8.65118 16.9726 8.65118H8.97263C8.48171 8.65118 8.08374 8.25322 8.08374 7.7623Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M8.08374 10.7685C8.08374 10.2776 8.48171 9.87964 8.97263 9.87964H24.0273C24.5182 9.87964 24.9162 10.2776 24.9162 10.7685C24.9162 11.2594 24.5182 11.6574 24.0273 11.6574H8.97263C8.48171 11.6574 8.08374 11.2594 8.08374 10.7685ZM8.08374 13.4352C8.08374 12.9443 8.48171 12.5463 8.97263 12.5463H24.0273C24.5182 12.5463 24.9162 12.9443 24.9162 13.4352C24.9162 13.9261 24.5182 14.3241 24.0273 14.3241H8.97263C8.48171 14.3241 8.08374 13.9261 8.08374 13.4352ZM8.08374 16.1019C8.08374 15.6109 8.48171 15.213 8.97263 15.213H24.0273C24.5182 15.213 24.9162 15.6109 24.9162 16.1019C24.9162 16.5928 24.5182 16.9907 24.0273 16.9907H8.97263C8.48171 16.9907 8.08374 16.5928 8.08374 16.1019ZM8.08374 18.7685C8.08374 18.2776 8.48171 17.8796 8.97263 17.8796H24.0273C24.5182 17.8796 24.9162 18.2776 24.9162 18.7685C24.9162 19.2594 24.5182 19.6574 24.0273 19.6574H8.97263C8.48171 19.6574 8.08374 19.2594 8.08374 18.7685Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M8.08374 10.7685C8.08374 10.2776 8.48171 9.87964 8.97263 9.87964H24.0273C24.5182 9.87964 24.9162 10.2776 24.9162 10.7685C24.9162 11.2594 24.5182 11.6574 24.0273 11.6574H8.97263C8.48171 11.6574 8.08374 11.2594 8.08374 10.7685ZM8.08374 13.4352C8.08374 12.9443 8.48171 12.5463 8.97263 12.5463H24.0273C24.5182 12.5463 24.9162 12.9443 24.9162 13.4352C24.9162 13.9261 24.5182 14.3241 24.0273 14.3241H8.97263C8.48171 14.3241 8.08374 13.9261 8.08374 13.4352ZM8.08374 16.1019C8.08374 15.6109 8.48171 15.213 8.97263 15.213H24.0273C24.5182 15.213 24.9162 15.6109 24.9162 16.1019C24.9162 16.5928 24.5182 16.9907 24.0273 16.9907H8.97263C8.48171 16.9907 8.08374 16.5928 8.08374 16.1019ZM8.08374 18.7685C8.08374 18.2776 8.48171 17.8796 8.97263 17.8796H24.0273C24.5182 17.8796 24.9162 18.2776 24.9162 18.7685C24.9162 19.2594 24.5182 19.6574 24.0273 19.6574H8.97263C8.48171 19.6574 8.08374 19.2594 8.08374 18.7685Z"
|
||||
fill="white"
|
||||
fill-opacity="0.65"
|
||||
/>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M8.08374 21.4666C8.08374 20.9757 8.48171 20.5777 8.97263 20.5777H24.0273C24.5182 20.5777 24.9162 20.9757 24.9162 21.4666C24.9162 21.9575 24.5182 22.3555 24.0273 22.3555H8.97263C8.48171 22.3555 8.08374 21.9575 8.08374 21.4666ZM8.08374 24.1333C8.08374 23.6424 8.48171 23.2444 8.97263 23.2444H24.0273C24.5182 23.2444 24.9162 23.6424 24.9162 24.1333C24.9162 24.6242 24.5182 25.0222 24.0273 25.0222H8.97263C8.48171 25.0222 8.08374 24.6242 8.08374 24.1333ZM8.08374 26.8C8.08374 26.309 8.48171 25.9111 8.97263 25.9111H24.0273C24.5182 25.9111 24.9162 26.309 24.9162 26.8C24.9162 27.2909 24.5182 27.6888 24.0273 27.6888H8.97263C8.48171 27.6888 8.08374 27.2909 8.08374 26.8ZM8.08374 29.4666C8.08374 28.9757 8.48171 28.5777 8.97263 28.5777H24.0273C24.5182 28.5777 24.9162 28.9757 24.9162 29.4666C24.9162 29.9575 24.5182 30.3555 24.0273 30.3555H8.97263C8.48171 30.3555 8.08374 29.9575 8.08374 29.4666Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M8.08374 21.4666C8.08374 20.9757 8.48171 20.5777 8.97263 20.5777H24.0273C24.5182 20.5777 24.9162 20.9757 24.9162 21.4666C24.9162 21.9575 24.5182 22.3555 24.0273 22.3555H8.97263C8.48171 22.3555 8.08374 21.9575 8.08374 21.4666ZM8.08374 24.1333C8.08374 23.6424 8.48171 23.2444 8.97263 23.2444H24.0273C24.5182 23.2444 24.9162 23.6424 24.9162 24.1333C24.9162 24.6242 24.5182 25.0222 24.0273 25.0222H8.97263C8.48171 25.0222 8.08374 24.6242 8.08374 24.1333ZM8.08374 26.8C8.08374 26.309 8.48171 25.9111 8.97263 25.9111H24.0273C24.5182 25.9111 24.9162 26.309 24.9162 26.8C24.9162 27.2909 24.5182 27.6888 24.0273 27.6888H8.97263C8.48171 27.6888 8.08374 27.2909 8.08374 26.8ZM8.08374 29.4666C8.08374 28.9757 8.48171 28.5777 8.97263 28.5777H24.0273C24.5182 28.5777 24.9162 28.9757 24.9162 29.4666C24.9162 29.9575 24.5182 30.3555 24.0273 30.3555H8.97263C8.48171 30.3555 8.08374 29.9575 8.08374 29.4666Z"
|
||||
fill="white"
|
||||
fill-opacity="0.65"
|
||||
/>
|
||||
<rect
|
||||
x="4.57422"
|
||||
y="0.5"
|
||||
width="23.9258"
|
||||
height="31.8206"
|
||||
fill="url(#paint0_linear_3236_2932)"
|
||||
fill-opacity="0.4"
|
||||
/>
|
||||
</g>
|
||||
<rect
|
||||
x="4.85"
|
||||
y="0.85"
|
||||
width="23.3"
|
||||
height="31.3"
|
||||
rx="3.20556"
|
||||
stroke="currentColor"
|
||||
stroke-width="0.7"
|
||||
/>
|
||||
<rect
|
||||
x="4.85"
|
||||
y="0.85"
|
||||
width="23.3"
|
||||
height="31.3"
|
||||
rx="3.20556"
|
||||
stroke="white"
|
||||
stroke-opacity="0.65"
|
||||
stroke-width="0.7"
|
||||
/>
|
||||
<rect
|
||||
x="4.85"
|
||||
y="0.85"
|
||||
width="23.3"
|
||||
height="31.3"
|
||||
rx="3.20556"
|
||||
stroke="url(#paint1_linear_3236_2932)"
|
||||
stroke-opacity="0.23"
|
||||
stroke-width="0.7"
|
||||
/>
|
||||
<rect
|
||||
x="10.0132"
|
||||
y="10.0132"
|
||||
width="12.9736"
|
||||
height="12.9736"
|
||||
rx="6.48682"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<rect
|
||||
x="10.0132"
|
||||
y="10.0132"
|
||||
width="12.9736"
|
||||
height="12.9736"
|
||||
rx="6.48682"
|
||||
stroke="white"
|
||||
stroke-width="1.21628"
|
||||
/>
|
||||
<path
|
||||
d="M17.9595 16.5L18.9325 17.473V18.2028H16.8648V20.5137L16.4999 20.8786L16.1351 20.5137V18.2028H14.0674V17.473L15.0404 16.5V13.8242H14.5539V13.0944H18.446V13.8242H17.9595V16.5Z"
|
||||
fill="white"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<linearGradient
|
||||
id="paint0_linear_3236_2932"
|
||||
x1="16.5371"
|
||||
y1="0.5"
|
||||
x2="16.5371"
|
||||
y2="32.3206"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stop-color="white" stop-opacity="0" />
|
||||
<stop offset="1" stop-color="white" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint1_linear_3236_2932"
|
||||
x1="16.5"
|
||||
y1="0.5"
|
||||
x2="16.5"
|
||||
y2="32.5"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stop-color="white" stop-opacity="0" />
|
||||
<stop offset="1" stop-color="white" />
|
||||
</linearGradient>
|
||||
<clipPath id="clip0_3236_2932">
|
||||
<rect
|
||||
width="32"
|
||||
height="32"
|
||||
fill="white"
|
||||
transform="translate(0.5 0.5)"
|
||||
/>
|
||||
</clipPath>
|
||||
<clipPath id="clip1_3236_2932">
|
||||
<rect x="4.5" y="0.5" width="24" height="32" rx="3.55556" fill="white" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 1017 B After Width: | Height: | Size: 6.7 KiB |
@@ -1,37 +1,117 @@
|
||||
<svg
|
||||
width="32"
|
||||
height="36"
|
||||
viewBox="0 0 32 36"
|
||||
width="33"
|
||||
height="33"
|
||||
viewBox="0 0 33 33"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<rect
|
||||
x="2.01394"
|
||||
y="1.23611"
|
||||
width="25.9722"
|
||||
height="33.5278"
|
||||
rx="3.54167"
|
||||
fill="white"
|
||||
/>
|
||||
<rect
|
||||
x="2.01394"
|
||||
y="1.23611"
|
||||
width="25.9722"
|
||||
height="33.5278"
|
||||
rx="3.54167"
|
||||
stroke="#E3E3FD"
|
||||
stroke-width="0.472222"
|
||||
/>
|
||||
<path
|
||||
d="M6.5 8.55554H15"
|
||||
stroke="#6A6AF4"
|
||||
stroke-width="1.88889"
|
||||
stroke-linecap="round"
|
||||
/>
|
||||
<path
|
||||
d="M6.5 11.3889H23.5M6.5 14.2222H23.5M6.5 17.0556H23.5M6.5 19.8889H23.5M6.5 22.7222H20.6667"
|
||||
stroke="#CACAFB"
|
||||
stroke-width="1.88889"
|
||||
stroke-linecap="round"
|
||||
/>
|
||||
<g clip-path="url(#clip0_3236_2952)">
|
||||
<g clip-path="url(#clip1_3236_2952)">
|
||||
<rect x="4.5" y="0.5" width="24" height="32" rx="3.55556" fill="white" />
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M8.08374 7.7623C8.08374 7.27138 8.48171 6.87341 8.97263 6.87341H16.9726C17.4635 6.87341 17.8615 7.27138 17.8615 7.7623C17.8615 8.25322 17.4635 8.65118 16.9726 8.65118H8.97263C8.48171 8.65118 8.08374 8.25322 8.08374 7.7623Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M8.08374 10.7685C8.08374 10.2776 8.48171 9.87964 8.97263 9.87964H24.0273C24.5182 9.87964 24.9162 10.2776 24.9162 10.7685C24.9162 11.2594 24.5182 11.6574 24.0273 11.6574H8.97263C8.48171 11.6574 8.08374 11.2594 8.08374 10.7685ZM8.08374 13.4352C8.08374 12.9443 8.48171 12.5463 8.97263 12.5463H24.0273C24.5182 12.5463 24.9162 12.9443 24.9162 13.4352C24.9162 13.9261 24.5182 14.3241 24.0273 14.3241H8.97263C8.48171 14.3241 8.08374 13.9261 8.08374 13.4352ZM8.08374 16.1019C8.08374 15.6109 8.48171 15.213 8.97263 15.213H24.0273C24.5182 15.213 24.9162 15.6109 24.9162 16.1019C24.9162 16.5928 24.5182 16.9907 24.0273 16.9907H8.97263C8.48171 16.9907 8.08374 16.5928 8.08374 16.1019ZM8.08374 18.7685C8.08374 18.2776 8.48171 17.8796 8.97263 17.8796H24.0273C24.5182 17.8796 24.9162 18.2776 24.9162 18.7685C24.9162 19.2594 24.5182 19.6574 24.0273 19.6574H8.97263C8.48171 19.6574 8.08374 19.2594 8.08374 18.7685Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M8.08374 10.7685C8.08374 10.2776 8.48171 9.87964 8.97263 9.87964H24.0273C24.5182 9.87964 24.9162 10.2776 24.9162 10.7685C24.9162 11.2594 24.5182 11.6574 24.0273 11.6574H8.97263C8.48171 11.6574 8.08374 11.2594 8.08374 10.7685ZM8.08374 13.4352C8.08374 12.9443 8.48171 12.5463 8.97263 12.5463H24.0273C24.5182 12.5463 24.9162 12.9443 24.9162 13.4352C24.9162 13.9261 24.5182 14.3241 24.0273 14.3241H8.97263C8.48171 14.3241 8.08374 13.9261 8.08374 13.4352ZM8.08374 16.1019C8.08374 15.6109 8.48171 15.213 8.97263 15.213H24.0273C24.5182 15.213 24.9162 15.6109 24.9162 16.1019C24.9162 16.5928 24.5182 16.9907 24.0273 16.9907H8.97263C8.48171 16.9907 8.08374 16.5928 8.08374 16.1019ZM8.08374 18.7685C8.08374 18.2776 8.48171 17.8796 8.97263 17.8796H24.0273C24.5182 17.8796 24.9162 18.2776 24.9162 18.7685C24.9162 19.2594 24.5182 19.6574 24.0273 19.6574H8.97263C8.48171 19.6574 8.08374 19.2594 8.08374 18.7685Z"
|
||||
fill="white"
|
||||
fill-opacity="0.65"
|
||||
/>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M8.08374 21.4666C8.08374 20.9757 8.48171 20.5777 8.97263 20.5777H24.0273C24.5182 20.5777 24.9162 20.9757 24.9162 21.4666C24.9162 21.9575 24.5182 22.3555 24.0273 22.3555H8.97263C8.48171 22.3555 8.08374 21.9575 8.08374 21.4666ZM8.08374 24.1333C8.08374 23.6424 8.48171 23.2444 8.97263 23.2444H24.0273C24.5182 23.2444 24.9162 23.6424 24.9162 24.1333C24.9162 24.6242 24.5182 25.0222 24.0273 25.0222H8.97263C8.48171 25.0222 8.08374 24.6242 8.08374 24.1333ZM8.08374 26.8C8.08374 26.309 8.48171 25.9111 8.97263 25.9111H24.0273C24.5182 25.9111 24.9162 26.309 24.9162 26.8C24.9162 27.2909 24.5182 27.6888 24.0273 27.6888H8.97263C8.48171 27.6888 8.08374 27.2909 8.08374 26.8ZM8.08374 29.4666C8.08374 28.9757 8.48171 28.5777 8.97263 28.5777H24.0273C24.5182 28.5777 24.9162 28.9757 24.9162 29.4666C24.9162 29.9575 24.5182 30.3555 24.0273 30.3555H8.97263C8.48171 30.3555 8.08374 29.9575 8.08374 29.4666Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M8.08374 21.4666C8.08374 20.9757 8.48171 20.5777 8.97263 20.5777H24.0273C24.5182 20.5777 24.9162 20.9757 24.9162 21.4666C24.9162 21.9575 24.5182 22.3555 24.0273 22.3555H8.97263C8.48171 22.3555 8.08374 21.9575 8.08374 21.4666ZM8.08374 24.1333C8.08374 23.6424 8.48171 23.2444 8.97263 23.2444H24.0273C24.5182 23.2444 24.9162 23.6424 24.9162 24.1333C24.9162 24.6242 24.5182 25.0222 24.0273 25.0222H8.97263C8.48171 25.0222 8.08374 24.6242 8.08374 24.1333ZM8.08374 26.8C8.08374 26.309 8.48171 25.9111 8.97263 25.9111H24.0273C24.5182 25.9111 24.9162 26.309 24.9162 26.8C24.9162 27.2909 24.5182 27.6888 24.0273 27.6888H8.97263C8.48171 27.6888 8.08374 27.2909 8.08374 26.8ZM8.08374 29.4666C8.08374 28.9757 8.48171 28.5777 8.97263 28.5777H24.0273C24.5182 28.5777 24.9162 28.9757 24.9162 29.4666C24.9162 29.9575 24.5182 30.3555 24.0273 30.3555H8.97263C8.48171 30.3555 8.08374 29.9575 8.08374 29.4666Z"
|
||||
fill="white"
|
||||
fill-opacity="0.65"
|
||||
/>
|
||||
<rect
|
||||
x="4.57422"
|
||||
y="0.5"
|
||||
width="23.9258"
|
||||
height="31.8206"
|
||||
fill="url(#paint0_linear_3236_2952)"
|
||||
fill-opacity="0.4"
|
||||
/>
|
||||
</g>
|
||||
<rect
|
||||
x="4.85"
|
||||
y="0.85"
|
||||
width="23.3"
|
||||
height="31.3"
|
||||
rx="3.20556"
|
||||
stroke="currentColor"
|
||||
stroke-width="0.7"
|
||||
/>
|
||||
<rect
|
||||
x="4.85"
|
||||
y="0.85"
|
||||
width="23.3"
|
||||
height="31.3"
|
||||
rx="3.20556"
|
||||
stroke="white"
|
||||
stroke-opacity="0.65"
|
||||
stroke-width="0.7"
|
||||
/>
|
||||
<rect
|
||||
x="4.85"
|
||||
y="0.85"
|
||||
width="23.3"
|
||||
height="31.3"
|
||||
rx="3.20556"
|
||||
stroke="url(#paint1_linear_3236_2952)"
|
||||
stroke-opacity="0.23"
|
||||
stroke-width="0.7"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<linearGradient
|
||||
id="paint0_linear_3236_2952"
|
||||
x1="16.5371"
|
||||
y1="0.5"
|
||||
x2="16.5371"
|
||||
y2="32.3206"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stop-color="white" stop-opacity="0" />
|
||||
<stop offset="1" stop-color="white" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint1_linear_3236_2952"
|
||||
x1="16.5"
|
||||
y1="0.5"
|
||||
x2="16.5"
|
||||
y2="32.5"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stop-color="white" stop-opacity="0" />
|
||||
<stop offset="1" stop-color="white" />
|
||||
</linearGradient>
|
||||
<clipPath id="clip0_3236_2952">
|
||||
<rect
|
||||
width="32"
|
||||
height="32"
|
||||
fill="white"
|
||||
transform="translate(0.5 0.5)"
|
||||
/>
|
||||
</clipPath>
|
||||
<clipPath id="clip1_3236_2952">
|
||||
<rect x="4.5" y="0.5" width="24" height="32" rx="3.55556" fill="white" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 683 B After Width: | Height: | Size: 6.2 KiB |
@@ -32,7 +32,7 @@ export const SimpleDocItem = ({
|
||||
showAccesses = false,
|
||||
}: SimpleDocItemProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { spacingsTokens } = useCunninghamTheme();
|
||||
const { spacingsTokens, colorsTokens } = useCunninghamTheme();
|
||||
const { isDesktop } = useResponsiveStore();
|
||||
const { untitledDocument } = useTrans();
|
||||
|
||||
@@ -52,9 +52,15 @@ export const SimpleDocItem = ({
|
||||
`}
|
||||
>
|
||||
{isPinned ? (
|
||||
<PinnedDocumentIcon aria-label={t('Pin document icon')} />
|
||||
<PinnedDocumentIcon
|
||||
aria-label={t('Pin document icon')}
|
||||
color={colorsTokens['primary-500']}
|
||||
/>
|
||||
) : (
|
||||
<SimpleFileIcon aria-label={t('Simple document icon')} />
|
||||
<SimpleFileIcon
|
||||
aria-label={t('Simple document icon')}
|
||||
color={colorsTokens['primary-500']}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
<Box $justify="center" $overflow="auto">
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
import Image from 'next/image';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import styled from 'styled-components';
|
||||
import styled, { css } from 'styled-components';
|
||||
|
||||
import { Box, StyledLink, Text } from '@/components/';
|
||||
import { useCunninghamTheme } from '@/cunningham';
|
||||
import { useConfig } from '@/core/config';
|
||||
|
||||
import { Title } from '../header';
|
||||
|
||||
import IconLink from './assets/external-link.svg';
|
||||
import { ContentType } from './types';
|
||||
|
||||
const BlueStripe = styled.div`
|
||||
position: absolute;
|
||||
@@ -16,9 +20,40 @@ const BlueStripe = styled.div`
|
||||
`;
|
||||
|
||||
export const Footer = () => {
|
||||
const { t } = useTranslation();
|
||||
const { themeTokens } = useCunninghamTheme();
|
||||
const logo = themeTokens.logo;
|
||||
const { data: config } = useConfig();
|
||||
const footerJson = config?.theme_customization?.footer;
|
||||
const { i18n, t } = useTranslation();
|
||||
const resolvedLanguage = i18n.resolvedLanguage;
|
||||
const [content, setContent] = useState<ContentType>();
|
||||
|
||||
useEffect(() => {
|
||||
if (!footerJson) {
|
||||
return;
|
||||
}
|
||||
|
||||
const langData = footerJson[resolvedLanguage as keyof typeof footerJson];
|
||||
const innerContent: ContentType = {};
|
||||
|
||||
innerContent.logo = langData?.logo || footerJson?.default?.logo;
|
||||
innerContent.legalLinks =
|
||||
langData?.legalLinks || footerJson?.default?.legalLinks;
|
||||
innerContent.externalLinks =
|
||||
langData && 'externalLinks' in langData
|
||||
? langData?.externalLinks
|
||||
: footerJson?.default?.externalLinks;
|
||||
innerContent.bottomInformation =
|
||||
langData && 'bottomInformation' in langData
|
||||
? langData?.bottomInformation
|
||||
: footerJson?.default?.bottomInformation;
|
||||
|
||||
setContent(innerContent);
|
||||
}, [footerJson, resolvedLanguage]);
|
||||
|
||||
const { logo, legalLinks, externalLinks, bottomInformation } = content || {};
|
||||
|
||||
if (!footerJson || (!legalLinks && !externalLinks && !bottomInformation)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Box $position="relative" as="footer" className="--docs--footer">
|
||||
@@ -34,14 +69,30 @@ export const Footer = () => {
|
||||
<Box className="--docs--footer-logo">
|
||||
<Box $align="center" $gap="6rem" $direction="row">
|
||||
{logo && (
|
||||
<Image
|
||||
priority
|
||||
src={logo.src}
|
||||
alt={logo.alt}
|
||||
width={0}
|
||||
height={0}
|
||||
style={{ width: logo.widthFooter, height: 'auto' }}
|
||||
/>
|
||||
<Box
|
||||
$align="center"
|
||||
$gap="0.5rem"
|
||||
$direction="row"
|
||||
$position="relative"
|
||||
$height="fit-content"
|
||||
>
|
||||
{logo?.src && (
|
||||
<Image
|
||||
className="c__image-system-filter"
|
||||
priority
|
||||
src={logo.src}
|
||||
alt={logo?.alt || t('Logo')}
|
||||
width={0}
|
||||
height={0}
|
||||
style={{ width: logo?.width || 'auto', height: 'auto' }}
|
||||
/>
|
||||
)}
|
||||
{logo.withTitle && (
|
||||
<Box $css="zoom:1.4;">
|
||||
<Title />
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
@@ -54,40 +105,24 @@ export const Footer = () => {
|
||||
`}
|
||||
className="--docs--footer-external-links"
|
||||
>
|
||||
{[
|
||||
{
|
||||
label: 'legifrance.gouv.fr',
|
||||
href: 'https://legifrance.gouv.fr/',
|
||||
},
|
||||
{
|
||||
label: 'info.gouv.fr',
|
||||
href: 'https://info.gouv.fr/',
|
||||
},
|
||||
{
|
||||
label: 'service-public.fr',
|
||||
href: 'https://service-public.fr/',
|
||||
},
|
||||
{
|
||||
label: 'data.gouv.fr',
|
||||
href: 'https://data.gouv.fr/',
|
||||
},
|
||||
].map(({ label, href }) => (
|
||||
<StyledLink
|
||||
key={label}
|
||||
href={href}
|
||||
target="__blank"
|
||||
$css={`
|
||||
gap:0.2rem;
|
||||
transition: box-shadow 0.3s;
|
||||
&:hover {
|
||||
box-shadow: 0px 2px 0 0 var(--c--theme--colors--greyscale-text);
|
||||
}
|
||||
`}
|
||||
>
|
||||
<Text $weight="bold">{label}</Text>
|
||||
<IconLink width={18} />
|
||||
</StyledLink>
|
||||
))}
|
||||
{externalLinks &&
|
||||
externalLinks.map(({ label, href }) => (
|
||||
<StyledLink
|
||||
key={label}
|
||||
href={href}
|
||||
target="__blank"
|
||||
$css={`
|
||||
gap:0.2rem;
|
||||
transition: box-shadow 0.3s;
|
||||
&:hover {
|
||||
box-shadow: 0px 2px 0 0 var(--c--theme--colors--greyscale-text);
|
||||
}
|
||||
`}
|
||||
>
|
||||
<Text $weight="bold">{label}</Text>
|
||||
<IconLink width={18} />
|
||||
</StyledLink>
|
||||
))}
|
||||
</Box>
|
||||
</Box>
|
||||
<Box
|
||||
@@ -102,66 +137,62 @@ export const Footer = () => {
|
||||
`}
|
||||
className="--docs--footer-internal-links"
|
||||
>
|
||||
{[
|
||||
{
|
||||
label: t('Legal Notice'),
|
||||
href: '/legal-notice',
|
||||
},
|
||||
{
|
||||
label: t('Personal data and cookies'),
|
||||
href: '/personal-data-cookies',
|
||||
},
|
||||
{
|
||||
label: t('Accessibility'),
|
||||
href: '/accessibility',
|
||||
},
|
||||
].map(({ label, href }) => (
|
||||
<StyledLink
|
||||
key={label}
|
||||
href={href}
|
||||
$css={`
|
||||
padding-right: 1rem;
|
||||
&:not(:last-child) {
|
||||
box-shadow: inset -1px 0px 0px 0px var(--c--theme--colors--greyscale-200);
|
||||
}
|
||||
`}
|
||||
>
|
||||
<Text
|
||||
$variation="600"
|
||||
$size="m"
|
||||
$transition="box-shadow 0.3s"
|
||||
$css={`
|
||||
&:hover {
|
||||
box-shadow: 0px 2px 0 0 var(--c--theme--colors--greyscale-text);
|
||||
{legalLinks &&
|
||||
legalLinks.map(({ label, href }) => (
|
||||
<StyledLink
|
||||
key={label}
|
||||
href={href}
|
||||
$css={css`
|
||||
padding-right: 1rem;
|
||||
&:not(:last-child) {
|
||||
box-shadow: inset -1px 0px 0px 0px
|
||||
var(--c--theme--colors--greyscale-200);
|
||||
}
|
||||
`}
|
||||
>
|
||||
{label}
|
||||
</Text>
|
||||
</StyledLink>
|
||||
))}
|
||||
<Text
|
||||
$variation="600"
|
||||
$size="m"
|
||||
$transition="box-shadow 0.3s"
|
||||
$css={css`
|
||||
&:hover {
|
||||
box-shadow: 0px 2px 0 0
|
||||
var(--c--theme--colors--greyscale-text);
|
||||
}
|
||||
`}
|
||||
>
|
||||
{label}
|
||||
</Text>
|
||||
</StyledLink>
|
||||
))}
|
||||
</Box>
|
||||
<Text
|
||||
as="p"
|
||||
$size="m"
|
||||
$margin={{ top: 'big' }}
|
||||
$variation="600"
|
||||
$display="inline"
|
||||
className="--docs--footer-licence"
|
||||
>
|
||||
{t('Unless otherwise stated, all content on this site is under')}{' '}
|
||||
<StyledLink
|
||||
href="https://github.com/etalab/licence-ouverte/blob/master/LO.md"
|
||||
target="__blank"
|
||||
$css={`
|
||||
display:inline-flex;
|
||||
box-shadow: 0px 1px 0 0 var(--c--theme--colors--greyscale-text);
|
||||
`}
|
||||
{bottomInformation && (
|
||||
<Text
|
||||
as="p"
|
||||
$size="m"
|
||||
$margin={{ top: 'big' }}
|
||||
$variation="600"
|
||||
$display="inline"
|
||||
className="--docs--footer-licence"
|
||||
>
|
||||
<Text $variation="600">licence etalab-2.0</Text>
|
||||
<IconLink width={18} />
|
||||
</StyledLink>
|
||||
</Text>
|
||||
{bottomInformation.label}{' '}
|
||||
{bottomInformation.link && (
|
||||
<StyledLink
|
||||
href={bottomInformation.link.href}
|
||||
target="__blank"
|
||||
$css={css`
|
||||
display: inline-flex;
|
||||
box-shadow: 0px 1px 0 0
|
||||
var(--c--theme--colors--greyscale-text);
|
||||
gap: 0.2rem;
|
||||
`}
|
||||
>
|
||||
<Text $variation="600">{bottomInformation.link.label}</Text>
|
||||
<IconLink width={14} />
|
||||
</StyledLink>
|
||||
)}
|
||||
</Text>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
export * from './Footer';
|
||||
export * from './types';
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
export interface FooterType {
|
||||
default: ContentType;
|
||||
[key: string]: ContentType;
|
||||
}
|
||||
|
||||
export interface BottomInformation {
|
||||
label: string;
|
||||
link?: Link;
|
||||
}
|
||||
|
||||
export interface Link {
|
||||
label: string;
|
||||
href: string;
|
||||
}
|
||||
|
||||
export interface Logo {
|
||||
src: string;
|
||||
width: string;
|
||||
alt: string;
|
||||
withTitle: boolean;
|
||||
}
|
||||
|
||||
export interface ContentType {
|
||||
logo?: Logo;
|
||||
externalLinks?: Link[];
|
||||
legalLinks?: Link[];
|
||||
bottomInformation?: BottomInformation;
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
<svg
|
||||
width="60"
|
||||
height="60"
|
||||
viewBox="0 0 60 60"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<rect
|
||||
opacity="0.1"
|
||||
x="1"
|
||||
y="1"
|
||||
width="58"
|
||||
height="58"
|
||||
rx="1"
|
||||
fill="white"
|
||||
stroke="#000091"
|
||||
stroke-width="2"
|
||||
/>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M29.4103 24.6079L34.1507 27.3446V32.8178L29.4103 35.5544L24.6699 32.8178V27.3446L29.4103 24.6079Z"
|
||||
fill="#000091"
|
||||
/>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M34.7463 15L39.4867 17.7367V23.2099L34.7463 25.9465L30.0059 23.2099V17.7367L34.7463 15Z"
|
||||
fill="#000091"
|
||||
/>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M34.7463 34.0537L39.4867 36.7904V42.2636L34.7463 45.0002L30.0059 42.2636V36.7904L34.7463 34.0537Z"
|
||||
fill="#000091"
|
||||
/>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M18.7404 24.6079L23.4808 27.3446V32.8178L18.7404 35.5544L14 32.8178V27.3446L18.7404 24.6079Z"
|
||||
fill="#000091"
|
||||
/>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M24.0744 15L28.8148 17.7367V23.2099L24.0744 25.9465L19.334 23.2099V17.7367L24.0744 15Z"
|
||||
fill="#000091"
|
||||
/>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M24.0744 34.0537L28.8148 36.7904V42.2636L24.0744 45.0002L19.334 42.2636V36.7904L24.0744 34.0537Z"
|
||||
fill="#000091"
|
||||
/>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M40.2717 24.6079L45.0121 27.3446V32.8178L40.2717 35.5544L35.5312 32.8178V27.3446L40.2717 24.6079Z"
|
||||
fill="#000091"
|
||||
/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.5 KiB |
@@ -48,7 +48,11 @@ export const Header = () => {
|
||||
$height="fit-content"
|
||||
$margin={{ top: 'auto' }}
|
||||
>
|
||||
<IconDocs aria-label={t('Docs Logo')} width={32} />
|
||||
<IconDocs
|
||||
aria-label={t('Docs Logo')}
|
||||
width={32}
|
||||
color={colorsTokens['primary-text']}
|
||||
/>
|
||||
<Title />
|
||||
</Box>
|
||||
</StyledLink>
|
||||
|
||||
@@ -15,7 +15,7 @@ const GaufreStyle = createGlobalStyle`
|
||||
export const LaGaufre = () => {
|
||||
const { componentTokens } = useCunninghamTheme();
|
||||
|
||||
if (!componentTokens['la-gauffre'].activated) {
|
||||
if (!componentTokens['la-gaufre']) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,9 @@ import { useCunninghamTheme } from '@/cunningham';
|
||||
|
||||
export const Title = () => {
|
||||
const { t } = useTranslation();
|
||||
const { spacingsTokens } = useCunninghamTheme();
|
||||
const { spacingsTokens, colorsTokens, componentTokens } =
|
||||
useCunninghamTheme();
|
||||
const isBeta = componentTokens['beta'];
|
||||
|
||||
return (
|
||||
<Box
|
||||
@@ -18,32 +20,34 @@ export const Title = () => {
|
||||
<Text
|
||||
$margin="none"
|
||||
as="h2"
|
||||
$color="#000091"
|
||||
$color={colorsTokens['primary-text']}
|
||||
$zIndex={1}
|
||||
$size="1.375rem"
|
||||
>
|
||||
{t('Docs')}
|
||||
</Text>
|
||||
<Text
|
||||
$padding={{
|
||||
horizontal: '6px',
|
||||
vertical: '4px',
|
||||
}}
|
||||
$size="11px"
|
||||
$theme="primary"
|
||||
$variation="500"
|
||||
$weight="bold"
|
||||
$radius="12px"
|
||||
$css={css`
|
||||
line-height: 9px;
|
||||
`}
|
||||
$width="40px"
|
||||
$height="16px"
|
||||
$background="#ECECFF"
|
||||
$color="#5958D3"
|
||||
>
|
||||
BETA
|
||||
</Text>
|
||||
{isBeta && (
|
||||
<Text
|
||||
$padding={{
|
||||
horizontal: '6px',
|
||||
vertical: '4px',
|
||||
}}
|
||||
$size="11px"
|
||||
$theme="primary"
|
||||
$variation="500"
|
||||
$weight="bold"
|
||||
$radius="12px"
|
||||
$css={css`
|
||||
line-height: 9px;
|
||||
`}
|
||||
$width="40px"
|
||||
$height="16px"
|
||||
$background="#ECECFF"
|
||||
$color="#5958D3"
|
||||
>
|
||||
BETA
|
||||
</Text>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -3,7 +3,7 @@ import Image from 'next/image';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { css } from 'styled-components';
|
||||
|
||||
import DocLogo from '@/assets/icons/icon-docs.svg?url';
|
||||
import IconDocs from '@/assets/icons/icon-docs.svg';
|
||||
import { Box, Icon, Text } from '@/components';
|
||||
import { useCunninghamTheme } from '@/cunningham';
|
||||
import { ProConnectButton, gotoLogin } from '@/features/auth';
|
||||
@@ -15,9 +15,10 @@ import { getHeaderHeight } from './HomeHeader';
|
||||
|
||||
export default function HomeBanner() {
|
||||
const { t } = useTranslation();
|
||||
const { componentTokens, spacingsTokens } = useCunninghamTheme();
|
||||
const { componentTokens, spacingsTokens, colorsTokens } =
|
||||
useCunninghamTheme();
|
||||
const { isMobile, isSmallMobile } = useResponsiveStore();
|
||||
const withProConnect = componentTokens['home-proconnect'].activated;
|
||||
const withProConnect = componentTokens['home-proconnect'];
|
||||
|
||||
return (
|
||||
<Box
|
||||
@@ -46,7 +47,11 @@ export default function HomeBanner() {
|
||||
$align="center"
|
||||
$gap={spacingsTokens['sm']}
|
||||
>
|
||||
<Image src={DocLogo} alt="DocLogo" width={64} />
|
||||
<IconDocs
|
||||
aria-label={t('Docs Logo')}
|
||||
width={64}
|
||||
color={colorsTokens['primary-text']}
|
||||
/>
|
||||
<Text
|
||||
as="h2"
|
||||
$size={!isMobile ? 'xs-alt' : '2.3rem'}
|
||||
@@ -83,6 +88,7 @@ export default function HomeBanner() {
|
||||
</Box>
|
||||
{!isMobile && (
|
||||
<Image
|
||||
className="c__image-system-filter"
|
||||
src={banner}
|
||||
alt={t('Banner image')}
|
||||
priority
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import Image from 'next/image';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import DocLogo from '@/assets/icons/icon-docs.svg?url';
|
||||
import IconDocs from '@/assets/icons/icon-docs.svg';
|
||||
import { Box, Text } from '@/components';
|
||||
import { useCunninghamTheme } from '@/cunningham';
|
||||
import { ProConnectButton } from '@/features/auth';
|
||||
@@ -10,7 +9,7 @@ import { useResponsiveStore } from '@/stores';
|
||||
|
||||
export function HomeBottom() {
|
||||
const { componentTokens } = useCunninghamTheme();
|
||||
const withProConnect = componentTokens['home-proconnect'].activated;
|
||||
const withProConnect = componentTokens['home-proconnect'];
|
||||
|
||||
if (!withProConnect) {
|
||||
return null;
|
||||
@@ -21,7 +20,7 @@ export function HomeBottom() {
|
||||
|
||||
function HomeProConnect() {
|
||||
const { t } = useTranslation();
|
||||
const { spacingsTokens } = useCunninghamTheme();
|
||||
const { spacingsTokens, colorsTokens } = useCunninghamTheme();
|
||||
const { isMobile } = useResponsiveStore();
|
||||
const parentGap = '230px';
|
||||
|
||||
@@ -45,7 +44,11 @@ function HomeProConnect() {
|
||||
$height="fit-content"
|
||||
$css="zoom: 1.9;"
|
||||
>
|
||||
<Image src={DocLogo} alt="DocLogo" />
|
||||
<IconDocs
|
||||
aria-label={t('Docs Logo')}
|
||||
width={34}
|
||||
color={colorsTokens['primary-text']}
|
||||
/>
|
||||
<Title />
|
||||
</Box>
|
||||
<Text $size="md" $variation="1000" $textAlign="center">
|
||||
|
||||
@@ -61,7 +61,7 @@ export function HomeContent() {
|
||||
$gap={isMobile ? '115px' : '230px'}
|
||||
$padding={{ bottom: '3rem' }}
|
||||
>
|
||||
<Box $gap="30px">
|
||||
<Box $gap={isMobile ? '115px' : '30px'}>
|
||||
<HomeSection
|
||||
isColumn={false}
|
||||
isSmallDevice={isTablet}
|
||||
|
||||
@@ -17,7 +17,7 @@ export const getHeaderHeight = (isSmallMobile: boolean) =>
|
||||
|
||||
export const HomeHeader = () => {
|
||||
const { t } = useTranslation();
|
||||
const { themeTokens, spacingsTokens } = useCunninghamTheme();
|
||||
const { themeTokens, spacingsTokens, colorsTokens } = useCunninghamTheme();
|
||||
const logo = themeTokens.logo;
|
||||
const { isSmallMobile } = useResponsiveStore();
|
||||
|
||||
@@ -44,7 +44,7 @@ export const HomeHeader = () => {
|
||||
<ButtonTogglePanel />
|
||||
</Box>
|
||||
)}
|
||||
{!isSmallMobile && logo && (
|
||||
{!isSmallMobile && logo?.src && (
|
||||
<Image
|
||||
priority
|
||||
src={logo.src}
|
||||
@@ -61,7 +61,11 @@ export const HomeHeader = () => {
|
||||
$position="relative"
|
||||
$height="fit-content"
|
||||
>
|
||||
<IconDocs aria-label={t('Docs Logo')} width={32} />
|
||||
<IconDocs
|
||||
aria-label={t('Docs Logo')}
|
||||
width={32}
|
||||
color={colorsTokens['primary-text']}
|
||||
/>
|
||||
<Title />
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
@@ -174,6 +174,7 @@ export const HomeSection = ({
|
||||
|
||||
{illustration && (isSmallDevice || !video) && (
|
||||
<Image
|
||||
className="c__image-system-filter"
|
||||
src={illustration}
|
||||
alt={t('Illustration')}
|
||||
style={{
|
||||
|
||||
@@ -108,10 +108,9 @@ const FALLBACK = {
|
||||
const precacheResources = [
|
||||
'/',
|
||||
'/index.html',
|
||||
'/401/',
|
||||
'/404/',
|
||||
'/accessibility/',
|
||||
'/legal-notice/',
|
||||
'/personal-data-cookies/',
|
||||
'/403/',
|
||||
FALLBACK.offline,
|
||||
FALLBACK.images,
|
||||
FALLBACK.docs,
|
||||
|
||||
@@ -29,6 +29,7 @@ const Page: NextPageWithLayout = () => {
|
||||
$padding={{ bottom: '2rem' }}
|
||||
>
|
||||
<Image
|
||||
className="c__image-system-filter"
|
||||
src={img401}
|
||||
alt={t('Image 401')}
|
||||
style={{
|
||||
|
||||
@@ -24,6 +24,7 @@ const Page: NextPageWithLayout = () => {
|
||||
$padding={{ bottom: '2rem' }}
|
||||
>
|
||||
<Image
|
||||
className="c__image-system-filter"
|
||||
src={img403}
|
||||
alt={t('Image 403')}
|
||||
style={{
|
||||
|
||||
@@ -1,37 +1,45 @@
|
||||
import { Button } from '@openfun/cunningham-react';
|
||||
import Image from 'next/image';
|
||||
import { ReactElement } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import Icon404 from '@/assets/icons/icon-404.svg';
|
||||
import img403 from '@/assets/icons/icon-403.png';
|
||||
import { Box, Icon, StyledLink, Text } from '@/components';
|
||||
import { PageLayout } from '@/layouts';
|
||||
import { NextPageWithLayout } from '@/types/next';
|
||||
|
||||
const StyledButton = styled(Button)`
|
||||
width: fit-content;
|
||||
padding-left: 2rem;
|
||||
padding-right: 2rem;
|
||||
`;
|
||||
|
||||
const Page: NextPageWithLayout = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<Box $align="center" $margin="auto" $height="70vh" $gap="2rem">
|
||||
<Icon404 aria-label="Image 404" role="img" />
|
||||
<Box
|
||||
$align="center"
|
||||
$margin="auto"
|
||||
$gap="1rem"
|
||||
$padding={{ bottom: '2rem' }}
|
||||
>
|
||||
<Image
|
||||
className="c__image-system-filter"
|
||||
src={img403}
|
||||
alt={t('Image 403')}
|
||||
style={{
|
||||
maxWidth: '100%',
|
||||
height: 'auto',
|
||||
}}
|
||||
/>
|
||||
|
||||
<Text $size="h2" $weight="700" $theme="greyscale" $variation="900">
|
||||
{t('Ouch !')}
|
||||
</Text>
|
||||
<Box $align="center" $gap="0.8rem">
|
||||
<Text as="p" $textAlign="center" $maxWidth="350px" $theme="primary">
|
||||
{t(
|
||||
'It seems that the page you are looking for does not exist or cannot be displayed correctly.',
|
||||
)}
|
||||
</Text>
|
||||
|
||||
<Text as="p" $textAlign="center" $maxWidth="400px" $size="m">
|
||||
{t(
|
||||
'It seems that the page you are looking for does not exist or cannot be displayed correctly.',
|
||||
)}
|
||||
</Text>
|
||||
|
||||
<Box $margin={{ top: 'large' }}>
|
||||
<StyledLink href="/">
|
||||
<StyledButton icon={<Icon iconName="house" $color="white" />}>
|
||||
{t('Home')}
|
||||
|
||||
@@ -3,6 +3,7 @@ import Head from 'next/head';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { AppProvider } from '@/core/';
|
||||
import { useCunninghamTheme } from '@/cunningham';
|
||||
import { useOffline, useSWRegister } from '@/features/service-worker/';
|
||||
import '@/i18n/initI18n';
|
||||
import { NextPageWithLayout } from '@/types/next';
|
||||
@@ -18,6 +19,8 @@ export default function App({ Component, pageProps }: AppPropsWithLayout) {
|
||||
useOffline();
|
||||
const getLayout = Component.getLayout ?? ((page) => page);
|
||||
const { t } = useTranslation();
|
||||
const { componentTokens } = useCunninghamTheme();
|
||||
const favicon = componentTokens['favicon'];
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -29,17 +32,17 @@ export default function App({ Component, pageProps }: AppPropsWithLayout) {
|
||||
'Docs: Your new companion to collaborate on documents efficiently, intuitively, and securely.',
|
||||
)}
|
||||
/>
|
||||
<link rel="icon" href="/favicon.ico" sizes="any" />
|
||||
<link rel="icon" href="/favicon.png" type="image/png" />
|
||||
<link rel="icon" href={favicon['ico']} sizes="any" />
|
||||
<link rel="icon" href={favicon['png-light']} type="image/png" />
|
||||
<link
|
||||
rel="icon"
|
||||
href="/favicon.png"
|
||||
href={favicon['png-light']}
|
||||
type="image/png"
|
||||
media="(prefers-color-scheme: light)"
|
||||
/>
|
||||
<link
|
||||
rel="icon"
|
||||
href="/favicon-dark.png"
|
||||
href={favicon['png-dark']}
|
||||
type="image/png"
|
||||
media="(prefers-color-scheme: dark)"
|
||||
/>
|
||||
|
||||
@@ -1,133 +0,0 @@
|
||||
import { ReactElement } from 'react';
|
||||
import { Trans, useTranslation } from 'react-i18next';
|
||||
|
||||
import { Box, Text, TextStyled } from '@/components';
|
||||
import { useCunninghamTheme } from '@/cunningham';
|
||||
import { PageLayout } from '@/layouts';
|
||||
import { NextPageWithLayout } from '@/types/next';
|
||||
|
||||
const Page: NextPageWithLayout = () => {
|
||||
const { t } = useTranslation();
|
||||
const { colorsTokens } = useCunninghamTheme();
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Box
|
||||
as="h1"
|
||||
$background={colorsTokens['primary-100']}
|
||||
$margin="none"
|
||||
$padding="large"
|
||||
>
|
||||
{t('Accessibility')}
|
||||
</Box>
|
||||
<Box $padding={{ horizontal: 'large', vertical: 'big' }}>
|
||||
<Text as="p" $display="inline">
|
||||
<Trans t={t} i18nKey="accessibility-dinum-services">
|
||||
<strong>DINUM</strong> is committed to making its digital services
|
||||
accessible, in accordance with article 47 of French law n° 2005-102
|
||||
dated February 11, 2005.
|
||||
</Trans>
|
||||
</Text>
|
||||
<Text as="h2" $margin={{ bottom: 'xtiny' }}>
|
||||
{t('Accessibility statement')}
|
||||
</Text>
|
||||
<Text as="p">{t('Established on December 20, 2023.')}</Text>
|
||||
<Text as="p" $display="inline">
|
||||
{t('This accessibility statement applies to the site hosted on')}{' '}
|
||||
<strong>https://docs.numerique.gouv.fr</strong>.
|
||||
</Text>
|
||||
<Text as="h2" $margin={{ bottom: 'xtiny' }}>
|
||||
{t('Compliance status')}
|
||||
</Text>
|
||||
<Text as="p" $display="inline">
|
||||
<Trans t={t} i18nKey="accessibility-not-audit">
|
||||
<strong>https://docs.numerique.gouv.fr</strong> is not compliant
|
||||
with RGAA 4.1. The site has <strong>not yet been audited.</strong>
|
||||
</Trans>
|
||||
</Text>
|
||||
<Text as="h2" $margin={{ bottom: 'xtiny' }}>
|
||||
{t('Improvement and contact')}
|
||||
</Text>
|
||||
<Text as="p" $display="inline">
|
||||
{t(
|
||||
'If you are unable to access a content or a service, you can contact the person responsible for https://lasuite.numerique.gouv.fr to be directed to an accessible alternative or to obtain the content in another form.',
|
||||
)}
|
||||
</Text>
|
||||
<Text as="p" $display="inline">
|
||||
<li>
|
||||
{t('E-mail:')}{' '}
|
||||
<TextStyled
|
||||
as="a"
|
||||
href="mailto:lasuite@modernisation.gouv.fr"
|
||||
$display="inline"
|
||||
>
|
||||
lasuite@modernisation.gouv.fr
|
||||
</TextStyled>
|
||||
</li>
|
||||
<li>
|
||||
{t('Address:')} <strong>DINUM</strong>, 20 avenue de Ségur 75007
|
||||
Paris
|
||||
</li>
|
||||
</Text>
|
||||
<Text as="p" $display="inline">
|
||||
{t('We try to respond within 2 working days.')}
|
||||
</Text>
|
||||
|
||||
<Text as="h2" $margin={{ bottom: 'xtiny' }}>
|
||||
{t('Remedies')}
|
||||
</Text>
|
||||
<Text as="p" $display="inline">
|
||||
{t('This procedure should be used in the following case:')}{' '}
|
||||
{t(
|
||||
'you have reported to the website manager a lack of accessibility that prevents you from accessing content or one of the services of the portal and you have not received a satisfactory response.',
|
||||
)}
|
||||
</Text>
|
||||
<Text as="p" $display="inline" $margin={{ bottom: 'tiny' }}>
|
||||
{t('You can:')}
|
||||
</Text>
|
||||
<Text as="p" $display="inline" $margin={{ top: 'tiny' }}>
|
||||
<li>
|
||||
<Trans t={t} i18nKey="accessibility-form-defenseurdesdroits">
|
||||
Write a message to the
|
||||
<TextStyled
|
||||
as="a"
|
||||
href="https://formulaire.defenseurdesdroits.fr/formulaire_saisine/"
|
||||
$display="inline"
|
||||
$margin={{ left: '4px' }}
|
||||
>
|
||||
Defender of Rights
|
||||
</TextStyled>
|
||||
</Trans>
|
||||
</li>
|
||||
<li>
|
||||
<Trans t={t} i18nKey="accessibility-contact-defenseurdesdroits">
|
||||
Contact the delegate of the
|
||||
<TextStyled
|
||||
as="a"
|
||||
href="https://www.defenseurdesdroits.fr/carte-des-delegues"
|
||||
$display="inline"
|
||||
$margin={{ left: '4px' }}
|
||||
>
|
||||
Defender of Rights in your region
|
||||
</TextStyled>
|
||||
</Trans>
|
||||
</li>
|
||||
<li>
|
||||
{t('Send a letter by post (free of charge, no stamp needed):')}{' '}
|
||||
<strong>
|
||||
{t(
|
||||
'Defender of Rights - Free response - 71120 75342 Paris CEDEX 07',
|
||||
)}
|
||||
</strong>
|
||||
</li>
|
||||
</Text>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
Page.getLayout = function getLayout(page: ReactElement) {
|
||||
return <PageLayout>{page}</PageLayout>;
|
||||
};
|
||||
|
||||
export default Page;
|
||||
@@ -1,72 +0,0 @@
|
||||
import { ReactElement } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { Box, Text, TextStyled } from '@/components';
|
||||
import { useCunninghamTheme } from '@/cunningham';
|
||||
import { PageLayout } from '@/layouts';
|
||||
import { NextPageWithLayout } from '@/types/next';
|
||||
|
||||
const Page: NextPageWithLayout = () => {
|
||||
const { t } = useTranslation();
|
||||
const { colorsTokens } = useCunninghamTheme();
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Box
|
||||
as="h1"
|
||||
$background={colorsTokens['primary-100']}
|
||||
$margin="none"
|
||||
$padding="large"
|
||||
>
|
||||
{t('Legal notice')}
|
||||
</Box>
|
||||
<Box $padding={{ horizontal: 'large', vertical: 'big' }}>
|
||||
<Text as="h2" $margin={{ bottom: 'xtiny' }}>
|
||||
{t('Publisher')}
|
||||
</Text>
|
||||
<Text as="p">
|
||||
{t(
|
||||
'French Interministerial Directorate for Digital Affairs (DINUM), 20 avenue de Ségur 75007 Paris.',
|
||||
)}
|
||||
</Text>
|
||||
<Text as="h2" $margin={{ bottom: 'xtiny' }}>
|
||||
{t('Publication Director')}
|
||||
</Text>
|
||||
<Text as="p">
|
||||
{t('Stéphanie Schaer: Interministerial Digital Director (DINUM).')}
|
||||
</Text>
|
||||
<Text as="h2" $margin={{ bottom: 'xtiny' }}>
|
||||
{t('Copyright')}
|
||||
</Text>
|
||||
<Text as="p" $display="inline">
|
||||
{t('Illustration:')}{' '}
|
||||
<Text $weight="bold" $display="inline">
|
||||
DINUM
|
||||
</Text>
|
||||
</Text>
|
||||
<Text as="h2" $margin={{ bottom: 'xtiny' }}>
|
||||
{t('More info?')}
|
||||
</Text>
|
||||
<Text as="p" $display="inline">
|
||||
{t(
|
||||
'The team in charge of the digital workspace "La Suite numérique" can be contacted directly at',
|
||||
)}{' '}
|
||||
<TextStyled
|
||||
as="a"
|
||||
href="mailto:lasuite@modernisation.gouv.fr"
|
||||
$display="inline"
|
||||
>
|
||||
lasuite@modernisation.gouv.fr
|
||||
</TextStyled>
|
||||
.
|
||||
</Text>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
Page.getLayout = function getLayout(page: ReactElement) {
|
||||
return <PageLayout>{page}</PageLayout>;
|
||||
};
|
||||
|
||||
export default Page;
|
||||
@@ -1,66 +0,0 @@
|
||||
import { ReactElement } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { Box, Text } from '@/components';
|
||||
import { useCunninghamTheme } from '@/cunningham';
|
||||
import { PageLayout } from '@/layouts';
|
||||
import { NextPageWithLayout } from '@/types/next';
|
||||
|
||||
const Page: NextPageWithLayout = () => {
|
||||
const { t } = useTranslation();
|
||||
const { colorsTokens } = useCunninghamTheme();
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Box
|
||||
as="h1"
|
||||
$background={colorsTokens['primary-100']}
|
||||
$margin="none"
|
||||
$padding="large"
|
||||
>
|
||||
{t('Personal data and cookies')}
|
||||
</Box>
|
||||
<Box $padding={{ horizontal: 'large', vertical: 'big' }}>
|
||||
<Text as="h2" $margin={{ bottom: 'xtiny' }}>
|
||||
{t('Cookies placed')}
|
||||
</Text>
|
||||
<Text as="p">
|
||||
{t(
|
||||
'This site places a small text file (a "cookie") on your computer when you visit it.',
|
||||
)}
|
||||
{t(
|
||||
'This allows us to measure the number of visits and understand which pages are the most viewed.',
|
||||
)}
|
||||
</Text>
|
||||
<Text as="p">
|
||||
{t('You can oppose the tracking of your browsing on this website.')}
|
||||
{t(
|
||||
'This will protect your privacy, but will also prevent the owner from learning from your actions and creating a better experience for you and other users.',
|
||||
)}
|
||||
</Text>
|
||||
<Text as="h2" $margin={{ bottom: 'xtiny' }}>
|
||||
{t('This site does not display a cookie consent banner, why?')}
|
||||
</Text>
|
||||
<Text as="p">
|
||||
{t(
|
||||
"It's true, you didn't have to click on a block that covers half the page to say you agree to the placement of cookies — even if you don't know what it means!",
|
||||
)}
|
||||
</Text>
|
||||
<Text as="p">
|
||||
{t(
|
||||
'Nothing exceptional, no special privileges related to a .gouv.fr.',
|
||||
)}
|
||||
{t(
|
||||
'We simply comply with the law, which states that certain audience measurement tools, properly configured to respect privacy, are exempt from prior authorization.',
|
||||
)}
|
||||
</Text>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
Page.getLayout = function getLayout(page: ReactElement) {
|
||||
return <PageLayout>{page}</PageLayout>;
|
||||
};
|
||||
|
||||
export default Page;
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "impress",
|
||||
"version": "3.2.1",
|
||||
"version": "3.3.0",
|
||||
"private": true,
|
||||
"workspaces": {
|
||||
"packages": [
|
||||
@@ -28,8 +28,8 @@
|
||||
"server:test": "yarn COLLABORATION_SERVER run test"
|
||||
},
|
||||
"resolutions": {
|
||||
"@types/node": "22.15.19",
|
||||
"@types/react": "19.1.4",
|
||||
"@types/node": "22.15.21",
|
||||
"@types/react": "19.1.5",
|
||||
"@types/react-dom": "19.1.5",
|
||||
"@typescript-eslint/eslint-plugin": "8.32.1",
|
||||
"@typescript-eslint/parser": "8.32.1",
|
||||
|
||||
@@ -13,6 +13,10 @@ const eslintTS = [
|
||||
rules: {
|
||||
'@typescript-eslint/no-explicit-any': 'error',
|
||||
'@typescript-eslint/no-non-null-assertion': 'error',
|
||||
'@typescript-eslint/no-unused-vars': [
|
||||
'error',
|
||||
{ varsIgnorePattern: '^_', argsIgnorePattern: '^_' },
|
||||
],
|
||||
'sort-imports': [
|
||||
'error',
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "eslint-config-impress",
|
||||
"version": "3.2.1",
|
||||
"version": "3.3.0",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"lint": "eslint --ext .js ."
|
||||
|
||||