From b09d5e5ffdf99a0b5b4bcc6b3cf09323f8b212b8 Mon Sep 17 00:00:00 2001 From: Sli Date: Mon, 7 Apr 2025 13:58:08 +0200 Subject: [PATCH 1/4] Remote calendar link for external sync --- com/ics_calendar.py | 17 +++++++++--- .../com/components/ics-calendar-index.ts | 26 +++++++++++++++++++ com/static/com/components/ics-calendar.scss | 17 ++++++++++++ locale/fr/LC_MESSAGES/djangojs.po | 10 ++++++- sith/settings.py | 6 +++-- 5 files changed, 70 insertions(+), 6 deletions(-) diff --git a/com/ics_calendar.py b/com/ics_calendar.py index e5324c8a..6cb10d2d 100644 --- a/com/ics_calendar.py +++ b/com/ics_calendar.py @@ -1,9 +1,11 @@ from pathlib import Path -from typing import final from dateutil.relativedelta import relativedelta from django.conf import settings +from django.contrib.sites.models import Site +from django.contrib.syndication.views import add_domain from django.db.models import F, QuerySet +from django.http import HttpRequest from django.urls import reverse from django.utils import timezone from ical.calendar import Calendar @@ -14,7 +16,14 @@ from com.models import NewsDate from core.models import User -@final +def as_absolute_url(url: str, request: HttpRequest | None = None) -> str: + return add_domain( + Site.objects.get_current(request=request), + url, + secure=request.is_secure() if request is not None else settings.HTTPS, + ) + + class IcsCalendar: _CACHE_FOLDER: Path = settings.MEDIA_ROOT / "com" / "calendars" _INTERNAL_CALENDAR = _CACHE_FOLDER / "internal.ics" @@ -58,7 +67,9 @@ class IcsCalendar: summary=news_date.news_title, start=news_date.start_date, end=news_date.end_date, - url=reverse("com:news_detail", kwargs={"news_id": news_date.news.id}), + url=as_absolute_url( + reverse("com:news_detail", kwargs={"news_id": news_date.news.id}) + ), ) calendar.events.append(event) diff --git a/com/static/bundled/com/components/ics-calendar-index.ts b/com/static/bundled/com/components/ics-calendar-index.ts index d8fc79d7..2befc97e 100644 --- a/com/static/bundled/com/components/ics-calendar-index.ts +++ b/com/static/bundled/com/components/ics-calendar-index.ts @@ -303,10 +303,36 @@ export class IcsCalendar extends inheritHtmlElement("div") { this.calendar = new Calendar(this.node, { plugins: [dayGridPlugin, iCalendarPlugin, listPlugin], locales: [frLocale, enLocale], + customButtons: { + getCalendarLink: { + text: gettext("Copy calendar link"), + click: async (event: Event) => { + const button = event.target as HTMLButtonElement; + button.classList.add("text-copy"); + button.setAttribute( + "tooltip", + gettext("Calendar link copied to the clipboard"), + ); + navigator.clipboard.writeText( + new URL( + await makeUrl(calendarCalendarInternal), + window.location.origin, + ).toString(), + ); + setTimeout(() => { + button.classList.remove("text-copied"); + button.classList.add("text-copied"); + button.classList.remove("text-copy"); + button.removeAttribute("tooltip"); + }, 700); + }, + }, + }, height: "auto", locale: this.locale, initialView: this.currentView(), headerToolbar: this.currentToolbar(), + footerToolbar: { start: "getCalendarLink" }, eventSources: await this.getEventSources(), windowResize: () => { this.calendar.changeView(this.currentView()); diff --git a/com/static/com/components/ics-calendar.scss b/com/static/com/components/ics-calendar.scss index 6c86cce0..bb0fea47 100644 --- a/com/static/com/components/ics-calendar.scss +++ b/com/static/com/components/ics-calendar.scss @@ -98,4 +98,21 @@ ics-calendar { background: white; } } + + .fc .fc-toolbar.fc-footer-toolbar { + margin-bottom: 0.5em; + } + + button.text-copy, + button.text-copy:focus, + button.text-copy:hover { + background-color: green !important; + transition: 200ms linear; + } + + button.text-copied, + button.text-copied:focus, + button.text-copied:hover { + transition: 200ms linear; + } } \ No newline at end of file diff --git a/locale/fr/LC_MESSAGES/djangojs.po b/locale/fr/LC_MESSAGES/djangojs.po index 7952baa4..e078509a 100644 --- a/locale/fr/LC_MESSAGES/djangojs.po +++ b/locale/fr/LC_MESSAGES/djangojs.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-04-06 15:47+0200\n" +"POT-Creation-Date: 2025-04-07 13:56+0200\n" "PO-Revision-Date: 2024-09-17 11:54+0200\n" "Last-Translator: Sli \n" "Language-Team: AE info \n" @@ -33,6 +33,14 @@ msgstr "Dépublier" msgid "Delete" msgstr "Supprimer" +#: com/static/bundled/com/components/ics-calendar-index.ts +msgid "Copy calendar link" +msgstr "Copier le lien du calendrier" + +#: com/static/bundled/com/components/ics-calendar-index.ts +msgid "Calendar link copied to the clipboard" +msgstr "Lien du calendrier copié dans le presse papier" + #: com/static/bundled/com/components/moderation-alert-index.ts #, javascript-format msgid "" diff --git a/sith/settings.py b/sith/settings.py index e948e971..7e3ef14f 100644 --- a/sith/settings.py +++ b/sith/settings.py @@ -78,10 +78,12 @@ DEBUG = env.bool("SITH_DEBUG", default=False) TESTING = "pytest" in sys.modules INTERNAL_IPS = ["127.0.0.1"] +HTTPS = env.bool("HTTPS", default=True) + # force csrf tokens and cookies to be secure when in https -CSRF_COOKIE_SECURE = env.bool("HTTPS", default=True) +CSRF_COOKIE_SECURE = HTTPS CSRF_TRUSTED_ORIGINS = env.list("CSRF_TRUSTED_ORIGINS", default=[]) -SESSION_COOKIE_SECURE = env.bool("HTTPS", default=True) +SESSION_COOKIE_SECURE = HTTPS X_FRAME_OPTIONS = "SAMEORIGIN" ALLOWED_HOSTS = ["*"] From 2e1a849aff54c8410c83cb02c64c774a1055f688 Mon Sep 17 00:00:00 2001 From: Kenneth SOARES Date: Mon, 7 Apr 2025 19:15:16 +0200 Subject: [PATCH 2/4] modification du style du tooltip --- .../com/components/ics-calendar-index.ts | 4 +-- com/static/com/components/ics-calendar.scss | 35 ++++++++++++++++++- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/com/static/bundled/com/components/ics-calendar-index.ts b/com/static/bundled/com/components/ics-calendar-index.ts index 2befc97e..ea1cadc5 100644 --- a/com/static/bundled/com/components/ics-calendar-index.ts +++ b/com/static/bundled/com/components/ics-calendar-index.ts @@ -310,7 +310,7 @@ export class IcsCalendar extends inheritHtmlElement("div") { const button = event.target as HTMLButtonElement; button.classList.add("text-copy"); button.setAttribute( - "tooltip", + "data-tooltip", gettext("Calendar link copied to the clipboard"), ); navigator.clipboard.writeText( @@ -323,7 +323,7 @@ export class IcsCalendar extends inheritHtmlElement("div") { button.classList.remove("text-copied"); button.classList.add("text-copied"); button.classList.remove("text-copy"); - button.removeAttribute("tooltip"); + button.removeAttribute("data-tooltip"); }, 700); }, }, diff --git a/com/static/com/components/ics-calendar.scss b/com/static/com/components/ics-calendar.scss index bb0fea47..e0047842 100644 --- a/com/static/com/components/ics-calendar.scss +++ b/com/static/com/components/ics-calendar.scss @@ -22,6 +22,8 @@ ics-calendar { border: none; box-shadow: none; + overflow: visible; + z-index: 1; #event-details { z-index: 10; @@ -106,7 +108,7 @@ ics-calendar { button.text-copy, button.text-copy:focus, button.text-copy:hover { - background-color: green !important; + background-color: #67AE6E !important; transition: 200ms linear; } @@ -115,4 +117,35 @@ ics-calendar { button.text-copied:hover { transition: 200ms linear; } + + + + /* Tooltip styles */ + button[data-tooltip] { + position: relative; + cursor: pointer; + } + + button[data-tooltip]::after { + font-size: 10px; + content: attr(data-tooltip); + position: absolute; + bottom: 120%; /* Adjust this value to position the tooltip above the button */ + left: 50%; + transform: translateX(-50%); + background-color: #333; + color: #fff; + padding: 5px 10px; + border-radius: 5px; + white-space: nowrap; + opacity: 0; + transition: opacity 0.3s; + pointer-events: none; + z-index: 99999; + } + + button[data-tooltip]:hover::after, + button[data-tooltip]:focus::after { + opacity: 1; + } } \ No newline at end of file From 5de05c036058f8399ab45074062f177a263e9dc7 Mon Sep 17 00:00:00 2001 From: Sli Date: Tue, 8 Apr 2025 10:12:05 +0200 Subject: [PATCH 3/4] Introduce position attributes for tooltips --- .../com/components/ics-calendar-index.ts | 6 ++- com/static/com/components/ics-calendar.scss | 33 +--------------- core/static/core/style.scss | 39 +++++++++++++++---- 3 files changed, 38 insertions(+), 40 deletions(-) diff --git a/com/static/bundled/com/components/ics-calendar-index.ts b/com/static/bundled/com/components/ics-calendar-index.ts index ea1cadc5..1373c517 100644 --- a/com/static/bundled/com/components/ics-calendar-index.ts +++ b/com/static/bundled/com/components/ics-calendar-index.ts @@ -310,9 +310,10 @@ export class IcsCalendar extends inheritHtmlElement("div") { const button = event.target as HTMLButtonElement; button.classList.add("text-copy"); button.setAttribute( - "data-tooltip", + "tooltip", gettext("Calendar link copied to the clipboard"), ); + button.setAttribute("position", "top"); navigator.clipboard.writeText( new URL( await makeUrl(calendarCalendarInternal), @@ -323,7 +324,8 @@ export class IcsCalendar extends inheritHtmlElement("div") { button.classList.remove("text-copied"); button.classList.add("text-copied"); button.classList.remove("text-copy"); - button.removeAttribute("data-tooltip"); + button.removeAttribute("tooltip"); + button.removeAttribute("position"); }, 700); }, }, diff --git a/com/static/com/components/ics-calendar.scss b/com/static/com/components/ics-calendar.scss index e0047842..9cb5638e 100644 --- a/com/static/com/components/ics-calendar.scss +++ b/com/static/com/components/ics-calendar.scss @@ -22,8 +22,6 @@ ics-calendar { border: none; box-shadow: none; - overflow: visible; - z-index: 1; #event-details { z-index: 10; @@ -118,34 +116,7 @@ ics-calendar { transition: 200ms linear; } - - - /* Tooltip styles */ - button[data-tooltip] { - position: relative; - cursor: pointer; - } - - button[data-tooltip]::after { - font-size: 10px; - content: attr(data-tooltip); - position: absolute; - bottom: 120%; /* Adjust this value to position the tooltip above the button */ - left: 50%; - transform: translateX(-50%); - background-color: #333; - color: #fff; - padding: 5px 10px; - border-radius: 5px; - white-space: nowrap; - opacity: 0; - transition: opacity 0.3s; - pointer-events: none; - z-index: 99999; - } - - button[data-tooltip]:hover::after, - button[data-tooltip]:focus::after { - opacity: 1; + [tooltip]::before { + font-size: 10px; // this will overflow otherwise } } \ No newline at end of file diff --git a/core/static/core/style.scss b/core/static/core/style.scss index f064332a..9ee96b7e 100644 --- a/core/static/core/style.scss +++ b/core/static/core/style.scss @@ -51,26 +51,51 @@ body { [tooltip]::before { @include shadow; - opacity: 0; z-index: 1; + pointer-events: none; content: attr(tooltip); - background: hsl(219.6, 20.8%, 96%); - color: $black-color; + left: 50%; + transform: translateX(-50%); + background-color: #333; + color: #fff; border: 0.5px solid hsl(0, 0%, 50%); - ; border-radius: 5px; - padding: 5px; - top: 1em; + padding: 5px 10px; position: absolute; - margin-top: 5px; white-space: nowrap; + opacity: 0; transition: opacity 500ms ease-out; + top: 120%; // Put the tooltip under the element } [tooltip]:hover::before { opacity: 1; } +[position="top"][tooltip]::before { + top: initial; + bottom: 120%; +} + +[position="bottom"][tooltip]::before { + top: 120%; + bottom: initial; +} + +[position="left"][tooltip]::before { + top: initial; + bottom: 0%; + left: initial; + right: 65%; +} + +[position="right"][tooltip]::before { + top: initial; + bottom: 0%; + left: 150%; + right: initial; +} + .ib { display: inline-block; padding: 1px; From 8a381aed3839ca8c5e48c05d95574f47a2490014 Mon Sep 17 00:00:00 2001 From: Sli Date: Tue, 8 Apr 2025 11:54:19 +0200 Subject: [PATCH 4/4] Smooth animation --- .../com/components/ics-calendar-index.ts | 37 +++++++++++++------ com/static/com/components/ics-calendar.scss | 9 +++-- core/static/core/style.scss | 6 +++ locale/fr/LC_MESSAGES/djangojs.po | 6 +-- 4 files changed, 39 insertions(+), 19 deletions(-) diff --git a/com/static/bundled/com/components/ics-calendar-index.ts b/com/static/bundled/com/components/ics-calendar-index.ts index 1373c517..09336db5 100644 --- a/com/static/bundled/com/components/ics-calendar-index.ts +++ b/com/static/bundled/com/components/ics-calendar-index.ts @@ -44,7 +44,18 @@ export class IcsCalendar extends inheritHtmlElement("div") { return this.isMobile() ? "listMonth" : "dayGridMonth"; } - currentToolbar() { + currentFooterToolbar() { + if (this.isMobile()) { + return { + start: "", + center: "getCalendarLink", + end: "", + }; + } + return { start: "getCalendarLink", center: "", end: "" }; + } + + currentHeaderToolbar() { if (this.isMobile()) { return { left: "prev,next", @@ -309,11 +320,14 @@ export class IcsCalendar extends inheritHtmlElement("div") { click: async (event: Event) => { const button = event.target as HTMLButtonElement; button.classList.add("text-copy"); - button.setAttribute( - "tooltip", - gettext("Calendar link copied to the clipboard"), - ); - button.setAttribute("position", "top"); + if (!button.hasAttribute("position")) { + button.setAttribute("tooltip", gettext("Link copied")); + button.setAttribute("position", "top"); + button.setAttribute("no-hover", ""); + } + if (button.classList.contains("text-copied")) { + button.classList.remove("text-copied"); + } navigator.clipboard.writeText( new URL( await makeUrl(calendarCalendarInternal), @@ -324,21 +338,20 @@ export class IcsCalendar extends inheritHtmlElement("div") { button.classList.remove("text-copied"); button.classList.add("text-copied"); button.classList.remove("text-copy"); - button.removeAttribute("tooltip"); - button.removeAttribute("position"); - }, 700); + }, 1500); }, }, }, height: "auto", locale: this.locale, initialView: this.currentView(), - headerToolbar: this.currentToolbar(), - footerToolbar: { start: "getCalendarLink" }, + headerToolbar: this.currentHeaderToolbar(), + footerToolbar: this.currentFooterToolbar(), eventSources: await this.getEventSources(), windowResize: () => { this.calendar.changeView(this.currentView()); - this.calendar.setOption("headerToolbar", this.currentToolbar()); + this.calendar.setOption("headerToolbar", this.currentHeaderToolbar()); + this.calendar.setOption("footerToolbar", this.currentFooterToolbar()); }, eventClick: (event) => { // Avoid our popup to be deleted because we clicked outside of it diff --git a/com/static/com/components/ics-calendar.scss b/com/static/com/components/ics-calendar.scss index 9cb5638e..49713f82 100644 --- a/com/static/com/components/ics-calendar.scss +++ b/com/static/com/components/ics-calendar.scss @@ -107,16 +107,17 @@ ics-calendar { button.text-copy:focus, button.text-copy:hover { background-color: #67AE6E !important; - transition: 200ms linear; + transition: 500ms ease-in; } button.text-copied, button.text-copied:focus, button.text-copied:hover { - transition: 200ms linear; + transition: 500ms ease-out; } - [tooltip]::before { - font-size: 10px; // this will overflow otherwise + button.text-copied[tooltip]::before { + opacity: 0; + transition: opacity 500ms ease-out; } } \ No newline at end of file diff --git a/core/static/core/style.scss b/core/static/core/style.scss index 9ee96b7e..a87ed3a3 100644 --- a/core/static/core/style.scss +++ b/core/static/core/style.scss @@ -70,6 +70,12 @@ body { [tooltip]:hover::before { opacity: 1; + transition: opacity 500ms ease-in; +} + +[no-hover][tooltip]::before { + opacity: 1; + transition: opacity 500ms ease-in; } [position="top"][tooltip]::before { diff --git a/locale/fr/LC_MESSAGES/djangojs.po b/locale/fr/LC_MESSAGES/djangojs.po index e078509a..3693c144 100644 --- a/locale/fr/LC_MESSAGES/djangojs.po +++ b/locale/fr/LC_MESSAGES/djangojs.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-04-07 13:56+0200\n" +"POT-Creation-Date: 2025-04-08 11:42+0200\n" "PO-Revision-Date: 2024-09-17 11:54+0200\n" "Last-Translator: Sli \n" "Language-Team: AE info \n" @@ -38,8 +38,8 @@ msgid "Copy calendar link" msgstr "Copier le lien du calendrier" #: com/static/bundled/com/components/ics-calendar-index.ts -msgid "Calendar link copied to the clipboard" -msgstr "Lien du calendrier copié dans le presse papier" +msgid "Link copied" +msgstr "Lien copié" #: com/static/bundled/com/components/moderation-alert-index.ts #, javascript-format