diff --git a/package-lock.json b/package-lock.json
index 1e49ca4..1e2227e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "anvil",
- "version": "0.0.12",
+ "version": "0.0.13",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "anvil",
- "version": "0.0.12",
+ "version": "0.0.13",
"dependencies": {
"@floating-ui/dom": "1.6.8",
"@fontsource/spline-sans-mono": "5.0.20",
diff --git a/package.json b/package.json
index 79ba940..aa5f996 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "anvil",
- "version": "0.0.12",
+ "version": "0.0.13",
"private": true,
"scripts": {
"dev": "vite dev",
diff --git a/src/lib/components/molecules/Settings.svelte b/src/lib/components/molecules/Settings.svelte
index 173b039..7f1a104 100644
--- a/src/lib/components/molecules/Settings.svelte
+++ b/src/lib/components/molecules/Settings.svelte
@@ -13,15 +13,34 @@ You should have received a copy of the GNU Affero General Public License along w
@@ -33,5 +52,7 @@ You should have received a copy of the GNU Affero General Public License along w
{:else if activeSetting === 'ssh_gpg_keys'}
+ {:else if activeSetting === 'appearance'}
+
{/if}
diff --git a/src/lib/components/molecules/SettingsAppearance.svelte b/src/lib/components/molecules/SettingsAppearance.svelte
new file mode 100644
index 0000000..ffa45bf
--- /dev/null
+++ b/src/lib/components/molecules/SettingsAppearance.svelte
@@ -0,0 +1,68 @@
+
+
+
+
+
+
+ {$_('settings.appearance.headline')}
+
+
+
+
+
+ {$_('settings.appearance.tab_indent.headline')}
+
+
{$_('settings.appearance.tab_indent.intro')}
+
+
+
diff --git a/src/lib/i18n/locales/bg.json b/src/lib/i18n/locales/bg.json
index e403b4f..0d14bac 100644
--- a/src/lib/i18n/locales/bg.json
+++ b/src/lib/i18n/locales/bg.json
@@ -192,7 +192,18 @@
}
},
"appearance": {
- "label": ""
+ "headline": "",
+ "label": "",
+ "tab_indent": {
+ "headline": "",
+ "intro": ""
+ },
+ "theme": {
+ "auto": "",
+ "dark": "",
+ "headline": "",
+ "light": ""
+ }
},
"notifications": {
"label": ""
diff --git a/src/lib/i18n/locales/de.json b/src/lib/i18n/locales/de.json
index 13f00ec..6f3ec0d 100644
--- a/src/lib/i18n/locales/de.json
+++ b/src/lib/i18n/locales/de.json
@@ -1,257 +1,268 @@
{
- "overlay": {
- "avatar": {
- "about_anvil": "Über Anvil",
- "dark_mode": "",
- "profile": "",
- "settings": "",
- "sign_out": ""
- }
- },
- "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": ""
- },
- "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": "",
- "prs": ""
- },
- "details": {
- "branches": "",
- "commits": "",
- "files": "",
- "issues": "",
- "merge_requests": "",
- "moderation": "",
- "overview": "",
- "people": "",
- "repository": "",
- "roles": "",
- "tags": ""
- }
- },
- "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": {
- "label": ""
- },
- "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": "",
+ "profile": "",
+ "settings": "",
+ "sign_out": ""
+ }
+ },
+ "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": ""
+ },
+ "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": "",
+ "prs": ""
+ },
+ "details": {
+ "branches": "",
+ "commits": "",
+ "files": "",
+ "issues": "",
+ "merge_requests": "",
+ "moderation": "",
+ "overview": "",
+ "people": "",
+ "repository": "",
+ "roles": "",
+ "tags": ""
+ }
+ },
+ "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": ""
+ }
+ }
+ }
+ }
}
diff --git a/src/lib/i18n/locales/en.json b/src/lib/i18n/locales/en.json
index d61f59e..dc048e9 100644
--- a/src/lib/i18n/locales/en.json
+++ b/src/lib/i18n/locales/en.json
@@ -192,7 +192,18 @@
}
},
"appearance": {
- "label": "Appearance"
+ "headline": "Appearance",
+ "label": "Appearance",
+ "tab_indent": {
+ "headline": "Tab indenting",
+ "intro": "Number of spaces per tab in code view."
+ },
+ "theme": {
+ "auto": "Auto",
+ "dark": "Dark",
+ "headline": "Theme",
+ "light": "Light"
+ }
},
"notifications": {
"label": "Notifications"
diff --git a/src/lib/i18n/locales/he.json b/src/lib/i18n/locales/he.json
index 6724254..c8889c6 100644
--- a/src/lib/i18n/locales/he.json
+++ b/src/lib/i18n/locales/he.json
@@ -192,7 +192,18 @@
}
},
"appearance": {
- "label": ""
+ "headline": "",
+ "label": "",
+ "tab_indent": {
+ "headline": "",
+ "intro": ""
+ },
+ "theme": {
+ "auto": "",
+ "dark": "",
+ "headline": "",
+ "light": ""
+ }
},
"notifications": {
"label": ""
diff --git a/src/lib/i18n/locales/pl.json b/src/lib/i18n/locales/pl.json
index 5a093ed..b6b8bca 100644
--- a/src/lib/i18n/locales/pl.json
+++ b/src/lib/i18n/locales/pl.json
@@ -192,7 +192,18 @@
}
},
"appearance": {
- "label": ""
+ "headline": "",
+ "label": "",
+ "tab_indent": {
+ "headline": "",
+ "intro": ""
+ },
+ "theme": {
+ "auto": "",
+ "dark": "",
+ "headline": "",
+ "light": ""
+ }
},
"notifications": {
"label": ""
diff --git a/stories/molecules/SettingsAppearance.stories.ts b/stories/molecules/SettingsAppearance.stories.ts
new file mode 100644
index 0000000..7f54190
--- /dev/null
+++ b/stories/molecules/SettingsAppearance.stories.ts
@@ -0,0 +1,26 @@
+/* Stories for SettingsAppearance 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 SettingsAppearance from '$lib/components/molecules/SettingsAppearance.svelte';
+
+const meta = {
+ title: 'Molecules/SettingsAppearance',
+ component: SettingsAppearance,
+ tags: ['autodocs']
+} satisfies Meta;
+
+export default meta;
+type Story = StoryObj;
+
+export const Plain: Story = {};
diff --git a/tests/components/molecules/SettingsAppearance.test.ts b/tests/components/molecules/SettingsAppearance.test.ts
new file mode 100644
index 0000000..195b333
--- /dev/null
+++ b/tests/components/molecules/SettingsAppearance.test.ts
@@ -0,0 +1,82 @@
+/* Component test for SettingsAppearance 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 SettingsAppearance from '../../../src/lib/components/molecules/SettingsAppearance.svelte';
+import enMessages from '../../../src/lib/i18n/locales/en.json';
+
+describe('SettingsAppearance.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(SettingsAppearance);
+
+ // Assert
+ expect(container).toBeTruthy();
+ });
+
+ it('should have a radio group for themes', () => {
+ // Arrange
+ // Nothing to prepare
+
+ // Act
+ render(SettingsAppearance);
+
+ // Assert
+ expect(screen.getByLabelText(enMessages.settings.appearance.theme.light)).toBeInTheDocument();
+ expect(screen.getByLabelText(enMessages.settings.appearance.theme.dark)).toBeInTheDocument();
+ expect(screen.getByLabelText(enMessages.settings.appearance.theme.auto)).toBeInTheDocument();
+ });
+
+ describe('when clicking a theme', () => {
+ it('should dispatch a switch-theme event', () => {
+ // Arrange
+ const listener = vi.fn();
+
+ // Act
+ const { component } = render(SettingsAppearance);
+ component.$on('switch-theme', listener);
+ const darkTheme = screen.getByLabelText(enMessages.settings.appearance.theme.dark);
+ darkTheme.click();
+ const ev = new CustomEvent({ detail: 'dark' });
+
+ // Assert
+ expect(listener).toHaveBeenCalledOnce();
+ expect(listener).toHaveBeenCalledWith(ev);
+ });
+ });
+
+ // TODO: Mark up proper label and input
+ it.skip('should have a tab indent input', () => {
+ // Arrange
+ // Nothing to prepare
+
+ // Act
+ render(SettingsAppearance);
+
+ // Assert
+ expect(
+ screen.getByPlaceholderText(enMessages.settings.appearance.tab_indent.label)
+ ).toBeInTheDocument();
+ });
+});