From d3e1bf049b19659cca0f5b57f205111c1f8ada7b Mon Sep 17 00:00:00 2001
From: Garret Patti <42485635+garretpatti@users.noreply.github.com>
Date: Sun, 12 Apr 2026 11:53:27 -0400
Subject: [PATCH 1/3] handle android and swap to os icons
---
src/app/icons/android.svg | 6 ++++++
src/app/icons/linux.svg | 6 ++++++
src/app/icons/mac.svg | 19 +++++++++++++++++
src/app/icons/windows.svg | 19 +++++++++++++++++
src/components/games/GameDetailModal.tsx | 25 ++++++++++++++++++++--
src/components/games/GamesView.tsx | 27 ++++++++++++++++++++++--
src/lib/games.ts | 1 +
src/types/index.ts | 2 +-
8 files changed, 100 insertions(+), 5 deletions(-)
create mode 100644 src/app/icons/android.svg
create mode 100644 src/app/icons/linux.svg
create mode 100644 src/app/icons/mac.svg
create mode 100644 src/app/icons/windows.svg
diff --git a/src/app/icons/android.svg b/src/app/icons/android.svg
new file mode 100644
index 0000000..b413770
--- /dev/null
+++ b/src/app/icons/android.svg
@@ -0,0 +1,6 @@
+
+
+
\ No newline at end of file
diff --git a/src/app/icons/linux.svg b/src/app/icons/linux.svg
new file mode 100644
index 0000000..2172e59
--- /dev/null
+++ b/src/app/icons/linux.svg
@@ -0,0 +1,6 @@
+
+
+
+
\ No newline at end of file
diff --git a/src/app/icons/mac.svg b/src/app/icons/mac.svg
new file mode 100644
index 0000000..381f84a
--- /dev/null
+++ b/src/app/icons/mac.svg
@@ -0,0 +1,19 @@
+
+
+
\ No newline at end of file
diff --git a/src/app/icons/windows.svg b/src/app/icons/windows.svg
new file mode 100644
index 0000000..81dcb9d
--- /dev/null
+++ b/src/app/icons/windows.svg
@@ -0,0 +1,19 @@
+
+
+
\ No newline at end of file
diff --git a/src/components/games/GameDetailModal.tsx b/src/components/games/GameDetailModal.tsx
index 8d29e7e..5d857c0 100644
--- a/src/components/games/GameDetailModal.tsx
+++ b/src/components/games/GameDetailModal.tsx
@@ -4,15 +4,25 @@ import { useEffect, useRef, useState, useCallback } from 'react'
import type { Game, GameFile, GamePlatform } from '@/types'
import TagSelector from '@/components/tags/TagSelector'
+// Import SVG icons
+import WindowsIcon from '@/app/icons/windows.svg'
+import LinuxIcon from '@/app/icons/linux.svg'
+import MacosIcon from '@/app/icons/mac.svg'
+import AndroidIcon from '@/app/icons/android.svg'
+
+// Update the PLATFORM_LABELS to include android
const PLATFORM_LABELS: Record = {
windows: 'WIN',
linux: 'LIN',
macos: 'MAC',
+ android: 'AND',
}
+
const PLATFORM_COLORS: Record = {
windows: '#0078d4',
linux: '#e95420',
macos: '#6e6e73',
+ android: '#10b981',
}
interface Props {
@@ -516,13 +526,24 @@ export default function GameDetailModal({ game, libraryId, onClose, onTagsChange
// ─── Download Button ──────────────────────────────────────────────────────────
+const PLATFORM_ICONS: Record = {
+ windows: (typeof WindowsIcon === 'string' ? WindowsIcon : (WindowsIcon as { src: string }).src),
+ linux: (typeof LinuxIcon === 'string' ? LinuxIcon : (LinuxIcon as { src: string }).src),
+ macos: (typeof MacosIcon === 'string' ? MacosIcon : (MacosIcon as { src: string }).src),
+ android: (typeof AndroidIcon === 'string' ? AndroidIcon : (AndroidIcon as { src: string }).src),
+}
+
function PlatformPill({ platform }: { platform: GamePlatform }) {
+ const src = PLATFORM_ICONS[platform]
+
return (
- {PLATFORM_LABELS[platform]}
+ {/* eslint-disable-next-line @next/next/no-img-element */}
+ {src &&
}
+ {PLATFORM_LABELS[platform]}
)
}
diff --git a/src/components/games/GamesView.tsx b/src/components/games/GamesView.tsx
index 66dc217..0aadb07 100644
--- a/src/components/games/GamesView.tsx
+++ b/src/components/games/GamesView.tsx
@@ -5,15 +5,37 @@ import type { Game, GamePlatform, GameSeries } from '@/types'
import GameDetailModal from './GameDetailModal'
import FilterPanel from '@/components/FilterPanel'
+// Import SVG icons
+import WindowsIcon from '@/app/icons/windows.svg'
+import LinuxIcon from '@/app/icons/linux.svg'
+import MacosIcon from '@/app/icons/mac.svg'
+import AndroidIcon from '@/app/icons/android.svg'
+
const PLATFORM_LABELS: Record = {
windows: 'WIN',
linux: 'LIN',
macos: 'MAC',
+ android: 'AND',
}
const PLATFORM_COLORS: Record = {
windows: '#0078d4',
linux: '#e95420',
macos: '#6e6e73',
+ android: '#10b981',
+}
+
+const PLATFORM_ICONS: Record = {
+ windows: (typeof WindowsIcon === 'string' ? WindowsIcon : (WindowsIcon as { src: string }).src),
+ linux: (typeof LinuxIcon === 'string' ? LinuxIcon : (LinuxIcon as { src: string }).src),
+ macos: (typeof MacosIcon === 'string' ? MacosIcon : (MacosIcon as { src: string }).src),
+ android: (typeof AndroidIcon === 'string' ? AndroidIcon : (AndroidIcon as { src: string }).src),
+}
+
+function getPlatformIcon(platform: GamePlatform) {
+ const src = PLATFORM_ICONS[platform]
+ if (!src) return null
+ // eslint-disable-next-line @next/next/no-img-element
+ return
}
function PlatformBadges({ platforms }: { platforms: GamePlatform[] }) {
@@ -23,10 +45,11 @@ function PlatformBadges({ platforms }: { platforms: GamePlatform[] }) {
{platforms.map((p) => (
- {PLATFORM_LABELS[p]}
+ {getPlatformIcon(p)}
+ {PLATFORM_LABELS[p]}
))}
diff --git a/src/lib/games.ts b/src/lib/games.ts
index 8f4c151..cc7ada8 100644
--- a/src/lib/games.ts
+++ b/src/lib/games.ts
@@ -12,6 +12,7 @@ function platformForFile(name: string): GamePlatform | null {
if (lower.endsWith('.zip')) return 'windows'
if (lower.endsWith('.tar.gz')) return 'linux'
if (lower.endsWith('.dmg')) return 'macos'
+ if (lower.endsWith('.apk')) return 'android'
return null
}
diff --git a/src/types/index.ts b/src/types/index.ts
index 411375a..19d014c 100644
--- a/src/types/index.ts
+++ b/src/types/index.ts
@@ -8,7 +8,7 @@ export interface Library {
coverExt: string | null
}
-export type GamePlatform = 'windows' | 'linux' | 'macos'
+export type GamePlatform = 'windows' | 'linux' | 'macos' | 'android'
export interface GameFile {
path: string
--
2.49.1
From 080cc011b9b9a0c2defa234a09e768a319fdd52b Mon Sep 17 00:00:00 2001
From: Garret Patti <42485635+garretpatti@users.noreply.github.com>
Date: Sun, 12 Apr 2026 12:41:42 -0400
Subject: [PATCH 2/3] icon color and size tweaks
---
src/components/games/GameDetailModal.tsx | 14 ++++++++------
src/components/games/GamesView.tsx | 8 ++++----
2 files changed, 12 insertions(+), 10 deletions(-)
diff --git a/src/components/games/GameDetailModal.tsx b/src/components/games/GameDetailModal.tsx
index 5d857c0..43ba60a 100644
--- a/src/components/games/GameDetailModal.tsx
+++ b/src/components/games/GameDetailModal.tsx
@@ -19,10 +19,10 @@ const PLATFORM_LABELS: Record = {
}
const PLATFORM_COLORS: Record = {
- windows: '#0078d4',
- linux: '#e95420',
- macos: '#6e6e73',
- android: '#10b981',
+ windows: '#85c0ec',
+ linux: '#efd27b',
+ macos: '#b0b0b7',
+ android: '#9ee0ca',
}
interface Props {
@@ -589,8 +589,9 @@ function DownloadButton({
onMouseLeave={(e) => ((e.currentTarget as HTMLElement).style.backgroundColor = 'var(--accent)')}
>
↓
-
- Download {primary.filename}
+ {primary.filename}
+
+
)
}
@@ -610,6 +611,7 @@ function DownloadButton({
↓
{primary.filename}
+
{/* Divider */}
diff --git a/src/components/games/GamesView.tsx b/src/components/games/GamesView.tsx
index 0aadb07..a278d1b 100644
--- a/src/components/games/GamesView.tsx
+++ b/src/components/games/GamesView.tsx
@@ -18,10 +18,10 @@ const PLATFORM_LABELS: Record = {
android: 'AND',
}
const PLATFORM_COLORS: Record = {
- windows: '#0078d4',
- linux: '#e95420',
- macos: '#6e6e73',
- android: '#10b981',
+ windows: '#85c0ec',
+ linux: '#efd27b',
+ macos: '#b0b0b7',
+ android: '#9ee0ca',
}
const PLATFORM_ICONS: Record = {
--
2.49.1
From 0091606e4d8050f8fc255935855689b07d204b2d Mon Sep 17 00:00:00 2001
From: Garret Patti <42485635+garretpatti@users.noreply.github.com>
Date: Sun, 12 Apr 2026 13:09:07 -0400
Subject: [PATCH 3/3] handle other archive types for linux
---
src/app/api/file/route.ts | 22 +++++++++++++++++++---
src/components/games/GameDetailModal.tsx | 3 +--
src/lib/games.ts | 4 ++++
3 files changed, 24 insertions(+), 5 deletions(-)
diff --git a/src/app/api/file/route.ts b/src/app/api/file/route.ts
index 36d76a2..cb97190 100644
--- a/src/app/api/file/route.ts
+++ b/src/app/api/file/route.ts
@@ -23,18 +23,34 @@ const MIME_TYPES: Record = {
'.zip': 'application/zip',
'.dmg': 'application/x-apple-diskimage',
'.gz': 'application/gzip',
+ '.tgz': 'application/gzip',
+ '.bz2': 'application/x-bzip2',
+ '.xz': 'application/x-xz',
+ '.zst': 'application/zstd',
}
function getMimeType(filePath: string): string {
- // Special-case .tar.gz before checking the last extension
- if (filePath.toLowerCase().endsWith('.tar.gz')) return 'application/gzip'
+ // Special-case multi-part extensions before checking the last extension
+ const lower = filePath.toLowerCase()
+ if (lower.endsWith('.tar.gz')) return 'application/gzip'
+ if (lower.endsWith('.tar.bz2')) return 'application/x-bzip2'
+ if (lower.endsWith('.tar.xz')) return 'application/x-xz'
+ if (lower.endsWith('.tar.zst')) return 'application/zstd'
const ext = path.extname(filePath).toLowerCase()
return MIME_TYPES[ext] ?? 'application/octet-stream'
}
function isDownloadAttachment(filePath: string): boolean {
const lower = filePath.toLowerCase()
- return lower.endsWith('.zip') || lower.endsWith('.tar.gz') || lower.endsWith('.dmg')
+ return (
+ lower.endsWith('.zip') ||
+ lower.endsWith('.tar.gz') ||
+ lower.endsWith('.tar.bz2') ||
+ lower.endsWith('.tar.xz') ||
+ lower.endsWith('.tar.zst') ||
+ lower.endsWith('.tgz') ||
+ lower.endsWith('.dmg')
+ )
}
export async function GET(request: NextRequest) {
diff --git a/src/components/games/GameDetailModal.tsx b/src/components/games/GameDetailModal.tsx
index 43ba60a..b9a8508 100644
--- a/src/components/games/GameDetailModal.tsx
+++ b/src/components/games/GameDetailModal.tsx
@@ -609,7 +609,6 @@ function DownloadButton({
onMouseLeave={(e) => ((e.currentTarget as HTMLElement).style.backgroundColor = 'transparent')}
>
↓
-
{primary.filename}
@@ -647,8 +646,8 @@ function DownloadButton({
onMouseLeave={(e) => ((e.currentTarget as HTMLElement).style.backgroundColor = 'transparent')}
>
↓
-
{file.filename}
+
))}
diff --git a/src/lib/games.ts b/src/lib/games.ts
index cc7ada8..30dbba7 100644
--- a/src/lib/games.ts
+++ b/src/lib/games.ts
@@ -11,6 +11,10 @@ function platformForFile(name: string): GamePlatform | null {
const lower = name.toLowerCase()
if (lower.endsWith('.zip')) return 'windows'
if (lower.endsWith('.tar.gz')) return 'linux'
+ if (lower.endsWith('.tar.bz2')) return 'linux'
+ if (lower.endsWith('.tar.xz')) return 'linux'
+ if (lower.endsWith('.tar.zst')) return 'linux'
+ if (lower.endsWith('.tgz')) return 'linux'
if (lower.endsWith('.dmg')) return 'macos'
if (lower.endsWith('.apk')) return 'android'
return null
--
2.49.1