Added basic tree discovery

This commit is contained in:
Benjamin Bädorf 2021-02-23 00:12:06 +01:00
parent d76f40cf7d
commit 7d6a3730c6
No known key found for this signature in database
GPG key ID: 4406E80E13CD656C
12 changed files with 101 additions and 40 deletions

View file

@ -1,10 +1,18 @@
import { Component } from 'vue';
export interface BlockTree {
name: string;
icon?: string;
children?: BlockTree[];
}
export interface BlockDefinition {
name: string;
icon?: string;
getDefaultData: any;
edit: Component;
display: Component;
getChildren?: (block: Block) => Block[],
}
export interface BlockLibraryDefinition {

View file

@ -73,7 +73,7 @@ export const SbBlock = defineComponent({
};
return () => {
const BlockComponent = getBlock(props.block.name) as any;
const BlockComponent = getBlock(props.block.name)?.[mode.value] as any;
if (!BlockComponent) {
const MissingBlock = SbMissingBlock[mode.value];
@ -84,12 +84,10 @@ export const SbBlock = defineComponent({
}
if (mode.value === SbMode.Display) {
return () => (
<BlockComponent
data={props.block.data}
blockId={props.block.blockId}
/>
);
return <BlockComponent
data={props.block.data}
blockId={props.block.blockId}
/>;
}
return <div

View file

@ -31,7 +31,6 @@ export default defineComponent({
},
setup(props: MissingBlockProps) {
console.log(props, props.name, props.data, props.blockId);
return () => (
<div class="sb-missing-block">
Missing block: {props.name}

View file

@ -0,0 +1,18 @@
.sb-context {
position: relative;
}
.sb-context-menu {
display: none;
flex-direction: column;
background: var(--grey-0);
border: 1px solid var(--grey-3);
top: 100%;
left: 0;
margin: 0;
z-index: var(--z-context-menu);
&[open] {
display: flex;
}
}

View file

@ -23,28 +23,33 @@ export const SbContextMenu = defineComponent({
setup(props: ContextMenuProps, context) {
const opened = ref(false);
const close = () => { opened.value = false; }
const open = () => { opened.value = true; };
const close = () => { opened.value = false; };
const closeOnEscape = ($event: KeyboardEvent) => {
if ($event.key === 'Escape') {
close();
}
};
const open = () => {
opened.value = true;
document.addEventListener('click', close);
document.addEventListener('keypress', closeOnEscape);
}
const toggle = () => { opened.value = !opened.value; }
const toggle = () => { opened.value ? close() : open() };
watch(opened, () => {
if (!opened.value) {
document.removeEventListener('click', close);
document.removeEventListener('keypress', closeOnEscape);
watch(opened, (curr, prev) => {
if (curr === prev) {
return;
}
if (!curr) {
document.body.removeEventListener('click', close);
document.body.removeEventListener('keypress', closeOnEscape);
} else {
setTimeout(() => {
document.body.addEventListener('click', close);
document.body.addEventListener('keypress', closeOnEscape);
});
}
});
return () => (
<div class="sb-context-menu">
<div class="sb-context">
{
context.slots.context({
opened,
@ -55,10 +60,12 @@ export const SbContextMenu = defineComponent({
<SbButton onClick={toggle}>Menu</SbButton>
}
<dialog
open={opened.value}
class="sb-context-menu"
open={opened.value ? true : undefined}
onClose={close}
onClick={($event: Event) => {
// Make sure clicks inside do not autoclose this
$event.stopPropagation();
}}
>
{context.slots.default({

View file

@ -4,7 +4,7 @@ import {
} from 'vue';
import { Block } from '../blocks';
import { TreeBlockSelect } from './TreeBlockSelect';
import { SbTreeBlockSelect } from './TreeBlockSelect';
import './MainMenu.scss';
@ -25,8 +25,8 @@ export const SbMainMenu = defineComponent({
setup(props: MainMenuProps, context) {
return () => (
<div class="sb-main-menu">
<TreeBlockSelect
block={block}
<SbTreeBlockSelect
block={props.block}
/>
</div>
);

View file

@ -67,18 +67,16 @@ export const Schlechtenburg = defineComponent({
provide(BlockLibrary, blockLibrary);
watch(props.block, () => {
console.log('Update', props.block);
});
return () => (
<div
class="sb-main"
ref={el}
>
<SbMainMenu
block={props.block}
/>
{
mode.value === SbMode.Edit
? <SbMainMenu block={props.block} />
: null
}
<SbBlock
block={props.block}
onUpdate={props.onUpdate}

View file

@ -1,8 +1,14 @@
import {
computed,
defineComponent,
PropType,
} from 'vue';
import { Block } from '../blocks';
import {
Block,
BlockTree,
} from '../blocks';
import { useDynamicBlocks } from '../use-dynamic-blocks';
import { SbContextMenu } from './ContextMenu';
import { SbButton } from './Button';
@ -23,16 +29,34 @@ export const SbTreeBlockSelect = defineComponent({
},
setup(props: TreeBlockSelectProps, context) {
const { getBlock } = useDynamicBlocks();
const getTreeForBlock = (block: Block): BlockTree => {
const getBlockChildren = getBlock(block.name)?.getChildren;
// TODO: vue-jxs apparently cannot parse arrow functions here
const getChildren = getBlockChildren || function ({ data }) { return data?.children; };
const children = getChildren(block) || [];
return {
name: block.name,
children: children.map(getTreeForBlock),
};
};
const tree = computed(() => getTreeForBlock(props.block));
const treeToHtml = (tree: BlockTree) => <li>
{tree.name}
{tree.children.length ? <ul>{tree.children.map(treeToHtml)}</ul> : null}
</li>;
return () => (
<SbContextMenu
class="sb-tree-block-select"
v-slots={{
context: ({ toggle }) => <SbButton onClick={toggle}>Tree</SbButton>,
default: () => <ul>
<li>Test</li>
</ul>,
default: () => <ul>{treeToHtml(tree.value)}</ul>,
}}
></SbContextMenu>
/>
);
},
});

View file

@ -10,7 +10,7 @@ export const BlockLibrary = Symbol('Schlechtenburg block library');
export function useDynamicBlocks() {
const mode = inject(Mode, ref(SbMode.Edit));
const customBlocks: BlockLibraryDefinition = inject(BlockLibrary, reactive({}));
const getBlock = (name: string) => customBlocks[name]?.[mode.value];
const getBlock = (name: string) => customBlocks[name];
return {
mode,

View file

@ -6,4 +6,5 @@ export default {
getDefaultData,
edit: defineAsyncComponent(() => import('./edit')),
display: defineAsyncComponent(() => import('./display')),
getChildren: (block) => [ block.data.description ],
};

View file

@ -49,13 +49,19 @@ export default defineComponent({
SbParagraph,
]}
key="edit"
mode="edit"
mode={SbMode.Edit}
/>;
case SbMode.Edit:
case SbMode.Display:
return <Schlechtenburg
block={block}
customBlocks={[
SbLayout,
SbHeading,
SbImage,
SbParagraph,
]}
key="display"
mode="display"
mode={SbMode.Display}
/>;
case 'data':
return <pre><code>{ JSON.stringify(block, null, 2) }</code></pre>;

View file

@ -22,6 +22,8 @@ html {
--fg: var(--black);
--interact: #3f9cff;
--z-context-menu: 3000;
}
body {