From 262ac046b6e28f8ad935076be8de377859c6c6d2 Mon Sep 17 00:00:00 2001 From: Amanda Date: Sun, 2 Nov 2025 00:37:46 -0400 Subject: [PATCH] First draft of UI --- .gitignore | 3 ++ src/App.tsx | 40 ++++++++++++----------- src/index.css | 40 +++++++++++++++++++++++ src/segmenting/Segment.tsx | 5 +++ src/segmenting/SegmentList.tsx | 58 ++++++++++++++++++++++++++++++++++ src/util/timestamp.ts | 9 ++++++ src/video/VideoPicker.tsx | 23 ++++++++++++++ src/video/VideoPlayer.tsx | 14 ++++++++ 8 files changed, 173 insertions(+), 19 deletions(-) create mode 100644 src/segmenting/Segment.tsx create mode 100644 src/segmenting/SegmentList.tsx create mode 100644 src/util/timestamp.ts create mode 100644 src/video/VideoPicker.tsx create mode 100644 src/video/VideoPlayer.tsx diff --git a/.gitignore b/.gitignore index 4d29575..150d9de 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,6 @@ npm-debug.log* yarn-debug.log* yarn-error.log* + + +data \ No newline at end of file diff --git a/src/App.tsx b/src/App.tsx index a53698a..5def202 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,24 +1,26 @@ -import React from 'react'; -import logo from './logo.svg'; -import './App.css'; +import { JSX, useState } from 'react' +import VideoPlayer from './video/VideoPlayer' +import VideoPicker from './video/VideoPicker' +import Segment from './segmenting/Segment'; +import SegmentList from './segmenting/SegmentList'; + +function App(): JSX.Element { + const [path, setPath] = useState(""); + const [segments, setSegments] = useState([]); -function App() { return ( -
-
- logo -

- Edit src/App.tsx and save to reload. -

- - Learn React - -
+
+
+ +
+ +
+ +
+

Amanda's VOD Segmenter

+ + +
); } diff --git a/src/index.css b/src/index.css index ec2585e..8be4ed1 100644 --- a/src/index.css +++ b/src/index.css @@ -11,3 +11,43 @@ code { font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace; } + +video { + background-color: black; + position: relative; +} + +#app { + width: 100%; + overflow: auto; +} + +.column { + width: auto; + padding: 20px; + float: left; +} + +#videoTimestamp { + text-align: center; + font-size: xx-large; +} + +.segmentEntry { + width: auto; +} + +.segmentData { + margin: 4px; + float: left; +} + +.scrollable { + overflow-y: auto; + height: 100%; + width: 100%; +} + +.timestamp { + font-family:'Courier New', Courier, monospace; +} \ No newline at end of file diff --git a/src/segmenting/Segment.tsx b/src/segmenting/Segment.tsx new file mode 100644 index 0000000..2796ac3 --- /dev/null +++ b/src/segmenting/Segment.tsx @@ -0,0 +1,5 @@ +export default interface Segment { + title: string; + inTime: number; + outTime: number; +} \ No newline at end of file diff --git a/src/segmenting/SegmentList.tsx b/src/segmenting/SegmentList.tsx new file mode 100644 index 0000000..1a379c9 --- /dev/null +++ b/src/segmenting/SegmentList.tsx @@ -0,0 +1,58 @@ +import { JSX } from "react"; +import Segment from "./Segment"; +import { createTimestamp } from "../util/timestamp"; + +export default function SegmentList({ segments, setSegments }: { segments: Segment[], setSegments: (segments: Segment[]) => void}): JSX.Element { + const videoPlayer: HTMLVideoElement = document.getElementById("videoPlayer") as HTMLVideoElement; + + function remSegment(remIndex: number) { + setSegments(segments.filter((value: Segment, index: number) => index != remIndex)); + } + + return
+
+ {segments.map((segment, index) => { + return ( +
+
+ +
+ + {createTimestamp(segment.inTime)} +
+
+ + {createTimestamp(segment.outTime)} +
+
+
+
+ ) + })} +
+ + +
; +} \ No newline at end of file diff --git a/src/util/timestamp.ts b/src/util/timestamp.ts new file mode 100644 index 0000000..401f38b --- /dev/null +++ b/src/util/timestamp.ts @@ -0,0 +1,9 @@ +export function createTimestamp(currentTime: number): string { + const hours = Math.floor(Math.floor(currentTime) / 3600); + const minutes = Math.floor((Math.floor(currentTime) % 3600) / 60); + const seconds = Math.floor(currentTime) % 60; + + return `${hours.toString().padStart(2, "0")}:${minutes + .toString() + .padStart(2, "0")}:${seconds.toString().padStart(2, "0")}`; +} diff --git a/src/video/VideoPicker.tsx b/src/video/VideoPicker.tsx new file mode 100644 index 0000000..c1a77a7 --- /dev/null +++ b/src/video/VideoPicker.tsx @@ -0,0 +1,23 @@ +import { JSX } from "react"; + +export default function VideoPicker( + { setPath }: { setPath: (path: string) => void} +): JSX.Element { + function openFile(file: FileList | null): void { + var f: File | null | undefined = file?.item(0) + if(f == null) return; + setPath( + f == null ? "" : URL.createObjectURL(f) + ); + } + + return ( +
+ openFile(event.target.files)} + /> +
+ ); +} \ No newline at end of file diff --git a/src/video/VideoPlayer.tsx b/src/video/VideoPlayer.tsx new file mode 100644 index 0000000..cc5c92f --- /dev/null +++ b/src/video/VideoPlayer.tsx @@ -0,0 +1,14 @@ +export default function VideoPlayer({path}: {path: string}) { + return ( +
+
+ ); +} \ No newline at end of file