catalog permalink
This commit is contained in:
@@ -27,144 +27,44 @@ const softwares = json.softwares;
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 gap-8 software-list">
|
||||
{softwares.map(({ software, releases, latestRelease }) => {
|
||||
const stableReleases = releases.filter((r: any) => !r.version.startsWith('dev-'));
|
||||
const devReleases = releases.filter((r: any) => r.version.startsWith('dev-'));
|
||||
{softwares.map(({ software, releases }) => {
|
||||
const latestStable = releases
|
||||
.filter((r: any) => !r.version.startsWith('dev-'))
|
||||
.sort((a: any, b: any) => new Date(b.UpdatedAt).getTime() - new Date(a.UpdatedAt).getTime())[0];
|
||||
|
||||
return (
|
||||
<div class="software-card" data-status={software.status}>
|
||||
<div class="software-card group" data-status={software.status}>
|
||||
<div class="software-card-content">
|
||||
<div class="flex items-center gap-3 mb-2">
|
||||
<h2 class="software-title mb-0">{software.title}</h2>
|
||||
<span class={`status-badge status-${software.status}`}>
|
||||
{software.status}
|
||||
</span>
|
||||
</div>
|
||||
<p class="software-desc">{software.desc}</p>
|
||||
<div class="software-meta">
|
||||
<div>Author: {software.author}</div>
|
||||
<div>Platform: {software.platform}</div>
|
||||
</div>
|
||||
|
||||
{latestRelease && (
|
||||
<div class="latest-release-actions">
|
||||
{latestRelease.htmlFolderPath ? (
|
||||
<a href={BASE + latestRelease.htmlFolderPath} target="_blank" class="btn-play-sm">▶ Play</a>
|
||||
) : (
|
||||
<span class="btn-disabled-sm">▶ Play</span>
|
||||
)}
|
||||
{latestRelease.cartridgePath ? (
|
||||
<a href={BASE + latestRelease.cartridgePath} target="_blank" class="btn-download-sm">Download</a>
|
||||
) : (
|
||||
<span class="btn-disabled-sm">Download</span>
|
||||
)}
|
||||
{latestRelease.sourcePath ? (
|
||||
<a href={BASE + latestRelease.sourcePath} target="_blank" class="btn-source-sm">Source</a>
|
||||
) : (
|
||||
<span class="btn-disabled-sm">Source</span>
|
||||
)}
|
||||
{latestRelease.docsFolderPath ? (
|
||||
<a href={BASE + latestRelease.docsFolderPath} target="_blank" class="btn-docs-sm">Docs</a>
|
||||
) : (
|
||||
<span class="btn-disabled-sm">Docs</span>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<details class="mt-4">
|
||||
<summary class="releases-summary">
|
||||
Releases ({releases.length})
|
||||
</summary>
|
||||
|
||||
<div class="mt-4">
|
||||
{/* Desktop Table View */}
|
||||
<div class="desktop-releases">
|
||||
<table class="releases-table">
|
||||
<thead class="releases-thead">
|
||||
<tr>
|
||||
<th scope="col" class="releases-th">Version</th>
|
||||
<th scope="col" class="releases-th">Created</th>
|
||||
<th scope="col" class="releases-th">Updated</th>
|
||||
<th scope="col" class="releases-th !text-right">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="releases-tbody">
|
||||
{stableReleases.map((release: any) => (
|
||||
<tr>
|
||||
<td class="releases-td font-medium text-gray-900">{release.version}</td>
|
||||
<td class="releases-td text-gray-500">{formatDateTime(release.CreatedAt)}</td>
|
||||
<td class="releases-td text-gray-500">{formatDateTime(release.UpdatedAt)}</td>
|
||||
<td class="releases-td text-right">
|
||||
{release.htmlFolderPath ? (<a href={BASE + release.htmlFolderPath} target="_blank" class="action-link-purple">▶ Play</a>) : (<span class="action-link-disabled">▶ Play</span>)}
|
||||
{release.cartridgePath ? (<a href={BASE + release.cartridgePath} target="_blank" class="action-link-blue">Download</a>) : (<span class="action-link-disabled">Download</span>)}
|
||||
{release.sourcePath ? (<a href={BASE + release.sourcePath} target="_blank" class="action-link-green">Source</a>) : (<span class="action-link-disabled">Source</span>)}
|
||||
{release.docsFolderPath ? (<a href={BASE + release.docsFolderPath} target="_blank" class="action-link-yellow">Docs</a>) : (<span class="action-link-disabled">Docs</span>)}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
{devReleases.length > 0 && (
|
||||
<tr>
|
||||
<td colspan="4" class="releases-td text-xs font-bold text-gray-400 uppercase tracking-wider pt-3 pb-1">Development Releases</td>
|
||||
</tr>
|
||||
)}
|
||||
{devReleases.map((release: any) => (
|
||||
<tr class="bg-yellow-50/50">
|
||||
<td class="releases-td font-medium text-yellow-800">{release.version}</td>
|
||||
<td class="releases-td text-gray-500">{formatDateTime(release.CreatedAt)}</td>
|
||||
<td class="releases-td text-gray-500">{formatDateTime(release.UpdatedAt)}</td>
|
||||
<td class="releases-td text-right">
|
||||
{release.htmlFolderPath ? (<a href={BASE + release.htmlFolderPath} target="_blank" class="action-link-purple">▶ Play</a>) : (<span class="action-link-disabled">▶ Play</span>)}
|
||||
{release.cartridgePath ? (<a href={BASE + release.cartridgePath} target="_blank" class="action-link-blue">Download</a>) : (<span class="action-link-disabled">Download</span>)}
|
||||
{release.sourcePath ? (<a href={BASE + release.sourcePath} target="_blank" class="action-link-green">Source</a>) : (<span class="action-link-disabled">Source</span>)}
|
||||
{release.docsFolderPath ? (<a href={BASE + release.docsFolderPath} target="_blank" class="action-link-yellow">Docs</a>) : (<span class="action-link-disabled">Docs</span>)}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="flex flex-col md:flex-row md:items-center justify-between gap-4">
|
||||
<div class="flex-grow">
|
||||
<div class="flex items-center gap-3 mb-2">
|
||||
<a href={`/catalog/${software.name}`} class="hover:text-purple-600 transition-colors">
|
||||
<h2 class="software-title mb-0">{software.title}</h2>
|
||||
</a>
|
||||
<span class={`status-badge status-${software.status}`}>
|
||||
{software.status}
|
||||
</span>
|
||||
</div>
|
||||
<p class="software-desc max-w-2xl">{software.desc}</p>
|
||||
<div class="software-meta">
|
||||
<span>Author: <span class="text-gray-900 font-medium">{software.author}</span></span>
|
||||
<span class="mx-2 text-gray-300">•</span>
|
||||
<span>Platform: <span class="text-gray-900 font-medium">{software.platform}</span></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Mobile Stacked View */}
|
||||
<div class="mobile-releases">
|
||||
{stableReleases.map((release: any) => (
|
||||
<div class="release-mobile-card">
|
||||
<div class="release-mobile-header">
|
||||
<span class="release-mobile-version">{release.version}</span>
|
||||
<span class="release-mobile-date">Created: {formatDateTime(release.CreatedAt)}</span>
|
||||
<span class="release-mobile-date">Updated: {formatDateTime(release.UpdatedAt)}</span>
|
||||
</div>
|
||||
<div class="release-mobile-grid">
|
||||
{release.htmlFolderPath ? (<a href={BASE + release.htmlFolderPath} target="_blank" class="mobile-btn-play">▶ Play</a>) : (<span class="mobile-btn-disabled">▶ Play</span>)}
|
||||
{release.cartridgePath ? (<a href={BASE + release.cartridgePath} target="_blank" class="mobile-btn-download">Download</a>) : (<span class="mobile-btn-disabled">Download</span>)}
|
||||
{release.sourcePath ? (<a href={BASE + release.sourcePath} target="_blank" class="mobile-btn-source">Source</a>) : (<span class="mobile-btn-disabled">Source</span>)}
|
||||
{release.docsFolderPath ? (<a href={BASE + release.docsFolderPath} target="_blank" class="mobile-btn-docs">Docs</a>) : (<span class="mobile-btn-disabled">Docs</span>)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
{devReleases.length > 0 && (
|
||||
<div class="text-xs font-bold text-gray-400 uppercase tracking-wider pt-3 pb-1">Development Releases</div>
|
||||
<div class="flex flex-wrap gap-2 items-center">
|
||||
{latestStable?.htmlFolderPath && (
|
||||
<a href={BASE + latestStable.htmlFolderPath} target="_blank" class="btn-play-sm">▶ Play</a>
|
||||
)}
|
||||
{devReleases.map((release: any) => (
|
||||
<div class="release-mobile-card border-yellow-200 bg-yellow-50">
|
||||
<div class="release-mobile-header">
|
||||
<span class="release-mobile-version text-yellow-800">{release.version}</span>
|
||||
<span class="release-mobile-date">Created: {formatDateTime(release.CreatedAt)}</span>
|
||||
<span class="release-mobile-date">Updated: {formatDateTime(release.UpdatedAt)}</span>
|
||||
</div>
|
||||
<div class="release-mobile-grid">
|
||||
{release.htmlFolderPath ? (<a href={BASE + release.htmlFolderPath} target="_blank" class="mobile-btn-play">▶ Play</a>) : (<span class="mobile-btn-disabled">▶ Play</span>)}
|
||||
{release.cartridgePath ? (<a href={BASE + release.cartridgePath} target="_blank" class="mobile-btn-download">Download</a>) : (<span class="mobile-btn-disabled">Download</span>)}
|
||||
{release.sourcePath ? (<a href={BASE + release.sourcePath} target="_blank" class="mobile-btn-source">Source</a>) : (<span class="mobile-btn-disabled">Source</span>)}
|
||||
{release.docsFolderPath ? (<a href={BASE + release.docsFolderPath} target="_blank" class="mobile-btn-docs">Docs</a>) : (<span class="mobile-btn-disabled">Docs</span>)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
<a href={`/catalog/${software.name}`} class="btn-info-sm">
|
||||
ℹ More Info
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
)})}
|
||||
</div>
|
||||
</main>
|
||||
</Layout>
|
||||
@@ -216,89 +116,19 @@ const softwares = json.softwares;
|
||||
@apply p-6;
|
||||
}
|
||||
.software-title {
|
||||
@apply text-2xl font-semibold mb-2;
|
||||
@apply text-2xl font-bold mb-0;
|
||||
}
|
||||
.software-desc {
|
||||
@apply text-gray-600 mb-4;
|
||||
@apply text-gray-600 mb-3;
|
||||
}
|
||||
.software-meta {
|
||||
@apply text-sm text-gray-500 mb-4;
|
||||
}
|
||||
.latest-release-actions {
|
||||
@apply flex flex-row flex-wrap gap-1 mb-4 sm:absolute sm:top-4 sm:right-4 sm:flex-col sm:mb-0 z-10;
|
||||
@apply text-sm text-gray-500;
|
||||
}
|
||||
|
||||
/* Small Action Buttons */
|
||||
.btn-base-sm {
|
||||
@apply inline-block font-bold py-1 px-2 rounded-lg text-sm transition-colors;
|
||||
@apply inline-flex items-center justify-center font-bold py-2.5 px-5 rounded-xl text-sm transition-all active:scale-95;
|
||||
}
|
||||
.btn-play-sm { @apply btn-base-sm bg-purple-600 hover:bg-purple-700 text-white; }
|
||||
.btn-download-sm { @apply btn-base-sm bg-blue-600 hover:bg-blue-700 text-white; }
|
||||
.btn-source-sm { @apply btn-base-sm bg-green-600 hover:bg-green-700 text-white; }
|
||||
.btn-docs-sm { @apply btn-base-sm bg-yellow-600 hover:bg-yellow-700 text-white; }
|
||||
.btn-disabled-sm { @apply btn-base-sm bg-gray-200 text-gray-400 cursor-not-allowed; }
|
||||
|
||||
.releases-summary {
|
||||
@apply cursor-pointer font-semibold text-purple-600 hover:text-purple-800;
|
||||
}
|
||||
|
||||
/* Desktop Table Styles */
|
||||
.desktop-releases {
|
||||
@apply hidden sm:block overflow-x-auto;
|
||||
}
|
||||
.releases-table {
|
||||
@apply min-w-full divide-y divide-gray-200;
|
||||
}
|
||||
.releases-thead {
|
||||
@apply bg-gray-50;
|
||||
}
|
||||
.releases-th {
|
||||
@apply px-3 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider;
|
||||
}
|
||||
.releases-tbody {
|
||||
@apply bg-white divide-y divide-gray-200;
|
||||
}
|
||||
.releases-td {
|
||||
@apply px-3 py-2 whitespace-nowrap text-sm;
|
||||
}
|
||||
|
||||
/* Action Links */
|
||||
.action-link-base {
|
||||
@apply hover:underline mr-2 last:mr-0;
|
||||
}
|
||||
.action-link-purple { @apply action-link-base text-purple-600 hover:text-purple-900; }
|
||||
.action-link-blue { @apply action-link-base text-blue-600 hover:text-blue-900; }
|
||||
.action-link-green { @apply action-link-base text-green-600 hover:text-green-900; }
|
||||
.action-link-yellow { @apply action-link-base text-yellow-600 hover:text-yellow-900; }
|
||||
.action-link-disabled { @apply text-gray-400 cursor-not-allowed mr-2 last:mr-0; }
|
||||
|
||||
/* Mobile Release Styles */
|
||||
.mobile-releases {
|
||||
@apply sm:hidden space-y-4;
|
||||
}
|
||||
.release-mobile-card {
|
||||
@apply border border-gray-100 rounded-lg p-4 bg-gray-50 shadow-sm;
|
||||
}
|
||||
.release-mobile-header {
|
||||
@apply flex flex-col mb-3 border-b border-gray-200 pb-2;
|
||||
}
|
||||
.release-mobile-version {
|
||||
@apply font-bold text-gray-900 text-lg break-words;
|
||||
}
|
||||
.release-mobile-date {
|
||||
@apply text-xs text-gray-500 mt-1;
|
||||
}
|
||||
.release-mobile-grid {
|
||||
@apply grid grid-cols-2 gap-2;
|
||||
}
|
||||
|
||||
/* Mobile Buttons */
|
||||
.mobile-btn-base {
|
||||
@apply flex items-center justify-center py-2 px-3 rounded text-sm font-bold shadow-sm;
|
||||
}
|
||||
.mobile-btn-play { @apply mobile-btn-base bg-purple-600 text-white; }
|
||||
.mobile-btn-download { @apply mobile-btn-base bg-blue-600 text-white; }
|
||||
.mobile-btn-source { @apply mobile-btn-base bg-green-600 text-white; }
|
||||
.mobile-btn-docs { @apply mobile-btn-base bg-yellow-600 text-white; }
|
||||
.mobile-btn-disabled { @apply mobile-btn-base bg-gray-200 text-gray-400 cursor-not-allowed; }
|
||||
.btn-play-sm { @apply btn-base-sm bg-purple-600 hover:bg-purple-700 text-white shadow-lg shadow-purple-600/20; }
|
||||
.btn-info-sm { @apply btn-base-sm bg-gray-100 hover:bg-gray-200 text-gray-700; }
|
||||
</style>
|
||||
@@ -0,0 +1,228 @@
|
||||
---
|
||||
import Layout from '../../layouts/Layout.astro';
|
||||
import { formatDateTime } from '../../utils/dateFormat';
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const BASE = "https://games.teletype.hu";
|
||||
const API = BASE + "/api/software";
|
||||
const res = await fetch(API);
|
||||
const json = await res.json();
|
||||
const softwares = json.softwares;
|
||||
|
||||
return softwares.map((item: any) => ({
|
||||
params: { name: item.software.name },
|
||||
props: { project: item },
|
||||
}));
|
||||
}
|
||||
|
||||
const { project } = Astro.props;
|
||||
const { software, releases } = project;
|
||||
const BASE = "https://games.teletype.hu";
|
||||
|
||||
const stableReleases = releases
|
||||
.filter((r: any) => !r.version.startsWith('dev-'))
|
||||
.sort((a: any, b: any) => new Date(b.UpdatedAt).getTime() - new Date(a.UpdatedAt).getTime());
|
||||
const devReleases = releases
|
||||
.filter((r: any) => r.version.startsWith('dev-'))
|
||||
.sort((a: any, b: any) => new Date(b.UpdatedAt).getTime() - new Date(a.UpdatedAt).getTime());
|
||||
|
||||
const latestStable = stableReleases[0];
|
||||
---
|
||||
|
||||
<Layout>
|
||||
<div class="bg-gray-50 min-h-screen pb-20">
|
||||
<header class="hero-section-gradient from-purple-700 to-indigo-800 py-12 md:py-20">
|
||||
<div class="hero-container">
|
||||
<nav class="mb-8">
|
||||
<a href="/catalog" class="text-purple-200 hover:text-white transition-colors flex items-center gap-2 font-medium">
|
||||
← Back to Catalog
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
<div class="flex flex-col md:flex-row md:items-end justify-between gap-6">
|
||||
<div class="flex-grow">
|
||||
<div class="flex items-center gap-3 mb-4">
|
||||
<span class={`status-badge status-${software.status} px-3 py-1`}>
|
||||
{software.status}
|
||||
</span>
|
||||
<span class="text-purple-300 font-mono text-sm tracking-widest uppercase">{software.platform}</span>
|
||||
</div>
|
||||
<h1 class="text-4xl md:text-6xl font-black text-white mb-4 leading-tight">{software.title}</h1>
|
||||
<p class="text-xl text-purple-100 max-w-3xl leading-relaxed">{software.desc}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="main-container -mt-10">
|
||||
<div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
|
||||
|
||||
<!-- Sidebar Info -->
|
||||
<div class="lg:col-span-1 space-y-6">
|
||||
<div class="bg-white rounded-3xl shadow-xl p-8 border border-gray-100">
|
||||
<h2 class="text-xl font-bold text-gray-900 mb-6 flex items-center gap-2">
|
||||
<span class="text-purple-600">ℹ</span> Project Info
|
||||
</h2>
|
||||
<dl class="space-y-4">
|
||||
<div>
|
||||
<dt class="text-xs font-bold text-gray-400 uppercase tracking-widest mb-1">Author</dt>
|
||||
<dd class="text-gray-900 font-medium">{software.author}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="text-xs font-bold text-gray-400 uppercase tracking-widest mb-1">Platform</dt>
|
||||
<dd class="text-gray-900 font-medium">{software.platform}</dd>
|
||||
</div>
|
||||
{software.license && (
|
||||
<div>
|
||||
<dt class="text-xs font-bold text-gray-400 uppercase tracking-widest mb-1">License</dt>
|
||||
<dd class="text-gray-900 font-medium">{software.license}</dd>
|
||||
</div>
|
||||
)}
|
||||
{software.site && (
|
||||
<div>
|
||||
<dt class="text-xs font-bold text-gray-400 uppercase tracking-widest mb-1">Source Code</dt>
|
||||
<dd>
|
||||
<a href={software.site} target="_blank" class="text-purple-600 hover:text-purple-800 font-bold break-all">
|
||||
Visit Repository ↗
|
||||
</a>
|
||||
</dd>
|
||||
</div>
|
||||
)}
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Main Content Area -->
|
||||
<div class="lg:col-span-2 space-y-8">
|
||||
|
||||
<!-- Latest Release (Prominent Section) -->
|
||||
{latestStable && (
|
||||
<div class="bg-gradient-to-br from-indigo-600 to-purple-700 rounded-3xl shadow-xl p-8 text-white">
|
||||
<div class="flex flex-col md:flex-row justify-between items-start md:items-center gap-6">
|
||||
<div>
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<span class="px-2 py-0.5 bg-white/20 text-white text-[10px] font-black uppercase rounded tracking-widest">Latest Stable</span>
|
||||
</div>
|
||||
<h2 class="text-4xl font-black mb-1">{latestStable.version}</h2>
|
||||
<p class="text-indigo-100 text-sm">Released: {formatDateTime(latestStable.UpdatedAt)}</p>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 sm:grid-cols-4 md:grid-cols-2 xl:grid-cols-4 gap-2 w-full md:w-auto">
|
||||
{latestStable.htmlFolderPath && (
|
||||
<a href={BASE + latestStable.htmlFolderPath} target="_blank" class="flex items-center justify-center py-3 px-4 bg-white text-indigo-900 font-bold rounded-xl transition-all hover:bg-indigo-50 shadow-lg shadow-black/10 text-sm whitespace-nowrap">
|
||||
▶ Play Now
|
||||
</a>
|
||||
)}
|
||||
{latestStable.cartridgePath && (
|
||||
<a href={BASE + latestStable.cartridgePath} target="_blank" class="flex items-center justify-center py-3 px-4 bg-indigo-500/30 border border-indigo-400/30 text-white font-bold rounded-xl transition-all hover:bg-indigo-500/40 text-sm whitespace-nowrap">
|
||||
💾 Download
|
||||
</a>
|
||||
)}
|
||||
{latestStable.sourcePath && (
|
||||
<a href={BASE + latestStable.sourcePath} target="_blank" class="flex items-center justify-center py-3 px-4 bg-indigo-500/30 border border-indigo-400/30 text-white font-bold rounded-xl transition-all hover:bg-indigo-500/40 text-sm whitespace-nowrap">
|
||||
📄 Source
|
||||
</a>
|
||||
)}
|
||||
{latestStable.docsFolderPath && (
|
||||
<a href={BASE + latestStable.docsFolderPath} target="_blank" class="flex items-center justify-center py-3 px-4 bg-indigo-500/30 border border-indigo-400/30 text-white font-bold rounded-xl transition-all hover:bg-indigo-500/40 text-sm whitespace-nowrap">
|
||||
📖 Docs
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<!-- Releases List Box -->
|
||||
<div class="bg-white rounded-3xl shadow-xl overflow-hidden border border-gray-100">
|
||||
<div class="p-8 border-b border-gray-100">
|
||||
<h2 class="text-2xl font-bold text-gray-900">All Releases</h2>
|
||||
</div>
|
||||
|
||||
<div class="p-0">
|
||||
{/* Desktop Table */}
|
||||
<div class="hidden md:block">
|
||||
<table class="w-full text-left">
|
||||
<thead class="bg-gray-50 text-gray-500 text-xs font-bold uppercase tracking-widest">
|
||||
<tr>
|
||||
<th class="px-8 py-4">Version</th>
|
||||
<th class="px-8 py-4">Release Date</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-gray-100">
|
||||
{stableReleases.map((release: any) => (
|
||||
<tr class="hover:bg-gray-50/50 transition-colors">
|
||||
<td class="px-8 py-4">
|
||||
<div class="font-bold text-gray-900 text-lg mb-2">{release.version}</div>
|
||||
<div class="flex flex-wrap gap-4">
|
||||
{release.htmlFolderPath && <a href={BASE + release.htmlFolderPath} target="_blank" class="text-purple-600 hover:text-purple-900 font-bold text-sm flex items-center gap-1">▶ Play</a>}
|
||||
{release.cartridgePath && <a href={BASE + release.cartridgePath} target="_blank" class="text-blue-600 hover:text-blue-900 font-bold text-sm flex items-center gap-1">💾 Download</a>}
|
||||
{release.sourcePath && <a href={BASE + release.sourcePath} target="_blank" class="text-green-600 hover:text-green-900 font-bold text-sm flex items-center gap-1">📄 Source</a>}
|
||||
{release.docsFolderPath && <a href={BASE + release.docsFolderPath} target="_blank" class="text-yellow-600 hover:text-yellow-900 font-bold text-sm flex items-center gap-1">📖 Docs</a>}
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-8 py-4 text-gray-500 align-top pt-5">{formatDateTime(release.UpdatedAt)}</td>
|
||||
</tr>
|
||||
))}
|
||||
|
||||
{devReleases.length > 0 && (
|
||||
<tr class="bg-yellow-50/30">
|
||||
<td colspan="2" class="px-8 py-3 text-[10px] font-black text-yellow-700 uppercase tracking-tighter">Development Versions</td>
|
||||
</tr>
|
||||
)}
|
||||
|
||||
{devReleases.map((release: any) => (
|
||||
<tr class="bg-yellow-50/10 hover:bg-yellow-50/30 transition-colors">
|
||||
<td class="px-8 py-4">
|
||||
<div class="font-bold text-yellow-800 text-lg mb-2">{release.version}</div>
|
||||
<div class="flex flex-wrap gap-4">
|
||||
{release.htmlFolderPath && <a href={BASE + release.htmlFolderPath} target="_blank" class="text-purple-600 hover:text-purple-900 font-bold text-sm flex items-center gap-1">▶ Play</a>}
|
||||
{release.cartridgePath && <a href={BASE + release.cartridgePath} target="_blank" class="text-blue-600 hover:text-blue-900 font-bold text-sm flex items-center gap-1">💾 Download</a>}
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-8 py-4 text-gray-500 align-top pt-5">{formatDateTime(release.UpdatedAt)}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{/* Mobile View */}
|
||||
<div class="md:hidden divide-y divide-gray-100">
|
||||
{releases.map((release: any) => (
|
||||
<div class={`p-6 ${release.version.startsWith('dev-') ? 'bg-yellow-50/20' : ''}`}>
|
||||
<div class="flex justify-between items-start mb-4">
|
||||
<div>
|
||||
<div class="font-bold text-gray-900 text-lg">{release.version}</div>
|
||||
<div class="text-gray-500 text-xs mt-1">{formatDateTime(release.UpdatedAt)}</div>
|
||||
</div>
|
||||
{release.version.startsWith('dev-') && (
|
||||
<span class="px-2 py-0.5 bg-yellow-100 text-yellow-800 text-[10px] font-black uppercase rounded">Dev</span>
|
||||
)}
|
||||
</div>
|
||||
<div class="grid grid-cols-2 gap-2">
|
||||
{release.htmlFolderPath && <a href={BASE + release.htmlFolderPath} target="_blank" class="flex items-center justify-center py-2 bg-purple-100 text-purple-700 font-bold rounded-lg text-sm">Play</a>}
|
||||
{release.cartridgePath && <a href={BASE + release.cartridgePath} target="_blank" class="flex items-center justify-center py-2 bg-blue-100 text-blue-700 font-bold rounded-lg text-sm">Download</a>}
|
||||
{release.sourcePath && <a href={BASE + release.sourcePath} target="_blank" class="flex items-center justify-center py-2 bg-green-100 text-green-700 font-bold rounded-lg text-sm">Source</a>}
|
||||
{release.docsFolderPath && <a href={BASE + release.docsFolderPath} target="_blank" class="flex items-center justify-center py-2 bg-yellow-100 text-yellow-700 font-bold rounded-lg text-sm">Docs</a>}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</Layout>
|
||||
|
||||
<style>
|
||||
.status-badge {
|
||||
@apply rounded text-[10px] font-black uppercase tracking-wider;
|
||||
}
|
||||
.status-released { @apply bg-green-500 text-white shadow-lg shadow-green-500/20; }
|
||||
.status-demo { @apply bg-blue-500 text-white shadow-lg shadow-blue-500/20; }
|
||||
.status-development { @apply bg-yellow-500 text-white shadow-lg shadow-yellow-500/20; }
|
||||
.status-archived { @apply bg-gray-500 text-white shadow-lg shadow-gray-500/20; }
|
||||
</style>
|
||||
@@ -156,8 +156,8 @@ const YOUTUBE_CHANNEL_ID = import.meta.env.YOUTUBE_CHANNEL_ID;
|
||||
▶ Play in Browser
|
||||
</a>
|
||||
)}
|
||||
<a href="/catalog" class="featured-btn-secondary">
|
||||
View in Catalog
|
||||
<a href={`/catalog/${highlightedSoftware.software.name}`} class="featured-btn-secondary">
|
||||
View Project Details
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user