mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-10-06 14:11:35 +02:00
The app was built dark-first, so hundreds of hardcoded Tailwind semantic text/icon utilities at light shades (text-amber-400, text-blue-300, ...) had no dark: variant. With darkMode:'class' they applied in light theme too, producing washed-out text on pale tints and white cards — including the three reported spots (AMS Drying banner, Archives no-3MF warning, debug-logging banner). Give each a theme-aware pair: a darker readable shade in light theme with the original pinned to dark:, so dark theme is unchanged. ~100 files. The bambu-* CSS-variable palette (self-correcting) and the dark-only SpoolBuddy kiosk are left untouched. Plain text-white is already theme-aware via the existing index.css .text-white override, so it needed no changes.
104 lines
3.7 KiB
TypeScript
104 lines
3.7 KiB
TypeScript
import { useQuery } from '@tanstack/react-query';
|
|
import { useTranslation } from 'react-i18next';
|
|
import { Loader2 } from 'lucide-react';
|
|
import { api } from '../api/client';
|
|
import { parseUTCDate } from '../utils/date';
|
|
|
|
interface PrintLogTableProps {
|
|
archiveId: number;
|
|
}
|
|
|
|
function formatDuration(seconds: number | null): string {
|
|
if (!seconds || seconds <= 0) return '—';
|
|
const h = Math.floor(seconds / 3600);
|
|
const m = Math.floor((seconds % 3600) / 60);
|
|
if (h > 0) return `${h}h ${m}m`;
|
|
return `${m}m`;
|
|
}
|
|
|
|
function formatDate(isoString: string | null): string {
|
|
if (!isoString) return '—';
|
|
const d = parseUTCDate(isoString);
|
|
return d ? d.toLocaleString() : '—';
|
|
}
|
|
|
|
export function PrintLogTable({ archiveId }: PrintLogTableProps) {
|
|
const { t } = useTranslation();
|
|
const { data, isLoading } = useQuery({
|
|
queryKey: ['archive-runs', archiveId],
|
|
queryFn: () => api.getArchiveRuns(archiveId),
|
|
});
|
|
|
|
if (isLoading) {
|
|
return (
|
|
<div className="flex justify-center py-4">
|
|
<Loader2 className="w-5 h-5 text-bambu-gray animate-spin" />
|
|
</div>
|
|
);
|
|
}
|
|
|
|
const runs = data?.items || [];
|
|
if (runs.length === 0) {
|
|
return (
|
|
<p className="text-sm text-bambu-gray italic py-2">
|
|
{t('archives.runLog.empty')}
|
|
</p>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="overflow-x-auto">
|
|
<table className="w-full text-xs">
|
|
<thead>
|
|
<tr className="text-bambu-gray border-b border-bambu-dark-tertiary">
|
|
<th className="text-left py-1.5 pr-2 font-medium">{t('archives.runLog.col.date')}</th>
|
|
<th className="text-left py-1.5 pr-2 font-medium">{t('archives.runLog.col.status')}</th>
|
|
<th className="text-right py-1.5 pr-2 font-medium">{t('archives.runLog.col.duration')}</th>
|
|
<th className="text-right py-1.5 pr-2 font-medium">{t('archives.runLog.col.filament')}</th>
|
|
<th className="text-right py-1.5 font-medium">{t('archives.runLog.col.cost')}</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{runs.map((run) => {
|
|
const statusClass =
|
|
run.status === 'completed'
|
|
? 'text-bambu-green'
|
|
: run.status === 'failed'
|
|
? 'text-red-700 dark:text-red-400'
|
|
: 'text-bambu-gray';
|
|
return (
|
|
<tr
|
|
key={run.id}
|
|
className="border-b border-bambu-dark-tertiary/40 last:border-0"
|
|
>
|
|
<td className="py-1.5 pr-2 text-bambu-gray-light">
|
|
{formatDate(run.started_at || run.created_at)}
|
|
</td>
|
|
<td className={`py-1.5 pr-2 font-medium ${statusClass}`}>
|
|
{t(`archives.runLog.status.${run.status}`, { defaultValue: run.status })}
|
|
{run.failure_reason && (
|
|
<span className="block text-[10px] text-bambu-gray font-normal">
|
|
{t(`editArchive.failureReasons.${run.failure_reason}`, { defaultValue: run.failure_reason })}
|
|
</span>
|
|
)}
|
|
</td>
|
|
<td className="py-1.5 pr-2 text-right text-bambu-gray-light">
|
|
{formatDuration(run.duration_seconds)}
|
|
</td>
|
|
<td className="py-1.5 pr-2 text-right text-bambu-gray-light">
|
|
{run.filament_used_grams != null
|
|
? `${run.filament_used_grams.toFixed(1)} g`
|
|
: '—'}
|
|
</td>
|
|
<td className="py-1.5 text-right text-bambu-gray-light">
|
|
{run.cost != null ? run.cost.toFixed(2) : '—'}
|
|
</td>
|
|
</tr>
|
|
);
|
|
})}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
);
|
|
}
|