@developer_tribe/react-builder 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/DeviceMockFrame.d.ts +2 -1
- package/dist/RenderPage.d.ts +4 -3
- package/dist/attributes-editor/Field.d.ts +16 -0
- package/dist/attributes-editor/FieldInfoTooltip.d.ts +7 -0
- package/dist/attributes-editor/LayoutPreviewPicker.d.ts +12 -0
- package/dist/attributes-editor/SpecialCategorySection.d.ts +19 -0
- package/dist/attributes-editor/types.d.ts +14 -0
- package/dist/background.jpg +0 -0
- package/dist/build-components/Button/Button.d.ts +1 -1
- package/dist/build-components/Button/ButtonProps.generated.d.ts +26 -1
- package/dist/build-components/Carousel/CarouselProps.generated.d.ts +27 -1
- package/dist/build-components/CarouselButtons/CarouselButtonsProps.generated.d.ts +25 -0
- package/dist/build-components/CarouselDots/CarouselDotsProps.generated.d.ts +25 -0
- package/dist/build-components/CarouselItem/CarouselItemProps.generated.d.ts +27 -1
- package/dist/build-components/CarouselProvider/CarouselProviderProps.generated.d.ts +27 -1
- package/dist/build-components/Image/ImageProps.generated.d.ts +25 -3
- package/dist/build-components/Onboard/OnboardProps.generated.d.ts +27 -1
- package/dist/build-components/OnboardButton/OnboardButtonProps.generated.d.ts +25 -0
- package/dist/build-components/OnboardButtons/OnboardButtonsProps.generated.d.ts +25 -0
- package/dist/build-components/OnboardDot/OnboardDot.d.ts +1 -1
- package/dist/build-components/OnboardDot/OnboardDotProps.generated.d.ts +22 -0
- package/dist/build-components/OnboardFooter/OnboardFooterProps.generated.d.ts +4 -5
- package/dist/build-components/OnboardImage/OnboardImageProps.generated.d.ts +25 -3
- package/dist/build-components/OnboardItem/OnboardItemProps.generated.d.ts +24 -3
- package/dist/build-components/OnboardProvider/OnboardProviderProps.generated.d.ts +25 -4
- package/dist/build-components/OnboardSubtitle/OnboardSubtitleProps.generated.d.ts +4 -5
- package/dist/build-components/OnboardTitle/OnboardTitleProps.generated.d.ts +4 -5
- package/dist/build-components/Text/TextProps.generated.d.ts +4 -5
- package/dist/build-components/View/ViewProps.generated.d.ts +3 -4
- package/dist/build-components/patterns.generated.d.ts +4855 -132
- package/dist/components/Breadcrumb.d.ts +3 -1
- package/dist/components/Checkbox.d.ts +17 -0
- package/dist/components/DeviceButton.d.ts +8 -0
- package/dist/components/DeviceNavigationBar.d.ts +10 -0
- package/dist/components/DeviceStatusBar.d.ts +9 -0
- package/dist/components/EditorHeader.d.ts +3 -8
- package/dist/index.cjs.js +5 -5
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +5 -5
- package/dist/index.esm.js.map +1 -1
- package/dist/mockOS/components/MockLaunchScreenComponent.d.ts +6 -0
- package/dist/mockOS/components/MockOSRouter.d.ts +8 -0
- package/dist/mockOS/components/PermissionModal.d.ts +9 -0
- package/dist/mockOS/context/MockOSContext.d.ts +36 -0
- package/dist/mockOS/hooks/useMockNavigation.d.ts +3 -0
- package/dist/mockOS/hooks/useMockPermission.d.ts +3 -0
- package/dist/mockOS/index.d.ts +9 -0
- package/dist/mockOS/managers/mockPermissionManager.d.ts +10 -0
- package/dist/mockOS/managers/navigationManager.d.ts +17 -0
- package/dist/modals/AddComponentModal.d.ts +8 -0
- package/dist/modals/ColorModal.d.ts +9 -0
- package/dist/modals/DeviceSelectorModal.d.ts +9 -0
- package/dist/modals/LocalicationModal.d.ts +8 -0
- package/dist/modals/Modal.d.ts +12 -0
- package/dist/modals/index.d.ts +5 -0
- package/dist/pages/ProjectPage.d.ts +1 -1
- package/dist/store.d.ts +0 -2
- package/dist/styles.css +1 -1
- package/dist/utils/patterns.d.ts +24 -0
- package/package.json +2 -1
- package/scripts/prebuild/utils/createGeneratedProps.js +11 -3
- package/scripts/prebuild/utils/validateAllComponentsOrThrow.js +45 -6
- package/scripts/prebuild/utils/validatePatternJson.js +13 -5
- package/src/AttributesEditor.tsx +433 -312
- package/src/DeviceMockFrame.tsx +21 -37
- package/src/RenderPage.tsx +5 -4
- package/src/assets/images/android.svg +42 -42
- package/src/assets/images/apple.svg +15 -15
- package/src/attributes-editor/Field.tsx +662 -0
- package/src/attributes-editor/FieldInfoTooltip.tsx +49 -0
- package/src/attributes-editor/LayoutPreviewPicker.tsx +199 -0
- package/src/attributes-editor/SpecialCategorySection.tsx +284 -0
- package/src/attributes-editor/types.ts +30 -0
- package/src/build-components/Button/Button.tsx +10 -2
- package/src/build-components/Button/ButtonProps.generated.ts +37 -1
- package/src/build-components/Button/pattern.json +31 -2
- package/src/build-components/Carousel/Carousel.tsx +15 -2
- package/src/build-components/Carousel/CarouselProps.generated.ts +39 -1
- package/src/build-components/Carousel/pattern.json +10 -0
- package/src/build-components/CarouselButtons/CarouselButtons.tsx +6 -2
- package/src/build-components/CarouselButtons/CarouselButtonsProps.generated.ts +36 -0
- package/src/build-components/CarouselButtons/pattern.json +22 -0
- package/src/build-components/CarouselDots/CarouselDots.tsx +40 -8
- package/src/build-components/CarouselDots/CarouselDotsProps.generated.ts +36 -0
- package/src/build-components/CarouselDots/pattern.json +15 -0
- package/src/build-components/CarouselItem/CarouselItem.tsx +5 -2
- package/src/build-components/CarouselItem/CarouselItemProps.generated.ts +39 -1
- package/src/build-components/CarouselItem/pattern.json +7 -0
- package/src/build-components/CarouselProvider/CarouselProvider.tsx +10 -2
- package/src/build-components/CarouselProvider/CarouselProviderProps.generated.ts +39 -1
- package/src/build-components/CarouselProvider/pattern.json +7 -0
- package/src/build-components/Image/Image.tsx +8 -2
- package/src/build-components/Image/ImageProps.generated.ts +36 -3
- package/src/build-components/Image/pattern.json +46 -3
- package/src/build-components/Onboard/Onboard.tsx +6 -1
- package/src/build-components/Onboard/OnboardProps.generated.ts +39 -1
- package/src/build-components/Onboard/pattern.json +11 -0
- package/src/build-components/OnboardButton/OnboardButton.tsx +46 -5
- package/src/build-components/OnboardButton/OnboardButtonProps.generated.ts +36 -0
- package/src/build-components/OnboardButton/pattern.json +71 -5
- package/src/build-components/OnboardButtons/OnboardButtons.tsx +20 -10
- package/src/build-components/OnboardButtons/OnboardButtonsProps.generated.ts +36 -0
- package/src/build-components/OnboardButtons/pattern.json +70 -4
- package/src/build-components/OnboardDot/OnboardDot.tsx +104 -4
- package/src/build-components/OnboardDot/OnboardDotProps.generated.ts +22 -0
- package/src/build-components/OnboardDot/pattern.json +54 -1
- package/src/build-components/OnboardFooter/OnboardFooter.tsx +9 -3
- package/src/build-components/OnboardFooter/OnboardFooterProps.generated.ts +4 -5
- package/src/build-components/OnboardFooter/pattern.json +58 -2
- package/src/build-components/OnboardImage/OnboardImage.tsx +27 -5
- package/src/build-components/OnboardImage/OnboardImageProps.generated.ts +36 -3
- package/src/build-components/OnboardImage/pattern.json +21 -0
- package/src/build-components/OnboardItem/OnboardItem.tsx +6 -1
- package/src/build-components/OnboardItem/OnboardItemProps.generated.ts +35 -3
- package/src/build-components/OnboardItem/pattern.json +38 -2
- package/src/build-components/OnboardProvider/OnboardProvider.tsx +20 -8
- package/src/build-components/OnboardProvider/OnboardProviderProps.generated.ts +37 -4
- package/src/build-components/OnboardProvider/pattern.json +51 -4
- package/src/build-components/OnboardSubtitle/OnboardSubtitleProps.generated.ts +4 -5
- package/src/build-components/OnboardSubtitle/pattern.json +6 -0
- package/src/build-components/OnboardTitle/OnboardTitleProps.generated.ts +4 -5
- package/src/build-components/OnboardTitle/pattern.json +6 -0
- package/src/build-components/Text/Text.tsx +7 -3
- package/src/build-components/Text/TextProps.generated.ts +4 -5
- package/src/build-components/Text/pattern.json +38 -2
- package/src/build-components/View/View.tsx +9 -6
- package/src/build-components/View/ViewProps.generated.ts +3 -4
- package/src/build-components/View/pattern.json +227 -19
- package/src/build-components/patterns.generated.ts +4905 -139
- package/src/components/AttributesEditorPanel.tsx +7 -61
- package/src/components/Breadcrumb.tsx +37 -5
- package/src/components/Builder.tsx +180 -77
- package/src/components/Checkbox.tsx +81 -0
- package/src/components/DeviceButton.tsx +39 -0
- package/src/components/DeviceNavigationBar.tsx +201 -0
- package/src/components/DeviceStatusBar.tsx +85 -0
- package/src/components/EditorHeader.tsx +26 -74
- package/src/mockOS/components/MockLaunchScreenComponent.tsx +43 -0
- package/src/mockOS/components/MockOSRouter.tsx +115 -0
- package/src/mockOS/components/PermissionModal.tsx +270 -0
- package/src/mockOS/context/MockOSContext.tsx +179 -0
- package/src/mockOS/hooks/useMockNavigation.ts +11 -0
- package/src/mockOS/hooks/useMockPermission.ts +11 -0
- package/src/mockOS/index.ts +26 -0
- package/src/mockOS/managers/mockPermissionManager.ts +54 -0
- package/src/mockOS/managers/navigationManager.ts +91 -0
- package/src/modals/AddComponentModal.tsx +313 -0
- package/src/modals/ColorModal.tsx +268 -0
- package/src/modals/DeviceSelectorModal.tsx +57 -0
- package/src/modals/LocalicationModal.tsx +54 -0
- package/src/modals/Modal.tsx +57 -0
- package/src/modals/index.ts +5 -0
- package/src/pages/ProjectPage.tsx +19 -21
- package/src/pages/tabs/DebugTab.tsx +50 -9
- package/src/pages/tabs/PreviewTab.tsx +52 -40
- package/src/size-matters/index.ts +21 -5
- package/src/store.ts +0 -4
- package/src/styles/{global.scss → base/_global.scss} +92 -39
- package/src/styles/components/_attributes-editor.scss +261 -0
- package/src/styles/{editor.scss → components/_editor-shell.scss} +72 -57
- package/src/styles/components/_mockos-router.scss +140 -0
- package/src/styles/components/_ui-components.scss +183 -0
- package/src/styles/foundation/_colors.scss +8 -0
- package/src/styles/{_mixins.scss → foundation/_mixins.scss} +5 -4
- package/src/styles/{_reset.scss → foundation/_reset.scss} +5 -2
- package/src/styles/foundation/_sizes.scss +37 -0
- package/src/styles/foundation/_typography.scss +4 -0
- package/src/styles/foundation/_variables.scss +3 -0
- package/src/styles/index.scss +22 -136
- package/src/styles/layout/_builder.scss +68 -0
- package/src/styles/layout/_pages.scss +3 -0
- package/src/styles/modals/_add-component.scss +122 -0
- package/src/styles/modals/_color-modal.scss +130 -0
- package/src/styles/modals/_device-selector.scss +18 -0
- package/src/styles/modals/_localication-modal.scss +68 -0
- package/src/styles/modals/_modal-shell.scss +46 -0
- package/src/styles/utilities/_carousel.scss +125 -0
- package/src/types/images.d.ts +8 -0
- package/src/utils/extractTextStyle.ts +4 -2
- package/src/utils/extractViewStyle.ts +51 -7
- package/src/utils/patterns.ts +33 -0
- package/dist/build-components/OnboardDot/OnboardExpandingDotProps.generated.d.ts +0 -10
- package/src/build-components/OnboardDot/OnboardExpandingDotProps.generated.ts +0 -20
- package/src/styles/_variables.scss +0 -27
- package/src/styles/builder.scss +0 -60
- package/src/styles/components.scss +0 -88
- package/src/styles/pages.scss +0 -2
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import React, { useEffect } from 'react';
|
|
2
|
+
|
|
3
|
+
type ModalProps = {
|
|
4
|
+
onClose: () => void;
|
|
5
|
+
ariaLabelledBy?: string;
|
|
6
|
+
children: React.ReactNode;
|
|
7
|
+
className?: string;
|
|
8
|
+
contentClassName?: string;
|
|
9
|
+
closeOnOverlayClick?: boolean;
|
|
10
|
+
closeOnEsc?: boolean;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export function Modal({
|
|
14
|
+
onClose,
|
|
15
|
+
ariaLabelledBy,
|
|
16
|
+
children,
|
|
17
|
+
className,
|
|
18
|
+
contentClassName,
|
|
19
|
+
closeOnOverlayClick = true,
|
|
20
|
+
closeOnEsc = true,
|
|
21
|
+
}: ModalProps) {
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
if (!closeOnEsc) return undefined;
|
|
24
|
+
if (typeof window === 'undefined') return undefined;
|
|
25
|
+
|
|
26
|
+
const handleKeyDown = (event: KeyboardEvent) => {
|
|
27
|
+
if (event.key === 'Escape') {
|
|
28
|
+
onClose();
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
window.addEventListener('keydown', handleKeyDown);
|
|
33
|
+
return () => window.removeEventListener('keydown', handleKeyDown);
|
|
34
|
+
}, [closeOnEsc, onClose]);
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<div
|
|
38
|
+
className={`modal${className ? ` ${className}` : ''}`}
|
|
39
|
+
role="dialog"
|
|
40
|
+
aria-modal="true"
|
|
41
|
+
aria-labelledby={ariaLabelledBy}
|
|
42
|
+
>
|
|
43
|
+
<div
|
|
44
|
+
className="modal__overlay"
|
|
45
|
+
onClick={closeOnOverlayClick ? onClose : undefined}
|
|
46
|
+
/>
|
|
47
|
+
<div
|
|
48
|
+
className={`modal__content${contentClassName ? ` ${contentClassName}` : ''}`}
|
|
49
|
+
role="document"
|
|
50
|
+
>
|
|
51
|
+
{children}
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export default Modal;
|
|
@@ -10,8 +10,8 @@ import { useRenderStore } from '../store';
|
|
|
10
10
|
import { logger } from '../utils/logger';
|
|
11
11
|
import { useLogRender } from '../utils/useLogRender';
|
|
12
12
|
import type { LogLevel } from '../types/Project';
|
|
13
|
-
|
|
14
|
-
export type Tab = 'builder' | 'preview'
|
|
13
|
+
import backgroundImage from '../assets/images/background.jpg';
|
|
14
|
+
export type Tab = 'builder' | 'preview';
|
|
15
15
|
|
|
16
16
|
export type ProjectPageProps = {
|
|
17
17
|
project: Project;
|
|
@@ -55,6 +55,11 @@ export function ProjectPage({
|
|
|
55
55
|
data: editorData,
|
|
56
56
|
});
|
|
57
57
|
}}
|
|
58
|
+
onRestoreProject={() => {
|
|
59
|
+
logger.info('ProjectPage', 'restore project', { name: project.name });
|
|
60
|
+
setEditorData(project.data);
|
|
61
|
+
setCurrent(project.data);
|
|
62
|
+
}}
|
|
58
63
|
current={current}
|
|
59
64
|
editorData={editorData}
|
|
60
65
|
setEditorData={setEditorData}
|
|
@@ -76,7 +81,7 @@ export function ProjectPage({
|
|
|
76
81
|
logger.info('ProjectPage', 'tab change', { to: 'builder' });
|
|
77
82
|
}}
|
|
78
83
|
>
|
|
79
|
-
Builder
|
|
84
|
+
<span className="editor-tab__label">Builder</span>
|
|
80
85
|
</button>
|
|
81
86
|
<button
|
|
82
87
|
className={`editor-tab ${tab === 'preview' ? 'editor-tab--active' : ''}`}
|
|
@@ -87,18 +92,7 @@ export function ProjectPage({
|
|
|
87
92
|
logger.info('ProjectPage', 'tab change', { to: 'preview' });
|
|
88
93
|
}}
|
|
89
94
|
>
|
|
90
|
-
Preview Config
|
|
91
|
-
</button>
|
|
92
|
-
<button
|
|
93
|
-
className={`editor-tab ${tab === 'debug' ? 'editor-tab--active' : ''}`}
|
|
94
|
-
role="tab"
|
|
95
|
-
aria-selected={tab === 'debug'}
|
|
96
|
-
onClick={() => {
|
|
97
|
-
setTab('debug');
|
|
98
|
-
logger.info('ProjectPage', 'tab change', { to: 'debug' });
|
|
99
|
-
}}
|
|
100
|
-
>
|
|
101
|
-
Debug
|
|
95
|
+
<span className="editor-tab__label">Preview Config</span>
|
|
102
96
|
</button>
|
|
103
97
|
</div>
|
|
104
98
|
|
|
@@ -112,15 +106,19 @@ export function ProjectPage({
|
|
|
112
106
|
)}
|
|
113
107
|
|
|
114
108
|
{tab === 'preview' && <PreviewTab />}
|
|
115
|
-
|
|
116
|
-
{tab === 'debug' && (
|
|
117
|
-
<DebugTab data={editorData} setData={setEditorData} />
|
|
118
|
-
)}
|
|
119
109
|
</div>
|
|
120
110
|
</div>
|
|
121
111
|
<div className="split-right">
|
|
122
|
-
<div className="split-
|
|
123
|
-
|
|
112
|
+
<div className="split-right__controls">
|
|
113
|
+
<DebugTab data={editorData} setData={setEditorData} />
|
|
114
|
+
</div>
|
|
115
|
+
<div
|
|
116
|
+
className="split-right-background"
|
|
117
|
+
style={{
|
|
118
|
+
backgroundImage: `url(${backgroundImage})`,
|
|
119
|
+
}}
|
|
120
|
+
/>
|
|
121
|
+
<RenderPage data={editorData} name={project.name} />
|
|
124
122
|
</div>
|
|
125
123
|
<div className="split-third">
|
|
126
124
|
<AttributesEditorPanel
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
1
2
|
import { JsonEditor } from 'json-edit-react';
|
|
3
|
+
import { Modal } from '../../modals';
|
|
2
4
|
import { Node } from '../..';
|
|
3
5
|
import { useLogRender } from '../../utils/useLogRender';
|
|
4
6
|
|
|
@@ -9,15 +11,54 @@ type DebugTabProps = {
|
|
|
9
11
|
|
|
10
12
|
export function DebugTab({ data, setData }: DebugTabProps) {
|
|
11
13
|
useLogRender('DebugTab');
|
|
14
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
12
15
|
return (
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
16
|
+
<>
|
|
17
|
+
<button
|
|
18
|
+
type="button"
|
|
19
|
+
className="editor-button debug-button"
|
|
20
|
+
title="Inspect raw JSON data"
|
|
21
|
+
onClick={() => setIsOpen(true)}
|
|
22
|
+
>
|
|
23
|
+
Debug JSON
|
|
24
|
+
</button>
|
|
25
|
+
{isOpen ? (
|
|
26
|
+
<Modal
|
|
27
|
+
onClose={() => setIsOpen(false)}
|
|
28
|
+
ariaLabelledBy="debug-json-editor-title"
|
|
29
|
+
className="modal--large modal--scrollable"
|
|
30
|
+
contentClassName="localication-modal__content"
|
|
31
|
+
>
|
|
32
|
+
<div className="modal__header localication-modal__header">
|
|
33
|
+
<div className="localication-modal__header-main">
|
|
34
|
+
<h3 id="debug-json-editor-title" className="modal__title">
|
|
35
|
+
Debug data
|
|
36
|
+
</h3>
|
|
37
|
+
<p className="localication-modal__description">
|
|
38
|
+
Inspect and edit the current node tree using the JSON editor.
|
|
39
|
+
</p>
|
|
40
|
+
</div>
|
|
41
|
+
<button
|
|
42
|
+
type="button"
|
|
43
|
+
className="editor-button"
|
|
44
|
+
onClick={() => setIsOpen(false)}
|
|
45
|
+
>
|
|
46
|
+
Close
|
|
47
|
+
</button>
|
|
48
|
+
</div>
|
|
49
|
+
<div className="localication-modal__body">
|
|
50
|
+
<div className="localication-modal__editor">
|
|
51
|
+
<JsonEditor
|
|
52
|
+
rootName="debug"
|
|
53
|
+
data={data as any}
|
|
54
|
+
setData={setData as any}
|
|
55
|
+
className="localication-modal__json-editor"
|
|
56
|
+
maxWidth={'100%'}
|
|
57
|
+
/>
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
60
|
+
</Modal>
|
|
61
|
+
) : null}
|
|
62
|
+
</>
|
|
22
63
|
);
|
|
23
64
|
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Localication
|
|
1
|
+
import React, { useCallback, useState } from 'react';
|
|
2
|
+
import { Localication } from '../..';
|
|
3
3
|
import { useLogRender } from '../../utils/useLogRender';
|
|
4
4
|
import { useRenderStore } from '../../store';
|
|
5
|
+
import { LocalicationModal } from '../../modals/LocalicationModal';
|
|
6
|
+
import { Checkbox } from '../../components/Checkbox';
|
|
5
7
|
|
|
6
8
|
type PreviewTabProps = {};
|
|
7
9
|
|
|
@@ -11,6 +13,18 @@ export function PreviewTab({}: PreviewTabProps) {
|
|
|
11
13
|
appConfig: s.appConfig,
|
|
12
14
|
setAppConfig: s.setAppConfig,
|
|
13
15
|
}));
|
|
16
|
+
const [isLocalicationModalOpen, setIsLocalicationModalOpen] = useState(false);
|
|
17
|
+
|
|
18
|
+
const handleLocalicationChange = useCallback(
|
|
19
|
+
(data: Localication) => {
|
|
20
|
+
setAppConfig({
|
|
21
|
+
...appConfig,
|
|
22
|
+
localication: data,
|
|
23
|
+
});
|
|
24
|
+
},
|
|
25
|
+
[appConfig, setAppConfig],
|
|
26
|
+
);
|
|
27
|
+
|
|
14
28
|
return (
|
|
15
29
|
<div
|
|
16
30
|
role="tabpanel"
|
|
@@ -134,21 +148,12 @@ export function PreviewTab({}: PreviewTabProps) {
|
|
|
134
148
|
className="input input--color"
|
|
135
149
|
/>
|
|
136
150
|
</div>
|
|
137
|
-
<div
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
alignItems: 'center',
|
|
141
|
-
gap: 8,
|
|
142
|
-
marginTop: 8,
|
|
143
|
-
}}
|
|
144
|
-
>
|
|
145
|
-
<div>Dark Mode</div>
|
|
146
|
-
<input
|
|
147
|
-
type="checkbox"
|
|
151
|
+
<div style={{ marginTop: 8 }}>
|
|
152
|
+
<Checkbox
|
|
153
|
+
label="Dark Mode"
|
|
148
154
|
checked={appConfig.theme === 'dark'}
|
|
149
|
-
onChange={(
|
|
150
|
-
const nextTheme =
|
|
151
|
-
|
|
155
|
+
onChange={(checked) => {
|
|
156
|
+
const nextTheme = checked ? 'dark' : 'light';
|
|
152
157
|
setAppConfig({
|
|
153
158
|
...appConfig,
|
|
154
159
|
theme: nextTheme,
|
|
@@ -156,39 +161,46 @@ export function PreviewTab({}: PreviewTabProps) {
|
|
|
156
161
|
}}
|
|
157
162
|
/>
|
|
158
163
|
</div>
|
|
159
|
-
<div
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
alignItems: 'center',
|
|
163
|
-
gap: 8,
|
|
164
|
-
marginTop: 8,
|
|
165
|
-
}}
|
|
166
|
-
>
|
|
167
|
-
<div>Is RTL</div>
|
|
168
|
-
<input
|
|
169
|
-
type="checkbox"
|
|
164
|
+
<div style={{ marginTop: 8 }}>
|
|
165
|
+
<Checkbox
|
|
166
|
+
label="Is RTL"
|
|
170
167
|
checked={appConfig.isRtl ?? false}
|
|
171
|
-
onChange={(
|
|
168
|
+
onChange={(checked) => {
|
|
172
169
|
setAppConfig({
|
|
173
170
|
...appConfig,
|
|
174
|
-
isRtl:
|
|
171
|
+
isRtl: checked,
|
|
175
172
|
});
|
|
176
173
|
}}
|
|
177
174
|
/>
|
|
178
175
|
</div>
|
|
179
|
-
<div
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
176
|
+
<div
|
|
177
|
+
style={{
|
|
178
|
+
marginTop: 16,
|
|
179
|
+
display: 'flex',
|
|
180
|
+
flexDirection: 'column',
|
|
181
|
+
gap: 8,
|
|
182
|
+
}}
|
|
183
|
+
>
|
|
184
|
+
<div style={{ fontWeight: 600 }}>Localization</div>
|
|
185
|
+
<p style={{ margin: 0, fontSize: 13, color: '#4b5563' }}>
|
|
186
|
+
Manage translations for each language configured in your preview.
|
|
187
|
+
</p>
|
|
188
|
+
<button
|
|
189
|
+
type="button"
|
|
190
|
+
className="editor-button"
|
|
191
|
+
onClick={() => setIsLocalicationModalOpen(true)}
|
|
192
|
+
>
|
|
193
|
+
Open localization editor
|
|
194
|
+
</button>
|
|
190
195
|
</div>
|
|
191
196
|
</div>
|
|
197
|
+
{isLocalicationModalOpen ? (
|
|
198
|
+
<LocalicationModal
|
|
199
|
+
data={appConfig.localication ?? {}}
|
|
200
|
+
onChange={handleLocalicationChange}
|
|
201
|
+
onClose={() => setIsLocalicationModalOpen(false)}
|
|
202
|
+
/>
|
|
203
|
+
) : null}
|
|
192
204
|
</div>
|
|
193
205
|
);
|
|
194
206
|
}
|
|
@@ -1,15 +1,31 @@
|
|
|
1
1
|
import { useRenderStore } from '../store';
|
|
2
|
+
import { defaultAppConfig } from '../types/PreviewConfig';
|
|
3
|
+
import { getDefaultDevice } from '../utils/getDevices';
|
|
4
|
+
|
|
5
|
+
const fallbackDevice = getDefaultDevice();
|
|
6
|
+
const fallbackBaseSize = defaultAppConfig.baseSize;
|
|
7
|
+
|
|
8
|
+
function ensureNumber(value: number | undefined, fallback: number) {
|
|
9
|
+
return typeof value === 'number' && Number.isFinite(value) ? value : fallback;
|
|
10
|
+
}
|
|
2
11
|
|
|
3
12
|
function getBaseDimensions() {
|
|
4
13
|
const currentState = useRenderStore.getState();
|
|
5
|
-
|
|
14
|
+
const device = currentState.device ?? fallbackDevice;
|
|
15
|
+
const baseSize = currentState.appConfig?.baseSize ?? fallbackBaseSize;
|
|
16
|
+
|
|
17
|
+
const deviceWidth = ensureNumber(device?.width, fallbackDevice.width);
|
|
18
|
+
const deviceHeight = ensureNumber(device?.height, fallbackDevice.height);
|
|
19
|
+
const baseWidth = ensureNumber(baseSize?.width, fallbackBaseSize.width);
|
|
20
|
+
const baseHeight = ensureNumber(baseSize?.height, fallbackBaseSize.height);
|
|
21
|
+
|
|
6
22
|
const [shortDimension, longDimension] =
|
|
7
|
-
|
|
8
|
-
? [
|
|
9
|
-
: [
|
|
23
|
+
deviceWidth < deviceHeight
|
|
24
|
+
? [deviceWidth, deviceHeight]
|
|
25
|
+
: [deviceHeight, deviceWidth];
|
|
10
26
|
|
|
11
27
|
return {
|
|
12
|
-
baseSize:
|
|
28
|
+
baseSize: { width: baseWidth, height: baseHeight },
|
|
13
29
|
shortDimension,
|
|
14
30
|
longDimension,
|
|
15
31
|
};
|
package/src/store.ts
CHANGED
|
@@ -19,8 +19,6 @@ type RenderStore = {
|
|
|
19
19
|
setDevice: (device: Device) => void;
|
|
20
20
|
appConfig: AppConfig;
|
|
21
21
|
setAppConfig: (appConfig: AppConfig) => void;
|
|
22
|
-
renderCount: number;
|
|
23
|
-
forceRender: () => void;
|
|
24
22
|
// Logging
|
|
25
23
|
logs: LogEntry[];
|
|
26
24
|
logLevel: LogLevel;
|
|
@@ -38,8 +36,6 @@ export const useRenderStore = createWithEqualityFn<RenderStore>()(
|
|
|
38
36
|
(set) => ({
|
|
39
37
|
copiedNode: null,
|
|
40
38
|
setCopiedNode: (node) => set({ copiedNode: node }),
|
|
41
|
-
renderCount: 0,
|
|
42
|
-
forceRender: () => set((state) => ({ renderCount: state.renderCount + 1 })),
|
|
43
39
|
device: getDefaultDevice(),
|
|
44
40
|
setDevice: (device) => set({ device }),
|
|
45
41
|
appConfig: defaultAppConfig,
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
@use '
|
|
2
|
-
@use '
|
|
3
|
-
@use '
|
|
1
|
+
@use '../foundation/colors' as colors;
|
|
2
|
+
@use '../foundation/sizes' as sizes;
|
|
3
|
+
@use '../foundation/typography' as type;
|
|
4
|
+
@use '../foundation/mixins' as *;
|
|
4
5
|
|
|
5
6
|
/* Global utility classes */
|
|
6
7
|
html,
|
|
7
8
|
body,
|
|
8
9
|
#root {
|
|
9
|
-
font-family:
|
|
10
|
+
font-family: type.$bodyFont;
|
|
10
11
|
}
|
|
11
12
|
|
|
12
13
|
.editor-container {
|
|
@@ -18,35 +19,30 @@ body,
|
|
|
18
19
|
.editor-panel-builder {
|
|
19
20
|
padding: 4px 8px;
|
|
20
21
|
}
|
|
21
|
-
.app-shell {
|
|
22
|
-
min-height: 100vh;
|
|
23
|
-
display: flex;
|
|
24
|
-
flex-direction: column;
|
|
25
|
-
}
|
|
26
22
|
|
|
27
23
|
.app-main {
|
|
28
24
|
flex: 1 1 auto;
|
|
29
|
-
background:
|
|
25
|
+
background: colors.$canvasColor;
|
|
30
26
|
}
|
|
31
27
|
|
|
32
28
|
.page-bg {
|
|
33
|
-
background:
|
|
29
|
+
background: colors.$canvasColor;
|
|
34
30
|
}
|
|
35
31
|
|
|
36
32
|
.grid-cards {
|
|
37
33
|
display: grid;
|
|
38
34
|
grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
|
|
39
|
-
gap:
|
|
35
|
+
gap: sizes.$spaceComfy;
|
|
40
36
|
}
|
|
41
37
|
|
|
42
38
|
.btn-add {
|
|
43
39
|
height: 120px;
|
|
44
|
-
border: 2px dashed
|
|
45
|
-
border-radius:
|
|
40
|
+
border: 2px dashed colors.$mutedTextColor;
|
|
41
|
+
border-radius: sizes.$radiusRounded;
|
|
46
42
|
background: #fff;
|
|
47
43
|
cursor: pointer;
|
|
48
44
|
font-weight: 600;
|
|
49
|
-
color:
|
|
45
|
+
color: colors.$textColor;
|
|
50
46
|
transition:
|
|
51
47
|
border-color 0.2s ease,
|
|
52
48
|
transform 0.1s ease,
|
|
@@ -54,7 +50,7 @@ body,
|
|
|
54
50
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
|
|
55
51
|
|
|
56
52
|
&:hover {
|
|
57
|
-
border-color: darken(
|
|
53
|
+
border-color: darken(colors.$mutedTextColor, 10%);
|
|
58
54
|
transform: translateY(-1px);
|
|
59
55
|
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.1);
|
|
60
56
|
}
|
|
@@ -62,48 +58,67 @@ body,
|
|
|
62
58
|
|
|
63
59
|
.split-left {
|
|
64
60
|
@include thin-scrollbar;
|
|
65
|
-
flex: 1 1
|
|
61
|
+
flex: 1 1 10%;
|
|
66
62
|
min-width: 0;
|
|
67
|
-
border-right: 1px solid
|
|
63
|
+
border-right: 1px solid colors.$borderColor;
|
|
68
64
|
overflow: auto;
|
|
69
65
|
}
|
|
70
66
|
|
|
71
67
|
.split-right {
|
|
72
68
|
position: relative;
|
|
73
69
|
flex: 1 1 45%;
|
|
74
|
-
|
|
75
|
-
|
|
70
|
+
max-height: calc(100vh + 60px);
|
|
71
|
+
//NOTE: Found by trial and error. We want it to make it full height of the screen with padding
|
|
72
|
+
padding: sizes.$spaceComfy;
|
|
73
|
+
padding-bottom: 120px;
|
|
76
74
|
overflow: auto;
|
|
77
75
|
}
|
|
78
76
|
|
|
77
|
+
.split-right__controls {
|
|
78
|
+
position: sticky;
|
|
79
|
+
top: sizes.$spaceCozy;
|
|
80
|
+
z-index: 2;
|
|
81
|
+
display: flex;
|
|
82
|
+
margin-bottom: sizes.$spaceCozy;
|
|
83
|
+
}
|
|
84
|
+
|
|
79
85
|
.split-third {
|
|
80
86
|
flex: 1 1 25%;
|
|
81
|
-
min-width:
|
|
82
|
-
border-right: 1px solid
|
|
87
|
+
min-width: 450px;
|
|
88
|
+
border-right: 1px solid colors.$borderColor;
|
|
83
89
|
overflow: auto;
|
|
84
90
|
max-height: calc(100vh - 120px);
|
|
85
91
|
}
|
|
86
92
|
|
|
87
93
|
.split-right-background {
|
|
88
94
|
position: absolute;
|
|
89
|
-
|
|
95
|
+
top: 0;
|
|
96
|
+
left: 0;
|
|
97
|
+
right: 0;
|
|
98
|
+
bottom: 0;
|
|
99
|
+
height: calc(100vh + 60px);
|
|
90
100
|
background-size: cover;
|
|
91
101
|
background-position: center;
|
|
92
102
|
background-repeat: repeat;
|
|
93
103
|
background-size: 500px auto;
|
|
94
104
|
opacity: 0.2;
|
|
105
|
+
z-index: 0;
|
|
106
|
+
pointer-events: none;
|
|
95
107
|
}
|
|
96
108
|
|
|
97
109
|
.stage-wrapper {
|
|
98
110
|
display: flex;
|
|
99
111
|
justify-content: center;
|
|
100
|
-
background:
|
|
101
|
-
padding:
|
|
112
|
+
background: transparent;
|
|
113
|
+
padding: sizes.$spaceComfy;
|
|
114
|
+
position: relative;
|
|
115
|
+
z-index: 1;
|
|
102
116
|
}
|
|
103
117
|
|
|
104
118
|
.stage {
|
|
105
119
|
@include card;
|
|
106
|
-
border: 1px solid
|
|
120
|
+
border: 1px solid colors.$borderColor;
|
|
121
|
+
overflow: hidden;
|
|
107
122
|
|
|
108
123
|
.scroll-container {
|
|
109
124
|
/* Mobile-like scrollbar styling */
|
|
@@ -133,15 +148,15 @@ body,
|
|
|
133
148
|
top: 0;
|
|
134
149
|
z-index: 10;
|
|
135
150
|
background: #fff;
|
|
136
|
-
border-bottom: 1px solid
|
|
151
|
+
border-bottom: 1px solid colors.$borderColor;
|
|
137
152
|
height: 60px;
|
|
138
|
-
padding: 0
|
|
153
|
+
padding: 0 sizes.$spaceComfy;
|
|
139
154
|
display: flex;
|
|
140
155
|
align-items: center;
|
|
141
156
|
justify-content: space-between;
|
|
142
157
|
|
|
143
158
|
a {
|
|
144
|
-
color:
|
|
159
|
+
color: colors.$textColor;
|
|
145
160
|
text-decoration: none;
|
|
146
161
|
}
|
|
147
162
|
}
|
|
@@ -152,20 +167,46 @@ body,
|
|
|
152
167
|
|
|
153
168
|
.app-header__nav {
|
|
154
169
|
display: flex;
|
|
155
|
-
gap:
|
|
170
|
+
gap: sizes.$spaceComfy;
|
|
156
171
|
}
|
|
157
172
|
.warning {
|
|
158
|
-
color:
|
|
173
|
+
color: colors.$dangerColor;
|
|
159
174
|
font-size: 12px;
|
|
160
175
|
font-weight: 600;
|
|
161
|
-
margin-bottom:
|
|
176
|
+
margin-bottom: sizes.$spaceComfy;
|
|
162
177
|
}
|
|
163
178
|
|
|
164
179
|
/* Breadcrumb */
|
|
165
180
|
.breadcrumb {
|
|
166
|
-
display:
|
|
181
|
+
display: flex;
|
|
182
|
+
align-items: center;
|
|
183
|
+
gap: sizes.$spaceCozy;
|
|
167
184
|
font-size: 12px;
|
|
168
|
-
color:
|
|
185
|
+
color: colors.$mutedTextColor;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.breadcrumb__back {
|
|
189
|
+
display: inline-flex;
|
|
190
|
+
align-items: center;
|
|
191
|
+
gap: sizes.$spaceTight;
|
|
192
|
+
padding: 0;
|
|
193
|
+
border: none;
|
|
194
|
+
background: none;
|
|
195
|
+
color: colors.$textColor;
|
|
196
|
+
font-weight: 600;
|
|
197
|
+
cursor: pointer;
|
|
198
|
+
transition: color 0.2s ease;
|
|
199
|
+
|
|
200
|
+
&:hover,
|
|
201
|
+
&:focus-visible {
|
|
202
|
+
color: colors.$accentColor;
|
|
203
|
+
outline: none;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
.breadcrumb__back-icon {
|
|
208
|
+
font-size: 14px;
|
|
209
|
+
line-height: 1;
|
|
169
210
|
}
|
|
170
211
|
|
|
171
212
|
.breadcrumb__list {
|
|
@@ -174,21 +215,24 @@ body,
|
|
|
174
215
|
margin: 0;
|
|
175
216
|
display: flex;
|
|
176
217
|
align-items: center;
|
|
177
|
-
gap:
|
|
218
|
+
gap: sizes.$spaceCompact;
|
|
178
219
|
}
|
|
179
220
|
|
|
180
221
|
.breadcrumb__item {
|
|
181
222
|
display: inline-flex;
|
|
182
223
|
align-items: center;
|
|
224
|
+
&--clickable {
|
|
225
|
+
cursor: pointer;
|
|
226
|
+
}
|
|
183
227
|
}
|
|
184
228
|
|
|
185
229
|
.breadcrumb__separator {
|
|
186
|
-
color:
|
|
187
|
-
margin: 0
|
|
230
|
+
color: colors.$borderColor;
|
|
231
|
+
margin: 0 sizes.$spaceTight;
|
|
188
232
|
}
|
|
189
233
|
|
|
190
234
|
.breadcrumb__link {
|
|
191
|
-
color:
|
|
235
|
+
color: colors.$textColor;
|
|
192
236
|
text-decoration: none;
|
|
193
237
|
&:hover {
|
|
194
238
|
text-decoration: underline;
|
|
@@ -196,5 +240,14 @@ body,
|
|
|
196
240
|
}
|
|
197
241
|
|
|
198
242
|
.breadcrumb__current {
|
|
199
|
-
color:
|
|
243
|
+
color: colors.$mutedTextColor;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
.device-status-bar {
|
|
247
|
+
position: relative;
|
|
248
|
+
z-index: 100;
|
|
249
|
+
}
|
|
250
|
+
.device-navigation-bar {
|
|
251
|
+
position: relative;
|
|
252
|
+
z-index: 100;
|
|
200
253
|
}
|