├── .env
├── .gitignore
├── README.md
├── package-lock.json
├── package.json
├── public
├── assets
│ ├── fonts
│ │ ├── Cerebri Sans Bold Italic.ttf
│ │ ├── Cerebri Sans Bold.ttf
│ │ ├── Cerebri Sans Book Italic.ttf
│ │ ├── Cerebri Sans Book.ttf
│ │ ├── Cerebri Sans ExtraBold Italic.ttf
│ │ ├── Cerebri Sans ExtraBold.ttf
│ │ ├── Cerebri Sans Heavy.ttf
│ │ ├── Cerebri Sans Italic.ttf
│ │ ├── Cerebri Sans SemiBold Italic.ttf
│ │ ├── Cerebri Sans SemiBold.ttf
│ │ └── abeatbyKaiRegular.otf
│ ├── images
│ │ ├── adele.jpg
│ │ ├── future.jpg
│ │ ├── imgPlaceholder.png
│ │ ├── logo-2.svg
│ │ ├── logo.svg
│ │ ├── menu.svg
│ │ ├── play-icon.svg
│ │ ├── play-icon2.svg
│ │ ├── profile-img.png
│ │ ├── ruger.jpg
│ │ ├── skip-bd.svg
│ │ ├── skip-fd.svg
│ │ ├── stop-icon.svg
│ │ └── video-placeholder.jpg
│ └── video
│ │ └── Real 4K HDR .mp4
├── favicon.ico
├── ffmpeg-core
│ ├── dist
│ │ ├── ffmpeg-core.js
│ │ ├── ffmpeg-core.wasm
│ │ └── ffmpeg-core.worker.js
│ ├── package-lock.json
│ └── package.json
├── index.html
├── logo192.png
├── logo512.png
├── manifest.json
└── robots.txt
├── src
├── App.css
├── App.test.tsx
├── App.tsx
├── assets
│ ├── fonts
│ │ ├── Cerebri Sans Bold Italic.ttf
│ │ ├── Cerebri Sans Bold.ttf
│ │ ├── Cerebri Sans Book Italic.ttf
│ │ ├── Cerebri Sans Book.ttf
│ │ ├── Cerebri Sans ExtraBold Italic.ttf
│ │ ├── Cerebri Sans ExtraBold.ttf
│ │ ├── Cerebri Sans Heavy.ttf
│ │ ├── Cerebri Sans Italic.ttf
│ │ ├── Cerebri Sans SemiBold Italic.ttf
│ │ ├── Cerebri Sans SemiBold.ttf
│ │ └── abeatbyKaiRegular.otf
│ └── images
│ │ ├── adele.jpg
│ │ ├── future.jpg
│ │ ├── gaddafi-rusli-2ueUnL4CkV8-unsplash 1.png
│ │ ├── imgPlaceholder.png
│ │ ├── logo.svg
│ │ ├── menu.svg
│ │ ├── nav1.svg
│ │ ├── nav2.svg
│ │ ├── nav3.svg
│ │ ├── nav4.svg
│ │ ├── nav5.svg
│ │ ├── nav6.svg
│ │ ├── nav7.svg
│ │ ├── play-icon.svg
│ │ ├── play-icon2.svg
│ │ ├── profile-img.png
│ │ ├── ruger.jpg
│ │ ├── skip-bd.svg
│ │ ├── skip-fd.svg
│ │ └── stop-icon.svg
├── components
│ ├── Assets
│ │ └── SVGs.jsx
│ ├── Layout
│ │ ├── Body
│ │ │ ├── Body.scss
│ │ │ ├── Body.tsx
│ │ │ └── index.js
│ │ ├── BodySections
│ │ │ ├── BodySection1.tsx
│ │ │ ├── BodySection2.tsx
│ │ │ ├── BodySection3.tsx
│ │ │ ├── BodySections.scss
│ │ │ └── index.js
│ │ ├── Cards
│ │ │ ├── Card1.tsx
│ │ │ ├── Card2.tsx
│ │ │ └── index.js
│ │ └── Navbar
│ │ │ ├── Navbar.scss
│ │ │ ├── Navbar.tsx
│ │ │ └── index.js
│ └── UI
│ │ ├── Button
│ │ ├── Button.scss
│ │ ├── Button.tsx
│ │ └── index.js
│ │ ├── Cards
│ │ ├── SideCard
│ │ │ ├── SideCard.scss
│ │ │ ├── SideCard.tsx
│ │ │ └── index.js
│ │ └── VideoCard
│ │ │ ├── VideoCard.scss
│ │ │ ├── VideoCard.tsx
│ │ │ └── index.js
│ │ ├── Convert
│ │ ├── Convert.scss
│ │ ├── Convert.tsx
│ │ └── index.js
│ │ ├── Dropdown
│ │ ├── Dropdown.scss
│ │ ├── Dropdown.tsx
│ │ └── index.js
│ │ ├── Modals
│ │ ├── Modal
│ │ │ ├── Modal.scss
│ │ │ ├── Modal.tsx
│ │ │ └── index.js
│ │ └── ModalChildren
│ │ │ ├── ImportVideo.tsx
│ │ │ ├── ModalChildren.scss
│ │ │ └── index.js
│ │ ├── ProfilePicture
│ │ ├── ProfilePicture.scss
│ │ ├── ProfilePicture.tsx
│ │ └── index.js
│ │ ├── Slider
│ │ ├── Slider.scss
│ │ ├── Slider.tsx
│ │ └── index.js
│ │ ├── Timeline
│ │ ├── Timeline.scss
│ │ ├── Timeline.tsx
│ │ ├── TimelineRow.tsx
│ │ └── index.js
│ │ ├── Timelines
│ │ ├── AudioTimeline.tsx
│ │ ├── TimelineHeader.tsx
│ │ ├── Timelines.scss
│ │ ├── VideoTimeline.tsx
│ │ └── index.js
│ │ ├── VideoPlaceholder
│ │ ├── VideoPlaceholder.scss
│ │ ├── VideoPlaceholder.tsx
│ │ └── index.js
│ │ └── WaveForm
│ │ ├── WaveForm.scss
│ │ ├── WaveForm.tsx
│ │ └── index.js
├── helpers
│ └── functions.tsx
├── hooks
│ └── useModal.ts
├── index.css
├── index.tsx
├── logo.svg
├── pages
│ └── VideoEditing.tsx
├── react-app-env.d.ts
├── redux
│ ├── slices
│ │ ├── currentTaskSlice.ts
│ │ ├── currentTimeSlice.ts
│ │ ├── currentVideoSlice.ts
│ │ ├── durationSlice.ts
│ │ ├── edgeTimesSlice.ts
│ │ └── storedVideoSlice.ts
│ └── store.ts
├── reportWebVitals.ts
├── services
│ └── apis.ts
├── setupTests.ts
└── styles
│ ├── _mixins.scss
│ ├── _variables.scss
│ └── main.scss
├── tsconfig.json
└── webpack.server.js
/.env:
--------------------------------------------------------------------------------
1 | REACT_APP_BASE_URL=http://localhost:3211
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.*
17 | .env.local
18 | .env.development.local
19 | .env.test.local
20 | .env.production.local
21 |
22 | npm-debug.log*
23 | yarn-debug.log*
24 | yarn-error.log*
25 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Veditor is a video editing application.You can trim and resize videos, as well as convert between file formats.
2 |
3 | 
4 |
5 |
6 | Noteworthy: 1656289277686--Real 4K HDR 60fps LG Jazz HDR UHD (Chromecast Ultra). This video is beautiful!
7 | link: https://www.youtube.com/watch?v=mkggXE5e2yk&t=5s
8 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "veditor",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@reduxjs/toolkit": "^1.8.1",
7 | "@testing-library/jest-dom": "^5.16.4",
8 | "@testing-library/react": "^13.1.1",
9 | "@testing-library/user-event": "^13.5.0",
10 | "@types/jest": "^27.4.1",
11 | "@types/node": "^16.11.32",
12 | "@types/react": "^18.0.8",
13 | "@types/react-dom": "^18.0.3",
14 | "axios": "^0.27.2",
15 | "env-cmd": "^10.1.0",
16 | "react": "^18.1.0",
17 | "react-dom": "^18.1.0",
18 | "react-icons": "^4.3.1",
19 | "react-loader-spinner": "^5.1.5",
20 | "react-redux": "^8.0.2",
21 | "react-router-dom": "^6.3.0",
22 | "react-scripts": "5.0.1",
23 | "react-toastify": "^9.0.5",
24 | "redux": "^4.2.0",
25 | "sass": "^1.51.0",
26 | "typescript": "^4.6.4",
27 | "web-vitals": "^2.1.4"
28 | },
29 | "scripts": {
30 | "start": "react-scripts start",
31 | "build": "react-scripts build",
32 | "test": "react-scripts test",
33 | "eject": "react-scripts eject"
34 | },
35 | "eslintConfig": {
36 | "extends": [
37 | "react-app",
38 | "react-app/jest"
39 | ]
40 | },
41 | "browserslist": {
42 | "production": [
43 | ">0.2%",
44 | "not dead",
45 | "not op_mini all"
46 | ],
47 | "development": [
48 | "last 1 chrome version",
49 | "last 1 firefox version",
50 | "last 1 safari version"
51 | ]
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/public/assets/fonts/Cerebri Sans Bold Italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elijahthis/veditor/9149005af6ebb093e9de1724a9fecba74c44f9be/public/assets/fonts/Cerebri Sans Bold Italic.ttf
--------------------------------------------------------------------------------
/public/assets/fonts/Cerebri Sans Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elijahthis/veditor/9149005af6ebb093e9de1724a9fecba74c44f9be/public/assets/fonts/Cerebri Sans Bold.ttf
--------------------------------------------------------------------------------
/public/assets/fonts/Cerebri Sans Book Italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elijahthis/veditor/9149005af6ebb093e9de1724a9fecba74c44f9be/public/assets/fonts/Cerebri Sans Book Italic.ttf
--------------------------------------------------------------------------------
/public/assets/fonts/Cerebri Sans Book.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elijahthis/veditor/9149005af6ebb093e9de1724a9fecba74c44f9be/public/assets/fonts/Cerebri Sans Book.ttf
--------------------------------------------------------------------------------
/public/assets/fonts/Cerebri Sans ExtraBold Italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elijahthis/veditor/9149005af6ebb093e9de1724a9fecba74c44f9be/public/assets/fonts/Cerebri Sans ExtraBold Italic.ttf
--------------------------------------------------------------------------------
/public/assets/fonts/Cerebri Sans ExtraBold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elijahthis/veditor/9149005af6ebb093e9de1724a9fecba74c44f9be/public/assets/fonts/Cerebri Sans ExtraBold.ttf
--------------------------------------------------------------------------------
/public/assets/fonts/Cerebri Sans Heavy.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elijahthis/veditor/9149005af6ebb093e9de1724a9fecba74c44f9be/public/assets/fonts/Cerebri Sans Heavy.ttf
--------------------------------------------------------------------------------
/public/assets/fonts/Cerebri Sans Italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elijahthis/veditor/9149005af6ebb093e9de1724a9fecba74c44f9be/public/assets/fonts/Cerebri Sans Italic.ttf
--------------------------------------------------------------------------------
/public/assets/fonts/Cerebri Sans SemiBold Italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elijahthis/veditor/9149005af6ebb093e9de1724a9fecba74c44f9be/public/assets/fonts/Cerebri Sans SemiBold Italic.ttf
--------------------------------------------------------------------------------
/public/assets/fonts/Cerebri Sans SemiBold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elijahthis/veditor/9149005af6ebb093e9de1724a9fecba74c44f9be/public/assets/fonts/Cerebri Sans SemiBold.ttf
--------------------------------------------------------------------------------
/public/assets/fonts/abeatbyKaiRegular.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elijahthis/veditor/9149005af6ebb093e9de1724a9fecba74c44f9be/public/assets/fonts/abeatbyKaiRegular.otf
--------------------------------------------------------------------------------
/public/assets/images/adele.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elijahthis/veditor/9149005af6ebb093e9de1724a9fecba74c44f9be/public/assets/images/adele.jpg
--------------------------------------------------------------------------------
/public/assets/images/future.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elijahthis/veditor/9149005af6ebb093e9de1724a9fecba74c44f9be/public/assets/images/future.jpg
--------------------------------------------------------------------------------
/public/assets/images/imgPlaceholder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elijahthis/veditor/9149005af6ebb093e9de1724a9fecba74c44f9be/public/assets/images/imgPlaceholder.png
--------------------------------------------------------------------------------
/public/assets/images/logo-2.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/public/assets/images/logo.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/public/assets/images/menu.svg:
--------------------------------------------------------------------------------
1 |
19 |
--------------------------------------------------------------------------------
/public/assets/images/play-icon.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/public/assets/images/play-icon2.svg:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/public/assets/images/profile-img.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elijahthis/veditor/9149005af6ebb093e9de1724a9fecba74c44f9be/public/assets/images/profile-img.png
--------------------------------------------------------------------------------
/public/assets/images/ruger.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elijahthis/veditor/9149005af6ebb093e9de1724a9fecba74c44f9be/public/assets/images/ruger.jpg
--------------------------------------------------------------------------------
/public/assets/images/skip-bd.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/public/assets/images/skip-fd.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/public/assets/images/stop-icon.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/public/assets/images/video-placeholder.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elijahthis/veditor/9149005af6ebb093e9de1724a9fecba74c44f9be/public/assets/images/video-placeholder.jpg
--------------------------------------------------------------------------------
/public/assets/video/Real 4K HDR .mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elijahthis/veditor/9149005af6ebb093e9de1724a9fecba74c44f9be/public/assets/video/Real 4K HDR .mp4
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elijahthis/veditor/9149005af6ebb093e9de1724a9fecba74c44f9be/public/favicon.ico
--------------------------------------------------------------------------------
/public/ffmpeg-core/dist/ffmpeg-core.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elijahthis/veditor/9149005af6ebb093e9de1724a9fecba74c44f9be/public/ffmpeg-core/dist/ffmpeg-core.wasm
--------------------------------------------------------------------------------
/public/ffmpeg-core/dist/ffmpeg-core.worker.js:
--------------------------------------------------------------------------------
1 | var threadInfoStruct=0;var selfThreadId=0;var parentThreadId=0;var Module={};function threadPrintErr(){var text=Array.prototype.slice.call(arguments).join(" ");console.error(text)}function threadAlert(){var text=Array.prototype.slice.call(arguments).join(" ");postMessage({cmd:"alert",text:text,threadId:selfThreadId})}var err=threadPrintErr;this.alert=threadAlert;Module["instantiateWasm"]=function(info,receiveInstance){var instance=new WebAssembly.Instance(Module["wasmModule"],info);Module["wasmModule"]=null;receiveInstance(instance);return instance.exports};this.onmessage=function(e){try{if(e.data.cmd==="load"){Module["wasmModule"]=e.data.wasmModule;Module["wasmMemory"]=e.data.wasmMemory;Module["buffer"]=Module["wasmMemory"].buffer;Module["ENVIRONMENT_IS_PTHREAD"]=true;if(typeof e.data.urlOrBlob==="string"){importScripts(e.data.urlOrBlob)}else{var objectUrl=URL.createObjectURL(e.data.urlOrBlob);importScripts(objectUrl);URL.revokeObjectURL(objectUrl)}createFFmpegCore(Module).then(function(instance){Module=instance;postMessage({"cmd":"loaded"})})}else if(e.data.cmd==="objectTransfer"){Module["PThread"].receiveObjectTransfer(e.data)}else if(e.data.cmd==="run"){Module["__performance_now_clock_drift"]=performance.now()-e.data.time;threadInfoStruct=e.data.threadInfoStruct;Module["registerPthreadPtr"](threadInfoStruct,/*isMainBrowserThread=*/0,/*isMainRuntimeThread=*/0);selfThreadId=e.data.selfThreadId;parentThreadId=e.data.parentThreadId;var max=e.data.stackBase;var top=e.data.stackBase+e.data.stackSize;Module["establishStackSpace"](top,max);Module["_emscripten_tls_init"]();Module["PThread"].receiveObjectTransfer(e.data);Module["PThread"].setThreadStatus(Module["_pthread_self"](),1);/*EM_THREAD_STATUS_RUNNING*/try{var result=Module["dynCall"]("ii",e.data.start_routine,[e.data.arg]);if(!Module["getNoExitRuntime"]())Module["PThread"].threadExit(result)}catch(ex){if(ex==="Canceled!"){Module["PThread"].threadCancel()}else if(ex!="unwind"){Atomics.store(Module["HEAPU32"],(threadInfoStruct+4)>>/*C_STRUCTS.pthread.threadExitCode*/2,(ex instanceof Module["ExitStatus"])?ex.status:-2);/*A custom entry specific to Emscripten denoting that the thread crashed.*/Atomics.store(Module["HEAPU32"],(threadInfoStruct+0)>>/*C_STRUCTS.pthread.threadStatus*/2,1);Module["_emscripten_futex_wake"](threadInfoStruct+0,/*C_STRUCTS.pthread.threadStatus*/2147483647);if(!(ex instanceof Module["ExitStatus"]))throw ex}}}else if(e.data.cmd==="cancel"){if(threadInfoStruct){Module["PThread"].threadCancel()}}else if(e.data.target==="setimmediate"){}else if(e.data.cmd==="processThreadQueue"){if(threadInfoStruct){Module["_emscripten_current_thread_process_queued_calls"]()}}else{err("worker.js received unknown command "+e.data.cmd);err(e.data)}}catch(ex){err("worker.js onmessage() captured an uncaught exception: "+ex);if(ex&&ex.stack)err(ex.stack);throw ex}};if(typeof process==="object"&&typeof process.versions==="object"&&typeof process.versions.node==="string"){self={location:{href:__filename}};var onmessage=this.onmessage;var nodeWorkerThreads=require("worker_threads");global.Worker=nodeWorkerThreads.Worker;var parentPort=nodeWorkerThreads.parentPort;parentPort.on("message",function(data){onmessage({data:data})});var nodeFS=require("fs");var nodeRead=function(filename){return nodeFS.readFileSync(filename,"utf8")};function globalEval(x){global.require=require;global.Module=Module;eval.call(null,x)}importScripts=function(f){globalEval(nodeRead(f))};postMessage=function(msg){parentPort.postMessage(msg)};if(typeof performance==="undefined"){performance={now:function(){return Date.now()}}}}
2 |
--------------------------------------------------------------------------------
/public/ffmpeg-core/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "_from": "@ffmpeg/core",
3 | "_id": "@ffmpeg/core@0.10.0",
4 | "_inBundle": false,
5 | "_integrity": "sha512-qunWJl5PezpXEm31tb8Qu5z37B5KVA1VYZCpXchMhuAb3X9T7PuE3SlhOwphEoRhzaOa3lpofDfzihAUMFaVPQ==",
6 | "_location": "/@ffmpeg/core",
7 | "_phantomChildren": {},
8 | "_requested": {
9 | "type": "tag",
10 | "registry": true,
11 | "raw": "@ffmpeg/core",
12 | "name": "@ffmpeg/core",
13 | "escapedName": "@ffmpeg%2fcore",
14 | "scope": "@ffmpeg",
15 | "rawSpec": "",
16 | "saveSpec": null,
17 | "fetchSpec": "latest"
18 | },
19 | "_requiredBy": [
20 | "#USER",
21 | "/"
22 | ],
23 | "_resolved": "https://registry.npmjs.org/@ffmpeg/core/-/core-0.10.0.tgz",
24 | "_shasum": "f6a58361b22d7c23c6f7071b9fff6d572bc3f499",
25 | "_spec": "@ffmpeg/core",
26 | "_where": "C:\\Users\\OWNER\\Documents\\veditor",
27 | "author": {
28 | "name": "jeromewus@gmail.com"
29 | },
30 | "bugs": {
31 | "url": "https://github.com/ffmpegwasm/FFmpeg/issues"
32 | },
33 | "bundleDependencies": false,
34 | "deprecated": false,
35 | "description": "ffmpeg.wasm core",
36 | "devDependencies": {
37 | "jest": "^26.4.2",
38 | "serve": "^11.3.2"
39 | },
40 | "files": [
41 | "dist",
42 | "package.json",
43 | "package-lock.json"
44 | ],
45 | "homepage": "https://github.com/ffmpegwasm/FFmpeg#readme",
46 | "keywords": [
47 | "ffmpeg",
48 | "webassembly",
49 | "video",
50 | "audio",
51 | "transcode"
52 | ],
53 | "license": "MIT",
54 | "main": "dist/ffmpeg-core.js",
55 | "name": "@ffmpeg/core",
56 | "repository": {
57 | "type": "git",
58 | "url": "git+https://github.com/ffmpegwasm/FFmpeg.git"
59 | },
60 | "scripts": {
61 | "start": "serve .",
62 | "test": "node --experimental-wasm-threads --experimental-wasm-bulk-memory ./node_modules/.bin/jest"
63 | },
64 | "version": "0.10.0"
65 | }
66 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
27 | veditor
28 |
29 |
30 |
31 |
32 |
36 |
46 |
47 |
--------------------------------------------------------------------------------
/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elijahthis/veditor/9149005af6ebb093e9de1724a9fecba74c44f9be/public/logo192.png
--------------------------------------------------------------------------------
/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elijahthis/veditor/9149005af6ebb093e9de1724a9fecba74c44f9be/public/logo512.png
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | /* text-align: center; */
3 | }
4 |
5 | @font-face {
6 | font-family: AbeatbyKai;
7 | src: url(assets/fonts/abeatbyKaiRegular.otf);
8 | }
9 |
10 | @font-face {
11 | font-family: 'Cerebri Sans Book';
12 | src: url(assets/fonts/Cerebri\ Sans\ Book.ttf);
13 | /* font-style: book; */
14 | }
15 |
16 | @font-face {
17 | font-family: 'Cerebri Sans';
18 | src: url(assets/fonts/Cerebri\ Sans\ Bold.ttf);
19 | font-weight: 700;
20 | font-style: normal;
21 | }
22 | @font-face {
23 | font-family: 'Cerebri Sans';
24 | src: url(assets/fonts/Cerebri\ Sans\ SemiBold.ttf);
25 | font-weight: 600;
26 | font-style: normal;
27 | }
28 | @font-face {
29 | font-family: 'Cerebri Sans';
30 | src: url(assets/fonts/Cerebri\ Sans\ SemiBold\ Italic.ttf);
31 | font-weight: 600;
32 | font-style: italic;
33 | }
34 |
35 |
36 | h3 {
37 | font-size: 1rem;
38 | line-height: 21px;
39 | font-family: Cerebri Sans;
40 | font-weight: 700;
41 | }
42 |
--------------------------------------------------------------------------------
/src/App.test.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render, screen } from '@testing-library/react';
3 | import App from './App';
4 |
5 | test('renders learn react link', () => {
6 | render();
7 | const linkElement = screen.getByText(/learn react/i);
8 | expect(linkElement).toBeInTheDocument();
9 | });
10 |
--------------------------------------------------------------------------------
/src/App.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import "./App.css";
3 | import VideoEditing from "./pages/VideoEditing";
4 | import { BrowserRouter } from "react-router-dom";
5 | import { Provider } from "react-redux";
6 | import { store } from "./redux/store";
7 | import { ToastContainer } from "react-toastify";
8 | import "react-toastify/dist/ReactToastify.css";
9 |
10 | function App() {
11 | return (
12 |
13 |
14 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | );
33 | }
34 |
35 | export default App;
36 |
--------------------------------------------------------------------------------
/src/assets/fonts/Cerebri Sans Bold Italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elijahthis/veditor/9149005af6ebb093e9de1724a9fecba74c44f9be/src/assets/fonts/Cerebri Sans Bold Italic.ttf
--------------------------------------------------------------------------------
/src/assets/fonts/Cerebri Sans Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elijahthis/veditor/9149005af6ebb093e9de1724a9fecba74c44f9be/src/assets/fonts/Cerebri Sans Bold.ttf
--------------------------------------------------------------------------------
/src/assets/fonts/Cerebri Sans Book Italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elijahthis/veditor/9149005af6ebb093e9de1724a9fecba74c44f9be/src/assets/fonts/Cerebri Sans Book Italic.ttf
--------------------------------------------------------------------------------
/src/assets/fonts/Cerebri Sans Book.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elijahthis/veditor/9149005af6ebb093e9de1724a9fecba74c44f9be/src/assets/fonts/Cerebri Sans Book.ttf
--------------------------------------------------------------------------------
/src/assets/fonts/Cerebri Sans ExtraBold Italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elijahthis/veditor/9149005af6ebb093e9de1724a9fecba74c44f9be/src/assets/fonts/Cerebri Sans ExtraBold Italic.ttf
--------------------------------------------------------------------------------
/src/assets/fonts/Cerebri Sans ExtraBold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elijahthis/veditor/9149005af6ebb093e9de1724a9fecba74c44f9be/src/assets/fonts/Cerebri Sans ExtraBold.ttf
--------------------------------------------------------------------------------
/src/assets/fonts/Cerebri Sans Heavy.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elijahthis/veditor/9149005af6ebb093e9de1724a9fecba74c44f9be/src/assets/fonts/Cerebri Sans Heavy.ttf
--------------------------------------------------------------------------------
/src/assets/fonts/Cerebri Sans Italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elijahthis/veditor/9149005af6ebb093e9de1724a9fecba74c44f9be/src/assets/fonts/Cerebri Sans Italic.ttf
--------------------------------------------------------------------------------
/src/assets/fonts/Cerebri Sans SemiBold Italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elijahthis/veditor/9149005af6ebb093e9de1724a9fecba74c44f9be/src/assets/fonts/Cerebri Sans SemiBold Italic.ttf
--------------------------------------------------------------------------------
/src/assets/fonts/Cerebri Sans SemiBold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elijahthis/veditor/9149005af6ebb093e9de1724a9fecba74c44f9be/src/assets/fonts/Cerebri Sans SemiBold.ttf
--------------------------------------------------------------------------------
/src/assets/fonts/abeatbyKaiRegular.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elijahthis/veditor/9149005af6ebb093e9de1724a9fecba74c44f9be/src/assets/fonts/abeatbyKaiRegular.otf
--------------------------------------------------------------------------------
/src/assets/images/adele.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elijahthis/veditor/9149005af6ebb093e9de1724a9fecba74c44f9be/src/assets/images/adele.jpg
--------------------------------------------------------------------------------
/src/assets/images/future.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elijahthis/veditor/9149005af6ebb093e9de1724a9fecba74c44f9be/src/assets/images/future.jpg
--------------------------------------------------------------------------------
/src/assets/images/gaddafi-rusli-2ueUnL4CkV8-unsplash 1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elijahthis/veditor/9149005af6ebb093e9de1724a9fecba74c44f9be/src/assets/images/gaddafi-rusli-2ueUnL4CkV8-unsplash 1.png
--------------------------------------------------------------------------------
/src/assets/images/imgPlaceholder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elijahthis/veditor/9149005af6ebb093e9de1724a9fecba74c44f9be/src/assets/images/imgPlaceholder.png
--------------------------------------------------------------------------------
/src/assets/images/logo.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/src/assets/images/menu.svg:
--------------------------------------------------------------------------------
1 |
19 |
--------------------------------------------------------------------------------
/src/assets/images/nav1.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/src/assets/images/nav2.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/src/assets/images/nav3.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/src/assets/images/nav4.svg:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/src/assets/images/nav5.svg:
--------------------------------------------------------------------------------
1 |
18 |
--------------------------------------------------------------------------------
/src/assets/images/nav6.svg:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/src/assets/images/nav7.svg:
--------------------------------------------------------------------------------
1 |
20 |
--------------------------------------------------------------------------------
/src/assets/images/play-icon.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/src/assets/images/play-icon2.svg:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/src/assets/images/profile-img.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elijahthis/veditor/9149005af6ebb093e9de1724a9fecba74c44f9be/src/assets/images/profile-img.png
--------------------------------------------------------------------------------
/src/assets/images/ruger.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elijahthis/veditor/9149005af6ebb093e9de1724a9fecba74c44f9be/src/assets/images/ruger.jpg
--------------------------------------------------------------------------------
/src/assets/images/skip-bd.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/src/assets/images/skip-fd.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/src/assets/images/stop-icon.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/src/components/Assets/SVGs.jsx:
--------------------------------------------------------------------------------
1 | export const LogoSVG = () => (
2 |
34 | );
35 |
36 | export const MenuSVG = () => (
37 |
89 | );
90 |
91 | export const NavSVG1 = () => (
92 |
118 | );
119 |
120 | export const NavSVG2 = () => (
121 |
137 | );
138 |
139 | export const NavSVG3 = () => (
140 |
166 | );
167 |
168 | export const NavSVG4 = () => (
169 |
209 | );
210 |
211 | export const NavSVG5 = () => (
212 |
318 | );
319 |
320 | export const NavSVG6 = () => (
321 |
376 | );
377 |
378 | export const NavSVG7 = () => (
379 |
499 | );
500 |
501 | export const PlayIcon1 = () => (
502 |
517 | );
518 |
519 | export const PlayIcon2 = () => (
520 |
556 | );
557 |
558 | export const IconlySearch = ({ color }) => (
559 |
583 | );
584 |
585 | export const ArrowDownCircle = ({ color }) => (
586 |
610 | );
611 |
612 | export const CameraIcon = ({ size }) => (
613 |
627 | );
628 |
629 | export const VolumeUp = ({ size }) => (
630 |
650 | );
651 |
652 | export const VolumeDown = ({ size }) => (
653 |
673 | );
674 |
675 | export const ExpandIcon = ({ size }) => (
676 |
696 | );
697 |
698 | export const StopIcon = () => (
699 |
714 | );
715 |
716 | export const SkipFD = () => (
717 |
750 | );
751 |
752 | export const SkipBD = () => (
753 |
785 | );
786 |
787 | export const PauseIcon = () => (
788 |
800 | );
801 |
802 | export const ImportVeditor = () => (
803 |
828 | );
829 |
830 | export const ImportDevice = () => (
831 |
858 | );
859 |
860 | export const MusicIcon = ({ size }) => (
861 |
875 | );
876 |
--------------------------------------------------------------------------------
/src/components/Layout/Body/Body.scss:
--------------------------------------------------------------------------------
1 | .body {
2 | padding: 15px 21px 0 27px;
3 | }
4 |
--------------------------------------------------------------------------------
/src/components/Layout/Body/Body.tsx:
--------------------------------------------------------------------------------
1 | import { BodySection1, BodySection2, BodySection3 } from "../BodySections";
2 | import "./Body.scss";
3 |
4 | const Body = (): JSX.Element => {
5 | return (
6 |
11 | );
12 | };
13 |
14 | export default Body;
15 |
--------------------------------------------------------------------------------
/src/components/Layout/Body/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./Body";
2 |
--------------------------------------------------------------------------------
/src/components/Layout/BodySections/BodySection1.tsx:
--------------------------------------------------------------------------------
1 | import { Card1, Card2 } from "../Cards";
2 | import VideoCard from "../../UI/Cards/VideoCard";
3 |
4 | import "./BodySections.scss";
5 |
6 | const BodySection1 = (): JSX.Element => (
7 |
12 | );
13 |
14 | export default BodySection1;
15 |
--------------------------------------------------------------------------------
/src/components/Layout/BodySections/BodySection2.tsx:
--------------------------------------------------------------------------------
1 | import "./BodySections.scss";
2 | import Timeline from "../../UI/Timeline";
3 | import { RootState } from "../../../redux/store";
4 | import { useSelector } from "react-redux";
5 | import Convert from "../../UI/Convert";
6 |
7 | const BodySection2 = (): JSX.Element => {
8 | const currentTask = useSelector(
9 | (state: RootState) => state.currentTask.currentTask
10 | );
11 |
12 | return (
13 |
14 | {currentTask.name === "Trim" ? : }
15 |
16 | );
17 | };
18 |
19 | export default BodySection2;
20 |
--------------------------------------------------------------------------------
/src/components/Layout/BodySections/BodySection3.tsx:
--------------------------------------------------------------------------------
1 | import Button from "../../UI/Button";
2 | import { RootState } from "../../../redux/store";
3 | import { useSelector } from "react-redux";
4 | import { transcodeVid, trimVid } from "../../../services/apis";
5 | import { toast } from "react-toastify";
6 | import { useState } from "react";
7 |
8 | const BodySection3 = () => {
9 | const state = useSelector((state: RootState) => state);
10 | const storedVideo = useSelector(
11 | (state: RootState) => state.storedVideo.storedVideo
12 | );
13 | const currentTask = useSelector(
14 | (state: RootState) => state.currentTask.currentTask
15 | );
16 | const edgeTimes = useSelector(
17 | (state: RootState) => state.edgeTimes.edgeTimes
18 | );
19 |
20 | const [loading, setLoading] = useState(false);
21 |
22 | return (
23 | {}}>
24 |
100 |
101 | );
102 | };
103 |
104 | export default BodySection3;
105 |
--------------------------------------------------------------------------------
/src/components/Layout/BodySections/BodySections.scss:
--------------------------------------------------------------------------------
1 | .BodySection1 {
2 | display: grid;
3 | grid-template-columns: 23.5fr 53fr 23.5fr;
4 | gap: 17px;
5 | max-height: 545px;
6 | margin-bottom: 10px;
7 | // overflow: scroll;
8 | }
9 |
10 | .BodySection2 {
11 | width: 100%;
12 | }
13 |
14 | .BodySection3 {
15 | padding: 1.5rem 0;
16 | }
17 |
18 | @media screen and (max-width: 1180px) {
19 | .BodySection1 {
20 | display: grid;
21 | grid-template-columns: unset;
22 | // grid-template-rows: 23.5fr 53fr 23.5fr;
23 | gap: 17px;
24 | max-height: 1000px;
25 | margin-bottom: 10px;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/components/Layout/BodySections/index.js:
--------------------------------------------------------------------------------
1 | export { default as BodySection1 } from "./BodySection1";
2 | export { default as BodySection2 } from "./BodySection2";
3 | export { default as BodySection3 } from "./BodySection3";
4 |
--------------------------------------------------------------------------------
/src/components/Layout/Cards/Card1.tsx:
--------------------------------------------------------------------------------
1 | import SideCard from "../../UI/Cards/SideCard";
2 | import VideoPlaceholder from "../../UI/VideoPlaceholder";
3 | import Button from "../../UI/Button";
4 | import { RootState } from "../../../redux/store";
5 | import { useSelector, useDispatch } from "react-redux";
6 | import { SETCURRENTTASK } from "../../../redux/slices/currentTaskSlice";
7 |
8 | const Card1 = (): JSX.Element => {
9 | const dataList: { image: string; title: string; duration: number }[] = [
10 | {
11 | image: "/assets/images/imgPlaceholder.png",
12 | title: "How to edit your first veditor video",
13 | duration: 60,
14 | },
15 | ];
16 | const taskList = ["Trim", "Convert"];
17 | const dispatch = useDispatch();
18 | const currentTask = useSelector(
19 | (state: RootState) => state.currentTask.currentTask
20 | );
21 |
22 | return (
23 |
24 |
25 |
26 |
27 |
Guides
28 |
29 |
30 | Learn all you need to know to get started on veditor
31 |
32 |
33 | {dataList.map((item, ind) => (
34 |
35 |
36 |
37 |
41 |
42 |
43 |
{item.title}
44 |
{item.duration}
45 |
46 |
47 |
48 | ))}
49 |
50 |
51 |
52 |
53 |
54 |
55 |
What are we doing today?
56 |
57 |
58 | {taskList.map((task, ind) => (
59 |
{
62 | dispatch(
63 | SETCURRENTTASK({
64 | ...currentTask,
65 | name: task,
66 | })
67 | );
68 | }}
69 | className={
70 | currentTask.name === task
71 | ? "active"
72 | : ""
73 | }
74 | >
75 | {task}
76 |
77 | ))}
78 |
79 | {/*
*/}
80 |
81 |
82 |
83 |
84 | );
85 | };
86 |
87 | export default Card1;
88 |
--------------------------------------------------------------------------------
/src/components/Layout/Cards/Card2.tsx:
--------------------------------------------------------------------------------
1 | import { useState } from "react";
2 | import SideCard from "../../UI/Cards/SideCard";
3 | import { IconlySearch } from "../../Assets/SVGs";
4 | import VideoPlaceholder from "../../UI/VideoPlaceholder";
5 | import Button from "../../UI/Button";
6 | import { ArrowDownCircle } from "../../Assets/SVGs";
7 | import WaveForm from "../../UI/WaveForm";
8 |
9 | interface dataListProps {
10 | image: string;
11 | title: string;
12 | artist: string;
13 | duration: number;
14 | }
15 | interface dataListPropsOptional {
16 | image?: string;
17 | title?: string;
18 | artist?: string;
19 | duration?: number;
20 | }
21 |
22 | const Card2 = (): JSX.Element => {
23 | const dataList: dataListProps[] = [
24 | {
25 | image: "/assets/images/ruger.jpg",
26 | title: "Dior",
27 | artist: "Ruger",
28 | duration: 165,
29 | },
30 | {
31 | image: "/assets/images/adele.jpg",
32 | title: "Someone Like You",
33 | artist: "Adele",
34 | duration: 165,
35 | },
36 | {
37 | image: "/assets/images/future.jpg",
38 | title: "WAIT FOR YOU",
39 | artist: "Future",
40 | duration: 60,
41 | },
42 | ];
43 |
44 | const [playing, setPlaying] = useState({});
45 |
46 | return (
47 |
48 |
49 |
50 |
Browse Music
51 |
52 |
53 | {Object.keys(playing).length ? (
54 |
55 |
56 |
57 |
58 |
61 |
62 |
63 |
{playing.title}
64 |
65 | {playing.artist} • {playing.duration}
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 | ) : null}
76 |
77 | {dataList.map((item, ind) => (
78 |
setPlaying(item)}
82 | >
83 |
84 |
85 |
86 |
87 |
88 |
{item.title}
89 |
90 | {item.artist} • {item.duration}
91 |
92 |
93 |
94 |
95 |
96 | ))}
97 |
98 |
99 |
100 | );
101 | };
102 |
103 | export default Card2;
104 |
--------------------------------------------------------------------------------
/src/components/Layout/Cards/index.js:
--------------------------------------------------------------------------------
1 | export { default as Card1 } from "./Card1";
2 | export { default as Card2 } from "./Card2";
3 |
--------------------------------------------------------------------------------
/src/components/Layout/Navbar/Navbar.scss:
--------------------------------------------------------------------------------
1 | .navbar {
2 | background-color: #000000;
3 | display: grid;
4 | grid-template-columns: 319px 1fr 319px;
5 | color: #bababa;
6 | font-family: Cerebri Sans Book;
7 | font-size: 10px;
8 |
9 | &__menu {
10 | cursor: pointer;
11 | > svg {
12 | display: block;
13 | }
14 | }
15 |
16 | &__logo > svg {
17 | width: 77px;
18 | // height: 17px;
19 | }
20 |
21 | &__profileImg {
22 | width: 41px;
23 | height: 41px;
24 | }
25 | &__listItem {
26 | display: flex;
27 | flex-direction: column;
28 | align-items: center;
29 | gap: 0.25rem;
30 | padding: 9px 0 8px 0;
31 | transition: color 0.3s;
32 |
33 | &:hover {
34 | cursor: pointer;
35 | color: #18c96a;
36 | path {
37 | fill: #18c96a;
38 | transition: fill 0.3s;
39 | }
40 | }
41 | &--active {
42 | color: #18c96a;
43 | path {
44 | fill: #18c96a;
45 | }
46 | }
47 | }
48 |
49 | & > :first-child {
50 | display: flex;
51 | flex-direction: row;
52 | align-items: center;
53 | gap: 20.5px;
54 | padding-left: 51px;
55 | }
56 |
57 | & > :nth-child(2) {
58 | ul {
59 | display: flex;
60 | flex-direction: row;
61 | align-items: center;
62 | justify-content: space-around;
63 | list-style-type: none;
64 |
65 | svg {
66 | height: 30px;
67 | }
68 | }
69 | }
70 |
71 | & > :last-child {
72 | display: flex;
73 | flex-direction: row;
74 | align-items: center;
75 | margin-left: auto;
76 | margin-right: 40px;
77 | }
78 | }
79 |
80 | @media screen and (max-width: 1180px) {
81 | .navbar {
82 | display: flex;
83 | flex-direction: row;
84 | align-items: center;
85 | justify-content: space-between;
86 |
87 | & > :last-child {
88 | margin-left: 0;
89 | }
90 | }
91 | nav {
92 | display: none;
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/src/components/Layout/Navbar/Navbar.tsx:
--------------------------------------------------------------------------------
1 | import { useState } from "react";
2 | import { NavLink } from "react-router-dom";
3 | import Modal from "../../UI/Modals/Modal";
4 | import {
5 | LogoSVG,
6 | MenuSVG,
7 | NavSVG1,
8 | NavSVG2,
9 | NavSVG3,
10 | NavSVG4,
11 | NavSVG5,
12 | NavSVG6,
13 | NavSVG7,
14 | } from "../../Assets/SVGs";
15 | import ProfilePicture from "../../UI/ProfilePicture";
16 | import { ImportVideo } from "../../UI/Modals/ModalChildren";
17 | import "./Navbar.scss";
18 | import { useModal } from "../../../hooks/useModal";
19 |
20 | const Navbar = (): JSX.Element => {
21 | const [active, setActive] = useState(0);
22 |
23 | const { openModal, setOpenModal, modalChild, setModalChild } = useModal();
24 |
25 | const navData = [
26 | { title: "Video Editing", icon: , clickFunc: () => {} },
27 | {
28 | title: "Import Video",
29 | icon: ,
30 | clickFunc: () => {
31 | console.log("button clickedd");
32 | setModalChild();
33 | setOpenModal(true);
34 | },
35 | },
36 | { title: "Add Voiceover", icon: , clickFunc: () => {} },
37 | { title: "Filters / Effects", icon: , clickFunc: () => {} },
38 | { title: "Add Subtitles", icon: , clickFunc: () => {} },
39 | { title: "3D Preview", icon: , clickFunc: () => {} },
40 | { title: "Sound Engine", icon: , clickFunc: () => {} },
41 | ];
42 |
43 | return (
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
77 |
82 |
83 | {modalChild}
84 |
85 |
86 | );
87 | };
88 |
89 | export default Navbar;
90 |
--------------------------------------------------------------------------------
/src/components/Layout/Navbar/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./Navbar";
2 |
--------------------------------------------------------------------------------
/src/components/UI/Button/Button.scss:
--------------------------------------------------------------------------------
1 | button {
2 | font-family: Cerebri Sans;
3 | font-weight: 600;
4 | font-size: 14px;
5 | line-height: 18px;
6 | cursor: pointer;
7 | }
8 |
9 | .primary {
10 | width: 100%;
11 | display: grid;
12 | place-items: center;
13 | padding: 10px 24px;
14 | background-color: transparent;
15 | color: #ffffff;
16 | border: 1px solid #ffffff;
17 | border-radius: 20px;
18 | transition: color ease-in 0.5s, background-color ease-in 0.5s;
19 |
20 | &:hover {
21 | background-color: #ffffff;
22 | color: black;
23 | }
24 | }
25 |
26 | .secondary {
27 | display: grid;
28 | place-items: center;
29 | padding: 9px 26px;
30 | padding-right: 28px;
31 | border-radius: 53px;
32 | color: #000000;
33 | background-color: #ffffff;
34 | border: 1px solid #ffffff;
35 | }
36 |
--------------------------------------------------------------------------------
/src/components/UI/Button/Button.tsx:
--------------------------------------------------------------------------------
1 | import "./Button.scss";
2 | import { Audio } from "react-loader-spinner";
3 |
4 | interface ButtonProps {
5 | children: JSX.Element | string;
6 | variant: string;
7 | disabled?: boolean;
8 | onClick?: () => void;
9 | href?: string;
10 | loading?: boolean;
11 | }
12 |
13 | const Button = ({
14 | children,
15 | variant,
16 | disabled = false,
17 | onClick,
18 | href,
19 | loading = false,
20 | }: ButtonProps): JSX.Element => {
21 | // const VARIANTS: string[] = ["primary", "secondary"];
22 | const disabledStyle = disabled && "disabled";
23 |
24 | const ButtonClassName = `${variant} ${disabledStyle}`;
25 |
26 | const clickFunc = () => {
27 | if (disabled || loading) return;
28 | else if (href) {
29 | return;
30 | } else {
31 | return onClick && onClick();
32 | }
33 | };
34 |
35 | return (
36 |
48 | );
49 | };
50 | export default Button;
51 |
--------------------------------------------------------------------------------
/src/components/UI/Button/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./Button";
2 |
--------------------------------------------------------------------------------
/src/components/UI/Cards/SideCard/SideCard.scss:
--------------------------------------------------------------------------------
1 | @import "../../../../styles/mixins";
2 |
3 | .SideCard {
4 | @include play_tiles();
5 |
6 | width: 100%;
7 | height: 100%;
8 | padding: 40px 19.5px 49px 15.5px;
9 |
10 | background: #080808 0% 0% no-repeat padding-box;
11 | color: #ffffff;
12 | border-radius: 10px;
13 | }
14 |
15 | .cardTitle {
16 | margin-bottom: 5px;
17 | display: flex;
18 | flex-direction: row;
19 | align-items: center;
20 | justify-content: space-between;
21 |
22 | svg {
23 | cursor: pointer;
24 | }
25 |
26 | &--song {
27 | margin-bottom: 12.5px;
28 | }
29 | }
30 |
31 | .desc {
32 | font: normal normal normal 12px/16px Cerebri Sans;
33 | letter-spacing: 0px;
34 | color: #bababa;
35 | }
36 |
37 | .videos {
38 | margin-top: 1px;
39 | }
40 |
41 | .btn {
42 | margin-top: 17px;
43 | padding-left: 10.5px;
44 | }
45 |
46 | .videoItem {
47 | display: flex;
48 | flex-direction: row;
49 | align-items: center;
50 | gap: 1rem;
51 | justify-content: space-between;
52 |
53 | border-bottom: 1px solid #161515;
54 | padding-top: 21px;
55 | padding-bottom: 18px;
56 | padding-left: 10.5px;
57 | cursor: pointer;
58 |
59 | &:hover {
60 | background-color: #242625;
61 | }
62 |
63 | & > :first-child {
64 | display: flex;
65 | flex-direction: row;
66 | align-items: center;
67 | gap: 1rem;
68 | }
69 |
70 | &--song {
71 | padding-bottom: 22.5px;
72 | padding-top: 20.5px;
73 | }
74 |
75 | &--song &__thumbnail {
76 | width: 40px;
77 | height: 40px;
78 | min-width: 40px;
79 | }
80 |
81 | &--song &__info {
82 | gap: 3px;
83 | }
84 |
85 | &__thumbnail {
86 | width: 76px;
87 | min-width: 76px;
88 | // width: max-content;
89 | height: 74px;
90 | }
91 | &__info {
92 | display: flex;
93 | flex-direction: column;
94 | align-items: flex-start;
95 | gap: 6px;
96 | }
97 |
98 | &--playing {
99 | margin-bottom: 0;
100 |
101 | &:hover {
102 | background-color: transparent;
103 | }
104 | // background-color: green;
105 | }
106 |
107 | svg {
108 | cursor: pointer;
109 | }
110 | }
111 |
112 | h3 {
113 | color: #ffffff !important;
114 | }
115 |
116 | .tasks {
117 | margin-top: 2.5rem;
118 |
119 | &__blocks {
120 | display: flex;
121 | flex-direction: row;
122 | align-items: center;
123 | justify-content: space-between;
124 | gap: 0.5rem;
125 | margin-top: 1rem;
126 |
127 | > * {
128 | background: #080808 0% 0% no-repeat padding-box;
129 | width: 100%;
130 | height: 7rem;
131 | border-radius: 0.5rem;
132 | cursor: pointer;
133 |
134 | display: grid;
135 | place-items: center;
136 | }
137 | > .active {
138 | background: #1a1a1a 0% 0% no-repeat padding-box;
139 | }
140 | }
141 | }
142 |
143 | .my-dropdown {
144 | background-color: #080808 !important;
145 |
146 | .ant-select-item {
147 | color: #ffffff !important;
148 | }
149 | }
150 |
151 | .waveDiv {
152 | padding-bottom: 12.5px;
153 | border-bottom: 1px solid #161515;
154 | }
155 |
156 | @media screen and (max-width: 1180px) {
157 | .SideCard {
158 | display: none;
159 | }
160 | }
161 |
--------------------------------------------------------------------------------
/src/components/UI/Cards/SideCard/SideCard.tsx:
--------------------------------------------------------------------------------
1 | import "./SideCard.scss";
2 |
3 | interface SideCardProps {
4 | children: JSX.Element;
5 | }
6 |
7 | const SideCard = ({ children }: SideCardProps): JSX.Element => {
8 | return ;
9 | };
10 |
11 | export default SideCard;
12 |
--------------------------------------------------------------------------------
/src/components/UI/Cards/SideCard/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./SideCard";
2 |
--------------------------------------------------------------------------------
/src/components/UI/Cards/VideoCard/VideoCard.scss:
--------------------------------------------------------------------------------
1 | .VideoCard {
2 | width: 100%;
3 | height: 100%;
4 | overflow: hidden;
5 | // padding: 40px 19.5px 49px 15.5px;
6 |
7 | background: #080808 0% 0% no-repeat padding-box;
8 | color: #ffffff;
9 | border-radius: 10px;
10 | // display: grid;
11 | // grid-template-rows: 85fr 15fr;
12 |
13 | &__placeholder {
14 | width: 100%;
15 | // height: 100%;
16 | overflow: hidden;
17 | display: grid;
18 | place-items: center;
19 | }
20 |
21 | video {
22 | width: 100%;
23 | overflow: hidden;
24 | }
25 | img {
26 | width: 100%;
27 | // height: 100%;
28 | max-width: 100%;
29 | // max-height: 100%;
30 | }
31 |
32 | &__controls {
33 | padding: 13px 51px 10px 17px;
34 | height: 89px;
35 | display: flex;
36 | flex-direction: column;
37 | align-items: flex-start;
38 | justify-content: space-between;
39 | gap: 1rem;
40 |
41 | > * {
42 | width: 100%;
43 | display: grid;
44 | grid-template-columns: 86.8fr 13.2fr;
45 | gap: 15px;
46 | // justify-content: center;
47 | align-items: center;
48 | }
49 | &__actions {
50 | display: flex;
51 | flex-direction: row;
52 | align-items: center;
53 | justify-content: space-between;
54 | gap: 0.5rem;
55 | > :first-child {
56 | display: flex;
57 | flex-direction: row;
58 | align-items: center;
59 | gap: 30px;
60 | }
61 |
62 | svg {
63 | cursor: pointer;
64 | }
65 | }
66 | &__other {
67 | display: flex;
68 | flex-direction: row;
69 | align-items: center;
70 | justify-content: space-between;
71 | gap: 0.5rem;
72 | svg {
73 | cursor: pointer;
74 | }
75 | }
76 | }
77 | }
78 |
79 | @media screen and (max-width: 1180px) {
80 | .VideoCard {
81 | &__controls {
82 | padding: 1rem;
83 |
84 | & > :nth-child(2) {
85 | display: flex;
86 | gap: 1rem;
87 | justify-content: space-between;
88 | }
89 | }
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/src/components/UI/Cards/VideoCard/VideoCard.tsx:
--------------------------------------------------------------------------------
1 | import Slider from "../../Slider";
2 | import "./VideoCard.scss";
3 | import {
4 | CameraIcon,
5 | VolumeUp,
6 | VolumeDown,
7 | ExpandIcon,
8 | SkipFD,
9 | SkipBD,
10 | StopIcon,
11 | PauseIcon,
12 | PlayIcon1,
13 | } from "../../../Assets/SVGs";
14 | import Dropdown from "../../Dropdown";
15 | import { MutableRefObject, useEffect, useRef, useState } from "react";
16 | import { secondsToTime } from "../../../../helpers/functions";
17 | import { RootState } from "../../../../redux/store";
18 | import { useSelector, useDispatch } from "react-redux";
19 | import { SETCURRENTTIME } from "../../../../redux/slices/currentTimeSlice";
20 | import { SETDURATION } from "../../../../redux/slices/durationSlice";
21 | import { SETEDGETIMES } from "../../../../redux/slices/edgeTimesSlice";
22 |
23 | declare global {
24 | interface Element {
25 | requestFullScreen?(): void;
26 | msRequestFullscreen(): void;
27 | webkitRequestFullscreen(): void;
28 | mozRequestFullScreen(): void;
29 | }
30 | }
31 |
32 | const VideoCard = (): JSX.Element => {
33 | const videoRef = useRef() as MutableRefObject;
34 | const [paused, setPaused] = useState(true);
35 | const [muted, setMuted] = useState(false);
36 |
37 | const currentVideo = useSelector(
38 | (state: RootState) => state.currentVideo.currentVideo
39 | );
40 | const currentTime = useSelector(
41 | (state: RootState) => state.currentTime.currentTime
42 | );
43 | const duration = useSelector((state: RootState) => state.duration.duration);
44 |
45 | const edgeTimes = useSelector(
46 | (state: RootState) => state.edgeTimes.edgeTimes
47 | );
48 | const dispatch = useDispatch();
49 |
50 | useEffect(() => {
51 | videoRef.current.currentTime = edgeTimes.start;
52 | }, [edgeTimes.start]);
53 |
54 | useEffect(() => {
55 | if (currentTime >= edgeTimes.end) videoRef.current.pause();
56 | }, [currentTime, edgeTimes.end]);
57 |
58 | return (
59 |
60 |
61 |
96 |
97 |
98 |
99 |
104 |
{secondsToTime(currentTime)}
105 |
106 |
107 |
108 |
109 |
{
111 | videoRef.current.currentTime -= 5;
112 | }}
113 | >
114 |
115 |
116 |
{
118 | videoRef.current.currentTime += 5;
119 | }}
120 | >
121 |
122 |
123 |
{
125 | videoRef.current.currentTime = 0;
126 | videoRef.current.pause();
127 | console.log(videoRef.current.paused);
128 | }}
129 | >
130 |
131 |
132 |
{
134 | paused
135 | ? videoRef.current.play()
136 | : videoRef.current.pause();
137 | setPaused(!paused);
138 | console.log(videoRef.current);
139 | }}
140 | >
141 | {paused ? : }
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 | {
152 | videoRef.current.muted = !muted;
153 | setMuted(!muted);
154 | console.log(videoRef.current);
155 | }}
156 | >
157 | {muted ? (
158 |
159 | ) : (
160 |
161 | )}
162 |
163 | {
165 | if (videoRef.current.requestFullscreen) {
166 | videoRef.current.requestFullscreen();
167 | } else if (
168 | videoRef.current.mozRequestFullScreen
169 | ) {
170 | videoRef.current.mozRequestFullScreen();
171 | } else if (
172 | videoRef.current.webkitRequestFullscreen
173 | ) {
174 | videoRef.current.webkitRequestFullscreen();
175 | } else if (
176 | videoRef.current.msRequestFullscreen
177 | ) {
178 | videoRef.current.msRequestFullscreen();
179 | }
180 | }}
181 | >
182 |
183 |
184 |
185 |
186 |
187 |
188 | );
189 | };
190 |
191 | export default VideoCard;
192 |
--------------------------------------------------------------------------------
/src/components/UI/Cards/VideoCard/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./VideoCard";
2 |
--------------------------------------------------------------------------------
/src/components/UI/Convert/Convert.scss:
--------------------------------------------------------------------------------
1 | .Convert {
2 | width: 100%;
3 | min-height: 230px;
4 | background: #080808 0% 0% no-repeat padding-box;
5 | color: white;
6 | border-radius: 10px;
7 |
8 | display: flex;
9 | flex-direction: row;
10 | align-items: center;
11 | flex-wrap: wrap;
12 | gap: 0.5rem;
13 | justify-content: space-evenly;
14 | padding: 1rem;
15 |
16 | &__box {
17 | min-width: 200px;
18 | min-height: 120px;
19 | background-color: #080808;
20 | color: #fff;
21 | border-radius: 4px;
22 | border: 1px solid white;
23 |
24 | display: grid;
25 | place-items: center;
26 | cursor: pointer;
27 | font-size: 1.5rem;
28 | font-weight: 600;
29 |
30 | transition: color ease-in 0.5s, background-color ease-in 0.5s;
31 |
32 | &--active {
33 | background-color: #fff;
34 | color: #080808;
35 | }
36 |
37 | &:hover {
38 | background-color: #fff;
39 | color: #080808;
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/components/UI/Convert/Convert.tsx:
--------------------------------------------------------------------------------
1 | import { useState } from "react";
2 | import "./Convert.scss";
3 | import { RootState } from "../../../redux/store";
4 | import { useSelector, useDispatch } from "react-redux";
5 | import { SETCURRENTTASK } from "../../../redux/slices/currentTaskSlice";
6 |
7 | const Convert = (): JSX.Element => {
8 | const [active, setActive] = useState(0);
9 |
10 | const conversionList = ["gif", "mp4", "wav", "avi", "m4a", "mp3"];
11 |
12 | const currentTask = useSelector(
13 | (state: RootState) => state.currentTask.currentTask
14 | );
15 |
16 | const dispatch = useDispatch();
17 |
18 | return (
19 |
20 | {conversionList.map((item, ind) => (
21 |
{
27 | setActive(ind);
28 | dispatch(
29 | SETCURRENTTASK({
30 | ...currentTask,
31 | details: conversionList[ind],
32 | })
33 | );
34 | }}
35 | >
36 | {item}
37 |
38 | ))}
39 |
40 | );
41 | };
42 |
43 | export default Convert;
44 |
--------------------------------------------------------------------------------
/src/components/UI/Convert/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./Convert";
2 |
--------------------------------------------------------------------------------
/src/components/UI/Dropdown/Dropdown.scss:
--------------------------------------------------------------------------------
1 | .Dropdown {
2 | min-width: 67px;
3 | background-color: #242625;
4 | border-radius: 5px;
5 |
6 | cursor: pointer;
7 | position: relative;
8 | z-index: 2;
9 |
10 | &__current {
11 | display: flex;
12 | flex-direction: row;
13 | align-items: center;
14 | justify-content: space-between;
15 | }
16 |
17 | &__item {
18 | padding: 4px 8px;
19 | }
20 |
21 | &__list {
22 | position: absolute;
23 | left: 0;
24 | bottom: 0%;
25 | background-color: #242625;
26 | width: 100%;
27 | height: max-content;
28 | overflow: hidden;
29 | transition: max-height 0.5s;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/components/UI/Dropdown/Dropdown.tsx:
--------------------------------------------------------------------------------
1 | import "./Dropdown.scss";
2 | import { BiChevronDown } from "react-icons/bi";
3 | import { useState } from "react";
4 |
5 | interface DropdownProps {
6 | list: string[];
7 | up?: boolean;
8 | }
9 |
10 | const Dropdown = ({ list, up }: DropdownProps): JSX.Element => {
11 | const [collapsed, setCollapsed] = useState(true);
12 |
13 | return (
14 | setCollapsed(!collapsed)}>
15 |
16 | {list[0]}
17 |
18 |
19 |
26 | {list.map((item, ind) => (
27 |
28 | {item}
29 |
30 | ))}
31 |
32 |
33 | );
34 | };
35 |
36 | export default Dropdown;
37 |
--------------------------------------------------------------------------------
/src/components/UI/Dropdown/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./Dropdown";
2 |
--------------------------------------------------------------------------------
/src/components/UI/Modals/Modal/Modal.scss:
--------------------------------------------------------------------------------
1 | .modal-div {
2 | width: 100vw;
3 | height: 100vh;
4 | place-items: center;
5 | overflow-y: scroll;
6 | background-color: #050404cb;
7 | color: #ffffff;
8 |
9 | &:focus {
10 | outline: none;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/components/UI/Modals/Modal/Modal.tsx:
--------------------------------------------------------------------------------
1 | import { createPortal } from "react-dom";
2 | import "./Modal.scss";
3 |
4 | interface ModalProps {
5 | children: JSX.Element;
6 | openModal: boolean;
7 | setOpenModal: (argg: boolean) => void;
8 | }
9 |
10 | const Modal = ({
11 | children,
12 | openModal,
13 | setOpenModal,
14 | }: ModalProps): JSX.Element => {
15 | return createPortal(
16 | {
22 | setOpenModal(false);
23 | }}
24 | onKeyDown={(ev) => {
25 | if (ev.code === "Escape") setOpenModal(false);
26 | }}
27 | tabIndex={3}
28 | >
29 | {children}
30 |
,
31 | document.getElementById("modal")!
32 | );
33 | };
34 |
35 | export default Modal;
36 |
--------------------------------------------------------------------------------
/src/components/UI/Modals/Modal/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./Modal";
2 |
--------------------------------------------------------------------------------
/src/components/UI/Modals/ModalChildren/ImportVideo.tsx:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from "react";
2 | import "./ModalChildren.scss";
3 | import { ImportVeditor, ImportDevice } from "../../../Assets/SVGs";
4 | import { IoClose } from "react-icons/io5";
5 | import { useDispatch } from "react-redux";
6 | import { Audio } from "react-loader-spinner";
7 | import { SETCURRENTVIDEO } from "../../../../redux/slices/currentVideoSlice";
8 | import { SETSTOREDVIDEO } from "../../../../redux/slices/storedVideoSlice";
9 | import { uploadVid } from "../../../../services/apis";
10 |
11 | interface ImportVideoProps {
12 | setOpenModal: (argg: boolean) => void;
13 | }
14 |
15 | const ImportVideo = ({ setOpenModal }: ImportVideoProps): JSX.Element => {
16 | const [loading, setLoading] = useState(false);
17 | const [myForm, setMyForm] = useState({});
18 |
19 | const dispatch = useDispatch();
20 |
21 | useEffect(() => {
22 | setMyForm(document.querySelector("#myForm")!);
23 | }, []);
24 |
25 | return (
26 | ev.stopPropagation()}>
27 |
28 |
Import Video
29 |
Please select how you would like to import your video
30 |
31 |
91 |
setOpenModal(false)}>
92 |
93 |
94 |
95 | );
96 | };
97 |
98 | export default ImportVideo;
99 |
--------------------------------------------------------------------------------
/src/components/UI/Modals/ModalChildren/ModalChildren.scss:
--------------------------------------------------------------------------------
1 | .ImportVideo {
2 | width: 711px;
3 | height: 459px;
4 |
5 | background: #1a1a1a 0% 0% no-repeat padding-box;
6 | border-radius: 20px;
7 |
8 | display: flex;
9 | flex-direction: column;
10 | align-items: center;
11 | padding: 50px 109px 50px 109px;
12 | position: relative;
13 |
14 | &__header {
15 | display: flex;
16 | flex-direction: column;
17 | align-items: center;
18 | gap: 12px;
19 |
20 | p {
21 | font: normal normal normal 14px/18px Cerebri Sans;
22 | color: #bababa;
23 | }
24 | }
25 |
26 | &__options {
27 | display: flex;
28 | flex-direction: row;
29 | align-items: center;
30 | gap: 30px;
31 | margin-top: 2rem;
32 | }
33 |
34 | &__option {
35 | position: relative;
36 | width: 231px;
37 | height: 219px;
38 | background: #080808 0% 0% no-repeat padding-box;
39 | border-radius: 12px;
40 | display: flex;
41 | flex-direction: column;
42 | align-items: center;
43 | justify-content: flex-end;
44 | gap: 32px;
45 | cursor: pointer;
46 | padding: 45px 16px;
47 | font: normal normal bold 12px/16px Cerebri Sans;
48 | }
49 |
50 | input[type="file"] {
51 | position: absolute;
52 | top: 0;
53 | left: 0;
54 | width: 100%;
55 | height: 100%;
56 | opacity: 0;
57 | cursor: pointer;
58 | }
59 | }
60 |
61 | .close {
62 | width: 20px;
63 | height: 20px;
64 | background: rgba(255, 255, 255, 0.4) 0% 0% no-repeat padding-box;
65 | border-radius: 0.4rem;
66 |
67 | display: grid;
68 | place-items: center;
69 |
70 | position: absolute;
71 | top: 20px;
72 | right: 20px;
73 | cursor: pointer;
74 | }
75 |
--------------------------------------------------------------------------------
/src/components/UI/Modals/ModalChildren/index.js:
--------------------------------------------------------------------------------
1 | export { default as ImportVideo } from "./ImportVideo";
2 |
--------------------------------------------------------------------------------
/src/components/UI/ProfilePicture/ProfilePicture.scss:
--------------------------------------------------------------------------------
1 | .profileImg {
2 | width: 100%;
3 | height: 100%;
4 | border-radius: 50%;
5 | overflow: hidden;
6 | cursor: pointer;
7 |
8 | img {
9 | width: 100%;
10 | height: 100%;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/components/UI/ProfilePicture/ProfilePicture.tsx:
--------------------------------------------------------------------------------
1 | import "./ProfilePicture.scss";
2 |
3 | const ProfilePicture = ({ imageURL }: { imageURL: string }): JSX.Element => (
4 |
5 |

6 |
7 | );
8 |
9 | export default ProfilePicture;
10 |
--------------------------------------------------------------------------------
/src/components/UI/ProfilePicture/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./ProfilePicture";
2 |
--------------------------------------------------------------------------------
/src/components/UI/Slider/Slider.scss:
--------------------------------------------------------------------------------
1 | .Slider {
2 | width: 100%;
3 | height: 3px;
4 | background-color: rgba(186, 186, 186, 0.3);
5 | cursor: pointer;
6 | transition: width 0.3s;
7 |
8 | &__track {
9 | height: 100%;
10 | background-color: #18c96a;
11 | position: relative;
12 | // display: flex;
13 | // flex-direction: row;
14 | // align-items: center;
15 | }
16 |
17 | &__thumb {
18 | width: 18px;
19 | height: 18px;
20 | background-color: #18c96a;
21 | border-radius: 50%;
22 | position: absolute;
23 | top: 50%;
24 | right: 0;
25 | transform: translate(50%, -50%);
26 | cursor: pointer;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/components/UI/Slider/Slider.tsx:
--------------------------------------------------------------------------------
1 | import "./Slider.scss";
2 | import { useDispatch } from "react-redux";
3 | import { SETCURRENTTIME } from "../../../redux/slices/currentTimeSlice";
4 |
5 | interface SliderProps {
6 | posn: number;
7 | duration: number;
8 | vidElement: HTMLVideoElement;
9 | }
10 |
11 | const Slider = ({ posn, duration, vidElement }: SliderProps): JSX.Element => {
12 | const dispatch = useDispatch();
13 | // const currentTime = useSelector(
14 | // (state: RootState) => state.currentTime.currentTime
15 | // );
16 |
17 | return (
18 | {
21 | const { currentTarget, clientX } = ev;
22 | if (currentTarget) {
23 | console.log(clientX);
24 | const offsetLeft = (currentTarget as HTMLDivElement)
25 | .offsetLeft;
26 | const clientWidth = (currentTarget as HTMLDivElement)
27 | .clientWidth;
28 | let newVal = clientX - offsetLeft;
29 | if (newVal < 0) {
30 | newVal = 0;
31 | } else if (newVal > clientWidth) {
32 | newVal = clientWidth;
33 | }
34 | dispatch(SETCURRENTTIME((newVal / clientWidth) * duration));
35 | vidElement.currentTime = (newVal / clientWidth) * duration;
36 | }
37 | }}
38 | >
39 |
47 |
48 | );
49 | };
50 |
51 | export default Slider;
52 |
--------------------------------------------------------------------------------
/src/components/UI/Slider/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./Slider";
2 |
--------------------------------------------------------------------------------
/src/components/UI/Timeline/Timeline.scss:
--------------------------------------------------------------------------------
1 | .TimelineGrid {
2 | display: grid;
3 | grid-template-rows: 54.5px 56px 56px 1fr;
4 | gap: 0;
5 | background: #080808 0% 0% no-repeat padding-box;
6 | color: white;
7 | border-radius: 10px;
8 | min-height: 230px;
9 | & > :last-child {
10 | border-bottom: 0;
11 | }
12 | }
13 |
14 | .TimelineGridRow {
15 | display: grid;
16 | grid-template-columns: 130px 1fr;
17 | gap: 0;
18 | border-bottom: 1px solid #bfbfbf27;
19 |
20 | & > :first-child {
21 | border-right: 1px solid #bfbfbf27;
22 | }
23 |
24 | &__icons {
25 | display: flex;
26 | flex-direction: row;
27 | align-items: center;
28 | justify-content: center;
29 | gap: 1rem;
30 | }
31 | }
32 |
33 | .timelineWrapper {
34 | padding: 11.5px 15.5px;
35 |
36 | &--header {
37 | display: flex;
38 | flex-direction: column;
39 | justify-content: flex-end;
40 | padding: 0 15.5px;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/components/UI/Timeline/Timeline.tsx:
--------------------------------------------------------------------------------
1 | import TimelineRow from "./TimelineRow";
2 | import "./Timeline.scss";
3 | import { RootState } from "../../../redux/store";
4 | import { useSelector, useDispatch } from "react-redux";
5 | import { SETEDGETIMES } from "../../../redux/slices/edgeTimesSlice";
6 | import { SETCURRENTTIME } from "../../../redux/slices/currentTimeSlice";
7 | import { useEffect } from "react";
8 |
9 | const Timeline = (): JSX.Element => {
10 | const dispatch = useDispatch();
11 | const duration = useSelector((state: RootState) => state.duration.duration);
12 |
13 | useEffect(() => {
14 | dispatch(SETEDGETIMES({ start: 0, end: duration }));
15 | dispatch(SETCURRENTTIME(0));
16 | console.log("mounted");
17 | }, [dispatch, duration]);
18 |
19 | return (
20 |
21 |
22 |
23 |
24 |
25 |
26 | );
27 | };
28 |
29 | export default Timeline;
30 |
--------------------------------------------------------------------------------
/src/components/UI/Timeline/TimelineRow.tsx:
--------------------------------------------------------------------------------
1 | import { HiOutlineDuplicate } from "react-icons/hi";
2 | import { FiSettings } from "react-icons/fi";
3 | import { IoVideocam } from "react-icons/io5";
4 | import { CgEyeAlt } from "react-icons/cg";
5 | import { MusicIcon } from "../../Assets/SVGs";
6 | import { AudioTimeline, VideoTimeline, TimelineHeader } from "../Timelines";
7 |
8 | import "./Timeline.scss";
9 |
10 | interface TimelineRowProps {
11 | variant: string;
12 | }
13 |
14 | const TimelineRow = ({ variant }: TimelineRowProps): JSX.Element => {
15 | switch (variant) {
16 | case "header":
17 | return (
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | );
28 |
29 | case "video":
30 | return (
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | );
41 |
42 | case "song":
43 | return (
44 |
45 |
46 |
47 |
48 |
49 |
52 |
53 | );
54 |
55 | default:
56 | return (
57 |
61 | );
62 | }
63 | };
64 |
65 | export default TimelineRow;
66 |
--------------------------------------------------------------------------------
/src/components/UI/Timeline/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./Timeline";
2 |
--------------------------------------------------------------------------------
/src/components/UI/Timelines/AudioTimeline.tsx:
--------------------------------------------------------------------------------
1 | import "./Timelines.scss";
2 |
3 | const AudioTimeline = (): JSX.Element => {
4 | return (
5 |
12 | );
13 | };
14 |
15 | export default AudioTimeline;
16 |
--------------------------------------------------------------------------------
/src/components/UI/Timelines/TimelineHeader.tsx:
--------------------------------------------------------------------------------
1 | import "./Timelines.scss";
2 | import { secondsToTime } from "../../../helpers/functions";
3 |
4 | const TimelineHeader = (): JSX.Element => {
5 | return (
6 |
7 |
8 | {Array(3)
9 | .fill(0)
10 | .map((item, ind) => (
11 |
12 | ))}
13 | {Array(28)
14 | .fill(0)
15 | .map((item, ind) => (
16 |
24 | {ind % 5 === 0 ? (
25 |
26 | {secondsToTime(ind)}
27 |
28 | ) : null}
29 |
30 | ))}
31 | {Array(3)
32 | .fill(0)
33 | .map((item, ind) => (
34 |
35 | ))}
36 |
37 |
38 | );
39 | };
40 |
41 | export default TimelineHeader;
42 |
--------------------------------------------------------------------------------
/src/components/UI/Timelines/Timelines.scss:
--------------------------------------------------------------------------------
1 | .VideoTimeline {
2 | width: 100%;
3 | height: 100%;
4 | background: #6a6b6b 0% 0% no-repeat padding-box;
5 |
6 | border-radius: 5px;
7 | position: relative;
8 | user-select: none;
9 |
10 | &__green {
11 | // width: 100%;
12 | height: 100%;
13 | padding: 2px;
14 | // border-radius: 5px;
15 | background: #28714f 0% 0% no-repeat padding-box;
16 | position: absolute;
17 | top: 0;
18 | left: 0;
19 | right: 0;
20 | cursor: grab;
21 | }
22 |
23 | &__edge {
24 | width: 7px;
25 | height: 100%;
26 | position: absolute;
27 | top: 0;
28 | background-color: white;
29 | cursor: e-resize;
30 |
31 | &--left {
32 | border-top-left-radius: 3px;
33 | border-bottom-left-radius: 3px;
34 | left: 0;
35 | transform: translateX(-70%);
36 | }
37 | &--right {
38 | border-top-right-radius: 3px;
39 | border-bottom-right-radius: 3px;
40 | right: 0;
41 | transform: translateX(70%);
42 | }
43 | }
44 |
45 | &__placeholder {
46 | width: 42px;
47 | height: 100%;
48 | border-radius: 3px;
49 | background-image: url("../../../assets/images/imgPlaceholder.png");
50 | background-size: cover;
51 | }
52 |
53 | &__tracker {
54 | position: absolute;
55 | top: -25%;
56 | width: 2px;
57 | height: 48px;
58 | background: #ffffff 0% 0% no-repeat padding-box;
59 | cursor: e-resize;
60 |
61 | > :first-child {
62 | width: 6px;
63 | height: 6px;
64 | border-radius: 50%;
65 | background: #ffffff 0% 0% no-repeat padding-box;
66 | position: absolute;
67 | top: -2px;
68 | left: -100%;
69 | z-index: 1;
70 | }
71 | > :last-child {
72 | width: 6px;
73 | height: 6px;
74 | border-radius: 50%;
75 | background: #ffffff 0% 0% no-repeat padding-box;
76 | position: absolute;
77 | bottom: -2px;
78 | left: -100%;
79 | z-index: 1;
80 | }
81 | }
82 | }
83 |
84 | .AudioTimeline {
85 | width: 100%;
86 | height: 100%;
87 | background: #242625 0% 0% no-repeat padding-box;
88 |
89 | border-radius: 5px;
90 | position: relative;
91 | padding: 2px;
92 |
93 | &__tracker {
94 | position: absolute;
95 | top: -25%;
96 | width: 2px;
97 | height: 48px;
98 | background: #ffffff 0% 0% no-repeat padding-box;
99 | cursor: e-resize;
100 |
101 | > :first-child {
102 | width: 6px;
103 | height: 6px;
104 | border-radius: 50%;
105 | background: #ffffff 0% 0% no-repeat padding-box;
106 | position: absolute;
107 | top: -2px;
108 | left: -100%;
109 | z-index: 1;
110 | }
111 | > :last-child {
112 | width: 6px;
113 | height: 6px;
114 | border-radius: 50%;
115 | background: #ffffff 0% 0% no-repeat padding-box;
116 | position: absolute;
117 | bottom: -2px;
118 | left: -100%;
119 | z-index: 1;
120 | }
121 | }
122 | }
123 |
124 | .TimelineHeader {
125 | &__lines {
126 | display: flex;
127 | flex-direction: row;
128 | align-items: flex-end;
129 | gap: 3px;
130 | justify-content: space-between;
131 | }
132 |
133 | &__line {
134 | width: 0px;
135 | height: 10px;
136 | border: 1px solid #707070;
137 | position: relative;
138 |
139 | &--long {
140 | border-color: #18c96a;
141 | height: 17px;
142 | }
143 | }
144 |
145 | &__number {
146 | position: absolute;
147 | top: -150%;
148 | left: -100%;
149 | transform: translateX(-50%);
150 | font: normal normal normal 12px/16px Cerebri Sans;
151 | color: #bababa;
152 | }
153 | }
154 |
155 | @media screen and (max-width: 1180px) {
156 | .TimelineHeader {
157 | &__number {
158 | display: none;
159 | }
160 | }
161 | }
162 |
163 | @media screen and (max-width: 700px) {
164 | .TimelineHeader {
165 | &__line {
166 | display: none;
167 | }
168 | }
169 | }
170 |
--------------------------------------------------------------------------------
/src/components/UI/Timelines/VideoTimeline.tsx:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from "react";
2 | import { useRef, MutableRefObject } from "react";
3 | import "./Timelines.scss";
4 | import { RootState } from "../../../redux/store";
5 | import { useSelector, useDispatch } from "react-redux";
6 | import { SETCURRENTTIME } from "../../../redux/slices/currentTimeSlice";
7 | import { SETEDGETIMES } from "../../../redux/slices/edgeTimesSlice";
8 |
9 | const VideoTimeline = (): JSX.Element => {
10 | const vidTimelineRef = useRef() as MutableRefObject;
11 | const greenTimelineRef = useRef() as MutableRefObject;
12 | const [resizing, setResizing] = useState(false);
13 | const [initialLength, setInitialLength] = useState(0);
14 | const [leftOffset, setLeftOffset] = useState(0);
15 | const [rightOffset, setRightOffset] = useState(0);
16 |
17 | const dispatch = useDispatch();
18 | const currentTime = useSelector(
19 | (state: RootState) => state.currentTime.currentTime
20 | );
21 | const duration = useSelector((state: RootState) => state.duration.duration);
22 | const edgeTimes = useSelector(
23 | (state: RootState) => state.edgeTimes.edgeTimes
24 | );
25 |
26 | const posn =
27 | ((currentTime - edgeTimes.start) /
28 | (duration - edgeTimes.start - (duration - edgeTimes.end))) *
29 | 100;
30 |
31 | useEffect(() => {
32 | setInitialLength(vidTimelineRef.current.clientWidth);
33 | // console.log(initialLength);
34 | }, []);
35 |
36 | useEffect(() => {}, [resizing]);
37 |
38 | const MouseDownFuncLeft = (
39 | mouseDownEv: React.MouseEvent
40 | ) => {
41 | const MouseMoveFunc = (ev: MouseEvent) => {
42 | if (
43 | ev.clientX <
44 | vidTimelineRef.current.clientWidth -
45 | rightOffset +
46 | vidTimelineRef.current.offsetLeft
47 | ) {
48 | setLeftOffset(
49 | Math.max(0, ev.clientX - mouseDownEv.clientX + leftOffset)
50 | );
51 |
52 | console.log(vidTimelineRef.current.clientWidth);
53 | }
54 | };
55 | const MouseUpFunc = (ev: MouseEvent) => {
56 | dispatch(
57 | SETEDGETIMES({
58 | ...edgeTimes,
59 | start: Math.min(
60 | (Math.max(
61 | 0,
62 | ev.clientX - mouseDownEv.clientX + leftOffset
63 | ) /
64 | initialLength) *
65 | duration,
66 | edgeTimes.end
67 | ),
68 | })
69 | );
70 | dispatch(SETCURRENTTIME(edgeTimes.start));
71 |
72 | window.removeEventListener("mousemove", MouseMoveFunc);
73 | window.removeEventListener("mouseup", MouseUpFunc);
74 | console.log("clean");
75 | };
76 |
77 | window.addEventListener("mousemove", MouseMoveFunc);
78 | window.addEventListener("mouseup", MouseUpFunc);
79 | };
80 |
81 | const MouseDownFuncRight = (
82 | mouseDownEv: React.MouseEvent
83 | ) => {
84 | const MouseMoveFunc = (ev: MouseEvent) => {
85 | if (ev.clientX - vidTimelineRef.current.offsetLeft > leftOffset) {
86 | console.log("ev.clientX", ev.clientX);
87 | console.log("leftOffset", leftOffset);
88 | // console.log(Math.max(0, ev.clientX - mouseDownEv.clientX));
89 | setRightOffset(
90 | Math.max(0, mouseDownEv.clientX - ev.clientX + rightOffset)
91 | );
92 | }
93 | };
94 | const MouseUpFunc = (ev: MouseEvent) => {
95 | console.log(
96 | "timeline element: ",
97 | vidTimelineRef.current.offsetLeft
98 | );
99 | console.log("Mousedown clientX: ", mouseDownEv.clientX);
100 | console.log("mouseup clientX: ", ev.clientX);
101 | console.log("rightOffset: ", rightOffset);
102 | console.log("greenTimelineRef: ", greenTimelineRef.current);
103 | dispatch(
104 | SETEDGETIMES({
105 | ...edgeTimes,
106 | end: Math.max(
107 | edgeTimes.start,
108 | Math.min(
109 | ((ev.clientX - vidTimelineRef.current.offsetLeft) /
110 | initialLength) *
111 | duration,
112 | duration
113 | )
114 | ),
115 | })
116 | );
117 |
118 | window.removeEventListener("mousemove", MouseMoveFunc);
119 | window.removeEventListener("mouseup", MouseUpFunc);
120 | setResizing(false);
121 | console.log("clean");
122 | };
123 |
124 | window.addEventListener("mousemove", MouseMoveFunc);
125 | window.addEventListener("mouseup", MouseUpFunc);
126 | };
127 |
128 | return (
129 |
130 |
{
134 | setResizing(true);
135 | console.log("start moving");
136 | console.log(ev.nativeEvent.offsetX);
137 | MouseDownFuncLeft(ev);
138 | }}
139 | >
140 |
{}}
150 | >
151 |
152 |
153 |
160 |
161 |
{
165 | setResizing(true);
166 | console.log("start moving");
167 | console.log(ev.nativeEvent.offsetX);
168 | MouseDownFuncRight(ev);
169 | }}
170 | >
171 |
172 | );
173 | };
174 |
175 | export default VideoTimeline;
176 |
--------------------------------------------------------------------------------
/src/components/UI/Timelines/index.js:
--------------------------------------------------------------------------------
1 | export { default as AudioTimeline } from "./AudioTimeline";
2 | export { default as VideoTimeline } from "./VideoTimeline";
3 | export { default as TimelineHeader } from "./TimelineHeader";
4 |
--------------------------------------------------------------------------------
/src/components/UI/VideoPlaceholder/VideoPlaceholder.scss:
--------------------------------------------------------------------------------
1 | .VideoPlaceholder {
2 | width: 100%;
3 | height: 100%;
4 | border-radius: 5px;
5 | overflow: hidden;
6 | position: relative;
7 |
8 | &__play {
9 | position: absolute;
10 | top: 0;
11 | left: 0;
12 | width: 100%;
13 | height: 100%;
14 | background: #000000a8;
15 | display: grid;
16 | place-items: center;
17 | border-radius: 5px;
18 | }
19 |
20 | img {
21 | width: 100%;
22 | height: 100%;
23 | min-width: 100%;
24 | min-height: 100%;
25 | // height: 100%;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/components/UI/VideoPlaceholder/VideoPlaceholder.tsx:
--------------------------------------------------------------------------------
1 | import "./VideoPlaceholder.scss";
2 | import { PlayIcon2 } from "../../Assets/SVGs";
3 |
4 | interface VideoPlaceholderProps {
5 | imageURL: string;
6 | video?: boolean;
7 | }
8 |
9 | const VideoPlaceholder = ({
10 | imageURL,
11 | video,
12 | }: VideoPlaceholderProps): JSX.Element => (
13 |
14 |

15 | {video ? (
16 |
19 | ) : null}
20 |
21 | );
22 |
23 | export default VideoPlaceholder;
24 |
--------------------------------------------------------------------------------
/src/components/UI/VideoPlaceholder/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./VideoPlaceholder";
2 |
--------------------------------------------------------------------------------
/src/components/UI/WaveForm/WaveForm.scss:
--------------------------------------------------------------------------------
1 | .WaveForm {
2 | width: 100%;
3 | height: 40px;
4 | background-color: #242625;
5 | }
6 |
--------------------------------------------------------------------------------
/src/components/UI/WaveForm/WaveForm.tsx:
--------------------------------------------------------------------------------
1 | import "./WaveForm.scss";
2 |
3 | const WaveForm = (): JSX.Element => ;
4 |
5 | export default WaveForm;
6 |
--------------------------------------------------------------------------------
/src/components/UI/WaveForm/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./WaveForm";
2 |
--------------------------------------------------------------------------------
/src/helpers/functions.tsx:
--------------------------------------------------------------------------------
1 | const doubleNumbers = (val: number): string => {
2 | return val < 10 ? `0${val}` : `${val}`;
3 | };
4 |
5 | export const secondsToTime = (secondsTime: number): string => {
6 | let microseconds: number, seconds: number, minutes: number, hours: number;
7 |
8 | hours = Math.floor(secondsTime / 3600);
9 | minutes = Math.floor((secondsTime - hours * 3600) / 60);
10 | seconds = Math.floor(secondsTime - (hours * 3600 + minutes * 60));
11 | microseconds = 0;
12 | return `${doubleNumbers(hours)}:${doubleNumbers(minutes)}:${doubleNumbers(
13 | seconds
14 | )}:${doubleNumbers(microseconds)}`;
15 | };
16 |
--------------------------------------------------------------------------------
/src/hooks/useModal.ts:
--------------------------------------------------------------------------------
1 | import { useState } from "react";
2 |
3 | export const useModal = () =>{
4 | const [openModal, setOpenModal] = useState(false);
5 | const [modalChild, setModalChild] = useState(null)
6 |
7 | return {openModal, setOpenModal, modalChild, setModalChild}
8 | }
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
5 | sans-serif;
6 | -webkit-font-smoothing: antialiased;
7 | -moz-osx-font-smoothing: grayscale;
8 | }
9 |
10 | code {
11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
12 | monospace;
13 | }
14 |
15 | * {
16 | margin: 0;
17 | padding: 0;
18 | box-sizing: border-box;
19 | }
--------------------------------------------------------------------------------
/src/index.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import "./index.css";
4 | import App from "./App";
5 | import { Provider } from "react-redux";
6 | import { store } from "./redux/store";
7 | import reportWebVitals from "./reportWebVitals";
8 |
9 | const root = ReactDOM.createRoot(
10 | document.getElementById("root") as HTMLElement
11 | );
12 | root.render(
13 |
14 |
15 |
16 |
17 |
18 | );
19 |
20 | // If you want to start measuring performance in your app, pass a function
21 | // to log results (for example: reportWebVitals(console.log))
22 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
23 | reportWebVitals();
24 |
--------------------------------------------------------------------------------
/src/logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/pages/VideoEditing.tsx:
--------------------------------------------------------------------------------
1 | import Body from "../components/Layout/Body";
2 | import Navbar from "../components/Layout/Navbar";
3 | import "../styles/main.scss";
4 |
5 | const VideoEditing = (): JSX.Element => {
6 | return (
7 | <>
8 |
9 |
10 |
11 |
12 | >
13 | );
14 | };
15 |
16 | export default VideoEditing;
17 |
--------------------------------------------------------------------------------
/src/react-app-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/src/redux/slices/currentTaskSlice.ts:
--------------------------------------------------------------------------------
1 | import { createSlice, PayloadAction } from "@reduxjs/toolkit";
2 |
3 | export interface CurrentTaskProps {
4 | name: string;
5 | details:string;
6 | }
7 |
8 | export interface CurrentTaskState {
9 | currentTask: CurrentTaskProps;
10 | }
11 |
12 | const initialState: CurrentTaskState = {
13 | currentTask:{name:"Trim", details:'gif'},
14 | };
15 |
16 | export const currentTaskSlice = createSlice({
17 | name: "currentTask",
18 | initialState,
19 | reducers: {
20 | SETCURRENTTASK: (state, action: PayloadAction) => {
21 | state.currentTask = action.payload;
22 | },
23 | },
24 | });
25 |
26 | export const { SETCURRENTTASK } = currentTaskSlice.actions;
27 |
28 | export default currentTaskSlice.reducer;
29 |
--------------------------------------------------------------------------------
/src/redux/slices/currentTimeSlice.ts:
--------------------------------------------------------------------------------
1 | import { createSlice, PayloadAction } from "@reduxjs/toolkit";
2 |
3 | export interface CurrentTimeState {
4 | currentTime: number;
5 | }
6 |
7 | const initialState: CurrentTimeState = {
8 | currentTime: 0,
9 | };
10 |
11 | export const currentTimeSlice = createSlice({
12 | name: "currentTime",
13 | initialState,
14 | reducers: {
15 | SETCURRENTTIME: (state, action: PayloadAction) => {
16 | state.currentTime = action.payload;
17 | },
18 | },
19 | });
20 |
21 | export const { SETCURRENTTIME } = currentTimeSlice.actions;
22 |
23 | export default currentTimeSlice.reducer;
24 |
--------------------------------------------------------------------------------
/src/redux/slices/currentVideoSlice.ts:
--------------------------------------------------------------------------------
1 | import { createSlice, PayloadAction } from "@reduxjs/toolkit";
2 |
3 | export interface CurrentVideoState {
4 | currentVideo: string;
5 | }
6 |
7 | const initialState: CurrentVideoState = {
8 | currentVideo: "",
9 | };
10 |
11 | export const currentVideoSlice = createSlice({
12 | name: "currentVideo",
13 | initialState,
14 | reducers: {
15 | SETCURRENTVIDEO: (state, action: PayloadAction) => {
16 | state.currentVideo = action.payload;
17 | },
18 | },
19 | });
20 |
21 | export const { SETCURRENTVIDEO } = currentVideoSlice.actions;
22 |
23 | export default currentVideoSlice.reducer;
24 |
--------------------------------------------------------------------------------
/src/redux/slices/durationSlice.ts:
--------------------------------------------------------------------------------
1 | import { createSlice, PayloadAction } from "@reduxjs/toolkit";
2 |
3 | export interface durationState {
4 | duration: number;
5 | }
6 |
7 | const initialState: durationState = {
8 | duration: 0,
9 | };
10 |
11 | export const durationSlice = createSlice({
12 | name: "duration",
13 | initialState,
14 | reducers: {
15 | SETDURATION: (state, action: PayloadAction) => {
16 | state.duration = action.payload;
17 | },
18 | },
19 | });
20 |
21 | export const { SETDURATION } = durationSlice.actions;
22 |
23 | export default durationSlice.reducer;
24 |
--------------------------------------------------------------------------------
/src/redux/slices/edgeTimesSlice.ts:
--------------------------------------------------------------------------------
1 | import { createSlice, PayloadAction } from "@reduxjs/toolkit";
2 |
3 | export interface EdgeTimesProps {
4 | start: number;
5 | end:number;
6 | }
7 |
8 | export interface EdgeTimesState {
9 | edgeTimes: EdgeTimesProps;
10 | }
11 |
12 | const initialState: EdgeTimesState = {
13 | edgeTimes:{start:0, end:12},
14 | };
15 |
16 | export const edgeTimesSlice = createSlice({
17 | name: "edgeTimes",
18 | initialState,
19 | reducers: {
20 | SETEDGETIMES: (state, action: PayloadAction) => {
21 | state.edgeTimes = action.payload;
22 | },
23 | },
24 | });
25 |
26 | export const { SETEDGETIMES } = edgeTimesSlice.actions;
27 |
28 | export default edgeTimesSlice.reducer;
29 |
--------------------------------------------------------------------------------
/src/redux/slices/storedVideoSlice.ts:
--------------------------------------------------------------------------------
1 | import { createSlice, PayloadAction } from "@reduxjs/toolkit";
2 |
3 | export interface storedVideoProps {
4 | filename:string;
5 | filepath:string
6 | }
7 |
8 | export interface storedVideoState {
9 | storedVideo: storedVideoProps;
10 | }
11 |
12 | const initialState: storedVideoState = {
13 | storedVideo: { filename: '', filepath: '' },
14 | };
15 |
16 |
17 |
18 | export const storedVideoSlice = createSlice({
19 | name: "storedVideo",
20 | initialState,
21 | reducers: {
22 | SETSTOREDVIDEO: (state, action: PayloadAction) => {
23 | state.storedVideo = {...state.storedVideo, filename: action.payload.filename, filepath: action.payload.filepath};
24 | },
25 | },
26 | });
27 |
28 | export const { SETSTOREDVIDEO } = storedVideoSlice.actions;
29 |
30 | export default storedVideoSlice.reducer;
31 |
--------------------------------------------------------------------------------
/src/redux/store.ts:
--------------------------------------------------------------------------------
1 | import { configureStore } from "@reduxjs/toolkit";
2 | import currentVideoReducer from "./slices/currentVideoSlice";
3 | import currentTimeReducer from "./slices/currentTimeSlice";
4 | import durationReducer from "./slices/durationSlice";
5 | import storedVideoReducer from "./slices/storedVideoSlice";
6 | import currentTaskReducer from "./slices/currentTaskSlice";
7 | import edgeTimesReducer from "./slices/edgeTimesSlice";
8 |
9 | export const store = configureStore({ reducer: {
10 | currentVideo: currentVideoReducer,
11 | currentTime: currentTimeReducer,
12 | duration: durationReducer,
13 | storedVideo: storedVideoReducer,
14 | currentTask:currentTaskReducer,
15 | edgeTimes:edgeTimesReducer
16 | }
17 | })
18 |
19 | export type RootState = ReturnType
20 | export type AppDispatch = typeof store.dispatch
--------------------------------------------------------------------------------
/src/reportWebVitals.ts:
--------------------------------------------------------------------------------
1 | import { ReportHandler } from 'web-vitals';
2 |
3 | const reportWebVitals = (onPerfEntry?: ReportHandler) => {
4 | if (onPerfEntry && onPerfEntry instanceof Function) {
5 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
6 | getCLS(onPerfEntry);
7 | getFID(onPerfEntry);
8 | getFCP(onPerfEntry);
9 | getLCP(onPerfEntry);
10 | getTTFB(onPerfEntry);
11 | });
12 | }
13 | };
14 |
15 | export default reportWebVitals;
16 |
--------------------------------------------------------------------------------
/src/services/apis.ts:
--------------------------------------------------------------------------------
1 | import axios from "axios"
2 |
3 | export const uploadVid = async (payload: FormData)=>{
4 | try{
5 | const response = await axios.post(
6 | `${process.env.REACT_APP_BASE_URL}/upload`,
7 | payload
8 | )
9 | return response
10 | }
11 | catch(err) {
12 | console.log(err)
13 | throw err
14 | }
15 | }
16 |
17 | export const transcodeVid = async (payload: {filename:string; filepath:string; filetype: string})=>{
18 | try{
19 | const response = await axios({
20 | method: 'post',
21 | url: `${process.env.REACT_APP_BASE_URL}/transcode`,
22 | data: payload,
23 | responseType: 'blob'
24 | })
25 |
26 | return response
27 | }
28 | catch(err) {
29 | console.log(err)
30 | throw err
31 | }
32 | }
33 |
34 | export const trimVid = async (payload: {filename:string; filepath:string; start: number, end:number;})=>{
35 | try{
36 | const response = await axios({
37 | method: 'post',
38 | url: `${process.env.REACT_APP_BASE_URL}/trim`,
39 | data: payload,
40 | responseType: 'blob'
41 | })
42 |
43 | return response
44 | }
45 | catch(err) {
46 | console.log(err)
47 | throw err
48 | }
49 | }
--------------------------------------------------------------------------------
/src/setupTests.ts:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import '@testing-library/jest-dom';
6 |
--------------------------------------------------------------------------------
/src/styles/_mixins.scss:
--------------------------------------------------------------------------------
1 | @mixin play_tiles() {
2 | .title {
3 | font-family: Cerebri Sans;
4 | font-size: 14px;
5 | line-height: 18px;
6 | font-weight: 600;
7 | color: #ffffff;
8 | }
9 |
10 | .info {
11 | font-family: Cerebri Sans Book;
12 | font-size: 14px;
13 | line-height: 18px;
14 | font-weight: 600;
15 | color: #bababa;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/styles/_variables.scss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elijahthis/veditor/9149005af6ebb093e9de1724a9fecba74c44f9be/src/styles/_variables.scss
--------------------------------------------------------------------------------
/src/styles/main.scss:
--------------------------------------------------------------------------------
1 | .main {
2 | min-height: 100vh;
3 | display: grid;
4 | grid-template-rows: 63px 1fr;
5 | background: #171616 0% 0% no-repeat padding-box;
6 | }
7 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "downlevelIteration": true,
5 | "lib": [
6 | "dom",
7 | "dom.iterable",
8 | "esnext"
9 | ],
10 | "allowJs": true,
11 | "skipLibCheck": true,
12 | "esModuleInterop": true,
13 | "allowSyntheticDefaultImports": true,
14 | "strict": true,
15 | "forceConsistentCasingInFileNames": true,
16 | "noFallthroughCasesInSwitch": true,
17 | "module": "esnext",
18 | "moduleResolution": "node",
19 | "resolveJsonModule": true,
20 | "isolatedModules": true,
21 | "noEmit": true,
22 | "jsx": "react-jsx"
23 | },
24 | "include": [
25 | "src"
26 | ]
27 | }
28 |
--------------------------------------------------------------------------------
/webpack.server.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 | const nodeExternals = require("webpack-node-externals");
3 |
4 | module.exports = {
5 | entry: "./server/index.js",
6 | target: "node",
7 | externals: [nodeExternals()],
8 | output: {
9 | path: path.resolve("server-build"),
10 | filename: "index.js",
11 | },
12 | module: {
13 | rules: [
14 | {
15 | test: /\.js$/,
16 | use: "babel-loader",
17 | },
18 | ],
19 | },
20 | };
21 |
--------------------------------------------------------------------------------