Skip to content

Commit

Permalink
Add package content, extracted and improved from tiberiuichim/volto-b…
Browse files Browse the repository at this point in the history
…locks-form
  • Loading branch information
tiberiuichim committed Sep 17, 2020
1 parent 3aa461b commit 97413b2
Show file tree
Hide file tree
Showing 10 changed files with 346 additions and 4 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ dist
.env.development.local
.env.test.local
.env.production.local
*~
106 changes: 106 additions & 0 deletions src/ColumnsBlock/ColumnsBlockEdit.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import React from 'react';
import { Grid } from 'semantic-ui-react';
import { isEmpty } from 'lodash';
import { SidebarPortal, InlineForm, BlocksForm } from '@plone/volto/components';
import { emptyBlocksForm } from '@plone/volto/helpers';

import { ColumnsBlockSchema } from './schema';
import { getColumns, empty } from './utils';

import './styles.less';

const ColumnsBlockEdit = (props) => {
const {
block,
data,
onChangeBlock,
onChangeField,
pathname,
selected,
} = props;

React.useEffect(() => {
if (!data.coldata) {
onChangeBlock(block, { ...data, coldata: empty() });
}
});

const [colSelections, setColSelections] = React.useState({});

const { coldata = empty() } = data;
const columnList = getColumns(coldata);

return (
<>
<div className="columns-block">
{/* {<h3>{data.block_title}</h3>} */}
<Grid columns={columnList.length}>
{columnList.map(([colId, column], index) => {
return (
<Grid.Column className="block-column" key={colId}>
{/* <h4>{`Column ${index}`}</h4> */}
<BlocksForm
properties={isEmpty(column) ? emptyBlocksForm() : column}
selectedBlock={selected ? colSelections[colId] : null}
onSelectBlock={(id) =>
setColSelections({
// this invalidates selection in all other columns
[colId]: id,
})
}
onChangeFormData={(newFormData) => {
onChangeBlock(block, {
...data,
coldata: {
...coldata,
columns: {
...coldata.columns,
[colId]: newFormData,
},
},
});
}}
onChangeField={(id, value) => {
if (['blocks', 'blocks_layout'].indexOf(id) > -1) {
onChangeBlock(block, {
...data,
coldata: {
...coldata,
columns: {
...coldata.columns,
[colId]: {
...coldata.columns?.[colId],
[id]: value,
},
},
},
});
} else {
onChangeField(id, value);
}
}}
pathname={pathname}
/>
</Grid.Column>
);
})}
</Grid>
</div>
<SidebarPortal selected={selected}>
<InlineForm
schema={ColumnsBlockSchema}
title={ColumnsBlockSchema.title}
onChangeField={(id, value) => {
onChangeBlock(block, {
...data,
[id]: value,
});
}}
formData={data}
/>
</SidebarPortal>
</>
);
};

export default ColumnsBlockEdit;
26 changes: 26 additions & 0 deletions src/ColumnsBlock/ColumnsBlockView.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React from 'react';
import { Grid } from 'semantic-ui-react';
import { renderBlocks } from '@plone/volto/helpers';
import { getColumns, empty } from './utils';

const ColumnsBlockView = (props) => {
const { coldata = empty(), block_title } = props.data;
const columnList = getColumns(coldata);
return (
<div>
{block_title ? <h3>{block_title}</h3> : ''}
<Grid columns={columnList.length}>
{columnList.map(([id, column], index) => {
return (
<Grid.Column className="demo-column" key={id}>
<h4>{`Column ${index}`}</h4>
{renderBlocks(column, props)}
</Grid.Column>
);
})}
</Grid>
</div>
);
};

export default ColumnsBlockView;
2 changes: 2 additions & 0 deletions src/ColumnsBlock/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export ColumnsBlockView from './ColumnsBlockView';
export ColumnsBlockEdit from './ColumnsBlockEdit';
21 changes: 21 additions & 0 deletions src/ColumnsBlock/schema.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
export const ColumnsBlockSchema = {
title: 'Columns block',
fieldsets: [
{
id: 'default',
title: 'Default',
fields: ['block_title', 'coldata'], // 'nrColumns'
},
],
properties: {
block_title: {
title: 'Block title',
default: 'Columns',
},
coldata: {
title: 'Columns',
type: 'columns',
},
},
required: ['title'],
};
28 changes: 28 additions & 0 deletions src/ColumnsBlock/styles.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
.columns-block {
.block-column {
padding: 0.3em;
}
}

.drag-drop-list-widget {
.columns-area {
padding: 1em 0em;

[data-rbd-draggable-context-id] {
margin-bottom: 0.3em;
}

.column-area {
display: flex;

.label {
flex-grow: 2;
padding-left: 1em;
}

button {
flex-grow: 0;
}
}
}
}
19 changes: 19 additions & 0 deletions src/ColumnsBlock/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { v4 as uuid } from 'uuid';
import { emptyBlocksForm } from '@plone/volto/helpers';

export const getColumns = (coldata) => {
return (coldata?.columns_layout?.items || []).map((id) => [
id,
coldata.columns?.[id],
]);
};

export const empty = () => {
const id = uuid();
return {
columns: { [id]: emptyBlocksForm() },
columns_layout: {
items: [id],
},
};
};
115 changes: 115 additions & 0 deletions src/ColumnsWidget/ColumnsWidget.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import React from 'react';
import { v4 as uuid } from 'uuid';
import { omit, without } from 'lodash';
import move from 'lodash-move';
import { DragDropList, Icon, FormFieldWrapper } from '@plone/volto/components';
import { emptyBlocksForm } from '@plone/volto/helpers';

import dragSVG from '@plone/volto/icons/drag.svg';
import trashSVG from '@plone/volto/icons/delete.svg';
import plusSVG from '@plone/volto/icons/circle-plus.svg';

export function moveColumn(formData, source, destination) {
return {
...formData,
columns_layout: {
items: move(formData.columns_layout?.items, source, destination),
},
};
}

const empty = () => {
return [uuid(), emptyBlocksForm()];
};

const ColumnsWidget = (props) => {
const { value = {}, id, onChange } = props;
const { columns = {} } = value;
const columnsList = (value.columns_layout?.items || []).map((id) => [
id,
columns[id],
]);
return (
<FormFieldWrapper
{...props}
draggable={false}
className="drag-drop-list-widget"
>
<div className="columns-area">
<DragDropList
childList={columnsList}
onMoveItem={(result) => {
const { source, destination } = result;
if (!destination) {
return;
}
const newFormData = moveColumn(
value,
source.index,
destination.index,
);
onChange(id, newFormData);
return true;
}}
renderChild={(child, childId, index, draginfo) => (
<div ref={draginfo.innerRef} {...draginfo.draggableProps}>
<div style={{ position: 'relative' }}>
<div
style={{
visibility: 'visible',
display: 'inline-block',
}}
{...draginfo.dragHandleProps}
className="drag handle wrapper"
>
<Icon name={dragSVG} size="18px" />
</div>
<div className="column-area">
<div className="label">Column {index}</div>
<button
onClick={() => {
const newFormData = {
...value,
columns: omit({ ...value.columns }, [childId]),
columns_layout: {
...value.columns_layout,
items: without(
[...value.columns_layout?.items],
childId,
),
},
};
onChange(id, newFormData);
}}
>
<Icon name={trashSVG} size="18px" />
</button>
</div>
</div>
</div>
)}
/>
<button
onClick={() => {
const [newId, newData] = empty();
onChange(id, {
...value,
columns: {
...value.columns,
[newId]: newData,
},
columns_layout: {
...value.columns_layout,
items: [...value.columns_layout?.items, newId],
},
});
}}
>
<Icon name={plusSVG} size="18px" />
</button>
</div>
</FormFieldWrapper>
);
};

export default ColumnsWidget;
2 changes: 2 additions & 0 deletions src/ColumnsWidget/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import ColumnsWidget from './ColumnsWidget';
export default ColumnsWidget;
30 changes: 26 additions & 4 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,27 @@
const applyConfig = (config) => {
return config;
};
import codeSVG from '@plone/volto/icons/code.svg';

import { ColumnsBlockView, ColumnsBlockEdit } from './ColumnsBlock';
import ColumnsWidget from './ColumnsWidget';

export default function install(config) {
config.blocks.blocksConfig.columnsBlock = {
id: 'columnsBlock',
title: 'Columns',
icon: codeSVG,
group: 'common',
view: ColumnsBlockView,
edit: ColumnsBlockEdit,
restricted: false,
mostUsed: true,
blockHasOwnFocusManagement: true,
sidebarTab: 1,
security: {
addPermission: [],
view: [],
},
};

export default applyConfig;
config.widgets.type.columns = ColumnsWidget;

return config;
}

0 comments on commit 97413b2

Please sign in to comment.