Author SHA1 Message Date
jakob.scheidandGitea 59ffa4b043 chore(licenses): add license headers to setup scripts 2026-07-28 20:16:13 +02:00
23 changed files with 864 additions and 1485 deletions
-16
View File
@@ -1,16 +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.
VITE_ASSETS_BUILD_ID=2026-08-04-76a067e
VITE_ASSETS_BASE_URL=https://assets.seekra.jcloud-services.ddns.net
-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

-22
View File
@@ -1,22 +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.
*/
export const getAssetsUrl = function getAssetsUrl () {
return new URL(
`${import.meta.env.VITE_ASSETS_BUILD_ID}/`,
import.meta.env.VITE_ASSETS_BASE_URL
).href;
};
@@ -39,7 +39,7 @@ vi.mock('@/features/icons/components/Icon.vue', () => ({
}
}));
describe('LanguageSwitchButton', () => {
describe('LanguageSwitchButton.vue', () => {
beforeEach(() => {
vi.clearAllMocks();
localStorage.clear();
@@ -1,94 +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.
*/
import { useSettingsConfigCacheStore } from '../../stores/settingsConfigCacheStore';
import { useSettingsStore } from '../../stores/settingsStore';
import { useSettings } from '../useSettings';
import { createTestingPinia } from '@pinia/testing';
import { setActivePinia } from 'pinia';
import { beforeEach, describe, expect, test, vi } from 'vitest';
const settingDefaultValue = 42;
const settingPath = ['test', 'number'];
describe('useSettings', () => {
describe('getSetting', () => {
test('returns stored value', () => {
const { getSetting } = useSettings();
const settings = useSettingsStore();
const key = 'setting';
const value = 42;
settings.set(key, value);
expect(getSetting(key)).toBe(value);
});
test('returns default value', () => {
const { getSetting } = useSettings();
expect(getSetting(settingPath)).toBe(settingDefaultValue);
});
test('returns stored value instead of default value', () => {
const { getSetting } = useSettings();
const settings = useSettingsStore();
const value = 43;
expect(getSetting(settingPath)).toBe(settingDefaultValue);
settings.set(settingPath, value);
expect(getSetting(settingPath)).toBe(value);
});
test('returns undefined if there is no value', () => {
const { getSetting } = useSettings();
expect(getSetting(['test', 'bool'])).toBeUndefined();
});
});
});
beforeEach(() => {
setActivePinia(
createTestingPinia({
createSpy: vi.fn,
stubActions: false
})
);
const settingsConfigCache = useSettingsConfigCacheStore();
settingsConfigCache.set({
contents: [
{
name: 'test',
i18n: '',
content: [
{
type: 'number',
i18n: '',
name: 'number',
default: settingDefaultValue
},
{
type: 'bool',
i18n: '',
name: 'bool'
}
]
}
]
});
});
@@ -1,44 +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.
*/
import { useSettingsConfigCacheStore } from '../stores/settingsConfigCacheStore';
import { useSettingsStore } from '../stores/settingsStore';
import { getSettingRecursively } from '../utils/getSetting';
import { loadSettingsConfig } from '../utils/settingsParser';
/**
* Provides access to the stored settings.
*/
export const useSettings = function useSettings () {
/**
* Returns the value of a specific setting.
* @param {string[]} key - The settings key.
* @return The value of the setting.
*/
const getSetting = function getSetting (key) {
const settingsStore = useSettingsStore();
const settings = useSettingsConfigCacheStore().get();
return (
settingsStore.get(key) ??
getSettingRecursively(
key, settings.contents ?? []
)?.default
);
};
return { getSetting };
};
@@ -1,31 +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.
*/
import { defineStore } from 'pinia';
export const useSettingsConfigCacheStore = defineStore('settingsConfigCache', () => {
let settingsConfig = undefined;
const set = function set (value) {
settingsConfig = value;
};
const get = function get () {
return settingsConfig;
};
return { set, get };
});
File diff suppressed because it is too large Load Diff
@@ -14,7 +14,6 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import { useSettingsConfigCacheStore } from '../stores/settingsConfigCacheStore';
import { validateSettingsConfig } from './settingsValidator.js';
/**
@@ -22,12 +21,10 @@ import { validateSettingsConfig } from './settingsValidator.js';
* @returns {Promise<import('../types/settingsConfig').SettingsConfig>}
*/
export async function loadSettingsConfig() {
const settingsConfigCache = useSettingsConfigCacheStore();
let raw;
try {
raw = (await import('../settings.json')).default;
settingsConfigCache.set(raw);
} catch (e) {
throw new Error(`[settings] Failed to load settings.json: ${e.message}`);
}
@@ -73,27 +73,12 @@ export const validateEntry = function validateEntry (entry, path) {
throw new Error(`[settings] "${path}.default" must be a string`);
}
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') {
throw new Error(`[settings] "${path}.default" must be a string`);
};
if (!entry.options.map((option) => option.name).includes(entry.default)) {
throw new Error(`[settings] option "${path}.default" does not exist`);
};
}
if (typeof entry.default !== 'string') {
throw new Error(`[settings] "${path}.default" must be a string`);
};
if (!entry.options.map((option) => option.name).includes(entry.default)) {
throw new Error(`[settings] option "${path}.default" does not exist`);
};
};
}
}
+1 -6
View File
@@ -61,10 +61,6 @@ onMounted(async () => {
});
settingsLoaded.value = true;
});
const toggleSidebarIfSmallScreen = function toggleSidebarIfSmallScreen (toggleSidebarFunction) {
if (matchMedia('(max-width: 48rem)').matches) toggleSidebarFunction();
};
</script>
<template>
@@ -75,14 +71,13 @@ const toggleSidebarIfSmallScreen = function toggleSidebarIfSmallScreen (toggleSi
</h1>
</header>
<LeftSidebarLayout class="layout">
<template #sidebar="{ toggleSidebar }">
<template #sidebar>
<ul class="sidebar-sections-list">
<li v-for="section in settings">
<RouterLink
:to="`/settings/${section.name}`"
class="button button-link link sidebar-section"
:class="{ active: activeSection === section.name }"
@click="toggleSidebarIfSmallScreen(toggleSidebar)"
>
{{ t(section.i18n) }}
</RouterLink>
+2 -47
View File
@@ -14,60 +14,15 @@ See the License for the specific language governing permissions and
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>
<nav class="sidebar" :class="{ expanded }">
<div class="sidebar-controls">
<SidebarExpandButton @click="toggleSidebar" class="sidebar-expand-button" />
</div>
<div class="sidebar-content" v-if="props.expanded">
<slot />
</div>
<nav class="sidebar">
<slot />
</nav>
</template>
<style scoped>
.sidebar {
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-top: 0;
}
</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>
+5 -66
View File
@@ -16,34 +16,15 @@ limitations under the License.
<script setup>
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 toggleSidebar = function toggleSidebar () {
expanded.value = !expanded.value;
};
</script>
<template>
<div class="layout-container" :class="{ expanded }">
<div class="sidebar-expand-button-container">
<SidebarExpandButton class="sidebar-expand-button" @click="toggleSidebar" />
</div>
<Sidebar @toggle-expanded="toggleSidebar" :expanded="expanded" class="sidebar">
<slot name="sidebar" :toggleSidebar="toggleSidebar" />
<div class="layout-container">
<Sidebar>
<slot name="sidebar" />
</Sidebar>
<main class="main-content">
<slot :toggleSidebar="toggleSidebar" />
<slot />
</main>
</div>
</template>
@@ -51,53 +32,11 @@ const toggleSidebar = function toggleSidebar () {
<style scoped>
.layout-container {
display: grid;
grid-template-columns: calc(32px + 2em) 1fr;
grid-template-rows: auto 1fr;
grid-template-areas:
"sidebar-expand sidebar-expand"
"sidebar main-content";
grid-template-columns: min(24%, 280px) 1fr;
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 {
grid-area: main-content;
padding: 20px;
}
</style>
+1 -24
View File
@@ -38,28 +38,5 @@
}
}
},
"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}"
}
}
}
"slogan": "Hecho para buscar."
}
+1 -24
View File
@@ -38,28 +38,5 @@
}
}
},
"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}"
}
}
}
"slogan": "Conçu pour chercher."
}
+1 -24
View File
@@ -38,28 +38,5 @@
}
}
},
"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}"
}
}
}
"slogan": "Costruito per cercare."
}
+1 -24
View File
@@ -38,28 +38,5 @@
}
}
},
"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}"
}
}
}
"slogan": "Feito para pesquisar."
}
-20
View File
@@ -14,7 +14,6 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import { getAssetsUrl } from './config/env';
import { createApp } from 'vue'
import { createPinia } from 'pinia';
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate';
@@ -26,29 +25,10 @@ import './styles/common.css'
import './styles/variables/colors.css'
import './styles/variables/dimensions.css';
import rawFonts from './styles/fonts.json';
import './styles/common.css';
import './styles/variables/colors.css';
(async () => {
const fonts = rawFonts.map((font) => new FontFace(
font.family ?? '',
Array.isArray(font.source)
? font.source.map(
(source) => `url('${source.url
? new URL(source.url, getAssetsUrl()).href
: ''
}') format('${source.format ?? ''}')`
).join(',')
: '',
{
weight: font.weight ?? undefined,
style: font.style ?? undefined
}
));
await Promise.all(fonts.map((font) => font.load()));
fonts.forEach((font) => document.fonts.add(font));
await loadLanguage(fallbackLocale);
await loadLanguage(getCurrentLanguage());
+2 -8
View File
@@ -19,14 +19,13 @@ body {
color: var(--dark);
margin: 0;
font-size: 16px;
font-family: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
}
.link {
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;
text-decoration: underline;
}
@@ -79,7 +78,7 @@ input {
color: inherit;
}
.button:focus-visible {
.button:focus {
background-color: var(--light-hover);
outline: none;
}
@@ -87,8 +86,3 @@ input {
.button:hover {
background-color: var(--light-hover);
}
/* Temporary until a custom tap highlight is implemented. */
* {
-webkit-tap-highlight-color: transparent;
}
-32
View File
@@ -1,32 +0,0 @@
[
{
"family": "Inter",
"weight": "100 900",
"style": "normal",
"source": [
{
"url": "fonts/Inter/Inter-Variable.woff2",
"format": "woff2"
},
{
"url": "fonts/Inter/Inter-Variable.ttf",
"format": "truetype"
}
]
},
{
"family": "Inter",
"weight": "100 900",
"style": "italic",
"source": [
{
"url": "fonts/Inter/Inter-Italic-Variable.woff2",
"format": "woff2"
},
{
"url": "fonts/Inter/Inter-Italic-Variable.ttf",
"format": "truetype"
}
]
}
]
+89 -91
View File
@@ -14,111 +14,109 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import { describe, expect, test } from 'vitest';
import { expect, test } from 'vitest';
import { ensureUnit } from '../cssDimensions';
describe('cssDimensions', () => {
test.for([
{ dimension: null, expected: '0px' },
{ dimension: undefined, expected: '0px' },
test.for([
{ dimension: null, expected: '0px' },
{ dimension: undefined, expected: '0px' },
{ dimension: 0, expected: '0px' },
{ dimension: -0, expected: '0px' },
{ dimension: -1, expected: '-1px' },
{ dimension: -42, expected: '-42px' },
{ dimension: 1, expected: '1px' },
{ dimension: 42, expected: '42px' },
{ dimension: 0, expected: '0px' },
{ dimension: -0, expected: '0px' },
{ dimension: -1, expected: '-1px' },
{ dimension: -42, expected: '-42px' },
{ dimension: 1, expected: '1px' },
{ dimension: 42, expected: '42px' },
{ dimension: 0.0, expected: '0px' },
{ dimension: -0.0, expected: '0px' },
{ dimension: -1.0, expected: '-1px' },
{ dimension: -42.0, expected: '-42px' },
{ dimension: 1.0, expected: '1px' },
{ dimension: 42.0, expected: '42px' },
{ dimension: 0.0, expected: '0px' },
{ dimension: -0.0, expected: '0px' },
{ dimension: -1.0, expected: '-1px' },
{ dimension: -42.0, expected: '-42px' },
{ dimension: 1.0, expected: '1px' },
{ dimension: 42.0, expected: '42px' },
{ dimension: 0.42, expected: '0.42px' },
{ dimension: -0.42, expected: '-0.42px' },
{ dimension: -1.42, expected: '-1.42px' },
{ dimension: -42.42, expected: '-42.42px' },
{ dimension: 1.42, expected: '1.42px' },
{ dimension: 42.42, expected: '42.42px' },
{ dimension: 0.42, expected: '0.42px' },
{ dimension: -0.42, expected: '-0.42px' },
{ dimension: -1.42, expected: '-1.42px' },
{ dimension: -42.42, expected: '-42.42px' },
{ dimension: 1.42, expected: '1.42px' },
{ dimension: 42.42, expected: '42.42px' },
{ dimension: '0', expected: '0px' },
{ dimension: '-0', expected: '-0px' },
{ dimension: '-1', expected: '-1px' },
{ dimension: '-42', expected: '-42px' },
{ dimension: '1', expected: '1px' },
{ dimension: '42', expected: '42px' },
{ dimension: '0', expected: '0px' },
{ dimension: '-0', expected: '-0px' },
{ dimension: '-1', expected: '-1px' },
{ dimension: '-42', expected: '-42px' },
{ dimension: '1', expected: '1px' },
{ dimension: '42', expected: '42px' },
{ dimension: '0.0', expected: '0.0px' },
{ dimension: '-0.0', expected: '-0.0px' },
{ dimension: '-1.0', expected: '-1.0px' },
{ dimension: '-42.0', expected: '-42.0px' },
{ dimension: '1.0', expected: '1.0px' },
{ dimension: '42.0', expected: '42.0px' },
{ dimension: '0.0', expected: '0.0px' },
{ dimension: '-0.0', expected: '-0.0px' },
{ dimension: '-1.0', expected: '-1.0px' },
{ dimension: '-42.0', expected: '-42.0px' },
{ dimension: '1.0', expected: '1.0px' },
{ dimension: '42.0', expected: '42.0px' },
{ dimension: '0.42', expected: '0.42px' },
{ dimension: '-0.42', expected: '-0.42px' },
{ dimension: '-1.42', expected: '-1.42px' },
{ dimension: '-42.42', expected: '-42.42px' },
{ dimension: '1.42', expected: '1.42px' },
{ dimension: '42.42', expected: '42.42px' },
{ dimension: '0.42', expected: '0.42px' },
{ dimension: '-0.42', expected: '-0.42px' },
{ dimension: '-1.42', expected: '-1.42px' },
{ dimension: '-42.42', expected: '-42.42px' },
{ dimension: '1.42', expected: '1.42px' },
{ dimension: '42.42', expected: '42.42px' },
{ dimension: '0px', expected: '0px' },
{ dimension: '-0px', expected: '-0px' },
{ dimension: '-1px', expected: '-1px' },
{ dimension: '-42px', expected: '-42px' },
{ dimension: '1px', expected: '1px' },
{ dimension: '42px', expected: '42px' },
{ dimension: '0px', expected: '0px' },
{ dimension: '-0px', expected: '-0px' },
{ dimension: '-1px', expected: '-1px' },
{ dimension: '-42px', expected: '-42px' },
{ dimension: '1px', expected: '1px' },
{ dimension: '42px', expected: '42px' },
{ dimension: '0.0px', expected: '0.0px' },
{ dimension: '-0.0px', expected: '-0.0px' },
{ dimension: '-1.0px', expected: '-1.0px' },
{ dimension: '-42.0px', expected: '-42.0px' },
{ dimension: '1.0px', expected: '1.0px' },
{ dimension: '42.0px', expected: '42.0px' },
{ dimension: '0.0px', expected: '0.0px' },
{ dimension: '-0.0px', expected: '-0.0px' },
{ dimension: '-1.0px', expected: '-1.0px' },
{ dimension: '-42.0px', expected: '-42.0px' },
{ dimension: '1.0px', expected: '1.0px' },
{ dimension: '42.0px', expected: '42.0px' },
{ dimension: '0.42px', expected: '0.42px' },
{ dimension: '-0.42px', expected: '-0.42px' },
{ dimension: '-1.42px', expected: '-1.42px' },
{ dimension: '-42.42px', expected: '-42.42px' },
{ dimension: '1.42px', expected: '1.42px' },
{ dimension: '42.42px', expected: '42.42px' },
{ dimension: '0.42px', expected: '0.42px' },
{ dimension: '-0.42px', expected: '-0.42px' },
{ dimension: '-1.42px', expected: '-1.42px' },
{ dimension: '-42.42px', expected: '-42.42px' },
{ dimension: '1.42px', expected: '1.42px' },
{ dimension: '42.42px', expected: '42.42px' },
{ dimension: '0em', expected: '0em' },
{ dimension: '-0em', expected: '-0em' },
{ dimension: '-1em', expected: '-1em' },
{ dimension: '-42em', expected: '-42em' },
{ dimension: '1em', expected: '1em' },
{ dimension: '42em', expected: '42em' },
{ dimension: '0em', expected: '0em' },
{ dimension: '-0em', expected: '-0em' },
{ dimension: '-1em', expected: '-1em' },
{ dimension: '-42em', expected: '-42em' },
{ dimension: '1em', expected: '1em' },
{ dimension: '42em', expected: '42em' },
{ dimension: '0.0em', expected: '0.0em' },
{ dimension: '-0.0em', expected: '-0.0em' },
{ dimension: '-1.0em', expected: '-1.0em' },
{ dimension: '-42.0em', expected: '-42.0em' },
{ dimension: '1.0em', expected: '1.0em' },
{ dimension: '42.0em', expected: '42.0em' },
{ dimension: '0.0em', expected: '0.0em' },
{ dimension: '-0.0em', expected: '-0.0em' },
{ dimension: '-1.0em', expected: '-1.0em' },
{ dimension: '-42.0em', expected: '-42.0em' },
{ dimension: '1.0em', expected: '1.0em' },
{ dimension: '42.0em', expected: '42.0em' },
{ dimension: '0.42em', expected: '0.42em' },
{ dimension: '-0.42em', expected: '-0.42em' },
{ dimension: '-1.42em', expected: '-1.42em' },
{ dimension: '-42.42em', expected: '-42.42em' },
{ dimension: '1.42em', expected: '1.42em' },
{ dimension: '42.42em', expected: '42.42em' },
{ dimension: '0.42em', expected: '0.42em' },
{ dimension: '-0.42em', expected: '-0.42em' },
{ dimension: '-1.42em', expected: '-1.42em' },
{ dimension: '-42.42em', expected: '-42.42em' },
{ dimension: '1.42em', expected: '1.42em' },
{ dimension: '42.42em', expected: '42.42em' },
{ dimension: 'calc(42px - 1em)', expected: 'calc(42px - 1em)' },
{ dimension: 'calc(42px)', expected: 'calc(42px)' },
{ dimension: 'calc(42vh)', expected: 'calc(42vh)' },
{ dimension: 'min(42px, 1em)', expected: 'min(42px, 1em)' },
{ dimension: 'max(42px, 5rem)', expected: 'max(42px, 5rem)' },
{ dimension: 'clamp(42vh, 23vw, 13cap)', expected: 'clamp(42vh, 23vw, 13cap)' },
{ dimension: 'calc(42px - 1em)', expected: 'calc(42px - 1em)' },
{ dimension: 'calc(42px)', expected: 'calc(42px)' },
{ dimension: 'calc(42vh)', expected: 'calc(42vh)' },
{ dimension: 'min(42px, 1em)', expected: 'min(42px, 1em)' },
{ dimension: 'max(42px, 5rem)', expected: 'max(42px, 5rem)' },
{ dimension: 'clamp(42vh, 23vw, 13cap)', expected: 'clamp(42vh, 23vw, 13cap)' },
{ dimension: 'calc(42px-1em)', expected: 'calc(42px-1em)' },
{ dimension: 'min(42px,1em)', expected: 'min(42px,1em)' },
{ dimension: 'max(42px,5rem)', expected: 'max(42px,5rem)' },
{ dimension: 'clamp(42vh,23vw,13cap)', expected: 'clamp(42vh,23vw,13cap)' },
{ dimension: 'clamp( 42vh,23vw,13cap )', expected: 'clamp( 42vh,23vw,13cap )' }
])('ensureUnit returns $expected with input $dimension', ({ dimension, expected }) => {
expect(ensureUnit(dimension)).toBe(expected);
});
{ dimension: 'calc(42px-1em)', expected: 'calc(42px-1em)' },
{ dimension: 'min(42px,1em)', expected: 'min(42px,1em)' },
{ dimension: 'max(42px,5rem)', expected: 'max(42px,5rem)' },
{ dimension: 'clamp(42vh,23vw,13cap)', expected: 'clamp(42vh,23vw,13cap)' },
{ dimension: 'clamp( 42vh,23vw,13cap )', expected: 'clamp( 42vh,23vw,13cap )' }
])('ensureUnit returns $expected with input $dimension', ({ dimension, expected }) => {
expect(ensureUnit(dimension)).toBe(expected);
});
+35 -35
View File
@@ -14,48 +14,48 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import { describe, expect, test } from 'vitest';
import { expect, test } from 'vitest';
import getCurrentLanguage from '../currentLanguage';
describe('currentLanguage', () => {
test.for([
{ navigatorLanguage: 'en', localStorageLanguage: null, expected: 'en'},
{ navigatorLanguage: 'de', localStorageLanguage: null, expected: 'de'},
{ navigatorLanguage: 'fr', localStorageLanguage: null, expected: 'fr'},
const locales = [
{ navigatorLanguage: 'en', localStorageLanguage: null, expected: 'en'},
{ navigatorLanguage: 'de', localStorageLanguage: null, expected: 'de'},
{ navigatorLanguage: 'fr', localStorageLanguage: null, expected: 'fr'},
{ navigatorLanguage: 'en-US', localStorageLanguage: null, expected: 'en'},
{ navigatorLanguage: 'en-AU', localStorageLanguage: null, expected: 'en'},
{ navigatorLanguage: 'de-DE', localStorageLanguage: null, expected: 'de'},
{ navigatorLanguage: 'fr-FR', localStorageLanguage: null, expected: 'fr'},
{ navigatorLanguage: 'en-US', localStorageLanguage: null, expected: 'en'},
{ navigatorLanguage: 'en-AU', localStorageLanguage: null, expected: 'en'},
{ navigatorLanguage: 'de-DE', localStorageLanguage: null, expected: 'de'},
{ navigatorLanguage: 'fr-FR', localStorageLanguage: null, expected: 'fr'},
{ navigatorLanguage: 'en-us', localStorageLanguage: null, expected: 'en'},
{ navigatorLanguage: 'en-au', localStorageLanguage: null, expected: 'en'},
{ navigatorLanguage: 'de-de', localStorageLanguage: null, expected: 'de'},
{ navigatorLanguage: 'fr-fr', localStorageLanguage: null, expected: 'fr'},
{ navigatorLanguage: 'en-us', localStorageLanguage: null, expected: 'en'},
{ navigatorLanguage: 'en-au', localStorageLanguage: null, expected: 'en'},
{ navigatorLanguage: 'de-de', localStorageLanguage: null, expected: 'de'},
{ navigatorLanguage: 'fr-fr', localStorageLanguage: null, expected: 'fr'},
{ navigatorLanguage: 'zh-Hans-CN', localStorageLanguage: null, expected: 'zh'},
{ navigatorLanguage: 'zh-Hant-TW', localStorageLanguage: null, expected: 'zh'},
{ navigatorLanguage: 'uz-Latn-UZ', localStorageLanguage: null, expected: 'uz'},
{ navigatorLanguage: 'zh-Hans-CN', localStorageLanguage: null, expected: 'zh'},
{ navigatorLanguage: 'zh-Hant-TW', localStorageLanguage: null, expected: 'zh'},
{ navigatorLanguage: 'uz-Latn-UZ', localStorageLanguage: null, expected: 'uz'},
{ navigatorLanguage: 'en-US-u-ca-gregory', localStorageLanguage: null, expected: 'en'},
{ navigatorLanguage: 'de-DE-u-co-phonebk', localStorageLanguage: null, expected: 'de'},
{ navigatorLanguage: 'zh-Hant-TW-u-co-phonebk', localStorageLanguage: null, expected: 'zh'},
{ navigatorLanguage: 'en-US-u-ca-gregory', localStorageLanguage: null, expected: 'en'},
{ navigatorLanguage: 'de-DE-u-co-phonebk', localStorageLanguage: null, expected: 'de'},
{ navigatorLanguage: 'zh-Hant-TW-u-co-phonebk', localStorageLanguage: null, expected: 'zh'},
{ navigatorLanguage: 'en', localStorageLanguage: 'de', expected: 'de'},
{ navigatorLanguage: 'de-DE', localStorageLanguage: 'en', expected: 'en'},
{ navigatorLanguage: 'de-de', localStorageLanguage: 'en', expected: 'en'},
{ navigatorLanguage: 'zh-Hans-CN', localStorageLanguage: 'fr', expected: 'fr'},
{ navigatorLanguage: 'en-US-u-ca-gregory', localStorageLanguage: 'zh', expected: 'zh'}
])('returns the language $expected (navigator: $navigatorLanguage; local storage: $localStorageLanguage)', ({ navigatorLanguage, localStorageLanguage, expected }) => {
Object.defineProperty(navigator, 'language', {
value: navigatorLanguage,
configurable: true
});
{ navigatorLanguage: 'en', localStorageLanguage: 'de', expected: 'de'},
{ navigatorLanguage: 'de-DE', localStorageLanguage: 'en', expected: 'en'},
{ navigatorLanguage: 'de-de', localStorageLanguage: 'en', expected: 'en'},
{ navigatorLanguage: 'zh-Hans-CN', localStorageLanguage: 'fr', expected: 'fr'},
{ navigatorLanguage: 'en-US-u-ca-gregory', localStorageLanguage: 'zh', expected: 'zh'}
];
if (localStorageLanguage) {
localStorage.setItem('locale', localStorageLanguage);
};
expect(getCurrentLanguage()).toBe(expected);
test.for(locales)('returns the language $expected (navigator: $navigatorLanguage; local storage: $localStorageLanguage)', ({ navigatorLanguage, localStorageLanguage, expected }) => {
Object.defineProperty(navigator, 'language', {
value: navigatorLanguage,
configurable: true
});
if (localStorageLanguage) {
localStorage.setItem('locale', localStorageLanguage);
};
expect(getCurrentLanguage()).toBe(expected);
});