make app mobile-friendly: responsive nav, scrollable tables, adaptive grids
All checks were successful
Build and Push Docker Image / build (push) Successful in 20s
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:
@@ -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>
|
||||
);
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user