diff --git a/package-lock.json b/package-lock.json
index 1e2227e..427c50c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "anvil",
- "version": "0.0.13",
+ "version": "0.0.14",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "anvil",
- "version": "0.0.13",
+ "version": "0.0.14",
"dependencies": {
"@floating-ui/dom": "1.6.8",
"@fontsource/spline-sans-mono": "5.0.20",
diff --git a/package.json b/package.json
index aa5f996..f7d0254 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "anvil",
- "version": "0.0.13",
+ "version": "0.0.14",
"private": true,
"scripts": {
"dev": "vite dev",
diff --git a/src/lib/components/molecules/Settings.svelte b/src/lib/components/molecules/Settings.svelte
index 9d3a627..877d149 100644
--- a/src/lib/components/molecules/Settings.svelte
+++ b/src/lib/components/molecules/Settings.svelte
@@ -15,6 +15,7 @@ You should have received a copy of the GNU Affero General Public License along w
import SettingsAccount from './SettingsAccount.svelte';
import SettingsAppearance from './SettingsAppearance.svelte';
import SettingsKeys from './SettingsKeys.svelte';
+ import SettingsNotifications from './SettingsNotifications.svelte';
import SettingsSidebar from '../atoms/SettingsSidebar.svelte';
import SettingsProfile from './SettingsProfile.svelte';
@@ -36,5 +37,7 @@ You should have received a copy of the GNU Affero General Public License along w
{:else if activeSetting === 'appearance'}
+ {:else if activeSetting === 'notifications'}
+
{/if}
diff --git a/src/lib/components/molecules/SettingsNotifications.svelte b/src/lib/components/molecules/SettingsNotifications.svelte
new file mode 100644
index 0000000..abcc627
--- /dev/null
+++ b/src/lib/components/molecules/SettingsNotifications.svelte
@@ -0,0 +1,98 @@
+
+
+
+
+
+
+ {$_('settings.notifications.headline')}
+
+
+
+ {$_('settings.notifications.mentions.headline')}
+
+
+ {@html $_('settings.notifications.mentions.intro', {
+ values: { blockElementOpen: '', blockElementClose: '', instance, username }
+ })}
+
+
+ {#if isNotifiedOnMention}
+ {$_('settings.notifications.mentions.labelYes')}
+ {:else}
+ {$_('settings.notifications.mentions.labelNo')}
+ {/if}
+
+
+
+
+
diff --git a/src/lib/i18n/locales/bg.json b/src/lib/i18n/locales/bg.json
index 0d14bac..a86f8b8 100644
--- a/src/lib/i18n/locales/bg.json
+++ b/src/lib/i18n/locales/bg.json
@@ -206,7 +206,23 @@
}
},
"notifications": {
- "label": ""
+ "default": {
+ "headline": "",
+ "intro": "",
+ "notification": {
+ "all": "",
+ "off": "",
+ "mentioned": ""
+ }
+ },
+ "headline": "",
+ "label": "",
+ "mentions": {
+ "headline": "",
+ "intro": "",
+ "labelNo": "",
+ "labelYes": ""
+ }
},
"profile": {
"avatar": {
diff --git a/src/lib/i18n/locales/de.json b/src/lib/i18n/locales/de.json
index 540ab3f..03e7e92 100644
--- a/src/lib/i18n/locales/de.json
+++ b/src/lib/i18n/locales/de.json
@@ -1,268 +1,284 @@
{
- "overlay": {
- "avatar": {
- "about_anvil": "Über Anvil",
- "dark_mode": "Nachtmodus",
- "profile": "Profil",
- "settings": "Einstellungen",
- "sign_out": "Ausloggen"
- }
- },
- "page": {
- "import_project": {
- "form": {
- "avatar": "Avatar",
- "components": "Komponenten",
- "fields": {
- "avatar": {
- "label": "Bild hochladen"
- },
- "description": {
- "label": "Beschreibung",
- "placeholder": "Beschreibe das Projekt in unter 100 Zeichen..."
- },
- "issues": {
- "label": "Issues"
- },
- "name": {
- "error": "Dieses Feld ist erforderlich",
- "label": "Name",
- "placeholder": "Name des Projekts..."
- },
- "pr": {
- "label": "Pullrequest"
- },
- "repository": {
- "hint": "optional: von Git-Repository importieren",
- "label": "Repository",
- "placeholder": "URL des Git-Repositorys"
- }
- },
- "submit": "Projekt erstellen"
- },
- "heading": "Projekt erstellen",
- "intro": "Neues F2-Projekt zu Anvil hinzufügen."
- },
- "login": {
- "form": {
- "fields": {
- "account": {
- "label": "Accountname"
- },
- "passphrase": {
- "label": "Passwort",
- "placeholder": "Passwort"
- },
- "server": {
- "label": "F2-Server"
- }
- },
- "reset": "Passwort zurücksetzen",
- "submit": "Einloggen",
- "validation": {
- "incorrect": "Accountname oder Kennwort sind falsch.",
- "missing": "Das Account-Feld ist verbindlich."
- }
- },
- "heading": "Einloggen",
- "intro": "Die Einwahldaten ausfüllen um Anvil mit deinem F2-Account zu benutzen."
- },
- "profile": {
- "activities": {
- "block_or_report": "{blockElementOpen}blockieren{blockElementClose} oder {reportElementOpen}melden{reportElementClose}",
- "like": "Gefällt mir"
- },
- "heading": "Profil für",
- "history": {
- "activities": {
- "commits": {
- "actions": {
- "browse": "",
- "copy": "Kopieren"
- },
- "number": "",
- "relative_time": ""
- },
- "setup": {
- "description": "Das F2-Konto @{username}@{instance} wurde erfolgreich innerhalb von {created_with} erstellt",
- "summary": "Kontoeinstellungen"
- }
- },
- "heading": "Aktivitäten"
- },
- "menu": {
- "actions": {
- "fork": "",
- "star": "",
- "watch": ""
- },
- "buttons": {
- "avatar": "",
- "issues": "",
- "notifications": "Benachrichtigungen",
- "prs": ""
- },
- "details": {
- "branches": "",
- "commits": "Commits",
- "files": "Dateien",
- "issues": "",
- "merge_requests": "",
- "moderation": "Moderation",
- "overview": "Übersicht",
- "people": "",
- "repository": "",
- "roles": "Rollen",
- "tags": "Schlagworte"
- }
- },
- "projects": {
- "actions": {
- "fork": "Fork",
- "star": "Favorisieren",
- "watch": "Beobachten"
- },
- "add_or_import": "{addElementOpen}Ein Projekt hinzufügen{addElementClose} oder {importElementOpen}Ein Projekt importieren{importElementClose}.",
- "empty": "Bisher keine Projekte hinzugefügt.",
- "heading": "Projekte"
- },
- "repositories": {
- "heading": ""
- }
- },
- "projects": {
- "file_table": {
- "updated": "Aktualisiert: {relativeTime}"
- },
- "form": {
- "fields": {
- "more_filters": {
- "submit": "Weitere Filter"
- },
- "projects": {
- "submit": "Meine Projekte"
- },
- "search": {
- "placeholder": "Suchen oder filtern",
- "submit": "Absenden"
- },
- "starred": {
- "submit": "Favorisiert"
- }
- }
- },
- "nav": {
- "next": "Weiter",
- "previous": "Zurück"
- },
- "table": {
- "heading": {
- "last_updated": "Letzte Aktualisierung",
- "name": "Name"
- }
- }
- },
- "welcome": {
- "create": "",
- "intro": "",
- "headline": "Willkommen bei Anvil",
- "login": "",
- "logo": {
- "alt": ""
- },
- "reset": ""
- }
- },
- "settings": {
- "headline": "",
- "account": {
- "delete": "",
- "f2": {
- "label": "",
- "placeholder": ""
- },
- "headline": "",
- "label": "",
- "password": {
- "label": "",
- "reset": ""
- },
- "verification": {
- "label": ""
- }
- },
- "appearance": {
- "headline": "",
- "label": "",
- "tab_indent": {
- "headline": "",
- "intro": ""
- },
- "theme": {
- "auto": "",
- "dark": "",
- "headline": "",
- "light": ""
- }
- },
- "notifications": {
- "label": ""
- },
- "profile": {
- "avatar": {
- "headline": "",
- "remove": "",
- "upload": ""
- },
- "bio": {
- "label": "",
- "placeholder": ""
- },
- "extra": {
- "content": {
- "placeholder": ""
- },
- "headline": "",
- "hint": "",
- "label": {
- "placeholder": ""
- }
- },
- "headline": "",
- "label": "",
- "name": {
- "label": "",
- "placeholder": ""
- },
- "pronouns": {
- "label": ""
- }
- },
- "ssh_gpg_keys": {
- "gpg": {
- "add": "",
- "headline": "",
- "key": {
- "placeholder": ""
- },
- "remove": "",
- "title": {
- "placeholder": ""
- }
- },
- "headline": "",
- "label": "",
- "ssh": {
- "add": "",
- "headline": "",
- "key": {
- "placeholder": ""
- },
- "remove": "",
- "title": {
- "placeholder": ""
- }
- }
- }
- }
+ "overlay": {
+ "avatar": {
+ "about_anvil": "Über Anvil",
+ "dark_mode": "Nachtmodus",
+ "profile": "Profil",
+ "settings": "Einstellungen",
+ "sign_out": "Ausloggen"
+ }
+ },
+ "page": {
+ "import_project": {
+ "form": {
+ "avatar": "Avatar",
+ "components": "Komponenten",
+ "fields": {
+ "avatar": {
+ "label": "Bild hochladen"
+ },
+ "description": {
+ "label": "Beschreibung",
+ "placeholder": "Beschreibe das Projekt in unter 100 Zeichen..."
+ },
+ "issues": {
+ "label": "Issues"
+ },
+ "name": {
+ "error": "Dieses Feld ist erforderlich",
+ "label": "Name",
+ "placeholder": "Name des Projekts..."
+ },
+ "pr": {
+ "label": "Pullrequest"
+ },
+ "repository": {
+ "hint": "optional: von Git-Repository importieren",
+ "label": "Repository",
+ "placeholder": "URL des Git-Repositorys"
+ }
+ },
+ "submit": "Projekt erstellen"
+ },
+ "heading": "Projekt erstellen",
+ "intro": "Neues F2-Projekt zu Anvil hinzufügen."
+ },
+ "login": {
+ "form": {
+ "fields": {
+ "account": {
+ "label": "Accountname"
+ },
+ "passphrase": {
+ "label": "Passwort",
+ "placeholder": "Passwort"
+ },
+ "server": {
+ "label": "F2-Server"
+ }
+ },
+ "reset": "Passwort zurücksetzen",
+ "submit": "Einloggen",
+ "validation": {
+ "incorrect": "Accountname oder Kennwort sind falsch.",
+ "missing": "Das Account-Feld ist verbindlich."
+ }
+ },
+ "heading": "Einloggen",
+ "intro": "Die Einwahldaten ausfüllen um Anvil mit deinem F2-Account zu benutzen."
+ },
+ "profile": {
+ "activities": {
+ "block_or_report": "{blockElementOpen}blockieren{blockElementClose} oder {reportElementOpen}melden{reportElementClose}",
+ "like": "Gefällt mir"
+ },
+ "heading": "Profil für",
+ "history": {
+ "activities": {
+ "commits": {
+ "actions": {
+ "browse": "",
+ "copy": "Kopieren"
+ },
+ "number": "",
+ "relative_time": ""
+ },
+ "setup": {
+ "description": "Das F2-Konto @{username}@{instance} wurde erfolgreich innerhalb von {created_with} erstellt",
+ "summary": "Kontoeinstellungen"
+ }
+ },
+ "heading": "Aktivitäten"
+ },
+ "menu": {
+ "actions": {
+ "fork": "",
+ "star": "",
+ "watch": ""
+ },
+ "buttons": {
+ "avatar": "",
+ "issues": "",
+ "notifications": "Benachrichtigungen",
+ "prs": ""
+ },
+ "details": {
+ "branches": "",
+ "commits": "Commits",
+ "files": "Dateien",
+ "issues": "",
+ "merge_requests": "",
+ "moderation": "Moderation",
+ "overview": "Übersicht",
+ "people": "",
+ "repository": "",
+ "roles": "Rollen",
+ "tags": "Schlagworte"
+ }
+ },
+ "projects": {
+ "actions": {
+ "fork": "Fork",
+ "star": "Favorisieren",
+ "watch": "Beobachten"
+ },
+ "add_or_import": "{addElementOpen}Ein Projekt hinzufügen{addElementClose} oder {importElementOpen}Ein Projekt importieren{importElementClose}.",
+ "empty": "Bisher keine Projekte hinzugefügt.",
+ "heading": "Projekte"
+ },
+ "repositories": {
+ "heading": ""
+ }
+ },
+ "projects": {
+ "file_table": {
+ "updated": "Aktualisiert: {relativeTime}"
+ },
+ "form": {
+ "fields": {
+ "more_filters": {
+ "submit": "Weitere Filter"
+ },
+ "projects": {
+ "submit": "Meine Projekte"
+ },
+ "search": {
+ "placeholder": "Suchen oder filtern",
+ "submit": "Absenden"
+ },
+ "starred": {
+ "submit": "Favorisiert"
+ }
+ }
+ },
+ "nav": {
+ "next": "Weiter",
+ "previous": "Zurück"
+ },
+ "table": {
+ "heading": {
+ "last_updated": "Letzte Aktualisierung",
+ "name": "Name"
+ }
+ }
+ },
+ "welcome": {
+ "create": "",
+ "intro": "",
+ "headline": "Willkommen bei Anvil",
+ "login": "",
+ "logo": {
+ "alt": ""
+ },
+ "reset": ""
+ }
+ },
+ "settings": {
+ "headline": "",
+ "account": {
+ "delete": "",
+ "f2": {
+ "label": "",
+ "placeholder": ""
+ },
+ "headline": "",
+ "label": "",
+ "password": {
+ "label": "",
+ "reset": ""
+ },
+ "verification": {
+ "label": ""
+ }
+ },
+ "appearance": {
+ "headline": "",
+ "label": "",
+ "tab_indent": {
+ "headline": "",
+ "intro": ""
+ },
+ "theme": {
+ "auto": "",
+ "dark": "",
+ "headline": "",
+ "light": ""
+ }
+ },
+ "notifications": {
+ "default": {
+ "headline": "",
+ "intro": "",
+ "notification": {
+ "all": "",
+ "off": "",
+ "mentioned": ""
+ }
+ },
+ "headline": "",
+ "label": "",
+ "mentions": {
+ "headline": "",
+ "intro": "",
+ "labelNo": "",
+ "labelYes": ""
+ }
+ },
+ "profile": {
+ "avatar": {
+ "headline": "",
+ "remove": "",
+ "upload": ""
+ },
+ "bio": {
+ "label": "",
+ "placeholder": ""
+ },
+ "extra": {
+ "content": {
+ "placeholder": ""
+ },
+ "headline": "",
+ "hint": "",
+ "label": {
+ "placeholder": ""
+ }
+ },
+ "headline": "",
+ "label": "",
+ "name": {
+ "label": "",
+ "placeholder": ""
+ },
+ "pronouns": {
+ "label": ""
+ }
+ },
+ "ssh_gpg_keys": {
+ "gpg": {
+ "add": "",
+ "headline": "",
+ "key": {
+ "placeholder": ""
+ },
+ "remove": "",
+ "title": {
+ "placeholder": ""
+ }
+ },
+ "headline": "",
+ "label": "",
+ "ssh": {
+ "add": "",
+ "headline": "",
+ "key": {
+ "placeholder": ""
+ },
+ "remove": "",
+ "title": {
+ "placeholder": ""
+ }
+ }
+ }
+ }
}
diff --git a/src/lib/i18n/locales/en.json b/src/lib/i18n/locales/en.json
index dc048e9..addd58e 100644
--- a/src/lib/i18n/locales/en.json
+++ b/src/lib/i18n/locales/en.json
@@ -206,7 +206,23 @@
}
},
"notifications": {
- "label": "Notifications"
+ "default": {
+ "headline": "Default notification",
+ "intro": "The default notification setting for starred projects",
+ "notification": {
+ "all": "All activity",
+ "off": "Turn off",
+ "mentioned": "Mentions only"
+ }
+ },
+ "headline": "Notifications",
+ "label": "Notifications",
+ "mentions": {
+ "headline": "Mentions",
+ "intro": "Receive notifications when {blockElementOpen}@{username}@{instance}{blockElementClose} is mentioned.",
+ "labelNo": "Off",
+ "labelYes": "On"
+ }
},
"profile": {
"avatar": {
diff --git a/src/lib/i18n/locales/pl.json b/src/lib/i18n/locales/pl.json
index b6b8bca..5d69954 100644
--- a/src/lib/i18n/locales/pl.json
+++ b/src/lib/i18n/locales/pl.json
@@ -206,7 +206,23 @@
}
},
"notifications": {
- "label": ""
+ "default": {
+ "headline": "",
+ "intro": "",
+ "notification": {
+ "all": "",
+ "off": "",
+ "mentioned": ""
+ }
+ },
+ "headline": "",
+ "label": "",
+ "mentions": {
+ "headline": "",
+ "intro": "",
+ "labelNo": "",
+ "labelYes": ""
+ }
},
"profile": {
"avatar": {
diff --git a/stories/molecules/SettingsNotifications.stories.ts b/stories/molecules/SettingsNotifications.stories.ts
new file mode 100644
index 0000000..908cddb
--- /dev/null
+++ b/stories/molecules/SettingsNotifications.stories.ts
@@ -0,0 +1,26 @@
+/* Stories for SettingsNotifications molecule.
+ * Copyright (C) 2024 André Jaenisch
+ * SPDX-FileCopyrightText: 2024 André Jaenisch
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ *
+ * This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License along with this program. If not, see .
+ */
+
+import type { Meta, StoryObj } from '@storybook/svelte';
+
+import SettingsNotifications from '$lib/components/molecules/SettingsNotifications.svelte';
+
+const meta = {
+ title: 'Molecules/SettingsNotifications',
+ component: SettingsNotifications,
+ tags: ['autodocs']
+} satisfies Meta;
+
+export default meta;
+type Story = StoryObj;
+
+export const Plain: Story = {};
diff --git a/tests/components/molecules/SettingsNotifications.test.ts b/tests/components/molecules/SettingsNotifications.test.ts
new file mode 100644
index 0000000..5c38a2b
--- /dev/null
+++ b/tests/components/molecules/SettingsNotifications.test.ts
@@ -0,0 +1,86 @@
+/* Component test for SettingsNotifications molecule.
+ * Copyright (C) 2024 André Jaenisch
+ * SPDX-FileCopyrightText: 2024 André Jaenisch
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ *
+ * This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License along with this program. If not, see .
+ */
+
+import '@testing-library/jest-dom';
+import { render, screen } from '@testing-library/svelte';
+import { init, locale, register } from 'svelte-i18n';
+
+import SettingsNotifications from '../../../src/lib/components/molecules/SettingsNotifications.svelte';
+import enMessages from '../../../src/lib/i18n/locales/en.json';
+
+describe('SettingsNotifications.svelte', () => {
+ beforeEach(() => {
+ register('en', () => import('../../../src/lib/i18n/locales/en.json'));
+ init({ fallbackLocale: 'en', initialLocale: 'en' });
+ locale.set('en');
+ });
+
+ it('should mount', () => {
+ // Arrange
+ // Nothing to prepare
+
+ // Act
+ const { container } = render(SettingsNotifications);
+
+ // Assert
+ expect(container).toBeTruthy();
+ });
+
+ it('should have a slide toggle', () => {
+ // Arrange
+ // Nothing to prepare
+
+ // Act
+ render(SettingsNotifications);
+
+ // Assert
+ expect(
+ screen.getByLabelText(enMessages.settings.notifications.mentions.labelNo)
+ ).toBeInTheDocument();
+ });
+
+ describe('when slide is toggled', () => {
+ it('should update the label', async () => {
+ // Arrange
+ // Nothing to prepare
+
+ // Act
+ render(SettingsNotifications);
+ const slideToggle = screen.getByLabelText(enMessages.settings.notifications.mentions.labelNo);
+ await slideToggle.click();
+
+ // Assert
+ expect(
+ screen.getByLabelText(enMessages.settings.notifications.mentions.labelYes)
+ ).toBeInTheDocument();
+ });
+ });
+
+ it('should have a default notification radio group', () => {
+ // Arrange
+ // Nothing to prepare
+
+ // Act
+ render(SettingsNotifications);
+
+ // Assert
+ expect(
+ screen.getByLabelText(enMessages.settings.notifications.default.notification.all)
+ ).toBeInTheDocument();
+ expect(
+ screen.getByLabelText(enMessages.settings.notifications.default.notification.off)
+ ).toBeInTheDocument();
+ expect(
+ screen.getByLabelText(enMessages.settings.notifications.default.notification.mentioned)
+ ).toBeInTheDocument();
+ });
+});