Spaces:
Running
Running
Upload 7 files
Browse files- README.md +64 -13
- index.html +354 -0
- prompts.txt +2 -0
- story_player_code.txt +237 -0
- style.css +28 -0
- upload.html +217 -0
- videos.js +165 -0
README.md
CHANGED
|
@@ -1,19 +1,70 @@
|
|
| 1 |
---
|
| 2 |
-
title:
|
| 3 |
-
emoji:
|
| 4 |
-
colorFrom:
|
| 5 |
-
colorTo:
|
| 6 |
-
sdk:
|
| 7 |
-
app_port: 8501
|
| 8 |
-
tags:
|
| 9 |
-
- streamlit
|
| 10 |
pinned: false
|
| 11 |
-
|
|
|
|
| 12 |
---
|
| 13 |
|
| 14 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
|
| 16 |
-
|
| 17 |
|
| 18 |
-
|
| 19 |
-
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
+
title: new3
|
| 3 |
+
emoji: 🐳
|
| 4 |
+
colorFrom: green
|
| 5 |
+
colorTo: gray
|
| 6 |
+
sdk: static
|
|
|
|
|
|
|
|
|
|
| 7 |
pinned: false
|
| 8 |
+
tags:
|
| 9 |
+
- deepsite
|
| 10 |
---
|
| 11 |
|
| 12 |
+
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
| 13 |
+
|
| 14 |
+
# Kho truyện Mã A Lềnh - Video Story Player
|
| 15 |
+
|
| 16 |
+
A beautiful story player system for displaying and playing Vietnamese folk stories with video support.
|
| 17 |
+
|
| 18 |
+
## Features
|
| 19 |
+
|
| 20 |
+
- Responsive design that works on desktop and mobile devices
|
| 21 |
+
- Beautiful card-based interface for browsing stories
|
| 22 |
+
- Video playback support with modal player
|
| 23 |
+
- Favorites system that persists between sessions (using localStorage)
|
| 24 |
+
- Filtering by story type
|
| 25 |
+
|
| 26 |
+
## Setup Instructions
|
| 27 |
+
|
| 28 |
+
### 1. Place your video files
|
| 29 |
+
|
| 30 |
+
Add your video files to the `videos` directory. The system is configured to use the following files:
|
| 31 |
+
|
| 32 |
+
- `videos/chuyen-con-suoi-muong-tien.mp4` - Story 1: Chuyện con suối Mường Tiên
|
| 33 |
+
- `videos/chiec-banh-trong-day-tui.mp4` - Story 2: Chiếc bánh trong đẩy túi
|
| 34 |
+
- `videos/vung-dam-cua-than-rong.mp4` - Story 3: Vũng đầm của thần rồng
|
| 35 |
+
|
| 36 |
+
### 2. Customize (Optional)
|
| 37 |
+
|
| 38 |
+
If you want to use different video files or paths:
|
| 39 |
+
|
| 40 |
+
1. Open `videos.js`
|
| 41 |
+
2. Modify the `videoSources` object to point to your video files
|
| 42 |
+
|
| 43 |
+
```javascript
|
| 44 |
+
const videoSources = {
|
| 45 |
+
1: "your/custom/path/to/video1.mp4",
|
| 46 |
+
2: "your/custom/path/to/video2.mp4",
|
| 47 |
+
3: "your/custom/path/to/video3.mp4",
|
| 48 |
+
};
|
| 49 |
+
```
|
| 50 |
+
|
| 51 |
+
### 3. Launch the website
|
| 52 |
+
|
| 53 |
+
Open `index.html` in your web browser or deploy it to your web server.
|
| 54 |
+
|
| 55 |
+
## Adding More Stories
|
| 56 |
+
|
| 57 |
+
To add additional stories:
|
| 58 |
+
|
| 59 |
+
1. Duplicate one of the existing story card sections in `index.html`
|
| 60 |
+
2. Update the content (image, title, description, duration)
|
| 61 |
+
3. Update the `data-story` attribute to a new unique number
|
| 62 |
+
4. Add the corresponding video source in `videos.js`
|
| 63 |
|
| 64 |
+
## Technologies Used
|
| 65 |
|
| 66 |
+
- HTML5
|
| 67 |
+
- CSS3 (with Tailwind CSS)
|
| 68 |
+
- JavaScript
|
| 69 |
+
- Font Awesome for icons
|
| 70 |
+
- Google Fonts
|
index.html
ADDED
|
@@ -0,0 +1,354 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="vi">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8" />
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
| 6 |
+
<title>Kho truyện Mã A Lềnh</title>
|
| 7 |
+
<script src="https://cdn.tailwindcss.com"></script>
|
| 8 |
+
<link
|
| 9 |
+
rel="stylesheet"
|
| 10 |
+
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"
|
| 11 |
+
/>
|
| 12 |
+
<link
|
| 13 |
+
href="https://fonts.googleapis.com/css2?family=Noto+Serif:wght@400;700&display=swap"
|
| 14 |
+
rel="stylesheet"
|
| 15 |
+
/>
|
| 16 |
+
<link rel="stylesheet" href="style.css" />
|
| 17 |
+
<style>
|
| 18 |
+
body {
|
| 19 |
+
font-family: "Noto Serif", serif;
|
| 20 |
+
background-color: #fffbeb;
|
| 21 |
+
}
|
| 22 |
+
.story-card {
|
| 23 |
+
transition: all 0.3s ease;
|
| 24 |
+
transform: translateY(0);
|
| 25 |
+
}
|
| 26 |
+
.story-card:hover {
|
| 27 |
+
transform: translateY(-5px);
|
| 28 |
+
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1);
|
| 29 |
+
}
|
| 30 |
+
.story-card:hover .play-overlay {
|
| 31 |
+
opacity: 1;
|
| 32 |
+
}
|
| 33 |
+
.play-overlay {
|
| 34 |
+
transition: opacity 0.3s ease;
|
| 35 |
+
}
|
| 36 |
+
.fade-in {
|
| 37 |
+
animation: fadeIn 0.5s ease-in-out;
|
| 38 |
+
}
|
| 39 |
+
@keyframes fadeIn {
|
| 40 |
+
from {
|
| 41 |
+
opacity: 0;
|
| 42 |
+
transform: translateY(10px);
|
| 43 |
+
}
|
| 44 |
+
to {
|
| 45 |
+
opacity: 1;
|
| 46 |
+
transform: translateY(0);
|
| 47 |
+
}
|
| 48 |
+
}
|
| 49 |
+
.progress-bar {
|
| 50 |
+
height: 6px;
|
| 51 |
+
background-color: #ede9e3;
|
| 52 |
+
border-radius: 3px;
|
| 53 |
+
}
|
| 54 |
+
.progress-fill {
|
| 55 |
+
height: 100%;
|
| 56 |
+
background: linear-gradient(90deg, #d4a373 0%, #a18072 100%);
|
| 57 |
+
border-radius: 3px;
|
| 58 |
+
transition: width 0.1s linear;
|
| 59 |
+
}
|
| 60 |
+
.story-tag {
|
| 61 |
+
position: absolute;
|
| 62 |
+
top: 12px;
|
| 63 |
+
left: 12px;
|
| 64 |
+
color: white;
|
| 65 |
+
padding: 4px 8px;
|
| 66 |
+
border-radius: 4px;
|
| 67 |
+
font-size: 12px;
|
| 68 |
+
font-weight: bold;
|
| 69 |
+
}
|
| 70 |
+
.tag-children {
|
| 71 |
+
background-color: rgba(74, 222, 128, 0.9);
|
| 72 |
+
}
|
| 73 |
+
.tag-journal {
|
| 74 |
+
background-color: rgba(59, 130, 246, 0.9);
|
| 75 |
+
}
|
| 76 |
+
.video-container {
|
| 77 |
+
position: relative;
|
| 78 |
+
width: 100%;
|
| 79 |
+
height: 0;
|
| 80 |
+
padding-bottom: 56.25%; /* 16:9 aspect ratio */
|
| 81 |
+
}
|
| 82 |
+
.video-player {
|
| 83 |
+
position: absolute;
|
| 84 |
+
top: 0;
|
| 85 |
+
left: 0;
|
| 86 |
+
width: 100%;
|
| 87 |
+
height: 100%;
|
| 88 |
+
background-color: #000;
|
| 89 |
+
}
|
| 90 |
+
.video-controls {
|
| 91 |
+
position: absolute;
|
| 92 |
+
bottom: 0;
|
| 93 |
+
left: 0;
|
| 94 |
+
right: 0;
|
| 95 |
+
background: linear-gradient(to top, rgba(0, 0, 0, 0.7), transparent);
|
| 96 |
+
padding: 10px;
|
| 97 |
+
display: flex;
|
| 98 |
+
flex-direction: column;
|
| 99 |
+
opacity: 0;
|
| 100 |
+
transition: opacity 0.3s;
|
| 101 |
+
}
|
| 102 |
+
.video-container:hover .video-controls {
|
| 103 |
+
opacity: 1;
|
| 104 |
+
}
|
| 105 |
+
.category-dropdown {
|
| 106 |
+
position: relative;
|
| 107 |
+
display: inline-block;
|
| 108 |
+
}
|
| 109 |
+
.dropdown-content {
|
| 110 |
+
display: none;
|
| 111 |
+
position: absolute;
|
| 112 |
+
background-color: #fff;
|
| 113 |
+
min-width: 200px;
|
| 114 |
+
box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.1);
|
| 115 |
+
z-index: 1;
|
| 116 |
+
border-radius: 0.5rem;
|
| 117 |
+
overflow: hidden;
|
| 118 |
+
}
|
| 119 |
+
.category-dropdown:hover .dropdown-content {
|
| 120 |
+
display: block;
|
| 121 |
+
}
|
| 122 |
+
.dropdown-content a {
|
| 123 |
+
color: #713f12;
|
| 124 |
+
padding: 12px 16px;
|
| 125 |
+
text-decoration: none;
|
| 126 |
+
display: block;
|
| 127 |
+
transition: background 0.3s;
|
| 128 |
+
}
|
| 129 |
+
.dropdown-content a:hover {
|
| 130 |
+
background-color: #f8f1e1;
|
| 131 |
+
}
|
| 132 |
+
</style>
|
| 133 |
+
</head>
|
| 134 |
+
<body class="bg-amber-50">
|
| 135 |
+
<div class="container mx-auto px-4 py-8 max-w-7xl">
|
| 136 |
+
<!-- Header -->
|
| 137 |
+
<header class="flex justify-between items-center mb-8">
|
| 138 |
+
<div class="flex items-center">
|
| 139 |
+
<div class="bg-amber-700 text-white p-3 rounded-lg mr-4">
|
| 140 |
+
<i class="fas fa-book-open text-2xl"></i>
|
| 141 |
+
</div>
|
| 142 |
+
<h1 class="text-4xl font-bold text-amber-900">
|
| 143 |
+
Kho truyện Mã A Lềnh
|
| 144 |
+
</h1>
|
| 145 |
+
</div>
|
| 146 |
+
<div class="flex space-x-4">
|
| 147 |
+
<button
|
| 148 |
+
id="all-stories-btn"
|
| 149 |
+
class="px-6 py-2 bg-amber-700 text-white rounded-xl hover:bg-amber-800 transition-all duration-300 flex items-center"
|
| 150 |
+
>
|
| 151 |
+
<i class="fas fa-book mr-2"></i>
|
| 152 |
+
<span>Tất cả truyện</span>
|
| 153 |
+
</button>
|
| 154 |
+
<button
|
| 155 |
+
id="favorites-btn"
|
| 156 |
+
class="px-6 py-2 border border-amber-700 text-amber-700 rounded-xl hover:bg-amber-100 transition-all duration-300 flex items-center"
|
| 157 |
+
>
|
| 158 |
+
<i class="fas fa-heart mr-2"></i>
|
| 159 |
+
<span>Yêu thích</span>
|
| 160 |
+
</button>
|
| 161 |
+
</div>
|
| 162 |
+
</header>
|
| 163 |
+
|
| 164 |
+
<!-- Category Filter -->
|
| 165 |
+
<div class="mb-8">
|
| 166 |
+
<div class="category-dropdown">
|
| 167 |
+
<button
|
| 168 |
+
class="px-6 py-2 bg-amber-100 text-amber-900 rounded-full border border-amber-300 flex items-center"
|
| 169 |
+
>
|
| 170 |
+
<span>Tất cả thể loại</span>
|
| 171 |
+
<i class="fas fa-chevron-down ml-2"></i>
|
| 172 |
+
</button>
|
| 173 |
+
<div class="dropdown-content">
|
| 174 |
+
<a href="#" class="active">Tất cả thể loại</a>
|
| 175 |
+
<a href="#">Văn học thiếu nhi</a>
|
| 176 |
+
<a href="#">Ký sự</a>
|
| 177 |
+
</div>
|
| 178 |
+
</div>
|
| 179 |
+
</div>
|
| 180 |
+
|
| 181 |
+
<!-- Main Content -->
|
| 182 |
+
<main>
|
| 183 |
+
<!-- Stories Section -->
|
| 184 |
+
<section id="all-stories" class="fade-in">
|
| 185 |
+
<div
|
| 186 |
+
class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-8 justify-items-center"
|
| 187 |
+
>
|
| 188 |
+
<!-- Story Card 1 -->
|
| 189 |
+
<div
|
| 190 |
+
class="story-card bg-white rounded-xl shadow-lg overflow-hidden relative w-full max-w-sm"
|
| 191 |
+
>
|
| 192 |
+
<div class="relative">
|
| 193 |
+
<img
|
| 194 |
+
src="https://i.imgur.com/nsjKQ2G.jpeg"
|
| 195 |
+
alt="Chuyện con suối Mường Tiên"
|
| 196 |
+
class="w-full h-64 object-cover"
|
| 197 |
+
/>
|
| 198 |
+
<div class="story-tag tag-children">Văn học thiếu nhi</div>
|
| 199 |
+
<div
|
| 200 |
+
class="play-overlay absolute inset-0 bg-black bg-opacity-40 flex items-center justify-center opacity-0 transition-opacity"
|
| 201 |
+
>
|
| 202 |
+
<button class="play-btn" data-story="1">
|
| 203 |
+
<div
|
| 204 |
+
class="bg-white bg-opacity-30 rounded-full p-4 hover:bg-opacity-50 transition"
|
| 205 |
+
>
|
| 206 |
+
<i class="fas fa-play text-white text-3xl"></i>
|
| 207 |
+
</div>
|
| 208 |
+
</button>
|
| 209 |
+
</div>
|
| 210 |
+
</div>
|
| 211 |
+
<div class="p-6">
|
| 212 |
+
<h3 class="text-xl font-bold mb-3 text-amber-900 text-center">
|
| 213 |
+
Chuyện con suối Mường Tiên
|
| 214 |
+
</h3>
|
| 215 |
+
<p class="text-amber-800 mb-4 text-sm text-center">
|
| 216 |
+
Câu chuyện về Chà, cậu bé lớn lên bên suối Mường Tiên. Khi
|
| 217 |
+
suối bị chặn lại để xây thủy điện, Chà quyết tâm học giỏi để
|
| 218 |
+
cứu suối, phản ánh sự gắn bó giữa con người và thiên nhiên.
|
| 219 |
+
</p>
|
| 220 |
+
<div class="flex justify-between items-center">
|
| 221 |
+
<div class="flex items-center text-sm text-amber-700">
|
| 222 |
+
<i class="fas fa-clock mr-2"></i>
|
| 223 |
+
<span>1:18 phút</span>
|
| 224 |
+
</div>
|
| 225 |
+
<button class="favorite-btn" data-story="1">
|
| 226 |
+
<i
|
| 227 |
+
class="far fa-heart text-xl text-amber-600 hover:text-red-500 transition"
|
| 228 |
+
></i>
|
| 229 |
+
</button>
|
| 230 |
+
</div>
|
| 231 |
+
</div>
|
| 232 |
+
</div>
|
| 233 |
+
|
| 234 |
+
<!-- Story Card 2 -->
|
| 235 |
+
<div
|
| 236 |
+
class="story-card bg-white rounded-xl shadow-lg overflow-hidden relative w-full max-w-sm"
|
| 237 |
+
>
|
| 238 |
+
<div class="relative">
|
| 239 |
+
<img
|
| 240 |
+
src="videos/card2.jpg"
|
| 241 |
+
alt="Chiếc bánh trong đẩy túi"
|
| 242 |
+
class="w-full h-64 object-cover"
|
| 243 |
+
/>
|
| 244 |
+
<div class="story-tag tag-children">Văn học thiếu nhi</div>
|
| 245 |
+
<div
|
| 246 |
+
class="play-overlay absolute inset-0 bg-black bg-opacity-40 flex items-center justify-center opacity-0 transition-opacity"
|
| 247 |
+
>
|
| 248 |
+
<button class="play-btn" data-story="2">
|
| 249 |
+
<div
|
| 250 |
+
class="bg-white bg-opacity-30 rounded-full p-4 hover:bg-opacity-50 transition"
|
| 251 |
+
>
|
| 252 |
+
<i class="fas fa-play text-white text-3xl"></i>
|
| 253 |
+
</div>
|
| 254 |
+
</button>
|
| 255 |
+
</div>
|
| 256 |
+
</div>
|
| 257 |
+
<div class="p-6">
|
| 258 |
+
<h3 class="text-xl font-bold mb-3 text-amber-900 text-center">
|
| 259 |
+
Chiếc bánh trong đẩy túi
|
| 260 |
+
</h3>
|
| 261 |
+
<p class="text-amber-800 mb-4 text-sm text-center">
|
| 262 |
+
Câu chuyện về Thạch Sơn, cậu bé sống trong vùng núi. Sau khi
|
| 263 |
+
mẹ mất, cậu luôn nhớ mẹ qua những chiếc bánh pa nếp. Mỗi dịp
|
| 264 |
+
Tết, cậu làm bánh cùng mẹ và các bác tiên tổ, giữ lại những ký
|
| 265 |
+
ức về mẹ suốt đời.
|
| 266 |
+
</p>
|
| 267 |
+
<div class="flex justify-between items-center">
|
| 268 |
+
<div class="flex items-center text-sm text-amber-700">
|
| 269 |
+
<i class="fas fa-clock mr-2"></i>
|
| 270 |
+
<span>20 phút</span>
|
| 271 |
+
</div>
|
| 272 |
+
<button class="favorite-btn" data-story="2">
|
| 273 |
+
<i
|
| 274 |
+
class="far fa-heart text-xl text-amber-600 hover:text-red-500 transition"
|
| 275 |
+
></i>
|
| 276 |
+
</button>
|
| 277 |
+
</div>
|
| 278 |
+
</div>
|
| 279 |
+
</div>
|
| 280 |
+
|
| 281 |
+
<!-- Story Card 3 -->
|
| 282 |
+
<div
|
| 283 |
+
class="story-card bg-white rounded-xl shadow-lg overflow-hidden relative w-full max-w-sm"
|
| 284 |
+
>
|
| 285 |
+
<div class="relative">
|
| 286 |
+
<img
|
| 287 |
+
src="videos/card3.jpg"
|
| 288 |
+
alt="Vũng đầm của thần rồng"
|
| 289 |
+
class="w-full h-64 object-cover"
|
| 290 |
+
/>
|
| 291 |
+
<div class="story-tag tag-journal">Ký sự</div>
|
| 292 |
+
<div
|
| 293 |
+
class="play-overlay absolute inset-0 bg-black bg-opacity-40 flex items-center justify-center opacity-0 transition-opacity"
|
| 294 |
+
>
|
| 295 |
+
<button class="play-btn" data-story="3">
|
| 296 |
+
<div
|
| 297 |
+
class="bg-white bg-opacity-30 rounded-full p-4 hover:bg-opacity-50 transition"
|
| 298 |
+
>
|
| 299 |
+
<i class="fas fa-play text-white text-3xl"></i>
|
| 300 |
+
</div>
|
| 301 |
+
</button>
|
| 302 |
+
</div>
|
| 303 |
+
</div>
|
| 304 |
+
<div class="p-6">
|
| 305 |
+
<h3 class="text-xl font-bold mb-3 text-amber-900 text-center">
|
| 306 |
+
Vũng đầm của thần rồng
|
| 307 |
+
</h3>
|
| 308 |
+
<p class="text-amber-800 mb-4 text-sm text-center">
|
| 309 |
+
Chàng Rồng biến thành ngựa rồng, giúp dân có nước. Cô gái mở
|
| 310 |
+
cối yêu anh và họ có mối quan hệ. Khi ông Trời phát hiện,
|
| 311 |
+
chàng Rồng bỏ chạy, làm cạn hồ nước. Cô gái sống cô đơn và chờ
|
| 312 |
+
đợi anh suốt đời.
|
| 313 |
+
</p>
|
| 314 |
+
<div class="flex justify-between items-center">
|
| 315 |
+
<div class="flex items-center text-sm text-amber-700">
|
| 316 |
+
<i class="fas fa-clock mr-2"></i>
|
| 317 |
+
<span>12 phút</span>
|
| 318 |
+
</div>
|
| 319 |
+
<button class="favorite-btn" data-story="3">
|
| 320 |
+
<i
|
| 321 |
+
class="far fa-heart text-xl text-amber-600 hover:text-red-500 transition"
|
| 322 |
+
></i>
|
| 323 |
+
</button>
|
| 324 |
+
</div>
|
| 325 |
+
</div>
|
| 326 |
+
</div>
|
| 327 |
+
</div>
|
| 328 |
+
</section>
|
| 329 |
+
|
| 330 |
+
<!-- Video Player Modal -->
|
| 331 |
+
<div
|
| 332 |
+
id="video-modal"
|
| 333 |
+
class="fixed inset-0 bg-black bg-opacity-75 hidden items-center justify-center z-50"
|
| 334 |
+
>
|
| 335 |
+
<div class="relative w-full max-w-5xl p-4">
|
| 336 |
+
<button
|
| 337 |
+
id="close-modal"
|
| 338 |
+
class="absolute top-0 right-0 -mt-10 -mr-10 text-white hover:text-amber-500 z-10"
|
| 339 |
+
>
|
| 340 |
+
<i class="fas fa-times text-2xl"></i>
|
| 341 |
+
</button>
|
| 342 |
+
<div class="video-container bg-black rounded-lg overflow-hidden">
|
| 343 |
+
<video id="video-player" class="video-player" controls>
|
| 344 |
+
Your browser does not support the video tag.
|
| 345 |
+
</video>
|
| 346 |
+
</div>
|
| 347 |
+
</div>
|
| 348 |
+
</div>
|
| 349 |
+
</main>
|
| 350 |
+
</div>
|
| 351 |
+
|
| 352 |
+
<script src="videos.js"></script>
|
| 353 |
+
</body>
|
| 354 |
+
</html>
|
prompts.txt
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
thêm audio cho câu chuyện bên trong các story card
|
| 2 |
+
tôi muốn thêm adio vào phần bên trong các story card
|
story_player_code.txt
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
<!DOCTYPE html>
|
| 3 |
+
<html lang="vi">
|
| 4 |
+
<head>
|
| 5 |
+
<meta charset="UTF-8">
|
| 6 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 7 |
+
<title>Kho truyện Mã A Lềnh</title>
|
| 8 |
+
<script src="https://cdn.tailwindcss.com"></script>
|
| 9 |
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
| 10 |
+
<link href="https://fonts.googleapis.com/css2?family=Noto+Serif:wght@400;700&display=swap" rel="stylesheet">
|
| 11 |
+
<style>
|
| 12 |
+
body {
|
| 13 |
+
font-family: 'Noto Serif', serif;
|
| 14 |
+
background-color: #FFF9F0;
|
| 15 |
+
}
|
| 16 |
+
.story-card {
|
| 17 |
+
transition: all 0.3s ease;
|
| 18 |
+
transform: translateY(0);
|
| 19 |
+
}
|
| 20 |
+
.story-card:hover {
|
| 21 |
+
transform: translateY(-5px);
|
| 22 |
+
box-shadow: 0 10px 20px rgba(0,0,0,0.1);
|
| 23 |
+
}
|
| 24 |
+
.story-card:hover .play-overlay {
|
| 25 |
+
opacity: 1;
|
| 26 |
+
}
|
| 27 |
+
.play-overlay {
|
| 28 |
+
transition: opacity 0.3s ease;
|
| 29 |
+
}
|
| 30 |
+
.fade-in {
|
| 31 |
+
animation: fadeIn 0.5s ease-in-out;
|
| 32 |
+
}
|
| 33 |
+
@keyframes fadeIn {
|
| 34 |
+
from { opacity: 0; transform: translateY(10px); }
|
| 35 |
+
to { opacity: 1; transform: translateY(0); }
|
| 36 |
+
}
|
| 37 |
+
.progress-bar {
|
| 38 |
+
height: 6px;
|
| 39 |
+
background-color: #EDE9E3;
|
| 40 |
+
border-radius: 3px;
|
| 41 |
+
}
|
| 42 |
+
.progress-fill {
|
| 43 |
+
height: 100%;
|
| 44 |
+
background: linear-gradient(90deg, #D4A373 0%, #A18072 100%);
|
| 45 |
+
border-radius: 3px;
|
| 46 |
+
transition: width 0.1s linear;
|
| 47 |
+
}
|
| 48 |
+
.story-tag {
|
| 49 |
+
position: absolute;
|
| 50 |
+
top: 12px;
|
| 51 |
+
left: 12px;
|
| 52 |
+
color: white;
|
| 53 |
+
padding: 4px 8px;
|
| 54 |
+
border-radius: 4px;
|
| 55 |
+
font-size: 12px;
|
| 56 |
+
font-weight: bold;
|
| 57 |
+
}
|
| 58 |
+
.tag-children {
|
| 59 |
+
background-color: rgba(74, 222, 128, 0.9);
|
| 60 |
+
}
|
| 61 |
+
.tag-journal {
|
| 62 |
+
background-color: rgba(59, 130, 246, 0.9);
|
| 63 |
+
}
|
| 64 |
+
.audio-wave {
|
| 65 |
+
display: flex;
|
| 66 |
+
align-items: center;
|
| 67 |
+
justify-content: space-between;
|
| 68 |
+
width: 60px;
|
| 69 |
+
height: 30px;
|
| 70 |
+
}
|
| 71 |
+
.wave-bar {
|
| 72 |
+
width: 4px;
|
| 73 |
+
background-color: #D4A373;
|
| 74 |
+
border-radius: 2px;
|
| 75 |
+
animation: wave 1.2s infinite ease-in-out;
|
| 76 |
+
}
|
| 77 |
+
.wave-bar:nth-child(1) { height: 8px; animation-delay: 0.1s; }
|
| 78 |
+
.wave-bar:nth-child(2) { height: 12px; animation-delay: 0.3s; }
|
| 79 |
+
.wave-bar:nth-child(3) { height: 16px; animation-delay: 0.5s; }
|
| 80 |
+
.wave-bar:nth-child(4) { height: 12px; animation-delay: 0.7s; }
|
| 81 |
+
.wave-bar:nth-child(5) { height: 8px; animation-delay: 0.9s; }
|
| 82 |
+
@keyframes wave {
|
| 83 |
+
0%, 100% { transform: scaleY(0.8); }
|
| 84 |
+
50% { transform: scaleY(1.5); }
|
| 85 |
+
}
|
| 86 |
+
.bookmark-icon {
|
| 87 |
+
position: absolute;
|
| 88 |
+
top: -10px;
|
| 89 |
+
right: 10px;
|
| 90 |
+
color: #D4A373;
|
| 91 |
+
font-size: 24px;
|
| 92 |
+
filter: drop-shadow(0 2px 4px rgba(0,0,0,0.2));
|
| 93 |
+
}
|
| 94 |
+
.center-container {
|
| 95 |
+
display: flex;
|
| 96 |
+
flex-direction: column;
|
| 97 |
+
align-items: center;
|
| 98 |
+
justify-content: center;
|
| 99 |
+
}
|
| 100 |
+
.video-container {
|
| 101 |
+
position: relative;
|
| 102 |
+
width: 100%;
|
| 103 |
+
height: 0;
|
| 104 |
+
padding-bottom: 56.25%; /* 16:9 aspect ratio */
|
| 105 |
+
}
|
| 106 |
+
.video-player {
|
| 107 |
+
position: absolute;
|
| 108 |
+
top: 0;
|
| 109 |
+
left: 0;
|
| 110 |
+
width: 100%;
|
| 111 |
+
height: 100%;
|
| 112 |
+
background-color: #000;
|
| 113 |
+
}
|
| 114 |
+
.video-controls {
|
| 115 |
+
position: absolute;
|
| 116 |
+
bottom: 0;
|
| 117 |
+
left: 0;
|
| 118 |
+
right: 0;
|
| 119 |
+
background: linear-gradient(to top, rgba(0,0,0,0.7), transparent);
|
| 120 |
+
padding: 10px;
|
| 121 |
+
display: flex;
|
| 122 |
+
flex-direction: column;
|
| 123 |
+
opacity: 0;
|
| 124 |
+
transition: opacity 0.3s;
|
| 125 |
+
}
|
| 126 |
+
.video-container:hover .video-controls {
|
| 127 |
+
opacity: 1;
|
| 128 |
+
}
|
| 129 |
+
.fullscreen-btn {
|
| 130 |
+
position: absolute;
|
| 131 |
+
bottom: 10px;
|
| 132 |
+
right: 10px;
|
| 133 |
+
color: white;
|
| 134 |
+
background: rgba(0,0,0,0.5);
|
| 135 |
+
border-radius: 4px;
|
| 136 |
+
padding: 5px 8px;
|
| 137 |
+
cursor: pointer;
|
| 138 |
+
}
|
| 139 |
+
.story-content {
|
| 140 |
+
max-height: 400px;
|
| 141 |
+
overflow-y: auto;
|
| 142 |
+
padding-right: 10px;
|
| 143 |
+
}
|
| 144 |
+
.story-content::-webkit-scrollbar {
|
| 145 |
+
width: 6px;
|
| 146 |
+
}
|
| 147 |
+
.story-content::-webkit-scrollbar-track {
|
| 148 |
+
background: #f1f1f1;
|
| 149 |
+
border-radius: 10px;
|
| 150 |
+
}
|
| 151 |
+
.story-content::-webkit-scrollbar-thumb {
|
| 152 |
+
background: #D4A373;
|
| 153 |
+
border-radius: 10px;
|
| 154 |
+
}
|
| 155 |
+
.story-content p {
|
| 156 |
+
margin-bottom: 1rem;
|
| 157 |
+
line-height: 1.6;
|
| 158 |
+
}
|
| 159 |
+
</style>
|
| 160 |
+
</head>
|
| 161 |
+
<body class="bg-amber-50">
|
| 162 |
+
<div class="container mx-auto px-4 py-8 max-w-7xl center-container">
|
| 163 |
+
<!-- Header -->
|
| 164 |
+
<header class="flex flex-col md:flex-row justify-between items-center mb-12 w-full">
|
| 165 |
+
<div class="flex items-center mb-4 md:mb-0">
|
| 166 |
+
<div class="bg-amber-700 text-white p-3 rounded-lg mr-4">
|
| 167 |
+
<i class="fas fa-book-open text-2xl"></i>
|
| 168 |
+
</div>
|
| 169 |
+
<h1 class="text-4xl font-bold text-amber-900">Kho truyện Mã A Lềnh</h1>
|
| 170 |
+
</div>
|
| 171 |
+
<div class="flex space-x-2 bg-amber-100 p-2 rounded-full shadow-inner">
|
| 172 |
+
<button id="all-stories-btn" class="px-6 py-2 bg-amber-700 text-white rounded-full hover:bg-amber-800 transition-all duration-300 flex items-center">
|
| 173 |
+
<i class="fas fa-book mr-2"></i>
|
| 174 |
+
<span>Tất cả truyện</span>
|
| 175 |
+
</button>
|
| 176 |
+
<button id="favorites-btn" class="px-6 py-2 rounded-full hover:bg-amber-200 transition-all duration-300 flex items-center">
|
| 177 |
+
<i class="fas fa-heart mr-2 text-amber-700"></i>
|
| 178 |
+
<span>Yêu thích</span>
|
| 179 |
+
</button>
|
| 180 |
+
</div>
|
| 181 |
+
</header>
|
| 182 |
+
|
| 183 |
+
<!-- Main Content -->
|
| 184 |
+
<main class="w-full">
|
| 185 |
+
<!-- All Stories Section -->
|
| 186 |
+
<section id="all-stories" class="fade-in w-full">
|
| 187 |
+
<div class="flex flex-col md:flex-row justify-between items-center mb-8 w-full">
|
| 188 |
+
<div class="relative">
|
| 189 |
+
<select id="story-filter" class="appearance-none bg-amber-100 border border-amber-300 text-amber-900 py-2 px-4 pr-8 rounded-full focus:outline-none focus:ring-2 focus:ring-amber-500">
|
| 190 |
+
<option value="all">Tất cả thể loại</option>
|
| 191 |
+
<option value="children">Văn học thiếu nhi</option>
|
| 192 |
+
<option value="journal">Ký sự</option>
|
| 193 |
+
</select>
|
| 194 |
+
<div class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-amber-700">
|
| 195 |
+
<i class="fas fa-chevron-down"></i>
|
| 196 |
+
</div>
|
| 197 |
+
</div>
|
| 198 |
+
</div>
|
| 199 |
+
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-8 justify-items-center">
|
| 200 |
+
<!-- Story Card 1 -->
|
| 201 |
+
<div class="story-card bg-white rounded-xl shadow-lg overflow-hidden relative w-full max-w-sm">
|
| 202 |
+
<div class="relative">
|
| 203 |
+
<img src="https://i.imgur.com/nsjKQ2G.jpeg" alt="Chuyện con suối Mường Tiên" class="w-full h-64 object-cover">
|
| 204 |
+
<div class="story-tag tag-children">Văn học thiếu nhi</div>
|
| 205 |
+
<div class="play-overlay absolute inset-0 bg-black bg-opacity-40 flex items-center justify-center opacity-0 transition-opacity">
|
| 206 |
+
<button class="play-btn" data-story="1">
|
| 207 |
+
<div class="bg-white bg-opacity-30 rounded-full p-4 hover:bg-opacity-50 transition">
|
| 208 |
+
<i class="fas fa-play text-white text-3xl"></i>
|
| 209 |
+
</div>
|
| 210 |
+
</button>
|
| 211 |
+
</div>
|
| 212 |
+
</div>
|
| 213 |
+
<div class="p-6">
|
| 214 |
+
<h3 class="text-xl font-bold mb-3 text-amber-900 text-center">Chuyện con suối Mường Tiên</h3>
|
| 215 |
+
<p class="text-amber-800 mb-4 text-sm text-center">Câu chuyện về Chà, cậu bé lớn lên bên suối Mường Tiên. Khi suối bị chặn lại để xây thủy điện, Chà quyết tâm học giỏi để cứu suối, phản ánh sự gắn bó giữa con người và thiên nhiên.</p>
|
| 216 |
+
<div class="flex justify-between items-center">
|
| 217 |
+
<div class="flex items-center text-sm text-amber-700">
|
| 218 |
+
<i class="fas fa-clock mr-2"></i>
|
| 219 |
+
<span>1:18 phút</span>
|
| 220 |
+
</div>
|
| 221 |
+
<button class="favorite-btn" data-story="1">
|
| 222 |
+
<i class="far fa-heart text-xl text-amber-600 hover:text-red-500 transition"></i>
|
| 223 |
+
</button>
|
| 224 |
+
</div>
|
| 225 |
+
</div>
|
| 226 |
+
</div>
|
| 227 |
+
<!-- Add other story cards -->
|
| 228 |
+
</div>
|
| 229 |
+
</section>
|
| 230 |
+
</main>
|
| 231 |
+
</div>
|
| 232 |
+
|
| 233 |
+
<script>
|
| 234 |
+
// JavaScript code for handling play/pause functionality and audio/video logic here
|
| 235 |
+
</script>
|
| 236 |
+
</body>
|
| 237 |
+
</html>
|
style.css
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
body {
|
| 2 |
+
padding: 2rem;
|
| 3 |
+
font-family: -apple-system, BlinkMacSystemFont, "Arial", sans-serif;
|
| 4 |
+
}
|
| 5 |
+
|
| 6 |
+
h1 {
|
| 7 |
+
font-size: 16px;
|
| 8 |
+
margin-top: 0;
|
| 9 |
+
}
|
| 10 |
+
|
| 11 |
+
p {
|
| 12 |
+
color: rgb(107, 114, 128);
|
| 13 |
+
font-size: 15px;
|
| 14 |
+
margin-bottom: 10px;
|
| 15 |
+
margin-top: 5px;
|
| 16 |
+
}
|
| 17 |
+
|
| 18 |
+
.card {
|
| 19 |
+
max-width: 620px;
|
| 20 |
+
margin: 0 auto;
|
| 21 |
+
padding: 16px;
|
| 22 |
+
border: 1px solid lightgray;
|
| 23 |
+
border-radius: 16px;
|
| 24 |
+
}
|
| 25 |
+
|
| 26 |
+
.card p:last-child {
|
| 27 |
+
margin-bottom: 0;
|
| 28 |
+
}
|
upload.html
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="vi">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8" />
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
| 6 |
+
<title>Upload Videos - Kho truyện Mã A Lềnh</title>
|
| 7 |
+
<script src="https://cdn.tailwindcss.com"></script>
|
| 8 |
+
<link
|
| 9 |
+
rel="stylesheet"
|
| 10 |
+
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"
|
| 11 |
+
/>
|
| 12 |
+
<link
|
| 13 |
+
href="https://fonts.googleapis.com/css2?family=Noto+Serif:wght@400;700&display=swap"
|
| 14 |
+
rel="stylesheet"
|
| 15 |
+
/>
|
| 16 |
+
<style>
|
| 17 |
+
body {
|
| 18 |
+
font-family: "Noto Serif", serif;
|
| 19 |
+
background-color: #fff9f0;
|
| 20 |
+
}
|
| 21 |
+
</style>
|
| 22 |
+
</head>
|
| 23 |
+
<body class="bg-amber-50">
|
| 24 |
+
<div class="container mx-auto px-4 py-8 max-w-2xl">
|
| 25 |
+
<div class="flex items-center mb-8">
|
| 26 |
+
<div class="bg-amber-700 text-white p-3 rounded-lg mr-4">
|
| 27 |
+
<i class="fas fa-upload text-2xl"></i>
|
| 28 |
+
</div>
|
| 29 |
+
<h1 class="text-3xl font-bold text-amber-900">Upload Videos</h1>
|
| 30 |
+
</div>
|
| 31 |
+
|
| 32 |
+
<div class="bg-white p-6 rounded-xl shadow-lg">
|
| 33 |
+
<h2 class="text-xl font-bold mb-4 text-amber-800">
|
| 34 |
+
Upload Story Videos
|
| 35 |
+
</h2>
|
| 36 |
+
|
| 37 |
+
<div class="space-y-6">
|
| 38 |
+
<!-- Video 1 -->
|
| 39 |
+
<div class="border border-amber-200 rounded-lg p-4">
|
| 40 |
+
<h3 class="font-bold text-amber-900 mb-2">
|
| 41 |
+
Chuyện con suối Mường Tiên
|
| 42 |
+
</h3>
|
| 43 |
+
<div class="mb-4">
|
| 44 |
+
<div class="relative">
|
| 45 |
+
<input
|
| 46 |
+
type="file"
|
| 47 |
+
id="video1"
|
| 48 |
+
name="video1"
|
| 49 |
+
accept="video/*"
|
| 50 |
+
class="hidden"
|
| 51 |
+
onchange="updateFileName(this, 'video1-name')"
|
| 52 |
+
/>
|
| 53 |
+
<label
|
| 54 |
+
for="video1"
|
| 55 |
+
class="flex items-center justify-center px-4 py-2 bg-amber-100 text-amber-800 rounded-lg cursor-pointer hover:bg-amber-200 transition w-full"
|
| 56 |
+
>
|
| 57 |
+
<i class="fas fa-file-video mr-2"></i>
|
| 58 |
+
<span>Choose Video File</span>
|
| 59 |
+
</label>
|
| 60 |
+
<div id="video1-name" class="mt-2 text-sm text-gray-600">
|
| 61 |
+
No file chosen
|
| 62 |
+
</div>
|
| 63 |
+
</div>
|
| 64 |
+
</div>
|
| 65 |
+
<button
|
| 66 |
+
class="upload-btn w-full bg-amber-600 hover:bg-amber-700 text-white font-bold py-2 px-4 rounded-lg transition"
|
| 67 |
+
data-video="1"
|
| 68 |
+
data-filename="chuyen-con-suoi-muong-tien.mp4"
|
| 69 |
+
>
|
| 70 |
+
Upload Video
|
| 71 |
+
</button>
|
| 72 |
+
</div>
|
| 73 |
+
|
| 74 |
+
<!-- Video 2 -->
|
| 75 |
+
<div class="border border-amber-200 rounded-lg p-4">
|
| 76 |
+
<h3 class="font-bold text-amber-900 mb-2">
|
| 77 |
+
Chiếc bánh trong đẩy túi
|
| 78 |
+
</h3>
|
| 79 |
+
<div class="mb-4">
|
| 80 |
+
<div class="relative">
|
| 81 |
+
<input
|
| 82 |
+
type="file"
|
| 83 |
+
id="video2"
|
| 84 |
+
name="video2"
|
| 85 |
+
accept="video/*"
|
| 86 |
+
class="hidden"
|
| 87 |
+
onchange="updateFileName(this, 'video2-name')"
|
| 88 |
+
/>
|
| 89 |
+
<label
|
| 90 |
+
for="video2"
|
| 91 |
+
class="flex items-center justify-center px-4 py-2 bg-amber-100 text-amber-800 rounded-lg cursor-pointer hover:bg-amber-200 transition w-full"
|
| 92 |
+
>
|
| 93 |
+
<i class="fas fa-file-video mr-2"></i>
|
| 94 |
+
<span>Choose Video File</span>
|
| 95 |
+
</label>
|
| 96 |
+
<div id="video2-name" class="mt-2 text-sm text-gray-600">
|
| 97 |
+
No file chosen
|
| 98 |
+
</div>
|
| 99 |
+
</div>
|
| 100 |
+
</div>
|
| 101 |
+
<button
|
| 102 |
+
class="upload-btn w-full bg-amber-600 hover:bg-amber-700 text-white font-bold py-2 px-4 rounded-lg transition"
|
| 103 |
+
data-video="2"
|
| 104 |
+
data-filename="chiec-banh-trong-day-tui.mp4"
|
| 105 |
+
>
|
| 106 |
+
Upload Video
|
| 107 |
+
</button>
|
| 108 |
+
</div>
|
| 109 |
+
|
| 110 |
+
<!-- Video 3 -->
|
| 111 |
+
<div class="border border-amber-200 rounded-lg p-4">
|
| 112 |
+
<h3 class="font-bold text-amber-900 mb-2">
|
| 113 |
+
Vũng đầm của thần rồng
|
| 114 |
+
</h3>
|
| 115 |
+
<div class="mb-4">
|
| 116 |
+
<div class="relative">
|
| 117 |
+
<input
|
| 118 |
+
type="file"
|
| 119 |
+
id="video3"
|
| 120 |
+
name="video3"
|
| 121 |
+
accept="video/*"
|
| 122 |
+
class="hidden"
|
| 123 |
+
onchange="updateFileName(this, 'video3-name')"
|
| 124 |
+
/>
|
| 125 |
+
<label
|
| 126 |
+
for="video3"
|
| 127 |
+
class="flex items-center justify-center px-4 py-2 bg-amber-100 text-amber-800 rounded-lg cursor-pointer hover:bg-amber-200 transition w-full"
|
| 128 |
+
>
|
| 129 |
+
<i class="fas fa-file-video mr-2"></i>
|
| 130 |
+
<span>Choose Video File</span>
|
| 131 |
+
</label>
|
| 132 |
+
<div id="video3-name" class="mt-2 text-sm text-gray-600">
|
| 133 |
+
No file chosen
|
| 134 |
+
</div>
|
| 135 |
+
</div>
|
| 136 |
+
</div>
|
| 137 |
+
<button
|
| 138 |
+
class="upload-btn w-full bg-amber-600 hover:bg-amber-700 text-white font-bold py-2 px-4 rounded-lg transition"
|
| 139 |
+
data-video="3"
|
| 140 |
+
data-filename="vung-dam-cua-than-rong.mp4"
|
| 141 |
+
>
|
| 142 |
+
Upload Video
|
| 143 |
+
</button>
|
| 144 |
+
</div>
|
| 145 |
+
</div>
|
| 146 |
+
|
| 147 |
+
<div class="mt-6 flex justify-between">
|
| 148 |
+
<a
|
| 149 |
+
href="index.html"
|
| 150 |
+
class="flex items-center text-amber-700 hover:text-amber-900 transition"
|
| 151 |
+
>
|
| 152 |
+
<i class="fas fa-arrow-left mr-2"></i>
|
| 153 |
+
<span>Back to Stories</span>
|
| 154 |
+
</a>
|
| 155 |
+
<div id="upload-status" class="text-green-600 font-bold"></div>
|
| 156 |
+
</div>
|
| 157 |
+
</div>
|
| 158 |
+
</div>
|
| 159 |
+
|
| 160 |
+
<script>
|
| 161 |
+
function updateFileName(input, targetId) {
|
| 162 |
+
const target = document.getElementById(targetId);
|
| 163 |
+
if (input.files.length > 0) {
|
| 164 |
+
target.textContent = input.files[0].name;
|
| 165 |
+
} else {
|
| 166 |
+
target.textContent = "No file chosen";
|
| 167 |
+
}
|
| 168 |
+
}
|
| 169 |
+
|
| 170 |
+
document.addEventListener("DOMContentLoaded", function () {
|
| 171 |
+
const uploadButtons = document.querySelectorAll(".upload-btn");
|
| 172 |
+
|
| 173 |
+
uploadButtons.forEach((button) => {
|
| 174 |
+
button.addEventListener("click", function () {
|
| 175 |
+
const videoId = this.getAttribute("data-video");
|
| 176 |
+
const targetFilename = this.getAttribute("data-filename");
|
| 177 |
+
const fileInput = document.getElementById("video" + videoId);
|
| 178 |
+
const statusElement = document.getElementById("upload-status");
|
| 179 |
+
|
| 180 |
+
if (!fileInput.files.length) {
|
| 181 |
+
statusElement.textContent = "Please select a file first.";
|
| 182 |
+
statusElement.className = "text-red-600 font-bold";
|
| 183 |
+
return;
|
| 184 |
+
}
|
| 185 |
+
|
| 186 |
+
const file = fileInput.files[0];
|
| 187 |
+
|
| 188 |
+
// In a real implementation, here you would upload the file to your server
|
| 189 |
+
// using fetch or FormData API. This is just a simulation:
|
| 190 |
+
|
| 191 |
+
button.textContent = "Uploading...";
|
| 192 |
+
button.disabled = true;
|
| 193 |
+
|
| 194 |
+
// Simulate upload delay
|
| 195 |
+
setTimeout(() => {
|
| 196 |
+
button.textContent = "Uploaded!";
|
| 197 |
+
button.classList.remove("bg-amber-600", "hover:bg-amber-700");
|
| 198 |
+
button.classList.add("bg-green-600", "hover:bg-green-700");
|
| 199 |
+
|
| 200 |
+
statusElement.textContent =
|
| 201 |
+
'Video "' + targetFilename + '" has been selected.';
|
| 202 |
+
statusElement.className = "text-green-600 font-bold";
|
| 203 |
+
|
| 204 |
+
// After simulated upload, restore button
|
| 205 |
+
setTimeout(() => {
|
| 206 |
+
button.textContent = "Upload Video";
|
| 207 |
+
button.disabled = false;
|
| 208 |
+
button.classList.remove("bg-green-600", "hover:bg-green-700");
|
| 209 |
+
button.classList.add("bg-amber-600", "hover:bg-amber-700");
|
| 210 |
+
}, 3000);
|
| 211 |
+
}, 1500);
|
| 212 |
+
});
|
| 213 |
+
});
|
| 214 |
+
});
|
| 215 |
+
</script>
|
| 216 |
+
</body>
|
| 217 |
+
</html>
|
videos.js
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
document.addEventListener("DOMContentLoaded", function () {
|
| 2 |
+
const videoModal = document.getElementById("video-modal");
|
| 3 |
+
const videoPlayer = document.getElementById("video-player");
|
| 4 |
+
const closeModalBtn = document.getElementById("close-modal");
|
| 5 |
+
const playButtons = document.querySelectorAll(".play-btn");
|
| 6 |
+
const favoriteButtons = document.querySelectorAll(".favorite-btn");
|
| 7 |
+
|
| 8 |
+
// Updated video sources using local video files
|
| 9 |
+
const videoSources = {
|
| 10 |
+
1: "videos/chuyen-con-suoi-muong-tien.mp4",
|
| 11 |
+
2: "videos/chiec-banh-trong-day-tui.mp4",
|
| 12 |
+
3: "videos/vung-dam-cua-than-rong.mp4",
|
| 13 |
+
};
|
| 14 |
+
|
| 15 |
+
// Play button click handler
|
| 16 |
+
playButtons.forEach((button) => {
|
| 17 |
+
button.addEventListener("click", function () {
|
| 18 |
+
const storyId = this.getAttribute("data-story");
|
| 19 |
+
const videoSrc = videoSources[storyId];
|
| 20 |
+
|
| 21 |
+
// Set video source
|
| 22 |
+
videoPlayer.src = videoSrc;
|
| 23 |
+
|
| 24 |
+
// Show modal
|
| 25 |
+
videoModal.classList.remove("hidden");
|
| 26 |
+
videoModal.classList.add("flex");
|
| 27 |
+
|
| 28 |
+
// Play video
|
| 29 |
+
videoPlayer.load();
|
| 30 |
+
videoPlayer.play();
|
| 31 |
+
});
|
| 32 |
+
});
|
| 33 |
+
|
| 34 |
+
// Close modal button
|
| 35 |
+
closeModalBtn.addEventListener("click", function () {
|
| 36 |
+
// Pause video
|
| 37 |
+
videoPlayer.pause();
|
| 38 |
+
|
| 39 |
+
// Hide modal
|
| 40 |
+
videoModal.classList.add("hidden");
|
| 41 |
+
videoModal.classList.remove("flex");
|
| 42 |
+
});
|
| 43 |
+
|
| 44 |
+
// Pressing escape key also closes the modal
|
| 45 |
+
document.addEventListener("keydown", function (e) {
|
| 46 |
+
if (e.key === "Escape" && !videoModal.classList.contains("hidden")) {
|
| 47 |
+
videoPlayer.pause();
|
| 48 |
+
videoModal.classList.add("hidden");
|
| 49 |
+
videoModal.classList.remove("flex");
|
| 50 |
+
}
|
| 51 |
+
});
|
| 52 |
+
|
| 53 |
+
// Clicking outside the video container closes the modal
|
| 54 |
+
videoModal.addEventListener("click", function (e) {
|
| 55 |
+
if (e.target === videoModal) {
|
| 56 |
+
videoPlayer.pause();
|
| 57 |
+
videoModal.classList.add("hidden");
|
| 58 |
+
videoModal.classList.remove("flex");
|
| 59 |
+
}
|
| 60 |
+
});
|
| 61 |
+
|
| 62 |
+
// Favorite button click handler
|
| 63 |
+
favoriteButtons.forEach((button) => {
|
| 64 |
+
button.addEventListener("click", function () {
|
| 65 |
+
const heartIcon = this.querySelector("i");
|
| 66 |
+
const storyId = this.getAttribute("data-story");
|
| 67 |
+
|
| 68 |
+
if (heartIcon.classList.contains("far")) {
|
| 69 |
+
// Add to favorites
|
| 70 |
+
heartIcon.classList.remove("far");
|
| 71 |
+
heartIcon.classList.add("fas");
|
| 72 |
+
heartIcon.classList.add("text-red-500");
|
| 73 |
+
|
| 74 |
+
// Save to localStorage
|
| 75 |
+
saveFavorite(storyId);
|
| 76 |
+
} else {
|
| 77 |
+
// Remove from favorites
|
| 78 |
+
heartIcon.classList.remove("fas");
|
| 79 |
+
heartIcon.classList.remove("text-red-500");
|
| 80 |
+
heartIcon.classList.add("far");
|
| 81 |
+
|
| 82 |
+
// Remove from localStorage
|
| 83 |
+
removeFavorite(storyId);
|
| 84 |
+
}
|
| 85 |
+
});
|
| 86 |
+
});
|
| 87 |
+
|
| 88 |
+
// Load favorites from localStorage
|
| 89 |
+
function loadFavorites() {
|
| 90 |
+
const favorites = JSON.parse(localStorage.getItem("favorites")) || [];
|
| 91 |
+
|
| 92 |
+
favorites.forEach((id) => {
|
| 93 |
+
const button = document.querySelector(
|
| 94 |
+
`.favorite-btn[data-story="${id}"]`
|
| 95 |
+
);
|
| 96 |
+
if (button) {
|
| 97 |
+
const heartIcon = button.querySelector("i");
|
| 98 |
+
heartIcon.classList.remove("far");
|
| 99 |
+
heartIcon.classList.add("fas");
|
| 100 |
+
heartIcon.classList.add("text-red-500");
|
| 101 |
+
}
|
| 102 |
+
});
|
| 103 |
+
}
|
| 104 |
+
|
| 105 |
+
// Save a favorite to localStorage
|
| 106 |
+
function saveFavorite(id) {
|
| 107 |
+
const favorites = JSON.parse(localStorage.getItem("favorites")) || [];
|
| 108 |
+
if (!favorites.includes(id)) {
|
| 109 |
+
favorites.push(id);
|
| 110 |
+
localStorage.setItem("favorites", JSON.stringify(favorites));
|
| 111 |
+
}
|
| 112 |
+
}
|
| 113 |
+
|
| 114 |
+
// Remove a favorite from localStorage
|
| 115 |
+
function removeFavorite(id) {
|
| 116 |
+
let favorites = JSON.parse(localStorage.getItem("favorites")) || [];
|
| 117 |
+
favorites = favorites.filter((favoriteId) => favoriteId !== id);
|
| 118 |
+
localStorage.setItem("favorites", JSON.stringify(favorites));
|
| 119 |
+
}
|
| 120 |
+
|
| 121 |
+
// Initialize favorites
|
| 122 |
+
loadFavorites();
|
| 123 |
+
|
| 124 |
+
// Handle tab switching (All Stories / Favorites)
|
| 125 |
+
const allStoriesBtn = document.getElementById("all-stories-btn");
|
| 126 |
+
const favoritesBtn = document.getElementById("favorites-btn");
|
| 127 |
+
const allStoriesSection = document.getElementById("all-stories");
|
| 128 |
+
|
| 129 |
+
allStoriesBtn.addEventListener("click", function () {
|
| 130 |
+
// Show all stories
|
| 131 |
+
allStoriesBtn.classList.add("bg-amber-700", "text-white");
|
| 132 |
+
allStoriesBtn.classList.remove("hover:bg-amber-200");
|
| 133 |
+
|
| 134 |
+
favoritesBtn.classList.remove("bg-amber-700", "text-white");
|
| 135 |
+
favoritesBtn.classList.add("hover:bg-amber-200");
|
| 136 |
+
|
| 137 |
+
// Show all story cards
|
| 138 |
+
document.querySelectorAll(".story-card").forEach((card) => {
|
| 139 |
+
card.classList.remove("hidden");
|
| 140 |
+
});
|
| 141 |
+
});
|
| 142 |
+
|
| 143 |
+
favoritesBtn.addEventListener("click", function () {
|
| 144 |
+
// Show only favorites
|
| 145 |
+
favoritesBtn.classList.add("bg-amber-700", "text-white");
|
| 146 |
+
favoritesBtn.classList.remove("hover:bg-amber-200");
|
| 147 |
+
|
| 148 |
+
allStoriesBtn.classList.remove("bg-amber-700", "text-white");
|
| 149 |
+
allStoriesBtn.classList.add("hover:bg-amber-200");
|
| 150 |
+
|
| 151 |
+
const favorites = JSON.parse(localStorage.getItem("favorites")) || [];
|
| 152 |
+
|
| 153 |
+
// Hide/show cards based on favorites
|
| 154 |
+
document.querySelectorAll(".story-card").forEach((card) => {
|
| 155 |
+
const storyId = card
|
| 156 |
+
.querySelector(".play-btn")
|
| 157 |
+
.getAttribute("data-story");
|
| 158 |
+
if (favorites.includes(storyId)) {
|
| 159 |
+
card.classList.remove("hidden");
|
| 160 |
+
} else {
|
| 161 |
+
card.classList.add("hidden");
|
| 162 |
+
}
|
| 163 |
+
});
|
| 164 |
+
});
|
| 165 |
+
});
|