diff --git a/src/Startpage/Clock/Clock.tsx b/src/Startpage/Clock/Clock.tsx
new file mode 100644
index 0000000..8eff763
--- /dev/null
+++ b/src/Startpage/Clock/Clock.tsx
@@ -0,0 +1,99 @@
+import { useEffect, useState } from "react"
+
+import styled from "@emotion/styled"
+
+import * as Settings from "../Settings/settingsHandler"
+
+const Greeting = styled.div`
+ font-size: 14px;
+ letter-spacing: 1px;
+ color: var(--accent-color);
+`
+
+const Time = styled.div`
+ font-size: 32px;
+ font-weight: 500;
+ font-variant-numeric: tabular-nums;
+`
+
+const DateLabel = styled.div`
+ font-size: 13px;
+ letter-spacing: 0.5px;
+ opacity: 0.7;
+`
+
+const ClockContainer = styled.div`
+ position: fixed;
+ top: 20px;
+ left: 24px;
+ display: flex;
+ flex-direction: column;
+ line-height: 1.15;
+ color: var(--default-color);
+ opacity: 0.5;
+ transition: 0.3s;
+ user-select: none;
+
+ :hover {
+ opacity: 1;
+
+ .clock-time {
+ animation: text-flicker 0.01s ease 0s infinite alternate;
+ }
+ }
+`
+
+const days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
+const months = [
+ "Jan",
+ "Feb",
+ "Mar",
+ "Apr",
+ "May",
+ "Jun",
+ "Jul",
+ "Aug",
+ "Sep",
+ "Oct",
+ "Nov",
+ "Dec",
+]
+
+const pad = (value: number) => String(value).padStart(2, "0")
+
+// Boundaries are subjective — tweak to taste.
+const greetingFor = (hour: number) => {
+ if (hour < 5) return "Good night"
+ if (hour < 12) return "Good morning"
+ if (hour < 17) return "Good afternoon"
+ if (hour < 21) return "Good evening"
+ return "Good night"
+}
+
+export const Clock = () => {
+ const [now, setNow] = useState(() => new Date())
+ const [settings] = useState(() => Settings.Clock.getWithFallback())
+
+ useEffect(() => {
+ const id = setInterval(() => setNow(new Date()), 1000)
+ return () => clearInterval(id)
+ }, [])
+
+ return (
+
+ {settings.showGreeting && (
+ {greetingFor(now.getHours())}
+ )}
+ {settings.showTime && (
+
+ )}
+ {settings.showDate && (
+
+ {days[now.getDay()]}, {now.getDate()} {months[now.getMonth()]}
+
+ )}
+
+ )
+}
diff --git a/src/Startpage/Settings/ClockSettings/ClockSettings.tsx b/src/Startpage/Settings/ClockSettings/ClockSettings.tsx
new file mode 100644
index 0000000..aff048a
--- /dev/null
+++ b/src/Startpage/Settings/ClockSettings/ClockSettings.tsx
@@ -0,0 +1,48 @@
+import { ToggleOption } from "../../../components/ToggleOption"
+import { ClockSettings as ClockSettingsType } from "../../../data/data"
+import {
+ StyledSettingsContent,
+ SettingElement,
+ SettingsLabel,
+} from "../SettingsWindow"
+
+interface props {
+ clockSettings: ClockSettingsType
+ setClockSettings: (clockSettings: ClockSettingsType) => void
+}
+
+export const ClockSettings = ({ clockSettings, setClockSettings }: props) => (
+
+ Clock
+
+
+
+ setClockSettings({ ...clockSettings, showGreeting: !disabled })
+ }
+ />
+
+
+
+
+ setClockSettings({ ...clockSettings, showTime: !disabled })
+ }
+ />
+
+
+
+
+ setClockSettings({ ...clockSettings, showDate: !disabled })
+ }
+ />
+
+
+)
diff --git a/src/Startpage/Settings/SettingsWindow.tsx b/src/Startpage/Settings/SettingsWindow.tsx
index 465ede0..9954e50 100644
--- a/src/Startpage/Settings/SettingsWindow.tsx
+++ b/src/Startpage/Settings/SettingsWindow.tsx
@@ -9,6 +9,7 @@ import {
} from "@fortawesome/free-solid-svg-icons"
import { Changelog } from "./Changelog/Changelog"
+import { ClockSettings } from "./ClockSettings/ClockSettings"
import { DesignSettings } from "./DesignSettings/DesignSettings"
import { LinkSettings } from "./LinkSettings/LinkSettings"
import { SearchSettings } from "./SearchSettings/SearchSettings"
@@ -123,7 +124,7 @@ const TabOption = styled.button<{ active: boolean }>`
}
`
-const TabOptions = ["Links", "Appearance", "Searchbar", "Changelog"]
+const TabOptions = ["Links", "Appearance", "Searchbar", "Clock", "Changelog"]
interface props {
hidePopup: () => void
@@ -137,12 +138,16 @@ export const SettingsWindow = ({ hidePopup }: props) => {
const [searchSettings, setSearchSettings] = useState(
Settings.Search.getWithFallback()
)
+ const [clockSettings, setClockSettings] = useState(
+ Settings.Clock.getWithFallback()
+ )
const applyValues = () => {
Settings.Design.set(design)
Settings.Themes.set(themes)
Settings.Search.set(searchSettings)
Settings.Links.set(linkGroups)
+ Settings.Clock.set(clockSettings)
window.location.reload()
}
@@ -184,6 +189,13 @@ export const SettingsWindow = ({ hidePopup }: props) => {
/>
)}
+ {currentTab === "Clock" && (
+
+ )}
+
{currentTab === "Changelog" && }
diff --git a/src/Startpage/Settings/settingsHandler.ts b/src/Startpage/Settings/settingsHandler.ts
index 10e2012..fb53053 100644
--- a/src/Startpage/Settings/settingsHandler.ts
+++ b/src/Startpage/Settings/settingsHandler.ts
@@ -2,11 +2,36 @@ import {
linkGroup,
Theme,
Search as SearchType,
+ ClockSettings as ClockType,
links,
searchSettings,
+ clockSettings,
themes,
} from "../../data/data"
+export const Clock = {
+ get: () => {
+ const lsClock = localStorage.getItem("clock-settings")
+ if (lsClock) return Clock.parse(lsClock)
+ return undefined
+ },
+ getWithFallback: () => {
+ try {
+ return Clock.get() ?? clockSettings
+ } catch {
+ console.error(
+ "Your currently applied clock settings appear to be corrupted."
+ )
+ return clockSettings
+ }
+ },
+
+ set: (clockSettings: ClockType) =>
+ localStorage.setItem("clock-settings", JSON.stringify(clockSettings)),
+
+ parse: (clockSettings: string) => JSON.parse(clockSettings) as ClockType,
+}
+
export const Search = {
get: () => {
const lsSearch = localStorage.getItem("search-settings")
diff --git a/src/Startpage/Startpage.tsx b/src/Startpage/Startpage.tsx
index fc735cb..29c9c87 100644
--- a/src/Startpage/Startpage.tsx
+++ b/src/Startpage/Startpage.tsx
@@ -2,6 +2,7 @@ import { useState } from "react"
import styled from "@emotion/styled"
+import { Clock } from "./Clock/Clock"
import { LinkContainer } from "./LinkContainer/LinkContainer"
import { Searchbar } from "./Searchbar/Searchbar"
import { Settings } from "./Settings/Settings"
@@ -47,6 +48,7 @@ export const Startpage = () => {
+
)
diff --git a/src/components/ToggleOption.tsx b/src/components/ToggleOption.tsx
new file mode 100644
index 0000000..522332a
--- /dev/null
+++ b/src/components/ToggleOption.tsx
@@ -0,0 +1,40 @@
+import styled from "@emotion/styled"
+
+const ToggleLabel = styled.label`
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ width: max-content;
+ color: var(--default-color);
+ cursor: pointer;
+ user-select: none;
+ transition: 0.3s;
+
+ :hover {
+ animation: circling-shadow-small 2s ease 0s infinite normal;
+ }
+`
+
+const ToggleCheckbox = styled.input`
+ width: 16px;
+ height: 16px;
+ accent-color: var(--accent-color);
+ cursor: pointer;
+`
+
+type props = {
+ label: string
+ checked: boolean
+ onChange: (checked: boolean) => void
+}
+
+export const ToggleOption = ({ label, checked, onChange }: props) => (
+
+ onChange(e.target.checked)}
+ />
+ {label}
+
+)
diff --git a/src/data/data.ts b/src/data/data.ts
index 5610108..4ae3495 100644
--- a/src/data/data.ts
+++ b/src/data/data.ts
@@ -198,6 +198,18 @@ export const searchSettings: Search = {
},
}
+export interface ClockSettings {
+ showGreeting: boolean
+ showTime: boolean
+ showDate: boolean
+}
+
+export const clockSettings: ClockSettings = {
+ showGreeting: true,
+ showTime: true,
+ showDate: true,
+}
+
export interface colorsType {
[key: string]: string
"--bg-color": string