Skip to content

Commit

Permalink
Feat Custom components (#8)
Browse files Browse the repository at this point in the history
* feat: Add custom component to markdown-remark integration

- Add a new custom component called "Custom" to the markdown-remark integration in Astro.
- The custom component is defined in the file "packages/markdown-remark/tests/fixture/astro/src/pages/custom-components/_comps/Custom.astro".
- This component will be used when processing markdown content.

* Refactor markdown-remark integration to remove unused code

* Refactor markdown-remark integration to remove unused code

* Refactor markdown-remark integration to clean up code

* Refactor markdown-remark integration to remove unused code and optimize component exports

* Refactor markdown-remark integration to optimize component exports

* Refactor markdown-remark integration to optimize component exports and remove unused code

* Refactor markdown-remark integration to optimize component exports and update type definition

* Refactor markdown-remark integration to optimize component exports and remove unused code

* add changeset

* Refactor markdown-remark integration to include callouts in shared state

* ensure all components are auto-converted to lowercase so they meet HTML spec

* refactor config

* Refactor markdown-remark integration to optimize config

* Refactor markdown-remark integration to update import paths

* Update readme to match new schema

* Refactor markdown-remark integration to update import paths and optimize config
  • Loading branch information
Adammatthiesen authored Jan 6, 2025
1 parent 0c76c8a commit 6b0053b
Show file tree
Hide file tree
Showing 26 changed files with 598 additions and 142 deletions.
27 changes: 27 additions & 0 deletions .changeset/wicked-bikes-raise.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
---
"@studiocms/markdown-remark": minor
---

Introduce custom User-Defined component handling.

This update includes significant enhancements to the Markdown Remark processor Astro Integration, allowing for more flexible and powerful Markdown rendering with custom components.

### New Features:

- Added custom components support in the Markdown Remark processor Astro Integration.
- Introduced utility functions in `utils.ts` for component proxy creation, indentation handling, dedenting strings, and merging records.
- Moved zod schema to separate `schema.ts` file.

### Integration Updates:

- Enhanced Astro integration to support custom components configuration via `astro.config.mjs`.
- Updated `markdown.ts` to include custom components during Markdown rendering.
- Extended `index.ts` to utilize the new schema and utilities.

### Documentation:

- Updated `README.md` with instructions for setting up custom components in Astro integration.

### Dependencies:

- Added `entities` and `ultrahtml` as new dependencies.
28 changes: 25 additions & 3 deletions packages/markdown-remark/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ pnpm add @studiocms/markdown-remark

### As an Astro Integration

With the Astro integration enabled, you can either pass in custom components into your astro config, or manually for the specific render your trying to do shown in the following methods.

#### Setup the integration

**`astro.config.mjs`**
Expand All @@ -44,7 +46,24 @@ export default defineConfig({
* https://docs.astro.build/en/reference/configuration-reference/#markdown-options
*/
},
integrations: [markdownRemark()],
integrations: [markdownRemark({
// Used for injecting CSS for Headings and Callouts
injectCSS: true,
// User defined components that will be used when processing markdown
components: {
// Example of a custom defined component
custom: "./src/components/Custom.astro",
},
// Custom Markdown config
markdown: {
// Configure the available callout themes
callouts: {
theme: 'obsidian' // Can also be 'github' or 'vitepress'
},
autoLinkHeadings: true,
sanitize: {} // see https://github.com/natemoo-re/ultrahtml?tab=readme-ov-file#sanitization for full options
}
})],
});
```

Expand All @@ -55,6 +74,7 @@ export default defineConfig({
```astro
---
import { Markdown } from 'studiocms:markdown-remark';
import Custom from '../components/Custom.astro';
---
<html>
<head>
Expand All @@ -63,7 +83,7 @@ import { Markdown } from 'studiocms:markdown-remark';
<title>Example</title>
</head>
<body>
<Markdown content={`# Hello World!`} />
<Markdown content={`# Hello World! <custom></custom>`} components={{ custom: Custom }} />
</body>
</html>
```
Expand All @@ -73,8 +93,10 @@ OR
```astro
---
import { render } from 'studiocms:markdown-remark';
import Custom from '../components/Custom.astro';
const { html } = render('# Hello World!')
// @ts-ignore
const { html } = render('# Hello World! <custom></custom>', {}, { $$result, {custom: Custom} })
---
<html>
<head>
Expand Down
13 changes: 7 additions & 6 deletions packages/markdown-remark/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"types": "./dist/processor/index.d.ts",
"default": "./dist/processor/index.js"
},
"./assets/*": "./assets/*"
"./styles/*": "./dist/integration/styles/*"
},
"imports": {
"#import-plugin": {
Expand All @@ -30,14 +30,13 @@
}
},
"files": [
"dist",
"assets"
"dist"
],
"scripts": {
"prepublish": "pnpm build",
"build": "run-scripts build \"src/**/*.ts\" && tsc -p tsconfig.json",
"build:ci": "run-scripts build \"src/**/*.ts\"",
"dev": "run-scripts dev \"src/**/*.ts\"",
"build": "run-scripts build \"src/**/*.{ts,css}\" && tsc -p tsconfig.json",
"build:ci": "run-scripts build \"src/**/*.{ts,css}\"",
"dev": "run-scripts dev \"src/**/*.{ts,css}\"",
"test": "pnpm build && vitest run"
},
"peerDependencies": {
Expand All @@ -46,6 +45,7 @@
"dependencies": {
"@astrojs/prism": "^3.2.0",
"astro-integration-kit": "^0.18.0",
"entities": "^6.0.0",
"github-slugger": "^2.0.0",
"hastscript": "^9.0.0",
"hast-util-from-html": "^2.0.3",
Expand All @@ -64,6 +64,7 @@
"remark-rehype": "^11.1.1",
"remark-smartypants": "^3.0.2",
"shiki": "^1.23.1",
"ultrahtml": "^1.5.3",
"unified": "^11.0.5",
"unist-util-remove-position": "^5.0.0",
"unist-util-visit": "^5.0.0",
Expand Down
6 changes: 5 additions & 1 deletion packages/markdown-remark/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
export * from './processor/index.js';
export { markdownRemark, markdownRemark as default } from './integration/index.js';
export {
markdownRemark,
default,
type StudioCMSMarkdownRemarkOptions,
} from './integration/index.js';
96 changes: 54 additions & 42 deletions packages/markdown-remark/src/integration/index.ts
Original file line number Diff line number Diff line change
@@ -1,79 +1,78 @@
import type { AstroIntegration } from 'astro';
import { addVirtualImports, createResolver } from 'astro-integration-kit';
import { z } from 'astro/zod';
import {
type StudioCMSMarkdownRemarkOptions,
StudioCMSMarkdownRemarkOptionsSchema,
} from './schema.js';
import { shared } from './shared.js';

const MarkdownRemarkOptionsSchema = z
.object({
/**
* Inject CSS for Rehype autolink headings styles.
*/
injectCSS: z.boolean().optional().default(true),

/**
* Options for the Markdown processor.
*/
markdown: z
.object({
/**
* Configures the callouts theme.
*/
callouts: z
.object({
/**
* The theme to use for callouts.
*/
theme: z
.union([z.literal('github'), z.literal('obsidian'), z.literal('vitepress')])
.optional()
.default('obsidian'),
})
.optional()
.default({}),
})
.optional()
.default({}),
})
.optional()
.default({});

export type MarkdownRemarkOptions = typeof MarkdownRemarkOptionsSchema._input;
export type { StudioCMSMarkdownRemarkOptions } from './schema.js';

/**
* Integrates the Markdown Remark processor into Astro available as `studiocms:markdown-remark`.
*
* @param {MarkdownRemarkOptions} opts Options for the Markdown Remark processor.
* @param {StudioCMSMarkdownRemarkOptions} opts Options for the Markdown Remark processor.
* @returns Astro integration.
*/
export function markdownRemark(opts?: MarkdownRemarkOptions): AstroIntegration {
const { injectCSS, markdown } = MarkdownRemarkOptionsSchema.parse(opts);
export function markdownRemark(opts?: StudioCMSMarkdownRemarkOptions): AstroIntegration {
// Parse the options
const { injectCSS, components, markdownExtended } =
StudioCMSMarkdownRemarkOptionsSchema.parse(opts);

// Create a resolver for the current file
const { resolve } = createResolver(import.meta.url);

// Resolve the callout theme based on the user's configuration
const resolvedCalloutTheme = resolve(
`../../assets/callout-themes/${markdown.callouts.theme}.css`
`./styles/callout-themes/${markdownExtended.callouts.theme}.css`
);

return {
name: '@studiocms/markdown-remark',
hooks: {
'astro:config:setup'(params) {
// Create a resolver for the Astro project root
const { resolve: astroRootResolve } = createResolver(params.config.root.pathname);

// Add virtual imports for the Markdown Remark processor
addVirtualImports(params, {
name: '@studiocms/markdown-remark',
imports: {
// The main Markdown Remark processor
'studiocms:markdown-remark': `export * from '${resolve('./markdown.js')}';`,
// Styles for the Markdown Remark processor
'studiocms:markdown-remark/css': `
import '${resolve('../../assets/headings.css')}';
import '${resolvedCalloutTheme}';
import '${resolve('./styles/headings.css')}';
${markdownExtended.callouts.enabled ? `import '${resolvedCalloutTheme}';` : ''}
`,
// User defined components for the Markdown processor
'studiocms:markdown-remark/user-components': `
export const componentKeys = ${JSON.stringify(Object.keys(components).map((name) => name.toLowerCase()))};
${Object.entries(components)
.map(
([name, path]) =>
`export { default as ${name.toLowerCase()} } from '${astroRootResolve(path)}';`
)
.join('\n')}
`,
},
});

// Inject the CSS for the Markdown processor if enabled
if (injectCSS) {
params.injectScript('page-ssr', 'import "studiocms:markdown-remark/css";');
}
},
'astro:config:done'({ injectTypes, config }) {
// Create a resolver for the Astro project root
const { resolve: astroRootResolve } = createResolver(config.root.pathname);

// Inject the Markdown configuration into the shared state
shared.markdownConfig = config.markdown;
shared.studiocms = markdownExtended;

// Inject types for the Markdown Remark processor
injectTypes({
filename: 'render.d.ts',
content: `// This file is generated by @studiocms/markdown-remark
Expand All @@ -84,9 +83,22 @@ export function markdownRemark(opts?: MarkdownRemarkOptions): AstroIntegration {
export type Props = import('${resolve('./markdown.js')}').Props;
export type RenderResponse = import('${resolve('./markdown.js')}').RenderResponse;
}
declare module 'studiocms:markdown-remark/user-components' {
export const componentKeys: string[];
${Object.entries(components)
.map(
([name, path]) =>
`export const ${name.toLowerCase()}: typeof import('${astroRootResolve(path)}').default;`
)
.join('\n')}
}
`,
});
},
},
};
}

export default markdownRemark;
Loading

0 comments on commit 6b0053b

Please sign in to comment.