feat(frontend): notifications

This commit is contained in:
sam 2025-03-05 01:18:21 +01:00
parent f99d10ecf0
commit dd9d35249c
Signed by: sam
GPG key ID: B4EF20DDE721CAA1
9 changed files with 129 additions and 6 deletions

View file

@ -112,3 +112,12 @@ export enum ClearableField {
Flags = "FLAGS",
CustomPreferences = "CUSTOM_PREFERENCES",
}
export type Notification = {
id: string;
type: "NOTICE" | "WARNING" | "SUSPENSION";
message?: string;
localization_key?: string;
localization_params: Record<string, string>;
acknowledged: boolean;
};

View file

@ -13,13 +13,21 @@
import Logo from "$components/Logo.svelte";
import { t } from "$lib/i18n";
type Props = { user: MeUser | null; meta: Meta };
let { user, meta }: Props = $props();
type Props = { user: MeUser | null; meta: Meta; unreadNotifications?: boolean };
let { user, meta, unreadNotifications }: Props = $props();
let isOpen = $state(true);
const toggleMenu = () => (isOpen = !isOpen);
</script>
{#if user && unreadNotifications}
<div class="notification-alert text-center py-3 mb-2 px-2">
<strong>{$t("nav.unread-notification-text")}</strong>
<br />
<a href="/settings/notifications">{$t("nav.unread-notification-link")}</a>
</div>
{/if}
{#if user && user.deleted}
<div class="deleted-alert text-center py-3 mb-2 px-2">
{#if user.suspended}
@ -87,6 +95,11 @@
background-color: var(--bs-danger-bg-subtle);
}
.notification-alert {
color: var(--bs-warning-text-emphasis);
background-color: var(--bs-warning-bg-subtle);
}
/* These exact values make it look almost identical to the SVG version, which is what we want */
#beta-text {
font-size: 0.7em;

View file

@ -0,0 +1,43 @@
<script lang="ts">
import type { Notification } from "$api/models/moderation";
import { t } from "$lib/i18n";
import InfoCircleFill from "svelte-bootstrap-icons/lib/InfoCircleFill.svelte";
import ExclamationTriangleFill from "svelte-bootstrap-icons/lib/ExclamationTriangleFill.svelte";
import XOctagonFill from "svelte-bootstrap-icons/lib/XOctagonFill.svelte";
import QuestionCircleFill from "svelte-bootstrap-icons/lib/QuestionCircleFill.svelte";
import { idTimestamp } from "$lib";
import { DateTime } from "luxon";
type Props = { notification: Notification };
let { notification }: Props = $props();
let Icon = $derived.by(() => {
if (notification.type === "NOTICE") return InfoCircleFill;
if (notification.type === "WARNING") return ExclamationTriangleFill;
if (notification.type === "SUSPENSION") return XOctagonFill;
return QuestionCircleFill;
});
</script>
<div class="card mb-2">
<div class="card-body">
<div class="d-flex">
<div aria-hidden="true">
<Icon width={48} height={48} />
</div>
<div class="mx-3">
<p class="card-text text-has-newline">
{#if notification.localization_key}
{$t(notification.localization_key, notification.localization_params)}
{:else}
{notification.message}
{/if}
</p>
</div>
</div>
</div>
<div class="card-footer text-body-secondary">
{idTimestamp(notification.id).toLocaleString(DateTime.DATETIME_MED)}
<a href="/settings/notifications/ack/{notification.id}">Mark as read</a>
</div>
</div>

View file

@ -9,7 +9,9 @@
"reactivate-account-link": "Reactivate account",
"delete-permanently-link": "I want my account deleted permanently",
"reactivate-or-delete-link": "I want to reactivate my account or delete all my data",
"export-link": "I want to export a copy of my data"
"export-link": "I want to export a copy of my data",
"unread-notification-text": "You have an unread notification.",
"unread-notification-link": "Go to your notifications"
},
"avatar-tooltip": "Avatar for {{name}}",
"profile": {
@ -329,7 +331,9 @@
},
"alert": {
"auth-method-remove-success": "Successfully unlinked account!",
"auth-required": "You must log in to access this page."
"auth-required": "You must log in to access this page.",
"notif-ack-successful": "Successfully marked notification as read!",
"notif-ack-fail": "Could not mark notification as read."
},
"footer": {
"version": "Version",
@ -342,5 +346,10 @@
"changelog": "Changelog",
"donate": "Donate",
"about-contact": "About and contact"
},
"notification": {
"suspension": "Your account has been suspended for the following reason: {{reason}}",
"warning": "You have been warned for the following reason: {{reason}}",
"warning-cleared-fields": "You have been warned for the following reason: {{reason}}\n\nAdditionally, the following fields have been cleared from your profile:\n{{clearedFields}}"
}
}