diff --git a/src/app/zxdb/entries/[id]/EntryDetail.tsx b/src/app/zxdb/entries/[id]/EntryDetail.tsx index 56bcceb..adab163 100644 --- a/src/app/zxdb/entries/[id]/EntryDetail.tsx +++ b/src/app/zxdb/entries/[id]/EntryDetail.tsx @@ -165,650 +165,651 @@ export default function EntryDetailClient({ data }: { data: EntryDetailData | nu {data.isXrated ? 18+ : null} -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - {typeof data.maxPlayers !== "undefined" && ( - - - - - )} - {typeof data.availabletypeId !== "undefined" && ( - - - - - )} - {typeof data.withoutLoadScreen !== "undefined" && ( - - - - - )} - {typeof data.withoutInlay !== "undefined" && ( - - - - - )} - {typeof data.issueId !== "undefined" && ( - - - - - )} - -
FieldValue
ID{data.id}
Title{data.title}
Machine - {data.machinetype.id != null ? ( - data.machinetype.name ? ( - {data.machinetype.name} - ) : ( - #{data.machinetype.id} - ) - ) : ( - - - )} -
Language - {data.language.id ? ( - data.language.name ? ( - {data.language.name} - ) : ( - {data.language.id} - ) - ) : ( - - - )} -
Genre - {data.genre.id ? ( - data.genre.name ? ( - {data.genre.name} - ) : ( - #{data.genre.id} - ) - ) : ( - - - )} -
Max Players{data.maxPlayers}
Available Type{data.availabletypeId ?? -}
Without Load Screen{data.withoutLoadScreen ? "Yes" : "No"}
Without Inlay{data.withoutInlay ? "Yes" : "No"}
Issue{data.issueId ? #{data.issueId} : -}
-
- -
- - {/* Downloads (flat, by entry_id). Render only this flat section; do not render grouped downloads here. */} -
-
Downloads
- {(!data.downloadsFlat || data.downloadsFlat.length === 0) &&
No downloads
} - {data.downloadsFlat && data.downloadsFlat.length > 0 && ( -
- - - - - - - - - - - - - - {data.downloadsFlat.map((d) => { - const isHttp = d.link.startsWith("http://") || d.link.startsWith("https://"); - return ( - - - - - - - - +
+
+
+
+
Entry Summary
+
+
TypeLinkSizeMD5FlagsDetailsComments
{d.type.name} - {isHttp ? ( - {d.link} - ) : ( - {d.link} - )} - {typeof d.size === "number" ? d.size.toLocaleString() : "-"}{d.md5 ?? "-"} -
- {d.isDemo ? Demo : null} - {d.scheme.name ? {d.scheme.name} : null} - {d.source.name ? {d.source.name} : null} - {d.case.name ? {d.case.name} : null} -
-
-
- {d.language.name && ( - {d.language.name} - )} - {d.machinetype.name && ( - {d.machinetype.name} - )} - {typeof d.year === "number" ? {d.year} : null} - - rel #{d.releaseSeq} - -
-
{d.comments ?? ""}
+ + + + - ); - })} - -
ID{data.id}
-
- )} -
- -
- -
-
-
Authors
- {data.authors.length === 0 &&
Unknown
} - {data.authors.length > 0 && ( - - )} -
-
-
Publishers
- {data.publishers.length === 0 &&
Unknown
} - {data.publishers.length > 0 && ( - - )} -
-
- -
- -
-
Releases
- {(!data.releases || data.releases.length === 0) &&
No releases recorded
} - {data.releases && data.releases.length > 0 && ( -
- - - - - - - - - - {data.releases.map((r) => ( - - - - - - ))} - -
Release #YearDownloads
- #{r.releaseSeq} - {r.year ?? -}{r.downloads.length}
-
- )} -
- -
- -
-
Origins
- {(!data.origins || data.origins.length === 0) &&
No origins recorded
} - {data.origins && data.origins.length > 0 && ( -
- - - - - - - - - - - - {data.origins.map((o, idx) => { - const dateParts = [o.date.year, o.date.month, o.date.day] - .filter((v) => typeof v === "number" && Number.isFinite(v)) - .map((v, i) => (i === 0 ? String(v) : String(v).padStart(2, "0"))); - const dateText = dateParts.length ? dateParts.join("/") : "-"; - return ( - - - - + + + + + + - - ); - })} - -
TypeTitlePublicationIssueDate
{o.type.name ?? o.type.id}{o.libraryTitle}{o.publication ?? -}
Title{data.title}
Machine - {o.issue ? ( -
- Issue #{o.issue.id} - {o.issue.magazineId != null && ( - - {o.issue.magazineTitle ?? `Magazine #${o.issue.magazineId}`} - - )} -
- ) : o.containerId ? ( - Container #{o.containerId} + {data.machinetype.id != null ? ( + data.machinetype.name ? ( + {data.machinetype.name} + ) : ( + #{data.machinetype.id} + ) ) : ( - )}
{dateText}
-
- )} -
- -
- -
-
Relations
- {(!data.relations || data.relations.length === 0) &&
No relations recorded
} - {data.relations && data.relations.length > 0 && ( -
- - - - - - - - - - {data.relations.map((r, idx) => ( - - - - - - ))} - -
DirectionTypeEntry
{r.direction === "from" ? "From" : "To"}{r.type.name ?? r.type.id} - - {r.entry.title ?? `Entry #${r.entry.id}`} - -
-
- )} -
- -
- -
-
Tags / Members
- {(!data.tags || data.tags.length === 0) &&
No tags recorded
} - {data.tags && data.tags.length > 0 && ( -
- - - - - - - - - - - - {data.tags.map((t) => ( - - - - - - - - ))} - -
TagTypeCategoryMember SeqLinks
{t.name}{t.type.name ?? t.type.id}{t.category.name ?? (t.category.id != null ? `#${t.category.id}` : "-")}{t.memberSeq ?? -} -
- {t.link && ( - Link - )} - {t.comments && {t.comments}} - {!t.link && !t.comments && -} -
-
-
- )} -
- -
- -
-
Ports
- {(!data.ports || data.ports.length === 0) &&
No ports recorded
} - {data.ports && data.ports.length > 0 && ( -
- - - - - - - - - - - {data.ports.map((p) => ( - - - - - - - ))} - -
TitlePlatformOfficialLink
{p.title ?? -}{p.platform.name ?? `#${p.platform.id}`}{p.isOfficial ? "Yes" : "No"} - {p.linkSystem ? ( - Link - ) : ( - - - )} -
-
- )} -
- -
- -
-
Remakes
- {(!data.remakes || data.remakes.length === 0) &&
No remakes recorded
} - {data.remakes && data.remakes.length > 0 && ( -
- - - - - - - - - - - - {data.remakes.map((r) => ( - - - - - - - - ))} - -
TitlePlatformsYearsFileNotes
{r.title}{r.platforms ?? -}{r.remakeYears ?? -} - {r.fileLink ? ( - File - ) : ( - - - )} - {r.remakeStatus ?? r.authors ?? -}
-
- )} -
- -
- -
-
Scores
- {(!data.scores || data.scores.length === 0) &&
No scores recorded
} - {data.scores && data.scores.length > 0 && ( -
- - - - - - - - - - {data.scores.map((s, idx) => ( - - - - - - ))} - -
WebsiteScoreVotes
{s.website.name ?? `#${s.website.id}`}{s.score}{s.votes}
-
- )} -
- -
- -
-
Notes
- {(!data.notes || data.notes.length === 0) &&
No notes recorded
} - {data.notes && data.notes.length > 0 && ( -
- - - - - - - - - {data.notes.map((n) => ( - - - - - ))} - -
TypeText
{n.type.name ?? n.type.id}{n.text}
-
- )} -
- -
- - {/* Aliases (alternative titles) */} -
-
Aliases
- {(!data.aliases || data.aliases.length === 0) &&
No aliases
} - {data.aliases && data.aliases.length > 0 && ( -
- - - - - - - - - - {data.aliases.map((a, idx) => ( - - - - - - ))} - -
Release #LanguageTitle
- #{a.releaseSeq} - {a.languageId}{a.title}
-
- )} -
- -
- -
-
Licenses
- {(!data.licenses || data.licenses.length === 0) &&
No licenses linked
} - {data.licenses && data.licenses.length > 0 && ( -
- - - - - - - - - - - {data.licenses.map((l) => ( - - - - - - - ))} - -
NameTypeOfficialLinks
{l.name}{l.type.name ?? l.type.id}{l.isOfficial ? "Yes" : "No"} -
- {l.linkWikipedia && ( - Wikipedia - )} - {l.linkSite && ( - Site - )} - {!l.linkWikipedia && !l.linkSite && -} -
-
-
- )} -
- -
- - {/* Web links (external references) */} -
-
Web links
- {(!data.webrefs || data.webrefs.length === 0) &&
No web links
} - {data.webrefs && data.webrefs.length > 0 && ( -
- - - - - - - - - - {data.webrefs.map((w, idx) => ( - - - - - - ))} - -
WebsiteLanguageURL
- {w.website.link ? ( - {w.website.name} - ) : ( - {w.website.name} - )} - {w.languageId} - {w.link} -
-
- )} -
- -
- -
-
Files
- {(!data.files || data.files.length === 0) &&
No files linked
} - {data.files && data.files.length > 0 && ( -
- - - - - - - - - - - - {data.files.map((f) => { - const isHttp = f.link.startsWith("http://") || f.link.startsWith("https://"); - return ( - - + + - - - - ); - })} - -
TypeLinkSizeMD5Comments
{f.type.name}
Language - {isHttp ? ( - {f.link} + {data.language.id ? ( + data.language.name ? ( + {data.language.name} + ) : ( + {data.language.id} + ) ) : ( - {f.link} + - )} {f.size != null ? new Intl.NumberFormat().format(f.size) : "-"}{f.md5 ?? "-"}{f.comments ?? ""}
+ + Genre + + {data.genre.id ? ( + data.genre.name ? ( + {data.genre.name} + ) : ( + #{data.genre.id} + ) + ) : ( + - + )} + + + {typeof data.maxPlayers !== "undefined" && ( + + Max Players + {data.maxPlayers} + + )} + {typeof data.availabletypeId !== "undefined" && ( + + Available Type + {data.availabletypeId ?? -} + + )} + {typeof data.withoutLoadScreen !== "undefined" && ( + + Without Load Screen + {data.withoutLoadScreen ? "Yes" : "No"} + + )} + {typeof data.withoutInlay !== "undefined" && ( + + Without Inlay + {data.withoutInlay ? "Yes" : "No"} + + )} + {typeof data.issueId !== "undefined" && ( + + Issue + {data.issueId ? #{data.issueId} : -} + + )} + + +
+
- )} - -
+
+
+
People
+
+
+
Authors
+ {data.authors.length === 0 &&
Unknown
} + {data.authors.length > 0 && ( +
    + {data.authors.map((a) => ( +
  • + {a.name} +
  • + ))} +
+ )} +
+
+
Publishers
+ {data.publishers.length === 0 &&
Unknown
} + {data.publishers.length > 0 && ( +
    + {data.publishers.map((p) => ( +
  • + {p.name} +
  • + ))} +
+ )} +
+
+
+
- {/* Removed grouped releases/downloads section to avoid duplicate downloads UI. */} +
+
+ Permalink + Back to Explorer +
+
+ -
- Permalink - Back to Explorer +
+
+
+
Downloads
+ {(!data.downloadsFlat || data.downloadsFlat.length === 0) &&
No downloads
} + {data.downloadsFlat && data.downloadsFlat.length > 0 && ( +
+ + + + + + + + + + + + + + {data.downloadsFlat.map((d) => { + const isHttp = d.link.startsWith("http://") || d.link.startsWith("https://"); + return ( + + + + + + + + + + ); + })} + +
TypeLinkSizeMD5FlagsDetailsComments
{d.type.name} + {isHttp ? ( + {d.link} + ) : ( + {d.link} + )} + {typeof d.size === "number" ? d.size.toLocaleString() : "-"}{d.md5 ?? "-"} +
+ {d.isDemo ? Demo : null} + {d.scheme.name ? {d.scheme.name} : null} + {d.source.name ? {d.source.name} : null} + {d.case.name ? {d.case.name} : null} +
+
+
+ {d.language.name && ( + {d.language.name} + )} + {d.machinetype.name && ( + {d.machinetype.name} + )} + {typeof d.year === "number" ? {d.year} : null} + + rel #{d.releaseSeq} + +
+
{d.comments ?? ""}
+
+ )} +
+
+ +
+
+
Releases
+ {(!data.releases || data.releases.length === 0) &&
No releases recorded
} + {data.releases && data.releases.length > 0 && ( +
+ + + + + + + + + + {data.releases.map((r) => ( + + + + + + ))} + +
Release #YearDownloads
+ #{r.releaseSeq} + {r.year ?? -}{r.downloads.length}
+
+ )} +
+
+ +
+
+
Origins
+ {(!data.origins || data.origins.length === 0) &&
No origins recorded
} + {data.origins && data.origins.length > 0 && ( +
+ + + + + + + + + + + + {data.origins.map((o, idx) => { + const dateParts = [o.date.year, o.date.month, o.date.day] + .filter((v) => typeof v === "number" && Number.isFinite(v)) + .map((v, i) => (i === 0 ? String(v) : String(v).padStart(2, "0"))); + const dateText = dateParts.length ? dateParts.join("/") : "-"; + return ( + + + + + + + + ); + })} + +
TypeTitlePublicationIssueDate
{o.type.name ?? o.type.id}{o.libraryTitle}{o.publication ?? -} + {o.issue ? ( +
+ Issue #{o.issue.id} + {o.issue.magazineId != null && ( + + {o.issue.magazineTitle ?? `Magazine #${o.issue.magazineId}`} + + )} +
+ ) : o.containerId ? ( + Container #{o.containerId} + ) : ( + - + )} +
{dateText}
+
+ )} +
+
+ +
+
+
Relations
+ {(!data.relations || data.relations.length === 0) &&
No relations recorded
} + {data.relations && data.relations.length > 0 && ( +
+ + + + + + + + + + {data.relations.map((r, idx) => ( + + + + + + ))} + +
DirectionTypeEntry
{r.direction === "from" ? "From" : "To"}{r.type.name ?? r.type.id} + + {r.entry.title ?? `Entry #${r.entry.id}`} + +
+
+ )} +
+
+ +
+
+
Tags / Members
+ {(!data.tags || data.tags.length === 0) &&
No tags recorded
} + {data.tags && data.tags.length > 0 && ( +
+ + + + + + + + + + + + {data.tags.map((t) => ( + + + + + + + + ))} + +
TagTypeCategoryMember SeqLinks
{t.name}{t.type.name ?? t.type.id}{t.category.name ?? (t.category.id != null ? `#${t.category.id}` : "-")}{t.memberSeq ?? -} +
+ {t.link && ( + Link + )} + {t.comments && {t.comments}} + {!t.link && !t.comments && -} +
+
+
+ )} +
+
+ +
+
+
Ports
+ {(!data.ports || data.ports.length === 0) &&
No ports recorded
} + {data.ports && data.ports.length > 0 && ( +
+ + + + + + + + + + + {data.ports.map((p) => ( + + + + + + + ))} + +
TitlePlatformOfficialLink
{p.title ?? -}{p.platform.name ?? `#${p.platform.id}`}{p.isOfficial ? "Yes" : "No"} + {p.linkSystem ? ( + Link + ) : ( + - + )} +
+
+ )} +
+
+ +
+
+
Remakes
+ {(!data.remakes || data.remakes.length === 0) &&
No remakes recorded
} + {data.remakes && data.remakes.length > 0 && ( +
+ + + + + + + + + + + + {data.remakes.map((r) => ( + + + + + + + + ))} + +
TitlePlatformsYearsFileNotes
{r.title}{r.platforms ?? -}{r.remakeYears ?? -} + {r.fileLink ? ( + File + ) : ( + - + )} + {r.remakeStatus ?? r.authors ?? -}
+
+ )} +
+
+ +
+
+
Scores
+ {(!data.scores || data.scores.length === 0) &&
No scores recorded
} + {data.scores && data.scores.length > 0 && ( +
+ + + + + + + + + + {data.scores.map((s, idx) => ( + + + + + + ))} + +
WebsiteScoreVotes
{s.website.name ?? `#${s.website.id}`}{s.score}{s.votes}
+
+ )} +
+
+ +
+
+
Notes
+ {(!data.notes || data.notes.length === 0) &&
No notes recorded
} + {data.notes && data.notes.length > 0 && ( +
+ + + + + + + + + {data.notes.map((n) => ( + + + + + ))} + +
TypeText
{n.type.name ?? n.type.id}{n.text}
+
+ )} +
+
+ +
+
+
Aliases
+ {(!data.aliases || data.aliases.length === 0) &&
No aliases
} + {data.aliases && data.aliases.length > 0 && ( +
+ + + + + + + + + + {data.aliases.map((a, idx) => ( + + + + + + ))} + +
Release #LanguageTitle
+ #{a.releaseSeq} + {a.languageId}{a.title}
+
+ )} +
+
+ +
+
+
Licenses
+ {(!data.licenses || data.licenses.length === 0) &&
No licenses linked
} + {data.licenses && data.licenses.length > 0 && ( +
+ + + + + + + + + + + {data.licenses.map((l) => ( + + + + + + + ))} + +
NameTypeOfficialLinks
{l.name}{l.type.name ?? l.type.id}{l.isOfficial ? "Yes" : "No"} +
+ {l.linkWikipedia && ( + Wikipedia + )} + {l.linkSite && ( + Site + )} + {!l.linkWikipedia && !l.linkSite && -} +
+
+
+ )} +
+
+ +
+
+
Web links
+ {(!data.webrefs || data.webrefs.length === 0) &&
No web links
} + {data.webrefs && data.webrefs.length > 0 && ( +
+ + + + + + + + + + {data.webrefs.map((w, idx) => ( + + + + + + ))} + +
WebsiteLanguageURL
+ {w.website.link ? ( + {w.website.name} + ) : ( + {w.website.name} + )} + {w.languageId} + {w.link} +
+
+ )} +
+
+ +
+
+
Files
+ {(!data.files || data.files.length === 0) &&
No files linked
} + {data.files && data.files.length > 0 && ( +
+ + + + + + + + + + + + {data.files.map((f) => { + const isHttp = f.link.startsWith("http://") || f.link.startsWith("https://"); + return ( + + + + + + + + ); + })} + +
TypeLinkSizeMD5Comments
{f.type.name} + {isHttp ? ( + {f.link} + ) : ( + {f.link} + )} + {f.size != null ? new Intl.NumberFormat().format(f.size) : "-"}{f.md5 ?? "-"}{f.comments ?? ""}
+
+ )} +
+
+
);