Compare commits
12
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ffee1d0569
|
||
|
|
0140e5669e
|
||
|
|
a4a857062b
|
||
|
|
6bfef99cda
|
||
|
|
72b7d313ed
|
||
|
|
b1dc260d47
|
||
|
|
3c9fd3052f
|
||
|
|
7cb1c2a403
|
||
|
|
e0a29b011c
|
||
|
|
9886d1e61e
|
||
|
|
f6d5ba28e0
|
||
|
|
ac44b59a61
|
No files matched your search
@@ -1,3 +1,2 @@
|
||||
.gitea/
|
||||
.github/
|
||||
eslint.config.js
|
||||
+69
-26
@@ -1,11 +1,40 @@
|
||||
import js from '@eslint/js';
|
||||
import { defineConfig } from 'eslint/config';
|
||||
import pluginVue from 'eslint-plugin-vue';
|
||||
import tseslint from 'typescript-eslint';
|
||||
import vueParser from 'vue-eslint-parser';
|
||||
import globals from 'globals';
|
||||
|
||||
const commonRules = {
|
||||
'eqeqeq': 'error', // prettier-ignore
|
||||
|
||||
'prefer-const': 'error',
|
||||
'no-var': 'error',
|
||||
'no-duplicate-imports': 'error',
|
||||
'no-import-assign': 'error',
|
||||
|
||||
'prefer-arrow-callback': 'error',
|
||||
'require-await': 'warn',
|
||||
'no-async-promise-executor': 'error',
|
||||
|
||||
'no-unreachable': 'error',
|
||||
'no-constant-condition': 'error',
|
||||
|
||||
'no-debugger': 'error',
|
||||
'no-alert': 'error',
|
||||
'no-console': 'warn',
|
||||
|
||||
'no-new-object': 'error',
|
||||
'no-array-constructor': 'error',
|
||||
'no-prototype-builtins': 'error',
|
||||
'object-shorthand': 'error',
|
||||
|
||||
'prefer-template': 'error',
|
||||
};
|
||||
|
||||
export default defineConfig([
|
||||
{
|
||||
files: ['**/*.{js,mjs,cjs,vue}'],
|
||||
files: ['**/*.{js,mjs,cjs,ts,mts,cts,vue}'],
|
||||
plugins: { js },
|
||||
extends: ['js/recommended'],
|
||||
languageOptions: {
|
||||
@@ -14,37 +43,51 @@ export default defineConfig([
|
||||
...globals.node,
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
'eqeqeq': 'error',
|
||||
rules: commonRules,
|
||||
},
|
||||
|
||||
pluginVue.configs['flat/essential'],
|
||||
|
||||
{
|
||||
files: ['**/*.{js,mjs,cjs}'],
|
||||
rules: {
|
||||
'no-unused-vars': 'error',
|
||||
'no-undef': 'error',
|
||||
'prefer-const': 'error',
|
||||
'no-var': 'error',
|
||||
'no-duplicate-imports': 'error',
|
||||
'no-import-assign': 'error',
|
||||
|
||||
'no-empty-function': 'error',
|
||||
'default-param-last': 'error',
|
||||
'prefer-arrow-callback': 'error',
|
||||
'require-await': 'warn',
|
||||
'no-async-promise-executor': 'error',
|
||||
|
||||
'no-unreachable': 'error',
|
||||
|
||||
'no-constant-condition': 'error',
|
||||
|
||||
'no-debugger': 'error',
|
||||
'no-alert': 'error',
|
||||
'no-console': 'warn',
|
||||
|
||||
'no-new-object': 'error',
|
||||
'no-array-constructor': 'error',
|
||||
'no-prototype-builtins': 'error',
|
||||
'object-shorthand': 'error',
|
||||
|
||||
'prefer-template': 'error',
|
||||
},
|
||||
},
|
||||
pluginVue.configs['flat/essential'],
|
||||
|
||||
{
|
||||
files: ['**/*.{ts,mts,cts,vue}'],
|
||||
extends: [tseslint.configs.recommended],
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.browser,
|
||||
...globals.node,
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
'no-undef': 'off',
|
||||
|
||||
'@typescript-eslint/no-unused-vars': 'error',
|
||||
'@typescript-eslint/no-empty-function': 'error',
|
||||
'@typescript-eslint/default-param-last': 'error',
|
||||
|
||||
'@typescript-eslint/consistent-type-imports': 'error',
|
||||
'@typescript-eslint/no-explicit-any': 'warn',
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
files: ['**/*.vue'],
|
||||
languageOptions: {
|
||||
parser: vueParser,
|
||||
parserOptions: {
|
||||
parser: tseslint.parser,
|
||||
extraFileExtensions: ['.vue'],
|
||||
},
|
||||
},
|
||||
},
|
||||
]);
|
||||
Generated
+2387
-2244
File diff suppressed because it is too large.
Load diff
+8
-2
@@ -5,8 +5,10 @@
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"build": "npm run type-check && vite build",
|
||||
"preview": "vite preview",
|
||||
"type-check": "vue-tsc --noEmit -p tsconfig.app.json && tsc --noEmit -p tsconfig.node.json",
|
||||
"type-check:watch": "vue-tsc --noEmit -p tsconfig.app.json --watch",
|
||||
"test": "vitest",
|
||||
"test:run": "vitest run",
|
||||
"lint": "eslint .",
|
||||
@@ -25,6 +27,7 @@
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^10.0.1",
|
||||
"@pinia/testing": "^1.0.3",
|
||||
"@types/node": "^26.6.5",
|
||||
"@vitejs/plugin-vue": "^6.0.6",
|
||||
"@vue/test-utils": "^2.4.6",
|
||||
"eslint": "^10.8.1",
|
||||
@@ -33,8 +36,11 @@
|
||||
"globals": "^17.9.0",
|
||||
"jsdom": "^29.1.1",
|
||||
"prettier": "^3.9.6",
|
||||
"typescript": "^6.0.3",
|
||||
"typescript-eslint": "^8.72.0",
|
||||
"vite": "^8.0.10",
|
||||
"vite-plugin-html": "^3.2.2",
|
||||
"vitest": "^4.1.7"
|
||||
"vitest": "^4.1.7",
|
||||
"vue-tsc": "^3.3.13"
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -15,7 +15,7 @@ limitations under the License.
|
||||
-->
|
||||
|
||||
<script setup>
|
||||
import { LANGUAGE_PATH } from './config/featureSettings.js';
|
||||
import { LANGUAGE_PATH } from './config/featureSettings';
|
||||
import AppFooter from './features/footer/components/AppFooter.vue';
|
||||
import AppNavbar from './features/nav/components/AppNavbar.vue';
|
||||
import { useSettings } from './features/settings/composables/useSettings.js';
|
||||
|
||||
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
export const getAssetsUrl = function getAssetsUrl() {
|
||||
export const getAssetsUrl = function getAssetsUrl(): string {
|
||||
return new URL(
|
||||
`${import.meta.env.VITE_ASSETS_BUILD_ID}/`,
|
||||
import.meta.env.VITE_ASSETS_BASE_URL,
|
||||
File renamed without changes.
@@ -15,7 +15,7 @@ limitations under the License.
|
||||
*/
|
||||
|
||||
import LanguageSwitchButton from '../LanguageSwitchButton.vue';
|
||||
import { LANGUAGE_PATH } from '@/config/featureSettings.js';
|
||||
import { LANGUAGE_PATH } from '@/config/featureSettings';
|
||||
import { useSettings } from '@/features/settings/composables/useSettings.js';
|
||||
import { mountComponent } from '@/test-utils/mountComponent.js';
|
||||
import { describe, expect, test } from 'vitest';
|
||||
|
||||
@@ -28,9 +28,11 @@ export const i18n = createI18n({
|
||||
messages: {},
|
||||
});
|
||||
|
||||
const loadedLanguages = new Set();
|
||||
const loadedLanguages = new Set<string>();
|
||||
|
||||
export const loadLanguage = async function loadLanguage(locale) {
|
||||
export const loadLanguage = async function loadLanguage(
|
||||
locale: string,
|
||||
): Promise<void> {
|
||||
if (!SUPPORTED_LANGUAGES.includes(locale)) {
|
||||
locale = fallbackLocale;
|
||||
}
|
||||
@@ -48,7 +50,9 @@ export const loadLanguage = async function loadLanguage(locale) {
|
||||
loadedLanguages.add(locale);
|
||||
};
|
||||
|
||||
export const setLocale = async function setLocale(locale) {
|
||||
export const setLocale = async function setLocale(
|
||||
locale: string,
|
||||
): Promise<void> {
|
||||
await loadLanguage(locale);
|
||||
document.documentElement.lang = locale;
|
||||
document.documentElement.dir = LANGUAGES_RTL.includes(locale)
|
||||
@@ -23,7 +23,7 @@ import { createApp } from 'vue';
|
||||
import App from './App.vue';
|
||||
|
||||
import './styles/common.css';
|
||||
import rawFonts from './styles/fonts.json';
|
||||
import rawFonts from './styles/fonts';
|
||||
import './styles/variables/colors.css';
|
||||
import './styles/variables/dimensions.css';
|
||||
|
||||
@@ -21,9 +21,14 @@ import SettingsView from '@/features/settings/views/SettingsView.vue';
|
||||
import NotFound from '@/views/NotFound.vue';
|
||||
|
||||
import { i18n } from '@/i18n';
|
||||
import { createRouter, createWebHistory } from 'vue-router';
|
||||
import {
|
||||
createRouter,
|
||||
createWebHistory,
|
||||
type RouteLocationNormalizedLoaded,
|
||||
type RouteRecordRaw,
|
||||
} from 'vue-router';
|
||||
|
||||
const routes = [
|
||||
const routes: RouteRecordRaw[] = [
|
||||
{
|
||||
path: '/',
|
||||
name: 'startPage',
|
||||
@@ -37,7 +42,7 @@ const routes = [
|
||||
searchQuery: route.query.q,
|
||||
}),
|
||||
meta: {
|
||||
title: (route) => route.query.q,
|
||||
title: (route: RouteLocationNormalizedLoaded) => route.query.q,
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -68,7 +73,9 @@ const router = createRouter({
|
||||
routes,
|
||||
});
|
||||
|
||||
export const updatePageTitle = function updatePageTitle(route) {
|
||||
export const updatePageTitle = function updatePageTitle(
|
||||
route: RouteLocationNormalizedLoaded,
|
||||
): void {
|
||||
const title =
|
||||
typeof route.meta.title === 'function'
|
||||
? route.meta.title(route)
|
||||
@@ -82,7 +89,7 @@ export const updatePageTitle = function updatePageTitle(route) {
|
||||
};
|
||||
|
||||
// remove trailing slash(es)
|
||||
router.beforeEach((route) => {
|
||||
router.beforeEach((route: RouteLocationNormalizedLoaded) => {
|
||||
if (route.path !== '/' && route.path.endsWith('/')) {
|
||||
return {
|
||||
path: route.path.replace(/\/+$/, ''),
|
||||
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
type FontFormat =
|
||||
'woff2' | 'woff' | 'truetype' | 'opentype' | 'embedded-opentype' | 'svg';
|
||||
|
||||
interface FontSource {
|
||||
url: string;
|
||||
format: FontFormat;
|
||||
}
|
||||
|
||||
interface RawFont {
|
||||
family: string;
|
||||
weight: string;
|
||||
style: string;
|
||||
source: FontSource[];
|
||||
}
|
||||
|
||||
const fonts: RawFont[] = [
|
||||
{
|
||||
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',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export default fonts;
|
||||
+8
-2
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { ensureUnit } from '../cssDimensions';
|
||||
import { ensureUnit, type RawDimension } from '../cssDimensions';
|
||||
import { describe, expect, test } from 'vitest';
|
||||
|
||||
describe('cssDimensions', () => {
|
||||
@@ -129,7 +129,13 @@ describe('cssDimensions', () => {
|
||||
},
|
||||
])(
|
||||
'ensureUnit returns $expected with input $dimension',
|
||||
({ dimension, expected }) => {
|
||||
({
|
||||
dimension,
|
||||
expected,
|
||||
}: {
|
||||
dimension: RawDimension;
|
||||
expected: string;
|
||||
}) => {
|
||||
expect(ensureUnit(dimension)).toBe(expected);
|
||||
},
|
||||
);
|
||||
@@ -14,7 +14,13 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
export const ensureUnit = function ensureUnit(d) {
|
||||
/*
|
||||
* null and undefined because they are intended to represent empty input
|
||||
* values
|
||||
*/
|
||||
export type RawDimension = null | number | string | undefined;
|
||||
|
||||
export const ensureUnit = function ensureUnit(d: RawDimension): string {
|
||||
if (!d) d = 0;
|
||||
|
||||
// ensure that it is a string
|
||||
Vendored
+24
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
interface ImportMetaEnv {
|
||||
readonly VITE_ASSETS_BUILD_ID: string;
|
||||
readonly VITE_ASSETS_BASE_URL: string;
|
||||
}
|
||||
|
||||
interface ImportMeta {
|
||||
readonly env: ImportMetaEnv;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||
"module": "esnext",
|
||||
"moduleResolution": "bundler",
|
||||
|
||||
"strict": true,
|
||||
"noEmit": true,
|
||||
"isolatedModules": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"noImplicitAny": true,
|
||||
|
||||
"allowJs": true,
|
||||
"checkJs": false,
|
||||
|
||||
"resolveJsonModule": true,
|
||||
"skipLibCheck": true,
|
||||
"types": ["vite/client"],
|
||||
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
},
|
||||
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
||||
|
||||
"useDefineForClassFields": true,
|
||||
"jsx": "preserve",
|
||||
"esModuleInterop": true
|
||||
},
|
||||
"include": ["src/**/*.ts", "src/**/*.js", "src/**/*.vue"]
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"files": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.app.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.node.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es2020",
|
||||
"lib": ["ES2020"],
|
||||
|
||||
"module": "esnext",
|
||||
"moduleResolution": "bundler",
|
||||
|
||||
"strict": true,
|
||||
"noEmit": true,
|
||||
"isolatedModules": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"noImplicitAny": true,
|
||||
|
||||
"allowJs": true,
|
||||
"checkJs": false,
|
||||
|
||||
"skipLibCheck": true,
|
||||
"types": ["node"],
|
||||
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo"
|
||||
},
|
||||
"include": [
|
||||
"vite.config.js",
|
||||
"vite.config.ts",
|
||||
"vitest.config.js",
|
||||
"vitest.config.ts",
|
||||
"eslint.config.js",
|
||||
"eslint.config.ts"
|
||||
]
|
||||
}
|
||||
@@ -15,8 +15,8 @@ limitations under the License.
|
||||
*/
|
||||
|
||||
import vue from '@vitejs/plugin-vue';
|
||||
import path from 'path';
|
||||
import { defineConfig } from 'vite';
|
||||
import { fileURLToPath, URL } from 'node:url';
|
||||
import { defineConfig } from 'vitest/config';
|
||||
import { createHtmlPlugin } from 'vite-plugin-html';
|
||||
|
||||
// https://vite.dev/config/
|
||||
@@ -32,7 +32,7 @@ export default defineConfig({
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': path.resolve(__dirname, './src'),
|
||||
'@': fileURLToPath(new URL('./src', import.meta.url)),
|
||||
},
|
||||
},
|
||||
test: {
|
||||
Reference in new issue
Block a user