Files
tweakcn/components/editor/editor.tsx
T
2548f49de1 ai chat (#107)
* Enhanced Editor (#100)

* refactor: editor page to improve responsiveness

* feat: add editor tab persistance to url

* chore: clean up classNames

* feat: enhance theme color-preview to make it responsive

* feat: add ai chat tab working with local state

* successful responses return a theme color-preview
* error responses return a generic message

* fix: invalid tabs fallback to default tab "colors"

* fix: remove messages scroll animation on tabs change and remove duplicate preview

* fix: minor fixes in classNames

* feat: Chat starts with a default message

* refactor: Enhance editor controls and toolbar buttons to disable when generating theme

- Updated button components to be extendible.
- Refactored buttons to utilize TooltipWrapper for consistent tooltip behavior.

* fix: sync controls tabs by 'value' instead of 'defaultValue'

* fix: load messages from local storage, otherwise set a default initial message

* fix: editor mention list positions correctly and add a tab handler for selecting mention

* fix: build errors due to unused imports

* chore: improve defaults and styles for ai chat interface and editor

* refactor: move AIChat state management to a zustand store

* feat: preserve control tab between edit mode and traditional editor mode

* feat: reset ai chat on editor reset button click

* feat: load chat messages dynamically to avoid layout shifts due to local storage

* fix: Use const id for default ai message to avoid re-render

* fix: Use searchParams for callback url as well after auth

* refactor: Remove unused getEditorConfig code

* feat: Only have 1 handler per postlogin action type

This was causing issues in AI Chat form. AI_GENERATE_FROM_CHAT action
was being scheduled twice because of re-render (caused by lazy-loaded
component)

* fix: Add user message for post login action

* refactor: Only use JSONContent in application state (derive textContent from it)

* feat: Auto-attach current theme to prompt after 1st user message

* feat: clean up AI interface and add community themes section

* feat: AI entrypoint redirect to main Editor and trigger theme generation

* chore: improve styles on ai page

* refactor: clean up AI components components from AI page and Editor page

* refactor: share repeated theme generation logic

* fix: chat messages inconsistent padding and pill buttons disabled state

* fix: build error

* feat: remove AI Generation Dialog and related logic

* feat: show agent response about the theme

* refactor: simplify theme generation logic and improve error handling

* refactor: transition from JSONContent to AIPromptData for theme generation

* feat: add retry functionality for user messages in AI chat interface

* refactor: remove unused loading fallback component and integrate loading indicator in chat messages

* change position of retry button

* feat: Improve system prompt

* refactor: replace createCurrentThemePrompt with attachCurrentThemeMention for improved prompt handling

* feat: add a placeholder for new chat and fix chat area styles

* chore: hide Community themes from AI page

* fix: build errors

* fix: ai theme generation only happens when there is content to be sent as the prompt

* feat: show AI tab in production

* fix: Early return after showing error message in ai chat

* feat: Attach last generated message instead of current theme for chat

* Use @ mentions in example prompts

* Enhance mention rendering in AI prompts and update mention styles in CSS

* skip posthog on dev

* Enhanced Editor (#100)

* refactor: editor page to improve responsiveness

* feat: add editor tab persistance to url

* chore: clean up classNames

* feat: enhance theme color-preview to make it responsive

* feat: add ai chat tab working with local state

* successful responses return a theme color-preview
* error responses return a generic message

* fix: invalid tabs fallback to default tab "colors"

* fix: remove messages scroll animation on tabs change and remove duplicate preview

* fix: minor fixes in classNames

* feat: Chat starts with a default message

* refactor: Enhance editor controls and toolbar buttons to disable when generating theme

- Updated button components to be extendible.
- Refactored buttons to utilize TooltipWrapper for consistent tooltip behavior.

* fix: sync controls tabs by 'value' instead of 'defaultValue'

* fix: load messages from local storage, otherwise set a default initial message

* fix: editor mention list positions correctly and add a tab handler for selecting mention

* fix: build errors due to unused imports

* chore: improve defaults and styles for ai chat interface and editor

* refactor: move AIChat state management to a zustand store

* feat: preserve control tab between edit mode and traditional editor mode

* feat: reset ai chat on editor reset button click

* feat: load chat messages dynamically to avoid layout shifts due to local storage

* fix: Use const id for default ai message to avoid re-render

* fix: Use searchParams for callback url as well after auth

* refactor: Remove unused getEditorConfig code

* feat: Only have 1 handler per postlogin action type

This was causing issues in AI Chat form. AI_GENERATE_FROM_CHAT action
was being scheduled twice because of re-render (caused by lazy-loaded
component)

* fix: Add user message for post login action

* refactor: Only use JSONContent in application state (derive textContent from it)

* feat: Auto-attach current theme to prompt after 1st user message

* feat: clean up AI interface and add community themes section

* feat: AI entrypoint redirect to main Editor and trigger theme generation

* chore: improve styles on ai page

* refactor: clean up AI components components from AI page and Editor page

* refactor: share repeated theme generation logic

* fix: chat messages inconsistent padding and pill buttons disabled state

* fix: build error

* feat: remove AI Generation Dialog and related logic

* feat: show agent response about the theme

* refactor: simplify theme generation logic and improve error handling

* refactor: transition from JSONContent to AIPromptData for theme generation

* feat: add retry functionality for user messages in AI chat interface

* refactor: remove unused loading fallback component and integrate loading indicator in chat messages

* change position of retry button

* feat: Improve system prompt

* refactor: replace createCurrentThemePrompt with attachCurrentThemeMention for improved prompt handling

* feat: add a placeholder for new chat and fix chat area styles

* chore: hide Community themes from AI page

* fix: build errors

* fix: ai theme generation only happens when there is content to be sent as the prompt

* feat: show AI tab in production

* fix: Early return after showing error message in ai chat

* feat: Attach last generated message instead of current theme for chat

* Use @ mentions in example prompts

* Enhance mention rendering in AI prompts and update mention styles in CSS

* fix: missing fade effect on chat messages scroll area and overflow in placeholder buttons

* feat: add user name from session to the chat placeholder component

* feat: Improve system prompt context

* chore: remove unnecessary context from example prompts

* feat: Enhance mention list with auto-scroll functionality and update prompt structures in no-messages placeholder

* feat: Add character limit for AI prompt input and integrate character count extension

* fix: Simplify prompt data handling in AI chat component and adjust textarea behavior during AI generation

* fix: Update theme state handling to include current mode in editor store

* chore: improve styles for consistency

* feat: add fun prompts to chat placeholder

* feat: add typography demo to preview panel

* feat: add responsive cards demo based on shadcn showcase

* fix: typography demo scroll area

* fix: build errors due to components refactor

* fix: wrap typography demo in ExamplesPreviewContainer

* feat: change default theme to match shadcn/ui default

* chore: move some theme previews into a dropdown to keep ui clean

---------

Co-authored-by: Luis Llanes <137589205+llanesluis@users.noreply.github.com>
Co-authored-by: Luis Llanes <luisllaboj@gmail.com>
2025-05-31 20:08:53 +05:30

128 lines
4.2 KiB
TypeScript

"use client";
import React, { useEffect, use } from "react";
import { ResizablePanelGroup, ResizablePanel, ResizableHandle } from "@/components/ui/resizable";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { Theme, ThemeStyles } from "@/types/theme";
import { Sliders } from "lucide-react";
import { useEditorStore } from "@/store/editor-store";
import { ActionBar } from "./action-bar/action-bar";
import ThemeControlPanel from "./theme-control-panel";
import ThemePreviewPanel from "./theme-preview-panel";
interface EditorProps {
themePromise: Promise<Theme | null>;
}
const isThemeStyles = (styles: unknown): styles is ThemeStyles => {
return (
!!styles &&
typeof styles === "object" &&
styles !== null &&
"light" in styles &&
"dark" in styles
);
};
const Editor: React.FC<EditorProps> = ({ themePromise }) => {
const themeState = useEditorStore((state) => state.themeState);
const setThemeState = useEditorStore((state) => state.setThemeState);
const initialTheme = themePromise ? use(themePromise) : null;
const handleStyleChange = React.useCallback(
(newStyles: ThemeStyles) => {
const prev = useEditorStore.getState().themeState;
setThemeState({ ...prev, styles: newStyles });
},
[setThemeState]
);
useEffect(() => {
if (initialTheme && isThemeStyles(initialTheme.styles)) {
const prev = useEditorStore.getState().themeState;
setThemeState({
...prev,
styles: initialTheme.styles,
preset: initialTheme.id,
});
}
}, [initialTheme, setThemeState]);
if (initialTheme && !isThemeStyles(initialTheme.styles)) {
return (
<div className="text-destructive flex h-full items-center justify-center">
Fetched theme data is invalid.
</div>
);
}
const styles = themeState.styles;
return (
<div className="relative isolate flex flex-1 overflow-hidden">
{/* Desktop Layout */}
<div className="hidden size-full md:block">
<ResizablePanelGroup direction="horizontal" className="isolate">
<ResizablePanel
defaultSize={30}
minSize={20}
maxSize={40}
className="z-1 min-w-[max(20%,22rem)]"
>
<div className="relative isolate flex h-full flex-1 flex-col">
<ThemeControlPanel
styles={styles}
onChange={handleStyleChange}
currentMode={themeState.currentMode}
themePromise={themePromise}
/>
</div>
</ResizablePanel>
<ResizableHandle />
<ResizablePanel defaultSize={70}>
<div className="flex h-full flex-col">
<div className="flex min-h-0 flex-1 flex-col">
<ActionBar />
<ThemePreviewPanel styles={styles} currentMode={themeState.currentMode} />
</div>
</div>
</ResizablePanel>
</ResizablePanelGroup>
</div>
{/* Mobile Layout */}
<div className="h-full w-full flex-1 overflow-hidden md:hidden">
<Tabs defaultValue="controls" className="h-full">
<TabsList className="w-full rounded-none">
<TabsTrigger value="controls" className="flex-1">
<Sliders className="mr-2 h-4 w-4" />
Controls
</TabsTrigger>
<TabsTrigger value="preview" className="flex-1">
Preview
</TabsTrigger>
</TabsList>
<TabsContent value="controls" className="mt-0 h-[calc(100%-2.5rem)]">
<div className="flex h-full flex-col">
<ThemeControlPanel
styles={styles}
onChange={handleStyleChange}
currentMode={themeState.currentMode}
themePromise={themePromise}
/>
</div>
</TabsContent>
<TabsContent value="preview" className="mt-0 h-[calc(100%-2.5rem)]">
<div className="flex h-full flex-col">
<ActionBar />
<ThemePreviewPanel styles={styles} currentMode={themeState.currentMode} />
</div>
</TabsContent>
</Tabs>
</div>
</div>
);
};
export default Editor;