project-nomad/admin/inertia/components/CuratedCollectionCard.tsx
Martin Seener 134d1642af
Added initial i18n framework and most german translations
- Add i18next, react-i18next, i18next-browser-languagedetector packages
- Configure i18n initialization with language detector in lib/i18n.ts
- Created en/de translation files and moved most hard-coded strings into the files and translated them
- Uses locale-aware date formatting where applicable
- Added language-specific Wikipedia content files (wikipedia.en.json, wikipedia.de.json) and updated download URLs
- Added NOMAD_REPO_URL env variable for fork-friendly URL resolution (easier testing and rollout independent of Crosstalk repo)
2026-03-24 13:21:31 +01:00

61 lines
2.2 KiB
TypeScript

import { formatBytes } from '~/lib/util'
import { useTranslation } from 'react-i18next'
import DynamicIcon, { DynamicIconName } from './DynamicIcon'
import type { CollectionWithStatus } from '../../types/collections'
import classNames from 'classnames'
import { IconCircleCheck } from '@tabler/icons-react'
export interface CuratedCollectionCardProps {
collection: CollectionWithStatus
onClick?: (collection: CollectionWithStatus) => void;
size?: 'small' | 'large'
}
const CuratedCollectionCard: React.FC<CuratedCollectionCardProps> = ({ collection, onClick, size = 'small' }) => {
const { t } = useTranslation()
const totalSizeBytes = collection.resources?.reduce(
(acc, resource) => acc + resource.size_mb * 1024 * 1024,
0
)
return (
<div
className={classNames(
'flex flex-col bg-desert-green rounded-lg p-6 text-white border border-b-desert-green shadow-sm hover:shadow-lg transition-shadow cursor-pointer',
{ 'opacity-65 cursor-not-allowed !hover:shadow-sm': collection.all_installed },
{ 'h-56': size === 'small', 'h-80': size === 'large' }
)}
onClick={() => {
if (collection.all_installed) {
return
}
if (onClick) {
onClick(collection)
}
}}
>
<div className="flex items-center mb-4">
<div className="flex justify-between w-full items-center">
<div className="flex">
<DynamicIcon icon={collection.icon as DynamicIconName} className="w-6 h-6 mr-2" />
<h3 className="text-lg font-semibold">{collection.name}</h3>
</div>
{collection.all_installed && (
<div className="flex items-center">
<IconCircleCheck
className="w-5 h-5 text-lime-400 ml-2"
title={t('common.allItemsDownloaded')}
/>
<p className="text-lime-400 text-sm ml-1">{t('common.allItemsDownloaded')}</p>
</div>
)}
</div>
</div>
<p className="text-gray-200 grow">{collection.description}</p>
<p className="text-gray-200 text-xs mt-2">
{t('common.items', { count: collection.resources?.length, size: formatBytes(totalSizeBytes, 0) })}
</p>
</div>
)
}
export default CuratedCollectionCard