diff --git a/next.config.mjs b/next.config.mjs index ed62259..ee65b13 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -5,6 +5,14 @@ const nextConfig = { images: { domains: ['covers.openlibrary.org', 'cdn.beitzah.net'], }, + async rewrites() { + return [ + { + source: '/search', + destination: '/books', + }, + ] + }, } export default withPayload(nextConfig, { devBundleServerPackages: false }) diff --git a/package-lock.json b/package-lock.json index 642881e..14a46a6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,6 +17,7 @@ "@payloadcms/payload-cloud": "3.31.0", "@payloadcms/richtext-lexical": "3.31.0", "@radix-ui/react-dialog": "^1.1.11", + "@radix-ui/react-dropdown-menu": "^2.1.12", "@radix-ui/react-label": "^2.1.4", "@radix-ui/react-popover": "^1.1.11", "@radix-ui/react-select": "^2.2.2", @@ -4352,6 +4353,77 @@ } } }, + "node_modules/@radix-ui/react-dropdown-menu": { + "version": "2.1.12", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.12.tgz", + "integrity": "sha512-VJoMs+BWWE7YhzEQyVwvF9n22Eiyr83HotCVrMQzla/OwRovXCgah7AcaEr4hMNj4gJxSdtIbcHGvmJXOoJVHA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-menu": "2.1.12", + "@radix-ui/react-primitive": "2.1.0", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-primitive": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.0.tgz", + "integrity": "sha512-/J/FhLdK0zVcILOwt5g+dH4KnkonCtkVJsa2G6JmvbbtZfBEI1gMsO3QMjseL4F/SwfAMt1Vc/0XKYKq+xJ1sw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", + "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-focus-guards": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.2.tgz", @@ -4479,6 +4551,169 @@ } } }, + "node_modules/@radix-ui/react-menu": { + "version": "2.1.12", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.12.tgz", + "integrity": "sha512-+qYq6LfbiGo97Zz9fioX83HCiIYYFNs8zAsVCMQrIakoNYylIzWuoD/anAD3UzvvR6cnswmfRFJFq/zYYq/k7Q==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-collection": "1.1.4", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.7", + "@radix-ui/react-focus-guards": "1.1.2", + "@radix-ui/react-focus-scope": "1.1.4", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.4", + "@radix-ui/react-portal": "1.1.6", + "@radix-ui/react-presence": "1.1.4", + "@radix-ui/react-primitive": "2.1.0", + "@radix-ui/react-roving-focus": "1.1.7", + "@radix-ui/react-slot": "1.2.0", + "@radix-ui/react-use-callback-ref": "1.1.1", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-collection": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.4.tgz", + "integrity": "sha512-cv4vSf7HttqXilDnAnvINd53OTl1/bjUYVZrkFnA7nwmY9Ob2POUy0WY0sfqBAe1s5FyKsyceQlqiEGPYNTadg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.0", + "@radix-ui/react-slot": "1.2.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-presence": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.4.tgz", + "integrity": "sha512-ueDqRbdc4/bkaQT3GIpLQssRlFgWaL/U2z/S31qRwwLWoxHLgry3SIfCwhxeQNbirEUXFa+lq3RL3oBYXtcmIA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-primitive": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.0.tgz", + "integrity": "sha512-/J/FhLdK0zVcILOwt5g+dH4KnkonCtkVJsa2G6JmvbbtZfBEI1gMsO3QMjseL4F/SwfAMt1Vc/0XKYKq+xJ1sw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-roving-focus": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.7.tgz", + "integrity": "sha512-C6oAg451/fQT3EGbWHbCQjYTtbyjNO1uzQgMzwyivcHT3GKNEmu1q3UuREhN+HzHAVtv3ivMVK08QlC+PkYw9Q==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-collection": "1.1.4", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-primitive": "2.1.0", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", + "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-popover": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.11.tgz", diff --git a/package.json b/package.json index beb8030..eaef63c 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "@payloadcms/payload-cloud": "3.31.0", "@payloadcms/richtext-lexical": "3.31.0", "@radix-ui/react-dialog": "^1.1.11", + "@radix-ui/react-dropdown-menu": "^2.1.12", "@radix-ui/react-label": "^2.1.4", "@radix-ui/react-popover": "^1.1.11", "@radix-ui/react-select": "^2.2.2", diff --git a/src/app/(frontend)/books/[bookId]/page.tsx b/src/app/(frontend)/books/[bookId]/page.tsx index cc333f3..795cc44 100644 --- a/src/app/(frontend)/books/[bookId]/page.tsx +++ b/src/app/(frontend)/books/[bookId]/page.tsx @@ -2,6 +2,18 @@ import { Book, Copy, Repository } from '@/payload-types' import { getPayload, PaginatedDocs } from 'payload' import configPromise from '@payload-config' import BookByIdPageClient from './page.client' +import { PageBreadCrumb, Route } from '@/components/PageBreadCrumb' + +const staticBreadcrumRoutes: Route[] = [ + { + label: 'Home', + href: '/', + }, + { + label: 'Search', + href: '/search', + }, +] type Params = Promise<{ bookId: string }> type SearchParams = Promise<{ [key: string]: string | undefined }> @@ -64,7 +76,26 @@ const BookByIdPage = async (props: Props) => { }, })) as PaginatedDocs - return + const createBreadcrumbRoutes =() => { + let title + if (!foundBook?.title) title = 'Book Not Found' + else title = foundBook.title.length > 25 ? `${foundBook.title.slice(0, 25)}...` : foundBook.title + + + return [...staticBreadcrumRoutes, { + label: title, + href: `/books/${bookId}` + }] + } + + console.log(createBreadcrumbRoutes()) + + return ( + <> + + + + ) } export default BookByIdPage diff --git a/src/app/(frontend)/books/page.client.tsx b/src/app/(frontend)/books/page.client.tsx index ec5f558..e34637c 100644 --- a/src/app/(frontend)/books/page.client.tsx +++ b/src/app/(frontend)/books/page.client.tsx @@ -1,6 +1,6 @@ 'use client' -import BookList from '@/components/BookList' +import SearchBooks from '@/components/Search/SearchBooks' import { Book } from '@/payload-types' import { PaginatedDocs } from 'payload' import { useMemo } from 'react' @@ -14,9 +14,9 @@ const BooksPageClient = (props: Props) => { }, [props.initialBooks]) return ( -
- -
+
+ +
) } diff --git a/src/app/(frontend)/books/page.tsx b/src/app/(frontend)/books/page.tsx index 12aa013..875e591 100644 --- a/src/app/(frontend)/books/page.tsx +++ b/src/app/(frontend)/books/page.tsx @@ -2,6 +2,18 @@ import { Book } from '@/payload-types' import { getPayload, PaginatedDocs } from 'payload' import configPromise from '@payload-config' import BooksPageClient from './page.client' +import { PageBreadCrumb, Route } from '@/components/PageBreadCrumb' + + const breadcrumRoutes: Route[] = [ + { + label: 'Home', + href: '/', + }, + { + label: 'Search', + href: '/search', + }, + ] type Params = Promise<{ slug: string }> type SearchParams = Promise<{ [key: string]: string | undefined }> @@ -38,7 +50,12 @@ const BooksPage = async (props: Props) => { }, })) as PaginatedDocs - return + return ( + <> + + + + ) } export default BooksPage diff --git a/src/app/(frontend)/page.tsx b/src/app/(frontend)/page.tsx index d08f1df..a702757 100644 --- a/src/app/(frontend)/page.tsx +++ b/src/app/(frontend)/page.tsx @@ -90,7 +90,7 @@ export default async function HomePage() { return (
- +
{user ? ( @@ -116,6 +116,7 @@ export default async function HomePage() {
)} +
) } diff --git a/src/components/HomeHero.tsx b/src/components/HomeHero.tsx index 0e2819d..55a6360 100644 --- a/src/components/HomeHero.tsx +++ b/src/components/HomeHero.tsx @@ -11,9 +11,15 @@ type Props = { } const HomeHero = (props: Props) => { const { user } = props + + const onClickEnter = () => { + const tabs = document.getElementById('homeContent') + tabs?.scrollIntoView({ behavior: 'smooth' }) + } + return ( -
-
+
+
{
-
+