countdowner to frontend
This commit is contained in:
Generated
+12
-1
@@ -9,7 +9,11 @@
|
||||
"version": "0.0.1",
|
||||
"dependencies": {
|
||||
"@astrojs/tailwind": "^6.0.2",
|
||||
"astro": "^5.17.1"
|
||||
"astro": "^5.17.1",
|
||||
"js-yaml": "^4.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/js-yaml": "^4.0.9"
|
||||
}
|
||||
},
|
||||
"node_modules/@alloc/quick-lru": {
|
||||
@@ -1587,6 +1591,13 @@
|
||||
"@types/unist": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/js-yaml": {
|
||||
"version": "4.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz",
|
||||
"integrity": "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/mdast": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz",
|
||||
|
||||
@@ -10,6 +10,10 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@astrojs/tailwind": "^6.0.2",
|
||||
"astro": "^5.17.1"
|
||||
"astro": "^5.17.1",
|
||||
"js-yaml": "^4.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/js-yaml": "^4.0.9"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
events:
|
||||
- name: "Projekt deadline"
|
||||
date: "2026-03-15T10:00:00Z"
|
||||
- name: "Summer Vacation"
|
||||
date: "2026-06-20T16:00:00Z"
|
||||
- name: "Christmas Party"
|
||||
date: "2026-12-22T19:00:00Z"
|
||||
- name: "Tech Conference"
|
||||
date: "2027-02-01T09:00:00Z"
|
||||
@@ -1,54 +1,198 @@
|
||||
---
|
||||
import Layout from '../layouts/Layout.astro';
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import yaml from 'js-yaml';
|
||||
|
||||
interface Event {
|
||||
name: string;
|
||||
date: string;
|
||||
}
|
||||
|
||||
interface EventData {
|
||||
events: Event[];
|
||||
}
|
||||
|
||||
let nextEvent: (Event & { dateISO: string; dateText: string }) | null = null;
|
||||
let followingEvents: (Event & { dateText: string })[] = [];
|
||||
|
||||
try {
|
||||
const rootDir = process.cwd();
|
||||
let eventsPath = path.join(rootDir, 'src', 'events.yaml');
|
||||
if (!fs.existsSync(eventsPath)) {
|
||||
eventsPath = path.join(rootDir, 'src', 'events-example.yaml');
|
||||
}
|
||||
|
||||
if (fs.existsSync(eventsPath)) {
|
||||
const fileContents = fs.readFileSync(eventsPath, 'utf8');
|
||||
const data = yaml.load(fileContents) as EventData;
|
||||
|
||||
if (data && data.events) {
|
||||
const now = new Date();
|
||||
const futureEvents = data.events
|
||||
.map(e => ({
|
||||
...e,
|
||||
dateObj: new Date(e.date)
|
||||
}))
|
||||
.filter(e => e.dateObj > now)
|
||||
.sort((a, b) => a.dateObj.getTime() - b.dateObj.getTime());
|
||||
|
||||
if (futureEvents.length > 0) {
|
||||
const first = futureEvents[0];
|
||||
nextEvent = {
|
||||
name: first.name,
|
||||
date: first.date,
|
||||
dateISO: first.dateObj.toISOString(),
|
||||
dateText: first.dateObj.toLocaleString('en-US', {
|
||||
year: 'numeric', month: 'short', day: 'numeric',
|
||||
hour: '2-digit', minute: '2-digit'
|
||||
})
|
||||
};
|
||||
|
||||
followingEvents = futureEvents.slice(1).map(e => ({
|
||||
name: e.name,
|
||||
date: e.date,
|
||||
dateText: e.dateObj.toLocaleString('en-US', {
|
||||
year: 'numeric', month: 'short', day: 'numeric',
|
||||
hour: '2-digit', minute: '2-digit'
|
||||
})
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Failed to load events:', e);
|
||||
}
|
||||
---
|
||||
|
||||
<Layout>
|
||||
<div class="space-y-12 py-12">
|
||||
<!-- Intro Section -->
|
||||
<section class="text-center max-w-3xl mx-auto px-4">
|
||||
<h1 class="text-5xl font-bold mb-4">Teletype Games</h1>
|
||||
<p class="text-xl text-gray-700">
|
||||
Teletype Games is an independent game development community built on creative freedom, equality, and an open-source mindset. Our goal is to create experimental and full-fledged games with short development cycles.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<!-- Sections Grid -->
|
||||
<section class="max-w-6xl mx-auto px-4 grid grid-cols-1 md:grid-cols-2 gap-8">
|
||||
<!-- Catalog Section -->
|
||||
<div class="bg-white p-8 rounded-lg shadow-lg text-center flex flex-col h-full">
|
||||
<h2 class="text-3xl font-bold mb-3">Catalog</h2>
|
||||
<p class="mb-6 min-h-[150px]">Here you can find our games. Discover our creations for TIC-80 and other platforms, many of which you can try directly in your browser.</p>
|
||||
<a href="/catalog" class="inline-block bg-purple-600 hover:bg-purple-700 text-white font-bold py-3 px-8 rounded-lg text-lg transition-colors mt-auto">
|
||||
Browse Games
|
||||
</a>
|
||||
<div class="bg-gray-50 min-h-screen pb-20">
|
||||
<!-- Header Section (Inspired by News) -->
|
||||
<header class="relative overflow-hidden bg-slate-900 py-24 text-white">
|
||||
<div class="absolute inset-0 opacity-30">
|
||||
<div class="absolute -top-24 -left-24 h-96 w-96 rounded-full bg-indigo-600 blur-3xl"></div>
|
||||
<div class="absolute -bottom-24 -right-24 h-96 w-96 rounded-full bg-purple-600 blur-3xl"></div>
|
||||
</div>
|
||||
|
||||
<!-- Wiki Section -->
|
||||
<div class="bg-white p-8 rounded-lg shadow-lg text-center flex flex-col h-full">
|
||||
<h2 class="text-3xl font-bold mb-3">Wiki</h2>
|
||||
<p class="mb-6 min-h-[150px]">We gather our public interest development knowledge here. Read through technical descriptions and development logs.</p>
|
||||
<a href="https://wiki.teletype.hu" target="_blank" rel="noopener noreferrer" class="inline-block bg-green-600 hover:bg-green-700 text-white font-bold py-3 px-8 rounded-lg text-lg transition-colors mt-auto">
|
||||
Knowledge Base
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Git Section -->
|
||||
<div class="bg-white p-8 rounded-lg shadow-lg text-center flex flex-col h-full">
|
||||
<h2 class="text-3xl font-bold mb-3">Git Repos</h2>
|
||||
<p class="mb-6 min-h-[150px]">All our projects are open source. Browse our code, study our solutions, or even participate in the development.</p>
|
||||
<a href="https://git.teletype.hu" target="_blank" rel="noopener noreferrer" class="inline-block bg-gray-800 hover:bg-gray-900 text-white font-bold py-3 px-8 rounded-lg text-lg transition-colors mt-auto">
|
||||
Gitea
|
||||
</a>
|
||||
|
||||
<div class="relative max-w-5xl mx-auto px-4 text-center">
|
||||
<div class="inline-block px-3 py-1 rounded-full bg-indigo-500/20 border border-indigo-400/30 text-indigo-300 text-sm font-medium mb-6 backdrop-blur-sm">
|
||||
Welcome to
|
||||
</div>
|
||||
<h1 class="text-5xl md:text-6xl font-extrabold tracking-tight mb-6">
|
||||
Teletype <span class="text-transparent bg-clip-text bg-gradient-to-r from-violet-400 to-fuchsia-400">Games</span>
|
||||
</h1>
|
||||
<p class="text-lg md:text-xl text-slate-300 max-w-2xl mx-auto leading-relaxed">
|
||||
Teletype Games is an independent game development community built on creative freedom, equality, and an open-source mindset. Our goal is to create experimental and full-fledged games with short development cycles.
|
||||
</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="max-w-6xl mx-auto px-4 -mt-12 relative z-10">
|
||||
<!-- Countdown Section -->
|
||||
<div class="bg-white p-8 rounded-lg shadow-lg text-center flex flex-col h-full">
|
||||
<h2 class="text-3xl font-bold mb-3">Countdown</h2>
|
||||
<p class="mb-6 min-h-[150px]">Stay up to date with our next game release. The countdown shows how much time is left until the next premiere.</p>
|
||||
<a href="https://countdown.teletype.hu" target="_blank" rel="noopener noreferrer" class="inline-block bg-blue-600 hover:bg-blue-700 text-white font-bold py-3 px-8 rounded-lg text-lg transition-colors mt-auto">
|
||||
Countdown
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
{nextEvent && (
|
||||
<section class="mb-12">
|
||||
<div class="bg-white rounded-2xl shadow-xl overflow-hidden border border-gray-100 p-8 md:p-12 text-center transition-all duration-300">
|
||||
<h2 class="text-2xl font-bold text-gray-400 uppercase tracking-widest mb-2">{nextEvent.name}</h2>
|
||||
<div id="countdown" data-date={nextEvent.dateISO} class="text-5xl md:text-7xl font-mono font-black text-transparent bg-clip-text bg-gradient-to-r from-violet-600 to-fuchsia-600 my-6">
|
||||
-- : -- : -- : --
|
||||
</div>
|
||||
<p class="text-gray-500 text-lg">Starts on: <span class="font-semibold">{nextEvent.dateText}</span></p>
|
||||
|
||||
{followingEvents.length > 0 && (
|
||||
<div class="mt-12 pt-12 border-t border-gray-100 text-left max-w-2xl mx-auto">
|
||||
<h3 class="text-xl font-bold text-gray-900 mb-6">Upcoming Events</h3>
|
||||
<div class="space-y-4">
|
||||
{followingEvents.map(event => (
|
||||
<div class="flex items-center justify-between p-4 bg-gray-50 rounded-xl border border-gray-100">
|
||||
<span class="font-bold text-gray-800">{event.name}</span>
|
||||
<span class="text-sm text-gray-500 font-mono">{event.dateText}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
)}
|
||||
|
||||
<!-- Navigation Grid -->
|
||||
<section class="grid grid-cols-1 md:grid-cols-3 gap-8">
|
||||
<!-- Catalog Section -->
|
||||
<div class="group bg-white p-8 rounded-2xl border border-gray-200 shadow-sm hover:shadow-xl hover:border-indigo-300 transition-all duration-300 flex flex-col h-full">
|
||||
<div class="w-14 h-14 bg-purple-50 rounded-xl flex items-center justify-center mb-6 group-hover:bg-purple-100 transition-colors">
|
||||
<span class="text-3xl">🎮</span>
|
||||
</div>
|
||||
<h2 class="text-2xl font-bold text-gray-900 mb-3">Catalog</h2>
|
||||
<p class="text-gray-600 mb-6 flex-grow leading-relaxed">Here you can find our games. Discover our creations for TIC-80 and other platforms, many of which you can try directly in your browser.</p>
|
||||
<a href="/catalog" class="inline-flex items-center justify-center bg-purple-600 hover:bg-purple-700 text-white font-bold py-3 px-8 rounded-xl transition-all shadow-lg hover:shadow-purple-200">
|
||||
Browse Games
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Wiki Section -->
|
||||
<div class="group bg-white p-8 rounded-2xl border border-gray-200 shadow-sm hover:shadow-xl hover:border-green-300 transition-all duration-300 flex flex-col h-full">
|
||||
<div class="w-14 h-14 bg-green-50 rounded-xl flex items-center justify-center mb-6 group-hover:bg-green-100 transition-colors">
|
||||
<span class="text-3xl">📚</span>
|
||||
</div>
|
||||
<h2 class="text-2xl font-bold text-gray-900 mb-3">Wiki</h2>
|
||||
<p class="text-gray-600 mb-6 flex-grow leading-relaxed">We gather our public interest development knowledge here. Read through technical descriptions and development logs.</p>
|
||||
<a href="https://wiki.teletype.hu" target="_blank" rel="noopener noreferrer" class="inline-flex items-center justify-center bg-green-600 hover:bg-green-700 text-white font-bold py-3 px-8 rounded-xl transition-all shadow-lg hover:shadow-green-200">
|
||||
Knowledge Base
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Git Section -->
|
||||
<div class="group bg-white p-8 rounded-2xl border border-gray-200 shadow-sm hover:shadow-xl hover:border-slate-300 transition-all duration-300 flex flex-col h-full">
|
||||
<div class="w-14 h-14 bg-slate-50 rounded-xl flex items-center justify-center mb-6 group-hover:bg-slate-100 transition-colors">
|
||||
<span class="text-3xl">💻</span>
|
||||
</div>
|
||||
<h2 class="text-2xl font-bold text-gray-900 mb-3">Git Repos</h2>
|
||||
<p class="text-gray-600 mb-6 flex-grow leading-relaxed">All our projects are open source. Browse our code, study our solutions, or even participate in the development.</p>
|
||||
<a href="https://git.teletype.hu" target="_blank" rel="noopener noreferrer" class="inline-flex items-center justify-center bg-slate-800 hover:bg-slate-900 text-white font-bold py-3 px-8 rounded-xl transition-all shadow-lg hover:shadow-slate-200">
|
||||
Gitea
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</div>
|
||||
</Layout>
|
||||
|
||||
<script>
|
||||
function updateCountdown() {
|
||||
const countdownElement = document.getElementById('countdown');
|
||||
if (!countdownElement) return;
|
||||
|
||||
const targetDateStr = countdownElement.getAttribute('data-date');
|
||||
if (!targetDateStr) return;
|
||||
|
||||
const targetDate = new Date(targetDateStr).getTime();
|
||||
|
||||
function update() {
|
||||
const now = Date.now();
|
||||
const distance = targetDate - now;
|
||||
|
||||
if (distance < 0) {
|
||||
countdownElement.innerHTML = "LIVE NOW!";
|
||||
return;
|
||||
}
|
||||
|
||||
const days = Math.floor(distance / (1000 * 60 * 60 * 24));
|
||||
const hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
|
||||
const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
|
||||
const seconds = Math.floor((distance % (1000 * 60)) / 1000);
|
||||
|
||||
const d = String(days).padStart(2, '0');
|
||||
const h = String(hours).padStart(2, '0');
|
||||
const m = String(minutes).padStart(2, '0');
|
||||
const s = String(seconds).padStart(2, '0');
|
||||
|
||||
countdownElement.innerHTML = `${d}d ${h}h ${m}m ${s}s`;
|
||||
}
|
||||
|
||||
update();
|
||||
setInterval(update, 1000);
|
||||
}
|
||||
|
||||
// Initialize countdown
|
||||
updateCountdown();
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user