Files
SkinbaseNova/resources/js/Pages/Enhance/Index.jsx

135 lines
8.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import React from 'react'
import { Head, Link, usePage } from '@inertiajs/react'
import EnhanceStatusBadge from '../../components/enhance/EnhanceStatusBadge'
import EnhanceStubWarning from '../../components/enhance/EnhanceStubWarning'
import { formatEnhanceDate, formatEnhanceInteger } from '../../utils/enhanceFormatting'
function formatDate(value) {
return formatEnhanceDate(value)
}
function JobCard({ job }) {
return (
<article className="overflow-hidden rounded-[28px] border border-white/10 bg-[#08111d] shadow-[0_18px_48px_rgba(2,6,23,0.2)]">
<div className="grid gap-4 md:grid-cols-[220px_1fr]">
<div className="aspect-square bg-black/30">
{job.preview_url || job.source_url ? <img src={job.preview_url || job.source_url} alt="Enhance preview" className="h-full w-full object-cover" /> : <div className="flex h-full items-center justify-center text-white/20"><i className="fa-solid fa-image text-4xl" /></div>}
</div>
<div className="p-5">
<div className="flex flex-wrap items-center gap-2">
<EnhanceStatusBadge status={job.status} />
<span className="rounded-full border border-white/10 bg-white/[0.05] px-3 py-1 text-[11px] font-semibold uppercase tracking-[0.16em] text-slate-200">{job.scale}x</span>
<span className="rounded-full border border-white/10 bg-white/[0.05] px-3 py-1 text-[11px] font-semibold uppercase tracking-[0.16em] text-slate-200">{job.mode}</span>
<span className="rounded-full border border-white/10 bg-white/[0.05] px-3 py-1 text-[11px] font-semibold uppercase tracking-[0.16em] text-slate-200">{job.engine}</span>
</div>
<h2 className="mt-4 text-2xl font-semibold tracking-[-0.03em] text-white">
{job.artwork?.title ? `Artwork enhance: ${job.artwork.title}` : `Enhance job #${job.id}`}
</h2>
<p className="mt-2 text-sm leading-6 text-slate-300">Created {formatDate(job.created_at)} {job.processing_seconds ? `${job.processing_seconds}s processing` : ''}</p>
<div className="mt-2 text-sm text-slate-400">{job.input_width} × {job.input_height}{job.output_width && job.output_height ? `${job.output_width} × ${job.output_height}` : ''}</div>
{job.error_message ? <div className="mt-4 rounded-2xl border border-rose-300/20 bg-rose-400/10 px-4 py-3 text-sm text-rose-100">{job.error_message}</div> : null}
<div className="mt-5 flex flex-wrap gap-2">
<Link href={job.show_url} className="inline-flex items-center gap-2 rounded-full border border-white/10 bg-white/[0.05] px-4 py-2 text-xs font-semibold uppercase tracking-[0.14em] text-white transition hover:bg-white/[0.09]">Open job</Link>
{job.artwork?.url ? <a href={job.artwork.url} className="inline-flex items-center gap-2 rounded-full border border-white/10 bg-white/[0.05] px-4 py-2 text-xs font-semibold uppercase tracking-[0.14em] text-white transition hover:bg-white/[0.09]">Open artwork</a> : null}
</div>
</div>
</div>
</article>
)
}
export default function EnhanceIndex() {
const { props } = usePage()
const jobs = props.jobs?.data || []
const latestCompleted = props.latestCompleted || []
const flash = props.flash || {}
const enhanceConfig = props.enhanceConfig || {}
return (
<div className="w-full pb-16 pt-8">
<Head title="Skinbase Enhance" />
<section className="rounded-[32px] border border-white/10 bg-[radial-gradient(circle_at_top_left,rgba(56,189,248,0.16),transparent_36%),linear-gradient(180deg,rgba(15,23,42,0.96),rgba(2,6,23,0.92))] p-6 shadow-[0_24px_70px_rgba(2,6,23,0.32)]">
<div className="flex flex-col gap-4 lg:flex-row lg:items-end lg:justify-between">
<div>
<p className="text-[11px] font-semibold uppercase tracking-[0.28em] text-sky-200/80">Skinbase Enhance</p>
<h1 className="mt-3 text-3xl font-semibold tracking-[-0.04em] text-white">Image Upscaler</h1>
<p className="mt-2 max-w-3xl text-sm leading-relaxed text-slate-300">Improve older wallpapers, digital art, and photos with a clean upscaled version. Your original file is never replaced automatically.</p>
</div>
<div className="flex flex-wrap gap-3">
<Link href={props.createUrl} className="inline-flex items-center gap-2 rounded-full border border-sky-300/20 bg-sky-400/12 px-5 py-3 text-xs font-semibold uppercase tracking-[0.14em] text-sky-50 transition hover:bg-sky-400/20">
<i className="fa-solid fa-sparkles text-[10px]" />
Start enhance
</Link>
</div>
</div>
<div className="mt-6 grid gap-4 md:grid-cols-3">
<div className="rounded-[24px] border border-white/10 bg-white/[0.04] p-5">
<div className="text-[11px] font-semibold uppercase tracking-[0.18em] text-slate-400">Daily limit</div>
<div className="mt-4 text-3xl font-semibold tracking-[-0.04em] text-white">{formatEnhanceInteger(props.dailyLimit || 0)}</div>
</div>
<div className="rounded-[24px] border border-white/10 bg-white/[0.04] p-5">
<div className="text-[11px] font-semibold uppercase tracking-[0.18em] text-slate-400">Total jobs</div>
<div className="mt-4 text-3xl font-semibold tracking-[-0.04em] text-white">{formatEnhanceInteger(props.jobs?.total || jobs.length)}</div>
</div>
<div className="rounded-[24px] border border-white/10 bg-white/[0.04] p-5">
<div className="text-[11px] font-semibold uppercase tracking-[0.18em] text-slate-400">Completed outputs</div>
<div className="mt-4 text-3xl font-semibold tracking-[-0.04em] text-white">{formatEnhanceInteger(latestCompleted.length)}</div>
</div>
</div>
</section>
<EnhanceStubWarning config={enhanceConfig} className="mt-6" />
{flash.success ? <div className="mt-6 rounded-2xl border border-emerald-300/20 bg-emerald-400/10 px-4 py-3 text-sm text-emerald-50">{flash.success}</div> : null}
{flash.error ? <div className="mt-6 rounded-2xl border border-rose-300/20 bg-rose-400/10 px-4 py-3 text-sm text-rose-100">{flash.error}</div> : null}
{latestCompleted.length > 0 ? (
<section className="mt-8">
<div className="mb-4 flex items-center justify-between gap-3">
<div>
<p className="text-[11px] font-semibold uppercase tracking-[0.22em] text-slate-400">Latest completed</p>
<h2 className="mt-2 text-2xl font-semibold tracking-[-0.03em] text-white">Recent enhanced outputs</h2>
</div>
</div>
<div className="grid gap-4 md:grid-cols-2 xl:grid-cols-4">
{latestCompleted.map((job) => (
<Link key={job.id} href={job.show_url} className="overflow-hidden rounded-[28px] border border-white/10 bg-[#08111d] transition hover:border-sky-300/30 hover:bg-[#0b1524]">
<div className="aspect-square bg-black/20">
{job.output_url ? <img src={job.output_url} alt={`Enhance job ${job.id}`} className="h-full w-full object-cover" /> : null}
</div>
<div className="p-4">
<EnhanceStatusBadge status={job.status} />
<div className="mt-3 text-sm font-semibold text-white">Job #{job.id}</div>
<div className="mt-1 text-xs uppercase tracking-[0.16em] text-slate-400">{job.scale}x {job.mode}</div>
</div>
</Link>
))}
</div>
</section>
) : null}
<section className="mt-8">
<div className="mb-4">
<p className="text-[11px] font-semibold uppercase tracking-[0.22em] text-slate-400">History</p>
<h2 className="mt-2 text-2xl font-semibold tracking-[-0.03em] text-white">Your enhance jobs</h2>
</div>
{jobs.length === 0 ? (
<div className="rounded-[28px] border border-white/10 bg-white/[0.04] px-6 py-12 text-center text-slate-300">No enhance jobs yet. Upload an image to start your first upscale.</div>
) : (
<div className="space-y-4">
{jobs.map((job) => <JobCard key={job.id} job={job} />)}
</div>
)}
</section>
</div>
)
}