Compare commits

16 Commits
23 changed files with 281 additions and 156 deletions
+16
View File
@@ -0,0 +1,16 @@
for stase management:
1. Klick auf Übung macht neuen Eintrag in der UserState mit dem Excercise Namen + benötigten Feldern in currentEdit.
2. Wenn CurrentEdit gesetzt zeig die Set Optionen an.
3. Speichere die Sets in User.Chest
4. Cleare den CurrentEdit
5. Display oben was Eingetragen wurde in User.Chest
In this rewritten example, we still use reactive to create the reactive inputValues object and ref to create the currentButton reference.
The setCurrentButton function sets the value of currentButton to the ID of the button that was clicked.
The saveInputValue function saves the input value for the current button in inputValues[currentButton.value].value.
The rest of the code remains largely the same, with the buttons array being rendered using v-for, and the input field and value display being updated based on the currently selected button.
With the Composition API, the reactive state and functions are defined within the setup function, providing a cleaner and more organized way to handle component logic.
+11
View File
@@ -0,0 +1,11 @@
Your selected colors:
Primary: #daeafb (RGB: 218, 234, 251)
Secondary: #000000 (RGB: 0, 0, 0)
Primary Button: #5b9a66 (RGB: 91, 154, 102)
Secondary Button: #120320 (RGB: 18, 3, 32)
Accent: #b574f1 (RGB: 181, 116, 241)
Realtime Colors link for selected colors: https://realtimecolors.com/?colors=daeafb-000000-5b9a66-120320-b574f1
Thanks for using RealtimeColors.com!
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

-2
View File
File diff suppressed because one or more lines are too long
+2
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1 +1 @@
<!doctype html><html lang="en"><head><meta charset="UTF-8"><link rel="icon" href="./logo.ico"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Gym Tracker</title><script type="module" crossorigin src="./assets/index-3d69e972.js"></script></head><body><div id="app"></div></body></html> <!doctype html><html lang="en"><head><meta charset="UTF-8"><link rel="icon" href="./logo.ico"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Gym Tracker</title><script type="module" crossorigin src="./assets/index-4ea6f92e.js"></script></head><body><div id="app"></div></body></html>
+1 -1
View File
@@ -4,7 +4,7 @@ import { NavigationModel } from "./components/Index.js";
</script> </script>
<template> <template>
<div class="app-containe"> <div class="app-container bg-background">
<NavigationModel /> <NavigationModel />
<div class="container px-3 mx-auto"> <div class="container px-3 mx-auto">
<router-view class="mt-4" /> <router-view class="mt-4" />
View File
+39 -29
View File
@@ -1,57 +1,57 @@
<template> <template>
<input class="search " type="text" v-model="input" placeholder="Search..." /> <input class="search
text-black py-2 px-2 rounded mt-5"
v-model="input"
type="text"
placeholder="Search..." />
<div class="flex"> <div class="flex">
<div class="exerciseList"> <div class="exerciseList">
<ul class="exerciseItem" v-for="exercise in filterExercises()" :key="exercise.name"> <ul class="exerciseItem" v-for="exercise in filterExercises()" :key="exercise.name">
<Button @click="exerciseClick(exercise)" class="btn bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4" >{{ exercise.name }}</Button> <button @click="exerciseClick(exercise); initSetInput()" :class="isActiveExercise(exercise.name)" >{{ exercise.name }}</button>
</ul> </ul>
</div> </div>
<div v-show="isClicked" class="show"> <div v-if="selectedExercise">
<label> {{ exerciseName }}</label> <WeightsInput :muscle="muscle" :selectedExercise="selectedExercise"></WeightsInput>
<WeightsInput/>
</div> </div>
</div> </div>
</template> </template>
<script setup> <script setup>
import { usePostStore } from '@/stores/store.js'; import { useExerciseStore } from '@/stores/storeExercise.js';
import { onMounted, ref } from 'vue'; import { onMounted, ref } from 'vue';
import WeightsInput from "@/views/weight/WeightsInput.vue"; import WeightsInput from "@/views/weight/WeightsInput.vue";
import { useWeightInputStore } from '@/stores/storeInput';
const muscle = defineProps({ const props = defineProps({
muscle: String, muscle: String,
warmUpSets: Array,
workingSets: Array,
warmUpReps: Array,
workingReps: Array,
}) })
let isClicked = false const json = useExerciseStore()
const json = usePostStore() const weightInput = useWeightInputStore()
const exercises = ref([]) const exercises = ref([])
let exerciseName = "" const selectedExercise = ref(null)
onMounted(async () => { onMounted(async () => {
await json.fetchMuscleExercise() await json.fetchMuscleExercise()
switch (muscle.muscle) { switch (props.muscle) {
case "Legs": case "Legs":
exercises.value = json.postList.muscle[0].exercises exercises.value = json.exerciseList.muscle[0].exercises
break; break;
case "Back": case "Back":
exercises.value = json.postList.muscle[1].exercises exercises.value = json.exerciseList.muscle[1].exercises
break; break;
case "Chest": case "Chest":
exercises.value = json.postList.muscle[2].exercises exercises.value = json.exerciseList.muscle[2].exercises
break; break;
case "Shoulder": case "Shoulder":
exercises.value = json.postList.muscle[3].exercises exercises.value = json.exerciseList.muscle[3].exercises
break; break;
case "Biceps": case "Biceps":
exercises.value = json.postList.muscle[4].exercises exercises.value = json.exerciseList.muscle[4].exercises
break; break;
case "Triceps": case "Triceps":
exercises.value = json.postList.muscle[5].exercises exercises.value = json.exerciseList.muscle[5].exercises
break; break;
} }
} }
@@ -65,16 +65,18 @@
}); });
}; };
const showWeightInput = (isClicked) => { function isActiveExercise(exercise){
isClicked.value = true //TODO: Implement (exercise in weightInput.exercises) to show which exercise are edited, or put them in a proper seperate list
} return { 'exercise-list-button': selectedExercise.value !== exercise, 'exercise-list-button-active': selectedExercise.value === exercise};
};
const exerciseClick = (exercise) => { const exerciseClick = (exercise) => {
isClicked = true selectedExercise.value = exercise.name;
exerciseName = exercise.name };
console.log(isClicked)
}
const initSetInput = () => {
weightInput.initSetsInputs(props.muscle, selectedExercise.value);
};
</script> </script>
@@ -88,6 +90,14 @@ const exerciseClick = (exercise) => {
margin-top: 0.5rem; margin-top: 0.5rem;
} }
.exercise-list-button {
@apply bg-secondary-button hover:bg-accent text-white font-bold py-2 px-2 rounded;
}
.exercise-list-button-active {
@apply bg-accent text-white font-bold py-2 px-2 rounded;
}
.search{ .search{
width: auto; width: auto;
height: 2rem; height: 2rem;
+7 -3
View File
@@ -25,7 +25,7 @@
width: 100%; width: 100%;
height: 4rem; height: 4rem;
justify-content: start; justify-content: start;
background: rgb(36, 165, 75); background: #0a0e06;
} }
.navbar-nav{ .navbar-nav{
display: flex; display: flex;
@@ -36,12 +36,16 @@
.nav-item{ .nav-item{
margin-left: 1rem; margin-left: 1rem;
margin-right: 1rem; margin-right: 1rem;
color: white; color: #e7f1df;
text-decoration: none; text-decoration: none;
font-size: 1.2rem;
} }
.nav-item:hover{ .nav-item:hover{
color: orangered; // color: rgb(91, 154, 102);
color: #699f65
} }
.logo{ .logo{
display: flex; display: flex;
} }
+1 -1
View File
@@ -1,6 +1,6 @@
import { createRouter, createWebHistory } from 'vue-router' import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/Home.vue' import HomeView from '../views/Home.vue'
import MusclesRouter from './muscle.js'; import MusclesRouter from './Muscle.js';
const router = createRouter({ const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL), history: createWebHistory(import.meta.env.BASE_URL),
-22
View File
@@ -1,22 +0,0 @@
import {defineStore} from 'pinia'
import muscleExercise from '../assets/muscleExercise';
import { ref } from 'vue'
export const usePostStore = defineStore('json', () => {
const postList = ref([])
const error = ref([])
async function fetchMuscleExercise() {
postList.value = muscleExercise
error.value = []
}
return {
postList,
error,
fetchMuscleExercise
}
}
)
export default usePostStore
+17
View File
@@ -0,0 +1,17 @@
import {defineStore} from 'pinia'
import muscleExercise from '../assets/muscleExercise';
import { ref } from 'vue'
export const useExerciseStore = defineStore('json', () => {
const exerciseList = ref([])
async function fetchMuscleExercise() {
exerciseList.value = muscleExercise
}
return {
exerciseList,
fetchMuscleExercise
}
}
)
+101
View File
@@ -0,0 +1,101 @@
import { defineStore } from 'pinia'
// import { reactive } from 'vue'
import { useLocalStorage } from '@vueuse/core'
export const useWeightInputStore = defineStore('weightInput', () => {
// localStorage https://vueuse.org/core/useLocalStorage/
const exercises = useLocalStorage('exercises', {});
function addWorkingSet(muscle, selectedExercise) {
if (!exercises.value[muscle][selectedExercise]) {
return;
}
exercises.value[muscle][selectedExercise].workingSet.push({
workingSetReps: [],
workingSetWeight: [],
});
console.log('Added working set:', exercises.value[muscle][selectedExercise]);
}
function addWarmUpSet(muscle, selectedExercise) {
if (!exercises.value[muscle][selectedExercise]) {
return;
}
exercises.value[muscle][selectedExercise].warmUpSet.push({
warmSetReps: [],
warmSetWeight: [],
});
}
function removeWorkingSet(muscle, selectedExercise) {
if(!exercises.value[muscle][selectedExercise]) {
return
}
exercises.value[muscle][selectedExercise].workingSet.pop({
workingSetReps: [],
workingSetsWeight: [],
})
}
function removeWarmUpSet(muscle, selectedExercise) {
if(!exercises.value[muscle][selectedExercise]) {
return;
}
exercises.value[muscle][selectedExercise].warmUpSet.pop({
warmUpSetReps: [],
warmUpSetsWeight: [],
})
}
function getWorkingSetCount(muscle, selectedExercise) {
if (exercises.value[muscle][selectedExercise]) {
return exercises.value[muscle][selectedExercise].workingSet.length;
}
return 1;
}
function getWarmUpSetCount(muscle, selectedExercise) {
if (exercises.value[muscle][selectedExercise]) {
return exercises.value[muscle][selectedExercise].warmUpSet.length;
}
return 1;
}
function initSetsInputs(muscle, selectedExercise) {
if (!exercises.value[muscle]) {
exercises.value[muscle] = {};
}
if (!exercises.value[muscle][selectedExercise]) {
exercises.value[muscle][selectedExercise] = {
workingSet: [],
warmUpSet: [],
};
exercises.value[muscle][selectedExercise].workingSet.push({
workingSetReps: [],
workingSetWeight: [],
});
exercises.value[muscle][selectedExercise].warmUpSet.push({
warmSetReps: [],
warmSetWeight: [],
});
}
console.log('Init sets inputs:', exercises.value[muscle][selectedExercise], selectedExercise);
}
return {
exercises,
addWorkingSet,
removeWorkingSet,
addWarmUpSet,
removeWarmUpSet,
getWorkingSetCount,
getWarmUpSetCount,
initSetsInputs }
}
)
-22
View File
@@ -1,22 +0,0 @@
import {defineStore} from 'pinia'
import {useStorage} from '@vueuse/core'
//see https://stephanlangeveld.medium.com/simple-local-storage-implementation-using-vue-3-vueuse-and-pinia-with-zero-extra-lines-of-code-cb9ed2cce42a
export const useWeightStore = defineStore({
id: 'weight',
state: () => ({
weight: [],
reps: []
}),
getters: {
getAllWeights() {
return this.weight.value
},
},
actions: {
addWeight(weight, reps) {
this.weight.push(weight);
this.reps.push(reps);
},
}
})
+1 -1
View File
@@ -1,5 +1,5 @@
<template> <template>
<div class="text-3xl font-bold underline text-blue-500"> <div class="text-white">
<h1>Back</h1> <h1>Back</h1>
<ExerciseList muscle="Back"/> <ExerciseList muscle="Back"/>
</div> </div>
+1 -1
View File
@@ -1,5 +1,5 @@
<template> <template>
<div class="biceps"> <div class="biceps text-text">
<h1>Biceps</h1> <h1>Biceps</h1>
<ExerciseList muscle="Biceps"/> <ExerciseList muscle="Biceps"/>
</div> </div>
+1 -4
View File
@@ -1,12 +1,9 @@
<template> <template>
<div class="flex"> <div class="text-white">
<div class="w-1/2"> <div class="w-1/2">
<h1>Chest</h1> <h1>Chest</h1>
<ExerciseList muscle="Chest"/> <ExerciseList muscle="Chest"/>
</div> </div>
<div>
<weightsInput/>
</div>
</div> </div>
</template> </template>
+1 -1
View File
@@ -1,5 +1,5 @@
<template> <template>
<div class="legs"> <div class="legs text-white">
<h1>Legs</h1> <h1>Legs</h1>
<ExerciseList muscle="Legs"/> <ExerciseList muscle="Legs"/>
</div> </div>
+1 -1
View File
@@ -1,5 +1,5 @@
<template> <template>
<div class="shoulder"> <div class="shoulder text-white">
<h1>Shoulder</h1> <h1>Shoulder</h1>
<ExerciseList muscle="Shoulder"/> <ExerciseList muscle="Shoulder"/>
</div> </div>
+1 -1
View File
@@ -1,5 +1,5 @@
<template> <template>
<div class="triceps"> <div class="triceps text-white ">
<h1>Triceps</h1> <h1>Triceps</h1>
<ExerciseList muscle="Triceps"/> <ExerciseList muscle="Triceps"/>
</div> </div>
+66 -63
View File
@@ -1,87 +1,90 @@
<template> <template>
//TODO make view resposive on button click add
<div class="w-2/3 mx-auto"> <div class="w-2/3 mx-auto">
<div class="warmup-sets mt-12 w-2/3"> <div class="mt-2">
<label>Warm-Up Sets</label> <label>Warm-Up Sets</label>
<button @click="warmUpAddSet()" class="add-btn bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded ml-5">Add</button> <button @click="weightInput.addWarmUpSet(muscle, selectedExercise)"
<div v-for="warmupset in warmUpInput.warmUpSets" class="item" :key="warmupset"> class="bg-accent hover:bg-primary-button text-white font-bold py-2 px-2 rounded ml-5">
{{ warmupset }} Add
<input name="warmupweight" class="mt-1 px-3 py-2 bg-black border shadow-sm border-slate-300 placeholder-slate-400 focus:outline-none focus:border-sky-500 focus:ring-sky-500 block rounded-md sm:text-sm focus:ring-1" placeholder="Weight in Kg" /> </button>
<!-- https://www.designcise.com/web/tutorial/how-to-conditionally-disable-a-button-in-vue-js -->
<button :disabled="weightInput.getWarmUpSetCount(muscle, selectedExercise) <= 1"
@click="weightInput.removeWarmUpSet(muscle, selectedExercise)"
class="bg-accent hover:bg-primary-button text-white font-bold py-2 px-2 rounded ml-5 disabled:opacity-25">
Remove
</button>
<div v-for="(warmUpSet, warmUpSetCount) in weightInput.exercises[muscle][selectedExercise].warmUpSet" :key="warmUpSetCount"
class="flex ml-2">
<label>Set {{ warmUpSetCount + 1 }}</label>
<div class="ml-3">
<input
v-model="warmUpSet.warmUpWeight"
type="number"
class="mt-1 px-3 py-2 bg-black border shadow-sm border-slate-300 placeholder-slate-400 focus:outline-none block rounded-md sm:text-sm "
placeholder="Weight (kg)"
onkeypress='return event.charCode >= 48 && event.charCode <= 57'/>
</div>
<div class="ml-3">
<input
v-model="warmUpSet.warmUpReps"
type="number"
class="mt-1 px-3 py-2 bg-black border shadow-sm border-slate-300 placeholder-slate-400 focus:outline-none block rounded-md sm:text-sm "
placeholder="Reps"
onkeypress='return event.charCode >= 48 && event.charCode <= 57'/>
</div> </div>
</div> </div>
<div class="working-set mt-5"> <div class="working-set mt-5">
<label>Working Sets</label> <label>Working Sets</label>
<button @click="workingAddSet()" class="add-btn bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded ml-7">Add</button> <button @click="weightInput.addWorkingSet(muscle, selectedExercise)"
class="bg-accent hover:bg-primary-button text-white font-bold py-2 px-2 rounded ml-7">
Add
</button>
<button :disabled="weightInput.getWorkingSetCount(muscle, selectedExercise) <= 1"
@click="weightInput.removeWorkingSet(muscle, selectedExercise)"
class="bg-accent hover:bg-primary-button text-white font-bold py-2 px-2 rounded ml-5 disabled:opacity-25">
Remove
</button>
<div> <div>
<div v-for="(workingset, index) in workingInput.workingSets" class="item flex justify-smart mt-3" :key="index"> <div v-for="(workingset, workingSetCount) in weightInput.exercises[muscle][selectedExercise].workingSet" :key="workingSetCount" class="item flex justify-smart mt-1">
{{ workingset }} <label class=""> {{ workingSetCount + 1 }}. Set</label>
<div class="ml-3"> <div class="ml-3">
<input v-model="workingInput.workingSets" class="mt-1 px-3 py-2 bg-black border shadow-sm border-slate-300 placeholder-slate-400 focus:outline-none focus:border-sky-500 focus:ring-sky-500 block rounded-md sm:text-sm focus:ring-1" placeholder="Weight in Kg"/> <input
v-model="workingset.workingSetWeight"
type="number"
class="mt-1 px-3 py-2 bg-black border shadow-sm border-slate-300 placeholder-slate-400 focus:outline-none block rounded-md sm:text-sm "
placeholder="Weight (Kg)"
onkeypress='return event.charCode >= 48 && event.charCode <= 57'/>
</div> </div>
<label>Reps</label>
<div class="ml-3"> <div class="ml-3">
<input v-model="workingInput.workingReps" class="mt-1 px-3 py-2 bg-black border shadow-sm border-slate-300 placeholder-slate-400 focus:outline-none focus:border-sky-500 focus:ring-sky-500 block rounded-md sm:text-sm focus:ring-1" placeholder="Reps"> <input
v-model="workingset.workingSetReps"
type="number"
class="mt-1 px-3 py-2 bg-black border shadow-sm border-slate-300 placeholder-slate-400 focus:outline-none block rounded-md sm:text-sm "
placeholder="Reps"
onkeypress='return event.charCode >= 48 && event.charCode <= 57'> <!-- https://stackoverflow.com/questions/66172698/textbox-which-accepts-only-numbers-in-vue-js -->
</div>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
</div>
<button @click="addWeight()" class="add-btn bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded mt-5">Save</button>
</div>
</template> </template>
<script setup> <script setup>
import { useWeightStore } from '@/stores/storeWeight'; import { useWeightInputStore } from '@/stores/storeInput';
import { ref } from 'vue';
let warmUpSetCount = 0; const props = defineProps({
let workingSetCount = 0; muscle: String,
selectedExercise: String,
});
const weight = useWeightStore(); const weightInput = useWeightInputStore();
weightInput.selectedExercise = ref(props.selectedExercise);
let warmUpInput = {
warmUpSets: [],
warmUpReps: []
}
let workingInput = {
workingSets: [],
workingReps: []
}
const warmUpAddSet = () => {
const newWarmUpSet = {
id: warmUpSetCount++,
content: warmUpSetCount + ". Set"
};
warmUpInput.warmUpSets.push(newWarmUpSet.content);
console.log(warmUpInput.warmUpSets);
};
const workingAddSet = () => {
const newWorkingSet = {
id: workingSetCount++,
content: workingSetCount + ". Set"
};
workingInput.workingSets.push(newWorkingSet.content);
console.log(workingInput);
};
const addWeight = () => {
//TODO: Add warmup sets and reps to store
weight.addWeight(workingSetInput.value, workingRepsSets.value);
workingSetInput.value = "";
workingRepsSets.value = "";
}
console.log(addWeight);
</script> </script>
<style>
</style>
export default weightsInput;
+11 -1
View File
@@ -5,7 +5,17 @@ export default {
"./src/**/*.{vue,js,ts,jsx,tsx}", "./src/**/*.{vue,js,ts,jsx,tsx}",
], ],
theme: { theme: {
extend: {}, extend: {
colors: {
'primary-button':'#5b9a66',
// 'secondary-button':'#0d1406',
'secondary-button':'#699f65',
'background':'#131d0c',
'text': '#e7f1df',
'accent': '#361f47',
'accent2': '#63992e',
}
},
}, },
plugins: [], plugins: [],
} }