Skip to content

Commit

Permalink
manage column properties in seperate column tab
Browse files Browse the repository at this point in the history
  • Loading branch information
aghontpi committed Oct 16, 2021
1 parent 364d501 commit 22ca5b6
Show file tree
Hide file tree
Showing 10 changed files with 215 additions and 41 deletions.
113 changes: 113 additions & 0 deletions src/Components/ColumnAttributes.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import styled from 'styled-components';
import { Tabs } from 'antd';
import { UNDOREDO } from '../Utils/undoRedo';
import { useEditor } from '../Hooks/Editor.hook';
import { useHtmlWrapper } from '../Hooks/Htmlwrapper.hook';
import { useEffect, useState } from 'react';
import { findSectionOfElement } from '../Utils/findElementsParent';
import { findElementInJson } from '../Utils/findElementInMjmlJson';
import { Background } from './Mods/Background';
import { Width } from './Mods/WidthHeight';
import { Padding } from './Mods/Paddings';
import { VerticalAlign } from './Mods/VerticalAlign';
import { Border } from './Mods/Border';
import { CordinalBorder } from './Mods/CordinalBorder';
import { BorderRadius } from './Mods/BorderRadius';
import Scrollbars from 'react-custom-scrollbars-2';

const { TabPane } = Tabs;
const CustomTabs = styled(Tabs)`
.ant-tabs-tab {
padding-top: 0px;
}
.ant-tabs-content {
height: 100%;
}
.mods {
padding: 24px 16px;
padding-top: 4px;
display: flex;
flex-direction: column;
}
.ant-row {
margin-bottom: 8px;
}
`;

const ColumnAttributes = () => {
const { mjmlJson } = useEditor();
const { active } = useHtmlWrapper();
const [columns, setActiveColumns] = useState<any>([]);

useEffect(() => {
if (active) {
const section = findSectionOfElement(active);
if (section) {
const [, uniqueSectionIdentifier] = section;
const find = findElementInJson(mjmlJson, uniqueSectionIdentifier);
if (find) {
let [item, path] = find;
path = path.slice(1);

if (item && item.children && item.children.length > 0) {
// this exists to make sure to not tigger rerender, on properties changes,
// but will trigger rerender when the number of columns change on the fly (ie. used clone operation)
if (columns.length === item.children.length) {
return;
}

let _columns = [];
for (var i = 0; i < item.children.length; i++) {
if (item.children[i].tagName === 'mj-column') {
_columns.push(`${path}.children[${i}]`);
}
}

setActiveColumns(_columns);
}
}
}
}
}, [active]);

return active ? (
<CustomTabs centered defaultActiveKey="0" style={{ height: '100%' }} destroyInactiveTabPane={false}>
{columns &&
columns.map((column: any, index: number) => {
return (
<TabPane tab={`column ${index + 1}`} key={index}>
<Scrollbars style={{ height: '100%' }} autoHide={true}>
<div
className="mods"
onMouseDown={(e) => {
UNDOREDO.newAction(mjmlJson);
}}
onBlur={(e) => {
UNDOREDO.newAction(mjmlJson);
}}
>
<Width activePath={column} />
<VerticalAlign activePath={column} />
<Padding activePath={column} />

<Background activePath={column} />
<Background
label={'Inner Background:'}
overrideAttribute="inner-background-color"
activePath={column}
/>
<BorderRadius activePath={column} />
<Border activePath={column} />
<CordinalBorder activePath={column} />
</div>
</Scrollbars>
</TabPane>
);
})}
</CustomTabs>
) : null;
};

export { ColumnAttributes };
18 changes: 12 additions & 6 deletions src/Components/Mods/Background.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,24 @@ import { useEffect, useState } from 'react';
import { useVisibility } from '../../Hooks/Attribute.hook';

const ATTRIBUTE = 'background-color';
interface BackgroundProps {
activePath?: string;
label?: string;
overrideAttribute?: string;
}

export const Background = () => {
export const Background = ({ activePath, label, overrideAttribute }: BackgroundProps) => {
const attribute = overrideAttribute || ATTRIBUTE;
const { mjmlJson, setMjmlJson } = useEditor();
const [active, setActive] = useState(() => false);
const [color, setColor] = useState(() => '#ccc');
const [visible, path] = useVisibility({ attribute: ATTRIBUTE });
const [visible, path] = useVisibility({ attribute, customPath: activePath });

useEffect(() => {
if (visible && path) {
const item = _.get(mjmlJson, path);
if (item && item.attributes && item.attributes[ATTRIBUTE]) {
setColor(item.attributes[ATTRIBUTE]);
if (item && item.attributes && item.attributes[attribute]) {
setColor(item.attributes[attribute]);
}
}
}, [path, visible]);
Expand All @@ -28,7 +34,7 @@ export const Background = () => {
setColor(hexCode);
if (path && visible) {
let element = _.get(mjmlJson, path);
element.attributes['background-color'] = hexCode;
element.attributes[attribute] = hexCode;
let json = _.set(mjmlJson, path, element);

setMjmlJson({ ...json });
Expand All @@ -39,7 +45,7 @@ export const Background = () => {
<>
<Row>
<Col flex="auto">
<Form.Item label="Background"></Form.Item>
<Form.Item label={label ? label : 'Background'}></Form.Item>
</Col>

<ColorPicker color={color} flex="none">
Expand Down
8 changes: 6 additions & 2 deletions src/Components/Mods/Border.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@ import { useValue, useVisibility } from '../../Hooks/Attribute.hook';

const ATTRIBUTE = 'border';

export const Border = () => {
const [visible, path] = useVisibility({ attribute: ATTRIBUTE });
interface BorderProps {
activePath?: string;
}

export const Border = ({ activePath }: BorderProps) => {
const [visible, path] = useVisibility({ attribute: ATTRIBUTE, customPath: activePath });
const { mjmlJson, setMjmlJson } = useEditor();
const { getValue } = useValue({ path, visible, attribute: ATTRIBUTE });
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
Expand Down
8 changes: 6 additions & 2 deletions src/Components/Mods/BorderRadius.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@ import { useVisibility } from '../../Hooks/Attribute.hook';

const ATTRIBUTE = 'border-radius';

export const BorderRadius = () => {
interface BorderRadiusProps {
activePath?: string;
}

export const BorderRadius = ({ activePath }: BorderRadiusProps) => {
const { mjmlJson, setMjmlJson } = useEditor();
const [visible, path] = useVisibility({ attribute: ATTRIBUTE });
const [visible, path] = useVisibility({ attribute: ATTRIBUTE, customPath: activePath });

const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
if (visible && e.target.value) {
Expand Down
7 changes: 5 additions & 2 deletions src/Components/Mods/CordinalBorder.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@ import { useEditor } from '../../Hooks/Editor.hook';
import { Form, Input, Row, Col } from 'antd';
import { useVisibility } from '../../Hooks/Attribute.hook';

export const CordinalBorder = () => {
interface CordinalBorderProps {
activePath?: string;
}
export const CordinalBorder = ({ activePath }: CordinalBorderProps) => {
const { mjmlJson, setMjmlJson } = useEditor();
const [visible, path] = useVisibility({ attribute: 'border-top' });
const [visible, path] = useVisibility({ attribute: 'border-top', customPath: activePath });

const handleChange = (e: React.ChangeEvent<HTMLInputElement>, direction: string) => {
if (visible && path && e.target.value) {
Expand Down
13 changes: 8 additions & 5 deletions src/Components/Mods/Paddings.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
import { Form, Input, Row, Col } from 'antd';
import _ from 'lodash';
import { ChangeEvent, useEffect, useMemo, useState } from 'react';
import { ChangeEvent, useMemo } from 'react';
import { useVisibility } from '../../Hooks/Attribute.hook';
import { useEditor } from '../../Hooks/Editor.hook';
import { useHtmlWrapper } from '../../Hooks/Htmlwrapper.hook';

const Padding = () => {
let [visible, path, active] = useVisibility({ attribute: 'padding' });
interface PaddingProps {
activePath?: string;
}

const Padding = ({ activePath }: PaddingProps) => {
let [visible, path, active] = useVisibility({ attribute: 'padding', customPath: activePath });
const { mjmlJson, setMjmlJson } = useEditor();

const handleChange = (e: ChangeEvent<HTMLInputElement>, direction: string) => {
if (e.currentTarget.value === '') {
e.currentTarget.value = '0px';
e.currentTarget.value = '0';
}
// if (!value.includes('px')) {
// e.currentTarget.value = `${value}px`;
Expand Down
8 changes: 6 additions & 2 deletions src/Components/Mods/VerticalAlign.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,12 @@ import _ from 'lodash';

const ATTRIBUTE = 'vertical-align';

export const VerticalAlign = () => {
const [visible, path] = useVisibility({ attribute: ATTRIBUTE });
interface VerticalAlignProps {
activePath?: string;
}

export const VerticalAlign = ({ activePath }: VerticalAlignProps) => {
const [visible, path] = useVisibility({ attribute: ATTRIBUTE, customPath: activePath });
const { mjmlJson, setMjmlJson } = useEditor();
const { active } = useHtmlWrapper();

Expand Down
9 changes: 7 additions & 2 deletions src/Components/Mods/WidthHeight.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,13 @@ import { useValue, useVisibility } from '../../Hooks/Attribute.hook';

const ATTRIBUTE = 'width';

export const Width = () => {
const [visible, path] = useVisibility({ attribute: ATTRIBUTE });
interface WidthHeightProps {
activePath?: string;
}

export const Width = ({ activePath }: WidthHeightProps) => {
const [visible, path] = useVisibility({ attribute: ATTRIBUTE, customPath: activePath });

const { mjmlJson, setMjmlJson } = useEditor();
const { getValue } = useValue({ path, visible, attribute: ATTRIBUTE });

Expand Down
10 changes: 8 additions & 2 deletions src/Hooks/Attribute.hook.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import _ from 'lodash';
import { useEffect, useMemo, useState } from 'react';
import { useEffect, useState } from 'react';
import { findUniqueIdentifier } from '../Utils/closestParent';
import { findElementInJson } from '../Utils/findElementInMjmlJson';
import { useEditor } from './Editor.hook';
Expand All @@ -8,9 +8,10 @@ import { useHtmlWrapper } from './Htmlwrapper.hook';
interface useVisibilityProps {
attribute?: string;
property?: string;
customPath?: string;
}

const useVisibility = ({ attribute, property }: useVisibilityProps): [boolean | null, string, any] => {
const useVisibility = ({ attribute, property, customPath }: useVisibilityProps): [boolean | null, string, any] => {
const [visible, setVisible] = useState<boolean | null>(false);

const { active } = useHtmlWrapper();
Expand All @@ -24,6 +25,11 @@ const useVisibility = ({ attribute, property }: useVisibilityProps): [boolean |
const uniqueIdentifier = findUniqueIdentifier(active, active.classList);
if (uniqueIdentifier) {
let path = findElementInJson(mjmlJson, uniqueIdentifier);

if (customPath) {
path = [null, '.' + customPath];
}

if (path) {
const [, pathToElement] = path;
if (pathToElement.length > 0) {
Expand Down
62 changes: 44 additions & 18 deletions src/Pages/Editor/Attributes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ import { UNDOREDO } from '../../Utils/undoRedo';
import { useEditor } from '../../Hooks/Editor.hook';
import { VerticalAlign } from '../../Components/Mods/VerticalAlign';
import { BackgroundImage } from '../../Components/Mods/BackgroundImage';
import { ColumnAttributes } from '../../Components/ColumnAttributes';
import { useHtmlWrapper } from '../../Hooks/Htmlwrapper.hook';
import { useEffect, useState } from 'react';

const { TabPane } = Tabs;

Expand All @@ -32,8 +35,18 @@ const CustomTabs = styled(Tabs)`

export const Attributes = () => {
const { mjmlJson } = useEditor();
const { active } = useHtmlWrapper();
const [isColumn, setIsColumn] = useState(false);

useEffect(() => {
if (active && active.classList && active.className.includes('mj-column')) {
setIsColumn(true);
}
isColumn && setIsColumn(false);
}, [active]);

return (
<CustomTabs defaultActiveKey="1" centered style={{ height: '100%' }}>
<CustomTabs defaultActiveKey="1" centered style={{ height: '100%' }} destroyInactiveTabPane={true}>
<TabPane tab="Attributes" key="1">
<Scrollbars style={{ height: '100%' }} autoHide={true}>
<div
Expand All @@ -45,23 +58,31 @@ export const Attributes = () => {
UNDOREDO.newAction(mjmlJson);
}}
>
<Width />
<Height />
<Align />
<VerticalAlign />
<Content />
<FontSize />
<FontFamily />
<Padding />
<InnerPadding />
<ContainerBackground />
<Background />
<BackgroundImage />
<Border />
<CordinalBorder />
<BorderRadius />
<Link />
<Img />
{isColumn ? (
<div style={{ textAlign: 'center' }}>
The selected Item is a Column, to modify properties <h2> check "Column Properties" Tab</h2>
</div>
) : (
<>
<Width />
<Height />
<Align />
<VerticalAlign />
<Content />
<FontSize />
<FontFamily />
<Padding />
<InnerPadding />
<ContainerBackground />
<Background />
<BackgroundImage />
<Border />
<CordinalBorder />
<BorderRadius />
<Link />
<Img />
</>
)}
</div>
</Scrollbars>
</TabPane>
Expand All @@ -72,6 +93,11 @@ export const Attributes = () => {
</div>
</Scrollbars>
</TabPane>
<TabPane tab="Column Properties" key="3">
<Scrollbars style={{ height: '100%' }} autoHide={true}>
<ColumnAttributes />
</Scrollbars>
</TabPane>
</CustomTabs>
);
};

0 comments on commit 22ca5b6

Please sign in to comment.