Compare commits

...

20 Commits

Author SHA1 Message Date
Kamran Ahmed
928f99588a Update scripts/generate-renderer.sh 2025-04-04 20:31:43 +01:00
Arik Chakma
8c3d24fdcc fix: update packages 2025-04-05 00:40:46 +06:00
Arik Chakma
ad8ae9e576 Merge branch 'master' into feat/xyflow 2025-04-05 00:29:40 +06:00
Arik Chakma
1cd660405b fix: remove unnecessary files 2025-03-12 18:17:22 +06:00
Arik Chakma
6904c7a86f Merge branch 'master' into feat/xyflow 2025-03-12 18:10:14 +06:00
Arik Chakma
254e6f6501 fix: remove xyflow 2025-03-12 18:04:43 +06:00
Arik Chakma
e8c8110f6e fix: add check pre-commit 2025-03-12 02:25:35 +06:00
Arik Chakma
e5542fa447 fix: try pre-commit 2025-03-12 02:17:17 +06:00
Arik Chakma
18ab8f02aa wip 2025-03-12 02:16:42 +06:00
Arik Chakma
7ec31deee3 wip 2025-03-12 02:00:09 +06:00
Arik Chakma
2855a75b99 wip 2025-03-12 01:08:57 +06:00
Arik Chakma
1a2a636768 wip 2025-03-11 23:39:31 +06:00
Arik Chakma
4edda2b087 wip 2025-03-11 23:09:01 +06:00
Arik Chakma
dd462dd031 fix: remove hacky code 2025-03-10 18:20:51 +06:00
Arik Chakma
efb2268500 wip 2025-03-10 16:36:06 +06:00
Arik Chakma
be6189fefc fix: add additional width 2025-03-10 16:33:11 +06:00
Arik Chakma
21c5b66cf3 fix: update 2025-02-04 12:59:13 +06:00
Arik Chakma
1de802537e fix: update zustand 2024-11-28 22:53:35 +06:00
Arik Chakma
9ea1b9b277 fix: reset the sizes 2024-11-26 21:44:04 +06:00
Arik Chakma
aa40efe278 wip 2024-11-26 15:44:32 +06:00
28 changed files with 1633 additions and 1771 deletions

7
.gitignore vendored
View File

@@ -28,9 +28,4 @@ pnpm-debug.log*
/playwright-report/
/playwright/.cache/
tests-examples
*.csv
/editor/*
!/editor/readonly-editor.tsx
!/editor/renderer/renderer.ts
!/editor/renderer/index.tsx
*.csv

View File

@@ -72,4 +72,9 @@ export default defineConfig({
}),
react(),
],
vite: {
ssr: {
noExternal: [/^@roadmapsh\/editor.*$/],
},
},
});

View File

@@ -1,14 +0,0 @@
export function ReadonlyEditor(props: any) {
return (
<div className="fixed bottom-0 left-0 right-0 top-0 z-[9999] border bg-white p-5 text-black">
<h2 className="mb-2 text-xl font-semibold">Private Component</h2>
<p className="mb-4">
Renderer is a private component. If you are a collaborator and have
access to it. Run the following command:
</p>
<code className="mt-5 rounded-md bg-gray-800 p-2 text-white">
npm run generate-renderer
</code>
</div>
);
}

View File

@@ -1,14 +0,0 @@
export function Renderer(props: any) {
return (
<div className="fixed bottom-0 left-0 right-0 top-0 z-[9999] border bg-white p-5 text-black">
<h2 className="mb-2 text-xl font-semibold">Private Component</h2>
<p className="mb-4">
Renderer is a private component. If you are a collaborator and have
access to it. Run the following command:
</p>
<code className="mt-5 rounded-md bg-gray-800 p-2 text-white">
npm run generate-renderer
</code>
</div>
);
}

View File

@@ -1,5 +0,0 @@
export function renderFlowJSON(data: any, options?: any) {
console.warn("renderFlowJSON is not implemented");
console.warn("run the following command to generate the renderer:");
console.warn("> npm run generate-renderer");
}

View File

@@ -26,6 +26,7 @@
"warm:urls": "sh ./scripts/warm-urls.sh https://roadmap.sh/sitemap-0.xml",
"compress:images": "tsx ./scripts/compress-images.ts",
"generate:roadmap-content-json": "tsx ./scripts/editor-roadmap-content-json.ts",
"migrate:editor-roadmaps": "tsx ./scripts/migrate-editor-roadmap.ts",
"test:e2e": "playwright test"
},
"dependencies": {
@@ -38,6 +39,7 @@
"@nanostores/react": "^0.8.0",
"@napi-rs/image": "^1.9.2",
"@resvg/resvg-js": "^2.6.2",
"@roadmapsh/editor": "npm:@roadmapsh/dummy-editor@^0.0.5",
"@tanstack/react-query": "^5.59.16",
"@types/react": "^18.3.11",
"@types/react-dom": "^18.3.1",
@@ -67,7 +69,6 @@
"react-resizable-panels": "^2.1.7",
"react-textarea-autosize": "^8.5.7",
"react-tooltip": "^5.28.0",
"reactflow": "^11.11.4",
"rehype-external-links": "^3.0.0",
"remark-parse": "^11.0.0",
"roadmap-renderer": "^1.0.6",
@@ -82,7 +83,7 @@
"tiptap-markdown": "^0.8.10",
"turndown": "^7.2.0",
"unified": "^11.0.5",
"zustand": "^4.5.5"
"zustand": "^5.0.1"
},
"devDependencies": {
"@ai-sdk/google": "^1.1.19",

3138
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,14 +0,0 @@
export function Renderer(props: any) {
return (
<div className="fixed bottom-0 left-0 right-0 top-0 z-[9999] border bg-white p-5 text-black">
<h2 className="mb-2 text-xl font-semibold">Private Component</h2>
<p className="mb-4">
Renderer is a private component. If you are a collaborator and have
access to it. Run the following command:
</p>
<code className="mt-5 rounded-md bg-gray-800 p-2 text-white">
npm run generate-renderer
</code>
</div>
);
}

View File

@@ -1,5 +0,0 @@
export function renderFlowJSON(data: any, options?: any) {
console.warn("renderFlowJSON is not implemented");
console.warn("run the following command to generate the renderer:");
console.warn("> npm run generate-renderer");
}

View File

@@ -1,7 +1,7 @@
import fs from 'node:fs/promises';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import type { Node } from 'reactflow';
import type { Node } from '@roadmapsh/editor';
import matter from 'gray-matter';
import type { RoadmapFrontmatter } from '../src/lib/roadmap';
import { slugify } from '../src/lib/slugger';

View File

@@ -1,7 +1,7 @@
import fs from 'node:fs/promises';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import type { Edge, Node } from 'reactflow';
import type { Edge, Node } from '@roadmapsh/editor';
import matter from 'gray-matter';
import type { RoadmapFrontmatter } from '../src/lib/roadmap';
import { slugify } from '../src/lib/slugger';

View File

@@ -1,7 +1,7 @@
import fs from 'node:fs/promises';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import type { Node } from 'reactflow';
import type { Node } from '@roadmapsh/editor';
import matter from 'gray-matter';
import type { RoadmapFrontmatter } from '../src/lib/roadmap';
import { slugify } from '../src/lib/slugger';

View File

@@ -2,33 +2,10 @@
set -e
# ignore cloning if .temp/web-draw already exists
if [ ! -d ".temp/web-draw" ]; then
mkdir -p .temp
git clone git@github.com:roadmapsh/web-draw.git .temp/web-draw
fi
# Fetch the latest commit hash from the GitHub repo
LATEST_COMMIT_HASH=$(git ls-remote https://github.com/roadmapsh/web-draw-v2.git refs/heads/main | awk '{print $1}')
rm -rf editor
mkdir editor
echo "Latest commit hash: $LATEST_COMMIT_HASH"
# copy the files at /src/editor/* to /editor
# while replacing any existing files
cp -rf .temp/web-draw/src/editor/* editor
# Add @ts-nocheck to the top of each ts and tsx file
# so that the typescript compiler doesn't complain
# about the missing types
find editor -type f \( -name "*.ts" -o -name "*.tsx" \) -print0 | while IFS= read -r -d '' file; do
if [ -f "$file" ]; then
echo "// @ts-nocheck" > temp
cat "$file" >> temp
mv temp "$file"
echo "Added @ts-nocheck to $file"
fi
done
# ignore the worktree changes for the editor directory
git update-index --assume-unchanged editor/readonly-editor.tsx || true
git update-index --assume-unchanged editor/renderer/index.tsx || true
git update-index --assume-unchanged editor/renderer/renderer.ts || true
# Install the package using the latest commit hash
pnpm add github:roadmapsh/web-draw#"$LATEST_COMMIT_HASH"\&path:packages/editor

View File

@@ -0,0 +1,76 @@
import fs from 'node:fs/promises';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import type { Node } from '@roadmapsh/editor';
import matter from 'gray-matter';
import type { RoadmapFrontmatter } from '../src/lib/roadmap';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// Directory containing the roadmaps
const ROADMAP_CONTENT_DIR = path.join(__dirname, '../src/data/roadmaps');
const allRoadmaps = await fs.readdir(ROADMAP_CONTENT_DIR);
const editorRoadmapIds = new Set<string>();
for (const roadmapId of allRoadmaps) {
const roadmapFrontmatterDir = path.join(
ROADMAP_CONTENT_DIR,
roadmapId,
`${roadmapId}.md`,
);
const roadmapFrontmatterRaw = await fs.readFile(
roadmapFrontmatterDir,
'utf-8',
);
const { data } = matter(roadmapFrontmatterRaw);
const roadmapFrontmatter = data as RoadmapFrontmatter;
if (roadmapFrontmatter.renderer === 'editor') {
editorRoadmapIds.add(roadmapId);
}
}
for (const roadmapId of editorRoadmapIds) {
const roadmapJSONDir = path.join(
ROADMAP_CONTENT_DIR,
roadmapId,
`${roadmapId}.json`,
);
const roadmapJSONRaw = await fs.readFile(roadmapJSONDir, 'utf-8');
const roadmapJSON = JSON.parse(roadmapJSONRaw);
const roadmapNodes = roadmapJSON.nodes as Node[];
const updatedNodes = roadmapNodes.map((node) => {
const width = +(node?.width || node?.style?.width || 0);
const height = +(node?.height || node?.style?.height || 0);
const ADDITIONAL_WIDTH = 1;
// adding one `1px` in width to avoid the node to be cut in half
// this is a quick fix to avoid the issue
if (node?.style?.width) {
node.style.width = width + ADDITIONAL_WIDTH;
}
if (node?.width) {
node.width = width + ADDITIONAL_WIDTH;
}
return {
...node,
measured: {
width: width + ADDITIONAL_WIDTH,
height,
},
};
});
const updatedRoadmapJSON = {
...roadmapJSON,
nodes: updatedNodes,
};
const updatedRoadmapJSONString = JSON.stringify(updatedRoadmapJSON, null, 2);
await fs.writeFile(roadmapJSONDir, updatedRoadmapJSONString, 'utf-8');
}

View File

@@ -1,4 +1,4 @@
import { ReadonlyEditor } from '../../../editor/readonly-editor';
import { ReadonlyEditor } from '@roadmapsh/editor';
import type { RoadmapDocument } from './CreateRoadmap/CreateRoadmapModal';
import {
refreshProgressCounters,
@@ -9,7 +9,7 @@ import {
} from '../../lib/resource-progress';
import { pageProgressMessage } from '../../stores/page';
import { useToast } from '../../hooks/use-toast';
import type { Node } from 'reactflow';
import type { Node } from '@roadmapsh/editor';
import { type MouseEvent, useCallback, useRef, useState } from 'react';
import { EmptyRoadmap } from './EmptyRoadmap';
import { cn } from '../../lib/classname';

View File

@@ -1,6 +1,5 @@
import { useStore } from '@nanostores/react';
import { useEffect, useState } from 'react';
import { cn } from '../../../editor/utils/classname';
import { useParams } from '../../hooks/use-params';
import { useToast } from '../../hooks/use-toast';
import { httpGet } from '../../lib/http';
@@ -13,6 +12,7 @@ import { TeamDashboard } from './TeamDashboard';
import type { QuestionGroupType } from '../../lib/question-group';
import type { GuideFileType } from '../../lib/guide';
import type { VideoFileType } from '../../lib/video';
import { cn } from '../../lib/classname';
type DashboardPageProps = {
builtInRoleRoadmaps?: BuiltInRoadmap[];

View File

@@ -11,8 +11,6 @@ import {
import { httpGet } from '../../lib/http';
import { ProgressNudge } from '../FrameRenderer/ProgressNudge';
import { getUrlParams } from '../../lib/browser.ts';
import { cn } from '../../lib/classname.ts';
import { getUser } from '../../lib/jwt.ts';
type EditorRoadmapProps = {
resourceId: string;

View File

@@ -1,5 +1,6 @@
import { useCallback, useEffect, useRef } from 'react';
import './EditorRoadmapRenderer.css';
import { lazy, useCallback, useEffect, useRef } from 'react';
import {
renderResourceProgress,
updateResourceProgress,
@@ -9,12 +10,17 @@ import {
} from '../../lib/resource-progress';
import { pageProgressMessage } from '../../stores/page';
import { useToast } from '../../hooks/use-toast';
import type { Edge, Node } from 'reactflow';
import { Renderer } from '../../../editor/renderer';
import type { Edge, Node } from '@roadmapsh/editor';
import { slugify } from '../../lib/slugger';
import { isLoggedIn } from '../../lib/jwt';
import { showLoginPopup } from '../../lib/popup';
const Renderer = lazy(() =>
import('@roadmapsh/editor').then((mod) => ({
default: mod.Renderer,
})),
);
export type RoadmapRendererProps = {
resourceId: string;
nodes: Node[];

View File

@@ -1,6 +1,6 @@
import '../GenerateRoadmap/GenerateRoadmap.css';
import { renderFlowJSON } from '../../../editor/renderer/renderer';
import { generateAIRoadmapFromText } from '../../../editor/utils/roadmap-generator';
import { renderFlowJSON } from '@roadmapsh/editor';
import { generateAIRoadmapFromText } from '@roadmapsh/editor';
import {
generateAICourseRoadmapStructure,
readAIRoadmapStream,

View File

@@ -1,3 +1,5 @@
import './GenerateRoadmap.css';
import {
type FormEvent,
type MouseEvent,
@@ -6,10 +8,8 @@ import {
useRef,
useState,
} from 'react';
import './GenerateRoadmap.css';
import { useToast } from '../../hooks/use-toast';
import { generateAIRoadmapFromText } from '../../../editor/utils/roadmap-generator';
import { renderFlowJSON } from '../../../editor/renderer/renderer';
import { generateAIRoadmapFromText, renderFlowJSON } from '@roadmapsh/editor';
import { replaceChildren } from '../../lib/dom';
import {
isLoggedIn,
@@ -278,6 +278,10 @@ export function GenerateRoadmap(props: GenerateRoadmapProps) {
width: undefined,
height: undefined,
},
measured: {
width: undefined,
height: undefined,
},
})),
edges,
},

View File

@@ -1,7 +1,7 @@
import { ChevronDownIcon, StarIcon, User2Icon } from 'lucide-react';
import { useState } from 'react';
import { cn } from '../../../editor/utils/classname';
import { markdownToHtml } from '../../lib/markdown';
import { cn } from '../../lib/classname';
type Review = {
name: string;

View File

@@ -1,3 +1,4 @@
import '../FrameRenderer/FrameRenderer.css';
import {
useCallback,
useEffect,
@@ -6,7 +7,6 @@ import {
useRef,
} from 'react';
import { Spinner } from '../ReactIcons/Spinner';
import '../FrameRenderer/FrameRenderer.css';
import type { TeamMember } from './TeamProgressPage';
import { httpGet } from '../../lib/http';
import {
@@ -15,13 +15,12 @@ import {
type ResourceType,
updateResourceProgress,
} from '../../lib/resource-progress';
import CloseIcon from '../../icons/close.svg';
import { useToast } from '../../hooks/use-toast';
import { useAuth } from '../../hooks/use-auth';
import { pageProgressMessage } from '../../stores/page';
import type { GetRoadmapResponse } from '../CustomRoadmap/CustomRoadmap';
import { ReadonlyEditor } from '../../../editor/readonly-editor';
import type { Node } from 'reactflow';
import { ReadonlyEditor } from '@roadmapsh/editor';
import type { Node } from '@roadmapsh/editor';
import { useKeydown } from '../../hooks/use-keydown';
import { useOutsideClick } from '../../hooks/use-outside-click';
import { MemberProgressModalHeader } from './MemberProgressModalHeader';

View File

@@ -20,7 +20,7 @@ import { MemberProgressModalHeader } from './MemberProgressModalHeader';
import { replaceChildren } from '../../lib/dom.ts';
import { XIcon } from 'lucide-react';
import type { PageType } from '../CommandMenu/CommandMenu.tsx';
import { renderFlowJSON } from '../../../editor/renderer/renderer.ts';
import { renderFlowJSON } from '@roadmapsh/editor';
import { getResourceMeta } from '../../lib/roadmap.ts';
export type ProgressMapProps = {

View File

@@ -1,4 +1,4 @@
import { useEffect, useMemo, useRef, useState, type RefObject } from 'react';
import { useEffect, useRef, useState } from 'react';
import { useOutsideClick } from '../../hooks/use-outside-click';
import { useKeydown } from '../../hooks/use-keydown';
import { httpGet } from '../../lib/http';
@@ -7,7 +7,7 @@ import { topicSelectorAll } from '../../lib/resource-progress';
import { deleteUrlParam, getUrlParams } from '../../lib/browser';
import { useAuth } from '../../hooks/use-auth';
import type { GetRoadmapResponse } from '../CustomRoadmap/CustomRoadmap';
import { ReadonlyEditor } from '../../../editor/readonly-editor';
import { ReadonlyEditor } from '@roadmapsh/editor';
import { ModalLoader } from './ModalLoader.tsx';
import { UserProgressModalHeader } from './UserProgressModalHeader';
import { X } from 'lucide-react';
@@ -173,7 +173,7 @@ export function UserCustomProgressModal(props: ProgressMapProps) {
variant="modal"
roadmap={roadmap!}
className="min-h-[400px]"
onRendered={(wrapperRef: RefObject<HTMLDivElement>) => {
onRendered={(wrapperRef) => {
const {
done = [],
learning = [],

View File

@@ -12,7 +12,7 @@ import { ModalLoader } from './ModalLoader.tsx';
import { UserProgressModalHeader } from './UserProgressModalHeader';
import { X } from 'lucide-react';
import type { AllowedRoadmapRenderer } from '../../lib/roadmap.ts';
import { renderFlowJSON } from '../../../editor/renderer/renderer.ts';
import { renderFlowJSON } from '@roadmapsh/editor';
export type ProgressMapProps = {
userId?: string;

View File

@@ -8,7 +8,7 @@ import {
import { useToast } from '../../hooks/use-toast';
import { replaceChildren } from '../../lib/dom.ts';
import type { GetUserProfileRoadmapResponse } from '../../api/user.ts';
import { ReadonlyEditor } from '../../../editor/readonly-editor.tsx';
import { ReadonlyEditor } from '@roadmapsh/editor';
import { cn } from '../../lib/classname.ts';
export type UserProfileRoadmapRendererProps = GetUserProfileRoadmapResponse & {
@@ -96,7 +96,7 @@ export function UserProfileRoadmapRenderer(
edges,
}}
className="min-h-[1000px]"
onRendered={(wrapperRef: RefObject<HTMLDivElement>) => {
onRendered={(wrapperRef) => {
done?.forEach((topicId: string) => {
topicSelectorAll(topicId, wrapperRef?.current!).forEach(
(el) => {

View File

@@ -1,4 +1,6 @@
---
import '../styles/global.css';
import Analytics from '../components/Analytics/Analytics.astro';
import LoginPopup from '../components/AuthenticationFlow/LoginPopup.astro';
import Authenticator from '../components/Authenticator/Authenticator.astro';
@@ -10,9 +12,9 @@ import { PageProgress } from '../components/PageProgress';
import { Toaster } from '../components/Toast';
import { PageSponsors } from '../components/PageSponsors/PageSponsors';
import { siteConfig } from '../lib/config';
import '../styles/global.css';
import { PageVisit } from '../components/PageVisit/PageVisit';
import type { ResourceType } from '../lib/resource-progress';
import ChangelogBanner from '../components/ChangelogBanner.astro';
import Clarity from '../components/Analytics/Clarity.astro';
import RedditPixel from '../components/Analytics/RedditPixel.astro';
import GoogleAd from '../components/Analytics/GoogleAd.astro';

View File

@@ -1,7 +1,28 @@
@import '@roadmapsh/editor/style.css';
@tailwind base;
@tailwind components;
@tailwind utilities;
/*
The default border color has changed to `currentColor` in Tailwind CSS v4,
so we've added these compatibility styles to make sure everything still
looks the same as it did with Tailwind CSS v3.
If we ever want to remove these styles, we need to add an explicit border
color utility to any element that depends on these defaults.
*/
@layer base {
*,
::after,
::before,
::backdrop,
::file-selector-button {
--color-gray-200: oklch(0.928 0.006 264.531);
border-color: var(--color-gray-200, currentColor);
}
}
@layer components {
.container {
@apply mx-auto !max-w-[830px] px-4;