From db78dabbf23fe84c235344aee55c6a39b18581d3 Mon Sep 17 00:00:00 2001 From: x1unix Date: Sun, 10 Apr 2022 03:00:58 +0200 Subject: [PATCH 01/13] ui: add preview panel command bar --- web/package.json | 1 + web/src/components/core/Panel/PanelAction.css | 16 +++++++ web/src/components/core/Panel/PanelAction.tsx | 31 +++++++++++++ web/src/components/core/Panel/PanelHeader.css | 34 ++++++++++++++ web/src/components/core/Panel/PanelHeader.tsx | 46 +++++++++++++++++++ web/src/components/modals/ChangeLogModal.tsx | 4 +- web/src/components/preview/Preview.css | 2 +- web/src/components/preview/Preview.tsx | 16 ++++--- .../components/preview/ResizablePreview.css | 4 ++ .../components/preview/ResizablePreview.tsx | 22 ++++++++- web/yarn.lock | 5 ++ 11 files changed, 170 insertions(+), 11 deletions(-) create mode 100644 web/src/components/core/Panel/PanelAction.css create mode 100644 web/src/components/core/Panel/PanelAction.tsx create mode 100644 web/src/components/core/Panel/PanelHeader.css create mode 100644 web/src/components/core/Panel/PanelHeader.tsx diff --git a/web/package.json b/web/package.json index abe775ba..5b388fef 100644 --- a/web/package.json +++ b/web/package.json @@ -22,6 +22,7 @@ "re-resizable": "^6.9.1", "react": "^17.0.2", "react-dom": "^17.0.2", + "react-icons": "^4.3.1", "react-monaco-editor": "^0.47.0", "react-redux": "^7.2.6", "react-router-dom": "^5.3.0", diff --git a/web/src/components/core/Panel/PanelAction.css b/web/src/components/core/Panel/PanelAction.css new file mode 100644 index 00000000..72656bb1 --- /dev/null +++ b/web/src/components/core/Panel/PanelAction.css @@ -0,0 +1,16 @@ +.PanelAction { + background: none; + font: inherit; + color: inherit; + border: none; + cursor: pointer; + display: flex; + align-items: center; + padding: 3px; + border-radius: 5px; + margin-right: 4px; +} + +.PanelAction:hover { + background: var(--pg-panel-action-hover-bg); +} diff --git a/web/src/components/core/Panel/PanelAction.tsx b/web/src/components/core/Panel/PanelAction.tsx new file mode 100644 index 00000000..6530f9e6 --- /dev/null +++ b/web/src/components/core/Panel/PanelAction.tsx @@ -0,0 +1,31 @@ +import React from 'react'; +import './PanelAction.css'; +import {getTheme} from "@fluentui/react"; + +export interface PanelActionProps { + hidden?: boolean + icon: React.ReactNode + label: string + onClick?: () => void +} + +const PanelAction: React.FC = ({hidden, icon, label, onClick}) => { + const { + palette: { neutralQuaternaryAlt } + } = getTheme(); + if (hidden) { + return null; + } + + return ( + + ); +}; + +export default PanelAction; diff --git a/web/src/components/core/Panel/PanelHeader.css b/web/src/components/core/Panel/PanelHeader.css new file mode 100644 index 00000000..42e925ea --- /dev/null +++ b/web/src/components/core/Panel/PanelHeader.css @@ -0,0 +1,34 @@ +.PanelHeader { + padding: 8px 8px; + display: flex; + flex-direction: row; + align-items: center; + /*justify-content: center;*/ + justify-content: space-between; +} + +.PanelHeader__title { + text-transform: uppercase; + font-size: 11px; + padding: 0 7px; +} + +.PanelHeader__side--left { + display: flex; + align-items: center; + /*background: #ff00aacc;*/ +} + +.PanelHeader__commands { + display: flex; + flex-direction: row; + list-style: none; + margin: 0; + padding: 0; + /*background: #00ffaacc;*/ +} + +.PanelHeader__commands>li { + margin: 0; + padding: 0; +} diff --git a/web/src/components/core/Panel/PanelHeader.tsx b/web/src/components/core/Panel/PanelHeader.tsx new file mode 100644 index 00000000..2fe11cb5 --- /dev/null +++ b/web/src/components/core/Panel/PanelHeader.tsx @@ -0,0 +1,46 @@ +import React from 'react'; +import { getTheme } from '@fluentui/react'; +import PanelAction from '@components/core/Panel/PanelAction'; +import './PanelHeader.css'; + +interface Props { + label: string + commands?: {[key: string]: {hidden?: boolean, icon: React.ReactNode, label: string}} +} + +const PanelHeader: React.FC = ({label, commands}) => { + const { + palette: { neutralLight, neutralDark, neutralQuaternaryAlt } + } = getTheme(); + + return ( +
+
+ + {label} + +
+
    + {commands ? ( + Object.entries(commands) + .map(([key, props]) => ({key, ...props})) + .filter(({hidden}) => !hidden) + .map((props) => ( +
  • + +
  • + )) + ) : null} +
+
+ ); +}; + +export default PanelHeader; diff --git a/web/src/components/modals/ChangeLogModal.tsx b/web/src/components/modals/ChangeLogModal.tsx index 21af6953..1b53ce04 100644 --- a/web/src/components/modals/ChangeLogModal.tsx +++ b/web/src/components/modals/ChangeLogModal.tsx @@ -41,7 +41,7 @@ export default function ChangeLogModal(props: ChangeLogModalProps) {
{Object.entries(changelog).map(([section, items]) => ( - <> +
{section}
    {items.map(({issueId, url, description}) => ( @@ -57,7 +57,7 @@ export default function ChangeLogModal(props: ChangeLogModalProps) { ))}
- +
))}

And more! diff --git a/web/src/components/preview/Preview.css b/web/src/components/preview/Preview.css index 3444a07d..5ac94837 100644 --- a/web/src/components/preview/Preview.css +++ b/web/src/components/preview/Preview.css @@ -4,7 +4,7 @@ } .app-preview__content { - padding: 15px; + padding: 0 15px 15px 15px; font-size: 10pt; } diff --git a/web/src/components/preview/Preview.tsx b/web/src/components/preview/Preview.tsx index 782b8f85..3dc50de6 100644 --- a/web/src/components/preview/Preview.tsx +++ b/web/src/components/preview/Preview.tsx @@ -42,13 +42,15 @@ export default class Preview extends React.Component { } else if (this.props.events) { - content = this.props.events.map((e, k) => ); + content = this.props.events.map(({Message, Delay, Kind}, k) => ( + + )); if (!isWasm) { content.push(

Program exited.
) diff --git a/web/src/components/preview/ResizablePreview.css b/web/src/components/preview/ResizablePreview.css index 9c26a7bd..26d4ce77 100644 --- a/web/src/components/preview/ResizablePreview.css +++ b/web/src/components/preview/ResizablePreview.css @@ -7,6 +7,10 @@ flex: 1 1 auto; } +.ResizablePreview__controls { + padding: 10px 15px 0 15px; +} + .ResizablePreview__handle--top:before { content: ""; position: absolute; diff --git a/web/src/components/preview/ResizablePreview.tsx b/web/src/components/preview/ResizablePreview.tsx index 772a3d02..5c4b49f8 100644 --- a/web/src/components/preview/ResizablePreview.tsx +++ b/web/src/components/preview/ResizablePreview.tsx @@ -1,8 +1,10 @@ import React, { useState, useCallback } from 'react'; +import { VscSplitHorizontal, VscSplitVertical } from 'react-icons/vsc'; import { getTheme } from '@fluentui/react'; import { Resizable } from 're-resizable'; import Preview from './Preview'; +import PanelHeader from "@components/core/Panel/PanelHeader"; import './ResizablePreview.css'; const DEFAULT_HEIGHT_PX = 300; @@ -26,7 +28,10 @@ const enabledCorners = { interface Props { } const ResizablePreview: React.FC = () => { - const { palette: { accent }, semanticColors: { buttonBorder } } = getTheme(); + const { + palette: { accent }, + semanticColors: { buttonBorder } + } = getTheme(); const [height, setHeight] = useState(DEFAULT_HEIGHT_PX); const onResize = useCallback((e, direction, ref, d) => { setHeight(height + d.height); @@ -44,6 +49,21 @@ const ResizablePreview: React.FC = () => { '--pg-handle-default-color': buttonBorder, } as any} > + , + label: 'Use horizontal layout' + }, + 'split-vertically': { + hidden: false, + icon: , + label: 'Use vertical layout' + } + }} + /> ); diff --git a/web/yarn.lock b/web/yarn.lock index 0718a1d0..ba837a27 100644 --- a/web/yarn.lock +++ b/web/yarn.lock @@ -7424,6 +7424,11 @@ react-error-overlay@^6.0.10: resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.10.tgz#0fe26db4fa85d9dbb8624729580e90e7159a59a6" integrity sha512-mKR90fX7Pm5seCOfz8q9F+66VCc1PGsWSBxKbITjfKVQHMNF2zudxHnMdJiB1fRCb+XsbQV9sO9DCkgsMQgBIA== +react-icons@^4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/react-icons/-/react-icons-4.3.1.tgz#2fa92aebbbc71f43d2db2ed1aed07361124e91ca" + integrity sha512-cB10MXLTs3gVuXimblAdI71jrJx8njrJZmNMEMC+sQu5B/BIOmlsAjskdqpn81y8UBVEGuHODd7/ci5DvoSzTQ== + react-is@^16.13.1, react-is@^16.8.1: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" From 214f47dcd926513946d51f24f32946cee4e4bae9 Mon Sep 17 00:00:00 2001 From: x1unix Date: Sun, 10 Apr 2022 03:03:59 +0200 Subject: [PATCH 02/13] ui: optimize height callback --- web/src/components/preview/ResizablePreview.tsx | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/web/src/components/preview/ResizablePreview.tsx b/web/src/components/preview/ResizablePreview.tsx index 5c4b49f8..fd7048dc 100644 --- a/web/src/components/preview/ResizablePreview.tsx +++ b/web/src/components/preview/ResizablePreview.tsx @@ -28,14 +28,11 @@ const enabledCorners = { interface Props { } const ResizablePreview: React.FC = () => { - const { - palette: { accent }, - semanticColors: { buttonBorder } - } = getTheme(); + const {palette: { accent }, semanticColors: { buttonBorder }} = getTheme(); const [height, setHeight] = useState(DEFAULT_HEIGHT_PX); const onResize = useCallback((e, direction, ref, d) => { - setHeight(height + d.height); - }, [setHeight, height]); + setHeight(prevValue => prevValue + d.height); + }, [setHeight]); return ( Date: Sun, 10 Apr 2022 03:22:01 +0200 Subject: [PATCH 03/13] ui: add resizable panel layouts --- .../components/preview/ResizablePreview.tsx | 47 ++++++++++++++++--- 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/web/src/components/preview/ResizablePreview.tsx b/web/src/components/preview/ResizablePreview.tsx index fd7048dc..1dc3e7fd 100644 --- a/web/src/components/preview/ResizablePreview.tsx +++ b/web/src/components/preview/ResizablePreview.tsx @@ -8,7 +8,7 @@ import PanelHeader from "@components/core/Panel/PanelHeader"; import './ResizablePreview.css'; const DEFAULT_HEIGHT_PX = 300; -const DEFAULT_WIDTH = '100%'; +const DEFAULT_WIDTH_PX = 400; const handleClasses = { top: 'ResizablePreview__handle--top' } @@ -25,20 +25,53 @@ const enabledCorners = { topLeft: false } -interface Props { } +export enum PanelLayout { + Horizontal = 'horizontal', + Vertical = 'vertical' +} + +interface Props { + layout?: PanelLayout +} -const ResizablePreview: React.FC = () => { +const ResizablePreview: React.FC = ({layout = PanelLayout.Horizontal}) => { const {palette: { accent }, semanticColors: { buttonBorder }} = getTheme(); const [height, setHeight] = useState(DEFAULT_HEIGHT_PX); - const onResize = useCallback((e, direction, ref, d) => { - setHeight(prevValue => prevValue + d.height); - }, [setHeight]); + const [width, setWidth] = useState(DEFAULT_WIDTH_PX); + const onResize = useCallback((e, direction, ref, {height, width}) => { + switch (layout) { + case PanelLayout.Horizontal: + setHeight(prevValue => prevValue + height); + return; + case PanelLayout.Vertical: + setWidth(prevValue => prevValue + width); + return; + default: + return; + } + }, [setHeight, setWidth]); + + const size = { + height: layout === PanelLayout.Horizontal ? height : '100%', + width: layout === PanelLayout.Vertical ? width : '100%' + }; + + const enabledCorners = { + top: layout === PanelLayout.Horizontal, + right: false, + bottom: false, + left: layout === PanelLayout.Vertical, + topRight: false, + bottomRight: false, + bottomLeft: false, + topLeft: false + }; return ( Date: Sun, 10 Apr 2022 04:13:15 +0200 Subject: [PATCH 04/13] ui: add collapse/expand command --- web/package.json | 1 + web/src/components/core/Panel/PanelHeader.tsx | 8 +-- .../components/preview/ResizablePreview.css | 19 ++++++ .../components/preview/ResizablePreview.tsx | 59 +++++++++++++------ web/yarn.lock | 5 ++ 5 files changed, 69 insertions(+), 23 deletions(-) diff --git a/web/package.json b/web/package.json index 5b388fef..7d1e2bc2 100644 --- a/web/package.json +++ b/web/package.json @@ -13,6 +13,7 @@ "@types/react-dom": "^17.0.11", "axios": "^0.25.0", "circular-dependency-plugin": "^5.2.2", + "clsx": "^1.1.1", "connected-react-router": "^6.9.2", "copy-to-clipboard": "^3.3.1", "craco-alias": "^3.0.1", diff --git a/web/src/components/core/Panel/PanelHeader.tsx b/web/src/components/core/Panel/PanelHeader.tsx index 2fe11cb5..0a9b47c4 100644 --- a/web/src/components/core/Panel/PanelHeader.tsx +++ b/web/src/components/core/Panel/PanelHeader.tsx @@ -1,11 +1,11 @@ import React from 'react'; import { getTheme } from '@fluentui/react'; -import PanelAction from '@components/core/Panel/PanelAction'; +import PanelAction, {PanelActionProps} from '@components/core/Panel/PanelAction'; import './PanelHeader.css'; interface Props { label: string - commands?: {[key: string]: {hidden?: boolean, icon: React.ReactNode, label: string}} + commands?: {[key: string]: PanelActionProps}, } const PanelHeader: React.FC = ({label, commands}) => { @@ -32,8 +32,8 @@ const PanelHeader: React.FC = ({label, commands}) => { Object.entries(commands) .map(([key, props]) => ({key, ...props})) .filter(({hidden}) => !hidden) - .map((props) => ( -
  • + .map(({key, ...props}) => ( +
  • )) diff --git a/web/src/components/preview/ResizablePreview.css b/web/src/components/preview/ResizablePreview.css index 26d4ce77..df08ec89 100644 --- a/web/src/components/preview/ResizablePreview.css +++ b/web/src/components/preview/ResizablePreview.css @@ -11,6 +11,25 @@ padding: 10px 15px 0 15px; } +/** Collapsed state **/ +.ResizablePreview.ResizablePreview--collapsed { + height: auto !important; +} + +.ResizablePreview.ResizablePreview--collapsed:before { + content: ""; + position: absolute; + background: var(--pg-handle-default-color); +} + +.ResizablePreview.ResizablePreview--collapsed.ResizablePreview--horizontal:before { + top: 0; + left: 0; + right: 0; + height: 1px; +} + +/** Handles **/ .ResizablePreview__handle--top:before { content: ""; position: absolute; diff --git a/web/src/components/preview/ResizablePreview.tsx b/web/src/components/preview/ResizablePreview.tsx index 1dc3e7fd..40c804f9 100644 --- a/web/src/components/preview/ResizablePreview.tsx +++ b/web/src/components/preview/ResizablePreview.tsx @@ -1,7 +1,10 @@ import React, { useState, useCallback } from 'react'; -import { VscSplitHorizontal, VscSplitVertical } from 'react-icons/vsc'; import { getTheme } from '@fluentui/react'; import { Resizable } from 're-resizable'; +import clsx from 'clsx'; +import { + VscSplitHorizontal, VscSplitVertical, VscChevronDown, VscChevronUp +} from 'react-icons/vsc'; import Preview from './Preview'; import PanelHeader from "@components/core/Panel/PanelHeader"; @@ -9,20 +12,10 @@ import './ResizablePreview.css'; const DEFAULT_HEIGHT_PX = 300; const DEFAULT_WIDTH_PX = 400; +const MIN_HEIGHT = 36; const handleClasses = { - top: 'ResizablePreview__handle--top' -} - -// re-resizable requires to implicitly mark disabled corners -const enabledCorners = { - top: true, - right: false, - bottom: false, - left: false, - topRight: false, - bottomRight: false, - bottomLeft: false, - topLeft: false + top: 'ResizablePreview__handle--top', + left: 'ResizablePreview__handle--left', } export enum PanelLayout { @@ -38,6 +31,7 @@ const ResizablePreview: React.FC = ({layout = PanelLayout.Horizontal}) => const {palette: { accent }, semanticColors: { buttonBorder }} = getTheme(); const [height, setHeight] = useState(DEFAULT_HEIGHT_PX); const [width, setWidth] = useState(DEFAULT_WIDTH_PX); + const [collapsed, setCollapsed] = useState(false); const onResize = useCallback((e, direction, ref, {height, width}) => { switch (layout) { case PanelLayout.Horizontal: @@ -49,7 +43,7 @@ const ResizablePreview: React.FC = ({layout = PanelLayout.Horizontal}) => default: return; } - }, [setHeight, setWidth]); + }, [setHeight, setWidth, layout]); const size = { height: layout === PanelLayout.Horizontal ? height : '100%', @@ -57,10 +51,10 @@ const ResizablePreview: React.FC = ({layout = PanelLayout.Horizontal}) => }; const enabledCorners = { - top: layout === PanelLayout.Horizontal, + top: !collapsed && layout === PanelLayout.Horizontal, right: false, bottom: false, - left: layout === PanelLayout.Vertical, + left: !collapsed && layout === PanelLayout.Vertical, topRight: false, bottomRight: false, bottomLeft: false, @@ -69,11 +63,18 @@ const ResizablePreview: React.FC = ({layout = PanelLayout.Horizontal}) => return ( = ({layout = PanelLayout.Horizontal}) => , + label: 'Collapse', + onClick: () => { + console.log('collapse!'); + setCollapsed(true); + } + }, + 'expand': { + hidden: !collapsed, + icon: , + label: 'Expand', + onClick: () => { + console.log('expand!'); + setCollapsed(false); + } + }, 'split-horizontally': { hidden: true, icon: , @@ -94,7 +113,9 @@ const ResizablePreview: React.FC = ({layout = PanelLayout.Horizontal}) => } }} /> - + { collapsed ? null : ( + + )} ); }; diff --git a/web/yarn.lock b/web/yarn.lock index ba837a27..4d7fade4 100644 --- a/web/yarn.lock +++ b/web/yarn.lock @@ -3107,6 +3107,11 @@ cliui@^7.0.2: strip-ansi "^6.0.0" wrap-ansi "^7.0.0" +clsx@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.1.1.tgz#98b3134f9abbdf23b2663491ace13c5c03a73188" + integrity sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA== + co@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" From 174f3fdaa7b339f88bfd42c05aea1c29f62f9d18 Mon Sep 17 00:00:00 2001 From: x1unix Date: Sun, 10 Apr 2022 04:27:39 +0200 Subject: [PATCH 05/13] ui: improve resize handle on touch --- web/src/components/preview/ResizablePreview.css | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/web/src/components/preview/ResizablePreview.css b/web/src/components/preview/ResizablePreview.css index df08ec89..93ff4165 100644 --- a/web/src/components/preview/ResizablePreview.css +++ b/web/src/components/preview/ResizablePreview.css @@ -71,9 +71,10 @@ .ResizablePreview__handle--top:after { content: ""; - background: #d3d3d3; - width: 25%; - height: 1px; + background: #999; + width: 86px; + height: 4px; + border-radius: 4px; align-self: center; } } From 4f45dccad84aeeb930be61d5dabf3f45bac05da7 Mon Sep 17 00:00:00 2001 From: x1unix Date: Sun, 10 Apr 2022 04:52:19 +0200 Subject: [PATCH 06/13] ui: preparation for different layouts --- web/src/components/core/Layout/Layout.css | 13 ++++++++++ web/src/components/core/Layout/Layout.tsx | 15 ++++++++++++ web/src/components/core/Layout/index.ts | 1 + web/src/components/pages/Playground.css | 5 ++-- web/src/components/pages/Playground.tsx | 13 ++++++---- .../components/preview/ResizablePreview.tsx | 24 ++++++++----------- web/src/styles/layout.ts | 4 ++++ 7 files changed, 54 insertions(+), 21 deletions(-) create mode 100644 web/src/components/core/Layout/Layout.css create mode 100644 web/src/components/core/Layout/Layout.tsx create mode 100644 web/src/components/core/Layout/index.ts create mode 100644 web/src/styles/layout.ts diff --git a/web/src/components/core/Layout/Layout.css b/web/src/components/core/Layout/Layout.css new file mode 100644 index 00000000..1e7eab20 --- /dev/null +++ b/web/src/components/core/Layout/Layout.css @@ -0,0 +1,13 @@ +.Layout { + display: flex; + flex: 1 1 auto; + overflow: hidden; +} + +.Layout.Layout--vertical { + flex-direction: column; +} + +.Layout.Layout--horizontal { + flex-direction: row; +} diff --git a/web/src/components/core/Layout/Layout.tsx b/web/src/components/core/Layout/Layout.tsx new file mode 100644 index 00000000..2ce55d43 --- /dev/null +++ b/web/src/components/core/Layout/Layout.tsx @@ -0,0 +1,15 @@ +import React from 'react'; +import {LayoutType} from '~/styles/layout'; +import './Layout.css'; + +interface Props { + layout?: LayoutType; +} + +const Layout: React.FC = ({layout = LayoutType.Vertical, children}) => ( +
    + {children} +
    +); + +export default Layout; diff --git a/web/src/components/core/Layout/index.ts b/web/src/components/core/Layout/index.ts new file mode 100644 index 00000000..9877e7f4 --- /dev/null +++ b/web/src/components/core/Layout/index.ts @@ -0,0 +1 @@ +export * from './Layout'; diff --git a/web/src/components/pages/Playground.css b/web/src/components/pages/Playground.css index e7b0ffc9..165c60e0 100644 --- a/web/src/components/pages/Playground.css +++ b/web/src/components/pages/Playground.css @@ -1,10 +1,11 @@ -.playground { +.Playground { position: absolute; top: 0; left: 0; bottom: 0; right: 0; + height: 100%; + width: 100%; display: flex; flex-direction: column; - /*background: #ccc;*/ } diff --git a/web/src/components/pages/Playground.tsx b/web/src/components/pages/Playground.tsx index 945d25ba..fa7c611a 100644 --- a/web/src/components/pages/Playground.tsx +++ b/web/src/components/pages/Playground.tsx @@ -7,6 +7,7 @@ import { Header } from '~/components/core/Header'; import CodeEditor from '~/components/editor/CodeEditor'; import FlexContainer from '~/components/editor/FlexContainer'; import ResizablePreview from '~/components/preview/ResizablePreview'; +import Layout from '~/components/core/Layout/Layout'; import StatusBar from '~/components/core/StatusBar'; import './Playground.css'; @@ -15,12 +16,14 @@ const Playground = connect()((props: any) => { const { snippetID } = useParams(); props.dispatch(newSnippetLoadDispatcher(snippetID)); - return
    + return
    - - - - + + + + + +
    ; }); diff --git a/web/src/components/preview/ResizablePreview.tsx b/web/src/components/preview/ResizablePreview.tsx index 40c804f9..1a5ffae9 100644 --- a/web/src/components/preview/ResizablePreview.tsx +++ b/web/src/components/preview/ResizablePreview.tsx @@ -7,7 +7,8 @@ import { } from 'react-icons/vsc'; import Preview from './Preview'; -import PanelHeader from "@components/core/Panel/PanelHeader"; +import PanelHeader from '~/components/core/Panel/PanelHeader'; +import {LayoutType} from '~/styles/layout'; import './ResizablePreview.css'; const DEFAULT_HEIGHT_PX = 300; @@ -18,26 +19,21 @@ const handleClasses = { left: 'ResizablePreview__handle--left', } -export enum PanelLayout { - Horizontal = 'horizontal', - Vertical = 'vertical' -} - interface Props { - layout?: PanelLayout + layout?: LayoutType } -const ResizablePreview: React.FC = ({layout = PanelLayout.Horizontal}) => { +const ResizablePreview: React.FC = ({layout = LayoutType.Horizontal}) => { const {palette: { accent }, semanticColors: { buttonBorder }} = getTheme(); const [height, setHeight] = useState(DEFAULT_HEIGHT_PX); const [width, setWidth] = useState(DEFAULT_WIDTH_PX); const [collapsed, setCollapsed] = useState(false); const onResize = useCallback((e, direction, ref, {height, width}) => { switch (layout) { - case PanelLayout.Horizontal: + case LayoutType.Horizontal: setHeight(prevValue => prevValue + height); return; - case PanelLayout.Vertical: + case LayoutType.Vertical: setWidth(prevValue => prevValue + width); return; default: @@ -46,15 +42,15 @@ const ResizablePreview: React.FC = ({layout = PanelLayout.Horizontal}) => }, [setHeight, setWidth, layout]); const size = { - height: layout === PanelLayout.Horizontal ? height : '100%', - width: layout === PanelLayout.Vertical ? width : '100%' + height: layout === LayoutType.Horizontal ? height : '100%', + width: layout === LayoutType.Vertical ? width : '100%' }; const enabledCorners = { - top: !collapsed && layout === PanelLayout.Horizontal, + top: !collapsed && layout === LayoutType.Horizontal, right: false, bottom: false, - left: !collapsed && layout === PanelLayout.Vertical, + left: !collapsed && layout === LayoutType.Vertical, topRight: false, bottomRight: false, bottomLeft: false, diff --git a/web/src/styles/layout.ts b/web/src/styles/layout.ts new file mode 100644 index 00000000..068f68d0 --- /dev/null +++ b/web/src/styles/layout.ts @@ -0,0 +1,4 @@ +export enum LayoutType { + Horizontal = 'horizontal', + Vertical = 'vertical' +} From 35164250100dbcf7534e652a0e2cf2a855c1eb0a Mon Sep 17 00:00:00 2001 From: x1unix Date: Sun, 10 Apr 2022 05:19:56 +0200 Subject: [PATCH 07/13] ui: hide collapse option in horizontal view --- web/src/components/core/Panel/PanelAction.tsx | 4 - web/src/components/pages/Playground.tsx | 5 +- .../components/preview/ResizablePreview.css | 2 +- .../components/preview/ResizablePreview.tsx | 97 ++++++++++--------- 4 files changed, 55 insertions(+), 53 deletions(-) diff --git a/web/src/components/core/Panel/PanelAction.tsx b/web/src/components/core/Panel/PanelAction.tsx index 6530f9e6..beb9e502 100644 --- a/web/src/components/core/Panel/PanelAction.tsx +++ b/web/src/components/core/Panel/PanelAction.tsx @@ -1,6 +1,5 @@ import React from 'react'; import './PanelAction.css'; -import {getTheme} from "@fluentui/react"; export interface PanelActionProps { hidden?: boolean @@ -10,9 +9,6 @@ export interface PanelActionProps { } const PanelAction: React.FC = ({hidden, icon, label, onClick}) => { - const { - palette: { neutralQuaternaryAlt } - } = getTheme(); if (hidden) { return null; } diff --git a/web/src/components/pages/Playground.tsx b/web/src/components/pages/Playground.tsx index fa7c611a..b886c954 100644 --- a/web/src/components/pages/Playground.tsx +++ b/web/src/components/pages/Playground.tsx @@ -9,6 +9,7 @@ import FlexContainer from '~/components/editor/FlexContainer'; import ResizablePreview from '~/components/preview/ResizablePreview'; import Layout from '~/components/core/Layout/Layout'; import StatusBar from '~/components/core/StatusBar'; +import {LayoutType} from "~/styles/layout"; import './Playground.css'; @@ -18,11 +19,11 @@ const Playground = connect()((props: any) => { return
    - + - +
    ; diff --git a/web/src/components/preview/ResizablePreview.css b/web/src/components/preview/ResizablePreview.css index 93ff4165..623c313e 100644 --- a/web/src/components/preview/ResizablePreview.css +++ b/web/src/components/preview/ResizablePreview.css @@ -22,7 +22,7 @@ background: var(--pg-handle-default-color); } -.ResizablePreview.ResizablePreview--collapsed.ResizablePreview--horizontal:before { +.ResizablePreview.ResizablePreview--collapsed.ResizablePreview--vertical:before { top: 0; left: 0; right: 0; diff --git a/web/src/components/preview/ResizablePreview.tsx b/web/src/components/preview/ResizablePreview.tsx index 1a5ffae9..de3cb53d 100644 --- a/web/src/components/preview/ResizablePreview.tsx +++ b/web/src/components/preview/ResizablePreview.tsx @@ -1,9 +1,12 @@ -import React, { useState, useCallback } from 'react'; -import { getTheme } from '@fluentui/react'; -import { Resizable } from 're-resizable'; +import React, {useCallback} from 'react'; +import {getTheme} from '@fluentui/react'; +import {Resizable} from 're-resizable'; import clsx from 'clsx'; import { - VscSplitHorizontal, VscSplitVertical, VscChevronDown, VscChevronUp + VscChevronDown, + VscChevronUp, + VscSplitHorizontal, + VscSplitVertical } from 'react-icons/vsc'; import Preview from './Preview'; @@ -19,50 +22,61 @@ const handleClasses = { left: 'ResizablePreview__handle--left', } -interface Props { +export interface ResizePanelParams { layout?: LayoutType + collapsed?: boolean + height?: string|number + width?: string|number } -const ResizablePreview: React.FC = ({layout = LayoutType.Horizontal}) => { +interface Props extends ResizePanelParams { + onViewChange?: (changes: ResizePanelParams) => void +} + +const ResizablePreview: React.FC = ({ + layout = LayoutType.Vertical, + height = DEFAULT_HEIGHT_PX, + width=DEFAULT_WIDTH_PX, + collapsed, + onViewChange +}) => { const {palette: { accent }, semanticColors: { buttonBorder }} = getTheme(); - const [height, setHeight] = useState(DEFAULT_HEIGHT_PX); - const [width, setWidth] = useState(DEFAULT_WIDTH_PX); - const [collapsed, setCollapsed] = useState(false); - const onResize = useCallback((e, direction, ref, {height, width}) => { + const onResize = useCallback((e, direction, ref, size) => { switch (layout) { - case LayoutType.Horizontal: - setHeight(prevValue => prevValue + height); - return; case LayoutType.Vertical: - setWidth(prevValue => prevValue + width); + onViewChange?.({ height: height + size.height}); + return; + case LayoutType.Horizontal: + onViewChange?.({ width: width + size.width}); return; default: return; } - }, [setHeight, setWidth, layout]); + }, [height, width, layout, onViewChange]); const size = { - height: layout === LayoutType.Horizontal ? height : '100%', - width: layout === LayoutType.Vertical ? width : '100%' + height: layout === LayoutType.Vertical ? height : '100%', + width: layout === LayoutType.Horizontal ? width : '100%' }; const enabledCorners = { - top: !collapsed && layout === LayoutType.Horizontal, + top: !collapsed && layout === LayoutType.Vertical, right: false, bottom: false, - left: !collapsed && layout === LayoutType.Vertical, + left: !collapsed && layout === LayoutType.Horizontal, topRight: false, bottomRight: false, bottomLeft: false, topLeft: false }; + const isCollapsed = collapsed && layout === LayoutType.Vertical; return ( = ({layout = LayoutType.Horizontal}) => , - label: 'Collapse', - onClick: () => { - console.log('collapse!'); - setCollapsed(true); - } - }, - 'expand': { - hidden: !collapsed, - icon: , - label: 'Expand', - onClick: () => { - console.log('expand!'); - setCollapsed(false); - } - }, - 'split-horizontally': { - hidden: true, + 'vertical-layout': { + hidden: layout === LayoutType.Vertical, icon: , - label: 'Use horizontal layout' + label: 'Use vertical layout', + onClick: () => onViewChange?.({ layout: LayoutType.Vertical }) }, - 'split-vertically': { - hidden: false, + 'horizontal-layout': { + hidden: layout === LayoutType.Horizontal, icon: , - label: 'Use vertical layout' - } + label: 'Use horizontal layout', + onClick: () => onViewChange?.({ layout: LayoutType.Horizontal }) + }, + 'collapse': { + hidden: layout === LayoutType.Horizontal, + icon: collapsed ? : , + label: collapsed ? 'Expand' : 'Collapse', + onClick: () => onViewChange?.({ collapsed: !collapsed }) + }, + }} /> - { collapsed ? null : ( + { isCollapsed ? null : ( )} From 05edaf36adaa577931bcbf4c99b12e1d27bde808 Mon Sep 17 00:00:00 2001 From: x1unix Date: Sun, 10 Apr 2022 05:37:13 +0200 Subject: [PATCH 08/13] ui: add mobile controls for vertical layout --- web/src/components/pages/Playground.tsx | 4 +- .../components/preview/ResizablePreview.css | 55 ++++++++++++++++++- .../components/preview/ResizablePreview.tsx | 2 +- 3 files changed, 57 insertions(+), 4 deletions(-) diff --git a/web/src/components/pages/Playground.tsx b/web/src/components/pages/Playground.tsx index b886c954..5d6776ee 100644 --- a/web/src/components/pages/Playground.tsx +++ b/web/src/components/pages/Playground.tsx @@ -19,11 +19,11 @@ const Playground = connect()((props: any) => { return
    - + - +
    ; diff --git a/web/src/components/preview/ResizablePreview.css b/web/src/components/preview/ResizablePreview.css index 623c313e..b9df67d7 100644 --- a/web/src/components/preview/ResizablePreview.css +++ b/web/src/components/preview/ResizablePreview.css @@ -29,7 +29,60 @@ height: 1px; } -/** Handles **/ +/** Handles - vertical **/ +.ResizablePreview__handle--left:before { + content: ""; + position: absolute; + background: var(--pg-handle-default-color); + transition: background-color 0.1s ease-in 0s; + width: 1px; + height: 100%; + top: 0; + left: 50%; +} + +.ResizablePreview__handle--left { + transition: background-color 0.1s ease-in 0s; +} + +.ResizablePreview__handle--left:hover:before, +.ResizablePreview__handle--left:active:before { + background: var(--pg-handle-active-color); + width: 3px; +} + +@media (hover: none), (pointer: coarse) { + .ResizablePreview__handle--left { + background: black; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + color: #999; + } + + .ResizablePreview__handle--left:hover, + .ResizablePreview__handle--left:active { + background: black; + color: white; + } + + .ResizablePreview__handle--left:before { + display: none; + } + + .ResizablePreview__handle--left:after { + content: ""; + background: currentColor; + height: 13.3%; + width: 4px; + border-radius: 4px; + align-self: center; + transition: color 0.15s ease 0s; + } +} + +/** Handles - Horizontal **/ .ResizablePreview__handle--top:before { content: ""; position: absolute; diff --git a/web/src/components/preview/ResizablePreview.tsx b/web/src/components/preview/ResizablePreview.tsx index de3cb53d..8c24c0f1 100644 --- a/web/src/components/preview/ResizablePreview.tsx +++ b/web/src/components/preview/ResizablePreview.tsx @@ -15,7 +15,7 @@ import {LayoutType} from '~/styles/layout'; import './ResizablePreview.css'; const DEFAULT_HEIGHT_PX = 300; -const DEFAULT_WIDTH_PX = 400; +const DEFAULT_WIDTH_PX = 320; const MIN_HEIGHT = 36; const handleClasses = { top: 'ResizablePreview__handle--top', From e61a63b372b3e08418cf022d42a6d67f04313e4d Mon Sep 17 00:00:00 2001 From: x1unix Date: Sun, 10 Apr 2022 05:44:37 +0200 Subject: [PATCH 09/13] ui: add mobile controls for vertical layout --- web/src/components/pages/Playground.tsx | 4 ++-- web/src/components/preview/ResizablePreview.css | 17 +++++++++++------ 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/web/src/components/pages/Playground.tsx b/web/src/components/pages/Playground.tsx index 5d6776ee..b886c954 100644 --- a/web/src/components/pages/Playground.tsx +++ b/web/src/components/pages/Playground.tsx @@ -19,11 +19,11 @@ const Playground = connect()((props: any) => { return
    - + - +
    ; diff --git a/web/src/components/preview/ResizablePreview.css b/web/src/components/preview/ResizablePreview.css index b9df67d7..045dd87a 100644 --- a/web/src/components/preview/ResizablePreview.css +++ b/web/src/components/preview/ResizablePreview.css @@ -74,7 +74,8 @@ .ResizablePreview__handle--left:after { content: ""; background: currentColor; - height: 13.3%; + height: 20%; + max-height: 80px; width: 4px; border-radius: 4px; align-self: center; @@ -104,18 +105,20 @@ height: 3px; } -@media (hover: none), (pointer: coarse) { +/*@media (hover: none), (pointer: coarse) {*/ .ResizablePreview__handle--top { background: black; display: flex; flex-direction: column; align-items: center; justify-content: center; + color: #999; } .ResizablePreview__handle--top:hover, .ResizablePreview__handle--top:active { - background: var(--pg-handle-active-color); + background: black; + color: #fff; } .ResizablePreview__handle--top:before { @@ -124,10 +127,12 @@ .ResizablePreview__handle--top:after { content: ""; - background: #999; - width: 86px; + background: currentColor; + width: 20%; + max-width: 80px; height: 4px; border-radius: 4px; align-self: center; + transition: 0.15s ease 0s; } -} +/*}*/ From 1895c866e7656f1ff5664a846b36b9469426890f Mon Sep 17 00:00:00 2001 From: x1unix Date: Sun, 10 Apr 2022 05:49:00 +0200 Subject: [PATCH 10/13] ui: hide horizontal layout on mobile screens --- web/src/components/core/Panel/PanelAction.css | 7 +++++++ web/src/components/core/Panel/PanelAction.tsx | 6 ++++-- web/src/components/preview/ResizablePreview.tsx | 1 + 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/web/src/components/core/Panel/PanelAction.css b/web/src/components/core/Panel/PanelAction.css index 72656bb1..7ad53519 100644 --- a/web/src/components/core/Panel/PanelAction.css +++ b/web/src/components/core/Panel/PanelAction.css @@ -14,3 +14,10 @@ .PanelAction:hover { background: var(--pg-panel-action-hover-bg); } + +@media (max-width: 480px) { + .PanelAction--desktopOnly { + display: none; + } +} + diff --git a/web/src/components/core/Panel/PanelAction.tsx b/web/src/components/core/Panel/PanelAction.tsx index beb9e502..f15fd279 100644 --- a/web/src/components/core/Panel/PanelAction.tsx +++ b/web/src/components/core/Panel/PanelAction.tsx @@ -1,21 +1,23 @@ import React from 'react'; +import clsx from 'clsx'; import './PanelAction.css'; export interface PanelActionProps { hidden?: boolean icon: React.ReactNode label: string + desktopOnly?: boolean onClick?: () => void } -const PanelAction: React.FC = ({hidden, icon, label, onClick}) => { +const PanelAction: React.FC = ({hidden, icon, desktopOnly, label, onClick}) => { if (hidden) { return null; } return (