Files
SkinbaseNova/resources/js/components/worlds/editor/WorldRelationCard.jsx
2026-04-18 17:02:56 +02:00

51 lines
3.7 KiB
JavaScript

import React from 'react'
function SmallBadge({ children, tone = 'default' }) {
const styles = {
default: 'border-white/10 bg-white/[0.06] text-slate-200',
accent: 'border-sky-300/20 bg-sky-400/10 text-sky-100',
feature: 'border-emerald-300/20 bg-emerald-400/10 text-emerald-100',
}
return <span className={`rounded-full border px-2.5 py-1 text-[10px] font-semibold uppercase tracking-[0.16em] ${styles[tone] || styles.default}`}>{children}</span>
}
export default function WorldRelationCard({ relation, index, total, sectionLabel, onEdit, onRemove, onMove }) {
const preview = relation?.preview || null
return (
<div className="rounded-[24px] border border-white/10 bg-black/20 p-4">
<div className="flex items-start gap-4">
<div className="relative h-20 w-20 shrink-0 overflow-hidden rounded-[20px] border border-white/10 bg-slate-950">
{preview?.image ? <img src={preview.image} alt="" className="h-full w-full object-cover" /> : null}
{!preview?.image && preview?.avatar ? <img src={preview.avatar} alt="" className="h-full w-full object-cover" /> : null}
{!preview?.image && !preview?.avatar ? <div className="flex h-full w-full items-center justify-center text-slate-500"><i className="fa-solid fa-shapes" /></div> : null}
{preview?.avatar && preview?.image ? <img src={preview.avatar} alt="" className="absolute bottom-2 left-2 h-8 w-8 rounded-xl border border-white/10 object-cover" /> : null}
</div>
<div className="min-w-0 flex-1">
<div className="flex flex-wrap items-center gap-2">
{preview?.entity_label ? <SmallBadge tone="accent">{preview.entity_label}</SmallBadge> : null}
{sectionLabel ? <SmallBadge>{sectionLabel}</SmallBadge> : null}
{relation?.is_featured ? <SmallBadge tone="feature">Featured</SmallBadge> : null}
</div>
<div className="mt-3 text-base font-semibold text-white">{preview?.title || 'Choose a relation'}</div>
{preview?.subtitle ? <div className="mt-1 text-xs uppercase tracking-[0.14em] text-slate-500">{preview.subtitle}</div> : null}
{preview?.description ? <div className="mt-2 line-clamp-2 text-sm leading-6 text-slate-400">{preview.description}</div> : null}
{relation?.context_label ? <div className="mt-2 text-sm font-medium text-sky-100">{relation.context_label}</div> : null}
{Array.isArray(preview?.meta) && preview.meta.length > 0 ? <div className="mt-2 flex flex-wrap gap-2 text-xs text-slate-500">{preview.meta.map((item) => <span key={item}>{item}</span>)}</div> : null}
</div>
<div className="flex flex-col gap-2">
<button type="button" onClick={() => onMove(index, -1)} disabled={index === 0} className="rounded-full border border-white/10 px-3 py-2 text-xs font-semibold text-white disabled:opacity-40">Up</button>
<button type="button" onClick={() => onMove(index, 1)} disabled={index === total - 1} className="rounded-full border border-white/10 px-3 py-2 text-xs font-semibold text-white disabled:opacity-40">Down</button>
<button type="button" onClick={onEdit} className="rounded-full border border-sky-300/20 bg-sky-400/10 px-3 py-2 text-xs font-semibold text-sky-100">Edit</button>
<button type="button" onClick={onRemove} className="rounded-full border border-rose-300/20 bg-rose-400/10 px-3 py-2 text-xs font-semibold text-rose-100">Remove</button>
</div>
</div>
{preview?.url ? <a href={preview.url} target="_blank" rel="noreferrer" className="mt-4 inline-flex items-center gap-2 text-xs font-semibold uppercase tracking-[0.16em] text-slate-300 hover:text-white">Open entity <i className="fa-solid fa-up-right-from-square" /></a> : null}
</div>
)
}