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