@promakeai/inspector 1.0.0 → 1.0.3

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.
Files changed (204) hide show
  1. package/README.md +111 -0
  2. package/dist/App.d.ts.map +1 -0
  3. package/dist/__tests__/App.test.d.ts.map +1 -0
  4. package/dist/components/Badge.d.ts.map +1 -0
  5. package/dist/components/ControlBox/ContentArea.d.ts.map +1 -0
  6. package/dist/components/ControlBox/PromptInput.d.ts.map +1 -0
  7. package/dist/components/ControlBox/index.d.ts.map +1 -0
  8. package/dist/components/ImageEditor/UploadBox.d.ts.map +1 -0
  9. package/dist/components/ImageEditor/index.d.ts.map +1 -0
  10. package/dist/components/Overlay.d.ts.map +1 -0
  11. package/dist/components/StyleEditor/BorderSection.d.ts.map +1 -0
  12. package/dist/components/StyleEditor/ColorPicker.d.ts.map +1 -0
  13. package/dist/components/StyleEditor/DisplaySection.d.ts.map +1 -0
  14. package/dist/components/StyleEditor/ImageSection.d.ts.map +1 -0
  15. package/dist/components/StyleEditor/LayoutSection.d.ts.map +1 -0
  16. package/dist/components/StyleEditor/NumberInput.d.ts.map +1 -0
  17. package/dist/components/StyleEditor/SliderInput.d.ts.map +1 -0
  18. package/dist/components/StyleEditor/SpacingSection.d.ts.map +1 -0
  19. package/dist/components/StyleEditor/TextSection.d.ts.map +1 -0
  20. package/dist/components/StyleEditor/index.d.ts.map +1 -0
  21. package/dist/components/TextEditor/index.d.ts.map +1 -0
  22. package/dist/components/ui/CustomCollapsible.d.ts.map +1 -0
  23. package/dist/components/ui/button.d.ts.map +1 -0
  24. package/dist/components/ui/color-picker.d.ts.map +1 -0
  25. package/dist/components/ui/input.d.ts.map +1 -0
  26. package/dist/components/ui/popover.d.ts.map +1 -0
  27. package/dist/components/ui/select.d.ts.map +1 -0
  28. package/dist/components/ui/slider.d.ts.map +1 -0
  29. package/dist/components/ui/textarea.d.ts.map +1 -0
  30. package/dist/components/ui/tooltip.d.ts.map +1 -0
  31. package/dist/core/highlighter.d.ts.map +1 -0
  32. package/dist/hooks/useMessageBridge.d.ts.map +1 -0
  33. package/dist/hooks/useStylePreview.d.ts.map +1 -0
  34. package/dist/index.d.ts.map +1 -0
  35. package/dist/lib/utils.d.ts.map +1 -0
  36. package/dist/plugin.d.ts.map +1 -0
  37. package/dist/store/useInspectorStore.d.ts.map +1 -0
  38. package/dist/styles.d.ts.map +1 -0
  39. package/dist/utils/colorUtils.d.ts.map +1 -0
  40. package/dist/utils/elementNames.d.ts.map +1 -0
  41. package/dist/utils/elementUtils.d.ts.map +1 -0
  42. package/dist/utils/errorTracker.d.ts.map +1 -0
  43. package/dist/utils/inputStyles.d.ts.map +1 -0
  44. package/dist/utils/styleUtils.d.ts.map +1 -0
  45. package/dist/utils/tailwindMapper.d.ts.map +1 -0
  46. package/dist/utils/urlTracker.d.ts.map +1 -0
  47. package/package.json +15 -10
  48. package/dist/packages/inspector/src/App.d.ts.map +0 -1
  49. package/dist/packages/inspector/src/__tests__/App.test.d.ts.map +0 -1
  50. package/dist/packages/inspector/src/components/Badge.d.ts.map +0 -1
  51. package/dist/packages/inspector/src/components/ControlBox/ContentArea.d.ts.map +0 -1
  52. package/dist/packages/inspector/src/components/ControlBox/PromptInput.d.ts.map +0 -1
  53. package/dist/packages/inspector/src/components/ControlBox/index.d.ts.map +0 -1
  54. package/dist/packages/inspector/src/components/ImageEditor/UploadBox.d.ts.map +0 -1
  55. package/dist/packages/inspector/src/components/ImageEditor/index.d.ts.map +0 -1
  56. package/dist/packages/inspector/src/components/Overlay.d.ts.map +0 -1
  57. package/dist/packages/inspector/src/components/StyleEditor/BorderSection.d.ts.map +0 -1
  58. package/dist/packages/inspector/src/components/StyleEditor/ColorPicker.d.ts.map +0 -1
  59. package/dist/packages/inspector/src/components/StyleEditor/DisplaySection.d.ts.map +0 -1
  60. package/dist/packages/inspector/src/components/StyleEditor/ImageSection.d.ts.map +0 -1
  61. package/dist/packages/inspector/src/components/StyleEditor/LayoutSection.d.ts.map +0 -1
  62. package/dist/packages/inspector/src/components/StyleEditor/NumberInput.d.ts.map +0 -1
  63. package/dist/packages/inspector/src/components/StyleEditor/SliderInput.d.ts.map +0 -1
  64. package/dist/packages/inspector/src/components/StyleEditor/SpacingSection.d.ts.map +0 -1
  65. package/dist/packages/inspector/src/components/StyleEditor/TextSection.d.ts.map +0 -1
  66. package/dist/packages/inspector/src/components/StyleEditor/index.d.ts.map +0 -1
  67. package/dist/packages/inspector/src/components/TextEditor/index.d.ts.map +0 -1
  68. package/dist/packages/inspector/src/components/ui/CustomCollapsible.d.ts.map +0 -1
  69. package/dist/packages/inspector/src/components/ui/button.d.ts.map +0 -1
  70. package/dist/packages/inspector/src/components/ui/color-picker.d.ts.map +0 -1
  71. package/dist/packages/inspector/src/components/ui/input.d.ts.map +0 -1
  72. package/dist/packages/inspector/src/components/ui/popover.d.ts.map +0 -1
  73. package/dist/packages/inspector/src/components/ui/select.d.ts.map +0 -1
  74. package/dist/packages/inspector/src/components/ui/slider.d.ts.map +0 -1
  75. package/dist/packages/inspector/src/components/ui/textarea.d.ts.map +0 -1
  76. package/dist/packages/inspector/src/components/ui/tooltip.d.ts.map +0 -1
  77. package/dist/packages/inspector/src/core/highlighter.d.ts.map +0 -1
  78. package/dist/packages/inspector/src/hooks/useMessageBridge.d.ts.map +0 -1
  79. package/dist/packages/inspector/src/hooks/useStylePreview.d.ts.map +0 -1
  80. package/dist/packages/inspector/src/index.d.ts.map +0 -1
  81. package/dist/packages/inspector/src/lib/utils.d.ts.map +0 -1
  82. package/dist/packages/inspector/src/plugin.d.ts.map +0 -1
  83. package/dist/packages/inspector/src/store/useInspectorStore.d.ts.map +0 -1
  84. package/dist/packages/inspector/src/styles.d.ts.map +0 -1
  85. package/dist/packages/inspector/src/utils/colorUtils.d.ts.map +0 -1
  86. package/dist/packages/inspector/src/utils/elementNames.d.ts.map +0 -1
  87. package/dist/packages/inspector/src/utils/elementUtils.d.ts.map +0 -1
  88. package/dist/packages/inspector/src/utils/errorTracker.d.ts.map +0 -1
  89. package/dist/packages/inspector/src/utils/inputStyles.d.ts.map +0 -1
  90. package/dist/packages/inspector/src/utils/styleUtils.d.ts.map +0 -1
  91. package/dist/packages/inspector/src/utils/tailwindMapper.d.ts.map +0 -1
  92. package/dist/packages/inspector/src/utils/urlTracker.d.ts.map +0 -1
  93. package/dist/packages/inspector/tsconfig.tsbuildinfo +0 -1
  94. package/src/App.tsx +0 -912
  95. package/src/__tests__/App.test.tsx +0 -373
  96. package/src/assets/fonts/Satoshi-Variable.woff +0 -0
  97. package/src/assets/fonts/Satoshi-Variable.woff2 +0 -0
  98. package/src/components/Badge.tsx +0 -118
  99. package/src/components/ControlBox/ContentArea.tsx +0 -13
  100. package/src/components/ControlBox/PromptInput.module.css +0 -66
  101. package/src/components/ControlBox/PromptInput.tsx +0 -104
  102. package/src/components/ControlBox/index.module.css +0 -81
  103. package/src/components/ControlBox/index.tsx +0 -409
  104. package/src/components/ImageEditor/UploadBox.module.css +0 -69
  105. package/src/components/ImageEditor/UploadBox.tsx +0 -113
  106. package/src/components/ImageEditor/index.module.css +0 -11
  107. package/src/components/ImageEditor/index.tsx +0 -84
  108. package/src/components/Overlay.tsx +0 -157
  109. package/src/components/StyleEditor/BorderSection.tsx +0 -147
  110. package/src/components/StyleEditor/ColorPicker.tsx +0 -182
  111. package/src/components/StyleEditor/DisplaySection.tsx +0 -349
  112. package/src/components/StyleEditor/ImageSection.tsx +0 -105
  113. package/src/components/StyleEditor/LayoutSection.tsx +0 -63
  114. package/src/components/StyleEditor/NumberInput.tsx +0 -138
  115. package/src/components/StyleEditor/SliderInput.tsx +0 -121
  116. package/src/components/StyleEditor/SpacingSection.tsx +0 -365
  117. package/src/components/StyleEditor/TextSection.tsx +0 -381
  118. package/src/components/StyleEditor/index.module.css +0 -133
  119. package/src/components/StyleEditor/index.tsx +0 -612
  120. package/src/components/StyleEditor/shared.module.css +0 -193
  121. package/src/components/TextEditor/index.module.css +0 -31
  122. package/src/components/TextEditor/index.tsx +0 -166
  123. package/src/components/ui/CustomCollapsible.tsx +0 -159
  124. package/src/components/ui/button.module.css +0 -141
  125. package/src/components/ui/button.tsx +0 -73
  126. package/src/components/ui/color-picker.module.css +0 -112
  127. package/src/components/ui/color-picker.tsx +0 -146
  128. package/src/components/ui/input.module.css +0 -49
  129. package/src/components/ui/input.tsx +0 -34
  130. package/src/components/ui/popover.module.css +0 -42
  131. package/src/components/ui/popover.tsx +0 -59
  132. package/src/components/ui/select.module.css +0 -160
  133. package/src/components/ui/select.tsx +0 -216
  134. package/src/components/ui/slider.module.css +0 -75
  135. package/src/components/ui/slider.tsx +0 -60
  136. package/src/components/ui/textarea.module.css +0 -30
  137. package/src/components/ui/textarea.tsx +0 -23
  138. package/src/components/ui/tooltip.module.css +0 -11
  139. package/src/components/ui/tooltip.tsx +0 -37
  140. package/src/core/highlighter.ts +0 -197
  141. package/src/hooks/useMessageBridge.ts +0 -49
  142. package/src/hooks/useStylePreview.ts +0 -332
  143. package/src/index.ts +0 -20
  144. package/src/lib/utils.ts +0 -5
  145. package/src/plugin.ts +0 -11
  146. package/src/store/useInspectorStore.ts +0 -235
  147. package/src/styles/fonts.css +0 -15
  148. package/src/styles/global.css +0 -138
  149. package/src/styles/variables.css +0 -151
  150. package/src/styles.ts +0 -5
  151. package/src/utils/colorUtils.ts +0 -133
  152. package/src/utils/elementNames.ts +0 -103
  153. package/src/utils/elementUtils.ts +0 -90
  154. package/src/utils/errorTracker.ts +0 -186
  155. package/src/utils/inputStyles.ts +0 -30
  156. package/src/utils/styleUtils.ts +0 -226
  157. package/src/utils/tailwindMapper.ts +0 -554
  158. package/src/utils/urlTracker.ts +0 -75
  159. package/src/vite-env.d.ts +0 -7
  160. /package/dist/{packages/inspector/src/App.d.ts → App.d.ts} +0 -0
  161. /package/dist/{packages/inspector/src/__tests__ → __tests__}/App.test.d.ts +0 -0
  162. /package/dist/{packages/inspector/src/components → components}/Badge.d.ts +0 -0
  163. /package/dist/{packages/inspector/src/components → components}/ControlBox/ContentArea.d.ts +0 -0
  164. /package/dist/{packages/inspector/src/components → components}/ControlBox/PromptInput.d.ts +0 -0
  165. /package/dist/{packages/inspector/src/components → components}/ControlBox/index.d.ts +0 -0
  166. /package/dist/{packages/inspector/src/components → components}/ImageEditor/UploadBox.d.ts +0 -0
  167. /package/dist/{packages/inspector/src/components → components}/ImageEditor/index.d.ts +0 -0
  168. /package/dist/{packages/inspector/src/components → components}/Overlay.d.ts +0 -0
  169. /package/dist/{packages/inspector/src/components → components}/StyleEditor/BorderSection.d.ts +0 -0
  170. /package/dist/{packages/inspector/src/components → components}/StyleEditor/ColorPicker.d.ts +0 -0
  171. /package/dist/{packages/inspector/src/components → components}/StyleEditor/DisplaySection.d.ts +0 -0
  172. /package/dist/{packages/inspector/src/components → components}/StyleEditor/ImageSection.d.ts +0 -0
  173. /package/dist/{packages/inspector/src/components → components}/StyleEditor/LayoutSection.d.ts +0 -0
  174. /package/dist/{packages/inspector/src/components → components}/StyleEditor/NumberInput.d.ts +0 -0
  175. /package/dist/{packages/inspector/src/components → components}/StyleEditor/SliderInput.d.ts +0 -0
  176. /package/dist/{packages/inspector/src/components → components}/StyleEditor/SpacingSection.d.ts +0 -0
  177. /package/dist/{packages/inspector/src/components → components}/StyleEditor/TextSection.d.ts +0 -0
  178. /package/dist/{packages/inspector/src/components → components}/StyleEditor/index.d.ts +0 -0
  179. /package/dist/{packages/inspector/src/components → components}/TextEditor/index.d.ts +0 -0
  180. /package/dist/{packages/inspector/src/components → components}/ui/CustomCollapsible.d.ts +0 -0
  181. /package/dist/{packages/inspector/src/components → components}/ui/button.d.ts +0 -0
  182. /package/dist/{packages/inspector/src/components → components}/ui/color-picker.d.ts +0 -0
  183. /package/dist/{packages/inspector/src/components → components}/ui/input.d.ts +0 -0
  184. /package/dist/{packages/inspector/src/components → components}/ui/popover.d.ts +0 -0
  185. /package/dist/{packages/inspector/src/components → components}/ui/select.d.ts +0 -0
  186. /package/dist/{packages/inspector/src/components → components}/ui/slider.d.ts +0 -0
  187. /package/dist/{packages/inspector/src/components → components}/ui/textarea.d.ts +0 -0
  188. /package/dist/{packages/inspector/src/components → components}/ui/tooltip.d.ts +0 -0
  189. /package/dist/{packages/inspector/src/core → core}/highlighter.d.ts +0 -0
  190. /package/dist/{packages/inspector/src/hooks → hooks}/useMessageBridge.d.ts +0 -0
  191. /package/dist/{packages/inspector/src/hooks → hooks}/useStylePreview.d.ts +0 -0
  192. /package/dist/{packages/inspector/src/index.d.ts → index.d.ts} +0 -0
  193. /package/dist/{packages/inspector/src/lib → lib}/utils.d.ts +0 -0
  194. /package/dist/{packages/inspector/src/plugin.d.ts → plugin.d.ts} +0 -0
  195. /package/dist/{packages/inspector/src/store → store}/useInspectorStore.d.ts +0 -0
  196. /package/dist/{packages/inspector/src/styles.d.ts → styles.d.ts} +0 -0
  197. /package/dist/{packages/inspector/src/utils → utils}/colorUtils.d.ts +0 -0
  198. /package/dist/{packages/inspector/src/utils → utils}/elementNames.d.ts +0 -0
  199. /package/dist/{packages/inspector/src/utils → utils}/elementUtils.d.ts +0 -0
  200. /package/dist/{packages/inspector/src/utils → utils}/errorTracker.d.ts +0 -0
  201. /package/dist/{packages/inspector/src/utils → utils}/inputStyles.d.ts +0 -0
  202. /package/dist/{packages/inspector/src/utils → utils}/styleUtils.d.ts +0 -0
  203. /package/dist/{packages/inspector/src/utils → utils}/tailwindMapper.d.ts +0 -0
  204. /package/dist/{packages/inspector/src/utils → utils}/urlTracker.d.ts +0 -0
@@ -1,81 +0,0 @@
1
- .controlBox {
2
- position: fixed;
3
- display: flex;
4
- flex-direction: column;
5
- padding: var(--spacing-3);
6
- gap: var(--spacing-2);
7
- border-radius: var(--radius-lg);
8
- box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.05);
9
- width: 100%;
10
- max-width: 480px;
11
- min-width: 320px;
12
- box-sizing: border-box;
13
- overflow: hidden;
14
- backdrop-filter: blur(8px);
15
- z-index: var(--z-inspector-controlbox);
16
- }
17
-
18
- .tabsContainer {
19
- flex: 1;
20
- display: flex;
21
- flex-direction: column;
22
- min-height: 0;
23
- /* width: 100%; */
24
- gap: var(--spacing-2);
25
- overflow: hidden;
26
- box-sizing: border-box;
27
- }
28
-
29
- .tabsList {
30
- display: flex;
31
- align-items: center;
32
- height: var(--spacing-9);
33
- /* width: 100%; */
34
- border-radius: var(--radius-md);
35
- flex-shrink: 0;
36
- box-sizing: border-box;
37
- border: 1px solid rgba(0, 0, 0, 0.05);
38
- }
39
-
40
- .tabTrigger {
41
- display: inline-flex;
42
- align-items: center;
43
- justify-content: center;
44
- gap: var(--spacing-1-5);
45
- height: calc(100% - 2 * var(--spacing-1));
46
- margin: var(--spacing-1);
47
- border-radius: var(--radius-md);
48
- border: 1px solid transparent;
49
- padding: var(--spacing-1) var(--spacing-3);
50
- font-family: 'Satoshi', var(--font-family-sans);
51
- font-size: var(--text-sm);
52
- font-weight: var(--font-medium);
53
- white-space: nowrap;
54
- cursor: pointer;
55
- transition: all var(--transition-fast);
56
- outline: none;
57
- background: none;
58
- box-sizing: border-box;
59
- box-shadow: none;
60
- }
61
-
62
- .tabTrigger:hover {
63
- opacity: 0.85;
64
- }
65
-
66
- /* Active tab */
67
- .tabTrigger[data-active="true"] {
68
- box-shadow: none;
69
- }
70
-
71
- .tabContent {
72
- flex: 1;
73
- display: flex;
74
- flex-direction: column;
75
- min-height: 0;
76
- width: 100%;
77
- max-width: 100%;
78
- overflow-y: auto;
79
- overflow-x: hidden;
80
- box-sizing: border-box;
81
- }
@@ -1,409 +0,0 @@
1
- /**
2
- * ControlBox - Main control interface for inspector
3
- * Layout: TOP (tabs) | CONTENT (editors) | BOTTOM (prompt input)
4
- */
5
-
6
- import { useEffect, useRef, useState } from "react";
7
- import { PromptInput } from "./PromptInput";
8
- import { TextEditor } from "../TextEditor";
9
- import { ImageEditor } from "../ImageEditor";
10
- import { StyleEditor } from "../StyleEditor";
11
- import { useInspectorStore } from "../../store/useInspectorStore";
12
- import type { SelectedElementData } from "@promakeai/inspector-types";
13
- import { getElementLabel } from "../../utils/elementNames";
14
- import clsx from "clsx";
15
- import styles from "./index.module.css";
16
-
17
- interface ControlBoxProps {
18
- className?: string;
19
- element: HTMLElement;
20
- elementData: SelectedElementData;
21
- activeTab: "text" | "image" | "style" | null;
22
- availableTabs: ("text" | "image" | "style")[];
23
- onTabChange: (tab: "text" | "image" | "style" | null) => void;
24
- onClose: () => void;
25
- onPromptSubmit: (prompt: string) => void;
26
- elementStack?: HTMLElement[];
27
- onElementSelect?: (element: HTMLElement) => void;
28
- labels?: Record<string, string>;
29
- }
30
-
31
- // Custom Tab Components
32
- const TabButton = ({
33
- active,
34
- onClick,
35
- children,
36
- theme,
37
- }: {
38
- active: boolean;
39
- onClick: () => void;
40
- children: React.ReactNode;
41
- theme: any;
42
- }) => {
43
- return (
44
- <button
45
- onClick={onClick}
46
- className={styles.tabTrigger}
47
- data-active={active}
48
- style={{
49
- backgroundColor: active ? theme.tabActiveBg : theme.tabInactiveBg,
50
- color: active ? theme.tabActiveColor : theme.tabInactiveColor,
51
- }}
52
- >
53
- {children}
54
- </button>
55
- );
56
- };
57
-
58
- export function ControlBox({
59
- className,
60
- element,
61
- elementData,
62
- activeTab,
63
- availableTabs,
64
- onTabChange,
65
- onClose,
66
- onPromptSubmit,
67
- elementStack = [],
68
- onElementSelect,
69
- labels: customLabels,
70
- }: ControlBoxProps) {
71
- const { theme, labels } = useInspectorStore();
72
- const boxRef = useRef<HTMLDivElement>(null);
73
- const [position, setPosition] = useState<{
74
- top?: number;
75
- bottom?: number;
76
- left: number;
77
- }>({ left: 0 });
78
- const [maxHeight, setMaxHeight] = useState<number>(0);
79
- const [anchorPosition, setAnchorPosition] = useState<
80
- "above" | "below" | "inside"
81
- >("below");
82
- const [isPositioned, setIsPositioned] = useState(false);
83
-
84
- const TAB_LABELS = {
85
- text: labels.textTabLabel || "Content",
86
- image: labels.imageTabLabel || "Image",
87
- style: labels.styleTabLabel || "Design",
88
- };
89
-
90
- // Reset positioned state and anchor when element changes
91
- useEffect(() => {
92
- setIsPositioned(false);
93
- // Don't reset anchor here - let calculatePosition do it
94
- }, [element]);
95
-
96
- // Calculate position based on element
97
- useEffect(() => {
98
- if (!boxRef.current || !element) return;
99
-
100
- let initialAnchor: "above" | "below" | "inside" | null = null;
101
-
102
- const calculatePosition = (isInitial = false) => {
103
- const rect = element.getBoundingClientRect();
104
- const viewportWidth = window.innerWidth;
105
- const viewportHeight = window.innerHeight;
106
- const padding = 10;
107
- const gap = 10;
108
- const insidePadding = 16;
109
- const minRequiredHeight = 250;
110
- const largeElementThreshold = 0.7;
111
-
112
- // Calculate box dimensions
113
- const maxWidth = Math.min(600, viewportWidth - padding * 2);
114
- const minWidth = Math.min(320, maxWidth);
115
- const boxWidth = Math.max(minWidth, Math.min(rect.width, maxWidth));
116
-
117
- // Horizontal position (always calculated)
118
- let centerLeft = rect.left + rect.width / 2 - boxWidth / 2;
119
- centerLeft = Math.max(
120
- padding,
121
- Math.min(centerLeft, viewportWidth - boxWidth - padding)
122
- );
123
-
124
- // Determine anchor position only on initial calculation
125
- if (isInitial || initialAnchor === null) {
126
- // Calculate actual visible space
127
- const spaceBelow = Math.max(0, viewportHeight - rect.bottom);
128
- const spaceAbove = Math.max(0, rect.top);
129
-
130
- // Check element size ratios
131
- const elementHeightRatio = rect.height / viewportHeight;
132
- const elementWidthRatio = rect.width / viewportWidth;
133
-
134
- // Element is large in both dimensions (e.g., full page, large section)
135
- const isLargeInBothDimensions =
136
- elementHeightRatio > largeElementThreshold &&
137
- elementWidthRatio > largeElementThreshold;
138
-
139
- // Element is wide but short (e.g., navbar, header) - should use outside positioning
140
- const isWideButShort =
141
- elementWidthRatio > largeElementThreshold &&
142
- elementHeightRatio <= largeElementThreshold;
143
-
144
- // Check if element extends beyond viewport (partially visible)
145
- const isPartiallyVisible = rect.top < 0 || rect.bottom > viewportHeight;
146
-
147
- // Check if there's insufficient space outside
148
- const hasInsufficientSpace =
149
- spaceAbove < minRequiredHeight && spaceBelow < minRequiredHeight;
150
-
151
- // Check if there's sufficient space outside (prefer outside for wide but short elements)
152
- const hasSufficientSpaceOutside =
153
- spaceAbove >= minRequiredHeight || spaceBelow >= minRequiredHeight;
154
-
155
- // Decision logic:
156
- // 1. Wide but short elements with space outside -> use outside positioning
157
- // 2. Large in both dimensions -> use inside positioning
158
- // 3. Tall elements OR partially visible large elements -> use inside if insufficient space
159
- if (isWideButShort && hasSufficientSpaceOutside) {
160
- // Wide but short (navbar/header): use outside positioning
161
- initialAnchor = spaceAbove > spaceBelow ? "above" : "below";
162
- } else if (
163
- isLargeInBothDimensions ||
164
- hasInsufficientSpace ||
165
- (isPartiallyVisible && elementHeightRatio > 0.5)
166
- ) {
167
- // Large element or insufficient space: use inside positioning
168
- initialAnchor = "inside";
169
- } else {
170
- // Normal elements: choose based on available space
171
- initialAnchor = spaceAbove > spaceBelow ? "above" : "below";
172
- }
173
- setAnchorPosition(initialAnchor);
174
- }
175
-
176
- // Calculate dynamic max-height based on anchor
177
- let calculatedMaxHeight: number;
178
- let newPosition: { top?: number; bottom?: number; left: number };
179
-
180
- if (initialAnchor === "inside") {
181
- // Position inside the element, but respect viewport boundaries
182
- // If element is scrolled partially off screen, start from viewport edge
183
- const topPos = Math.max(rect.top + insidePadding, insidePadding);
184
-
185
- // Calculate available height: from topPos to element bottom or viewport bottom
186
- const availableBottom = Math.min(
187
- rect.bottom - insidePadding,
188
- viewportHeight - insidePadding
189
- );
190
- calculatedMaxHeight = availableBottom - topPos;
191
-
192
- // Horizontal positioning
193
- let insideLeft = rect.left + insidePadding;
194
-
195
- // If element is scrolled partially off screen horizontally, start from viewport edge
196
- if (rect.left < 0) {
197
- insideLeft = insidePadding;
198
- }
199
-
200
- // Ensure the box fits within element width and viewport
201
- const elementRightEdge = Math.min(rect.right, viewportWidth);
202
- const maxBoxWidth = elementRightEdge - insideLeft - insidePadding;
203
- const actualBoxWidth = Math.min(boxWidth, maxBoxWidth);
204
-
205
- // Center horizontally within element if there's room
206
- const elementVisibleWidth =
207
- Math.min(rect.right, viewportWidth) - Math.max(rect.left, 0);
208
- if (actualBoxWidth < elementVisibleWidth - insidePadding * 2) {
209
- const elementVisibleLeft = Math.max(rect.left, 0);
210
- insideLeft =
211
- elementVisibleLeft + (elementVisibleWidth - actualBoxWidth) / 2;
212
- }
213
-
214
- newPosition = { top: topPos, left: insideLeft };
215
-
216
- // Update box width for inside positioning
217
- if (boxRef.current && actualBoxWidth !== boxWidth) {
218
- boxRef.current.style.width = `${actualBoxWidth}px`;
219
- }
220
- } else if (initialAnchor === "above") {
221
- // Anchored above: grow upward from element
222
- calculatedMaxHeight = rect.top - padding - gap;
223
- const bottomPos = viewportHeight - rect.top + gap;
224
- newPosition = { bottom: bottomPos, left: centerLeft };
225
- } else {
226
- // Anchored below: grow downward from element
227
- calculatedMaxHeight = viewportHeight - rect.bottom - padding - gap;
228
- const topPos = rect.bottom + gap;
229
- newPosition = { top: topPos, left: centerLeft };
230
- }
231
-
232
- // Ensure minimum height
233
- calculatedMaxHeight = Math.max(200, calculatedMaxHeight);
234
-
235
- setMaxHeight(calculatedMaxHeight);
236
- setPosition(newPosition);
237
-
238
- // Update box width (for non-inside positioning)
239
- if (boxRef.current && initialAnchor !== "inside") {
240
- boxRef.current.style.width = `${boxWidth}px`;
241
- }
242
-
243
- // Mark as positioned after first calculation
244
- if (isInitial) {
245
- setIsPositioned(true);
246
- }
247
- };
248
-
249
- // Initial calculation
250
- calculatePosition(true);
251
-
252
- // Update position on scroll/resize (but keep anchor)
253
- const handleUpdate = () => calculatePosition(false);
254
- window.addEventListener("scroll", handleUpdate, true);
255
- window.addEventListener("resize", handleUpdate);
256
-
257
- // Watch for content height changes (e.g., tab switches)
258
- const resizeObserver = new ResizeObserver(() => {
259
- // Only update if already positioned (avoid flash on initial render)
260
- if (initialAnchor !== null) {
261
- calculatePosition(false);
262
- }
263
- });
264
- resizeObserver.observe(boxRef.current);
265
-
266
- return () => {
267
- window.removeEventListener("scroll", handleUpdate, true);
268
- window.removeEventListener("resize", handleUpdate);
269
- resizeObserver.disconnect();
270
- initialAnchor = null;
271
- };
272
- }, [element]);
273
-
274
- return (
275
- <div
276
- ref={boxRef}
277
- className={clsx(styles.controlBox, className)}
278
- style={{
279
- top: position.top !== undefined ? `${position.top}px` : undefined,
280
- bottom:
281
- position.bottom !== undefined ? `${position.bottom}px` : undefined,
282
- left: `${position.left}px`,
283
- maxHeight: maxHeight > 0 ? `${maxHeight}px` : undefined,
284
- backgroundColor: theme.backgroundColor,
285
- opacity: isPositioned ? 1 : 0,
286
- transform: isPositioned ? "scale(1)" : "scale(0.95)",
287
- transition: "opacity 0.2s ease, transform 0.2s ease",
288
- }}
289
- >
290
- {/* Element name tags - at top of control box */}
291
- {(() => {
292
- const shouldShow = elementStack.length > 1;
293
- console.log("🔘 Element Tags Debug:", {
294
- shouldShow,
295
- stackLength: elementStack.length,
296
- stack: elementStack.map((el) => ({
297
- tag: el.tagName,
298
- id: el.id,
299
- className: el.className,
300
- devId: el.getAttribute("data-dev-id"),
301
- })),
302
- isPositioned,
303
- });
304
-
305
- return (
306
- shouldShow && (
307
- <div
308
- className="inspector-element-tags"
309
- data-inspector-ignore
310
- style={{
311
- display: "flex",
312
- gap: "4px",
313
- overflowX: "auto",
314
- overflowY: "hidden",
315
- width: "calc(100% + 24px)",
316
- marginLeft: "-12px",
317
- marginRight: "-12px",
318
- marginTop: "-12px",
319
- paddingLeft: "12px",
320
- paddingRight: "12px",
321
- paddingTop: "12px",
322
- paddingBottom: "10px",
323
- borderBottom: "1px solid rgba(0, 0, 0, 0.05)",
324
- }}
325
- >
326
- {elementStack.map((el, index) => {
327
- const labelText = getElementLabel(el, customLabels || labels);
328
- const isSelected = el === element; // Check if this element is the currently selected one
329
- console.log(`🏷️ Button ${index}:`, labelText, el, {
330
- isSelected,
331
- });
332
- return (
333
- <button
334
- key={index}
335
- className="inspector-element-tag"
336
- onClick={() => onElementSelect?.(el)}
337
- style={{
338
- background: isSelected ? "rgb(58, 18, 189)" : "#ffffff",
339
- color: isSelected ? "#ffffff" : "#475569",
340
- border: isSelected ? "none" : "1px solid #e2e8f0",
341
- padding: "4px 8px",
342
- borderRadius: "4px",
343
- fontSize: "11px",
344
- fontWeight: "500",
345
- cursor: "pointer",
346
- whiteSpace: "nowrap",
347
- flexShrink: 0,
348
- height: "24px",
349
- display: "flex",
350
- alignItems: "center",
351
- boxShadow: isSelected
352
- ? "0 1px 3px rgba(58, 18, 189, 0.2)"
353
- : "0 1px 2px rgba(0, 0, 0, 0.05)",
354
- }}
355
- >
356
- {String(labelText)}
357
- </button>
358
- );
359
- })}
360
- </div>
361
- )
362
- );
363
- })()}
364
-
365
- <PromptInput
366
- placeholder={labels.promptPlaceholder || "Ask AI..."}
367
- onSubmit={onPromptSubmit}
368
- onClose={onClose}
369
- autoFocus={!activeTab}
370
- />
371
- {/* Custom Tabs */}
372
- {availableTabs.length > 0 && activeTab ? (
373
- <div className={styles.tabsContainer}>
374
- {/* Tab Buttons */}
375
- <div
376
- className={styles.tabsList}
377
- style={{
378
- backgroundColor: theme.tabContainerBg,
379
- }}
380
- >
381
- {availableTabs.map((tab) => (
382
- <TabButton
383
- key={tab}
384
- active={activeTab === tab}
385
- onClick={() => onTabChange(tab)}
386
- theme={theme}
387
- >
388
- {TAB_LABELS[tab]}
389
- </TabButton>
390
- ))}
391
- </div>
392
-
393
- {/* Tab Content */}
394
- <div className={styles.tabContent}>
395
- {activeTab === "text" && (
396
- <TextEditor element={element} elementData={elementData} />
397
- )}
398
- {activeTab === "image" && (
399
- <ImageEditor element={element} elementData={elementData} />
400
- )}
401
- {activeTab === "style" && (
402
- <StyleEditor element={element} elementData={elementData} />
403
- )}
404
- </div>
405
- </div>
406
- ) : null}
407
- </div>
408
- );
409
- }
@@ -1,69 +0,0 @@
1
- .hiddenInput {
2
- position: absolute;
3
- width: 1px;
4
- height: 1px;
5
- padding: 0;
6
- margin: -1px;
7
- overflow: hidden;
8
- clip: rect(0, 0, 0, 0);
9
- white-space: nowrap;
10
- border-width: 0;
11
- opacity: 0;
12
- pointer-events: none;
13
- }
14
-
15
- .uploadBox {
16
- min-height: 100px;
17
- border: 2px dashed;
18
- border-radius: var(--radius-lg);
19
- cursor: pointer;
20
- transition: all var(--transition-fast);
21
- display: flex;
22
- align-items: center;
23
- justify-content: center;
24
- flex-direction: column;
25
- gap: var(--spacing-2);
26
- padding: var(--spacing-4);
27
- position: relative;
28
- overflow: hidden;
29
- }
30
-
31
- .uploadBox:hover {
32
- opacity: 0.9;
33
- }
34
-
35
- .uploadContent {
36
- text-align: center;
37
- pointer-events: none;
38
- display: flex;
39
- flex-direction: column;
40
- align-items: center;
41
- gap: var(--spacing-2);
42
- }
43
-
44
- .uploadIcon {
45
- width: 32px;
46
- height: 32px;
47
- margin-bottom: var(--spacing-2);
48
- opacity: 0.5;
49
- }
50
-
51
- .uploadTitle {
52
- font-family: "Satoshi", var(--font-family-sans);
53
- font-size: var(--text-sm);
54
- font-weight: var(--font-medium);
55
- }
56
-
57
- .uploadHint {
58
- font-family: "Satoshi", var(--font-family-sans);
59
- font-size: var(--text-xs);
60
- margin-top: var(--spacing-0_5);
61
- }
62
-
63
- .previewImage {
64
- width: 100%;
65
- height: auto;
66
- max-height: 100px;
67
- object-fit: contain;
68
- border-radius: var(--radius-lg);
69
- }
@@ -1,113 +0,0 @@
1
- /**
2
- * UploadBox component - Drag & drop image upload
3
- */
4
-
5
- import { useRef, useState } from "react";
6
- import { useInspectorStore } from "../../store/useInspectorStore";
7
- import styles from "./UploadBox.module.css";
8
-
9
- interface UploadBoxProps {
10
- onFileSelect: (file: File) => void;
11
- previewImage: string | null;
12
- }
13
-
14
- export function UploadBox({ onFileSelect, previewImage }: UploadBoxProps) {
15
- const { theme, labels } = useInspectorStore();
16
- const inputRef = useRef<HTMLInputElement>(null);
17
- const [isDragging, setIsDragging] = useState(false);
18
-
19
- const handleClick = () => {
20
- inputRef.current?.click();
21
- };
22
-
23
- const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
24
- const file = e.target.files?.[0];
25
- if (file && file.type.startsWith("image/")) {
26
- onFileSelect(file);
27
- }
28
- };
29
-
30
- const handleDragOver = (e: React.DragEvent<HTMLDivElement>) => {
31
- e.preventDefault();
32
- setIsDragging(true);
33
- };
34
-
35
- const handleDragLeave = (e: React.DragEvent<HTMLDivElement>) => {
36
- e.preventDefault();
37
- setIsDragging(false);
38
- };
39
-
40
- const handleDrop = (e: React.DragEvent<HTMLDivElement>) => {
41
- e.preventDefault();
42
- setIsDragging(false);
43
-
44
- const file = e.dataTransfer?.files[0];
45
- if (file && file.type.startsWith("image/")) {
46
- onFileSelect(file);
47
- }
48
- };
49
-
50
- return (
51
- <>
52
- <input
53
- ref={inputRef}
54
- type="file"
55
- accept="image/*"
56
- onChange={handleFileChange}
57
- className={styles.hiddenInput}
58
- />
59
- <div
60
- onClick={handleClick}
61
- onDragOver={handleDragOver}
62
- onDragLeave={handleDragLeave}
63
- onDrop={handleDrop}
64
- className={styles.uploadBox}
65
- style={{
66
- borderColor: isDragging ? theme.buttonColor : theme.inputBorderColor,
67
- backgroundColor: isDragging
68
- ? `${theme.buttonColor}10`
69
- : theme.inputBackgroundColor,
70
- }}
71
- >
72
- {!previewImage ? (
73
- <div className={styles.uploadContent}>
74
- <svg
75
- width="32"
76
- height="32"
77
- viewBox="0 0 24 24"
78
- fill="none"
79
- className={styles.uploadIcon}
80
- style={{ color: theme.secondaryTextColor }}
81
- >
82
- <path
83
- d="M21 15V19C21 19.5304 20.7893 20.0391 20.4142 20.4142C20.0391 20.7893 19.5304 21 19 21H5C4.46957 21 3.96086 20.7893 3.58579 20.4142C3.21071 20.0391 3 19.5304 3 19V15M17 8L12 3M12 3L7 8M12 3V15"
84
- stroke="currentColor"
85
- strokeWidth="2"
86
- strokeLinecap="round"
87
- strokeLinejoin="round"
88
- />
89
- </svg>
90
- <div
91
- className={styles.uploadTitle}
92
- style={{ color: theme.textColor }}
93
- >
94
- {labels.imageUploadTitle || "Click or drag image"}
95
- </div>
96
- <div
97
- className={styles.uploadHint}
98
- style={{ color: theme.secondaryTextColor }}
99
- >
100
- {labels.imageUploadHint || "Supports: JPG, PNG, GIF"}
101
- </div>
102
- </div>
103
- ) : (
104
- <img
105
- src={previewImage}
106
- alt="Preview"
107
- className={styles.previewImage}
108
- />
109
- )}
110
- </div>
111
- </>
112
- );
113
- }
@@ -1,11 +0,0 @@
1
- .container {
2
- display: flex;
3
- flex-direction: column;
4
- gap: var(--spacing-2);
5
- flex: 1;
6
- box-sizing: border-box;
7
- }
8
-
9
- .button {
10
- width: 100%;
11
- }