- Published on
IndiesReadIt Development Diary - Week 3
- Authors
- Name
- Dany
- @MajorBaguette
Table of Contents
IndiesReadIt Development Diary - Week 3
In the third week of IndiesReadIt's evolution, I delved into refining admin features and enhancing user interactions. Here's a detailed look at the week's journey:
Development Summary
18/12 - 2h+ - UI Enhancements and Domain Claim
- Bought IndiesRead.it because I’m already posting about it on X, would be a shame if some troll steals my domain… .it is under Italian juridiction tho, let’s see how it goes..
- Finished slug routing for category
- Made the combobox to redirect to cat page, for SEO purpose I chose to redirect to a whole new page so I’ll get a lot of page to step up the SEO game (multiple search queries)
- Launched majorleaguebaguette.com blog!
19/12 - 3h+ - Logic and Functionality
- Wired the book types toggles (physical, audio & ebook) AND search
- Copilot made spared me atleast 1h of coding, just chat your idea using @workspace so it knows your entire codebase and ask him what you want, it generates almost perfect code or atleast guide you on the right track
- I used to block on bugs or lack ok knowledge for days, it’s not the case anymore
- Finally used Context instead of props drilling, it was about time, here an example :
import React, { createContext, useState, useContext } from "react";
import { ExtendedBooks } from "types";
const BooksContext = createContext<
| {
books: ExtendedBooks[];
setBooks: React.Dispatch<React.SetStateAction<ExtendedBooks[]>>;
}
| undefined
>(undefined);
export const BooksProvider: React.FC<{
initialBooks: ExtendedBooks[];
children: React.ReactNode;
}> = ({ initialBooks, children }) => {
const [books, setBooks] = useState(initialBooks);
return (
<BooksContext.Provider value={{ books, setBooks }}>
{children}
</BooksContext.Provider>
);
};
export const useBooks = () => {
const context = useContext(BooksContext);
if (context === undefined) {
throw new Error("useBooks must be used within a BooksProvider");
}
return context;
};
<BooksProvider initialBooks={books}>
<div className="z-10">
<div className="border-b p-8">
<h1 className="scroll-m-20 text-4xl font-extrabold tracking-tight lg:text-5xl">
Collaborative directory of hand-picked books for indies.
</h1>
<h2 className="scroll-m-20 pb-4 text-3xl font-semibold italic tracking-tight transition-colors">
Best books by rating
</h2>
<Button>
<PlusIcon className="mr-2 h-4 w-4" />
Submit a book
</Button>
</div>
<FilterBar />
<MainLayout />
</div>
</BooksProvider>
export const MainLayout = () => {
const { books } = useBooks();
return (
<div className="grid grid-cols-1 gap-8 p-8 md:grid-cols-2 lg:grid-cols-3">
{books ? (
books.map((book) => <BookCard key={book.title} book={book} />)
) : (
<div>no books</div>
)}
</div>
);
};
- After a book author I commented book on X asked if submit book function was active, I decided to focus on this one
- Wanted to do a ultra basic form that email me the result but found out it wasn’t as easy as a thought so I went for the complete implementation
- Took me less than 1 hour thanks to shadcn/ui react-hook-form and zod!
- Getting user session to redirect to login page if unauth was more tricky and got me blocked for 2 hours until I re-discovered the useSession hook…
- Main problem was the client and server component differenciation, I’m not used to it for now
20/12 - 3h+ - Session Handling and Refinements
- Wasted 1 hour on trying to get the session info in client component, all I had to do was to provide the session context from layout.tsx to providers.ts and then use “const session = useSession()” where I want.
const session = await getServerSession(authOptions);
return (
<html lang="en">
<body className={cx(sfPro.variable, inter.variable)}>
<div className="fixed h-screen w-full bg-gradient-to-br from-indigo-50 via-white to-cyan-100" />
<Suspense fallback="...">
<Nav />
</Suspense>
<main className="flex min-h-screen w-full flex-col items-center justify-start py-32">
<Providers session={session}>{children}</Providers>
</main>
<Footer />
<Analytics />
<Toaster />
</body>
</html>
);
export default function Providers({
children,
session,
}: {
children: React.ReactNode;
session: any;
}) {
const [queryClient] = useState(() => new QueryClient());
return (
<QueryClientProvider client={queryClient}>
<SessionProvider session={session}>{children}</SessionProvider>
</QueryClientProvider>
);
}
- I added auto modal close on submit success + toast in less than 5min thanks to shadcn again.
- I switched from VercelDB to supabase in 10min too, Vercel storage and DB options are overpriced and very limited, avoid them.
- Added final url IndiesRead.it to google credential to make Next-Auth to work.
21/12 - 4h+ - Diverse Development
- Updated Book Prisma schema to accept 3 types of link (physical/audio/ebook), I hope it’ll encourage more people to buy from here.
- I added my first book from an actual user : The Chameleon Founder by @matteomosca
- I asked him how it went, had already some feedback from X (no explicit return from submission, already updated), he confirmed me that asking category from the form was a good idea
- I’ll now try to reach more indie authors to get some coverage and early users
- Created a new logo from freshly shipped logofas.st by @marc_louvion on X, easy way to get a better logo and he often retweet or gives credit, which is very fair and nice from him
- Tried for 1 hour to get the opengraph-image generation from Nextjs 13+ to work but no success.
- I went for the old way and created the OG and Twitter (630 vs 675 pixel height…) on Canva.
- Added a connect dot pattern to background from https://fffuel.co/ and updated bg colors as I had a little work time tonight (I often do little aesthetic updates if I know I only have few minutes, it’s a bad idea to start a feature and rush it)
- Here the code to implement it :
<html lang="en">
<body lang="en" className={GeistSans.className}>
<div className="fixed h-screen w-full bg-gradient-to-br from-rose-200 via-white to-rose-50" />
<div
className="fixed h-screen w-full opacity-30"
style={{
backgroundAttachment: "fixed",
backgroundImage: "url(/ooorganize.svg)",
backgroundBlendMode: "overlay",
}}
/>
...
22/12 - 1h - Stylistic Updates
- Improved text description at back of cards, line-clamp-[…] must be encapsulated in it’s own div
- Improved category combobox by making it return to all books when unselect category. Made search bar to take author in count.
const action = (currentValue: string | string[]) => {
if (currentValue === value)
return setValue(''), setOpen(false), router.push(`/`);
if (currentValue !== value)
return (
setValue(currentValue),
setOpen(false),
router.push(`/categories/${currentValue}`)
);
};
Week 3 Summary
For Weeks 3, key highlights include significant UI enhancements, the acquisition of the domain IndiesRead.it to fortify the project's online presence, and the launch of the majorleaguebaguette.com blog. I tackled challenges such as session handling, refined user interactions, and implemented admin empowerment features like an "Add a Book" form.
Submit your favorite indie books to IndiesReadIt and help build this collaborative directory.
Stay tuned for more updates!