diff --git a/packages/common/src/models/activities.ts b/packages/common/src/models/activities.ts index 7235300..ce9d5e4 100644 --- a/packages/common/src/models/activities.ts +++ b/packages/common/src/models/activities.ts @@ -1,7 +1,16 @@ import { z } from "zod"; -export const Activity = z.object({ +export const Time = z.object({ hour: z.number(), minute: z.number() }) +export const Activity = z.object({ + type: z.number(), + title: z.string(), + subtitle: z.string().optional(), + time: z.object({ start: Time, end: Time }), + lessons: z.object({ count: z.number(), first: z.date(), last: z.date() }), + price: z.number(), + color: z.string() }) +export type Time = z.infer export type Activity = z.infer diff --git a/packages/web/src/components/Calendar.astro b/packages/web/src/components/Calendar.astro index 859759c..b5c0b3a 100644 --- a/packages/web/src/components/Calendar.astro +++ b/packages/web/src/components/Calendar.astro @@ -1,5 +1,6 @@ --- import type { Activity } from "common"; +import { gcd } from "../lib/maths"; interface Props { activities: Activity[][]; @@ -9,7 +10,25 @@ const { activities } = Astro.props; const timeMin = 8; const timeMax = 22; -const timeStep = 1; +const cellSize = 4; +const minutesPerTick = 30; + +// NOTE: CSS grid does not allow to have fractional spans. +// Therefore, it is needed to scale it by the smallest time interval in every activity. +const minutes = [ + ...activities.flat(2).reduce( + (set, activity) => { + set.add(activity.time.start.minute); + set.add(activity.time.end.minute); + return set; + }, + new Set([minutesPerTick]), + ), +].filter((min) => min !== 0); +const minuteScale = gcd(minutes); +const gridScale = minutesPerTick / minuteScale; +const timeStep = minutesPerTick / 60; +const cellScale = gridScale / timeStep; function formatTime(time: number): string { const hour = Math.floor(time); @@ -22,7 +41,7 @@ function formatTime(time: number): string {
{ @@ -51,7 +70,7 @@ function formatTime(time: number): string { (_, row) => (
), ) @@ -61,7 +80,7 @@ function formatTime(time: number): string { Array.from({ length: (timeMax - timeMin) / timeStep + 1 }).map((_, i) => (
{formatTime(timeMin + i * timeStep)} @@ -69,6 +88,23 @@ function formatTime(time: number): string {
)) } + + { + // --- Activity squares --- + activities.map((list, weekday) => + list.map((activity) => ( +
+ {activity.title} - {activity.subtitle} +
+ )), + ) + }
diff --git a/packages/web/src/lib/maths.test.ts b/packages/web/src/lib/maths.test.ts index 096f939..5b0aa05 100644 --- a/packages/web/src/lib/maths.test.ts +++ b/packages/web/src/lib/maths.test.ts @@ -1,22 +1,7 @@ import { describe, expect, test, } from "vitest"; -import { gcd, lcm } from "./maths"; +import { gcd, } from "./maths"; describe("maths", function() { - test("lcm", function() { - const tests = [ - { inputs: [1], expected: 1 }, - { inputs: [1, 2], expected: 2 }, - { inputs: [2, 3], expected: 6 }, - { inputs: [2, 4], expected: 4 }, - { inputs: [2, 3, 4], expected: 12 }, - { inputs: [1, 3, 5, 8], expected: 120 }, - ] - - tests.forEach((test, i) => { - expect(lcm(test.inputs)).to.equal(test.expected, `tests[${i}]: expected ${test.inputs} to have ${test.expected} as lcm`); - }) - }) - test("gcd", function() { const tests = [ { inputs: [1], expected: 1 }, diff --git a/packages/web/src/lib/maths.ts b/packages/web/src/lib/maths.ts index b437380..6b81ce7 100644 --- a/packages/web/src/lib/maths.ts +++ b/packages/web/src/lib/maths.ts @@ -25,25 +25,3 @@ export function gcd(n: number[]): number { } return stack[0] } - -/** -* Lowest Common Multiple -*/ -export function lcm(n: number[]): number { - if (n.length === 0) { - return 0 - } - - if (n.length <= 2) { - const product = n.reduce((p, curr) => p * curr, 1) - return product / gcd(n) - } - - const stack = [...n] - while (stack.length >= 2) { - let a = stack.pop()! - let b = stack.pop()! - stack.push(lcm([a, b])) - } - return stack[0] -} diff --git a/packages/web/src/pages/horaire.astro b/packages/web/src/pages/horaire.astro index 9116847..7b08c2f 100644 --- a/packages/web/src/pages/horaire.astro +++ b/packages/web/src/pages/horaire.astro @@ -10,19 +10,34 @@ const activities: Activity[][] = [ type: 0, title: "Récréatif", subtitle: "6 ans et plus", - time: { start: 9, end: 10.5 }, + time: { start: { hour: 8, minute: 0 }, end: { hour: 10, minute: 45 } }, lessons: { count: 8, first: new Date(2025, 1, 6), last: new Date(2025, 5, 5), }, price: 120, + color: "#ff00ff", }, ], [], [], [], - [], + [ + { + type: 0, + title: "Récréatif", + subtitle: "12 ans et plus", + time: { start: { hour: 10, minute: 15 }, end: { hour: 12, minute: 45 } }, + lessons: { + count: 8, + first: new Date(2025, 1, 6), + last: new Date(2025, 5, 5), + }, + price: 120, + color: "#ff0000", + }, + ], [], ]; ---