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 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 df36fcf..8fb9f91 100644 Binary files a/public/favicon.ico and b/public/favicon.ico differ 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 0000000..a5f23ae Binary files /dev/null and b/src/assets/logo.png differ diff --git a/src/assets/logo.svg b/src/assets/logo.svg new file mode 100644 index 0000000..d57771c --- /dev/null +++ b/src/assets/logo.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/components/HelloWorld.vue b/src/components/HelloWorld.vue new file mode 100644 index 0000000..0a27e96 --- /dev/null +++ b/src/components/HelloWorld.vue @@ -0,0 +1,114 @@ + + + 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..ac84dd6 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,37 +1,14 @@ -import '@fortawesome/fontawesome-free/css/all.css'; +import 'unfonts.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'; - -// Detect backend URL -let backendURL: string; - -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'; -} - -configure( { - 'backendURL': new URL( backendURL ), - 'defaultAuthErrorResolution': 'resolve', - 'authErrorEvent': 'autherror' -} ); + registerPlugins +} from '@/plugins'; const app = createApp( App ); -app.use( createPinia() ); -app.use( router ); -app.use( Notifications ); +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..79b8208 --- /dev/null +++ b/src/plugins/index.ts @@ -0,0 +1,14 @@ +import type { + App +} from 'vue'; +import { + createPinia +} from 'pinia'; +import router from '../router'; +import vuetify from './vuetify'; + +export function registerPlugins ( app: App ) { + app.use( vuetify ); + app.use( createPinia() ); + app.use( router ); +} 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