Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: page editor #240

Merged
merged 51 commits into from
Mar 22, 2023
Merged
Changes from 1 commit
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
d3836a3
TipTap basic editor
badgeth-dao Mar 1, 2023
e11c45b
Merge branch 'master' into tip-tap
badgeth-dao Mar 6, 2023
202589a
Exploring tip tap commands
badgeth-dao Mar 6, 2023
9059533
Exploring how to toggle state
badgeth-dao Mar 6, 2023
8b42d2f
Rendering tip tap custom react component
badgeth-dao Mar 7, 2023
779f498
Show header boolean prop toggle added to entity table container
badgeth-dao Mar 7, 2023
2e0ce78
Rename react component to table-node
badgeth-dao Mar 7, 2023
1633096
Insert table with click
badgeth-dao Mar 7, 2023
6536fc6
Memoize this shit
badgeth-dao Mar 7, 2023
6542d84
Inserting table node with a paragraph after
badgeth-dao Mar 7, 2023
766b9af
Command list looking fly
badgeth-dao Mar 8, 2023
e11e8b2
Image start
badgeth-dao Mar 8, 2023
44bb000
Memoize some things
badgeth-dao Mar 8, 2023
10635d5
Custom v2 page for reading/writing TipTap
badgeth-dao Mar 8, 2023
2c1efac
Exploring how to add this plus button in tiptap...
badgeth-dao Mar 8, 2023
2c1ccf0
It works for plus button too
badgeth-dao Mar 8, 2023
9e2c9a8
Commands looking good
badgeth-dao Mar 9, 2023
3f13cc7
Frustrating ability to style components
badgeth-dao Mar 9, 2023
1d84ab5
Command list showing up properly
badgeth-dao Mar 9, 2023
bf2e50b
Command list popover best
badgeth-dao Mar 9, 2023
0b1957d
Merge branch 'master' into tip-tap-v2-bugfix
badgeth-dao Mar 10, 2023
2e5501d
Type fetching for table
badgeth-dao Mar 10, 2023
8f10b20
Simpler command code
badgeth-dao Mar 10, 2023
fbd4b86
Inserting table of type
badgeth-dao Mar 10, 2023
e0fc423
Type fixing
badgeth-dao Mar 10, 2023
b0f0379
Working on serializing data
badgeth-dao Mar 10, 2023
a2958f2
Wire up Docker to TipTap's private registry
badgeth-dao Mar 14, 2023
2c9636b
Producing a lot of blocks
badgeth-dao Mar 14, 2023
ff7bf8f
Loading blocks step 1
badgeth-dao Mar 14, 2023
8425719
Load blocks
badgeth-dao Mar 14, 2023
7ac4e3f
More comments on how this Editing works
badgeth-dao Mar 15, 2023
9b8c5c3
Tiptap hell
badgeth-dao Mar 15, 2023
f303a6b
WIP on block IDs triple
badgeth-dao Mar 15, 2023
50b72e9
Tip tap v2 hell
badgeth-dao Mar 15, 2023
1f6ef2e
Content goodness
badgeth-dao Mar 15, 2023
94c38cf
Minor clean up on the code
badgeth-dao Mar 15, 2023
8784f8f
WIP
badgeth-dao Mar 16, 2023
373af10
Making entity-store look like edit-events
badgeth-dao Mar 16, 2023
1cdf01e
Setting the parent entity on blocks
badgeth-dao Mar 16, 2023
1871b82
Clean up unused code in editor
badgeth-dao Mar 17, 2023
f5bae4d
Figuring out how to create our home-brew UUID extension
badgeth-dao Mar 17, 2023
ae61e50
ID generation working
badgeth-dao Mar 20, 2023
6a3604e
Update test
badgeth-dao Mar 20, 2023
9290320
Fixing re-render and id problem
badgeth-dao Mar 20, 2023
f82dd14
Remove unused packages
badgeth-dao Mar 20, 2023
d34e011
Ensure paste works for editor
badgeth-dao Mar 20, 2023
f8ccffb
Make name property from EntityStore computed
badgeth-dao Mar 21, 2023
d289bd4
Remove unneeded memoization and guard statement
badgeth-dao Mar 21, 2023
b36ff25
Remove uneeded useEffect
badgeth-dao Mar 22, 2023
63e6ce1
Rebuilt
badgeth-dao Mar 22, 2023
6e97e6c
Merge branch 'master' into tip-tap-editor
badgeth-dao Mar 22, 2023
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
Prev Previous commit
Next Next commit
Wire up Docker to TipTap's private registry
badgeth-dao committed Mar 14, 2023
commit a2958f25f8699734f369c340f68633e6b635cfdb
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -6,5 +6,4 @@ build
.turbo
dist
.env
.npmrc

2 changes: 2 additions & 0 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
@tiptap-pro:registry=https://registry.tiptap.dev/
//registry.tiptap.dev/:_authToken=${NPM_TOKEN}
43 changes: 43 additions & 0 deletions apps/web/modules/components/entity/editor/editor-utils.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { Extensions, generateHTML, JSONContent } from '@tiptap/react';
import TurndownService from 'turndown';

const turndownService = new TurndownService();

interface TiptapNode {
content: string;
nodeName?: string;
type?: string;
attrs?: Record<string, unknown>;
}

export const tiptapJsonToTriples = ({
content,
extensions,
spaceId,
entityId,
}: {
content: JSONContent[];
extensions: Extensions;
spaceId: string;
entityId: string;
}) => {
/* We are converting TipTap text nodes to a markdown representation for backwards compatibility */

return content.map(node => {
if (node.type === 'tableNode') {
return node;
} else {
const html = generateHTML({ type: 'doc', content: [node] }, extensions);
const nodeNameLength = 20;
const nodeName = htmlToPlainText(html).slice(0, nodeNameLength);
const markdown = turndownService.turndown(html);
return { ...node, content: markdown, nodeName };
}
});
};

export const htmlToPlainText = (html: string) => {
const div = document.createElement('div');
div.innerHTML = html;
return div.textContent || '';
};
78 changes: 55 additions & 23 deletions apps/web/modules/components/entity/editor/editor.tsx
Original file line number Diff line number Diff line change
@@ -3,42 +3,74 @@ import Image from '@tiptap/extension-image';
import Placeholder from '@tiptap/extension-placeholder';
import { EditorContent, FloatingMenu, useEditor } from '@tiptap/react';
import StarterKit from '@tiptap/starter-kit';
import { useMemo } from 'react';
import { useActionsStore } from '~/modules/action';
import { SquareButton } from '~/modules/design-system/button';
import { useEntityStore } from '~/modules/entity';
import { useEditEvents } from '../edit-events';
import { ConfiguredCommandExtension } from './command-extension';
import { tiptapJsonToTriples } from './editor-utils';
import { TableNode } from './table-node';

interface Props {
spaceId: string;
editable?: boolean;
entityId: string;
name: string;
}

export const Editor = ({ editable = true, spaceId }: Props) => {
export const Editor = ({ editable = true, spaceId, entityId, name }: Props) => {
const { triples: localTriples, update, create, remove } = useEntityStore();

const { actions } = useActionsStore(spaceId);

// const triples = localTriples.length === 0 && actions.length === 0 ? serverTriples : localTriples;

const send = useEditEvents({
context: {
entityId,
spaceId: spaceId,
entityName: name,
},
api: {
create,
update,
remove,
},
});

const allExtensions = useMemo(
() => [
StarterKit,
ConfiguredCommandExtension(spaceId),
TableNode,
Image,
Placeholder.configure({
placeholder: ({ node }) => {
if (node.type.name === 'heading') {
return 'Heading...';
}

return '/ to select content block or write some content...';
},
}),
UniqueID.configure({
types: ['tableNode', 'paragraph', 'heading'],
}),
],
[spaceId]
);

const editor = useEditor(
{
extensions: [
StarterKit,
ConfiguredCommandExtension(spaceId),
TableNode,
Image,
Placeholder.configure({
placeholder: ({ node }) => {
if (node.type.name === 'heading') {
return 'Heading...';
}

return '/ to select content block or write some content...';
},
}),
// TextBlock,
// HeadingBlock,
UniqueID.configure({
types: ['tableNode', 'paragraph', 'heading'],
}),
],
extensions: allExtensions,
editable,

onBlur({ editor, event }) {
console.log(editor.getJSON());
onBlur({ editor }) {
const { content } = editor.getJSON();
if (content) {
console.log(tiptapJsonToTriples({ content, extensions: allExtensions, spaceId, entityId }));
}
},
},
[editable]
Copy link
Contributor Author

Choose a reason for hiding this comment

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

useEditor takes a dependency array - I think there's potential for problems if entityStore.editorJson isn't fully hydrated by the time we reach this point.

We don't always want editorJson as a dependency however, since it will update onBlur and defocus and close our command popover triggered by the "/" or the "+" button.

Will know if this is a problem once we put it into our actual entity page.

19 changes: 0 additions & 19 deletions apps/web/modules/components/entity/editor/table-node.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { mergeAttributes, Node, NodeViewRendererProps, NodeViewWrapper, ReactNodeViewRenderer } from '@tiptap/react';
import React from 'react';
import { EntityTableStoreProvider } from '~/modules/entity';
import { Triple } from '~/modules/types';
import { EntityTableContainer } from '../../entity-table/entity-table-container';

export const TableNode = Node.create({
@@ -33,7 +32,6 @@ export const TableNode = Node.create({
},

renderHTML({ HTMLAttributes }) {
console.log({ HTMLAttributes });
return ['table-node', mergeAttributes(HTMLAttributes), 0];
},

@@ -42,26 +40,9 @@ export const TableNode = Node.create({
},
});

const spaceId = `0xb5E2cD8A5F88517d3576ba99d52C005b19351A43`;

const initialSelectedType: Triple = {
id: '0xb5E2cD8A5F88517d3576ba99d52C005b19351A43:fec429e7-0f17-4dd4-a39e-2e60f91fcd5d:type:d7ab4092-0ab5-441e-88c3-5c27952de773',
entityId: 'fec429e7-0f17-4dd4-a39e-2e60f91fcd5d',
entityName: 'Place',
attributeId: 'type',
attributeName: 'Types',
value: {
type: 'entity',
id: 'd7ab4092-0ab5-441e-88c3-5c27952de773',
name: 'Type',
},
space: '0xb5E2cD8A5F88517d3576ba99d52C005b19351A43',
};

export const TableNodeComponent = React.memo(function TableNodeComponent({ node }: NodeViewRendererProps) {
const { spaceId, selectedType } = node.attrs;

console.log({ spaceId, selectedType });
return (
<NodeViewWrapper className="react-component-with-content">
<div contentEditable="false">
3 changes: 3 additions & 0 deletions apps/web/package.json
Original file line number Diff line number Diff line change
@@ -35,10 +35,12 @@
"@tiptap/extension-image": "2.0.0-beta.220",
"@tiptap/extension-paragraph": "2.0.0-beta.220",
"@tiptap/extension-placeholder": "2.0.0-beta.220",
"@tiptap/html": "2.0.0-beta.220",
"@tiptap/pm": "2.0.0-beta.220",
"@tiptap/react": "2.0.0-beta.220",
"@tiptap/starter-kit": "2.0.0-beta.220",
"@tiptap/suggestion": "2.0.0-beta.220",
"@types/turndown": "^5.0.1",
"@vercel/analytics": "^0.1.6",
"boring-avatars": "^1.7.0",
"class-variance-authority": "^0.4.0",
@@ -62,6 +64,7 @@
"react-query": "^3.39.2",
"react-use-measure": "^2.1.1",
"tippy.js": "^6.3.7",
"turndown": "^7.1.1",
"undici": "^5.10.0",
"wagmi": "^0.10.4"
},
4 changes: 2 additions & 2 deletions apps/web/pages/space/[id]/[entityId]/v2.tsx
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm making changes to the main [entityId].tsx page which will probably cause issues when you try and migrate this v2 page over. We might want to get in my versioning changes on the page before we migrate the editor over.

Original file line number Diff line number Diff line change
@@ -51,13 +51,13 @@ export default function EntityPage(props: Props) {
<div>
<h2 className="text-2xl font-bold">{props.name} Editable TipTap Editor</h2>
<div>Entity ID: {props.id}</div>
<Editor spaceId={props.space} />
<Editor spaceId={props.space} entityId={props.id} name={props.name} />
</div>
) : (
<div>
<h2 className="text-2xl font-bold">{props.name} Read-Only TipTap Editor</h2>
<div>Entity ID: {props.id}</div>
<Editor editable={false} spaceId={props.space} />
<Editor editable={false} spaceId={props.space} entityId={props.id} name={props.name} />
</div>
)}
</EntityTableStoreProvider>
5 changes: 4 additions & 1 deletion docker/Build.dockerfile
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@ FROM node:18.8.0-alpine3.16 AS base

ARG TURBO_TEAM
ARG TURBO_TOKEN
ARG NPM_TOKEN

RUN apk --no-cache add curl python3 build-base jq yq

@@ -12,16 +13,18 @@ RUN curl -f https://get.pnpm.io/v6.16.js | node - add --global pnpm
WORKDIR /app

COPY pnpm-lock.yaml .
COPY .npmrc .
RUN --mount=type=cache,id=pnpm,target=/root/.local/share/pnpm/store \
pnpm fetch

# Install

ENV TURBO_TEAM=$TURBO_TEAM
ENV TURBO_TOKEN=$TURBO_TOKEN
ENV NPM_TOKEN=$NPM_TOKEN
ENV TURBO_REMOTE_ONLY=true

COPY . .
COPY . .

RUN pnpm install --recursive --offline --frozen-lockfile
RUN pnpm build
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@
"format": "turbo run format",
"dev": "turbo run dev",
"clean": "turbo run clean && rimraf \"**/.turbo\"",
"docker:build": "docker compose build --build-arg TURBO_TEAM --build-arg TURBO_TOKEN",
"docker:build": "docker compose build --build-arg TURBO_TEAM --build-arg TURBO_TOKEN --build-arg NPM_TOKEN",
"docker:up": "docker compose up",
"docker:down": "docker compose down -v --rmi all",
"docker:clean": "rimraf build",
22 changes: 22 additions & 0 deletions packages/ids/system-ids.ts
Original file line number Diff line number Diff line change
@@ -53,6 +53,28 @@ export const FOREIGN_TYPES = 'be745973-05a9-4cd0-a46d-1c5538270faf'
/* Example Usage: SF Config -> TYPES -> SPACE_CONFIGURATION */
export const SPACE_CONFIGURATION = '1d5d0c2a-db23-466c-a0b0-9abe879df457'

/* Example Usage: Block Entity -> TYPES -> TABLE_BLOCK */
export const TABLE_BLOCK = '88d59252-17ae-4d9a-a367-24710129eb47'

/* Example Usage: Block Entity -> TYPES -> TEXT_BLOCK */
export const TEXT_BLOCK = '8426caa1-43d6-47d4-a6f1-00c7c1a9a320'

/* Example Usage: Block Entity -> TYPES -> IMAGE_BLOCK */
export const IMAGE_BLOCK = 'f0553d4d-4838-425e-bcd7-613bd8f475a5'

/* Example Usage: Entity -> BLOCKS -> Some_Entity_Of_Type_TEXT_BLOCK_or_TABLE_BLOCK */
export const BLOCKS = 'beaba5cb-a677-41a8-b353-77030613fc70'

/* Example Usage:
Block Entity -> TYPES -> TEXT_BLOCK
Block Entity -> MARKDOWN_CONTENT -> "**hello world!**" */
export const MARKDOWN_CONTENT = 'f88047ce-bd8d-4fbf-83f6-58e84ee533e4'

/* Example Usage:
Block Entity -> TYPES -> TABLE_BLOCK
Block Entity -> ROW_TYPE -> Some_Type_ID */
export const ROW_TYPE = '577bd9fb-b29e-4e2b-b5f8-f48aedbd26ac'

// This represents the PermissionlessSpace contract acting as the registry for all
// permissionless spaces.
export const PERMISSIONLESS_SPACE_REGISTRY_ADDRESS = ''
27 changes: 27 additions & 0 deletions packages/subgraph/src/bootstrap.ts
Original file line number Diff line number Diff line change
@@ -7,15 +7,21 @@ import {
import {
ATTRIBUTE,
ATTRIBUTES,
BLOCKS,
DESCRIPTION,
FOREIGN_TYPES,
IMAGE_ATTRIBUTE,
IMAGE_BLOCK,
MARKDOWN_CONTENT,
NAME,
RELATION,
ROW_TYPE,
SCHEMA_TYPE,
SPACE,
SPACE_CONFIGURATION,
TABLE_BLOCK,
TEXT,
TEXT_BLOCK,
TYPES,
VALUE_TYPE,
} from '@geogenesis/ids/system-ids'
@@ -37,6 +43,12 @@ const entities: string[] = [
ATTRIBUTE,
SPACE_CONFIGURATION,
FOREIGN_TYPES,
TABLE_BLOCK,
TEXT_BLOCK,
IMAGE_BLOCK,
BLOCKS,
MARKDOWN_CONTENT,
ROW_TYPE,
]

class Tuple<T, U> {
@@ -61,6 +73,15 @@ const names: Tuple<string, StringValue>[] = [
_1: new StringValue(SPACE_CONFIGURATION, 'Space Configuration'),
},
{ _0: FOREIGN_TYPES, _1: new StringValue(FOREIGN_TYPES, 'Foreign Types') },
{ _0: TABLE_BLOCK, _1: new StringValue(TABLE_BLOCK, 'Table Block') },
{ _0: TEXT_BLOCK, _1: new StringValue(TEXT_BLOCK, 'Text Block') },
{ _0: IMAGE_BLOCK, _1: new StringValue(IMAGE_BLOCK, 'Image Block') },
{ _0: BLOCKS, _1: new StringValue(BLOCKS, 'Blocks') },
{
_0: MARKDOWN_CONTENT,
_1: new StringValue(MARKDOWN_CONTENT, 'Markdown Content'),
},
{ _0: ROW_TYPE, _1: new StringValue(ROW_TYPE, 'Row Type') },
]

/* Multi-dimensional array of [EntityId, ValueType] */
@@ -73,6 +94,9 @@ const attributes: Tuple<string, string>[] = [
{ _0: NAME, _1: TEXT },
{ _0: SPACE, _1: TEXT },
{ _0: FOREIGN_TYPES, _1: RELATION },
{ _0: MARKDOWN_CONTENT, _1: TEXT },
{ _0: ROW_TYPE, _1: RELATION },
{ _0: BLOCKS, _1: RELATION },
]

/* Multi-dimensional array of [TypeId, [Attributes]] */
@@ -82,6 +106,9 @@ const types: Tuple<string, string[]>[] = [
{ _0: ATTRIBUTE, _1: [VALUE_TYPE] },
{ _0: SCHEMA_TYPE, _1: [ATTRIBUTES] },
{ _0: SPACE_CONFIGURATION, _1: [FOREIGN_TYPES] },
{ _0: IMAGE_BLOCK, _1: [IMAGE_ATTRIBUTE] },
{ _0: TABLE_BLOCK, _1: [ROW_TYPE] },
{ _0: TEXT_BLOCK, _1: [MARKDOWN_CONTENT] },
]

export function bootstrapRootSpaceCoreTypes(
43 changes: 43 additions & 0 deletions pnpm-lock.yaml