Author SHA1 Message Date
jakob.scheid 4b010d03ac feat(settings): toggle sidebar on small screens when section is selected
The settings view now hides the sidebar on small screens when a settings
section is selected.
2026-08-02 13:58:37 +02:00
jakob.scheid 813cc7c7fc feat(sidebar): allow left sidebar layout content to toggle sidebar 2026-08-02 13:57:11 +02:00
jakob.scheid a77bbec3fa refactor(sidebar): rename sidebar toggling function
Renamed the sidebar toggling function in the left sidebar layout to
toggleSidebar.
2026-08-02 13:56:25 +02:00
jakob.scheidandGitea 447207e5f0 Merge pull request 'Feat(sidebar): implement sidebar toggling' (#157) from feature/expandable-sidebar into main
Deploy on dev / Deploy on dev (push) Successful in 39s
Reviewed-on: #157
Reviewed-by: Jakob Gregory
2026-07-31 21:00:19 +02:00
jakob.scheidandGitea 0939379c0a feat(sidebar): decrease horizontal padding when sidebar is not expanded
Set the horizontal padding of the unexpanded sidebar to 1em.
2026-07-31 20:59:19 +02:00
jakob.scheidandGitea 48e979ac64 fix(sidebar): fix main content displaying
Do not show main content on small screens when the sidebar is expanded.
2026-07-31 20:59:19 +02:00
jakob.scheidandGitea 0a58944157 feat(sidebar): add sidebar expand button to left sidebar layout
Added a sidebar expand button to the left sidebar layout that is shown
on small screens when the sidebar is not expanded.
2026-07-31 20:59:19 +02:00
jakob.scheidandGitea 63d9e31d29 fix(sidebar): do not show sidebar expanding button on small screens when sidebar is not expanded 2026-07-31 20:59:19 +02:00
jakob.scheidandGitea e43784bff0 feat(sidebar): implement sidebar visibility toggling 2026-07-31 20:59:19 +02:00
jakob.scheidandGitea 5b1f2b57a7 feat(sidebar): add sidebar expand button
Added a button to expand the sidebar to the sidebar and reorganized
sidebar elements accordingly.
2026-07-31 20:59:19 +02:00
jakob.scheidandGitea c70e285026 feat(icons): add sidebar expanding icon 2026-07-31 20:59:19 +02:00
jakob.scheidandGitea 8f83efb16b Merge pull request 'Fix(settings): settings validator selection setting default values array handling' (#155) from fix/settings-validator-selection-default-values-array into main
Deploy on dev / Deploy on dev (push) Successful in 36s
Reviewed-on: #155
Reviewed-by: Jakob Gregory
2026-07-31 20:58:29 +02:00
jakob.scheid f41c5c407f test(settings): add settings validator test cases
Added test cases to the settings validator unit test to test the
selection setting default value array handling when allowMultiple is
true.
2026-07-30 10:45:58 +02:00
jakob.scheid 35bfedbd6b fix(settings): expect array default values for multiple choice selections 2026-07-30 10:43:47 +02:00
4 changed files with 84 additions and 12 deletions
@@ -557,6 +557,30 @@ describe('settingsValidator', () => {
{ name: 'maybe', i18n: 'selectSomething.options.maybe' } { name: 'maybe', i18n: 'selectSomething.options.maybe' }
] }], ] }],
[{ name: 'selectMultiple', type: 'selection', i18n: 'selectMultiple.title', default: ['1', '2', '3'], allowMultiple: true, options: [
{ name: '1', i18n: 'selectMultiple.options.1' },
{ name: '2', i18n: 'selectMultiple.options.2' },
{ name: '3', i18n: 'selectMultiple.options.3' }
] }],
[{ name: 'selectMultiple', type: 'selection', i18n: 'selectMultiple.title', default: ['2', '3'], allowMultiple: true, options: [
{ name: '1', i18n: 'selectMultiple.options.1' },
{ name: '2', i18n: 'selectMultiple.options.2' },
{ name: '3', i18n: 'selectMultiple.options.3' }
] }],
[{ name: 'selectMultiple', type: 'selection', i18n: 'selectMultiple.title', default: ['2'], allowMultiple: true, options: [
{ name: '1', i18n: 'selectMultiple.options.1' },
{ name: '2', i18n: 'selectMultiple.options.2' },
{ name: '3', i18n: 'selectMultiple.options.3' }
] }],
[{ name: 'selectMultiple', type: 'selection', i18n: 'selectMultiple.title', default: [], allowMultiple: true, options: [
{ name: '1', i18n: 'selectMultiple.options.1' },
{ name: '2', i18n: 'selectMultiple.options.2' },
{ name: '3', i18n: 'selectMultiple.options.3' }
] }],
[{ name: 'aSection', type: 'section', i18n: 'sections.aSection.title', content: [] }], [{ name: 'aSection', type: 'section', i18n: 'sections.aSection.title', content: [] }],
[{ name: 'aSection', type: 'section', i18n: 'sections.aSection.title', content: [ [{ name: 'aSection', type: 'section', i18n: 'sections.aSection.title', content: [
{ name: 'enableFeature42', type: 'bool', i18n: 'feature.42.enable', default: true } { name: 'enableFeature42', type: 'bool', i18n: 'feature.42.enable', default: true }
@@ -616,6 +640,34 @@ describe('settingsValidator', () => {
[{ name: 'selectSomething', type: 'selection', i18n: 'selectSomething.title', default: 'a', options: true }], [{ name: 'selectSomething', type: 'selection', i18n: 'selectSomething.title', default: 'a', options: true }],
[{ name: 'selectSomething', type: 'selection', i18n: 'selectSomething.title', default: 'a', options: [] }], [{ name: 'selectSomething', type: 'selection', i18n: 'selectSomething.title', default: 'a', options: [] }],
[{ name: 'selectSomething', type: 'selection', i18n: 'selectSomething.title', default: ['a'], options: [
{ name: 'a', i18n: 'a' },
{ name: 'b', i18n: 'b' }
] }],
[{ name: 'selectSomething', type: 'selection', i18n: 'selectSomething.title', default: ['a', 'b'], options: [
{ name: 'a', i18n: 'a' },
{ name: 'b', i18n: 'b' }
] }],
[{ name: 'selectSomething', type: 'selection', i18n: 'selectSomething.title', allowMultiple: true, default: 'a', options: [
{ name: 'a', i18n: 'a' },
{ name: 'b', i18n: 'b' }
] }],
[{ name: 'selectSomething', type: 'selection', i18n: 'selectSomething.title', allowMultiple: true, default: 'a', options: [
{ name: 'a', i18n: 'a' },
{ name: 'b', i18n: 'b' }
] }],
[{ name: 'selectSomething', type: 'selection', i18n: 'selectSomething.title', allowMultiple: true, default: ['c'], options: [
{ name: 'a', i18n: 'a' },
{ name: 'b', i18n: 'b' }
] }],
[{ name: 'selectSomething', type: 'selection', i18n: 'selectSomething.title', allowMultiple: true, default: [1], options: [
{ name: 'a', i18n: 'a' },
{ name: 'b', i18n: 'b' }
] }],
[{ name: 'selectSomething', type: 'selection', i18n: 'selectSomething.title', allowMultiple: true, default: ['a', 1], options: [
{ name: 'a', i18n: 'a' },
{ name: 'b', i18n: 'b' }
] }],
[{ name: 'selectSomething', type: 'selection', i18n: 'selectSomething.title', default: 'c', options: [ [{ name: 'selectSomething', type: 'selection', i18n: 'selectSomething.title', default: 'c', options: [
{ name: 'a', i18n: 'a' }, { name: 'a', i18n: 'a' },
{ name: 'b', i18n: 'b' } { name: 'b', i18n: 'b' }
@@ -73,12 +73,27 @@ export const validateEntry = function validateEntry (entry, path) {
throw new Error(`[settings] "${path}.default" must be a string`); throw new Error(`[settings] "${path}.default" must be a string`);
} }
if (entry.type === 'selection') { if (entry.type === 'selection') {
if (entry.allowMultiple) {
if (!Array.isArray(entry.default)) {
throw new Error(`[settings] "${path}.default" must be an array`);
}
const allOptions = entry.options.map((option) => option.name);
entry.default.forEach((defaultValue, index) => {
if (typeof defaultValue !== 'string') {
throw new Error(`[settings] "${path}.default[${index}]" must be a string`);
}
if (!allOptions.includes(defaultValue)) {
throw new Error(`[settings] option "${path}.default[${index}]" does not exist`);
}
});
} else {
if (typeof entry.default !== 'string') { if (typeof entry.default !== 'string') {
throw new Error(`[settings] "${path}.default" must be a string`); throw new Error(`[settings] "${path}.default" must be a string`);
}; };
if (!entry.options.map((option) => option.name).includes(entry.default)) { if (!entry.options.map((option) => option.name).includes(entry.default)) {
throw new Error(`[settings] option "${path}.default" does not exist`); throw new Error(`[settings] option "${path}.default" does not exist`);
}; };
}
}; };
} }
} }
+6 -1
View File
@@ -61,6 +61,10 @@ onMounted(async () => {
}); });
settingsLoaded.value = true; settingsLoaded.value = true;
}); });
const toggleSidebarIfSmallScreen = function toggleSidebarIfSmallScreen (toggleSidebarFunction) {
if (matchMedia('(max-width: 48rem)').matches) toggleSidebarFunction();
};
</script> </script>
<template> <template>
@@ -71,13 +75,14 @@ onMounted(async () => {
</h1> </h1>
</header> </header>
<LeftSidebarLayout class="layout"> <LeftSidebarLayout class="layout">
<template #sidebar> <template #sidebar="{ toggleSidebar }">
<ul class="sidebar-sections-list"> <ul class="sidebar-sections-list">
<li v-for="section in settings"> <li v-for="section in settings">
<RouterLink <RouterLink
:to="`/settings/${section.name}`" :to="`/settings/${section.name}`"
class="button button-link link sidebar-section" class="button button-link link sidebar-section"
:class="{ active: activeSection === section.name }" :class="{ active: activeSection === section.name }"
@click="toggleSidebarIfSmallScreen(toggleSidebar)"
> >
{{ t(section.i18n) }} {{ t(section.i18n) }}
</RouterLink> </RouterLink>
+5 -5
View File
@@ -29,7 +29,7 @@ const props = defineProps({
const expanded = ref(props.expanded); const expanded = ref(props.expanded);
const toggleExpanded = function toggleExpanded () { const toggleSidebar = function toggleSidebar () {
expanded.value = !expanded.value; expanded.value = !expanded.value;
}; };
</script> </script>
@@ -37,13 +37,13 @@ const toggleExpanded = function toggleExpanded () {
<template> <template>
<div class="layout-container" :class="{ expanded }"> <div class="layout-container" :class="{ expanded }">
<div class="sidebar-expand-button-container"> <div class="sidebar-expand-button-container">
<SidebarExpandButton class="sidebar-expand-button" @click="toggleExpanded" /> <SidebarExpandButton class="sidebar-expand-button" @click="toggleSidebar" />
</div> </div>
<Sidebar @toggle-expanded="toggleExpanded" :expanded="expanded" class="sidebar"> <Sidebar @toggle-expanded="toggleSidebar" :expanded="expanded" class="sidebar">
<slot name="sidebar" /> <slot name="sidebar" :toggleSidebar="toggleSidebar" />
</Sidebar> </Sidebar>
<main class="main-content"> <main class="main-content">
<slot /> <slot :toggleSidebar="toggleSidebar" />
</main> </main>
</div> </div>
</template> </template>