rss feed and download stats

This commit is contained in:
2026-07-28 10:42:39 +02:00
parent 746143decd
commit 4afa440b12
20 changed files with 186 additions and 14 deletions
+3
View File
@@ -9,6 +9,7 @@ export default {
contact: 'Contact us',
retro: 'Retro Mode',
exitRetro: 'Exit Retro Mode',
rss: 'RSS',
},
common: {
status: {
@@ -120,6 +121,7 @@ export default {
platform: 'Platform:',
play: '▶ Play',
moreInfo: ' More Info',
downloads: 'downloads',
},
catalogShow: {
back: '← Back to Catalog',
@@ -142,6 +144,7 @@ export default {
failedToLoad: 'Failed to load:',
loading: 'Loading...',
play: '▶ Play',
downloads: 'downloads',
},
team: {
title: 'Our Team',
+3
View File
@@ -9,6 +9,7 @@ export default {
contact: 'Kapcsolat',
retro: 'Retró mód',
exitRetro: 'Retró mód kikapcsolása',
rss: 'RSS',
},
common: {
status: {
@@ -120,6 +121,7 @@ export default {
platform: 'Platform:',
play: '▶ Játék',
moreInfo: ' Részletek',
downloads: 'letöltés',
},
catalogShow: {
back: '← Vissza a katalógushoz',
@@ -142,6 +144,7 @@ export default {
failedToLoad: 'Nem sikerült betölteni:',
loading: 'Betöltés...',
play: '▶ Játék',
downloads: 'letöltés',
},
team: {
title: 'Csapatunk',
+14 -3
View File
@@ -49,9 +49,20 @@
</main>
<div class="retro-toggle-bar">
<button class="retro-toggle-btn" @click="toggleRetroMode">
🖥 {{ isRetroMode ? t('nav.exitRetro') : t('nav.retro') }}
</button>
<div class="flex items-center justify-center gap-4">
<button class="retro-toggle-btn" @click="toggleRetroMode">
🖥 {{ isRetroMode ? t('nav.exitRetro') : t('nav.retro') }}
</button>
<div class="flex items-center gap-2 text-xs text-gray-400">
<a href="/api/rss/blog" target="_blank" class="hover:text-orange-400 transition-colors" title="Blog RSS">
📡 Blog
</a>
<span class="text-gray-600">|</span>
<a href="/api/rss/releases" target="_blank" class="hover:text-orange-400 transition-colors" title="Releases RSS">
📡 Releases
</a>
</div>
</div>
</div>
</div>
</template>
@@ -4,6 +4,7 @@ export interface Release {
cartridgePath?: string
sourcePath?: string
docsFolderPath?: string
downloadCount?: number
UpdatedAt: string
}
@@ -30,4 +31,5 @@ export interface Software {
export interface SoftwareEntry {
software: Software
releases: Release[]
totalDownloads?: number
}
@@ -51,6 +51,9 @@
<RouterLink :to="`/catalog/${software.name}`" class="btn-info-sm">
{{ t('catalog.moreInfo') }}
</RouterLink>
<span v-if="getTotalDownloads(software.name)" class="text-xs text-gray-400 font-medium ml-1">
{{ getTotalDownloads(software.name) }} {{ t('catalog.downloads') }}
</span>
</div>
</div>
</div>
@@ -66,7 +69,7 @@ import { storeToRefs } from 'pinia'
import { RouterLink } from 'vue-router'
import { useI18n } from 'vue-i18n'
import { useSoftwareStore } from '../../stores/software.store'
import type { Software } from '../../lib/interfaces/software.interface'
import type { Software, SoftwareEntry } from '../../lib/interfaces/software.interface'
const { t } = useI18n()
@@ -77,6 +80,11 @@ const store = useSoftwareStore()
const { items: softwares } = storeToRefs(store)
const { getLatestStable } = store
function getTotalDownloads(name: string): number | null {
const entry = softwares.value.find((e: SoftwareEntry) => e.software.name === name)
return entry?.totalDownloads || null
}
function getDefaultImageUrl(sw: Software): string | null {
if (sw.images?.length) {
const def = sw.images.find(i => i.isDefault)
@@ -95,8 +95,8 @@
<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">{{ t('catalogShow.playNow') }}</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">{{ t('catalogShow.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">{{ t('catalogShow.source') }}</a>
<a v-if="latestStable.cartridgePath" :href="downloadUrl(latestStable.cartridgePath)" 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">{{ t('catalogShow.download') }}</a>
<a v-if="latestStable.sourcePath" :href="downloadUrl(latestStable.sourcePath)" 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">{{ t('catalogShow.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">{{ t('catalogShow.docs') }}</a>
</div>
</div>
@@ -119,11 +119,14 @@
<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 items-center gap-2 mb-2">
<span class="font-bold text-gray-900 text-lg">{{ release.version }}</span>
<span v-if="release.downloadCount" class="text-xs text-gray-400 font-medium"> {{ release.downloadCount }}</span>
</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">{{ t('catalogShow.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">{{ t('catalogShow.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">{{ t('catalogShow.source') }}</a>
<a v-if="release.cartridgePath" :href="downloadUrl(release.cartridgePath)" class="text-blue-600 hover:text-blue-900 font-bold text-sm flex items-center gap-1">{{ t('catalogShow.download') }}</a>
<a v-if="release.sourcePath" :href="downloadUrl(release.sourcePath)" class="text-green-600 hover:text-green-900 font-bold text-sm flex items-center gap-1">{{ t('catalogShow.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">{{ t('catalogShow.docs') }}</a>
</div>
</td>
@@ -139,7 +142,7 @@
<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">{{ t('catalogShow.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">{{ t('catalogShow.download') }}</a>
<a v-if="release.cartridgePath" :href="downloadUrl(release.cartridgePath)" class="text-blue-600 hover:text-blue-900 font-bold text-sm flex items-center gap-1">{{ t('catalogShow.download') }}</a>
</div>
</td>
<td class="px-8 py-4 text-gray-500 align-top pt-5">{{ formatDateTime(release.UpdatedAt) }}</td>
@@ -164,8 +167,8 @@
</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">{{ t('catalogShow.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">{{ t('catalogShow.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">{{ t('catalogShow.source') }}</a>
<a v-if="release.cartridgePath" :href="downloadUrl(release.cartridgePath)" class="flex items-center justify-center py-2 bg-blue-100 text-blue-700 font-bold rounded-lg text-sm">{{ t('catalogShow.download') }}</a>
<a v-if="release.sourcePath" :href="downloadUrl(release.sourcePath)" class="flex items-center justify-center py-2 bg-green-100 text-green-700 font-bold rounded-lg text-sm">{{ t('catalogShow.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">{{ t('catalogShow.docs') }}</a>
</div>
</div>
@@ -250,6 +253,9 @@ const devReleases = computed(() =>
const allReleases = computed(() => [...stableReleases.value, ...devReleases.value])
const latestStable = computed(() => stableReleases.value[0] ?? null)
const downloadUrl = (path: string) =>
`/download?path=${encodeURIComponent(path.replace('/file/', ''))}`
onMounted(async () => {
try {
await store.fetchAll()