diff --git a/public/assets/iria-carballo.jpeg b/public/assets/iria-carballo.jpeg new file mode 100644 index 00000000..a0e0bb4d Binary files /dev/null and b/public/assets/iria-carballo.jpeg differ diff --git a/public/rich-components/loading-indicator.svg b/public/rich-components/loading-indicator.svg new file mode 100644 index 00000000..3a245919 --- /dev/null +++ b/public/rich-components/loading-indicator.svg @@ -0,0 +1,10 @@ + + + + + + + + Loading... + + diff --git a/src/common/components/mock-components/front-rich-components/index.ts b/src/common/components/mock-components/front-rich-components/index.ts index e1ca7951..d3097d8d 100644 --- a/src/common/components/mock-components/front-rich-components/index.ts +++ b/src/common/components/mock-components/front-rich-components/index.ts @@ -14,5 +14,6 @@ export * from './appBar'; export * from './buttonBar/buttonBar'; export * from './tabsbar'; export * from './audio-player'; +export * from './loading-indicator'; export * from './videoconference'; export * from './togglelightdark-shape'; diff --git a/src/common/components/mock-components/front-rich-components/loading-indicator.tsx b/src/common/components/mock-components/front-rich-components/loading-indicator.tsx new file mode 100644 index 00000000..5319ac8a --- /dev/null +++ b/src/common/components/mock-components/front-rich-components/loading-indicator.tsx @@ -0,0 +1,91 @@ +import { useRef, forwardRef } from 'react'; +import { Group, Rect, Text, Circle } from 'react-konva'; +import Konva from 'konva'; +import { ShapeProps } from '../shape.model'; +import { ShapeSizeRestrictions, ShapeType } from '@/core/model'; +import { BASIC_SHAPE } from '../front-components/shape.const'; +import { useShapeProps } from '../../shapes/use-shape-props.hook'; +import { useGroupShapeProps } from '../mock-components.utils'; + +const LoadIndicatorSizeRestrictions: ShapeSizeRestrictions = { + minWidth: 200, + minHeight: 100, + maxWidth: -1, + maxHeight: -1, + defaultWidth: 200, + defaultHeight: 100, +}; + +const shapeType: ShapeType = 'loading-indicator'; + +export const getLoadIndicatorSizeRestrictions = (): ShapeSizeRestrictions => + LoadIndicatorSizeRestrictions; + +export const LoadIndicator = forwardRef((props, ref) => { + const { x, y, width, height, otherProps, ...shapeProps } = props; + + const restrictedSize = { + width: width || LoadIndicatorSizeRestrictions.defaultWidth, + height: height || LoadIndicatorSizeRestrictions.defaultHeight, + }; + + const { width: restrictedWidth, height: restrictedHeight } = restrictedSize; + + const colors = ['#666', '#888', '#aaa', '#ccc']; + const circlesRef = useRef>([]); + + const { textColor } = useShapeProps(otherProps, BASIC_SHAPE); + + const commonGroupProps = useGroupShapeProps( + props, + restrictedSize, + shapeType, + ref + ); + + const circleRadius = Math.min(restrictedWidth / 10, 15); + const circleSpacing = restrictedWidth / (colors.length + 1); + + return ( + + {/* Load Indicator Background */} + + + {/* Animated Circles */} + {colors.map((color, index) => ( + (circlesRef.current[index] = el)} + x={circleSpacing * (index + 1)} + y={restrictedHeight / 2} + radius={circleRadius} + fill={color} + stroke="#000" + strokeWidth={2} + /> + ))} + + {/* Loading Text */} + + + ); +}); + +export default LoadIndicator; diff --git a/src/core/model/index.ts b/src/core/model/index.ts index 7a51b45d..af039047 100644 --- a/src/core/model/index.ts +++ b/src/core/model/index.ts @@ -71,6 +71,8 @@ export type ShapeType = | 'slider' | 'link' | 'cilinder' + | 'richtext' + | 'loading-indicator' | 'videoconference' | 'richtext'; @@ -134,6 +136,7 @@ export const ShapeDisplayName: Record = { slider: 'Slider', richtext: 'Rich Text', cilinder: 'Cilinder', + 'loading-indicator': 'Loading', videoconference: 'Videoconference', }; diff --git a/src/pods/about/members.ts b/src/pods/about/members.ts index 8b86fd66..12f03175 100644 --- a/src/pods/about/members.ts +++ b/src/pods/about/members.ts @@ -136,9 +136,15 @@ export const memberList: Member[] = [ urlLinkedin: 'https://www.linkedin.com/in/sergioelmoreno/', image: './assets/sergio-del-campo.jpg', }, - { id: '18', + name: 'Iria', + surname: 'Carballo', + urlLinkedin: 'https://www.linkedin.com/in/iria-carballo/', + image: './assets/iria-carballo.jpeg', + }, + { + id: '19', name: 'Gabriel', surname: 'Ionut', urlLinkedin: 'https://www.linkedin.com/in/gabriel-ionut-birsan-b14816307/', @@ -146,7 +152,7 @@ export const memberList: Member[] = [ }, { - id: '19', + id: '20', name: 'Antonio', surname: 'Contreras', urlLinkedin: @@ -155,7 +161,7 @@ export const memberList: Member[] = [ }, { - id: '20', + id: '21', name: 'Braulio', surname: 'Diez', urlLinkedin: 'https://www.linkedin.com/in/brauliodiez/', diff --git a/src/pods/canvas/model/inline-editable.model.ts b/src/pods/canvas/model/inline-editable.model.ts index a4f0cef0..7843b8b8 100644 --- a/src/pods/canvas/model/inline-editable.model.ts +++ b/src/pods/canvas/model/inline-editable.model.ts @@ -36,6 +36,7 @@ const inlineEditableShapes = new Set([ 'datepickerinput', 'browser', 'modalDialog', + 'loading-indicator', ]); // Check if a shape type allows inline editing @@ -76,6 +77,7 @@ const shapeTypesWithDefaultText = new Set([ 'datepickerinput', 'browser', 'modalDialog', + 'loading-indicator', ]); // Map of ShapeTypes to their default text values @@ -113,6 +115,7 @@ const defaultTextValueMap: Partial> = { datepickerinput: new Date().toLocaleDateString(), browser: 'https://example.com', modalDialog: 'Title here...', + 'loading-indicator': 'Loading...', }; export const generateDefaultTextValue = ( diff --git a/src/pods/canvas/model/shape-size.mapper.ts b/src/pods/canvas/model/shape-size.mapper.ts index e362f27f..f6a5c993 100644 --- a/src/pods/canvas/model/shape-size.mapper.ts +++ b/src/pods/canvas/model/shape-size.mapper.ts @@ -52,6 +52,7 @@ import { getCalendarShapeSizeRestrictions, getHorizontalMenuShapeSizeRestrictions, getLineChartShapeSizeRestrictions, + getLoadIndicatorSizeRestrictions, getMapChartShapeSizeRestrictions, getModalShapeSizeRestrictions, getPieChartShapeSizeRestrictions, @@ -145,6 +146,7 @@ const shapeSizeMap: Record ShapeSizeRestrictions> = { slider: getSliderShapeSizeRestrictions, audioPlayer: getAudioPlayerShapeSizeRestrictions, cilinder: getCilinderShapeSizeRestrictions, + 'loading-indicator': getLoadIndicatorSizeRestrictions, videoconference: getVideoconferenceShapeSizeRestrictions, }; diff --git a/src/pods/canvas/model/transformer.model.ts b/src/pods/canvas/model/transformer.model.ts index 59185373..092380f1 100644 --- a/src/pods/canvas/model/transformer.model.ts +++ b/src/pods/canvas/model/transformer.model.ts @@ -64,6 +64,7 @@ export const generateTypeOfTransformer = (shapeType: ShapeType): string[] => { case 'link': case 'horizontalScrollBar': case 'appBar': + case 'loading-indicator': case 'buttonBar': case 'slider': return ['middle-left', 'middle-right']; diff --git a/src/pods/canvas/shape-renderer/index.tsx b/src/pods/canvas/shape-renderer/index.tsx index d72062fe..25ee3cb6 100644 --- a/src/pods/canvas/shape-renderer/index.tsx +++ b/src/pods/canvas/shape-renderer/index.tsx @@ -70,6 +70,7 @@ import { renderSmalltext } from './simple-text-components/smalltext.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'; +import { renderLoadingIndicator } from './simple-rich-components/loading-indicator.renderer'; export const renderShapeComponent = ( shape: ShapeModel, @@ -192,6 +193,8 @@ export const renderShapeComponent = ( return renderSlider(shape, shapeRenderedProps); case 'cilinder': return renderCilinder(shape, shapeRenderedProps); + case 'loading-indicator': + return renderLoadingIndicator(shape, shapeRenderedProps); case 'videoconference': return renderVideoconference(shape, shapeRenderedProps); default: 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 f0dad515..9690dbd1 100644 --- a/src/pods/canvas/shape-renderer/simple-rich-components/index.ts +++ b/src/pods/canvas/shape-renderer/simple-rich-components/index.ts @@ -15,4 +15,5 @@ export * from './appBar.renderer'; export * from './button-bar.renderer'; export * from './tabsbar.renderer'; export * from './audio-player.renderer'; +export * from './loading-indicator.renderer'; export * from './videoconference.renderer'; diff --git a/src/pods/canvas/shape-renderer/simple-rich-components/loading-indicator.renderer.tsx b/src/pods/canvas/shape-renderer/simple-rich-components/loading-indicator.renderer.tsx new file mode 100644 index 00000000..39610f09 --- /dev/null +++ b/src/pods/canvas/shape-renderer/simple-rich-components/loading-indicator.renderer.tsx @@ -0,0 +1,33 @@ +import { LoadIndicator } from '@/common/components/mock-components/front-rich-components/loading-indicator'; +import { ShapeRendererProps } from '../model'; +import { ShapeModel } from '@/core/model'; + +export const renderLoadingIndicator = ( + shape: ShapeModel, + shapeRenderedProps: ShapeRendererProps +) => { + const { handleSelected, shapeRefs, handleDragEnd, handleTransform } = + shapeRenderedProps; + + return ( + + ); +}; diff --git a/src/pods/galleries/rich-components-gallery/rich-components-gallery-data/index.ts b/src/pods/galleries/rich-components-gallery/rich-components-gallery-data/index.ts index cd6d16c4..37e2042e 100644 --- a/src/pods/galleries/rich-components-gallery/rich-components-gallery-data/index.ts +++ b/src/pods/galleries/rich-components-gallery/rich-components-gallery-data/index.ts @@ -13,6 +13,10 @@ export const mockRichComponentsCollection: ItemInfo[] = [ type: 'horizontal-menu', }, { thumbnailSrc: '/rich-components/line-chart.svg', type: 'linechart' }, + { + thumbnailSrc: '/rich-components/loading-indicator.svg', + type: 'loading-indicator', + }, { thumbnailSrc: '/rich-components/map.svg', type: 'map' }, { thumbnailSrc: '/rich-components/modal.svg', type: 'modal' }, { thumbnailSrc: '/rich-components/pie.svg', type: 'pie' },