1
0
Fork 0

feat(org): Switched to better dynamic mdx

This commit is contained in:
Joost De Cock 2023-10-09 11:42:16 +02:00
parent 166c8bc03b
commit 90afd3e28e
36 changed files with 267 additions and 267 deletions

View file

@ -0,0 +1,12 @@
---
title: What to do after saving a new pattern?
---
When you create a new pattern in FreeSewing's pattern editor, you have the option to save the pattern to your account.
After you save the pattern to your account, there are several options for what you might want to do next:
- Continue editing the saved patter
- Display the pattern information page
Because we cannot read your mind, you can choose what you would like to happen when you save a new pattern to your account.

View file

@ -0,0 +1,8 @@
---
title: "Patterns: Image"
---
If you'd like you can add an **image** to your pattern, for example of the finished make.
This can help you remember exactly what this pattern was, which can be useful as you can end up having many patterns saved to your account.

View file

@ -0,0 +1,8 @@
---
title: "Patterns: Public"
---
This settings controls whether your pattern will accessible by the **public** or not.
By default, patterns are private and only you can access your own patterns.
If you'd like to share your pattern with others -- perhaps because they showed an interest or you are loooking for input -- you should first make it public.

View file

@ -1,14 +0,0 @@
//import { DynamicOrgDocs as Component } from 'shared/components/dynamic-docs/org.mjs'
export const DynamicOrgDocs = () => <p>No longer supported</p>
// (
// <Popout note>
// <h5>The FreeSewing lab does not include documentation</h5>
// <p>
// Go to <WebLink href="https://freesewing.org/" txt="FreeSewing.org" /> if you want all features
// enabled.
// </p>
// </Popout>
//)
//export const DynamicOrgDocs = Component

View file

@ -8,8 +8,9 @@ import { loadMdxAsStaticProps } from 'shared/mdx/load.mjs'
import { PageWrapper, ns as pageNs } from 'shared/components/wrappers/page.mjs' import { PageWrapper, ns as pageNs } from 'shared/components/wrappers/page.mjs'
import { MdxWrapper } from 'shared/components/wrappers/mdx.mjs' import { MdxWrapper } from 'shared/components/wrappers/mdx.mjs'
import { DocsLayout, ns as layoutNs } from 'site/components/layouts/docs.mjs' import { DocsLayout, ns as layoutNs } from 'site/components/layouts/docs.mjs'
import { ns as designNs } from 'shared/components/designs/info.mjs'
export const ns = nsMerge(pageNs, layoutNs, 'designs', 'account', 'tags') export const ns = nsMerge(pageNs, layoutNs, designNs)
/** /**
* A page to display documentation markdown * A page to display documentation markdown

View file

@ -1,21 +1,25 @@
// Dependencies // Dependencies
import { serverSideTranslations } from 'next-i18next/serverSideTranslations' import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
// Hooks import { loadMdxAsStaticProps } from 'shared/mdx/load.mjs'
import { useCallback } from 'react' import { nsMerge } from 'shared/utils.mjs'
import { useDynamicMdx } from 'shared/hooks/use-dynamic-mdx.mjs'
// Components // Components
import { Page, ns } from './[...slug].mjs' import { PageWrapper, ns as pageNs } from 'shared/components/wrappers/page.mjs'
import { MdxWrapper } from 'shared/components/wrappers/mdx.mjs'
import { DocsLayout, ns as layoutNs } from 'site/components/layouts/docs.mjs'
const DocsHomePage = ({ page, slug, locale }) => { export const ns = nsMerge('docs', pageNs, layoutNs)
const loader = useCallback(
() =>
import(/* webpackInclude: /docs\/\w+\.md/ */ `../../../../markdown/org/docs/${locale}.md`),
[locale]
)
const { frontmatter, MDX } = useDynamicMdx(loader)
return <Page {...{ page, slug, frontmatter, MDX, locale }} /> const DocsHomePage = ({ page, locale, frontmatter, mdx, mdxSlug }) => (
} <PageWrapper
{...page}
locale={locale}
title={frontmatter.title}
intro={frontmatter.intro || frontmatter.lead}
layout={(props) => <DocsLayout {...props} {...{ slug: page.path.join('/'), frontmatter }} />}
>
<MdxWrapper mdx={mdx} site="org" slug={mdxSlug} />
</PageWrapper>
)
export default DocsHomePage export default DocsHomePage
@ -26,7 +30,12 @@ export default DocsHomePage
export async function getStaticProps({ locale }) { export async function getStaticProps({ locale }) {
return { return {
props: { props: {
...(await serverSideTranslations('en', ['docs', ...ns])), ...(await serverSideTranslations(locale, ns)),
...(await loadMdxAsStaticProps({
language: locale,
site: 'org',
slug: 'docs',
})),
slug: 'docs', slug: 'docs',
locale, locale,
page: { page: {

View file

@ -16,7 +16,7 @@ import { Popout } from 'shared/components/popout/index.mjs'
import { LeftIcon, PlusIcon, CopyIcon, RightIcon, TrashIcon } from 'shared/components/icons.mjs' import { LeftIcon, PlusIcon, CopyIcon, RightIcon, TrashIcon } from 'shared/components/icons.mjs'
import { PageLink, Link } from 'shared/components/link.mjs' import { PageLink, Link } from 'shared/components/link.mjs'
import { StringInput, ListInput, FormControl } from 'shared/components/inputs.mjs' import { StringInput, ListInput, FormControl } from 'shared/components/inputs.mjs'
import { DynamicOrgDocs } from 'site/components/dynamic-org-docs.mjs' import { DynamicMdx } from 'shared/components/mdx/dynamic.mjs'
export const ns = ['account', 'status'] export const ns = ['account', 'status']
@ -149,10 +149,9 @@ const NewKey = ({ account, setGenerate, backend }) => {
const [apikey, setApikey] = useState(false) const [apikey, setApikey] = useState(false)
const { setLoadingStatus } = useContext(LoadingStatusContext) const { setLoadingStatus } = useContext(LoadingStatusContext)
const { t, i18n } = useTranslation(ns) const { t, i18n } = useTranslation(ns)
// FIXME: implement a solution for loading docs dynamically the is simple and work as expected
const docs = {} const docs = {}
for (const option of ['name', 'expiry', 'level']) { for (const option of ['name', 'expiry', 'level']) {
docs[option] = <DynamicOrgDocs language={i18n.language} path={`site/apikeys/${option}`} /> docs[option] = <DynamicMdx language={i18n.language} slug={`docs/site/apikeys/${option}`} />
} }
const levels = account.role === 'admin' ? [0, 1, 2, 3, 4, 5, 6, 7, 8] : [0, 1, 2, 3, 4] const levels = account.role === 'admin' ? [0, 1, 2, 3, 4, 5, 6, 7, 8] : [0, 1, 2, 3, 4]

View file

@ -11,7 +11,7 @@ import { Icons, welcomeSteps, BackToAccountButton } from './shared.mjs'
import { SaveSettingsButton } from 'shared/components/buttons/save-settings-button.mjs' import { SaveSettingsButton } from 'shared/components/buttons/save-settings-button.mjs'
import { ContinueButton } from 'shared/components/buttons/continue-button.mjs' import { ContinueButton } from 'shared/components/buttons/continue-button.mjs'
import { MarkdownInput } from 'shared/components/inputs.mjs' import { MarkdownInput } from 'shared/components/inputs.mjs'
import { DynamicOrgDocs } from 'site/components/dynamic-org-docs.mjs' import { DynamicMdx } from 'shared/components/mdx/dynamic.mjs'
import { TipIcon } from 'shared/components/icons.mjs' import { TipIcon } from 'shared/components/icons.mjs'
export const ns = ['account', 'status'] export const ns = ['account', 'status']
@ -60,7 +60,7 @@ export const BioSettings = ({ welcome = false }) => {
update={setBio} update={setBio}
current={bio} current={bio}
placeholder={t('bioTitle')} placeholder={t('bioTitle')}
docs={<DynamicOrgDocs language={i18n.language} path={`site/account/bio`} />} docs={<DynamicMdx language={i18n.language} slug={`docs/site/account/bio`} />}
labelBL={ labelBL={
<span className="flex flex-row items-center gap-1"> <span className="flex flex-row items-center gap-1">
<TipIcon className="w-6 h-6 text-success" /> <TipIcon className="w-6 h-6 text-success" />

View file

@ -11,7 +11,7 @@ import { PlusIcon, TrashIcon, LeftIcon } from 'shared/components/icons.mjs'
import { PageLink, WebLink, Link } from 'shared/components/link.mjs' import { PageLink, WebLink, Link } from 'shared/components/link.mjs'
import { DisplayRow } from './shared.mjs' import { DisplayRow } from './shared.mjs'
import { StringInput } from 'shared/components/inputs.mjs' import { StringInput } from 'shared/components/inputs.mjs'
import { DynamicOrgDocs } from 'site/components/dynamic-org-docs.mjs' import { DynamicMdx } from 'shared/components/mdx/dynamic.mjs'
export const ns = ['account', 'status'] export const ns = ['account', 'status']
@ -47,10 +47,9 @@ export const NewBookmark = () => {
const router = useRouter() const router = useRouter()
const backend = useBackend() const backend = useBackend()
const { t, i18n } = useTranslation(ns) const { t, i18n } = useTranslation(ns)
// FIXME: implement a solution for loading docs dynamically the is simple and work as expected
const docs = {} const docs = {}
for (const option of ['title', 'location', 'type']) { for (const option of ['title', 'location', 'type']) {
docs[option] = <DynamicOrgDocs language={i18n.language} path={`site/bookmarks/${option}`} /> docs[option] = <DynamicMdx language={i18n.language} slug={`docs/site/bookmarks/${option}`} />
} }
// State // State

View file

@ -11,7 +11,7 @@ import { Icons, welcomeSteps, BackToAccountButton } from './shared.mjs'
import { ContinueButton } from 'shared/components/buttons/continue-button.mjs' import { ContinueButton } from 'shared/components/buttons/continue-button.mjs'
import { ListInput } from 'shared/components/inputs.mjs' import { ListInput } from 'shared/components/inputs.mjs'
import { OkIcon, NoIcon } from 'shared/components/icons.mjs' import { OkIcon, NoIcon } from 'shared/components/icons.mjs'
import { DynamicOrgDocs } from 'site/components/dynamic-org-docs.mjs' import { DynamicMdx } from 'shared/components/mdx/dynamic.mjs'
export const ns = ['account', 'status'] export const ns = ['account', 'status']
@ -67,7 +67,7 @@ export const CompareSettings = ({ welcome = false }) => {
}))} }))}
current={selection} current={selection}
update={update} update={update}
docs={<DynamicOrgDocs language={i18n.language} path={`site/account/compare`} />} docs={<DynamicMdx language={i18n.language} slug={`docs/site/account/compare`} />}
/> />
{welcome ? ( {welcome ? (
<> <>

View file

@ -11,8 +11,8 @@ import { useBackend } from 'shared/hooks/use-backend.mjs'
import { BackToAccountButton, Icons, welcomeSteps } from './shared.mjs' import { BackToAccountButton, Icons, welcomeSteps } from './shared.mjs'
import { ContinueButton } from 'shared/components/buttons/continue-button.mjs' import { ContinueButton } from 'shared/components/buttons/continue-button.mjs'
import { ListInput } from 'shared/components/inputs.mjs' import { ListInput } from 'shared/components/inputs.mjs'
import { DynamicOrgDocs } from 'site/components/dynamic-org-docs.mjs'
import { ControlScore } from 'shared/components/control/score.mjs' import { ControlScore } from 'shared/components/control/score.mjs'
import { DynamicMdx } from 'shared/components/mdx/dynamic.mjs'
export const ns = ['account', 'status'] export const ns = ['account', 'status']
@ -78,7 +78,7 @@ export const ControlSettings = ({ welcome = false, noBack = false }) => {
}))} }))}
current={selection} current={selection}
update={update} update={update}
docs={<DynamicOrgDocs language={i18n.language} path={`site/account/control`} />} docs={<DynamicMdx language={i18n.language} slug="docs/site/account/control" />}
/> />
{welcome ? ( {welcome ? (
<> <>

View file

@ -12,7 +12,7 @@ import { validateEmail, validateTld } from 'shared/utils.mjs'
import { BackToAccountButton } from './shared.mjs' import { BackToAccountButton } from './shared.mjs'
import { Popout } from 'shared/components/popout/index.mjs' import { Popout } from 'shared/components/popout/index.mjs'
import { EmailInput } from 'shared/components/inputs.mjs' import { EmailInput } from 'shared/components/inputs.mjs'
import { DynamicOrgDocs } from 'site/components/dynamic-org-docs.mjs' import { DynamicMdx } from 'shared/components/mdx/dynamic.mjs'
export const ns = ['account', 'status'] export const ns = ['account', 'status']
@ -59,7 +59,7 @@ export const EmailSettings = () => {
current={email} current={email}
original={account.email} original={account.email}
valid={() => valid} valid={() => valid}
docs={<DynamicOrgDocs language={i18n.language} path={`site/account/email`} />} docs={<DynamicMdx language={i18n.language} slug={`docs/site/account/email`} />}
/> />
<button <button
className="btn mt-4 btn-primary w-full" className="btn mt-4 btn-primary w-full"

View file

@ -9,7 +9,7 @@ import { useBackend } from 'shared/hooks/use-backend.mjs'
import { BackToAccountButton } from './shared.mjs' import { BackToAccountButton } from './shared.mjs'
import { SaveSettingsButton } from 'shared/components/buttons/save-settings-button.mjs' import { SaveSettingsButton } from 'shared/components/buttons/save-settings-button.mjs'
import { StringInput } from 'shared/components/inputs.mjs' import { StringInput } from 'shared/components/inputs.mjs'
import { DynamicOrgDocs } from 'site/components/dynamic-org-docs.mjs' import { DynamicMdx } from 'shared/components/mdx/dynamic.mjs'
export const ns = ['account', 'status'] export const ns = ['account', 'status']
@ -44,7 +44,7 @@ export const GithubSettings = () => {
update={setGithubEmail} update={setGithubEmail}
valid={(val) => val.length > 0} valid={(val) => val.length > 0}
placeholder={'joostdecock'} placeholder={'joostdecock'}
docs={<DynamicOrgDocs language={i18n.language} path={`site/account/github`} />} docs={<DynamicMdx language={i18n.language} slug={`docs/site/account/github`} />}
/> />
<StringInput <StringInput
id="account-github-username" id="account-github-username"
@ -53,7 +53,7 @@ export const GithubSettings = () => {
update={setGithubUsername} update={setGithubUsername}
valid={(val) => val.length > 0} valid={(val) => val.length > 0}
placeholder={'joost@joost.at'} placeholder={'joost@joost.at'}
docs={<DynamicOrgDocs language={i18n.language} path={`site/account/github`} />} docs={<DynamicOrgDocs language={i18n.language} path={`docs/site/account/github`} />}
/> />
<SaveSettingsButton btnProps={{ onClick: save }} /> <SaveSettingsButton btnProps={{ onClick: save }} />
<BackToAccountButton /> <BackToAccountButton />

View file

@ -12,7 +12,7 @@ import { Icons, welcomeSteps, BackToAccountButton } from './shared.mjs'
import { ContinueButton } from 'shared/components/buttons/continue-button.mjs' import { ContinueButton } from 'shared/components/buttons/continue-button.mjs'
import { SaveSettingsButton } from 'shared/components/buttons/save-settings-button.mjs' import { SaveSettingsButton } from 'shared/components/buttons/save-settings-button.mjs'
import { PassiveImageInput } from 'shared/components/inputs.mjs' import { PassiveImageInput } from 'shared/components/inputs.mjs'
import { DynamicOrgDocs } from 'site/components/dynamic-org-docs.mjs' import { DynamicMdx } from 'shared/components/mdx/dynamic.mjs'
export const ns = ['account', 'status'] export const ns = ['account', 'status']
@ -51,7 +51,7 @@ export const ImgSettings = ({ welcome = false }) => {
update={setImg} update={setImg}
current={img} current={img}
valid={(val) => val.length > 0} valid={(val) => val.length > 0}
docs={<DynamicOrgDocs language={i18n.language} path={`site/account/img`} />} docs={<DynamicMdx language={i18n.language} slug={`docs/site/account/img`} />}
/> />
{welcome ? ( {welcome ? (
<> <>

View file

@ -9,7 +9,7 @@ import { useBackend } from 'shared/hooks/use-backend.mjs'
import { Icons, welcomeSteps, BackToAccountButton, NumberBullet } from './shared.mjs' import { Icons, welcomeSteps, BackToAccountButton, NumberBullet } from './shared.mjs'
import { ContinueButton } from 'shared/components/buttons/continue-button.mjs' import { ContinueButton } from 'shared/components/buttons/continue-button.mjs'
import { ListInput } from 'shared/components/inputs.mjs' import { ListInput } from 'shared/components/inputs.mjs'
import { DynamicOrgDocs } from 'site/components/dynamic-org-docs.mjs' import { DynamicMdx } from 'shared/components/mdx/dynamic.mjs'
export const ns = ['account', 'status'] export const ns = ['account', 'status']
@ -59,7 +59,7 @@ export const ImperialSettings = ({ welcome = false }) => {
}))} }))}
current={selection} current={selection}
update={update} update={update}
docs={<DynamicOrgDocs language={i18n.language} path={`site/account/units`} />} docs={<DynamicMdx language={i18n.language} slug={`docs/site/account/units`} />}
/> />
{welcome ? ( {welcome ? (
<> <>

View file

@ -8,7 +8,7 @@ import { useBackend } from 'shared/hooks/use-backend.mjs'
// Components // Components
import { BackToAccountButton, NumberBullet } from './shared.mjs' import { BackToAccountButton, NumberBullet } from './shared.mjs'
import { ListInput } from 'shared/components/inputs.mjs' import { ListInput } from 'shared/components/inputs.mjs'
import { DynamicOrgDocs } from 'site/components/dynamic-org-docs.mjs' import { DynamicMdx } from 'shared/components/mdx/dynamic.mjs'
// Config // Config
import { siteConfig as conf } from 'site/site.config.mjs' import { siteConfig as conf } from 'site/site.config.mjs'
@ -58,7 +58,7 @@ export const LanguageSettings = () => {
}))} }))}
current={language} current={language}
update={update} update={update}
docs={<DynamicOrgDocs language={i18n.language} path={`site/account/language`} />} docs={<DynamicMdx language={i18n.language} slug={`docs/site/account/language`} />}
/> />
<BackToAccountButton /> <BackToAccountButton />
</div> </div>

View file

@ -9,7 +9,7 @@ import { useBackend } from 'shared/hooks/use-backend.mjs'
import { BackToAccountButton, Icons, welcomeSteps } from './shared.mjs' import { BackToAccountButton, Icons, welcomeSteps } from './shared.mjs'
import { ContinueButton } from 'shared/components/buttons/continue-button.mjs' import { ContinueButton } from 'shared/components/buttons/continue-button.mjs'
import { ListInput } from 'shared/components/inputs.mjs' import { ListInput } from 'shared/components/inputs.mjs'
import { DynamicOrgDocs } from 'site/components/dynamic-org-docs.mjs' import { DynamicMdx } from 'shared/components/mdx/dynamic.mjs'
import { OkIcon, NoIcon } from 'shared/components/icons.mjs' import { OkIcon, NoIcon } from 'shared/components/icons.mjs'
export const ns = ['account', 'status'] export const ns = ['account', 'status']
@ -63,7 +63,7 @@ export const NewsletterSettings = ({ welcome = false, bare = false }) => {
}))} }))}
current={selection} current={selection}
update={update} update={update}
docs={<DynamicOrgDocs language={i18n.language} path={`site/account/newsletter`} />} docs={<DynamicMdx language={i18n.language} slug={`account/site/account/newsletter`} />}
/> />
{welcome ? ( {welcome ? (
<> <>

View file

@ -13,7 +13,7 @@ import { SaveSettingsButton } from 'shared/components/buttons/save-settings-butt
import { Popout } from 'shared/components/popout/index.mjs' import { Popout } from 'shared/components/popout/index.mjs'
import { RightIcon } from 'shared/components/icons.mjs' import { RightIcon } from 'shared/components/icons.mjs'
import { PasswordInput } from 'shared/components/inputs.mjs' import { PasswordInput } from 'shared/components/inputs.mjs'
import { DynamicOrgDocs } from 'site/components/dynamic-org-docs.mjs' import { DynamicMdx } from 'shared/components/mdx/dynamic.mjs'
export const ns = ['account', 'status'] export const ns = ['account', 'status']
@ -46,7 +46,7 @@ export const PasswordSettings = ({ welcome = false }) => {
update={setPassword} update={setPassword}
valid={(val) => val.length > 0} valid={(val) => val.length > 0}
placeholder={t('passwordTitle')} placeholder={t('passwordTitle')}
docs={<DynamicOrgDocs language={i18n.language} path={`site/account/password`} />} docs={<DynamicMdx language={i18n.language} slug={`docs/site/account/password`} />}
/> />
<SaveSettingsButton btnProps={{ onClick: save, disabled: password.length < 4 }} /> <SaveSettingsButton btnProps={{ onClick: save, disabled: password.length < 4 }} />
{!welcome && <BackToAccountButton />} {!welcome && <BackToAccountButton />}

View file

@ -48,9 +48,9 @@ import { ModalWrapper } from 'shared/components/wrappers/modal.mjs'
import Markdown from 'react-markdown' import Markdown from 'react-markdown'
import Timeago from 'react-timeago' import Timeago from 'react-timeago'
import { TableWrapper } from 'shared/components/wrappers/table.mjs' import { TableWrapper } from 'shared/components/wrappers/table.mjs'
import { DynamicOrgDocs } from 'site/components/dynamic-org-docs.mjs'
import { PatternReactPreview } from 'shared/components/pattern/preview.mjs' import { PatternReactPreview } from 'shared/components/pattern/preview.mjs'
import { Lightbox } from 'shared/components/lightbox.mjs' import { Lightbox } from 'shared/components/lightbox.mjs'
import { DynamicMdx } from 'shared/components/mdx/dynamic.mjs'
export const ns = ['account', 'patterns', 'status'] export const ns = ['account', 'patterns', 'status']
@ -165,11 +165,6 @@ export const Pattern = ({ id }) => {
const { setLoadingStatus } = useContext(LoadingStatusContext) const { setLoadingStatus } = useContext(LoadingStatusContext)
const backend = useBackend() const backend = useBackend()
const { t, i18n } = useTranslation(ns) const { t, i18n } = useTranslation(ns)
// FIXME: implement a solution for loading docs dynamically
const docs = {}
for (const option of ['name', 'units', 'public', 'notes', 'image']) {
docs[option] = <DynamicOrgDocs language={i18n.language} path={`site/patterns/${option}`} />
}
// Context // Context
const { setModal } = useContext(ModalContext) const { setModal } = useContext(ModalContext)
@ -380,9 +375,9 @@ export const Pattern = ({ id }) => {
update={setName} update={setName}
current={name} current={name}
original={pattern.name} original={pattern.name}
docs={docs.name}
placeholder="Maurits Cornelis Escher" placeholder="Maurits Cornelis Escher"
valid={(val) => val && val.length > 0} valid={(val) => val && val.length > 0}
docs={<DynamicMdx language={i18n.language} slug="docs/site/patterns/name" />}
/> />
{/* img: Control level determines whether or not to show this */} {/* img: Control level determines whether or not to show this */}
@ -393,8 +388,8 @@ export const Pattern = ({ id }) => {
label={t('image')} label={t('image')}
update={setImage} update={setImage}
current={image} current={image}
docs={docs.image}
valid={(val) => val.length > 0} valid={(val) => val.length > 0}
docs={<DynamicMdx language={i18n.language} slug="docs/site/patterns/image" />}
/> />
) : null} ) : null}
@ -405,7 +400,6 @@ export const Pattern = ({ id }) => {
id="pattern-public" id="pattern-public"
label={t('public')} label={t('public')}
update={setIsPublic} update={setIsPublic}
docs={docs.public}
list={[ list={[
{ {
val: true, val: true,
@ -432,6 +426,7 @@ export const Pattern = ({ id }) => {
}, },
]} ]}
current={isPublic} current={isPublic}
docs={<DynamicMdx language={i18n.language} slug="docs/site/patterns/public" />}
/> />
) : null} ) : null}
@ -442,9 +437,9 @@ export const Pattern = ({ id }) => {
id="pattern-notes" id="pattern-notes"
label={t('notes')} label={t('notes')}
update={setNotes} update={setNotes}
docs={docs.notes}
current={notes} current={notes}
placeholder={t('mdSupport')} placeholder={t('mdSupport')}
docs={<DynamicMdx language={i18n.language} slug="docs/site/patterns/notes" />}
/> />
) : null} ) : null}
<button <button

View file

@ -9,7 +9,7 @@ import { useBackend } from 'shared/hooks/use-backend.mjs'
import { BackToAccountButton } from './shared.mjs' import { BackToAccountButton } from './shared.mjs'
import { SaveSettingsButton } from 'shared/components/buttons/save-settings-button.mjs' import { SaveSettingsButton } from 'shared/components/buttons/save-settings-button.mjs'
import { StringInput } from 'shared/components/inputs.mjs' import { StringInput } from 'shared/components/inputs.mjs'
import { DynamicOrgDocs } from 'site/components/dynamic-org-docs.mjs' import { DynamicMdx } from 'shared/components/mdx/dynamic.mjs'
export const ns = ['account', 'status'] export const ns = ['account', 'status']
@ -46,7 +46,7 @@ export const PlatformSettings = ({ platform }) => {
update={setPlatformId} update={setPlatformId}
valid={(val) => val.length > 0} valid={(val) => val.length > 0}
placeholder={'joostdecock'} placeholder={'joostdecock'}
docs={<DynamicOrgDocs language={i18n.language} path={`site/account/platform`} />} docs={<DynamicMdx language={i18n.language} slug={`docs/site/account/platform`} />}
/> />
<SaveSettingsButton btnProps={{ onClick: save }} /> <SaveSettingsButton btnProps={{ onClick: save }} />
<BackToAccountButton /> <BackToAccountButton />

View file

@ -43,7 +43,6 @@ import { ModalWrapper } from 'shared/components/wrappers/modal.mjs'
import Markdown from 'react-markdown' import Markdown from 'react-markdown'
import Timeago from 'react-timeago' import Timeago from 'react-timeago'
import { DisplayRow } from './shared.mjs' import { DisplayRow } from './shared.mjs'
import { DynamicOrgDocs } from 'site/components/dynamic-org-docs.mjs'
import { import {
StringInput, StringInput,
PassiveImageInput, PassiveImageInput,
@ -54,6 +53,7 @@ import {
ns as inputNs, ns as inputNs,
} from 'shared/components/inputs.mjs' } from 'shared/components/inputs.mjs'
import { BookmarkButton } from 'shared/components/bookmarks.mjs' import { BookmarkButton } from 'shared/components/bookmarks.mjs'
import { DynamicMdx } from 'shared/components/mdx/dynamic.mjs'
export const ns = [inputNs, 'account', 'patterns', 'status', 'measurements', 'sets'] export const ns = [inputNs, 'account', 'patterns', 'status', 'measurements', 'sets']
@ -192,16 +192,6 @@ export const Mset = ({ id, publicOnly = false }) => {
const { setLoadingStatus } = useContext(LoadingStatusContext) const { setLoadingStatus } = useContext(LoadingStatusContext)
const backend = useBackend() const backend = useBackend()
const { t, i18n } = useTranslation(ns) const { t, i18n } = useTranslation(ns)
// FIXME: implement a solution for loading docs dynamically the is simple and work as expected
const docs = {}
for (const option of ['name', 'units', 'public', 'notes', 'image']) {
docs[option] = <DynamicOrgDocs language={i18n.language} path={`site/sets/${option}`} />
}
// FIXME: implement a solution for loading docs dynamically the is simple and work as expected
const measieDocs = {}
for (const m of measurements) {
measieDocs[m] = <DynamicOrgDocs language={i18n.language} path={`measurements/${m}`} />
}
// Context // Context
const { setModal } = useContext(ModalContext) const { setModal } = useContext(ModalContext)
@ -293,6 +283,11 @@ export const Mset = ({ id, publicOnly = false }) => {
} else setLoadingStatus([true, 'backendError', true, false]) } else setLoadingStatus([true, 'backendError', true, false])
} }
const docs = {}
for (const option of ['name', 'units', 'public', 'notes', 'image']) {
docs[option] = <DynamicMdx language={i18n.language} slug={`docs/site/sets/${option}`} />
}
const heading = ( const heading = (
<> <>
<div className="flex flex-wrap md:flex-nowrap flex-row gap-2 w-full"> <div className="flex flex-wrap md:flex-nowrap flex-row gap-2 w-full">
@ -490,17 +485,6 @@ export const Mset = ({ id, publicOnly = false }) => {
label={t('filterByDesign')} label={t('filterByDesign')}
current={filter} current={filter}
firstOption={<option value="">{t('noFilter')}</option>} firstOption={<option value="">{t('noFilter')}</option>}
docs={
<div className="max-w-prose">
<h2>
{t('measies')}: {t('filterByDesign')}
</h2>
<p>
If you have a specific design in mind, you can <b>filter by design</b> to only list
those measurements that are required for this design.
</p>
</div>
}
/> />
</div> </div>
{filterMeasurements().map((mplus) => { {filterMeasurements().map((mplus) => {
@ -511,12 +495,14 @@ export const Mset = ({ id, publicOnly = false }) => {
id={`measie-${m}`} id={`measie-${m}`}
key={m} key={m}
m={m} m={m}
docs={measieDocs[m]}
imperial={mset.imperial} imperial={mset.imperial}
label={translated} label={translated}
current={mset.measies[m]} current={mset.measies[m]}
original={mset.measies[m]} original={mset.measies[m]}
update={updateMeasies} update={updateMeasies}
docs={
<DynamicMdx language={i18n.language} slug={`docs/measurements/${m.toLowerCase()}`} />
}
/> />
) )
})} })}
@ -531,9 +517,9 @@ export const Mset = ({ id, publicOnly = false }) => {
update={setName} update={setName}
current={name} current={name}
original={mset.name} original={mset.name}
docs={docs.name}
placeholder="Georg Cantor" placeholder="Georg Cantor"
valid={(val) => val && val.length > 0} valid={(val) => val && val.length > 0}
docs={docs.name}
/> />
{/* img: Control level determines whether or not to show this */} {/* img: Control level determines whether or not to show this */}
@ -544,8 +530,8 @@ export const Mset = ({ id, publicOnly = false }) => {
label={t('image')} label={t('image')}
update={setImage} update={setImage}
current={image} current={image}
docs={docs.image}
valid={(val) => val.length > 0} valid={(val) => val.length > 0}
docs={docs.image}
/> />
) : null} ) : null}
@ -556,7 +542,6 @@ export const Mset = ({ id, publicOnly = false }) => {
id="set-public" id="set-public"
label={t('public')} label={t('public')}
update={setIsPublic} update={setIsPublic}
docs={docs.public}
list={[ list={[
{ {
val: true, val: true,
@ -583,6 +568,7 @@ export const Mset = ({ id, publicOnly = false }) => {
}, },
]} ]}
current={isPublic} current={isPublic}
docs={docs.public}
/> />
) : null} ) : null}
@ -592,7 +578,6 @@ export const Mset = ({ id, publicOnly = false }) => {
<ListInput <ListInput
id="set-units" id="set-units"
label={t('units')} label={t('units')}
docs={docs.units}
update={setImperial} update={setImperial}
list={[ list={[
{ {
@ -617,6 +602,7 @@ export const Mset = ({ id, publicOnly = false }) => {
}, },
]} ]}
current={imperial} current={imperial}
docs={docs.units}
/> />
) : null} ) : null}
@ -627,9 +613,9 @@ export const Mset = ({ id, publicOnly = false }) => {
id="set-notes" id="set-notes"
label={t('notes')} label={t('notes')}
update={setNotes} update={setNotes}
docs={docs.notes}
current={notes} current={notes}
placeholder={t('mdSupport')} placeholder={t('mdSupport')}
docs={docs.notes}
/> />
) : null} ) : null}
<button <button

View file

@ -10,7 +10,7 @@ import { Icons, welcomeSteps, BackToAccountButton } from './shared.mjs'
import { OkIcon, NoIcon } from 'shared/components/icons.mjs' import { OkIcon, NoIcon } from 'shared/components/icons.mjs'
import { ContinueButton } from 'shared/components/buttons/continue-button.mjs' import { ContinueButton } from 'shared/components/buttons/continue-button.mjs'
import { StringInput } from 'shared/components/inputs.mjs' import { StringInput } from 'shared/components/inputs.mjs'
import { DynamicOrgDocs } from 'site/components/dynamic-org-docs.mjs' import { DynamicMdx } from 'shared/components/mdx/dynamic.mjs'
export const ns = ['account', 'status'] export const ns = ['account', 'status']
@ -72,7 +72,7 @@ export const UsernameSettings = ({ welcome = false }) => {
)} )}
</span> </span>
} }
docs={<DynamicOrgDocs language={i18n.language} path={`site/account/username`} />} docs={<DynamicMdx language={i18n.language} slug={`docs/site/account/username`} />}
/> />
<button className={btnClasses} disabled={!available} onClick={save}> <button className={btnClasses} disabled={!available} onClick={save}>
<span className="flex flex-row items-center gap-2"> <span className="flex flex-row items-center gap-2">

View file

@ -21,7 +21,6 @@ import { ns as designNs } from 'shared/components/designs/design.mjs'
import { Difficulty } from 'shared/components/designs/difficulty.mjs' import { Difficulty } from 'shared/components/designs/difficulty.mjs'
import { PageLink, AnchorLink, Link } from 'shared/components/link.mjs' import { PageLink, AnchorLink, Link } from 'shared/components/link.mjs'
import { DocsLink, DocsTitle } from 'shared/components/mdx/docs-helpers.mjs' import { DocsLink, DocsTitle } from 'shared/components/mdx/docs-helpers.mjs'
import { DynamicOrgDocs as DynamicDocs } from 'site/components/dynamic-org-docs.mjs'
import { Popout } from 'shared/components/popout/index.mjs' import { Popout } from 'shared/components/popout/index.mjs'
import { NewPatternIcon } from 'shared/components/icons.mjs' import { NewPatternIcon } from 'shared/components/icons.mjs'
@ -40,10 +39,7 @@ export const ns = nsMerge(
const Option = ({ id, option, t, design }) => const Option = ({ id, option, t, design }) =>
optionType(option) === 'constant' ? null : ( optionType(option) === 'constant' ? null : (
<li key={option.name}> <li key={option.name}>
<PageLink <DocsLink site="org" slug={`docs/designs/${design}/options/${id.toLowerCase()}`} />
txt={t(`${design}:${option.name}.t`)}
href={`/docs/designs/${design}/options/${id.toLowerCase()}`}
/>
</li> </li>
) )
@ -168,7 +164,6 @@ export const DesignInfo = ({ design, docs = false, workbench = false }) => {
format={(t) => t.split(':').pop().trim()} format={(t) => t.split(':').pop().trim()}
/> />
</h2> </h2>
<DynamicDocs path={`designs/${design}/notes`} language={language} noFooter noTitle />
</> </>
)} )}
{docs ? docsContent : null} {docs ? docsContent : null}
@ -229,12 +224,6 @@ export const DesignInfo = ({ design, docs = false, workbench = false }) => {
format={(t) => t.split(':').pop().trim()} format={(t) => t.split(':').pop().trim()}
/> />
</h2> </h2>
<DynamicDocs
path={`designs/${design}/${page}`}
language={language}
noFooter
noTitle
/>
</Fragment> </Fragment>
))} ))}

View file

@ -1,59 +0,0 @@
import dynamic from 'next/dynamic'
import { useState } from 'react'
import { Spinner } from 'shared/components/spinner.mjs'
import { MdxWrapper } from './wrapper.mjs'
import { components } from 'shared/components/mdx/index.mjs'
const orgComponents = components()
export const loaders = {
en: (path) => import(`orgmarkdown/docs/${path}/en.md`),
de: (path) => import(`orgmarkdown/docs/${path}/de.md`),
fr: (path) => import(`orgmarkdown/docs/${path}/fr.md`),
es: (path) => import(`orgmarkdown/docs/${path}/es.md`),
nl: (path) => import(`orgmarkdown/docs/${path}/nl.md`),
uk: (path) => import(`orgmarkdown/docs/${path}/uk.md`),
}
/*
* Webpack will check on disk for all possible files matching this
* dynamic import. So unless we divide it up a bit your computer
* will melt when running this in development mode
*
* This will return a language-specific component
*/
function DynamicDocs({ path, lang, noFooter = false, noTitle = false }) {
const [frontmatter, setFrontmatter] = useState({})
const mdx = dynamic(
() =>
loaders[lang](path).then((mod) => {
setFrontmatter(mod.frontmatter)
return mod
}),
{ ssr: false }
)
const MDX = mdx ? mdx : <Spinner className="w16 h-16 animate-spin text-primary" />
return (
<MdxWrapper
path={path}
language={lang}
noFooter={noFooter}
title={noTitle ? false : frontmatter.title}
>
<MDX components={orgComponents} />
</MdxWrapper>
)
}
/*
* Return language-specific component
*/
export const DynamicOrgDocs = ({
path = false,
language = 'en',
noTitle = false,
noFooter = false,
}) => {
if (!path) return null
return <DynamicDocs lang={language} {...{ path, noTitle, noFooter }} />
}

View file

@ -1,22 +0,0 @@
import { PageLink } from 'shared/components/link.mjs'
import { DocsIcon } from 'shared/components/icons.mjs'
export const MdxWrapper = ({ title = false, path, language, children, noFooter = false }) => {
const slug = `${language === 'en' ? '' : '/' + language}/docs/${path}`
return (
<>
{title ? <h1>{title}</h1> : null}
<div className="mdx text-base-content">{children}</div>
{noFooter ? null : (
<div
className={`flex flex-row gap-1 text-sm opacity-70 justify-end items-center
border border-solid border-neutral border-b-0 border-r-0 border-l-0 pt-1 mt-2`}
>
<DocsIcon className="w-5 h-5" />
<PageLink txt={slug} href={slug} />
</div>
)}
</>
)
}

View file

@ -1,53 +0,0 @@
import dynamic from 'next/dynamic'
import { MDXProvider } from '@mdx-js/react'
import { useState } from 'react'
import { Spinner } from 'shared/components/spinner.mjs'
import { PageLink } from 'shared/components/link.mjs'
import { useTranslation } from 'next-i18next'
import { components } from 'shared/components/mdx/index.mjs'
export const ns = ['modal']
export const MdxWrapper = ({ title = false, path, language, children }) => {
const { t } = useTranslation(ns)
const slug = `${language === 'en' ? '' : '/' + language}/docs/${path}`
return (
<>
{title ? <h1>{title}</h1> : null}
<div className="mdx text-base-content text-base">
<MDXProvider components={components}>{children}</MDXProvider>
</div>
<div
className={`flex flex-row gap-1 text-sm opacity-70 justify-end items-center
border border-solid border-neutral border-b-0 border-r-0 border-l-0 pt-1 mt-2`}
>
<span>{t('modal:source')}:</span>
<PageLink txt={slug} href={slug} />
</div>
</>
)
}
export const DynamicMdx = ({ path = false, language = 'en' }) => {
// Extract frontmatter from mdx
const [frontmatter, setFrontmatter] = useState({})
// Dynamic import of the MDX content
const mdx = dynamic(
() =>
import(`markdown/docs/${path}/${language}.md`).then((mod) => {
setFrontmatter(mod.frontmatter)
return mod
}),
{ ssr: false }
)
const MDX = mdx ? mdx : <Spinner className="w16 h-16 animate-spin text-primary" />
return (
<MdxWrapper {...{ path, language, ...frontmatter }}>
<MDX components={components} />
</MdxWrapper>
)
}

View file

@ -0,0 +1,51 @@
// Dependencies
import { compileMdx } from 'shared/mdx/browser-compile.mjs'
import * as runtime from 'react/jsx-runtime'
import { run } from '@mdx-js/mdx'
// Hooks
import { useState, useEffect } from 'react'
// Components
import { MdxWrapper } from 'shared/components/wrappers/mdx.mjs'
import { Loading } from 'shared/components/spinner.mjs'
const ghPrefix = 'https://raw.githubusercontent.com/freesewing/freesewing/develop/markdown'
const fromGithub = true
const titles = {
1: ({ title }) => <h1>{title}</h1>,
2: ({ title }) => <h2>{title}</h2>,
3: ({ title }) => <h3>{title}</h3>,
4: ({ title }) => <h4>{title}</h4>,
5: ({ title }) => <h5>{title}</h5>,
6: ({ title }) => <h6>{title}</h6>,
}
const NoTitle = () => null
export const DynamicMdx = ({ site = 'org', slug, language, title = 1 }) => {
const [mdx, setMdx] = useState(false)
const [frontmatter, setFrontmatter] = useState(false)
useEffect(() => {
const loadMdx = async () => {
const response = await fetch(`${ghPrefix}/${site}/${slug}/${language}.md`)
const md = await response.text()
const mdx = await compileMdx({ site, slug, language, md, fromGithub })
const { frontmatter: fm } = await run(mdx, runtime)
setMdx(mdx)
setFrontmatter(fm)
}
if (!mdx) loadMdx()
}, [site, slug, language])
const Title = title && frontmatter?.title && titles[Number(title)] ? titles[title] : () => null
return mdx ? (
<>
<Title title={frontmatter?.title} />
<MdxWrapper {...{ mdx, site, slug }} />
</>
) : (
<Loading />
)
}

View file

@ -10,10 +10,10 @@ import { EditIcon } from 'shared/components/icons.mjs'
import { useAccount } from 'shared/hooks/use-account.mjs' import { useAccount } from 'shared/hooks/use-account.mjs'
// Components // Components
import { PageLink } from 'shared/components/link.mjs' import { PageLink } from 'shared/components/link.mjs'
import { TimeAgo } from 'shared/components/timeago/index.mjs' import { TimeAgo, ns as timeagoNs } from 'shared/components/timeago/index.mjs'
import { BookmarkButton } from 'shared/components/bookmarks.mjs' import { BookmarkButton } from 'shared/components/bookmarks.mjs'
export const ns = 'account' export const ns = ['account', timeagoNs]
const PersonList = ({ list }) => const PersonList = ({ list }) =>
list ? ( list ? (

View file

@ -11,7 +11,7 @@ import Link from 'next/link'
import { Robot } from 'shared/components/robot/index.mjs' import { Robot } from 'shared/components/robot/index.mjs'
import { StringInput, PasswordInput } from 'shared/components/inputs.mjs' import { StringInput, PasswordInput } from 'shared/components/inputs.mjs'
import { FreeSewingAnimation } from 'shared/components/animations/freesewing.mjs' import { FreeSewingAnimation } from 'shared/components/animations/freesewing.mjs'
import { DynamicOrgDocs } from 'site/components/dynamic-org-docs.mjs' import { DynamicMdx } from 'shared/components/mdx/dynamic.mjs'
// Translation namespaces used on this page // Translation namespaces used on this page
export const ns = ['signup', 'errros', 'account'] export const ns = ['signup', 'errros', 'account']
@ -114,7 +114,7 @@ export const Migrate = () => {
current={username} current={username}
update={setUsername} update={setUsername}
valid={(val) => val.length > 1} valid={(val) => val.length > 1}
docs={<DynamicOrgDocs language={i18n.language} path={`site/account/username`} />} docs={<DynamicMdx language={i18n.language} slug={`docs/site/account/username`} />}
/> />
<PasswordInput <PasswordInput
id="migrate-password" id="migrate-password"
@ -123,7 +123,7 @@ export const Migrate = () => {
current={password} current={password}
update={setPassword} update={setPassword}
valid={(val) => val.length > 1} valid={(val) => val.length > 1}
docs={<DynamicOrgDocs language={i18n.language} path={`site/account/password`} />} docs={<DynamicMdx language={i18n.language} slug={`docs/site/account/password`} />}
/> />
<button <button
className="btn btn-primary btn-lg w-full mt-4" className="btn btn-primary btn-lg w-full mt-4"

View file

@ -2,7 +2,7 @@
import { nsMerge } from 'shared/utils.mjs' import { nsMerge } from 'shared/utils.mjs'
import { MeasieInput, ns as inputNs } from 'shared/components/inputs.mjs' import { MeasieInput, ns as inputNs } from 'shared/components/inputs.mjs'
import { useTranslation } from 'next-i18next' import { useTranslation } from 'next-i18next'
import { DynamicOrgDocs } from 'site/components/dynamic-org-docs.mjs' import { DynamicMdx } from 'shared/components/mdx/dynamic.mjs'
export const ns = nsMerge('workbench', inputNs) export const ns = nsMerge('workbench', inputNs)
@ -22,8 +22,10 @@ export const MeasiesEditor = ({ Design, settings, update }) => {
imperial={settings.units === 'umperial' ? true : false} imperial={settings.units === 'umperial' ? true : false}
original={settings.measurements?.[m]} original={settings.measurements?.[m]}
update={(m, newVal) => onUpdate(m, newVal)} update={(m, newVal) => onUpdate(m, newVal)}
docs={<DynamicOrgDocs language={i18n.language} path={`measurements/${m}`} />}
id={`edit-${m}`} id={`edit-${m}`}
docs={
<DynamicMdx language={i18n.language} slug={`docs/measurements/${m.toLowerCase()}`} />
}
/> />
))} ))}
</div> </div>

View file

@ -28,13 +28,13 @@ import {
} from 'shared/components/icons.mjs' } from 'shared/components/icons.mjs'
import { Popout } from 'shared/components/popout/index.mjs' import { Popout } from 'shared/components/popout/index.mjs'
import { PageLink } from 'shared/components/link.mjs' import { PageLink } from 'shared/components/link.mjs'
import { DynamicOrgDocs } from 'site/components/dynamic-org-docs.mjs' import { DynamicMdx } from 'shared/components/mdx/dynamic.mjs'
export const ns = ['workbench', 'status'] export const ns = ['workbench', 'status']
export const SaveView = ({ design, settings, setView, saveAs }) => { export const SaveView = ({ design, settings, setView, saveAs }) => {
// Hooks // Hooks
const { t } = useTranslation(ns) const { t, i18n } = useTranslation(ns)
const backend = useBackend() const backend = useBackend()
const router = useRouter() const router = useRouter()
const { setLoadingStatus } = useContext(LoadingStatusContext) const { setLoadingStatus } = useContext(LoadingStatusContext)
@ -112,6 +112,11 @@ export const SaveView = ({ design, settings, setView, saveAs }) => {
} else setLoadingStatus([true, 'backendError', true, false]) } else setLoadingStatus([true, 'backendError', true, false])
} }
const docs = {}
for (const field of ['name', 'notes', 'goto']) {
docs[field] = <DynamicMdx language={i18n.language} slug={`docs/site/patterns/${field}`} />
}
return ( return (
<AuthWrapper> <AuthWrapper>
<div className="m-auto mt-8 max-w-2xl px-4"> <div className="m-auto mt-8 max-w-2xl px-4">
@ -154,7 +159,7 @@ export const SaveView = ({ design, settings, setView, saveAs }) => {
current={name} current={name}
update={setName} update={setName}
valid={notEmpty} valid={notEmpty}
docs={<DynamicOrgDocs language={router.locale} path={`site/patterns/name`} />} docs={docs.name}
/> />
{withNotes ? ( {withNotes ? (
@ -162,7 +167,7 @@ export const SaveView = ({ design, settings, setView, saveAs }) => {
label={t('workbench:notes')} label={t('workbench:notes')}
current={notes} current={notes}
update={setNotes} update={setNotes}
docs={<DynamicOrgDocs language={router.locale} path={`site/patterns/notes`} />} docs={docs.notes}
/> />
) : null} ) : null}
</div> </div>
@ -170,6 +175,7 @@ export const SaveView = ({ design, settings, setView, saveAs }) => {
update={setEditAfterSaveAs} update={setEditAfterSaveAs}
label={t('workbench:whereToGoAfterSaveAs')} label={t('workbench:whereToGoAfterSaveAs')}
current={editAfterSaveAs} current={editAfterSaveAs}
docs={docs.goto}
list={[ list={[
{ {
val: true, val: true,

View file

@ -1,7 +1,7 @@
// __SDEFILE__ - This file is a dependency for the stand-alone environment // __SDEFILE__ - This file is a dependency for the stand-alone environment
// Dependencies // Dependencies
import * as runtime from 'react/jsx-runtime' import * as runtime from 'react/jsx-runtime'
import { runSync } from '@mdx-js/mdx' import { run, runSync } from '@mdx-js/mdx'
import { useState, useEffect } from 'react' import { useState, useEffect } from 'react'
// Components that are available in MDX content // Components that are available in MDX content
import { components as baseComponents } from 'shared/components/mdx/index.mjs' import { components as baseComponents } from 'shared/components/mdx/index.mjs'
@ -14,7 +14,7 @@ import { Loading } from 'shared/components/spinner.mjs'
* This is the default async version * This is the default async version
*/ */
const runMdx = async (mdx) => { const runMdx = async (mdx) => {
const { default: Content } = await runSync(mdx, runtime) const { default: Content } = await run(mdx, runtime)
return Content return Content
} }

View file

@ -0,0 +1,36 @@
// MDX compiler
import { compile } from '@mdx-js/mdx'
// Remark plugins from the ecosystem
import remarkFrontmatter from 'remark-frontmatter'
import remarkMdxFrontmatter from 'remark-mdx-frontmatter'
import remarkGfm from 'remark-gfm'
import smartypants from 'remark-smartypants'
// FreeSewing custom remark plugins
import { remarkGithubImages } from './remark-github-images.mjs'
/*
* Compiles markdown/mdx to a function body
*/
export const compileMdx = async ({
md, // A string holding the markdown
site, // The site folder, one of 'org' or 'dev'
slug, // The slug to the page below the folder (like 'guides/plugins')
jargon, // An object of jargon definitions. See rehype-jargon
fromGithub = false, // Set this to true when dynamically loading mdx from Github
}) => {
const mdx = String(
await compile(md, {
outputFormat: 'function-body',
development: false,
remarkPlugins: [
remarkFrontmatter,
remarkMdxFrontmatter,
remarkGfm,
smartypants,
[remarkGithubImages, { site, slug }],
],
})
)
return mdx
}

View file

@ -11,6 +11,7 @@ import smartypants from 'remark-smartypants'
// FreeSewing custom remark plugins // FreeSewing custom remark plugins
import { remarkIntroAsFrontmatter } from './remark-intro-as-frontmatter.mjs' import { remarkIntroAsFrontmatter } from './remark-intro-as-frontmatter.mjs'
import { remarkTocAsFrontmatter } from './remark-toc-as-frontmatter.mjs' import { remarkTocAsFrontmatter } from './remark-toc-as-frontmatter.mjs'
import { remarkGithubImages } from './remark-github-images.mjs'
// Rehype plugins from the ecosystem // Rehype plugins from the ecosystem
import rehypeHighlight from 'rehype-highlight' import rehypeHighlight from 'rehype-highlight'
import rehypeAutolinkHeadings from 'rehype-autolink-headings' import rehypeAutolinkHeadings from 'rehype-autolink-headings'
@ -28,6 +29,7 @@ export const compileMdx = async ({
site, // The site folder, one of 'org' or 'dev' site, // The site folder, one of 'org' or 'dev'
slug, // The slug to the page below the folder (like 'guides/plugins') slug, // The slug to the page below the folder (like 'guides/plugins')
jargon, // An object of jargon definitions. See rehype-jargon jargon, // An object of jargon definitions. See rehype-jargon
fromGithub = false, // Set this to true when dynamically loading mdx from Github
}) => { }) => {
const mdx = String( const mdx = String(
await compile(md, { await compile(md, {
@ -38,14 +40,16 @@ export const compileMdx = async ({
remarkMdxFrontmatter, remarkMdxFrontmatter,
remarkGfm, remarkGfm,
smartypants, smartypants,
[ fromGithub
remarkCopyLinkedFiles, ? remarkGithubImages
{ : [
destinationDir: path.resolve(`../${site}/public/mdx`), remarkCopyLinkedFiles,
sourceDir: path.resolve(`../../markdown/${site}/${slug}`), {
staticPath: '/mdx/', destinationDir: path.resolve(`../${site}/public/mdx`),
}, sourceDir: path.resolve(`../../markdown/${site}/${slug}`),
], staticPath: '/mdx/',
},
],
remarkTocAsFrontmatter, remarkTocAsFrontmatter,
remarkIntroAsFrontmatter, remarkIntroAsFrontmatter,
], ],

View file

@ -2,6 +2,7 @@ import fs from 'fs'
import path from 'path' import path from 'path'
import { compileMdx } from './compile.mjs' import { compileMdx } from './compile.mjs'
import { jargon } from 'shared/jargon/index.mjs' import { jargon } from 'shared/jargon/index.mjs'
import { ghPrefix } from './remark-github-images.mjs'
/* /*
* Loads markdown/mdx from disk * Loads markdown/mdx from disk
@ -13,6 +14,20 @@ export const loadMdxFromDisk = async ({
}) => }) =>
await fs.promises.readFile(path.resolve(`../../markdown/${site}/${slug}/${language}.md`), 'utf-8') await fs.promises.readFile(path.resolve(`../../markdown/${site}/${slug}/${language}.md`), 'utf-8')
/*
* Loads markdown/mdx from Github
*/
export const loadMdxFromGithub = async ({
language, // The language code of the markdown to load (like 'en')
site, // The site folder, one of 'dev' or 'org'
slug, // The slug below that folder, like 'guides/plugins'
}) => {
const response = await fetch(`${ghPrefix}/${site}/${slug}/${language}.md`)
const md = await response.text()
return md
}
/* /*
* Loads markdown/mdx from disk and compiles it for use * Loads markdown/mdx from disk and compiles it for use
* in static props. * in static props.
@ -24,7 +39,7 @@ export const loadMdxAsStaticProps = async ({
slugs = {}, // An object where key is an ID and value the slug to load slugs = {}, // An object where key is an ID and value the slug to load
}) => { }) => {
const result = {} const result = {}
if (slug) result.default = slug if (slug) slugs.default = slug
for (const [key, val] of Object.entries(slugs)) { for (const [key, val] of Object.entries(slugs)) {
const md = await loadMdxFromDisk({ language, site, slug: val }) const md = await loadMdxFromDisk({ language, site, slug: val })
const mdx = await compileMdx({ const mdx = await compileMdx({
@ -33,7 +48,7 @@ export const loadMdxAsStaticProps = async ({
slug: val, slug: val,
jargon: jargon[language], jargon: jargon[language],
}) })
result[key] = { mdx, slug: val } result[key] = { ...mdx, slug: val }
} }
return slug ? result.default : result return slug ? result.default : result

View file

@ -0,0 +1,28 @@
/*
* This is a remark plugin that will update the src of local images to
* load them from Github. It is used when we load markdown/mdx dynamically
* from Github rather than from disk.
*/
import { visit } from 'unist-util-visit'
export const ghPrefix = 'https://raw.githubusercontent.com/freesewing/freesewing/develop/markdown'
const convertUrl = ({ site, slug, url }) => {
if (url.slice(0, 1) === 'http://') return url
if (url.slice(0, 7) === 'http://') return url
if (url.slice(0, 8) === 'https://') return url
return `${ghPrefix}/${site}/${slug}/${url}`
}
export function remarkGithubImages({ site, slug }) {
return (tree) => {
visit(tree, function (node, index, parent) {
if (node.type === 'image') node.url = convertUrl({ site, slug, url: node.url })
return node
})
return tree
}
}