diff --git a/index.html b/index.html
index f2c5ab4..7d5b322 100644
--- a/index.html
+++ b/index.html
@@ -2,7 +2,6 @@
-
Work Hours Tracker
diff --git a/public/favicon/initial.ico b/public/favicon/initial.ico
new file mode 100644
index 0000000..d62c8f9
Binary files /dev/null and b/public/favicon/initial.ico differ
diff --git a/public/favicon/on-break.ico b/public/favicon/on-break.ico
new file mode 100644
index 0000000..a441db6
Binary files /dev/null and b/public/favicon/on-break.ico differ
diff --git a/public/favicon/working.ico b/public/favicon/working.ico
new file mode 100644
index 0000000..1e4fc16
Binary files /dev/null and b/public/favicon/working.ico differ
diff --git a/src/App.svelte b/src/App.svelte
index ddf613f..9da338b 100644
--- a/src/App.svelte
+++ b/src/App.svelte
@@ -4,6 +4,7 @@
import { type User } from "./lib/tracker";
import WorkdayForm from "./ui/WorkdayForm.svelte";
import { getDatabase } from "./lib/database";
+ import Favicon from "./ui/Favicon.svelte";
let user: User | null = $state(null);
@@ -30,6 +31,12 @@
}
+
+ {#if !user}
+
+ {/if}
+
+
Welcome {user ? user.settings.username : "to Work Hours Tracker"}
diff --git a/src/ui/Favicon.svelte b/src/ui/Favicon.svelte
new file mode 100644
index 0000000..29cd2e0
--- /dev/null
+++ b/src/ui/Favicon.svelte
@@ -0,0 +1,9 @@
+
+
+
diff --git a/src/ui/Status.svelte b/src/ui/Status.svelte
new file mode 100644
index 0000000..8a74adb
--- /dev/null
+++ b/src/ui/Status.svelte
@@ -0,0 +1,38 @@
+
+
+{mapping[getStatusClass()]}
+
+
diff --git a/src/ui/WorkdayEvents.svelte b/src/ui/WorkdayEvents.svelte
index 18a47fd..fc14508 100644
--- a/src/ui/WorkdayEvents.svelte
+++ b/src/ui/WorkdayEvents.svelte
@@ -21,7 +21,7 @@
{#if type === "start-workday"}
Workday Started
{:else if type === "break-ongoing"}
- On Break
+ Break started
{:else if type === "break"}
Break
{:else if type === "end-workday"}
diff --git a/src/ui/WorkdayForm.svelte b/src/ui/WorkdayForm.svelte
index 24c592f..d2b18b2 100644
--- a/src/ui/WorkdayForm.svelte
+++ b/src/ui/WorkdayForm.svelte
@@ -2,6 +2,8 @@
import { createTracker, type User } from "../lib/tracker";
import Button from "./Button.svelte";
import ConfirmationModal from "./ConfirmationModal.svelte";
+ import Favicon from "./Favicon.svelte";
+ import Status from "./Status.svelte";
import WorkdayEvents from "./WorkdayEvents.svelte";
import WorkDuration from "./WorkDuration.svelte";
@@ -26,6 +28,18 @@
}
+
+
+
+
+
+
{#if tracker.hasWorkdayStarted()}
{/if}
diff --git a/tests/e2e.spec.ts b/tests/e2e.spec.ts
index d6d906e..dcab8bf 100644
--- a/tests/e2e.spec.ts
+++ b/tests/e2e.spec.ts
@@ -4,6 +4,10 @@ test("first visit, full workday", async ({ page }) => {
await page.goto("/");
await expect(page).toHaveTitle("Work Hours Tracker");
+ await expect(page.getByTestId("favicon")).toHaveAttribute(
+ "href",
+ "/work-hours-tracker/favicon/initial.ico",
+ );
await expect(
page.getByRole("heading", { name: "Welcome to Work Hours Tracker" }),
).toBeVisible();
@@ -36,6 +40,18 @@ test("first visit, full workday", async ({ page }) => {
page.getByRole("button", { name: "End Workday" }),
).toBeDisabled();
+ await expect(page.getByText("Not working")).toBeVisible();
+ await expect(page.getByText("Not working")).toHaveCSS(
+ "color",
+ "rgb(255, 0, 0)",
+ );
+
+ // Favicon updated
+ await expect(page.getByTestId("favicon")).toHaveAttribute(
+ "href",
+ "/work-hours-tracker/favicon/initial.ico",
+ );
+
// Workday starts at 8:05:00
await page.clock.setFixedTime(new Date(2025, 2, 2, 8, 5, 0));
await page.getByRole("button", { name: "Start Workday" }).click();
@@ -45,6 +61,15 @@ test("first visit, full workday", async ({ page }) => {
).toBeDisabled();
await expect(page.getByRole("button", { name: "Start Break" })).toBeEnabled();
await expect(page.getByRole("button", { name: "End Workday" })).toBeEnabled();
+ await expect(page.getByText("Working")).toBeVisible();
+ await expect(page.getByText("Working")).toHaveCSS(
+ "color",
+ "rgb(127, 255, 0)",
+ );
+ await expect(page.getByTestId("favicon")).toHaveAttribute(
+ "href",
+ "/work-hours-tracker/favicon/working.ico",
+ );
// Take a break at 8:35:00
await page.clock.setFixedTime(new Date(2025, 2, 2, 8, 35, 0));
@@ -60,6 +85,15 @@ test("first visit, full workday", async ({ page }) => {
page.getByRole("button", { name: "Start Break" }),
).not.toBeVisible();
await expect(page.getByRole("button", { name: "End Break" })).toBeVisible();
+ await expect(page.getByText("On break")).toBeVisible();
+ await expect(page.getByText("On break")).toHaveCSS(
+ "color",
+ "rgb(255, 234, 0)",
+ );
+ await expect(page.getByTestId("favicon")).toHaveAttribute(
+ "href",
+ "/work-hours-tracker/favicon/on-break.ico",
+ );
// End the break at 9:05:00
await page.clock.setFixedTime(new Date(2025, 2, 2, 9, 5, 0));
@@ -89,6 +123,10 @@ test("first visit, full workday", async ({ page }) => {
page.getByRole("button", { name: "Yes, I'm done for today" }),
).toBeVisible();
await expect(page.getByRole("button", { name: "Cancel" })).toBeVisible();
+ await expect(page.getByTestId("favicon")).toHaveAttribute(
+ "href",
+ "/work-hours-tracker/favicon/working.ico",
+ );
await page.getByRole("button", { name: "Yes, I'm done for today" }).click();
@@ -115,6 +153,15 @@ test("first visit, full workday", async ({ page }) => {
await expect(
page.getByRole("button", { name: "End Workday" }),
).toBeDisabled();
+ await expect(page.getByText("Not working")).toBeVisible();
+ await expect(page.getByText("Not working")).toHaveCSS(
+ "color",
+ "rgb(255, 0, 0)",
+ );
+ await expect(page.getByTestId("favicon")).toHaveAttribute(
+ "href",
+ "/work-hours-tracker/favicon/initial.ico",
+ );
});
test("User data persists through reloads", async ({ page }) => {