From 125b46ae8295584a32e61a23d27570f90f3f301d Mon Sep 17 00:00:00 2001 From: Janis Hutz Date: Wed, 4 Nov 2026 09:42:28 +0100 Subject: [PATCH 1/3] chore: scaffold vuetify --- env.d.ts | 1 + index.html | 16 +-- package.json | 45 +++--- public/favicon.ico | Bin 4286 -> 15406 bytes public/layers.css | 1 + src/App.vue | 124 ++-------------- src/assets/logo.png | Bin 0 -> 11955 bytes src/assets/logo.svg | 6 + src/components/HelloWorld.vue | 113 +++++++++++++++ src/components/README.md | 35 +++++ .../authz/LoginProvider.vue} | 37 +---- src/components/authz/LogoutProvider.vue | 0 .../PopupElement.vue | 6 +- src/components/custom-ui-elements/README.md | 4 + src/components/elements/SwitchOption.vue | 48 ------- src/main.ts | 48 +++---- src/{views/AppView.vue => pages/AppPage.vue} | 1 - src/pages/StartPage.vue | 7 + src/plugins/README.md | 3 + src/plugins/index.ts | 19 +++ src/plugins/vuetify.ts | 28 ++++ src/router/index.ts | 4 +- src/scss/app.scss | 37 ----- src/scss/components/toggles.scss | 56 -------- src/scss/main.scss | 132 ------------------ src/scss/pages/home.scss | 58 -------- src/scss/theme.scss | 129 ----------------- src/styles/README.md | 3 + src/styles/settings.scss | 10 ++ src/ts/util/theme.ts | 57 -------- tsconfig.app.json | 32 +++-- tsconfig.node.json | 25 ++-- vite.config.ts | 65 +++++++-- vue-readme.md | 42 ------ vuetify-readme.md | 76 ++++++++++ 35 files changed, 447 insertions(+), 821 deletions(-) create mode 100644 public/layers.css create mode 100644 src/assets/logo.png create mode 100644 src/assets/logo.svg create mode 100644 src/components/HelloWorld.vue create mode 100644 src/components/README.md rename src/{views/StartPage.vue => components/authz/LoginProvider.vue} (51%) create mode 100644 src/components/authz/LogoutProvider.vue rename src/components/{elements => custom-ui-elements}/PopupElement.vue (93%) create mode 100644 src/components/custom-ui-elements/README.md delete mode 100644 src/components/elements/SwitchOption.vue rename src/{views/AppView.vue => pages/AppPage.vue} (60%) create mode 100644 src/pages/StartPage.vue create mode 100644 src/plugins/README.md create mode 100644 src/plugins/index.ts create mode 100644 src/plugins/vuetify.ts delete mode 100644 src/scss/app.scss delete mode 100644 src/scss/components/toggles.scss delete mode 100644 src/scss/main.scss delete mode 100644 src/scss/pages/home.scss delete mode 100644 src/scss/theme.scss create mode 100644 src/styles/README.md create mode 100644 src/styles/settings.scss delete mode 100644 src/ts/util/theme.ts delete mode 100644 vue-readme.md create mode 100644 vuetify-readme.md diff --git a/env.d.ts b/env.d.ts index 11f02fe..db56195 100644 --- a/env.d.ts +++ b/env.d.ts @@ -1 +1,2 @@ /// +/// diff --git a/index.html b/index.html index 8cc325a..f88041d 100644 --- a/index.html +++ b/index.html @@ -1,16 +1,14 @@ - - - + + + - Vite App - - - + Welcome to Vuetify 4 + +
- - + diff --git a/package.json b/package.json index 7721f50..4e24963 100644 --- a/package.json +++ b/package.json @@ -1,44 +1,43 @@ { - "name": "frontend", - "version": "0.0.0", + "name": "studyphoenix-frontend", "private": true, "type": "module", + "version": "1.0.0", "scripts": { "dev": "vite", "build": "run-p type-check \"build-only {@}\" --", "preview": "vite preview", "build-only": "vite build", + "type-check": "vue-tsc --build --force", "lint": "eslint ./src", - "lint-fix": "eslint ./src --fix", - "type-check": "vue-tsc --build" + "lint-fix": "eslint ./src --fix" }, "dependencies": { - "@fortawesome/fontawesome-free": "^7.3.1", + "@fontsource/roboto": "^5.2.10", "@janishutz/oidc-login-sdk-browser": "^1.5.2", - "@kyvg/vue3-notification": "^3.4.2", - "pinia": "^4.0.3", - "vue": "^3.5.42", - "vue-router": "^5.3.1" + "@mdi/font": "7.4.47", + "pinia": "^3.0.4", + "vue": "^3.5.30", + "vue-router": "^5.0.3", + "vuetify": "^4.0.2" }, "devDependencies": { "@eslint/js": "^10.0.1", "@stylistic/eslint-plugin": "^5.10.0", - "@tsconfig/node24": "^24.0.5", - "@types/node": "^24.13.4", - "@vitejs/plugin-vue": "^6.0.8", - "@vue/tsconfig": "^0.9.1", + "@tsconfig/node22": "^22.0.5", + "@types/node": "^24.12.0", + "@vitejs/plugin-vue": "^6.0.5", + "@vue/tsconfig": "^0.9.0", "eslint": "^10.14.0", "eslint-plugin-vue": "^10.12.0", - "globals": "^17.13.0", - "npm-run-all2": "^9.0.3", - "sass-embedded": "^1.107.0", - "typescript": "~6.0.0", + "globals": "^17.14.0", + "npm-run-all2": "^8.0.4", + "sass-embedded": "^1.98.0", + "typescript": "~5.9.3", "typescript-eslint": "^8.72.1", - "vite": "^8.2.2", - "vite-plugin-vue-devtools": "^8.2.1", - "vue-tsc": "^3.3.11" - }, - "engines": { - "node": "^22.18.0 || >=24.12.0" + "unplugin-fonts": "^2.0.0", + "vite": "^8.0.0", + "vite-plugin-vuetify": "^2.1.3", + "vue-tsc": "^3.2.5" } } diff --git a/public/favicon.ico b/public/favicon.ico index df36fcfb72584e00488330b560ebcf34a41c64c2..8fb9f91b3aab4eec0c76ffc5342528033c61e247 100644 GIT binary patch literal 15406 zcmeHO3v5%@8NNVarCoU?zSqezmT6npu}xxXJJhY(x=s~hQ>SSYYSncU&|(|9Y?QVX z@}TB1G8mASM;tRKYgJkrAW)&g7${B%c>oE7;)O>NNO_bu4G-IdNB({PbTkJL{ZGDJe2DLL+vq#sL?l$jZPe_*I2y@|4sBRjso zUy`aUlJo$60})6B%aMKN&yMG1Qvjth%4dDy{HM^34) z&_TyGJg3UC{J|n2-wr)LDYwhNWBH4VL-JgYz;erTEKiMF20`|$Cf~GysBU40j@&)u zboK>@(yL25%R|RmS~6@99bG>PviV`j>&k~M@~J%cn{`uCzUOyY^23rlWt6DH=aut3 zlZo^g63xIXwP(4)hgT<|I>hSGqh7YbLP$jL+%p0>vM2Su?wmOV;-uyLFww=KN5Ox{j<% zmi}mZc22bZyxbmI!x+Ch3+qsk+#YbHJ{CdQjDh~;LRJB63Pq&~p

*N){PEn7FA;EAwj=|b_AUGw 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 diff --git a/public/layers.css b/public/layers.css new file mode 100644 index 0000000..2d403cb --- /dev/null +++ b/public/layers.css @@ -0,0 +1 @@ +@layer vuetify-core, vuetify-components, vuetify-overrides, vuetify-utilities, vuetify-final; diff --git a/src/App.vue b/src/App.vue index 18123e5..a054987 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,119 +1,11 @@ - - - + diff --git a/src/assets/logo.png b/src/assets/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..a5f23ae7bff64954cf3537377a9f99306baf083d GIT binary patch literal 11955 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 + + + + + diff --git a/src/components/HelloWorld.vue b/src/components/HelloWorld.vue new file mode 100644 index 0000000..2e2f1c9 --- /dev/null +++ b/src/components/HelloWorld.vue @@ -0,0 +1,113 @@ + + + diff --git a/src/components/README.md b/src/components/README.md new file mode 100644 index 0000000..d1dc92f --- /dev/null +++ b/src/components/README.md @@ -0,0 +1,35 @@ +# Components + +Vue template files in this folder are automatically imported. + +## ๐Ÿš€ Usage + +Importing is handled by [unplugin-vue-components](https://github.com/unplugin/unplugin-vue-components). This plugin automatically imports `.vue` files created in the `src/components` directory, and registers them as global components. This means that you can use any component in your application without having to manually import it. + +The following example assumes a component located at `src/components/MyComponent.vue`: + +```vue + + + +``` + +When your template is rendered, the component's import will automatically be inlined, which renders to this: + +```vue + + + +``` diff --git a/src/views/StartPage.vue b/src/components/authz/LoginProvider.vue similarity index 51% rename from src/views/StartPage.vue rename to src/components/authz/LoginProvider.vue index 4725d1f..724544b 100644 --- a/src/views/StartPage.vue +++ b/src/components/authz/LoginProvider.vue @@ -9,9 +9,8 @@ useAuthStore } from '@/stores/authstore'; - const isLoggingIn = ref( true ); - const isUnowned = ref( false ); const store = useAuthStore(); + const isLoggingIn = ref( true ); const check = async ( force?: boolean ) => { isLoggingIn.value = true; @@ -25,7 +24,6 @@ if ( e instanceof sdk.request.AuthError ) { throw e; } else if ( ( e as Error ).message === 'ERR_402' ) { - isUnowned.value = true; console.log( 'Error' ); } } @@ -52,38 +50,11 @@ isLoggingIn.value = false; }; - const version = ( import.meta.env.VITE_GIT_REF ? ( import.meta.env.VITE_GIT_REF as string ).slice( 0, 10 ) : 'dev' ) + ( import.meta.env.PROD ? '-prod' : '-dev' ); - const gitRef = import.meta.env.VITE_GIT_REF; - onMounted( check ); - - diff --git a/src/components/authz/LogoutProvider.vue b/src/components/authz/LogoutProvider.vue new file mode 100644 index 0000000..e69de29 diff --git a/src/components/elements/PopupElement.vue b/src/components/custom-ui-elements/PopupElement.vue similarity index 93% rename from src/components/elements/PopupElement.vue rename to src/components/custom-ui-elements/PopupElement.vue index 7030066..b350a1f 100644 --- a/src/components/elements/PopupElement.vue +++ b/src/components/custom-ui-elements/PopupElement.vue @@ -39,7 +39,7 @@ width: 100vw; height: 100vh; position: absolute; - background-color: var( --theme-shadow ); + background-color: rgba(0, 0, 0, 0.7); top: 0; left: 0; overflow: hidden; @@ -51,8 +51,8 @@ height: fit-content; max-width: 90%; max-height: 90%; - background-color: var( --theme-app ); - color: var( --theme-on-app ); + background-color: white; + color: black; padding: 2.5%; border-radius: 20px; transform: scale(1); diff --git a/src/components/custom-ui-elements/README.md b/src/components/custom-ui-elements/README.md new file mode 100644 index 0000000..2baf969 --- /dev/null +++ b/src/components/custom-ui-elements/README.md @@ -0,0 +1,4 @@ +# Custom Modules +Implement custom UI elements here, such as a custom popup, etc. + +Any normal component (that isn't a UI element) should *NOT* go in this folder diff --git a/src/components/elements/SwitchOption.vue b/src/components/elements/SwitchOption.vue deleted file mode 100644 index bdb55dc..0000000 --- a/src/components/elements/SwitchOption.vue +++ /dev/null @@ -1,48 +0,0 @@ - - - - - diff --git a/src/main.ts b/src/main.ts index 485a6a5..f898fe4 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,37 +1,23 @@ -import '@fortawesome/fontawesome-free/css/all.css'; -import App from './App.vue'; -import Notifications from '@kyvg/vue3-notification'; -import { - configure -} from '@janishutz/oidc-login-sdk-browser'; -import { - createApp -} from 'vue'; -import { - createPinia -} from 'pinia'; -import router from './router'; +/** + * main.ts + * + * Bootstraps Vuetify and other plugins then mounts the App` + */ -// Detect backend URL -let backendURL: string; +// Composables +import { createApp } from 'vue' -if ( import.meta.env.PROD ) { - backendURL = import.meta.env.VITE_BACKEND_URL ?? ( location.protocol + '//api.' + location.host ); -} else { - console.warn( '[BACKEND] Development backend enabled' ); - backendURL = import.meta.env.VITE_BACKEND_URL ?? 'http://localhost:8080'; -} +// Plugins +import { registerPlugins } from '@/plugins' -configure( { - 'backendURL': new URL( backendURL ), - 'defaultAuthErrorResolution': 'resolve', - 'authErrorEvent': 'autherror' -} ); +// Components +import App from './App.vue' -const app = createApp( App ); +// Styles +import 'unfonts.css' -app.use( createPinia() ); -app.use( router ); -app.use( Notifications ); +const app = createApp(App) -app.mount( '#app' ); +registerPlugins(app) + +app.mount('#app') diff --git a/src/views/AppView.vue b/src/pages/AppPage.vue similarity index 60% rename from src/views/AppView.vue rename to src/pages/AppPage.vue index 504e7f5..9623b96 100644 --- a/src/views/AppView.vue +++ b/src/pages/AppPage.vue @@ -1,5 +1,4 @@ diff --git a/src/pages/StartPage.vue b/src/pages/StartPage.vue new file mode 100644 index 0000000..2619c0f --- /dev/null +++ b/src/pages/StartPage.vue @@ -0,0 +1,7 @@ + + + diff --git a/src/plugins/README.md b/src/plugins/README.md new file mode 100644 index 0000000..62201c7 --- /dev/null +++ b/src/plugins/README.md @@ -0,0 +1,3 @@ +# Plugins + +Plugins are a way to extend the functionality of your Vue application. Use this folder for registering plugins that you want to use globally. diff --git a/src/plugins/index.ts b/src/plugins/index.ts new file mode 100644 index 0000000..ccbf88e --- /dev/null +++ b/src/plugins/index.ts @@ -0,0 +1,19 @@ +import router from '../router'; +import { createPinia } from 'pinia'; +/** + * plugins/index.ts + * + * Automatically included in `./src/main.ts` + */ + +// Types +import type { App } from 'vue' + +// Plugins +import vuetify from './vuetify' + +export function registerPlugins (app: App) { + app.use(vuetify) + app.use(createPinia()); + app.use(router); +} \ No newline at end of file diff --git a/src/plugins/vuetify.ts b/src/plugins/vuetify.ts new file mode 100644 index 0000000..4b1c17d --- /dev/null +++ b/src/plugins/vuetify.ts @@ -0,0 +1,28 @@ +/** + * plugins/vuetify.ts + * + * Framework documentation: https://vuetifyjs.com` + */ + +import '@mdi/font/css/materialdesignicons.css'; +import 'vuetify/styles'; +import { + createVuetify +} from 'vuetify'; +import { + md3 +} from 'vuetify/blueprints'; + +// https://vuetifyjs.com/en/introduction/why-vuetify/#feature-guides +export default createVuetify( { + 'defaults': { + 'VBtn': { + 'color': 'primary', + 'rounded': 'true' + } + }, + 'blueprint': md3, // TODO: custom themes + 'theme': { + 'defaultTheme': 'system' + } +} ); diff --git a/src/router/index.ts b/src/router/index.ts index caee70b..aef6ca6 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -12,7 +12,7 @@ const router = createRouter( { { 'path': '/', 'name': 'home', - 'component': () => import( '@/views/StartPage.vue' ), + 'component': () => import( '@/pages/StartPage.vue' ), 'meta': { 'title': 'Home', 'auth': false @@ -21,7 +21,7 @@ const router = createRouter( { { 'path': '/app', 'name': 'app', - 'component': () => import( '@/views/AppView.vue' ), + 'component': () => import( '@/pages/AppPage.vue' ), 'meta': { 'title': 'App', 'auth': true diff --git a/src/scss/app.scss b/src/scss/app.scss deleted file mode 100644 index 7e61f71..0000000 --- a/src/scss/app.scss +++ /dev/null @@ -1,37 +0,0 @@ -/* Primary styling for the page */ -#app { - transition: 0.5s; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - font-size: 1rem; - width: 100vw; - height: 100vh; - margin: 0; - display: flex; - justify-content: center; - align-items: center; - flex-direction: column; - text-align: center; -} - -/* Vue intra-page transitions */ -.scale-enter-active, -.scale-leave-active { - transition: all 0.5s ease; -} - -.scale-enter-from, -.scale-leave-to { - opacity: 0; - transform: scale(0.9); -} - -.fade-enter-active, -.fade-leave-active { - transition: opacity 0.2s ease; -} - -.fade-enter-from, -.fade-leave-to { - opacity: 0; -} diff --git a/src/scss/components/toggles.scss b/src/scss/components/toggles.scss deleted file mode 100644 index ec84b15..0000000 --- a/src/scss/components/toggles.scss +++ /dev/null @@ -1,56 +0,0 @@ -/* https://www.w3schools.com/howto/tryit.asp?filename=tryhow_css_switch */ -.switch { - position: relative; - display: inline-block; - width: 50px; - height: 25px; - - >input { - opacity: 0; - width: 0; - height: 0; - - &:checked+.slider { - background-color: var(--theme-secondary-hover); - } - - &:checked+.slider:before { - -webkit-transform: translateX(26px); - -ms-transform: translateX(26px); - transform: translateX(26px); - } - } - - >.slider { - position: absolute; - cursor: pointer; - top: 0; - left: 0; - right: 0; - bottom: 0; - background-color: var(--theme-secondary); - -webkit-transition: .4s; - transition: .4s; - - &:before { - position: absolute; - content: ""; - height: 18px; - width: 18px; - left: 3px; - bottom: 3px; - background-color: var(--theme-on-secondary); - -webkit-transition: .4s; - transition: .4s; - } - - /* Rounded sliders */ - &.round { - border-radius: 34px; - - &:before { - border-radius: 50%; - } - } - } -} diff --git a/src/scss/main.scss b/src/scss/main.scss deleted file mode 100644 index d3eab5d..0000000 --- a/src/scss/main.scss +++ /dev/null @@ -1,132 +0,0 @@ -@forward '@/scss/theme.scss'; -@forward '@/scss/app.scss'; - -html { - width: 100%; - height: 100%; - margin: 0; - padding: 0; - font-size: 17px; - background-color: var(--theme-bg); - color: var(--theme-on-bg); - font-family: sans-serif; - - &.init-complete { - transition: background-color 0.5s, color 0.5s; - } -} - -body { - transition: none; - margin: 0; - padding: 0; -} - -a { - color: var(--theme-on-bg); -} - -.info { - font-style: italic; -} - -.small-divider { - width: 10vw; -} - -.divider { - width: 20vw; -} - -// โ”€โ”€ Notifications โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -.notifications { - .vue-notification { - padding: 20px; - - .notification-title { - font-size: 1rem; - } - - .notification-text { - font-size: 0.75rem; - } - } -} - -::selection { - background-color: var(--theme-secondary); - color: var(--theme-on-secondary); -} - -button { - color: var(--theme-on-primary); - padding: 7px; - background: var(--theme-primary); - border-radius: 20px; - margin: 2px; - border: none; - font-size: 1rem; - cursor: pointer; - transition: background-color 0.5s, border-radius 0.5s; - - &:hover { - border-radius: 5px; - background-color: var(--theme-primary-hover); - } - - &.inactive { - cursor: not-allowed; - filter: saturate(0.2); - } - - &.fancy-button { - color: var(--theme-on-primary); - text-decoration: none; - padding: 20px; - background: linear-gradient(45deg, var(--theme-primary), var(--theme-secondary)); - font-size: larger; - transition: all 0.5s; - background-size: 150%; - - &:hover { - border-radius: 5px; - background-position: 50%; - } - - &.inactive { - cursor: not-allowed; - - &:hover { - border-radius: 20px; - background-position: 0px; - } - } - } -} - -input, -select { - background: none; - border-radius: 10px; - border: solid 1px var(--theme-on-app); - color: var(--theme-on-app); - padding: 5px; - font-size: 0.9rem; -} - -progress { - border: none; - border-radius: 10px; - height: 6px; - appearance: none; - - &::-webkit-progress-value, - & { - background-color: var(--theme-primary); - } - - &::-moz-progress-bar, - &::-webkit-progress-bar { - background-color: var(--theme-primary-hover); - } -} diff --git a/src/scss/pages/home.scss b/src/scss/pages/home.scss deleted file mode 100644 index 392cb8f..0000000 --- a/src/scss/pages/home.scss +++ /dev/null @@ -1,58 +0,0 @@ -.home-page { - display: flex; - flex-direction: column-reverse; - justify-content: center; - align-items: center; - height: 100%; - width: 100%; - margin: 0; - - .side-container { - width: 95%; - margin: 2.5%; - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - - >img { - width: min(85vw, 45vh); - border-radius: 10px; - } - - >i { - color: var(--theme-dimmed); - font-size: 0.8rem; - } - } - - >.version { - position: fixed; - bottom: 10px; - right: 10px; - - >a { - color: var(--theme-dimmed); - font-size: 0.8rem; - text-decoration: none; - } - } - - @media screen and (min-aspect-ratio: 1) { - flex-direction: row; - - .side-container { - height: 95%; - width: 45%; - - >h1 { - font-size: 4rem; - margin: 10px; - } - - >img { - width: min(35vw, 80vh); - } - } - } -} diff --git a/src/scss/theme.scss b/src/scss/theme.scss deleted file mode 100644 index 7649876..0000000 --- a/src/scss/theme.scss +++ /dev/null @@ -1,129 +0,0 @@ -@use 'sass:color'; - -$theme-red-light: ( - on-bg: #040404, - bg: #ffe0e0, - app: #eeeeee, - on-app: #040404, - primary: #b50808, - primary-hover: #820808, - on-primary: #ffffff, - secondary: #fa5347, - secondary-hover: #ca2745, - on-secondary: #ffffff, - dimmed: #aaaaaa, - shadow: rgba(0, 0, 0, 0.7), -); - -$theme-red-dark: ( - on-bg: #ffffff, - bg: #1a0303, - app: #030303, - on-app: #ffffff, - primary: #510f0c, - primary-hover: #910f0c, - on-primary: #ffffff, - secondary: #fa5347, - secondary-hover: #ca2745, - on-secondary: #ffffff, - dimmed: #aaaaaa, - shadow: rgba(0, 0, 0, 0.7), -); - -$theme-blue-light: ( - on-bg: #000000, - bg: #dadae3, - on-app: #000000, - app: #fefefe, - on-primary: #ffffff, - primary: #04305c, - primary-hover: #144197, - on-secondary: #ffffff, - secondary: #7583da, - secondary-hover: #7593c0, - dimmed: #444444, - shadow: rgba(0, 0, 0, 0.7), -); - -$theme-blue-dark: ( - on-bg: #ffffff, - bg: #111220, - on-app: #ffffff, - app: #020202, - on-primary: #ffffff, - primary: #04305c, - primary-hover: #144197, - on-secondary: #ffffff, - secondary: #7583da, - secondary-hover: #7593c0, - dimmed: #aaaaaa, - shadow: rgba(20, 20, 20, 0.7), -); - -$theme-purple-light: ( - on-bg: #000000, - bg: #f5e3f5, - app: #ffffff, - on-app: #000000, - primary: #800580, - primary-hover: #500340, - on-primary: #ffffff, - secondary: #9040a5, - secondary-hover: #503060, - on-secondary: #ffffff, - dimmed: #aaaaaa, - shadow: rgba(0, 0, 0, 0.7), -); - -$theme-purple-dark: ( - on-bg: #ffffff, - bg: #100113, - app: #030303, - on-app: #ffffff, - primary: #360340, - primary-hover: #600955, - on-primary: #ffffff, - secondary: #9040a5, - secondary-hover: #503060, - on-secondary: #ffffff, - dimmed: #aaaaaa, - shadow: rgba(0, 0, 0, 0.7), -); - -$theme-monochrome-light: ( - on-bg: #000000, - bg: #e0e0e0, - app: #ffffff, - on-app: #000000, - primary: #a0a0a0, - primary-hover: #cacaca, - on-primary: #000000, - secondary: #cccccc, - secondary-hover: #888888, - on-secondary: #ffffff, - dimmed: #aaaaaa, - shadow: rgba(0, 0, 0, 0.7), -); - -$theme-monochrome-dark: ( - on-bg: #ffffff, - bg: #101010, - app: #000000, - on-app: #ffffff, - primary: #666666, - primary-hover: #333333, - on-primary: #ffffff, - secondary: #222222, - secondary-hover: #4f4f4f, - on-secondary: #ffffff, - dimmed: #aaaaaa, - shadow: rgba(0, 0, 0, 0.7), -); - -@mixin gen-theme ($selector, $theme) { - #{$selector} { - @each $var, $value in $theme { - --theme-#{$var}: #{$value}; - } - } -} diff --git a/src/styles/README.md b/src/styles/README.md new file mode 100644 index 0000000..ea86179 --- /dev/null +++ b/src/styles/README.md @@ -0,0 +1,3 @@ +# Styles + +This directory is for configuring the styles of the application. diff --git a/src/styles/settings.scss b/src/styles/settings.scss new file mode 100644 index 0000000..3e36a27 --- /dev/null +++ b/src/styles/settings.scss @@ -0,0 +1,10 @@ +/** + * src/styles/settings.scss + * + * Configures SASS variables and Vuetify overwrites + */ + +// https://vuetifyjs.com/features/sass-variables/` +// @use 'vuetify/settings' with ( +// $color-pack: false +// ); diff --git a/src/ts/util/theme.ts b/src/ts/util/theme.ts deleted file mode 100644 index 7d9916f..0000000 --- a/src/ts/util/theme.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { - type Ref, - ref, - watch -} from 'vue'; - -const themes: Ref = ref( [ - 'Blue', - 'Red', - 'Monochrome', - 'Purple' -] ); -const darkMode: Ref = ref( localStorage.getItem( 'theme-mode' ) !== 'light' ); -const selectedTheme = ref( themes.value[ 0 ]! ); - -let currTheme = ''; - -const formatThemeName = ( base: string ) => { - return 'theme-' + base.toLowerCase() + '-' + ( darkMode.value ? 'dark' : 'light' ); -}; - -watch( [ - selectedTheme, - darkMode -], () => { - if ( formatThemeName( selectedTheme.value ) !== currTheme ) { - document.documentElement.classList.remove( currTheme ); - currTheme = formatThemeName( selectedTheme.value ); - document.documentElement.classList.add( currTheme ); - localStorage.setItem( 'theme', selectedTheme.value ); - localStorage.setItem( 'theme-mode', darkMode.value ? 'dark' : 'light' ); - } -} ); - -const tempTheme = localStorage.getItem( 'theme' ); - -if ( tempTheme ) { - if ( !themes.value.includes( tempTheme ) ) { - localStorage.setItem( 'theme', selectedTheme.value ); - localStorage.setItem( 'theme-mode', darkMode.value ? 'dark' : 'light' ); - document.documentElement.classList.add( formatThemeName( themes.value[ 0 ]! ) ); - } else { - selectedTheme.value = tempTheme; - document.documentElement.classList.add( formatThemeName( selectedTheme.value ) ); - } -} else { - document.documentElement.classList.add( formatThemeName( themes.value[ 0 ]!.toLowerCase() ) ); -} - -currTheme = formatThemeName( selectedTheme.value ); -document.documentElement.classList.add( 'init-complete' ); - -export { - themes, - selectedTheme, - darkMode -}; diff --git a/tsconfig.app.json b/tsconfig.app.json index c0f2d86..4ba76cc 100644 --- a/tsconfig.app.json +++ b/tsconfig.app.json @@ -1,18 +1,26 @@ { "extends": "@vue/tsconfig/tsconfig.dom.json", - "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], - "exclude": ["src/**/__tests__/*"], + "include": [ + "env.d.ts", + "src/**/*", + "src/**/*.vue" + ], + "exclude": [ + "src/**/__tests__/*" + ], "compilerOptions": { - // Extra safety for array and object lookups, but may have false positives. - "noUncheckedIndexedAccess": true, - - // Path mapping for cleaner imports. + "composite": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", "paths": { - "@/*": ["./src/*"] - }, - - // `vue-tsc --build` produces a .tsbuildinfo file for incremental type-checking. - // Specified here to keep it out of the root directory. - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo" + "@/*": [ + "./src/*" + ] + } + }, + "vueCompilerOptions": { + "plugins": [ + "vue-router/volar/sfc-typed-router", + "vue-router/volar/sfc-route-blocks" + ] } } diff --git a/tsconfig.node.json b/tsconfig.node.json index 7274bd4..5a0c6a5 100644 --- a/tsconfig.node.json +++ b/tsconfig.node.json @@ -1,28 +1,19 @@ -// TSConfig for modules that run in Node.js environment via either transpilation or type-stripping. { - "extends": "@tsconfig/node24/tsconfig.json", + "extends": "@tsconfig/node22/tsconfig.json", "include": [ "vite.config.*", "vitest.config.*", "cypress.config.*", - "playwright.config.*", - "eslint.config.*" + "nightwatch.conf.*", + "playwright.config.*" ], "compilerOptions": { - // Most tools use transpilation instead of Node.js's native type-stripping. - // Bundler mode provides a smoother developer experience. - "module": "preserve", - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - - // Include Node.js types and avoid accidentally including other `@types/*` packages. - "types": ["node"], - - // Disable emitting output during `vue-tsc --build`, which is used for type-checking only. + "composite": true, "noEmit": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - // `vue-tsc --build` produces a .tsbuildinfo file for incremental type-checking. - // Specified here to keep it out of the root directory. - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo" + "module": "ESNext", + "moduleResolution": "Bundler", + "types": ["node"] } } diff --git a/vite.config.ts b/vite.config.ts index 42c779c..3f45f1c 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -2,31 +2,66 @@ import { URL, fileURLToPath } from 'node:url'; +import Vuetify, { + transformAssetUrls +} from 'vite-plugin-vuetify'; +import Fonts from 'unplugin-fonts/vite'; +import Vue from '@vitejs/plugin-vue'; import { defineConfig } from 'vite'; -import vue from '@vitejs/plugin-vue'; -import vueDevTools from 'vite-plugin-vue-devtools'; -// https://vite.dev/config/ +// https://vitejs.dev/config/ export default defineConfig( { 'plugins': [ - vue(), - vueDevTools() - ], - 'css': { - 'preprocessorOptions': { - 'scss': { - 'additionalData': ` -@use "@/scss/main.scss" as *; -` + Vue( { + 'template': { + transformAssetUrls + } + } ), + // https://github.com/vuetifyjs/vuetify-loader/tree/master/packages/vite-plugin#readme + Vuetify( { + 'autoImport': true, + 'styles': { + 'configFile': 'src/styles/settings.scss' } - } + } ), + Fonts( { + 'fontsource': { + 'families': [ { + 'name': 'Roboto', + 'weights': [ + 100, + 300, + 400, + 500, + 700, + 900 + ], + 'styles': [ + 'normal', + 'italic' + ] + } ] + } + } ) + ], + 'define': { + 'process.env': {} }, 'resolve': { 'alias': { - '@': fileURLToPath( new URL( './src', import.meta.url ) ) - } + '@': fileURLToPath( new URL( 'src', import.meta.url ) ) + }, + 'extensions': [ + '.js', + '.json', + '.jsx', + '.mjs', + '.ts', + '.tsx', + '.vue' + ] }, 'server': { 'port': 8081 diff --git a/vue-readme.md b/vue-readme.md deleted file mode 100644 index 0791adb..0000000 --- a/vue-readme.md +++ /dev/null @@ -1,42 +0,0 @@ -# frontend - -This template should help get you started developing with Vue 3 in Vite. - -## 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 -npm install -``` - -### Compile and Hot-Reload for Development - -```sh -npm run dev -``` - -### Type-Check, Compile and Minify for Production - -```sh -npm run build -``` diff --git a/vuetify-readme.md b/vuetify-readme.md new file mode 100644 index 0000000..2f3de7c --- /dev/null +++ b/vuetify-readme.md @@ -0,0 +1,76 @@ +# studyphoenix-frontend + +Scaffolded with Vuetify CLI. + +## โ—๏ธ Documentation + +- Primary docs: https://vuetifyjs.com/ +- Getting started guide: https://vuetifyjs.com/en/getting-started/installation/ +- Community support: https://community.vuetifyjs.com/ +- Issue tracker: https://issues.vuetifyjs.com/ + +## ๐Ÿงฑ Stack + +- Framework: Vue 3 + Vite +- UI Library: Vuetify +- Language: TypeScript +- Package manager: npm + +## ๐Ÿงญ Start Here + +- Main entry: `src/main.ts` +- Main app component: `src/App.vue` +- Main styles: `src/styles/` +- Plugin setup: `src/plugins/` + +## ๐Ÿ“ Project Structure + +- `src/main.ts` โ€” application entry point +- `src/App.vue` โ€” root component +- `src/components/` โ€” reusable Vue components +- `src/plugins/` โ€” plugin registration and setup +- `src/styles/` โ€” global styles and theme settings +- `public/` โ€” static public files + +## โœจ Enabled Features + +- Pinia +- Vue Router + +## ๐Ÿ’ฟ Install + +Use your selected package manager (npm) to install dependencies: + +```bash +npm install +``` + +## ๐Ÿš€ Quick Start + +```bash +npm install +npm run dev +``` + +## ๐Ÿ—๏ธ Build + +```bash +npm run build +``` + +## ๐Ÿงช Available Scripts + +- `npm run dev` +- `npm run build` +- `npm run preview` +- `npm run build-only` +- `npm run type-check` + +## ๐Ÿ’ช Support Vuetify Development + +This project uses Vuetify - an MIT licensed Open Source project. We are glad to welcome contributors and any support for ongoing development: + +- Contribute to Vuetify and ecosystem projects: https://github.com/vuetifyjs +- Request enterprise support: https://support.vuetifyjs.com/ +- Sponsor on GitHub: https://github.com/sponsors/vuetifyjs +- Support on Open Collective: https://opencollective.com/vuetify From fbe2ce719ba77810283f70f97b7361d9d1d11d2f Mon Sep 17 00:00:00 2001 From: Janis Hutz Date: Wed, 4 Nov 2026 09:44:20 +0100 Subject: [PATCH 2/3] fix: eslint errors --- src/components/HelloWorld.vue | 3 ++- src/main.ts | 31 +++++++++++-------------------- src/plugins/index.ts | 29 ++++++++++++----------------- 3 files changed, 25 insertions(+), 38 deletions(-) diff --git a/src/components/HelloWorld.vue b/src/components/HelloWorld.vue index 2e2f1c9..0a27e96 100644 --- a/src/components/HelloWorld.vue +++ b/src/components/HelloWorld.vue @@ -78,7 +78,8 @@ diff --git a/src/main.ts b/src/main.ts index f898fe4..ac84dd6 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,23 +1,14 @@ -/** - * main.ts - * - * Bootstraps Vuetify and other plugins then mounts the App` - */ +import 'unfonts.css'; +import App from './App.vue'; +import { + createApp +} from 'vue'; +import { + registerPlugins +} from '@/plugins'; -// Composables -import { createApp } from 'vue' +const app = createApp( App ); -// Plugins -import { registerPlugins } from '@/plugins' +registerPlugins( app ); -// Components -import App from './App.vue' - -// Styles -import 'unfonts.css' - -const app = createApp(App) - -registerPlugins(app) - -app.mount('#app') +app.mount( '#app' ); diff --git a/src/plugins/index.ts b/src/plugins/index.ts index ccbf88e..79b8208 100644 --- a/src/plugins/index.ts +++ b/src/plugins/index.ts @@ -1,19 +1,14 @@ +import type { + App +} from 'vue'; +import { + createPinia +} from 'pinia'; import router from '../router'; -import { createPinia } from 'pinia'; -/** - * plugins/index.ts - * - * Automatically included in `./src/main.ts` - */ +import vuetify from './vuetify'; -// Types -import type { App } from 'vue' - -// Plugins -import vuetify from './vuetify' - -export function registerPlugins (app: App) { - app.use(vuetify) - app.use(createPinia()); - app.use(router); -} \ No newline at end of file +export function registerPlugins ( app: App ) { + app.use( vuetify ); + app.use( createPinia() ); + app.use( router ); +} From f65acc158f9ba4e5b0cf20ba558c09faff011b96 Mon Sep 17 00:00:00 2001 From: Janis Hutz Date: Wed, 4 Nov 2026 09:52:42 +0100 Subject: [PATCH 3/3] chore: readme updates --- README.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 8225ce0..439009d 100644 --- a/README.md +++ b/README.md @@ -10,14 +10,18 @@ Please note the starter code was "stolen" from https://github.com/janishutz/Musi ## Development ### Getting Started with WebDev -Learning Vue: -- [Official Docs](https://vuejs.org/guide/introduction.html) -- Docs here +Learning Vue & Vuetify (learning the basics of Vue should suffice to be able to use Vuetify): +- [Vuetify Docs](https://vuetifyjs.com) +- [Vue Docs](https://vuejs.org/guide/introduction.html) +- [Guide in reporting repo](https://github.com/studyphoenix/reporting/blob/main/DOCS.md) +- [Icons](https://vuetifyjs.com/en/components/icons/) +- This README - [MDN Docs](https://developer.mozilla.org/en-US/) - [MusicPlayer](https://github.com/janishutz/MusicPlayer/tree/dev/web) by @janishutz (as a reference for implementation) - [EYE-TAP frontend](https://github.com/eye-tap/frontend) (as a reference for implementation) - Any other docs online -- [FontAwesome](https://fontawesome.com/search?ic=free-collection) + +We may add fontawesome icons if you prefer them over the Material Design Icons. ### Linter and type checker runs on PRs