refactor(ui): mobil yerleşimi iyileştir ve taşmayı düzelt
- AppLayout başlığının mobil uyumluluğunu yeniden düzenle - İkon tabanlı butonlar kullanarak mobil alan tasarrufu sağla - TimerPage'de taşan metinler için truncate sınıfları ekle - Torrent bilgileri için daha iyi duyarlı düzen yapısı oluştur
This commit is contained in:
@@ -8,7 +8,7 @@ import { useAppStore } from "../../store/useAppStore";
|
|||||||
import { connectSocket } from "../../socket/socket";
|
import { connectSocket } from "../../socket/socket";
|
||||||
import { api } from "../../api/client";
|
import { api } from "../../api/client";
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
import { faMoon, faSun } from "@fortawesome/free-solid-svg-icons";
|
import { faMoon, faSun, faRightFromBracket } from "@fortawesome/free-solid-svg-icons";
|
||||||
import { AlertToastStack } from "../ui/AlertToastStack";
|
import { AlertToastStack } from "../ui/AlertToastStack";
|
||||||
|
|
||||||
export const AppLayout = ({ children }: { children: React.ReactNode }) => {
|
export const AppLayout = ({ children }: { children: React.ReactNode }) => {
|
||||||
@@ -65,12 +65,20 @@ export const AppLayout = ({ children }: { children: React.ReactNode }) => {
|
|||||||
return (
|
return (
|
||||||
<Shell>
|
<Shell>
|
||||||
<header className="rounded-xl border border-slate-200 bg-white/80 px-4 py-3">
|
<header className="rounded-xl border border-slate-200 bg-white/80 px-4 py-3">
|
||||||
<div className="flex items-start justify-between gap-3 md:items-center">
|
<div className="flex flex-col gap-3 md:flex-row md:items-center md:justify-between">
|
||||||
<div>
|
<div>
|
||||||
<div className="text-lg font-semibold text-slate-900">q-buffer</div>
|
<div className="text-lg font-semibold text-slate-900">q-buffer</div>
|
||||||
<div className="text-xs text-slate-500">
|
<div className="text-xs text-slate-500">
|
||||||
qBittorrent {qbit.version ?? "unknown"}
|
qBittorrent {qbit.version ?? "unknown"}
|
||||||
</div>
|
</div>
|
||||||
|
<div className="mt-2 flex flex-wrap items-center gap-2">
|
||||||
|
<Badge variant={qbit.ok ? "success" : "danger"}>
|
||||||
|
{qbit.ok ? "Qbit OK" : "Qbit Down"}
|
||||||
|
</Badge>
|
||||||
|
<Badge variant={connected ? "success" : "warn"}>
|
||||||
|
{connected ? "Live" : "Offline"}
|
||||||
|
</Badge>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
className="inline-flex items-center justify-center rounded-md border border-slate-300 px-3 py-2 text-xs font-semibold text-slate-700 md:hidden"
|
className="inline-flex items-center justify-center rounded-md border border-slate-300 px-3 py-2 text-xs font-semibold text-slate-700 md:hidden"
|
||||||
@@ -79,53 +87,44 @@ export const AppLayout = ({ children }: { children: React.ReactNode }) => {
|
|||||||
>
|
>
|
||||||
{menuOpen ? "Close" : "Menu"}
|
{menuOpen ? "Close" : "Menu"}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
<div
|
||||||
<div
|
className={`flex flex-col gap-3 md:flex md:flex-row md:items-center ${
|
||||||
className={`mt-3 flex flex-col gap-3 md:mt-0 md:flex md:flex-row md:items-center md:justify-between ${
|
menuOpen ? "flex" : "hidden md:flex"
|
||||||
menuOpen ? "flex" : "hidden md:flex"
|
}`}
|
||||||
}`}
|
>
|
||||||
>
|
<nav className="flex flex-wrap items-center gap-2 rounded-full bg-slate-100 px-2 py-1 text-xs font-semibold text-slate-600">
|
||||||
<nav className="flex flex-wrap items-center gap-2 rounded-full bg-slate-100 px-2 py-1 text-xs font-semibold text-slate-600 md:justify-start">
|
<NavLink
|
||||||
<NavLink
|
to="/buffer"
|
||||||
to="/buffer"
|
className={({ isActive }) =>
|
||||||
className={({ isActive }) =>
|
`rounded-full px-3 py-1 ${
|
||||||
`rounded-full px-3 py-1 ${
|
isActive ? "bg-slate-900 text-white" : "hover:bg-white"
|
||||||
isActive ? "bg-slate-900 text-white" : "hover:bg-white"
|
}`
|
||||||
}`
|
}
|
||||||
}
|
>
|
||||||
>
|
Buffer
|
||||||
Buffer
|
</NavLink>
|
||||||
</NavLink>
|
<NavLink
|
||||||
<NavLink
|
to="/timer"
|
||||||
to="/timer"
|
className={({ isActive }) =>
|
||||||
className={({ isActive }) =>
|
`rounded-full px-3 py-1 ${
|
||||||
`rounded-full px-3 py-1 ${
|
isActive ? "bg-slate-900 text-white" : "hover:bg-white"
|
||||||
isActive ? "bg-slate-900 text-white" : "hover:bg-white"
|
}`
|
||||||
}`
|
}
|
||||||
}
|
>
|
||||||
>
|
Timer
|
||||||
Timer
|
</NavLink>
|
||||||
</NavLink>
|
</nav>
|
||||||
</nav>
|
|
||||||
<div className="flex flex-wrap items-center gap-2">
|
|
||||||
<Badge variant={qbit.ok ? "success" : "danger"}>
|
|
||||||
{qbit.ok ? "Qbit OK" : "Qbit Down"}
|
|
||||||
</Badge>
|
|
||||||
<Badge variant={connected ? "success" : "warn"}>
|
|
||||||
{connected ? "Live" : "Offline"}
|
|
||||||
</Badge>
|
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
onClick={() => applyTheme(theme === "dark" ? "light" : "dark")}
|
onClick={() => applyTheme(theme === "dark" ? "light" : "dark")}
|
||||||
|
title={theme === "dark" ? "Light" : "Dark"}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
icon={theme === "dark" ? faSun : faMoon}
|
icon={theme === "dark" ? faSun : faMoon}
|
||||||
className="mr-2"
|
|
||||||
/>
|
/>
|
||||||
{theme === "dark" ? "Light" : "Dark"}
|
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant="outline" onClick={logout}>
|
<Button variant="outline" onClick={logout} title="Logout">
|
||||||
Logout
|
<FontAwesomeIcon icon={faRightFromBracket} />
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -292,34 +292,36 @@ export const TimerPage = () => {
|
|||||||
className="rounded-lg border border-slate-200 bg-white px-3 py-2"
|
className="rounded-lg border border-slate-200 bg-white px-3 py-2"
|
||||||
>
|
>
|
||||||
<div className="flex items-start justify-between gap-3">
|
<div className="flex items-start justify-between gap-3">
|
||||||
<div>
|
<div className="min-w-0 flex-1">
|
||||||
<div
|
<div
|
||||||
className="text-sm font-semibold text-slate-900"
|
className="truncate text-sm font-semibold text-slate-900"
|
||||||
title={torrent.name}
|
title={torrent.name}
|
||||||
>
|
>
|
||||||
{torrent.name}
|
{torrent.name}
|
||||||
</div>
|
</div>
|
||||||
<div className="text-xs text-slate-500">
|
<div className="truncate text-xs text-slate-500">
|
||||||
{formatBytes(torrent.size)} • {trackerLabel(torrent.tracker)}
|
{formatBytes(torrent.size)} • {trackerLabel(torrent.tracker)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-right text-xs text-slate-600">
|
<div className="w-24 flex-shrink-0 text-right text-xs text-slate-600">
|
||||||
<div className="font-semibold text-slate-900">
|
<div className="font-semibold text-slate-900">
|
||||||
{formatCountdown(remainingSeconds)}
|
{formatCountdown(remainingSeconds)}
|
||||||
</div>
|
</div>
|
||||||
<div>Kural: {formatDuration(rule.seedLimitSeconds)}</div>
|
<div>Kural: {formatDuration(rule.seedLimitSeconds)}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-2 flex flex-wrap gap-2 text-xs text-slate-600">
|
<div className="mt-2 grid grid-cols-2 gap-2 text-xs text-slate-600">
|
||||||
<span>Hash: {torrent.hash.slice(0, 12)}...</span>
|
<div className="truncate">
|
||||||
<span>
|
Hash: {torrent.hash.slice(0, 12)}...
|
||||||
|
</div>
|
||||||
|
<div className="truncate">
|
||||||
Etiket:{" "}
|
Etiket:{" "}
|
||||||
{(torrent.tags || torrent.category || "-")
|
{(torrent.tags || torrent.category || "-")
|
||||||
.split(",")
|
.split(",")
|
||||||
.map((tag) => tag.trim())
|
.map((tag) => tag.trim())
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
.join(", ") || "-"}
|
.join(", ") || "-"}
|
||||||
</span>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|||||||
Reference in New Issue
Block a user