Skip to content

initial setup with clerk, hompage, new book page#1

Open
sumit-dey98 wants to merge 1 commit into
mainfrom
setup-ui
Open

initial setup with clerk, hompage, new book page#1
sumit-dey98 wants to merge 1 commit into
mainfrom
setup-ui

Conversation

@sumit-dey98

@sumit-dey98 sumit-dey98 commented Jun 11, 2026

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • New Features

    • Initialized LibAi application with book library management functionality
    • Added book upload feature with PDF and cover image support
    • Implemented user authentication system
    • Created home page with book browsing and display
    • Added voice selection during book upload process
  • Documentation

    • Added project README with setup instructions
  • Chores

    • Configured project dependencies and build tools
    • Set up TypeScript, ESLint, and PostCSS configuration
    • Configured Tailwind CSS styling framework
    • Added authentication middleware

@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR initializes a complete Next.js application called LibAi, an AI-assisted library for uploading PDFs and voice chatting with books. It includes full-stack scaffolding with configuration, global styling, reusable UI components, authenticated root layout, home page with book discovery, and a book upload workflow with form validation.

Changes

LibAi Application Build-out

Layer / File(s) Summary
Project Configuration & Tooling
package.json, tsconfig.json, eslint.config.mjs, postcss.config.mjs, next.config.ts, proxy.ts, components.json, .gitignore, README.md
Dependency management, TypeScript strict mode, ESLint flat config with Next.js rules, PostCSS Tailwind plugin, Next.js image remote patterns for Open Library covers, Clerk middleware routing, Shadcn component registry, and standard Node/Next.js/environment gitignore rules.
Global Styling & Design System
app/globals.css
Tailwind theme with light/dark color tokens, comprehensive utility layers for layout containers, buttons, typography, navbar, alerts, VAPI/transcript/voice UI, book cards, and upload forms. Extensive Clerk authentication overrides for buttons, form fields, pricing tables, drawers, and "current plan" indicator styling.
UI Component Library & Utilities
lib/utils.ts, components/ui/*
Reusable styled components: Button with variant/size options, Form system (FormField, FormItem, FormControl, FormLabel, FormDescription, FormMessage) with accessible IDs and validation state, Input, Label, Select dropdown with scroll buttons, and LoadingOverlay spinner. Class name composition utility using clsx and tailwind-merge.
Root Layout, Metadata & Navigation
app/layout.tsx, components/Navbar.tsx
Root layout with Google fonts, Clerk provider wrapping, navbar mounting, and site metadata ("LibAi" title, PDF upload/chat description). Navbar with active route detection, conditional Clerk auth UI (Sign In/Sign Up modals when signed out, UserButton and subscriptions link when signed in).
Home Page with Book Discovery
lib/constants.ts, components/home/HeroSection.tsx, components/home/BookCard.tsx, app/page.tsx
Home page displaying HeroSection with headline, CTA button to /books/new, feature steps sidebar, and hero illustration. Recent Books grid mapping over sample books (10 predefined book objects with Open Library cover URLs). BookCard component renders linked cards with optional cover images, title/author metadata, and hover overlays.
Book Upload Page & Form
app/books/new/page.tsx, components/forms/UploadBookForm.tsx
New book page with header and UploadBookForm component. Form validates PDF (required, max 50MB), optional cover image (max 10MB), title, author, and voice selection via Zod. UI includes FileDropzone subcomponent for drag-and-drop/click file selection with preview, VoiceOption radio selector, and loading overlay during 1.4-second delayed submission. Logs validated payload on successful submit.

Sequence Diagram

Since this PR is a comprehensive initial project setup spanning configuration, styling, components, and multiple feature areas rather than a single focused feature flow, a sequence diagram would not meaningfully represent the changes. The interactions are scattered across setup, UI composition, and data display rather than forming a coherent sequential narrative.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 A burrow of code, layer by layer so deep,
Forms and fonts, and colors to keep,
Books awaiting their voice to be heard,
LibAi sprouts green—the first seedling word! 📚✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main changes: initial project setup including Clerk authentication integration, homepage with book cards, and a new book upload page.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch setup-ui

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🧹 Nitpick comments (2)
components/ui/form.tsx (1)

58-75: ⚡ Quick win

Add a guard for missing <FormItem> context in useFormField.

useFormField throws when <FormField> is missing, but not when <FormItem> is missing. In that case, IDs are derived from undefined, which silently breaks form accessibility wiring.

Suggested patch
 function useFormField() {
   const fieldContext = React.useContext(FormFieldContext);
   const itemContext = React.useContext(FormItemContext);
   const {getFieldState, formState} = useFormContext();

   if (!fieldContext.name) {
     throw new Error("useFormField should be used within <FormField>.");
   }
+  if (!itemContext.id) {
+    throw new Error("useFormField should be used within <FormItem>.");
+  }

   const fieldState = getFieldState(fieldContext.name, formState);
   const {id} = itemContext;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@components/ui/form.tsx` around lines 58 - 75, useFormField currently assumes
FormItemContext exists and uses itemContext.id which can be undefined; add a
guard after reading const itemContext = React.useContext(FormItemContext) to
verify itemContext and itemContext.id are present and throw a clear error (e.g.
"useFormField should be used within <FormItem>.") before computing
formItemId/formDescriptionId/formMessageId so IDs are never derived from
undefined; keep existing FormField presence check and use the same pattern
(throw early) to prevent silent accessibility breakage.
components/ui/loading-overlay.tsx (1)

15-27: ⚡ Quick win

Expose loading state to assistive tech.

The overlay should announce progress when it appears; adding status semantics here improves submit-flow accessibility.

Suggested patch
-    <div className="loading-wrapper">
+    <div className="loading-wrapper" role="status" aria-live="polite" aria-busy="true">
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@components/ui/loading-overlay.tsx` around lines 15 - 27, Wrap the overlay
container (the element with class "loading-wrapper") with appropriate ARIA
status semantics so screen readers announce the progress: add role="status"
aria-live="polite" aria-atomic="true" and set aria-busy="true" while visible;
also include a visually-hidden element (e.g., a span) that renders the dynamic
text using the existing title and/or description props (referencing title and
description) so assistive tech receives the message; keep the visual layout and
Loader2 element unchanged and ensure aria-busy is removed/updated when the
overlay unmounts or loading finishes.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/globals.css`:
- Around line 936-938: The current-plan styling targets
.cl-pricingTableCard:first-child which depends on DOM order; update the
selectors to be state-driven by targeting the disabled button state instead
(e.g., use button[aria-disabled="true"] within .cl-pricingTableCard) so the
border and badge highlight follow the actual current plan; replace occurrences
referencing .cl-pricingTableCard:first-child (and the matching badge selector
around lines where the badge is styled) with selectors that scope from
.cl-pricingTableCard to the descendant button[aria-disabled="true"] to apply the
special border and badge styles.
- Around line 185-188: Update Tailwind apply usages to Tailwind v4 important
syntax by moving leading "!" prefixes into trailing "!" (e.g., change
lg:!text-lg -> lg:text-lg!, !font-medium -> font-medium!, !text-3xl ->
text-3xl!, !mt-3 -> mt-3!, !w-full -> w-full!, !h-12 -> h-12!, !ml-auto ->
ml-auto!) for the rules in .label and the other affected classes; also remove
the fragile .cl-pricingTableCard:first-child selector and replace it with a
reliable active/current selector such as .cl-pricingTableCard.is-current and
include fallbacks like .cl-pricingTableCard[aria-current="true"] and
.cl-pricingTableCard[data-current="true"] so the intended “current plan” styling
targets an explicit active state rather than DOM order.

In `@components/forms/UploadBookForm.tsx`:
- Around line 112-116: The dropzone's onKeyDown handler in UploadBookForm.tsx is
triggering the file picker when keyboard events bubble from nested controls;
update the onKeyDown handler (the arrow function that checks event.key and calls
inputRef.current?.click()) to first verify the event originated on the container
by checking event.currentTarget === event.target (or return early if not), so
only direct container key presses (Enter/Space) activate the file input.

In `@components/home/BookCard.tsx`:
- Around line 4-15: The BookCard component allows slug to be undefined which
causes Link to fall back to an empty string and produce broken /books/ URLs;
make slug a required prop in the BookCardProps interface (remove the optional
marker) and update the BookCard signature to expect a non-optional slug so
callers must provide it, and remove or stop relying on the `slug ?? ""` fallback
in the Link href inside the BookCard component; adjust any call sites that pass
no slug to supply a valid slug or guard there.

In `@components/Navbar.tsx`:
- Around line 51-53: The optional-chaining expression is malformed: replace the
invalid `user ?. firstName` with a valid check (e.g. `user?.firstName` or `user
&& user.firstName`) where the JSX conditional renders the Link; update the
conditional in the Navbar component that references user and firstName so it
uses proper optional chaining without spaces around the `?.` operator to avoid
TSX parse errors.

In `@proxy.ts`:
- Around line 1-12: The middleware file is misnamed so Next.js won't load the
Clerk middleware; rename the file from proxy.ts to middleware.ts at the project
root (or src/) so export default clerkMiddleware() and the exported config with
matcher are recognized and invoked by Next.js; ensure exported symbols
clerkMiddleware and config stay unchanged after renaming.

In `@README.md`:
- Line 21: Update the README's font reference to match the implementation in
app/layout.tsx: replace the mention of "Geist" with the actual fonts used ("IBM
Plex Serif" and "Mona Sans") and note that they are loaded via next/font in
app/layout.tsx; ensure the README text and any linked examples or docs
accurately reference IBM Plex Serif and Mona Sans so readers aren't misled by
the previous Geist reference.

---

Nitpick comments:
In `@components/ui/form.tsx`:
- Around line 58-75: useFormField currently assumes FormItemContext exists and
uses itemContext.id which can be undefined; add a guard after reading const
itemContext = React.useContext(FormItemContext) to verify itemContext and
itemContext.id are present and throw a clear error (e.g. "useFormField should be
used within <FormItem>.") before computing
formItemId/formDescriptionId/formMessageId so IDs are never derived from
undefined; keep existing FormField presence check and use the same pattern
(throw early) to prevent silent accessibility breakage.

In `@components/ui/loading-overlay.tsx`:
- Around line 15-27: Wrap the overlay container (the element with class
"loading-wrapper") with appropriate ARIA status semantics so screen readers
announce the progress: add role="status" aria-live="polite" aria-atomic="true"
and set aria-busy="true" while visible; also include a visually-hidden element
(e.g., a span) that renders the dynamic text using the existing title and/or
description props (referencing title and description) so assistive tech receives
the message; keep the visual layout and Loader2 element unchanged and ensure
aria-busy is removed/updated when the overlay unmounts or loading finishes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 767d6caa-5ab9-4ca0-b9aa-2e528e03f6c6

📥 Commits

Reviewing files that changed from the base of the PR and between 14f8287 and e7f4a8f.

⛔ Files ignored due to path filters (17)
  • app/favicon.ico is excluded by !**/*.ico
  • package-lock.json is excluded by !**/package-lock.json
  • public/Gemini_Generated_Image_jlix6fjlix6fjlix (1) 1.png is excluded by !**/*.png
  • public/banner.svg is excluded by !**/*.svg
  • public/book-cover.svg is excluded by !**/*.svg
  • public/book.png is excluded by !**/*.png
  • public/desktop-banner.png is excluded by !**/*.png
  • public/hero-illustration.png is excluded by !**/*.png
  • public/image.png is excluded by !**/*.png
  • public/images/illustration-library.png is excluded by !**/*.png
  • public/loader.png is excluded by !**/*.png
  • public/logo-full.svg is excluded by !**/*.svg
  • public/logo.png is excluded by !**/*.png
  • public/mobile-banner.png is excluded by !**/*.png
  • public/open-book.svg is excluded by !**/*.svg
  • public/tab-banner.png is excluded by !**/*.png
  • public/wave.png is excluded by !**/*.png
📒 Files selected for processing (25)
  • .gitignore
  • README.md
  • app/books/new/page.tsx
  • app/globals.css
  • app/layout.tsx
  • app/page.tsx
  • components.json
  • components/Navbar.tsx
  • components/forms/UploadBookForm.tsx
  • components/home/BookCard.tsx
  • components/home/HeroSection.tsx
  • components/ui/button.tsx
  • components/ui/form.tsx
  • components/ui/input.tsx
  • components/ui/label.tsx
  • components/ui/loading-overlay.tsx
  • components/ui/select.tsx
  • eslint.config.mjs
  • lib/constants.ts
  • lib/utils.ts
  • next.config.ts
  • package.json
  • postcss.config.mjs
  • proxy.ts
  • tsconfig.json

Comment thread app/globals.css
Comment on lines +185 to +188
@apply h-12 border-none lg:!text-lg shadow-none focus:outline-none focus-visible:ring-0;
}
.label {
@apply text-lg mb-1 !font-medium;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Confirm Tailwind + stylelint versions
echo "== package.json (Tailwind/stylelint versions) =="
if [ -f package.json ]; then
  cat package.json | sed -n '1,200p' | rg -n '"tailwindcss"|tailwind|stylelint' || true
fi
if [ -f package-lock.json ]; then
  echo "== package-lock (tailwindcss/stylelint occurrences) =="
  rg -n '"tailwindcss"|"stylelint"' package-lock.json | head -n 50 || true
fi
if [ -f pnpm-lock.yaml ]; then
  echo "== pnpm-lock (tailwindcss/stylelint occurrences) =="
  rg -n 'tailwindcss:|stylelint:' pnpm-lock.yaml | head -n 50 || true
fi
if [ -f yarn.lock ]; then
  echo "== yarn.lock (tailwindcss/stylelint occurrences) =="
  rg -n 'tailwindcss|stylelint' yarn.lock | head -n 50 || true
fi

# 2) Inspect app/globals.css around the reported lines
echo
echo "== app/globals.css around lines 160-260 =="
if [ -f app/globals.css ]; then
  nl -ba app/globals.css | sed -n '150,260p'
else
  echo "Missing app/globals.css"
fi

# 3) Search for invalid/variant important prefix patterns in `@apply`
echo
echo "== Find `@apply` usages containing '!': prefix/variant forms =="
rg -n --hidden --no-ignore -g'app/globals.css' "`@apply`[^;]*!([a-zA-Z]|[0-9\\[])|`@apply`[^;]*lg:!|`@apply`[^;]*sm:!|`@apply`[^;]*md:!|`@apply`[^;]*xl:!|`@apply`[^;]*hover:!|`@apply`[^;]*focus:!" app/globals.css || true
rg -n --hidden --no-ignore -g'app/globals.css' "`@apply`[^;]*!;" app/globals.css || true
rg -n --hidden --no-ignore -g'app/globals.css' "`@apply`" app/globals.css | head -n 200

# 4) Look for the active-plan selector mentioned in the original comment (if present)
echo
echo "== Search for .cl-pricingTableCard:first-child in repo =="
rg -n --hidden --no-ignore ".cl-pricingTableCard:first-child" || true

# 5) Stylelint config mismatch check
echo
echo "== stylelint configuration files =="
ls -1 . | rg -i 'stylelint' || true
ls -1 ./**/*stylelint* 2>/dev/null | head -n 50 || true
if [ -f .stylelintrc ]; then
  echo "== .stylelintrc =="
  nl -ba .stylelintrc | sed -n '1,220p'
elif [ -f .stylelintrc.json ]; then
  echo "== .stylelintrc.json =="
  nl -ba .stylelintrc.json | sed -n '1,220p'
elif [ -f .stylelintrc.js ]; then
  echo "== .stylelintrc.js =="
  nl -ba .stylelintrc.js | sed -n '1,260p'
elif [ -f stylelint.config.js ]; then
  echo "== stylelint.config.js =="
  nl -ba stylelint.config.js | sed -n '1,260p'
fi

Repository: sumit-dey98/lib-ai

Length of output: 476


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Basic checks =="
ls -la app || true
test -f app/globals.css && echo "app/globals.css exists" || (echo "MISSING app/globals.css" && exit 1)

echo
echo "== Tailwind v4 check (from package.json) =="
cat package.json | sed -n '1,120p' | rg -n 'tailwindcss|`@tailwindcss/postcss`|stylelint' || true

echo
echo "== stylelint config files =="
ls -1 . | rg -i 'stylelint' || true
ls -1 ./**/*stylelint* 2>/dev/null | head -n 50 || true
for f in .stylelintrc .stylelintrc.json .stylelintrc.js stylelint.config.js .config/stylelint.config.js 2>/dev/null; do
  if [ -f "$f" ]; then echo "== $f =="; head -n 220 "$f"; fi
done

echo
echo "== app/globals.css (lines ~160-260) =="
awk 'NR>=150 && NR<=260 { printf "%6d  %s\n", NR, $0 }' app/globals.css | head -n 200

echo
echo "== Find `@apply` usages containing '!': =="
rg -n --hidden --no-ignore -g'app/globals.css' "`@apply`[^;]*!" app/globals.css || true
echo
echo "== Find `@apply` lines around the reported range 175-230 =="
awk 'NR>=170 && NR<=230 { if ($0 ~ /@apply/) printf "%6d  %s\n", NR, $0 }' app/globals.css || true

echo
echo "== Search for .cl-pricingTableCard:first-child =="
rg -n --hidden --no-ignore ".cl-pricingTableCard:first-child" . || true

Repository: sumit-dey98/lib-ai

Length of output: 739


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== app/globals.css (lines ~160-230) =="
awk 'NR>=150 && NR<=240 { printf "%6d  %s\n", NR, $0 }' app/globals.css | sed -n '1,300p'

echo
echo "== stylelint config files (best-effort) =="
# common filenames
for f in .stylelintrc .stylelintrc.json .stylelintrc.js stylelint.config.js .config/stylelint.config.js .config/.stylelintrc .config/.stylelintrc.json; do
  if [ -f "$f" ]; then
    echo "-- $f --"
    head -n 220 "$f" | sed -n '1,220p'
  fi
done
# any other stylelint-named configs
fd --hidden --no-ignore -t f 'stylelint*' . 2>/dev/null | head -n 50 || true

echo
echo "== Find `@apply` usages containing '!': =="
rg -n --hidden --no-ignore "`@apply`[^;]*!" app/globals.css || true

echo
echo "== Find `@apply` with variant + '!': (lg:! / sm:! / hover:! / focus:! etc) =="
rg -n --hidden --no-ignore "`@apply`[^;]*[a-zA-Z0-9_-]+:!" app/globals.css || true

Repository: sumit-dey98/lib-ai

Length of output: 5641


🌐 Web query:

Tailwind CSS v4 important modifier syntax !text-lg and lg:!text-lg vs text-lg! documentation

💡 Result:

In Tailwind CSS v4, the important modifier syntax has been updated to place the exclamation mark (!) at the end of the utility class (e.g., text-lg!) [1][2][3]. This replaces the v3 convention of placing the exclamation mark at the beginning of the class (e.g.,!text-lg) [1][3]. Regarding the specific syntax variations: text-lg! (Correct): This is the standard, modern syntax for Tailwind CSS v4 [1][4]. Placing the! at the end marks the specific utility as!important [4][3].!text-lg (Deprecated/Legacy): While Tailwind v4 maintains backward compatibility for this syntax [1][5], it is deprecated and intended to be replaced by the suffix version [1]. It is recommended to use the suffix version for all new development [1][3]. lg:!text-lg vs lg:text-lg!: When using variants (like responsive prefixes), the important modifier should still be applied to the base utility name [6][5]. In v4, this means appending the! to the end of the utility (e.g., lg:text-lg!) [6]. Using lg:!text-lg relies on the same backward compatibility as the non-prefixed version and is similarly deprecated [5]. Summary of rules: Always place the! at the end of the class name: utility-name! [1][4]. When using variants, append the! to the end of the utility: variant:utility-name! [6]. The old prefixed syntax (!utility-name) is supported for backward compatibility only [1][5]. The!important flag is no longer supported inside @apply directives; instead, you must append the! to each individual utility within the @apply rule (e.g., @apply flex! text-lg!) [7][5].

Citations:


🌐 Web query:

Tailwind v4 @apply important modifier syntax lg:text-lg! vs lg:!text-lg documentation

💡 Result:

In Tailwind CSS v4, the correct syntax for the important modifier is to place the ! at the end of the utility class (e.g., lg:text-lg!) [1][2]. Key details regarding this syntax: The ! modifier: In v4, placing ! at the end of a class name (e.g., text-lg!) marks that utility as !important [1][3]. This applies to variants as well; for example, lg:text-lg! correctly applies the !important flag to the text utility when the large breakpoint is active [2]. Deprecated syntax: Placing the ! at the beginning of the utility name (e.g., !text-lg) was the convention in v3 and is supported in v4 only for backward compatibility [1][2]. It is recommended to migrate to the trailing ! syntax [1]. Usage with @apply: When using the @apply directive, you should also use the trailing ! syntax [4]. For example: @apply lg:text-lg!; Important note on global important flags: If you have enabled the global important flag (by adding important to your Tailwind import, such as @import "tailwindcss" important;), it will apply !important to utilities by default [5][6][7]. Recent updates have clarified that @apply should generally ignore this global state, ensuring that explicit ! markers are the primary way to control importance within @apply [5].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== app/globals.css (top ~1-120) =="
awk 'NR>=1 && NR<=120 { printf "%6d  %s\n", NR, $0 }' app/globals.css | head -n 200

echo
echo "== Search for 'important' in app/globals.css =="
rg -n --hidden --no-ignore 'important' app/globals.css || true

echo
echo "== Search for .cl-pricingTableCard:first-child in repo =="
rg -n --hidden --no-ignore ".cl-pricingTableCard:first-child" . || true

echo
echo "== Search for '.cl-pricingTableCard' occurrences =="
rg -n --hidden --no-ignore ".cl-pricingTableCard" . || true

Repository: sumit-dey98/lib-ai

Length of output: 8512


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== app/globals.css (lines ~228-270) =="
awk 'NR>=220 && NR<=280 { printf "%6d  %s\n", NR, $0 }' app/globals.css | head -n 200

echo
echo "== app/globals.css (lines ~900-980) =="
awk 'NR>=880 && NR<=990 { printf "%6d  %s\n", NR, $0 }' app/globals.css | head -n 200

echo
echo "== package.json scripts (stylelint?) =="
cat package.json | sed -n '1,200p' | rg -n '"scripts"|stylelint' || true

Repository: sumit-dey98/lib-ai

Length of output: 5852


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== package.json (relevant sections) =="
awk 'NR>=1 && NR<=200 {print NR ":" $0}' package.json | sed -n '1,120p'
echo "----"
awk 'NR>=120 && NR<=260 {print NR ":" $0}' package.json | sed -n '120,260p' || true

echo
echo "== Search package.json for stylelint =="
rg -n "stylelint" package.json || true

Repository: sumit-dey98/lib-ai

Length of output: 1176


Fix deprecated Tailwind v4 @apply important syntax (! prefixes) and hardcoded active-plan selector

  • In app/globals.css, @apply still uses v3-style ! prefixes (lg:!text-lg, !font-medium, !text-3xl, !mt-3, !w-full, !h-12, !ml-auto) around lines ~185-188, 200-203, 215-216, and 243-246. Tailwind v4 expects trailing ! (e.g., lg:text-lg!, font-medium!, text-3xl!, mt-3!, w-full!, h-12!, ml-auto!) to ensure !important is applied reliably.
  • The “current plan” styling relies on .cl-pricingTableCard:first-child (lines ~933-965). If Clerk changes card order, the wrong plan can be highlighted.
Proposed fix (example replacements)
 .input-reset {
-  `@apply` h-12 border-none lg:!text-lg shadow-none focus:outline-none focus-visible:ring-0;
+  `@apply` h-12 border-none lg:text-lg! shadow-none focus:outline-none focus-visible:ring-0;
 }
 .label {
-  `@apply` text-lg mb-1 !font-medium;
+  `@apply` text-lg mb-1 font-medium!;
 }
 .page-title {
-  `@apply` !text-3xl font-bold text-center;
+  `@apply` text-3xl! font-bold text-center;
 }
 .page-description {
-  `@apply` !mt-3 text-center text-lg;
+  `@apply` mt-3! text-center text-lg;
 }
 .form-btn {
-  `@apply` !w-full h-14 rounded-[10px] bg-[`#663820`] cursor-pointer hover:bg-[`#7a4528`] text-base text-white font-semibold normal-case tracking-normal transition-colors;
+  `@apply` w-full! h-14 rounded-[10px] bg-[`#663820`] cursor-pointer hover:bg-[`#7a4528`] text-base text-white font-semibold normal-case tracking-normal transition-colors;
 }
 .select-trigger {
-  `@apply` !w-full !h-12 rounded-lg;
+  `@apply` w-full! h-12! rounded-lg;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@apply h-12 border-none lg:!text-lg shadow-none focus:outline-none focus-visible:ring-0;
}
.label {
@apply text-lg mb-1 !font-medium;
`@apply` h-12 border-none lg:text-lg! shadow-none focus:outline-none focus-visible:ring-0;
}
.label {
`@apply` text-lg mb-1 font-medium!;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/globals.css` around lines 185 - 188, Update Tailwind apply usages to
Tailwind v4 important syntax by moving leading "!" prefixes into trailing "!"
(e.g., change lg:!text-lg -> lg:text-lg!, !font-medium -> font-medium!,
!text-3xl -> text-3xl!, !mt-3 -> mt-3!, !w-full -> w-full!, !h-12 -> h-12!,
!ml-auto -> ml-auto!) for the rules in .label and the other affected classes;
also remove the fragile .cl-pricingTableCard:first-child selector and replace it
with a reliable active/current selector such as .cl-pricingTableCard.is-current
and include fallbacks like .cl-pricingTableCard[aria-current="true"] and
.cl-pricingTableCard[data-current="true"] so the intended “current plan” styling
targets an explicit active state rather than DOM order.

Comment thread app/globals.css
Comment on lines +936 to +938
.cl-pricingTableCard:first-child {
border: 2px solid #663820 !important;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Make “Your Current Plan” styling state-driven instead of DOM-order-based.
In app/globals.css the current-plan border and badge rely on .cl-pricingTableCard:first-child (lines 936-938 and 954-955), so if Clerk reorders the pricing cards the wrong plan could be highlighted and labeled “Your Current Plan”. Since the current plan is already marked in the markup via button[aria-disabled='true'], switch the selectors to target that state.

State-driven selector approach
-.cl-pricingTableCard:first-child {
+.cl-pricingTableCard:has(button[aria-disabled='true']) {
   border: 2px solid `#663820` !important;
 }

-.cl-pricingTableCard:first-child .cl-pricingTableCardContent::after {
+.cl-pricingTableCard:has(button[aria-disabled='true']) .cl-pricingTableCardContent::after {
   content: 'Your Current Plan';
   display: block;
   text-align: center;
   padding: 0.75rem 1.5rem;
   margin-top: 1rem;
   background-color: `#f3e4c7` !important;
   color: `#212a3b` !important;
   font-weight: 600;
   border-radius: 0.75rem;
   font-size: 1.125rem;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
.cl-pricingTableCard:first-child {
border: 2px solid #663820 !important;
}
.cl-pricingTableCard:has(button[aria-disabled='true']) {
border: 2px solid `#663820` !important;
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/globals.css` around lines 936 - 938, The current-plan styling targets
.cl-pricingTableCard:first-child which depends on DOM order; update the
selectors to be state-driven by targeting the disabled button state instead
(e.g., use button[aria-disabled="true"] within .cl-pricingTableCard) so the
border and badge highlight follow the actual current plan; replace occurrences
referencing .cl-pricingTableCard:first-child (and the matching badge selector
around lines where the badge is styled) with selectors that scope from
.cl-pricingTableCard to the descendant button[aria-disabled="true"] to apply the
special border and badge styles.

Comment on lines +112 to +116
onKeyDown={(event) => {
if (event.key === "Enter" || event.key === " ") {
event.preventDefault();
inputRef.current?.click();
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Scope dropzone keyboard activation to the container itself.

Keyboard events from nested controls can bubble to this handler and trigger the file picker unexpectedly. Guarding on event.currentTarget === event.target prevents that.

Suggested patch
       onKeyDown={(event) => {
+        if (event.currentTarget !== event.target) return;
         if (event.key === "Enter" || event.key === " ") {
           event.preventDefault();
           inputRef.current?.click();
         }
       }}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
onKeyDown={(event) => {
if (event.key === "Enter" || event.key === " ") {
event.preventDefault();
inputRef.current?.click();
}
onKeyDown={(event) => {
if (event.currentTarget !== event.target) return;
if (event.key === "Enter" || event.key === " ") {
event.preventDefault();
inputRef.current?.click();
}
}}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@components/forms/UploadBookForm.tsx` around lines 112 - 116, The dropzone's
onKeyDown handler in UploadBookForm.tsx is triggering the file picker when
keyboard events bubble from nested controls; update the onKeyDown handler (the
arrow function that checks event.key and calls inputRef.current?.click()) to
first verify the event originated on the container by checking
event.currentTarget === event.target (or return early if not), so only direct
container key presses (Enter/Space) activate the file input.

Comment on lines +4 to +15
interface BookCardProps {
title?: string,
author?: string,
slug?: string,
coverURL?: string,
coverColor?: string
}

const BookCard = ({title, author, slug, coverURL, coverColor}: BookCardProps) => {
return (
<Link href={`/books/${slug ?? ""}`} className="group block">
<article className="book-card">

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Make slug required to avoid silently generating /books/ links.

Line 14 falls back to an empty slug; that can create broken navigation if this component is reused with incomplete data.

Proposed fix
 interface BookCardProps {
-  title?: string,
-  author?: string,
-  slug?: string,
+  title?: string,
+  author?: string,
+  slug: string,
   coverURL?: string,
   coverColor?: string
 }

 const BookCard = ({title, author, slug, coverURL, coverColor}: BookCardProps) => {
   return (
-    <Link href={`/books/${slug ?? ""}`} className="group block">
+    <Link href={`/books/${slug}`} className="group block">
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
interface BookCardProps {
title?: string,
author?: string,
slug?: string,
coverURL?: string,
coverColor?: string
}
const BookCard = ({title, author, slug, coverURL, coverColor}: BookCardProps) => {
return (
<Link href={`/books/${slug ?? ""}`} className="group block">
<article className="book-card">
interface BookCardProps {
title?: string,
author?: string,
slug: string,
coverURL?: string,
coverColor?: string
}
const BookCard = ({title, author, slug, coverURL, coverColor}: BookCardProps) => {
return (
<Link href={`/books/${slug}`} className="group block">
<article className="book-card">
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@components/home/BookCard.tsx` around lines 4 - 15, The BookCard component
allows slug to be undefined which causes Link to fall back to an empty string
and produce broken /books/ URLs; make slug a required prop in the BookCardProps
interface (remove the optional marker) and update the BookCard signature to
expect a non-optional slug so callers must provide it, and remove or stop
relying on the `slug ?? ""` fallback in the Link href inside the BookCard
component; adjust any call sites that pass no slug to supply a valid slug or
guard there.

Comment thread components/Navbar.tsx
Comment on lines +51 to +53
{user ?. firstName && (
<Link href="/subscriptions" className="nav-user-name">{user.firstName}</Link>
)}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify there are no whitespace-broken optional chaining tokens in TS/TSX files
rg -nP '\?\s+\.' --type=ts --type=tsx

Repository: sumit-dey98/lib-ai

Length of output: 90


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the relevant portion of Navbar.tsx
if [ -f components/Navbar.tsx ]; then
  echo "=== components/Navbar.tsx (lines 35-80) ==="
  nl -ba components/Navbar.tsx | sed -n '35,80p'
else
  echo "Missing: components/Navbar.tsx" >&2
  exit 1
fi

# Check for whitespace-broken optional chaining in TS/TSX sources
echo
echo "=== Whitespace-broken optional chaining pattern (? .) in .ts/.tsx ==="
rg -nP '\?\s+\.' --glob '*.ts' --glob '*.tsx' || true

# Check Clerk dependency version (if available)
echo
echo "=== `@clerk/nextjs` version from package.json (if present) ==="
if [ -f package.json ]; then
  cat package.json | rg -n '"`@clerk/nextjs`"\s*:\s*"' || true
fi

# Find usage of Show from `@clerk/nextjs`
echo
echo "=== Usage of <Show from `@clerk/nextjs` ==="
rg -n --glob '*.tsx' --glob '*.ts' "from ['\"]`@clerk/nextjs`['\"]" || true
rg -n --glob '*.tsx' --glob '*.ts' "<Show\b" || true

Repository: sumit-dey98/lib-ai

Length of output: 167


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Print relevant portion of Navbar.tsx (using cat -n since nl is unavailable)
echo "=== components/Navbar.tsx (lines 35-80) ==="
if [ -f components/Navbar.tsx ]; then
  cat -n components/Navbar.tsx | sed -n '35,80p'
else
  echo "Missing: components/Navbar.tsx" >&2
  exit 1
fi

# Optional chaining whitespace typo check in TS/TSX sources
echo
echo "=== Whitespace-broken optional chaining pattern (? .) in .ts/.tsx ==="
rg -nP '\?\s+\.' --glob '*.ts' --glob '*.tsx' || true

# Check `@clerk/nextjs` version (if package.json exists)
echo
echo "=== `@clerk/nextjs` version from package.json (if present) ==="
if [ -f package.json ]; then
  rg -n '"`@clerk/nextjs`"\s*:\s*"' package.json || true
fi

# Find usage of Show from `@clerk/nextjs`
echo
echo "=== Usage of `@clerk/nextjs` <Show ==="
rg -n --glob '*.tsx' --glob '*.ts' "from ['\"]`@clerk/nextjs`['\"]" || true
rg -n --glob '*.tsx' --glob '*.ts' "<Show\b" || true

Repository: sumit-dey98/lib-ai

Length of output: 1606


🌐 Web query:

@clerk/nextjs Show when="signed-in" "signed-out" component

💡 Result:

In the @clerk/nextjs SDK, you can conditionally render content based on a user's authentication status using either the component or the and components [1][2]. The component is a flexible control component that uses the when prop to determine visibility [1]. Example using : import { Show } from '@clerk/nextjs'; export default function Page { return ( <Show when="signed-in" fallback={

You are signed out.

}>

You are signed in.

); } The when prop can be set to 'signed-in' or 'signed-out' [1]. Additionally, supports more advanced access control by passing objects like { role: '...' } or { permission: '...' } to the when prop [1]. Alternatively, you can use the specialized and components for simpler authentication checks [3][2]. Example using and : import { SignedIn, SignedOut } from '@clerk/nextjs'; export default function Header { return (

Please sign in.

Welcome back!

); } Both , , and can be used in both client-side and server-side components [1][4].

Citations:


Fix invalid optional-chaining syntax in components/Navbar.tsx
components/Navbar.tsx line 51 uses user ?. firstName (space between ? and .), which is invalid TSX and can fail parsing.

Proposed fix
-              {user ?. firstName && (
+              {user?.firstName && (
                 <Link href="/subscriptions" className="nav-user-name">{user.firstName}</Link>
               )}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{user ?. firstName && (
<Link href="/subscriptions" className="nav-user-name">{user.firstName}</Link>
)}
{user?.firstName && (
<Link href="/subscriptions" className="nav-user-name">{user.firstName}</Link>
)}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@components/Navbar.tsx` around lines 51 - 53, The optional-chaining expression
is malformed: replace the invalid `user ?. firstName` with a valid check (e.g.
`user?.firstName` or `user && user.firstName`) where the JSX conditional renders
the Link; update the conditional in the Navbar component that references user
and firstName so it uses proper optional chaining without spaces around the `?.`
operator to avoid TSX parse errors.

Comment thread proxy.ts
Comment on lines +1 to +12
import { clerkMiddleware } from '@clerk/nextjs/server'

export default clerkMiddleware()

export const config = {
matcher: [
'/((?!_next|[^?]*\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)',
// Always run for Clerk's auto-proxy path
'/__clerk/(.*)',
'/(api|trpc)(.*)',
],
} No newline at end of file

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Critical: Rename this file to middleware.ts for Next.js to recognize it.

Next.js middleware must be named exactly middleware.ts (or middleware.js) and placed at the project root or in the src/ directory. The current filename proxy.ts will not be recognized by Next.js, so this Clerk middleware will never execute.

Without the middleware running, Clerk authentication will fail completely—useUser(), <SignInButton>, <UserButton>, and all auth-dependent features in your Navbar and throughout the app will break.

🔧 Required fix

Rename the file:

mv proxy.ts middleware.ts
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@proxy.ts` around lines 1 - 12, The middleware file is misnamed so Next.js
won't load the Clerk middleware; rename the file from proxy.ts to middleware.ts
at the project root (or src/) so export default clerkMiddleware() and the
exported config with matcher are recognized and invoked by Next.js; ensure
exported symbols clerkMiddleware and config stay unchanged after renaming.

Comment thread README.md

You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.

This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Update font reference to match actual implementation.

The README states the project uses Geist font, but the actual app/layout.tsx imports and uses IBM Plex Serif and Mona Sans. This documentation inconsistency may confuse developers.

📝 Suggested fix
-This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
+This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load IBM Plex Serif and Mona Sans fonts.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load IBM Plex Serif and Mona Sans fonts.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@README.md` at line 21, Update the README's font reference to match the
implementation in app/layout.tsx: replace the mention of "Geist" with the actual
fonts used ("IBM Plex Serif" and "Mona Sans") and note that they are loaded via
next/font in app/layout.tsx; ensure the README text and any linked examples or
docs accurately reference IBM Plex Serif and Mona Sans so readers aren't misled
by the previous Geist reference.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant