Add a loading indactor that is stylized

This commit is contained in:
Nate Kelley 2025-08-21 22:05:44 -06:00
parent fbc0e94281
commit 8cd289ea59
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
5 changed files with 49 additions and 26 deletions

View File

@ -28,7 +28,6 @@ const editorVariants = cva(
true: 'ring-2 ring-ring ring-offset-2'
},
variant: {
ai: 'w-full px-0 text-base md:text-sm',
comment: cn('rounded-none border-none bg-transparent text-sm'),
default: 'size-full px-16 pt-4 pb-72 text-base sm:px-[max(64px,calc(50%-350px))]',
fullWidth: 'size-full px-16 pt-4 pb-72 text-base sm:px-24',
@ -41,7 +40,7 @@ const editorVariants = cva(
export type EditorProps = PlateContentProps & VariantProps<typeof editorVariants>;
export const Editor = React.forwardRef<HTMLDivElement, EditorProps>(
({ className, disabled, focused, variant, ...props }, ref) => {
({ className, disabled, focused, variant, children, ...props }, ref) => {
return (
<PlateContent
ref={ref}

View File

@ -31,6 +31,7 @@ interface ReportEditorProps {
id?: string;
mode?: 'export' | 'default';
children?: React.ReactNode;
postEditorChildren?: React.ReactNode;
}
export type IReportEditor = TPlateEditor<Value, AnyPluginConfig>;
@ -60,16 +61,14 @@ export const ReportEditor = React.memo(
readOnly = false,
disabled = false,
isStreaming = false,
children
children,
postEditorChildren
},
ref
) => {
// Initialize the editor instance using the custom useEditor hook
const isReady = useRef(false);
// readOnly = true;
// isStreaming = true;
const editor = useReportEditor({
isStreaming,
mode,
@ -132,7 +131,7 @@ export const ReportEditor = React.memo(
variant={variant}
readonly={readOnly}
disabled={disabled}
className={cn('editor-container overflow-auto', containerClassName)}>
className={cn('editor-container relative overflow-auto', containerClassName)}>
{children}
<ThemeWrapper id={id}>
<Editor
@ -142,12 +141,8 @@ export const ReportEditor = React.memo(
className={cn('editor', className)}
autoFocus
/>
{isStreaming && (
<div className="absolute bottom-4 left-1/2 transform -translate-x-1/2 flex items-center gap-1.5 bg-background/80 backdrop-blur-sm px-3 py-2 rounded-md border border-border/50 shadow-sm">
<ShimmerText text="Generating content..." className="text-sm" />
</div>
)}
</ThemeWrapper>
{postEditorChildren}
</EditorContainer>
</Plate>
);

View File

@ -46,18 +46,11 @@ const EDITOR_THEME = { ...CSS_VARIABLES_THEME, ...THEME_RESET_STYLE };
export function ThemeWrapper({ children, className, defaultTheme, id }: ThemeWrapperProps) {
return (
<>
<div
id={id}
style={EDITOR_THEME}
className={cn(
'themes-wrapper h-full w-full overflow-visible bg-transparent antialiased',
className
)}>
className={cn('themes-wrapper w-full bg-transparent antialiased', className)}>
{children}
</div>
{/* <ThemesStyle /> */}
</>
);
}

View File

@ -0,0 +1,27 @@
import { queryKeys } from '@/api/query_keys';
import { ShimmerText } from '@/components/ui/typography/ShimmerText';
import { cn } from '@/lib/classMerge';
import { useQuery } from '@tanstack/react-query';
export const GeneratingContent = ({
messageId,
className
}: {
messageId: string;
className?: string;
}) => {
const { data: text } = useQuery({
...queryKeys.chatsBlackBoxMessages(messageId),
notifyOnChangeProps: ['data'],
select: (data) => data
});
return (
<div
className={cn('right-0 bottom-0 left-0 -mt-68 flex items-center justify-center', className)}>
<div className="border-border item-center flex w-full justify-center rounded border px-8 py-1.5 shadow">
<ShimmerText text={text || 'Generating content...'} className="text-lg" />
</div>
</div>
);
};

View File

@ -10,6 +10,8 @@ import { type IReportEditor } from '@/components/ui/report/ReportEditor';
import { ReportEditorSkeleton } from '@/components/ui/report/ReportEditorSkeleton';
import { useChatIndividualContextSelector } from '@/layouts/ChatLayout/ChatContext';
import { useTrackAndUpdateReportChanges } from '@/api/buster-electric/reports/hooks';
import { ShimmerText } from '@/components/ui/typography/ShimmerText';
import { GeneratingContent } from './GeneratingContent';
export const ReportPageController: React.FC<{
reportId: string;
@ -21,8 +23,10 @@ export const ReportPageController: React.FC<{
({ reportId, readOnly = false, className = '', onReady: onReadyProp, mode = 'default' }) => {
const { data: report } = useGetReport({ reportId, versionNumber: undefined });
const isStreamingMessage = useChatIndividualContextSelector((x) => x.isStreamingMessage);
const messageId = useChatIndividualContextSelector((x) => x.currentMessageId);
const content = report?.content || '';
const showGeneratingContent = messageId && isStreamingMessage;
const commonClassName = 'sm:px-[max(64px,calc(50%-350px))]';
const { mutate: updateReport } = useUpdateReport();
@ -68,7 +72,12 @@ export const ReportPageController: React.FC<{
readOnly={readOnly || !report}
mode={mode}
onReady={onReadyProp}
isStreaming={isStreamingMessage}>
isStreaming={isStreamingMessage}
postEditorChildren={
showGeneratingContent ? (
<GeneratingContent messageId={messageId} className={commonClassName} />
) : null
}>
<ReportPageHeader
name={report?.name}
updatedAt={report?.updated_at}