From 963eb5bd3e36ea8802b1173b5cb33b4e3fdc6434 Mon Sep 17 00:00:00 2001 From: Harley Turan Date: Sat, 2 Jul 2022 01:40:59 +0100 Subject: [PATCH 001/261] break everything to make pasting work --- packages/gui/package.json | 1 + .../gui/src/components/Editor/Controls.tsx | 17 ++- packages/gui/src/components/html/editor.tsx | 144 ++++++++++++++++++ .../gui/src/components/schemas/options.tsx | 8 +- .../lib/transformers/html-to-editor-schema.ts | 50 ++++++ 5 files changed, 213 insertions(+), 7 deletions(-) create mode 100644 packages/gui/src/components/html/editor.tsx diff --git a/packages/gui/package.json b/packages/gui/package.json index 856c1cad..c97cdce6 100644 --- a/packages/gui/package.json +++ b/packages/gui/package.json @@ -70,6 +70,7 @@ "rehype-parse": "^8.0.4", "rehype-sanitize": "^5.0.1", "rehype-stringify": "^9.0.3", + "style-to-object": "^0.3.0", "theme-ui": "^0.14.6", "unified": "^10.1.2", "unist-util-remove": "^3.1.0", diff --git a/packages/gui/src/components/Editor/Controls.tsx b/packages/gui/src/components/Editor/Controls.tsx index 997b67c6..edc1c465 100644 --- a/packages/gui/src/components/Editor/Controls.tsx +++ b/packages/gui/src/components/Editor/Controls.tsx @@ -408,12 +408,21 @@ export function parseStyles(styles: Record) { return mapValues(styles, (value, property) => { const schema = properties[property] if (!schema) { - throw new Error(`Parsing unknown property: ${property}`) + // throw new Error(`Parsing unknown property: ${property}`) + return } - const [parsed, rest] = schema.parse!(tokenize(value)) - if (isNil(parsed) || rest.length > 0) { - throw new Error(`Error parsing given value ${value} into ${property}`) + + console.log('schema', schema) + console.log('tokenized', tokenize(value)) + + if (!schema.parse) { + return tokenize(value) } + + const [parsed, rest] = schema.parse!(tokenize(value)) + // if (isNil(parsed) || rest.length > 0) { + // throw new Error(`Error parsing given value ${value} into ${property}`) + // } return parsed }) } diff --git a/packages/gui/src/components/html/editor.tsx b/packages/gui/src/components/html/editor.tsx new file mode 100644 index 00000000..92129f53 --- /dev/null +++ b/packages/gui/src/components/html/editor.tsx @@ -0,0 +1,144 @@ +import { Editor } from '../Editor' +import { HtmlNode } from './types' +import * as Tabs from '@radix-ui/react-tabs' +import { Code, Layers } from 'react-feather' +import { useHtmlEditor } from './Provider' +import { getChildAtPath, removeChildAtPath, setChildAtPath } from './util' +import { Export } from './Export' +import { useTheme } from '../providers/ThemeContext' +import { NodeEditor } from './Editors/NodeEditor' +import { TreeNode } from './TreeNode' + +interface HtmlEditorProps { + onChange(value: HtmlNode): void +} + +const TABS_TRIGGER_STYLES: any = { + all: 'unset', + cursor: 'pointer', + fontSize: 0, + fontWeight: 500, + px: 2, + py: 1, + color: 'muted', + display: 'inline-flex', + gap: '.5em', + alignItems: 'center', + '&[data-state="active"]': { + color: 'text', + }, +} +const TABS_CONTENT_STYLES: any = { + width: 400, + height: 'calc(100vh - 81px)', + overflow: 'auto', + resize: 'horizontal', + borderRightWidth: '1px', + borderRightStyle: 'solid', + borderColor: 'border', + '&::-webkit-scrollbar': { display: 'none' }, + scrollbarWidth: 0, +} + +/** + * An HTML tree-based editor that lets you add HTML nodes and mess around with their styles + */ +export function HtmlEditor({ onChange }: HtmlEditorProps) { + const { value, selected: providedSelected, setSelected } = useHtmlEditor() + const theme = useTheme() + + const selected = providedSelected || [] + const nodeValue = getChildAtPath(value, selected) + + return ( +
+ + + + 🎨 Styles + + + Layers + + + Export + + + +
+ { + const newItem = { ...nodeValue, style: newStyles } + onChange(setChildAtPath(value, selected, newItem)) + }} + showRegenerate + showAddProperties + /> +
+
+ +
+ + onChange(setChildAtPath(value, selected, newItem)) + } + onParentChange={(newItem) => { + const parentPath = [...(selected || [])] + parentPath.pop() + const newValue = setChildAtPath(value, parentPath, newItem) + onChange(newValue) + }} + onRemove={() => { + onChange(removeChildAtPath(value, selected)) + const newPath = [...selected] + newPath.pop() + setSelected(newPath) + }} + /> + +
+
+ + + +
+
+ ) +} diff --git a/packages/gui/src/components/schemas/options.tsx b/packages/gui/src/components/schemas/options.tsx index 251fe91e..e6fb98ef 100644 --- a/packages/gui/src/components/schemas/options.tsx +++ b/packages/gui/src/components/schemas/options.tsx @@ -110,9 +110,11 @@ export function optionsSchema>({ // FIXME deal with instances where the one of the variants just swallows up the other for (const variantSchema of Object.values(variants)) { console.log('checking', variantSchema.type, 'on', tokens) - const [result, rest] = variantSchema.parse(tokens) - if (result) { - return [result, rest] + if (variantSchema.parse) { + const [result, rest] = variantSchema.parse(tokens) + if (result) { + return [result, rest] + } } } return [undefined, tokens] diff --git a/packages/gui/src/lib/transformers/html-to-editor-schema.ts b/packages/gui/src/lib/transformers/html-to-editor-schema.ts index 9faaf313..86baf6ca 100644 --- a/packages/gui/src/lib/transformers/html-to-editor-schema.ts +++ b/packages/gui/src/lib/transformers/html-to-editor-schema.ts @@ -2,6 +2,55 @@ import { unified } from 'unified' import rehypeParse from 'rehype-parse' import { cleanNewLines } from './plugins/clean-new-lines' import { propertiesToAttributes } from './plugins/properties-to-attributes' +import parse from 'style-to-object' +import { parseStyles } from '../../components/Editor/Controls' +import { camelCase } from 'lodash-es' +import { visit } from 'unist-util-visit' + +import {stylesToEditorSchema} from './styles-to-editor-schema' + +const handleStyles = () => (tree: any) => { + visit(tree, 'element', (node) => { + + if (node.attributes.style) { + // inline-style to JS obj + let js = parse(node.attributes.style); + + // css-case to camelCase + js = Object.keys(js).reduce((acc, val) => ({...acc, [camelCase(val)]: js[val]}), {}) + + // js obj to editor style obj + const parsedStyles = parseStyles(js); + // filter out unparsable entries + Object.keys(parsedStyles).forEach(key => { + if (parsedStyles[key] === undefined) { + delete parsedStyles[key] + } + }) + + // hi! :) + // color parsing seems a little busted right now, so doing this manually + if (js['color']) { + parsedStyles['color'] = js['color'].replace(' !important', '') + } + if (js['backgroundColor']) { + parsedStyles['backgroundColor'] = js['backgroundColor'].replace(' !important', '') + } + + // not sure what stylesToEditorSchema does, but it works? + node.style = stylesToEditorSchema(parsedStyles); + + // style attributes cause an editor crash + delete node.attributes.style; + } + + // avoid classname conflicts, just in case + if (node.attributes.className) { + delete node.attributes.className; + } + + }) +} export const htmlToEditorSchema = (text: string) => { const tree = unified().use(rehypeParse, { fragment: true }).parse(text) @@ -10,6 +59,7 @@ export const htmlToEditorSchema = (text: string) => { .use(cleanNewLines) // @ts-ignore .use(propertiesToAttributes) + .use(handleStyles) .runSync(tree) const htmlBody = processedTree.children[0] From 4e533589b80131fd5b06398050b2191c9a7a4983 Mon Sep 17 00:00:00 2001 From: John Otander Date: Fri, 15 Jul 2022 16:12:25 -0600 Subject: [PATCH 002/261] Handle tab --- packages/gui/src/components/html/Editor.tsx | 5 +- packages/gui/src/components/html/editor.tsx | 144 -------------------- 2 files changed, 4 insertions(+), 145 deletions(-) delete mode 100644 packages/gui/src/components/html/editor.tsx diff --git a/packages/gui/src/components/html/Editor.tsx b/packages/gui/src/components/html/Editor.tsx index 92129f53..7cc28e13 100644 --- a/packages/gui/src/components/html/Editor.tsx +++ b/packages/gui/src/components/html/Editor.tsx @@ -1,7 +1,7 @@ import { Editor } from '../Editor' import { HtmlNode } from './types' import * as Tabs from '@radix-ui/react-tabs' -import { Code, Layers } from 'react-feather' +import { Code, Layers, LogIn } from 'react-feather' import { useHtmlEditor } from './Provider' import { getChildAtPath, removeChildAtPath, setChildAtPath } from './util' import { Export } from './Export' @@ -88,6 +88,9 @@ export function HtmlEditor({ onChange }: HtmlEditorProps) { Layers + + Import + Export diff --git a/packages/gui/src/components/html/editor.tsx b/packages/gui/src/components/html/editor.tsx deleted file mode 100644 index 92129f53..00000000 --- a/packages/gui/src/components/html/editor.tsx +++ /dev/null @@ -1,144 +0,0 @@ -import { Editor } from '../Editor' -import { HtmlNode } from './types' -import * as Tabs from '@radix-ui/react-tabs' -import { Code, Layers } from 'react-feather' -import { useHtmlEditor } from './Provider' -import { getChildAtPath, removeChildAtPath, setChildAtPath } from './util' -import { Export } from './Export' -import { useTheme } from '../providers/ThemeContext' -import { NodeEditor } from './Editors/NodeEditor' -import { TreeNode } from './TreeNode' - -interface HtmlEditorProps { - onChange(value: HtmlNode): void -} - -const TABS_TRIGGER_STYLES: any = { - all: 'unset', - cursor: 'pointer', - fontSize: 0, - fontWeight: 500, - px: 2, - py: 1, - color: 'muted', - display: 'inline-flex', - gap: '.5em', - alignItems: 'center', - '&[data-state="active"]': { - color: 'text', - }, -} -const TABS_CONTENT_STYLES: any = { - width: 400, - height: 'calc(100vh - 81px)', - overflow: 'auto', - resize: 'horizontal', - borderRightWidth: '1px', - borderRightStyle: 'solid', - borderColor: 'border', - '&::-webkit-scrollbar': { display: 'none' }, - scrollbarWidth: 0, -} - -/** - * An HTML tree-based editor that lets you add HTML nodes and mess around with their styles - */ -export function HtmlEditor({ onChange }: HtmlEditorProps) { - const { value, selected: providedSelected, setSelected } = useHtmlEditor() - const theme = useTheme() - - const selected = providedSelected || [] - const nodeValue = getChildAtPath(value, selected) - - return ( -
- - - - 🎨 Styles - - - Layers - - - Export - - - -
- { - const newItem = { ...nodeValue, style: newStyles } - onChange(setChildAtPath(value, selected, newItem)) - }} - showRegenerate - showAddProperties - /> -
-
- -
- - onChange(setChildAtPath(value, selected, newItem)) - } - onParentChange={(newItem) => { - const parentPath = [...(selected || [])] - parentPath.pop() - const newValue = setChildAtPath(value, parentPath, newItem) - onChange(newValue) - }} - onRemove={() => { - onChange(removeChildAtPath(value, selected)) - const newPath = [...selected] - newPath.pop() - setSelected(newPath) - }} - /> - -
-
- - - -
-
- ) -} From eef7cab950ce5384851b8caedd6ea3a62f2523b6 Mon Sep 17 00:00:00 2001 From: John Otander Date: Fri, 15 Jul 2022 16:17:44 -0600 Subject: [PATCH 003/261] Add tab content --- packages/gui/src/components/html/Editor.tsx | 34 +++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/packages/gui/src/components/html/Editor.tsx b/packages/gui/src/components/html/Editor.tsx index 7cc28e13..1403ca3e 100644 --- a/packages/gui/src/components/html/Editor.tsx +++ b/packages/gui/src/components/html/Editor.tsx @@ -8,6 +8,7 @@ import { Export } from './Export' import { useTheme } from '../providers/ThemeContext' import { NodeEditor } from './Editors/NodeEditor' import { TreeNode } from './TreeNode' +import { htmlToEditorSchema } from '../../lib' interface HtmlEditorProps { onChange(value: HtmlNode): void @@ -138,6 +139,39 @@ export function HtmlEditor({ onChange }: HtmlEditorProps) { /> + +
+