added times to calendar; added counters; improved element structure and styles slightly;
This commit is contained in:
parent
55df8e8dad
commit
781ef76416
6 changed files with 150 additions and 34 deletions
56
src/lib/components/counters.svelte
Normal file
56
src/lib/components/counters.svelte
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
<script>
|
||||
import { onMount } from 'svelte';
|
||||
import { writable } from 'svelte/store';
|
||||
|
||||
export let actions = []; // Array of actions passed to the component
|
||||
|
||||
// Stores for each action type
|
||||
let awakeMinutes = writable(0);
|
||||
let asleepMinutes = writable(0);
|
||||
let foodMinutes = writable(0);
|
||||
let diaperMinutes = writable(0);
|
||||
let poopDays = writable(0);
|
||||
|
||||
const getLastActionTime = (type) => {
|
||||
const lastAction = actions.filter(action => action.type === type).pop();
|
||||
return lastAction ? new Date(lastAction.created) : null;
|
||||
};
|
||||
|
||||
const calculateDiffMinutes = (date) => {
|
||||
const now = new Date();
|
||||
return date ? Math.floor((now - date) / 60000) : null; // Convert milliseconds to minutes
|
||||
};
|
||||
|
||||
const calculateDiffDays = (date) => {
|
||||
const now = new Date();
|
||||
return date ? Math.floor((now - date) / (1000 * 60 * 60 * 24)) : null; // Convert milliseconds to days
|
||||
};
|
||||
|
||||
const updateTimes = () => {
|
||||
awakeMinutes.set(calculateDiffMinutes(getLastActionTime("awake")));
|
||||
asleepMinutes.set(calculateDiffMinutes(getLastActionTime("asleep")));
|
||||
foodMinutes.set(calculateDiffMinutes(getLastActionTime("food")));
|
||||
diaperMinutes.set(calculateDiffMinutes(getLastActionTime("diaper")));
|
||||
poopDays.set(calculateDiffDays(getLastActionTime("poop")));
|
||||
};
|
||||
|
||||
// Update immediately when the component has access to actions
|
||||
updateTimes();
|
||||
|
||||
onMount(() => {
|
||||
const interval = setInterval(updateTimes, 1000); // Update every minute
|
||||
|
||||
return () => {
|
||||
clearInterval(interval); // Cleanup on component destruction
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="column">
|
||||
{#if $awakeMinutes !== null && $awakeMinutes < $asleepMinutes}<p>Awake for {$awakeMinutes} minutes</p>{/if}
|
||||
{#if $asleepMinutes !== null && $asleepMinutes < $awakeMinutes}<p>Sleeping for {$asleepMinutes} minutes</p>{/if}
|
||||
{#if $foodMinutes !== null}<p>Ate {$foodMinutes} minutes ago</p>{/if}
|
||||
{#if $diaperMinutes !== null}<p>Diaper changed {$diaperMinutes} minutes ago</p>{/if}
|
||||
{#if $poopDays === 0}<p>Pooped today</p>{:else if $poopDays !== null}<p>Pooped {$poopDays} days ago</p>{/if}
|
||||
</div>
|
||||
|
||||
|
|
@ -18,12 +18,23 @@
|
|||
<header>
|
||||
<h1>Coover Tracker</h1>
|
||||
<nav>
|
||||
<a href="/">Home</a>
|
||||
{#if $currentUser}
|
||||
<a href="/stats">Stats</a>
|
||||
<a href="/calendar">Calendar</a>
|
||||
{/if}
|
||||
<a href="/signin">{ $currentUser ? $currentUser.username : 'Sign In'}</a>
|
||||
<ul>
|
||||
<li><a href="/">Home</a></li>
|
||||
{#if $currentUser}
|
||||
<li><a href="/stats">Stats</a></li>
|
||||
<li><a href="/calendar">Calendar</a></li>
|
||||
{/if}
|
||||
<li>
|
||||
<a href="/signin">
|
||||
{#if $currentUser}
|
||||
<strong>( {$currentUser.username} )</strong>
|
||||
{:else}
|
||||
'Sign In'
|
||||
{/if}
|
||||
</a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import { pb, currentUser } from '$lib/pocketbase';
|
||||
import { user } from '$lib/userStore';
|
||||
import Counters from '$lib/components/counters.svelte';
|
||||
|
||||
type Action = {
|
||||
type: string;
|
||||
|
|
@ -39,18 +39,25 @@
|
|||
</script>
|
||||
|
||||
{#if $currentUser}
|
||||
<div>
|
||||
<button on:click={() => recordAction('awake')}>Awake</button>
|
||||
<button on:click={() => recordAction('asleep')}>Asleep</button>
|
||||
<button on:click={() => recordAction('food')}>Food</button>
|
||||
<button on:click={() => recordAction('diaper')}>Diaper</button>
|
||||
<button on:click={() => recordAction('poop')}>Poop</button>
|
||||
<aside>
|
||||
<button on:click={() => recordAction('awake')}>Awake</button>
|
||||
<button on:click={() => recordAction('asleep')}>Asleep</button>
|
||||
<button on:click={() => recordAction('food')}>Food</button>
|
||||
<button on:click={() => recordAction('diaper')}>Diaper</button>
|
||||
<button on:click={() => recordAction('poop')}>Poop</button>
|
||||
</aside>
|
||||
|
||||
<h2>Today</h2>
|
||||
<ul>
|
||||
{#each actions as action}
|
||||
<li>{action.type} at {new Date(action.created).toLocaleTimeString('en-NL', { hour: '2-digit', minute: '2-digit' })}</li>
|
||||
{/each}
|
||||
</ul>
|
||||
</div>
|
||||
<section>
|
||||
<h2>Today</h2>
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<ul class="column">
|
||||
{#each actions as action}
|
||||
<li>{action.type} at {new Date(action.created).toLocaleTimeString('en-NL', { hour: '2-digit', minute: '2-digit' })}</li>
|
||||
{/each}
|
||||
</ul>
|
||||
<Counters {actions} />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{/if}
|
||||
|
|
@ -34,20 +34,26 @@ import { onMount } from 'svelte';
|
|||
|
||||
// Generate hours for the grid
|
||||
const hours = Array.from({ length: 24 }, (_, i) => i);
|
||||
|
||||
// Function to format hour in HH:mm format
|
||||
const formatHour = (hour: number) => {
|
||||
return `${hour.toString().padStart(2, '0')}:00`;
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.calendar {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(7, 1fr);
|
||||
grid-template-columns: 60px repeat(7, 1fr); /* Adjusted for hour column */
|
||||
text-align: center;
|
||||
}
|
||||
.day-header {
|
||||
.day-header, .hour-label {
|
||||
font-weight: bold;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
.hour {
|
||||
border: 1px solid #ccc;
|
||||
min-height: 60px;
|
||||
height: 60px;
|
||||
}
|
||||
.event {
|
||||
background-color: lightblue;
|
||||
|
|
@ -55,21 +61,41 @@ import { onMount } from 'svelte';
|
|||
padding: 2px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.event--food {
|
||||
background-color: lightgreen;
|
||||
}
|
||||
.event--poop {
|
||||
background-color: burlywood;
|
||||
}
|
||||
.event--asleep {
|
||||
background-color: lightblue;
|
||||
}
|
||||
.event--awake {
|
||||
background-color: gold;
|
||||
}
|
||||
.event--diaper {
|
||||
background-color: lightpink;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="calendar">
|
||||
<!-- Empty cell for top-left corner -->
|
||||
<div></div>
|
||||
|
||||
<!-- Day Headers -->
|
||||
{#each daysOfWeek as day}
|
||||
<div class="day-header">{day}</div>
|
||||
{/each}
|
||||
|
||||
<!-- Calendar Grid -->
|
||||
<!-- Hour Labels and Calendar Grid -->
|
||||
{#each hours as hour}
|
||||
<div class="hour-label">{formatHour(hour)}</div> <!-- Hour label -->
|
||||
{#each daysOfWeek as _, dayIndex}
|
||||
<div class="hour">
|
||||
{#each actions as action}
|
||||
{#if getDayOfWeek(action.created) === dayIndex && getHourOfDay(action.created) === hour}
|
||||
<div class="event">{action.type}</div>
|
||||
<div class="event event--{action.type}">{action.type}</div>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@
|
|||
totalDays += interval;
|
||||
}
|
||||
|
||||
return totalDays / (poopDates.length - 1);
|
||||
return parseFloat((totalDays / (poopDates.length - 1)).toFixed(2));
|
||||
}
|
||||
|
||||
function calculateAvgMealsPerDay(actions: Action[]): number {
|
||||
|
|
@ -174,14 +174,14 @@
|
|||
}
|
||||
</script>
|
||||
|
||||
<main>
|
||||
<section>
|
||||
<h2>Stats</h2>
|
||||
<ul>
|
||||
<li>Average Sleep per Nap: {stats.avgSleepPerNap} minutes</li>
|
||||
<li>Average Naps per Day: {stats.avgNapsPerDay} naps</li>
|
||||
<li>Average Sleep per Day: {stats.avgSleepPerDay} minutes</li>
|
||||
<li>Average Diaper Changes per Day: {stats.avgDiaperChanges}</li>
|
||||
<li>Average Days Between Poops: {stats.avgPoops}</li>
|
||||
<li>Average Number of Meals per Day: {stats.avgEatingTimes}</li>
|
||||
<li>{stats.avgSleepPerNap} min / nap</li>
|
||||
<li>{stats.avgNapsPerDay} naps / day</li>
|
||||
<li>{stats.avgSleepPerDay} min of sleep / day</li>
|
||||
<li>{stats.avgDiaperChanges} diapers / day</li>
|
||||
<li>{stats.avgPoops} days between poops</li>
|
||||
<li>{stats.avgEatingTimes} meals / day</li>
|
||||
</ul>
|
||||
</main>
|
||||
</section>
|
||||
|
|
|
|||
|
|
@ -15,4 +15,20 @@ button,
|
|||
input[type="submit"] {
|
||||
background-color: var(--c-primary);
|
||||
border-color: var(--c-primary);
|
||||
}
|
||||
|
||||
nav ul {
|
||||
list-style: circle inside;
|
||||
display: flex;
|
||||
list-style: none;
|
||||
gap: 1em;
|
||||
justify-content: end;
|
||||
}
|
||||
|
||||
header {
|
||||
padding-top: 2rem;
|
||||
}
|
||||
|
||||
section {
|
||||
margin-top: 4rem;
|
||||
}
|
||||
Loading…
Reference in a new issue