Add better samples components support
Signed-off-by: Felipe Cardoso <felipe.cardoso@hotmail.it>
This commit is contained in:
@@ -2,9 +2,10 @@
|
|||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
import {useSamples} from '@/contexts/SamplesContext'
|
import {useSamples} from '@/contexts/SamplesContext'
|
||||||
import Image from 'next/image'
|
|
||||||
import Link from "next/link"
|
import Link from "next/link"
|
||||||
import {useMemo} from 'react'
|
import {useMemo} from 'react'
|
||||||
|
import {useTraining} from "@/contexts/TrainingContext";
|
||||||
|
import {SampleCard} from "@/components/SampleCard";
|
||||||
|
|
||||||
// Helper function to parse sample information
|
// Helper function to parse sample information
|
||||||
const parseSampleInfo = (filename: string) => {
|
const parseSampleInfo = (filename: string) => {
|
||||||
@@ -18,7 +19,11 @@ const parseSampleInfo = (filename: string) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function SamplesPage() {
|
export default function SamplesPage() {
|
||||||
const {samples, isLoading, error} = useSamples()
|
const {samples, isLoading: samplesLoading, error: samplesError} = useSamples()
|
||||||
|
const {config, isLoading: configLoading} = useTraining()
|
||||||
|
|
||||||
|
// Get prompts from config
|
||||||
|
const prompts = config?.config?.process[0]?.sample?.prompts || []
|
||||||
|
|
||||||
// Group samples by batch number using a memoized calculation
|
// Group samples by batch number using a memoized calculation
|
||||||
const groupedSamples = useMemo(() => {
|
const groupedSamples = useMemo(() => {
|
||||||
@@ -45,25 +50,26 @@ export default function SamplesPage() {
|
|||||||
return new Map([...groups].sort((a, b) => b[0] - a[0]))
|
return new Map([...groups].sort((a, b) => b[0] - a[0]))
|
||||||
}, [samples])
|
}, [samples])
|
||||||
|
|
||||||
// Handle loading and error states with appropriate styling
|
// Handle loading and error states
|
||||||
if (isLoading) return (
|
if (samplesLoading || configLoading) return (
|
||||||
<div className="min-h-screen bg-gray-900 p-4">
|
<div className="min-h-screen bg-gray-900 p-4">
|
||||||
<div className="max-w-7xl mx-auto text-gray-400">Loading samples...</div>
|
<div className="max-w-7xl mx-auto text-gray-400">Loading...</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
if (error) return (
|
if (samplesError) return (
|
||||||
<div className="min-h-screen bg-gray-900 p-4">
|
<div className="min-h-screen bg-gray-900 p-4">
|
||||||
<div className="max-w-7xl mx-auto text-red-400">Error: {error.message}</div>
|
<div className="max-w-7xl mx-auto text-red-400">Error: {samplesError.message}</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main className="min-h-screen bg-gray-900 p-4">
|
<main className="min-h-screen bg-gray-900 p-4">
|
||||||
<div className="max-w-7xl mx-auto space-y-6">
|
<div className="max-w-7xl mx-auto space-y-6">
|
||||||
{/* Header with navigation */}
|
{/* Header with navigation */}
|
||||||
<header className="flex justify-between items-center">
|
<header className="flex justify-between items-center">
|
||||||
<h1 className="text-3xl font-bold text-gray-100">Sample Gallery</h1>
|
<h1 className="text-3xl font-bold text-gray-100">Samples Gallery</h1>
|
||||||
<Link
|
<Link
|
||||||
href="/"
|
href="/"
|
||||||
className="text-gray-400 hover:text-gray-200 transition-colors duration-200 flex items-center gap-2 group"
|
className="text-gray-400 hover:text-gray-200 transition-colors duration-200 flex items-center gap-2 group"
|
||||||
@@ -72,49 +78,42 @@ export default function SamplesPage() {
|
|||||||
</Link>
|
</Link>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
|
||||||
|
{/* Prompts display */}
|
||||||
|
<div className="sticky top-4 z-10 bg-gray-800 rounded-lg shadow-lg border border-gray-700 p-6">
|
||||||
|
<h2 className="text-xl font-semibold text-gray-300 mb-4">
|
||||||
|
Generation Prompts
|
||||||
|
</h2>
|
||||||
|
<div className="grid grid-cols-[repeat(auto-fit,minmax(200px,1fr))] gap-4">
|
||||||
|
{prompts.map((prompt, index) => (
|
||||||
|
<div
|
||||||
|
key={index}
|
||||||
|
className="text-sm text-gray-400 p-3 bg-gray-700 rounded-lg"
|
||||||
|
>
|
||||||
|
<span className="font-mono text-gray-500 mr-2">{index}:</span>
|
||||||
|
{prompt}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Sample groups */}
|
{/* Sample groups */}
|
||||||
<div className="space-y-8">
|
<div className="space-y-8">
|
||||||
{Array.from(groupedSamples).map(([batch, items]) => (
|
{Array.from(groupedSamples).map(([batch, items]) => (
|
||||||
<div key={batch} className="bg-gray-800 rounded-lg shadow-lg border border-gray-700 p-6">
|
<div key={batch} className="bg-gray-800 rounded-lg shadow-lg border border-gray-700 p-6">
|
||||||
<h2 className="text-xl font-semibold text-gray-300 mb-4">
|
<h2 className="text-xl font-semibold text-gray-300 mb-4">
|
||||||
Step {batch}
|
Steps {batch}
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
{/* Scrollable container for samples */}
|
{/* Scrollable container for samples */}
|
||||||
<div className="overflow-x-auto">
|
<div className="overflow-x-auto">
|
||||||
<div className="flex gap-4 min-w-full pb-4">
|
<div className="flex gap-4 min-w-full pb-4">
|
||||||
{items.map((sample: any) => (
|
{items.map((sample: any) => (
|
||||||
<div
|
<SampleCard
|
||||||
key={sample.filename}
|
key={sample.filename}
|
||||||
className="flex-shrink-0 group"
|
sample={sample}
|
||||||
>
|
prompt={prompts[sample.index]}
|
||||||
{/* Image container with hover effects */}
|
/>
|
||||||
<div
|
|
||||||
className="w-48 overflow-hidden rounded-lg bg-gray-700 shadow-md transition-all duration-200 group-hover:shadow-lg">
|
|
||||||
<Image
|
|
||||||
src={`${process.env.NEXT_PUBLIC_API_URL}${sample.url}`}
|
|
||||||
alt={`Sample ${sample.index}`}
|
|
||||||
width={200}
|
|
||||||
height={200}
|
|
||||||
className="object-cover w-full h-48 rounded-lg transition-transform duration-200 group-hover:scale-105"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Sample information */}
|
|
||||||
<div className="mt-2 space-y-1">
|
|
||||||
<div className="text-sm text-gray-400">
|
|
||||||
{new Date(sample.created_at).toLocaleString()}
|
|
||||||
</div>
|
|
||||||
<a
|
|
||||||
href={`${process.env.NEXT_PUBLIC_API_URL}${sample.url}`}
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
className="text-sm text-gray-400 hover:text-gray-200 transition-colors duration-200 font-mono"
|
|
||||||
>
|
|
||||||
Sample {sample.index}
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
43
frontend/src/components/SampleCard.tsx
Normal file
43
frontend/src/components/SampleCard.tsx
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import Image from 'next/image'
|
||||||
|
|
||||||
|
interface SampleCardProps {
|
||||||
|
sample: {
|
||||||
|
filename: string
|
||||||
|
url: string
|
||||||
|
created_at: string
|
||||||
|
index: number
|
||||||
|
}
|
||||||
|
prompt?: string // Associated prompt from config
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SampleCard({sample, prompt}: SampleCardProps) {
|
||||||
|
return (
|
||||||
|
<div className="flex-shrink-0 group">
|
||||||
|
<div
|
||||||
|
className="w-48 overflow-hidden rounded-lg bg-gray-700 shadow-md transition-all duration-200 group-hover/card:shadow-lg">
|
||||||
|
<Image
|
||||||
|
src={`${process.env.NEXT_PUBLIC_API_URL}${sample.url}`}
|
||||||
|
alt={`Sample ${sample.index}`}
|
||||||
|
width={200}
|
||||||
|
height={200}
|
||||||
|
className="object-cover w-full h-48 rounded-lg transition-transform duration-200 group-hover/card:scale-105"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-2 space-y-1">
|
||||||
|
<div className="text-sm text-gray-400">
|
||||||
|
{new Date(sample.created_at).toLocaleString()}
|
||||||
|
</div>
|
||||||
|
<a href={`${process.env.NEXT_PUBLIC_API_URL}${sample.url}`}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="text-sm text-gray-400 hover:text-gray-200 transition-colors duration-200 font-mono"
|
||||||
|
>
|
||||||
|
Sample {sample.index}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -43,7 +43,7 @@ export function SamplesGallery() {
|
|||||||
|
|
||||||
{/* Style the filename with appropriate dark mode colors */}
|
{/* Style the filename with appropriate dark mode colors */}
|
||||||
<p className="text-sm mt-2 text-gray-400 font-mono transition-colors duration-200 group-hover:text-gray-200">
|
<p className="text-sm mt-2 text-gray-400 font-mono transition-colors duration-200 group-hover:text-gray-200">
|
||||||
{sample.url.split('__')[1]}
|
{sample.url.split('__')[1].split(".")[0]}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|||||||
Reference in New Issue
Block a user