diff --git a/README.md b/README.md index 88ceef1..2cdc411 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,12 @@ App Version +# Development Branch +This branch is for the upcoming version 4 of Music Player and is in early stages of development + + +# MusicPlayer + A music player, specifically created for displaying song information on multiple different displays that are connected to the same network, just from the browser. The [hosted version](https://music.janishutz.com) of this MusicPlayer, which is fully set up for you is subscription-based and can be paid for on my [store](https://store.janishutz.com/product/com.janishutz). diff --git a/web/eslint.config.mjs b/web/eslint.config.mjs new file mode 100644 index 0000000..48eb7aa --- /dev/null +++ b/web/eslint.config.mjs @@ -0,0 +1,744 @@ +import eslint from '@eslint/js'; +import globals from 'globals'; +import stylistic from '@stylistic/eslint-plugin'; +import tseslint from 'typescript-eslint'; +import typescript from '@typescript-eslint/eslint-plugin'; +import vue from 'eslint-plugin-vue'; + +const style = { + 'plugins': { + '@stylistic': stylistic, + '@stylistic/js': stylistic, + '@stylistic/ts': stylistic + }, + 'files': [ + '**/*.ts', + '**/*.js', + '**/*.mjs', + '**/*.cjs', + '**/*.tsx', + '**/*.jsx' + ], + 'rules': { + 'sort-imports': [ + 'warn', + { + 'ignoreCase': false, + 'ignoreDeclarationSort': false, + 'ignoreMemberSort': false, + 'memberSyntaxSortOrder': [ + 'none', + 'all', + 'multiple', + 'single' + ], + 'allowSeparatedGroups': false + } + ], + // Formatting + '@stylistic/array-bracket-newline': [ + 'error', + { + 'multiline': false, + 'minItems': 2 + } + ], + '@stylistic/array-bracket-spacing': [ + 'error', + 'always' + ], + '@stylistic/array-element-newline': [ + 'error', + { + 'consistent': false, + 'multiline': false, + 'minItems': 2 + } + ], + '@stylistic/arrow-parens': [ + 'error', + 'as-needed' + ], + '@stylistic/arrow-spacing': [ + 'error', + { + 'before': true, + 'after': true + } + ], + '@stylistic/block-spacing': [ + 'error', + 'always' + ], + '@stylistic/brace-style': [ + 'error', + '1tbs', + { + 'allowSingleLine': false + } + ], + '@stylistic/comma-dangle': [ + 'error', + 'never' + ], + '@stylistic/comma-spacing': [ + 'error', + { + 'before': false, + 'after': true + } + ], + '@stylistic/comma-style': [ + 'error', + 'last' + ], + '@stylistic/dot-location': [ + 'error', + 'property' + ], + '@stylistic/function-call-argument-newline': [ + 'error', + 'consistent' + ], + '@stylistic/function-call-spacing': [ + 'error', + 'never' + ], + '@stylistic/function-paren-newline': [ + 'error', + 'multiline-arguments' + ], + '@stylistic/implicit-arrow-linebreak': [ + 'error', + 'beside' + ], + '@stylistic/indent': [ + 'error', + 4 + ], + '@stylistic/indent-binary-ops': [ + 'error', + 4 + ], + '@stylistic/key-spacing': [ + 'error', + { + 'beforeColon': false, + 'afterColon': true + } + ], + '@stylistic/keyword-spacing': [ + 'error', + { + 'before': true, + 'after': true + } + ], + '@stylistic/lines-between-class-members': [ + 'error', + 'always' + ], + '@stylistic/max-len': [ + 'warn', + { + 'code': 140, + 'comments': 160, + 'ignoreComments': false, + 'ignoreUrls': true, + 'ignoreStrings': true, + 'ignoreTemplateLiterals': true, + 'ignoreRegExpLiterals': true + } + ], + '@stylistic/max-statements-per-line': [ + 'error', + { + 'max': 1 + } + ], + '@stylistic/multiline-ternary': [ + 'error', + 'always-multiline' + ], + '@stylistic/new-parens': [ + 'error', + 'always' + ], + '@stylistic/newline-per-chained-call': 'error', + '@stylistic/no-confusing-arrow': 'error', + '@stylistic/no-extra-parens': [ + 'error', + 'all', + { + 'nestedBinaryExpressions': false, + 'ternaryOperandBinaryExpressions': false, + 'ignoreJSX': 'multi-line', + 'nestedConditionalExpressions': false + } + ], + '@stylistic/no-extra-semi': 'error', + '@stylistic/no-floating-decimal': 'error', + '@stylistic/no-mixed-operators': 'error', + '@stylistic/no-mixed-spaces-and-tabs': 'error', + '@stylistic/no-multi-spaces': 'error', + '@stylistic/no-multiple-empty-lines': [ + 'error', + { + 'max': 3, + 'maxEOF': 2 + } + ], + '@stylistic/no-tabs': 'error', + '@stylistic/no-trailing-spaces': 'error', + '@stylistic/no-whitespace-before-property': 'error', + '@stylistic/object-curly-newline': [ + 'error', + { + 'multiline': true, + 'minProperties': 1 + } + ], + '@stylistic/object-curly-spacing': [ + 'error', + 'always' + ], + '@stylistic/object-property-newline': 'error', + '@stylistic/one-var-declaration-per-line': 'error', + '@stylistic/operator-linebreak': [ + 'error', + 'before' + ], + '@stylistic/padded-blocks': [ + 'error', + { + 'blocks': 'never', + 'classes': 'always', + 'switches': 'never' + } + ], + + // Padding lines. The most in-depth part of this config + '@stylistic/padding-line-between-statements': [ + 'error', + // Variables, Constants + { + 'blankLine': 'never', + 'prev': 'var', + 'next': 'var' + }, + { + 'blankLine': 'never', + 'prev': 'let', + 'next': 'let' + }, + { + 'blankLine': 'never', + 'prev': 'const', + 'next': 'const' + }, + { + 'blankLine': 'always', + 'prev': 'var', + 'next': [ + 'block', + 'block-like', + 'break', + 'cjs-export', + 'cjs-import', + 'class', + 'const', + 'continue', + 'debugger', + 'directive', + 'do', + 'empty', + 'export', + 'expression', + 'for', + 'function', + 'if', + 'iife', + 'import', + 'let', + 'return', + 'switch', + 'throw', + 'try', + 'var', + 'with' + ] + }, + { + 'blankLine': 'always', + 'prev': 'let', + 'next': [ + 'block', + 'block-like', + 'break', + 'cjs-export', + 'cjs-import', + 'class', + 'const', + 'continue', + 'debugger', + 'directive', + 'do', + 'empty', + 'export', + 'expression', + 'for', + 'function', + 'if', + 'iife', + 'import', + 'return', + 'switch', + 'throw', + 'try', + 'var', + 'while', + 'with' + ] + }, + { + 'blankLine': 'always', + 'prev': 'const', + 'next': [ + 'block', + 'block-like', + 'break', + 'cjs-export', + 'cjs-import', + 'class', + 'continue', + 'debugger', + 'directive', + 'do', + 'empty', + 'export', + 'expression', + 'for', + 'function', + 'if', + 'iife', + 'import', + 'let', + 'return', + 'switch', + 'throw', + 'try', + 'var', + 'while', + 'with' + ] + }, + // Import + { + 'blankLine': 'never', + 'prev': 'import', + 'next': 'import' + }, + { + 'blankLine': 'never', + 'prev': 'cjs-import', + 'next': 'cjs-import' + }, + { + 'blankLine': 'always', + 'prev': [ + 'block', + 'block-like', + 'break', + 'cjs-export', + 'class', + 'const', + 'continue', + 'debugger', + 'directive', + 'do', + 'empty', + 'export', + 'expression', + 'for', + 'function', + 'if', + 'iife', + 'let', + 'return', + 'switch', + 'throw', + 'try', + 'var', + 'while', + 'with' + ], + 'next': 'cjs-import' + }, + { + 'blankLine': 'always', + 'prev': 'cjs-import', + 'next': [ + 'block', + 'block-like', + 'break', + 'cjs-export', + 'class', + 'const', + 'continue', + 'debugger', + 'directive', + 'do', + 'empty', + 'export', + 'expression', + 'for', + 'function', + 'if', + 'iife', + 'let', + 'return', + 'switch', + 'throw', + 'try', + 'var', + 'while', + 'with' + ] + }, + { + 'blankLine': 'always', + 'prev': [ + 'block', + 'block-like', + 'break', + 'cjs-export', + 'class', + 'const', + 'continue', + 'debugger', + 'directive', + 'do', + 'empty', + 'export', + 'expression', + 'for', + 'function', + 'if', + 'iife', + 'let', + 'return', + 'switch', + 'throw', + 'try', + 'var', + 'while', + 'with' + ], + 'next': 'import' + }, + { + 'blankLine': 'always', + 'prev': 'import', + 'next': [ + 'block', + 'block-like', + 'break', + 'cjs-export', + 'class', + 'const', + 'continue', + 'debugger', + 'directive', + 'do', + 'empty', + 'export', + 'expression', + 'for', + 'function', + 'if', + 'iife', + 'let', + 'return', + 'switch', + 'throw', + 'try', + 'var', + 'while', + 'with' + ] + }, + // If + { + 'blankLine': 'always', + 'prev': '*', + 'next': 'if' + }, + { + 'blankLine': 'always', + 'prev': 'if', + 'next': '*' + }, + // For + { + 'blankLine': 'always', + 'prev': '*', + 'next': 'for' + }, + { + 'blankLine': 'always', + 'prev': 'for', + 'next': '*' + }, + // While + { + 'blankLine': 'always', + 'prev': '*', + 'next': 'while' + }, + { + 'blankLine': 'always', + 'prev': 'while', + 'next': '*' + }, + // Functions + { + 'blankLine': 'always', + 'prev': '*', + 'next': 'function' + }, + { + 'blankLine': 'always', + 'prev': 'function', + 'next': '*' + }, + // Block Statements + { + 'blankLine': 'always', + 'prev': '*', + 'next': 'block-like' + }, + { + 'blankLine': 'always', + 'prev': 'block-like', + 'next': '*' + }, + // Switch + { + 'blankLine': 'always', + 'prev': '*', + 'next': 'switch' + }, + { + 'blankLine': 'always', + 'prev': 'switch', + 'next': '*' + }, + // Try-Catch + { + 'blankLine': 'always', + 'prev': '*', + 'next': 'try' + }, + { + 'blankLine': 'always', + 'prev': 'try', + 'next': '*' + }, + // Throw + { + 'blankLine': 'always', + 'prev': '*', + 'next': 'throw' + }, + { + 'blankLine': 'always', + 'prev': 'throw', + 'next': '*' + }, + // Return + { + 'blankLine': 'never', + 'prev': 'return', + 'next': '*' + }, + { + 'blankLine': 'always', + 'prev': '*', + 'next': 'return' + }, + // Export + { + 'blankLine': 'always', + 'prev': '*', + 'next': 'export' + }, + { + 'blankLine': 'always', + 'prev': 'export', + 'next': '*' + }, + { + 'blankLine': 'always', + 'prev': '*', + 'next': 'cjs-export' + }, + { + 'blankLine': 'always', + 'prev': 'cjs-export', + 'next': '*' + }, + // Classes + { + 'blankLine': 'always', + 'prev': '*', + 'next': 'class' + }, + { + 'blankLine': 'always', + 'prev': 'class', + 'next': '*' + } + ], + '@stylistic/quote-props': [ + 'error', + 'always' + ], + '@stylistic/quotes': [ + 'error', + 'single' + ], + '@stylistic/rest-spread-spacing': [ + 'error', + 'never' + ], + '@stylistic/semi': [ + 'error', + 'always' + ], + '@stylistic/semi-spacing': [ + 'error', + { + 'before': false, + 'after': true + } + ], + '@stylistic/semi-style': [ + 'error', + 'last' + ], + '@stylistic/space-before-blocks': [ + 'error', + 'always' + ], + '@stylistic/space-before-function-paren': [ + 'error', + 'always' + ], + '@stylistic/space-in-parens': [ + 'error', + 'always' + ], + '@stylistic/space-infix-ops': [ + 'error', + { + 'int32Hint': false + } + ], + '@stylistic/space-unary-ops': 'error', + '@stylistic/spaced-comment': [ + 'error', + 'always' + ], + '@stylistic/switch-colon-spacing': 'error', + '@stylistic/template-curly-spacing': [ + 'error', + 'always' + ], + '@stylistic/template-tag-spacing': [ + 'error', + 'always' + ], + '@stylistic/type-generic-spacing': 'error', + '@stylistic/type-named-tuple-spacing': 'error', + '@stylistic/wrap-iife': [ + 'error', + 'inside' + ], + '@stylistic/wrap-regex': 'error', + '@stylistic/ts/type-annotation-spacing': 'error' + } +}; + +/** @type {import('eslint').Linter.Config} */ +export default tseslint.config( + // Base JavaScript rules + eslint.configs.recommended, + tseslint.configs.recommended, + style, + + // Vue support (including TS and JSX inside SFCs) + { + 'files': [ '**/*.vue' ], + 'languageOptions': { + 'sourceType': 'module', + 'ecmaVersion': 'latest', + 'globals': globals.browser, + 'parserOptions': { + 'parser': tseslint.parser + } + }, + 'plugins': { + 'vue': vue, + '@stylistic': stylistic, + '@stylistic/js': stylistic, + '@stylistic/ts': stylistic, + '@typescript-eslint': typescript + }, + 'extends': [ + eslint.configs.recommended, + ...vue.configs['flat/recommended'] + ], + 'rules': { + ...typescript.configs.recommended.rules, + ...style.rules, + + // Vue specific rules + '@stylistic/indent': 'off', + 'vue/html-indent': [ + 'error', + 4 + ], + 'vue/html-comment-indent': [ + 'error', + 4 + ], + 'vue/script-indent': [ + 'error', + 4, + { + 'baseIndent': 1, + 'switchCase': 1 + } + ], + 'vue/html-self-closing': [ + 'error', + { + 'html': { + 'void': 'never', + 'normal': 'never', + 'component': 'always' + }, + 'svg': 'always', + 'math': 'never' + } + ], + 'vue/max-attributes-per-line': [ + 'error', + { + 'singleline': 3, + 'multiline': 1 + } + ] + } + } +); diff --git a/web/package.json b/web/package.json index 9e909d5..1d0abe7 100644 --- a/web/package.json +++ b/web/package.json @@ -16,12 +16,17 @@ "vue-router": "^5.2.0" }, "devDependencies": { + "@eslint/js": "^10.0.1", + "@stylistic/eslint-plugin": "^5.10.0", "@tsconfig/node24": "^24.0.4", "@types/node": "^24.13.3", "@vitejs/plugin-vue": "^6.0.8", "@vue/tsconfig": "^0.9.1", + "eslint-plugin-vue": "^10.10.0", + "globals": "^17.11.0", "npm-run-all2": "^9.0.2", "typescript": "~6.0.0", + "typescript-eslint": "^8.67.0", "vite": "^8.1.5", "vite-plugin-vue-devtools": "^8.1.5", "vue-tsc": "^3.3.7" diff --git a/web/public/bar-config.json b/web/public/bar-config.json new file mode 100644 index 0000000..c9d63c3 --- /dev/null +++ b/web/public/bar-config.json @@ -0,0 +1,193 @@ +{ + "ages": { + "below": "Orange", + "16-18": "Yellow", + "18+": "Turquoise" + }, + "offering": { + "big-bar": { + "offering": { + "softdrinks": { + "name": "Softdrinks", + "price": 400, + "id": "softdrinks" + }, + "energy": { + "name": "Energy", + "price": 400, + "id": "energy" + }, + "mate": { + "name": "Mate", + "price": 500, + "id": "mate", + "depot": 200 + }, + "sparkly-water": { + "name": "Mineralwasser mit", + "price": 300, + "id": "sparkly-water", + "showLine": true + }, + "rose": { + "name": "Rosé", + "price": 1500, + "id": "rose", + "depot": 200 + }, + "red": { + "name": "Rotwein", + "price": 2000, + "id": "red", + "depot": 200 + }, + "wine-glasses": { + "name": "Weingläser", + "price": 0, + "id": "wine-glasses", + "depot": 200 + }, + "appenzeller": { + "name": "Appenzeller Vollmond", + "price": 500, + "id": "appenzeller", + "depot": 200 + }, + "feldschloesschen": { + "name": "Feldschlösschen", + "price": 500, + "id": "feldschloesschen", + "depot": 200 + }, + "sommersby": { + "name": "Sommersby", + "price": 500, + "id": "sommersby", + "depot": 200 + }, + "jever-fun": { + "name": "Jever Fun", + "price": 400, + "id": "jever-fun", + "depot": 200 + }, + "trojka-ice": { + "name": "Trojka Ice", + "price": 600, + "id": "trojka-ice", + "depot": 200, + "showLine": true + }, + "vodka-red-energy": { + "name": "Vodka Rot Energy", + "price": 800, + "id": "vodka-red-energy" + }, + "vodka-green-citro": { + "name": "Vodka Grün Citro", + "price": 800, + "id": "vodka-green-citro" + }, + "vodka-white-energy": { + "name": "Vodka White Energy", + "price": 900, + "id": "vodka-white-energy" + }, + "gin-tonic": { + "name": "Gin Tonic", + "price": 900, + "id": "gin-tonic" + }, + "rum-cola": { + "name": "Rum Cola", + "price": 900, + "id": "rum-cola" + }, + "whiskey-cola": { + "name": "Whiskey Cola", + "price": 900, + "id": "whiskey-cola" + }, + "mate-mit-schuss": { + "name": "Mate mit Schuss", + "price": 1200, + "id": "mate-mit-schuss", + "depot": 200, + "showLine": true + }, + "poseidon": { + "name": "Poseidon", + "price": 900, + "id": "poseidon" + }, + "arielle": { + "name": "Arielle", + "price": 900, + "id": "arielle" + }, + "pearl-driver": { + "name": "Pearl Driver", + "price": 400, + "id": "pearl-driver" + } + }, + "name": "Poseidon's Quelle", + "id": "big-bar" + }, + "small-bar": { + "offering": { + "softdrinks": { + "name": "Softdrinks (Alle)", + "price": 300, + "id": "softdrinks", + "showLine": true + }, + "appenzeller": { + "name": "Appenzeller Vollmond", + "price": 500, + "id": "appenzeller", + "depot": 200 + }, + "feldschloesschen": { + "name": "Feldschlösschen", + "price": 500, + "id": "feldschloesschen", + "depot": 200 + }, + "sommersby": { + "name": "Sommersby", + "price": 500, + "id": "sommersby", + "depot": 200 + }, + "jever-fun": { + "name": "Jever Fun", + "price": 400, + "id": "jever-fun", + "depot": 200, + "showLine": true + }, + "rose": { + "name": "Rosé", + "price": 1500, + "id": "rose", + "depot": 200 + }, + "red": { + "name": "Rotwein", + "price": 2000, + "id": "red", + "depot": 200 + }, + "wine-glasses": { + "name": "Weingläser", + "price": 0, + "id": "wine-glasses", + "depot": 200 + } + }, + "name": "Seepferdchenbar", + "id": "small-bar" + } + } +} diff --git a/web/src/App.vue b/web/src/App.vue index abfd315..b841e7d 100644 --- a/web/src/App.vue +++ b/web/src/App.vue @@ -1,11 +1,209 @@ - + - + + + diff --git a/web/src/components/PlayerControls.vue b/web/src/components/PlayerControls.vue new file mode 100644 index 0000000..e69de29 diff --git a/web/src/components/PlaylistPicker.vue b/web/src/components/PlaylistPicker.vue new file mode 100644 index 0000000..e69de29 diff --git a/web/src/components/PopupElement.vue b/web/src/components/PopupElement.vue new file mode 100644 index 0000000..534622b --- /dev/null +++ b/web/src/components/PopupElement.vue @@ -0,0 +1,65 @@ + + + + + + + diff --git a/web/src/main.ts b/web/src/main.ts index fda1e6e..0540e36 100644 --- a/web/src/main.ts +++ b/web/src/main.ts @@ -1,12 +1,15 @@ -import { createApp } from 'vue' -import { createPinia } from 'pinia' +import App from './App.vue'; +import { + createApp +} from 'vue'; +import { + createPinia +} from 'pinia'; +import router from './router'; -import App from './App.vue' -import router from './router' +const app = createApp( App ); -const app = createApp(App) +app.use( createPinia() ); +app.use( router ); -app.use(createPinia()) -app.use(router) - -app.mount('#app') +app.mount( '#app' ); diff --git a/web/src/router/index.ts b/web/src/router/index.ts index e1eab52..85ca752 100644 --- a/web/src/router/index.ts +++ b/web/src/router/index.ts @@ -1,8 +1,10 @@ -import { createRouter, createWebHistory } from 'vue-router' +import { + createRouter, createWebHistory +} from 'vue-router'; -const router = createRouter({ - history: createWebHistory(import.meta.env.BASE_URL), - routes: [], -}) +const router = createRouter( { + 'history': createWebHistory( import.meta.env.BASE_URL ), + 'routes': [] +} ); -export default router +export default router; diff --git a/web/src/router/routes.ts b/web/src/router/routes.ts new file mode 100644 index 0000000..e69de29 diff --git a/web/src/scss/main.scss b/web/src/scss/main.scss new file mode 100644 index 0000000..e69de29 diff --git a/web/src/ts/dtype/playlist.d.ts b/web/src/ts/dtype/playlist.d.ts new file mode 100644 index 0000000..68d34f5 --- /dev/null +++ b/web/src/ts/dtype/playlist.d.ts @@ -0,0 +1,44 @@ +// NOTE: For re-associating files with details here, can use dropdown in UI + +export type Playlist = Song[]; + +export interface UrlToFileMapping { + [key: string]: string +} + +export interface Song { + /** + * Where the song can be found + */ + 'source': 'local' | 'applemusic'; + + /** + * The identifier for the song so it can be found again (such as Apple Music ID or filename) + */ + 'identifier': string; + + /** + * Additional info, such as dance type to be displayed on remote screens + */ + 'additional-info': string; + + /** + * The artist of the song + */ + 'artist': string; + + /** + * The name of the song + */ + 'name': string; + + /** + * The cover image as a URL + */ + 'cover': string; + + /** + * Song duration + */ + 'duration': string; +} diff --git a/web/src/ts/messages/index.ts b/web/src/ts/messages/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/web/src/ts/player/index.ts b/web/src/ts/player/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/web/src/ts/player/musickit/index.ts b/web/src/ts/player/musickit/index.ts new file mode 100644 index 0000000..f4d2b40 --- /dev/null +++ b/web/src/ts/player/musickit/index.ts @@ -0,0 +1,17 @@ +export const useMusicKit = () => { + const init = () => { + isInit = true; + }; + + let isInit = false; + + if ( !window.MusicKit ) { + document.addEventListener( 'musickitloaded', () => { + init(); + } ); + } else { + init(); + } + + return {}; +}; diff --git a/web/src/ts/player/musickit/playback.ts b/web/src/ts/player/musickit/playback.ts new file mode 100644 index 0000000..e1137eb --- /dev/null +++ b/web/src/ts/player/musickit/playback.ts @@ -0,0 +1,9 @@ +export const play = () => {}; + +export const pause = () => {}; + +export const skip10 = () => {}; + +export const back10 = () => {}; + +export const playSong = ( id: string ) => {}; diff --git a/web/src/ts/player/musickit/user.ts b/web/src/ts/player/musickit/user.ts new file mode 100644 index 0000000..d51e1eb --- /dev/null +++ b/web/src/ts/player/musickit/user.ts @@ -0,0 +1,3 @@ +export const login = async () => { + +}; diff --git a/web/src/ts/player/queue.ts b/web/src/ts/player/queue.ts new file mode 100644 index 0000000..e69de29 diff --git a/web/src/ts/player/state.ts b/web/src/ts/player/state.ts new file mode 100644 index 0000000..51c8810 --- /dev/null +++ b/web/src/ts/player/state.ts @@ -0,0 +1,21 @@ +import { + type Ref, + ref +} from 'vue'; +import type { + Playlist +} from '../dtype/playlist'; + +export const queueIdx = ref( 0 ); + +export const queue: Ref = ref( [] ); + +export const isPlaying = ref( false ); + +export const shuffle = ref( false ); + +export const repeat: Ref<'off' | 'one' | 'all'> = ref( 'off' ); + +export const playbackPercentage = ref( 0 ); + +export const duration = ref( 0 ); diff --git a/web/src/ts/playlists/index.ts b/web/src/ts/playlists/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/web/src/ts/request.ts b/web/src/ts/request.ts new file mode 100644 index 0000000..e69de29 diff --git a/web/src/views/404View.vue b/web/src/views/404View.vue new file mode 100644 index 0000000..8baf6a6 --- /dev/null +++ b/web/src/views/404View.vue @@ -0,0 +1,24 @@ + + + + + diff --git a/web/src/views/AppView.vue b/web/src/views/AppView.vue new file mode 100644 index 0000000..e69de29 diff --git a/web/src/views/BarView.vue b/web/src/views/BarView.vue new file mode 100644 index 0000000..28a8900 --- /dev/null +++ b/web/src/views/BarView.vue @@ -0,0 +1,229 @@ + + + + + diff --git a/web/src/views/SharedView.vue b/web/src/views/SharedView.vue new file mode 100644 index 0000000..e69de29 diff --git a/web/src/views/StartPage.vue b/web/src/views/StartPage.vue new file mode 100644 index 0000000..e69de29 diff --git a/web/vite.config.ts b/web/vite.config.ts index 0414681..6854739 100644 --- a/web/vite.config.ts +++ b/web/vite.config.ts @@ -1,18 +1,24 @@ -import { fileURLToPath, URL } from 'node:url' - -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import vueDevTools from 'vite-plugin-vue-devtools' +import { + URL, fileURLToPath +} 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)), +export default defineConfig( { + 'plugins': [ + vue(), + vueDevTools() + ], + 'resolve': { + 'alias': { + '@': fileURLToPath( new URL( './src', import.meta.url ) ) + } }, - }, -}) + 'server': { + 'port': 8081 + } +} );