Add minimap so user can tell where they are on page

This commit is contained in:
Triston Armstrong 2024-10-05 10:14:00 -04:00
parent d14b240333
commit 665e82ca43
7 changed files with 103 additions and 16 deletions

BIN
bun.lockb

Binary file not shown.

View File

@ -1,32 +1,31 @@
import { useState, useRef, useEffect } from "kaioken" import { useRef, useEffect } from "kaioken"
import { CardSelector } from "./CardSelector" import { CardSelector } from "./CardSelector"
import { NotesSigal } from "../signals" import { NotesSigal, canvasDimentsion } from "../signals"
import { NoteCard } from "./NoteCard" import { NoteCard } from "./NoteCard"
import notes from "../signals/notes" import notes from "../signals/notes"
import { MiniMap } from "./MiniMap"
export default function InfiniteCanvas() { export default function InfiniteCanvas() {
const [dimensions, setDimensions] = useState({ width: 3000, height: 3000 })
const containerRef = useRef<HTMLDivElement>(null) const containerRef = useRef<HTMLDivElement>(null)
useEffect(() => { useEffect(() => {
window.scrollTo({ window.scrollTo({
left: (dimensions.width / 2) - (window.innerWidth / 2), left: (canvasDimentsion.value.width / 2) - (window.innerWidth / 2),
top: (dimensions.height / 2) - (window.innerHeight / 2) top: (canvasDimentsion.value.height / 2) - (window.innerHeight / 2)
}) })
const updateDimensions = () => { const updateDimensions = () => {
setDimensions((prevDimensions) => ({ canvasDimentsion.value = {
width: Math.max(prevDimensions.width, window.innerWidth), width: Math.max(canvasDimentsion.value.width, window.innerWidth),
height: Math.max(prevDimensions.height, window.innerHeight), height: Math.max(canvasDimentsion.value.height, window.innerHeight),
})) }
} }
updateDimensions() updateDimensions()
window.addEventListener("resize", updateDimensions) window.addEventListener("resize", updateDimensions)
notes.loadLocalStorage() notes.loadLocalStorage()
return () => { return () => {
window.removeEventListener("resize", updateDimensions) window.removeEventListener("resize", updateDimensions)
} }
@ -35,6 +34,7 @@ export default function InfiniteCanvas() {
return ( return (
<> <>
<CardSelector /> <CardSelector />
<MiniMap />
<div <div
className="h-screen w-full absolute top-0 left-0" className="h-screen w-full absolute top-0 left-0"
@ -43,8 +43,8 @@ export default function InfiniteCanvas() {
className="absolute top-0 left-0" className="absolute top-0 left-0"
ref={containerRef} ref={containerRef}
style={{ style={{
width: `${dimensions.width.toString()}px`, width: `${canvasDimentsion.value.width}px`,
height: `${dimensions.width.toString()}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(255, 255, 255, 0.2) 1px, transparent 1px)",
}}> }}>

View File

@ -0,0 +1,78 @@
import { signal, useEffect, useRef } from "kaioken"
import notes from "../signals/notes"
import { Card } from "../types/Card"
import { canvasDimentsion } from "../signals"
import { LayerEnum } from "../utils/enums"
const _MAP_OFFSET = 20
const _MAP_SCALE_FACTOR = 10
const _defaults = { width: 0, height: 0 }
export function MiniMap() {
const el = useRef<HTMLDivElement>(null)
const scrollX = signal(0)
const scrollY = signal(0)
const elMeta = el.current?.getBoundingClientRect() ?? _defaults
const viewportWidth = window.innerWidth
const viewportHeight = window.innerHeight
const xPos = viewportWidth - elMeta?.width - _MAP_OFFSET
const yPos = viewportHeight - elMeta.height - _MAP_OFFSET
const width = canvasDimentsion.value.width / _MAP_SCALE_FACTOR
const height = canvasDimentsion.value.height / _MAP_SCALE_FACTOR
useEffect(() => {
function _handleScroll(_e: Event) {
scrollX.value = window.scrollX
scrollY.value = window.scrollY
}
window.addEventListener('scroll', _handleScroll)
return () => window.removeEventListener('scroll', _handleScroll)
}, [])
return (
<div ref={el} style={{
position: 'fixed',
backgroundColor: '#ffffff11',
width: `${width}px`,
height: `${height}px`,
translate: `${xPos}px ${yPos}px`,
zIndex: `${LayerEnum.MINIMAP}`,
borderRadius: '4px'
}}>
{Object.keys(notes.notes.value).map((noteKey: Card['id']) => {
const note = notes.notes.value[noteKey]
return (
<div
style={{
position: 'absolute',
width: `${note.dimensions.w / _MAP_SCALE_FACTOR}px`,
height: `${note.dimensions.h / _MAP_SCALE_FACTOR}px`,
top: `${(note.position.y / _MAP_SCALE_FACTOR)}px`,
left: `${(note.position.x / _MAP_SCALE_FACTOR)}px`,
backgroundColor: "#666",
border: '1px solid #222',
borderRadius: '2px'
}}
></div>
)
})}
<div style={{
position: 'absolute',
width: `${viewportWidth / _MAP_SCALE_FACTOR}px`,
height: `${viewportHeight / _MAP_SCALE_FACTOR}px`,
top: `${scrollY.value / _MAP_SCALE_FACTOR}px`,
left: `${scrollX.value / _MAP_SCALE_FACTOR}px`,
border: '1px solid #777',
zIndex: `${LayerEnum.MINIMAP}`,
backgroundColor: '#fff1',
borderRadius: '2px'
}}></div>
</div >
)
}

View File

@ -3,7 +3,7 @@ import { NotesSigal, focusedItem } from "../signals"
import { Card } from "../types" import { Card } from "../types"
import { useDebounce } from "../utils/useDebounce" import { useDebounce } from "../utils/useDebounce"
import notes from "../signals/notes" import notes from "../signals/notes"
import { save } from "@tauri-apps/api/dialog" import { LayerEnum } from "../utils/enums"
namespace NoteCard { namespace NoteCard {
export interface NoteCardProps { export interface NoteCardProps {
@ -56,14 +56,12 @@ export function NoteCard({ key: itemKey, data: item }: NoteCard.NoteCardProps) {
window.addEventListener('mouseup', _handleMouseUp) window.addEventListener('mouseup', _handleMouseUp)
} }
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="select-none transition flex flex-col justify-stretch shadow-lg rounded border border-[#3c3c3c] absolute"
style={{ style={{
zIndex: focusedItem.value == itemKey ? '999' : '0', 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`,

View File

@ -2,5 +2,6 @@ import { signal } from "kaioken"
/** this should be an ID of some card/item */ /** this should be an ID of some card/item */
export const focusedItem = signal<string | null>(null) export const focusedItem = signal<string | null>(null)
export const canvasDimentsion = signal({ width: 3000, height: 3000 })
export * as NotesSigal from "./notes" export * as NotesSigal from "./notes"

View File

@ -8,6 +8,10 @@
box-sizing: border-box; box-sizing: border-box;
} }
*::-webkit-scrollbar {
display: none;
}
html { html {
overflow: scroll; overflow: scroll;
} }

6
src/utils/enums.ts Normal file
View File

@ -0,0 +1,6 @@
export enum LayerEnum {
BACKGROUND,
CARD,
CARD_ELEVATED,
MINIMAP,
}