Skip to content

Commit

Permalink
revamp homescreen
Browse files Browse the repository at this point in the history
  • Loading branch information
catdevnull committed Nov 30, 2024
1 parent a8e408b commit 2b9a39c
Show file tree
Hide file tree
Showing 8 changed files with 277 additions and 380 deletions.
88 changes: 88 additions & 0 deletions sitio/src/lib/StatsCalendar.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<script lang="ts">
import dayjs from "dayjs";
import {
getStatsForDaysInTimePeriod,
processDataForDays,
} from "$lib/data-processing/days";
import { likesCutoff, tz } from "$lib/consts";
import { formatTinyDurationFromMs } from "$lib/data-processing/screenTime";
import { HeartIcon, Repeat2Icon } from "lucide-svelte";
export let monthData: Awaited<ReturnType<typeof getStatsForDaysInTimePeriod>>;
export let start: Date;
let daysWithData: ReturnType<typeof processDataForDays>["daysWithData"];
let maxTime: ReturnType<typeof processDataForDays>["maxTime"];
$: ({ daysWithData, maxTime } = processDataForDays(monthData));
</script>

<div class="grid w-full table-fixed grid-cols-7 gap-[2px]">
<div class="text-sm *:font-light">dom.</div>
<div class="text-sm *:font-light">lun.</div>
<div class="text-sm *:font-light">mar.</div>
<div class="text-sm *:font-light">mié.</div>
<div class="text-sm *:font-light">jue.</div>
<div class="text-sm *:font-light">vie.</div>
<div class="text-sm *:font-light">sáb.</div>
{#if true}
{@const firstWeek = dayjs(start).tz(tz).startOf("week")}
{#each [firstWeek, firstWeek.add(1, "week"), firstWeek.add(2, "week"), firstWeek.add(3, "week"), firstWeek.add(4, "week"), firstWeek.add(5, "week")] as week}
{#each [week, week.add(1, "day"), week.add(2, "day"), week.add(3, "day"), week.add(4, "day"), week.add(5, "day"), week.add(6, "day")] as weekday}
<!-- {@const day = dayjs(data.start).add(index * week, "day")} -->
{@const dayStr = weekday.format("YYYY-MM-DD")}
{@const dayData = daysWithData.find((x) => x.day === dayStr)}
{@const level = dayData && dayData.screenTime / maxTime}
{#if dayData}
<div
class="fancy-colors rounded px-1 align-super md:px-2"
style={dayData && `--level: ${level}`}
>
<div class="flex h-full flex-col justify-between">
<div>
<div>
{weekday.format("D")}
</div>
<div>
<strong class="font-black"
>{formatTinyDurationFromMs(dayData.screenTime)}</strong
>
</div>
</div>
<div class="">
{#if !(likesCutoff && (weekday.isAfter(likesCutoff.cutAt, "day") || weekday.isSame(likesCutoff.cutAt, "day")))}
<div class="align-center flex gap-1 py-1 leading-none">
<HeartIcon class="size-[1em]" />
{dayData.tweets.length}
</div>
{/if}
<div class="align-center flex gap-1 py-1 leading-none">
<Repeat2Icon class="size-[1em]" />
{dayData.retweets.length}
</div>
</div>
</div>
</div>
{/if}
{/each}
{/each}
{/if}
</div>

<style>
@media (prefers-color-scheme: dark) {
.fancy-colors {
--background: rgb(255 255 255 / var(--level));
}
}
@media (prefers-color-scheme: light) {
.fancy-colors {
--background: rgb(255 0 0 / var(--level));
}
}
.fancy-colors {
background: var(--background, rgb(255 0 0 / var(--level)));
}
.fancy-colors > div {
color: light-dark(black, black);
}
</style>
38 changes: 38 additions & 0 deletions sitio/src/lib/StatsCalendarNavigation.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<script lang="ts">
import dayjs from "dayjs";
import { monthFormatter, tz } from "./consts";
import { dateToMonthString } from "../routes/promedios/[year]/[month]/months";
import { ArrowLeftIcon, ArrowRightIcon } from "lucide-svelte";
import Button from "./components/ui/button/button.svelte";
export let start: Date;
export let hasNextMonth: boolean;
export let hideIfNotExists = false;
$: mesAnterior = dayjs(start).tz(tz).subtract(1, "month");
$: mesAnteriorHref = `/promedios/${mesAnterior.year()}/${dateToMonthString(mesAnterior)}`;
$: mesProximo = dayjs(start).tz(tz).add(1, "month");
$: mesProximoHref = `/promedios/${mesProximo.year()}/${dateToMonthString(mesProximo)}`;
$: hasPrevMonth = mesAnterior.isAfter(dayjs("2024-01-29"));
</script>

<div class="flex flex-wrap gap-2">
{#if !hideIfNotExists || hasPrevMonth}
<Button
href={hasPrevMonth ? mesAnteriorHref : undefined}
disabled={!hasPrevMonth}
>
<ArrowLeftIcon class="mr-2 size-5" />
{monthFormatter.format(mesAnterior.toDate())}
</Button>
{/if}
{#if !hideIfNotExists || hasNextMonth}
<Button
href={hasNextMonth ? mesProximoHref : undefined}
disabled={!hasNextMonth}
>
{monthFormatter.format(mesProximo.toDate())}
<ArrowRightIcon class="ml-2 size-5" />
</Button>
{/if}
</div>
1 change: 1 addition & 0 deletions sitio/src/lib/consts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export const longDateFormatter = Intl.DateTimeFormat("es-AR", {
});
export const monthFormatter = Intl.DateTimeFormat("es-AR", {
month: "long",
year: "numeric",
timeZone: tz,
});

Expand Down
23 changes: 23 additions & 0 deletions sitio/src/lib/data-processing/days.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@ import { desc, and, gte, lte } from "drizzle-orm";
import {
calculateSessions,
getInteractionTimes,
msToDuration,
totalFromDurations,
} from "./screenTime";
import { formatDuration } from "date-fns";
import { es } from "date-fns/locale/es";

export function makeMapOfDays<T>(
days: Array<Date>,
Expand Down Expand Up @@ -118,3 +121,23 @@ export function getDaysInTimePeriod(start: Dayjs, end: Dayjs) {
days.push(date);
return days;
}

export type DataForDays = Awaited<
ReturnType<typeof getStatsForDaysInTimePeriod>
>;

export function processDataForDays(data: DataForDays) {
const daysWithData = data.filter((day) => day.screenTime > 0);
const avg =
daysWithData.reduce((prev, day) => prev + day.screenTime, 0) /
daysWithData.length;
const avgString = formatDuration(msToDuration(avg), {
locale: es,
delimiter: " y ",
format: ["hours", "minutes"],
});

const minTime = Math.min(...daysWithData.map((day) => day.screenTime));
const maxTime = Math.max(...daysWithData.map((day) => day.screenTime));
return { daysWithData, avg, avgString, minTime, maxTime };
}
20 changes: 16 additions & 4 deletions sitio/src/routes/+page.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type { PageServerLoad } from "./$types";
import { dayjs, likesCutoffSql } from "$lib/consts";
import { error } from "@sveltejs/kit";
import { getLastWeek } from "$lib/data-processing/weekly";
import { getStatsForDaysInTimePeriod } from "@/data-processing/days";

const tz = "America/Argentina/Buenos_Aires";

Expand Down Expand Up @@ -36,8 +37,9 @@ export const load: PageServerLoad = async ({ params, url, setHeaders }) => {
retweets,
tweets,
lastUpdated,
ultimaSemana,
firstLikedTweet,
monthData,
hasNextMonth,
] = await Promise.all([
db.query.likedTweets.findMany({
columns: {
Expand Down Expand Up @@ -95,12 +97,21 @@ export const load: PageServerLoad = async ({ params, url, setHeaders }) => {
where: isNotNull(schema.scraps.totalTweetsSeen),
}),

getLastWeek(startingFrom.startOf("day")),

db.query.likedTweets.findFirst({
orderBy: asc(schema.likedTweets.firstSeenAt),
where: likesCutoffSql,
}),
getStatsForDaysInTimePeriod(
db,
startingFrom.startOf("month"),
startingFrom.endOf("month"),
),
db.query.retweets.findFirst({
where: gte(
schema.retweets.retweetAt,
startingFrom.add(1, "month").toDate(),
),
}),
]);
const t1 = performance.now();
console.log("queries", t1 - t0);
Expand All @@ -118,8 +129,9 @@ export const load: PageServerLoad = async ({ params, url, setHeaders }) => {
})),
lastUpdated,
start: startingFrom.toDate(),
ultimaSemana,
firstLikedTweet,
monthData,
hasNextMonth: !!hasNextMonth,
query,
};
};
Loading

0 comments on commit 2b9a39c

Please sign in to comment.