Skip to content

Commit

Permalink
prettier
Browse files Browse the repository at this point in the history
  • Loading branch information
StephDietz committed May 1, 2024
1 parent 4b86ad6 commit 5950ca0
Show file tree
Hide file tree
Showing 7 changed files with 315 additions and 300 deletions.
117 changes: 61 additions & 56 deletions app/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,67 +1,72 @@
import { fetchBookById } from '../lib/data';
import Link from 'next/link';
import Tile from '../components/tile';
import { fetchBookById } from "../lib/data";
import Link from "next/link";
import Tile from "../components/tile";

export default async function Page({ params }: { params: { id: string } }) {
const book = await fetchBookById(params.id);
return (
<div className="flex flex-col items-center w-full">
<Link
className="p-3 mb-8 mr-auto rounded dark:text-white hover:font-bold hover:opacity-80"
href="/"
>
← Back to all books
</Link>
<div className="flex flex-col w-full md:flex-row">
<div className="w-1/4 mr-6 flex-none relative aspect-[2/3] mb-6">
<Tile src={book.image} title={book.title} />
</div>
<div>
<div className="mb-2 text-5xl font-bold">{book.title}</div>
<div className="mb-4 text-lg">{book.author}</div>
<StarRating rating={book.rating} />
<div className="mt-4 opacity-80">{book.description}</div>
</div>
</div>
</div>
);
const book = await fetchBookById(params.id);
return (
<div className="flex flex-col items-center w-full">
<Link
className="p-3 mb-8 mr-auto rounded dark:text-white hover:font-bold hover:opacity-80"
href="/"
>
← Back to all books
</Link>
<div className="flex flex-col w-full md:flex-row">
<div className="w-1/4 mr-6 flex-none relative aspect-[2/3] mb-6">
<Tile src={book.image} title={book.title} />
</div>
<div>
<div className="mb-2 text-5xl font-bold">{book.title}</div>
<div className="mb-4 text-lg">{book.author}</div>
<StarRating rating={book.rating} />
<div className="mt-4 opacity-80">{book.description}</div>
</div>
</div>
</div>
);
}

const StarRating = ({ rating }: { rating: number }) => {
const totalStars = 5;
let remainingRating = rating;
const totalStars = 5;
let remainingRating = rating;

// Generate stars based on the rating
const stars = Array.from({ length: totalStars }).map((_, index) => {
let fill = 'white';
if (remainingRating >= 1) {
fill = 'gold';
remainingRating -= 1;
} else if (remainingRating > 0) {
fill = 'half';
remainingRating = 0;
}
return <SVGStar key={index} fill={fill} />;
});
// Generate stars based on the rating
const stars = Array.from({ length: totalStars }).map((_, index) => {
let fill = "white";
if (remainingRating >= 1) {
fill = "gold";
remainingRating -= 1;
} else if (remainingRating > 0) {
fill = "half";
remainingRating = 0;
}
return <SVGStar key={index} fill={fill} />;
});

return <div className="flex space-x-1">{stars}</div>;
return <div className="flex space-x-1">{stars}</div>;
};

const SVGStar = ({ fill = 'none' }) => {
const fillColor = fill === 'half' ? 'url(#half)' : fill;
const SVGStar = ({ fill = "none" }) => {
const fillColor = fill === "half" ? "url(#half)" : fill;

return (
<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="half">
<stop offset="50%" stop-color="gold" />
<stop offset="50%" stop-color="white" />
</linearGradient>
</defs>
<path
fill={fillColor}
d="M12 .587l3.668 7.425 8.2.637-6 5.847 1.4 8.174L12 18.256l-7.268 3.414 1.4-8.174-6-5.847 8.2-.637L12 .587z"
/>
</svg>
);
return (
<svg
width="24"
height="24"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<defs>
<linearGradient id="half">
<stop offset="50%" stop-color="gold" />
<stop offset="50%" stop-color="white" />
</linearGradient>
</defs>
<path
fill={fillColor}
d="M12 .587l3.668 7.425 8.2.637-6 5.847 1.4 8.174L12 18.256l-7.268 3.414 1.4-8.174-6-5.847 8.2-.637L12 .587z"
/>
</svg>
);
};
217 changes: 111 additions & 106 deletions app/components/panel.tsx
Original file line number Diff line number Diff line change
@@ -1,121 +1,126 @@
'use client';
"use client";

import { useRouter } from 'next/navigation';
import { useOptimistic, useTransition, useState } from 'react';
import { ChevronDownIcon } from '@heroicons/react/24/outline';
import { useRouter } from "next/navigation";
import { useOptimistic, useTransition, useState } from "react";
import { ChevronDownIcon } from "@heroicons/react/24/outline";

interface ExpandedSections {
[key: string]: boolean;
[key: string]: boolean;
}

export default function Panel({
authors,
allAuthors
authors,
allAuthors,
}: {
authors: string[];
allAuthors: string[];
authors: string[];
allAuthors: string[];
}) {
let router = useRouter();
let [pending, startTransition] = useTransition();
let [optimisticAuthors, setOptimisticAuthors] = useOptimistic(authors);
let [expandedSections, setExpandedSections] = useState<ExpandedSections>({});
let router = useRouter();
let [pending, startTransition] = useTransition();
let [optimisticAuthors, setOptimisticAuthors] = useOptimistic(authors);
let [expandedSections, setExpandedSections] = useState<ExpandedSections>({});

const authorGroups = allAuthors.reduce(
(acc: { [key: string]: string[] }, author: string) => {
const firstLetter = author[0].toUpperCase(); // Get the first letter, capitalize it
if (!acc[firstLetter]) {
acc[firstLetter] = []; // Initialize the array if this is the first author with this letter
}
acc[firstLetter].push(author); // Add the author to the appropriate array
return acc; // Return the updated accumulator
},
{} as { [key: string]: string[] }
);
const toggleSection = (letter: string): void => {
setExpandedSections((prev: Record<string, boolean>) => ({
...prev,
[letter]: !prev[letter]
}));
};
const authorGroups = allAuthors.reduce(
(acc: { [key: string]: string[] }, author: string) => {
const firstLetter = author[0].toUpperCase(); // Get the first letter, capitalize it
if (!acc[firstLetter]) {
acc[firstLetter] = []; // Initialize the array if this is the first author with this letter
}
acc[firstLetter].push(author); // Add the author to the appropriate array
return acc; // Return the updated accumulator
},
{} as { [key: string]: string[] },
);
const toggleSection = (letter: string): void => {
setExpandedSections((prev: Record<string, boolean>) => ({
...prev,
[letter]: !prev[letter],
}));
};

return (
<div className="mb-auto bg-white rounded-md shadow-md lg:w-60 dark:shadow-gray-950/30 dark:bg-white/10">
<div data-pending={pending ? '' : undefined} className=" lg:h-[70vh] md:h-80 overflow-auto">
<div className="p-4">
<h2 className="text-lg font-semibold tracking-tight dark:text-gray-100">Authors</h2>
{Object.entries(authorGroups).map(([letter, authors]) => (
<div key={letter}>
<button
onClick={() => toggleSection(letter)}
className="flex items-center justify-between w-full p-1 mb-1 text-left rounded hover:bg-stone-100 dark:hover:bg-white/20"
>
<div>
{letter} <span className="text-xs">({authors.length})</span>
</div>
<ChevronDownIcon
className={`w-4 ${expandedSections[letter] ? 'rotate-180' : ''}`}
/>
</button>
<div
className={`overflow-hidden transition-max-height duration-300 ease-in-out flex flex-col gap-1 ${
expandedSections[letter] ? '' : 'max-h-0'
}`}
>
{expandedSections[letter] &&
authors.map((author) => (
<button
onClick={() => {
let newAuthors = !optimisticAuthors.includes(author)
? [...optimisticAuthors, author]
: optimisticAuthors.filter((g) => g !== author);
return (
<div className="mb-auto bg-white rounded-md shadow-md lg:w-60 dark:shadow-gray-950/30 dark:bg-white/10">
<div
data-pending={pending ? "" : undefined}
className=" lg:h-[70vh] md:h-80 overflow-auto"
>
<div className="p-4">
<h2 className="text-lg font-semibold tracking-tight dark:text-gray-100">
Authors
</h2>
{Object.entries(authorGroups).map(([letter, authors]) => (
<div key={letter}>
<button
onClick={() => toggleSection(letter)}
className="flex items-center justify-between w-full p-1 mb-1 text-left rounded hover:bg-stone-100 dark:hover:bg-white/20"
>
<div>
{letter} <span className="text-xs">({authors.length})</span>
</div>
<ChevronDownIcon
className={`w-4 ${expandedSections[letter] ? "rotate-180" : ""}`}
/>
</button>
<div
className={`overflow-hidden transition-max-height duration-300 ease-in-out flex flex-col gap-1 ${
expandedSections[letter] ? "" : "max-h-0"
}`}
>
{expandedSections[letter] &&
authors.map((author) => (
<button
onClick={() => {
let newAuthors = !optimisticAuthors.includes(author)
? [...optimisticAuthors, author]
: optimisticAuthors.filter((g) => g !== author);

let newParams = new URLSearchParams(
newAuthors.sort().map((author) => ['author', author])
);
let newParams = new URLSearchParams(
newAuthors.sort().map((author) => ["author", author]),
);

startTransition(() => {
setOptimisticAuthors(newAuthors.sort());
startTransition(() => {
setOptimisticAuthors(newAuthors.sort());

router.push(`?${newParams}`);
});
}}
key={author}
className="flex items-center space-x-2 text-xs text-left"
>
<input
type="checkbox"
className=""
checked={optimisticAuthors.includes(author)}
/>
<div>{author}</div>
</button>
))}
</div>
</div>
))}
</div>
</div>
router.push(`?${newParams}`);
});
}}
key={author}
className="flex items-center space-x-2 text-xs text-left"
>
<input
type="checkbox"
className=""
checked={optimisticAuthors.includes(author)}
/>
<div>{author}</div>
</button>
))}
</div>
</div>
))}
</div>
</div>

{optimisticAuthors.length > 0 && (
<div className="p-1 bg-white border-t dark:border-black dark:bg-white/10">
<div className="p-2 text-xs">
{optimisticAuthors.map((author) => (
<p key={author}>{author}</p>
))}
</div>
<button
className="w-full py-2 text-sm font-medium text-center rounded dark:hover:bg-gray-600 hover:bg-black hover:text-white"
onClick={() => {
startTransition(() => {
setOptimisticAuthors([]);
router.push(`/`);
});
}}
>
Clear authors
</button>
</div>
)}
</div>
);
{optimisticAuthors.length > 0 && (
<div className="p-1 bg-white border-t dark:border-black dark:bg-white/10">
<div className="p-2 text-xs">
{optimisticAuthors.map((author) => (
<p key={author}>{author}</p>
))}
</div>
<button
className="w-full py-2 text-sm font-medium text-center rounded dark:hover:bg-gray-600 hover:bg-black hover:text-white"
onClick={() => {
startTransition(() => {
setOptimisticAuthors([]);
router.push(`/`);
});
}}
>
Clear authors
</button>
</div>
)}
</div>
);
}
Loading

0 comments on commit 5950ca0

Please sign in to comment.