active nav style; fixed stats; added age; fixed sunday issue; frame style, 1st step;
This commit is contained in:
parent
725bb127b0
commit
26784b4aba
6 changed files with 110 additions and 26 deletions
|
|
@ -1,6 +1,7 @@
|
|||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import { writable } from 'svelte/store';
|
||||
import { convertMinutes } from '$lib/utils';
|
||||
|
||||
export let actions = []; // Array of actions passed to the component
|
||||
|
||||
|
|
@ -37,16 +38,6 @@
|
|||
// Update immediately when the component has access to actions
|
||||
updateTimes();
|
||||
|
||||
function convertMinutes(minutes: number): string {
|
||||
if (minutes < 60) {
|
||||
return `${minutes}m`;
|
||||
} else {
|
||||
const hours = Math.floor(minutes / 60);
|
||||
const remainingMinutes = minutes % 60;
|
||||
return `${hours}h${remainingMinutes}m`;
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
const interval = setInterval(updateTimes, 2000); // Update every 2 minutes
|
||||
|
||||
|
|
|
|||
9
src/lib/utils.ts
Normal file
9
src/lib/utils.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
export function convertMinutes(minutes: number): string {
|
||||
if (minutes < 60) {
|
||||
return `${minutes}m`;
|
||||
} else {
|
||||
const hours = Math.floor(minutes / 60);
|
||||
const remainingMinutes = minutes % 60;
|
||||
return `${hours}h${remainingMinutes}m`;
|
||||
}
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@
|
|||
</svelte:head>
|
||||
|
||||
<script lang="ts">
|
||||
import { page } from '$app/stores';
|
||||
import { currentUser } from '$lib/pocketbase';
|
||||
import 'normalize.css/normalize.css';
|
||||
import 'milligram/dist/milligram.min.css';
|
||||
|
|
@ -16,18 +17,18 @@
|
|||
|
||||
<main class="container">
|
||||
<header>
|
||||
<h1>Coover Tracker</h1>
|
||||
<h1><a href="/">Coover Tracker</a></h1>
|
||||
<nav>
|
||||
<ul>
|
||||
<li><a href="/">Home</a></li>
|
||||
<li><a href="/" class={$page.url.pathname === '/' ? 'active' : ''}>Home</a></li>
|
||||
{#if $currentUser}
|
||||
<li><a href="/stats">Stats</a></li>
|
||||
<li><a href="/calendar">Calendar</a></li>
|
||||
<li><a href="/stats" class={$page.url.pathname === '/stats' ? 'active' : ''}>Stats</a></li>
|
||||
<li><a href="/calendar" class={$page.url.pathname === '/calendar' ? 'active' : ''}>Calendar</a></li>
|
||||
{/if}
|
||||
<li>
|
||||
<a href="/signin">
|
||||
<a href="/signin" class={$page.url.pathname === '/signin' ? 'active' : ''}>
|
||||
{#if $currentUser}
|
||||
<strong>( {$currentUser.username} )</strong>
|
||||
( {$currentUser.username} )
|
||||
{:else}
|
||||
'Sign In'
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
// Adjust currentWeekStart to the beginning of the week
|
||||
currentWeekStart.setDate(currentWeekStart.getDate() - currentWeekStart.getDay());
|
||||
currentWeekStart.setHours(0, 0, 0, 0);
|
||||
const oldestDataDate: Date = new Date('2024-01-22');
|
||||
|
||||
// Reactive store to hold actions
|
||||
|
|
@ -62,7 +63,7 @@
|
|||
|
||||
// Function to get the day of the week from a date string
|
||||
const getDayOfWeek = (dateString: string) => {
|
||||
return new Date(dateString).getDay();
|
||||
return new Date(dateString).getDay(); // 0 = Sunday, 1 = Monday, etc.
|
||||
};
|
||||
|
||||
// Function to get the hour of the day from a date string
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import { pb } from '$lib/pocketbase';
|
||||
import { parse } from 'svelte/compiler';
|
||||
import { convertMinutes } from '$lib/utils';
|
||||
|
||||
type Action = {
|
||||
type: string;
|
||||
|
|
@ -78,7 +80,7 @@
|
|||
}
|
||||
|
||||
const totalNaps = Array.from(daysMap.values()).reduce((acc, naps) => acc + naps, 0);
|
||||
return daysMap.size > 0 ? totalNaps / daysMap.size : 0;
|
||||
return daysMap.size > 0 ? parseFloat((totalNaps / daysMap.size).toFixed(1)) : 0;
|
||||
}
|
||||
|
||||
function calculateAvgSleepPerDay(actions: Action[]): number {
|
||||
|
|
@ -161,7 +163,7 @@
|
|||
totalDays += interval;
|
||||
}
|
||||
|
||||
return parseFloat((totalDays / (poopDates.length - 1)).toFixed(2));
|
||||
return parseFloat((totalDays / (poopDates.length - 1)).toFixed(1));
|
||||
}
|
||||
|
||||
function calculateAvgMealsPerDay(actions: any[]): number {
|
||||
|
|
@ -194,18 +196,77 @@
|
|||
// Return the average to one decimal place
|
||||
return parseFloat(average.toFixed(1));
|
||||
}
|
||||
|
||||
function calculateAgeFormatted(birthdate: Date): string {
|
||||
const now = new Date();
|
||||
const birthDate = new Date(birthdate);
|
||||
const diffInMilliseconds = now.getTime() - birthDate.getTime();
|
||||
const diffInDays = diffInMilliseconds / (1000 * 3600 * 24);
|
||||
const diffInWeeks = diffInDays / 7;
|
||||
const diffInMonths = diffInDays / 30.4375; // Average days per month in a year
|
||||
const diffInYears = diffInDays / 365.25; // Average, accounting for leap years
|
||||
|
||||
// Determine the largest unit (years, months, weeks, days) for the age
|
||||
if (diffInYears >= 1) {
|
||||
return formatAge(diffInYears, 'year');
|
||||
} else if (diffInMonths >= 1) {
|
||||
return formatAge(diffInMonths, 'month');
|
||||
} else if (diffInWeeks >= 1) {
|
||||
return formatAge(diffInWeeks, 'week');
|
||||
} else {
|
||||
return formatAge(diffInDays, 'day');
|
||||
}
|
||||
}
|
||||
|
||||
function formatAge(value: number, unit: string): string {
|
||||
// Round to nearest quarter
|
||||
const nearestQuarter = Math.round(value * 4) / 4;
|
||||
const integerPart = Math.floor(nearestQuarter);
|
||||
const fractionPart = nearestQuarter - integerPart;
|
||||
let fractionString = '';
|
||||
|
||||
switch (fractionPart) {
|
||||
case 0.25:
|
||||
fractionString = '¼';
|
||||
break;
|
||||
case 0.5:
|
||||
fractionString = '½';
|
||||
break;
|
||||
case 0.75:
|
||||
fractionString = '¾';
|
||||
break;
|
||||
case 0:
|
||||
fractionString = '';
|
||||
break;
|
||||
default:
|
||||
// This case should not happen with rounding to nearest quarter
|
||||
break;
|
||||
}
|
||||
|
||||
const ageString = `${integerPart}${fractionString} ${unit}${integerPart > 1 || integerPart === 0 ? 's' : ''}`;
|
||||
return ageString;
|
||||
}
|
||||
</script>
|
||||
|
||||
<section>
|
||||
<h2>Stats</h2>
|
||||
<p>(diapers and meals should be correct now)</p>
|
||||
<ul>
|
||||
<li>{stats.avgSleepPerNap} min / nap</li>
|
||||
<li>{stats.avgNapsPerDay} naps / day</li>
|
||||
<!-- <li>{stats.avgSleepPerDay} min of sleep / day</li> -->
|
||||
<li>{stats.avgSleepPerNap * stats.avgNapsPerDay} min of sleep / day</li>
|
||||
<li>{stats.avgDiaperChanges} diapers / day</li>
|
||||
<li>{stats.avgPoops} days between poops</li>
|
||||
<li>{calculateAgeFormatted(new Date('2023-08-30'))} old</li>
|
||||
</ul>
|
||||
<h3>Input</h3>
|
||||
<ul>
|
||||
<li>{stats.avgEatingTimes} meals / day</li>
|
||||
</ul>
|
||||
<h3>Output</h3>
|
||||
<ul>
|
||||
<li>{stats.avgDiaperChanges} diapers / day</li>
|
||||
<li>{stats.avgPoops} days between poops</li>
|
||||
</ul>
|
||||
<h3>Downtime</h3>
|
||||
<ul>
|
||||
<li>{convertMinutes(stats.avgSleepPerNap)} / nap</li>
|
||||
<li>{stats.avgNapsPerDay} naps / day</li>
|
||||
<!-- <li>{stats.avgSleepPerDay} min of sleep / day</li> -->
|
||||
<li>{convertMinutes(Math.round(stats.avgSleepPerNap * stats.avgNapsPerDay))} of sleep / day</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
|
|
|||
|
|
@ -90,6 +90,10 @@ nav ul li {
|
|||
list-style: none;
|
||||
}
|
||||
|
||||
nav ul li a.active{
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
header {
|
||||
|
||||
position: sticky;
|
||||
|
|
@ -98,6 +102,11 @@ header {
|
|||
z-index: 1;
|
||||
margin: 0 -2rem;
|
||||
padding: 2rem 2rem 0 2rem;
|
||||
border-radius: 3rem 3rem 0 0;
|
||||
}
|
||||
|
||||
h1 a {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
/* aside {
|
||||
|
|
@ -140,3 +149,15 @@ section {
|
|||
min-width: 10ch;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
main.container {
|
||||
max-width: 80rem;
|
||||
background: var(--c-bkg);
|
||||
border-radius: 3rem;
|
||||
margin: 3rem auto;
|
||||
padding-bottom: 3rem;
|
||||
}
|
||||
|
||||
body {
|
||||
background: #303443;
|
||||
}
|
||||
Loading…
Reference in a new issue