🚧 ui: re-scaffolding

- built a new bare vue 3.5 project with vite
- partly merged in old configs
This commit is contained in:
Jörn-Michael Miehe 2026-02-20 22:22:05 +00:00
parent 8c231b5bf4
commit 022c9138bf
73 changed files with 2517 additions and 8269 deletions

View file

@ -1,4 +0,0 @@
> 1%
last 2 versions
not dead
not ie 11

View file

@ -29,9 +29,12 @@
// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"dbaeumer.vscode-eslint",
"EditorConfig.EditorConfig",
"esbenp.prettier-vscode",
"mhutchie.git-graph",
"oxc.oxc-vscode",
"Syler.sass-indented",
"vitest.explorer",
"Vue.volar"
]
}

8
ui/.editorconfig Normal file
View file

@ -0,0 +1,8 @@
[*.{js,jsx,mjs,cjs,ts,tsx,mts,cts,vue,css,scss,sass,less,styl}]
charset = utf-8
indent_size = 2
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
end_of_line = lf
max_line_length = 100

1
ui/.gitattributes vendored Normal file
View file

@ -0,0 +1 @@
* text=auto eol=lf

15
ui/.gitignore vendored
View file

@ -1,4 +1,19 @@
# from newly scaffolded vite project
.DS_Store
dist-ssr
coverage
*.local
# Cypress
/cypress/videos/
/cypress/screenshots/
# Vitest
__screenshots__/
# Vite
*.timestamp-*-*.mjs
# https://raw.githubusercontent.com/github/gitignore/refs/heads/main/Node.gitignore

10
ui/.oxlintrc.json Normal file
View file

@ -0,0 +1,10 @@
{
"$schema": "./node_modules/oxlint/configuration_schema.json",
"plugins": ["eslint", "typescript", "unicorn", "oxc", "vue", "vitest"],
"env": {
"browser": true
},
"categories": {
"correctness": "error"
}
}

6
ui/.prettierrc.json Normal file
View file

@ -0,0 +1,6 @@
{
"$schema": "https://json.schemastore.org/prettierrc",
"semi": false,
"singleQuote": true,
"printWidth": 100
}

View file

@ -1,3 +1,12 @@
{
"recommendations": ["sdras.vue-vscode-snippets"]
"recommendations": [
"dbaeumer.vscode-eslint",
"EditorConfig.EditorConfig",
"esbenp.prettier-vscode",
"mhutchie.git-graph",
"oxc.oxc-vscode",
"Syler.sass-indented",
"vitest.explorer",
"Vue.volar"
]
}

View file

@ -8,6 +8,7 @@
},
"editor.codeActionsOnSave": {
"source.fixAll": "explicit",
"source.organizeImports": "explicit"
},
@ -15,9 +16,16 @@
"editor.formatOnSave": true,
"editor.tabSize": 2,
"explorer.fileNesting.enabled": true,
"explorer.fileNesting.patterns": {
"tsconfig.json": "tsconfig.*.json, env.d.ts, typed-router.d.ts",
"vite.config.*": "jsconfig*, vitest.config.*, cypress.config.*, playwright.config.*",
"package.json": "package-lock.json, pnpm*, .yarnrc*, yarn*, .eslint*, eslint*, .oxlint*, oxlint*, .oxfmt*, .prettier*, prettier*, .editorconfig"
},
"sass.disableAutoIndent": true,
"sass.format.convert": false,
"sass.format.deleteWhitespace": true,
"prettier.trailingComma": "all",
"prettier.trailingComma": "all"
}

View file

@ -1,29 +1,54 @@
# advent22_ui
## Project setup
This template should help get you started developing with Vue 3 in Vite.
```
yarn install
## Recommended IDE Setup
[VS Code](https://code.visualstudio.com/) + [Vue (Official)](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur).
## Recommended Browser Setup
- Chromium-based browsers (Chrome, Edge, Brave, etc.):
- [Vue.js devtools](https://chromewebstore.google.com/detail/vuejs-devtools/nhdogjmejiglipccpnnnanhbledajbpd)
- [Turn on Custom Object Formatter in Chrome DevTools](http://bit.ly/object-formatters)
- Firefox:
- [Vue.js devtools](https://addons.mozilla.org/en-US/firefox/addon/vue-js-devtools/)
- [Turn on Custom Object Formatter in Firefox DevTools](https://fxdx.dev/firefox-devtools-custom-object-formatters/)
## Type Support for `.vue` Imports in TS
TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types.
## Customize configuration
See [Vite Configuration Reference](https://vite.dev/config/).
## Project Setup
```sh
yarn
```
### Compiles and hot-reloads for development
### Compile and Hot-Reload for Development
```
yarn serve
```sh
yarn dev
```
### Compiles and minifies for production
### Type-Check, Compile and Minify for Production
```
```sh
yarn build
```
### Lints and fixes files
### Run Unit Tests with [Vitest](https://vitest.dev/)
```sh
yarn test:unit
```
### Lint with [ESLint](https://eslint.org/)
```sh
yarn lint
```
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).

47
ui/_legacy/package.json Normal file
View file

@ -0,0 +1,47 @@
{
"name": "advent22_ui",
"version": "0.1.0",
"private": true,
"packageManager": "yarn@4.12.0",
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"test:unit": "vue-cli-service test:unit",
"test:unit-watch": "vue-cli-service test:unit --watch",
"lint": "vue-cli-service lint",
"ui": "vue ui --host 0.0.0.0 --headless"
},
"devDependencies": {
"@fortawesome/fontawesome-svg-core": "^7.2.0",
"@fortawesome/free-solid-svg-icons": "^7.2.0",
"@fortawesome/vue-fontawesome": "^3.1.3",
"@types/chai": "^5.2.3",
"@types/luxon": "^3.7.1",
"@types/mocha": "^10.0.10",
"@typescript-eslint/eslint-plugin": "^8.55.0",
"@typescript-eslint/parser": "^8.55.0",
"@vue/cli-plugin-babel": "^5.0.9",
"@vue/cli-plugin-eslint": "^5.0.9",
"@vue/cli-plugin-typescript": "^5.0.9",
"@vue/cli-plugin-unit-mocha": "^5.0.9",
"@vue/cli-service": "^5.0.9",
"@vue/eslint-config-typescript": "^13.0.0",
"@vue/test-utils": "^2.4.6",
"@vue/tsconfig": "^0.8.1",
"animate.css": "^4.1.1",
"axios": "^1.13.5",
"bulma": "^1.0.4",
"bulma-toast": "2.4.3",
"chai": "^6.2.2",
"core-js": "^3.48.0",
"eslint": "^8.57.1",
"eslint-plugin-vue": "^9.33.0",
"luxon": "^3.7.2",
"pinia": "^3.0.4",
"sass": "~1.94.3",
"sass-loader": "^16.0.0",
"typescript": "^5.9.3",
"vue": "^3.5.25",
"vue-cli-plugin-webpack-bundle-analyzer": "^4.0.0"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

67
ui/_legacy/src/App.vue Normal file
View file

@ -0,0 +1,67 @@
<template>
<section class="hero is-small is-primary">
<div class="hero-body">
<h1 class="title is-uppercase">{{ store.site_config.title }}</h1>
<h2 class="subtitle">{{ store.site_config.subtitle }}</h2>
</div>
</section>
<section class="section px-3">
<progress
v-if="store.background_image === 'loading'"
class="progress is-primary"
max="100"
/>
<div
v-else-if="store.background_image === 'error'"
class="notification is-danger"
>
Hintergrundbild konnte nicht geladen werden
</div>
<div v-else class="container">
<AdminView v-if="store.is_admin" />
<UserView v-else />
</div>
</section>
<div class="is-flex-grow-1" />
<footer class="footer">
<div class="level">
<div class="level-item">
<p v-html="store.site_config.footer" />
</div>
<div class="level-right">
<div class="level-item">
<TouchButton class="is-small is-warning" />
</div>
<div class="level-item">
<AdminButton class="is-small is-link is-outlined" />
</div>
</div>
</div>
</footer>
</template>
<script setup lang="ts">
import { advent22Store } from "./lib/store";
import AdminView from "./components/admin/AdminView.vue";
import AdminButton from "./components/AdminButton.vue";
import TouchButton from "./components/TouchButton.vue";
import UserView from "./components/UserView.vue";
const store = advent22Store();
</script>
<style>
html {
overflow-y: auto !important;
}
#app {
min-height: 100vh;
display: flex;
flex-direction: column;
}
</style>

BIN
ui/_legacy/src/assets/logo.png (Stored with Git LFS) Normal file

Binary file not shown.

27
ui/_legacy/src/main.ts Normal file
View file

@ -0,0 +1,27 @@
import FontAwesomeIcon from "@/lib/fontawesome";
import { advent22Store } from "@/lib/store";
import { setDefaults as toast_set_defaults } from "bulma-toast";
import { createPinia } from "pinia";
import { createApp } from "vue";
import App from "./App.vue";
import "@/main.scss";
const app = createApp(App);
app.use(createPinia());
app.component("FontAwesomeIcon", FontAwesomeIcon);
advent22Store().init();
app.mount("#app");
toast_set_defaults({
duration: 10e3,
pauseOnHover: true,
dismissible: true,
closeOnClick: false,
type: "is-white",
position: "top-center",
animate: { in: "backInDown", out: "backOutUp" },
});

33
ui/_legacy/tsconfig.json Normal file
View file

@ -0,0 +1,33 @@
{
"extends": "@vue/tsconfig/tsconfig.dom.json",
"compilerOptions": {
"experimentalDecorators": true,
"lib": [
"es2020",
"dom",
"dom.iterable",
"es2022.object",
"es2023.array",
],
// "moduleResolution": "node",
// "sourceMap": true,
"baseUrl": ".",
"types": [
"webpack-env",
"mocha",
"chai",
],
"paths": {
"@/*": [
"src/*",
]
},
},
"include": [
"src/**/*.vue",
"src/**/*.ts",
// "src/**/*.tsx",
"tests/**/*.ts",
// "tests/**/*.tsx",
],
}

View file

@ -1,5 +0,0 @@
{
"presets": [
"@vue/cli-plugin-babel/preset"
]
}

1
ui/env.d.ts vendored Normal file
View file

@ -0,0 +1 @@
/// <reference types="vite/client" />

32
ui/eslint.config.ts Normal file
View file

@ -0,0 +1,32 @@
import { globalIgnores } from 'eslint/config'
import { defineConfigWithVueTs, vueTsConfigs } from '@vue/eslint-config-typescript'
import pluginVue from 'eslint-plugin-vue'
import pluginVitest from '@vitest/eslint-plugin'
import pluginOxlint from 'eslint-plugin-oxlint'
import skipFormatting from 'eslint-config-prettier/flat'
// To allow more languages other than `ts` in `.vue` files, uncomment the following lines:
// import { configureVueProject } from '@vue/eslint-config-typescript'
// configureVueProject({ scriptLangs: ['ts', 'tsx'] })
// More info at https://github.com/vuejs/eslint-config-typescript/#advanced-setup
export default defineConfigWithVueTs(
{
name: 'app/files-to-lint',
files: ['**/*.{vue,ts,mts,tsx}'],
},
globalIgnores(['**/dist/**', '**/dist-ssr/**', '**/coverage/**']),
...pluginVue.configs['flat/essential'],
vueTsConfigs.recommended,
{
...pluginVitest.configs.recommended,
files: ['src/**/__tests__/*'],
},
...pluginOxlint.buildFromOxlintConfigFile('.oxlintrc.json'),
skipFormatting,
)

13
ui/index.html Normal file
View file

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vite App</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

View file

@ -1,47 +1,50 @@
{
"name": "advent22_ui",
"version": "0.1.0",
"version": "0.0.0",
"private": true,
"type": "module",
"packageManager": "yarn@4.12.0",
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"test:unit": "vue-cli-service test:unit",
"test:unit-watch": "vue-cli-service test:unit --watch",
"lint": "vue-cli-service lint",
"ui": "vue ui --host 0.0.0.0 --headless"
"dev": "vite",
"build": "run-p type-check \"build-only {@}\" --",
"preview": "vite preview",
"test:unit": "vitest",
"build-only": "vite build",
"type-check": "vue-tsc --build",
"lint": "run-s lint:*",
"lint:oxlint": "oxlint . --fix",
"lint:eslint": "eslint . --fix --cache",
"format": "prettier --write --experimental-cli src/"
},
"dependencies": {
"pinia": "^3.0.4",
"vue": "^3.5.28"
},
"devDependencies": {
"@fortawesome/fontawesome-svg-core": "^7.2.0",
"@fortawesome/free-solid-svg-icons": "^7.2.0",
"@fortawesome/vue-fontawesome": "^3.1.3",
"@types/chai": "^5.2.3",
"@types/luxon": "^3.7.1",
"@types/mocha": "^10.0.10",
"@typescript-eslint/eslint-plugin": "^8.55.0",
"@typescript-eslint/parser": "^8.55.0",
"@vue/cli-plugin-babel": "^5.0.9",
"@vue/cli-plugin-eslint": "^5.0.9",
"@vue/cli-plugin-typescript": "^5.0.9",
"@vue/cli-plugin-unit-mocha": "^5.0.9",
"@vue/cli-service": "^5.0.9",
"@vue/eslint-config-typescript": "^13.0.0",
"@tsconfig/node24": "^24.0.4",
"@types/jsdom": "^27.0.0",
"@types/node": "^25.3.0",
"@vitejs/plugin-vue": "^6.0.4",
"@vitest/eslint-plugin": "^1.6.9",
"@vue/eslint-config-typescript": "^14.6.0",
"@vue/test-utils": "^2.4.6",
"@vue/tsconfig": "^0.8.1",
"animate.css": "^4.1.1",
"axios": "^1.13.5",
"bulma": "^1.0.4",
"bulma-toast": "2.4.3",
"chai": "^6.2.2",
"core-js": "^3.48.0",
"eslint": "^8.57.1",
"eslint-plugin-vue": "^9.33.0",
"luxon": "^3.7.2",
"pinia": "^3.0.4",
"sass": "~1.94.3",
"sass-loader": "^16.0.0",
"typescript": "^5.9.3",
"vue": "^3.5.25",
"vue-cli-plugin-webpack-bundle-analyzer": "^4.0.0"
"eslint": "^9.39.2",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-oxlint": "~1.46.0",
"eslint-plugin-vue": "~10.8.0",
"jiti": "^2.6.1",
"jsdom": "^28.1.0",
"npm-run-all2": "^8.0.4",
"oxlint": "~1.47.0",
"prettier": "3.8.1",
"typescript": "~5.9.3",
"vite": "^7.3.1",
"vite-plugin-vue-devtools": "^8.0.6",
"vitest": "^4.0.18",
"vue-tsc": "^3.2.4"
},
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

View file

@ -1,67 +1,11 @@
<script setup lang="ts"></script>
<template>
<section class="hero is-small is-primary">
<div class="hero-body">
<h1 class="title is-uppercase">{{ store.site_config.title }}</h1>
<h2 class="subtitle">{{ store.site_config.subtitle }}</h2>
</div>
</section>
<section class="section px-3">
<progress
v-if="store.background_image === 'loading'"
class="progress is-primary"
max="100"
/>
<div
v-else-if="store.background_image === 'error'"
class="notification is-danger"
>
Hintergrundbild konnte nicht geladen werden
</div>
<div v-else class="container">
<AdminView v-if="store.is_admin" />
<UserView v-else />
</div>
</section>
<div class="is-flex-grow-1" />
<footer class="footer">
<div class="level">
<div class="level-item">
<p v-html="store.site_config.footer" />
</div>
<div class="level-right">
<div class="level-item">
<TouchButton class="is-small is-warning" />
</div>
<div class="level-item">
<AdminButton class="is-small is-link is-outlined" />
</div>
</div>
</div>
</footer>
<h1>You did it!</h1>
<p>
Visit <a href="https://vuejs.org/" target="_blank" rel="noopener">vuejs.org</a> to read the
documentation
</p>
</template>
<script setup lang="ts">
import { advent22Store } from "./lib/store";
import AdminView from "./components/admin/AdminView.vue";
import AdminButton from "./components/AdminButton.vue";
import TouchButton from "./components/TouchButton.vue";
import UserView from "./components/UserView.vue";
const store = advent22Store();
</script>
<style>
html {
overflow-y: auto !important;
}
#app {
min-height: 100vh;
display: flex;
flex-direction: column;
}
</style>
<style scoped></style>

View file

@ -0,0 +1,11 @@
import { describe, it, expect } from 'vitest'
import { mount } from '@vue/test-utils'
import App from '../App.vue'
describe('App', () => {
it('mounts renders properly', () => {
const wrapper = mount(App)
expect(wrapper.text()).toContain('You did it!')
})
})

View file

@ -1,27 +1,9 @@
import FontAwesomeIcon from "@/lib/fontawesome";
import { advent22Store } from "@/lib/store";
import { setDefaults as toast_set_defaults } from "bulma-toast";
import { createPinia } from "pinia";
import { createApp } from "vue";
import App from "./App.vue";
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
import "@/main.scss";
const app = createApp(App)
const app = createApp(App);
app.use(createPinia())
app.use(createPinia());
app.component("FontAwesomeIcon", FontAwesomeIcon);
advent22Store().init();
app.mount("#app");
toast_set_defaults({
duration: 10e3,
pauseOnHover: true,
dismissible: true,
closeOnClick: false,
type: "is-white",
position: "top-center",
animate: { in: "backInDown", out: "backOutUp" },
});
app.mount('#app')

12
ui/src/stores/counter.ts Normal file
View file

@ -0,0 +1,12 @@
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
const doubleCount = computed(() => count.value * 2)
function increment() {
count.value++
}
return { count, doubleCount, increment }
})

12
ui/tsconfig.app.json Normal file
View file

@ -0,0 +1,12 @@
{
"extends": "@vue/tsconfig/tsconfig.dom.json",
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
"exclude": ["src/**/__tests__/*"],
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"paths": {
"@/*": ["./src/*"]
}
}
}

View file

@ -1,33 +1,14 @@
{
"extends": "@vue/tsconfig/tsconfig.dom.json",
"compilerOptions": {
"experimentalDecorators": true,
"lib": [
"es2020",
"dom",
"dom.iterable",
"es2022.object",
"es2023.array",
],
// "moduleResolution": "node",
// "sourceMap": true,
"baseUrl": ".",
"types": [
"webpack-env",
"mocha",
"chai",
],
"paths": {
"@/*": [
"src/*",
]
"files": [],
"references": [
{
"path": "./tsconfig.node.json"
},
{
"path": "./tsconfig.app.json"
},
"include": [
"src/**/*.vue",
"src/**/*.ts",
// "src/**/*.tsx",
"tests/**/*.ts",
// "tests/**/*.tsx",
],
{
"path": "./tsconfig.vitest.json"
}
]
}

19
ui/tsconfig.node.json Normal file
View file

@ -0,0 +1,19 @@
{
"extends": "@tsconfig/node24/tsconfig.json",
"include": [
"vite.config.*",
"vitest.config.*",
"cypress.config.*",
"nightwatch.conf.*",
"playwright.config.*",
"eslint.config.*"
],
"compilerOptions": {
"noEmit": true,
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
"module": "ESNext",
"moduleResolution": "Bundler",
"types": ["node"]
}
}

11
ui/tsconfig.vitest.json Normal file
View file

@ -0,0 +1,11 @@
{
"extends": "./tsconfig.app.json",
"include": ["src/**/__tests__/*", "env.d.ts"],
"exclude": [],
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.vitest.tsbuildinfo",
"lib": [],
"types": ["node", "jsdom"]
}
}

18
ui/vite.config.ts Normal file
View file

@ -0,0 +1,18 @@
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueDevTools from 'vite-plugin-vue-devtools'
// https://vite.dev/config/
export default defineConfig({
plugins: [
vue(),
vueDevTools(),
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
},
},
})

14
ui/vitest.config.ts Normal file
View file

@ -0,0 +1,14 @@
import { fileURLToPath } from 'node:url'
import { mergeConfig, defineConfig, configDefaults } from 'vitest/config'
import viteConfig from './vite.config'
export default mergeConfig(
viteConfig,
defineConfig({
test: {
environment: 'jsdom',
exclude: [...configDefaults.exclude, 'e2e/**'],
root: fileURLToPath(new URL('./', import.meta.url)),
},
}),
)

View file

@ -1,26 +0,0 @@
/* eslint-disable @typescript-eslint/no-require-imports */
const { defineConfig } = require("@vue/cli-service");
const webpack = require("webpack");
module.exports = defineConfig({
transpileDependencies: true,
devServer: {
host: "127.0.0.1",
},
pages: {
index: {
entry: "src/main.ts",
title: "Kalender-Gewinnspiel",
},
},
// https://stackoverflow.com/a/77765007
configureWebpack: {
plugins: [
new webpack.DefinePlugin({
// Vue CLI is in maintenance mode, and probably won't merge my PR to fix this in their tooling
// https://github.com/vuejs/vue-cli/pull/7443
__VUE_PROD_HYDRATION_MISMATCH_DETAILS__: "false",
}),
],
},
});

10018
ui/yarn.lock

File diff suppressed because it is too large Load diff