mirror of
https://github.com/ae-utbm/sith.git
synced 2026-05-22 08:50:17 +00:00
Merge pull request #1391 from ae-utbm/notifications-magic
improve `$notifications`
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
<title>{% trans %}Slideshow{% endtrans %}</title>
|
||||
<link rel="shortcut icon" href="{{ static('core/img/favicon.ico') }}">
|
||||
<link href="{{ static('css/slideshow.scss') }}" rel="stylesheet" type="text/css" />
|
||||
<script type="module" src="{{ static('bundled/alpine-index.js') }}"></script>
|
||||
<script type="module" src="{{ static('bundled/alpine-index.ts') }}"></script>
|
||||
<script type="module" src="{{ static('bundled/com/slideshow-index.ts') }}"></script>
|
||||
</head>
|
||||
<body x-data="slideshow([
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
import sort from "@alpinejs/sort";
|
||||
import Alpine from "alpinejs";
|
||||
import { limitedChoices } from "#core:alpine/limited-choices.ts";
|
||||
import { alpinePlugin as notificationPlugin } from "#core:utils/notifications.ts";
|
||||
|
||||
Alpine.plugin([sort, limitedChoices]);
|
||||
Alpine.magic("notifications", notificationPlugin);
|
||||
window.Alpine = Alpine;
|
||||
|
||||
window.addEventListener("DOMContentLoaded", () => {
|
||||
Alpine.start();
|
||||
});
|
||||
@@ -0,0 +1,21 @@
|
||||
import sort from "@alpinejs/sort";
|
||||
import { Alpine } from "alpinejs";
|
||||
import { limitedChoices } from "#core:alpine/limited-choices";
|
||||
import {
|
||||
type NotificationPlugin,
|
||||
notificationsPlugin as notifications,
|
||||
} from "#core:utils/notifications";
|
||||
|
||||
declare module "alpinejs" {
|
||||
interface Magics<T> {
|
||||
$notifications: NotificationPlugin;
|
||||
}
|
||||
}
|
||||
|
||||
Alpine.plugin([sort, limitedChoices, notifications]);
|
||||
// biome-ignore lint/style/useNamingConvention: it's how it's named
|
||||
Object.assign(window, { Alpine });
|
||||
|
||||
window.addEventListener("DOMContentLoaded", () => {
|
||||
Alpine.start();
|
||||
});
|
||||
@@ -1,36 +1,64 @@
|
||||
import { Alpine } from "alpinejs";
|
||||
|
||||
export enum NotificationLevel {
|
||||
Error = "error",
|
||||
Warning = "warning",
|
||||
Success = "success",
|
||||
}
|
||||
|
||||
export function createNotification(message: string, level: NotificationLevel) {
|
||||
const element = document.getElementById("quick-notifications");
|
||||
if (element === null) {
|
||||
return false;
|
||||
}
|
||||
return element.dispatchEvent(
|
||||
new CustomEvent("quick-notification-add", {
|
||||
detail: { text: message, tag: level },
|
||||
}),
|
||||
);
|
||||
export interface NotificationPlugin {
|
||||
/**
|
||||
* Add an error message to the notifications.
|
||||
*/
|
||||
error: (message: string) => void;
|
||||
/**
|
||||
* Add a warning message to the notifications
|
||||
*/
|
||||
warning: (message: string) => void;
|
||||
/**
|
||||
* Add a success message to the notifications
|
||||
*/
|
||||
success: (message: string) => void;
|
||||
/**
|
||||
* Remove all notifications displayed on the page.
|
||||
*/
|
||||
clear: () => void;
|
||||
/**
|
||||
* Add multiple notifications at once.
|
||||
* The added notifications can have different notification levels.
|
||||
*/
|
||||
addMany: (notifs: Notification[]) => void;
|
||||
/**
|
||||
* Return all notifications displayed on the page.
|
||||
*/
|
||||
getAll: () => Notification[];
|
||||
}
|
||||
|
||||
export function deleteNotifications() {
|
||||
const element = document.getElementById("quick-notifications");
|
||||
if (element === null) {
|
||||
return false;
|
||||
}
|
||||
return element.dispatchEvent(new CustomEvent("quick-notification-delete"));
|
||||
export interface Notification {
|
||||
tag: NotificationLevel;
|
||||
text: string;
|
||||
}
|
||||
|
||||
export function alpinePlugin() {
|
||||
return {
|
||||
error: (message: string) => createNotification(message, NotificationLevel.Error),
|
||||
warning: (message: string) =>
|
||||
createNotification(message, NotificationLevel.Warning),
|
||||
success: (message: string) =>
|
||||
createNotification(message, NotificationLevel.Success),
|
||||
clear: () => deleteNotifications(),
|
||||
};
|
||||
Alpine.store("notifications", [] as Notification[]);
|
||||
|
||||
function createNotification(message: string, level: NotificationLevel) {
|
||||
(Alpine.store("notifications") as Notification[]).push({ text: message, tag: level });
|
||||
}
|
||||
function createManyNotifications(notifs: Notification[]) {
|
||||
for (const notif of notifs) {
|
||||
createNotification(notif.text, notif.tag);
|
||||
}
|
||||
}
|
||||
|
||||
export const notifications: NotificationPlugin = {
|
||||
error: (message: string) => createNotification(message, NotificationLevel.Error),
|
||||
warning: (message: string) => createNotification(message, NotificationLevel.Warning),
|
||||
success: (message: string) => createNotification(message, NotificationLevel.Success),
|
||||
clear: () => Alpine.store("notifications", []),
|
||||
addMany: (notifs: Notification[]) => createManyNotifications(notifs),
|
||||
getAll: () => Alpine.store("notifications") as Notification[],
|
||||
};
|
||||
|
||||
export function notificationsPlugin(GlobalAlpine: Alpine) {
|
||||
GlobalAlpine.magic("notifications", () => ({ ...notifications }));
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
<script src="{{ url('javascript-catalog') }}"></script>
|
||||
<script type="module" src="{{ static("bundled/core/navbar-index.ts") }}"></script>
|
||||
<script type="module" src="{{ static("bundled/core/components/include-index.ts") }}"></script>
|
||||
<script type="module" src="{{ static('bundled/alpine-index.js') }}"></script>
|
||||
<script type="module" src="{{ static('bundled/alpine-index.ts') }}"></script>
|
||||
<script type="module" src="{{ static('bundled/htmx-index.js') }}"></script>
|
||||
<script type="module" src="{{ static('bundled/country-flags-index.ts') }}"></script>
|
||||
<script type="module" src="{{ static('bundled/core/tooltips-index.ts') }}"></script>
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
<div id="quick-notifications"
|
||||
x-data='{
|
||||
messages: [
|
||||
x-init='$notifications.addMany([
|
||||
{%- for message in messages -%}
|
||||
{%- if not message.extra_tags -%}
|
||||
{ tag: {{ message.tags|string|tojson }}, text: {{ message|string|tojson }} },
|
||||
{ tag: "{{ message.tags }}", text: {{ message|string|tojson }} },
|
||||
{%- endif -%}
|
||||
{%- endfor -%}
|
||||
]
|
||||
}'
|
||||
@quick-notification-add="(e) => messages.push(e?.detail)"
|
||||
@quick-notification-delete="messages = []">
|
||||
<template x-for="(message, index) in messages">
|
||||
])'
|
||||
>
|
||||
<template x-for="(message, index) in $notifications.getAll()">
|
||||
<div class="alert" :class="`alert-${message.tag}`" x-transition>
|
||||
<span class="alert-main" x-text="message.text"></span>
|
||||
<span class="clickable" @click="messages = messages.filter((item, i) => i !== index)">
|
||||
|
||||
@@ -226,7 +226,7 @@
|
||||
<button type="button" onclick="checkbox_{{form_id}}(false);">{% trans %}Unselect All{% endtrans %}</button>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro update_notifications(messages, clear) %}
|
||||
{% macro update_notifications(messages, clear = True) %}
|
||||
{# Update notification area from new messages sent by django backend
|
||||
This is useful when performing fragment swaps to keep messages up to date
|
||||
Without this, the fragment would need to take control of the notification area and
|
||||
@@ -236,16 +236,19 @@
|
||||
messages: messages from django.contrib
|
||||
clear : optional boolean that controls if notifications should be cleared first. True is the default
|
||||
#}
|
||||
{% set clear = clear|default(true) %}
|
||||
{% if messages %}
|
||||
<div x-init="() => {
|
||||
{% if clear %}
|
||||
$notifications.clear()
|
||||
{% endif %}
|
||||
{% for message in messages %}
|
||||
$notifications.{{ message.tags }}('{{ message }}')
|
||||
{% endfor %}
|
||||
}"></div>
|
||||
<div x-init='() => {
|
||||
{%- if clear -%}
|
||||
$notifications.clear();
|
||||
{%- endif -%}
|
||||
$notifications.addMany([
|
||||
{%- for message in messages -%}
|
||||
{%- if not message.extra_tags -%}
|
||||
{ tag: "{{ message.tags }}", text: {{ message|string|tojson }} },
|
||||
{%- endif -%}
|
||||
{%- endfor -%}
|
||||
])
|
||||
}'></div>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ class FragmentRenderer(Protocol):
|
||||
) -> SafeString: ...
|
||||
|
||||
|
||||
class FragmentMixin(TemplateResponseMixin, ContextMixin):
|
||||
class FragmentMixin(TemplateResponseMixin, AllowFragment, ContextMixin):
|
||||
"""Make a view buildable as a fragment that can be embedded in a template.
|
||||
|
||||
Most fragments are used in two different ways :
|
||||
|
||||
@@ -35,8 +35,8 @@ les fichiers sont à mettre dans un dossier `static/bundled` de l'application à
|
||||
Pour accéder au fichier, il faut utiliser `static` comme pour le reste mais en ajouter `bundled/` comme prefix.
|
||||
|
||||
```jinja
|
||||
{# Example pour ajouter sith/core/bundled/alpine-index.js #}
|
||||
<script type="module" src="{{ static('bundled/alpine-index.js') }}"></script>
|
||||
{# Example pour ajouter sith/core/bundled/alpine-index.ts #}
|
||||
<script type="module" src="{{ static('bundled/alpine-index.ts') }}"></script>
|
||||
<script type="module" src="{{ static('bundled/other-index.ts') }}"></script>
|
||||
```
|
||||
|
||||
|
||||
@@ -32,5 +32,7 @@
|
||||
</form>
|
||||
</div>
|
||||
<br>
|
||||
{{ update_notifications(messages) }}
|
||||
{% if is_fragment %}
|
||||
{{ update_notifications(messages) }}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
@@ -32,7 +32,7 @@ class JsBundlerManifestEntry:
|
||||
# because that's what the user types when importing statics and that's what django gives us
|
||||
# This is really similar to what we are doing in the bundler, it uses a similar algorithm
|
||||
# Example:
|
||||
# core/static/bundled/alpine-index.js -> bundled/alpine-index.js
|
||||
# core/static/bundled/alpine-index.ts -> bundled/alpine-index.ts
|
||||
# core/static/bundled/components/include-index.ts -> core/static/bundled/components/include-index.ts
|
||||
def get_relative_src_name(name: str) -> str:
|
||||
original_path = Path(name)
|
||||
|
||||
Reference in New Issue
Block a user