Skip to content

Commit 2252fd4

Browse files
committed
allowing uploading youtube video URLs
1 parent bffa407 commit 2252fd4

File tree

13 files changed

+227
-44
lines changed

13 files changed

+227
-44
lines changed

app/.eslintrc.json

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,17 @@
1717
"@typescript-eslint/semi": ["error", "always"],
1818
"@typescript-eslint/no-misused-promises": "off",
1919
"@typescript-eslint/space-before-function-paren": "off",
20-
"@typescript-eslint/comma-dangle": ["error", "always-multiline"]
20+
"@typescript-eslint/comma-dangle": ["error", "always-multiline"],
21+
"@typescript-eslint/member-delimiter-style": ["error", {
22+
"multiline": {
23+
"delimiter": "semi",
24+
"requireLast": true
25+
},
26+
"singleline": {
27+
"delimiter": "semi",
28+
"requireLast": false
29+
},
30+
"multilineDetection": "brackets"
31+
}]
2132
}
2233
}

app/src/app/globals.css

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@
1010

1111
body {
1212
color: rgb(var(--foreground-rgb));
13-
background: linear-gradient(to bottom,
13+
background: linear-gradient(
14+
to bottom,
1415
transparent,
15-
rgb(var(--background-end-rgb))) rgb(var(--background-start-rgb));
16-
}
16+
rgb(var(--background-end-rgb))
17+
)
18+
rgb(var(--background-start-rgb));
19+
}

app/src/app/layout.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export const metadata: Metadata = {
1212
export default function RootLayout({
1313
children,
1414
}: {
15-
children: React.ReactNode
15+
children: React.ReactNode;
1616
}) {
1717
return (
1818
<html lang="en">

app/src/app/page.tsx

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,24 @@
33
import { useState } from 'react';
44
import QuestionForm from '@/components/QuestionForm';
55
import VideoList, { type VideoDocument } from '@/components/VideoList';
6+
import Modal from '@/components/Modal';
7+
import UploadButton from '@/components/UploadButton';
8+
import VideoForm from '@/components/VideoForm';
69

710
export default function Home() {
811
const [videos, setVideos] = useState<VideoDocument[]>([]);
12+
const [showModal, setShowModal] = useState(false);
13+
14+
const handleSubmit = async (videos: string[]) => {
15+
// API call with the videos URLs
16+
17+
await fetch(`/api/upload`, {
18+
method: 'POST',
19+
body: JSON.stringify({ videos }),
20+
});
21+
22+
setShowModal(false);
23+
};
924

1025
const handleSearch = async (question: string) => {
1126
// Replace with your API call
@@ -15,14 +30,29 @@ export default function Home() {
1530
};
1631

1732
return (
18-
<main className="flex min-h-screen flex-col items-center justify-between p-24">
19-
<div className="container mx-auto p-4">
20-
<h1 className="text-3xl md:text-4xl font-bold text-center text-indigo-600 my-8">
21-
Search for videos... semantically!
22-
</h1>
23-
<QuestionForm onSubmit={handleSearch} />
24-
<VideoList videos={videos} />
25-
</div>
26-
</main>
33+
<>
34+
<main className="flex min-h-screen flex-col items-center justify-between p-24">
35+
<div className="container mx-auto p-4">
36+
<h1 className="text-3xl md:text-4xl font-bold text-center text-indigo-600 my-8">
37+
Search for videos... semantically!
38+
</h1>
39+
<QuestionForm onSubmit={handleSearch} />
40+
<VideoList videos={videos} />
41+
</div>
42+
</main>
43+
44+
<Modal
45+
show={showModal}
46+
onClose={() => {
47+
setShowModal(false);
48+
}}>
49+
<VideoForm onSubmit={handleSubmit} />
50+
</Modal>
51+
<UploadButton
52+
onClick={() => {
53+
setShowModal(true);
54+
}}
55+
/>
56+
</>
2757
);
2858
}

app/src/components/Modal.tsx

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
export interface ModalProps {
2+
show: boolean;
3+
onClose: () => void;
4+
children: React.ReactNode;
5+
}
6+
7+
function Modal({ show, onClose, children }: ModalProps) {
8+
if (!show) {
9+
return null;
10+
}
11+
12+
return (
13+
<div
14+
className="fixed inset-0 bg-black bg-opacity-50 overflow-y-auto h-full w-full"
15+
onClick={onClose}>
16+
<div
17+
className="relative top-20 mx-auto p-5 border w-full md:w-3/4 lg:w-1/2 xl:w-1/4 shadow-lg rounded-md bg-white"
18+
onClick={(e) => {
19+
e.stopPropagation();
20+
}}>
21+
{children}
22+
</div>
23+
</div>
24+
);
25+
}
26+
27+
export default Modal;

app/src/components/QuestionForm.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { Formik, Form, Field } from 'formik';
22
import CircularProgress from './CircularProgress';
33

44
interface QuestionFormProps {
5-
onSubmit: (question: string) => Promise<void> | void
5+
onSubmit: (question: string) => Promise<void> | void;
66
}
77

88
export default function QuestionForm({ onSubmit }: QuestionFormProps) {
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
export interface UploadButtonProps {
2+
onClick: () => void;
3+
}
4+
5+
function UploadButton({ onClick }: UploadButtonProps) {
6+
return (
7+
<button
8+
onClick={onClick}
9+
className="fixed bottom-4 right-4 bg-indigo-600 hover:bg-indigo-700 text-white p-4 rounded-full shadow-lg">
10+
<svg
11+
className="w-6 h-6"
12+
fill="none"
13+
stroke="currentColor"
14+
viewBox="0 0 24 24"
15+
xmlns="http://www.w3.org/2000/svg">
16+
<path
17+
strokeLinecap="round"
18+
strokeLinejoin="round"
19+
strokeWidth="2"
20+
d="M4 17v2a2 2 0 0 1 2 2h2m8 0h2a2 2 0 0 1 2-2v-2m-4-5l-4-4m0 0l-4 4m4-4v12"></path>
21+
</svg>
22+
</button>
23+
);
24+
}
25+
26+
export default UploadButton;

app/src/components/VideoForm.tsx

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { Formik, Form, Field, FieldArray } from 'formik';
2+
3+
export interface VideoFormProps {
4+
onSubmit: (videos: string[]) => Promise<void> | void;
5+
}
6+
7+
function VideoForm({ onSubmit }: VideoFormProps) {
8+
return (
9+
<Formik
10+
initialValues={{ videos: [''] }}
11+
onSubmit={(values) => {
12+
void onSubmit(values.videos);
13+
}}>
14+
{({ values }) => (
15+
<Form className="space-y-4">
16+
<FieldArray name="videos">
17+
{({ insert, remove }) => (
18+
<div>
19+
{values.videos.map((video, index) => (
20+
<div
21+
key={index}
22+
className="flex flex-wrap items-center gap-2">
23+
<Field
24+
name={`videos.${index}`}
25+
placeholder="Enter YouTube URL"
26+
className="flex-1 px-3 py-2 border rounded shadow-sm focus:outline-none focus:ring-2 focus:ring-indigo-600"
27+
/>
28+
<button
29+
type="button"
30+
onClick={() => remove(index)}
31+
className="px-3 py-1 bg-red-500 text-white rounded hover:bg-red-600 focus:outline-none">
32+
Remove
33+
</button>
34+
<button
35+
type="button"
36+
onClick={() => {
37+
insert(index, '');
38+
}}
39+
className="px-3 py-1 bg-green-500 text-white rounded hover:bg-green-600 focus:outline-none">
40+
Add
41+
</button>
42+
</div>
43+
))}
44+
</div>
45+
)}
46+
</FieldArray>
47+
<div className="flex justify-center">
48+
<button
49+
type="submit"
50+
className="py-2 px-4 bg-indigo-600 text-white rounded hover:bg-indigo-700 focus:outline-none">
51+
Submit
52+
</button>
53+
</div>
54+
</Form>
55+
)}
56+
</Formik>
57+
);
58+
}
59+
60+
export default VideoForm;

app/src/components/VideoList.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import Image from 'next/image';
22

33
export interface VideoDocument {
4-
pageContent: string
4+
pageContent: string;
55
metadata: {
6-
id: string
7-
link: string
8-
title: string
9-
description: string
10-
thumbnail: string
11-
}
6+
id: string;
7+
link: string;
8+
title: string;
9+
description: string;
10+
thumbnail: string;
11+
};
1212
}
1313

1414
const VideoList = ({ videos }: { videos: VideoDocument[] }) => {

services/video-search/.eslintrc.json

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,17 @@
1717
"@typescript-eslint/semi": ["error", "always"],
1818
"@typescript-eslint/no-misused-promises": "off",
1919
"@typescript-eslint/space-before-function-paren": "off",
20-
"@typescript-eslint/comma-dangle": ["error", "always-multiline"]
20+
"@typescript-eslint/comma-dangle": ["error", "always-multiline"],
21+
"@typescript-eslint/member-delimiter-style": ["error", {
22+
"multiline": {
23+
"delimiter": "semi",
24+
"requireLast": true
25+
},
26+
"singleline": {
27+
"delimiter": "semi",
28+
"requireLast": false
29+
},
30+
"multilineDetection": "brackets"
31+
}]
2132
}
2233
}

0 commit comments

Comments
 (0)