build concerns, build matrix
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
import type { BuildsData } from '../lib/interfaces/builds.interface'
|
||||
|
||||
const index = async (): Promise<BuildsData> => {
|
||||
const res = await fetch('/api/builds')
|
||||
if (!res.ok) throw new Error(`HTTP ${res.status}`)
|
||||
return res.json()
|
||||
}
|
||||
|
||||
export default { index }
|
||||
@@ -179,6 +179,10 @@ export default {
|
||||
new: 'New',
|
||||
read: 'Read',
|
||||
},
|
||||
builds: {
|
||||
title: 'Build Matrix',
|
||||
subtitle: 'Which engines build for which platforms.',
|
||||
},
|
||||
code: {
|
||||
title: 'Codebase',
|
||||
subtitle: 'Explore our collection of open-source projects, study our source code, and contribute to our independent game development tools.',
|
||||
|
||||
@@ -179,6 +179,10 @@ export default {
|
||||
new: 'Új',
|
||||
read: 'Olvasás',
|
||||
},
|
||||
builds: {
|
||||
title: 'Build mátrix',
|
||||
subtitle: 'Melyik engine melyik platformra fordít.',
|
||||
},
|
||||
code: {
|
||||
title: 'Kódbázis',
|
||||
subtitle: 'Fedezd fel nyílt forráskódú projektek gyűjteményét, tanulmányozd forráskódunkat, és járulj hozzá független játékfejlesztő eszközeinkhez.',
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
export interface PlatformBuilds {
|
||||
label: string
|
||||
kinds: string[]
|
||||
}
|
||||
|
||||
export interface BuildsData {
|
||||
platforms: Record<string, PlatformBuilds>
|
||||
allKinds: string[]
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
<template>
|
||||
<header class="hero-section-gradient from-slate-700 to-gray-800 py-16">
|
||||
<div class="hero-container">
|
||||
<h1 class="hero-title">{{ t('builds.title') }}</h1>
|
||||
<p class="hero-subtitle text-slate-300">{{ t('builds.subtitle') }}</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="main-container py-12 px-4 mt-0">
|
||||
<div v-if="error" class="builds-error">{{ error }}</div>
|
||||
|
||||
<div v-else-if="!data" class="builds-loading">{{ t('common.loading') }}</div>
|
||||
|
||||
<div v-else class="builds-table-wrap">
|
||||
<table class="builds-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="builds-th-engine">Engine</th>
|
||||
<th v-for="kind in data.allKinds" :key="kind" class="builds-th-kind">
|
||||
<i :class="kindIcon(kind)" class="builds-kind-icon"></i>
|
||||
<span class="builds-kind-label">{{ t('catalogShow.assetKind.' + kind) }}</span>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(info, platform) in data.platforms" :key="platform" class="builds-row">
|
||||
<td class="builds-td-engine">{{ info.label }}</td>
|
||||
<td v-for="kind in data.allKinds" :key="kind" class="builds-td-kind">
|
||||
<i v-if="info.kinds.includes(kind)" class="fa-solid fa-check builds-check"></i>
|
||||
<i v-else class="fa-solid fa-xmark builds-xmark"></i>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="builds-back">
|
||||
<RouterLink to="/catalog" class="builds-back-link">
|
||||
← {{ t('catalogShow.back') }}
|
||||
</RouterLink>
|
||||
</div>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { RouterLink } from 'vue-router'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useBuildsStore } from '../../stores/builds.store'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const store = useBuildsStore()
|
||||
const { data, error } = storeToRefs(store)
|
||||
|
||||
const kindIcon = (kind: string) =>
|
||||
kind.startsWith('win_') ? 'fa-brands fa-windows'
|
||||
: kind.startsWith('linux_') ? 'fa-brands fa-linux'
|
||||
: kind.startsWith('mac_') ? 'fa-brands fa-apple'
|
||||
: kind === 'cartridge' ? 'fa-solid fa-gamepad'
|
||||
: kind === 'source' ? 'fa-solid fa-code'
|
||||
: kind === 'docs' ? 'fa-solid fa-book'
|
||||
: kind === 'html' ? 'fa-solid fa-globe'
|
||||
: 'fa-solid fa-cube'
|
||||
|
||||
onMounted(() => store.fetch())
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.builds-error {
|
||||
@apply text-center text-red-500 font-bold py-12;
|
||||
}
|
||||
.builds-loading {
|
||||
@apply text-center text-gray-400 py-12;
|
||||
}
|
||||
.builds-table-wrap {
|
||||
@apply bg-white rounded-2xl shadow-xl border border-gray-100 overflow-x-auto;
|
||||
}
|
||||
.builds-table {
|
||||
@apply w-full text-sm;
|
||||
}
|
||||
.builds-th-engine {
|
||||
@apply px-6 py-4 text-left text-xs font-bold text-gray-400 uppercase tracking-widest bg-gray-50;
|
||||
}
|
||||
.builds-th-kind {
|
||||
@apply px-3 py-4 text-center bg-gray-50;
|
||||
}
|
||||
.builds-kind-icon {
|
||||
@apply block text-gray-500 text-base mb-1;
|
||||
}
|
||||
.builds-kind-label {
|
||||
@apply block text-[10px] font-bold text-gray-400 uppercase tracking-wider leading-tight;
|
||||
}
|
||||
.builds-row {
|
||||
@apply border-t border-gray-100 hover:bg-gray-50/50 transition-colors;
|
||||
}
|
||||
.builds-td-engine {
|
||||
@apply px-6 py-4 font-bold text-gray-900 whitespace-nowrap;
|
||||
}
|
||||
.builds-td-kind {
|
||||
@apply px-3 py-4 text-center;
|
||||
}
|
||||
.builds-check {
|
||||
@apply text-green-500 text-lg;
|
||||
}
|
||||
.builds-xmark {
|
||||
@apply text-gray-200 text-lg;
|
||||
}
|
||||
.builds-back {
|
||||
@apply mt-8 text-center;
|
||||
}
|
||||
.builds-back-link {
|
||||
@apply text-gray-400 hover:text-gray-600 text-sm font-medium transition-colors;
|
||||
}
|
||||
</style>
|
||||
@@ -18,6 +18,12 @@
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="builds-link-row">
|
||||
<RouterLink to="/builds" class="builds-link">
|
||||
<i class="fa-solid fa-table-cells"></i> {{ t('builds.title') }}
|
||||
</RouterLink>
|
||||
</div>
|
||||
|
||||
<div class="software-list">
|
||||
<template v-for="{ software, releases } in softwares" :key="software.name">
|
||||
<div v-show="activeFilter === 'all' || software.status === activeFilter" class="software-card group">
|
||||
@@ -152,4 +158,10 @@ onMounted(() => store.fetchAll())
|
||||
.software-download-count {
|
||||
@apply text-xs text-gray-400 font-medium ml-1;
|
||||
}
|
||||
.builds-link-row {
|
||||
@apply text-center mb-6;
|
||||
}
|
||||
.builds-link {
|
||||
@apply text-sm text-gray-400 hover:text-purple-600 font-medium transition-colors;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
import type { RouteRecordRaw } from 'vue-router'
|
||||
|
||||
export const buildsRouter: RouteRecordRaw[] = [
|
||||
{ path: '/builds', name: 'buildsIndex', component: () => import('../page/builds/BuildsIndexPage.vue') },
|
||||
]
|
||||
@@ -6,6 +6,7 @@ import { codeRouter } from './code.router'
|
||||
import { contactRouter } from './contact.router'
|
||||
import { howtosRouter } from './howtos.router'
|
||||
import { teamRouter } from './team.router'
|
||||
import { buildsRouter } from './builds.router'
|
||||
|
||||
export const router = createRouter({
|
||||
history: createWebHistory(),
|
||||
@@ -17,6 +18,7 @@ export const router = createRouter({
|
||||
...contactRouter,
|
||||
...howtosRouter,
|
||||
...teamRouter,
|
||||
...buildsRouter,
|
||||
],
|
||||
scrollBehavior() {
|
||||
return { top: 0 }
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
import buildsApi from '../api/builds.api'
|
||||
import { useLoadable } from '../composables/useLoadable'
|
||||
import type { BuildsData } from '../lib/interfaces/builds.interface'
|
||||
|
||||
export const useBuildsStore = defineStore('builds', () => {
|
||||
const data = ref<BuildsData | null>(null)
|
||||
const { loading, error, withCache, invalidate } = useLoadable()
|
||||
|
||||
async function fetch() {
|
||||
await withCache(async () => {
|
||||
data.value = await buildsApi.index()
|
||||
})
|
||||
}
|
||||
|
||||
return { data, loading, error, fetch, invalidate }
|
||||
})
|
||||
Reference in New Issue
Block a user