diff --git a/.astro/settings.json b/.astro/settings.json
index 4d5033b8e..501b47e44 100644
--- a/.astro/settings.json
+++ b/.astro/settings.json
@@ -3,6 +3,6 @@
"enabled": false
},
"_variables": {
- "lastUpdateCheck": 1748277554631
+ "lastUpdateCheck": 1749494681580
}
}
\ No newline at end of file
diff --git a/.astro/types.d.ts b/.astro/types.d.ts
index 03d7cc43f..f964fe0cf 100644
--- a/.astro/types.d.ts
+++ b/.astro/types.d.ts
@@ -1,2 +1 @@
///
-///
\ No newline at end of file
diff --git a/src/components/Billing/UpgradeAccountModal.tsx b/src/components/Billing/UpgradeAccountModal.tsx
index 4192bf63f..cb8e08843 100644
--- a/src/components/Billing/UpgradeAccountModal.tsx
+++ b/src/components/Billing/UpgradeAccountModal.tsx
@@ -185,6 +185,7 @@ export function UpgradeAccountModal(props: UpgradeAccountModalProps) {
bodyClassName="p-4 sm:p-6 bg-white"
wrapperClassName="h-auto rounded-xl max-w-3xl w-full min-h-[540px] mx-2 sm:mx-4"
overlayClassName="items-start md:items-center"
+ hasCloseButton={true}
>
e.stopPropagation()}>
{errorContent}
diff --git a/src/components/EditorRoadmap/EditorRoadmap.tsx b/src/components/EditorRoadmap/EditorRoadmap.tsx
index 1a0df65a9..4f91be514 100644
--- a/src/components/EditorRoadmap/EditorRoadmap.tsx
+++ b/src/components/EditorRoadmap/EditorRoadmap.tsx
@@ -9,8 +9,8 @@ import {
type ResourceType,
} from '../../lib/resource-progress';
import { httpGet } from '../../lib/http';
-import { ProgressNudge } from '../FrameRenderer/ProgressNudge';
import { getUrlParams } from '../../lib/browser.ts';
+import { RoadmapFloatingChat } from '../FrameRenderer/RoadmapFloatingChat.tsx';
type EditorRoadmapProps = {
resourceId: string;
@@ -99,7 +99,7 @@ export function EditorRoadmap(props: EditorRoadmapProps) {
dimensions={dimensions}
resourceId={resourceId}
/>
-
+
);
}
diff --git a/src/components/FrameRenderer/FrameRenderer.css b/src/components/FrameRenderer/FrameRenderer.css
index a3b9514ce..fa076d228 100644
--- a/src/components/FrameRenderer/FrameRenderer.css
+++ b/src/components/FrameRenderer/FrameRenderer.css
@@ -4,7 +4,7 @@ svg text tspan {
text-rendering: optimizeSpeed;
}
-code {
+code:not(pre code) {
background: #1e1e3f;
color: #9efeff;
padding: 3px 5px;
diff --git a/src/components/FrameRenderer/RoadmapFloatingChat.tsx b/src/components/FrameRenderer/RoadmapFloatingChat.tsx
new file mode 100644
index 000000000..25a77e64b
--- /dev/null
+++ b/src/components/FrameRenderer/RoadmapFloatingChat.tsx
@@ -0,0 +1,589 @@
+import { useQuery } from '@tanstack/react-query';
+import type { JSONContent } from '@tiptap/core';
+import {
+ BookOpen,
+ ChevronDown,
+ MessageCirclePlus,
+ PauseCircleIcon,
+ PersonStanding,
+ SendIcon,
+ SquareArrowOutUpRight,
+ Trash2,
+ Wand2,
+ X,
+} from 'lucide-react';
+import { Fragment, useEffect, useMemo, useRef, useState } from 'react';
+import { flushSync } from 'react-dom';
+import { useKeydown } from '../../hooks/use-keydown';
+import {
+ useRoadmapAIChat,
+ type RoadmapAIChatHistoryType,
+} from '../../hooks/use-roadmap-ai-chat';
+import { cn } from '../../lib/classname';
+import { lockBodyScroll } from '../../lib/dom';
+import { slugify } from '../../lib/slugger';
+import { getAiCourseLimitOptions } from '../../queries/ai-course';
+import { billingDetailsOptions } from '../../queries/billing';
+import { roadmapJSONOptions } from '../../queries/roadmap';
+import { roadmapQuestionsOptions } from '../../queries/roadmap-questions';
+import { queryClient } from '../../stores/query-client';
+import { UpgradeAccountModal } from '../Billing/UpgradeAccountModal';
+import { RoadmapAIChatCard } from '../RoadmapAIChat/RoadmapAIChatCard';
+import { CLOSE_TOPIC_DETAIL_EVENT } from '../TopicDetail/TopicDetail';
+import { UpdatePersonaModal } from '../UserPersona/UpdatePersonaModal';
+import { isLoggedIn } from '../../lib/jwt';
+import { showLoginPopup } from '../../lib/popup';
+
+type ChatHeaderButtonProps = {
+ onClick?: () => void;
+ href?: string;
+ icon: React.ReactNode;
+ children?: React.ReactNode;
+ className?: string;
+ target?: string;
+};
+
+function ChatHeaderButton(props: ChatHeaderButtonProps) {
+ const { onClick, href, icon, children, className, target } = props;
+
+ const classNames = cn(
+ 'flex items-center gap-1.5 text-xs text-gray-600 transition-colors hover:text-gray-900',
+ className,
+ );
+
+ if (!onClick && !href) {
+ return (
+
+ {icon}
+ {children && {children}}
+
+ );
+ }
+
+ if (href) {
+ return (
+
+ {icon}
+ {children && {children}}
+
+ );
+ }
+
+ return (
+
+ );
+}
+
+type UpgradeMessageProps = {
+ onUpgradeClick?: () => void;
+};
+
+function UpgradeMessage(props: UpgradeMessageProps) {
+ const { onUpgradeClick } = props;
+
+ return (
+
+
+
+
+
+ You've reached your AI usage limit
+
+
+ Upgrade to Pro for relaxed limits and advanced features
+
+
+
+
+
+ );
+}
+
+type UsageButtonProps = {
+ percentageUsed: number;
+ onUpgradeClick?: () => void;
+};
+
+function UsageButton(props: UsageButtonProps) {
+ const { percentageUsed, onUpgradeClick } = props;
+
+ return (
+