mirror of
https://github.com/kamranahmedse/developer-roadmap.git
synced 2025-08-01 06:50:26 +02:00
Allow embedding of roadmaps
This commit is contained in:
@@ -53,14 +53,20 @@ export type GetRoadmapResponse = RoadmapDocument & {
|
||||
|
||||
export function hideRoadmapLoader() {
|
||||
const loaderEl = document.querySelector(
|
||||
'[data-roadmap-loader]'
|
||||
'[data-roadmap-loader]',
|
||||
) as HTMLElement;
|
||||
if (loaderEl) {
|
||||
loaderEl.remove();
|
||||
}
|
||||
}
|
||||
|
||||
export function CustomRoadmap() {
|
||||
type CustomRoadmapProps = {
|
||||
isEmbed?: boolean;
|
||||
};
|
||||
|
||||
export function CustomRoadmap(props: CustomRoadmapProps) {
|
||||
const { isEmbed = false } = props;
|
||||
|
||||
const { id, secret } = getUrlParams() as { id: string; secret: string };
|
||||
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
@@ -71,14 +77,15 @@ export function CustomRoadmap() {
|
||||
setIsLoading(true);
|
||||
|
||||
const roadmapUrl = new URL(
|
||||
`${import.meta.env.PUBLIC_API_URL}/v1-get-roadmap/${id}`
|
||||
`${import.meta.env.PUBLIC_API_URL}/v1-get-roadmap/${id}`,
|
||||
);
|
||||
|
||||
if (secret) {
|
||||
roadmapUrl.searchParams.set('secret', secret);
|
||||
}
|
||||
|
||||
const { response, error } = await httpGet<GetRoadmapResponse>(
|
||||
roadmapUrl.toString()
|
||||
roadmapUrl.toString(),
|
||||
);
|
||||
|
||||
if (error || !response) {
|
||||
@@ -95,7 +102,10 @@ export function CustomRoadmap() {
|
||||
}
|
||||
|
||||
async function trackVisit() {
|
||||
if (!isLoggedIn()) return;
|
||||
if (!isLoggedIn() || isEmbed) {
|
||||
return;
|
||||
}
|
||||
|
||||
await httpPost(`${import.meta.env.PUBLIC_API_URL}/v1-visit`, {
|
||||
resourceId: id,
|
||||
resourceType: 'roadmap',
|
||||
@@ -119,9 +129,9 @@ export function CustomRoadmap() {
|
||||
|
||||
return (
|
||||
<>
|
||||
<RoadmapHeader />
|
||||
<FlowRoadmapRenderer roadmap={roadmap!} />
|
||||
<TopicDetail canSubmitContribution={false} />
|
||||
{!isEmbed && <RoadmapHeader />}
|
||||
<FlowRoadmapRenderer isEmbed={isEmbed} roadmap={roadmap!} />
|
||||
<TopicDetail isEmbed={isEmbed} canSubmitContribution={false} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@@ -1,26 +1,27 @@
|
||||
import { ReadonlyEditor } from '../../../editor/readonly-editor';
|
||||
import type { RoadmapDocument } from './CreateRoadmap/CreateRoadmapModal';
|
||||
import {
|
||||
renderResourceProgress,
|
||||
updateResourceProgress,
|
||||
type ResourceProgressType,
|
||||
renderTopicProgress,
|
||||
refreshProgressCounters,
|
||||
renderResourceProgress,
|
||||
renderTopicProgress,
|
||||
type ResourceProgressType,
|
||||
updateResourceProgress,
|
||||
} from '../../lib/resource-progress';
|
||||
import { pageProgressMessage } from '../../stores/page';
|
||||
import { useToast } from '../../hooks/use-toast';
|
||||
import type { Node } from 'reactflow';
|
||||
import { useCallback, type MouseEvent, useMemo, useState, useRef } from 'react';
|
||||
import { type MouseEvent, useCallback, useRef, useState } from 'react';
|
||||
import { EmptyRoadmap } from './EmptyRoadmap';
|
||||
import { cn } from '../../lib/classname';
|
||||
import { totalRoadmapNodes } from '../../stores/roadmap.ts';
|
||||
|
||||
type FlowRoadmapRendererProps = {
|
||||
isEmbed?: boolean;
|
||||
roadmap: RoadmapDocument;
|
||||
};
|
||||
|
||||
export function FlowRoadmapRenderer(props: FlowRoadmapRendererProps) {
|
||||
const { roadmap } = props;
|
||||
const { roadmap, isEmbed = false } = props;
|
||||
const roadmapId = String(roadmap._id!);
|
||||
|
||||
const [hideRenderer, setHideRenderer] = useState(false);
|
||||
@@ -32,6 +33,10 @@ export function FlowRoadmapRenderer(props: FlowRoadmapRendererProps) {
|
||||
topicId: string,
|
||||
newStatus: ResourceProgressType,
|
||||
) {
|
||||
if (isEmbed) {
|
||||
return;
|
||||
}
|
||||
|
||||
pageProgressMessage.set('Updating progress');
|
||||
updateResourceProgress(
|
||||
{
|
||||
|
@@ -29,6 +29,7 @@ import { Spinner } from '../ReactIcons/Spinner';
|
||||
import { GitHubIcon } from '../ReactIcons/GitHubIcon.tsx';
|
||||
|
||||
type TopicDetailProps = {
|
||||
isEmbed?: boolean;
|
||||
canSubmitContribution: boolean;
|
||||
};
|
||||
|
||||
@@ -42,7 +43,7 @@ const linkTypes: Record<AllowedLinkTypes, string> = {
|
||||
};
|
||||
|
||||
export function TopicDetail(props: TopicDetailProps) {
|
||||
const { canSubmitContribution } = props;
|
||||
const { canSubmitContribution, isEmbed = false } = props;
|
||||
|
||||
const [hasEnoughLinks, setHasEnoughLinks] = useState(false);
|
||||
const [contributionUrl, setContributionUrl] = useState('');
|
||||
@@ -163,9 +164,9 @@ export function TopicDetail(props: TopicDetailProps) {
|
||||
);
|
||||
|
||||
const links = topicDom.querySelectorAll('a');
|
||||
const contributionUrl =
|
||||
topicDom.querySelector('[data-github-url]')?.dataset?.githubUrl ||
|
||||
'';
|
||||
const urlElem: HTMLElement =
|
||||
topicDom.querySelector('[data-github-url]')!;
|
||||
const contributionUrl = urlElem?.dataset?.githubUrl || '';
|
||||
|
||||
setContributionUrl(contributionUrl);
|
||||
setHasEnoughLinks(links.length >= 3);
|
||||
@@ -218,14 +219,16 @@ export function TopicDetail(props: TopicDetailProps) {
|
||||
<>
|
||||
{/* Actions for the topic */}
|
||||
<div className="mb-2">
|
||||
<TopicProgressButton
|
||||
topicId={topicId}
|
||||
resourceId={resourceId}
|
||||
resourceType={resourceType}
|
||||
onClose={() => {
|
||||
setIsActive(false);
|
||||
}}
|
||||
/>
|
||||
{!isEmbed && (
|
||||
<TopicProgressButton
|
||||
topicId={topicId}
|
||||
resourceId={resourceId}
|
||||
resourceType={resourceType}
|
||||
onClose={() => {
|
||||
setIsActive(false);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
<button
|
||||
type="button"
|
||||
|
29
src/pages/r/embed.astro
Normal file
29
src/pages/r/embed.astro
Normal file
@@ -0,0 +1,29 @@
|
||||
---
|
||||
import BaseLayout from '../../layouts/BaseLayout.astro';
|
||||
import { CustomRoadmap } from '../../components/CustomRoadmap/CustomRoadmap';
|
||||
import { SkeletonRoadmapHeader } from '../../components/CustomRoadmap/SkeletonRoadmapHeader';
|
||||
import Loader from '../../components/Loader.astro';
|
||||
import ProgressHelpPopup from '../../components/ProgressHelpPopup.astro';
|
||||
import SkeletonLayout from '../../layouts/SkeletonLayout.astro';
|
||||
---
|
||||
|
||||
<SkeletonLayout title='Roadmaps' noIndex={true}>
|
||||
<div class='relative flex min-h-[550px] flex-col'>
|
||||
<div data-roadmap-loader class='flex w-full grow flex-col'>
|
||||
<div class='flex grow items-center justify-center'>
|
||||
<Loader />
|
||||
</div>
|
||||
</div>
|
||||
<CustomRoadmap isEmbed={true} client:only='react' />
|
||||
|
||||
<div class='fixed bottom-5 right-4'>
|
||||
<a
|
||||
target='_blank'
|
||||
class='rounded-md bg-gray-600 p-2 text-white hover:bg-black'
|
||||
href='https://roadmap.sh'
|
||||
>
|
||||
roadmap.sh
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</SkeletonLayout>
|
Reference in New Issue
Block a user