generated from Seekra/repository-template
Compare commits
14
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
77bfa24536
|
||
|
|
c785ad552c
|
||
|
|
e71b917c8e
|
||
|
|
de5bee2c4a
|
||
|
|
baa924a2b2
|
||
|
|
26535cad45
|
||
|
|
5fdf0490b6
|
||
|
|
61817bf4fc
|
||
|
|
0f71f1240e
|
||
|
|
d67c8aa80e
|
||
|
|
44c457ba20
|
||
|
|
4b010d03ac
|
||
|
|
813cc7c7fc
|
||
|
|
a77bbec3fa
|
@@ -1,2 +1,16 @@
|
||||
# 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
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
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'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
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 };
|
||||
};
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
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 };
|
||||
});
|
||||
@@ -14,6 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { useSettingsConfigCacheStore } from '../stores/settingsConfigCacheStore';
|
||||
import { validateSettingsConfig } from './settingsValidator.js';
|
||||
|
||||
/**
|
||||
@@ -21,10 +22,12 @@ 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}`);
|
||||
}
|
||||
|
||||
@@ -61,6 +61,10 @@ onMounted(async () => {
|
||||
});
|
||||
settingsLoaded.value = true;
|
||||
});
|
||||
|
||||
const toggleSidebarIfSmallScreen = function toggleSidebarIfSmallScreen (toggleSidebarFunction) {
|
||||
if (matchMedia('(max-width: 48rem)').matches) toggleSidebarFunction();
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -71,13 +75,14 @@ onMounted(async () => {
|
||||
</h1>
|
||||
</header>
|
||||
<LeftSidebarLayout class="layout">
|
||||
<template #sidebar>
|
||||
<template #sidebar="{ toggleSidebar }">
|
||||
<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>
|
||||
|
||||
@@ -29,7 +29,7 @@ const props = defineProps({
|
||||
|
||||
const expanded = ref(props.expanded);
|
||||
|
||||
const toggleExpanded = function toggleExpanded () {
|
||||
const toggleSidebar = function toggleSidebar () {
|
||||
expanded.value = !expanded.value;
|
||||
};
|
||||
</script>
|
||||
@@ -37,13 +37,13 @@ const toggleExpanded = function toggleExpanded () {
|
||||
<template>
|
||||
<div class="layout-container" :class="{ expanded }">
|
||||
<div class="sidebar-expand-button-container">
|
||||
<SidebarExpandButton class="sidebar-expand-button" @click="toggleExpanded" />
|
||||
<SidebarExpandButton class="sidebar-expand-button" @click="toggleSidebar" />
|
||||
</div>
|
||||
<Sidebar @toggle-expanded="toggleExpanded" :expanded="expanded" class="sidebar">
|
||||
<slot name="sidebar" />
|
||||
<Sidebar @toggle-expanded="toggleSidebar" :expanded="expanded" class="sidebar">
|
||||
<slot name="sidebar" :toggleSidebar="toggleSidebar" />
|
||||
</Sidebar>
|
||||
<main class="main-content">
|
||||
<slot />
|
||||
<slot :toggleSidebar="toggleSidebar" />
|
||||
</main>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -87,3 +87,8 @@ input {
|
||||
.button:hover {
|
||||
background-color: var(--light-hover);
|
||||
}
|
||||
|
||||
/* Temporary until a custom tap highlight is implemented. */
|
||||
* {
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
Reference in New Issue
Block a user