Skip to content

Commit 17e2634

Browse files
authored
Merge pull request #778 from Lemoncode/feature/#713-add-adorner-to-mobile-device
Feature/#713 add adorner to mobile device
2 parents 5e02eca + 77e9490 commit 17e2634

File tree

2 files changed

+128
-3
lines changed

2 files changed

+128
-3
lines changed

public/containers/mobile.svg

Lines changed: 21 additions & 0 deletions
Loading

src/common/components/mock-components/front-containers/mobilephone-shape.tsx

Lines changed: 107 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1-
import { forwardRef } from 'react';
2-
import { Group, Rect, Circle } from 'react-konva';
1+
import { forwardRef, useEffect, useState } from 'react';
2+
import { Group, Rect, Circle, Image, Text } from 'react-konva';
33
import { ShapeSizeRestrictions, ShapeType } from '@/core/model';
44
import { ShapeProps } from '../shape.model';
55
import { fitSizeToShapeSizeRestrictions } from '@/common/utils/shapes/shape-restrictions';
66
import { useGroupShapeProps } from '../mock-components.utils';
7+
import { loadSvgWithFill } from '@/common/utils/svg.utils';
8+
import { BASIC_SHAPE } from '../front-components/shape.const';
79

810
const mobilePhoneShapeSizeRestrictions: ShapeSizeRestrictions = {
9-
minWidth: 150,
11+
minWidth: 200,
1012
minHeight: 150,
1113
maxWidth: 1000,
1214
maxHeight: 1000,
@@ -37,13 +39,68 @@ export const MobilePhoneShape = forwardRef<any, ShapeProps>((props, ref) => {
3739
const speakerRadius = 2;
3840
const buttonRadius = 9;
3941

42+
const [wifiIcon, setWifiIcon] = useState<HTMLImageElement | null>(null);
43+
const [batteryIcon, setBatteryIcon] = useState<HTMLImageElement | null>(null);
44+
const [signalIcon, setSignalIcon] = useState<HTMLImageElement | null>(null);
45+
const [currentTime, setCurrentTime] = useState('');
46+
47+
const adornerIconSize = 20;
48+
const adornerPadding = 5;
49+
const adornerTotalWidth = adornerIconSize * 3 + 17 * 2 + 30;
50+
51+
// Calculate inner screen coordinates (excluding frame margins)
52+
const screenX = margin + screenMargin; // Left edge of inner screen
53+
const screenY = screenMargin * 3; // Top edge of inner screen
54+
const screenWidth = restrictedWidth - 2 * margin - 2 * screenMargin; // Available width inside screen
55+
56+
// Position adorner in top-right corner of inner screen
57+
const adornerStartX = screenX + screenWidth - adornerTotalWidth; // Right-aligned positioning
58+
const adornerY = screenY + adornerPadding; // Top-aligned with padding
59+
60+
// Individual icon positions within the adorner
61+
const wifiX = adornerStartX;
62+
const signalX = adornerStartX + 17;
63+
const batteryX = adornerStartX + 20 * 2;
64+
65+
const timeX = adornerStartX + 23 * 3;
66+
const timeY = adornerY + 4;
67+
const timeWidth = 40;
68+
4069
const commonGroupProps = useGroupShapeProps(
4170
props,
4271
restrictedSize,
4372
shapeType,
4473
ref
4574
);
4675

76+
useEffect(() => {
77+
loadSvgWithFill('/icons/wifi.svg', 'black').then(img => setWifiIcon(img));
78+
loadSvgWithFill('/icons/cellsignal.svg', 'black').then(img =>
79+
setSignalIcon(img)
80+
);
81+
loadSvgWithFill('/icons/batteryfull.svg', 'black').then(img =>
82+
setBatteryIcon(img)
83+
);
84+
}, []);
85+
86+
useEffect(() => {
87+
const updateTime = () => {
88+
const now = new Date();
89+
setCurrentTime(
90+
now.toLocaleTimeString('es-ES', {
91+
hour: '2-digit',
92+
minute: '2-digit',
93+
hour12: false,
94+
})
95+
);
96+
};
97+
98+
updateTime();
99+
const timer = setInterval(updateTime, 1000);
100+
101+
return () => clearInterval(timer);
102+
}, []);
103+
47104
return (
48105
<Group {...commonGroupProps} {...shapeProps}>
49106
{/* Mobile Frame */}
@@ -82,6 +139,53 @@ export const MobilePhoneShape = forwardRef<any, ShapeProps>((props, ref) => {
82139
fill="white"
83140
/>
84141

142+
{/* Adorner */}
143+
144+
{/* Wifi */}
145+
{wifiIcon && (
146+
<Image
147+
image={wifiIcon}
148+
x={wifiX}
149+
y={adornerY - 2}
150+
width={adornerIconSize}
151+
height={adornerIconSize}
152+
/>
153+
)}
154+
155+
{/* Cell signal */}
156+
{signalIcon && (
157+
<Image
158+
image={signalIcon}
159+
x={signalX}
160+
y={adornerY}
161+
width={adornerIconSize}
162+
height={adornerIconSize}
163+
/>
164+
)}
165+
166+
{/* Battery */}
167+
{batteryIcon && (
168+
<Image
169+
image={batteryIcon}
170+
x={batteryX}
171+
y={adornerY}
172+
width={adornerIconSize}
173+
height={adornerIconSize}
174+
/>
175+
)}
176+
177+
{/* Current time */}
178+
<Text
179+
x={timeX}
180+
y={timeY}
181+
width={timeWidth}
182+
height={adornerIconSize}
183+
text={currentTime}
184+
fontFamily={BASIC_SHAPE.DEFAULT_FONT_FAMILY}
185+
fontSize={14}
186+
wrap="none"
187+
/>
188+
85189
{/* Init button */}
86190
<Circle
87191
x={restrictedWidth / 2}

0 commit comments

Comments
 (0)