feat: extract SettingsSidebar into component

This is in need of at least one refactoring. Skeleton is redesigning
the AppRail we are using here. The layout is hard to style.
This implementation interacts with a drawer, but it will likely be
dropped in the final version.

Signed-off-by: André Jaenisch <andre.jaenisch@posteo.de>
This commit is contained in:
André Jaenisch 2024-07-22 09:30:06 +02:00
parent 5d1bada084
commit ead9d281d0
No known key found for this signature in database
GPG key ID: 5A668E771F1ED854
9 changed files with 343 additions and 3 deletions

4
package-lock.json generated
View file

@ -1,12 +1,12 @@
{ {
"name": "anvil", "name": "anvil",
"version": "0.0.8", "version": "0.0.10",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "anvil", "name": "anvil",
"version": "0.0.8", "version": "0.0.10",
"dependencies": { "dependencies": {
"@floating-ui/dom": "1.6.7", "@floating-ui/dom": "1.6.7",
"axios": "1.7.2", "axios": "1.7.2",

View file

@ -1,6 +1,6 @@
{ {
"name": "anvil", "name": "anvil",
"version": "0.0.8", "version": "0.0.10",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "vite dev", "dev": "vite dev",

View file

@ -0,0 +1,125 @@
<!--
SettingsSidebar atom.
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 <http://www.gnu.org/licenses/>.
-->
<script>
import { AppRail, AppRailAnchor, AppRailTile, getDrawerStore } from '@skeletonlabs/skeleton';
import { _, locale, locales } from 'svelte-i18n';
import { Bell24, Gear24, Key24, Paintbrush24, Person24 } from 'svelte-octicons';
let currentTile = 0;
const drawerStore = getDrawerStore();
function onTileChanged(ev) {
const settings = { id: ev.target.value };
drawerStore.open(settings);
}
</script>
<AppRail aspectRatio="auto" gap="gap-8" height="h-auto" width="w-[230px]" spacing="my-2">
<svelte:fragment slot="lead">
<AppRailTile
regionLabel="!text-3xl text-surface-500 bg-surface-100 float-start w-full text-start ps-8 pt-8 -my-2"
>{$_('settings.headline')}</AppRailTile
>
</svelte:fragment>
<AppRailTile
bind:group={currentTile}
name="profile"
value="profile"
on:change={onTileChanged}
regionLabel="float-start ps-2 py-1 text-surface-500"
regionLead="float-start ps-8 text-surface-500"
title={$_('settings.profile.label')}
>
<svelte:fragment slot="lead">
<Person24 fill="currentColor" class="inline" />
</svelte:fragment>
<span>{$_('settings.profile.label')}</span>
</AppRailTile>
<AppRailTile
bind:group={currentTile}
name="account"
value="account"
on:change={onTileChanged}
regionLabel="float-start ps-2 py-1 text-surface-500"
regionLead="float-start ps-8 text-surface-500"
title={$_('settings.account.label')}
>
<svelte:fragment slot="lead">
<Gear24 fill="currentColor" class="inline" />
</svelte:fragment>
<span>{$_('settings.account.label')}</span>
</AppRailTile>
<AppRailTile
bind:group={currentTile}
name="ssh_gpg_keys"
value="ssh_gpg_keys"
on:change={onTileChanged}
regionLabel="float-start ps-2 py-1 text-surface-500"
regionLead="float-start ps-8 text-surface-500"
title={$_('settings.ssh_gpg_keys.label')}
>
<svelte:fragment slot="lead">
<Key24 fill="currentColor" class="inline" />
</svelte:fragment>
<span>{$_('settings.ssh_gpg_keys.label')}</span>
</AppRailTile>
<AppRailTile
bind:group={currentTile}
name="appearance"
value="appearance"
on:change={onTileChanged}
regionLabel="float-start ps-2 py-1 text-surface-500"
regionLead="float-start ps-8 text-surface-500"
title={$_('settings.appearance.label')}
>
<svelte:fragment slot="lead">
<Paintbrush24 fill="currentColor" class="inline" />
</svelte:fragment>
<span>{$_('settings.appearance.label')}</span>
</AppRailTile>
<AppRailTile
bind:group={currentTile}
name="notifications"
value="notifications"
on:change={onTileChanged}
regionLabel="float-start ps-2 py-1 text-surface-500"
regionLead="float-start ps-8 text-surface-500"
title={$_('settings.notifications.label')}
>
<svelte:fragment slot="lead">
<Bell24 fill="currentColor" class="inline" />
</svelte:fragment>
<span>{$_('settings.notifications.label')}</span>
</AppRailTile>
<svelte:fragment slot="trail">
<select bind:value={$locale} class="select">
{#each $locales as locale}
<option value={locale}>{locale}</option>
{/each}
</select>
<AppRailAnchor
href="https://matrix.to/#/#general-forgefed:matrix.batsense.net"
target="_blank"
rel="noreferrer"
>
Matrix
</AppRailAnchor>
<AppRailAnchor href="https://forgefed.org" target="_blank" rel="noreferrer">
ForgeFed
</AppRailAnchor>
<AppRailAnchor href="https://codeberg.org/anvil/anvil" target="_blank" rel="noreferrer">
Code
</AppRailAnchor>
</svelte:fragment>
</AppRail>

View file

@ -172,5 +172,23 @@
}, },
"reset": "" "reset": ""
} }
},
"settings": {
"headline": "",
"account": {
"label": ""
},
"appearance": {
"label": ""
},
"notifications": {
"label": ""
},
"profile": {
"label": ""
},
"ssh_gpg_keys": {
"label": ""
}
} }
} }

View file

@ -172,5 +172,23 @@
}, },
"reset": "" "reset": ""
} }
},
"settings": {
"headline": "",
"account": {
"label": ""
},
"appearance": {
"label": ""
},
"notifications": {
"label": ""
},
"profile": {
"label": ""
},
"ssh_gpg_keys": {
"label": ""
}
} }
} }

View file

@ -172,5 +172,23 @@
}, },
"reset": "Reset passphrase" "reset": "Reset passphrase"
} }
},
"settings": {
"headline": "Settings",
"account": {
"label": "Account"
},
"appearance": {
"label": "Appearance"
},
"notifications": {
"label": "Notifications"
},
"profile": {
"label": "Profile"
},
"ssh_gpg_keys": {
"label": "SSH/GPG Keys"
}
} }
} }

View file

@ -172,5 +172,23 @@
}, },
"reset": "" "reset": ""
} }
},
"settings": {
"headline": "",
"account": {
"label": ""
},
"appearance": {
"label": ""
},
"notifications": {
"label": ""
},
"profile": {
"label": ""
},
"ssh_gpg_keys": {
"label": ""
}
} }
} }

View file

@ -172,5 +172,23 @@
}, },
"reset": "" "reset": ""
} }
},
"settings": {
"headline": "",
"account": {
"label": ""
},
"appearance": {
"label": ""
},
"notifications": {
"label": ""
},
"profile": {
"label": ""
},
"ssh_gpg_keys": {
"label": ""
}
} }
} }

View file

@ -0,0 +1,125 @@
/* Component test for SettingsSidebar atom.
* 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 <http://www.gnu.org/licenses/>.
*/
import '@testing-library/jest-dom';
import { render, screen } from '@testing-library/svelte';
import { get, readable } from 'svelte/store';
import { init, locale, register } from 'svelte-i18n';
import SettingsSidebar from '../../../src/lib/components/atoms/SettingsSidebar.svelte';
import enMessages from '../../../src/lib/i18n/locales/en.json';
describe('SettingsSidebar.svelte', () => {
beforeEach(() => {
register('en', () => import('../../../src/lib/i18n/locales/en.json'));
init({ fallbackLocale: 'en', initialLocale: 'en' });
locale.set('en');
});
it('should mount', () => {
// Arrange
// See https://testing-library.com/docs/svelte-testing-library/example#contexts
const drawerStore = readable([]);
// Act
const { container } = render(SettingsSidebar, {
context: new Map([['drawerStore', drawerStore]])
});
// Assert
expect(container).toBeTruthy();
});
it('should have a headline', () => {
// Arrange
// See https://testing-library.com/docs/svelte-testing-library/example#contexts
const drawerStore = readable([]);
// Act
render(SettingsSidebar, {
context: new Map([['drawerStore', drawerStore]])
});
// Assert
expect(screen.getByText(enMessages.settings.headline)).toBeInTheDocument();
});
it('should have a profile tile', () => {
// Arrange
// See https://testing-library.com/docs/svelte-testing-library/example#contexts
const drawerStore = readable([]);
// Act
render(SettingsSidebar, {
context: new Map([['drawerStore', drawerStore]])
});
// Assert
expect(screen.getByText(enMessages.settings.profile.label)).toBeInTheDocument();
});
it('should have an account tile', () => {
// Arrange
// See https://testing-library.com/docs/svelte-testing-library/example#contexts
const drawerStore = readable([]);
// Act
render(SettingsSidebar, {
context: new Map([['drawerStore', drawerStore]])
});
// Assert
expect(screen.getByText(enMessages.settings.account.label)).toBeInTheDocument();
});
it('should have a SSH/GPG keys tile', () => {
// Arrange
// See https://testing-library.com/docs/svelte-testing-library/example#contexts
const drawerStore = readable([]);
// Act
render(SettingsSidebar, {
context: new Map([['drawerStore', drawerStore]])
});
// Assert
expect(screen.getByText(enMessages.settings.ssh_gpg_keys.label)).toBeInTheDocument();
});
it('should have an appearance tile', () => {
// Arrange
// See https://testing-library.com/docs/svelte-testing-library/example#contexts
const drawerStore = readable([]);
// Act
render(SettingsSidebar, {
context: new Map([['drawerStore', drawerStore]])
});
// Assert
expect(screen.getByText(enMessages.settings.appearance.label)).toBeInTheDocument();
});
it('should have a notifications tile', () => {
// Arrange
// See https://testing-library.com/docs/svelte-testing-library/example#contexts
const drawerStore = readable([]);
// Act
render(SettingsSidebar, {
context: new Map([['drawerStore', drawerStore]])
});
// Assert
expect(screen.getByText(enMessages.settings.notifications.label)).toBeInTheDocument();
});
});