Use svelte instead
This commit is contained in:
parent
a53f5a2ad2
commit
3f453bc3b5
10 changed files with 769 additions and 1774 deletions
1
.gitignore → backend/.gitignore
vendored
1
.gitignore → backend/.gitignore
vendored
|
@ -1,3 +1,2 @@
|
||||||
.env
|
.env
|
||||||
.venv/
|
|
||||||
__pycache__/
|
__pycache__/
|
1
frontend/.gitignore
vendored
1
frontend/.gitignore
vendored
|
@ -1,2 +1 @@
|
||||||
node_modules/
|
node_modules/
|
||||||
dist/
|
|
||||||
|
|
|
@ -4,23 +4,18 @@
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Document</title>
|
<title>Document</title>
|
||||||
<link rel="stylesheet" href="styles.css" />
|
|
||||||
|
<style>
|
||||||
|
@import "tailwindcss";
|
||||||
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="app"></div>
|
||||||
<script type="module">
|
<script type="module">
|
||||||
import React from "react";
|
import { mount } from "svelte";
|
||||||
import { createRoot } from "react-dom/client";
|
import App from "./src/App.svelte";
|
||||||
|
|
||||||
import App from "./src/app.jsx";
|
mount(App, { target: document.getElementById("app") });
|
||||||
|
|
||||||
createRoot(document.getElementById("root")).render(
|
|
||||||
React.createElement(
|
|
||||||
React.StrictMode,
|
|
||||||
null,
|
|
||||||
React.createElement(App, null),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
2333
frontend/package-lock.json
generated
2333
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -1,29 +1,22 @@
|
||||||
{
|
{
|
||||||
|
"name": "svelte-hello",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"react": "^18.3.1",
|
"@sveltejs/vite-plugin-svelte": "^5.0.3",
|
||||||
"react-dom": "^18.3.1",
|
"@tailwindcss/vite": "^4.1.3",
|
||||||
"react-youtube": "^10.1.0"
|
"prettier": "^3.5.3",
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"autoprefixer": "^10.4.19",
|
|
||||||
"postcss": "^8.4.38",
|
|
||||||
"prettier": "^3.3.2",
|
|
||||||
"prettier-plugin-css-order": "^2.1.2",
|
"prettier-plugin-css-order": "^2.1.2",
|
||||||
"prettier-plugin-tailwindcss": "^0.6.5",
|
"prettier-plugin-svelte": "^3.3.3",
|
||||||
"tailwindcss": "^3.4.4",
|
"prettier-plugin-tailwindcss": "^0.6.11",
|
||||||
|
"svelte": "^5.25.9",
|
||||||
|
"tailwindcss": "^4.1.3",
|
||||||
"vite": "^6.2.5"
|
"vite": "^6.2.5"
|
||||||
},
|
},
|
||||||
"prettier": {
|
"prettier": {
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"prettier-plugin-css-order",
|
"prettier-plugin-css-order",
|
||||||
|
"prettier-plugin-svelte",
|
||||||
"prettier-plugin-tailwindcss"
|
"prettier-plugin-tailwindcss"
|
||||||
]
|
]
|
||||||
},
|
|
||||||
"postcss": {
|
|
||||||
"plugins": {
|
|
||||||
"tailwindcss": {},
|
|
||||||
"autoprefixer": {}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
65
frontend/src/App.svelte
Normal file
65
frontend/src/App.svelte
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
<script>
|
||||||
|
let channelName = "";
|
||||||
|
let videoId = "";
|
||||||
|
let loading = false;
|
||||||
|
let error = "";
|
||||||
|
|
||||||
|
async function fetchVideo() {
|
||||||
|
if (!channelName) return;
|
||||||
|
loading = true;
|
||||||
|
error = "";
|
||||||
|
videoId = "";
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await fetch(`http://localhost:8000/video?channel_name=${channelName}`);
|
||||||
|
if (!res.ok) throw new Error("Channel not found or API error");
|
||||||
|
const data = await res.json();
|
||||||
|
videoId = data.id;
|
||||||
|
} catch (err) {
|
||||||
|
error = err.message;
|
||||||
|
} finally {
|
||||||
|
loading = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleSubmit(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
fetchVideo();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<main class="min-h-screen bg-gray-100 flex flex-col items-center justify-center p-6">
|
||||||
|
<h1 class="text-4xl font-extrabold mb-6">YouTube Latest Video Finder</h1>
|
||||||
|
|
||||||
|
<form on:submit={handleSubmit} class="flex flex-col sm:flex-row items-center gap-4">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
bind:value={channelName}
|
||||||
|
placeholder="Enter channel name"
|
||||||
|
class="px-4 py-2 border border-gray-300 rounded-md w-72"
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
disabled={loading}
|
||||||
|
class="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 disabled:opacity-50"
|
||||||
|
>
|
||||||
|
{loading ? "Loading..." : "Get Latest Video"}
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{#if error}
|
||||||
|
<p class="text-red-600 mt-4 text-sm">{error}</p>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if videoId}
|
||||||
|
<div class="mt-8 w-full flex justify-center">
|
||||||
|
<iframe
|
||||||
|
title="video"
|
||||||
|
width="560"
|
||||||
|
height="315"
|
||||||
|
src={`https://www.youtube.com/embed/${videoId}?rel=0`}
|
||||||
|
class="rounded-lg shadow-lg"
|
||||||
|
></iframe>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</main>
|
|
@ -1,76 +0,0 @@
|
||||||
import { useState } from "react";
|
|
||||||
import YouTube from "react-youtube";
|
|
||||||
|
|
||||||
export default function App() {
|
|
||||||
const [channelName, setChannelName] = useState("");
|
|
||||||
const [videoId, setVideoId] = useState(null);
|
|
||||||
const [loading, setLoading] = useState(false);
|
|
||||||
const [error, setError] = useState("");
|
|
||||||
|
|
||||||
async function fetchLatestVideo() {
|
|
||||||
if (!channelName) return;
|
|
||||||
setLoading(true);
|
|
||||||
setError("");
|
|
||||||
setVideoId(null);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const res = await fetch(
|
|
||||||
`http://localhost:8000/video?channel_name=${channelName}`,
|
|
||||||
);
|
|
||||||
if (!res.ok) throw new Error("Channel not found or API error");
|
|
||||||
const data = await res.json();
|
|
||||||
setVideoId(data.id);
|
|
||||||
} catch (err) {
|
|
||||||
setError(err.message);
|
|
||||||
} finally {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const playerOptions = {
|
|
||||||
playerVars: {
|
|
||||||
autoplay: 0,
|
|
||||||
rel: 0,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="flex min-h-screen flex-col items-center justify-center bg-gray-100 p-6">
|
|
||||||
<h1 className="mb-6 text-4xl font-extrabold">
|
|
||||||
YouTube Latest Video Finder
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
<form
|
|
||||||
onSubmit={(e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
fetchLatestVideo();
|
|
||||||
}}
|
|
||||||
className="flex flex-col items-center gap-4 sm:flex-row"
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
value={channelName}
|
|
||||||
onChange={(e) => setChannelName(e.target.value)}
|
|
||||||
placeholder="Enter channel name"
|
|
||||||
className="w-72 rounded-md border border-gray-300 px-4 py-2"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<button
|
|
||||||
type="submit"
|
|
||||||
disabled={loading}
|
|
||||||
className="rounded-md bg-blue-600 px-4 py-2 text-white hover:bg-blue-700 disabled:opacity-50"
|
|
||||||
>
|
|
||||||
{loading ? "Loading..." : "Get Latest Video"}
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
{error && <p className="mt-4 text-sm text-red-600">{error}</p>}
|
|
||||||
|
|
||||||
{videoId && (
|
|
||||||
<div className="mt-8 flex w-full justify-center">
|
|
||||||
<YouTube videoId={videoId} opts={playerOptions} />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -1,3 +0,0 @@
|
||||||
@tailwind base;
|
|
||||||
@tailwind components;
|
|
||||||
@tailwind utilities;
|
|
|
@ -1,8 +0,0 @@
|
||||||
/** @type {import('tailwindcss').Config} */
|
|
||||||
export default {
|
|
||||||
content: ["./index.html", "./src/**/*.jsx"],
|
|
||||||
theme: {
|
|
||||||
extend: {},
|
|
||||||
},
|
|
||||||
plugins: [],
|
|
||||||
};
|
|
|
@ -1,7 +1,11 @@
|
||||||
|
import tailwindcss from "@tailwindcss/vite"
|
||||||
import { defineConfig } from "vite";
|
import { defineConfig } from "vite";
|
||||||
|
import { svelte } from "@sveltejs/vite-plugin-svelte";
|
||||||
|
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
esbuild: {
|
plugins: [
|
||||||
jsxInject: `import React from 'react'`,
|
svelte(),
|
||||||
},
|
tailwindcss()
|
||||||
|
],
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Reference in a new issue