From 6f48a9a151b933a8d614f45d83be85f330c9140d Mon Sep 17 00:00:00 2001 From: Sli Date: Thu, 5 Jun 2025 19:57:25 +0200 Subject: [PATCH 01/33] Fix bad css scoping on accordions --- core/static/core/accordion.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/static/core/accordion.scss b/core/static/core/accordion.scss index 07793a7a..abdbba02 100644 --- a/core/static/core/accordion.scss +++ b/core/static/core/accordion.scss @@ -33,7 +33,7 @@ details.accordion>summary::before { font-size: 0.8em; } -details[open]>summary::before { +details[open].accordion>summary::before { font-family: FontAwesome; content: '\f0d7'; } From 4774a7b741d65dcf8292939bb16953898c74d718 Mon Sep 17 00:00:00 2001 From: Sli Date: Thu, 5 Jun 2025 20:37:58 +0200 Subject: [PATCH 02/33] Improve accordion animation --- core/static/bundled/core/accordion-index.ts | 16 ++++++++++++---- core/static/core/accordion.scss | 11 ++++++++--- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/core/static/bundled/core/accordion-index.ts b/core/static/bundled/core/accordion-index.ts index 39e37564..d2007767 100644 --- a/core/static/bundled/core/accordion-index.ts +++ b/core/static/bundled/core/accordion-index.ts @@ -1,11 +1,19 @@ -const setMaxHeight = (element: HTMLDetailsElement) => { - element.setAttribute("style", `max-height: ${element.scrollHeight}px`); +const updateMaxHeight = (element: HTMLDetailsElement) => { + const content = element.querySelector(".accordion-content") as HTMLElement | null; + if (!content) { + return; + } + if (element.hasAttribute("open")) { + content.style.maxHeight = `${content.scrollHeight}px`; + } else { + content.style.maxHeight = "0px"; + } }; // Initialize max-height at load window.addEventListener("DOMContentLoaded", () => { for (const el of document.querySelectorAll("details.accordion")) { - setMaxHeight(el as HTMLDetailsElement); + updateMaxHeight(el as HTMLDetailsElement); } }); @@ -16,7 +24,7 @@ new MutationObserver((mutations: MutationRecord[]) => { if (target.tagName !== "DETAILS" || !target.classList.contains("accordion")) { continue; } - setMaxHeight(target); + updateMaxHeight(target); } }).observe(document.body, { attributes: true, diff --git a/core/static/core/accordion.scss b/core/static/core/accordion.scss index abdbba02..17443e5e 100644 --- a/core/static/core/accordion.scss +++ b/core/static/core/accordion.scss @@ -44,12 +44,17 @@ details.accordion>.accordion-content { background: #ffffff; color: #333333; padding: 1em 2.2em; - overflow: auto; border: 1px solid #dddddd; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; + opacity: 0; + overflow: hidden; } -details.accordion { - transition: max-height 300ms ease-in-out; +details[open].accordion>.accordion-content { + opacity: 1; + // Setting a transition on all states of the content + // will create a strange behavior where the transition + // continues without being shown, creating inconsistenties + transition: all 300ms ease-out; } \ No newline at end of file From 36d4a02a459b4f91e7bd073866743fb96d046941 Mon Sep 17 00:00:00 2001 From: Sli Date: Tue, 10 Jun 2025 15:06:59 +0200 Subject: [PATCH 03/33] Remove js size animation and only use the opacity one --- core/static/bundled/core/accordion-index.ts | 33 --------------------- core/templates/core/base.jinja | 1 - 2 files changed, 34 deletions(-) delete mode 100644 core/static/bundled/core/accordion-index.ts diff --git a/core/static/bundled/core/accordion-index.ts b/core/static/bundled/core/accordion-index.ts deleted file mode 100644 index d2007767..00000000 --- a/core/static/bundled/core/accordion-index.ts +++ /dev/null @@ -1,33 +0,0 @@ -const updateMaxHeight = (element: HTMLDetailsElement) => { - const content = element.querySelector(".accordion-content") as HTMLElement | null; - if (!content) { - return; - } - if (element.hasAttribute("open")) { - content.style.maxHeight = `${content.scrollHeight}px`; - } else { - content.style.maxHeight = "0px"; - } -}; - -// Initialize max-height at load -window.addEventListener("DOMContentLoaded", () => { - for (const el of document.querySelectorAll("details.accordion")) { - updateMaxHeight(el as HTMLDetailsElement); - } -}); - -// Accordion opened -new MutationObserver((mutations: MutationRecord[]) => { - for (const mutation of mutations) { - const target = mutation.target as HTMLDetailsElement; - if (target.tagName !== "DETAILS" || !target.classList.contains("accordion")) { - continue; - } - updateMaxHeight(target); - } -}).observe(document.body, { - attributes: true, - attributeFilter: ["open"], - subtree: true, -}); diff --git a/core/templates/core/base.jinja b/core/templates/core/base.jinja index 0d476689..a3afb49f 100644 --- a/core/templates/core/base.jinja +++ b/core/templates/core/base.jinja @@ -27,7 +27,6 @@ - From 7b8102c242d72d3747ff6284179873bcbe93bf8e Mon Sep 17 00:00:00 2001 From: Sli Date: Tue, 10 Jun 2025 23:08:04 +0200 Subject: [PATCH 04/33] Add lit-html and use it for ics-calendar popups --- .../com/components/ics-calendar-index.ts | 113 +++---- package-lock.json | 302 +++++++++++------- package.json | 1 + 3 files changed, 237 insertions(+), 179 deletions(-) diff --git a/com/static/bundled/com/components/ics-calendar-index.ts b/com/static/bundled/com/components/ics-calendar-index.ts index ad85280a..bc2ec9b4 100644 --- a/com/static/bundled/com/components/ics-calendar-index.ts +++ b/com/static/bundled/com/components/ics-calendar-index.ts @@ -7,6 +7,7 @@ import frLocale from "@fullcalendar/core/locales/fr"; import dayGridPlugin from "@fullcalendar/daygrid"; import iCalendarPlugin from "@fullcalendar/icalendar"; import listPlugin from "@fullcalendar/list"; +import { type HTMLTemplateResult, html, render } from "lit-html"; import { calendarCalendarInternal, calendarCalendarUnpublished, @@ -176,29 +177,25 @@ export class IcsCalendar extends inheritHtmlElement("div") { oldPopup.remove(); } - const makePopupInfo = (info: HTMLElement, iconClass: string) => { - const row = document.createElement("div"); - const icon = document.createElement("i"); - - row.setAttribute("class", "event-details-row"); - - icon.setAttribute("class", `event-detail-row-icon fa-xl ${iconClass}`); - - row.appendChild(icon); - row.appendChild(info); - - return row; + const makePopupInfo = (info: HTMLTemplateResult, iconClass: string) => { + return html` +
+ + ${info} +
+ `; }; const makePopupTitle = (event: EventImpl) => { - const row = document.createElement("div"); - row.innerHTML = ` -

- ${event.title} -

- - ${this.formatDate(event.start)} - ${this.formatDate(event.end)} - + const row = html` +
+

+ ${event.title} +

+ + ${this.formatDate(event.start)} - ${this.formatDate(event.end)} + +
`; return makePopupInfo( row, @@ -210,9 +207,11 @@ export class IcsCalendar extends inheritHtmlElement("div") { if (event.extendedProps.location === null) { return null; } - const info = document.createElement("div"); - info.innerText = event.extendedProps.location; - + const info = html` +
+ ${event.extendedProps.location} +
+ `; return makePopupInfo(info, "fa-solid fa-location-dot"); }; @@ -220,10 +219,7 @@ export class IcsCalendar extends inheritHtmlElement("div") { if (event.url === "") { return null; } - const url = document.createElement("a"); - url.href = event.url; - url.textContent = gettext("More info"); - + const url = html`${gettext("More info")}`; return makePopupInfo(url, "fa-solid fa-link"); }; @@ -232,64 +228,59 @@ export class IcsCalendar extends inheritHtmlElement("div") { return null; } const newsId = this.getNewsId(event); - const div = document.createElement("div"); + const buttons = [] as HTMLTemplateResult[]; + if (this.canModerate) { if (event.source.internalEventSource.ui.classNames.includes("unpublished")) { - const button = document.createElement("button"); - button.innerHTML = `${gettext("Publish")}`; - button.setAttribute("class", "btn btn-green"); - button.onclick = () => { - this.publishNews(newsId); - }; - div.appendChild(button); + const button = html` + + `; + buttons.push(button); } else { - const button = document.createElement("button"); - button.innerHTML = `${gettext("Unpublish")}`; - button.setAttribute("class", "btn btn-orange"); - button.onclick = () => { - this.unpublishNews(newsId); - }; - div.appendChild(button); + const button = html` + + `; + buttons.push(button); } } if (this.canDelete) { - const button = document.createElement("button"); - button.innerHTML = `${gettext("Delete")}`; - button.setAttribute("class", "btn btn-red"); - button.onclick = () => { - this.deleteNews(newsId); - }; - div.appendChild(button); + const button = html` + + `; + buttons.push(button); } - return makePopupInfo(div, "fa-solid fa-toolbox"); + return makePopupInfo(html`
${buttons}
`, "fa-solid fa-toolbox"); }; // Create new popup - const popup = document.createElement("div"); - const popupContainer = document.createElement("div"); - - popup.setAttribute("id", "event-details"); - popupContainer.setAttribute("class", "event-details-container"); - - popupContainer.appendChild(makePopupTitle(event.event)); + const infos = [] as HTMLTemplateResult[]; + infos.push(makePopupTitle(event.event)); const location = makePopupLocation(event.event); if (location !== null) { - popupContainer.appendChild(location); + infos.push(location); } const url = makePopupUrl(event.event); if (url !== null) { - popupContainer.appendChild(url); + infos.push(url); } const tools = makePopupTools(event.event); if (tools !== null) { - popupContainer.appendChild(tools); + infos.push(tools); } - popup.appendChild(popupContainer); + const popup = document.createElement("div"); + popup.setAttribute("id", "event-details"); + render(html`
${infos}
`, popup); // We can't just add the element relative to the one we want to appear under // Otherwise, it either gets clipped by the boundaries of the calendar or resize cells diff --git a/package-lock.json b/package-lock.json index 87d4bc5c..0aea6a29 100644 --- a/package-lock.json +++ b/package-lock.json @@ -34,6 +34,7 @@ "jquery": "^3.7.1", "jquery-ui": "^1.14.0", "js-cookie": "^3.0.5", + "lit-html": "^3.3.0", "native-file-system-adapter": "^3.0.1", "three": "^0.172.0", "three-spritetext": "^1.9.0", @@ -79,15 +80,15 @@ "integrity": "sha512-Uu3CYSvFrNdDkYKEaEKHAk0decaxVFlSSqf50Okte/9vJjO2rESzPF1ngQjS9H1aX45RIXRGMYOXJ/LPDFwUdQ==" }, "node_modules/@babel/code-frame": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", - "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.25.9", + "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" + "picocolors": "^1.1.1" }, "engines": { "node": ">=6.9.0" @@ -358,9 +359,9 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", - "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", "dev": true, "license": "MIT", "engines": { @@ -368,9 +369,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", - "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", "dev": true, "license": "MIT", "engines": { @@ -403,27 +404,27 @@ } }, "node_modules/@babel/helpers": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.0.tgz", - "integrity": "sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==", + "version": "7.27.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.6.tgz", + "integrity": "sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug==", "dev": true, "license": "MIT", "dependencies": { - "@babel/template": "^7.25.9", - "@babel/types": "^7.26.0" + "@babel/template": "^7.27.2", + "@babel/types": "^7.27.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.26.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.5.tgz", - "integrity": "sha512-SRJ4jYmXRqV1/Xc+TIVG84WjHBXKlxO9sHQnA2Pf12QQEAp1LOh6kDzNHXcUnbH1QI0FDoPPVOt+vyUDucxpaw==", + "version": "7.27.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.5.tgz", + "integrity": "sha512-OsQd175SxWkGlzbny8J3K8TnnDD0N3lrIUtB92xwyRpzaenGZhxDvxN/JgU00U3CDZNj9tPuDJ5H0WS4Nt3vKg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.26.5" + "@babel/types": "^7.27.3" }, "bin": { "parser": "bin/babel-parser.js" @@ -1527,15 +1528,15 @@ } }, "node_modules/@babel/template": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz", - "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==", + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.25.9", - "@babel/parser": "^7.25.9", - "@babel/types": "^7.25.9" + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1561,14 +1562,14 @@ } }, "node_modules/@babel/types": { - "version": "7.26.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.5.tgz", - "integrity": "sha512-L6mZmwFDK6Cjh1nRCLXpa6no13ZIioJDz7mdkzHv399pThrTa/k0nUlNaenOeh2kWu/iaOQYElEpKPUswUa9Vg==", + "version": "7.27.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.6.tgz", + "integrity": "sha512-ETyHEk2VHHvl9b9jZP5IHPavHYk57EhanlRRuae9XCpb/j5bDCbPPMOBfCWhnl/7EDJz0jEMCi/RhccCE8r1+Q==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9" + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -2469,9 +2470,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.30.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.30.1.tgz", - "integrity": "sha512-pSWY+EVt3rJ9fQ3IqlrEUtXh3cGqGtPDH1FQlNZehO2yYxCHEX1SPsz1M//NXwYfbTlcKr9WObLnJX9FsS9K1Q==", + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.42.0.tgz", + "integrity": "sha512-gldmAyS9hpj+H6LpRNlcjQWbuKUtb94lodB9uCz71Jm+7BxK1VIOo7y62tZZwxhA7j1ylv/yQz080L5WkS+LoQ==", "cpu": [ "arm" ], @@ -2483,9 +2484,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.30.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.30.1.tgz", - "integrity": "sha512-/NA2qXxE3D/BRjOJM8wQblmArQq1YoBVJjrjoTSBS09jgUisq7bqxNHJ8kjCHeV21W/9WDGwJEWSN0KQ2mtD/w==", + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.42.0.tgz", + "integrity": "sha512-bpRipfTgmGFdCZDFLRvIkSNO1/3RGS74aWkJJTFJBH7h3MRV4UijkaEUeOMbi9wxtxYmtAbVcnMtHTPBhLEkaw==", "cpu": [ "arm64" ], @@ -2497,9 +2498,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.30.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.30.1.tgz", - "integrity": "sha512-r7FQIXD7gB0WJ5mokTUgUWPl0eYIH0wnxqeSAhuIwvnnpjdVB8cRRClyKLQr7lgzjctkbp5KmswWszlwYln03Q==", + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.42.0.tgz", + "integrity": "sha512-JxHtA081izPBVCHLKnl6GEA0w3920mlJPLh89NojpU2GsBSB6ypu4erFg/Wx1qbpUbepn0jY4dVWMGZM8gplgA==", "cpu": [ "arm64" ], @@ -2511,9 +2512,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.30.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.30.1.tgz", - "integrity": "sha512-x78BavIwSH6sqfP2xeI1hd1GpHL8J4W2BXcVM/5KYKoAD3nNsfitQhvWSw+TFtQTLZ9OmlF+FEInEHyubut2OA==", + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.42.0.tgz", + "integrity": "sha512-rv5UZaWVIJTDMyQ3dCEK+m0SAn6G7H3PRc2AZmExvbDvtaDc+qXkei0knQWcI3+c9tEs7iL/4I4pTQoPbNL2SA==", "cpu": [ "x64" ], @@ -2525,9 +2526,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.30.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.30.1.tgz", - "integrity": "sha512-HYTlUAjbO1z8ywxsDFWADfTRfTIIy/oUlfIDmlHYmjUP2QRDTzBuWXc9O4CXM+bo9qfiCclmHk1x4ogBjOUpUQ==", + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.42.0.tgz", + "integrity": "sha512-fJcN4uSGPWdpVmvLuMtALUFwCHgb2XiQjuECkHT3lWLZhSQ3MBQ9pq+WoWeJq2PrNxr9rPM1Qx+IjyGj8/c6zQ==", "cpu": [ "arm64" ], @@ -2539,9 +2540,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.30.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.30.1.tgz", - "integrity": "sha512-1MEdGqogQLccphhX5myCJqeGNYTNcmTyaic9S7CG3JhwuIByJ7J05vGbZxsizQthP1xpVx7kd3o31eOogfEirw==", + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.42.0.tgz", + "integrity": "sha512-CziHfyzpp8hJpCVE/ZdTizw58gr+m7Y2Xq5VOuCSrZR++th2xWAz4Nqk52MoIIrV3JHtVBhbBsJcAxs6NammOQ==", "cpu": [ "x64" ], @@ -2553,9 +2554,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.30.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.30.1.tgz", - "integrity": "sha512-PaMRNBSqCx7K3Wc9QZkFx5+CX27WFpAMxJNiYGAXfmMIKC7jstlr32UhTgK6T07OtqR+wYlWm9IxzennjnvdJg==", + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.42.0.tgz", + "integrity": "sha512-UsQD5fyLWm2Fe5CDM7VPYAo+UC7+2Px4Y+N3AcPh/LdZu23YcuGPegQly++XEVaC8XUTFVPscl5y5Cl1twEI4A==", "cpu": [ "arm" ], @@ -2567,9 +2568,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.30.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.30.1.tgz", - "integrity": "sha512-B8Rcyj9AV7ZlEFqvB5BubG5iO6ANDsRKlhIxySXcF1axXYUyqwBok+XZPgIYGBgs7LDXfWfifxhw0Ik57T0Yug==", + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.42.0.tgz", + "integrity": "sha512-/i8NIrlgc/+4n1lnoWl1zgH7Uo0XK5xK3EDqVTf38KvyYgCU/Rm04+o1VvvzJZnVS5/cWSd07owkzcVasgfIkQ==", "cpu": [ "arm" ], @@ -2581,9 +2582,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.30.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.30.1.tgz", - "integrity": "sha512-hqVyueGxAj3cBKrAI4aFHLV+h0Lv5VgWZs9CUGqr1z0fZtlADVV1YPOij6AhcK5An33EXaxnDLmJdQikcn5NEw==", + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.42.0.tgz", + "integrity": "sha512-eoujJFOvoIBjZEi9hJnXAbWg+Vo1Ov8n/0IKZZcPZ7JhBzxh2A+2NFyeMZIRkY9iwBvSjloKgcvnjTbGKHE44Q==", "cpu": [ "arm64" ], @@ -2595,9 +2596,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.30.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.30.1.tgz", - "integrity": "sha512-i4Ab2vnvS1AE1PyOIGp2kXni69gU2DAUVt6FSXeIqUCPIR3ZlheMW3oP2JkukDfu3PsexYRbOiJrY+yVNSk9oA==", + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.42.0.tgz", + "integrity": "sha512-/3NrcOWFSR7RQUQIuZQChLND36aTU9IYE4j+TB40VU78S+RA0IiqHR30oSh6P1S9f9/wVOenHQnacs/Byb824g==", "cpu": [ "arm64" ], @@ -2609,9 +2610,9 @@ ] }, "node_modules/@rollup/rollup-linux-loongarch64-gnu": { - "version": "4.30.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.30.1.tgz", - "integrity": "sha512-fARcF5g296snX0oLGkVxPmysetwUk2zmHcca+e9ObOovBR++9ZPOhqFUM61UUZ2EYpXVPN1redgqVoBB34nTpQ==", + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.42.0.tgz", + "integrity": "sha512-O8AplvIeavK5ABmZlKBq9/STdZlnQo7Sle0LLhVA7QT+CiGpNVe197/t8Aph9bhJqbDVGCHpY2i7QyfEDDStDg==", "cpu": [ "loong64" ], @@ -2623,9 +2624,9 @@ ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.30.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.30.1.tgz", - "integrity": "sha512-GLrZraoO3wVT4uFXh67ElpwQY0DIygxdv0BNW9Hkm3X34wu+BkqrDrkcsIapAY+N2ATEbvak0XQ9gxZtCIA5Rw==", + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.42.0.tgz", + "integrity": "sha512-6Qb66tbKVN7VyQrekhEzbHRxXXFFD8QKiFAwX5v9Xt6FiJ3BnCVBuyBxa2fkFGqxOCSGGYNejxd8ht+q5SnmtA==", "cpu": [ "ppc64" ], @@ -2637,9 +2638,23 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.30.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.30.1.tgz", - "integrity": "sha512-0WKLaAUUHKBtll0wvOmh6yh3S0wSU9+yas923JIChfxOaaBarmb/lBKPF0w/+jTVozFnOXJeRGZ8NvOxvk/jcw==", + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.42.0.tgz", + "integrity": "sha512-KQETDSEBamQFvg/d8jajtRwLNBlGc3aKpaGiP/LvEbnmVUKlFta1vqJqTrvPtsYsfbE/DLg5CC9zyXRX3fnBiA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.42.0.tgz", + "integrity": "sha512-qMvnyjcU37sCo/tuC+JqeDKSuukGAd+pVlRl/oyDbkvPJ3awk6G6ua7tyum02O3lI+fio+eM5wsVd66X0jQtxw==", "cpu": [ "riscv64" ], @@ -2651,9 +2666,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.30.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.30.1.tgz", - "integrity": "sha512-GWFs97Ruxo5Bt+cvVTQkOJ6TIx0xJDD/bMAOXWJg8TCSTEK8RnFeOeiFTxKniTc4vMIaWvCplMAFBt9miGxgkA==", + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.42.0.tgz", + "integrity": "sha512-I2Y1ZUgTgU2RLddUHXTIgyrdOwljjkmcZ/VilvaEumtS3Fkuhbw4p4hgHc39Ypwvo2o7sBFNl2MquNvGCa55Iw==", "cpu": [ "s390x" ], @@ -2665,9 +2680,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.30.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.30.1.tgz", - "integrity": "sha512-UtgGb7QGgXDIO+tqqJ5oZRGHsDLO8SlpE4MhqpY9Llpzi5rJMvrK6ZGhsRCST2abZdBqIBeXW6WPD5fGK5SDwg==", + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.42.0.tgz", + "integrity": "sha512-Gfm6cV6mj3hCUY8TqWa63DB8Mx3NADoFwiJrMpoZ1uESbK8FQV3LXkhfry+8bOniq9pqY1OdsjFWNsSbfjPugw==", "cpu": [ "x64" ], @@ -2679,9 +2694,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.30.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.30.1.tgz", - "integrity": "sha512-V9U8Ey2UqmQsBT+xTOeMzPzwDzyXmnAoO4edZhL7INkwQcaW1Ckv3WJX3qrrp/VHaDkEWIBWhRwP47r8cdrOow==", + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.42.0.tgz", + "integrity": "sha512-g86PF8YZ9GRqkdi0VoGlcDUb4rYtQKyTD1IVtxxN4Hpe7YqLBShA7oHMKU6oKTCi3uxwW4VkIGnOaH/El8de3w==", "cpu": [ "x64" ], @@ -2693,9 +2708,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.30.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.30.1.tgz", - "integrity": "sha512-WabtHWiPaFF47W3PkHnjbmWawnX/aE57K47ZDT1BXTS5GgrBUEpvOzq0FI0V/UYzQJgdb8XlhVNH8/fwV8xDjw==", + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.42.0.tgz", + "integrity": "sha512-+axkdyDGSp6hjyzQ5m1pgcvQScfHnMCcsXkx8pTgy/6qBmWVhtRVlgxjWwDp67wEXXUr0x+vD6tp5W4x6V7u1A==", "cpu": [ "arm64" ], @@ -2707,9 +2722,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.30.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.30.1.tgz", - "integrity": "sha512-pxHAU+Zv39hLUTdQQHUVHf4P+0C47y/ZloorHpzs2SXMRqeAWmGghzAhfOlzFHHwjvgokdFAhC4V+6kC1lRRfw==", + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.42.0.tgz", + "integrity": "sha512-F+5J9pelstXKwRSDq92J0TEBXn2nfUrQGg+HK1+Tk7VOL09e0gBqUHugZv7SW4MGrYj41oNCUe3IKCDGVlis2g==", "cpu": [ "ia32" ], @@ -2721,9 +2736,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.30.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.30.1.tgz", - "integrity": "sha512-D6qjsXGcvhTjv0kI4fU8tUuBDF/Ueee4SVX79VfNDXZa64TfCW1Slkb6Z7O1p7vflqZjcmOVdZlqf8gvJxc6og==", + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.42.0.tgz", + "integrity": "sha512-LpHiJRwkaVz/LqjHjK8LCi8osq7elmpwujwbXKNW88bM8eeGxavJIKKjkjpMHAh/2xfnrt1ZSnhTv41WYUHYmA==", "cpu": [ "x64" ], @@ -2832,9 +2847,9 @@ } }, "node_modules/@types/estree": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", - "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", + "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", "license": "MIT" }, "node_modules/@types/jquery": { @@ -2876,6 +2891,12 @@ "@types/estree": "*" } }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "license": "MIT" + }, "node_modules/@vue/reactivity": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.1.5.tgz", @@ -3833,6 +3854,21 @@ "reusify": "^1.0.4" } }, + "node_modules/fdir": { + "version": "6.4.6", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz", + "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, "node_modules/fetch-blob": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", @@ -4415,6 +4451,15 @@ "integrity": "sha512-WUNxuO7O79TEkxCj6OIaK5TJBkaWaR/IKNTakgV9PwDn+mrr63MLHed34AcE2yTaDntgO6l0zGFIzhcoTeroTA==", "license": "EPL-1.0" }, + "node_modules/lit-html": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-3.3.0.tgz", + "integrity": "sha512-RHoswrFAxY2d8Cf2mm4OZ1DgzCoBKUKSPvA1fhtSELxUERq2aQQ2h05pO9j81gS1o7RIRJ+CePLogfyahwmynw==", + "license": "BSD-3-Clause", + "dependencies": { + "@types/trusted-types": "^2.0.2" + } + }, "node_modules/lodash-es": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", @@ -5173,13 +5218,13 @@ } }, "node_modules/rollup": { - "version": "4.30.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.30.1.tgz", - "integrity": "sha512-mlJ4glW020fPuLi7DkM/lN97mYEZGWeqBnrljzN0gs7GLctqX3lNWxKQ7Gl712UAX+6fog/L3jh4gb7R6aVi3w==", + "version": "4.42.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.42.0.tgz", + "integrity": "sha512-LW+Vse3BJPyGJGAJt1j8pWDKPd73QM8cRXYK1IxOBgL2AGLu7Xd2YOW0M2sLUBCkF5MshXXtMApyEAEzMVMsnw==", "dev": true, "license": "MIT", "dependencies": { - "@types/estree": "1.0.6" + "@types/estree": "1.0.7" }, "bin": { "rollup": "dist/bin/rollup" @@ -5189,25 +5234,26 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.30.1", - "@rollup/rollup-android-arm64": "4.30.1", - "@rollup/rollup-darwin-arm64": "4.30.1", - "@rollup/rollup-darwin-x64": "4.30.1", - "@rollup/rollup-freebsd-arm64": "4.30.1", - "@rollup/rollup-freebsd-x64": "4.30.1", - "@rollup/rollup-linux-arm-gnueabihf": "4.30.1", - "@rollup/rollup-linux-arm-musleabihf": "4.30.1", - "@rollup/rollup-linux-arm64-gnu": "4.30.1", - "@rollup/rollup-linux-arm64-musl": "4.30.1", - "@rollup/rollup-linux-loongarch64-gnu": "4.30.1", - "@rollup/rollup-linux-powerpc64le-gnu": "4.30.1", - "@rollup/rollup-linux-riscv64-gnu": "4.30.1", - "@rollup/rollup-linux-s390x-gnu": "4.30.1", - "@rollup/rollup-linux-x64-gnu": "4.30.1", - "@rollup/rollup-linux-x64-musl": "4.30.1", - "@rollup/rollup-win32-arm64-msvc": "4.30.1", - "@rollup/rollup-win32-ia32-msvc": "4.30.1", - "@rollup/rollup-win32-x64-msvc": "4.30.1", + "@rollup/rollup-android-arm-eabi": "4.42.0", + "@rollup/rollup-android-arm64": "4.42.0", + "@rollup/rollup-darwin-arm64": "4.42.0", + "@rollup/rollup-darwin-x64": "4.42.0", + "@rollup/rollup-freebsd-arm64": "4.42.0", + "@rollup/rollup-freebsd-x64": "4.42.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.42.0", + "@rollup/rollup-linux-arm-musleabihf": "4.42.0", + "@rollup/rollup-linux-arm64-gnu": "4.42.0", + "@rollup/rollup-linux-arm64-musl": "4.42.0", + "@rollup/rollup-linux-loongarch64-gnu": "4.42.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.42.0", + "@rollup/rollup-linux-riscv64-gnu": "4.42.0", + "@rollup/rollup-linux-riscv64-musl": "4.42.0", + "@rollup/rollup-linux-s390x-gnu": "4.42.0", + "@rollup/rollup-linux-x64-gnu": "4.42.0", + "@rollup/rollup-linux-x64-musl": "4.42.0", + "@rollup/rollup-win32-arm64-msvc": "4.42.0", + "@rollup/rollup-win32-ia32-msvc": "4.42.0", + "@rollup/rollup-win32-x64-msvc": "4.42.0", "fsevents": "~2.3.2" } }, @@ -5563,6 +5609,23 @@ "integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==", "license": "MIT" }, + "node_modules/tinyglobby": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", + "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.4.4", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, "node_modules/tmp": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", @@ -5731,15 +5794,18 @@ } }, "node_modules/vite": { - "version": "6.2.5", - "resolved": "https://registry.npmjs.org/vite/-/vite-6.2.5.tgz", - "integrity": "sha512-j023J/hCAa4pRIUH6J9HemwYfjB5llR2Ps0CWeikOtdR8+pAURAk0DoJC5/mm9kd+UgdnIy7d6HE4EAvlYhPhA==", + "version": "6.3.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz", + "integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==", "dev": true, "license": "MIT", "dependencies": { "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", "postcss": "^8.5.3", - "rollup": "^4.30.1" + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" }, "bin": { "vite": "bin/vite.js" diff --git a/package.json b/package.json index 22b1d2c1..474e0cc6 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,7 @@ "jquery": "^3.7.1", "jquery-ui": "^1.14.0", "js-cookie": "^3.0.5", + "lit-html": "^3.3.0", "native-file-system-adapter": "^3.0.1", "three": "^0.172.0", "three-spritetext": "^1.9.0", From 96f91138dd0ffe5320178fad7f51b9f5468df3de Mon Sep 17 00:00:00 2001 From: Sli Date: Wed, 11 Jun 2025 00:20:46 +0200 Subject: [PATCH 05/33] Fix accordion transition on chrome --- core/static/core/accordion.scss | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/core/static/core/accordion.scss b/core/static/core/accordion.scss index 17443e5e..c19e10ca 100644 --- a/core/static/core/accordion.scss +++ b/core/static/core/accordion.scss @@ -57,4 +57,17 @@ details[open].accordion>.accordion-content { // will create a strange behavior where the transition // continues without being shown, creating inconsistenties transition: all 300ms ease-out; +} + +// For some reason, it's still not enough for chrome +// We repeat duplicate the transition again but only for chrome +// And since everything with ::details-content crashes firefox +// we put this at the end so it doesn't break the previous code +details.accordion::details-content { + opacity: 0; +} + +details[open].accordion::details-content { + opacity: 1; + transition: all 300ms ease-out; } \ No newline at end of file From 4c67bb1e2a3502b328006303dea3589456d52f92 Mon Sep 17 00:00:00 2001 From: Sli Date: Wed, 11 Jun 2025 01:21:53 +0200 Subject: [PATCH 06/33] Support animation with calc-size and detect browser features --- core/static/core/accordion.scss | 52 +++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 18 deletions(-) diff --git a/core/static/core/accordion.scss b/core/static/core/accordion.scss index c19e10ca..4f40ba71 100644 --- a/core/static/core/accordion.scss +++ b/core/static/core/accordion.scss @@ -38,8 +38,6 @@ details[open].accordion>summary::before { content: '\f0d7'; } -// ::details-content isn't available on firefox yet -// we use .accordion-content as a workaround details.accordion>.accordion-content { background: #ffffff; color: #333333; @@ -47,27 +45,45 @@ details.accordion>.accordion-content { border: 1px solid #dddddd; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; - opacity: 0; overflow: hidden; } -details[open].accordion>.accordion-content { - opacity: 1; - // Setting a transition on all states of the content - // will create a strange behavior where the transition - // continues without being shown, creating inconsistenties - transition: all 300ms ease-out; +@mixin animation($selector) { + details.accordion#{$selector} { + opacity: 0; + + @supports (max-height: calc-size(max-content, size)) { + max-height: 0px; + } + } + + details[open].accordion#{$selector} { + opacity: 1; + + // Setting a transition on all states of the content + // will create a strange behavior where the transition + // continues without being shown, creating inconsistenties + transition: all 300ms ease-out; + + @supports (max-height: calc-size(max-content, size)) { + max-height: calc-size(max-content, size); + } + } } -// For some reason, it's still not enough for chrome -// We repeat duplicate the transition again but only for chrome -// And since everything with ::details-content crashes firefox -// we put this at the end so it doesn't break the previous code -details.accordion::details-content { - opacity: 0; +// ::details-content isn't available on firefox yet +// we use .accordion-content as a workaround +// But we need to use ::details-content for chrome because it's +// not working correctly otherwise +// it only happen in chrome, not safari or firefox +// Note: `selector` is not supported by scss so we comment it out to +// avoid compiling it and sending it straight to the css +// This is a trick that comes from here : +// https://stackoverflow.com/questions/62665318/using-supports-selector-despite-sass-not-supporting-it +@supports #{'selector(details::details-content)'} { + @include animation("::details-content") } -details[open].accordion::details-content { - opacity: 1; - transition: all 300ms ease-out; +@supports #{'not selector(details::details-content)'} { + @include animation(">.accordion-content") } \ No newline at end of file From c07f0c33cbff66270063337e4a2c7a5ad018c01d Mon Sep 17 00:00:00 2001 From: imperosol Date: Wed, 11 Jun 2025 17:38:21 +0200 Subject: [PATCH 07/33] fix permanent notification callback --- com/models.py | 7 +++++-- com/tests/test_notifications.py | 23 +++++++++++++++++++++++ core/models.py | 20 +++++++++++--------- 3 files changed, 39 insertions(+), 11 deletions(-) create mode 100644 com/tests/test_notifications.py diff --git a/com/models.py b/com/models.py index c7e66515..b6253619 100644 --- a/com/models.py +++ b/com/models.py @@ -160,9 +160,12 @@ class News(models.Model): ) -def news_notification_callback(notif): +def news_notification_callback(notif: Notification): + # the NewsDate linked to the News + # which creation triggered this callback may not exist yet, + # so it's important to filter by "not past date" rather than by "future date" count = News.objects.filter( - dates__start_date__gt=timezone.now(), is_published=False + ~Q(dates__start_date__gt=timezone.now()), is_published=False ).count() if count: notif.viewed = False diff --git a/com/tests/test_notifications.py b/com/tests/test_notifications.py new file mode 100644 index 00000000..fa541efb --- /dev/null +++ b/com/tests/test_notifications.py @@ -0,0 +1,23 @@ +import pytest +from django.conf import settings +from model_bakery import baker + +from com.models import News +from core.models import Group, Notification, User + + +@pytest.mark.django_db +def test_notification_created(): + com_admin_group = Group.objects.get(pk=settings.SITH_GROUP_COM_ADMIN_ID) + com_admin_group.users.all().delete() + Notification.objects.all().delete() + com_admin = baker.make(User, groups=[com_admin_group]) + for i in range(2): + # news notifications are permanent, so the notification created + # during the first iteration should be reused during the second one. + baker.make(News) + notifications = list(Notification.objects.all()) + assert len(notifications) == 1 + assert notifications[0].user == com_admin + assert notifications[0].type == "NEWS_MODERATION" + assert notifications[0].param == str(i + 1) diff --git a/core/models.py b/core/models.py index b71f5408..0a7a5e37 100644 --- a/core/models.py +++ b/core/models.py @@ -23,7 +23,6 @@ # from __future__ import annotations -import importlib import logging import os import string @@ -51,6 +50,7 @@ from django.urls import reverse from django.utils import timezone from django.utils.functional import cached_property from django.utils.html import escape +from django.utils.module_loading import import_string from django.utils.timezone import localdate, now from django.utils.translation import gettext_lazy as _ from phonenumber_field.modelfields import PhoneNumberField @@ -1452,22 +1452,24 @@ class Notification(models.Model): return self.get_type_display() def save(self, *args, **kwargs): - if not self.id and self.type in settings.SITH_PERMANENT_NOTIFICATIONS: + if self._state.adding and self.type in settings.SITH_PERMANENT_NOTIFICATIONS: old_notif = self.user.notifications.filter(type=self.type).last() if old_notif: old_notif.callback() old_notif.save() return + # if this permanent notification is the first one, + # go into the callback nonetheless, because the logic + # to set Notification.param is here + # (please don't be mad at me, I'm not the one who cooked this spaghetti) + self.callback() super().save(*args, **kwargs) def callback(self): - # Get the callback defined in settings to update existing - # notifications - mod_name, func_name = settings.SITH_PERMANENT_NOTIFICATIONS[self.type].rsplit( - ".", 1 - ) - mod = importlib.import_module(mod_name) - getattr(mod, func_name)(self) + func_name = settings.SITH_PERMANENT_NOTIFICATIONS.get(self.type) + if not func_name: + return + import_string(func_name)(self) class Gift(models.Model): From c62c09f603dc0c0cb09031739c07ee414e02a06d Mon Sep 17 00:00:00 2001 From: imperosol Date: Thu, 12 Jun 2025 14:35:39 +0200 Subject: [PATCH 08/33] fix: counter selection queryset performance on SellingForm --- club/forms.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/club/forms.py b/club/forms.py index 6bb09fc4..5d6a3b10 100644 --- a/club/forms.py +++ b/club/forms.py @@ -163,15 +163,16 @@ class SellingsForm(forms.Form): def __init__(self, club, *args, **kwargs): super().__init__(*args, **kwargs) - counters_qs = ( - Counter.objects.filter( - Q(club=club) - | Q(products__club=club) - | Exists(Selling.objects.filter(counter=OuterRef("pk"), club=club)) - ) - .distinct() - .order_by(Lower("name")) + # postgres struggles really hard with a single query having three WHERE conditions, + # but deals perfectly fine with UNION of multiple queryset with their own WHERE clause, + # so we do this to get the ids, which we use to build another queryset that can be used by django. + club_sales_subquery = Selling.objects.filter(counter=OuterRef("pk"), club=club) + ids = ( + Counter.objects.filter(Q(club=club) | Q(products__club=club)) + .union(Counter.objects.filter(Exists(club_sales_subquery))) + .values_list("id", flat=True) ) + counters_qs = Counter.objects.filter(id__in=ids).order_by(Lower("name")) self.fields["counters"] = forms.ModelMultipleChoiceField( counters_qs, label=_("Counter"), required=False ) From dcc84894e5a340618fe370303e6d3b78e68ac228 Mon Sep 17 00:00:00 2001 From: imperosol Date: Sat, 14 Jun 2025 10:43:02 +0200 Subject: [PATCH 09/33] fix: bad role title alignment in election.scss --- election/static/election/css/election.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/election/static/election/css/election.scss b/election/static/election/css/election.scss index 95f87f17..3f12ebc1 100644 --- a/election/static/election/css/election.scss +++ b/election/static/election/css/election.scss @@ -93,13 +93,14 @@ $min_col_width: 100px; align-items: center; justify-content: space-between; margin: 0; - row-gap: 10px; + gap: 20px; padding: $padding; width: 100%; >.role_text { display: flex; + width: 100%; flex-direction: column; >h4 { @@ -107,7 +108,6 @@ $min_col_width: 100px; } .role_description { - flex-grow: 1; margin-top: .5em; text-wrap: auto; text-align: left; From c7e4de7df2fe7f256f29e9289c0b48131f481acd Mon Sep 17 00:00:00 2001 From: imperosol Date: Sat, 14 Jun 2025 11:54:58 +0200 Subject: [PATCH 10/33] fix: datetime format in main page news list --- .../com/components/upcoming-news-loader-index.ts | 6 +++++- com/templates/com/news_list.jinja | 10 +++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/com/static/bundled/com/components/upcoming-news-loader-index.ts b/com/static/bundled/com/components/upcoming-news-loader-index.ts index ccc1e714..2bda7fba 100644 --- a/com/static/bundled/com/components/upcoming-news-loader-index.ts +++ b/com/static/bundled/com/components/upcoming-news-loader-index.ts @@ -8,13 +8,17 @@ interface ParsedNewsDateSchema extends Omit { - Alpine.data("upcomingNewsLoader", (startDate: Date) => ({ + Alpine.data("upcomingNewsLoader", (startDate: Date, locale: string) => ({ startDate: startDate, currentPage: 1, pageSize: 6, hasNext: true, loading: false, newsDates: [] as NewsDateSchema[], + dateFormat: new Intl.DateTimeFormat(locale, { + dateStyle: "medium", + timeStyle: "short", + }), async loadMore() { this.loading = true; diff --git a/com/templates/com/news_list.jinja b/com/templates/com/news_list.jinja index e9ff641a..e4b31e26 100644 --- a/com/templates/com/news_list.jinja +++ b/com/templates/com/news_list.jinja @@ -84,11 +84,11 @@ {{ date.news.club }}
-
@@ -103,7 +103,7 @@ {% endfor %} -
+