generated from Klectr/KTemplate
Add minimap so user can tell where they are on page
This commit is contained in:
parent
d14b240333
commit
665e82ca43
@ -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)",
|
||||||
}}>
|
}}>
|
||||||
|
78
src/components/MiniMap.tsx
Normal file
78
src/components/MiniMap.tsx
Normal 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 >
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -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`,
|
||||||
|
@ -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"
|
||||||
|
@ -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
6
src/utils/enums.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
export enum LayerEnum {
|
||||||
|
BACKGROUND,
|
||||||
|
CARD,
|
||||||
|
CARD_ELEVATED,
|
||||||
|
MINIMAP,
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user