finish restructuring, add eslint config, add more questions to form

This commit is contained in:
2024-10-02 15:45:35 +02:00
parent 734259ae6a
commit d37464a344
11 changed files with 1694 additions and 59 deletions

View File

@@ -5,32 +5,32 @@ import fs from 'node:fs';
import bodyParser from 'body-parser'; import bodyParser from 'body-parser';
import cors from 'cors'; import cors from 'cors';
declare let __dirname: string | undefined declare let __dirname: string | undefined;
if ( typeof( __dirname ) === 'undefined' ) { if ( typeof __dirname === 'undefined' ) {
__dirname = path.resolve( path.dirname( '' ) ); __dirname = path.resolve( path.dirname( '' ) );
} }
declare module 'express-session' { declare module 'express-session' {
interface SessionData { interface SessionData {
isAuth: boolean; 'isAuth': boolean;
} }
} }
const run = () => { const run = () => {
let app = express(); const app = express();
app.use( expressSession( { app.use( expressSession( {
secret: 'oasdvövböoweivaöiewväiweväowecäievwoaweävciwecfwegifwp9uiqc32p9qc', 'secret': 'oasdvövböoweivaöiewväiweväowecäievwoaweävciwecfwegifwp9uiqc32p9qc',
resave: true, 'resave': true,
saveUninitialized: true 'saveUninitialized': true
} ) ); } ) );
app.use( cors( { app.use( cors( {
origin: true, 'origin': true,
credentials: true, 'credentials': true,
} ) ); } ) );
app.set( 'trust proxy', 1 ); app.set( 'trust proxy', 1 );
app.use( bodyParser.urlencoded( { extended: false } ) ); app.use( bodyParser.urlencoded( { 'extended': false } ) );
app.use( bodyParser.json() ); app.use( bodyParser.json() );
@@ -99,14 +99,12 @@ const run = () => {
} ); } );
app.use( ( request: express.Request, response: express.Response ) => { app.use( ( request: express.Request, response: express.Response ) => {
response.status( 404 ).send( 'ERR_NOT_FOUND' ) response.status( 404 ).send( 'ERR_NOT_FOUND' );
} ); } );
const PORT = process.env.PORT || 8080; const PORT = process.env.PORT || 8080;
app.listen( PORT ); app.listen( PORT );
} };
export default { export default { run };
run
}

68
eslint.config.mjs Normal file
View File

@@ -0,0 +1,68 @@
// @ts-check
import eslint from '@eslint/js';
import tseslint from 'typescript-eslint';
import stylistic from '@stylistic/eslint-plugin';
export default tseslint.config(
eslint.configs.recommended,
...tseslint.configs.recommended,
{
'ignores': [ '**/dist/', '**/*.cjs' ],
},
{
'plugins': {
'@stylistic/js': stylistic,
'@stylistic/ts': stylistic,
},
'rules': {
// Formatting
'@stylistic/js/array-bracket-newline': [ 'error', { 'multiline': true, 'minItems': 4 } ],
'@stylistic/js/array-bracket-spacing': [ 'error', 'always' ],
'@stylistic/js/array-element-newline': [ 'error', { 'multiline': true, 'minItems': 4 } ],
'@stylistic/js/arrow-parens': [ 'error', 'always' ],
'@stylistic/js/arrow-spacing': [ 'error', { 'before': true, 'after': true } ],
'@stylistic/js/block-spacing': [ 'error', 'always' ],
'@stylistic/js/brace-style': [ 'error', '1tbs' ],
'@stylistic/js/comma-spacing': [ 'error', { 'before': false, 'after': true } ],
'@stylistic/js/comma-style': [ 'error', 'last' ],
'@stylistic/js/dot-location': [ 'error', 'property' ],
'@stylistic/js/eol-last': [ 'error', 'always' ],
'@stylistic/js/function-call-spacing': [ 'error', 'never' ],
'@stylistic/js/implicit-arrow-linebreak': [ 'error', 'beside' ],
'@stylistic/js/indent': [ 'error', 4 ],
'@stylistic/js/key-spacing': [ 'error', { 'beforeColon': false, 'afterColon': true } ],
'@stylistic/js/keyword-spacing': [ 'error', { 'before': true, 'after': true } ],
'@stylistic/js/lines-between-class-members': [ 'error', 'always' ],
'@stylistic/js/new-parens': [ 'error', 'always' ],
'@stylistic/js/no-extra-parens': [ 'error', 'all' ],
'@stylistic/js/no-extra-semi': 'error',
'@stylistic/js/no-floating-decimal': 'error',
'@stylistic/js/no-mixed-operators': 'error',
'@stylistic/js/no-mixed-spaces-and-tabs': 'error',
'@stylistic/js/no-multi-spaces': 'error',
'@stylistic/js/no-trailing-spaces': 'error',
'@stylistic/js/no-whitespace-before-property': 'error',
'@stylistic/js/object-curly-newline': [ 'error', { 'multiline': true, 'minProperties': 3 } ],
'@stylistic/js/object-curly-spacing': [ 'error', 'always' ],
'@stylistic/js/one-var-declaration-per-line': 'error',
'@stylistic/js/quote-props': [ 'error', 'always' ],
'@stylistic/js/quotes': [ 'error', 'single' ],
'@stylistic/js/rest-spread-spacing': [ 'error', 'never' ],
'@stylistic/js/semi': [ 'error', 'always' ],
'@stylistic/js/semi-spacing': [ 'error', { 'before': false, 'after': true } ],
'@stylistic/js/semi-style': [ 'error', 'last' ],
'@stylistic/js/space-before-blocks': [ 'error', 'always' ],
'@stylistic/js/space-before-function-paren': [ 'error', 'always' ],
'@stylistic/js/space-in-parens': [ 'error', 'always' ],
'@stylistic/js/space-infix-ops': [ 'error', { 'int32Hint': false } ],
'@stylistic/js/space-unary-ops': 'error',
'@stylistic/js/spaced-comment': [ 'error', 'always' ],
'@stylistic/js/switch-colon-spacing': 'error',
'@stylistic/js/template-curly-spacing': [ 'error', 'always' ],
'@stylistic/js/wrap-iife': [ 'error', 'inside' ],
'@stylistic/js/wrap-regex': 'error',
'@stylistic/ts/type-annotation-spacing': 'error',
}
}
);

1503
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

11
package.json Normal file
View File

@@ -0,0 +1,11 @@
{
"dependencies": {
"@stylistic/eslint-plugin": "^2.8.0",
"eslint": "^9.11.1",
"typescript-eslint": "^8.8.0"
},
"scripts": {
"lint": "eslint",
"lint-fix": "eslint --fix"
}
}

View File

@@ -1,14 +0,0 @@
/* eslint-env node */
require('@rushstack/eslint-patch/modern-module-resolution')
module.exports = {
root: true,
'extends': [
'plugin:vue/vue3-essential',
'eslint:recommended',
'@vue/eslint-config-typescript'
],
parserOptions: {
ecmaVersion: 'latest'
}
}

View File

@@ -0,0 +1 @@
<svg width="98" height="96" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M48.854 0C21.839 0 0 22 0 49.217c0 21.756 13.993 40.172 33.405 46.69 2.427.49 3.316-1.059 3.316-2.362 0-1.141-.08-5.052-.08-9.127-13.59 2.934-16.42-5.867-16.42-5.867-2.184-5.704-5.42-7.17-5.42-7.17-4.448-3.015.324-3.015.324-3.015 4.934.326 7.523 5.052 7.523 5.052 4.367 7.496 11.404 5.378 14.235 4.074.404-3.178 1.699-5.378 3.074-6.6-10.839-1.141-22.243-5.378-22.243-24.283 0-5.378 1.94-9.778 5.014-13.2-.485-1.222-2.184-6.275.486-13.038 0 0 4.125-1.304 13.426 5.052a46.97 46.97 0 0 1 12.214-1.63c4.125 0 8.33.571 12.213 1.63 9.302-6.356 13.427-5.052 13.427-5.052 2.67 6.763.97 11.816.485 13.038 3.155 3.422 5.015 7.822 5.015 13.2 0 18.905-11.404 23.06-22.324 24.283 1.78 1.548 3.316 4.481 3.316 9.126 0 6.6-.08 11.897-.08 13.526 0 1.304.89 2.853 3.316 2.364 19.412-6.52 33.405-24.935 33.405-46.691C97.707 22 75.788 0 48.854 0z" fill="#fff"/></svg>

After

Width:  |  Height:  |  Size: 960 B

View File

@@ -0,0 +1 @@
<svg width="98" height="96" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M48.854 0C21.839 0 0 22 0 49.217c0 21.756 13.993 40.172 33.405 46.69 2.427.49 3.316-1.059 3.316-2.362 0-1.141-.08-5.052-.08-9.127-13.59 2.934-16.42-5.867-16.42-5.867-2.184-5.704-5.42-7.17-5.42-7.17-4.448-3.015.324-3.015.324-3.015 4.934.326 7.523 5.052 7.523 5.052 4.367 7.496 11.404 5.378 14.235 4.074.404-3.178 1.699-5.378 3.074-6.6-10.839-1.141-22.243-5.378-22.243-24.283 0-5.378 1.94-9.778 5.014-13.2-.485-1.222-2.184-6.275.486-13.038 0 0 4.125-1.304 13.426 5.052a46.97 46.97 0 0 1 12.214-1.63c4.125 0 8.33.571 12.213 1.63 9.302-6.356 13.427-5.052 13.427-5.052 2.67 6.763.97 11.816.485 13.038 3.155 3.422 5.015 7.822 5.015 13.2 0 18.905-11.404 23.06-22.324 24.283 1.78 1.548 3.316 4.481 3.316 9.126 0 6.6-.08 11.897-.08 13.526 0 1.304.89 2.853 3.316 2.364 19.412-6.52 33.405-24.935 33.405-46.691C97.707 22 75.788 0 48.854 0z" fill="#24292f"/></svg>

After

Width:  |  Height:  |  Size: 963 B

View File

@@ -93,7 +93,7 @@
const hasSelectedDate = ref( false ); const hasSelectedDate = ref( false );
const difficulty = ref( -1 ); const difficulty = ref( -1 );
const difficultyLevels = ref( [ const difficultyLevels = ref( [
'sleep sessions', 'sleep therapy',
'very easy', 'very easy',
'easy', 'easy',
'of medium difficulty', 'of medium difficulty',
@@ -131,18 +131,36 @@
'average', 'average',
'above average', 'above average',
'high', 'high',
'so high I felt like I was never going to fail my studies' 'so high I felt like I would certainly fail my studies'
] ); ] );
const stressSlider = ref( stopSlider ); const stressSlider = ref( stopSlider );
const setStress = ( value: number ) => {
stress.value = value;
}
const freeTime = ref( -1 );
const freeTimeLevels = ref( [
'a lot of free time',
'quite a bit of free time',
'some free time',
'little free time',
'no free time',
] );
const freeTimeSlider = ref( stopSlider );
const setFreeTime = ( value: number ) => {
freeTime.value = value;
}
const cigaretCount = ref( 0 ); const cigaretCount = ref( 0 );
const sleepHours = ref( 0 ); const sleepHours = ref( 0 );
const setStress = ( value: number ) => {
stress.value = value;
}
const setUpRestSlider = () => { const setUpRestSlider = () => {
@@ -163,23 +181,48 @@
}, 1500 ); }, 1500 );
} }
const setUpFreeTimeSlider = () => {
setTimeout( () => {
freeTimeSlider.value.setUp( 5, 2 );
}, 2000 );
}
const showStats = () => { const showStats = () => {
alert( 'Coming soon!' ); alert( 'Coming soon!' );
} }
const submitForm = () => { const submitForm = () => {
if ( date.value && difficulty.value > -1 && stress.value > -1 && rest.value > -1 && cigaretCount.value >= 0 && sleepHours.value >= 0 ) {
if ( sleepHours.value < 2 ) {
if ( confirm( 'Are you sure you have entered the right number of sleep hours? Do you want to proceed with the entered ' + sleepHours.value + ' hours of sleep?' ) ) {
sendForm();
}
} else {
sendForm();
}
} else {
alert( 'Some entries are missing. Please fill them out before saving!' );
}
}
const sendForm = () => {
alert( 'Data submitted. Remember: Stop smoking! Smoking hurts your health!' ); alert( 'Data submitted. Remember: Stop smoking! Smoking hurts your health!' );
} }
const dateUpdatedHandler = () => { const dateUpdatedHandler = () => {
console.log( date.value ); console.log( date.value );
if ( date.value ) { if ( date.value ) {
if ( date.value.getTime() <= new Date().getTime() + 10000 ) {
hasSelectedDate.value = true; hasSelectedDate.value = true;
// TODO: Load old data, if present // TODO: Load old data, if present
if ( oldData[ date.value.toISOString() ] ) { if ( oldData[ date.value.toISOString() ] ) {
// TODO: Finish // TODO: Finish
} }
} else {
alert( 'Nice job, diviner, you just predicted the future. But since we are not at Hogwarts School of Witchcraft and Wizardry, we do not believe in this subject... They do not even really' )
}
} else { } else {
hasSelectedDate.value = false; hasSelectedDate.value = false;
} }
@@ -210,6 +253,7 @@
<template> <template>
<div> <div>
<a id="github-link" href="https://github.com/janishutz/batu-ui" target="_blank"><img :src="theme === 'dark_mode' ? '/github-mark-white.svg' : '/github-mark.svg'" alt="GitHub Logo"></a>
<button @click="changeTheme();" id="themeSelector" title="Toggle between light and dark mode"><span class="material-symbols-outlined" v-html="theme"></span></button> <button @click="changeTheme();" id="themeSelector" title="Toggle between light and dark mode"><span class="material-symbols-outlined" v-html="theme"></span></button>
<main> <main>
<h1 id="title">Smoke Data Recorder</h1> <h1 id="title">Smoke Data Recorder</h1>
@@ -247,6 +291,11 @@
<p>That day, my stress level was {{ stress >= 0 ? stressLevels[ stress ] : '...' }}</p> <p>That day, my stress level was {{ stress >= 0 ? stressLevels[ stress ] : '...' }}</p>
<stopSlider slider-id="stress" style="width: 50vw;" @slider-pos="( pos ) => setStress( pos )" ref="stressSlider" @ready="setUpStressSlider()"></stopSlider> <stopSlider slider-id="stress" style="width: 50vw;" @slider-pos="( pos ) => setStress( pos )" ref="stressSlider" @ready="setUpStressSlider()"></stopSlider>
</div> </div>
<div class="input-element">
<p>That day, I had {{ freeTime >= 0 ? freeTimeLevels[ freeTime ] : '...' }}</p>
<stopSlider slider-id="freeTime" style="width: 50vw;" @slider-pos="( pos ) => setFreeTime( pos )" ref="freeTimeSlider" @ready="setUpFreeTimeSlider()"></stopSlider>
</div>
<button @click="submitForm()" class="fancy-button" style="margin-top: 20px;">Submit</button> <button @click="submitForm()" class="fancy-button" style="margin-top: 20px;">Submit</button>
</div> </div>
</div> </div>
@@ -278,6 +327,30 @@
flex-direction: column; flex-direction: column;
width: 100vw; width: 100vw;
} }
#github-link {
position: fixed;
top: 10px;
right: 10px;
background: none;
border: none;
color: var( --primary-color );
cursor: pointer;
height: 2rem;
width: 2rem;
}
#github-link img {
width: 100%;
height: 100%;
}
.input-element {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
</style> </style>
<style> <style>

View File

@@ -112,7 +112,9 @@
<div class="slider-container"> <div class="slider-container">
<div :class="'slider-knob' + ( isDragging ? ' dragging' : '' )" :style="'left: ' + sliderKnobPos + 'px;'"> <div :class="'slider-knob' + ( isDragging ? ' dragging' : '' )" :style="'left: ' + sliderKnobPos + 'px;'">
<div :class="'slider-drag-support' + ( isDragging ? ' dragging' : '' )" @mousemove="( e ) => handleDrag( e.clientX )" <div :class="'slider-drag-support' + ( isDragging ? ' dragging' : '' )" @mousemove="( e ) => handleDrag( e.clientX )"
@mouseup="() => endDrag()" @mousedown="( e ) => startDrag( e.clientX )"></div> @mouseup="() => endDrag()" @mousedown="( e ) => startDrag( e.clientX )"
@touchstart="( e ) => startDrag( e.touches[ 0 ].clientX )"
@touchend="() => endDrag()" @touchmove="( e ) => handleDrag( e.touches[ 0 ].clientX )"></div>
</div> </div>

View File

@@ -1,19 +1,11 @@
import { fileURLToPath, URL } from 'node:url' import { fileURLToPath, URL } from 'node:url';
import { defineConfig } from 'vite' import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue' import vue from '@vitejs/plugin-vue';
// https://vitejs.dev/config/ // https://vitejs.dev/config/
export default defineConfig( { export default defineConfig( {
plugins: [ 'plugins': [ vue(), ],
vue(), 'resolve': { 'alias': { '@': fileURLToPath( new URL( './src', import.meta.url ) ) } },
], 'server': { 'port': 8081 }
resolve: { } );
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
},
server: {
port: 8081
}
})