|
|
|
@ -8,24 +8,43 @@ import { |
|
|
|
|
import { useRef, useState } from 'react'; |
|
|
|
|
import { useOutsideClick } from '../hooks/use-outside-click'; |
|
|
|
|
import { markdownToHtml } from '../lib/markdown'; |
|
|
|
|
import { cn } from '../lib/classname'; |
|
|
|
|
import { useScrollPosition } from '../hooks/use-scroll-position'; |
|
|
|
|
|
|
|
|
|
type RoadmapTitleQuestionProps = { |
|
|
|
|
question: string; |
|
|
|
|
answer: string; |
|
|
|
|
roadmapId?: string; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
export function RoadmapTitleQuestion(props: RoadmapTitleQuestionProps) { |
|
|
|
|
const { question, answer } = props; |
|
|
|
|
const { question, answer, roadmapId } = props; |
|
|
|
|
|
|
|
|
|
const [isAnswerVisible, setIsAnswerVisible] = useState(false); |
|
|
|
|
const ref = useRef<HTMLDivElement>(null); |
|
|
|
|
const h2Ref = useRef<HTMLHeadingElement>(null); |
|
|
|
|
|
|
|
|
|
useOutsideClick(ref, () => { |
|
|
|
|
setIsAnswerVisible(false); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
const { y: scrollY } = useScrollPosition(); |
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
|
<div className="relative hidden rounded-b-[5px] border-t bg-white text-sm font-medium hover:bg-gray-50 sm:block"> |
|
|
|
|
<div |
|
|
|
|
className={cn( |
|
|
|
|
'relative hidden rounded-b-[5px] border-t bg-white text-sm font-medium hover:bg-gray-50 sm:block', |
|
|
|
|
{ |
|
|
|
|
'rounded-0 -mx-4 sm:mx-0': isAnswerVisible, |
|
|
|
|
// @FIXME:
|
|
|
|
|
// The line below is to keep the question hidden on mobile devices except for
|
|
|
|
|
// the frontend roadmap. This is because we did not use to have the question
|
|
|
|
|
// on mobile devices before and we don't want to cause any SEO issues. It will
|
|
|
|
|
// be enabled on other roadmaps in the future.
|
|
|
|
|
block: roadmapId === 'frontend', |
|
|
|
|
}, |
|
|
|
|
)} |
|
|
|
|
> |
|
|
|
|
{isAnswerVisible && ( |
|
|
|
|
<div className="fixed left-0 right-0 top-0 z-[100] h-full items-center justify-center overflow-y-auto overflow-x-hidden overscroll-contain bg-black/50"></div> |
|
|
|
|
)} |
|
|
|
@ -47,15 +66,25 @@ export function RoadmapTitleQuestion(props: RoadmapTitleQuestionProps) { |
|
|
|
|
</h2> |
|
|
|
|
|
|
|
|
|
<div |
|
|
|
|
className={`absolute left-0 right-0 top-0 z-[100] mt-0 rounded-md border bg-white ${ |
|
|
|
|
isAnswerVisible ? 'block' : 'hidden' |
|
|
|
|
className={`absolute left-0 right-0 top-0 z-[100] mt-0 border bg-white ${ |
|
|
|
|
isAnswerVisible ? 'rounded-0 block sm:rounded-md' : 'hidden' |
|
|
|
|
}`}
|
|
|
|
|
ref={ref} |
|
|
|
|
> |
|
|
|
|
{isAnswerVisible && ( |
|
|
|
|
<h2 |
|
|
|
|
className="flex cursor-pointer select-none items-center border-b px-[7px] py-[9px] text-base font-medium" |
|
|
|
|
onClick={() => setIsAnswerVisible(false)} |
|
|
|
|
className={cn( |
|
|
|
|
'sticky top-0 flex cursor-pointer select-none items-center rounded-t-md border-b bg-white px-[7px] py-[9px] text-base font-medium', |
|
|
|
|
)} |
|
|
|
|
onClick={() => { |
|
|
|
|
setIsAnswerVisible(false); |
|
|
|
|
if ( |
|
|
|
|
scrollY > (h2Ref?.current?.getBoundingClientRect().top || 0) |
|
|
|
|
) { |
|
|
|
|
ref.current?.scrollIntoView(); |
|
|
|
|
} |
|
|
|
|
}} |
|
|
|
|
ref={h2Ref} |
|
|
|
|
> |
|
|
|
|
<span className="flex flex-grow items-center"> |
|
|
|
|
<Info className="mr-2 inline-block h-4 w-4" strokeWidth={2.5} /> |
|
|
|
@ -67,7 +96,7 @@ export function RoadmapTitleQuestion(props: RoadmapTitleQuestionProps) { |
|
|
|
|
</h2> |
|
|
|
|
)} |
|
|
|
|
<div |
|
|
|
|
className="bg-gray-100 p-3 text-base [&>h2]:mb-2 [&>h2]:mt-5 [&>h2]:text-[17px] [&>h2]:font-medium [&>p:last-child]:mb-0 [&>p>a]:font-semibold [&>p>a]:underline [&>p>a]:underline-offset-2 [&>p]:mb-3 [&>p]:font-normal [&>p]:leading-relaxed [&>p]:text-gray-800" |
|
|
|
|
className="bg-gray-100 p-3 text-base [&>h2]:mb-2 [&>h2]:mt-5 [&>h2]:text-[17px] [&>h2]:font-medium [&>p:last-child]:mb-0 [&>p>a]:font-semibold [&>p>a]:underline [&>p>a]:underline-offset-2 [&>p]:mb-3 [&>p]:font-normal [&>p]:leading-relaxed [&>p]:text-gray-800 [&>ul>li]:mb-2 [&>ul>li]:font-normal" |
|
|
|
|
dangerouslySetInnerHTML={{ __html: markdownToHtml(answer, false) }} |
|
|
|
|
></div> |
|
|
|
|
</div> |
|
|
|
|