diff --git a/app/web/config/webpack.config.js b/app/web/config/webpack.config.js
index 5f8af79..08dcbd9 100644
--- a/app/web/config/webpack.config.js
+++ b/app/web/config/webpack.config.js
@@ -5,5 +5,9 @@ module.exports = (config, { env }) => {
plugin.userOptions.favicon = './src/favicon.svg'
}
})
+ config.module.rules.push({
+ test: /\.md$|\.jscad$|\.py$|\.SCAD$/i,
+ use: 'raw-loader',
+ });
return config
}
diff --git a/app/web/package.json b/app/web/package.json
index d3f435e..1dd0060 100644
--- a/app/web/package.json
+++ b/app/web/package.json
@@ -58,6 +58,7 @@
"postcss": "^8.3.6",
"postcss-import": "^14.0.2",
"postcss-loader": "^6.1.1",
+ "raw-loader": "^4.0.2",
"tailwindcss": "^2.2.7"
}
}
diff --git a/app/web/src/components/CadPackage/CadPackage.tsx b/app/web/src/components/CadPackage/CadPackage.tsx
index fa3aa82..e339995 100644
--- a/app/web/src/components/CadPackage/CadPackage.tsx
+++ b/app/web/src/components/CadPackage/CadPackage.tsx
@@ -1,43 +1,63 @@
-export type CadPackageType = 'openscad' | 'cadquery' | 'jscad'
+export type CadPackageType = 'openscad' | 'cadquery' | 'jscad' | 'INIT'
-export const ideTypeNameMap: { [key in CadPackageType]: string } = {
- openscad: 'OpenSCAD',
- cadquery: 'CadQuery',
- jscad: 'JSCAD',
+interface CadPackageConfig {
+ label: string
+ buttonClasses: string
+ dotClasses: string
}
+export const cadPackageConfigs: { [key in CadPackageType]: CadPackageConfig } =
+ {
+ openscad: {
+ label: 'OpenSCAD',
+ buttonClasses: 'bg-yellow-800',
+ dotClasses: 'bg-yellow-200',
+ },
+ cadquery: {
+ label: 'CadQuery',
+ buttonClasses: 'bg-ch-blue-700',
+ dotClasses: 'bg-blue-800',
+ },
+ jscad: {
+ label: 'JSCAD',
+ buttonClasses: 'bg-ch-purple-500',
+ dotClasses: 'bg-yellow-300',
+ },
+ INIT: {
+ label: '',
+ buttonClasses: '',
+ dotClasses: '',
+ },
+ }
+
interface CadPackageProps {
cadPackage: CadPackageType
className?: string
dotClass?: string
+ onClick?: any
}
const CadPackage = ({
cadPackage,
className = '',
dotClass = 'w-5 h-5',
+ onClick,
}: CadPackageProps) => {
- const cadName = ideTypeNameMap[cadPackage] || ''
- const isOpenScad = cadPackage === 'openscad'
- const isCadQuery = cadPackage === 'cadquery'
- const isJsCad = cadPackage === 'jscad'
+ const cadPackageConfig = cadPackageConfigs[cadPackage]
+
return (
-
+ {cadPackageConfig.label}
+
)
}
diff --git a/app/web/src/components/EditorGuide/EditorGuide.tsx b/app/web/src/components/EditorGuide/EditorGuide.tsx
new file mode 100644
index 0000000..a5f53a6
--- /dev/null
+++ b/app/web/src/components/EditorGuide/EditorGuide.tsx
@@ -0,0 +1,53 @@
+import { extractMetaData } from 'src/helpers/markdown'
+import Editor from 'rich-markdown-editor'
+import { useRef } from 'react'
+import KeyValue from 'src/components/KeyValue/KeyValue'
+
+export default function EditorGuide({ content }) {
+ const [rawMetadata, metadata] = extractMetaData(content)
+
+ const processedContent = rawMetadata
+ ? content.replace(rawMetadata[0], '')
+ : content
+ const ref = useRef(null)
+
+ return (
+
+ {metadata && (
+ <>
+
{metadata.title}
+
+ {Object.entries(metadata)
+ .filter(([key]) => key !== 'title')
+ .map(([key, value], i) => (
+
+ {value}
+
+ ))}
+
+ >
+ )}
+ {}}
+ />
+
+ )
+}
+
+function LinkOrParagraph({ children }) {
+ const markdownUrlExpression =
+ /\[(.*)\]\((https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|www\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9]+\.[^\s]{2,}|www\.[a-zA-Z0-9]+\.[^\s]{2,})\)/i
+ const matches = children.match(markdownUrlExpression)
+
+ return matches === null ? (
+ {children}
+ ) : (
+
+ {matches[1]}
+
+ )
+}
diff --git a/app/web/src/components/EditorMenu/EditorMenu.tsx b/app/web/src/components/EditorMenu/EditorMenu.tsx
index 9ef9456..33c0517 100644
--- a/app/web/src/components/EditorMenu/EditorMenu.tsx
+++ b/app/web/src/components/EditorMenu/EditorMenu.tsx
@@ -48,7 +48,24 @@ const EditorMenu = () => {
-
+ {
+ thunkDispatch({
+ type: 'addEditorModel',
+ payload: {
+ type: 'guide',
+ label: 'Guide',
+ content: state.ideGuide,
+ },
+ })
+ thunkDispatch({
+ type: 'switchEditorModel',
+ payload: state.models.length,
+ })
+ }}
+ />
>
diff --git a/app/web/src/components/EncodedUrl/ExternalScript.tsx b/app/web/src/components/EncodedUrl/ExternalScript.tsx
index 99687dd..db152a4 100644
--- a/app/web/src/components/EncodedUrl/ExternalScript.tsx
+++ b/app/web/src/components/EncodedUrl/ExternalScript.tsx
@@ -1,6 +1,6 @@
import { useState } from 'react'
import { useIdeContext } from 'src/helpers/hooks/useIdeContext'
-import { ideTypeNameMap } from 'src/components/CadPackage/CadPackage'
+import { cadPackageConfigs } from 'src/components/CadPackage/CadPackage'
import OutBound from 'src/components/OutBound/OutBound'
import { prepareEncodedUrl, makeExternalUrl } from './helpers'
import { copyTextToClipboard } from 'src/helpers/clipboard'
@@ -16,7 +16,7 @@ const ExternalScript = () => {
'INIT' | 'SUCCESS' | 'ERROR' | 'LOADING'
>('INIT')
- const cadName = ideTypeNameMap[state.ideType]
+ const cadName = cadPackageConfigs[state.ideType].label
const onPaste: React.ClipboardEventHandler = async ({
clipboardData,
diff --git a/app/web/src/components/IdeEditor/IdeEditor.tsx b/app/web/src/components/IdeEditor/IdeEditor.tsx
index 06fcd1f..7840d4c 100644
--- a/app/web/src/components/IdeEditor/IdeEditor.tsx
+++ b/app/web/src/components/IdeEditor/IdeEditor.tsx
@@ -1,10 +1,11 @@
-import { useEffect, useState } from 'react'
+import { useEffect, useRef, useState } from 'react'
import { useIdeContext } from 'src/helpers/hooks/useIdeContext'
import { makeCodeStoreKey, requestRender } from 'src/helpers/hooks/useIdeState'
import Editor, { useMonaco } from '@monaco-editor/react'
import { theme } from 'src/../config/tailwind.config'
import { useSaveCode } from 'src/components/IdeWrapper/useSaveCode'
import type { CadPackageType } from 'src/components/CadPackage/CadPackage'
+import EditorGuide from 'src/components/EditorGuide/EditorGuide'
const colors = theme.extend.colors
@@ -17,6 +18,7 @@ const IdeEditor = ({ Loading }) => {
cadquery: 'python',
openscad: 'cpp',
jscad: 'javascript',
+ INIT: '',
}
const monaco = useMonaco()
useEffect(() => {
@@ -73,34 +75,50 @@ const IdeEditor = ({ Loading }) => {
className="h-full"
onKeyDown={handleSaveHotkey}
>
- { (state.models.length > 1) && (
-