Skip to content

refactor: remove ai chat integration and rebuild the chat ui on shadcn/ui - #28

Merged
itsnyein merged 1 commit into
mainfrom
refactor/ai-chat-ui-only
Aug 22, 2026
Merged

itsnyein merged 1 commit into
mainfrom
refactor/ai-chat-ui-only

Conversation

@nyeinphyoaung

Copy link
Copy Markdown
Collaborator

Summary

Drops the AI backend entirely and rebuilds the chat screen as a UI-only demo on shadcn/ui + Tailwind.

Integration removed

  • app/api/chat/route.ts deleted. It was the only backend, calling gemini-2.0-flash through streamText.
  • GOOGLE_GENERATIVE_AI_API_KEY removed from .env.example (and from the local .env, which is gitignored, so the key was never pushed).
  • Nine packages removed:
    • runtime AI: ai, @ai-sdk/google, @ai-sdk/react
    • pulled in only by the deleted elements/: @xyflow/react, shiki, streamdown, tokenlens, use-stick-to-bottom, @radix-ui/react-use-controllable-state

@xyflow/react is a full flow-diagram library and shiki a syntax highlighter shipping every language grammar; neither had any use once the chat was simplified. nanoid and motion were checked and kept, since other features still import them.

elements/ folder removed

All 30 files. It arrived as an ai-elements install and carried far more than a chat needs - canvas.tsx, node.tsx, edge.tsx, connection.tsx and controls.tsx were a node-graph editor, alongside artifacts, checkpoints, plans, queues, web previews and inline citations.

New chat UI

Four files, roughly 400 lines, using only shadcn primitives (Button, Select, Tooltip, Spinner):

  • ai-chat.tsx - container, state, auto-scroll, centred empty state with clickable suggestions
  • chat-message.tsx - user text in a right-aligned bubble, assistant replies full-width with no bubble, copy and regenerate on hover
  • chat-composer.tsx - textarea that grows to 200px, Enter sends and Shift+Enter newlines, model select and send button inline
  • data.ts / types.ts - suggestions, models, and a 5-line message type replacing the SDK's generics

Submitting appends the message, shows a thinking state, then returns a canned reply explaining that no model is connected and pointing at app/api/chat/route.ts for wiring one up. This keeps every UI state reachable rather than leaving a form that does nothing.

thinking-orbs

Added thinking-orbs (MIT, zero runtime dependencies, sideEffects: false, canvas-based) for the assistant mark, replacing a lucide Sparkles icon. It auto-detects the Tailwind dark class, so it follows the theme with no configuration.

It is used in two places only: a 64px breathing orb as the empty-state hero, and a 20px working orb in the "Thinking..." indicator - which is what the library is for. Delivered assistant messages have no avatar; a paused orb read as arbitrary noise at 20px and would have created one canvas element per message in a long conversation.

Notes

  • The model list is now vendor-neutral (Fast / Balanced / Advanced). It previously named three Gemini models, which would imply an integration that no longer exists.
  • The web-search toggle was dropped; it set state that went nowhere once the backend was removed.

Verification

  • tsc --noEmit clean
  • eslint clean
  • next build compiles
  • Signed in with the seed account and clicked through the real page: empty state, suggestion click, user message, thinking indicator, assistant reply, copy and regenerate all work

@vercel

vercel Bot commented Aug 22, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
shadcn-admindashboard Ready Ready Preview Aug 22, 2026 4:47pm

@claude

claude Bot commented Aug 22, 2026 •

Copy link
Copy Markdown

Claude finished @nyeinphyoaung's task in 2m 11s —— View job


Code Review: refactor: remove ai chat integration and rebuild the chat ui on shadcn/ui

Summary

Clean, well-scoped removal of the AI backend and the oversized elements/ vendor folder, with a small (~370 line) UI-only replacement. No leftover references to the deleted packages, env var, or route were found anywhere in the codebase. A couple of medium-severity robustness gaps in the new chat UI and one minor consistency nit are worth addressing, but nothing blocks merge.


Medium Issues

1. Pending timeout not cleared on unmount (features/ai-chat/components/ai-chat.tsx:58-71)

const respond = useCallback((prompt: string) => {
  setStatus("thinking");
  window.setTimeout(() => {
    setMessages((current) => [...current, { ... }]);
    setStatus("ready");
  }, 700);
}, []);

If the user navigates away from the page while the "thinking" timeout is pending, setMessages/setStatus still fire after unmount, producing a React warning (Can't perform a state update on an unmounted component) and briefly holding a stale closure alive. It's low-impact for a demo, but easy to fix:

const respond = useCallback((prompt: string) => {
  setStatus("thinking");
  const timeoutId = window.setTimeout(() => {
    setMessages((current) => [...current, { ... }]);
    setStatus("ready");
  }, 700);
  return () => window.clearTimeout(timeoutId);
}, []);

(with the caller storing/clearing the id in a ref, or via a useEffect cleanup keyed off a pending-timeout ref).

2. Enter key sends during IME composition (features/ai-chat/components/chat-composer.tsx:44-49)

const handleKeyDown = (event: React.KeyboardEvent<HTMLTextAreaElement>) => {
  if (event.key === "Enter" && !event.shiftKey) {
    event.preventDefault();
    if (canSend) onSubmit();
  }
};

For users composing text with an IME (Japanese, Chinese, Korean input), pressing Enter to confirm a candidate also fires a keydown with key === "Enter", which will submit the message prematurely instead of just confirming the composition. Guard with the composition flag:

if (event.key === "Enter" && !event.shiftKey && !event.nativeEvent.isComposing) {
  event.preventDefault();
  if (canSend) onSubmit();
}

Minor Issues

3. Duplicated max-height constant (features/ai-chat/components/chat-composer.tsx:16,39,67)

MAX_HEIGHT = 200 (JS) and the Tailwind class max-h-50 (which evaluates to 200px under Tailwind v4's calc(var(--spacing) * 50)) encode the same value in two different unit systems. They happen to agree today, but nothing enforces that — a future edit to one is likely to silently desync from the other. Consider deriving one from the other (e.g. an inline style={{ maxHeight: MAX_HEIGHT }} instead of the Tailwind class) or a comment noting the coupling.

4. Silent clipboard failure has no user-facing feedback (features/ai-chat/components/chat-message.tsx:54-62)

const copy = async () => {
  try {
    await navigator.clipboard.writeText(message.content);
    setCopied(true);
    window.setTimeout(() => setCopied(false), 2000);
  } catch {
    // Clipboard unavailable; the text stays selectable by hand.
  }
};

If navigator.clipboard.writeText rejects (e.g. non-secure context, permission denied), the button gives no indication that copying failed — the user just sees nothing happen. Not critical, but a toast (the project already uses sonner) would be more consistent with how other failures are surfaced elsewhere in the app.


Strengths

  • The elements/ removal is thorough and verified — no dangling imports of ai, @ai-sdk/*, @xyflow/react, shiki, streamdown, tokenlens, use-stick-to-bottom, GOOGLE_GENERATIVE_AI_API_KEY, or the deleted route remain anywhere in the tree (checked via grep across .ts/.tsx/README.md).
  • New files follow the project's feature-folder convention (features/ai-chat/{components,data.ts,types.ts}) and use only components/ui/* primitives and lucide-react icons, per repo conventions.
  • DEMO_REPLY in features/ai-chat/data.ts:14-15 clearly communicates the disconnected-backend state and points at the right file for wiring up a real integration, rather than leaving a dead-end form.
  • package.json dependency trimming is precise — nine packages removed, nanoid/motion correctly kept since other features still depend on them.

Verdict: No critical issues. Remaining items (timeout cleanup, IME composition guard) can be iterated on later, but are worth a follow-up before this pattern is copied elsewhere.

Note: tsc/eslint/next build could not be run in this sandbox (command execution required approval that wasn't available), so the PR author's own verification notes (clean tsc, eslint, and next build) were not independently re-verified — everything above is from manual reading of the diff and full file contents.

@itsnyein
itsnyein merged commit 0d8e5db into main Aug 22, 2026
4 checks passed
@itsnyein
itsnyein deleted the refactor/ai-chat-ui-only branch August 23, 2026 09:23

This branch was successfully deployed

1 active deployment
Preview — 30ee8c59 Deployed Aug 22, 2026 by vercel[bot]
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.

2 participants