add support for dark/light modes

This commit is contained in:
Triston Armstrong 2024-10-06 23:30:20 -04:00
parent c5abeb7a31
commit 39b13b6dcb
8 changed files with 31 additions and 37 deletions

View File

@ -3,6 +3,7 @@
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="color-scheme" content="light dark" />
<title>KlectrTemplate</title> <title>KlectrTemplate</title>
</head> </head>

View File

@ -4,6 +4,7 @@ import { useDebounce } from "../utils/useDebounce"
import { LayerEnum } from "../utils/enums" import { LayerEnum } from "../utils/enums"
import images, { ImageCardType } from "../signals/images" import images, { ImageCardType } from "../signals/images"
import { updateLocalStorage } from "../utils/localStorage" import { updateLocalStorage } from "../utils/localStorage"
import { isTheme } from "../utils/isTheme"
namespace ImageCard { namespace ImageCard {
export interface ImageCardProps { export interface ImageCardProps {
@ -90,7 +91,7 @@ export function ImageCard({ key: itemKey, data: item }: ImageCard.ImageCardProps
return ( return (
<div <div
onmousedown={_handleMouseDown} onmousedown={_handleMouseDown}
className="select-none transition flex flex-col justify-stretch shadow-lg rounded border border-[#3c3c3c] absolute" className="select-none transition flex flex-col justify-stretch shadow-md rounded border border-[#1c1c1c] absolute"
style={{ style={{
zIndex: `${focusedItem.value == itemKey ? LayerEnum.CARD_ELEVATED : LayerEnum.CARD}`, zIndex: `${focusedItem.value == itemKey ? LayerEnum.CARD_ELEVATED : LayerEnum.CARD}`,
top: `${item.position.y}px`, top: `${item.position.y}px`,
@ -104,7 +105,7 @@ export function ImageCard({ key: itemKey, data: item }: ImageCard.ImageCardProps
backgroundPosition: 'center' backgroundPosition: 'center'
}} }}
> >
<button className="flex justify-center items-center hover:bg-blue-500 w-5 h-5 text-white text-md absolute right-0 top-0" onclick={(_e: Event) => { <button className="flex justify-center items-center hover:bg-blue-500 rounded w-5 h-5 dark:text-[#777] dark:hover:text-white text-white text-md absolute right-0 top-0" onclick={(_e: Event) => {
ImagesSignal.default.removeImage(item.id) ImagesSignal.default.removeImage(item.id)
ImagesSignal.default.images.notify() ImagesSignal.default.images.notify()
debounceLSUpdate() debounceLSUpdate()
@ -128,7 +129,7 @@ function ExpandIcon({ cb }: {
height="24" height="24"
viewBox="0 0 24 24" viewBox="0 0 24 24"
fill="none" fill="none"
stroke="#333" stroke={isTheme('dark') ? "#777" : "#999"}
stroke-width="1" stroke-width="1"
stroke-linecap="round" stroke-linecap="round"
stroke-linejoin="round" stroke-linejoin="round"

View File

@ -6,6 +6,7 @@ import { MiniMap } from "./MiniMap"
import { ImageCard } from "./ImageCard" import { ImageCard } from "./ImageCard"
import images from "../signals/images" import images from "../signals/images"
import { CardSelector } from "./cardSelector/CardSelector" import { CardSelector } from "./cardSelector/CardSelector"
import { isTheme } from "../utils/isTheme"
export default function InfiniteCanvas() { export default function InfiniteCanvas() {
const containerRef = useRef<HTMLDivElement>(null) const containerRef = useRef<HTMLDivElement>(null)
@ -42,13 +43,13 @@ export default function InfiniteCanvas() {
className="h-screen w-full absolute top-0 left-0" className="h-screen w-full absolute top-0 left-0"
> >
<div <div
className="absolute top-0 left-0" className="dark:bg-black absolute top-0 left-0"
ref={containerRef} ref={containerRef}
style={{ style={{
width: `${canvasDimentsion.value.width}px`, width: `${canvasDimentsion.value.width}px`,
height: `${canvasDimentsion.value.width}px`, height: `${canvasDimentsion.value.width}px`,
backgroundSize: "30px 30px", backgroundSize: "30px 30px",
backgroundImage: "radial-gradient(circle, rgba(255, 255, 255, 0.2) 1px, transparent 1px)", backgroundImage: `radial-gradient(circle, rgba(${isTheme('dark') ? '255, 255, 255, 0.2' : '0, 0, 0, 0.2'}) 1px, transparent 1px)`,
}}> }}>
{Object.keys(NotesSigal.default.notes.value).map((itemKey: string) => { {Object.keys(NotesSigal.default.notes.value).map((itemKey: string) => {
const item = NotesSigal.default.notes.value[itemKey] const item = NotesSigal.default.notes.value[itemKey]

View File

@ -34,15 +34,14 @@ export function MiniMap() {
return ( return (
<div ref={el} style={{ <div
position: 'fixed', className="dark:bg-[#ffffff11] bg-[#0001] fixed rounded"
backgroundColor: '#ffffff11', ref={el} style={{
width: `${width}px`, width: `${width}px`,
height: `${height}px`, height: `${height}px`,
translate: `${xPos}px ${yPos}px`, translate: `${xPos}px ${yPos}px`,
zIndex: `${LayerEnum.MINIMAP}`, zIndex: `${LayerEnum.MINIMAP}`,
borderRadius: '4px' }}>
}}>
{Object.keys(images.images.value).map((imageKey: ImageCardType['id']) => { {Object.keys(images.images.value).map((imageKey: ImageCardType['id']) => {
const image = images.images.value[imageKey] const image = images.images.value[imageKey]
@ -57,16 +56,13 @@ export function MiniMap() {
} }
return ( return (
<div ref={el} className={"bg-green-500 hover:bg-blue-500 cursor-pointer"} <div ref={el} className={"absolute dark:bg-green-500 bg-green-300 dark:hover:bg-blue-500 hover:bg-blue-300 cursor-pointer border dark:border-[#222] border-green-500 rounded"}
onclick={_handleItemClick} onclick={_handleItemClick}
style={{ style={{
position: 'absolute',
width: `${image.dimensions.w / _MAP_SCALE_FACTOR}px`, width: `${image.dimensions.w / _MAP_SCALE_FACTOR}px`,
height: `${image.dimensions.h / _MAP_SCALE_FACTOR}px`, height: `${image.dimensions.h / _MAP_SCALE_FACTOR}px`,
top: `${(image.position.y / _MAP_SCALE_FACTOR)}px`, top: `${(image.position.y / _MAP_SCALE_FACTOR)}px`,
left: `${(image.position.x / _MAP_SCALE_FACTOR)}px`, left: `${(image.position.x / _MAP_SCALE_FACTOR)}px`,
border: '1px solid #222',
borderRadius: '2px',
zIndex: `${LayerEnum.MINIMAP + 1}` zIndex: `${LayerEnum.MINIMAP + 1}`
}} }}
></div> ></div>
@ -86,16 +82,13 @@ export function MiniMap() {
} }
return ( return (
<div className={"bg-gray-500 hover:bg-blue-500 cursor-pointer"} <div className={"absolute dark:bg-gray-500 bg-gray-300 hover:bg-blue-500 cursor-pointer border dark:border-[#222] border-gray-500 rounded"}
onclick={_handleItemClick} onclick={_handleItemClick}
style={{ style={{
position: 'absolute',
width: `${note.dimensions.w / _MAP_SCALE_FACTOR}px`, width: `${note.dimensions.w / _MAP_SCALE_FACTOR}px`,
height: `${note.dimensions.h / _MAP_SCALE_FACTOR}px`, height: `${note.dimensions.h / _MAP_SCALE_FACTOR}px`,
top: `${(note.position.y / _MAP_SCALE_FACTOR)}px`, top: `${(note.position.y / _MAP_SCALE_FACTOR)}px`,
left: `${(note.position.x / _MAP_SCALE_FACTOR)}px`, left: `${(note.position.x / _MAP_SCALE_FACTOR)}px`,
border: '1px solid #222',
borderRadius: '2px',
zIndex: `${LayerEnum.MINIMAP + 1}` zIndex: `${LayerEnum.MINIMAP + 1}`
}} }}
></div> ></div>
@ -103,16 +96,13 @@ export function MiniMap() {
})} })}
<div <div
className={'bg-blue-200 bg-opacity-10'} className={'absolute bg-blue-200 bg-opacity-10 border dark:border-blue-800 border-blue-500 bg-blue-500 rounded'}
style={{ style={{
position: 'absolute',
width: `${viewportWidth / _MAP_SCALE_FACTOR}px`, width: `${viewportWidth / _MAP_SCALE_FACTOR}px`,
height: `${viewportHeight / _MAP_SCALE_FACTOR}px`, height: `${viewportHeight / _MAP_SCALE_FACTOR}px`,
top: `${scrollY.value / _MAP_SCALE_FACTOR}px`, top: `${scrollY.value / _MAP_SCALE_FACTOR}px`,
left: `${scrollX.value / _MAP_SCALE_FACTOR}px`, left: `${scrollX.value / _MAP_SCALE_FACTOR}px`,
border: '1px solid #777', zIndex: `${LayerEnum.MINIMAP * 1000}`,
zIndex: `${LayerEnum.MINIMAP}`,
borderRadius: '2px'
}}></div> }}></div>
</div > </div >
) )

View File

@ -3,6 +3,7 @@ import { NotesSigal, focusedItem } from "../signals"
import { useDebounce } from "../utils/useDebounce" import { useDebounce } from "../utils/useDebounce"
import notes, { NoteCardType } from "../signals/notes" import notes, { NoteCardType } from "../signals/notes"
import { LayerEnum } from "../utils/enums" import { LayerEnum } from "../utils/enums"
import { isTheme } from "../utils/isTheme"
namespace NoteCard { namespace NoteCard {
export interface NoteCardProps { export interface NoteCardProps {
@ -88,31 +89,30 @@ export function NoteCard({ key: itemKey, data: item }: NoteCard.NoteCardProps) {
return ( return (
<div <div
onmousedown={() => focusedItem.value = itemKey} onmousedown={() => focusedItem.value = itemKey}
className="select-none transition flex flex-col justify-stretch shadow-lg rounded border border-[#3c3c3c] absolute" className="text-[#333] dark:bg-[#111] dark:border-[#1c1c1c] bg-[#eee] select-none transition flex flex-col justify-stretch shadow-md rounded border border-[#ddd] absolute"
style={{ style={{
zIndex: `${focusedItem.value == itemKey ? LayerEnum.CARD_ELEVATED : LayerEnum.CARD}`, zIndex: `${focusedItem.value == itemKey ? LayerEnum.CARD_ELEVATED : LayerEnum.CARD}`,
width: `${item.dimensions.w}px`, width: `${item.dimensions.w}px`,
height: `${item.dimensions.h}px`, height: `${item.dimensions.h}px`,
top: `${item.position.y}px`, top: `${item.position.y}px`,
left: `${item.position.x}px`, left: `${item.position.x}px`,
backgroundColor: '#181818',
}} }}
> >
<div className="flex-1 flex flex-col gap-1"> <div className="flex-1 flex flex-col gap-1">
<div className="px-2 flex justify-between items-center cursor-move" onmousedown={_handleMouseDown}> <div className="px-2 flex justify-between items-center cursor-move" onmousedown={_handleMouseDown}>
<div style={{ <div style={{
opacity: saved.value ? '0' : '100' opacity: saved.value ? '0' : '100'
}} className={`rounded-full w-1 h-1 bg-white`}></div> }} className={`rounded-full w-1 h-1 dark:bg-white bg-green-500`}></div>
<button className="text-md" onclick={(_e: Event) => { <button className="text-md dark:text-[#777] text-black" onclick={(_e: Event) => {
NotesSigal.default.removeNote(item.id) NotesSigal.default.removeNote(item.id)
NotesSigal.default.notes.notify() NotesSigal.default.notes.notify()
updateLocalStorage() updateLocalStorage()
}}>x</button> }}>x</button>
</div> </div>
<hr className="border border-[#3c3c3c]" /> <hr className="border dark:border-[#1c1c1c] border-[#ddd]" />
<textarea <textarea
placeholder={"Todo: put some note here"} placeholder={"Todo: put some note here"}
className="flex resize-none px-2 w-full h-full bg-transparent resize-none focus:outline-none text-gray-300" className="flex resize-none px-2 w-full h-full bg-transparent resize-none focus:outline-none dark:text-gray-300"
value={item.contents} value={item.contents}
onkeypress={() => { saved.value = false }} onkeypress={() => { saved.value = false }}
onchange={(e) => { onchange={(e) => {
@ -142,7 +142,7 @@ function ExpandIcon({ cb }: {
height="24" height="24"
viewBox="0 0 24 24" viewBox="0 0 24 24"
fill="none" fill="none"
stroke="#333" stroke={isTheme('dark') ? "#777" : "#999"}
stroke-width="1" stroke-width="1"
stroke-linecap="round" stroke-linecap="round"
stroke-linejoin="round" stroke-linejoin="round"

View File

@ -10,7 +10,7 @@ export function CardSelector() {
return ( return (
<div <div
ref={containerRef} ref={containerRef}
className="z-50 flex gap-1 border border-[#9c9c9c] rounded-full fixed px-4 bg-[#181818] top-2 py-1 shadow-xl" className="z-50 flex gap-1 border dark:border-[#3c3c3c] border-[#ddd] rounded-full fixed px-4 dark:bg-[#222] bg-[#eee] top-2 py-1 shadow-md"
style={{ style={{
left: `${window.innerWidth / 2 - (containerRef.current?.getBoundingClientRect().width ?? 1) / 2}px` left: `${window.innerWidth / 2 - (containerRef.current?.getBoundingClientRect().width ?? 1) / 2}px`
}}> }}>

View File

@ -23,11 +23,9 @@ html {
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
-webkit-text-size-adjust: 100%; -webkit-text-size-adjust: 100%;
color: white;
} }
body { body {
margin: 0; margin: 0;
padding: 0; padding: 0;
background-color: #111;
} }

3
src/utils/isTheme.ts Normal file
View File

@ -0,0 +1,3 @@
export function isTheme(value: "light" | "dark") {
return window.matchMedia(`(prefers-color-scheme: ${value})`).matches
}