develop #3
16
.browserslistrc
Normal file
16
.browserslistrc
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
|
||||||
|
# For additional information regarding the format and rule options, please see:
|
||||||
|
# https://github.com/browserslist/browserslist#queries
|
||||||
|
|
||||||
|
# For the full list of supported browsers by the Angular framework, please see:
|
||||||
|
# https://angular.io/guide/browser-support
|
||||||
|
|
||||||
|
# You can see what browsers were selected by your queries by running:
|
||||||
|
# npx browserslist
|
||||||
|
|
||||||
|
Chrome >=79
|
||||||
|
ChromeAndroid >=79
|
||||||
|
Firefox >=70
|
||||||
|
Edge >=79
|
||||||
|
Safari >=14
|
||||||
|
iOS >=14
|
||||||
16
.editorconfig
Normal file
16
.editorconfig
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# Editor configuration, see https://editorconfig.org
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[*.ts]
|
||||||
|
quote_type = single
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
max_line_length = off
|
||||||
|
trim_trailing_whitespace = false
|
||||||
46
.eslintrc.json
Normal file
46
.eslintrc.json
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
{
|
||||||
|
"root": true,
|
||||||
|
"ignorePatterns": ["projects/**/*"],
|
||||||
|
"overrides": [
|
||||||
|
{
|
||||||
|
"files": ["*.ts"],
|
||||||
|
"parserOptions": {
|
||||||
|
"project": ["tsconfig.json"],
|
||||||
|
"createDefaultProgram": true
|
||||||
|
},
|
||||||
|
"extends": [
|
||||||
|
"plugin:@angular-eslint/recommended",
|
||||||
|
"plugin:@angular-eslint/template/process-inline-templates"
|
||||||
|
],
|
||||||
|
"rules": {
|
||||||
|
"@angular-eslint/component-class-suffix": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
"suffixes": ["Page", "Component"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"@angular-eslint/component-selector": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
"type": "element",
|
||||||
|
"prefix": "app",
|
||||||
|
"style": "kebab-case"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"@angular-eslint/directive-selector": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
"type": "attribute",
|
||||||
|
"prefix": "app",
|
||||||
|
"style": "camelCase"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"files": ["*.html"],
|
||||||
|
"extends": ["plugin:@angular-eslint/template/recommended"],
|
||||||
|
"rules": {}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
39
.gitea/workflows/build-and-deploy.yaml
Normal file
39
.gitea/workflows/build-and-deploy.yaml
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
name: Build and Deploy develop
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- develop
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
builds:
|
||||||
|
runs-on: host
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Set up Node.js
|
||||||
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: '20'
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
npm install
|
||||||
|
npm install -g @angular/cli
|
||||||
|
|
||||||
|
- name: Build Angular project
|
||||||
|
run: ng build --configuration=production
|
||||||
|
|
||||||
|
- name: Build Docker image
|
||||||
|
run: |
|
||||||
|
docker build -t 192.168.2.28:5050/tusha-fe:latest .
|
||||||
|
|
||||||
|
- name: Push Docker image
|
||||||
|
env:
|
||||||
|
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
|
||||||
|
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
|
||||||
|
run: |
|
||||||
|
echo "${DOCKER_PASSWORD}" | docker login -u "${DOCKER_USERNAME}" --password-stdin
|
||||||
|
docker push 192.168.2.28:5050/tusha-fe:latest
|
||||||
|
|
||||||
69
.gitignore
vendored
Normal file
69
.gitignore
vendored
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
# Specifies intentionally untracked files to ignore when using Git
|
||||||
|
# http://git-scm.com/docs/gitignore
|
||||||
|
|
||||||
|
*~
|
||||||
|
*.sw[mnpcod]
|
||||||
|
.tmp
|
||||||
|
*.tmp
|
||||||
|
*.tmp.*
|
||||||
|
UserInterfaceState.xcuserstate
|
||||||
|
$RECYCLE.BIN/
|
||||||
|
|
||||||
|
*.log
|
||||||
|
log.txt
|
||||||
|
|
||||||
|
|
||||||
|
/.sourcemaps
|
||||||
|
/.versions
|
||||||
|
/coverage
|
||||||
|
|
||||||
|
# Ionic
|
||||||
|
/.ionic
|
||||||
|
/www
|
||||||
|
/platforms
|
||||||
|
/plugins
|
||||||
|
|
||||||
|
# Compiled output
|
||||||
|
/dist
|
||||||
|
/tmp
|
||||||
|
/out-tsc
|
||||||
|
/bazel-out
|
||||||
|
|
||||||
|
# Node
|
||||||
|
/node_modules
|
||||||
|
npm-debug.log
|
||||||
|
yarn-error.log
|
||||||
|
|
||||||
|
# IDEs and editors
|
||||||
|
.idea/
|
||||||
|
.project
|
||||||
|
.classpath
|
||||||
|
.c9/
|
||||||
|
*.launch
|
||||||
|
.settings/
|
||||||
|
*.sublime-project
|
||||||
|
*.sublime-workspace
|
||||||
|
|
||||||
|
# Visual Studio Code
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.history/*
|
||||||
|
|
||||||
|
|
||||||
|
# Miscellaneous
|
||||||
|
/.angular
|
||||||
|
/.angular/cache
|
||||||
|
.sass-cache/
|
||||||
|
/connect.lock
|
||||||
|
/coverage
|
||||||
|
/libpeerconnection.log
|
||||||
|
testem.log
|
||||||
|
/typings
|
||||||
|
|
||||||
|
# System files
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
.vscode
|
||||||
16
Dockerfile
Normal file
16
Dockerfile
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
FROM node:20-bullseye as build
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY package*.json ./
|
||||||
|
|
||||||
|
RUN npm install
|
||||||
|
RUN npm install -g @angular/cli
|
||||||
|
|
||||||
|
COPY . ./
|
||||||
|
|
||||||
|
RUN ng build --configuration=production
|
||||||
|
|
||||||
|
FROM nginx:latest
|
||||||
|
COPY --from=build app/dist/aftas-angular /usr/share/nginx/html
|
||||||
|
|
||||||
|
EXPOSE 80
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# Project Decisions
|
||||||
|
|
||||||
|
### backend
|
||||||
|
Looked at Spring Boot, Quarkus and Open Liberty. <br/>
|
||||||
|
The choise has been made for: <br/>
|
||||||
|
_*QUARKUS*_ <br/>
|
||||||
|
Quarkus does more at build time, can compile native (which is nice since it is in a container anyay), and spins up fast. It's the most optimized for running in containers.
|
||||||
|
|||||||
19
aantekeningen_dag-doelen.txt
Normal file
19
aantekeningen_dag-doelen.txt
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
12:30 tenissen
|
||||||
|
16:00 Ronja naar dansles brengen
|
||||||
|
|
||||||
|
- eerste twaalf kaartjes leren
|
||||||
|
V min. 1 pomodoro ochtend
|
||||||
|
- min. 1 pomodoro middag
|
||||||
|
V PR nakijken
|
||||||
|
V Angular blog lezen
|
||||||
|
- Queues blog lezen
|
||||||
|
- min. 1/2 uur aan Tusha
|
||||||
|
V fruit
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Declarabel:
|
||||||
|
- 07:00 - 12:00 = 5 uur
|
||||||
|
- 13:55 - 14:10 = 5,25 uur
|
||||||
|
- 14:30 - 16:00 = 6,75 uur
|
||||||
|
|
||||||
32
aantekeningen_q-doelen.txt
Normal file
32
aantekeningen_q-doelen.txt
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
Dreams:
|
||||||
|
- Eigen Tusha-app met eigen omzet
|
||||||
|
- Senior Front-end developer
|
||||||
|
- Eigen boek uitgegeven
|
||||||
|
|
||||||
|
Q2-doelen (approx. 10 weken):
|
||||||
|
- sporten - voor een gezondere en fittere geest
|
||||||
|
- progressie aan Tusha-app
|
||||||
|
- Kennes en ervaring met front-end development
|
||||||
|
- Meer focus
|
||||||
|
|
||||||
|
Normen en waarden - focus voor Q2:
|
||||||
|
- Weerbaar - niet blijven hangen in falen, noch in succes
|
||||||
|
- No-nonsense - eerlijk en oprecht naar eigen gedrag
|
||||||
|
- Compassie - liefde tonen voor waar je goed in bent
|
||||||
|
- Dankbaar - dankbaarheid tonen voor wat je hebt gekregen en hebt bereikt
|
||||||
|
|
||||||
|
SMART doelen Q2:
|
||||||
|
- 8x tenissen - sporten, focus, weerbaarheid
|
||||||
|
- 7x swingfit - sporten, focus, weerbaarheid
|
||||||
|
- smartcards the now habit leren - focus, weerbaarheid
|
||||||
|
- 8 uur development aan tusha - progressie, kennis & ervaring, compassie
|
||||||
|
- 30 dagen met ochtend pomodoro - focus, kennis & ervaring, weerbaarheid
|
||||||
|
- 30 dagen met middag pomodoro - focus, kennis & ervaring, weerbaarheid
|
||||||
|
- 10 focus meditatiesessies - focus, weerbaarheid
|
||||||
|
- 10 ontspanning meditatiesessies - weerbaarheid, dankbaarheid
|
||||||
|
- 8 uur zelfstudie m.b.t. front-end - compassie, kennis & ervaring
|
||||||
|
- 8x wekelijkse evaluatie - weerbaarheid, no-nonsense
|
||||||
|
|
||||||
|
|
||||||
|
------ VOORTGANG ------
|
||||||
|
|
||||||
22
aantekeningen_w-doelen.txt
Normal file
22
aantekeningen_w-doelen.txt
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
Week-doelen:
|
||||||
|
- Sporten
|
||||||
|
- Angular leren
|
||||||
|
- Weerbaarheid/focus leren
|
||||||
|
- Aan Tusha werken
|
||||||
|
- Kennis backend op peil houden
|
||||||
|
|
||||||
|
SMART DOELEN:
|
||||||
|
- sporten: 1 x tennissen
|
||||||
|
- weerbaarheidstraining: alle kaartjes een keer doorgenomen - de eerste 12 geleerd, de tweede 12 soms met spieken
|
||||||
|
- 1 uur development aan Tusha
|
||||||
|
- 4 ochtenden met min. 1 pomodoro
|
||||||
|
- 4 middagen met min. 1 pomodoro
|
||||||
|
- 1 back-end gerelateerd artikel lezen
|
||||||
|
- 1 front-end gerelateerd artikel lezen
|
||||||
|
- 1 x focus meditatie
|
||||||
|
- 1 x ontspanningsmeditatie
|
||||||
|
- Week evalueren
|
||||||
|
- min. 5 dagen fruit
|
||||||
|
|
||||||
|
|
||||||
|
---- VOORTGANG ---
|
||||||
148
angular.json
Normal file
148
angular.json
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
{
|
||||||
|
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||||
|
"version": 1,
|
||||||
|
"newProjectRoot": "projects",
|
||||||
|
"projects": {
|
||||||
|
"app": {
|
||||||
|
"projectType": "application",
|
||||||
|
"schematics": {
|
||||||
|
"@ionic/angular-toolkit:page": {
|
||||||
|
"styleext": "scss",
|
||||||
|
"standalone": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "",
|
||||||
|
"sourceRoot": "src",
|
||||||
|
"prefix": "app",
|
||||||
|
"architect": {
|
||||||
|
"build": {
|
||||||
|
"builder": "@angular-devkit/build-angular:browser",
|
||||||
|
"options": {
|
||||||
|
"outputPath": "www",
|
||||||
|
"index": "src/index.html",
|
||||||
|
"main": "src/main.ts",
|
||||||
|
"polyfills": "src/polyfills.ts",
|
||||||
|
"tsConfig": "tsconfig.app.json",
|
||||||
|
"inlineStyleLanguage": "scss",
|
||||||
|
"assets": [
|
||||||
|
{
|
||||||
|
"glob": "**/*",
|
||||||
|
"input": "src/assets",
|
||||||
|
"output": "assets"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"styles": ["src/theme/variables.scss", "src/global.scss"],
|
||||||
|
"scripts": []
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"production": {
|
||||||
|
"budgets": [
|
||||||
|
{
|
||||||
|
"type": "initial",
|
||||||
|
"maximumWarning": "2mb",
|
||||||
|
"maximumError": "5mb"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "anyComponentStyle",
|
||||||
|
"maximumWarning": "2kb",
|
||||||
|
"maximumError": "4kb"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"fileReplacements": [
|
||||||
|
{
|
||||||
|
"replace": "src/environments/environment.ts",
|
||||||
|
"with": "src/environments/environment.prod.ts"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputHashing": "all"
|
||||||
|
},
|
||||||
|
"development": {
|
||||||
|
"buildOptimizer": false,
|
||||||
|
"optimization": false,
|
||||||
|
"vendorChunk": true,
|
||||||
|
"extractLicenses": false,
|
||||||
|
"sourceMap": true,
|
||||||
|
"namedChunks": true
|
||||||
|
},
|
||||||
|
"ci": {
|
||||||
|
"progress": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"defaultConfiguration": "production"
|
||||||
|
},
|
||||||
|
"serve": {
|
||||||
|
"builder": "@angular-devkit/build-angular:dev-server",
|
||||||
|
"configurations": {
|
||||||
|
"production": {
|
||||||
|
"buildTarget": "app:build:production"
|
||||||
|
},
|
||||||
|
"development": {
|
||||||
|
"buildTarget": "app:build:development"
|
||||||
|
},
|
||||||
|
"ci": {
|
||||||
|
"progress": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"defaultConfiguration": "development"
|
||||||
|
},
|
||||||
|
"extract-i18n": {
|
||||||
|
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||||
|
"options": {
|
||||||
|
"buildTarget": "app:build"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"test": {
|
||||||
|
"builder": "@angular-devkit/build-angular:karma",
|
||||||
|
"options": {
|
||||||
|
"main": "src/test.ts",
|
||||||
|
"polyfills": "src/polyfills.ts",
|
||||||
|
"tsConfig": "tsconfig.spec.json",
|
||||||
|
"karmaConfig": "karma.conf.js",
|
||||||
|
"inlineStyleLanguage": "scss",
|
||||||
|
"assets": [
|
||||||
|
{
|
||||||
|
"glob": "**/*",
|
||||||
|
"input": "src/assets",
|
||||||
|
"output": "assets"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"styles": ["src/theme/variables.scss", "src/global.scss"],
|
||||||
|
"scripts": []
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"ci": {
|
||||||
|
"progress": false,
|
||||||
|
"watch": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"lint": {
|
||||||
|
"builder": "@angular-eslint/builder:lint",
|
||||||
|
"options": {
|
||||||
|
"lintFilePatterns": ["src/**/*.ts", "src/**/*.html"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cli": {
|
||||||
|
"schematicCollections": [
|
||||||
|
"@ionic/angular-toolkit"
|
||||||
|
],
|
||||||
|
"analytics": false
|
||||||
|
},
|
||||||
|
"schematics": {
|
||||||
|
"@ionic/angular-toolkit:component": {
|
||||||
|
"styleext": "scss"
|
||||||
|
},
|
||||||
|
"@ionic/angular-toolkit:page": {
|
||||||
|
"styleext": "scss"
|
||||||
|
},
|
||||||
|
"@angular-eslint/schematics:application": {
|
||||||
|
"setParserOptionsProject": true
|
||||||
|
},
|
||||||
|
"@angular-eslint/schematics:library": {
|
||||||
|
"setParserOptionsProject": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
12
capacitor.config.ts
Normal file
12
capacitor.config.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { CapacitorConfig } from '@capacitor/cli';
|
||||||
|
|
||||||
|
const config: CapacitorConfig = {
|
||||||
|
appId: 'io.ionic.starter',
|
||||||
|
appName: 'tusha-fe',
|
||||||
|
webDir: 'www',
|
||||||
|
server: {
|
||||||
|
androidScheme: 'https'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default config;
|
||||||
7
ionic.config.json
Normal file
7
ionic.config.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"name": "tusha-fe",
|
||||||
|
"integrations": {
|
||||||
|
"capacitor": {}
|
||||||
|
},
|
||||||
|
"type": "angular-standalone"
|
||||||
|
}
|
||||||
44
karma.conf.js
Normal file
44
karma.conf.js
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
// Karma configuration file, see link for more information
|
||||||
|
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||||
|
|
||||||
|
module.exports = function (config) {
|
||||||
|
config.set({
|
||||||
|
basePath: '',
|
||||||
|
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
||||||
|
plugins: [
|
||||||
|
require('karma-jasmine'),
|
||||||
|
require('karma-chrome-launcher'),
|
||||||
|
require('karma-jasmine-html-reporter'),
|
||||||
|
require('karma-coverage'),
|
||||||
|
require('@angular-devkit/build-angular/plugins/karma')
|
||||||
|
],
|
||||||
|
client: {
|
||||||
|
jasmine: {
|
||||||
|
// you can add configuration options for Jasmine here
|
||||||
|
// the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
|
||||||
|
// for example, you can disable the random execution with `random: false`
|
||||||
|
// or set a specific seed with `seed: 4321`
|
||||||
|
},
|
||||||
|
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
||||||
|
},
|
||||||
|
jasmineHtmlReporter: {
|
||||||
|
suppressAll: true // removes the duplicated traces
|
||||||
|
},
|
||||||
|
coverageReporter: {
|
||||||
|
dir: require('path').join(__dirname, './coverage/app'),
|
||||||
|
subdir: '.',
|
||||||
|
reporters: [
|
||||||
|
{ type: 'html' },
|
||||||
|
{ type: 'text-summary' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
reporters: ['progress', 'kjhtml'],
|
||||||
|
port: 9876,
|
||||||
|
colors: true,
|
||||||
|
logLevel: config.LOG_INFO,
|
||||||
|
autoWatch: true,
|
||||||
|
browsers: ['Chrome'],
|
||||||
|
singleRun: false,
|
||||||
|
restartOnFileChange: true
|
||||||
|
});
|
||||||
|
};
|
||||||
17340
package-lock.json
generated
Normal file
17340
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
66
package.json
Normal file
66
package.json
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
{
|
||||||
|
"name": "tusha-fe",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"author": "Ionic Framework",
|
||||||
|
"homepage": "https://ionicframework.com/",
|
||||||
|
"scripts": {
|
||||||
|
"ng": "ng",
|
||||||
|
"start": "ng serve",
|
||||||
|
"build": "ng build",
|
||||||
|
"watch": "ng build --watch --configuration development",
|
||||||
|
"test": "ng test",
|
||||||
|
"lint": "ng lint"
|
||||||
|
},
|
||||||
|
"private": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@angular/animations": "^17.3.0",
|
||||||
|
"@angular/common": "^17.3.0",
|
||||||
|
"@angular/compiler": "^17.3.0",
|
||||||
|
"@angular/core": "^17.3.0",
|
||||||
|
"@angular/forms": "^17.3.0",
|
||||||
|
"@angular/platform-browser": "^17.3.0",
|
||||||
|
"@angular/platform-browser-dynamic": "^17.3.0",
|
||||||
|
"@angular/router": "^17.3.0",
|
||||||
|
"@capacitor/app": "5.0.6",
|
||||||
|
"@capacitor/core": "5.6.0",
|
||||||
|
"@capacitor/haptics": "5.0.6",
|
||||||
|
"@capacitor/keyboard": "5.0.7",
|
||||||
|
"@capacitor/status-bar": "5.0.6",
|
||||||
|
"@ionic/angular": "^7.5.0",
|
||||||
|
"chart.js": "^4.4.1",
|
||||||
|
"ionicons": "^7.2.1",
|
||||||
|
"rxjs": "~7.8.0",
|
||||||
|
"tslib": "^2.3.0",
|
||||||
|
"zone.js": "~0.14.2"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@angular-devkit/build-angular": "^17.3.0",
|
||||||
|
"@angular-eslint/builder": "^17.0.0",
|
||||||
|
"@angular-eslint/eslint-plugin": "^17.0.0",
|
||||||
|
"@angular-eslint/eslint-plugin-template": "^17.0.0",
|
||||||
|
"@angular-eslint/schematics": "^17.0.0",
|
||||||
|
"@angular-eslint/template-parser": "^17.0.0",
|
||||||
|
"@angular/cli": "^17.3.0",
|
||||||
|
"@angular/compiler-cli": "^17.3.0",
|
||||||
|
"@angular/language-service": "^17.3.0",
|
||||||
|
"@capacitor/cli": "5.6.0",
|
||||||
|
"@ionic/angular-toolkit": "^9.0.0",
|
||||||
|
"@types/jasmine": "~5.1.0",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
||||||
|
"@typescript-eslint/parser": "^6.0.0",
|
||||||
|
"eslint": "^7.26.0",
|
||||||
|
"eslint-plugin-import": "2.22.1",
|
||||||
|
"eslint-plugin-jsdoc": "30.7.6",
|
||||||
|
"eslint-plugin-prefer-arrow": "1.2.2",
|
||||||
|
"jasmine-core": "~5.1.0",
|
||||||
|
"jasmine-spec-reporter": "~5.0.0",
|
||||||
|
"karma": "~6.4.0",
|
||||||
|
"karma-chrome-launcher": "~3.2.0",
|
||||||
|
"karma-coverage": "~2.2.0",
|
||||||
|
"karma-jasmine": "~5.1.0",
|
||||||
|
"karma-jasmine-html-reporter": "~2.1.0",
|
||||||
|
"ts-node": "^8.3.0",
|
||||||
|
"typescript": "~5.2.2"
|
||||||
|
},
|
||||||
|
"description": "An Ionic project"
|
||||||
|
}
|
||||||
20
src/app/app.component.html
Normal file
20
src/app/app.component.html
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<ion-app>
|
||||||
|
<ion-split-pane contentId="main-content">
|
||||||
|
<ion-menu contentId="main-content" type="overlay">
|
||||||
|
<ion-content>
|
||||||
|
<ion-list id="inbox-list">
|
||||||
|
<ion-list-header>Inbox</ion-list-header>
|
||||||
|
<ion-note>hi@ionicframework.com</ion-note>
|
||||||
|
|
||||||
|
<ion-menu-toggle auto-hide="false" *ngFor="let p of appPages; let i = index">
|
||||||
|
<ion-item routerDirection="root" [routerLink]="[p.url]" lines="none" detail="false" routerLinkActive="selected">
|
||||||
|
<ion-icon aria-hidden="true" slot="start" [ios]="p.icon + '-outline'" [md]="p.icon + '-sharp'"></ion-icon>
|
||||||
|
<ion-label>{{ p.title }}</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
</ion-menu-toggle>
|
||||||
|
</ion-list>
|
||||||
|
</ion-content>
|
||||||
|
</ion-menu>
|
||||||
|
<ion-router-outlet id="main-content"></ion-router-outlet>
|
||||||
|
</ion-split-pane>
|
||||||
|
</ion-app>
|
||||||
119
src/app/app.component.scss
Normal file
119
src/app/app.component.scss
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
ion-menu ion-content {
|
||||||
|
--background: var(--ion-item-background, var(--ion-background-color, #fff));
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-menu.md ion-content {
|
||||||
|
--padding-start: 8px;
|
||||||
|
--padding-end: 8px;
|
||||||
|
--padding-top: 20px;
|
||||||
|
--padding-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-menu.md ion-list {
|
||||||
|
padding: 20px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-menu.md ion-note {
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-menu.md ion-list-header,
|
||||||
|
ion-menu.md ion-note {
|
||||||
|
padding-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-menu.md ion-list#inbox-list {
|
||||||
|
border-bottom: 1px solid var(--ion-color-step-150, #d7d8da);
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-menu.md ion-list#inbox-list ion-list-header {
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: 600;
|
||||||
|
|
||||||
|
min-height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-menu.md ion-list#labels-list ion-list-header {
|
||||||
|
font-size: 16px;
|
||||||
|
|
||||||
|
margin-bottom: 18px;
|
||||||
|
|
||||||
|
color: #757575;
|
||||||
|
|
||||||
|
min-height: 26px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-menu.md ion-item {
|
||||||
|
--padding-start: 10px;
|
||||||
|
--padding-end: 10px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-menu.md ion-item.selected {
|
||||||
|
--background: rgba(var(--ion-color-primary-rgb), 0.14);
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-menu.md ion-item.selected ion-icon {
|
||||||
|
color: var(--ion-color-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-menu.md ion-item ion-icon {
|
||||||
|
color: #616e7e;
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-menu.md ion-item ion-label {
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-menu.ios ion-content {
|
||||||
|
--padding-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-menu.ios ion-list {
|
||||||
|
padding: 20px 0 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-menu.ios ion-note {
|
||||||
|
line-height: 24px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-menu.ios ion-item {
|
||||||
|
--padding-start: 16px;
|
||||||
|
--padding-end: 16px;
|
||||||
|
--min-height: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-menu.ios ion-item.selected ion-icon {
|
||||||
|
color: var(--ion-color-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-menu.ios ion-item ion-icon {
|
||||||
|
font-size: 24px;
|
||||||
|
color: #73849a;
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-menu.ios ion-list#labels-list ion-list-header {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-menu.ios ion-list-header,
|
||||||
|
ion-menu.ios ion-note {
|
||||||
|
padding-left: 16px;
|
||||||
|
padding-right: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-menu.ios ion-note {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-note {
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 16px;
|
||||||
|
|
||||||
|
color: var(--ion-color-medium-shade);
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-item.selected {
|
||||||
|
--color: var(--ion-color-primary);
|
||||||
|
}
|
||||||
44
src/app/app.component.spec.ts
Normal file
44
src/app/app.component.spec.ts
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
|
|
||||||
|
import { AppComponent } from './app.component';
|
||||||
|
|
||||||
|
describe('AppComponent', () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
TestBed.overrideComponent(AppComponent, {
|
||||||
|
add: {
|
||||||
|
imports: [RouterTestingModule]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create the app', () => {
|
||||||
|
const fixture = TestBed.createComponent(AppComponent);
|
||||||
|
const app = fixture.componentInstance;
|
||||||
|
expect(app).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have menu labels', () => {
|
||||||
|
const fixture = TestBed.createComponent(AppComponent);
|
||||||
|
fixture.detectChanges();
|
||||||
|
const app = fixture.nativeElement;
|
||||||
|
const menuItems = app.querySelectorAll('ion-label');
|
||||||
|
expect(menuItems.length).toEqual(12);
|
||||||
|
expect(menuItems[0].textContent).toContain('Inbox');
|
||||||
|
expect(menuItems[1].textContent).toContain('Outbox');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have urls', () => {
|
||||||
|
const fixture = TestBed.createComponent(AppComponent);
|
||||||
|
fixture.detectChanges();
|
||||||
|
const app = fixture.nativeElement;
|
||||||
|
const menuItems = app.querySelectorAll('ion-item');
|
||||||
|
expect(menuItems.length).toEqual(12);
|
||||||
|
expect(menuItems[0].getAttribute('ng-reflect-router-link')).toEqual(
|
||||||
|
'/folder/inbox'
|
||||||
|
);
|
||||||
|
expect(menuItems[1].getAttribute('ng-reflect-router-link')).toEqual(
|
||||||
|
'/folder/outbox'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
32
src/app/app.component.ts
Normal file
32
src/app/app.component.ts
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { Component } from '@angular/core';
|
||||||
|
import { RouterLink, RouterLinkActive } from '@angular/router';
|
||||||
|
import { IonApp, IonSplitPane, IonMenu, IonContent, IonList, IonListHeader, IonNote, IonMenuToggle, IonItem, IonIcon, IonLabel, IonRouterOutlet } from '@ionic/angular/standalone';
|
||||||
|
import { addIcons } from 'ionicons';
|
||||||
|
import { mailOutline, mailSharp, paperPlaneOutline, paperPlaneSharp, heartOutline, heartSharp, archiveOutline, archiveSharp, trashOutline, trashSharp, warningOutline, warningSharp, bookmarkOutline, bookmarkSharp } from 'ionicons/icons';
|
||||||
|
import { HomePage} from "./pages/home/home.component";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-root',
|
||||||
|
templateUrl: 'app.component.html',
|
||||||
|
styleUrls: ['app.component.scss'],
|
||||||
|
standalone: true,
|
||||||
|
imports: [HomePage, RouterLink, RouterLinkActive, CommonModule, IonApp, IonSplitPane, IonMenu, IonContent, IonList, IonListHeader, IonNote, IonMenuToggle, IonItem, IonIcon, IonLabel, IonRouterOutlet],
|
||||||
|
})
|
||||||
|
export class AppComponent {
|
||||||
|
public appPages = [
|
||||||
|
{ title: 'Home', url: '/tusha/home', icon: 'home' },
|
||||||
|
{ title: 'Daily goals', url: '/folder/daily', icon: 'today' },
|
||||||
|
{ title: 'Weekly goals', url: '/folder/weekly', icon: 'calendar' },
|
||||||
|
{ title: 'Quarterly goals', url: '/folder/quaterly', icon: 'book' },
|
||||||
|
{ title: 'Modus', url: '/tusha/modus', icon: 'aperture' },
|
||||||
|
{ title: 'Settings', url: '/folder/settings', icon: 'settings' },
|
||||||
|
];
|
||||||
|
public labels = ['Family', 'Friends', 'Notes', 'Work', 'Travel', 'Reminders'];
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
type Test = 'a' | 'b';
|
||||||
|
// ^?
|
||||||
|
addIcons({ mailOutline, mailSharp, paperPlaneOutline, paperPlaneSharp, heartOutline, heartSharp, archiveOutline, archiveSharp, trashOutline, trashSharp, warningOutline, warningSharp, bookmarkOutline, bookmarkSharp });
|
||||||
|
}
|
||||||
|
}
|
||||||
26
src/app/app.routes.ts
Normal file
26
src/app/app.routes.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import { Routes } from '@angular/router';
|
||||||
|
|
||||||
|
export const routes: Routes = [
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
redirectTo: 'tusha/home',
|
||||||
|
pathMatch: 'full',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'tusha/home',
|
||||||
|
loadComponent: () => import('./pages/home/home.component').then(m => m.HomePage)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'tusha/modus',
|
||||||
|
loadComponent: () => import('./pages/modus/modus-overview.component').then(m => m.ModusOverviewPage)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'tusha/modus/focus',
|
||||||
|
loadComponent: () => import('./pages/modus/focus/focus.component').then(m => m.FocusPage)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'folder/:id',
|
||||||
|
loadComponent: () =>
|
||||||
|
import('./folder/folder.page').then((m) => m.FolderPage),
|
||||||
|
},
|
||||||
|
];
|
||||||
21
src/app/folder/folder.page.html
Normal file
21
src/app/folder/folder.page.html
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<ion-header [translucent]="true">
|
||||||
|
<ion-toolbar>
|
||||||
|
<ion-buttons slot="start">
|
||||||
|
<ion-menu-button></ion-menu-button>
|
||||||
|
</ion-buttons>
|
||||||
|
<ion-title>{{ folder }}</ion-title>
|
||||||
|
</ion-toolbar>
|
||||||
|
</ion-header>
|
||||||
|
|
||||||
|
<ion-content [fullscreen]="true">
|
||||||
|
<ion-header collapse="condense">
|
||||||
|
<ion-toolbar>
|
||||||
|
<ion-title size="large">{{ folder }}</ion-title>
|
||||||
|
</ion-toolbar>
|
||||||
|
</ion-header>
|
||||||
|
|
||||||
|
<div id="container">
|
||||||
|
<strong class="capitalize">{{ folder }}</strong>
|
||||||
|
<p>Explore <a target="_blank" rel="noopener noreferrer" href="https://ionicframework.com/docs/components">UI Components</a></p>
|
||||||
|
</div>
|
||||||
|
</ion-content>
|
||||||
28
src/app/folder/folder.page.scss
Normal file
28
src/app/folder/folder.page.scss
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
ion-menu-button {
|
||||||
|
color: var(--ion-color-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
#container {
|
||||||
|
text-align: center;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
#container strong {
|
||||||
|
font-size: 20px;
|
||||||
|
line-height: 26px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#container p {
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 22px;
|
||||||
|
color: #8c8c8c;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#container a {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
25
src/app/folder/folder.page.spec.ts
Normal file
25
src/app/folder/folder.page.spec.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
|
|
||||||
|
import { FolderPage } from './folder.page';
|
||||||
|
|
||||||
|
describe('FolderPage', () => {
|
||||||
|
let component: FolderPage;
|
||||||
|
let fixture: ComponentFixture<FolderPage>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
TestBed.overrideComponent(FolderPage, {
|
||||||
|
add: {
|
||||||
|
imports: [RouterTestingModule]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(FolderPage);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
20
src/app/folder/folder.page.ts
Normal file
20
src/app/folder/folder.page.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import { Component, inject, OnInit } from '@angular/core';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
import { IonHeader, IonToolbar, IonButtons, IonMenuButton, IonTitle, IonContent } from '@ionic/angular/standalone';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-folder',
|
||||||
|
templateUrl: './folder.page.html',
|
||||||
|
styleUrls: ['./folder.page.scss'],
|
||||||
|
standalone: true,
|
||||||
|
imports: [IonHeader, IonToolbar, IonButtons, IonMenuButton, IonTitle, IonContent],
|
||||||
|
})
|
||||||
|
export class FolderPage implements OnInit {
|
||||||
|
public folder!: string;
|
||||||
|
private activatedRoute = inject(ActivatedRoute);
|
||||||
|
constructor() {}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.folder = this.activatedRoute.snapshot.paramMap.get('id') as string;
|
||||||
|
}
|
||||||
|
}
|
||||||
0
src/app/pages/daily/dialy.component.css
Normal file
0
src/app/pages/daily/dialy.component.css
Normal file
11
src/app/pages/home/home.component.css
Normal file
11
src/app/pages/home/home.component.css
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
|
||||||
|
ion-footer ion-title {
|
||||||
|
position: absolute;
|
||||||
|
right: 0px;
|
||||||
|
color: darkgray;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
13
src/app/pages/home/home.component.html
Normal file
13
src/app/pages/home/home.component.html
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<app-tusha-page>
|
||||||
|
<ion-breadcrumbs slot="breadcrumb">
|
||||||
|
<ion-breadcrumb >
|
||||||
|
<ion-icon slot="start" name="home"/>
|
||||||
|
Home
|
||||||
|
</ion-breadcrumb>
|
||||||
|
</ion-breadcrumbs>
|
||||||
|
|
||||||
|
<tusha-status-cards [card1]="card1" [card2]="card2" />
|
||||||
|
|
||||||
|
<tusha-nav-rows [navcards]="navcards" />
|
||||||
|
|
||||||
|
</app-tusha-page>
|
||||||
54
src/app/pages/home/home.component.ts
Normal file
54
src/app/pages/home/home.component.ts
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
import { Component } from "@angular/core";
|
||||||
|
import {Router} from "@angular/router";
|
||||||
|
import {
|
||||||
|
IonBreadcrumbs, IonCard, IonCardContent, IonCol, IonRow, IonBreadcrumb, IonIcon
|
||||||
|
} from "@ionic/angular/standalone";
|
||||||
|
import {TushaNavRowsComponent} from "../../tusha/tusha-nav-rows/tusha-nav-rows.component";
|
||||||
|
import {NavCardData} from "../../tusha/tusha-nav-rows/nav-card-data";
|
||||||
|
import {TushaPageComponent} from "../../tusha/tusha-page/tusha-page.component";
|
||||||
|
import {TushaStatusCardsComponent} from "../../tusha/tusha-status-cards/tusha-status-cards.component";
|
||||||
|
import {StatusCardsData} from "../../tusha/tusha-status-cards/status-cards-data";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
templateUrl: 'home.component.html',
|
||||||
|
styleUrls: ['home.component.css'],
|
||||||
|
standalone: true,
|
||||||
|
imports: [IonRow, IonCol, IonCard, IonCardContent, TushaNavRowsComponent, TushaPageComponent, IonBreadcrumbs, IonBreadcrumb, IonIcon, TushaStatusCardsComponent]
|
||||||
|
})
|
||||||
|
export class HomePage {
|
||||||
|
navcards: NavCardData[];
|
||||||
|
card1: StatusCardsData;
|
||||||
|
card2: StatusCardsData;
|
||||||
|
|
||||||
|
constructor(public router: Router) {
|
||||||
|
this.navcards = [
|
||||||
|
{id: 1, title: 'Daily Goals', color: {color: 'blue'}, onclick: this.goToDailyGoals.bind(this), icon: 'today-outline'},
|
||||||
|
{id: 2, title: 'Weekly Goals', color: {color: 'green'}, onclick: this.goToDailyGoals.bind(this), icon: 'calendar-outline'},
|
||||||
|
{id: 3, title: 'Quaterly Goals', color: {color: 'orange'}, onclick: this.goToDailyGoals.bind(this), icon: 'book-outline'},
|
||||||
|
{id: 4, title: 'Go Into Modus', color: {color: 'black'}, onclick: this.goToModus.bind(this), icon: 'aperture-outline'},
|
||||||
|
];
|
||||||
|
this.card1 = {
|
||||||
|
id: 1,
|
||||||
|
color: {color: 'orange'},
|
||||||
|
type: 'number',
|
||||||
|
amount: 15,
|
||||||
|
description: 'Tasks Done'
|
||||||
|
};
|
||||||
|
this.card2 = {
|
||||||
|
id: 2,
|
||||||
|
color: {color: 'green'},
|
||||||
|
type: 'percentage',
|
||||||
|
amount: 58,
|
||||||
|
description: 'Week Progress'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
goToDailyGoals() {
|
||||||
|
this.router.navigate(['folder/daily']);
|
||||||
|
}
|
||||||
|
|
||||||
|
goToModus() {
|
||||||
|
this.router.navigate(['tusha/modus']);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
9
src/app/pages/modus/focus/focus-configuration.ts
Normal file
9
src/app/pages/modus/focus/focus-configuration.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
export class FocusConfiguration {
|
||||||
|
focusMinutes: number = 25;
|
||||||
|
shortBreak: number = 5;
|
||||||
|
longBreak: number = 15;
|
||||||
|
|
||||||
|
cyclesBeforeLongBreak: number = 4;
|
||||||
|
|
||||||
|
behaviorOnFocusEnd: 'nothing' | 'startBreak' | 'overtime' = 'overtime';
|
||||||
|
}
|
||||||
3
src/app/pages/modus/focus/focus-state.ts
Normal file
3
src/app/pages/modus/focus/focus-state.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export enum FocusState {
|
||||||
|
FOCUS = 'in_focus', SHORT_BREAK = 'short_break', LONG_BREAK = 'long_break', STOPPED = 'stopped'
|
||||||
|
}
|
||||||
79
src/app/pages/modus/focus/focus-stats.ts
Normal file
79
src/app/pages/modus/focus/focus-stats.ts
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
import {FocusState} from "./focus-state";
|
||||||
|
|
||||||
|
export class FocusStats {
|
||||||
|
private _focusCycles: number = 0;
|
||||||
|
private _focusTimeInMs: number = 0;
|
||||||
|
private _focusTime: string = '';
|
||||||
|
private _shortBreakCycles: number = 0;
|
||||||
|
private _longBreakCycles: number = 0;
|
||||||
|
private _breakTimeInMs: number = 0;
|
||||||
|
private _breakTime: string = '';
|
||||||
|
|
||||||
|
inc(state: FocusState, deltaInMs?: number): void {
|
||||||
|
switch (state) {
|
||||||
|
case FocusState.FOCUS:
|
||||||
|
this._focusCycles++;
|
||||||
|
this._focusTimeInMs += !!deltaInMs ? deltaInMs : 0;
|
||||||
|
this.updateFocusTime();
|
||||||
|
break;
|
||||||
|
case FocusState.SHORT_BREAK:
|
||||||
|
this._shortBreakCycles++;
|
||||||
|
this._breakTimeInMs += !!deltaInMs ? deltaInMs : 0;
|
||||||
|
this.updateBreakTime();
|
||||||
|
break;
|
||||||
|
case FocusState.LONG_BREAK:
|
||||||
|
this._longBreakCycles++;
|
||||||
|
this._breakTimeInMs += !!deltaInMs ? deltaInMs : 0;
|
||||||
|
this.updateBreakTime();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// nothing
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private updateFocusTime() {
|
||||||
|
this._focusTime = this.transformTime(this._focusTimeInMs);
|
||||||
|
}
|
||||||
|
|
||||||
|
private updateBreakTime() {
|
||||||
|
this._breakTime = this.transformTime(this._breakTimeInMs);
|
||||||
|
}
|
||||||
|
|
||||||
|
private transformTime(ms: number): string {
|
||||||
|
const totalSeconds = Math.floor(ms / 1000);
|
||||||
|
const seconds = totalSeconds % 60;
|
||||||
|
const totalMinutes = Math.floor(totalSeconds / 60);
|
||||||
|
const minutes = totalMinutes % 60;
|
||||||
|
const hours = Math.floor(totalMinutes / 60);
|
||||||
|
|
||||||
|
const pad = (n: number) => n.toString().padStart(2, "0");
|
||||||
|
|
||||||
|
if (hours > 0) {
|
||||||
|
return `${pad(hours)}:${pad(minutes)}:${pad(seconds)}`;
|
||||||
|
} else {
|
||||||
|
return `${pad(minutes)}:${pad(seconds)}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get focusCycles(): number {
|
||||||
|
return this._focusCycles;
|
||||||
|
}
|
||||||
|
|
||||||
|
get shortBreakCycles(): number {
|
||||||
|
return this._shortBreakCycles;
|
||||||
|
}
|
||||||
|
|
||||||
|
get longBreakCycles(): number {
|
||||||
|
return this._longBreakCycles;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
get focusTime(): string {
|
||||||
|
return this._focusTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
get breakTime(): string {
|
||||||
|
return this._breakTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
169
src/app/pages/modus/focus/focus.component.css
Normal file
169
src/app/pages/modus/focus/focus.component.css
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
|
||||||
|
/* focus-timer.component.scss */
|
||||||
|
app-tusha-page {
|
||||||
|
height: 500px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.leftright-line {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fullwidth {
|
||||||
|
width: 320px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.countdown-box {
|
||||||
|
height: 320px;
|
||||||
|
border: 2px solid;
|
||||||
|
padding: 0.5em 0.5em 0.5em 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.countdown-state-text {
|
||||||
|
font-family: Monaco, "Lucida Console", monospace;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.countdown-state-stopped-box {
|
||||||
|
background-color: lightcoral;
|
||||||
|
border-color: darkred;
|
||||||
|
}
|
||||||
|
|
||||||
|
.countdown-state-stopped-text{
|
||||||
|
color: darkred;
|
||||||
|
}
|
||||||
|
|
||||||
|
.countdown-state-short_break-box {
|
||||||
|
background-color: lightcyan;
|
||||||
|
border-color: darkgreen;
|
||||||
|
}
|
||||||
|
|
||||||
|
.countdown-state-short_break-text {
|
||||||
|
color: darkgreen;
|
||||||
|
}
|
||||||
|
|
||||||
|
.countdown-state-long_break-box {
|
||||||
|
background-color: peachpuff;
|
||||||
|
border-color: orangered;
|
||||||
|
}
|
||||||
|
|
||||||
|
.countdown-state-long_break-text {
|
||||||
|
color: orangered;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.countdown-state-in_focus-box {
|
||||||
|
background-color: lightblue;
|
||||||
|
border-color: darkblue;
|
||||||
|
}
|
||||||
|
|
||||||
|
.countdown-state-in_focus-text {
|
||||||
|
color: darkblue;
|
||||||
|
}
|
||||||
|
|
||||||
|
.focustimer {
|
||||||
|
position: relative;
|
||||||
|
width: 270px;
|
||||||
|
height: 270px;
|
||||||
|
border-radius: 50%;
|
||||||
|
overflow: hidden;
|
||||||
|
margin: 0 auto;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border: 2px solid;
|
||||||
|
background-color: lavender;
|
||||||
|
}
|
||||||
|
|
||||||
|
.countdown-text {
|
||||||
|
position: relative;
|
||||||
|
transform: translate(25%, -225%);
|
||||||
|
font-size: 4em;
|
||||||
|
color: var(--ion-color-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-button {
|
||||||
|
position: relative;
|
||||||
|
width: 120px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.countdown {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
width: 300px;
|
||||||
|
height: 300px;
|
||||||
|
align-content: center;
|
||||||
|
z-index: 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.focusmode {
|
||||||
|
border-width: 10px;
|
||||||
|
border-color: lightblue;
|
||||||
|
border-style: outset;
|
||||||
|
background-color: aliceblue;
|
||||||
|
}
|
||||||
|
|
||||||
|
.breakmode {
|
||||||
|
border-width: 10px;
|
||||||
|
border-color: antiquewhite;
|
||||||
|
border-style: outset;
|
||||||
|
background-color: beige;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.timer {
|
||||||
|
width: 350px;
|
||||||
|
height: 350px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.state {
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 1.5em;
|
||||||
|
border: 2px solid;
|
||||||
|
width: 350px;
|
||||||
|
height: 350px;
|
||||||
|
text-align: center;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 10px;
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
top: -350px;
|
||||||
|
left: -50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.state-stopped {
|
||||||
|
color: darkred;
|
||||||
|
background-color: lightcoral;
|
||||||
|
border-color: darkred;
|
||||||
|
}
|
||||||
|
|
||||||
|
.state-short_break {
|
||||||
|
color: darkgreen;
|
||||||
|
background-color: lightgreen;
|
||||||
|
border-color: darkgreen;
|
||||||
|
}
|
||||||
|
|
||||||
|
.state-long_break {
|
||||||
|
color: orangered;
|
||||||
|
background-color: peachpuff;
|
||||||
|
border-color: orangered;
|
||||||
|
}
|
||||||
|
|
||||||
|
.state_in_focus {
|
||||||
|
color: darkblue;
|
||||||
|
background-color: lightblue;
|
||||||
|
border-color: darkblue;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-bar {
|
||||||
|
width: 350px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
107
src/app/pages/modus/focus/focus.component.html
Normal file
107
src/app/pages/modus/focus/focus.component.html
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
<app-tusha-page>
|
||||||
|
<ion-breadcrumbs slot="breadcrumb">
|
||||||
|
<ion-breadcrumb href="tusha/home">
|
||||||
|
<ion-icon slot="start" name="home"/>
|
||||||
|
Home
|
||||||
|
</ion-breadcrumb>
|
||||||
|
<ion-breadcrumb href="tusha/modus">
|
||||||
|
<ion-icon slot="start" name="aperture"/>
|
||||||
|
Modus
|
||||||
|
</ion-breadcrumb>
|
||||||
|
<ion-breadcrumb>
|
||||||
|
<ion-icon slot="start" name="time"/>
|
||||||
|
Focus
|
||||||
|
</ion-breadcrumb>
|
||||||
|
</ion-breadcrumbs>
|
||||||
|
|
||||||
|
<!-- TODO add default action to div -->
|
||||||
|
<!-- TODO add are you sure pop-ups -->
|
||||||
|
|
||||||
|
<div class="leftright-line fullwidth">
|
||||||
|
<ion-button (click)="focus()" color="primary">
|
||||||
|
<ion-icon slot="start" name="aperture"></ion-icon>
|
||||||
|
Focus
|
||||||
|
</ion-button>
|
||||||
|
<ion-button (click)="stopTimer()" color="danger">
|
||||||
|
<ion-icon slot="start" name="close-circle"></ion-icon>
|
||||||
|
STOP
|
||||||
|
</ion-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="countdown-box countdown-state-{{state}}-box fullwidth">
|
||||||
|
<div class="leftright-line">
|
||||||
|
<span class="countdown-state-text countdown-state-{{state}}-text">{{state}}</span>
|
||||||
|
<!-- TODO add behaviour to settings cogwheel -->
|
||||||
|
<ion-icon name="settings-outline"></ion-icon>
|
||||||
|
</div>
|
||||||
|
<div class="countdown-timer">
|
||||||
|
<svg class="focustimer countdown-state-{{state}}-box" width="100%" height="100%" viewBox="0 0 200 200" (click)="startWhereWeAre()">
|
||||||
|
<!-- Definieer de gradient -->
|
||||||
|
<defs>
|
||||||
|
<!-- have the gradient follow the path is possible but too difficult for now - can be read at https://stackoverflow.com/questions/14633363/can-i-apply-a-gradient-along-an-svg-path -->
|
||||||
|
<linearGradient id="grad1" x1="1" y1="0" x2="0" y2="0">
|
||||||
|
<stop offset="0%" stop-color="blue"></stop>
|
||||||
|
<stop offset="80%" stop-color="green"></stop>
|
||||||
|
<stop offset="100%" stop-color="red"></stop>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
|
||||||
|
<path id="1stPath" [attr.d]="pathD"
|
||||||
|
fill="none" stroke="url(#grad1)" stroke-width="30" stroke-dasharray="0" [attr.stroke-dashoffset]="dashOffset" />
|
||||||
|
</svg>
|
||||||
|
<div class="countdown-text">{{ minutesText }}:{{ secondsText }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="leftright-line fullwidth">
|
||||||
|
<ion-button (click)="reload()" color="secondary">
|
||||||
|
<ion-icon slot="start" name="refresh-circle" ></ion-icon>
|
||||||
|
Reload
|
||||||
|
</ion-button>
|
||||||
|
<ion-button (click)="recharge()" color="warning">
|
||||||
|
<ion-icon slot="start" name="battery-charging"></ion-icon>
|
||||||
|
Recharge
|
||||||
|
</ion-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="focus-stats">
|
||||||
|
hier komen de stats
|
||||||
|
<ion-card>
|
||||||
|
<ion-list>
|
||||||
|
<ion-item>
|
||||||
|
<ion-label>
|
||||||
|
<p>Aantal focus cycles: <span>{{ ($stats | async)?.focusCycles }}</span></p>
|
||||||
|
</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
<ion-item>
|
||||||
|
<ion-label>
|
||||||
|
<p>Focus tijd: <span>{{ ($stats | async)?.focusTime}}</span></p>
|
||||||
|
</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
<ion-item>
|
||||||
|
<ion-label>
|
||||||
|
<p>Aantal korte pauzes: <span>{{ ($stats | async)?.shortBreakCycles}}</span></p>
|
||||||
|
</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
<ion-item>
|
||||||
|
<ion-label>
|
||||||
|
<p>Aantal lange pauzes: <span>{{ ($stats | async)?.longBreakCycles}}</span></p>
|
||||||
|
</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
<ion-item>
|
||||||
|
<ion-label>
|
||||||
|
<p>Pauze tijd: <span>{{ ($stats | async)?.breakTime}}</span></p>
|
||||||
|
</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
</ion-list>
|
||||||
|
</ion-card>
|
||||||
|
<!--
|
||||||
|
ion-card
|
||||||
|
met daarin ion-lines met de vol
|
||||||
|
|
||||||
|
-->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</app-tusha-page>
|
||||||
|
|
||||||
179
src/app/pages/modus/focus/focus.component.ts
Normal file
179
src/app/pages/modus/focus/focus.component.ts
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
import {Component, OnDestroy, OnInit, Renderer2} from "@angular/core";
|
||||||
|
import {
|
||||||
|
IonBreadcrumb,
|
||||||
|
IonBreadcrumbs,
|
||||||
|
IonButton,
|
||||||
|
IonCard,
|
||||||
|
IonContent,
|
||||||
|
IonIcon, IonItem, IonLabel, IonList,
|
||||||
|
IonProgressBar
|
||||||
|
} from "@ionic/angular/standalone";
|
||||||
|
import {TushaPageComponent} from "../../../tusha/tusha-page/tusha-page.component";
|
||||||
|
import {FocusState} from "./focus-state";
|
||||||
|
import {FocusService} from "./focus.service";
|
||||||
|
import {Observable} from "rxjs";
|
||||||
|
import {FocusStats} from "./focus-stats";
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
templateUrl: 'focus.component.html',
|
||||||
|
styleUrls: ['focus.component.css'],
|
||||||
|
standalone: true,
|
||||||
|
imports: [IonBreadcrumbs, IonBreadcrumb, IonIcon, TushaPageComponent, IonProgressBar, IonContent, IonButton, IonCard, IonItem, IonLabel, IonList, CommonModule]
|
||||||
|
})
|
||||||
|
export class FocusPage implements OnInit, OnDestroy {
|
||||||
|
duration: number = 0; // default duration in minutes
|
||||||
|
minutesText: string = '';
|
||||||
|
secondsText: string = '';
|
||||||
|
private interval: number | undefined;
|
||||||
|
private timerStarted: number | null = null;
|
||||||
|
state: FocusState = FocusState.STOPPED;
|
||||||
|
private focusRuns = 0;
|
||||||
|
$stats: Observable<FocusStats> = this.focusService.$stats;
|
||||||
|
|
||||||
|
private endOfTimerChime: HTMLAudioElement;
|
||||||
|
private forcedEndOfTimerChime: HTMLAudioElement;
|
||||||
|
private windUpChime: HTMLAudioElement;
|
||||||
|
|
||||||
|
pathD: string = 'M100 10 A90 90 0 1 1 0 0';
|
||||||
|
|
||||||
|
dashOffset = 0;
|
||||||
|
|
||||||
|
constructor(private renderer: Renderer2, private focusService: FocusService) {
|
||||||
|
this.endOfTimerChime = new Audio('../../../assets/race-start-beeps-125125.mp3');
|
||||||
|
this.forcedEndOfTimerChime = new Audio('../../../assets/hardstop.mp3');
|
||||||
|
this.windUpChime = new Audio('../../../assets/wind-up.mp3');
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.updateTimeDisplay(this.duration * 60, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
if (this.interval) {
|
||||||
|
clearInterval(this.interval);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
startTimer(duration: number) {
|
||||||
|
this.duration = duration;
|
||||||
|
if (this.interval) {
|
||||||
|
clearInterval(this.interval);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.timerStarted = Date.now();
|
||||||
|
this.update();
|
||||||
|
this.interval = setInterval(() => this.update(), 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
private update() {
|
||||||
|
const elapsed = this.timerStarted ? Math.round((Date.now() - (this.timerStarted)) / 1000) : 0; // in seconden
|
||||||
|
let progress = elapsed / (this.duration * 60); // from 0 to 1
|
||||||
|
|
||||||
|
if( progress === 0) {
|
||||||
|
progress = 0.0000001; // otherwise no graph
|
||||||
|
}
|
||||||
|
|
||||||
|
if (progress >= 1 || isNaN(progress)) {
|
||||||
|
if (this.duration === 0) {
|
||||||
|
clearInterval(this.interval);
|
||||||
|
this.timerStarted = null;
|
||||||
|
}
|
||||||
|
else if (progress === 1) {
|
||||||
|
this.endOfTimerChime.play().catch(error => {
|
||||||
|
console.error('Error playing audio:', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
progress = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.renderer.setStyle(
|
||||||
|
document.documentElement,
|
||||||
|
'--progress',
|
||||||
|
progress.toString()
|
||||||
|
);
|
||||||
|
|
||||||
|
this.updateTimeDisplay(this.duration * 60 - elapsed, elapsed, 1 - progress);
|
||||||
|
}
|
||||||
|
|
||||||
|
private updateTimeDisplay(timeLeft: number, elapsed: number, percentage: number) {
|
||||||
|
const theta = 2 * Math.PI * (percentage - 0.25);
|
||||||
|
const circleEndX = 100 + 90 * Math.cos(theta);
|
||||||
|
const circleEndY = 100 + 90 * Math.sin(theta);
|
||||||
|
this.pathD = 'M100 10 A90 90 0 ' + (percentage > 0.5 ? '1' : '0') + ' 1 ' + circleEndX + ' ' + circleEndY;
|
||||||
|
|
||||||
|
const twoNumbers = (n: number) => n < 10 && n >= 0 ? '0' + n.toString() : n.toString();
|
||||||
|
const floorPositiveCeilNegative = (n: number): number => n > 0 ? Math.floor(n) : Math.ceil(n);
|
||||||
|
this.minutesText = twoNumbers(Math.abs(floorPositiveCeilNegative(timeLeft / 60)));
|
||||||
|
this.secondsText = twoNumbers(Math.abs(floorPositiveCeilNegative(timeLeft % 60)));
|
||||||
|
|
||||||
|
this.dashOffset = elapsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
startWhereWeAre() {
|
||||||
|
switch (this.state) {
|
||||||
|
case FocusState.FOCUS:
|
||||||
|
this.focusRuns++;
|
||||||
|
if (this.focusRuns > 3) {
|
||||||
|
this.focusRuns = 0;
|
||||||
|
this.recharge();
|
||||||
|
} else {
|
||||||
|
this.reload();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
this.focus();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stopTimer() {
|
||||||
|
this.focusRuns = 0;
|
||||||
|
this.state = FocusState.STOPPED;
|
||||||
|
this.stopStatsCounter();
|
||||||
|
this.startTimer(0);
|
||||||
|
this.forcedEndOfTimerChime.play().catch(error => {
|
||||||
|
console.error('Error playing audio:', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private stopStatsCounter() {
|
||||||
|
this.focusService.stopCurrent(this.timerStarted !== null);
|
||||||
|
}
|
||||||
|
|
||||||
|
focus() {
|
||||||
|
this.windUpChime.play().catch(error => {
|
||||||
|
console.error('Error playing audio:', error);
|
||||||
|
});
|
||||||
|
this.state = FocusState.FOCUS;
|
||||||
|
this.stopStatsCounter();
|
||||||
|
this.focusService.startFocus();
|
||||||
|
this.startTimer(0.3); // 25
|
||||||
|
}
|
||||||
|
|
||||||
|
reload() {
|
||||||
|
this.windUpChime.play().catch(error => {
|
||||||
|
console.error('Error playing audio:', error);
|
||||||
|
});
|
||||||
|
if (!!this.timerStarted) {
|
||||||
|
this.focusRuns = 0;
|
||||||
|
}
|
||||||
|
this.state = FocusState.SHORT_BREAK;
|
||||||
|
this.stopStatsCounter();
|
||||||
|
this.focusService.startShortBreak();
|
||||||
|
this.startTimer(0.1); // 5
|
||||||
|
}
|
||||||
|
|
||||||
|
recharge() {
|
||||||
|
this.windUpChime.play().catch(error => {
|
||||||
|
console.error('Error playing audio:', error);
|
||||||
|
});
|
||||||
|
if (!!this.timerStarted) {
|
||||||
|
this.focusRuns = 0;
|
||||||
|
}
|
||||||
|
this.state = FocusState.LONG_BREAK;
|
||||||
|
this.stopStatsCounter();
|
||||||
|
this.focusService.startLongBreak();
|
||||||
|
this.startTimer(0.2); // 15
|
||||||
|
}
|
||||||
|
}
|
||||||
40
src/app/pages/modus/focus/focus.service.ts
Normal file
40
src/app/pages/modus/focus/focus.service.ts
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import {FocusStats} from "./focus-stats";
|
||||||
|
import {FocusState} from "./focus-state";
|
||||||
|
import {Injectable} from "@angular/core";
|
||||||
|
import {BehaviorSubject, Observable} from "rxjs";
|
||||||
|
|
||||||
|
@Injectable({ providedIn: 'root',})
|
||||||
|
export class FocusService {
|
||||||
|
current: {state: FocusState, start: Date} = {state: FocusState.STOPPED, start: new Date()};
|
||||||
|
private localStats = new FocusStats();
|
||||||
|
private statsSubject: BehaviorSubject<FocusStats> = new BehaviorSubject<FocusStats>(this.localStats);
|
||||||
|
$stats: Observable<FocusStats> = this.statsSubject.asObservable();
|
||||||
|
|
||||||
|
private startState(state: FocusState) {
|
||||||
|
this.current.state = state;
|
||||||
|
this.current.start = new Date();
|
||||||
|
}
|
||||||
|
|
||||||
|
startFocus(): void {
|
||||||
|
this.startState(FocusState.FOCUS);
|
||||||
|
}
|
||||||
|
|
||||||
|
startShortBreak(): void {
|
||||||
|
this.startState(FocusState.SHORT_BREAK);
|
||||||
|
}
|
||||||
|
|
||||||
|
startLongBreak(): void {
|
||||||
|
this.startState(FocusState.LONG_BREAK);
|
||||||
|
}
|
||||||
|
|
||||||
|
stopCurrent(forced: boolean) {
|
||||||
|
if (!forced) {
|
||||||
|
const deltaInMs = new Date().getTime() - this.current.start.getTime();
|
||||||
|
this.localStats.inc(this.current.state, deltaInMs);
|
||||||
|
this.statsSubject.next(this.localStats);
|
||||||
|
} else {
|
||||||
|
this.localStats.inc(this.current.state);
|
||||||
|
this.statsSubject.next(this.localStats);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
0
src/app/pages/modus/modus-overview.component.css
Normal file
0
src/app/pages/modus/modus-overview.component.css
Normal file
16
src/app/pages/modus/modus-overview.component.html
Normal file
16
src/app/pages/modus/modus-overview.component.html
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<app-tusha-page>
|
||||||
|
<ion-breadcrumbs slot="breadcrumb">
|
||||||
|
<ion-breadcrumb href="tusha/home">
|
||||||
|
<ion-icon slot="start" name="home"/>
|
||||||
|
Home
|
||||||
|
</ion-breadcrumb>
|
||||||
|
<ion-breadcrumb >
|
||||||
|
<ion-icon slot="start" name="aperture"/>
|
||||||
|
Modus
|
||||||
|
</ion-breadcrumb>
|
||||||
|
</ion-breadcrumbs>
|
||||||
|
|
||||||
|
<tusha-status-cards [card1]="card1" [card2]="card2" />
|
||||||
|
|
||||||
|
<tusha-nav-rows [navcards]="navcards" />
|
||||||
|
</app-tusha-page>
|
||||||
61
src/app/pages/modus/modus-overview.component.ts
Normal file
61
src/app/pages/modus/modus-overview.component.ts
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
import {Component} from "@angular/core";
|
||||||
|
import {
|
||||||
|
IonBreadcrumb,
|
||||||
|
IonBreadcrumbs,
|
||||||
|
IonCard,
|
||||||
|
IonCardContent,
|
||||||
|
IonCol,
|
||||||
|
IonIcon,
|
||||||
|
IonRow
|
||||||
|
} from "@ionic/angular/standalone";
|
||||||
|
import {TushaNavRowsComponent} from "../../tusha/tusha-nav-rows/tusha-nav-rows.component";
|
||||||
|
import {TushaPageComponent} from "../../tusha/tusha-page/tusha-page.component";
|
||||||
|
import {NavCardData} from "../../tusha/tusha-nav-rows/nav-card-data";
|
||||||
|
import {Router} from "@angular/router";
|
||||||
|
import {StatusCardsData} from "../../tusha/tusha-status-cards/status-cards-data";
|
||||||
|
import {TushaStatusCardsComponent} from "../../tusha/tusha-status-cards/tusha-status-cards.component";
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
templateUrl: 'modus-overview.component.html',
|
||||||
|
styleUrls: ['modus-overview.component.css'],
|
||||||
|
standalone: true,
|
||||||
|
imports: [IonRow, IonCol, IonCard, IonCardContent, TushaNavRowsComponent, TushaPageComponent, IonBreadcrumb, IonBreadcrumbs, IonIcon, TushaStatusCardsComponent]
|
||||||
|
})
|
||||||
|
export class ModusOverviewPage {
|
||||||
|
navcards: NavCardData[];
|
||||||
|
card1: StatusCardsData;
|
||||||
|
card2: StatusCardsData;
|
||||||
|
|
||||||
|
constructor(public router: Router) {
|
||||||
|
this.navcards = [
|
||||||
|
{id: 1, title: 'Focus', color: {color: 'blue'}, onclick: this.goToFocus.bind(this), icon: 'time-outline'},
|
||||||
|
{id: 2, title: 'Perceive', color: {color: 'purple'}, onclick: this.goToDailyGoals.bind(this), icon: 'leaf-outline'},
|
||||||
|
{id: 3, title: 'Grow', color: {color: 'green'}, onclick: this.goToDailyGoals.bind(this), icon: 'rocket-outline'},
|
||||||
|
{id: 4, title: 'Reflect', color: {color: 'beige'}, onclick: this.goToDailyGoals.bind(this), icon: 'speedometer-outline'},
|
||||||
|
{id: 5, title: 'Love', color: {color: 'red'}, onclick: this.goToDailyGoals.bind(this), icon: 'heart-outline'},
|
||||||
|
];
|
||||||
|
this.card1 = {
|
||||||
|
id: 1,
|
||||||
|
color: {color: 'blue'},
|
||||||
|
type: 'number',
|
||||||
|
amount: 3,
|
||||||
|
description: 'Focus sessions'
|
||||||
|
};
|
||||||
|
this.card2 = {
|
||||||
|
id: 2,
|
||||||
|
color: {color: 'orange'},
|
||||||
|
type: 'number',
|
||||||
|
amount: 4,
|
||||||
|
description: 'Modus types'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
goToDailyGoals() {
|
||||||
|
this.router.navigate(['folder/daily']);
|
||||||
|
}
|
||||||
|
|
||||||
|
goToFocus() {
|
||||||
|
this.router.navigate(['tusha/modus/focus']);
|
||||||
|
}
|
||||||
|
}
|
||||||
3
src/app/tusha/tusha-nav-card/card-color.ts
Normal file
3
src/app/tusha/tusha-nav-card/card-color.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export interface CardColor {
|
||||||
|
color: '' | 'blue' | 'green' | 'orange' | 'black' | 'purple' | 'beige' | 'red';
|
||||||
|
}
|
||||||
115
src/app/tusha/tusha-nav-card/tusha-nav-card.component.css
Normal file
115
src/app/tusha/tusha-nav-card/tusha-nav-card.component.css
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
ion-card {
|
||||||
|
margin: 0 0 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-grid.innergrid {
|
||||||
|
margin: 0 0 0 0;
|
||||||
|
padding: 0 0 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-grid.innergrid ion-row {
|
||||||
|
margin: 0 0 0 0;
|
||||||
|
padding: 0 0 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-grid.innergrid ion-row ion-col {
|
||||||
|
margin: 0 0 0 0;
|
||||||
|
padding: 0 0 0 0;
|
||||||
|
}
|
||||||
|
.navcard {
|
||||||
|
margin-bottom: 0;
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navcard.daily {
|
||||||
|
background-color: lightcyan;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navcard.daily :active {
|
||||||
|
background-color: cyan;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navcard.weekly {
|
||||||
|
background-color: mistyrose;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navcard.weekly :active {
|
||||||
|
background-color: rosybrown;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navcard.quarterly {
|
||||||
|
background-color: bisque;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navcard.quarterly :active {
|
||||||
|
background-color: burlywood;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navcard.modus {
|
||||||
|
background-color: lightgoldenrodyellow;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navcard.modus :active {
|
||||||
|
background-color: gold;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.navcard.blue {
|
||||||
|
background-color: #dbeeff;
|
||||||
|
}
|
||||||
|
.navcard.blue :active {
|
||||||
|
background-color: #2898ff;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.navcard.green {
|
||||||
|
background-color: #cafae7;
|
||||||
|
}
|
||||||
|
.navcard.green :active {
|
||||||
|
background-color: #33a86a;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.navcard.orange {
|
||||||
|
background-color: #ffbaa0;
|
||||||
|
}
|
||||||
|
.navcard.orange :active {
|
||||||
|
background-color: #ff5b1a;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.navcard.black {
|
||||||
|
background-color: #2f2f2f;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.navcard.black :active {
|
||||||
|
background-color: #e1e1e1;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navcard.purple {
|
||||||
|
background-color: #794279;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navcard.purple :active {
|
||||||
|
background-color: #f3adf3;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navcard.beige {
|
||||||
|
background-color: #ecbb9e;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navcard.beige :active {
|
||||||
|
background-color: #735b4c;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navcard.red {
|
||||||
|
background-color: #770101;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navcard.red :active {
|
||||||
|
background-color: #d5b2b2;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
18
src/app/tusha/tusha-nav-card/tusha-nav-card.component.html
Normal file
18
src/app/tusha/tusha-nav-card/tusha-nav-card.component.html
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
|
||||||
|
<ion-card (click)="onClick()" class="navcard {{ color().color }}">
|
||||||
|
<ion-card-content>
|
||||||
|
<ion-grid class="innergrid">
|
||||||
|
<ion-row>
|
||||||
|
<ion-col size="1.5">
|
||||||
|
<ng-content />
|
||||||
|
</ion-col>
|
||||||
|
<ion-col size="9.5">
|
||||||
|
<p>{{ title() }}</p>
|
||||||
|
</ion-col>
|
||||||
|
<ion-col size="1">
|
||||||
|
<ion-icon name="caret-forward"></ion-icon>
|
||||||
|
</ion-col>
|
||||||
|
</ion-row>
|
||||||
|
</ion-grid>
|
||||||
|
</ion-card-content>
|
||||||
|
</ion-card>
|
||||||
28
src/app/tusha/tusha-nav-card/tusha-nav-card.component.ts
Normal file
28
src/app/tusha/tusha-nav-card/tusha-nav-card.component.ts
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import {Component, input, InputSignal, output} from "@angular/core";
|
||||||
|
import {Router} from "@angular/router";
|
||||||
|
import {
|
||||||
|
IonCard, IonCardContent, IonCol,IonGrid, IonIcon, IonRow,
|
||||||
|
} from "@ionic/angular/standalone";
|
||||||
|
import {CardColor} from "./card-color";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'tusha-nav-card',
|
||||||
|
templateUrl: 'tusha-nav-card.component.html',
|
||||||
|
styleUrls: ['tusha-nav-card.component.css'],
|
||||||
|
standalone: true,
|
||||||
|
imports: [ IonIcon, IonCard, IonCardContent, IonGrid, IonRow, IonCol],
|
||||||
|
styles: []
|
||||||
|
})
|
||||||
|
export class TushaNavCardComponent {
|
||||||
|
title = input.required<String>();
|
||||||
|
color: InputSignal<CardColor> = input<CardColor>({color: ''});
|
||||||
|
|
||||||
|
click = output<void>();
|
||||||
|
|
||||||
|
constructor(public router: Router) {
|
||||||
|
}
|
||||||
|
|
||||||
|
onClick() {
|
||||||
|
this.click.emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
9
src/app/tusha/tusha-nav-rows/nav-card-data.ts
Normal file
9
src/app/tusha/tusha-nav-rows/nav-card-data.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import {CardColor} from "../tusha-nav-card/card-color";
|
||||||
|
|
||||||
|
export interface NavCardData {
|
||||||
|
id: number;
|
||||||
|
title: string;
|
||||||
|
color: CardColor;
|
||||||
|
icon: string;
|
||||||
|
onclick: () => void;
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
@for (navcard of navcards(); track navcard.id) {
|
||||||
|
<ion-row>
|
||||||
|
<ion-col size="12">
|
||||||
|
<tusha-nav-card [title]="navcard.title" [color]="navcard.color" (click)="navcard.onclick()">
|
||||||
|
<ion-icon [name]="navcard.icon"></ion-icon>
|
||||||
|
</tusha-nav-card>
|
||||||
|
</ion-col>
|
||||||
|
</ion-row>
|
||||||
|
}
|
||||||
22
src/app/tusha/tusha-nav-rows/tusha-nav-rows.component.ts
Normal file
22
src/app/tusha/tusha-nav-rows/tusha-nav-rows.component.ts
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import {Component, input, Input} from "@angular/core";
|
||||||
|
import {IonCol, IonGrid, IonIcon, IonRow,
|
||||||
|
} from "@ionic/angular/standalone";
|
||||||
|
import {NavCardData} from "./nav-card-data";
|
||||||
|
import {TushaNavCardComponent} from "../tusha-nav-card/tusha-nav-card.component";
|
||||||
|
import {Route, Router} from "@angular/router";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'tusha-nav-rows',
|
||||||
|
templateUrl: 'tusha-nav-rows.component.html',
|
||||||
|
styleUrls: ['tusha-nav-rows.component.css'],
|
||||||
|
standalone: true,
|
||||||
|
imports: [IonIcon, IonGrid, IonRow, IonCol, TushaNavCardComponent],
|
||||||
|
styles: []
|
||||||
|
})
|
||||||
|
export class TushaNavRowsComponent {
|
||||||
|
navcards = input<NavCardData[]>([]);
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
22
src/app/tusha/tusha-page/tusha-page.component.css
Normal file
22
src/app/tusha/tusha-page/tusha-page.component.css
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
ion-grid {
|
||||||
|
max-width: 280px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-grid .backpane {
|
||||||
|
background-color: rgb(249, 239, 214);
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-grid.innergrid {
|
||||||
|
margin: 0 0 0 0;
|
||||||
|
padding: 0 0 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-grid.innergrid ion-row {
|
||||||
|
margin: 0 0 0 0;
|
||||||
|
padding: 0 0 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-grid.innergrid ion-row ion-col {
|
||||||
|
margin: 0 0 0 0;
|
||||||
|
padding: 0 0 0 0;
|
||||||
|
}
|
||||||
19
src/app/tusha/tusha-page/tusha-page.component.html
Normal file
19
src/app/tusha/tusha-page/tusha-page.component.html
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<ion-header [translucent]="true">
|
||||||
|
<ion-toolbar>
|
||||||
|
<ion-buttons slot="start">
|
||||||
|
<ion-menu-button></ion-menu-button>
|
||||||
|
</ion-buttons>
|
||||||
|
<ion-title>{{ 'Tusha - Home' }}</ion-title>
|
||||||
|
</ion-toolbar>
|
||||||
|
</ion-header>
|
||||||
|
|
||||||
|
<ng-content select="[slot=breadcrumb]"></ng-content>
|
||||||
|
<ion-grid class="backpane">
|
||||||
|
<ng-content />
|
||||||
|
|
||||||
|
</ion-grid>
|
||||||
|
<ion-footer>
|
||||||
|
<ion-toolbar>
|
||||||
|
<ion-title>{{ 'Tusha - The Ultimate SelfHelp App - By AgileCC' }}</ion-title>
|
||||||
|
</ion-toolbar>
|
||||||
|
</ion-footer>
|
||||||
18
src/app/tusha/tusha-page/tusha-page.component.ts
Normal file
18
src/app/tusha/tusha-page/tusha-page.component.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import {Component} from "@angular/core";
|
||||||
|
import {
|
||||||
|
IonBreadcrumb, IonBreadcrumbs,
|
||||||
|
IonButtons, IonFooter, IonGrid, IonHeader, IonIcon, IonMenuButton, IonTitle, IonToolbar
|
||||||
|
} from "@ionic/angular/standalone";
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-tusha-page',
|
||||||
|
templateUrl: 'tusha-page.component.html',
|
||||||
|
styleUrls: ['tusha-page.component.css'],
|
||||||
|
standalone: true,
|
||||||
|
imports: [IonGrid, IonTitle, IonToolbar, IonFooter, IonMenuButton, IonButtons, IonHeader, IonBreadcrumb, IonBreadcrumbs, IonIcon],
|
||||||
|
styles: []
|
||||||
|
})
|
||||||
|
export class TushaPageComponent {
|
||||||
|
|
||||||
|
}
|
||||||
9
src/app/tusha/tusha-status-cards/status-cards-data.ts
Normal file
9
src/app/tusha/tusha-status-cards/status-cards-data.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import {CardColor} from "../tusha-nav-card/card-color";
|
||||||
|
|
||||||
|
export interface StatusCardsData {
|
||||||
|
id: number,
|
||||||
|
color: CardColor,
|
||||||
|
type: "number" | "percentage",
|
||||||
|
amount: number,
|
||||||
|
description: string
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
ion-card {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scorecard {
|
||||||
|
width: 7rem;
|
||||||
|
height: 7rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scorecard .content {
|
||||||
|
display: flex;
|
||||||
|
height: 100%;
|
||||||
|
justify-content: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
padding: 1rem 0.2rem 1rem 0.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scorecard .number {
|
||||||
|
color: black;
|
||||||
|
height: 4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scoreboard .number, .large {
|
||||||
|
font-size: 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scoreboard .number, .medium {
|
||||||
|
font-size: 2.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scorecard.orange {
|
||||||
|
background-color: lightsalmon;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scorecard.green {
|
||||||
|
background-color: lightgreen;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scorecard.blue {
|
||||||
|
background-color: #2898ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scorecard .description {
|
||||||
|
color: black;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
<ion-row>
|
||||||
|
<ion-col size="6">
|
||||||
|
<ion-card class={{card1_container_css}} id=`tusha-card-${card1().id}`>
|
||||||
|
<ion-card-content class="content">
|
||||||
|
<p class={{card1_number_css}}>{{ card1_number }}</p>
|
||||||
|
<p class="description">{{ card1().description }}</p>
|
||||||
|
</ion-card-content>
|
||||||
|
</ion-card>
|
||||||
|
</ion-col>
|
||||||
|
<ion-col size="6">
|
||||||
|
<ion-card class={{card2_container_css}} id=`tusha-card-${card2().id}`>
|
||||||
|
<ion-card-content class="content">
|
||||||
|
<p class={{card2_number_css}}>{{ card2_number }}</p>
|
||||||
|
<p class="description">{{ card2().description }}</p>
|
||||||
|
</ion-card-content>
|
||||||
|
</ion-card>
|
||||||
|
</ion-col>
|
||||||
|
</ion-row>
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
import {Component, input, InputSignal, OnInit} from "@angular/core";
|
||||||
|
import {StatusCardsData} from "./status-cards-data";
|
||||||
|
import {IonCard, IonCardContent, IonCol, IonRow} from "@ionic/angular/standalone";
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: "tusha-status-cards",
|
||||||
|
templateUrl: "tusha-status-cards.component.html",
|
||||||
|
styleUrls: ["tusha-status-cards.component.css"],
|
||||||
|
standalone: true,
|
||||||
|
imports: [IonRow, IonCol, IonCard, IonCardContent]
|
||||||
|
})
|
||||||
|
export class TushaStatusCardsComponent implements OnInit {
|
||||||
|
card1: InputSignal<StatusCardsData> = input.required<StatusCardsData>();
|
||||||
|
card2: InputSignal<StatusCardsData> = input.required<StatusCardsData>();
|
||||||
|
card1_number_css: string = '';
|
||||||
|
card2_number_css: string = '';
|
||||||
|
card1_container_css: string = '';
|
||||||
|
card2_container_css: string = '';
|
||||||
|
card1_number: string = '';
|
||||||
|
card2_number: string = '';
|
||||||
|
|
||||||
|
getSuffix(statusCard: StatusCardsData): string {
|
||||||
|
console.log(statusCard);
|
||||||
|
if (statusCard.type === 'percentage') {
|
||||||
|
return '%';
|
||||||
|
} else {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getSizeClass(statusCard: StatusCardsData): string {
|
||||||
|
if (statusCard.type === 'percentage') {
|
||||||
|
return 'medium';
|
||||||
|
} else {
|
||||||
|
return 'large';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
function initCard(statusCardsData: StatusCardsData): { css_number: string, css_container: string, number: string } {
|
||||||
|
if (statusCardsData.type === 'percentage') {
|
||||||
|
return {
|
||||||
|
css_container: 'scorecard ' + statusCardsData.color.color,
|
||||||
|
css_number: 'number medium',
|
||||||
|
number: statusCardsData.amount + ' %'
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
css_container: 'scorecard ' + statusCardsData.color.color,
|
||||||
|
css_number: 'number large',
|
||||||
|
number: statusCardsData.amount + ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const values1 = initCard(this.card1());
|
||||||
|
this.card1_container_css = values1.css_container;
|
||||||
|
this.card1_number_css = values1.css_number;
|
||||||
|
this.card1_number = values1.number;
|
||||||
|
|
||||||
|
const values2 = initCard(this.card2());
|
||||||
|
this.card2_container_css = values2.css_container;
|
||||||
|
this.card2_number_css = values2.css_number;
|
||||||
|
this.card2_number = values2.number;
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
src/assets/hardstop.mp3
Normal file
BIN
src/assets/hardstop.mp3
Normal file
Binary file not shown.
BIN
src/assets/icon/favicon.png
Normal file
BIN
src/assets/icon/favicon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 930 B |
BIN
src/assets/race-start-beeps-125125.mp3
Normal file
BIN
src/assets/race-start-beeps-125125.mp3
Normal file
Binary file not shown.
1
src/assets/shapes.svg
Normal file
1
src/assets/shapes.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg width="350" height="140" xmlns="http://www.w3.org/2000/svg" style="background:#f6f7f9"><g fill="none" fill-rule="evenodd"><path fill="#F04141" style="mix-blend-mode:multiply" d="M61.905-34.23l96.194 54.51-66.982 54.512L22 34.887z"/><circle fill="#10DC60" style="mix-blend-mode:multiply" cx="155.5" cy="135.5" r="57.5"/><path fill="#3880FF" style="mix-blend-mode:multiply" d="M208.538 9.513l84.417 15.392L223.93 93.93z"/><path fill="#FFCE00" style="mix-blend-mode:multiply" d="M268.625 106.557l46.332-26.75 46.332 26.75v53.5l-46.332 26.75-46.332-26.75z"/><circle fill="#7044FF" style="mix-blend-mode:multiply" cx="299.5" cy="9.5" r="38.5"/><rect fill="#11D3EA" style="mix-blend-mode:multiply" transform="rotate(-60 148.47 37.886)" x="143.372" y="-7.056" width="10.196" height="89.884" rx="5.098"/><path d="M-25.389 74.253l84.86 8.107c5.498.525 9.53 5.407 9.004 10.905a10 10 0 0 1-.057.477l-12.36 85.671a10.002 10.002 0 0 1-11.634 8.42l-86.351-15.226c-5.44-.959-9.07-6.145-8.112-11.584l13.851-78.551a10 10 0 0 1 10.799-8.219z" fill="#7044FF" style="mix-blend-mode:multiply"/><circle fill="#0CD1E8" style="mix-blend-mode:multiply" cx="273.5" cy="106.5" r="20.5"/></g></svg>
|
||||||
|
After Width: | Height: | Size: 1.1 KiB |
BIN
src/assets/wind-up.mp3
Normal file
BIN
src/assets/wind-up.mp3
Normal file
Binary file not shown.
3
src/environments/environment.prod.ts
Normal file
3
src/environments/environment.prod.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export const environment = {
|
||||||
|
production: true
|
||||||
|
};
|
||||||
16
src/environments/environment.ts
Normal file
16
src/environments/environment.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
// This file can be replaced during build by using the `fileReplacements` array.
|
||||||
|
// `ng build` replaces `environment.ts` with `environment.prod.ts`.
|
||||||
|
// The list of file replacements can be found in `angular.json`.
|
||||||
|
|
||||||
|
export const environment = {
|
||||||
|
production: false
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For easier debugging in development mode, you can import the following file
|
||||||
|
* to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.
|
||||||
|
*
|
||||||
|
* This import should be commented out in production mode because it will have a negative impact
|
||||||
|
* on performance if an error is thrown.
|
||||||
|
*/
|
||||||
|
// import 'zone.js/plugins/zone-error'; // Included with Angular CLI.
|
||||||
26
src/global.scss
Normal file
26
src/global.scss
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* App Global CSS
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
* Put style rules here that you want to apply globally. These styles are for
|
||||||
|
* the entire app and not just one component. Additionally, this file can be
|
||||||
|
* used as an entry point to import other CSS/Sass files to be included in the
|
||||||
|
* output CSS.
|
||||||
|
* For more information on global stylesheets, visit the documentation:
|
||||||
|
* https://ionicframework.com/docs/layout/global-stylesheets
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Core CSS required for Ionic components to work properly */
|
||||||
|
@import "@ionic/angular/css/core.css";
|
||||||
|
|
||||||
|
/* Basic CSS for apps built with Ionic */
|
||||||
|
@import "@ionic/angular/css/normalize.css";
|
||||||
|
@import "@ionic/angular/css/structure.css";
|
||||||
|
@import "@ionic/angular/css/typography.css";
|
||||||
|
@import "@ionic/angular/css/display.css";
|
||||||
|
|
||||||
|
/* Optional CSS utils that can be commented out */
|
||||||
|
@import "@ionic/angular/css/padding.css";
|
||||||
|
@import "@ionic/angular/css/float-elements.css";
|
||||||
|
@import "@ionic/angular/css/text-alignment.css";
|
||||||
|
@import "@ionic/angular/css/text-transformation.css";
|
||||||
|
@import "@ionic/angular/css/flex-utils.css";
|
||||||
29
src/index.html
Normal file
29
src/index.html
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title>Ionic App</title>
|
||||||
|
|
||||||
|
<base href="/" />
|
||||||
|
|
||||||
|
<meta name="color-scheme" content="light dark" />
|
||||||
|
<meta name="viewport" content="viewport-fit=cover, width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||||
|
<meta name="format-detection" content="telephone=no" />
|
||||||
|
<meta name="msapplication-tap-highlight" content="no" />
|
||||||
|
|
||||||
|
<link rel="icon" type="image/png" href="assets/icon/favicon.png" />
|
||||||
|
|
||||||
|
<!-- add to homescreen for ios -->
|
||||||
|
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||||
|
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
|
||||||
|
|
||||||
|
<script type="module" src="https://unpkg.com/ionicons@5.0.0/dist/ionicons/ionicons.esm.js"></script>
|
||||||
|
<script nomodule="" src="https://unpkg.com/ionicons@5.0.0/dist/ionicons/ionicons.js"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<app-root></app-root>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
20
src/main.ts
Normal file
20
src/main.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import { enableProdMode } from '@angular/core';
|
||||||
|
import { bootstrapApplication } from '@angular/platform-browser';
|
||||||
|
import { RouteReuseStrategy, provideRouter } from '@angular/router';
|
||||||
|
import { IonicRouteStrategy, provideIonicAngular } from '@ionic/angular/standalone';
|
||||||
|
|
||||||
|
import { routes } from './app/app.routes';
|
||||||
|
import { AppComponent } from './app/app.component';
|
||||||
|
import { environment } from './environments/environment';
|
||||||
|
|
||||||
|
if (environment.production) {
|
||||||
|
enableProdMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
bootstrapApplication(AppComponent, {
|
||||||
|
providers: [
|
||||||
|
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
|
||||||
|
provideIonicAngular(),
|
||||||
|
provideRouter(routes),
|
||||||
|
],
|
||||||
|
});
|
||||||
55
src/polyfills.ts
Normal file
55
src/polyfills.ts
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
/**
|
||||||
|
* This file includes polyfills needed by Angular and is loaded before the app.
|
||||||
|
* You can add your own extra polyfills to this file.
|
||||||
|
*
|
||||||
|
* This file is divided into 2 sections:
|
||||||
|
* 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
|
||||||
|
* 2. Application imports. Files imported after ZoneJS that should be loaded before your main
|
||||||
|
* file.
|
||||||
|
*
|
||||||
|
* The current setup is for so-called "evergreen" browsers; the last versions of browsers that
|
||||||
|
* automatically update themselves. This includes recent versions of Safari, Chrome (including
|
||||||
|
* Opera), Edge on the desktop, and iOS and Chrome on mobile.
|
||||||
|
*
|
||||||
|
* Learn more in https://angular.io/guide/browser-support
|
||||||
|
*/
|
||||||
|
|
||||||
|
/***************************************************************************************************
|
||||||
|
* BROWSER POLYFILLS
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* By default, zone.js will patch all possible macroTask and DomEvents
|
||||||
|
* user can disable parts of macroTask/DomEvents patch by setting following flags
|
||||||
|
* because those flags need to be set before `zone.js` being loaded, and webpack
|
||||||
|
* will put import in the top of bundle, so user need to create a separate file
|
||||||
|
* in this directory (for example: zone-flags.ts), and put the following flags
|
||||||
|
* into that file, and then add the following code before importing zone.js.
|
||||||
|
* import './zone-flags';
|
||||||
|
*
|
||||||
|
* The flags allowed in zone-flags.ts are listed here.
|
||||||
|
*
|
||||||
|
* The following flags will work for all browsers.
|
||||||
|
*
|
||||||
|
* (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
|
||||||
|
* (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
|
||||||
|
* (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
|
||||||
|
*
|
||||||
|
* in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
|
||||||
|
* with the following flag, it will bypass `zone.js` patch for IE/Edge
|
||||||
|
*
|
||||||
|
* (window as any).__Zone_enable_cross_context_check = true;
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
import './zone-flags';
|
||||||
|
|
||||||
|
/***************************************************************************************************
|
||||||
|
* Zone JS is required by default for Angular itself.
|
||||||
|
*/
|
||||||
|
import 'zone.js'; // Included with Angular CLI.
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************************************
|
||||||
|
* APPLICATION IMPORTS
|
||||||
|
*/
|
||||||
14
src/test.ts
Normal file
14
src/test.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
||||||
|
|
||||||
|
import 'zone.js/testing';
|
||||||
|
import { getTestBed } from '@angular/core/testing';
|
||||||
|
import {
|
||||||
|
BrowserDynamicTestingModule,
|
||||||
|
platformBrowserDynamicTesting
|
||||||
|
} from '@angular/platform-browser-dynamic/testing';
|
||||||
|
|
||||||
|
// First, initialize the Angular testing environment.
|
||||||
|
getTestBed().initTestEnvironment(
|
||||||
|
BrowserDynamicTestingModule,
|
||||||
|
platformBrowserDynamicTesting(),
|
||||||
|
);
|
||||||
244
src/theme/variables.scss
Normal file
244
src/theme/variables.scss
Normal file
@@ -0,0 +1,244 @@
|
|||||||
|
// Ionic Variables and Theming. For more info, please see:
|
||||||
|
// http://ionicframework.com/docs/theming/
|
||||||
|
|
||||||
|
/** Ionic CSS Variables **/
|
||||||
|
:root {
|
||||||
|
/** primary **/
|
||||||
|
--ion-color-primary: #3880ff;
|
||||||
|
--ion-color-primary-rgb: 56, 128, 255;
|
||||||
|
--ion-color-primary-contrast: #ffffff;
|
||||||
|
--ion-color-primary-contrast-rgb: 255, 255, 255;
|
||||||
|
--ion-color-primary-shade: #3171e0;
|
||||||
|
--ion-color-primary-tint: #4c8dff;
|
||||||
|
|
||||||
|
/** secondary **/
|
||||||
|
--ion-color-secondary: #3dc2ff;
|
||||||
|
--ion-color-secondary-rgb: 61, 194, 255;
|
||||||
|
--ion-color-secondary-contrast: #ffffff;
|
||||||
|
--ion-color-secondary-contrast-rgb: 255, 255, 255;
|
||||||
|
--ion-color-secondary-shade: #36abe0;
|
||||||
|
--ion-color-secondary-tint: #50c8ff;
|
||||||
|
|
||||||
|
/** tertiary **/
|
||||||
|
--ion-color-tertiary: #5260ff;
|
||||||
|
--ion-color-tertiary-rgb: 82, 96, 255;
|
||||||
|
--ion-color-tertiary-contrast: #ffffff;
|
||||||
|
--ion-color-tertiary-contrast-rgb: 255, 255, 255;
|
||||||
|
--ion-color-tertiary-shade: #4854e0;
|
||||||
|
--ion-color-tertiary-tint: #6370ff;
|
||||||
|
|
||||||
|
/** success **/
|
||||||
|
--ion-color-success: #2dd36f;
|
||||||
|
--ion-color-success-rgb: 45, 211, 111;
|
||||||
|
--ion-color-success-contrast: #ffffff;
|
||||||
|
--ion-color-success-contrast-rgb: 255, 255, 255;
|
||||||
|
--ion-color-success-shade: #28ba62;
|
||||||
|
--ion-color-success-tint: #42d77d;
|
||||||
|
|
||||||
|
/** warning **/
|
||||||
|
--ion-color-warning: #ffc409;
|
||||||
|
--ion-color-warning-rgb: 255, 196, 9;
|
||||||
|
--ion-color-warning-contrast: #000000;
|
||||||
|
--ion-color-warning-contrast-rgb: 0, 0, 0;
|
||||||
|
--ion-color-warning-shade: #e0ac08;
|
||||||
|
--ion-color-warning-tint: #ffca22;
|
||||||
|
|
||||||
|
/** danger **/
|
||||||
|
--ion-color-danger: #eb445a;
|
||||||
|
--ion-color-danger-rgb: 235, 68, 90;
|
||||||
|
--ion-color-danger-contrast: #ffffff;
|
||||||
|
--ion-color-danger-contrast-rgb: 255, 255, 255;
|
||||||
|
--ion-color-danger-shade: #cf3c4f;
|
||||||
|
--ion-color-danger-tint: #ed576b;
|
||||||
|
|
||||||
|
/** dark **/
|
||||||
|
--ion-color-dark: #222428;
|
||||||
|
--ion-color-dark-rgb: 34, 36, 40;
|
||||||
|
--ion-color-dark-contrast: #ffffff;
|
||||||
|
--ion-color-dark-contrast-rgb: 255, 255, 255;
|
||||||
|
--ion-color-dark-shade: #1e2023;
|
||||||
|
--ion-color-dark-tint: #383a3e;
|
||||||
|
|
||||||
|
/** medium **/
|
||||||
|
--ion-color-medium: #92949c;
|
||||||
|
--ion-color-medium-rgb: 146, 148, 156;
|
||||||
|
--ion-color-medium-contrast: #ffffff;
|
||||||
|
--ion-color-medium-contrast-rgb: 255, 255, 255;
|
||||||
|
--ion-color-medium-shade: #808289;
|
||||||
|
--ion-color-medium-tint: #9d9fa6;
|
||||||
|
|
||||||
|
/** light **/
|
||||||
|
--ion-color-light: #f4f5f8;
|
||||||
|
--ion-color-light-rgb: 244, 245, 248;
|
||||||
|
--ion-color-light-contrast: #000000;
|
||||||
|
--ion-color-light-contrast-rgb: 0, 0, 0;
|
||||||
|
--ion-color-light-shade: #d7d8da;
|
||||||
|
--ion-color-light-tint: #f5f6f9;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
/*
|
||||||
|
* Dark Colors
|
||||||
|
* -------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
body {
|
||||||
|
--ion-color-primary: #428cff;
|
||||||
|
--ion-color-primary-rgb: 66,140,255;
|
||||||
|
--ion-color-primary-contrast: #ffffff;
|
||||||
|
--ion-color-primary-contrast-rgb: 255,255,255;
|
||||||
|
--ion-color-primary-shade: #3a7be0;
|
||||||
|
--ion-color-primary-tint: #5598ff;
|
||||||
|
|
||||||
|
--ion-color-secondary: #50c8ff;
|
||||||
|
--ion-color-secondary-rgb: 80,200,255;
|
||||||
|
--ion-color-secondary-contrast: #ffffff;
|
||||||
|
--ion-color-secondary-contrast-rgb: 255,255,255;
|
||||||
|
--ion-color-secondary-shade: #46b0e0;
|
||||||
|
--ion-color-secondary-tint: #62ceff;
|
||||||
|
|
||||||
|
--ion-color-tertiary: #6a64ff;
|
||||||
|
--ion-color-tertiary-rgb: 106,100,255;
|
||||||
|
--ion-color-tertiary-contrast: #ffffff;
|
||||||
|
--ion-color-tertiary-contrast-rgb: 255,255,255;
|
||||||
|
--ion-color-tertiary-shade: #5d58e0;
|
||||||
|
--ion-color-tertiary-tint: #7974ff;
|
||||||
|
|
||||||
|
--ion-color-success: #2fdf75;
|
||||||
|
--ion-color-success-rgb: 47,223,117;
|
||||||
|
--ion-color-success-contrast: #000000;
|
||||||
|
--ion-color-success-contrast-rgb: 0,0,0;
|
||||||
|
--ion-color-success-shade: #29c467;
|
||||||
|
--ion-color-success-tint: #44e283;
|
||||||
|
|
||||||
|
--ion-color-warning: #ffd534;
|
||||||
|
--ion-color-warning-rgb: 255,213,52;
|
||||||
|
--ion-color-warning-contrast: #000000;
|
||||||
|
--ion-color-warning-contrast-rgb: 0,0,0;
|
||||||
|
--ion-color-warning-shade: #e0bb2e;
|
||||||
|
--ion-color-warning-tint: #ffd948;
|
||||||
|
|
||||||
|
--ion-color-danger: #ff4961;
|
||||||
|
--ion-color-danger-rgb: 255,73,97;
|
||||||
|
--ion-color-danger-contrast: #ffffff;
|
||||||
|
--ion-color-danger-contrast-rgb: 255,255,255;
|
||||||
|
--ion-color-danger-shade: #e04055;
|
||||||
|
--ion-color-danger-tint: #ff5b71;
|
||||||
|
|
||||||
|
--ion-color-dark: #f4f5f8;
|
||||||
|
--ion-color-dark-rgb: 244,245,248;
|
||||||
|
--ion-color-dark-contrast: #000000;
|
||||||
|
--ion-color-dark-contrast-rgb: 0,0,0;
|
||||||
|
--ion-color-dark-shade: #d7d8da;
|
||||||
|
--ion-color-dark-tint: #f5f6f9;
|
||||||
|
|
||||||
|
--ion-color-medium: #989aa2;
|
||||||
|
--ion-color-medium-rgb: 152,154,162;
|
||||||
|
--ion-color-medium-contrast: #000000;
|
||||||
|
--ion-color-medium-contrast-rgb: 0,0,0;
|
||||||
|
--ion-color-medium-shade: #86888f;
|
||||||
|
--ion-color-medium-tint: #a2a4ab;
|
||||||
|
|
||||||
|
--ion-color-light: #222428;
|
||||||
|
--ion-color-light-rgb: 34,36,40;
|
||||||
|
--ion-color-light-contrast: #ffffff;
|
||||||
|
--ion-color-light-contrast-rgb: 255,255,255;
|
||||||
|
--ion-color-light-shade: #1e2023;
|
||||||
|
--ion-color-light-tint: #383a3e;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* iOS Dark Theme
|
||||||
|
* -------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
.ios body {
|
||||||
|
--ion-background-color: #000000;
|
||||||
|
--ion-background-color-rgb: 0,0,0;
|
||||||
|
|
||||||
|
--ion-text-color: #ffffff;
|
||||||
|
--ion-text-color-rgb: 255,255,255;
|
||||||
|
|
||||||
|
--ion-color-step-50: #0d0d0d;
|
||||||
|
--ion-color-step-100: #1a1a1a;
|
||||||
|
--ion-color-step-150: #262626;
|
||||||
|
--ion-color-step-200: #333333;
|
||||||
|
--ion-color-step-250: #404040;
|
||||||
|
--ion-color-step-300: #4d4d4d;
|
||||||
|
--ion-color-step-350: #595959;
|
||||||
|
--ion-color-step-400: #666666;
|
||||||
|
--ion-color-step-450: #737373;
|
||||||
|
--ion-color-step-500: #808080;
|
||||||
|
--ion-color-step-550: #8c8c8c;
|
||||||
|
--ion-color-step-600: #999999;
|
||||||
|
--ion-color-step-650: #a6a6a6;
|
||||||
|
--ion-color-step-700: #b3b3b3;
|
||||||
|
--ion-color-step-750: #bfbfbf;
|
||||||
|
--ion-color-step-800: #cccccc;
|
||||||
|
--ion-color-step-850: #d9d9d9;
|
||||||
|
--ion-color-step-900: #e6e6e6;
|
||||||
|
--ion-color-step-950: #f2f2f2;
|
||||||
|
|
||||||
|
--ion-item-background: #000000;
|
||||||
|
|
||||||
|
--ion-card-background: #1c1c1d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ios ion-modal {
|
||||||
|
--ion-background-color: var(--ion-color-step-100);
|
||||||
|
--ion-toolbar-background: var(--ion-color-step-150);
|
||||||
|
--ion-toolbar-border-color: var(--ion-color-step-250);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Material Design Dark Theme
|
||||||
|
* -------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
.md body {
|
||||||
|
--ion-background-color: #121212;
|
||||||
|
--ion-background-color-rgb: 18,18,18;
|
||||||
|
|
||||||
|
--ion-text-color: #ffffff;
|
||||||
|
--ion-text-color-rgb: 255,255,255;
|
||||||
|
|
||||||
|
--ion-border-color: #222222;
|
||||||
|
|
||||||
|
--ion-color-step-50: #1e1e1e;
|
||||||
|
--ion-color-step-100: #2a2a2a;
|
||||||
|
--ion-color-step-150: #363636;
|
||||||
|
--ion-color-step-200: #414141;
|
||||||
|
--ion-color-step-250: #4d4d4d;
|
||||||
|
--ion-color-step-300: #595959;
|
||||||
|
--ion-color-step-350: #656565;
|
||||||
|
--ion-color-step-400: #717171;
|
||||||
|
--ion-color-step-450: #7d7d7d;
|
||||||
|
--ion-color-step-500: #898989;
|
||||||
|
--ion-color-step-550: #949494;
|
||||||
|
--ion-color-step-600: #a0a0a0;
|
||||||
|
--ion-color-step-650: #acacac;
|
||||||
|
--ion-color-step-700: #b8b8b8;
|
||||||
|
--ion-color-step-750: #c4c4c4;
|
||||||
|
--ion-color-step-800: #d0d0d0;
|
||||||
|
--ion-color-step-850: #dbdbdb;
|
||||||
|
--ion-color-step-900: #e7e7e7;
|
||||||
|
--ion-color-step-950: #f3f3f3;
|
||||||
|
|
||||||
|
--ion-item-background: #1e1e1e;
|
||||||
|
|
||||||
|
--ion-toolbar-background: #1f1f1f;
|
||||||
|
|
||||||
|
--ion-tab-bar-background: #1f1f1f;
|
||||||
|
|
||||||
|
--ion-card-background: #1e1e1e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
/*
|
||||||
|
* For more information on dynamic font scaling, visit the documentation:
|
||||||
|
* https://ionicframework.com/docs/layout/dynamic-font-scaling
|
||||||
|
*/
|
||||||
|
--ion-dynamic-font: var(--ion-default-dynamic-font);
|
||||||
|
}
|
||||||
6
src/zone-flags.ts
Normal file
6
src/zone-flags.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
/**
|
||||||
|
* Prevents Angular change detection from
|
||||||
|
* running with certain Web Component callbacks
|
||||||
|
*/
|
||||||
|
// eslint-disable-next-line no-underscore-dangle
|
||||||
|
(window as any).__Zone_disable_customElements = true;
|
||||||
15
tsconfig.app.json
Normal file
15
tsconfig.app.json
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||||
|
{
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "./out-tsc/app",
|
||||||
|
"types": []
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"src/main.ts",
|
||||||
|
"src/polyfills.ts"
|
||||||
|
],
|
||||||
|
"include": [
|
||||||
|
"src/**/*.d.ts"
|
||||||
|
]
|
||||||
|
}
|
||||||
30
tsconfig.json
Normal file
30
tsconfig.json
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||||
|
{
|
||||||
|
"compileOnSave": false,
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": "./",
|
||||||
|
"outDir": "./dist/out-tsc",
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"strict": true,
|
||||||
|
"noImplicitOverride": true,
|
||||||
|
"noPropertyAccessFromIndexSignature": true,
|
||||||
|
"noImplicitReturns": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"sourceMap": true,
|
||||||
|
"declaration": false,
|
||||||
|
"downlevelIteration": true,
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"importHelpers": true,
|
||||||
|
"target": "es2022",
|
||||||
|
"module": "es2020",
|
||||||
|
"lib": ["es2018", "dom"],
|
||||||
|
"useDefineForClassFields": false
|
||||||
|
},
|
||||||
|
"angularCompilerOptions": {
|
||||||
|
"enableI18nLegacyMessageIdFormat": false,
|
||||||
|
"strictInjectionParameters": true,
|
||||||
|
"strictInputAccessModifiers": true,
|
||||||
|
"strictTemplates": true
|
||||||
|
}
|
||||||
|
}
|
||||||
18
tsconfig.spec.json
Normal file
18
tsconfig.spec.json
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||||
|
{
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "./out-tsc/spec",
|
||||||
|
"types": [
|
||||||
|
"jasmine"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"src/test.ts",
|
||||||
|
"src/polyfills.ts"
|
||||||
|
],
|
||||||
|
"include": [
|
||||||
|
"src/**/*.spec.ts",
|
||||||
|
"src/**/*.d.ts"
|
||||||
|
]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user