mirror of
https://github.com/kamranahmedse/developer-roadmap.git
synced 2025-09-03 06:12:53 +02:00
feat: show loading status
This commit is contained in:
@@ -220,7 +220,9 @@ export function RoadmapAIChat(props: RoadmapAIChatProps) {
|
||||
return;
|
||||
}
|
||||
|
||||
const jsx = await renderMessage(content, renderer);
|
||||
const jsx = await renderMessage(content, renderer, {
|
||||
isLoading: true,
|
||||
});
|
||||
|
||||
flushSync(() => {
|
||||
setStreamedMessage(jsx);
|
||||
@@ -233,7 +235,9 @@ export function RoadmapAIChat(props: RoadmapAIChatProps) {
|
||||
return;
|
||||
}
|
||||
|
||||
const jsx = await renderMessage(content, renderer);
|
||||
const jsx = await renderMessage(content, renderer, {
|
||||
isLoading: false,
|
||||
});
|
||||
const newMessages: RoamdapAIChatHistoryType[] = [
|
||||
...messages,
|
||||
{
|
||||
|
@@ -69,10 +69,11 @@ type BulkUpdateResourceProgressResponse = {
|
||||
type UserProgressActionListProps = {
|
||||
roadmapId: string;
|
||||
content: string;
|
||||
isLoading?: boolean;
|
||||
};
|
||||
|
||||
export function UserProgressActionList(props: UserProgressActionListProps) {
|
||||
const { roadmapId, content } = props;
|
||||
const { roadmapId, content, isLoading = false } = props;
|
||||
|
||||
const toast = useToast();
|
||||
const updateUserProgress = parseUserProgress(content);
|
||||
@@ -157,12 +158,19 @@ export function UserProgressActionList(props: UserProgressActionListProps) {
|
||||
<div className="absolute inset-x-0 right-0 bottom-0.5 translate-y-1/2">
|
||||
<div className="flex items-center justify-center gap-2">
|
||||
<button
|
||||
className="rounded-md bg-gray-100 px-2 py-1 text-[10px] leading-none font-medium"
|
||||
className="rounded-md bg-gray-100 px-2 py-1 text-[10px] leading-none font-medium disabled:cursor-not-allowed disabled:opacity-70"
|
||||
onClick={() => setShowAll(!showAll)}
|
||||
disabled={isLoading}
|
||||
>
|
||||
{showAll
|
||||
? '- Show Less'
|
||||
: `+${progressItemWithText.length - itemCountToShow} more`}
|
||||
{isLoading && <Loader2Icon className="size-2.5 animate-spin" />}
|
||||
|
||||
{!isLoading && (
|
||||
<>
|
||||
{showAll
|
||||
? '- Show Less'
|
||||
: `+${progressItemWithText.length - itemCountToShow} more`}
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -10,16 +10,24 @@ type MessagePart = {
|
||||
|
||||
type MessagePartRendererProps = {
|
||||
content: string;
|
||||
isLoading?: boolean;
|
||||
};
|
||||
|
||||
export type MessagePartRenderer = (
|
||||
props: MessagePartRendererProps,
|
||||
) => React.ReactNode | string;
|
||||
|
||||
export type MessagePartRendererOptions = {
|
||||
isLoading?: boolean;
|
||||
};
|
||||
|
||||
export async function parseMessageParts(
|
||||
content: string,
|
||||
renderer: Record<string, MessagePartRenderer>,
|
||||
): Promise<MessagePart[]> {
|
||||
options: MessagePartRendererOptions = {
|
||||
isLoading: false,
|
||||
},
|
||||
) {
|
||||
const parts: MessagePart[] = [];
|
||||
const regex = /<([a-zA-Z0-9\-]+)>(.*?)<\/\1>/gs;
|
||||
|
||||
@@ -46,7 +54,10 @@ export async function parseMessageParts(
|
||||
});
|
||||
}
|
||||
|
||||
const output = renderer[tag]({ content: innerContent });
|
||||
const output = renderer[tag]({
|
||||
content: innerContent,
|
||||
isLoading: options.isLoading,
|
||||
});
|
||||
parts.push({
|
||||
id: nanoid(),
|
||||
type: 'html',
|
||||
@@ -81,7 +92,10 @@ export async function parseMessageParts(
|
||||
}
|
||||
|
||||
const innerContent = content.slice(openingIndex + openingTag.length);
|
||||
const output = renderer[tag]({ content: innerContent });
|
||||
const output = renderer[tag]({
|
||||
content: innerContent,
|
||||
isLoading: options.isLoading,
|
||||
});
|
||||
parts.push({
|
||||
id: nanoid(),
|
||||
type: 'html',
|
||||
@@ -109,8 +123,11 @@ export async function parseMessageParts(
|
||||
export async function renderMessage(
|
||||
content: string,
|
||||
renderer: Record<string, MessagePartRenderer>,
|
||||
options: MessagePartRendererOptions = {
|
||||
isLoading: false,
|
||||
},
|
||||
) {
|
||||
const parts = await parseMessageParts(content, renderer);
|
||||
const parts = await parseMessageParts(content, renderer, options);
|
||||
|
||||
return (
|
||||
<div className="max-w-[calc(100%-38px)]">
|
||||
|
Reference in New Issue
Block a user