retro mode
This commit is contained in:
@@ -1,39 +1,47 @@
|
||||
<template>
|
||||
<div class="win-app">
|
||||
<header class="win-menubar">
|
||||
<span class="win-menu-logo">📟 Teletype Games</span>
|
||||
<div :class="{ 'retro-mode': isRetroMode }" class="app-root">
|
||||
<header class="bg-gray-800 text-white p-4 flex justify-between items-center relative">
|
||||
<RouterLink to="/" class="text-xl font-bold">Teletype Games</RouterLink>
|
||||
|
||||
<nav class="win-menu-items hidden md:flex">
|
||||
<RouterLink to="/" class="win-menu-item">Home</RouterLink>
|
||||
<RouterLink to="/catalog" class="win-menu-item">Catalog</RouterLink>
|
||||
<RouterLink to="/blog" class="win-menu-item">Blog</RouterLink>
|
||||
<RouterLink to="/howtos" class="win-menu-item">How-tos</RouterLink>
|
||||
<RouterLink to="/code" class="win-menu-item">Code</RouterLink>
|
||||
<RouterLink to="/team" class="win-menu-item">Team</RouterLink>
|
||||
<RouterLink to="/contact" class="win-menu-item">Contact</RouterLink>
|
||||
<!-- Desktop Navigation -->
|
||||
<nav class="hidden md:flex space-x-4">
|
||||
<RouterLink to="/" class="p-2 hover:text-purple-300 transition-colors duration-200">Home</RouterLink>
|
||||
<RouterLink to="/catalog" class="p-2 hover:text-purple-300 transition-colors duration-200">Catalog</RouterLink>
|
||||
<RouterLink to="/blog" class="p-2 hover:text-purple-300 transition-colors duration-200">Blog</RouterLink>
|
||||
<RouterLink to="/howtos" class="p-2 hover:text-purple-300 transition-colors duration-200">How-tos</RouterLink>
|
||||
<RouterLink to="/code" class="p-2 hover:text-purple-300 transition-colors duration-200">Code</RouterLink>
|
||||
<RouterLink to="/team" class="p-2 hover:text-purple-300 transition-colors duration-200">Team</RouterLink>
|
||||
<RouterLink to="/contact" class="p-2 hover:text-purple-300 transition-colors duration-200">Contact us</RouterLink>
|
||||
</nav>
|
||||
|
||||
<button @click="toggleMenu" class="md:hidden win-btn mobile-menu-toggle">☰ Menu</button>
|
||||
<!-- Hamburger Button (Mobile only) -->
|
||||
<button @click="toggleMenu" class="md:hidden p-2 focus:outline-none focus:ring-2 focus:ring-purple-500 rounded-md">
|
||||
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"></path>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<!-- Mobile Navigation -->
|
||||
<nav v-show="menuOpen" class="md:hidden absolute top-full left-0 w-full bg-gray-800 flex flex-col items-center py-4 space-y-2 z-50">
|
||||
<RouterLink to="/" class="block p-2 w-full text-center hover:bg-gray-700 transition-colors duration-200">Home</RouterLink>
|
||||
<RouterLink to="/catalog" class="block p-2 w-full text-center hover:bg-gray-700 transition-colors duration-200">Catalog</RouterLink>
|
||||
<RouterLink to="/blog" class="block p-2 w-full text-center hover:bg-gray-700 transition-colors duration-200">Blog</RouterLink>
|
||||
<RouterLink to="/howtos" class="block p-2 w-full text-center hover:bg-gray-700 transition-colors duration-200">How-tos</RouterLink>
|
||||
<RouterLink to="/code" class="block p-2 w-full text-center hover:bg-gray-700 transition-colors duration-200">Code</RouterLink>
|
||||
<RouterLink to="/team" class="block p-2 w-full text-center hover:bg-gray-700 transition-colors duration-200">Team</RouterLink>
|
||||
<RouterLink to="/contact" class="block p-2 w-full text-center hover:bg-gray-700 transition-colors duration-200">Contact us</RouterLink>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<nav v-show="menuOpen" class="md:hidden win-mobile-menu">
|
||||
<RouterLink to="/" class="win-mobile-item">Home</RouterLink>
|
||||
<RouterLink to="/catalog" class="win-mobile-item">Catalog</RouterLink>
|
||||
<RouterLink to="/blog" class="win-mobile-item">Blog</RouterLink>
|
||||
<RouterLink to="/howtos" class="win-mobile-item">How-tos</RouterLink>
|
||||
<RouterLink to="/code" class="win-mobile-item">Code</RouterLink>
|
||||
<RouterLink to="/team" class="win-mobile-item">Team</RouterLink>
|
||||
<RouterLink to="/contact" class="win-mobile-item">Contact</RouterLink>
|
||||
</nav>
|
||||
|
||||
<main class="win-main">
|
||||
<main>
|
||||
<slot />
|
||||
</main>
|
||||
|
||||
<footer class="win-statusbar">
|
||||
<div class="win-status-panel">Teletype Games © 2024 — Independent Game Development Community</div>
|
||||
<div class="win-status-panel" style="flex: 0; white-space: nowrap;">Open Source</div>
|
||||
</footer>
|
||||
<div class="retro-toggle-bar">
|
||||
<button class="retro-toggle-btn" @click="toggleRetroMode">
|
||||
🖥 {{ isRetroMode ? 'Exit Retro Mode' : 'Retro Mode' }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -41,60 +49,42 @@
|
||||
import { ref, watch } from 'vue'
|
||||
import { RouterLink, useRoute } from 'vue-router'
|
||||
|
||||
function getCookie(name: string): string | null {
|
||||
const match = document.cookie.match(new RegExp('(?:^|; )' + name + '=([^;]*)'))
|
||||
return match ? decodeURIComponent(match[1]) : null
|
||||
}
|
||||
|
||||
function setCookie(name: string, value: string, days = 365) {
|
||||
const expires = new Date(Date.now() + days * 864e5).toUTCString()
|
||||
document.cookie = `${name}=${encodeURIComponent(value)};expires=${expires};path=/`
|
||||
}
|
||||
|
||||
const menuOpen = ref(false)
|
||||
const route = useRoute()
|
||||
const isRetroMode = ref(getCookie('retro-mode') === '1')
|
||||
|
||||
function toggleMenu() {
|
||||
menuOpen.value = !menuOpen.value
|
||||
}
|
||||
|
||||
function toggleRetroMode() {
|
||||
isRetroMode.value = !isRetroMode.value
|
||||
setCookie('retro-mode', isRetroMode.value ? '1' : '0')
|
||||
}
|
||||
|
||||
watch(() => route.path, () => {
|
||||
menuOpen.value = false
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.win-app {
|
||||
.app-root {
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
font-family: Tahoma, "MS Sans Serif", Arial, sans-serif;
|
||||
background: #D4D0C8;
|
||||
}
|
||||
|
||||
.win-main {
|
||||
.app-root > main {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.mobile-menu-toggle {
|
||||
margin-left: auto;
|
||||
margin-right: 4px;
|
||||
min-width: auto;
|
||||
padding: 2px 8px;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.win-mobile-menu {
|
||||
background: #D4D0C8;
|
||||
border-bottom: 1px solid #808080;
|
||||
box-shadow: 0 1px 0 #fff;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.win-mobile-item {
|
||||
padding: 5px 12px;
|
||||
color: #000;
|
||||
text-decoration: none;
|
||||
display: block;
|
||||
border-bottom: 1px solid #C0BDB8;
|
||||
font-size: 12px;
|
||||
font-family: Tahoma, Arial, sans-serif;
|
||||
}
|
||||
|
||||
.win-mobile-item:hover,
|
||||
.win-mobile-item.router-link-exact-active {
|
||||
background: #000080;
|
||||
color: #fff;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -2,5 +2,6 @@ import { createApp } from 'vue'
|
||||
import { router } from './router/index.router'
|
||||
import App from './App.vue'
|
||||
import './styles/global.css'
|
||||
import './styles/retro.css'
|
||||
|
||||
createApp(App).use(router).mount('#app')
|
||||
|
||||
@@ -1,58 +1,75 @@
|
||||
<template>
|
||||
<div class="main-container">
|
||||
<div class="win-window">
|
||||
<div class="win-titlebar">
|
||||
<span class="win-titlebar-text">📰 Developer Blog</span>
|
||||
<div class="win-titlebar-btns">
|
||||
<button class="win-titlebar-btn">_</button>
|
||||
<button class="win-titlebar-btn">□</button>
|
||||
<button class="win-titlebar-btn">×</button>
|
||||
</div>
|
||||
<div class="blog-container">
|
||||
<header class="blog-header">
|
||||
<div class="blog-header-decor">
|
||||
<div class="hero-decor-blob -top-24 -left-24 h-96 w-96 bg-purple-600"></div>
|
||||
<div class="hero-decor-blob -bottom-24 -right-24 h-96 w-96 bg-blue-600"></div>
|
||||
</div>
|
||||
|
||||
<div class="win-body" style="padding: 4px 8px 6px;">
|
||||
<p style="margin: 0 0 2px; font-size: 12px; color: #404040;">
|
||||
<div class="hero-container">
|
||||
<div class="hero-badge">Community Stories</div>
|
||||
<h1 class="hero-title">
|
||||
Developer <span class="text-transparent bg-clip-text bg-gradient-to-r from-blue-400 to-purple-400">Blog</span>
|
||||
</h1>
|
||||
<p class="hero-subtitle mb-10">
|
||||
News, updates, and behind-the-scenes stories from the Teletype Games community.
|
||||
</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="win-body" style="padding: 0;">
|
||||
|
||||
<div v-if="error" class="win-notice-error" style="margin: 8px;">
|
||||
<span>⚠</span>
|
||||
<div>
|
||||
<strong>Failed to connect to Wiki</strong><br>
|
||||
<span style="font-size: 11px;">{{ error }}</span>
|
||||
</div>
|
||||
<main class="blog-main">
|
||||
<div v-if="error" class="error-banner" role="alert">
|
||||
<span class="text-2xl">⚠️</span>
|
||||
<div>
|
||||
<h3 class="error-banner-title">Failed to connect to Wiki</h3>
|
||||
<p class="error-banner-desc">{{ error }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else-if="!loading && blogPages.length === 0" class="empty-state">
|
||||
<div style="font-size: 32px; margin-bottom: 8px;">📭</div>
|
||||
<div style="font-weight: bold; margin-bottom: 4px;">No blog posts found</div>
|
||||
<div style="font-size: 11px; color: #404040;">We haven't published any blog posts yet. Check back soon!</div>
|
||||
</div>
|
||||
<div v-else-if="!loading && blogPages.length === 0" class="empty-state">
|
||||
<div class="empty-state-icon">📭</div>
|
||||
<h2 class="empty-state-title">No blog posts found</h2>
|
||||
<p class="empty-state-desc">We haven't published any blog posts yet. Check back soon!</p>
|
||||
</div>
|
||||
|
||||
<div v-else>
|
||||
<article v-for="page in blogPages" :key="page.id" class="blog-post-row">
|
||||
<div class="blog-post-inner">
|
||||
<div class="blog-post-meta-row">
|
||||
<span v-if="isNew(page.createdAt)" class="new-badge">★ New</span>
|
||||
<span class="blog-post-date">{{ formatDateTime(page.createdAt) }}</span>
|
||||
</div>
|
||||
<RouterLink :to="getPermalink(page.path)" class="blog-post-title-link">
|
||||
{{ page.title }}
|
||||
</RouterLink>
|
||||
<div v-if="page.description" class="blog-post-desc">{{ page.description }}</div>
|
||||
<div v-else-if="page.content" class="blog-post-desc">{{ getCleanPreview(page.content) }}</div>
|
||||
<div class="blog-post-footer">
|
||||
<RouterLink :to="getPermalink(page.path)" class="win-btn win-btn-sm">Read more →</RouterLink>
|
||||
<div v-else class="blog-posts-list">
|
||||
<article v-for="page in blogPages" :key="page.id" class="blog-post-card">
|
||||
<div class="blog-post-content">
|
||||
<div class="blog-post-meta">
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="blog-post-timestamp">
|
||||
<span v-if="isNew(page.createdAt)" class="new-post-badge">
|
||||
<span class="new-post-dot"></span>
|
||||
New Post
|
||||
</span>
|
||||
<span>{{ formatDateTime(page.createdAt) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<h2 class="blog-post-title">
|
||||
<RouterLink :to="getPermalink(page.path)" class="hover:text-indigo-600 transition-colors">
|
||||
{{ page.title }}
|
||||
</RouterLink>
|
||||
</h2>
|
||||
|
||||
<div class="blog-post-preview">
|
||||
<p v-if="page.description" class="blog-post-description">{{ page.description }}</p>
|
||||
<p v-if="page.content" class="blog-post-body">{{ getCleanPreview(page.content) }}</p>
|
||||
</div>
|
||||
|
||||
<div class="mt-6">
|
||||
<RouterLink :to="getPermalink(page.path)" class="read-more-btn">
|
||||
Read more
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 ml-1" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path fill-rule="evenodd" d="M10.293 3.293a1 1 0 011.414 0l6 6a1 1 0 010 1.414l-6 6a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-4.293-4.293a1 1 0 010-1.414z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
</RouterLink>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -78,7 +95,7 @@ function getPermalink(path: string): string {
|
||||
|
||||
function getCleanPreview(content: string): string {
|
||||
if (!content) return ''
|
||||
return content.replace(/[#*`_\[\]()]/g, '').trim().slice(0, 250) + '...'
|
||||
return content.replace(/[#*`_\[\]()]/g, '').trim().slice(0, 300) + '...'
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
@@ -93,61 +110,69 @@ onMounted(async () => {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.blog-container {
|
||||
@apply bg-gray-50 min-h-screen pb-20;
|
||||
}
|
||||
.blog-header {
|
||||
@apply relative overflow-hidden py-24 text-white text-center bg-indigo-900;
|
||||
}
|
||||
.blog-header-decor {
|
||||
@apply absolute inset-0 opacity-30;
|
||||
}
|
||||
.blog-main {
|
||||
@apply max-w-5xl mx-auto px-4 md:px-8 -mt-12 relative z-10;
|
||||
}
|
||||
.banner-base {
|
||||
@apply max-w-7xl mx-auto border-l-4 p-6 rounded-r-xl shadow-lg mb-12 flex items-start gap-4;
|
||||
}
|
||||
.error-banner { @apply banner-base bg-red-50 border-red-500; }
|
||||
.error-banner-title { @apply text-red-800 font-bold text-lg; }
|
||||
.error-banner-desc { @apply text-red-700 mt-1; }
|
||||
.empty-state {
|
||||
text-align: center;
|
||||
padding: 24px;
|
||||
color: #404040;
|
||||
font-size: 12px;
|
||||
@apply max-w-7xl mx-auto bg-white rounded-2xl shadow-xl p-12 text-center border border-gray-100;
|
||||
}
|
||||
.blog-post-row {
|
||||
border-bottom: 1px solid #D0D0D0;
|
||||
.empty-state-icon { @apply text-6xl mb-4; }
|
||||
.empty-state-title { @apply text-2xl font-bold text-gray-900 mb-2; }
|
||||
.empty-state-desc { @apply text-gray-500 max-w-md mx-auto; }
|
||||
.blog-posts-list {
|
||||
@apply flex flex-col gap-12;
|
||||
}
|
||||
.blog-post-row:last-child { border-bottom: none; }
|
||||
.blog-post-inner {
|
||||
padding: 8px 10px;
|
||||
.blog-post-card {
|
||||
@apply bg-white rounded-2xl shadow-xl border border-gray-100 overflow-hidden;
|
||||
}
|
||||
.blog-post-row:hover .blog-post-inner {
|
||||
background: #EEF0F8;
|
||||
.blog-post-content {
|
||||
@apply p-6 md:p-10;
|
||||
}
|
||||
.blog-post-meta-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
margin-bottom: 3px;
|
||||
.blog-post-meta {
|
||||
@apply flex items-center justify-between mb-4;
|
||||
}
|
||||
.new-badge {
|
||||
font-size: 10px;
|
||||
font-weight: bold;
|
||||
background: #C8F0C8;
|
||||
color: #007000;
|
||||
border: 1px solid #009000;
|
||||
padding: 0 4px;
|
||||
.blog-post-timestamp {
|
||||
@apply flex items-center gap-2 text-xs font-semibold uppercase tracking-wider text-gray-400;
|
||||
}
|
||||
.blog-post-date {
|
||||
font-size: 11px;
|
||||
color: #808080;
|
||||
font-family: "Courier New", Courier, monospace;
|
||||
.new-post-badge {
|
||||
@apply flex items-center gap-1 text-green-600 bg-green-50 px-2 py-0.5 rounded-full border border-green-100;
|
||||
}
|
||||
.blog-post-title-link {
|
||||
display: block;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
color: #000080;
|
||||
text-decoration: underline;
|
||||
margin-bottom: 4px;
|
||||
line-height: 1.3;
|
||||
.new-post-dot {
|
||||
@apply w-1.5 h-1.5 rounded-full bg-green-500 animate-pulse;
|
||||
}
|
||||
.blog-post-title-link:hover { color: #0000FF; }
|
||||
.blog-post-desc {
|
||||
font-size: 12px;
|
||||
color: #404040;
|
||||
margin-bottom: 8px;
|
||||
line-height: 1.5;
|
||||
max-height: 4em;
|
||||
overflow: hidden;
|
||||
.blog-post-title {
|
||||
@apply text-2xl md:text-3xl font-black text-gray-900 mb-4 leading-tight;
|
||||
}
|
||||
.blog-post-footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
.blog-post-preview {
|
||||
@apply relative overflow-hidden;
|
||||
max-height: 8rem;
|
||||
}
|
||||
.blog-post-preview::after {
|
||||
content: "";
|
||||
@apply absolute bottom-0 left-0 w-full h-16 bg-gradient-to-b from-transparent to-white pointer-events-none;
|
||||
}
|
||||
.blog-post-description {
|
||||
@apply text-lg text-gray-800 font-bold mb-2 leading-relaxed;
|
||||
}
|
||||
.blog-post-body {
|
||||
@apply text-base text-gray-500 font-medium leading-relaxed;
|
||||
}
|
||||
.read-more-btn {
|
||||
@apply inline-flex items-center text-indigo-600 font-bold hover:text-indigo-800 transition-colors;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,48 +1,41 @@
|
||||
<template>
|
||||
<div class="main-container">
|
||||
<div class="win-window">
|
||||
<div class="win-titlebar">
|
||||
<span class="win-titlebar-text">📰 {{ pageContent ? pageContent.title : 'Blog Post' }}</span>
|
||||
<div class="win-titlebar-btns">
|
||||
<button class="win-titlebar-btn">_</button>
|
||||
<button class="win-titlebar-btn">□</button>
|
||||
<button class="win-titlebar-btn">×</button>
|
||||
<div class="blog-container">
|
||||
<header class="blog-header">
|
||||
<div class="blog-header-decor">
|
||||
<div class="hero-decor-blob -top-24 -left-24 h-96 w-96 bg-purple-600"></div>
|
||||
<div class="hero-decor-blob -bottom-24 -right-24 h-96 w-96 bg-blue-600"></div>
|
||||
</div>
|
||||
|
||||
<div class="post-hero-container">
|
||||
<RouterLink to="/blog" class="back-link">← Back to Blog</RouterLink>
|
||||
<template v-if="pageContent">
|
||||
<h1 class="hero-title mt-4">{{ pageContent.title }}</h1>
|
||||
<p class="hero-subtitle mb-4">{{ pageContent.description }}</p>
|
||||
<div class="blog-post-timestamp text-indigo-200">{{ formatDateTime(pageContent.createdAt) }}</div>
|
||||
</template>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="blog-main">
|
||||
<div v-if="error" class="error-banner" role="alert">
|
||||
<span class="text-2xl">⚠️</span>
|
||||
<div>
|
||||
<h3 class="error-banner-title">Error</h3>
|
||||
<p class="error-banner-desc">{{ error }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="win-toolbar">
|
||||
<RouterLink to="/blog" class="win-btn win-btn-sm">← Back to Blog</RouterLink>
|
||||
<span v-if="pageContent" class="post-date">
|
||||
{{ formatDateTime(pageContent.createdAt) }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="win-body" style="padding: 0;">
|
||||
|
||||
<div v-if="error" class="win-notice-error" style="margin: 8px;">
|
||||
<span>⚠</span>
|
||||
<div><strong>Error</strong><br><span style="font-size: 11px;">{{ error }}</span></div>
|
||||
</div>
|
||||
|
||||
<article v-else-if="pageContent" class="post-content">
|
||||
<div v-if="pageContent.description" class="post-description">
|
||||
{{ pageContent.description }}
|
||||
</div>
|
||||
<hr class="win-separator" style="margin: 8px 0;">
|
||||
<div
|
||||
v-if="pageContent.render"
|
||||
class="wiki-content"
|
||||
v-html="pageContent.render"
|
||||
/>
|
||||
<div v-else class="post-empty">No content available for this post.</div>
|
||||
</article>
|
||||
|
||||
<div v-else-if="loading" class="post-loading">
|
||||
Loading...
|
||||
<article v-else-if="pageContent" class="blog-post-card">
|
||||
<div class="blog-post-content">
|
||||
<div v-if="pageContent.render" class="wiki-content max-w-none text-gray-700 leading-relaxed" v-html="pageContent.render" />
|
||||
<div v-else class="blog-post-fallback">No content available for this post.</div>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<div v-else-if="loading" class="blog-post-card">
|
||||
<div class="blog-post-content text-center text-gray-400 py-12">Loading...</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -76,32 +69,42 @@ onMounted(async () => {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.post-date {
|
||||
font-size: 11px;
|
||||
color: #404040;
|
||||
font-family: "Courier New", Courier, monospace;
|
||||
margin-left: 8px;
|
||||
.blog-container {
|
||||
@apply bg-gray-50 min-h-screen pb-20;
|
||||
}
|
||||
.post-content {
|
||||
padding: 10px 12px;
|
||||
.blog-header {
|
||||
@apply relative overflow-hidden py-24 text-white text-center bg-indigo-900;
|
||||
}
|
||||
.post-description {
|
||||
font-size: 13px;
|
||||
font-weight: bold;
|
||||
color: #000080;
|
||||
margin-bottom: 8px;
|
||||
line-height: 1.4;
|
||||
.blog-header-decor {
|
||||
@apply absolute inset-0 opacity-30;
|
||||
}
|
||||
.post-empty {
|
||||
padding: 16px;
|
||||
text-align: center;
|
||||
color: #808080;
|
||||
font-size: 12px;
|
||||
.post-hero-container {
|
||||
@apply relative z-10 max-w-4xl mx-auto px-4;
|
||||
}
|
||||
.post-loading {
|
||||
padding: 16px;
|
||||
text-align: center;
|
||||
color: #404040;
|
||||
font-size: 12px;
|
||||
.back-link {
|
||||
@apply inline-block text-indigo-300 hover:text-white transition-colors font-medium;
|
||||
}
|
||||
.hero-title {
|
||||
@apply text-4xl md:text-5xl font-black mb-4 leading-tight;
|
||||
}
|
||||
.hero-subtitle {
|
||||
@apply text-xl text-indigo-100 font-medium;
|
||||
}
|
||||
.blog-post-timestamp {
|
||||
@apply text-sm font-semibold uppercase tracking-wider;
|
||||
}
|
||||
.blog-main {
|
||||
@apply max-w-4xl mx-auto px-4 md:px-8 -mt-12 relative z-10;
|
||||
}
|
||||
.blog-post-card {
|
||||
@apply bg-white rounded-2xl shadow-xl border border-gray-100 overflow-hidden;
|
||||
}
|
||||
.blog-post-content {
|
||||
@apply p-6 md:p-12;
|
||||
}
|
||||
.error-banner {
|
||||
@apply max-w-7xl mx-auto bg-red-50 border-l-4 border-red-500 p-6 rounded-r-xl shadow-lg mb-12 flex items-start gap-4;
|
||||
}
|
||||
.error-banner-title { @apply text-red-800 font-bold text-lg; }
|
||||
.error-banner-desc { @apply text-red-700 mt-1; }
|
||||
</style>
|
||||
|
||||
@@ -1,63 +1,63 @@
|
||||
<template>
|
||||
<div class="main-container">
|
||||
<div class="win-window">
|
||||
<div class="win-titlebar">
|
||||
<span class="win-titlebar-text">🎮 Games Catalog</span>
|
||||
<div class="win-titlebar-btns">
|
||||
<button class="win-titlebar-btn">_</button>
|
||||
<button class="win-titlebar-btn">□</button>
|
||||
<button class="win-titlebar-btn">×</button>
|
||||
</div>
|
||||
</div>
|
||||
<header class="hero-section-gradient from-purple-600 to-indigo-600 py-16">
|
||||
<div class="hero-container">
|
||||
<h1 class="hero-title">Our Games</h1>
|
||||
<p class="hero-subtitle text-purple-50">Discover games made for TIC-80 and other platforms, with versions playable directly in your browser!</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="win-toolbar">
|
||||
<span style="font-size: 11px; margin-right: 4px;">Filter:</span>
|
||||
<button
|
||||
v-for="f in filters"
|
||||
:key="f"
|
||||
:class="['win-btn-sm', { 'is-active': activeFilter === f }]"
|
||||
@click="activeFilter = f"
|
||||
>{{ f.charAt(0).toUpperCase() + f.slice(1) }}</button>
|
||||
</div>
|
||||
<main class="main-container py-12 px-4 mt-0">
|
||||
<div class="flex flex-wrap gap-4 mb-8 justify-center filter-buttons pb-4">
|
||||
<button
|
||||
v-for="f in filters"
|
||||
:key="f"
|
||||
:class="['filter-btn', { active: activeFilter === f }]"
|
||||
@click="activeFilter = f"
|
||||
>
|
||||
{{ f.charAt(0).toUpperCase() + f.slice(1) }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="win-body" style="padding: 4px;">
|
||||
<template v-for="{ software, releases } in softwares" :key="software.name">
|
||||
<div v-show="activeFilter === 'all' || software.status === activeFilter" class="software-row">
|
||||
<div class="software-row-inner">
|
||||
<div v-if="software.imageUrl" class="software-thumb-wrap">
|
||||
<div class="grid grid-cols-1 gap-8">
|
||||
<template v-for="{ software, releases } in softwares" :key="software.name">
|
||||
<div v-show="activeFilter === 'all' || software.status === activeFilter" class="software-card group">
|
||||
<div class="software-card-content">
|
||||
<div class="flex flex-col md:flex-row md:items-center justify-between gap-4">
|
||||
<div v-if="software.imageUrl" class="flex-shrink-0">
|
||||
<img :src="software.imageUrl" :alt="software.title" class="software-thumb" />
|
||||
</div>
|
||||
<div class="software-info">
|
||||
<div class="software-header-row">
|
||||
<RouterLink :to="`/catalog/${software.name}`" class="software-title-link">
|
||||
{{ software.title }}
|
||||
<div class="flex-grow">
|
||||
<div class="flex items-center gap-3 mb-2">
|
||||
<RouterLink :to="`/catalog/${software.name}`" class="hover:text-purple-600 transition-colors">
|
||||
<h2 class="software-title mb-0">{{ software.title }}</h2>
|
||||
</RouterLink>
|
||||
<span :class="`status-badge status-${software.status}`">{{ software.status }}</span>
|
||||
</div>
|
||||
<div class="software-desc">{{ software.desc }}</div>
|
||||
<p class="software-desc max-w-2xl">{{ software.desc }}</p>
|
||||
<div class="software-meta">
|
||||
Author: <strong>{{ software.author }}</strong>
|
||||
·
|
||||
Platform: <strong>{{ software.platform }}</strong>
|
||||
<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>
|
||||
<div class="software-actions">
|
||||
|
||||
<div class="flex flex-wrap gap-2 items-center">
|
||||
<a
|
||||
v-if="getLatestStable(releases)?.htmlFolderPath"
|
||||
:href="getLatestStable(releases).htmlFolderPath"
|
||||
target="_blank"
|
||||
class="win-btn-sm"
|
||||
class="btn-play-sm"
|
||||
>▶ Play</a>
|
||||
<RouterLink :to="`/catalog/${software.name}`" class="win-btn-sm">
|
||||
ℹ Info
|
||||
<RouterLink :to="`/catalog/${software.name}`" class="btn-info-sm">
|
||||
ℹ More Info
|
||||
</RouterLink>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
@@ -86,60 +86,40 @@ onMounted(async () => {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.software-row {
|
||||
border-bottom: 1px solid #D0D0D0;
|
||||
.filter-btn {
|
||||
@apply px-4 py-2 rounded-full border-2 border-purple-600 text-purple-600 font-bold transition-all hover:bg-purple-600 hover:text-white;
|
||||
}
|
||||
.software-row:last-child {
|
||||
border-bottom: none;
|
||||
.filter-btn.active {
|
||||
@apply bg-purple-600 text-white;
|
||||
}
|
||||
.software-row:hover {
|
||||
background: #EEF0F8;
|
||||
.status-badge {
|
||||
@apply px-2 py-0.5 rounded text-xs font-bold uppercase;
|
||||
}
|
||||
.software-row-inner {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 8px;
|
||||
padding: 6px 8px;
|
||||
flex-wrap: wrap;
|
||||
.status-released { @apply bg-green-100 text-green-800 border border-green-200; }
|
||||
.status-demo { @apply bg-blue-100 text-blue-800 border border-blue-200; }
|
||||
.status-development { @apply bg-yellow-100 text-yellow-800 border border-yellow-200; }
|
||||
.status-archived { @apply bg-gray-100 text-gray-800 border border-gray-200; }
|
||||
.software-card {
|
||||
@apply bg-white shadow-lg relative rounded-xl overflow-hidden hover:shadow-2xl transition-shadow duration-300;
|
||||
}
|
||||
.software-thumb-wrap { flex-shrink: 0; }
|
||||
.software-thumb {
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
object-fit: cover;
|
||||
border: 2px solid;
|
||||
border-color: #808080 #fff #fff #808080;
|
||||
.software-card-content {
|
||||
@apply p-6;
|
||||
}
|
||||
.software-info { flex: 1; min-width: 180px; }
|
||||
.software-header-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
margin-bottom: 3px;
|
||||
flex-wrap: wrap;
|
||||
.software-title {
|
||||
@apply text-2xl font-bold mb-0;
|
||||
}
|
||||
.software-title-link {
|
||||
font-size: 13px;
|
||||
font-weight: bold;
|
||||
color: #000080;
|
||||
text-decoration: underline;
|
||||
}
|
||||
.software-title-link:hover { color: #0000FF; }
|
||||
.software-desc {
|
||||
font-size: 12px;
|
||||
color: #404040;
|
||||
margin-bottom: 3px;
|
||||
line-height: 1.4;
|
||||
@apply text-gray-600 mb-3;
|
||||
}
|
||||
.software-meta {
|
||||
font-size: 11px;
|
||||
color: #808080;
|
||||
@apply text-sm text-gray-500;
|
||||
}
|
||||
.software-actions {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 3px;
|
||||
align-items: flex-start;
|
||||
flex-shrink: 0;
|
||||
.btn-base-sm {
|
||||
@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 shadow-lg shadow-purple-600/20; }
|
||||
.btn-info-sm { @apply btn-base-sm bg-gray-100 hover:bg-gray-200 text-gray-700; }
|
||||
.software-thumb {
|
||||
@apply w-24 h-24 object-cover rounded-xl border border-gray-100 shadow-sm;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,170 +1,168 @@
|
||||
<template>
|
||||
<div class="main-container">
|
||||
<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">
|
||||
<RouterLink to="/catalog" class="text-purple-200 hover:text-white transition-colors flex items-center gap-2 font-medium">
|
||||
← Back to Catalog
|
||||
</RouterLink>
|
||||
</nav>
|
||||
|
||||
<div v-if="software" class="show-layout">
|
||||
|
||||
<!-- Info Sidebar -->
|
||||
<div class="show-sidebar">
|
||||
<div class="win-window">
|
||||
<div class="win-titlebar">
|
||||
<span class="win-titlebar-text">ℹ Project Info</span>
|
||||
<div class="win-titlebar-btns">
|
||||
<button class="win-titlebar-btn">_</button>
|
||||
<button class="win-titlebar-btn">□</button>
|
||||
<button class="win-titlebar-btn">×</button>
|
||||
<div v-if="software" 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>
|
||||
</div>
|
||||
<div class="win-body">
|
||||
<div class="back-link-row">
|
||||
<RouterLink to="/catalog" class="win-btn win-btn-sm">← Back to Catalog</RouterLink>
|
||||
</div>
|
||||
|
||||
<div v-if="software.imageUrl" class="sidebar-img-wrap">
|
||||
<img :src="software.imageUrl" :alt="software.title" class="sidebar-img" />
|
||||
</div>
|
||||
|
||||
<table class="info-table">
|
||||
<tr>
|
||||
<td class="info-label">Title</td>
|
||||
<td class="info-value"><strong>{{ software.title }}</strong></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="info-label">Status</td>
|
||||
<td class="info-value">
|
||||
<span :class="`status-badge status-${software.status}`">{{ software.status }}</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="info-label">Author</td>
|
||||
<td class="info-value">{{ software.author }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="info-label">Platform</td>
|
||||
<td class="info-value">{{ software.platform }}</td>
|
||||
</tr>
|
||||
<tr v-if="software.license">
|
||||
<td class="info-label">License</td>
|
||||
<td class="info-value">{{ software.license }}</td>
|
||||
</tr>
|
||||
<tr v-for="link in software.externalLinks" :key="link.url">
|
||||
<td class="info-label">{{ link.label }}</td>
|
||||
<td class="info-value">
|
||||
<a :href="link.url" target="_blank" class="win-link">{{ link.url }} ↗</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<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 Content -->
|
||||
<div class="show-main">
|
||||
<main v-if="software" class="main-container -mt-10">
|
||||
<div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
|
||||
|
||||
<!-- About Window -->
|
||||
<div v-if="software.story" class="win-window">
|
||||
<div class="win-titlebar">
|
||||
<span class="win-titlebar-text">📄 About {{ software.title }}</span>
|
||||
<div class="win-titlebar-btns">
|
||||
<button class="win-titlebar-btn">_</button>
|
||||
<button class="win-titlebar-btn">□</button>
|
||||
<button class="win-titlebar-btn">×</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="win-body">
|
||||
<div class="win-inset" style="padding: 8px;">
|
||||
<p style="margin: 0; font-size: 12px; line-height: 1.6; white-space: pre-line;">{{ software.story }}</p>
|
||||
<!-- 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">
|
||||
<div v-if="software.imageUrl" class="mb-6 flex justify-center">
|
||||
<img :src="software.imageUrl" :alt="software.title" class="max-h-48 w-auto object-contain border-4 border-gray-100 shadow-sm" />
|
||||
</div>
|
||||
<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>
|
||||
<div v-if="software.license">
|
||||
<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>
|
||||
<div v-for="link in software.externalLinks" :key="link.url">
|
||||
<dt class="text-xs font-bold text-gray-400 uppercase tracking-widest mb-1">{{ link.label }}</dt>
|
||||
<dd>
|
||||
<a :href="link.url" target="_blank" class="text-purple-600 hover:text-purple-800 font-bold break-all">
|
||||
{{ link.url }} ↗
|
||||
</a>
|
||||
</dd>
|
||||
</div>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Latest Stable Window -->
|
||||
<div v-if="latestStable" class="win-window">
|
||||
<div class="win-titlebar">
|
||||
<span class="win-titlebar-text">💾 Latest Stable Release — {{ latestStable.version }}</span>
|
||||
<div class="win-titlebar-btns">
|
||||
<button class="win-titlebar-btn">_</button>
|
||||
<button class="win-titlebar-btn">□</button>
|
||||
<button class="win-titlebar-btn">×</button>
|
||||
</div>
|
||||
<!-- Main Content Area -->
|
||||
<div class="lg:col-span-2 space-y-8">
|
||||
<div v-if="software.story" class="bg-white rounded-3xl shadow-xl p-8 border border-gray-100">
|
||||
<h2 class="text-xl font-bold text-gray-900 mb-4">About</h2>
|
||||
<p class="text-gray-700 leading-relaxed whitespace-pre-line">{{ software.story }}</p>
|
||||
</div>
|
||||
<div class="win-body">
|
||||
<div style="font-size: 11px; color: #404040; margin-bottom: 8px;">
|
||||
Released: <span style="font-family: 'Courier New', monospace;">{{ formatDateTime(latestStable.UpdatedAt) }}</span>
|
||||
</div>
|
||||
<div class="release-actions">
|
||||
<a v-if="latestStable.htmlFolderPath" :href="latestStable.htmlFolderPath" target="_blank" class="win-btn win-btn-default-action">▶ Play Now</a>
|
||||
<a v-if="latestStable.cartridgePath" :href="latestStable.cartridgePath" target="_blank" class="win-btn">💾 Download</a>
|
||||
<a v-if="latestStable.sourcePath" :href="latestStable.sourcePath" target="_blank" class="win-btn">📄 Source</a>
|
||||
<a v-if="latestStable.docsFolderPath" :href="latestStable.docsFolderPath" target="_blank" class="win-btn">📖 Docs</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- All Releases Window -->
|
||||
<div class="win-window">
|
||||
<div class="win-titlebar">
|
||||
<span class="win-titlebar-text">📋 All Releases</span>
|
||||
<div class="win-titlebar-btns">
|
||||
<button class="win-titlebar-btn">_</button>
|
||||
<button class="win-titlebar-btn">□</button>
|
||||
<button class="win-titlebar-btn">×</button>
|
||||
<div v-if="latestStable" 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">
|
||||
<a v-if="latestStable.htmlFolderPath" :href="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>
|
||||
<a v-if="latestStable.cartridgePath" :href="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>
|
||||
<a v-if="latestStable.sourcePath" :href="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>
|
||||
<a v-if="latestStable.docsFolderPath" :href="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>
|
||||
<div class="win-body" style="padding: 0;">
|
||||
<table class="win-table" style="width: 100%;">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Version</th>
|
||||
<th>Release Date</th>
|
||||
<th>Downloads</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="release in stableReleases" :key="release.version">
|
||||
<td><strong>{{ release.version }}</strong></td>
|
||||
<td style="font-family: 'Courier New', monospace; font-size: 11px; white-space: nowrap;">{{ formatDateTime(release.UpdatedAt) }}</td>
|
||||
<td>
|
||||
<div class="release-link-row">
|
||||
<a v-if="release.htmlFolderPath" :href="release.htmlFolderPath" target="_blank" class="win-link-small">▶ Play</a>
|
||||
<a v-if="release.cartridgePath" :href="release.cartridgePath" target="_blank" class="win-link-small">💾 Download</a>
|
||||
<a v-if="release.sourcePath" :href="release.sourcePath" target="_blank" class="win-link-small">📄 Source</a>
|
||||
<a v-if="release.docsFolderPath" :href="release.docsFolderPath" target="_blank" class="win-link-small">📖 Docs</a>
|
||||
|
||||
<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">
|
||||
<tr v-for="release in stableReleases" :key="release.version" 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">
|
||||
<a v-if="release.htmlFolderPath" :href="release.htmlFolderPath" target="_blank" class="text-purple-600 hover:text-purple-900 font-bold text-sm flex items-center gap-1">▶ Play</a>
|
||||
<a v-if="release.cartridgePath" :href="release.cartridgePath" target="_blank" class="text-blue-600 hover:text-blue-900 font-bold text-sm flex items-center gap-1">💾 Download</a>
|
||||
<a v-if="release.sourcePath" :href="release.sourcePath" target="_blank" class="text-green-600 hover:text-green-900 font-bold text-sm flex items-center gap-1">📄 Source</a>
|
||||
<a v-if="release.docsFolderPath" :href="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>
|
||||
|
||||
<tr v-if="devReleases.length > 0" 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>
|
||||
|
||||
<tr v-for="release in devReleases" :key="release.version" 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">
|
||||
<a v-if="release.htmlFolderPath" :href="release.htmlFolderPath" target="_blank" class="text-purple-600 hover:text-purple-900 font-bold text-sm flex items-center gap-1">▶ Play</a>
|
||||
<a v-if="release.cartridgePath" :href="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">
|
||||
<div
|
||||
v-for="release in allReleases"
|
||||
:key="release.version"
|
||||
: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>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="devReleases.length > 0">
|
||||
<td colspan="3" class="dev-section-header">— Development Versions —</td>
|
||||
</tr>
|
||||
<tr v-for="release in devReleases" :key="release.version" class="dev-row">
|
||||
<td><span style="color: #808000; font-weight: bold;">{{ release.version }}</span></td>
|
||||
<td style="font-family: 'Courier New', monospace; font-size: 11px; white-space: nowrap;">{{ formatDateTime(release.UpdatedAt) }}</td>
|
||||
<td>
|
||||
<div class="release-link-row">
|
||||
<a v-if="release.htmlFolderPath" :href="release.htmlFolderPath" target="_blank" class="win-link-small">▶ Play</a>
|
||||
<a v-if="release.cartridgePath" :href="release.cartridgePath" target="_blank" class="win-link-small">💾 Download</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<span v-if="release.version.startsWith('dev-')" 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">
|
||||
<a v-if="release.htmlFolderPath" :href="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>
|
||||
<a v-if="release.cartridgePath" :href="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>
|
||||
<a v-if="release.sourcePath" :href="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>
|
||||
<a v-if="release.docsFolderPath" :href="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>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<div v-else class="win-window">
|
||||
<div class="win-titlebar">
|
||||
<span class="win-titlebar-text">Loading...</span>
|
||||
<div class="win-titlebar-btns">
|
||||
<button class="win-titlebar-btn">×</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="win-body" style="text-align: center; padding: 24px;">
|
||||
<main v-else class="main-container -mt-10">
|
||||
<div class="bg-white rounded-3xl shadow-xl p-12 text-center text-gray-400">
|
||||
{{ error || 'Loading...' }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</main>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -192,6 +190,7 @@ const devReleases = computed(() =>
|
||||
.sort((a, b) => new Date(b.UpdatedAt).getTime() - new Date(a.UpdatedAt).getTime())
|
||||
)
|
||||
|
||||
const allReleases = computed(() => [...stableReleases.value, ...devReleases.value])
|
||||
const latestStable = computed(() => stableReleases.value[0] ?? null)
|
||||
|
||||
onMounted(async () => {
|
||||
@@ -211,79 +210,11 @@ onMounted(async () => {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.show-layout {
|
||||
display: grid;
|
||||
grid-template-columns: 200px 1fr;
|
||||
gap: 8px;
|
||||
align-items: flex-start;
|
||||
}
|
||||
@media (max-width: 640px) {
|
||||
.show-layout { grid-template-columns: 1fr; }
|
||||
}
|
||||
.show-sidebar, .show-main { }
|
||||
|
||||
.back-link-row { margin-bottom: 8px; }
|
||||
|
||||
.sidebar-img-wrap {
|
||||
margin-bottom: 8px;
|
||||
text-align: center;
|
||||
}
|
||||
.sidebar-img {
|
||||
max-width: 100%;
|
||||
max-height: 100px;
|
||||
object-fit: contain;
|
||||
border: 2px solid;
|
||||
border-color: #808080 #fff #fff #808080;
|
||||
}
|
||||
.info-table {
|
||||
width: 100%;
|
||||
font-size: 11px;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
.info-table tr { border-bottom: 1px solid #D0D0D0; }
|
||||
.info-label {
|
||||
color: #404040;
|
||||
padding: 2px 4px 2px 0;
|
||||
white-space: nowrap;
|
||||
vertical-align: top;
|
||||
width: 50px;
|
||||
}
|
||||
.info-value {
|
||||
padding: 2px 0 2px 4px;
|
||||
word-break: break-all;
|
||||
}
|
||||
.win-link {
|
||||
color: #0000FF;
|
||||
text-decoration: underline;
|
||||
font-size: 11px;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.release-actions {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.release-link-row {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.win-link-small {
|
||||
color: #0000FF;
|
||||
text-decoration: underline;
|
||||
font-size: 11px;
|
||||
}
|
||||
.win-link-small:visited { color: #800080; }
|
||||
.dev-section-header {
|
||||
background: #FFFFC8;
|
||||
font-size: 11px;
|
||||
color: #808000;
|
||||
padding: 2px 8px;
|
||||
text-align: center;
|
||||
font-style: italic;
|
||||
}
|
||||
.dev-row td {
|
||||
background: #FFFFE8;
|
||||
.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>
|
||||
|
||||
@@ -1,99 +1,61 @@
|
||||
<template>
|
||||
<div class="main-container">
|
||||
<header class="hero-section-gradient from-teal-600 to-green-600 py-20">
|
||||
<div class="hero-container max-w-4xl">
|
||||
<h1 class="hero-title">Codebase</h1>
|
||||
<p class="hero-subtitle text-teal-50 mb-10">
|
||||
Explore our collection of open-source projects, study our source code, and contribute to our independent game development tools.
|
||||
</p>
|
||||
<a href="https://git.teletype.hu" target="_blank" class="btn-hero-teal">
|
||||
Open Gitea
|
||||
</a>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div v-if="error" class="win-notice-error">
|
||||
<span>⚠</span>
|
||||
<div><strong>Error</strong><br><span style="font-size: 11px;">{{ error }}</span></div>
|
||||
<main class="main-container">
|
||||
<div v-if="error" class="error-alert" role="alert">
|
||||
<strong class="font-bold">Error!</strong>
|
||||
<span class="block sm:inline"> {{ error }}</span>
|
||||
</div>
|
||||
|
||||
<!-- Repositories Window -->
|
||||
<div v-if="!error && publicRepos.length > 0" class="win-window">
|
||||
<div class="win-titlebar">
|
||||
<span class="win-titlebar-text">💻 Public Repositories</span>
|
||||
<div class="win-titlebar-btns">
|
||||
<button class="win-titlebar-btn">_</button>
|
||||
<button class="win-titlebar-btn">□</button>
|
||||
<button class="win-titlebar-btn">×</button>
|
||||
<div v-if="!error && publicRepos.length > 0" class="card-grid mb-16">
|
||||
<div v-for="repo in publicRepos" :key="repo.name" class="card-base">
|
||||
<h3 class="repo-card-title">
|
||||
<a :href="repo.html_url" target="_blank" class="repo-link">
|
||||
{{ repo.owner.login }}/{{ repo.name }}
|
||||
</a>
|
||||
</h3>
|
||||
<p v-if="repo.description" class="repo-card-desc">{{ repo.description }}</p>
|
||||
<p v-if="repo.language" class="repo-card-meta">Language: {{ repo.language }}</p>
|
||||
<p class="repo-card-meta">Updated: {{ formatDateTime(repo.updated_at) }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2 class="commits-section-title">Recent Commits</h2>
|
||||
|
||||
<p v-if="!error && recentCommits.length === 0" class="empty-commits-msg">
|
||||
No recent commits found or accessible from public repositories.
|
||||
</p>
|
||||
|
||||
<div class="commits-list">
|
||||
<div v-for="commit in recentCommits" :key="commit.sha" class="commit-item">
|
||||
<div class="commit-icon">🚀</div>
|
||||
<div class="commit-content">
|
||||
<p class="commit-message">
|
||||
<a :href="commit.repo.html_url" target="_blank" class="commit-repo-link">
|
||||
<span class="font-bold">{{ commit.repo.owner }}</span> / <span class="font-bold">{{ commit.repo.name }}</span>
|
||||
</a>
|
||||
: <span class="text-gray-700">{{ commit.message.split('\n')[0] }}</span>
|
||||
</p>
|
||||
<p class="commit-meta">
|
||||
Authored by <span class="font-bold">{{ commit.author.name }}</span> on {{ formatDateTime(commit.date) }}
|
||||
<a :href="commit.url" target="_blank" class="commit-sha-link">
|
||||
<span class="font-mono text-xs">{{ commit.sha.substring(0, 7) }}</span>
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="win-toolbar">
|
||||
<a href="https://git.teletype.hu" target="_blank" class="win-btn win-btn-sm">Open Gitea ↗</a>
|
||||
<span style="font-size: 11px; color: #404040; margin-left: 4px;">{{ publicRepos.length }} repositories</span>
|
||||
</div>
|
||||
<div class="win-body" style="padding: 0;">
|
||||
<table class="win-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Repository</th>
|
||||
<th>Description</th>
|
||||
<th>Language</th>
|
||||
<th>Updated</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="repo in publicRepos" :key="repo.name">
|
||||
<td>
|
||||
<a :href="repo.html_url" target="_blank" class="repo-link">
|
||||
{{ repo.owner.login }}/{{ repo.name }}
|
||||
</a>
|
||||
</td>
|
||||
<td style="font-size: 11px; color: #404040; max-width: 300px;">{{ repo.description || '—' }}</td>
|
||||
<td style="font-size: 11px; font-family: 'Courier New', monospace; white-space: nowrap;">{{ repo.language || '—' }}</td>
|
||||
<td style="font-size: 11px; font-family: 'Courier New', monospace; white-space: nowrap;">{{ formatDateTime(repo.updated_at) }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Recent Commits Window -->
|
||||
<div class="win-window">
|
||||
<div class="win-titlebar">
|
||||
<span class="win-titlebar-text">🚀 Recent Commits</span>
|
||||
<div class="win-titlebar-btns">
|
||||
<button class="win-titlebar-btn">_</button>
|
||||
<button class="win-titlebar-btn">□</button>
|
||||
<button class="win-titlebar-btn">×</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="recentCommits.length === 0" class="win-body" style="text-align: center; color: #404040; font-size: 12px;">
|
||||
No recent commits found.
|
||||
</div>
|
||||
|
||||
<div v-else class="win-body" style="padding: 0;">
|
||||
<table class="win-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Repository</th>
|
||||
<th>Commit Message</th>
|
||||
<th>Author</th>
|
||||
<th>Date</th>
|
||||
<th>SHA</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="commit in recentCommits" :key="commit.sha">
|
||||
<td style="white-space: nowrap;">
|
||||
<a :href="commit.repo.html_url" target="_blank" class="repo-link" style="font-size: 11px;">
|
||||
{{ commit.repo.owner }}/{{ commit.repo.name }}
|
||||
</a>
|
||||
</td>
|
||||
<td style="font-size: 11px; max-width: 250px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">
|
||||
{{ commit.message.split('\n')[0] }}
|
||||
</td>
|
||||
<td style="font-size: 11px; white-space: nowrap;">{{ commit.author.name }}</td>
|
||||
<td style="font-size: 11px; font-family: 'Courier New', monospace; white-space: nowrap;">{{ formatDateTime(commit.date) }}</td>
|
||||
<td>
|
||||
<a :href="commit.url" target="_blank" class="sha-link">{{ commit.sha.substring(0, 7) }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
@@ -109,9 +71,11 @@ const error = ref<string | null>(null)
|
||||
onMounted(async () => {
|
||||
try {
|
||||
publicRepos.value = await gitApi.repos()
|
||||
|
||||
const commitPromises = publicRepos.value.map(repo =>
|
||||
gitApi.commits(repo.owner.login, repo.name, repo.html_url)
|
||||
)
|
||||
|
||||
const all = (await Promise.all(commitPromises)).flat()
|
||||
all.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime())
|
||||
recentCommits.value = all.slice(0, 20)
|
||||
@@ -122,18 +86,49 @@ onMounted(async () => {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.error-alert {
|
||||
@apply bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative mb-8;
|
||||
}
|
||||
.repo-card-title {
|
||||
@apply text-xl font-semibold mb-2;
|
||||
}
|
||||
.repo-link {
|
||||
color: #0000FF;
|
||||
text-decoration: underline;
|
||||
font-size: 12px;
|
||||
font-family: "Courier New", Courier, monospace;
|
||||
@apply text-blue-600 hover:text-blue-800;
|
||||
}
|
||||
.repo-link:hover { color: #0000CC; }
|
||||
.sha-link {
|
||||
color: #0000FF;
|
||||
text-decoration: underline;
|
||||
font-family: "Courier New", Courier, monospace;
|
||||
font-size: 11px;
|
||||
.repo-card-desc {
|
||||
@apply text-gray-700 text-sm;
|
||||
}
|
||||
.repo-card-meta {
|
||||
@apply text-gray-500 text-xs mt-1;
|
||||
}
|
||||
.commits-section-title {
|
||||
@apply text-3xl font-bold mb-8 text-center text-gray-800;
|
||||
}
|
||||
.empty-commits-msg {
|
||||
@apply text-center text-gray-600 text-lg;
|
||||
}
|
||||
.commits-list {
|
||||
@apply space-y-4 mb-12;
|
||||
}
|
||||
.commit-item {
|
||||
@apply bg-white shadow-lg rounded-lg p-4 flex items-center space-x-4 border border-gray-100;
|
||||
}
|
||||
.commit-icon {
|
||||
@apply flex-shrink-0 text-3xl;
|
||||
}
|
||||
.commit-content {
|
||||
@apply flex-grow;
|
||||
}
|
||||
.commit-message {
|
||||
@apply text-gray-800 font-semibold;
|
||||
}
|
||||
.commit-repo-link {
|
||||
@apply text-blue-600 hover:text-blue-800;
|
||||
}
|
||||
.commit-meta {
|
||||
@apply text-gray-600 text-sm mt-1;
|
||||
}
|
||||
.commit-sha-link {
|
||||
@apply ml-2 text-blue-500 hover:text-blue-700;
|
||||
}
|
||||
.sha-link:hover { color: #0000CC; }
|
||||
</style>
|
||||
|
||||
@@ -1,99 +1,79 @@
|
||||
<template>
|
||||
<div class="main-container">
|
||||
<header class="hero-section-gradient from-blue-600 to-indigo-700 py-20 text-white">
|
||||
<div class="hero-container text-center">
|
||||
<h1 class="hero-title mb-6">Contact Us</h1>
|
||||
<p class="hero-subtitle mb-10 text-blue-100">
|
||||
Have questions, feedback, or just want to say hi? We'd love to hear from you!
|
||||
</p>
|
||||
<a :href="DISCORD_INVITE_LINK" target="_blank" class="discord-hero-btn">
|
||||
<svg class="w-6 h-6" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037 19.736 19.736 0 0 0-4.885 1.515.069.069 0 0 0-.032.027C.533 9.048-.32 13.58.099 18.057a.082.082 0 0 0 .031.057 19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.028c.462-.63.862-1.297 1.197-1.99.051-.105.001-.23-.106-.272a13.223 13.223 0 0 1-1.878-.894.077.077 0 0 1-.007-.128c.126-.094.252-.192.372-.29a.074.074 0 0 1 .077-.01c3.927 1.793 8.18 1.793 12.061 0a.074.074 0 0 1 .077.01c.12.098.246.196.373.29a.077.077 0 0 1-.006.128 12.299 12.299 0 0 1-1.878.894.077.077 0 0 0-.106.272c.335.693.735 1.36 1.197 1.99a.078.078 0 0 0 .084.028 19.83 19.83 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03zM8.02 15.33c-1.182 0-2.156-1.085-2.156-2.419 0-1.333.956-2.419 2.156-2.419 1.21 0 2.176 1.096 2.156 2.419 0 1.334-.956 2.419-2.156 2.419zm7.974 0c-1.182 0-2.156-1.085-2.156-2.419 0-1.333.955-2.419 2.156-2.419 1.21 0 2.176 1.096 2.156 2.419 0 1.334-.946 2.419-2.156 2.419z"/>
|
||||
</svg>
|
||||
Join our Discord
|
||||
</a>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Email Window -->
|
||||
<div class="win-window">
|
||||
<div class="win-titlebar">
|
||||
<span class="win-titlebar-text">📧 Contact Us</span>
|
||||
<div class="win-titlebar-btns">
|
||||
<button class="win-titlebar-btn">_</button>
|
||||
<button class="win-titlebar-btn">□</button>
|
||||
<button class="win-titlebar-btn">×</button>
|
||||
<main class="main-container py-16 px-4">
|
||||
<div class="contact-grid">
|
||||
<div class="contact-card">
|
||||
<h2 class="contact-card-title">
|
||||
<span class="text-3xl">📧</span> Email Us
|
||||
</h2>
|
||||
<p class="contact-card-desc">
|
||||
For business inquiries, support, or detailed feedback, feel free to drop us an email.
|
||||
</p>
|
||||
<div @click="openEmail" class="email-link cursor-pointer">
|
||||
contact@teletype.hu
|
||||
</div>
|
||||
</div>
|
||||
<div class="win-body">
|
||||
<p style="margin: 0 0 8px; font-size: 12px; color: #404040;">
|
||||
Have questions, feedback, or just want to say hi?
|
||||
|
||||
<div class="contact-card">
|
||||
<h2 class="contact-card-title">
|
||||
<span class="text-3xl">💬</span> Community
|
||||
</h2>
|
||||
<p class="contact-card-desc mb-8">
|
||||
Join our primarily Hungarian-speaking community (English speakers are also welcome!).
|
||||
</p>
|
||||
<table class="contact-table">
|
||||
<tr>
|
||||
<td class="contact-label">Email:</td>
|
||||
<td>
|
||||
<span @click="openEmail" class="email-link">contact@teletype.hu</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div style="margin-top: 8px;">
|
||||
<a :href="DISCORD_INVITE_LINK" target="_blank" class="win-btn">
|
||||
<svg class="discord-icon" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037 19.736 19.736 0 0 0-4.885 1.515.069.069 0 0 0-.032.027C.533 9.048-.32 13.58.099 18.057a.082.082 0 0 0 .031.057 19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.028c.462-.63.862-1.297 1.197-1.99.051-.105.001-.23-.106-.272a13.223 13.223 0 0 1-1.878-.894.077.077 0 0 1-.007-.128c.126-.094.252-.192.372-.29a.074.074 0 0 1 .077-.01c3.927 1.793 8.18 1.793 12.061 0a.074.074 0 0 1 .077.01c.12.098.246.196.373.29a.077.077 0 0 1-.006.128 12.299 12.299 0 0 1-1.878.894.077.077 0 0 0-.106.272c.335.693.735 1.36 1.197 1.99a.078.078 0 0 0 .084.028 19.83 19.83 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03z"/>
|
||||
</svg>
|
||||
Join our Discord Server
|
||||
</a>
|
||||
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 justify-center">
|
||||
<div class="community-section border-[#5865F2]">
|
||||
<h3 class="community-section-title text-[#5865F2]">Discord</h3>
|
||||
<p class="community-section-desc">We have a vibrant Discord server for real-time chat and support.</p>
|
||||
<a :href="DISCORD_INVITE_LINK" target="_blank" class="community-link-discord">
|
||||
Join Discord Server <span>→</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="community-section border-red-600">
|
||||
<h3 class="community-section-title text-red-600">YouTube</h3>
|
||||
<p class="community-section-desc">Watch our latest vlogs and development videos on our channel.</p>
|
||||
<a href="https://www.youtube.com/@teletypegames" target="_blank" class="community-link-youtube">
|
||||
Visit Channel <span>→</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="community-section border-green-500">
|
||||
<h3 class="community-section-title text-green-700">IRC</h3>
|
||||
<p class="text-sm text-gray-600 mb-3">If Discord is too modern, find us on IRC!</p>
|
||||
<div class="irc-box">
|
||||
<span class="irc-network">Network: Libera.Chat</span>
|
||||
<code class="irc-channel">#teletypegames</code>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="community-section border-amber-500">
|
||||
<h3 class="community-section-title text-amber-700">BBS</h3>
|
||||
<p class="community-section-desc">Join us for some retro vibes on our BBS!</p>
|
||||
<div class="bbs-box">
|
||||
<span class="bbs-host">Host: games.teletype.hu</span>
|
||||
<code class="bbs-port">Port: 2323</code>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Community Window -->
|
||||
<div class="win-window">
|
||||
<div class="win-titlebar">
|
||||
<span class="win-titlebar-text">💬 Community Channels</span>
|
||||
<div class="win-titlebar-btns">
|
||||
<button class="win-titlebar-btn">_</button>
|
||||
<button class="win-titlebar-btn">□</button>
|
||||
<button class="win-titlebar-btn">×</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="win-body">
|
||||
<p style="margin: 0 0 10px; font-size: 12px; color: #404040;">
|
||||
Join our primarily Hungarian-speaking community (English speakers also welcome!).
|
||||
</p>
|
||||
|
||||
<div class="community-grid">
|
||||
|
||||
<div class="community-item win-raised-panel">
|
||||
<div class="community-header" style="color: #5865F2;">
|
||||
<span class="community-icon">💬</span> Discord
|
||||
</div>
|
||||
<p class="community-desc">Real-time chat and support on our Discord server.</p>
|
||||
<a :href="DISCORD_INVITE_LINK" target="_blank" class="win-btn win-btn-sm">Join Discord →</a>
|
||||
</div>
|
||||
|
||||
<div class="community-item win-raised-panel">
|
||||
<div class="community-header" style="color: #CC0000;">
|
||||
<span class="community-icon">📺</span> YouTube
|
||||
</div>
|
||||
<p class="community-desc">Watch our latest vlogs and development videos.</p>
|
||||
<a href="https://www.youtube.com/@teletypegames" target="_blank" class="win-btn win-btn-sm">Visit Channel →</a>
|
||||
</div>
|
||||
|
||||
<div class="community-item win-raised-panel">
|
||||
<div class="community-header" style="color: #007000;">
|
||||
<span class="community-icon">🖥</span> IRC
|
||||
</div>
|
||||
<p class="community-desc">If Discord is too modern, find us on IRC!</p>
|
||||
<div class="code-box">
|
||||
<div style="font-size: 10px; color: #404040; margin-bottom: 2px;">Network: Libera.Chat</div>
|
||||
<code class="irc-code">#teletypegames</code>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="community-item win-raised-panel">
|
||||
<div class="community-header" style="color: #805000;">
|
||||
<span class="community-icon">📟</span> BBS
|
||||
</div>
|
||||
<p class="community-desc">Retro vibes on our BBS!</p>
|
||||
<div class="code-box">
|
||||
<div style="font-size: 10px; color: #404040; margin-bottom: 2px;">Host: games.teletype.hu</div>
|
||||
<code class="bbs-code">Port: 2323</code>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
@@ -105,83 +85,55 @@ function openEmail() {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.contact-table {
|
||||
font-size: 12px;
|
||||
margin-bottom: 4px;
|
||||
.discord-hero-btn {
|
||||
@apply inline-flex items-center gap-3 bg-[#5865F2] hover:bg-[#4752C4] text-white font-black py-4 px-8 rounded-full text-lg transition-all transform hover:scale-105 shadow-xl;
|
||||
}
|
||||
.contact-label {
|
||||
color: #404040;
|
||||
padding-right: 8px;
|
||||
white-space: nowrap;
|
||||
.contact-grid {
|
||||
@apply grid grid-cols-1 gap-12 max-w-5xl mx-auto;
|
||||
}
|
||||
.contact-card {
|
||||
@apply bg-white p-8 rounded-2xl shadow-xl border border-gray-100;
|
||||
}
|
||||
.contact-card-title {
|
||||
@apply text-2xl font-black text-gray-900 mb-6 flex items-center gap-3;
|
||||
}
|
||||
.contact-card-desc {
|
||||
@apply text-gray-600 mb-6 leading-relaxed;
|
||||
}
|
||||
.email-link {
|
||||
color: #0000FF;
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
font-size: 13px;
|
||||
@apply text-indigo-600 font-bold text-xl hover:underline transition-all;
|
||||
}
|
||||
.email-link:hover { color: #0000CC; }
|
||||
|
||||
.discord-icon {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
.community-section {
|
||||
@apply border-l-4 pl-4;
|
||||
}
|
||||
|
||||
.community-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 6px;
|
||||
.community-section-title {
|
||||
@apply text-lg font-bold mb-2;
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
.community-grid { grid-template-columns: repeat(2, 1fr); }
|
||||
.community-section-desc {
|
||||
@apply text-gray-600 text-sm mb-3;
|
||||
}
|
||||
@media (max-width: 420px) {
|
||||
.community-grid { grid-template-columns: 1fr; }
|
||||
.community-link-discord {
|
||||
@apply text-[#5865F2] font-bold hover:underline inline-flex items-center gap-1;
|
||||
}
|
||||
|
||||
.community-item {
|
||||
padding: 8px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
.community-link-youtube {
|
||||
@apply text-red-600 font-bold hover:underline inline-flex items-center gap-1;
|
||||
}
|
||||
.community-header {
|
||||
font-size: 13px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
.irc-box {
|
||||
@apply bg-green-100 p-4 rounded-xl border border-green-200 mt-3 inline-block;
|
||||
}
|
||||
.community-icon { font-size: 14px; }
|
||||
.community-desc {
|
||||
font-size: 11px;
|
||||
color: #404040;
|
||||
margin: 0 0 8px;
|
||||
flex-grow: 1;
|
||||
line-height: 1.4;
|
||||
.irc-network {
|
||||
@apply block text-xs font-semibold text-green-500 uppercase tracking-wider mb-1;
|
||||
}
|
||||
|
||||
.code-box {
|
||||
background: #fff;
|
||||
border: 1px solid #808080;
|
||||
padding: 4px 6px;
|
||||
margin-top: auto;
|
||||
box-shadow:
|
||||
inset 1px 1px 0 0 #808080,
|
||||
inset -1px -1px 0 0 #D4D0C8;
|
||||
.irc-channel {
|
||||
@apply text-green-800 font-mono text-lg font-bold;
|
||||
}
|
||||
.irc-code {
|
||||
font-family: "Courier New", Courier, monospace;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
color: #007000;
|
||||
display: block;
|
||||
.bbs-box {
|
||||
@apply bg-amber-50 p-4 rounded-xl border border-amber-100 mt-3 inline-block;
|
||||
}
|
||||
.bbs-code {
|
||||
font-family: "Courier New", Courier, monospace;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
color: #805000;
|
||||
display: block;
|
||||
.bbs-host {
|
||||
@apply block text-xs font-semibold text-amber-500 uppercase tracking-wider mb-1;
|
||||
}
|
||||
.bbs-port {
|
||||
@apply text-amber-700 font-mono text-lg font-bold;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,179 +1,188 @@
|
||||
<template>
|
||||
<div class="main-container">
|
||||
|
||||
<!-- Welcome Window -->
|
||||
<div class="win-window">
|
||||
<div class="win-titlebar">
|
||||
<span class="win-titlebar-text">📟 Welcome to Teletype Games</span>
|
||||
<div class="win-titlebar-btns">
|
||||
<button class="win-titlebar-btn">_</button>
|
||||
<button class="win-titlebar-btn">□</button>
|
||||
<button class="win-titlebar-btn">×</button>
|
||||
</div>
|
||||
<div class="home-container">
|
||||
<!-- Header Section -->
|
||||
<header class="hero-section-slate">
|
||||
<div class="home-header-decor">
|
||||
<div class="hero-decor-blob -top-24 -left-24 h-96 w-96 bg-indigo-600"></div>
|
||||
<div class="hero-decor-blob -bottom-24 -right-24 h-96 w-96 bg-purple-600"></div>
|
||||
</div>
|
||||
<div class="win-body">
|
||||
<p style="margin: 0; font-size: 13px;">
|
||||
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.
|
||||
|
||||
<div class="hero-container">
|
||||
<div class="hero-badge">Welcome to</div>
|
||||
<h1 class="hero-title">
|
||||
Teletype <span class="text-transparent bg-clip-text bg-gradient-to-r from-violet-400 to-fuchsia-400">Games</span>
|
||||
</h1>
|
||||
<p class="hero-subtitle">
|
||||
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>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Two-column: Countdown + Featured -->
|
||||
<div class="home-two-col">
|
||||
<main class="main-container max-w-6xl">
|
||||
<!-- Countdown Section -->
|
||||
<section v-if="nextEvent" class="mb-12">
|
||||
<div class="countdown-card">
|
||||
<h2 class="countdown-event-name">{{ nextEvent.name }}</h2>
|
||||
<div class="countdown-timer">{{ countdownText }}</div>
|
||||
<p class="countdown-date">Starts on: <span class="font-semibold">{{ nextEvent.dateText }}</span></p>
|
||||
|
||||
<!-- Countdown Window -->
|
||||
<div v-if="nextEvent" class="win-window">
|
||||
<div class="win-titlebar">
|
||||
<span class="win-titlebar-text">⏱ Next Event</span>
|
||||
<div class="win-titlebar-btns">
|
||||
<button class="win-titlebar-btn">_</button>
|
||||
<button class="win-titlebar-btn">□</button>
|
||||
<button class="win-titlebar-btn">×</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="win-body" style="text-align: center;">
|
||||
<div class="countdown-name">{{ nextEvent.name }}</div>
|
||||
<div class="win-inset countdown-display">
|
||||
<span class="countdown-mono">{{ countdownText }}</span>
|
||||
</div>
|
||||
<div class="countdown-date">
|
||||
Starts: <strong>{{ nextEvent.dateText }}</strong>
|
||||
</div>
|
||||
|
||||
<div v-if="followingEvents.length > 0" class="upcoming-section">
|
||||
<div class="win-separator"></div>
|
||||
<div class="upcoming-label">Upcoming Events:</div>
|
||||
<div v-for="event in followingEvents" :key="event.name" class="upcoming-row">
|
||||
<span>{{ event.name }}</span>
|
||||
<span class="upcoming-date-mono">{{ event.dateText }}</span>
|
||||
<div v-if="followingEvents.length > 0" class="upcoming-events-section">
|
||||
<h3 class="upcoming-events-title">Upcoming Events</h3>
|
||||
<div class="space-y-4">
|
||||
<div v-for="event in followingEvents" :key="event.name" class="upcoming-event-item">
|
||||
<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>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Featured Software Window -->
|
||||
<div v-if="highlightedSoftware" class="win-window">
|
||||
<div class="win-titlebar">
|
||||
<span class="win-titlebar-text">🎮 Featured Game</span>
|
||||
<div class="win-titlebar-btns">
|
||||
<button class="win-titlebar-btn">_</button>
|
||||
<button class="win-titlebar-btn">□</button>
|
||||
<button class="win-titlebar-btn">×</button>
|
||||
<!-- Featured Software Section -->
|
||||
<section v-if="highlightedSoftware" class="mb-16">
|
||||
<div class="featured-card group">
|
||||
<div v-if="highlightedSoftware.software.imageUrl" class="featured-image-panel">
|
||||
<img :src="highlightedSoftware.software.imageUrl" :alt="highlightedSoftware.software.title" class="featured-image" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="win-body featured-body">
|
||||
<div v-if="highlightedSoftware.software.imageUrl" class="featured-img-wrap">
|
||||
<img :src="highlightedSoftware.software.imageUrl" :alt="highlightedSoftware.software.title" class="featured-img" />
|
||||
</div>
|
||||
<div class="featured-info">
|
||||
<div class="featured-badges">
|
||||
<div class="featured-content">
|
||||
<div class="flex items-center gap-2 mb-4">
|
||||
<span class="featured-badge">Featured Game</span>
|
||||
<span :class="`status-badge status-${highlightedSoftware.software.status}`">{{ highlightedSoftware.software.status }}</span>
|
||||
<span v-if="highlightedStableRelease" class="featured-version">{{ highlightedStableRelease.version }}</span>
|
||||
<span v-if="highlightedStableRelease" class="featured-version-badge">{{ highlightedStableRelease.version }}</span>
|
||||
</div>
|
||||
<div class="featured-title">{{ highlightedSoftware.software.title }}</div>
|
||||
<div class="featured-desc">{{ highlightedSoftware.software.desc }}</div>
|
||||
<div class="featured-actions">
|
||||
<h2 class="featured-title">{{ highlightedSoftware.software.title }}</h2>
|
||||
<p class="featured-desc">{{ highlightedSoftware.software.desc }}</p>
|
||||
|
||||
<div class="flex flex-wrap gap-4 mt-8">
|
||||
<a
|
||||
v-if="highlightedStableRelease?.htmlFolderPath"
|
||||
:href="highlightedStableRelease.htmlFolderPath"
|
||||
target="_blank"
|
||||
class="win-btn"
|
||||
class="featured-btn-play"
|
||||
>▶ Play in Browser</a>
|
||||
<RouterLink :to="`/catalog/${highlightedSoftware.software.name}`" class="win-btn">
|
||||
More Info
|
||||
<RouterLink :to="`/catalog/${highlightedSoftware.software.name}`" class="featured-btn-secondary">
|
||||
View Project Details
|
||||
</RouterLink>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</div>
|
||||
<!-- Latest YouTube Video -->
|
||||
<section class="mb-16">
|
||||
<div class="yt-featured-wrapper group">
|
||||
<div class="yt-glow"></div>
|
||||
|
||||
<!-- YouTube Window -->
|
||||
<div class="win-window">
|
||||
<div class="win-titlebar">
|
||||
<span class="win-titlebar-text">📺 Latest from YouTube</span>
|
||||
<div class="win-titlebar-btns">
|
||||
<button class="win-titlebar-btn">_</button>
|
||||
<button class="win-titlebar-btn">□</button>
|
||||
<button class="win-titlebar-btn">×</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="win-body yt-layout">
|
||||
<div class="yt-player win-inset">
|
||||
<div v-if="ytState === 'loading'" class="yt-state">Loading...</div>
|
||||
<div v-else-if="ytState === 'error'" class="yt-state yt-state-error">⚠ {{ ytError }}</div>
|
||||
<div v-else-if="ytState === 'no-config'" class="yt-state">YouTube API not configured.</div>
|
||||
<iframe
|
||||
v-else-if="ytVideoId"
|
||||
:src="`https://www.youtube.com/embed/${ytVideoId}?autoplay=0&rel=0&modestbranding=1`"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowfullscreen
|
||||
style="width: 100%; height: 100%; border: none; display: block;"
|
||||
></iframe>
|
||||
</div>
|
||||
<div v-if="ytVideoId" class="yt-info">
|
||||
<div class="yt-title">{{ ytTitle }}</div>
|
||||
<div class="yt-meta">
|
||||
<span v-if="ytPublishDate">{{ ytPublishDate }}</span>
|
||||
<span v-if="ytPublishDate && ytViewCount"> · </span>
|
||||
<span v-if="ytViewCount">{{ ytViewCount }}</span>
|
||||
<div class="yt-header-area">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="yt-status-blob">
|
||||
<div class="yt-status-dot"></div>
|
||||
</div>
|
||||
<span class="yt-label-text">Latest from YouTube</span>
|
||||
</div>
|
||||
<a href="https://www.youtube.com/@teletypegames" target="_blank" class="yt-channel-link">
|
||||
Visit Channel ↗
|
||||
</a>
|
||||
</div>
|
||||
<div class="yt-actions">
|
||||
<a :href="`https://www.youtube.com/watch?v=${ytVideoId}`" target="_blank" class="win-btn">▶ Watch on YouTube</a>
|
||||
<a href="https://www.youtube.com/@teletypegames" target="_blank" class="win-btn">Visit Channel</a>
|
||||
|
||||
<div class="yt-content-grid">
|
||||
<div class="yt-player-container">
|
||||
<div class="player-wrap relative w-full aspect-video">
|
||||
<div v-if="ytState === 'loading'" class="state-overlay absolute inset-0 flex items-center justify-center bg-slate-950">
|
||||
<div class="w-10 h-10 border-4 border-white/5 border-t-indigo-500 rounded-full animate-spin"></div>
|
||||
</div>
|
||||
<div v-else-if="ytState === 'error'" class="state-overlay absolute inset-0 flex items-center justify-center bg-slate-950 flex-col gap-2">
|
||||
<div class="text-xl">⚠️</div>
|
||||
<div class="text-[11px] text-slate-500 text-center px-4 font-bold uppercase tracking-tighter">{{ ytError }}</div>
|
||||
</div>
|
||||
<div v-else-if="ytState === 'no-config'" class="state-overlay absolute inset-0 flex items-center justify-center bg-slate-950">
|
||||
<div class="text-slate-500 text-xs">Missing API Configuration</div>
|
||||
</div>
|
||||
<iframe
|
||||
v-else-if="ytVideoId"
|
||||
:src="`https://www.youtube.com/embed/${ytVideoId}?autoplay=0&rel=0&modestbranding=1`"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowfullscreen
|
||||
class="w-full h-full border-none block"
|
||||
></iframe>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="ytVideoId" class="yt-info-sidebar">
|
||||
<div class="mb-auto">
|
||||
<span class="yt-new-tag">New Release</span>
|
||||
<h3 class="yt-video-title">{{ ytTitle }}</h3>
|
||||
<div class="yt-stats-row">
|
||||
<span v-if="ytPublishDate">📅 {{ ytPublishDate }}</span>
|
||||
<span v-if="ytViewCount">👁 {{ ytViewCount }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-6">
|
||||
<a :href="`https://www.youtube.com/watch?v=${ytVideoId}`" target="_blank" class="yt-play-button">
|
||||
<span class="text-xl">▶</span> Watch on YouTube
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Navigation Window -->
|
||||
<div class="win-window">
|
||||
<div class="win-titlebar">
|
||||
<span class="win-titlebar-text">🗺 Navigation</span>
|
||||
<div class="win-titlebar-btns">
|
||||
<button class="win-titlebar-btn">_</button>
|
||||
<button class="win-titlebar-btn">□</button>
|
||||
<button class="win-titlebar-btn">×</button>
|
||||
<!-- Navigation Grid -->
|
||||
<section class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
|
||||
<div class="nav-card group card-interactive">
|
||||
<div class="nav-card-icon bg-purple-50 group-hover:bg-purple-100">
|
||||
<span class="text-3xl">🎮</span>
|
||||
</div>
|
||||
<h2 class="nav-card-title">Catalog</h2>
|
||||
<p class="nav-card-desc">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>
|
||||
<RouterLink to="/catalog" class="btn-primary bg-purple-600 hover:bg-purple-700 text-white hover:shadow-purple-200">
|
||||
Browse Games
|
||||
</RouterLink>
|
||||
</div>
|
||||
|
||||
<div class="nav-card group card-interactive">
|
||||
<div class="nav-card-icon bg-green-50 group-hover:bg-green-100">
|
||||
<span class="text-3xl">📚</span>
|
||||
</div>
|
||||
<h2 class="nav-card-title">Wiki</h2>
|
||||
<p class="nav-card-desc">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="btn-primary bg-green-600 hover:bg-green-700 text-white hover:shadow-green-200">
|
||||
Knowledge Base
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="nav-card group card-interactive">
|
||||
<div class="nav-card-icon bg-slate-50 group-hover:bg-slate-100">
|
||||
<span class="text-3xl">💻</span>
|
||||
</div>
|
||||
<h2 class="nav-card-title">Git Repos</h2>
|
||||
<p class="nav-card-desc">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="btn-primary bg-slate-800 hover:bg-slate-900 text-white hover:shadow-slate-200">
|
||||
Gitea
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="nav-card group card-interactive">
|
||||
<div class="nav-card-icon bg-red-50 group-hover:bg-red-100">
|
||||
<span class="text-3xl">📺</span>
|
||||
</div>
|
||||
<h2 class="nav-card-title">YouTube</h2>
|
||||
<p class="nav-card-desc">Watch our development vlogs, gameplay videos, and tutorials on our official YouTube channel.</p>
|
||||
<a href="https://www.youtube.com/@teletypegames" target="_blank" rel="noopener noreferrer" class="btn-primary bg-red-600 hover:bg-red-700 text-white hover:shadow-red-200">
|
||||
Watch on YouTube
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- AI Content Notice -->
|
||||
<div class="mb-12 mt-12 bg-white rounded-2xl border border-indigo-100 p-6 shadow-sm flex items-center gap-4">
|
||||
<div class="w-12 h-12 rounded-full bg-indigo-50 flex items-center justify-center text-2xl flex-shrink-0">🤖</div>
|
||||
<div class="flex-grow text-slate-600 text-sm md:text-base italic">
|
||||
<strong>Note:</strong> Our HowTo-s and blog posts are written by AI with human supervision.
|
||||
</div>
|
||||
</div>
|
||||
<div class="win-body">
|
||||
<div class="nav-grid">
|
||||
<div class="nav-item win-raised-panel">
|
||||
<div class="nav-icon">🎮</div>
|
||||
<div class="nav-title">Catalog</div>
|
||||
<div class="nav-desc">Discover our games for TIC-80 and other platforms, many playable directly in browser.</div>
|
||||
<RouterLink to="/catalog" class="win-btn nav-btn">Browse Games</RouterLink>
|
||||
</div>
|
||||
<div class="nav-item win-raised-panel">
|
||||
<div class="nav-icon">📚</div>
|
||||
<div class="nav-title">Wiki</div>
|
||||
<div class="nav-desc">Technical descriptions and development logs from our knowledge base.</div>
|
||||
<a href="https://wiki.teletype.hu" target="_blank" class="win-btn nav-btn">Knowledge Base</a>
|
||||
</div>
|
||||
<div class="nav-item win-raised-panel">
|
||||
<div class="nav-icon">💻</div>
|
||||
<div class="nav-title">Git Repos</div>
|
||||
<div class="nav-desc">All our projects are open source. Browse code, study solutions, or contribute.</div>
|
||||
<a href="https://git.teletype.hu" target="_blank" class="win-btn nav-btn">Gitea</a>
|
||||
</div>
|
||||
<div class="nav-item win-raised-panel">
|
||||
<div class="nav-icon">📺</div>
|
||||
<div class="nav-title">YouTube</div>
|
||||
<div class="nav-desc">Development vlogs, gameplay videos, and tutorials on our official channel.</div>
|
||||
<a href="https://www.youtube.com/@teletypegames" target="_blank" class="win-btn nav-btn">Watch on YouTube</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- AI Notice -->
|
||||
<div class="win-notice-info">
|
||||
<span>🤖</span>
|
||||
<span><strong>Note:</strong> Our HowTo-s and blog posts are written by AI with human supervision.</span>
|
||||
</div>
|
||||
|
||||
</main>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -284,204 +293,132 @@ onUnmounted(() => {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.home-two-col {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 8px;
|
||||
margin-bottom: 0;
|
||||
.home-container {
|
||||
@apply bg-gray-50 min-h-screen pb-20;
|
||||
}
|
||||
.home-header-decor {
|
||||
@apply absolute inset-0 opacity-30;
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.home-two-col {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
/* Featured Card */
|
||||
.featured-card {
|
||||
@apply relative overflow-hidden bg-gradient-to-br from-indigo-900 to-slate-900 rounded-3xl shadow-2xl flex flex-col md:flex-row min-h-[400px];
|
||||
}
|
||||
|
||||
/* Countdown */
|
||||
.countdown-name {
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 1px;
|
||||
color: #000080;
|
||||
margin-bottom: 8px;
|
||||
.featured-content {
|
||||
@apply p-8 md:p-12 flex flex-col justify-center flex-1 z-10;
|
||||
}
|
||||
.countdown-display {
|
||||
display: inline-block;
|
||||
padding: 6px 12px;
|
||||
margin: 4px auto 8px;
|
||||
}
|
||||
.countdown-mono {
|
||||
font-family: "Courier New", Courier, monospace;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
letter-spacing: 2px;
|
||||
color: #000080;
|
||||
}
|
||||
.countdown-date {
|
||||
font-size: 11px;
|
||||
color: #404040;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.upcoming-section {
|
||||
text-align: left;
|
||||
margin-top: 8px;
|
||||
}
|
||||
.upcoming-label {
|
||||
font-size: 11px;
|
||||
font-weight: bold;
|
||||
color: #000080;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.upcoming-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 2px 4px;
|
||||
font-size: 12px;
|
||||
border-bottom: 1px solid #D0D0D0;
|
||||
}
|
||||
.upcoming-row:hover {
|
||||
background: #000080;
|
||||
color: #fff;
|
||||
}
|
||||
.upcoming-date-mono {
|
||||
font-family: "Courier New", Courier, monospace;
|
||||
font-size: 11px;
|
||||
color: #404040;
|
||||
}
|
||||
.upcoming-row:hover .upcoming-date-mono {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* Featured */
|
||||
.featured-body {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: flex-start;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.featured-img-wrap { flex-shrink: 0; }
|
||||
.featured-img {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
object-fit: cover;
|
||||
border: 2px solid;
|
||||
border-color: #808080 #fff #fff #808080;
|
||||
}
|
||||
.featured-info { flex: 1; min-width: 160px; }
|
||||
.featured-badges {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.featured-version {
|
||||
font-family: "Courier New", Courier, monospace;
|
||||
font-size: 11px;
|
||||
color: #404040;
|
||||
.featured-badge {
|
||||
@apply px-3 py-1 bg-indigo-500/20 text-indigo-300 border border-indigo-400/30 rounded-full text-xs font-bold uppercase tracking-wider;
|
||||
}
|
||||
.featured-title {
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 4px;
|
||||
@apply text-4xl md:text-5xl font-black text-white mb-6;
|
||||
}
|
||||
.featured-desc {
|
||||
font-size: 11px;
|
||||
color: #404040;
|
||||
margin-bottom: 10px;
|
||||
line-height: 1.5;
|
||||
@apply text-indigo-100/80 text-lg leading-relaxed max-w-xl;
|
||||
}
|
||||
.featured-actions {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
flex-wrap: wrap;
|
||||
.featured-btn-play {
|
||||
@apply px-8 py-4 bg-white text-indigo-900 font-bold rounded-xl transition-all hover:scale-105 hover:shadow-xl hover:shadow-indigo-500/20 active:scale-95;
|
||||
}
|
||||
.featured-btn-secondary {
|
||||
@apply px-8 py-4 bg-indigo-500/10 text-white border border-indigo-400/30 font-bold rounded-xl transition-all hover:bg-indigo-500/20;
|
||||
}
|
||||
.featured-image-panel {
|
||||
@apply flex-shrink-0 flex items-center justify-center p-6 md:p-8;
|
||||
}
|
||||
.featured-image {
|
||||
@apply max-h-48 w-auto object-contain border-4 border-white shadow-xl opacity-90 group-hover:opacity-100 transition-opacity;
|
||||
}
|
||||
.featured-version-badge {
|
||||
@apply px-2 py-0.5 rounded text-[10px] font-bold bg-white/10 text-white/70 border border-white/20;
|
||||
}
|
||||
|
||||
/* YouTube */
|
||||
.yt-layout {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: flex-start;
|
||||
flex-wrap: wrap;
|
||||
/* Status Badges */
|
||||
.status-badge {
|
||||
@apply px-2 py-0.5 rounded text-[10px] font-bold uppercase;
|
||||
}
|
||||
.yt-player {
|
||||
flex: 1.6;
|
||||
min-width: 200px;
|
||||
aspect-ratio: 16 / 9;
|
||||
overflow: hidden;
|
||||
.status-released { @apply bg-green-500/20 text-green-300 border border-green-500/30; }
|
||||
.status-demo { @apply bg-blue-500/20 text-blue-300 border border-blue-500/30; }
|
||||
.status-development { @apply bg-yellow-500/20 text-yellow-300 border border-yellow-500/30; }
|
||||
.status-archived { @apply bg-gray-500/20 text-gray-300 border border-gray-500/30; }
|
||||
|
||||
/* Countdown Card */
|
||||
.countdown-card {
|
||||
@apply bg-white rounded-2xl shadow-xl overflow-hidden border border-gray-100 p-8 md:p-12 text-center transition-all duration-300;
|
||||
}
|
||||
.yt-state {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
min-height: 120px;
|
||||
font-size: 12px;
|
||||
color: #404040;
|
||||
padding: 16px;
|
||||
.countdown-event-name {
|
||||
@apply text-2xl font-bold text-gray-400 uppercase tracking-widest mb-2;
|
||||
}
|
||||
.yt-state-error { color: #800000; }
|
||||
.yt-info {
|
||||
flex: 1;
|
||||
min-width: 140px;
|
||||
.countdown-timer {
|
||||
@apply 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;
|
||||
}
|
||||
.yt-title {
|
||||
font-size: 13px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 4px;
|
||||
color: #000080;
|
||||
line-height: 1.4;
|
||||
.countdown-date {
|
||||
@apply text-gray-500 text-lg;
|
||||
}
|
||||
.yt-meta {
|
||||
font-size: 11px;
|
||||
color: #404040;
|
||||
margin-bottom: 10px;
|
||||
font-family: "Courier New", Courier, monospace;
|
||||
.upcoming-events-section {
|
||||
@apply mt-12 pt-12 border-t border-gray-100 text-left max-w-2xl mx-auto;
|
||||
}
|
||||
.yt-actions {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
.upcoming-events-title {
|
||||
@apply text-xl font-bold text-gray-900 mb-6;
|
||||
}
|
||||
.upcoming-event-item {
|
||||
@apply flex items-center justify-between p-4 bg-gray-50 rounded-xl border border-gray-100;
|
||||
}
|
||||
|
||||
/* Navigation Grid */
|
||||
.nav-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 6px;
|
||||
/* Nav Cards */
|
||||
.nav-card {
|
||||
@apply flex flex-col h-full;
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
.nav-grid { grid-template-columns: repeat(2, 1fr); }
|
||||
.nav-card-icon {
|
||||
@apply w-14 h-14 rounded-xl flex items-center justify-center mb-6 transition-colors;
|
||||
}
|
||||
@media (max-width: 420px) {
|
||||
.nav-grid { grid-template-columns: 1fr; }
|
||||
.nav-card-title {
|
||||
@apply text-2xl font-bold text-gray-900 mb-3;
|
||||
}
|
||||
.nav-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
padding: 8px;
|
||||
.nav-card-desc {
|
||||
@apply text-gray-600 mb-6 flex-grow leading-relaxed;
|
||||
}
|
||||
.nav-icon {
|
||||
font-size: 22px;
|
||||
margin-bottom: 4px;
|
||||
|
||||
/* YouTube Featured Wrapper */
|
||||
.yt-featured-wrapper {
|
||||
@apply relative overflow-hidden bg-gradient-to-br from-slate-900 via-slate-900 to-indigo-950 rounded-3xl shadow-2xl border border-slate-800 p-6 md:p-8;
|
||||
}
|
||||
.nav-title {
|
||||
font-size: 13px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 3px;
|
||||
.yt-glow {
|
||||
@apply absolute -top-24 -right-24 w-96 h-96 bg-indigo-500/10 rounded-full blur-[100px] pointer-events-none;
|
||||
}
|
||||
.nav-desc {
|
||||
font-size: 11px;
|
||||
color: #404040;
|
||||
margin-bottom: 8px;
|
||||
flex-grow: 1;
|
||||
line-height: 1.5;
|
||||
.yt-header-area {
|
||||
@apply flex items-center justify-between mb-6 relative z-10;
|
||||
}
|
||||
.nav-btn {
|
||||
margin-top: auto;
|
||||
min-width: auto;
|
||||
font-size: 11px;
|
||||
padding: 2px 8px 3px;
|
||||
.yt-status-blob {
|
||||
@apply w-3 h-3 bg-red-500/20 rounded-full flex items-center justify-center;
|
||||
}
|
||||
.yt-status-dot {
|
||||
@apply w-1.5 h-1.5 bg-red-500 rounded-full animate-pulse;
|
||||
}
|
||||
.yt-label-text {
|
||||
@apply text-xs font-bold uppercase tracking-widest text-slate-400;
|
||||
}
|
||||
.yt-channel-link {
|
||||
@apply text-xs font-semibold text-indigo-400 hover:text-indigo-300 transition-colors;
|
||||
}
|
||||
.yt-content-grid {
|
||||
@apply flex flex-col lg:flex-row gap-8 relative z-10;
|
||||
}
|
||||
.yt-player-container {
|
||||
@apply flex-[1.6] overflow-hidden rounded-2xl border border-white/5 shadow-inner bg-black;
|
||||
}
|
||||
.yt-info-sidebar {
|
||||
@apply flex-1 flex flex-col justify-center;
|
||||
}
|
||||
.yt-new-tag {
|
||||
@apply inline-block px-2 py-1 bg-red-500/10 text-red-400 border border-red-500/20 rounded-md text-[10px] font-black uppercase tracking-tighter mb-4;
|
||||
}
|
||||
.yt-video-title {
|
||||
@apply text-2xl font-black text-white mb-4 leading-tight group-hover:text-indigo-200 transition-colors;
|
||||
}
|
||||
.yt-stats-row {
|
||||
@apply flex gap-4 text-sm text-slate-400 font-medium;
|
||||
}
|
||||
.yt-play-button {
|
||||
@apply flex items-center justify-center gap-2 w-full py-4 bg-white text-slate-900 font-black rounded-xl transition-all hover:scale-[1.02] hover:bg-indigo-50 active:scale-95 shadow-xl;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,66 +1,79 @@
|
||||
<template>
|
||||
<div class="main-container">
|
||||
<div class="win-window">
|
||||
<div class="win-titlebar">
|
||||
<span class="win-titlebar-text">📖 Tech HowTo Center</span>
|
||||
<div class="win-titlebar-btns">
|
||||
<button class="win-titlebar-btn">_</button>
|
||||
<button class="win-titlebar-btn">□</button>
|
||||
<button class="win-titlebar-btn">×</button>
|
||||
<div class="howtos-container">
|
||||
<header class="hero-section-slate">
|
||||
<div class="howtos-header-decor">
|
||||
<div class="hero-decor-blob -top-24 -left-24 h-96 w-96 bg-indigo-600"></div>
|
||||
<div class="hero-decor-blob -bottom-24 -right-24 h-96 w-96 bg-purple-600"></div>
|
||||
</div>
|
||||
|
||||
<div class="hero-container">
|
||||
<div class="hero-badge">Knowledge Base</div>
|
||||
<h1 class="hero-title">
|
||||
Tech <span class="text-transparent bg-clip-text bg-gradient-to-r from-indigo-400 to-purple-400">HowTo Center</span>
|
||||
</h1>
|
||||
<p class="hero-subtitle mb-10">
|
||||
The latest documentation, technical guides, and development logs from our knowledge base.
|
||||
</p>
|
||||
<a :href="WIKI_BASE" target="_blank" class="btn-hero-indigo">
|
||||
Knowledge Base
|
||||
</a>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="main-container">
|
||||
<div v-if="error" class="error-banner" role="alert">
|
||||
<span class="text-2xl">⚠️</span>
|
||||
<div>
|
||||
<h3 class="error-banner-title">Failed to connect to Wiki</h3>
|
||||
<p class="error-banner-desc">{{ error }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="win-toolbar">
|
||||
<a :href="WIKI_BASE" target="_blank" class="win-btn win-btn-sm">Open Wiki ↗</a>
|
||||
<span style="font-size: 11px; color: #404040; margin-left: 4px;">
|
||||
Latest documentation, technical guides, and development logs.
|
||||
</span>
|
||||
<div v-else-if="!loading && recentPages.length === 0" class="empty-state">
|
||||
<div class="empty-state-icon">📭</div>
|
||||
<h2 class="empty-state-title">No pages found</h2>
|
||||
<p class="empty-state-desc">It seems like there aren't any public pages available on the wiki at the moment.</p>
|
||||
</div>
|
||||
|
||||
<div class="win-body" style="padding: 0;">
|
||||
|
||||
<div v-if="error" class="win-notice-error" style="margin: 8px;">
|
||||
<span>⚠</span>
|
||||
<div>
|
||||
<strong>Failed to connect to Wiki</strong><br>
|
||||
<span style="font-size: 11px;">{{ error }}</span>
|
||||
<div v-else class="card-grid">
|
||||
<a
|
||||
v-for="page in recentPages"
|
||||
:key="page.id"
|
||||
:href="`${WIKI_BASE}/${page.locale}/${page.path}`"
|
||||
target="_blank"
|
||||
class="group card-interactive flex flex-col"
|
||||
>
|
||||
<div class="howto-card-meta">
|
||||
<div class="howto-card-timestamp">
|
||||
<span v-if="isNew(page.createdAt)" class="new-badge">
|
||||
<span class="new-dot"></span>
|
||||
New
|
||||
</span>
|
||||
<span>{{ formatDateTime(page.updatedAt) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else-if="!loading && recentPages.length === 0" class="empty-state">
|
||||
<div style="font-size: 32px; margin-bottom: 8px;">📭</div>
|
||||
<div style="font-weight: bold; margin-bottom: 4px;">No pages found</div>
|
||||
<div style="font-size: 11px; color: #404040;">No public pages available on the wiki at the moment.</div>
|
||||
</div>
|
||||
<h2 class="howto-card-title">{{ page.title }}</h2>
|
||||
|
||||
<div v-else class="howto-grid">
|
||||
<a
|
||||
v-for="page in recentPages"
|
||||
:key="page.id"
|
||||
:href="`${WIKI_BASE}/${page.locale}/${page.path}`"
|
||||
target="_blank"
|
||||
class="howto-card win-raised-panel"
|
||||
>
|
||||
<div class="howto-meta">
|
||||
<span v-if="isNew(page.createdAt)" class="new-badge">★ New</span>
|
||||
<span class="howto-date">{{ formatDateTime(page.updatedAt) }}</span>
|
||||
</div>
|
||||
<div class="howto-title">{{ page.title }}</div>
|
||||
<div v-if="page.description" class="howto-desc">{{ page.description }}</div>
|
||||
<div v-else class="howto-no-desc">No description provided.</div>
|
||||
<div class="howto-footer">
|
||||
<span class="howto-path">{{ page.path }}</span>
|
||||
<span class="howto-arrow">Read →</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div v-if="!error && recentPages.length > 0" class="howto-more">
|
||||
<a :href="WIKI_BASE" target="_blank" class="win-btn">Browse All Wiki Pages →</a>
|
||||
</div>
|
||||
<p v-if="page.description" class="howto-card-desc">{{ page.description }}</p>
|
||||
<div v-else class="howto-card-no-desc">No description provided.</div>
|
||||
|
||||
<div class="howto-card-footer">
|
||||
<span class="howto-card-path">{{ page.path }}</span>
|
||||
<span class="howto-card-read-link">Read <span class="text-lg">→</span></span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="!error && recentPages.length > 0" class="howtos-footer">
|
||||
<a :href="WIKI_BASE" target="_blank" class="browse-wiki-btn">
|
||||
Browse Wiki Home
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path fill-rule="evenodd" d="M10.293 3.293a1 1 0 011.414 0l6 6a1 1 0 010 1.414l-6 6a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-4.293-4.293a1 1 0 010-1.414z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -90,110 +103,58 @@ onMounted(async () => {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.howtos-container {
|
||||
@apply bg-gray-50 min-h-screen pb-20;
|
||||
}
|
||||
.howtos-header-decor {
|
||||
@apply absolute inset-0 opacity-30;
|
||||
}
|
||||
.banner-base {
|
||||
@apply max-w-7xl mx-auto border-l-4 p-6 rounded-r-xl shadow-lg mb-12 flex items-start gap-4;
|
||||
}
|
||||
.error-banner { @apply banner-base bg-red-50 border-red-500; }
|
||||
.error-banner-title { @apply text-red-800 font-bold text-lg; }
|
||||
.error-banner-desc { @apply text-red-700 mt-1; }
|
||||
.empty-state {
|
||||
text-align: center;
|
||||
padding: 24px;
|
||||
color: #404040;
|
||||
font-size: 12px;
|
||||
@apply max-w-7xl mx-auto bg-white rounded-2xl shadow-xl p-12 text-center border border-gray-100;
|
||||
}
|
||||
|
||||
.howto-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 6px;
|
||||
padding: 6px;
|
||||
.empty-state-icon { @apply text-6xl mb-4; }
|
||||
.empty-state-title { @apply text-2xl font-bold text-gray-900 mb-2; }
|
||||
.empty-state-desc { @apply text-gray-500 max-w-md mx-auto; }
|
||||
.howto-card-meta {
|
||||
@apply flex items-center justify-end mb-4;
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
.howto-grid { grid-template-columns: repeat(2, 1fr); }
|
||||
}
|
||||
@media (max-width: 480px) {
|
||||
.howto-grid { grid-template-columns: 1fr; }
|
||||
}
|
||||
|
||||
.howto-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 7px;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
cursor: pointer;
|
||||
}
|
||||
.howto-card:hover {
|
||||
background: #EEF0F8;
|
||||
}
|
||||
|
||||
.howto-meta {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
margin-bottom: 3px;
|
||||
.howto-card-timestamp {
|
||||
@apply flex items-center gap-2 text-xs font-semibold uppercase tracking-wider text-gray-400;
|
||||
}
|
||||
.new-badge {
|
||||
font-size: 10px;
|
||||
font-weight: bold;
|
||||
background: #C8F0C8;
|
||||
color: #007000;
|
||||
border: 1px solid #009000;
|
||||
padding: 0 3px;
|
||||
@apply flex items-center gap-1 text-green-600 bg-green-50 px-2 py-0.5 rounded-full border border-green-100;
|
||||
}
|
||||
.howto-date {
|
||||
font-size: 10px;
|
||||
color: #808080;
|
||||
font-family: "Courier New", Courier, monospace;
|
||||
.new-dot {
|
||||
@apply w-1.5 h-1.5 rounded-full bg-green-500 animate-pulse;
|
||||
}
|
||||
.howto-title {
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
color: #000080;
|
||||
margin-bottom: 3px;
|
||||
line-height: 1.3;
|
||||
.howto-card-title {
|
||||
@apply text-xl font-bold text-gray-900 group-hover:text-indigo-600 transition-colors mb-2 line-clamp-2 leading-tight;
|
||||
}
|
||||
.howto-card:hover .howto-title { color: #0000FF; }
|
||||
.howto-desc {
|
||||
font-size: 11px;
|
||||
color: #404040;
|
||||
margin-bottom: 4px;
|
||||
flex-grow: 1;
|
||||
line-height: 1.4;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 3;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
.howto-card-desc {
|
||||
@apply text-gray-600 text-sm mb-4 line-clamp-3 leading-relaxed flex-grow;
|
||||
}
|
||||
.howto-no-desc {
|
||||
font-size: 11px;
|
||||
color: #808080;
|
||||
font-style: italic;
|
||||
flex-grow: 1;
|
||||
margin-bottom: 4px;
|
||||
.howto-card-no-desc {
|
||||
@apply flex-grow mb-4 italic text-gray-400 text-sm;
|
||||
}
|
||||
.howto-footer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
border-top: 1px solid #D0D0D0;
|
||||
padding-top: 4px;
|
||||
margin-top: auto;
|
||||
.howto-card-footer {
|
||||
@apply pt-4 border-t border-gray-100 mt-auto flex items-center justify-between;
|
||||
}
|
||||
.howto-path {
|
||||
font-size: 10px;
|
||||
color: #808080;
|
||||
font-family: "Courier New", Courier, monospace;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
max-width: 120px;
|
||||
.howto-card-path {
|
||||
@apply text-xs font-mono text-gray-400 truncate max-w-[180px];
|
||||
}
|
||||
.howto-arrow {
|
||||
font-size: 11px;
|
||||
color: #000080;
|
||||
font-weight: bold;
|
||||
flex-shrink: 0;
|
||||
.howto-card-read-link {
|
||||
@apply text-indigo-600 text-sm font-bold flex items-center gap-1 group-hover:translate-x-1 transition-transform;
|
||||
}
|
||||
|
||||
.howto-more {
|
||||
padding: 8px;
|
||||
border-top: 1px solid #D0D0D0;
|
||||
text-align: center;
|
||||
.howtos-footer {
|
||||
@apply mt-16 text-center;
|
||||
}
|
||||
.browse-wiki-btn {
|
||||
@apply inline-flex items-center gap-2 bg-slate-900 text-white px-8 py-4 rounded-xl hover:bg-slate-800 transition-all font-bold shadow-lg hover:shadow-indigo-200/50;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,36 +1,26 @@
|
||||
<template>
|
||||
<div class="main-container">
|
||||
<div class="win-window">
|
||||
<div class="win-titlebar">
|
||||
<span class="win-titlebar-text">👥 Our Team</span>
|
||||
<div class="win-titlebar-btns">
|
||||
<button class="win-titlebar-btn">_</button>
|
||||
<button class="win-titlebar-btn">□</button>
|
||||
<button class="win-titlebar-btn">×</button>
|
||||
<header class="hero-section-gradient from-purple-600 to-blue-700 py-20 text-white">
|
||||
<div class="hero-container text-center">
|
||||
<h1 class="hero-title mb-6">Our Team</h1>
|
||||
<p class="hero-subtitle mb-10 text-purple-100">
|
||||
Meet the brilliant minds behind Teletype Games.
|
||||
</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="main-container py-16 px-4">
|
||||
<div class="team-grid">
|
||||
<div v-for="member in members" :key="member.nick" class="team-card">
|
||||
<div class="team-card-image-container">
|
||||
<img :src="resolvedAvatarUrl(member)" :alt="member.nick" class="team-card-image" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="win-body">
|
||||
<p style="margin: 0 0 8px; font-size: 12px; color: #404040;">
|
||||
Meet the people behind Teletype Games.
|
||||
</p>
|
||||
|
||||
<div class="team-grid">
|
||||
<div v-for="member in members" :key="member.nick" class="team-card win-raised-panel">
|
||||
<div class="team-img-wrap">
|
||||
<img :src="resolvedAvatarUrl(member)" :alt="member.nick" class="team-img" />
|
||||
</div>
|
||||
<div class="team-info">
|
||||
<div class="team-nick">{{ member.nick }}</div>
|
||||
<div class="team-realname">{{ member.real_nick }}</div>
|
||||
<div class="win-separator"></div>
|
||||
<div class="team-motto">{{ member.motto }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="team-card-content">
|
||||
<h2 class="team-card-title">{{ member.nick }}: {{ member.real_nick }}</h2>
|
||||
<p class="team-card-desc">{{ member.motto }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
@@ -56,54 +46,24 @@ onMounted(async () => {
|
||||
|
||||
<style scoped>
|
||||
.team-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 6px;
|
||||
@apply grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-8 max-w-7xl mx-auto;
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
.team-grid { grid-template-columns: repeat(2, 1fr); }
|
||||
}
|
||||
@media (max-width: 420px) {
|
||||
.team-grid { grid-template-columns: 1fr; }
|
||||
}
|
||||
|
||||
.team-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 8px;
|
||||
text-align: center;
|
||||
@apply bg-white rounded-2xl shadow-xl overflow-hidden border border-gray-100 transition-all hover:scale-105;
|
||||
}
|
||||
.team-img-wrap {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
overflow: hidden;
|
||||
border: 2px solid;
|
||||
border-color: #808080 #fff #fff #808080;
|
||||
margin-bottom: 8px;
|
||||
flex-shrink: 0;
|
||||
.team-card-image-container {
|
||||
@apply aspect-square overflow-hidden bg-gray-200;
|
||||
}
|
||||
.team-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
.team-card-image {
|
||||
@apply w-full h-full object-cover;
|
||||
}
|
||||
.team-info { width: 100%; }
|
||||
.team-nick {
|
||||
font-size: 13px;
|
||||
font-weight: bold;
|
||||
color: #000080;
|
||||
margin-bottom: 2px;
|
||||
.team-card-content {
|
||||
@apply p-6;
|
||||
}
|
||||
.team-realname {
|
||||
font-size: 11px;
|
||||
color: #404040;
|
||||
margin-bottom: 4px;
|
||||
.team-card-title {
|
||||
@apply text-xl font-black text-gray-900 mb-2;
|
||||
}
|
||||
.team-motto {
|
||||
font-size: 11px;
|
||||
color: #404040;
|
||||
font-style: italic;
|
||||
line-height: 1.4;
|
||||
.team-card-desc {
|
||||
@apply text-gray-600 leading-relaxed;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -2,489 +2,98 @@
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
/* ===== WIN98/2000 DESIGN SYSTEM ===== */
|
||||
:root {
|
||||
--w-bg: #D4D0C8;
|
||||
--w-face: #D4D0C8;
|
||||
--w-text: #000000;
|
||||
--w-gray: #808080;
|
||||
--w-dark: #404040;
|
||||
--w-ink: #0a0a0a;
|
||||
--w-white: #FFFFFF;
|
||||
--w-titlebar-start: #000080;
|
||||
--w-titlebar-end: #1084D0;
|
||||
--w-select: #000080;
|
||||
--w-select-text: #FFFFFF;
|
||||
--w-window: #FFFFFF;
|
||||
--w-font: Tahoma, "MS Sans Serif", Arial, sans-serif;
|
||||
}
|
||||
|
||||
html, body {
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
min-height: 100%;
|
||||
font-family: var(--w-font);
|
||||
font-size: 13px;
|
||||
background: var(--w-bg);
|
||||
color: var(--w-text);
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
* { box-sizing: border-box; }
|
||||
|
||||
@layer components {
|
||||
|
||||
/* ---- BUTTONS ---- */
|
||||
.win-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 4px;
|
||||
padding: 3px 12px 4px;
|
||||
min-height: 23px;
|
||||
min-width: 75px;
|
||||
background: var(--w-face);
|
||||
color: var(--w-text);
|
||||
font-family: var(--w-font);
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
border: 1px solid #0a0a0a;
|
||||
border-radius: 0;
|
||||
text-decoration: none;
|
||||
white-space: nowrap;
|
||||
box-shadow:
|
||||
inset 1px 1px 0 0 #fff,
|
||||
inset -1px -1px 0 0 #404040,
|
||||
inset 2px 2px 0 0 #D4D0C8,
|
||||
inset -2px -2px 0 0 #808080;
|
||||
user-select: none;
|
||||
/* Hero Section */
|
||||
.hero-section {
|
||||
@apply relative overflow-hidden py-24 text-white text-center;
|
||||
}
|
||||
|
||||
.win-btn:active,
|
||||
.win-btn.is-active {
|
||||
box-shadow:
|
||||
inset 1px 1px 0 0 #404040,
|
||||
inset -1px -1px 0 0 #fff,
|
||||
inset 2px 2px 0 0 #808080,
|
||||
inset -2px -2px 0 0 #D4D0C8;
|
||||
padding: 4px 11px 3px 13px;
|
||||
.hero-section-gradient {
|
||||
@apply hero-section bg-gradient-to-r;
|
||||
}
|
||||
|
||||
.win-btn-sm {
|
||||
@apply win-btn;
|
||||
min-height: 20px;
|
||||
min-width: 50px;
|
||||
padding: 2px 8px 3px;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.win-btn-default-action {
|
||||
@apply win-btn;
|
||||
border: 2px solid #0a0a0a;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* ---- WINDOWS ---- */
|
||||
.win-window {
|
||||
background: var(--w-face);
|
||||
border: 1px solid #0a0a0a;
|
||||
box-shadow:
|
||||
inset 1px 1px 0 0 #fff,
|
||||
inset -1px -1px 0 0 #808080;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.win-titlebar {
|
||||
background: linear-gradient(to right, var(--w-titlebar-start), var(--w-titlebar-end));
|
||||
color: #fff;
|
||||
font-family: var(--w-font);
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
padding: 3px 2px 3px 6px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
user-select: none;
|
||||
min-height: 20px;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.win-titlebar-text {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
.win-titlebar-btns {
|
||||
display: flex;
|
||||
gap: 2px;
|
||||
margin-left: 4px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.win-titlebar-btn {
|
||||
width: 16px;
|
||||
height: 14px;
|
||||
background: var(--w-face);
|
||||
color: var(--w-text);
|
||||
font-size: 9px;
|
||||
font-weight: bold;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: default;
|
||||
border: 1px solid #0a0a0a;
|
||||
border-radius: 0;
|
||||
user-select: none;
|
||||
box-shadow:
|
||||
inset 1px 1px 0 0 #fff,
|
||||
inset -1px -1px 0 0 #404040,
|
||||
inset 2px 2px 0 0 #D4D0C8,
|
||||
inset -2px -2px 0 0 #808080;
|
||||
flex-shrink: 0;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.win-body {
|
||||
padding: 8px;
|
||||
background: var(--w-face);
|
||||
font-family: var(--w-font);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.win-content-area {
|
||||
padding: 8px;
|
||||
background: var(--w-window);
|
||||
box-shadow:
|
||||
inset 1px 1px 0 0 #808080,
|
||||
inset -1px -1px 0 0 #fff;
|
||||
}
|
||||
|
||||
.win-inset {
|
||||
background: var(--w-window);
|
||||
box-shadow:
|
||||
inset 1px 1px 0 0 #808080,
|
||||
inset -1px -1px 0 0 #D4D0C8,
|
||||
inset 2px 2px 0 0 #0a0a0a,
|
||||
inset -2px -2px 0 0 #fff;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.win-raised-panel {
|
||||
background: var(--w-face);
|
||||
box-shadow:
|
||||
inset 1px 1px 0 0 #fff,
|
||||
inset -1px -1px 0 0 #808080;
|
||||
padding: 6px;
|
||||
}
|
||||
|
||||
/* ---- NAVIGATION ---- */
|
||||
.win-menubar {
|
||||
background: var(--w-face);
|
||||
font-family: var(--w-font);
|
||||
font-size: 12px;
|
||||
border-bottom: 1px solid var(--w-gray);
|
||||
box-shadow: 0 1px 0 #fff;
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
min-height: 22px;
|
||||
}
|
||||
|
||||
.win-menu-logo {
|
||||
font-weight: bold;
|
||||
font-size: 12px;
|
||||
padding: 3px 10px;
|
||||
color: var(--w-text);
|
||||
border-right: 1px solid #808080;
|
||||
box-shadow: inset -1px 0 0 #fff;
|
||||
user-select: none;
|
||||
white-space: nowrap;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.win-menu-items {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.win-menu-item {
|
||||
padding: 0 8px;
|
||||
color: var(--w-text);
|
||||
text-decoration: none;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
white-space: nowrap;
|
||||
cursor: default;
|
||||
user-select: none;
|
||||
font-size: 12px;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
.win-menu-item:hover,
|
||||
.win-menu-item.router-link-exact-active {
|
||||
background: var(--w-select);
|
||||
color: var(--w-select-text);
|
||||
}
|
||||
|
||||
/* ---- STATUS BAR ---- */
|
||||
.win-statusbar {
|
||||
background: var(--w-face);
|
||||
border-top: 1px solid var(--w-gray);
|
||||
box-shadow: inset 0 1px 0 #fff;
|
||||
padding: 2px 4px;
|
||||
font-size: 11px;
|
||||
font-family: var(--w-font);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.win-status-panel {
|
||||
box-shadow:
|
||||
inset 1px 1px 0 0 #808080,
|
||||
inset -1px -1px 0 0 #fff;
|
||||
padding: 1px 6px;
|
||||
flex: 1;
|
||||
font-size: 11px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
/* ---- LAYOUT ---- */
|
||||
.main-container {
|
||||
max-width: 960px;
|
||||
margin: 0 auto;
|
||||
padding: 8px;
|
||||
position: relative;
|
||||
z-index: auto;
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
|
||||
/* ---- TOOLBAR ---- */
|
||||
.win-toolbar {
|
||||
background: var(--w-face);
|
||||
padding: 3px 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
border-bottom: 1px solid var(--w-gray);
|
||||
box-shadow: 0 1px 0 #fff;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
/* ---- TABLE ---- */
|
||||
.win-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-family: var(--w-font);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.win-table th {
|
||||
background: var(--w-face);
|
||||
text-align: left;
|
||||
padding: 3px 8px;
|
||||
font-weight: bold;
|
||||
border: 1px solid var(--w-gray);
|
||||
white-space: nowrap;
|
||||
cursor: default;
|
||||
box-shadow:
|
||||
inset 1px 1px 0 0 #fff,
|
||||
inset -1px -1px 0 0 #808080;
|
||||
}
|
||||
|
||||
.win-table td {
|
||||
padding: 3px 8px;
|
||||
border-bottom: 1px solid #D0D0D0;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.win-table tr:hover td {
|
||||
background: var(--w-select);
|
||||
color: var(--w-select-text);
|
||||
}
|
||||
|
||||
.win-table tr:hover td a {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* ---- INPUT ---- */
|
||||
.win-input {
|
||||
border: 1px solid #0a0a0a;
|
||||
border-radius: 0;
|
||||
background: #fff;
|
||||
padding: 2px 4px;
|
||||
font-family: var(--w-font);
|
||||
font-size: 12px;
|
||||
box-shadow:
|
||||
inset 1px 1px 0 0 #808080,
|
||||
inset -1px -1px 0 0 #D4D0C8,
|
||||
inset 2px 2px 0 0 #0a0a0a,
|
||||
inset -2px -2px 0 0 #fff;
|
||||
}
|
||||
|
||||
.win-textarea {
|
||||
@apply win-input;
|
||||
resize: vertical;
|
||||
padding: 4px;
|
||||
min-height: 80px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* ---- STATUS BADGES ---- */
|
||||
.status-badge {
|
||||
padding: 1px 5px;
|
||||
font-size: 10px;
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
font-family: var(--w-font);
|
||||
border: 1px solid;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.status-released { background: #C8F0C8; color: #007000; border-color: #009000; }
|
||||
.status-demo { background: #C8C8FF; color: #000080; border-color: #0000C0; }
|
||||
.status-development { background: #FFFFC8; color: #808000; border-color: #B0A000; }
|
||||
.status-archived { background: #E0E0E0; color: #404040; border-color: #808080; }
|
||||
|
||||
/* ---- SEPARATORS ---- */
|
||||
.win-separator {
|
||||
border: none;
|
||||
border-top: 1px solid var(--w-gray);
|
||||
border-bottom: 1px solid #fff;
|
||||
margin: 4px 2px;
|
||||
}
|
||||
|
||||
/* ---- NOTIFICATION BOXES ---- */
|
||||
.win-notice-info {
|
||||
background: #CCCCFF;
|
||||
border-left: 3px solid #0000CC;
|
||||
border: 1px solid #0000CC;
|
||||
padding: 6px 8px;
|
||||
font-size: 12px;
|
||||
margin-bottom: 8px;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.win-notice-warning {
|
||||
background: #FFFFC8;
|
||||
border: 1px solid #AAAA00;
|
||||
padding: 6px 8px;
|
||||
font-size: 12px;
|
||||
margin-bottom: 8px;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.win-notice-error {
|
||||
background: #FFCCCC;
|
||||
border: 1px solid #CC0000;
|
||||
padding: 6px 8px;
|
||||
font-size: 12px;
|
||||
margin-bottom: 8px;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
/* ---- CARD GRID ---- */
|
||||
.card-grid {
|
||||
@apply grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.card-base {
|
||||
@apply win-window;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.card-interactive {
|
||||
@apply win-window;
|
||||
padding: 8px;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
/* ---- LEGACY HERO OVERRIDES ---- */
|
||||
.hero-section,
|
||||
.hero-section-gradient,
|
||||
.hero-section-slate {
|
||||
display: none;
|
||||
@apply hero-section bg-slate-900;
|
||||
}
|
||||
|
||||
.hero-badge,
|
||||
.hero-decor-blob,
|
||||
.hero-container,
|
||||
.home-header-decor,
|
||||
.howtos-header-decor,
|
||||
.blog-header-decor {
|
||||
display: none;
|
||||
.hero-container {
|
||||
@apply relative max-w-5xl mx-auto px-4 z-10;
|
||||
}
|
||||
|
||||
.hero-badge {
|
||||
@apply 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;
|
||||
}
|
||||
|
||||
.hero-title {
|
||||
font-size: 15px;
|
||||
font-weight: bold;
|
||||
font-family: var(--w-font);
|
||||
color: var(--w-text);
|
||||
margin: 0;
|
||||
text-transform: none;
|
||||
@apply text-5xl md:text-6xl font-extrabold tracking-tight mb-6;
|
||||
}
|
||||
|
||||
.hero-subtitle {
|
||||
font-size: 12px;
|
||||
font-family: var(--w-font);
|
||||
color: var(--w-dark);
|
||||
margin: 4px 0 0;
|
||||
@apply text-lg md:text-xl text-slate-300 max-w-2xl mx-auto leading-relaxed;
|
||||
}
|
||||
|
||||
/* Buttons */
|
||||
.btn-hero {
|
||||
@apply inline-flex items-center gap-3 bg-white px-8 py-4 rounded-xl transition-all font-bold shadow-xl hover:scale-105 active:scale-95;
|
||||
}
|
||||
|
||||
.btn-hero-teal {
|
||||
@apply btn-hero text-teal-700 hover:bg-teal-50;
|
||||
}
|
||||
|
||||
.btn-hero-indigo {
|
||||
@apply btn-hero text-indigo-900 hover:bg-indigo-50;
|
||||
}
|
||||
|
||||
/* ---- LEGACY BUTTON OVERRIDES ---- */
|
||||
.btn-hero,
|
||||
.btn-hero-teal,
|
||||
.btn-hero-indigo,
|
||||
.btn-primary {
|
||||
@apply win-btn;
|
||||
border-radius: 0 !important;
|
||||
transform: none !important;
|
||||
@apply inline-flex items-center justify-center font-bold py-3 px-8 rounded-xl transition-all shadow-lg;
|
||||
}
|
||||
|
||||
/* Grid and Containers */
|
||||
.main-container {
|
||||
@apply max-w-7xl mx-auto px-4 -mt-12 relative z-10;
|
||||
}
|
||||
|
||||
.card-grid {
|
||||
@apply grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6;
|
||||
}
|
||||
|
||||
/* Cards */
|
||||
.card-base {
|
||||
@apply bg-white rounded-2xl border border-gray-200 p-6 shadow-sm;
|
||||
}
|
||||
|
||||
.card-interactive {
|
||||
@apply bg-white rounded-2xl border border-gray-200 p-6 shadow-sm hover:shadow-xl transition-all duration-300 ease-out hover:-translate-y-1;
|
||||
}
|
||||
|
||||
/* Decorative Background Elements */
|
||||
.hero-decor-blob {
|
||||
@apply absolute rounded-full blur-3xl opacity-30;
|
||||
}
|
||||
}
|
||||
|
||||
/* ---- WIKI CONTENT ---- */
|
||||
.wiki-content {
|
||||
font-family: var(--w-font);
|
||||
font-size: 13px;
|
||||
color: var(--w-text);
|
||||
line-height: 1.6;
|
||||
}
|
||||
.wiki-content h1 {
|
||||
font-size: 17px; font-weight: bold; margin: 12px 0 6px; color: #000080;
|
||||
border-bottom: 1px solid var(--w-gray); padding-bottom: 4px;
|
||||
}
|
||||
.wiki-content h2 { font-size: 15px; font-weight: bold; margin: 10px 0 5px; color: #000060; }
|
||||
.wiki-content h3 { font-size: 13px; font-weight: bold; margin: 8px 0 4px; }
|
||||
.wiki-content p { margin-bottom: 8px; }
|
||||
.wiki-content ul { list-style: disc; margin: 4px 0 8px 20px; }
|
||||
.wiki-content ol { list-style: decimal; margin: 4px 0 8px 20px; }
|
||||
.wiki-content li { margin-bottom: 2px; }
|
||||
.wiki-content a { color: #0000FF; text-decoration: underline; }
|
||||
.wiki-content a:visited { color: #800080; }
|
||||
.wiki-content img { max-width: 100%; height: auto; border: 1px solid var(--w-gray); margin: 6px 0; }
|
||||
.wiki-content pre {
|
||||
background: #000080; color: #C0C0C0; padding: 8px; overflow-x: auto; margin: 8px 0;
|
||||
font-family: "Courier New", Courier, monospace; font-size: 11px;
|
||||
}
|
||||
.wiki-content code {
|
||||
background: var(--w-window); color: #800000; padding: 1px 4px;
|
||||
font-family: "Courier New", Courier, monospace; font-size: 11px; border: 1px solid var(--w-gray);
|
||||
}
|
||||
.wiki-content blockquote {
|
||||
border-left: 3px solid var(--w-gray); margin: 6px 0; padding-left: 10px;
|
||||
font-style: italic; color: #404040;
|
||||
}
|
||||
.wiki-content table { width: 100%; border-collapse: collapse; margin: 8px 0; }
|
||||
.wiki-content th { background: #000080; color: #fff; padding: 3px 8px; text-align: left; font-weight: bold; font-size: 11px; }
|
||||
.wiki-content td { padding: 3px 8px; border: 1px solid var(--w-gray); font-size: 12px; }
|
||||
.wiki-content tr:nth-child(even) td { background: #F0F0F0; }
|
||||
/* Wiki content styles (used with v-html) */
|
||||
.wiki-content h1 { @apply text-2xl font-bold mt-8 mb-4 text-gray-900; }
|
||||
.wiki-content h2 { @apply text-xl font-bold mt-6 mb-3 text-gray-800; }
|
||||
.wiki-content h3 { @apply text-lg font-bold mt-4 mb-2 text-gray-800; }
|
||||
.wiki-content p { @apply mb-4 text-gray-700 leading-relaxed; }
|
||||
.wiki-content ul { @apply list-disc ml-6 mb-4 text-gray-700; }
|
||||
.wiki-content ol { @apply list-decimal ml-6 mb-4 text-gray-700; }
|
||||
.wiki-content li { @apply mb-1; }
|
||||
.wiki-content a { @apply text-indigo-600 hover:underline; }
|
||||
.wiki-content img { @apply max-w-full h-auto rounded-lg my-6 shadow-md; }
|
||||
.wiki-content pre { @apply bg-gray-900 text-gray-100 p-4 rounded-lg overflow-x-auto my-6 font-mono text-sm; }
|
||||
.wiki-content code { @apply bg-gray-100 text-pink-600 px-1 rounded font-mono text-sm; }
|
||||
.wiki-content blockquote { @apply border-l-4 border-gray-300 pl-4 italic my-6 text-gray-600; }
|
||||
.wiki-content table { @apply w-full border-collapse my-6; }
|
||||
.wiki-content th,
|
||||
.wiki-content td { @apply border border-gray-200 p-3 text-left; }
|
||||
.wiki-content th { @apply bg-gray-50 font-bold; }
|
||||
|
||||
@@ -0,0 +1,823 @@
|
||||
/* ===================================================================
|
||||
RETRO MODE — Windows 98/2000 style
|
||||
All rules scoped under .retro-mode on the root app wrapper.
|
||||
Activated via cookie "retro-mode=1".
|
||||
=================================================================== */
|
||||
|
||||
/* ---- BASE ---- */
|
||||
.retro-mode,
|
||||
.retro-mode body {
|
||||
font-family: Tahoma, "MS Sans Serif", Arial, sans-serif !important;
|
||||
background: #D4D0C8 !important;
|
||||
color: #000 !important;
|
||||
}
|
||||
|
||||
.retro-mode * {
|
||||
border-radius: 0 !important;
|
||||
transition: none !important;
|
||||
animation-duration: 0.001s !important;
|
||||
}
|
||||
|
||||
.retro-mode .animate-spin {
|
||||
animation-duration: 1s !important;
|
||||
}
|
||||
|
||||
/* ---- NAVIGATION HEADER ---- */
|
||||
.retro-mode header.bg-gray-800 {
|
||||
background: #D4D0C8 !important;
|
||||
color: #000 !important;
|
||||
padding: 0 0 0 4px !important;
|
||||
border-bottom: 1px solid #808080 !important;
|
||||
box-shadow: 0 1px 0 #fff !important;
|
||||
display: flex !important;
|
||||
align-items: stretch !important;
|
||||
min-height: 22px !important;
|
||||
}
|
||||
|
||||
.retro-mode header.bg-gray-800 a.text-xl {
|
||||
color: #000 !important;
|
||||
font-size: 12px !important;
|
||||
font-weight: bold !important;
|
||||
padding: 2px 10px !important;
|
||||
border-right: 1px solid #808080 !important;
|
||||
box-shadow: inset -1px 0 0 #fff !important;
|
||||
display: flex !important;
|
||||
align-items: center !important;
|
||||
text-decoration: none !important;
|
||||
}
|
||||
|
||||
.retro-mode header.bg-gray-800 nav.hidden a,
|
||||
.retro-mode header.bg-gray-800 nav.hidden.md\:flex a {
|
||||
color: #000 !important;
|
||||
font-size: 12px !important;
|
||||
padding: 0 8px !important;
|
||||
display: inline-flex !important;
|
||||
align-items: center !important;
|
||||
}
|
||||
|
||||
.retro-mode header.bg-gray-800 nav a:hover,
|
||||
.retro-mode header.bg-gray-800 nav.hidden a:hover,
|
||||
.retro-mode header.bg-gray-800 nav.hidden.md\:flex a:hover {
|
||||
background: #000080 !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
.retro-mode header.bg-gray-800 nav a.router-link-exact-active,
|
||||
.retro-mode header.bg-gray-800 nav.hidden a.router-link-exact-active,
|
||||
.retro-mode header.bg-gray-800 nav.hidden.md\:flex a.router-link-exact-active {
|
||||
background: #000080 !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
.retro-mode header.bg-gray-800 button {
|
||||
background: #D4D0C8 !important;
|
||||
color: #000 !important;
|
||||
border: 1px solid #0a0a0a !important;
|
||||
box-shadow:
|
||||
inset 1px 1px 0 0 #fff,
|
||||
inset -1px -1px 0 0 #0a0a0a,
|
||||
inset 2px 2px 0 0 #D4D0C8,
|
||||
inset -2px -2px 0 0 #808080 !important;
|
||||
margin: 2px 4px !important;
|
||||
}
|
||||
|
||||
/* Mobile nav */
|
||||
.retro-mode nav.md\:hidden.absolute {
|
||||
background: #D4D0C8 !important;
|
||||
border: 1px solid #808080 !important;
|
||||
box-shadow: 2px 2px 0 0 #0a0a0a !important;
|
||||
}
|
||||
|
||||
.retro-mode nav.md\:hidden.absolute a {
|
||||
color: #000 !important;
|
||||
font-size: 12px !important;
|
||||
border-bottom: 1px solid #C0BDB8 !important;
|
||||
}
|
||||
|
||||
.retro-mode nav.md\:hidden.absolute a:hover {
|
||||
background: #000080 !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
/* ---- PAGE BACKGROUNDS ---- */
|
||||
.retro-mode .bg-gray-50,
|
||||
.retro-mode .home-container,
|
||||
.retro-mode .blog-container,
|
||||
.retro-mode .howtos-container {
|
||||
background: #D4D0C8 !important;
|
||||
min-height: auto !important;
|
||||
}
|
||||
|
||||
/* ---- MAIN CONTAINER ---- */
|
||||
.retro-mode .main-container,
|
||||
.retro-mode .blog-main {
|
||||
margin-top: 0 !important;
|
||||
padding: 8px !important;
|
||||
max-width: 960px !important;
|
||||
}
|
||||
|
||||
/* ---- HERO SECTIONS → Win98 title bar ---- */
|
||||
.retro-mode .hero-section,
|
||||
.retro-mode .hero-section-gradient,
|
||||
.retro-mode .hero-section-slate,
|
||||
.retro-mode .blog-header {
|
||||
background: linear-gradient(to right, #000080, #1084D0) !important;
|
||||
padding: 4px 8px !important;
|
||||
color: #fff !important;
|
||||
overflow: visible !important;
|
||||
text-align: left !important;
|
||||
}
|
||||
|
||||
.retro-mode .hero-decor-blob,
|
||||
.retro-mode .home-header-decor,
|
||||
.retro-mode .howtos-header-decor,
|
||||
.retro-mode .blog-header-decor {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.retro-mode .hero-badge {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.retro-mode .hero-container,
|
||||
.retro-mode .post-hero-container {
|
||||
max-width: none !important;
|
||||
padding: 0 !important;
|
||||
position: static !important;
|
||||
z-index: auto !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
.retro-mode .hero-title {
|
||||
font-size: 13px !important;
|
||||
font-weight: bold !important;
|
||||
font-family: Tahoma, Arial, sans-serif !important;
|
||||
margin: 0 !important;
|
||||
text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.5) !important;
|
||||
letter-spacing: 0 !important;
|
||||
background: none !important;
|
||||
-webkit-background-clip: unset !important;
|
||||
background-clip: unset !important;
|
||||
-webkit-text-fill-color: #fff !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
.retro-mode .hero-title span.text-transparent {
|
||||
-webkit-text-fill-color: #C8C8FF !important;
|
||||
background: none !important;
|
||||
}
|
||||
|
||||
.retro-mode .hero-subtitle {
|
||||
font-size: 11px !important;
|
||||
color: #D0D4FF !important;
|
||||
font-family: Tahoma, Arial, sans-serif !important;
|
||||
margin: 1px 0 0 !important;
|
||||
max-width: none !important;
|
||||
line-height: 1.3 !important;
|
||||
}
|
||||
|
||||
.retro-mode .back-link {
|
||||
color: #C8C8FF !important;
|
||||
font-size: 11px !important;
|
||||
}
|
||||
|
||||
.retro-mode .back-link:hover {
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
/* ---- BUTTONS ---- */
|
||||
.retro-mode .btn-hero,
|
||||
.retro-mode .btn-hero-teal,
|
||||
.retro-mode .btn-hero-indigo,
|
||||
.retro-mode .btn-primary,
|
||||
.retro-mode .btn-play-sm,
|
||||
.retro-mode .btn-info-sm,
|
||||
.retro-mode .browse-wiki-btn,
|
||||
.retro-mode .discord-hero-btn,
|
||||
.retro-mode .read-more-btn,
|
||||
.retro-mode .yt-play-button {
|
||||
background: #D4D0C8 !important;
|
||||
color: #000 !important;
|
||||
border: 1px solid #0a0a0a !important;
|
||||
box-shadow:
|
||||
inset 1px 1px 0 0 #fff,
|
||||
inset -1px -1px 0 0 #0a0a0a,
|
||||
inset 2px 2px 0 0 #D4D0C8,
|
||||
inset -2px -2px 0 0 #808080 !important;
|
||||
font-family: Tahoma, Arial, sans-serif !important;
|
||||
font-size: 12px !important;
|
||||
font-weight: normal !important;
|
||||
text-shadow: none !important;
|
||||
transform: none !important;
|
||||
padding: 3px 12px 4px !important;
|
||||
text-decoration: none !important;
|
||||
display: inline-flex !important;
|
||||
align-items: center !important;
|
||||
justify-content: center !important;
|
||||
gap: 4px !important;
|
||||
min-height: 23px !important;
|
||||
}
|
||||
|
||||
.retro-mode .btn-hero:active,
|
||||
.retro-mode .btn-hero-teal:active,
|
||||
.retro-mode .btn-hero-indigo:active,
|
||||
.retro-mode .btn-primary:active,
|
||||
.retro-mode .btn-play-sm:active,
|
||||
.retro-mode .btn-info-sm:active,
|
||||
.retro-mode .browse-wiki-btn:active,
|
||||
.retro-mode .discord-hero-btn:active,
|
||||
.retro-mode .yt-play-button:active {
|
||||
box-shadow:
|
||||
inset 1px 1px 0 0 #0a0a0a,
|
||||
inset -1px -1px 0 0 #fff,
|
||||
inset 2px 2px 0 0 #808080,
|
||||
inset -2px -2px 0 0 #D4D0C8 !important;
|
||||
padding: 4px 11px 3px 13px !important;
|
||||
}
|
||||
|
||||
.retro-mode .btn-hero:hover,
|
||||
.retro-mode .btn-hero-teal:hover,
|
||||
.retro-mode .btn-hero-indigo:hover,
|
||||
.retro-mode .btn-primary:hover,
|
||||
.retro-mode .browse-wiki-btn:hover,
|
||||
.retro-mode .discord-hero-btn:hover {
|
||||
background: #D4D0C8 !important;
|
||||
color: #000 !important;
|
||||
transform: none !important;
|
||||
box-shadow:
|
||||
inset 1px 1px 0 0 #fff,
|
||||
inset -1px -1px 0 0 #0a0a0a,
|
||||
inset 2px 2px 0 0 #D4D0C8,
|
||||
inset -2px -2px 0 0 #808080 !important;
|
||||
}
|
||||
|
||||
.retro-mode .filter-btn {
|
||||
background: #D4D0C8 !important;
|
||||
color: #000 !important;
|
||||
border: 1px solid #0a0a0a !important;
|
||||
box-shadow:
|
||||
inset 1px 1px 0 0 #fff,
|
||||
inset -1px -1px 0 0 #0a0a0a,
|
||||
inset 2px 2px 0 0 #D4D0C8,
|
||||
inset -2px -2px 0 0 #808080 !important;
|
||||
padding: 2px 8px 3px !important;
|
||||
font-size: 12px !important;
|
||||
font-family: Tahoma, Arial, sans-serif !important;
|
||||
}
|
||||
|
||||
.retro-mode .filter-btn:hover,
|
||||
.retro-mode .filter-btn.active {
|
||||
background: #000080 !important;
|
||||
color: #fff !important;
|
||||
box-shadow:
|
||||
inset 1px 1px 0 0 #0a0a0a,
|
||||
inset -1px -1px 0 0 #fff,
|
||||
inset 2px 2px 0 0 #808080,
|
||||
inset -2px -2px 0 0 #D4D0C8 !important;
|
||||
}
|
||||
|
||||
/* ---- CARDS / PANELS ---- */
|
||||
.retro-mode .card-base,
|
||||
.retro-mode .card-interactive {
|
||||
background: #D4D0C8 !important;
|
||||
border: 1px solid #0a0a0a !important;
|
||||
box-shadow:
|
||||
inset 1px 1px 0 0 #fff,
|
||||
inset -1px -1px 0 0 #808080 !important;
|
||||
transform: none !important;
|
||||
}
|
||||
|
||||
.retro-mode .card-interactive:hover {
|
||||
transform: none !important;
|
||||
box-shadow:
|
||||
inset 1px 1px 0 0 #fff,
|
||||
inset -1px -1px 0 0 #808080 !important;
|
||||
}
|
||||
|
||||
.retro-mode .bg-white {
|
||||
background: #fff !important;
|
||||
}
|
||||
|
||||
.retro-mode .shadow-xl,
|
||||
.retro-mode .shadow-2xl,
|
||||
.retro-mode .shadow-lg,
|
||||
.retro-mode .shadow-sm,
|
||||
.retro-mode .shadow-md {
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
/* ---- STATUS BADGES ---- */
|
||||
.retro-mode .status-badge {
|
||||
padding: 1px 5px !important;
|
||||
font-size: 10px !important;
|
||||
font-family: Tahoma, Arial, sans-serif !important;
|
||||
}
|
||||
|
||||
.retro-mode .status-released { background: #C8F0C8 !important; color: #007000 !important; border-color: #009000 !important; }
|
||||
.retro-mode .status-demo { background: #C8C8FF !important; color: #000080 !important; border-color: #0000C0 !important; }
|
||||
.retro-mode .status-development { background: #FFFFC8 !important; color: #808000 !important; border-color: #B0A000 !important; }
|
||||
.retro-mode .status-archived { background: #E0E0E0 !important; color: #404040 !important; border-color: #808080 !important; }
|
||||
|
||||
/* ---- COUNTDOWN ---- */
|
||||
.retro-mode .countdown-card {
|
||||
background: #D4D0C8 !important;
|
||||
border: 1px solid #0a0a0a !important;
|
||||
box-shadow:
|
||||
inset 1px 1px 0 0 #fff,
|
||||
inset -1px -1px 0 0 #808080 !important;
|
||||
padding: 12px !important;
|
||||
}
|
||||
|
||||
.retro-mode .countdown-event-name {
|
||||
font-size: 11px !important;
|
||||
letter-spacing: 1px !important;
|
||||
color: #000080 !important;
|
||||
}
|
||||
|
||||
.retro-mode .countdown-timer {
|
||||
font-family: "Courier New", Courier, monospace !important;
|
||||
font-size: 26px !important;
|
||||
background: none !important;
|
||||
-webkit-background-clip: unset !important;
|
||||
background-clip: unset !important;
|
||||
-webkit-text-fill-color: #000080 !important;
|
||||
color: #000080 !important;
|
||||
letter-spacing: 2px !important;
|
||||
margin: 6px 0 !important;
|
||||
}
|
||||
|
||||
.retro-mode .countdown-date {
|
||||
font-size: 11px !important;
|
||||
color: #404040 !important;
|
||||
}
|
||||
|
||||
.retro-mode .upcoming-events-section {
|
||||
border-top-color: #808080 !important;
|
||||
}
|
||||
|
||||
.retro-mode .upcoming-event-item {
|
||||
background: #fff !important;
|
||||
border: 1px solid #D0D0D0 !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
/* ---- FEATURED GAME CARD ---- */
|
||||
.retro-mode .featured-card {
|
||||
background: #D4D0C8 !important;
|
||||
border: 1px solid #0a0a0a !important;
|
||||
box-shadow:
|
||||
inset 1px 1px 0 0 #fff,
|
||||
inset -1px -1px 0 0 #808080 !important;
|
||||
}
|
||||
|
||||
.retro-mode .featured-badge {
|
||||
background: #000080 !important;
|
||||
color: #fff !important;
|
||||
border-color: #0000C0 !important;
|
||||
}
|
||||
|
||||
.retro-mode .featured-title {
|
||||
color: #000 !important;
|
||||
font-size: 22px !important;
|
||||
font-family: Tahoma, Arial, sans-serif !important;
|
||||
-webkit-text-fill-color: #000 !important;
|
||||
}
|
||||
|
||||
.retro-mode .featured-desc {
|
||||
color: #404040 !important;
|
||||
}
|
||||
|
||||
.retro-mode .featured-btn-play {
|
||||
background: #D4D0C8 !important;
|
||||
color: #000 !important;
|
||||
border: 1px solid #0a0a0a !important;
|
||||
box-shadow:
|
||||
inset 1px 1px 0 0 #fff,
|
||||
inset -1px -1px 0 0 #0a0a0a,
|
||||
inset 2px 2px 0 0 #D4D0C8,
|
||||
inset -2px -2px 0 0 #808080 !important;
|
||||
}
|
||||
|
||||
.retro-mode .featured-btn-secondary {
|
||||
background: #D4D0C8 !important;
|
||||
color: #000 !important;
|
||||
border: 1px solid #0a0a0a !important;
|
||||
box-shadow:
|
||||
inset 1px 1px 0 0 #fff,
|
||||
inset -1px -1px 0 0 #0a0a0a,
|
||||
inset 2px 2px 0 0 #D4D0C8,
|
||||
inset -2px -2px 0 0 #808080 !important;
|
||||
}
|
||||
|
||||
.retro-mode .featured-image {
|
||||
border: 2px solid !important;
|
||||
border-color: #808080 #fff #fff #808080 !important;
|
||||
}
|
||||
|
||||
.retro-mode .featured-version-badge {
|
||||
background: #fff !important;
|
||||
color: #404040 !important;
|
||||
border-color: #808080 !important;
|
||||
}
|
||||
|
||||
/* ---- YOUTUBE SECTION ---- */
|
||||
.retro-mode .yt-featured-wrapper {
|
||||
background: #D4D0C8 !important;
|
||||
border: 1px solid #0a0a0a !important;
|
||||
box-shadow:
|
||||
inset 1px 1px 0 0 #fff,
|
||||
inset -1px -1px 0 0 #808080 !important;
|
||||
}
|
||||
|
||||
.retro-mode .yt-glow {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.retro-mode .yt-label-text {
|
||||
color: #000 !important;
|
||||
font-size: 11px !important;
|
||||
}
|
||||
|
||||
.retro-mode .yt-channel-link {
|
||||
color: #0000FF !important;
|
||||
font-size: 11px !important;
|
||||
text-decoration: underline !important;
|
||||
}
|
||||
|
||||
.retro-mode .yt-player-container {
|
||||
border: 2px solid !important;
|
||||
border-color: #808080 #fff #fff #808080 !important;
|
||||
background: #000 !important;
|
||||
}
|
||||
|
||||
.retro-mode .yt-status-blob,
|
||||
.retro-mode .yt-status-dot {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.retro-mode .yt-new-tag {
|
||||
background: #FFFFC8 !important;
|
||||
color: #808000 !important;
|
||||
border-color: #B0A000 !important;
|
||||
}
|
||||
|
||||
.retro-mode .yt-video-title {
|
||||
color: #000080 !important;
|
||||
font-size: 13px !important;
|
||||
}
|
||||
|
||||
.retro-mode .yt-stats-row {
|
||||
color: #404040 !important;
|
||||
font-family: "Courier New", Courier, monospace !important;
|
||||
font-size: 11px !important;
|
||||
}
|
||||
|
||||
/* ---- NAVIGATION GRID CARDS ---- */
|
||||
.retro-mode .nav-card-icon {
|
||||
background: #E8E4DC !important;
|
||||
box-shadow:
|
||||
inset 1px 1px 0 0 #fff,
|
||||
inset -1px -1px 0 0 #808080 !important;
|
||||
}
|
||||
|
||||
.retro-mode .nav-card-title {
|
||||
color: #000 !important;
|
||||
font-family: Tahoma, Arial, sans-serif !important;
|
||||
font-size: 14px !important;
|
||||
}
|
||||
|
||||
.retro-mode .nav-card-desc {
|
||||
color: #404040 !important;
|
||||
font-size: 12px !important;
|
||||
}
|
||||
|
||||
/* AI notice */
|
||||
.retro-mode .border-indigo-100 {
|
||||
background: #FFFFC8 !important;
|
||||
border-color: #B0A000 !important;
|
||||
}
|
||||
|
||||
/* ---- BLOG ---- */
|
||||
.retro-mode .blog-post-card {
|
||||
background: #D4D0C8 !important;
|
||||
border: 1px solid #0a0a0a !important;
|
||||
box-shadow:
|
||||
inset 1px 1px 0 0 #fff,
|
||||
inset -1px -1px 0 0 #808080 !important;
|
||||
}
|
||||
|
||||
.retro-mode .blog-post-title a {
|
||||
color: #000080 !important;
|
||||
text-decoration: underline !important;
|
||||
}
|
||||
|
||||
.retro-mode .blog-post-title a:hover {
|
||||
color: #0000FF !important;
|
||||
}
|
||||
|
||||
.retro-mode .read-more-btn {
|
||||
color: #0000FF !important;
|
||||
text-decoration: underline !important;
|
||||
}
|
||||
|
||||
.retro-mode .new-post-badge {
|
||||
background: #C8F0C8 !important;
|
||||
border-color: #009000 !important;
|
||||
}
|
||||
|
||||
.retro-mode .new-post-dot {
|
||||
background: #007000 !important;
|
||||
}
|
||||
|
||||
.retro-mode .blog-post-preview::after {
|
||||
background: linear-gradient(to bottom, transparent, #D4D0C8) !important;
|
||||
}
|
||||
|
||||
.retro-mode .blog-post-description {
|
||||
color: #000 !important;
|
||||
}
|
||||
|
||||
.retro-mode .blog-post-body {
|
||||
color: #404040 !important;
|
||||
}
|
||||
|
||||
/* ---- SOFTWARE CATALOG ---- */
|
||||
.retro-mode .software-card {
|
||||
background: #D4D0C8 !important;
|
||||
border: 1px solid #0a0a0a !important;
|
||||
box-shadow:
|
||||
inset 1px 1px 0 0 #fff,
|
||||
inset -1px -1px 0 0 #808080 !important;
|
||||
}
|
||||
|
||||
.retro-mode .software-thumb {
|
||||
border: 2px solid !important;
|
||||
border-color: #808080 #fff #fff #808080 !important;
|
||||
}
|
||||
|
||||
.retro-mode .software-title {
|
||||
color: #000080 !important;
|
||||
}
|
||||
|
||||
.retro-mode .software-desc {
|
||||
color: #404040 !important;
|
||||
}
|
||||
|
||||
.retro-mode .software-meta {
|
||||
color: #808080 !important;
|
||||
}
|
||||
|
||||
/* Catalog Show */
|
||||
.retro-mode .bg-gradient-to-br.from-indigo-600 {
|
||||
background: #000080 !important;
|
||||
}
|
||||
|
||||
.retro-mode .bg-gradient-to-br.from-indigo-600 * {
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
.retro-mode .bg-gradient-to-br.from-indigo-600 a {
|
||||
background: #D4D0C8 !important;
|
||||
color: #000 !important;
|
||||
border: 1px solid #0a0a0a !important;
|
||||
box-shadow:
|
||||
inset 1px 1px 0 0 #fff,
|
||||
inset -1px -1px 0 0 #0a0a0a,
|
||||
inset 2px 2px 0 0 #D4D0C8,
|
||||
inset -2px -2px 0 0 #808080 !important;
|
||||
text-decoration: none !important;
|
||||
}
|
||||
|
||||
.retro-mode .bg-gradient-to-br.from-purple-700 {
|
||||
background: linear-gradient(to right, #000080, #1084D0) !important;
|
||||
}
|
||||
|
||||
.retro-mode .text-purple-200 {
|
||||
color: #C8C8FF !important;
|
||||
}
|
||||
|
||||
.retro-mode .text-purple-300 {
|
||||
color: #D0D0FF !important;
|
||||
}
|
||||
|
||||
.retro-mode table thead {
|
||||
background: #D4D0C8 !important;
|
||||
}
|
||||
|
||||
.retro-mode table th {
|
||||
background: #D4D0C8 !important;
|
||||
color: #000 !important;
|
||||
box-shadow:
|
||||
inset 1px 1px 0 0 #fff,
|
||||
inset -1px -1px 0 0 #808080 !important;
|
||||
border: 1px solid #808080 !important;
|
||||
}
|
||||
|
||||
.retro-mode table tr:hover td,
|
||||
.retro-mode table tr:hover th {
|
||||
background: #000080 !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
.retro-mode table tr:hover a {
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
/* ---- TEAM ---- */
|
||||
.retro-mode .team-card {
|
||||
background: #D4D0C8 !important;
|
||||
border: 1px solid #0a0a0a !important;
|
||||
box-shadow:
|
||||
inset 1px 1px 0 0 #fff,
|
||||
inset -1px -1px 0 0 #808080 !important;
|
||||
transform: none !important;
|
||||
}
|
||||
|
||||
.retro-mode .team-card:hover {
|
||||
transform: none !important;
|
||||
}
|
||||
|
||||
.retro-mode .team-card-title {
|
||||
color: #000080 !important;
|
||||
}
|
||||
|
||||
.retro-mode .team-card-image-container {
|
||||
border: 2px solid !important;
|
||||
border-color: #808080 #fff #fff #808080 !important;
|
||||
}
|
||||
|
||||
/* ---- CONTACT ---- */
|
||||
.retro-mode .contact-card {
|
||||
background: #D4D0C8 !important;
|
||||
border: 1px solid #0a0a0a !important;
|
||||
box-shadow:
|
||||
inset 1px 1px 0 0 #fff,
|
||||
inset -1px -1px 0 0 #808080 !important;
|
||||
}
|
||||
|
||||
.retro-mode .email-link {
|
||||
color: #0000FF !important;
|
||||
}
|
||||
|
||||
.retro-mode .community-link-discord,
|
||||
.retro-mode .community-link-youtube {
|
||||
color: #0000FF !important;
|
||||
text-decoration: underline !important;
|
||||
}
|
||||
|
||||
.retro-mode .irc-box,
|
||||
.retro-mode .bbs-box {
|
||||
background: #fff !important;
|
||||
border: 1px solid #808080 !important;
|
||||
box-shadow:
|
||||
inset 1px 1px 0 0 #808080,
|
||||
inset -1px -1px 0 0 #D4D0C8 !important;
|
||||
}
|
||||
|
||||
.retro-mode .irc-channel {
|
||||
color: #007000 !important;
|
||||
}
|
||||
|
||||
.retro-mode .bbs-port {
|
||||
color: #805000 !important;
|
||||
}
|
||||
|
||||
.retro-mode .community-section {
|
||||
border-left-color: #808080 !important;
|
||||
}
|
||||
|
||||
.retro-mode .community-section-title {
|
||||
color: #000080 !important;
|
||||
}
|
||||
|
||||
/* ---- CODE PAGE ---- */
|
||||
.retro-mode .error-alert {
|
||||
background: #FFCCCC !important;
|
||||
border-color: #CC0000 !important;
|
||||
}
|
||||
|
||||
.retro-mode .commit-item {
|
||||
background: #D4D0C8 !important;
|
||||
border: 1px solid #0a0a0a !important;
|
||||
box-shadow:
|
||||
inset 1px 1px 0 0 #fff,
|
||||
inset -1px -1px 0 0 #808080 !important;
|
||||
}
|
||||
|
||||
.retro-mode .commits-section-title {
|
||||
color: #000080 !important;
|
||||
font-family: Tahoma, Arial, sans-serif !important;
|
||||
}
|
||||
|
||||
.retro-mode .repo-link,
|
||||
.retro-mode .commit-repo-link,
|
||||
.retro-mode .commit-sha-link {
|
||||
color: #0000FF !important;
|
||||
text-decoration: underline !important;
|
||||
}
|
||||
|
||||
/* ---- HOWTOS ---- */
|
||||
.retro-mode .howto-card-title {
|
||||
color: #000080 !important;
|
||||
}
|
||||
|
||||
.retro-mode .howto-card-title:hover,
|
||||
.retro-mode .group:hover .howto-card-title {
|
||||
color: #0000FF !important;
|
||||
}
|
||||
|
||||
.retro-mode .howto-card-footer {
|
||||
border-top-color: #808080 !important;
|
||||
}
|
||||
|
||||
.retro-mode .howto-card-read-link {
|
||||
color: #0000FF !important;
|
||||
transform: none !important;
|
||||
}
|
||||
|
||||
.retro-mode .new-badge {
|
||||
background: #C8F0C8 !important;
|
||||
border-color: #009000 !important;
|
||||
color: #007000 !important;
|
||||
}
|
||||
|
||||
.retro-mode .new-dot {
|
||||
background: #007000 !important;
|
||||
}
|
||||
|
||||
/* ---- WIKI CONTENT ---- */
|
||||
.retro-mode .wiki-content h1 {
|
||||
color: #000080 !important;
|
||||
border-bottom-color: #808080 !important;
|
||||
}
|
||||
.retro-mode .wiki-content h2 { color: #000060 !important; }
|
||||
.retro-mode .wiki-content a { color: #0000FF !important; }
|
||||
.retro-mode .wiki-content a:visited { color: #800080 !important; }
|
||||
.retro-mode .wiki-content img { border-color: #808080 !important; }
|
||||
.retro-mode .wiki-content pre {
|
||||
background: #000080 !important;
|
||||
color: #C0C0C0 !important;
|
||||
}
|
||||
.retro-mode .wiki-content code {
|
||||
background: #fff !important;
|
||||
color: #800000 !important;
|
||||
border-color: #808080 !important;
|
||||
}
|
||||
.retro-mode .wiki-content blockquote { border-left-color: #808080 !important; }
|
||||
.retro-mode .wiki-content th {
|
||||
background: #000080 !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
.retro-mode .wiki-content tr:nth-child(even) td {
|
||||
background: #F0F0F0 !important;
|
||||
}
|
||||
|
||||
/* ---- RETRO TOGGLE BUTTON (self-styling) ---- */
|
||||
.retro-toggle-bar {
|
||||
padding: 6px 8px;
|
||||
background: #f5f5f5;
|
||||
border-top: 1px solid #e0e0e0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.retro-toggle-btn {
|
||||
background: #f0f0f0;
|
||||
border: 1px solid #ccc;
|
||||
padding: 4px 14px;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
font-family: inherit;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.retro-toggle-btn:hover {
|
||||
background: #e4e4e4;
|
||||
}
|
||||
|
||||
.retro-mode .retro-toggle-bar {
|
||||
background: #D4D0C8 !important;
|
||||
border-top: 1px solid #808080 !important;
|
||||
box-shadow: inset 0 1px 0 #fff !important;
|
||||
}
|
||||
|
||||
.retro-mode .retro-toggle-btn {
|
||||
background: #D4D0C8 !important;
|
||||
color: #000 !important;
|
||||
border: 1px solid #0a0a0a !important;
|
||||
box-shadow:
|
||||
inset 1px 1px 0 0 #fff,
|
||||
inset -1px -1px 0 0 #0a0a0a,
|
||||
inset 2px 2px 0 0 #D4D0C8,
|
||||
inset -2px -2px 0 0 #808080 !important;
|
||||
font-family: Tahoma, Arial, sans-serif !important;
|
||||
font-size: 12px !important;
|
||||
}
|
||||
|
||||
.retro-mode .retro-toggle-btn:active {
|
||||
box-shadow:
|
||||
inset 1px 1px 0 0 #0a0a0a,
|
||||
inset -1px -1px 0 0 #fff,
|
||||
inset 2px 2px 0 0 #808080,
|
||||
inset -2px -2px 0 0 #D4D0C8 !important;
|
||||
padding: 5px 13px 3px 15px !important;
|
||||
}
|
||||
Reference in New Issue
Block a user