1 Commits
Author SHA1 Message Date
jakob.scheidandGitea 59ffa4b043 chore(licenses): add license headers to setup scripts 2026-07-28 20:16:13 +02:00
14 changed files with 861 additions and 1209 deletions
-38
View File
@@ -1,38 +0,0 @@
<!--
Copyright 2026 Seekra
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<path
stroke="currentColor"
stroke-width="2"
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
d="
M6 4
h12
a4 4 0 0 1 4 4
v8
a4 4 0 0 1 -4 4
h-12
a4 4 0 0 1 -4 -4
v-8
a4 4 0 0 1 4 -4
m2 0
v16
"
/>
</svg>

Before

Width:  |  Height:  |  Size: 1.0 KiB

@@ -39,7 +39,7 @@ vi.mock('@/features/icons/components/Icon.vue', () => ({
} }
})); }));
describe('LanguageSwitchButton', () => { describe('LanguageSwitchButton.vue', () => {
beforeEach(() => { beforeEach(() => {
vi.clearAllMocks(); vi.clearAllMocks();
localStorage.clear(); localStorage.clear();
@@ -17,7 +17,6 @@ limitations under the License.
import { describe, test, expect } from 'vitest'; import { describe, test, expect } from 'vitest';
import { validateSettingsConfig, validateEntry, validateSelectionOptions, assertType, assertString } from '../settingsValidator'; import { validateSettingsConfig, validateEntry, validateSelectionOptions, assertType, assertString } from '../settingsValidator';
describe('settingsValidator', () => {
describe('validateSettingsConfig', () => { describe('validateSettingsConfig', () => {
test.for([ test.for([
{ raw: false, expected: false }, { raw: false, expected: false },
@@ -557,30 +556,6 @@ 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 }
@@ -640,34 +615,6 @@ 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' }
@@ -809,4 +756,3 @@ describe('settingsValidator', () => {
expect(() => assertString(value)).throws(Error); expect(() => assertString(value)).throws(Error);
}); });
}); });
});
@@ -73,27 +73,12 @@ 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`);
}; };
}
}; };
} }
} }
+1 -46
View File
@@ -14,60 +14,15 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
--> -->
<script setup>
import SidebarExpandButton from './SidebarExpandButton.vue';
const props = defineProps({
'expanded': {
default: false,
required: false,
type: Boolean
}
});
const emit = defineEmits(['toggleExpanded']);
const toggleSidebar = function toggleSidebar () {
emit('toggleExpanded');
};
</script>
<template> <template>
<nav class="sidebar" :class="{ expanded }"> <nav class="sidebar">
<div class="sidebar-controls">
<SidebarExpandButton @click="toggleSidebar" class="sidebar-expand-button" />
</div>
<div class="sidebar-content" v-if="props.expanded">
<slot /> <slot />
</div>
</nav> </nav>
</template> </template>
<style scoped> <style scoped>
.sidebar { .sidebar {
border-right: 1px solid var(--border); border-right: 1px solid var(--border);
}
.sidebar-controls {
display: flex;
align-items: center;
justify-content: end;
padding: 1em 20px;
padding-bottom: 0;
margin-bottom: 8px;
}
.sidebar:not(.expanded) .sidebar-controls {
padding: 1em;
}
@media (max-width: 48rem) {
.sidebar:not(.expanded) .sidebar-expand-button {
display: none;
}
}
.sidebar-content {
padding: 20px; padding: 20px;
padding-top: 0;
} }
</style> </style>
@@ -1,41 +0,0 @@
<!--
Copyright 2026 Seekra
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script setup>
import Icon from '@/features/icons/components/Icon.vue';
const emit = defineEmits(['click']);
const click = function click (event) {
emit('click', event);
};
</script>
<template>
<button class="button sidebar-expand-button">
<Icon name="sidebar-expand" @click="click" />
</button>
</template>
<style scoped>
.sidebar-expand-button {
display: flex;
justify-content: center;
align-items: center;
padding: 4px;
border-radius: 10px;
}
</style>
+3 -64
View File
@@ -16,30 +16,11 @@ limitations under the License.
<script setup> <script setup>
import Sidebar from '@/features/sidebar/components/Sidebar.vue'; import Sidebar from '@/features/sidebar/components/Sidebar.vue';
import SidebarExpandButton from '@/features/sidebar/components/SidebarExpandButton.vue';
import { ref } from 'vue';
const props = defineProps({
'expanded': {
default: false,
required: false,
type: Boolean
}
});
const expanded = ref(props.expanded);
const toggleExpanded = function toggleExpanded () {
expanded.value = !expanded.value;
};
</script> </script>
<template> <template>
<div class="layout-container" :class="{ expanded }"> <div class="layout-container">
<div class="sidebar-expand-button-container"> <Sidebar>
<SidebarExpandButton class="sidebar-expand-button" @click="toggleExpanded" />
</div>
<Sidebar @toggle-expanded="toggleExpanded" :expanded="expanded" class="sidebar">
<slot name="sidebar" /> <slot name="sidebar" />
</Sidebar> </Sidebar>
<main class="main-content"> <main class="main-content">
@@ -51,53 +32,11 @@ const toggleExpanded = function toggleExpanded () {
<style scoped> <style scoped>
.layout-container { .layout-container {
display: grid; display: grid;
grid-template-columns: calc(32px + 2em) 1fr; grid-template-columns: min(24%, 280px) 1fr;
grid-template-rows: auto 1fr;
grid-template-areas:
"sidebar-expand sidebar-expand"
"sidebar main-content";
border-top: 1px solid var(--border); border-top: 1px solid var(--border);
} }
.layout-container.expanded {
grid-template-columns: min(24%, 280px) 1fr;
}
.sidebar-expand-button-container {
grid-area: sidebar-expand;
display: none;
}
.sidebar {
grid-area: sidebar;
}
@media (max-width: 48rem) {
.layout-container {
grid-template-columns: 0 1fr;
}
.layout-container.expanded {
grid-template-columns: 1fr 0;
}
.layout-container:not(.expanded) .sidebar-expand-button-container {
justify-content: end;
display: block;
padding: 20px;
}
.layout-container:not(.expanded) .main-content {
padding-top: 0;
}
.layout-container.expanded .main-content {
display: none;
}
}
.main-content { .main-content {
grid-area: main-content;
padding: 20px; padding: 20px;
} }
</style> </style>
+1 -24
View File
@@ -38,28 +38,5 @@
} }
} }
}, },
"slogan": "Hecho para buscar.", "slogan": "Hecho para buscar."
"settings": {
"input": {
"done": {
"title": "Guardar valor",
"ariaLabel": "Guarda el valor introducido"
}
},
"switch": {
"title": "Cambiar valor",
"ariaLabel": "Cambia el valor"
},
"pages": {
"link": {
"ariaLabel": "Va a la página de configuración {page}"
}
},
"noSectionSelected": "No se ha seleccionado ninguna sección de configuración.",
"selection": {
"option": {
"ariaLabel": "Selecciona la opción {option}"
}
}
}
} }
+1 -24
View File
@@ -38,28 +38,5 @@
} }
} }
}, },
"slogan": "Conçu pour chercher.", "slogan": "Conçu pour chercher."
"settings": {
"input": {
"done": {
"title": "Enregistrer la valeur",
"ariaLabel": "Enregistre la valeur saisie"
}
},
"switch": {
"title": "Basculer la valeur",
"ariaLabel": "Bascule la valeur"
},
"pages": {
"link": {
"ariaLabel": "Accéder à la page de paramètres {page}"
}
},
"noSectionSelected": "Aucune section des paramètres n'est sélectionnée.",
"selection": {
"option": {
"ariaLabel": "Sélectionne l'option {option}"
}
}
}
} }
+1 -24
View File
@@ -38,28 +38,5 @@
} }
} }
}, },
"slogan": "Costruito per cercare.", "slogan": "Costruito per cercare."
"settings": {
"input": {
"done": {
"title": "Salva valore",
"ariaLabel": "Salva il valore inserito"
}
},
"switch": {
"title": "Attiva/disattiva valore",
"ariaLabel": "Attiva o disattiva il valore"
},
"pages": {
"link": {
"ariaLabel": "Vai alla pagina delle impostazioni {page}"
}
},
"noSectionSelected": "Nessuna sezione delle impostazioni è selezionata.",
"selection": {
"option": {
"ariaLabel": "Seleziona l'opzione {option}"
}
}
}
} }
+1 -24
View File
@@ -38,28 +38,5 @@
} }
} }
}, },
"slogan": "Feito para pesquisar.", "slogan": "Feito para pesquisar."
"settings": {
"input": {
"done": {
"title": "Guardar valor",
"ariaLabel": "Guarda o valor introduzido"
}
},
"switch": {
"title": "Alternar valor",
"ariaLabel": "Alterna o valor"
},
"pages": {
"link": {
"ariaLabel": "Ir para a página de definições {page}"
}
},
"noSectionSelected": "Nenhuma secção de definições está selecionada.",
"selection": {
"option": {
"ariaLabel": "Seleciona a opção {option}"
}
}
}
} }
+2 -2
View File
@@ -25,7 +25,7 @@ body {
text-decoration: none; text-decoration: none;
} }
.link:hover:not(.button-link), .link:focus-visible:not(.button-link) { .link:hover:not(.button-link), .link:focus:not(.button-link) {
outline: none; outline: none;
text-decoration: underline; text-decoration: underline;
} }
@@ -78,7 +78,7 @@ input {
color: inherit; color: inherit;
} }
.button:focus-visible { .button:focus {
background-color: var(--light-hover); background-color: var(--light-hover);
outline: none; outline: none;
} }
+1 -3
View File
@@ -14,10 +14,9 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import { describe, expect, test } from 'vitest'; import { expect, test } from 'vitest';
import { ensureUnit } from '../cssDimensions'; import { ensureUnit } from '../cssDimensions';
describe('cssDimensions', () => {
test.for([ test.for([
{ dimension: null, expected: '0px' }, { dimension: null, expected: '0px' },
{ dimension: undefined, expected: '0px' }, { dimension: undefined, expected: '0px' },
@@ -121,4 +120,3 @@ describe('cssDimensions', () => {
])('ensureUnit returns $expected with input $dimension', ({ dimension, expected }) => { ])('ensureUnit returns $expected with input $dimension', ({ dimension, expected }) => {
expect(ensureUnit(dimension)).toBe(expected); expect(ensureUnit(dimension)).toBe(expected);
}); });
});
+5 -5
View File
@@ -14,11 +14,10 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import { describe, expect, test } from 'vitest'; import { expect, test } from 'vitest';
import getCurrentLanguage from '../currentLanguage'; import getCurrentLanguage from '../currentLanguage';
describe('currentLanguage', () => { const locales = [
test.for([
{ navigatorLanguage: 'en', localStorageLanguage: null, expected: 'en'}, { navigatorLanguage: 'en', localStorageLanguage: null, expected: 'en'},
{ navigatorLanguage: 'de', localStorageLanguage: null, expected: 'de'}, { navigatorLanguage: 'de', localStorageLanguage: null, expected: 'de'},
{ navigatorLanguage: 'fr', localStorageLanguage: null, expected: 'fr'}, { navigatorLanguage: 'fr', localStorageLanguage: null, expected: 'fr'},
@@ -46,7 +45,9 @@ describe('currentLanguage', () => {
{ navigatorLanguage: 'de-de', localStorageLanguage: 'en', expected: 'en'}, { navigatorLanguage: 'de-de', localStorageLanguage: 'en', expected: 'en'},
{ navigatorLanguage: 'zh-Hans-CN', localStorageLanguage: 'fr', expected: 'fr'}, { navigatorLanguage: 'zh-Hans-CN', localStorageLanguage: 'fr', expected: 'fr'},
{ navigatorLanguage: 'en-US-u-ca-gregory', localStorageLanguage: 'zh', expected: 'zh'} { navigatorLanguage: 'en-US-u-ca-gregory', localStorageLanguage: 'zh', expected: 'zh'}
])('returns the language $expected (navigator: $navigatorLanguage; local storage: $localStorageLanguage)', ({ navigatorLanguage, localStorageLanguage, expected }) => { ];
test.for(locales)('returns the language $expected (navigator: $navigatorLanguage; local storage: $localStorageLanguage)', ({ navigatorLanguage, localStorageLanguage, expected }) => {
Object.defineProperty(navigator, 'language', { Object.defineProperty(navigator, 'language', {
value: navigatorLanguage, value: navigatorLanguage,
configurable: true configurable: true
@@ -58,4 +59,3 @@ describe('currentLanguage', () => {
expect(getCurrentLanguage()).toBe(expected); expect(getCurrentLanguage()).toBe(expected);
}); });
});