feat: extract SettingsProfile into component

This is taking care of the view when the Settings is selected for a profile.

Signed-off-by: André Jaenisch <andre.jaenisch@posteo.de>
This commit is contained in:
André Jaenisch 2024-07-26 16:38:46 +02:00
parent 841ddd5a17
commit 581ab76ca7
No known key found for this signature in database
GPG key ID: 5A668E771F1ED854
9 changed files with 409 additions and 5 deletions

View file

@ -0,0 +1,22 @@
<!--
Settings 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 <http://www.gnu.org/licenses/>.
-->
<script>
import SettingsSidebar from '../atoms/SettingsSidebar.svelte';
import SettingsProfile from './SettingsProfile.svelte';
</script>
<div class="flex bg-surface-50">
<SettingsSidebar />
<SettingsProfile />
</div>

View file

@ -0,0 +1,121 @@
<!--
SettingsProfile 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 <http://www.gnu.org/licenses/>.
-->
<script>
import { _ } from 'svelte-i18n';
import { Person24, Upload16, XCircleFill12 } from 'svelte-octicons';
</script>
<div class="flex flex-col flex-1 gap-4 pe-8 pb-8 pt-20 bg-surface-100">
<div class="flex text-surface-500 text-xl font-semibold">{$_('settings.profile.headline')}</div>
<div class="flex flex-col gap-6">
<div class="text-surface-500 font-semibold">{$_('settings.profile.avatar.headline')}</div>
<div class="flex flex-col px-2">
<div class="flex gap-4">
<Person24 fill="currentColor" class="h-16 w-16 text-white bg-surface-400 rounded-full" />
<button
type="button"
class="btn flex gap-4 justify-between px-4 bg-surface-50 border-surface-100"
>
<Upload16 fill="currentColor" />
<span>{$_('settings.profile.avatar.upload')}</span>
</button>
</div>
<div>
<button type="button" class="btn p-0 text-warning-700">
<XCircleFill12 fill="currentColor" />
<span>{$_('settings.profile.avatar.remove')}</span>
</button>
</div>
</div>
<div>
<div class="flex gap-8">
<div class="flex flex-col gap-2 grow">
<span class="text-surface-500 font-semibold">{$_('settings.profile.name.label')}</span>
<input
type="text"
placeholder={$_('settings.profile.name.placeholder')}
class="input bg-white placeholder:text-surface-300"
/>
</div>
<div class="flex flex-col gap-2 flex-1 shrink basis-40">
<span class="text-surface-500 font-semibold">{$_('settings.profile.pronouns.label')}</span
>
<input type="text" class="input bg-white" />
</div>
</div>
</div>
<div>
<div class="flex flex-col gap-2">
<span class="text-surface-500 font-semibold">{$_('settings.profile.bio.label')}</span>
<textarea
placeholder={$_('settings.profile.bio.placeholder')}
rows="4"
class="placeholder:text-surface-300"
></textarea>
</div>
</div>
<div class="flex flex-col">
<div class="text-surface-500 font-semibold">{$_('settings.profile.extra.headline')}</div>
<div class="text-surface-500">{$_('settings.profile.extra.hint')}</div>
<div class="flex gap-2 py-1">
<input
type="text"
class="input bg-white shrink basis-40 placeholder:text-surface-300"
placeholder={$_('settings.profile.extra.label.placeholder')}
/>
<input
type="text"
class="input bg-white grow placeholder:text-surface-300"
placeholder={$_('settings.profile.extra.content.placeholder')}
/>
</div>
<div class="flex gap-2 py-1">
<input
type="text"
class="input bg-white shrink basis-40 placeholder:text-surface-300"
placeholder={$_('settings.profile.extra.label.placeholder')}
/>
<input
type="text"
class="input bg-white grow placeholder:text-surface-300"
placeholder={$_('settings.profile.extra.content.placeholder')}
/>
</div>
<div class="flex gap-2 py-1">
<input
type="text"
class="input bg-white shrink basis-40 placeholder:text-surface-300"
placeholder={$_('settings.profile.extra.label.placeholder')}
/>
<input
type="text"
class="input bg-white grow placeholder:text-surface-300"
placeholder={$_('settings.profile.extra.content.placeholder')}
/>
</div>
<div class="flex gap-2 py-1">
<input
type="text"
class="input bg-white shrink basis-40 placeholder:text-surface-300"
placeholder={$_('settings.profile.extra.label.placeholder')}
/>
<input
type="text"
class="input bg-white grow placeholder:text-surface-300"
placeholder={$_('settings.profile.extra.content.placeholder')}
/>
</div>
</div>
</div>
</div>

View file

@ -185,7 +185,34 @@
"label": "" "label": ""
}, },
"profile": { "profile": {
"avatar": {
"headline": "",
"remove": "",
"upload": ""
},
"bio": {
"label": "",
"placeholder": ""
},
"extra": {
"content": {
"placeholder": ""
},
"headline": "",
"hint": "",
"label": {
"placeholder": ""
}
},
"headline": "",
"label": "",
"name": {
"label": "",
"placeholder": ""
},
"pronouns": {
"label": "" "label": ""
}
}, },
"ssh_gpg_keys": { "ssh_gpg_keys": {
"label": "" "label": ""

View file

@ -185,7 +185,34 @@
"label": "" "label": ""
}, },
"profile": { "profile": {
"avatar": {
"headline": "",
"remove": "",
"upload": ""
},
"bio": {
"label": "",
"placeholder": ""
},
"extra": {
"content": {
"placeholder": ""
},
"headline": "",
"hint": "",
"label": {
"placeholder": ""
}
},
"headline": "",
"label": "",
"name": {
"label": "",
"placeholder": ""
},
"pronouns": {
"label": "" "label": ""
}
}, },
"ssh_gpg_keys": { "ssh_gpg_keys": {
"label": "" "label": ""

View file

@ -185,7 +185,34 @@
"label": "Notifications" "label": "Notifications"
}, },
"profile": { "profile": {
"label": "Profile" "avatar": {
"headline": "Avatar",
"remove": "remove",
"upload": "Upload image"
},
"bio": {
"label": "Bio",
"placeholder": "Tell us something about you in less than 250 characters..."
},
"extra": {
"content": {
"placeholder": "Content"
},
"headline": "Extra fields",
"hint": "Your homepage, age, location, anything you want.",
"label": {
"placeholder": "Label"
}
},
"headline": "Profile",
"label": "Profile",
"name": {
"label": "Name",
"placeholder": "Name others recognize you by"
},
"pronouns": {
"label": "Pronouns"
}
}, },
"ssh_gpg_keys": { "ssh_gpg_keys": {
"label": "SSH/GPG Keys" "label": "SSH/GPG Keys"

View file

@ -185,7 +185,34 @@
"label": "" "label": ""
}, },
"profile": { "profile": {
"avatar": {
"headline": "",
"remove": "",
"upload": ""
},
"bio": {
"label": "",
"placeholder": ""
},
"extra": {
"content": {
"placeholder": ""
},
"headline": "",
"hint": "",
"label": {
"placeholder": ""
}
},
"headline": "",
"label": "",
"name": {
"label": "",
"placeholder": ""
},
"pronouns": {
"label": "" "label": ""
}
}, },
"ssh_gpg_keys": { "ssh_gpg_keys": {
"label": "" "label": ""

View file

@ -185,7 +185,34 @@
"label": "" "label": ""
}, },
"profile": { "profile": {
"avatar": {
"headline": "",
"remove": "",
"upload": ""
},
"bio": {
"label": "",
"placeholder": ""
},
"extra": {
"content": {
"placeholder": ""
},
"headline": "",
"hint": "",
"label": {
"placeholder": ""
}
},
"headline": "",
"label": "",
"name": {
"label": "",
"placeholder": ""
},
"pronouns": {
"label": "" "label": ""
}
}, },
"ssh_gpg_keys": { "ssh_gpg_keys": {
"label": "" "label": ""

View file

@ -0,0 +1,26 @@
/* Stories for SettingsProfile 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 <http://www.gnu.org/licenses/>.
*/
import type { Meta, StoryObj } from '@storybook/svelte';
import SettingsProfile from '$lib/components/molecules/SettingsProfile.svelte';
const meta = {
title: 'Molecules/SettingsProfile',
component: SettingsProfile,
tags: ['autodocs']
} satisfies Meta<SettingsProfile>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Plain: Story = {};

View file

@ -0,0 +1,100 @@
/* Component test for SettingsProfile 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 <http://www.gnu.org/licenses/>.
*/
import '@testing-library/jest-dom';
import { render, screen } from '@testing-library/svelte';
import { init, locale, register } from 'svelte-i18n';
import SettingsProfile from '../../../src/lib/components/molecules/SettingsProfile.svelte';
import enMessages from '../../../src/lib/i18n/locales/en.json';
describe('SettingsProfile.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(SettingsProfile);
// Assert
expect(container).toBeTruthy();
});
it('should have an avatar section', () => {
// Arrange
// Nothing to prepare
// Act
render(SettingsProfile);
// Assert
expect(screen.getByText(enMessages.settings.profile.avatar.headline)).toBeInTheDocument();
});
it('should have an avatar upload button', () => {
// Arrange
// Nothing to prepare
// Act
render(SettingsProfile);
// Assert
expect(
screen.getByRole('button', { name: enMessages.settings.profile.avatar.upload })
).toBeInTheDocument();
});
it('should have an avatar remove button', () => {
// Arrange
// Nothing to prepare
// Act
render(SettingsProfile);
// Assert
expect(
screen.getByRole('button', { name: enMessages.settings.profile.avatar.remove })
).toBeInTheDocument();
});
it('should have a name input', () => {
// Arrange
// Nothing to prepare
// Act
render(SettingsProfile);
// Assert
expect(
screen.getByPlaceholderText(enMessages.settings.profile.name.placeholder)
).toBeInTheDocument();
});
it.skip('should have a pronouns input', () => {
// Arrange
// Nothing to prepare
// Act
render(SettingsProfile);
// Assert
expect(
screen.getByRole('textbox', { name: enMessages.settings.profile.pronouns.label })
).toBeInTheDocument();
});
});