Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 25 additions & 17 deletions components/AppStore/AppDetails.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,15 +76,15 @@ const AppDetails = () => {

const getGradeDescription = (grade) => {
const gradeKey = grade?.toLowerCase();
return t.appStore.details.grades[gradeKey] || "";
return t.appStore?.details?.grades?.[gradeKey] || '';
}

if (loading) {
return (
<div className="min-h-screen flex items-center justify-center bg-zinc-50 dark:bg-black">
<div className="text-center">
<div className="inline-block w-12 h-12 border-4 border-zinc-200 border-t-blue-600 rounded-full animate-spin mb-4"></div>
<p className="text-zinc-500">{t.appStore.details.loading}</p>
<p className="text-zinc-500">{t.appStore?.details?.loading || 'Loading app details...'}</p>
</div>
</div>
);
Expand All @@ -94,8 +94,8 @@ const AppDetails = () => {
return (
<div className="min-h-screen flex items-center justify-center bg-zinc-50 dark:bg-black">
<div className="text-center">
<h1 className="text-2xl font-bold mb-4 text-zinc-900 dark:text-white">{t.appStore.details.notFound}</h1>
<Link to="/appstore" className="text-blue-600 hover:underline">{t.appStore.details.back}</Link>
<h1 className="text-2xl font-bold mb-4 text-zinc-900 dark:text-white">{t.appStore?.details?.notFound || 'App not found'}</h1>
<Link to="/appstore" className="text-blue-600 hover:underline">{t.appStore?.details?.back || 'Back to App Store'}</Link>
</div>
</div>
);
Expand All @@ -106,7 +106,7 @@ const AppDetails = () => {
<section className="pt-32 pb-12 bg-white dark:bg-zinc-900/20 border-b border-zinc-200 dark:border-white/5">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<Link to="/appstore" className="inline-flex items-center text-zinc-500 hover:text-zinc-900 dark:hover:text-white mb-8 transition-colors">
<ArrowLeft className="w-4 h-4 mr-2" /> {t.appStore.details.back}
<ArrowLeft className="w-4 h-4 mr-2" /> {t.appStore?.details?.back || 'Back to App Store'}
</Link>

<div className="flex flex-col md:flex-row gap-8 items-start">
Expand Down Expand Up @@ -138,15 +138,15 @@ const AppDetails = () => {
className="inline-flex items-center px-6 py-3 rounded-full bg-blue-600 hover:bg-blue-700 text-white font-medium transition-colors"
>
<Download className="w-5 h-5 mr-2" />
{t.appStore.details.install}
{t.appStore?.details?.install || 'Install'}
</Link>
{reviewContent && (
<button
onClick={() => setShowReview(true)}
className="inline-flex items-center px-6 py-3 rounded-full bg-zinc-100 dark:bg-zinc-800 hover:bg-zinc-200 dark:hover:bg-zinc-700 text-zinc-900 dark:text-white font-medium transition-colors"
>
<Star className="w-5 h-5 mr-2" />
{t.appStore.details.readReview}
{t.appStore?.details?.readReview || 'Read review'}
</button>
)}
</div>
Expand All @@ -168,7 +168,7 @@ const AppDetails = () => {
<section>
<h2 className="text-2xl font-bold text-zinc-900 dark:text-white mb-4 flex items-center gap-2">
<Shield className="w-6 h-6 text-blue-600" />
{t.appStore.details.aboutGrade.replace('{grade}', entry.Grade)}
{(t.appStore?.details?.aboutGrade || 'About this {grade} app').replace('{grade}', entry.Grade)}
</h2>
<p className="text-zinc-600 dark:text-zinc-400 text-lg leading-relaxed">
{getGradeDescription(entry.Grade)}
Expand All @@ -179,17 +179,17 @@ const AppDetails = () => {
<section>
<h2 className="text-2xl font-bold text-zinc-900 dark:text-white mb-6 flex items-center gap-2">
<Package className="w-6 h-6 text-purple-600" />
{t.appStore.details.dependencies.title}
{t.appStore?.details?.dependencies?.title || 'Dependencies'}
</h2>
<p className="text-zinc-600 dark:text-zinc-400 mb-6">
{t.appStore.details.dependencies.description}
{t.appStore?.details?.dependencies?.description || 'These dependencies are required for the installer.'}
</p>
<div className="grid md:grid-cols-2 gap-4">
{details.Dependencies.map(dep => (
<div key={dep} className="bg-white dark:bg-zinc-900 p-6 rounded-xl border border-zinc-200 dark:border-zinc-800">
<h3 className="font-bold text-zinc-900 dark:text-white mb-2">{dep}</h3>
<p className="text-sm text-zinc-600 dark:text-zinc-400">
{dependenciesData[dep]?.Description || t.appStore.details.dependencies.noDescription}
{dependenciesData[dep]?.Description || t.appStore?.details?.dependencies?.noDescription || 'No description available.'}
</p>
</div>
))}
Expand All @@ -201,24 +201,32 @@ const AppDetails = () => {
<section>
<h2 className="text-2xl font-bold text-zinc-900 dark:text-white mb-6 flex items-center gap-2">
<Settings className="w-6 h-6 text-zinc-500" />
{t.appStore.details.configuration.title}
{t.appStore?.details?.configuration?.title || 'Configuration'}
</h2>
<p className="text-zinc-600 dark:text-zinc-400 mb-6">
{t.appStore.details.configuration.description}
{t.appStore?.details?.configuration?.description || 'The following configuration will be applied to your bottle:'}
</p>
<div className="bg-white dark:bg-zinc-900 p-6 rounded-xl border border-zinc-200 dark:border-zinc-800">
<ul className="space-y-2">
{Object.entries(details.Parameters).map(([param, value]) => (
<li key={param} className="flex items-center gap-2 text-zinc-700 dark:text-zinc-300 font-mono text-sm">
<div className={`w-2 h-2 rounded-full ${value ? 'bg-green-500' : 'bg-red-500'}`}></div>
{param}: <span className={value ? 'text-green-600 dark:text-green-400' : 'text-red-600 dark:text-red-400'}>{value ? t.appStore.details.configuration.enabled : t.appStore.details.configuration.disabled}</span>
{param}: <span className={value ? 'text-green-600 dark:text-green-400' : 'text-red-600 dark:text-red-400'}>{value ? (t.appStore?.details?.configuration?.enabled || 'enabled') : (t.appStore?.details?.configuration?.disabled || 'disabled')}</span>
</li>
))}
</ul>
</div>
</section>
)}

<section className="py-6 bg-white dark:bg-zinc-900/20 rounded-2xl border border-zinc-200 dark:border-zinc-800">
<div className="px-6">
<p className="text-xs text-zinc-500 dark:text-zinc-400 leading-relaxed">
{t.appStore?.details?.disclaimer || 'Bottles does not re-distribute or host the files but only downloads them from the vendor\'s official sources. These files are checked by our maintainers and do not contain viruses. However, they may be subject to copyright or licenses of different types, including proprietary ones.'}
</p>
</div>
</section>

<section className="pt-8 border-t border-zinc-200 dark:border-zinc-800">
<div className="flex flex-col sm:flex-row gap-4 justify-center">
<a
Expand All @@ -227,15 +235,15 @@ const AppDetails = () => {
rel="noopener noreferrer"
className="flex items-center justify-center gap-2 px-6 py-3 rounded-xl bg-zinc-100 dark:bg-zinc-800 hover:bg-zinc-200 dark:hover:bg-zinc-700 text-zinc-900 dark:text-white transition-colors"
>
{t.appStore.details.wineDb} <ExternalLink className="w-4 h-4" />
{t.appStore?.details?.wineDb || 'More info on WineDB'} <ExternalLink className="w-4 h-4" />
</a>
<a
href={`https://www.protondb.com/search?q=${entry.Name}`}
target="_blank"
rel="noopener noreferrer"
className="flex items-center justify-center gap-2 px-6 py-3 rounded-xl bg-zinc-100 dark:bg-zinc-800 hover:bg-zinc-200 dark:hover:bg-zinc-700 text-zinc-900 dark:text-white transition-colors"
>
{t.appStore.details.protonDb} <ExternalLink className="w-4 h-4" />
{t.appStore?.details?.protonDb || 'More info on ProtonDB'} <ExternalLink className="w-4 h-4" />
</a>
</div>
</section>
Expand All @@ -245,7 +253,7 @@ const AppDetails = () => {
<div className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/50 backdrop-blur-sm animate-in fade-in duration-200">
<div className="bg-white dark:bg-zinc-900 w-full max-w-3xl max-h-[80vh] rounded-2xl shadow-2xl flex flex-col">
<div className="p-6 border-b border-zinc-200 dark:border-zinc-800 flex justify-between items-center">
<h2 className="text-2xl font-bold text-zinc-900 dark:text-white">{t.appStore.details.review} {entry.Name}</h2>
<h2 className="text-2xl font-bold text-zinc-900 dark:text-white">{t.appStore?.details?.review || 'Review for'} {entry.Name}</h2>
<button onClick={() => setShowReview(false)} className="text-zinc-500 hover:text-zinc-900 dark:hover:text-white">
<X className="w-6 h-6" />
</button>
Expand Down
29 changes: 29 additions & 0 deletions i18n/translations/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,35 @@ export const en = {
card: {
details: 'Details',
install: 'Install'
},
details: {
loading: 'Loading app details...',
notFound: 'App not found',
back: 'Back to App Store',
aboutGrade: 'About this {grade} app',
grades: {
bronze: 'This application works but not in the best way. The installer has configured your bottle to give you the best possible experience but you have to expect glitches, inaccessible features (e.g. multiplayer if it\'s a game) and other problems. In the future, this installer may receive updates to improve the result.',
silver: 'This application works fine. There are some glitches, but they do not affect the application\'s functionality. All features are accessible and work as expected.',
gold: 'This application works in the best way. There may be rare glitches but they do not affect the application\'s functionality. All features are accessible and work as expected.',
platinum: 'This application works in the best way. There are no glitches. All features are accessible and work as expected, and the overall experience is smooth.',
},
dependencies: {
title: 'Dependencies',
description: 'The following dependencies will be automatically installed with this app:',
noDescription: 'No description available.',
},
configuration: {
title: 'Configuration',
description: 'The following configuration will be applied to your bottle:',
enabled: 'enabled',
disabled: 'disabled',
},
install: 'How to Install',
readReview: 'Read review',
review: 'Review for',
disclaimer: 'Bottles does not re-distribute or host the files but only downloads them from the vendor\'s official sources. These files are checked by our maintainers and do not contain viruses. However, they may be subject to copyright or licenses of different types, including proprietary ones.',
wineDb: 'More info on WineDB',
protonDb: 'More info on ProtonDB',
}
},
hero: {
Expand Down
29 changes: 29 additions & 0 deletions i18n/translations/es.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,35 @@ export const es = {
card: {
details: 'Detalles',
install: 'Instalar'
},
details: {
loading: 'Cargando detalles de la aplicación...',
notFound: 'Aplicación no encontrada',
back: 'Volver a la Tienda de Aplicaciones',
aboutGrade: 'Acerca de esta aplicación {grade}',
grades: {
bronze: 'Esta aplicación funciona, pero no de la mejor manera. El instalador ha configurado tu botella para ofrecerte la mejor experiencia posible, pero debes esperar fallos, funciones inaccesibles (por ejemplo, el multijugador si es un juego) y otros problemas. En el futuro, este instalador puede recibir actualizaciones para mejorar el resultado.',
silver: 'Esta aplicación funciona bien. Hay algunos fallos, pero no afectan la funcionalidad de la aplicación. Todas las funciones están accesibles y funcionan como se espera.',
gold: 'Esta aplicación funciona de la mejor manera. Puede haber fallos raros, pero no afectan la funcionalidad de la aplicación. Todas las funciones están accesibles y funcionan como se espera.',
platinum: 'Esta aplicación funciona de la mejor manera. No hay fallos. Todas las funciones están accesibles y funcionan como se espera, y la experiencia general es fluida.',
},
dependencies: {
title: 'Dependencias',
description: 'Las siguientes dependencias se instalarán automáticamente con esta aplicación:',
noDescription: 'No hay descripción disponible.',
},
configuration: {
title: 'Configuración',
description: 'La siguiente configuración se aplicará a tu botella:',
enabled: 'habilitado',
disabled: 'deshabilitado',
},
install: 'Cómo instalar',
readReview: 'Leer reseña',
review: 'Reseña de',
disclaimer: 'Bottles no redistribuye ni aloja los archivos, solo los descarga desde las fuentes oficiales del proveedor. Estos archivos son revisados por nuestros mantenedores y no contienen virus. Sin embargo, pueden estar sujetos a derechos de autor o licencias de distintos tipos, incluidas licencias propietarias.',
wineDb: 'Más información en WineDB',
protonDb: 'Más información en ProtonDB',
}
},
hero: {
Expand Down
29 changes: 29 additions & 0 deletions i18n/translations/it.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,35 @@ export const it = {
card: {
details: 'Dettagli',
install: 'Installa'
},
details: {
loading: 'Caricamento dettagli app...',
notFound: 'App non trovata',
back: 'Torna all\'App Store',
aboutGrade: 'Informazioni su questa app {grade}',
grades: {
bronze: 'Questa applicazione funziona, ma non nel modo migliore. L\'installer ha configurato la tua bottle per offrirti la migliore esperienza possibile, ma devi aspettarti glitch, funzionalita non accessibili (ad esempio il multiplayer se e un gioco) e altri problemi. In futuro, questo installer potrebbe ricevere aggiornamenti per migliorare il risultato.',
silver: 'Questa applicazione funziona bene. Ci sono alcuni glitch, ma non influenzano la funzionalita dell\'applicazione. Tutte le funzionalita sono accessibili e funzionano come previsto.',
gold: 'Questa applicazione funziona nel modo migliore. Potrebbero esserci rari glitch, ma non influenzano la funzionalita dell\'applicazione. Tutte le funzionalita sono accessibili e funzionano come previsto.',
platinum: 'Questa applicazione funziona nel modo migliore. Non ci sono glitch. Tutte le funzionalita sono accessibili e funzionano come previsto, e l\'esperienza complessiva e fluida.',
},
dependencies: {
title: 'Dipendenze',
description: 'Le seguenti dipendenze verranno installate automaticamente con questa applicazione:',
noDescription: 'Nessuna descrizione disponibile.',
},
configuration: {
title: 'Configurazione',
description: 'La seguente configurazione verra applicata alla tua bottle:',
enabled: 'abilitato',
disabled: 'disabilitato',
},
install: 'Come installare',
readReview: 'Leggi la recensione',
review: 'Recensione di',
disclaimer: 'Bottles non ridistribuisce ne ospita i file, ma li scarica solo dalle fonti ufficiali del fornitore. Questi file sono controllati dai nostri maintainer e non contengono virus. Tuttavia, possono essere soggetti a copyright o licenze di vario tipo, incluse quelle proprietarie.',
wineDb: 'Maggiori info su WineDB',
protonDb: 'Maggiori info su ProtonDB',
}
},
hero: {
Expand Down
Loading