styling and building out trimmer component

This commit is contained in:
michalcourson
2026-02-07 10:25:53 -05:00
parent c292350b25
commit 0346efd504
6 changed files with 645 additions and 65 deletions

View File

@ -1,4 +1,3 @@
@import "tailwindcss";
@tailwind base;
@tailwind components;
@ -10,19 +9,25 @@
@theme {
--color-midnight: #1E1E1E;
--color-plum: #4f3186;
--color-plum: #6e44ba;
--color-plumDark: #4f3186;
--color-offwhite: #d4d4d4;
}
button {
background-color: #4f3186;
padding: 10px 20px;
border-radius: 10px;
::-webkit-scrollbar {
height: 12px;
width: 12px;
background: #1e1e1e;
}
button:hover {
transform: scale(1.05);
opacity: 1;
::-webkit-scrollbar-thumb {
background: #303030;
-webkit-border-radius: 1ex;
-webkit-box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.75);
}
::-webkit-scrollbar-corner {
background: #1e1e1e;
}
li {

View File

@ -6,7 +6,7 @@ import AudioTrimmer from './components/AudioTrimer';
function Hello() {
return (
<div className="min-h-screen min-w-screen flex flex-col items-center justify-center bg-midnight text-offwhite">
<div className="min-h-screen flex flex-col justify-center bg-midnight text-offwhite">
{/* <div className="Hello">
<img width="200" alt="icon" src={icon} />
</div>
@ -37,13 +37,21 @@ function Hello() {
</button>
</a>
</div> */}
<div className="bg-midnight min-w-screen">
<AudioTrimmer
title="audio_capture_20251206_123108.wav"
filePath="C:\\Users\\mickl\\Music\\clips\\original\\audio_capture_20250118_000351.wav"
// section="Section 1"
/>
</div>
<AudioTrimmer
title="audio_capture_20251206_123108.wav"
filePath="C:\\Users\\mickl\\Music\\clips\\original\\audio_capture_20250118_000351.wav"
// section="Section 1"
/>
<AudioTrimmer
title="audio_capture_20251206_123108.wav"
filePath="C:\\Users\\mickl\\Music\\clips\\original\\audio_capture_20250118_000351.wav"
// section="Section 1"
/>
<AudioTrimmer
title="audio_capture_20251206_123108.wav"
filePath="C:\\Users\\mickl\\Music\\clips\\original\\audio_capture_20250118_000351.wav"
// section="Section 1"
/>
</div>
);
}

View File

@ -5,8 +5,13 @@ import React, {
useCallback,
useRef,
} from 'react';
import Regions from 'wavesurfer.js/dist/plugins/regions.esm.js';
import { useWavesurfer } from '@wavesurfer/react';
import Regions from 'wavesurfer.js/dist/plugins/regions.esm.js';
import ZoomPlugin from 'wavesurfer.js/dist/plugins/zoom.esm.js';
import PlayArrowIcon from '@mui/icons-material/PlayArrow';
import PauseIcon from '@mui/icons-material/Pause';
import SaveIcon from '@mui/icons-material/Save';
import DeleteIcon from '@mui/icons-material/Delete';
export interface AudioTrimmerProps {
filePath: string;
@ -29,14 +34,25 @@ export default function AudioTrimmer({
}: AudioTrimmerProps) {
const [blobUrl, setBlobUrl] = useState<string | undefined>(undefined);
const containerRef = useRef(null);
const [clipStart, setClipStart] = useState<number>(0);
const [clipEnd, setClipEnd] = useState<number>(0);
const plugins = useMemo(() => [Regions.create()], []);
const plugins = useMemo(
() => [
Regions.create(),
ZoomPlugin.create({
scale: 0.25,
}),
],
[],
);
const { wavesurfer, isReady, isPlaying } = useWavesurfer({
container: containerRef,
height: 100,
waveColor: '#ccb1ff',
progressColor: '#6e44ba',
hideScrollbar: true,
url: blobUrl,
plugins,
});
@ -50,6 +66,8 @@ export default function AudioTrimmer({
region.remove();
}
});
setClipStart(newRegion.start);
setClipEnd(newRegion.end);
},
[plugins, wavesurfer],
);
@ -57,6 +75,8 @@ export default function AudioTrimmer({
useEffect(() => {
console.log('ready, setting up regions plugin', wavesurfer);
if (trimStart !== undefined && trimEnd !== undefined) {
setClipStart(trimStart);
setClipEnd(trimEnd);
plugins[0].addRegion({
start: trimStart,
end: trimEnd,
@ -64,6 +84,9 @@ export default function AudioTrimmer({
drag: false,
resize: true,
});
} else {
setClipStart(0);
setClipEnd(wavesurfer ? wavesurfer.getDuration() : 0);
}
plugins[0].enableDragSelection({
@ -104,17 +127,56 @@ export default function AudioTrimmer({
}
};
const formatTime = (seconds: number) => {
const minutes = Math.floor(seconds / 60);
const secs = (seconds % 60).toFixed(0);
return `${minutes}:${secs.padStart(2, '0')}`;
};
return (
<div className="shadow-[0_4px_6px_rgba(0,0,0,0.5)] m-2 p-4 rounded-lg bg-darkDrop">
<div>
<text className="m-2 font-bold text-lg">{title}</text>
</div>
<div className="w-[100%] m-2 ">
<div ref={containerRef} />
<button type="button" onClick={onPlayPause}>
{isPlaying ? 'Pause' : 'Play'}
</button>
{/* <div className="flex flex-col"> */}
<div className="">
<div className="grid justify-items-stretch grid-cols-2">
<div className="m-1 mb-5px flex flex-col">
<text className="font-bold text-lg">{title}</text>
<text className="text-sm text-neutral-500">{filePath}</text>
</div>
<div className="flex justify-end">
<button
type="button"
className="bg-plum hover:bg-plumDark text-white font-bold h-11 w-11 rounded-md ml-1"
onClick={onPlayPause}
>
{isPlaying ? <PauseIcon /> : <PlayArrowIcon />}
</button>
<button
type="button"
className="bg-plum hover:bg-plumDark text-white font-bold h-11 w-11 rounded-md ml-1"
onClick={onSave}
>
<SaveIcon />
</button>
<button
type="button"
className="bg-plum hover:bg-plumDark text-white font-bold h-11 w-11 rounded-md ml-1"
onClick={onDelete}
>
<DeleteIcon />
</button>
</div>
</div>
<div className="m-1 wavesurfer-scroll-container">
<div ref={containerRef} className="wavesurfer-inner" />
</div>
<div className="grid justify-items-stretch grid-cols-2 text-neutral-500">
<div className="m-1">
<text className="text-sm ">Start: {formatTime(clipStart)}</text>
</div>
<div className="mx-1 flex justify-end">
<text className="text-sm">End: {formatTime(clipEnd)}</text>
</div>
</div>
</div>
</div>
);