From 6055c2ff2eca1a3b5963ead30da083e17e6ad403 Mon Sep 17 00:00:00 2001 From: "LAPTOP-G2U17NSB\\duy_9" Date: Wed, 28 Aug 2024 11:20:17 +0200 Subject: [PATCH 1/6] AppBar component implementation. NOTE: Currently experiencing issues with the component selection functionality. --- public/rich-components/appBar.svg | 12 ++ .../front-components/shape.const.ts | 4 + .../front-rich-components/appBar.tsx | 115 ++++++++++++++++++ .../components/front-rich-components/index.ts | 1 + src/core/model/index.ts | 4 +- src/pods/canvas/canvas.model.ts | 12 +- src/pods/canvas/shape-renderer/index.tsx | 3 + .../appBar.renderer.tsx | 33 +++++ .../simple-rich-components/index.ts | 1 + .../rich-components-gallery-data/index.ts | 1 + 10 files changed, 183 insertions(+), 3 deletions(-) create mode 100644 public/rich-components/appBar.svg create mode 100644 src/common/components/front-rich-components/appBar.tsx create mode 100644 src/pods/canvas/shape-renderer/simple-rich-components/appBar.renderer.tsx diff --git a/public/rich-components/appBar.svg b/public/rich-components/appBar.svg new file mode 100644 index 00000000..50254702 --- /dev/null +++ b/public/rich-components/appBar.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + App Title + diff --git a/src/common/components/front-components/shape.const.ts b/src/common/components/front-components/shape.const.ts index dbee26a5..03ac73b3 100644 --- a/src/common/components/front-components/shape.const.ts +++ b/src/common/components/front-components/shape.const.ts @@ -1,6 +1,7 @@ const DEFAULT_CORNER_RADIUS = 4; const DEFAULT_STROKE_COLOR = '#000000'; const DEFAULT_STROKE_WIDTH = 1; +const DEFAULT_STROKE_STYLE: number[] = []; const DEFAULT_FILL_BACKGROUND = '#ffffff'; const DEFAULT_FONT_FAMILY = 'Comic Sans MS, cursive'; const DEFAULT_FONT_SIZE = 16; @@ -24,6 +25,7 @@ interface DefaultStyleShape { DEFAULT_LINE_HEIGHT: number; DEFAULT_TEXT_WIDTH: number; DEFAULT_TEXT_HEIGHT: number; + DEFAULT_STROKE_STYLE: number[]; } export const BASIC_SHAPE: DefaultStyleShape = { @@ -38,6 +40,7 @@ export const BASIC_SHAPE: DefaultStyleShape = { DEFAULT_LINE_HEIGHT, DEFAULT_TEXT_WIDTH, DEFAULT_TEXT_HEIGHT, + DEFAULT_STROKE_STYLE, }; export const INPUT_SHAPE: DefaultStyleShape = { @@ -52,6 +55,7 @@ export const INPUT_SHAPE: DefaultStyleShape = { DEFAULT_LINE_HEIGHT, DEFAULT_TEXT_WIDTH, DEFAULT_TEXT_HEIGHT, + DEFAULT_STROKE_STYLE, }; //! maybe a function to calc max height base on the text diff --git a/src/common/components/front-rich-components/appBar.tsx b/src/common/components/front-rich-components/appBar.tsx new file mode 100644 index 00000000..2a0f4012 --- /dev/null +++ b/src/common/components/front-rich-components/appBar.tsx @@ -0,0 +1,115 @@ +import { forwardRef, useMemo } from 'react'; +import { Group, Rect, Text } from 'react-konva'; +import { ShapeProps } from '../front-components/shape.model'; +import { ShapeSizeRestrictions } from '@/core/model'; +import { BASIC_SHAPE } from '../front-components/shape.const'; +import { fitSizeToShapeSizeRestrictions } from '@/common/utils/shapes/shape-restrictions'; + +const AppBarShapeSizeRestrictions: ShapeSizeRestrictions = { + minWidth: 100, + minHeight: 100, + maxWidth: -1, + maxHeight: 38, + defaultWidth: 250, + defaultHeight: BASIC_SHAPE.DEFAULT_TEXT_HEIGHT, +}; + +export const getAppBarShapeSizeRestrictions = (): ShapeSizeRestrictions => + AppBarShapeSizeRestrictions; + +export const AppBarShape = forwardRef( + ( + { x, y, width, height, title, id, text, otherProps, ...shapeProps }, + ref + ) => { + const { width: restrictedWidth, height: restrictedHeight } = + fitSizeToShapeSizeRestrictions( + AppBarShapeSizeRestrictions, + width, + height + ); + + const iconSize = 4; + const iconWidth = 30; + const iconPadding = 10; + + const textColor = useMemo( + () => otherProps?.textColor ?? '#ffffff', + [otherProps?.textColor] + ); + + const backgroundColor = useMemo( + () => otherProps?.backgroundColor ?? '#A9A9A9', + [otherProps?.textColor] + ); + + const stroke = useMemo( + () => otherProps?.stroke ?? BASIC_SHAPE.DEFAULT_STROKE_COLOR, + [otherProps?.stroke] + ); + + const strokeStyle = useMemo( + () => otherProps?.strokeStyle ?? BASIC_SHAPE.DEFAULT_STROKE_STYLE, + [otherProps?.strokeStyle] + ); + + return ( + + {/* AppBar background*/} + + + {/* Menu Icon*/} + + + + + {/* AppBar title*/} + + + ); + } +); + +export default AppBarShape; diff --git a/src/common/components/front-rich-components/index.ts b/src/common/components/front-rich-components/index.ts index d9e9a8dc..9d2360dc 100644 --- a/src/common/components/front-rich-components/index.ts +++ b/src/common/components/front-rich-components/index.ts @@ -10,3 +10,4 @@ export * from './vertical-menu/vertical-menu'; export * from './calendar/calendar'; export * from './table/table'; export * from './modal/modal'; +export * from './appBar'; diff --git a/src/core/model/index.ts b/src/core/model/index.ts index 82537e83..b8fb2592 100644 --- a/src/core/model/index.ts +++ b/src/core/model/index.ts @@ -56,7 +56,8 @@ export type ShapeType = | 'table' | 'verticalScrollBar' | 'horizontalScrollBar' - | 'modal'; + | 'modal' + | 'appBar'; export const ShapeDisplayName: Record = { combobox: 'Combobox', @@ -104,6 +105,7 @@ export const ShapeDisplayName: Record = { calendar: 'Calendar', verticalScrollBar: 'Vertical Scroll Bar', modal: 'Modal', + appBar: 'AppBar', }; export type EditType = 'input' | 'textarea' | 'imageupload'; diff --git a/src/pods/canvas/canvas.model.ts b/src/pods/canvas/canvas.model.ts index 3b7c50ef..2ba7e2f1 100644 --- a/src/pods/canvas/canvas.model.ts +++ b/src/pods/canvas/canvas.model.ts @@ -55,6 +55,7 @@ import { getCalendarShapeSizeRestrictions, getTableSizeRestrictions, getModalShapeSizeRestrictions, + getAppBarShapeSizeRestrictions, } from '@/common/components/front-rich-components'; import { getHeading1SizeRestrictions, @@ -87,9 +88,8 @@ export const getSizeRestrictionFromShape = ( return getDatepickerInputShapeSizeRestrictions(); case 'button': return getButtonShapeSizeRestrictions(); - case 'progressbar': { + case 'progressbar': return getProgressBarShapeSizeRestrictions(); - } case 'listbox': return getListboxShapeSizeRestrictions(); case 'browser': @@ -164,6 +164,8 @@ export const getSizeRestrictionFromShape = ( return getVerticalScrollBarShapeSizeRestrictions(); case 'modal': return getModalShapeSizeRestrictions(); + case 'appBar': + return getAppBarShapeSizeRestrictions(); default: console.warn( `** Shape ${shapeType} has not defined default size, check getDefaultSizeFromShape helper function` @@ -217,6 +219,7 @@ const doesShapeAllowInlineEdition = (shapeType: ShapeType): boolean => { case 'image': case 'table': case 'modal': + case 'appBar': return true; default: return false; @@ -245,6 +248,7 @@ const generateTypeOfTransformer = (shapeType: ShapeType): string[] => { case 'normaltext': case 'smalltext': case 'horizontalScrollBar': + case 'appBar': return ['middle-left', 'middle-right']; case 'verticalScrollBar': return ['top-center', 'bottom-center']; @@ -308,6 +312,8 @@ const generateDefaultTextValue = (shapeType: ShapeType): string | undefined => { return 'Name ^, Age ^v, Country v\nJohn Doe, 30, USA\nJane Smith, 25, UK\nLuis Gomez, 35, Argentina\n{*L,20R,30C}'; case 'modal': return 'Alert\nWarning: The action you are about to perform may affect existing data. Are you sure you want to proceed? Once confirmed, this action cannot be undone.\nConfirm,Cancel'; + case 'appBar': + return 'AppBar'; default: return undefined; } @@ -327,6 +333,7 @@ const getShapeEditInlineType = (shapeType: ShapeType): EditType | undefined => { case 'vertical-menu': case 'table': case 'modal': + case 'appBar': return 'textarea'; break; case 'image': @@ -356,6 +363,7 @@ export const generateDefaultOtherProps = ( case 'datepickerinput': case 'timepickerinput': case 'modal': + case 'appBar': return { stroke: BASIC_SHAPE.DEFAULT_STROKE_COLOR, backgroundColor: BASIC_SHAPE.DEFAULT_FILL_BACKGROUND, diff --git a/src/pods/canvas/shape-renderer/index.tsx b/src/pods/canvas/shape-renderer/index.tsx index 32b41021..c9fee91c 100644 --- a/src/pods/canvas/shape-renderer/index.tsx +++ b/src/pods/canvas/shape-renderer/index.tsx @@ -56,6 +56,7 @@ import { renderSmalltext } from './simple-text-components/smalltext.renderer'; import { renderParagraph } from './simple-text-components/paragraph.renderer'; import { renderImage } from './simple-basic-shapes/image.renderer'; import { renderCalendar } from './simple-rich-components/calendar.renderer'; +import { renderAppBar } from './simple-rich-components/appBar.renderer'; export const renderShapeComponent = ( shape: ShapeModel, @@ -152,6 +153,8 @@ export const renderShapeComponent = ( return renderVerticalScrollBar(shape, shapeRenderedProps); case 'modal': return renderModal(shape, shapeRenderedProps); + case 'appBar': + return renderAppBar(shape, shapeRenderedProps); default: return renderNotFound(shape, shapeRenderedProps); } diff --git a/src/pods/canvas/shape-renderer/simple-rich-components/appBar.renderer.tsx b/src/pods/canvas/shape-renderer/simple-rich-components/appBar.renderer.tsx new file mode 100644 index 00000000..1ab2387b --- /dev/null +++ b/src/pods/canvas/shape-renderer/simple-rich-components/appBar.renderer.tsx @@ -0,0 +1,33 @@ +import { AppBarShape } from '@/common/components/front-rich-components/appBar'; +import { ShapeRendererProps } from '../model'; +import { ShapeModel } from '@/core/model'; + +export const renderAppBar = ( + shape: ShapeModel, + shapeRenderedProps: ShapeRendererProps +) => { + const { handleSelected, shapeRefs, handleDragEnd, handleTransform } = + shapeRenderedProps; + + return ( + + ); +}; diff --git a/src/pods/canvas/shape-renderer/simple-rich-components/index.ts b/src/pods/canvas/shape-renderer/simple-rich-components/index.ts index 84c63d37..f7d2b070 100644 --- a/src/pods/canvas/shape-renderer/simple-rich-components/index.ts +++ b/src/pods/canvas/shape-renderer/simple-rich-components/index.ts @@ -10,3 +10,4 @@ export * from './vertical-menu.renderer'; export * from './calendar.renderer'; export * from './table.renderer'; export * from './modal.renderer'; +export * from './appBar.renderer'; diff --git a/src/pods/rich-components-gallery/rich-components-gallery-data/index.ts b/src/pods/rich-components-gallery/rich-components-gallery-data/index.ts index b8091981..846672d2 100644 --- a/src/pods/rich-components-gallery/rich-components-gallery-data/index.ts +++ b/src/pods/rich-components-gallery/rich-components-gallery-data/index.ts @@ -19,4 +19,5 @@ export const mockRichComponentsCollection: ItemInfo[] = [ { thumbnailSrc: '/rich-components/calendar.svg', type: 'calendar' }, { thumbnailSrc: '/rich-components/table.svg', type: 'table' }, { thumbnailSrc: '/rich-components/modal.svg', type: 'modal' }, + { thumbnailSrc: '/rich-components/appBar.svg', type: 'appBar' }, ]; From 555ed2859e29175717d177397f507ac704801e63 Mon Sep 17 00:00:00 2001 From: "LAPTOP-G2U17NSB\\duy_9" Date: Wed, 28 Aug 2024 12:09:34 +0200 Subject: [PATCH 2/6] Fixed selection issue --- .../front-rich-components/appBar.tsx | 20 +++++++++++++++---- src/pods/canvas/canvas.model.ts | 8 +++++++- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/common/components/front-rich-components/appBar.tsx b/src/common/components/front-rich-components/appBar.tsx index 2a0f4012..4d52e9f3 100644 --- a/src/common/components/front-rich-components/appBar.tsx +++ b/src/common/components/front-rich-components/appBar.tsx @@ -6,10 +6,10 @@ import { BASIC_SHAPE } from '../front-components/shape.const'; import { fitSizeToShapeSizeRestrictions } from '@/common/utils/shapes/shape-restrictions'; const AppBarShapeSizeRestrictions: ShapeSizeRestrictions = { - minWidth: 100, - minHeight: 100, + minWidth: 155, + minHeight: 38, maxWidth: -1, - maxHeight: 38, + maxHeight: -1, defaultWidth: 250, defaultHeight: BASIC_SHAPE.DEFAULT_TEXT_HEIGHT, }; @@ -19,7 +19,18 @@ export const getAppBarShapeSizeRestrictions = (): ShapeSizeRestrictions => export const AppBarShape = forwardRef( ( - { x, y, width, height, title, id, text, otherProps, ...shapeProps }, + { + x, + y, + width, + height, + title, + id, + text, + otherProps, + onSelected, + ...shapeProps + }, ref ) => { const { width: restrictedWidth, height: restrictedHeight } = @@ -61,6 +72,7 @@ export const AppBarShape = forwardRef( width={restrictedWidth} height={restrictedHeight} {...shapeProps} + onClick={() => onSelected(id, 'appBar')} > {/* AppBar background*/} Date: Wed, 28 Aug 2024 13:50:12 +0200 Subject: [PATCH 3/6] Adding wrap and ellipsis --- .../front-rich-components/appBar.tsx | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/common/components/front-rich-components/appBar.tsx b/src/common/components/front-rich-components/appBar.tsx index 4d52e9f3..f20187cb 100644 --- a/src/common/components/front-rich-components/appBar.tsx +++ b/src/common/components/front-rich-components/appBar.tsx @@ -49,9 +49,9 @@ export const AppBarShape = forwardRef( [otherProps?.textColor] ); - const backgroundColor = useMemo( - () => otherProps?.backgroundColor ?? '#A9A9A9', - [otherProps?.textColor] + const fill = useMemo( + () => otherProps?.backgroundColor ?? 'lightgrey', + [otherProps?.backgroundColor] ); const stroke = useMemo( @@ -64,6 +64,10 @@ export const AppBarShape = forwardRef( [otherProps?.strokeStyle] ); + const padding = 10; + const textStartX = iconPadding + iconWidth + padding; + const textWidth = restrictedWidth - textStartX - padding; + return ( ( y={0} width={width} height={height} - fill={backgroundColor} + fill={fill} stroke={stroke} dash={strokeStyle} strokeWidth={BASIC_SHAPE.DEFAULT_STROKE_WIDTH} @@ -92,7 +96,6 @@ export const AppBarShape = forwardRef( y={height / 2 - 10} width={iconWidth} height={iconSize} - fill={backgroundColor} /> ( {/* AppBar title*/} ); From a8bbd4a388c86d88bd0270932f2d1f373b6c417c Mon Sep 17 00:00:00 2001 From: "LAPTOP-G2U17NSB\\duy_9" Date: Wed, 28 Aug 2024 14:42:21 +0200 Subject: [PATCH 4/6] First steps on progressbar's progress. Still need to fix: Correct calculation and rendering of progress --- .../front-components/progressbar-shape.tsx | 18 +++++++--- src/core/model/index.ts | 1 + src/pods/canvas/canvas.model.ts | 4 +++ src/pods/properties/components/index.ts | 1 + .../properties/components/progress/index.ts | 1 + .../progress/progress.component.tsx | 36 +++++++++++++++++++ .../components/progress/progress.module.css | 32 +++++++++++++++++ src/pods/properties/properties.pod.tsx | 10 ++++++ 8 files changed, 99 insertions(+), 4 deletions(-) create mode 100644 src/pods/properties/components/progress/index.ts create mode 100644 src/pods/properties/components/progress/progress.component.tsx create mode 100644 src/pods/properties/components/progress/progress.module.css diff --git a/src/common/components/front-components/progressbar-shape.tsx b/src/common/components/front-components/progressbar-shape.tsx index 9d1dd76f..6e8fd7aa 100644 --- a/src/common/components/front-components/progressbar-shape.tsx +++ b/src/common/components/front-components/progressbar-shape.tsx @@ -1,5 +1,5 @@ import { ShapeSizeRestrictions } from '@/core/model'; -import { forwardRef } from 'react'; +import { forwardRef, useMemo } from 'react'; import { ShapeProps } from './shape.model'; import { fitSizeToShapeSizeRestrictions } from '@/common/utils/shapes/shape-restrictions'; import { Group, Rect } from 'react-konva'; @@ -17,7 +17,7 @@ export const getProgressBarShapeSizeRestrictions = (): ShapeSizeRestrictions => progressBarShapeRestrictions; export const ProgressBarShape = forwardRef( - ({ x, y, width, height, id, onSelected, ...shapeProps }, ref) => { + ({ x, y, width, height, id, onSelected, otherProps, ...shapeProps }, ref) => { const { width: restrictedWidth, height: restrictedHeight } = fitSizeToShapeSizeRestrictions( progressBarShapeRestrictions, @@ -25,6 +25,16 @@ export const ProgressBarShape = forwardRef( height ); + const progress = useMemo(() => { + const prog = otherProps?.progress ?? 50; + return typeof prog === 'string' ? parseFloat(prog) : prog; + }, [otherProps?.progress]); + + const progressWidth = useMemo( + () => (progress / 100) * restrictedWidth, + [progress, restrictedWidth] + ); + return ( ( ); diff --git a/src/core/model/index.ts b/src/core/model/index.ts index b8fb2592..83834289 100644 --- a/src/core/model/index.ts +++ b/src/core/model/index.ts @@ -144,6 +144,7 @@ export interface OtherProps { icon?: IconInfo; iconSize?: IconSize; imageSrc?: string; + progress?: string; } export const BASE_ICONS_URL = '/icons/'; diff --git a/src/pods/canvas/canvas.model.ts b/src/pods/canvas/canvas.model.ts index a7534f2d..7414442d 100644 --- a/src/pods/canvas/canvas.model.ts +++ b/src/pods/canvas/canvas.model.ts @@ -436,6 +436,10 @@ export const generateDefaultOtherProps = ( }, iconSize: 'M', }; + case 'progressbar': + return { + progress: '50', + }; default: return undefined; } diff --git a/src/pods/properties/components/index.ts b/src/pods/properties/components/index.ts index 05569ea4..f6b8734f 100644 --- a/src/pods/properties/components/index.ts +++ b/src/pods/properties/components/index.ts @@ -2,3 +2,4 @@ export * from './zindex'; export * from './select-size'; export * from './color-picker'; export * from './icon-selector'; +export * from './progress'; diff --git a/src/pods/properties/components/progress/index.ts b/src/pods/properties/components/progress/index.ts new file mode 100644 index 00000000..ffde39a5 --- /dev/null +++ b/src/pods/properties/components/progress/index.ts @@ -0,0 +1 @@ +export * from './progress.component'; diff --git a/src/pods/properties/components/progress/progress.component.tsx b/src/pods/properties/components/progress/progress.component.tsx new file mode 100644 index 00000000..8d65f345 --- /dev/null +++ b/src/pods/properties/components/progress/progress.component.tsx @@ -0,0 +1,36 @@ +import classes from './progress.module.css'; + +interface Props { + label: string; + progress: string; + onChange: (progress: string) => void; +} + +export const Progress: React.FC = props => { + const { label, progress, onChange } = props; + + return ( +
+

{label}

+ +
+ ); +}; diff --git a/src/pods/properties/components/progress/progress.module.css b/src/pods/properties/components/progress/progress.module.css new file mode 100644 index 00000000..8e51ebc3 --- /dev/null +++ b/src/pods/properties/components/progress/progress.module.css @@ -0,0 +1,32 @@ +.container { + display: flex; + gap: 0.5em; + align-items: center; + padding: var(--space-xs) var(--space-md); + border-bottom: 1px solid var(--primary-300); +} + +.container :first-child { + flex: 1; +} + +.button { + border: none; + color: var(--text-color); + background-color: inherit; + width: var(--space-lg); + height: var(--space-lg); + border-radius: var(--border-radius-s); + font-size: var(--fs-xs); + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: var(--space-s); + transition: all 0.3s ease-in-out; + cursor: pointer; +} + +.button:hover { + background-color: var(--primary-100); +} diff --git a/src/pods/properties/properties.pod.tsx b/src/pods/properties/properties.pod.tsx index 20bc97a9..c1fd24f7 100644 --- a/src/pods/properties/properties.pod.tsx +++ b/src/pods/properties/properties.pod.tsx @@ -5,6 +5,7 @@ import { ColorPicker } from './components/color-picker/color-picker.component'; import { Checked } from './components/checked/checked.component'; import { SelectSize, SelectIcon } from './components'; import { StrokeStyle } from './components/stroke-style/stroke.style.component'; +import { Progress } from './components/progress/progress.component'; export const PropertiesPod = () => { const { selectionInfo } = useCanvasContext(); @@ -80,6 +81,15 @@ export const PropertiesPod = () => { onChange={checked => updateOtherPropsOnSelected('checked', checked)} /> )} + {selectedShapeData?.otherProps?.progress && ( + + updateOtherPropsOnSelected('progress', progress) + } + /> + )} ); }; From b01d4104a0c2ed6d3b97272f6d3d5bb6143843b9 Mon Sep 17 00:00:00 2001 From: "LAPTOP-G2U17NSB\\duy_9" Date: Wed, 28 Aug 2024 14:49:06 +0200 Subject: [PATCH 5/6] Adding one more rect to AppBar --- .../front-rich-components/appBar.tsx | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/common/components/front-rich-components/appBar.tsx b/src/common/components/front-rich-components/appBar.tsx index f20187cb..2f06bd85 100644 --- a/src/common/components/front-rich-components/appBar.tsx +++ b/src/common/components/front-rich-components/appBar.tsx @@ -68,6 +68,10 @@ export const AppBarShape = forwardRef( const textStartX = iconPadding + iconWidth + padding; const textWidth = restrictedWidth - textStartX - padding; + const barHeight = 3; // Height bar + const barSpacing = 2; // Space between bars + const totalIconHeight = 3 * barHeight + 2 * barSpacing; // Total height including spacing + return ( ( {...shapeProps} onClick={() => onSelected(id, 'appBar')} > - {/* AppBar background*/} + {/* AppBar background */} ( strokeWidth={BASIC_SHAPE.DEFAULT_STROKE_WIDTH} /> - {/* Menu Icon*/} + {/* Menu Icon */} - {/* AppBar title*/} + {/* AppBar title */} Date: Wed, 28 Aug 2024 14:52:21 +0200 Subject: [PATCH 6/6] Deleting unread const --- src/common/components/front-rich-components/appBar.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/common/components/front-rich-components/appBar.tsx b/src/common/components/front-rich-components/appBar.tsx index 2f06bd85..6b82cc8e 100644 --- a/src/common/components/front-rich-components/appBar.tsx +++ b/src/common/components/front-rich-components/appBar.tsx @@ -40,7 +40,6 @@ export const AppBarShape = forwardRef( height ); - const iconSize = 4; const iconWidth = 30; const iconPadding = 10;