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