diff --git a/src/blobbi/tour/components/FirstHatchTourCard.tsx b/src/blobbi/tour/components/FirstHatchTourCard.tsx new file mode 100644 index 00000000..b16ce310 --- /dev/null +++ b/src/blobbi/tour/components/FirstHatchTourCard.tsx @@ -0,0 +1,99 @@ +/** + * FirstHatchTourCard - Inline card shown below the egg during the first-hatch tour. + * + * Replaces the modal. Rendered directly in the BlobbiPage layout so the + * experience feels focused and guided rather than interrupted. + */ + +import { Send, Check } from 'lucide-react'; + +import { Button } from '@/components/ui/button'; + +// ─── Types ──────────────────────────────────────────────────────────────────── + +interface FirstHatchTourCardProps { + /** The Blobbi's display name */ + blobbiName: string; + /** The exact phrase the user needs to include in their post */ + requiredPhrase: string; + /** Whether the post mission has been completed */ + postCompleted: boolean; + /** Open the post composer */ + onCreatePost: () => void; + /** Advance the tour (called after post is confirmed complete) */ + onContinue: () => void; +} + +// ─── Component ──────────────────────────────────────────────────────────────── + +export function FirstHatchTourCard({ + blobbiName, + requiredPhrase, + postCompleted, + onCreatePost, + onContinue, +}: FirstHatchTourCardProps) { + const capitalizedName = blobbiName.charAt(0).toUpperCase() + blobbiName.slice(1); + + return ( +
+ {/* Title + description */} +
+

+ {capitalizedName} is ready to hatch! +

+

+ Share a post to the Nostr network and help {capitalizedName} break free. +

+
+ + {/* Mission card */} +
+
+ {/* Status indicator */} +
+ {postCompleted && } +
+ +
+

+ {postCompleted ? 'Post shared!' : 'Share a hatch post'} +

+

+ Your post must include: +

+

+ {requiredPhrase} +

+
+
+ + {!postCompleted && ( + + )} +
+ + {/* Continue or hint */} + {postCompleted ? ( + + ) : ( +

+ You can add extra text before or after the required phrase. +

+ )} +
+ ); +} diff --git a/src/blobbi/tour/index.ts b/src/blobbi/tour/index.ts index 262e8d4b..564b3240 100644 --- a/src/blobbi/tour/index.ts +++ b/src/blobbi/tour/index.ts @@ -43,4 +43,4 @@ export type { } from './hooks/useFirstHatchTourActivation'; // ── First Hatch Tour - Components ── -export { FirstHatchTourModal } from './components/FirstHatchTourModal'; +export { FirstHatchTourCard } from './components/FirstHatchTourCard'; diff --git a/src/pages/BlobbiPage.tsx b/src/pages/BlobbiPage.tsx index 8be277ff..ac9de9ca 100644 --- a/src/pages/BlobbiPage.tsx +++ b/src/pages/BlobbiPage.tsx @@ -90,7 +90,7 @@ import { getActionEmotion, type ActionType } from '@/blobbi/ui/lib/status-reacti import type { BlobbiEmotion } from '@/blobbi/ui/lib/emotions'; import { useQuery } from '@tanstack/react-query'; import { useNostr } from '@nostrify/react'; -import { useFirstHatchTour, useFirstHatchTourActivation, FirstHatchTourModal } from '@/blobbi/tour'; +import { useFirstHatchTour, useFirstHatchTourActivation, FirstHatchTourCard } from '@/blobbi/tour'; import { buildHatchPhrase, isValidHatchPost } from '@/blobbi/actions'; import type { EggTourVisualState } from '@/blobbi/egg'; @@ -946,26 +946,30 @@ function BlobbiDashboard({ // The required phrase for the first-hatch post const firstHatchPhrase = useMemo(() => buildHatchPhrase(companion.name), [companion.name]); - // Auto-advance from idle to egg_ready_hint, then to show_hatch_modal + // Auto-advance from idle -> egg_ready_hint -> show_hatch_modal (inline card) useEffect(() => { if (!isFirstHatchTourActive) return; if (firstHatchTour.isStep('idle')) { - // Advance immediately to egg_ready_hint - firstHatchTour.actions.advance(); + firstHatchTour.actions.advance(); // -> egg_ready_hint } }, [isFirstHatchTourActive, firstHatchTour]); useEffect(() => { if (!isFirstHatchTourActive) return; if (firstHatchTour.isStep('egg_ready_hint')) { - // Show the ready hint briefly, then move to the modal + // Show the ready hint wiggle briefly, then show the inline card const timer = setTimeout(() => { - firstHatchTour.actions.advance(); + firstHatchTour.actions.advance(); // -> show_hatch_modal (inline card step) }, 3000); return () => clearTimeout(timer); } }, [isFirstHatchTourActive, firstHatchTour]); + // Whether the inline first-hatch card should be shown + const showFirstHatchCard = isFirstHatchTourActive && ( + firstHatchTour.isStep('show_hatch_modal') || firstHatchTour.isStep('await_create_post') + ); + // Detect hatch post completion for the first-hatch tour const { user } = useCurrentUser(); const { nostr } = useNostr(); @@ -1419,8 +1423,8 @@ function BlobbiDashboard({ {/* Hero Section */}
- {/* Floating Dashboard Controls */} -