feat: frontend fixes
This commit is contained in:
Binary file not shown.
57
frontend/package-lock.json
generated
57
frontend/package-lock.json
generated
@@ -9,9 +9,11 @@
|
|||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tailwindcss/vite": "^4.1.18",
|
"@tailwindcss/vite": "^4.1.18",
|
||||||
|
"howler": "^2.2.4",
|
||||||
"lucide-react": "^0.564.0",
|
"lucide-react": "^0.564.0",
|
||||||
"react": "^19.2.0",
|
"react": "^19.2.0",
|
||||||
"react-dom": "^19.2.0",
|
"react-dom": "^19.2.0",
|
||||||
|
"react-howler": "^5.2.0",
|
||||||
"tailwindcss": "^4.1.18"
|
"tailwindcss": "^4.1.18"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -2369,6 +2371,12 @@
|
|||||||
"hermes-estree": "0.25.1"
|
"hermes-estree": "0.25.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/howler": {
|
||||||
|
"version": "2.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/howler/-/howler-2.2.4.tgz",
|
||||||
|
"integrity": "sha512-iARIBPgcQrwtEr+tALF+rapJ8qSc+Set2GJQl7xT1MQzWaVkFebdJhR3alVlSiUf5U7nAANKuj3aWpwerocD5w==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/ignore": {
|
"node_modules/ignore": {
|
||||||
"version": "5.3.2",
|
"version": "5.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
|
||||||
@@ -2449,7 +2457,6 @@
|
|||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
|
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/js-yaml": {
|
"node_modules/js-yaml": {
|
||||||
@@ -2808,6 +2815,18 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/loose-envify": {
|
||||||
|
"version": "1.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||||
|
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"js-tokens": "^3.0.0 || ^4.0.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"loose-envify": "cli.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/lru-cache": {
|
"node_modules/lru-cache": {
|
||||||
"version": "5.1.1",
|
"version": "5.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
|
||||||
@@ -2888,6 +2907,15 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/object-assign": {
|
||||||
|
"version": "4.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||||
|
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/optionator": {
|
"node_modules/optionator": {
|
||||||
"version": "0.9.4",
|
"version": "0.9.4",
|
||||||
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
|
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
|
||||||
@@ -3027,6 +3055,17 @@
|
|||||||
"node": ">= 0.8.0"
|
"node": ">= 0.8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/prop-types": {
|
||||||
|
"version": "15.8.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
|
||||||
|
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"loose-envify": "^1.4.0",
|
||||||
|
"object-assign": "^4.1.1",
|
||||||
|
"react-is": "^16.13.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/punycode": {
|
"node_modules/punycode": {
|
||||||
"version": "2.3.1",
|
"version": "2.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
||||||
@@ -3058,6 +3097,22 @@
|
|||||||
"react": "^19.2.4"
|
"react": "^19.2.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-howler": {
|
||||||
|
"version": "5.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-howler/-/react-howler-5.2.0.tgz",
|
||||||
|
"integrity": "sha512-oDK+zML0MHf3nVNM4lMxh+re87NDa7fHowea2WK8197yqnMiZfPVHoMXtfb/PtuoOsWLO06vmEAtovwTRWpTFg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"howler": "^2.2.0",
|
||||||
|
"prop-types": "^15.5.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react-is": {
|
||||||
|
"version": "16.13.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||||
|
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/react-refresh": {
|
"node_modules/react-refresh": {
|
||||||
"version": "0.18.0",
|
"version": "0.18.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz",
|
||||||
|
|||||||
@@ -11,9 +11,11 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tailwindcss/vite": "^4.1.18",
|
"@tailwindcss/vite": "^4.1.18",
|
||||||
|
"howler": "^2.2.4",
|
||||||
"lucide-react": "^0.564.0",
|
"lucide-react": "^0.564.0",
|
||||||
"react": "^19.2.0",
|
"react": "^19.2.0",
|
||||||
"react-dom": "^19.2.0",
|
"react-dom": "^19.2.0",
|
||||||
|
"react-howler": "^5.2.0",
|
||||||
"tailwindcss": "^4.1.18"
|
"tailwindcss": "^4.1.18"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
BIN
frontend/public/logo-prev.png
Normal file
BIN
frontend/public/logo-prev.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 297 KiB |
@@ -209,10 +209,10 @@ export default function App() {
|
|||||||
|
|
||||||
// Main App
|
// Main App
|
||||||
return (
|
return (
|
||||||
<div className="h-screen bg-gray-50 text-gray-800 flex flex-col overflow-hidden">
|
<div className="h-screen bg-white-50 text-gray-800 flex flex-col overflow-hidden">
|
||||||
<Header onSearch={handleSearch} onLogout={handleLogout} onNavigateToSearch={handleNavigateToSearch} />
|
<Header onSearch={handleSearch} onLogout={handleLogout} onNavigateToSearch={handleNavigateToSearch} />
|
||||||
|
|
||||||
<div className="flex-1 flex overflow-hidden max-w-[1400px] mx-auto w-full">
|
<div className="flex-1 flex overflow-hidden max-w-[1550px] mx-auto w-full">
|
||||||
<Sidebar user={user} activeTab={activeTab} onTabChange={handleTabChange} />
|
<Sidebar user={user} activeTab={activeTab} onTabChange={handleTabChange} />
|
||||||
|
|
||||||
<main className="flex-1 overflow-y-auto p-6">
|
<main className="flex-1 overflow-y-auto p-6">
|
||||||
|
|||||||
@@ -21,16 +21,14 @@ export default function AudioPostCard({ post, onViewPost }) {
|
|||||||
}, [post])
|
}, [post])
|
||||||
|
|
||||||
const formatDate = (dateString) => {
|
const formatDate = (dateString) => {
|
||||||
const date = new Date(dateString)
|
return new Date(dateString).toLocaleDateString('en-US', {
|
||||||
const now = new Date()
|
year: 'numeric',
|
||||||
const diffMs = now - date
|
month: 'long',
|
||||||
const diffMins = Math.floor(diffMs / 60000)
|
day: 'numeric',
|
||||||
|
hour: '2-digit',
|
||||||
if (diffMins < 60) return `${diffMins}m ago`
|
minute: '2-digit'
|
||||||
if (diffMins < 1440) return `${Math.floor(diffMins / 60)}h ago`
|
})
|
||||||
return `${Math.floor(diffMins / 1440)}d ago`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const formatTime = (seconds) => {
|
const formatTime = (seconds) => {
|
||||||
if (!seconds || isNaN(seconds)) return '0:00'
|
if (!seconds || isNaN(seconds)) return '0:00'
|
||||||
const mins = Math.floor(seconds / 60)
|
const mins = Math.floor(seconds / 60)
|
||||||
@@ -298,41 +296,18 @@ export default function AudioPostCard({ post, onViewPost }) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Transcript Section - Always shown */}
|
{/* Transcript Section - Always shown */}
|
||||||
<div className="mt-4 border border-gray-200 rounded-lg overflow-hidden">
|
<div className="mt-6">
|
||||||
<button
|
{transcript ? (
|
||||||
onClick={() => setTranscriptExpanded(!transcriptExpanded)}
|
<p className="text-sm text-gray-700 leading-relaxed whitespace-pre-wrap line-clamp-3">
|
||||||
className="w-full flex items-center justify-between p-3 bg-gray-50 hover:bg-gray-100 transition-colors"
|
{transcript}
|
||||||
>
|
</p>
|
||||||
<span className="text-sm font-medium text-gray-900">Transcript</span>
|
) : (
|
||||||
{loadingTranscript ? (
|
<p className="text-sm text-gray-500 italic">No transcript available</p>
|
||||||
<div className="animate-spin rounded-full h-4 w-4 border-b-2 border-gray-600"></div>
|
|
||||||
) : (
|
|
||||||
transcriptExpanded ? <ChevronUp size={18} /> : <ChevronDown size={18} />
|
|
||||||
)}
|
|
||||||
</button>
|
|
||||||
|
|
||||||
{transcript && (
|
|
||||||
<div className={`bg-white transition-all ${transcriptExpanded ? 'max-h-96' : 'max-h-24'} overflow-y-auto`}>
|
|
||||||
<div className="p-4">
|
|
||||||
<p className="text-sm text-gray-700 leading-relaxed whitespace-pre-wrap">
|
|
||||||
{transcript}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{!transcript && !loadingTranscript && (
|
|
||||||
<div className="p-4 bg-white">
|
|
||||||
<p className="text-sm text-gray-500 italic">No transcript available</p>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{loadingTranscript && (
|
|
||||||
<div className="p-4 bg-white text-center">
|
|
||||||
<p className="text-sm text-gray-500">Loading transcript...</p>
|
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ export default function PostDetail({ postId, user, onBack }) {
|
|||||||
const [volume, setVolume] = useState(1)
|
const [volume, setVolume] = useState(1)
|
||||||
const [downloading, setDownloading] = useState(false)
|
const [downloading, setDownloading] = useState(false)
|
||||||
const audioRef = useRef(null)
|
const audioRef = useRef(null)
|
||||||
const [audioSrc, setAudioSrc] = useState(null)
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (postId) {
|
if (postId) {
|
||||||
@@ -24,6 +23,16 @@ export default function PostDetail({ postId, user, onBack }) {
|
|||||||
}
|
}
|
||||||
}, [postId])
|
}, [postId])
|
||||||
|
|
||||||
|
// Add this useEffect in PostDetail
|
||||||
|
useEffect(() => {
|
||||||
|
if (audioRef.current && post?.audio_url) {
|
||||||
|
console.log('Setting audio src:', post.audio_url)
|
||||||
|
audioRef.current.src = post.audio_url
|
||||||
|
audioRef.current.load() // Force reload
|
||||||
|
}
|
||||||
|
}, [post?.audio_url])
|
||||||
|
|
||||||
|
|
||||||
const loadPostData = async () => {
|
const loadPostData = async () => {
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
setError(null)
|
setError(null)
|
||||||
@@ -35,8 +44,6 @@ export default function PostDetail({ postId, user, onBack }) {
|
|||||||
|
|
||||||
// Load audio URL if available
|
// Load audio URL if available
|
||||||
if (postData.audio_url && audioRef.current) {
|
if (postData.audio_url && audioRef.current) {
|
||||||
setPost(postData)
|
|
||||||
setAudioSrc(postData.audio_url)
|
|
||||||
audioRef.current.src = postData.audio_url
|
audioRef.current.src = postData.audio_url
|
||||||
audioRef.current.load()
|
audioRef.current.load()
|
||||||
}
|
}
|
||||||
@@ -293,14 +300,12 @@ export default function PostDetail({ postId, user, onBack }) {
|
|||||||
|
|
||||||
<audio
|
<audio
|
||||||
ref={audioRef}
|
ref={audioRef}
|
||||||
src={audioSrc}
|
|
||||||
onTimeUpdate={handleTimeUpdate}
|
onTimeUpdate={handleTimeUpdate}
|
||||||
onLoadedMetadata={handleLoadedMetadata}
|
onLoadedMetadata={handleLoadedMetadata}
|
||||||
onEnded={handleEnded}
|
onEnded={handleEnded}
|
||||||
preload="metadata"
|
preload="metadata"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
||||||
<div className="flex items-center gap-4 mb-4">
|
<div className="flex items-center gap-4 mb-4">
|
||||||
<button
|
<button
|
||||||
onClick={togglePlay}
|
onClick={togglePlay}
|
||||||
|
|||||||
Reference in New Issue
Block a user