fixed note editor, dropdown is suck use modal instead
This commit is contained in:
parent
7ff1b1f81d
commit
e66eeb961b
@ -7,6 +7,7 @@ import EvoDropDown from "../forms/EvoDropDown";
|
||||
import Button from "../forms/Button";
|
||||
import { pitch } from "../../data/melodies";
|
||||
import { PatchPiezoMusic } from "../../controllers/BoardController";
|
||||
import SearchItemModal from "../modals/SearchItemModal";
|
||||
|
||||
function getNoteItems () {
|
||||
const pitches = Object.keys(pitch);
|
||||
@ -45,6 +46,7 @@ function NoteItem ({note, index, parentIndex}: { note: string, index: number, pa
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
className="min-w-40 h-40 transition border group border-border rounded-lg animate-size-fade-in relative"
|
||||
>
|
||||
@ -65,13 +67,22 @@ function NoteItem ({note, index, parentIndex}: { note: string, index: number, pa
|
||||
<div className="text-xl">
|
||||
{note}
|
||||
</div>
|
||||
<EvoDropDown.Menu
|
||||
{/* <EvoDropDown.Menu
|
||||
className="!w-44 top-0 h-40 z-30 overflow-y-scroll v-scrollbar left-2"
|
||||
appear={dropAppear}
|
||||
items={noteItems}
|
||||
onValueChange={handleChange}
|
||||
/>
|
||||
/> */}
|
||||
</button>
|
||||
|
||||
{dropAppear == true && <SearchItemModal
|
||||
name="Piezo"
|
||||
items={noteItems}
|
||||
initItem={{ name: note.replace("S", "#"), value: note.replace("S", "#") }}
|
||||
onValueChange={handleChange}
|
||||
onClose={toggleDropdown}
|
||||
/>}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@ -84,23 +95,32 @@ function NotePlus ({ parentIndex }: { parentIndex: number }) {
|
||||
|
||||
const handleAddNote = (item: { name: string, value: any }) => {
|
||||
addNote(parentIndex, item.value);
|
||||
setApper(false);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<button className="border border-border bg-secondary-solid rounded-lg min-w-40 h-40" onClick={toggleDropdown}>
|
||||
<i className="bi bi-plus text-2xl"></i>
|
||||
<EvoDropDown.Menu
|
||||
{/* <EvoDropDown.Menu
|
||||
className="!w-32 top-0 h-56 z-30 overflow-y-scroll v-scrollbar"
|
||||
appear={dropAppear}
|
||||
items={noteItems}
|
||||
onValueChange={handleAddNote}
|
||||
/>
|
||||
/> */}
|
||||
</button>
|
||||
{dropAppear == true && <SearchItemModal
|
||||
name="Piezo"
|
||||
items={noteItems}
|
||||
onValueChange={handleAddNote}
|
||||
onClose={toggleDropdown}
|
||||
/>}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
function PiezoEditor ({ piezo, index }: { piezo: PiezoMusic, index: number }) {
|
||||
const { setName, setPin, setBeat, setTempo } = usePiezoMusic();
|
||||
const { setName, setPin, setBeat, setTempo, removePiezo } = usePiezoMusic();
|
||||
|
||||
const beatsItem = [
|
||||
{
|
||||
@ -123,6 +143,9 @@ function PiezoEditor ({ piezo, index }: { piezo: PiezoMusic, index: number }) {
|
||||
|
||||
const initBeatItem = beatsItem.find((item) => item.value == piezo.beats);
|
||||
|
||||
const exportJson = () => {
|
||||
}
|
||||
|
||||
const handle = {
|
||||
changeName: (e: ChangeEvent<HTMLInputElement | null>) => {
|
||||
setName(index, e.target.value);
|
||||
@ -137,13 +160,20 @@ function PiezoEditor ({ piezo, index }: { piezo: PiezoMusic, index: number }) {
|
||||
const tempo = Number.parseInt(e.target.value);
|
||||
setTempo(index, tempo);
|
||||
},
|
||||
remove: () => {
|
||||
removePiezo(index);
|
||||
},
|
||||
play: () => {
|
||||
PatchPiezoMusic(piezo);
|
||||
}
|
||||
},
|
||||
export: exportJson
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-5 bg-secondary border border-border rounded-lg p-5 animate-size-fade-in">
|
||||
<div className="flex flex-col gap-5 bg-secondary border border-border rounded-lg p-5 animate-size-fade-in relative">
|
||||
<button className="ms-auto absolute -right-24 top-1/2 -translate-y-1/2 bg-finn hover:bg-secondary transition border border-border rounded-lg px-5" onClick={handle.remove}>
|
||||
<i className="bi bi-dash text-3xl"></i>
|
||||
</button>
|
||||
<div className="flex flex-row justify-between">
|
||||
<div className="flex flex-row gap-3">
|
||||
<Input
|
||||
@ -174,7 +204,7 @@ function PiezoEditor ({ piezo, index }: { piezo: PiezoMusic, index: number }) {
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-row gap-3">
|
||||
<Button.Secondary className="!py-0 !px-6 flex items-center gap-3">
|
||||
<Button.Secondary className="!py-0 !px-6 flex items-center gap-3" onClick={exportJson}>
|
||||
<div className="text-sm">Export</div>
|
||||
<i className="bi bi-upload text-sm"></i>
|
||||
</Button.Secondary>
|
||||
|
74
src/components/modals/SearchItemModal.tsx
Normal file
74
src/components/modals/SearchItemModal.tsx
Normal file
@ -0,0 +1,74 @@
|
||||
import { ChangeEvent, useEffect, useState } from "react";
|
||||
import EvoInput from "../forms/EvoInput";
|
||||
import Input from "../forms/Input";
|
||||
|
||||
type EvoDropDownItem = {
|
||||
name: string,
|
||||
value: any
|
||||
}
|
||||
|
||||
interface SearchItemModalProps {
|
||||
className?: string;
|
||||
name?: string;
|
||||
items: EvoDropDownItem[];
|
||||
initItem?: EvoDropDownItem;
|
||||
onValueChange?: (item: EvoDropDownItem) => void;
|
||||
onClose?: () => void
|
||||
}
|
||||
|
||||
export default function SearchItemModal ({ className, items, name, initItem, onClose, onValueChange }: SearchItemModalProps) {
|
||||
const [filteredItems, setItems] = useState<EvoDropDownItem[]>(items);
|
||||
const [currentItem, setItem] = useState<EvoDropDownItem>(initItem || items[0]);
|
||||
|
||||
const [searchVal, setSearch] = useState<string>("");
|
||||
|
||||
const handleSearch = (e: ChangeEvent<HTMLInputElement | null>) => {
|
||||
setSearch(e.target.value);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (searchVal.length > 0) {
|
||||
const filter = items.filter(item => item.name.toLocaleLowerCase().includes(searchVal.toLowerCase()));
|
||||
setItems(filter);
|
||||
}
|
||||
else {
|
||||
setItems(items);
|
||||
}
|
||||
}, [searchVal])
|
||||
|
||||
return (
|
||||
<div className={`fixed left-0 top-0 bg-finn w-screen h-screen z-50 ${className}`}>
|
||||
<div className="bg-black border border-border rounded-lg absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 h-96 w-96 p-3 flex flex-col justify-items-start">
|
||||
<button className="p-1 absolute right-2 top-2" onClick={onClose}>
|
||||
<i className="bi bi-x text-3xl"></i>
|
||||
</button>
|
||||
<header className="text-left">
|
||||
<h1 className="text-2xl font-bold font-poppins px-2 py-4">{name}</h1>
|
||||
<Input
|
||||
className="w-full mb-3"
|
||||
name="Search"
|
||||
placeholder="Search..."
|
||||
value={searchVal}
|
||||
onChange={handleSearch}
|
||||
/>
|
||||
</header>
|
||||
<div className="overflow-y-scroll flex-grow flex flex-col">
|
||||
{filteredItems.map((item) => (
|
||||
<button
|
||||
className="py-2 px-3 flex justify-between items-center bg-transparent bg-opacity-100 hover:bg-indigo-300 hover:bg-opacity-20 rounded-md"
|
||||
onClick={() => {
|
||||
setItem(item);
|
||||
if (onValueChange) onValueChange(item)}
|
||||
}
|
||||
>
|
||||
<div className="text-left text-sm">
|
||||
{item.name}
|
||||
</div>
|
||||
{currentItem.value == item.value && <div className="rounded-full bg-white w-2 h-2"></div>}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user