Completed initial CAD package guides, tweaked initial code import

This commit is contained in:
Frank Johnson
2021-09-18 23:16:43 -04:00
parent 2f006d3e3b
commit b27bcd2d35
17 changed files with 297 additions and 139 deletions

View File

@@ -5,5 +5,9 @@ module.exports = (config, { env }) => {
plugin.userOptions.favicon = './src/favicon.svg' plugin.userOptions.favicon = './src/favicon.svg'
} }
}) })
config.module.rules.push({
test: /\.md$|\.jscad$|\.py$|\.SCAD$/i,
use: 'raw-loader',
});
return config return config
} }

View File

@@ -58,6 +58,7 @@
"postcss": "^8.3.6", "postcss": "^8.3.6",
"postcss-import": "^14.0.2", "postcss-import": "^14.0.2",
"postcss-loader": "^6.1.1", "postcss-loader": "^6.1.1",
"raw-loader": "^4.0.2",
"tailwindcss": "^2.2.7" "tailwindcss": "^2.2.7"
} }
} }

View File

@@ -1,43 +1,63 @@
export type CadPackageType = 'openscad' | 'cadquery' | 'jscad' export type CadPackageType = 'openscad' | 'cadquery' | 'jscad' | 'INIT'
export const ideTypeNameMap: { [key in CadPackageType]: string } = { interface CadPackageConfig {
openscad: 'OpenSCAD', label: string
cadquery: 'CadQuery', buttonClasses: string
jscad: 'JSCAD', 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 { interface CadPackageProps {
cadPackage: CadPackageType cadPackage: CadPackageType
className?: string className?: string
dotClass?: string dotClass?: string
onClick?: any
} }
const CadPackage = ({ const CadPackage = ({
cadPackage, cadPackage,
className = '', className = '',
dotClass = 'w-5 h-5', dotClass = 'w-5 h-5',
onClick,
}: CadPackageProps) => { }: CadPackageProps) => {
const cadName = ideTypeNameMap[cadPackage] || '' const cadPackageConfig = cadPackageConfigs[cadPackage]
const isOpenScad = cadPackage === 'openscad'
const isCadQuery = cadPackage === 'cadquery'
const isJsCad = cadPackage === 'jscad'
return ( return (
<div <button
onClick={onClick}
className={ className={
`grid grid-flow-col-dense items-center gap-2 text-gray-100 ${ `grid grid-flow-col-dense items-center gap-2 text-gray-100 bg-opacity-30 hover:bg-opacity-80 ${cadPackageConfig.buttonClasses} ` +
isOpenScad && 'bg-yellow-800' className
} ${isCadQuery && 'bg-ch-blue-700'} ${
isJsCad && 'bg-ch-purple-500'
} bg-opacity-30 ` + className
} }
> >
<div <div
className={`${isOpenScad && 'bg-yellow-200'} ${ className={`${cadPackageConfig.dotClasses} ${dotClass} rounded-full`}
isCadQuery && 'bg-blue-800'
} ${isJsCad && 'bg-yellow-300'} ${dotClass} rounded-full`}
/> />
<div>{cadName}</div> {cadPackageConfig.label}
</div> </button>
) )
} }

View File

@@ -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 (
<div className="markdown-overrides py-6 px-8">
{metadata && (
<>
<h1 className="my-4">{metadata.title}</h1>
<section className="grid grid-cols-3 my-6 gap-y-4">
{Object.entries(metadata)
.filter(([key]) => key !== 'title')
.map(([key, value], i) => (
<KeyValue keyName={key.replace(/"/g, '')} key={key + '-' + i}>
<LinkOrParagraph>{value}</LinkOrParagraph>
</KeyValue>
))}
</section>
</>
)}
<Editor
ref={ref}
readOnly={true}
defaultValue={processedContent}
value={processedContent}
onChange={() => {}}
/>
</div>
)
}
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 ? (
<p>{children}</p>
) : (
<a href={matches[2]} rel="noopener noreferrer" target="_blank">
{matches[1]}
</a>
)
}

View File

@@ -48,7 +48,24 @@ const EditorMenu = () => {
<Svg name="gear" className="w-6 p-px" /> <Svg name="gear" className="w-6 p-px" />
</button> </button>
</div> </div>
<CadPackage cadPackage={state.ideType} className="px-3" /> <CadPackage
cadPackage={state.ideType}
className="px-3"
onClick={() => {
thunkDispatch({
type: 'addEditorModel',
payload: {
type: 'guide',
label: 'Guide',
content: state.ideGuide,
},
})
thunkDispatch({
type: 'switchEditorModel',
payload: state.models.length,
})
}}
/>
</div> </div>
<AllShortcutsModal /> <AllShortcutsModal />
</> </>

View File

@@ -1,6 +1,6 @@
import { useState } from 'react' import { useState } from 'react'
import { useIdeContext } from 'src/helpers/hooks/useIdeContext' 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 OutBound from 'src/components/OutBound/OutBound'
import { prepareEncodedUrl, makeExternalUrl } from './helpers' import { prepareEncodedUrl, makeExternalUrl } from './helpers'
import { copyTextToClipboard } from 'src/helpers/clipboard' import { copyTextToClipboard } from 'src/helpers/clipboard'
@@ -16,7 +16,7 @@ const ExternalScript = () => {
'INIT' | 'SUCCESS' | 'ERROR' | 'LOADING' 'INIT' | 'SUCCESS' | 'ERROR' | 'LOADING'
>('INIT') >('INIT')
const cadName = ideTypeNameMap[state.ideType] const cadName = cadPackageConfigs[state.ideType].label
const onPaste: React.ClipboardEventHandler<HTMLInputElement> = async ({ const onPaste: React.ClipboardEventHandler<HTMLInputElement> = async ({
clipboardData, clipboardData,

View File

@@ -1,10 +1,11 @@
import { useEffect, useState } from 'react' import { useEffect, useRef, useState } from 'react'
import { useIdeContext } from 'src/helpers/hooks/useIdeContext' import { useIdeContext } from 'src/helpers/hooks/useIdeContext'
import { makeCodeStoreKey, requestRender } from 'src/helpers/hooks/useIdeState' import { makeCodeStoreKey, requestRender } from 'src/helpers/hooks/useIdeState'
import Editor, { useMonaco } from '@monaco-editor/react' import Editor, { useMonaco } from '@monaco-editor/react'
import { theme } from 'src/../config/tailwind.config' import { theme } from 'src/../config/tailwind.config'
import { useSaveCode } from 'src/components/IdeWrapper/useSaveCode' import { useSaveCode } from 'src/components/IdeWrapper/useSaveCode'
import type { CadPackageType } from 'src/components/CadPackage/CadPackage' import type { CadPackageType } from 'src/components/CadPackage/CadPackage'
import EditorGuide from 'src/components/EditorGuide/EditorGuide'
const colors = theme.extend.colors const colors = theme.extend.colors
@@ -17,6 +18,7 @@ const IdeEditor = ({ Loading }) => {
cadquery: 'python', cadquery: 'python',
openscad: 'cpp', openscad: 'cpp',
jscad: 'javascript', jscad: 'javascript',
INIT: '',
} }
const monaco = useMonaco() const monaco = useMonaco()
useEffect(() => { useEffect(() => {
@@ -73,34 +75,50 @@ const IdeEditor = ({ Loading }) => {
className="h-full" className="h-full"
onKeyDown={handleSaveHotkey} onKeyDown={handleSaveHotkey}
> >
{ (state.models.length > 1) && ( {state.models.length > 1 && (
<fieldset <fieldset className="bg-ch-gray-700 text-ch-gray-300 flex m-0 p-0">
className='bg-ch-gray-700 text-ch-gray-300 flex m-0 p-0'> {state.models.map((model, i) => (
{ state.models.map((model, i) => ( <label
<label key={model.type + '-' + i} key={model.type + '-' + i}
className={'flex items-center gap-2 px-4 py-1 block m-0 select-none relative bg-ch-gray-600 ' + ((state.currentModel === i) && 'bg-ch-gray-800')}> className={
{ model.label } 'flex items-center gap-2 px-4 py-1 block m-0 select-none relative bg-ch-gray-600 ' +
(state.currentModel === i && 'bg-ch-gray-800')
}
>
{model.label}
<input <input
type='radio' type="radio"
name='models' name="models"
className='sr-only absolute inset-0' className="sr-only absolute inset-0"
value={i} value={i}
checked={state.currentModel === i} checked={state.currentModel === i}
onChange={() => thunkDispatch({ type: 'switchEditorModel', payload: i })} /> onChange={() =>
{ (model.type !== 'code') && thunkDispatch({ type: 'switchEditorModel', payload: i })
<button onClick={() => thunkDispatch({ type: 'removeEditorModel', payload: i })} }
className='block p-1 m-.5 hover:bg-ch-gray-550' > />
<svg viewBox='0 0 5 5' className='w-4 text-ch-gray-300'> {model.type !== 'code' && (
<path stroke='currentColor' d='M 1 1 l 3 3 M 1 4 l 3 -3' strokeLinecap='round' strokeWidth='.5' /> <button
</svg> onClick={() =>
</button> thunkDispatch({ type: 'removeEditorModel', payload: i })
} }
className="block p-1 m-.5 hover:bg-ch-gray-550"
>
<svg viewBox="0 0 5 5" className="w-4 text-ch-gray-300">
<path
stroke="currentColor"
d="M 1 1 l 3 3 M 1 4 l 3 -3"
strokeLinecap="round"
strokeWidth=".5"
/>
</svg>
</button>
)}
</label> </label>
)) } ))}
</fieldset> </fieldset>
)} )}
{ (state.models[state.currentModel].type === 'code') {state.models[state.currentModel].type === 'code' ? (
? <Editor <Editor
defaultValue={state.code} defaultValue={state.code}
value={state.code} value={state.code}
theme={theme} theme={theme}
@@ -110,8 +128,11 @@ const IdeEditor = ({ Loading }) => {
language={ideTypeToLanguageMap[state.ideType] || 'cpp'} language={ideTypeToLanguageMap[state.ideType] || 'cpp'}
onChange={handleCodeChange} onChange={handleCodeChange}
/> />
: <pre className="bg-ch-gray-800 text-ch-gray-300 p-6 h-full">{ state.models[state.currentModel].content }</pre> ) : (
} <div className="bg-ch-gray-800 h-full">
<EditorGuide content={state.models[state.currentModel].content} />
</div>
)}
</div> </div>
) )
} }

View File

@@ -0,0 +1,17 @@
# demo shaft coupler
# ^ first comment is used for download title (i.e. "demo-shaft-coupler.stl")
# CadQuery docs: https://cadquery.readthedocs.io/
import cadquery as cq
from cadquery import exporters
diam = 5.0
result = (cq.Workplane().circle(diam).extrude(20.0)
.faces(">Z").workplane(invert=True).circle(1.05).cutBlind(8.0)
.faces("<Z").workplane(invert=True).circle(0.8).cutBlind(12.0)
.edges("%CIRCLE").chamfer(0.15))
show_object(result)

View File

@@ -1,9 +1,10 @@
--- ---
"Written with": Python title: CadQuery
"Kernal type": BREP Written with: Python
Kernal type: BREP
Maintained by: [The CadQuery Group](https://github.com/CadQuery)
Documentation: [cadquery.readthedocs.io](https://cadquery.readthedocs.io)
--- ---
# CadQuery
CadQuery is an intuitive, easy-to-use Python library for building parametric 3D CAD models. It has several goals: CadQuery is an intuitive, easy-to-use Python library for building parametric 3D CAD models. It has several goals:
- Build models with scripts that are as close as possible to how youd describe the object to a human, using a standard, already established programming language - Build models with scripts that are as close as possible to how youd describe the object to a human, using a standard, already established programming language

View File

@@ -0,0 +1,33 @@
const jscad = require('@jscad/modeling')
// https://openjscad.xyz/docs/module-modeling_primitives.html
const { cuboid, cylinder } = jscad.primitives
const { rotate, translate } = jscad.transforms
const { degToRad } = jscad.utils // because jscad uses radians for rotations
// https://openjscad.xyz/docs/module-modeling_booleans.html
const { subtract } = jscad.booleans
function main({//@jscad-params
// Box example
width=40, // Width
length=20, // Length
height=10, // Height
hole=3,// Hole for cables diameter (0=no hole)
wall=1, // wall {min:0.5, step:0.5}
flip=0, // print orientation {type: 'choice', values: [0, 90, 180]}
}){
let wallOffset = wall * 2
let model = subtract(
cuboid({size:[width, length, height]}),
translate([0,0,wall], cuboid({size:[width-wallOffset, length-wallOffset, height+wall]})),
)
if(hole){
model = subtract( model,
translate([width/2-wall/2], rotate([0, degToRad(90), 0 ], cylinder({radius:hole/2, height:wall})))
)
}
return rotate([degToRad(flip), 0, degToRad(90)], model)
}
module.exports = {main}

View File

@@ -1,7 +1,8 @@
--- ---
"Written with": JavaScript title: JSCAD
"Kernal type": BREP Written with: JavaScript
Kernal type: BREP
Maintained by: [Z3 Development + 39 contributors](https://www.github.com/jscad)
Documentation: [openjscad.xyz/docs](https://openjscad.xyz/docs/)
--- ---
# JSCAD
JSCAD is an open source set of modular, browser and command line tools for creating parametric 2D and 3D designs with Javascript code. It provides a quick, precise and reproducible method for generating 3D models, and is especially useful for 3D printing applications. JSCAD is an open source set of modular, browser and command line tools for creating parametric 2D and 3D designs with Javascript code. It provides a quick, precise and reproducible method for generating 3D models, and is especially useful for 3D printing applications.

View File

@@ -0,0 +1,12 @@
// involute donut
// ^ first comment is used for download title (i.e "involute-donut.stl")
// Follow the OpenSCAD tutorial: https://learn.cadhub.xyz/docs/
radius=3;
color(c="DarkGoldenrod")rotate_extrude()translate([20,0])circle(d=30);
color(c="hotpink")rotate_extrude()translate([20,0])offset(radius)offset(-radius)difference(){
circle(d=34);
translate([-200,-500])square([500,500]);
}

View File

@@ -1,7 +1,8 @@
--- ---
"Written with": C+-like title: OpenSCAD
"Kernal type": BREP Written with: Custom language
Kernal type: BREP
Maintained by: [Marius Kintel + 15 members](https://github.com/openscad)
Documentation: [openscad.org](https://openscad.org/)
--- ---
# OpenSCAD
OpenSCAD is a solid 3D modeler that enables the creation of parametric models using its scripting language. Models are created by utilizing a technique called constructive solid geometry. According to this technique, simple objects can be transformed and combined in order to create almost any complex model. OpenSCAD is a solid 3D modeler that enables the creation of parametric models using its scripting language. Models are created by utilizing a technique called constructive solid geometry. According to this technique, simple objects can be transformed and combined in order to create almost any complex model.

View File

@@ -6,6 +6,14 @@ import type {
ArtifactTypes, ArtifactTypes,
} from 'src/helpers/cadPackages/common' } from 'src/helpers/cadPackages/common'
import { CadhubParams } from 'src/components/Customizer/customizerConverter' import { CadhubParams } from 'src/components/Customizer/customizerConverter'
import openScadGuide from 'src/helpers/cadPackages/openScad/userGuide.md'
import openScadInitialCode from 'src/helpers/cadPackages/openScad/initialCode.SCAD'
import cadQueryGuide from 'src/helpers/cadPackages/cadQuery/userGuide.md'
import cadQueryInitialCode from 'src/helpers/cadPackages/cadQuery/initialCode.py'
import jsCadGuide from 'src/helpers/cadPackages/jsCad/userGuide.md'
import jsCadInitialCode from 'src/helpers/cadPackages/jsCad/initialCode.jscad'
console.log('jscad', { jsCadInitialCode })
function withThunk(dispatch, getState) { function withThunk(dispatch, getState) {
return (actionOrThunk) => return (actionOrThunk) =>
@@ -15,74 +23,18 @@ function withThunk(dispatch, getState) {
} }
import { CadPackageType } from 'src/components/CadPackage/CadPackage' import { CadPackageType } from 'src/components/CadPackage/CadPackage'
const initCodeMap: { [key in CadPackageType]: string } = { const initGuideMap: { [key in CadPackageType]: string } = {
openscad: `// involute donut openscad: openScadGuide,
cadquery: cadQueryGuide,
// ^ first comment is used for download title (i.e "involute-donut.stl") jscad: jsCadGuide,
INIT: '',
// Follow the OpenSCAD tutorial: https://learn.cadhub.xyz/docs/
radius=3;
color(c="DarkGoldenrod")rotate_extrude()translate([20,0])circle(d=30);
color(c="hotpink")rotate_extrude()translate([20,0])offset(radius)offset(-radius)difference(){
circle(d=34);
translate([-200,-500])square([500,500]);
}`,
cadquery: `# demo shaft coupler
# ^ first comment is used for download title (i.e. "demo-shaft-coupler.stl")
# CadQuery docs: https://cadquery.readthedocs.io/
import cadquery as cq
from cadquery import exporters
diam = 5.0
result = (cq.Workplane().circle(diam).extrude(20.0)
.faces(">Z").workplane(invert=True).circle(1.05).cutBlind(8.0)
.faces("<Z").workplane(invert=True).circle(0.8).cutBlind(12.0)
.edges("%CIRCLE").chamfer(0.15))
show_object(result)
`,
jscad: `
const jscad = require('@jscad/modeling')
// https://openjscad.xyz/docs/module-modeling_primitives.html
const { cuboid, cylinder } = jscad.primitives
const { rotate, translate } = jscad.transforms
const { degToRad } = jscad.utils // because jscad uses radians for rotations
// https://openjscad.xyz/docs/module-modeling_booleans.html
const { subtract } = jscad.booleans
function main({//@jscad-params
// Box example
width=40, // Width
length=20, // Length
height=10, // Height
hole=3,// Hole for cables diameter (0=no hole)
wall=1, // wall {min:0.5, step:0.5}
flip=0, // print orientation {type: 'choice', values: [0, 90, 180]}
}){
let wallOffset = wall * 2
let model = subtract(
cuboid({size:[width, length, height]}),
translate([0,0,wall], cuboid({size:[width-wallOffset, length-wallOffset, height+wall]})),
)
if(hole){
model = subtract( model,
translate([width/2-wall/2], rotate([0, degToRad(90), 0 ], cylinder({radius:hole/2, height:wall})))
)
}
return rotate([degToRad(flip), 0, degToRad(90)], model)
} }
module.exports = {main} const initCodeMap: { [key in CadPackageType]: string } = {
openscad: openScadInitialCode,
`, cadquery: cadQueryInitialCode,
jscad: jsCadInitialCode,
INIT: '',
} }
const codeStorageKey = 'Last-editor-code' const codeStorageKey = 'Last-editor-code'
@@ -103,6 +55,7 @@ interface EditorModel {
export interface State { export interface State {
ideType: 'INIT' | CadPackageType ideType: 'INIT' | CadPackageType
ideGuide?: string
consoleMessages: { type: 'message' | 'error'; message: string; time: Date }[] consoleMessages: { type: 'message' | 'error'; message: string; time: Date }[]
code: string code: string
models: EditorModel[] models: EditorModel[]
@@ -144,10 +97,7 @@ export const initialState: State = {
{ type: 'message', message: 'Initialising', time: new Date() }, { type: 'message', message: 'Initialising', time: new Date() },
], ],
code, code,
models: [ models: [{ type: 'code', label: 'Code' }],
{ type: 'code', label: 'Code', },
{ type: 'guide', label: 'Test', content: '# Testing!' },
],
currentModel: 0, currentModel: 0,
objectData: { objectData: {
type: 'INIT', type: 'INIT',
@@ -174,6 +124,7 @@ const reducer = (state: State, { type, payload }): State => {
initCodeMap[payload.cadPackage] || initCodeMap[payload.cadPackage] ||
'', '',
ideType: payload.cadPackage, ideType: payload.cadPackage,
ideGuide: initGuideMap[payload.cadPackage],
} }
case 'updateCode': case 'updateCode':
return { ...state, code: payload } return { ...state, code: payload }
@@ -290,10 +241,7 @@ const reducer = (state: State, { type, payload }): State => {
case 'addEditorModel': case 'addEditorModel':
return { return {
...state, ...state,
models: [ models: [...state.models, payload],
...state.models,
payload,
]
} }
case 'removeEditorModel': case 'removeEditorModel':
return { return {
@@ -302,10 +250,10 @@ const reducer = (state: State, { type, payload }): State => {
...state.models.slice(0, payload), ...state.models.slice(0, payload),
...state.models.slice(payload + 1), ...state.models.slice(payload + 1),
], ],
currentModel: (payload === 0) ? 0 : payload - 1, currentModel: payload === 0 ? 0 : payload - 1,
} }
case 'updateEditorModel': { case 'updateEditorModel': {
let newModels = [...state.models] const newModels = [...state.models]
newModels[state.currentModel].content = payload newModels[state.currentModel].content = payload
return { return {
...state, ...state,
@@ -313,9 +261,9 @@ const reducer = (state: State, { type, payload }): State => {
} }
} }
case 'reorderEditorModels': { case 'reorderEditorModels': {
let newModels = [ const newModels = [
...state.models.slice(0, state.currentModel), ...state.models.slice(0, state.currentModel),
...state.models.slice(state.currentModel + 1) ...state.models.slice(state.currentModel + 1),
].splice(payload, 0, state.models[state.currentModel]) ].splice(payload, 0, state.models[state.currentModel])
return { return {
...state, ...state,

View File

@@ -0,0 +1,24 @@
// Extracts YAML frontmatter from Markdown files
// Gotten from this helpful comment on a react-markdown GitHub Issue: https://github.com/remarkjs/react-markdown/issues/164#issuecomment-890497653
export function extractMetaData(text: string): Array<any> {
const metaData = {} as any
const metaRegExp = RegExp(/^---[\r\n](((?!---).|[\r\n])*)[\r\n]---$/m)
// get metadata
const rawMetaData = metaRegExp.exec(text)
let keyValues
if (rawMetaData!) {
// rawMeta[1] are the stuff between "---"
keyValues = rawMetaData[1].split('\n')
// which returns a list of key values: ["key1: value", "key2: value"]
keyValues.forEach((keyValue) => {
// split each keyValue to keys and values
const [, key, value] = keyValue.split(/(.+): (.+)/)
metaData[key] = value.trim()
})
}
return [rawMetaData, metaData]
}

View File

@@ -48,19 +48,24 @@
.markdown-overrides { .markdown-overrides {
@apply bg-transparent; @apply bg-transparent;
} }
.markdown-overrides,
.markdown-overrides div { .markdown-overrides div {
@apply text-ch-gray-300 bg-transparent; @apply text-ch-gray-300 bg-transparent;
} }
.markdown-overrides a,
.markdown-overrides div a { .markdown-overrides div a {
@apply text-ch-pink-500 underline bg-transparent; @apply text-ch-pink-500 underline bg-transparent;
} }
.markdown-overrides h3,
.markdown-overrides div h3 { .markdown-overrides div h3 {
@apply text-xl; @apply text-xl;
} }
.markdown-overrides h2,
.markdown-overrides div h2 { .markdown-overrides div h2 {
@apply text-2xl; @apply text-2xl;
} }
.markdown-overrides h1,
.markdown-overrides div h1 { .markdown-overrides div h1 {
@apply text-3xl; @apply text-3xl;
} }

View File

@@ -15425,7 +15425,7 @@ raw-body@2.4.0:
raw-loader@^4.0.2: raw-loader@^4.0.2:
version "4.0.2" version "4.0.2"
resolved "https://registry.npmjs.org/raw-loader/-/raw-loader-4.0.2.tgz" resolved "https://registry.yarnpkg.com/raw-loader/-/raw-loader-4.0.2.tgz#1aac6b7d1ad1501e66efdac1522c73e59a584eb6"
integrity sha512-ZnScIV3ag9A4wPX/ZayxL/jZH+euYb6FcUinPcgiQW0+UBtEv0O6Q3lGd3cqJ+GHH+rksEv3Pj99oxJ3u3VIKA== integrity sha512-ZnScIV3ag9A4wPX/ZayxL/jZH+euYb6FcUinPcgiQW0+UBtEv0O6Q3lGd3cqJ+GHH+rksEv3Pj99oxJ3u3VIKA==
dependencies: dependencies:
loader-utils "^2.0.0" loader-utils "^2.0.0"