A pinch of responsiveness

This commit is contained in:
2025-10-10 18:45:16 +02:00
parent 9148c1f320
commit e26fa39e88
3 changed files with 97 additions and 53 deletions

View File

@@ -0,0 +1,14 @@
import { useSyncExternalStore } from "react";
const query = window.matchMedia("@media (width >= 48rem)");
const subscribe = (callback: () => void) => {
query.addEventListener("change", callback);
return () => {
query.removeEventListener("change", callback);
};
}
const getSnapshot = () => query.matches;
export const useBreakpoint = () => useSyncExternalStore(subscribe, getSnapshot);

View File

@@ -5,6 +5,7 @@ import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle, DialogT
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
import { useBreakpoint } from "@/hooks/useBreakpoint";
import { useCache } from "@/hooks/useCache";
import { useLoading } from "@/hooks/useLoading";
import { authors, created, DEBOUNCE, modified, SAVE_DELAY } from "@/snippets";
@@ -25,6 +26,8 @@ export function Pieces() {
const [importDialogOpen, setImportDialogOpen] = useState(false);
const debounce = useRef(Effect.void);
const breakpoint = useBreakpoint();
const columns = breakpoint ? 4 : 1;
const { isLoading, error, data: pieceIds, refresh } = useLoading(Effect.gen(function* () {
yield* debounce.current;
@@ -39,7 +42,7 @@ export function Pieces() {
return (
<div className="p-4 overflow-y-auto flex flex-col items-start gap-4">
<div className="flex flex-row gap-4">
<div className="flex flex-row flex-wrap gap-4">
<Dialog>
<DialogTrigger asChild>
<Button variant="outline">
@@ -57,7 +60,7 @@ export function Pieces() {
<ImportPiecesDialogContent setDialogOpen={setImportDialogOpen} refresh={refresh} />
</Dialog>
<Input
className="w-[32ch]"
className="w-full md:w-[32ch]"
type="text"
placeholder="Tytuł"
value={name}
@@ -67,7 +70,7 @@ export function Pieces() {
}}
/>
<Input
className="w-[32ch]"
className="w-full md:w-[32ch]"
type="text"
placeholder="Twórcy"
value={author}
@@ -78,18 +81,20 @@ export function Pieces() {
/>
</div>
<Table>
<TableHeader className="bg-white sticky top-0">
<TableRow>
<TableHead>Tytuł</TableHead>
<TableHead>Twórcy</TableHead>
<TableHead className="text-center">Dodano</TableHead>
<TableHead className="text-center">Zmodyfikowano</TableHead>
</TableRow>
</TableHeader>
{breakpoint && (
<TableHeader className="bg-white sticky top-0">
<TableRow>
<TableHead>Tytuł</TableHead>
<TableHead>Twórcy</TableHead>
<TableHead className="text-center">Dodano</TableHead>
<TableHead className="text-center">Zmodyfikowano</TableHead>
</TableRow>
</TableHeader>
)}
<TableBody>
{isLoading ? (
<TableRow>
<TableCell colSpan={4} >
<TableCell colSpan={columns} >
<div className="flex items-center justify-center gap-2">
<Loader2 className="animate-spin" />
Ładowanie
@@ -98,7 +103,7 @@ export function Pieces() {
</TableRow>
) : error !== null ? (
<TableRow>
<TableCell colSpan={4} className="text-center">
<TableCell colSpan={columns} className="text-center">
{Cause.isUnknownException(error) ? "Wystąpił nieznany błąd" : `Wystąpił błąd: ${JSON.stringify(error)}`}
</TableCell>
</TableRow>
@@ -121,10 +126,13 @@ function PieceRow(props: PieceRow.Props) {
const { isLoading, error, data: piece } = useCache(pieceCache, props.pieceId);
const breakpoint = useBreakpoint();
const columns = breakpoint ? 4 : 1;
if (isLoading) {
return (
<TableRow>
<TableCell colSpan={4}>Ładowanie</TableCell>
<TableCell colSpan={columns}>Ładowanie</TableCell>
</TableRow>
);
}
@@ -132,7 +140,7 @@ function PieceRow(props: PieceRow.Props) {
if (error !== null) {
return (
<TableRow>
<TableCell colSpan={4}>
<TableCell colSpan={columns}>
Wystąpił błąd: {Match.value(error).pipe(
Match.tag("FetchError", () => "Nie można połączyć się z serwerem"),
Match.tag("NotFound", () => "Utwór nie istnieje"),
@@ -147,18 +155,25 @@ function PieceRow(props: PieceRow.Props) {
return (
<TableRow>
<TableCell>
<Link className="underline" to={piece.pieceId}>{piece.name}</Link>
</TableCell>
<TableCell>
{authors(piece)}
</TableCell>
<TableCell className="text-center text-xs">
{created(piece)}
</TableCell>
<TableCell className="text-center text-xs">
{modified(piece)}
</TableCell>
{breakpoint ? (<>
<TableCell>
<Link className="underline" to={piece.pieceId}>{piece.name}</Link>
</TableCell>
<TableCell>
{authors(piece)}
</TableCell>
<TableCell className="text-center text-xs">
{created(piece)}
</TableCell>
<TableCell className="text-center text-xs">
{modified(piece)}
</TableCell>
</>) : (
<TableCell className="flex flex-col">
<Link className="underline" to={piece.pieceId}>{piece.name}</Link>
<div className="text-xs">{authors(piece)}</div>
</TableCell>
)}
</TableRow>
);
}

View File

@@ -5,6 +5,7 @@ import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle, DialogT
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
import { useBreakpoint } from "@/hooks/useBreakpoint";
import { useCache } from "@/hooks/useCache";
import { useLoading } from "@/hooks/useLoading";
import { created, DEBOUNCE, modified } from "@/snippets";
@@ -19,6 +20,8 @@ export function Repertoires() {
const [name, setName] = useState("");
const debounce = useRef(Effect.void);
const breakpoint = useBreakpoint();
const columns = breakpoint ? 4 : 1;
const { isLoading, error, data: repertoireIds } = useLoading(Effect.gen(function* () {
yield* debounce.current;
@@ -32,7 +35,7 @@ export function Repertoires() {
return (
<div className="p-4 overflow-y-auto flex flex-col items-start gap-4">
<div className="flex flex-row gap-4">
<div className="flex flex-row flex-wrap gap-4">
<Dialog>
<DialogTrigger asChild>
<Button variant="outline">
@@ -42,7 +45,7 @@ export function Repertoires() {
<AddRepertoireDialogContent />
</Dialog>
<Input
className="w-[32ch]"
className="w-full md:w-[32ch]"
type="text"
placeholder="Nazwa"
value={name}
@@ -53,18 +56,20 @@ export function Repertoires() {
/>
</div>
<Table>
<TableHeader className="bg-white sticky top-0">
<TableRow>
<TableHead>Nazwa</TableHead>
<TableHead>Utwory</TableHead>
<TableHead className="text-center">Dodano</TableHead>
<TableHead className="text-center">Zmodyfikowano</TableHead>
</TableRow>
</TableHeader>
{breakpoint && (
<TableHeader className="bg-white sticky top-0">
<TableRow>
<TableHead>Nazwa</TableHead>
<TableHead>Utwory</TableHead>
<TableHead className="text-center">Dodano</TableHead>
<TableHead className="text-center">Zmodyfikowano</TableHead>
</TableRow>
</TableHeader>
)}
<TableBody>
{isLoading ? (
<TableRow>
<TableCell colSpan={4} >
<TableCell colSpan={columns} >
<div className="flex items-center justify-center gap-2">
<Loader2 className="animate-spin" />
Ładowanie
@@ -73,7 +78,7 @@ export function Repertoires() {
</TableRow>
) : error !== null ? (
<TableRow>
<TableCell colSpan={4} className="text-center">
<TableCell colSpan={columns} className="text-center">
{Cause.isUnknownException(error) ? "Wystąpił nieznany błąd" : `Wystąpił błąd: ${JSON.stringify(error)}`}
</TableCell>
</TableRow>
@@ -96,10 +101,13 @@ function RepertoireRow(props: RepertoireRow.Props) {
const { isLoading, error, data: repertoire } = useCache(repertoireCache, props.repertoireId);
const breakpoint = useBreakpoint();
const columns = breakpoint ? 4 : 1;
if (isLoading) {
return (
<TableRow>
<TableCell colSpan={4}>Ładowanie</TableCell>
<TableCell colSpan={columns}>Ładowanie</TableCell>
</TableRow>
);
}
@@ -107,7 +115,7 @@ function RepertoireRow(props: RepertoireRow.Props) {
if (error !== null) {
return (
<TableRow>
<TableCell colSpan={4}>
<TableCell colSpan={columns}>
Wystąpił błąd: {Match.value(error).pipe(
Match.tag("FetchError", () => "Nie można połączyć się z serwerem"),
Match.tag("NotFound", () => "Repertuar nie istnieje"),
@@ -136,18 +144,25 @@ function RepertoireRow(props: RepertoireRow.Props) {
return (
<TableRow>
<TableCell>
<Link className="underline" to={repertoire.repertoireId}>{repertoire.name}</Link>
</TableCell>
<TableCell>
{...piecesParts}
</TableCell>
<TableCell className="text-center text-xs">
{created(repertoire)}
</TableCell>
<TableCell className="text-center text-xs">
{modified(repertoire)}
</TableCell>
{breakpoint ? (<>
<TableCell>
<Link className="underline" to={repertoire.repertoireId}>{repertoire.name}</Link>
</TableCell>
<TableCell>
{...piecesParts}
</TableCell>
<TableCell className="text-center text-xs">
{created(repertoire)}
</TableCell>
<TableCell className="text-center text-xs">
{modified(repertoire)}
</TableCell>
</>) : (
<TableCell className="flex flex-col">
<Link className="underline" to={repertoire.repertoireId}>{repertoire.name}</Link>
<div className="text-xs">{...piecesParts}</div>
</TableCell>
)}
</TableRow>
);
}