Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
coverage
node_modules

.env
.idea/
.vscode/
*.code-*
Expand Down
13 changes: 13 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
include .env

.DEFAULT_GOAL := help
.PHONY: help
.EXPORT_ALL_VARIABLES:
Expand All @@ -14,6 +16,17 @@ example/public/img/emojis: node_modules/@readme/emojis
mkdir -p example/public/img/emojis
cp node_modules/@readme/emojis/src/img/*.png example/public/img/emojis/

mdx:
npm run build && \
cp -R dist/* ${README_PATH}/node_modules/@readme/mdx/dist && \
cd ${README_PATH} && \
npm run build --workspace=@readme/react && \
npm run build --workspace=@readme/bundles && \
npm run ui:build && \
echo "${NODE_ENV}" > public/data/build-env && \
npx ts-node ./bin/print-webpack-config.ts > ./build-time-webpack-config.json && \
npm run ui

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hee hee

ifeq ($(USE_LEGACY), true)
dockerfile = -f Dockerfile.legacy
endif
Expand Down
6 changes: 6 additions & 0 deletions __tests__/compilers/images.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,10 @@ describe('image compiler', () => {

expect(mdx(mdast(txt))).toMatch(txt);
});

it('correctly serializes an Image component back to MDX', () => {
const doc = '<Image src="/path/to/image.png" width="200px" alt="alt text" />';

expect(mdx(mdast(doc))).toMatch(doc);
});
});
2 changes: 1 addition & 1 deletion __tests__/html-block-parser.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { mdast } from '../index';

describe.skip('Parse html block', () => {
describe('Parse html block', () => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀

it('parses an html block', () => {
const text = `
<div>Some block html</div>
Expand Down
8 changes: 4 additions & 4 deletions __tests__/transformers/readme-components.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,10 @@ Second
</CodeTabs>
`,
},
image: {
md: `![](http://placekitten.com/600/200)`,
mdx: `<Image url="http://placekitten.com/600/200" />`,
},
// image: {
// md: `![](http://placekitten.com/600/200)`,
// mdx: `<Image src="http://placekitten.com/600/200" />`,
// },
table: {
md: `
| h1 | h2 |
Expand Down
2 changes: 1 addition & 1 deletion components/Embed/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ const Embed = ({ lazy = true, url, provider, title, html, iframe, image, favicon
) : (
<a className="embed-link" href={url} rel="noopener noreferrer" target="_blank">
{!image || <img alt={title} className="embed-img" loading={lazy ? 'lazy' : undefined} src={image} />}
{title ? (
{title && title !== '@embed' ? (
<div className="embed-body">
{!favicon || <Favicon alt={provider} src={favicon} />}
{provider && (
Expand Down
14 changes: 4 additions & 10 deletions processor/compile/embed.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,10 @@
import type { Embed } from "types";

const embed = (node: Embed) => {
const { image, favicon, iframe, title, url } = node.data?.hProperties || {};
const complexEmbed: boolean = Boolean(image) || Boolean(favicon) || iframe;

if (complexEmbed) {
const attributes = Object.keys(node.data?.hProperties).map(key => `${key}="${node.data?.hProperties[key]}"`).join(' ')
// TODO: make this a util
return `<Embed ${attributes} />`;
}

return `[${title}](${url} "@embed")'`;
// TODO: make this a util
const attributes = Object.keys(node.data?.hProperties).map(key => `${key}='${node.data?.hProperties[key]}'`).join(' ')

return `<Embed ${attributes} />`;
}

export default embed;
10 changes: 5 additions & 5 deletions processor/compile/image.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import type { Image } from 'mdast';

const image = (node: Image) => {
const { align, className, width } = node.data?.hProperties || {};
const complexImage: boolean = Boolean(width) || Boolean(className) || Boolean(align);

const { align, border, width, src } = node.data?.hProperties || {};
const complexImage: boolean = Boolean(width) || Boolean(border) || Boolean(align);
if (complexImage) {
const attributes = Object.keys(node.data?.hProperties)
.map(key => `${key}="${node.data?.hProperties[key]}"`)
.join(' ');
return `<Image ${attributes} />`;
}

return `![${node.alt}](${node.url}${node.title ? ` "${node.title}")` : ')'}`;
};
return `![${node.alt ?? ''}](${src ? src : node.url}${node.title ? ` "${node.title}")` : ')'})`;
}

export default image;
18 changes: 12 additions & 6 deletions processor/transform/embeds.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
import { visit } from 'unist-util-visit';

import { NodeTypes } from '../../enums';
import { Embed } from '../../types';

const embedTransformer = () => {
return (tree: any) => {
visit(tree, 'link', (node, _, parent) => {
if (parent.type !== 'paragraph' || parent.children.length > 1 || node.title !== '@embed') return;
visit(tree, 'link', (node, i, parent) => {

if (node.title !== '@embed') return;

const newNode = {
type: NodeTypes.embed,
data: {
hProperties: { title: node.children[0]?.value ?? node.url, url: node.url, provider: node.url },
hName: 'Embed',
hProperties: {
url: node.url,
title: node.title,
},
hName: 'embed',
},
position: node.position,
children: [],
};
} as Embed;

parent = newNode;
});
};
Expand Down
32 changes: 32 additions & 0 deletions processor/transform/images.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { visit } from 'unist-util-visit';

import { NodeTypes } from '../../enums';

const imageTransformer = () => {
return (tree: any) => {
visit(tree, 'image', (node, _, parent) => {
// check if inline or already transformed
if (parent.type !== 'paragraph' || parent.children.length > 1 || node.data?.hName === 'image') return;
const newNode = {
type: NodeTypes.image,
data: {
hProperties: {
title: node.title,
src: node.url,
alt: node.alt,
align: node.align,
border: node.border,
width: node.width,
caption: node.caption,
lazy: node.lazy,
},
hName: 'image',
},
position: node.position,
};
parent = newNode;
});
};
};

export default imageTransformer;
3 changes: 2 additions & 1 deletion processor/transform/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import calloutTransformer from './callouts';
import codeTabsTransfromer from './code-tabs';
import embedTransformer from './embeds';
import imageTransformer from './images';
import gemojiTransformer from './gemoji+';
import readmeComponentsTransformer from './readme-components';

export { readmeComponentsTransformer };

export default [calloutTransformer, codeTabsTransfromer, embedTransformer, gemojiTransformer];
export default [calloutTransformer, codeTabsTransfromer, embedTransformer, imageTransformer, gemojiTransformer];
26 changes: 13 additions & 13 deletions processor/transform/readme-components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,19 +52,19 @@ const coerceJsxToMd =
};

parent.children[index] = mdNode;
} else if (node.name === 'Image') {
const { position } = node;
const { alt = '', url, title = null } = attributes<Pick<Image, 'alt' | 'title' | 'url'>>(node);

const mdNode: Image = {
alt,
position,
title,
type: 'image',
url,
};

parent.children[index] = mdNode;
// } else if (node.name === 'Image') {
// const { position } = node;
// const { alt = '', url, title = null } = attributes<Pick<Image, 'alt' | 'title' | 'url'>>(node);

// const mdNode: Image = {
// alt,
// position,
// title,
// type: 'image',
// url,
// };

// parent.children[index] = mdNode;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kellyjosephprice i commented out some of your image stuff because it was gettin' rull weird with my changes and i figured we could work it out later

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this means 'complexImages' won't render as the image widget in the editor, right?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same for embeds, I think we need to convert them from JSX to mdast/slate-y type nodes for the editor to pick them up.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it works in the editor playground, but i haven't checked in a project yet (doing so now)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you change the playground source to:

<Image align="center" className="border" url="https://drastik.ch/wp-content/uploads/2023/06/blackcat.gif" />

does it load as a widget or as JSX?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in the playground, yeah
image

image

but in the dash editor not so much, goddammit

Copy link
Collaborator

@kellyjosephprice kellyjosephprice May 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OH I think it's falling through to here:

const hProperties = attributes(node);
// @ts-ignore
const mdNode: CodeTabs = {
children: node.children as any,
type: types[node.name],
...(['tr', 'td'].includes(node.name)
? {}
: {
data: {
hName: node.name,
...(Object.keys(hProperties).length ? { hProperties } : {}),
},
}),
position: node.position,

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should add embeds to this map:

const types = {
Callout: NodeTypes['callout'],
Code: 'code',
CodeTabs: NodeTypes['codeTabs'],
Glossary: NodeTypes['glossary'],
Image: 'image',
Table: 'table',
Variable: NodeTypes['variable'],
td: 'tableCell',
tr: 'tableRow',
};

And then they'll get picked up in the editor?

} else if (node.name === 'Table') {
const { children, position } = node;
const { align = [...new Array(node.children.length)].map(() => null) } = attributes<Pick<Table, 'align'>>(node);
Expand Down
21 changes: 21 additions & 0 deletions types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ interface Embed extends Parent {
image?: string;
favicon?: string;
iframe?: boolean;
typeOfEmbed?: string;
};
};
}
Expand All @@ -44,6 +45,26 @@ interface HTMLBlock extends Node {
};
}

interface Image extends Node {
type: NodeTypes.image;
url: string;
alt: string;
title: string;
data: Data & {
hName: 'image';
hProperties: {
align?: string;
alt?: string;
caption?: string;
border?: string;
src: string;
title?: string;
width?: string;
lazy?: boolean;
};
};
}

interface Gemoji extends Literal {
type: NodeTypes.emoji;
name: string;
Expand Down