feat/hotkeys #11

Merged
tristonarmstrong merged 4 commits from feat/hotkeys into main 2024-10-22 18:31:52 +00:00
2 changed files with 160 additions and 54 deletions

View File

@ -1,4 +1,4 @@
import { signal, useRef } from "kaioken" import { signal, useCallback, useEffect, useRef } from "kaioken"
import { NotesSigal, focusedItem } from "../signals" 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"
@ -10,6 +10,7 @@ import { Divider } from "./Divider"
import { ExportIcon } from "./icons/ExportIcon" import { ExportIcon } from "./icons/ExportIcon"
import { createFileAndExport } from "../utils/createFileAndExport" import { createFileAndExport } from "../utils/createFileAndExport"
import { ContextMenuPortal } from "./ContextMenuPortal" import { ContextMenuPortal } from "./ContextMenuPortal"
import { HelpIcon } from "./icons/HelpIcon"
namespace NoteCard { namespace NoteCard {
export interface NoteCardProps { export interface NoteCardProps {
@ -28,6 +29,7 @@ export function NoteCard({ key: itemKey, data: item }: NoteCard.NoteCardProps) {
const initialResizeX = useRef(0) const initialResizeX = useRef(0)
const initialResizeY = useRef(0) const initialResizeY = useRef(0)
const openContextMenu = signal(false) const openContextMenu = signal(false)
const showHelp = signal(false)
const { debounce } = useDebounce() const { debounce } = useDebounce()
@ -111,10 +113,14 @@ export function NoteCard({ key: itemKey, data: item }: NoteCard.NoteCardProps) {
focusedItem.value = itemKey focusedItem.value = itemKey
} }
function _handleExportClick(_e: MouseEvent) { function _exportFile() {
createFileAndExport("Note", item.contents, "text/markdown") createFileAndExport("Note", item.contents, "text/markdown")
} }
function _handleExportClick(_e: MouseEvent) {
_exportFile()
}
function _handleMouseClick(e: MouseEvent) { function _handleMouseClick(e: MouseEvent) {
e.preventDefault() e.preventDefault()
openContextMenu.value = !openContextMenu.value openContextMenu.value = !openContextMenu.value
@ -124,6 +130,49 @@ export function NoteCard({ key: itemKey, data: item }: NoteCard.NoteCardProps) {
openContextMenu.value = false openContextMenu.value = false
} }
function _handleHelpHover() {
if (showHelp.value) return
showHelp.value = true
}
function _handleHelpOut() {
if (!showHelp.value) return
showHelp.value = false
}
const _handleKeyDown = useCallback((e: KeyboardEvent) => {
if (!e.ctrlKey) return
// TODO: add support for other os
// TODO: add modal popup
switch (e.key) {
case 'Delete':
e.preventDefault()
_handleClose(e)
break
case 'Backspace':
e.preventDefault()
_handleClose(e)
break
case 'e':
e.preventDefault()
_exportFile()
break
default:
break
}
}, [itemKey, item.position, NotesSigal.default])
useEffect(() => {
if (focusedItem.value !== itemKey) return
window.addEventListener('keydown', _handleKeyDown)
return () => {
window.removeEventListener('keydown', _handleKeyDown)
}
}, [focusedItem.value, itemKey])
const cardPositionStyle = { const cardPositionStyle = {
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`,
@ -137,6 +186,7 @@ export function NoteCard({ key: itemKey, data: item }: NoteCard.NoteCardProps) {
} }
return ( return (
<>
<div <div
oncontextmenu={_handleMouseClick} oncontextmenu={_handleMouseClick}
onmousedown={_handleFocusCard} onmousedown={_handleFocusCard}
@ -146,8 +196,11 @@ export function NoteCard({ key: itemKey, data: item }: NoteCard.NoteCardProps) {
<div className="overflow-hidden flex-1 flex flex-col gap-1"> <div className="overflow-hidden flex-1 flex flex-col gap-1">
{/* Header Bar */} {/* Header Bar */}
<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 className={"flex gap-1 items-center"}>
<HelpIcon onMouseOver={_handleHelpHover} onMouseOut={_handleHelpOut} />
{/* Save indicator*/}
<div style={saveIndicatorStyle} className="rounded-full w-1 h-1 dark:bg-white bg-green-500"></div> <div style={saveIndicatorStyle} className="rounded-full w-1 h-1 dark:bg-white bg-green-500"></div>
</div>
<div className="flex gap-2"> <div className="flex gap-2">
<div <div
onclick={_handleExportClick} onclick={_handleExportClick}
@ -199,6 +252,23 @@ export function NoteCard({ key: itemKey, data: item }: NoteCard.NoteCardProps) {
</ContextMenuPortal> </ContextMenuPortal>
</div > </div >
{/* HOTKEY PAPER */}
{showHelp.value &&
<div
className={"text-white absolute bg-[#1c1c1c] rounded-md p-1 z-[1000] border border-blue-500"}
style={{
top: `${item.position.y}px`,
left: `${item.position.x - 120}px`
}}
>
<div className="flex flex-col text-sm dark:text-[#999] text-black">
<small>ctrl + del = delete</small>
<small>ctrl + back = delete</small>
<small>ctrl + e = export</small>
</div>
</div>
}
</>
) )
} }
@ -228,3 +298,4 @@ function ExpandIcon({ cb }: {
) )
} }

View File

@ -0,0 +1,35 @@
namespace HelpIcon {
export interface Props {
onMouseOver?: () => void
onMouseOut?: () => void
}
}
export function HelpIcon({ onMouseOver, onMouseOut }: HelpIcon.Props) {
return (
<svg
onmouseout={onMouseOut}
onmouseover={onMouseOver}
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
className="w-4 h-4 hover:text-blue-500 cursor-pointer"
>
<circle
cx="12"
cy="12"
r="10"
/>
<path
d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3" />
<path
d="M12 17h.01"
/>
</svg>)
}