make app mobile-friendly: responsive nav, scrollable tables, adaptive grids
All checks were successful
Build and Push Docker Image / build (push) Successful in 20s

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-04 21:44:08 +01:00
parent 59ab56785d
commit a393dd280e
7 changed files with 34 additions and 26 deletions

View File

@@ -98,7 +98,7 @@ export function ExecutePage() {
</div>
{jobs.length > 0 && (
<table className="w-full border-collapse text-[0.82rem]">
<div className="overflow-x-auto -mx-3 px-3 sm:mx-0 sm:px-0"><table className="w-full border-collapse text-[0.82rem]">
<thead>
<tr>
{['#', 'Item', 'Command', 'Node', 'Status', 'Actions'].map((h) => (
@@ -180,7 +180,7 @@ export function ExecutePage() {
);
})}
</tbody>
</table>
</table></div>
)}
</div>
);

View File

@@ -61,7 +61,7 @@ export function NodesPage() {
<div className="font-semibold text-sm mb-3">Add Node</div>
{error && <Alert variant="error" className="mb-3">{error}</Alert>}
<form onSubmit={submit}>
<div className="grid grid-cols-2 gap-4 mb-3">
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4 mb-3">
<label className="block text-sm text-gray-700 mb-0.5">
Name
<Input name="name" placeholder="my-server" required className="mt-0.5" />
@@ -117,7 +117,7 @@ export function NodesPage() {
{nodes.length === 0 ? (
<p className="text-gray-500">No nodes configured. Add one above.</p>
) : (
<table className="w-full border-collapse text-[0.82rem]">
<div className="overflow-x-auto -mx-3 px-3 sm:mx-0 sm:px-0"><table className="w-full border-collapse text-[0.82rem]">
<thead>
<tr>
{['Name', 'Host', 'Port', 'User', 'FFmpeg', 'Movies', 'Series', 'Status', 'Actions'].map((h) => (
@@ -149,7 +149,7 @@ export function NodesPage() {
</tr>
))}
</tbody>
</table>
</table></div>
)}
</div>
);

View File

@@ -78,7 +78,7 @@ function StreamTable({ data, onUpdate }: StreamTableProps) {
};
return (
<table className="w-full border-collapse text-[0.79rem] mt-1">
<div className="overflow-x-auto -mx-4 px-4 sm:mx-0 sm:px-0"><table className="w-full border-collapse text-[0.79rem] mt-1">
<thead>
<tr>
{['Out', 'Codec', 'Language', 'Title / Info', 'Flags', 'Action'].map((h) => (
@@ -156,7 +156,7 @@ function StreamTable({ data, onUpdate }: StreamTableProps) {
];
})}
</tbody>
</table>
</table></div>
);
}

View File

@@ -250,13 +250,14 @@ export function AudioListPage() {
<div className="flex items-center gap-2 mt-5 mb-1.5 text-[0.72rem] font-bold uppercase tracking-[0.07em] text-gray-500">
Movies <span className="bg-gray-100 text-gray-600 px-1.5 py-0.5 rounded-full">{movies.length}</span>
</div>
<table className="w-full border-collapse text-[0.82rem]">
<div className="overflow-x-auto -mx-3 px-3 sm:mx-0 sm:px-0">
<table className="w-full border-collapse text-[0.82rem]">
<thead><tr><Th>Name</Th><Th>Lang</Th><Th>Remove</Th><Th>Status</Th><Th>Actions</Th></tr></thead>
<tbody>
{movies.map(({ item, plan, removeCount }) => (
<tr key={item.id} className="hover:bg-gray-50">
<Td>
<span className="truncate inline-block max-w-[360px]" title={item.name}>{item.name}</span>
<span className="truncate inline-block max-w-[200px] sm:max-w-[360px]" title={item.name}>{item.name}</span>
{item.year && <span className="text-gray-400 text-[0.72rem]"> ({item.year})</span>}
</Td>
<Td>
@@ -278,6 +279,7 @@ export function AudioListPage() {
))}
</tbody>
</table>
</div>
</>
)}
@@ -287,10 +289,12 @@ export function AudioListPage() {
<div className={`flex items-center gap-2 mb-1.5 text-[0.72rem] font-bold uppercase tracking-[0.07em] text-gray-500 ${movies.length > 0 ? 'mt-5' : 'mt-0'}`}>
TV Series <span className="bg-gray-100 text-gray-600 px-1.5 py-0.5 rounded-full">{series.length}</span>
</div>
<div className="overflow-x-auto -mx-3 px-3 sm:mx-0 sm:px-0">
<table className="w-full border-collapse text-[0.82rem]">
<thead><tr><Th>Series</Th><Th>Lang</Th><Th>S</Th><Th>Ep</Th><Th>Status</Th><Th>Actions</Th></tr></thead>
{series.map((g) => <SeriesRow key={g.series_key} g={g} />)}
</table>
</div>
</>
)}
</div>

View File

@@ -74,7 +74,7 @@ function StreamTable({ streams, decisions, editable, onLanguageChange, onTitleCh
if (streams.length === 0) return <p className="text-gray-500 text-sm">No subtitle streams in container.</p>;
return (
<table className="w-full border-collapse text-[0.79rem] mt-1">
<div className="overflow-x-auto -mx-4 px-4 sm:mx-0 sm:px-0"><table className="w-full border-collapse text-[0.79rem] mt-1">
<thead>
<tr>
{['#', 'Codec', 'Language', 'Title / Info', 'Flags', 'Action'].map((h) => (
@@ -139,7 +139,7 @@ function StreamTable({ streams, decisions, editable, onLanguageChange, onTitleCh
);
})}
</tbody>
</table>
</table></div>
);
}
@@ -149,7 +149,7 @@ function ExtractedFilesTable({ files, onDelete }: { files: SubtitleFile[]; onDel
if (files.length === 0) return <p className="text-gray-500 text-sm">No extracted files yet.</p>;
return (
<table className="w-full border-collapse text-[0.82rem]">
<div className="overflow-x-auto -mx-4 px-4 sm:mx-0 sm:px-0"><table className="w-full border-collapse text-[0.82rem]">
<thead>
<tr>
{['File', 'Language', 'Codec', 'Flags', 'Size', ''].map((h) => (
@@ -160,7 +160,7 @@ function ExtractedFilesTable({ files, onDelete }: { files: SubtitleFile[]; onDel
<tbody>
{files.map((f) => (
<tr key={f.id} className="hover:bg-gray-50">
<td className="py-1.5 px-2 border-b border-gray-100 font-mono text-xs max-w-[360px] truncate" title={f.file_path}>
<td className="py-1.5 px-2 border-b border-gray-100 font-mono text-xs max-w-[200px] sm:max-w-[360px] truncate" title={f.file_path}>
{fileName(f.file_path)}
</td>
<td className="py-1.5 px-2 border-b border-gray-100">
@@ -182,7 +182,7 @@ function ExtractedFilesTable({ files, onDelete }: { files: SubtitleFile[]; onDel
</tr>
))}
</tbody>
</table>
</table></div>
);
}

View File

@@ -87,7 +87,7 @@ export function SubtitleListPage() {
)}
{items.length > 0 && (
<table className="w-full border-collapse text-[0.82rem]">
<div className="overflow-x-auto -mx-3 px-3 sm:mx-0 sm:px-0"><table className="w-full border-collapse text-[0.82rem]">
<thead>
<tr>
{['Name', 'Lang', 'Container Subs', 'Extracted Files', 'Status'].map((h) => (
@@ -119,7 +119,7 @@ export function SubtitleListPage() {
);
})}
</tbody>
</table>
</table></div>
)}
</div>
);

View File

@@ -43,20 +43,24 @@ function RootLayout() {
DEV MODE fresh test database, 50 movies + 10 series per scan
</div>
)}
<nav className="flex items-center gap-0.5 px-5 h-12 bg-white border-b border-gray-200 sticky top-0 z-50">
<Link to="/" className="font-bold text-[0.95rem] mr-5 no-underline text-gray-900">
🎬 netfelix-audio-fix
<nav className="flex flex-wrap items-center gap-0.5 px-3 sm:px-5 py-2 sm:py-0 sm:h-12 bg-white border-b border-gray-200 sticky top-0 z-50">
<Link to="/" className="font-bold text-[0.95rem] mr-3 sm:mr-5 no-underline text-gray-900">
🎬 netfelix
</Link>
<VersionBadge />
<NavLink to="/scan">Scan</NavLink>
<NavLink to="/review/audio">Audio</NavLink>
<NavLink to="/review/subtitles">Subtitles</NavLink>
<NavLink to="/execute">Execute</NavLink>
<div className="flex flex-wrap items-center gap-0.5">
<NavLink to="/scan">Scan</NavLink>
<NavLink to="/review/audio">Audio</NavLink>
<NavLink to="/review/subtitles">Subs</NavLink>
<NavLink to="/execute">Execute</NavLink>
</div>
<div className="flex-1" />
<NavLink to="/nodes">Nodes</NavLink>
<NavLink to="/settings">Settings</NavLink>
<div className="flex items-center gap-0.5">
<NavLink to="/nodes">Nodes</NavLink>
<NavLink to="/settings">Settings</NavLink>
</div>
</nav>
<main className="max-w-[1600px] mx-auto px-5 pt-4 pb-12">
<main className="max-w-[1600px] mx-auto px-3 sm:px-5 pt-4 pb-12">
<Outlet />
</main>
</div>