Refactor RowboatX configuration and enhance editor features

- Updated `next.config.ts` to scope Turbopack to the app's directory.
- Modified `package.json` and `package-lock.json` to include new dependencies for Tiptap and markdown processing.
- Removed deprecated chat API and added new agent and config routes for file management.
- Introduced `JsonEditor` and `MarkdownViewer` components for improved content editing and display.
- Enhanced `TiptapMarkdownEditor` with additional toolbar options and markdown parsing capabilities.
- Updated layout and page components to integrate new editors and improve user experience.
This commit is contained in:
tusharmagar 2025-12-22 09:14:09 +05:30 committed by Ramnique Singh
parent da20e280f4
commit c637cb49ac
26 changed files with 2552 additions and 540 deletions

View file

@ -53,7 +53,13 @@ export const CheckpointTrigger = ({
tooltip ? (
<Tooltip>
<TooltipTrigger asChild>
<Button size={size} type="button" variant={variant} {...props}>
<Button
className={cn(className)}
size={size}
type="button"
variant={variant}
{...props}
>
{children}
</Button>
</TooltipTrigger>
@ -62,7 +68,13 @@ export const CheckpointTrigger = ({
</TooltipContent>
</Tooltip>
) : (
<Button size={size} type="button" variant={variant} {...props}>
<Button
className={cn(className)}
size={size}
type="button"
variant={variant}
{...props}
>
{children}
</Button>
);

View file

@ -1,3 +1,4 @@
/* eslint-disable @next/next/no-img-element */
import { cn } from "@/lib/utils";
import type { Experimental_GeneratedImage } from "ai";
@ -8,7 +9,6 @@ export type ImageProps = Experimental_GeneratedImage & {
export const Image = ({
base64,
uint8Array,
mediaType,
...props
}: ImageProps) => (

View file

@ -1,5 +1,6 @@
"use client";
/* eslint-disable @next/next/no-img-element */
import { Button } from "@/components/ui/button";
import {
ButtonGroup,
@ -20,7 +21,7 @@ import {
XIcon,
} from "lucide-react";
import type { ComponentProps, HTMLAttributes, ReactElement } from "react";
import { createContext, memo, useContext, useEffect, useState } from "react";
import { createContext, memo, useContext, useEffect, useMemo, useState } from "react";
import { Streamdown } from "streamdown";
export type MessageProps = HTMLAttributes<HTMLDivElement> & {
@ -188,7 +189,10 @@ export const MessageBranchContent = ({
...props
}: MessageBranchContentProps) => {
const { currentBranch, setBranches, branches } = useMessageBranch();
const childrenArray = Array.isArray(children) ? children : [children];
const childrenArray = useMemo(
() => (Array.isArray(children) ? children : [children]),
[children]
);
// Use useEffect to update branches when they change
useEffect(() => {
@ -211,13 +215,10 @@ export const MessageBranchContent = ({
));
};
export type MessageBranchSelectorProps = HTMLAttributes<HTMLDivElement> & {
from: UIMessage["role"];
};
export type MessageBranchSelectorProps = HTMLAttributes<HTMLDivElement>;
export const MessageBranchSelector = ({
className,
from,
...props
}: MessageBranchSelectorProps) => {
const { totalBranches } = useMessageBranch();
@ -229,7 +230,10 @@ export const MessageBranchSelector = ({
return (
<ButtonGroup
className="[&>*:not(:first-child)]:rounded-l-md [&>*:not(:last-child)]:rounded-r-md"
className={cn(
"[&>*:not(:first-child)]:rounded-l-md [&>*:not(:last-child)]:rounded-r-md",
className
)}
orientation="horizontal"
{...props}
/>
@ -276,6 +280,7 @@ export const MessageBranchNext = ({
size="icon-sm"
type="button"
variant="ghost"
className={className}
{...props}
>
{children ?? <ChevronRightIcon size={14} />}

View file

@ -1,3 +1,4 @@
/* eslint-disable @next/next/no-img-element */
import {
Command,
CommandDialog,

View file

@ -1,5 +1,6 @@
"use client";
/* eslint-disable @next/next/no-img-element */
import { Button } from "@/components/ui/button";
import {
Command,
@ -666,7 +667,6 @@ export const PromptInput = ({
}
}
},
// eslint-disable-next-line react-hooks/exhaustive-deps -- cleanup only on unmount; filesRef always current
[usingProvider]
);
@ -726,7 +726,7 @@ export const PromptInput = ({
// Convert blob URLs to data URLs asynchronously
Promise.all(
files.map(async ({ id, ...item }) => {
files.map(async ({ ...item }) => {
if (item.url && item.url.startsWith("blob:")) {
const dataUrl = await convertBlobUrlToDataUrl(item.url);
// If conversion failed, keep the original blob URL
@ -1060,13 +1060,13 @@ interface SpeechRecognition extends EventTarget {
lang: string;
start(): void;
stop(): void;
onstart: ((this: SpeechRecognition, ev: Event) => any) | null;
onend: ((this: SpeechRecognition, ev: Event) => any) | null;
onstart: ((this: SpeechRecognition, ev: Event) => void) | null;
onend: ((this: SpeechRecognition, ev: Event) => void) | null;
onresult:
| ((this: SpeechRecognition, ev: SpeechRecognitionEvent) => any)
| ((this: SpeechRecognition, ev: SpeechRecognitionEvent) => void)
| null;
onerror:
| ((this: SpeechRecognition, ev: SpeechRecognitionErrorEvent) => any)
| ((this: SpeechRecognition, ev: SpeechRecognitionErrorEvent) => void)
| null;
}

View file

@ -1,5 +1,6 @@
"use client";
/* eslint-disable @next/next/no-img-element */
import { Button } from "@/components/ui/button";
import {
Collapsible,