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 Button from "../forms/Button";
|
||||||
import { pitch } from "../../data/melodies";
|
import { pitch } from "../../data/melodies";
|
||||||
import { PatchPiezoMusic } from "../../controllers/BoardController";
|
import { PatchPiezoMusic } from "../../controllers/BoardController";
|
||||||
|
import SearchItemModal from "../modals/SearchItemModal";
|
||||||
|
|
||||||
function getNoteItems () {
|
function getNoteItems () {
|
||||||
const pitches = Object.keys(pitch);
|
const pitches = Object.keys(pitch);
|
||||||
@ -45,6 +46,7 @@ function NoteItem ({note, index, parentIndex}: { note: string, index: number, pa
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
<button
|
<button
|
||||||
className="min-w-40 h-40 transition border group border-border rounded-lg animate-size-fade-in relative"
|
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">
|
<div className="text-xl">
|
||||||
{note}
|
{note}
|
||||||
</div>
|
</div>
|
||||||
<EvoDropDown.Menu
|
{/* <EvoDropDown.Menu
|
||||||
className="!w-44 top-0 h-40 z-30 overflow-y-scroll v-scrollbar left-2"
|
className="!w-44 top-0 h-40 z-30 overflow-y-scroll v-scrollbar left-2"
|
||||||
appear={dropAppear}
|
appear={dropAppear}
|
||||||
items={noteItems}
|
items={noteItems}
|
||||||
onValueChange={handleChange}
|
onValueChange={handleChange}
|
||||||
/>
|
/> */}
|
||||||
</button>
|
</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 }) => {
|
const handleAddNote = (item: { name: string, value: any }) => {
|
||||||
addNote(parentIndex, item.value);
|
addNote(parentIndex, item.value);
|
||||||
|
setApper(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
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>
|
<button className="border border-border bg-secondary-solid rounded-lg min-w-40 h-40" onClick={toggleDropdown}>
|
||||||
<EvoDropDown.Menu
|
<i className="bi bi-plus text-2xl"></i>
|
||||||
className="!w-32 top-0 h-56 z-30 overflow-y-scroll v-scrollbar"
|
{/* <EvoDropDown.Menu
|
||||||
appear={dropAppear}
|
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}
|
items={noteItems}
|
||||||
onValueChange={handleAddNote}
|
onValueChange={handleAddNote}
|
||||||
/>
|
onClose={toggleDropdown}
|
||||||
</button>
|
/>}
|
||||||
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function PiezoEditor ({ piezo, index }: { piezo: PiezoMusic, index: number }) {
|
function PiezoEditor ({ piezo, index }: { piezo: PiezoMusic, index: number }) {
|
||||||
const { setName, setPin, setBeat, setTempo } = usePiezoMusic();
|
const { setName, setPin, setBeat, setTempo, removePiezo } = usePiezoMusic();
|
||||||
|
|
||||||
const beatsItem = [
|
const beatsItem = [
|
||||||
{
|
{
|
||||||
@ -123,6 +143,9 @@ function PiezoEditor ({ piezo, index }: { piezo: PiezoMusic, index: number }) {
|
|||||||
|
|
||||||
const initBeatItem = beatsItem.find((item) => item.value == piezo.beats);
|
const initBeatItem = beatsItem.find((item) => item.value == piezo.beats);
|
||||||
|
|
||||||
|
const exportJson = () => {
|
||||||
|
}
|
||||||
|
|
||||||
const handle = {
|
const handle = {
|
||||||
changeName: (e: ChangeEvent<HTMLInputElement | null>) => {
|
changeName: (e: ChangeEvent<HTMLInputElement | null>) => {
|
||||||
setName(index, e.target.value);
|
setName(index, e.target.value);
|
||||||
@ -137,13 +160,20 @@ function PiezoEditor ({ piezo, index }: { piezo: PiezoMusic, index: number }) {
|
|||||||
const tempo = Number.parseInt(e.target.value);
|
const tempo = Number.parseInt(e.target.value);
|
||||||
setTempo(index, tempo);
|
setTempo(index, tempo);
|
||||||
},
|
},
|
||||||
|
remove: () => {
|
||||||
|
removePiezo(index);
|
||||||
|
},
|
||||||
play: () => {
|
play: () => {
|
||||||
PatchPiezoMusic(piezo);
|
PatchPiezoMusic(piezo);
|
||||||
}
|
},
|
||||||
|
export: exportJson
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
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 justify-between">
|
||||||
<div className="flex flex-row gap-3">
|
<div className="flex flex-row gap-3">
|
||||||
<Input
|
<Input
|
||||||
@ -174,7 +204,7 @@ function PiezoEditor ({ piezo, index }: { piezo: PiezoMusic, index: number }) {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-row gap-3">
|
<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>
|
<div className="text-sm">Export</div>
|
||||||
<i className="bi bi-upload text-sm"></i>
|
<i className="bi bi-upload text-sm"></i>
|
||||||
</Button.Secondary>
|
</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