@yogiswara/honcho-editor-ui 3.9.2 → 4.0.1
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/components/editor/SectionAlbum/AlbumSectionTabs.d.ts +22 -0
- package/dist/components/editor/SectionAlbum/AlbumSectionTabs.js +414 -0
- package/dist/components/editor/SectionAlbum/AlbumSectionTabsSelectMode.d.ts +14 -0
- package/dist/components/editor/SectionAlbum/AlbumSectionTabsSelectMode.js +180 -0
- package/dist/components/editor/SectionAlbum/HBaseDialog.d.ts +24 -0
- package/dist/components/editor/SectionAlbum/HBaseDialog.js +75 -0
- package/dist/components/editor/svg/IcChevron.d.ts +5 -0
- package/dist/components/editor/svg/IcChevron.js +15 -0
- package/dist/components/editor/svg/IcPencilIcon.d.ts +3 -0
- package/dist/components/editor/svg/IcPencilIcon.js +10 -0
- package/dist/components/editor/svg/IcPlusButton.d.ts +2 -0
- package/dist/components/editor/svg/IcPlusButton.js +5 -0
- package/dist/components/editor/svg/IcTrashIcon.d.ts +2 -0
- package/dist/components/editor/svg/IcTrashIcon.js +6 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/themes/colors.d.ts +2 -0
- package/dist/themes/colors.js +3 -1
- package/dist/themes/colours.d.ts +14 -0
- package/dist/themes/colours.js +14 -0
- package/package.json +1 -1
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type FC } from "react";
|
|
2
|
+
export interface AlbumSection {
|
|
3
|
+
id: string;
|
|
4
|
+
label: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
}
|
|
7
|
+
interface Props {
|
|
8
|
+
sections: AlbumSection[];
|
|
9
|
+
activeSectionIndex: number;
|
|
10
|
+
onSectionChange: (index: number) => void;
|
|
11
|
+
onSectionsReorder: (reordered: AlbumSection[]) => void;
|
|
12
|
+
onAddSection: (name: string, description: string) => void;
|
|
13
|
+
onEditSection?: (index: number, name: string, description: string) => void;
|
|
14
|
+
onDeleteSection?: (sectionId: string) => void;
|
|
15
|
+
compact?: boolean;
|
|
16
|
+
selectedMode?: boolean;
|
|
17
|
+
onLoadMore?: () => void;
|
|
18
|
+
isLoadingMoreSections?: boolean;
|
|
19
|
+
hasMoreSections?: boolean;
|
|
20
|
+
}
|
|
21
|
+
declare const AlbumSectionTabs: FC<Props>;
|
|
22
|
+
export default AlbumSectionTabs;
|
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useRef, useState, useEffect } from "react";
|
|
3
|
+
import { Box, Typography, Menu, MenuItem, TextField, Stack, Skeleton } from "@mui/material";
|
|
4
|
+
import useHonchoTypography from '../../../themes/honchoTheme';
|
|
5
|
+
import useColorsSecond from '../../../themes/colours';
|
|
6
|
+
import useIsMobile from '../../../utils/isMobile';
|
|
7
|
+
import IcPlusButton from "../svg/IcPlusButton";
|
|
8
|
+
import { IcChevronArrowDarkColor } from "../svg/IcChevron";
|
|
9
|
+
import { IcPencilIconDark } from "../svg/IcPencilIcon";
|
|
10
|
+
import { IcTrashIcon } from "../svg/IcTrashIcon";
|
|
11
|
+
import { HBaseDialog, NegativeButton, PositiveButton } from "../../editor/SectionAlbum/HBaseDialog";
|
|
12
|
+
const DRAG_THRESHOLD = 4;
|
|
13
|
+
const AlbumSectionTabs = ({ sections, activeSectionIndex, onSectionChange, onSectionsReorder, onAddSection, onEditSection, onDeleteSection, compact = false, onLoadMore, isLoadingMoreSections = false, hasMoreSections = false, }) => {
|
|
14
|
+
const isMobile = useIsMobile();
|
|
15
|
+
const colors = useColorsSecond();
|
|
16
|
+
const typography = useHonchoTypography();
|
|
17
|
+
// ---------- drag state ----------
|
|
18
|
+
const [dragIndex, setDragIndex] = useState(null);
|
|
19
|
+
const [overIndex, setOverIndex] = useState(null);
|
|
20
|
+
const [isDragging, setIsDragging] = useState(false);
|
|
21
|
+
const [cursorPos, setCursorPos] = useState({ x: 0, y: 0 });
|
|
22
|
+
const [openMenuIndex, setOpenMenuIndex] = useState(null);
|
|
23
|
+
const [menuAnchorEl, setMenuAnchorEl] = useState(null);
|
|
24
|
+
const [isEditDialogOpen, setIsEditDialogOpen] = useState(false);
|
|
25
|
+
const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false);
|
|
26
|
+
const [isCreateSectionDialogOpen, setIsCreateSectionDialogOpen] = useState(false);
|
|
27
|
+
const [selectedSectionIndex, setSelectedSectionIndex] = useState(null);
|
|
28
|
+
const [sectionName, setSectionName] = useState("");
|
|
29
|
+
const [sectionDescription, setSectionDescription] = useState("");
|
|
30
|
+
const pointerDownPos = useRef(null);
|
|
31
|
+
const pointerDownIndex = useRef(null);
|
|
32
|
+
const dragStarted = useRef(false);
|
|
33
|
+
const scrollRef = useRef(null);
|
|
34
|
+
const [canScrollLeft, setCanScrollLeft] = useState(false);
|
|
35
|
+
const [canScrollRight, setCanScrollRight] = useState(false);
|
|
36
|
+
// Prevents firing onLoadMore multiple times for the same scroll position
|
|
37
|
+
const isLoadingMoreRef = useRef(false);
|
|
38
|
+
const updateScrollButtons = () => {
|
|
39
|
+
const el = scrollRef.current;
|
|
40
|
+
if (!el)
|
|
41
|
+
return;
|
|
42
|
+
setCanScrollLeft(el.scrollLeft > 0);
|
|
43
|
+
setCanScrollRight(el.scrollLeft + el.clientWidth < el.scrollWidth - 1);
|
|
44
|
+
// Trigger load-more when within 80px of the right edge
|
|
45
|
+
const nearRightEdge = el.scrollLeft + el.clientWidth >= el.scrollWidth - 80;
|
|
46
|
+
if (nearRightEdge && hasMoreSections && !isLoadingMoreSections && !isLoadingMoreRef.current) {
|
|
47
|
+
isLoadingMoreRef.current = true;
|
|
48
|
+
onLoadMore?.();
|
|
49
|
+
}
|
|
50
|
+
if (!nearRightEdge) {
|
|
51
|
+
isLoadingMoreRef.current = false;
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
useEffect(() => {
|
|
55
|
+
updateScrollButtons();
|
|
56
|
+
const el = scrollRef.current;
|
|
57
|
+
if (!el)
|
|
58
|
+
return;
|
|
59
|
+
el.addEventListener("scroll", updateScrollButtons);
|
|
60
|
+
const ro = new ResizeObserver(updateScrollButtons);
|
|
61
|
+
ro.observe(el);
|
|
62
|
+
return () => {
|
|
63
|
+
el.removeEventListener("scroll", updateScrollButtons);
|
|
64
|
+
ro.disconnect();
|
|
65
|
+
};
|
|
66
|
+
}, [sections, hasMoreSections, isLoadingMoreSections]);
|
|
67
|
+
const scrollBy = (direction) => {
|
|
68
|
+
const el = scrollRef.current;
|
|
69
|
+
if (!el)
|
|
70
|
+
return;
|
|
71
|
+
el.scrollBy({ left: direction === "left" ? -160 : 160, behavior: "smooth" });
|
|
72
|
+
};
|
|
73
|
+
const activeSection = sections[activeSectionIndex]; // Get the current section
|
|
74
|
+
const handleEditSection = (index) => {
|
|
75
|
+
setOpenMenuIndex(null);
|
|
76
|
+
setMenuAnchorEl(null);
|
|
77
|
+
setSelectedSectionIndex(index);
|
|
78
|
+
setSectionName(sections[index].label);
|
|
79
|
+
setSectionDescription(sections[index].description || "");
|
|
80
|
+
setIsEditDialogOpen(true);
|
|
81
|
+
};
|
|
82
|
+
const handleDeleteSection = (index) => {
|
|
83
|
+
setOpenMenuIndex(null);
|
|
84
|
+
setMenuAnchorEl(null);
|
|
85
|
+
setSelectedSectionIndex(index);
|
|
86
|
+
setIsDeleteDialogOpen(true);
|
|
87
|
+
};
|
|
88
|
+
const handleCreateSection = () => {
|
|
89
|
+
setOpenMenuIndex(null);
|
|
90
|
+
setMenuAnchorEl(null);
|
|
91
|
+
setSectionName("");
|
|
92
|
+
setSectionDescription("");
|
|
93
|
+
setIsCreateSectionDialogOpen(true);
|
|
94
|
+
};
|
|
95
|
+
// ---------- pointer handlers ----------
|
|
96
|
+
const handlePointerDown = (e, index) => {
|
|
97
|
+
pointerDownPos.current = { x: e.clientX, y: e.clientY };
|
|
98
|
+
pointerDownIndex.current = index;
|
|
99
|
+
dragStarted.current = false;
|
|
100
|
+
e.currentTarget.setPointerCapture(e.pointerId);
|
|
101
|
+
};
|
|
102
|
+
const handlePointerMove = (e, index) => {
|
|
103
|
+
if (pointerDownPos.current === null)
|
|
104
|
+
return;
|
|
105
|
+
const dx = Math.abs(e.clientX - pointerDownPos.current.x);
|
|
106
|
+
const dy = Math.abs(e.clientY - pointerDownPos.current.y);
|
|
107
|
+
if (!dragStarted.current && (dx > DRAG_THRESHOLD || dy > DRAG_THRESHOLD)) {
|
|
108
|
+
dragStarted.current = true;
|
|
109
|
+
setDragIndex(pointerDownIndex.current);
|
|
110
|
+
setIsDragging(true);
|
|
111
|
+
}
|
|
112
|
+
if (dragStarted.current) {
|
|
113
|
+
setCursorPos({ x: e.clientX, y: e.clientY });
|
|
114
|
+
const elementUnderPointer = document.elementFromPoint(e.clientX, e.clientY);
|
|
115
|
+
if (elementUnderPointer) {
|
|
116
|
+
const tabNode = elementUnderPointer.closest('[data-index]');
|
|
117
|
+
if (tabNode) {
|
|
118
|
+
const hoveredIndex = parseInt(tabNode.getAttribute('data-index') || '-1', 10);
|
|
119
|
+
if (hoveredIndex !== -1 && hoveredIndex !== overIndex) {
|
|
120
|
+
setOverIndex(hoveredIndex);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
const handlePointerUp = (e, index) => {
|
|
127
|
+
if (!dragStarted.current) {
|
|
128
|
+
onSectionChange(index);
|
|
129
|
+
}
|
|
130
|
+
else if (dragIndex !== null && overIndex !== null && dragIndex !== overIndex) {
|
|
131
|
+
const reordered = [...sections];
|
|
132
|
+
const [moved] = reordered.splice(dragIndex, 1);
|
|
133
|
+
reordered.splice(overIndex, 0, moved);
|
|
134
|
+
let newActive = activeSectionIndex;
|
|
135
|
+
if (activeSectionIndex === dragIndex) {
|
|
136
|
+
newActive = overIndex;
|
|
137
|
+
}
|
|
138
|
+
else if (dragIndex < activeSectionIndex && overIndex >= activeSectionIndex) {
|
|
139
|
+
newActive = activeSectionIndex - 1;
|
|
140
|
+
}
|
|
141
|
+
else if (dragIndex > activeSectionIndex && overIndex <= activeSectionIndex) {
|
|
142
|
+
newActive = activeSectionIndex + 1;
|
|
143
|
+
}
|
|
144
|
+
onSectionsReorder(reordered);
|
|
145
|
+
onSectionChange(newActive);
|
|
146
|
+
}
|
|
147
|
+
setDragIndex(null);
|
|
148
|
+
setOverIndex(null);
|
|
149
|
+
setIsDragging(false);
|
|
150
|
+
dragStarted.current = false;
|
|
151
|
+
pointerDownPos.current = null;
|
|
152
|
+
pointerDownIndex.current = null;
|
|
153
|
+
};
|
|
154
|
+
const handlePointerCancel = () => {
|
|
155
|
+
setDragIndex(null);
|
|
156
|
+
setOverIndex(null);
|
|
157
|
+
setIsDragging(false);
|
|
158
|
+
dragStarted.current = false;
|
|
159
|
+
pointerDownPos.current = null;
|
|
160
|
+
pointerDownIndex.current = null;
|
|
161
|
+
};
|
|
162
|
+
useEffect(() => {
|
|
163
|
+
if (!scrollRef.current)
|
|
164
|
+
return;
|
|
165
|
+
const timeout = setTimeout(() => {
|
|
166
|
+
const activeTabNode = scrollRef.current?.querySelector(`[data-index="${activeSectionIndex}"]`);
|
|
167
|
+
if (activeTabNode) {
|
|
168
|
+
activeTabNode.scrollIntoView({
|
|
169
|
+
behavior: "smooth",
|
|
170
|
+
block: "nearest",
|
|
171
|
+
inline: "center",
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
}, 50);
|
|
175
|
+
return () => clearTimeout(timeout);
|
|
176
|
+
}, [activeSectionIndex]);
|
|
177
|
+
// ---------- render ----------
|
|
178
|
+
return (_jsxs(Box, { sx: {
|
|
179
|
+
// Removed the border from here, moved to the tab row so it sits above the description
|
|
180
|
+
...(compact ? {
|
|
181
|
+
width: "100%",
|
|
182
|
+
} : {
|
|
183
|
+
width: "100vw",
|
|
184
|
+
position: "relative",
|
|
185
|
+
left: "50%",
|
|
186
|
+
right: "50%",
|
|
187
|
+
marginLeft: "-50vw",
|
|
188
|
+
marginRight: "-50vw",
|
|
189
|
+
}),
|
|
190
|
+
}, children: [_jsxs(Box, { sx: { position: "relative" }, children: [!isMobile && canScrollLeft && (_jsx(Box, { onClick: () => scrollBy("left"), sx: {
|
|
191
|
+
position: "absolute",
|
|
192
|
+
left: 0,
|
|
193
|
+
top: 0,
|
|
194
|
+
bottom: "1px",
|
|
195
|
+
zIndex: 2,
|
|
196
|
+
display: "flex",
|
|
197
|
+
alignItems: "center",
|
|
198
|
+
px: "4px",
|
|
199
|
+
pl: "24px",
|
|
200
|
+
cursor: "pointer",
|
|
201
|
+
background: colors.surface,
|
|
202
|
+
}, children: _jsx(IcChevronArrowDarkColor, { sx: {
|
|
203
|
+
width: "20px",
|
|
204
|
+
height: "20px",
|
|
205
|
+
color: colors.onSurface,
|
|
206
|
+
transform: "rotate(90deg)",
|
|
207
|
+
} }) })), !isMobile && canScrollRight && (_jsx(Box, { onClick: () => scrollBy("right"), sx: {
|
|
208
|
+
position: "absolute",
|
|
209
|
+
right: 0,
|
|
210
|
+
top: 0,
|
|
211
|
+
bottom: "1px",
|
|
212
|
+
zIndex: 2,
|
|
213
|
+
display: "flex",
|
|
214
|
+
alignItems: "center",
|
|
215
|
+
px: "4px",
|
|
216
|
+
pr: "24px",
|
|
217
|
+
cursor: "pointer",
|
|
218
|
+
background: colors.surface,
|
|
219
|
+
}, children: _jsx(IcChevronArrowDarkColor, { sx: {
|
|
220
|
+
width: "20px",
|
|
221
|
+
height: "20px",
|
|
222
|
+
color: colors.onSurface,
|
|
223
|
+
transform: "rotate(270deg)",
|
|
224
|
+
} }) })), _jsxs(Box, { ref: scrollRef, sx: {
|
|
225
|
+
display: "flex",
|
|
226
|
+
flexDirection: "row",
|
|
227
|
+
alignItems: "flex-end", // Aligns active bars to bottom
|
|
228
|
+
px: isMobile ? "16px" : "24px",
|
|
229
|
+
gap: "20px",
|
|
230
|
+
overflowX: "auto",
|
|
231
|
+
overflowY: "visible",
|
|
232
|
+
"&::-webkit-scrollbar": { display: "none" },
|
|
233
|
+
scrollbarWidth: "none",
|
|
234
|
+
userSelect: "none",
|
|
235
|
+
borderBottom: "1px solid", // Bottom border lives here now
|
|
236
|
+
borderColor: colors.outlineVariant,
|
|
237
|
+
}, children: [sections.map((section, index) => {
|
|
238
|
+
const isActive = index === activeSectionIndex;
|
|
239
|
+
const isBeingDragged = index === dragIndex;
|
|
240
|
+
const isDropTarget = index === overIndex && dragIndex !== null && dragIndex !== overIndex;
|
|
241
|
+
return (_jsxs(Box, { "data-index": index, onPointerDown: (e) => handlePointerDown(e, index), onPointerMove: (e) => handlePointerMove(e, index), onPointerUp: (e) => handlePointerUp(e, index), onPointerCancel: handlePointerCancel, sx: {
|
|
242
|
+
position: "relative",
|
|
243
|
+
overflow: "visible",
|
|
244
|
+
flexShrink: 0,
|
|
245
|
+
display: "flex",
|
|
246
|
+
alignItems: "center",
|
|
247
|
+
cursor: isDragging ? "grabbing" : "pointer",
|
|
248
|
+
height: "44px", // FIXED HEIGHT to ensure perfect alignment
|
|
249
|
+
boxSizing: "border-box",
|
|
250
|
+
px: "0px",
|
|
251
|
+
// active indicator
|
|
252
|
+
"&::after": {
|
|
253
|
+
content: '""',
|
|
254
|
+
position: "absolute",
|
|
255
|
+
bottom: "0px",
|
|
256
|
+
left: 0,
|
|
257
|
+
right: 0,
|
|
258
|
+
height: "1.5px",
|
|
259
|
+
backgroundColor: isActive ? colors.onSurface : "transparent",
|
|
260
|
+
transition: "background-color 0.15s ease",
|
|
261
|
+
},
|
|
262
|
+
// drop-target indicator
|
|
263
|
+
"&::before": isDropTarget
|
|
264
|
+
? {
|
|
265
|
+
content: '""',
|
|
266
|
+
position: "absolute",
|
|
267
|
+
// Dynamic placement based on drag direction
|
|
268
|
+
left: dragIndex !== null && dragIndex > index ? "-10px" : "auto",
|
|
269
|
+
right: dragIndex !== null && dragIndex < index ? "-10px" : "auto",
|
|
270
|
+
top: "20%",
|
|
271
|
+
height: "60%",
|
|
272
|
+
width: "2px",
|
|
273
|
+
borderRadius: "2px",
|
|
274
|
+
backgroundColor: colors.onSurface,
|
|
275
|
+
}
|
|
276
|
+
: {},
|
|
277
|
+
opacity: isBeingDragged ? 0.35 : 1,
|
|
278
|
+
transform: isBeingDragged ? "scale(0.97)" : "scale(1)",
|
|
279
|
+
transition: "opacity 0.1s ease, transform 0.1s ease",
|
|
280
|
+
touchAction: "none",
|
|
281
|
+
}, children: [_jsx(Typography, { sx: {
|
|
282
|
+
...typography.bodyMedium,
|
|
283
|
+
color: colors.onSurface,
|
|
284
|
+
opacity: isActive ? 1 : 0.6,
|
|
285
|
+
transition: "opacity 0.15s ease",
|
|
286
|
+
whiteSpace: "nowrap",
|
|
287
|
+
lineHeight: 1,
|
|
288
|
+
}, children: section.label }), _jsx(Box, { component: "span", className: "chevron-toggle", onPointerDown: (e) => {
|
|
289
|
+
e.stopPropagation();
|
|
290
|
+
}, onClick: (e) => {
|
|
291
|
+
e.stopPropagation();
|
|
292
|
+
if (openMenuIndex === index) {
|
|
293
|
+
setOpenMenuIndex(null);
|
|
294
|
+
setMenuAnchorEl(null);
|
|
295
|
+
}
|
|
296
|
+
else {
|
|
297
|
+
setOpenMenuIndex(index);
|
|
298
|
+
setMenuAnchorEl(e.currentTarget);
|
|
299
|
+
}
|
|
300
|
+
}, sx: { display: "flex", alignItems: "center", ml: "4px" }, children: _jsx(IcChevronArrowDarkColor, { sx: {
|
|
301
|
+
width: "16px",
|
|
302
|
+
height: "16px",
|
|
303
|
+
color: colors.onSurface,
|
|
304
|
+
opacity: (isActive || isMobile) ? 1 : 0,
|
|
305
|
+
visibility: isBeingDragged ? "hidden" : "visible",
|
|
306
|
+
transform: openMenuIndex === index ? 'rotate(180deg)' : 'rotate(0deg)',
|
|
307
|
+
transition: 'transform 0.2s ease, opacity 0.15s ease'
|
|
308
|
+
} }) })] }, section.id));
|
|
309
|
+
}), isLoadingMoreSections && (_jsx(Box, { sx: {
|
|
310
|
+
flexShrink: 0,
|
|
311
|
+
display: "flex",
|
|
312
|
+
alignItems: "center",
|
|
313
|
+
height: "44px",
|
|
314
|
+
px: "4px",
|
|
315
|
+
opacity: 0.4,
|
|
316
|
+
}, children: _jsx(Skeleton, { variant: "rectangular", width: 80, height: 24 }) })), _jsxs(Box, { onClick: handleCreateSection, sx: {
|
|
317
|
+
flexShrink: 0,
|
|
318
|
+
display: "flex",
|
|
319
|
+
alignItems: "center",
|
|
320
|
+
cursor: "pointer",
|
|
321
|
+
height: "44px", // FIXED HEIGHT matches the section tabs
|
|
322
|
+
boxSizing: "border-box",
|
|
323
|
+
px: "0px",
|
|
324
|
+
gap: "4px",
|
|
325
|
+
opacity: 0.5,
|
|
326
|
+
"&:hover": {
|
|
327
|
+
opacity: 1,
|
|
328
|
+
},
|
|
329
|
+
transition: "opacity 0.15s ease",
|
|
330
|
+
}, children: [_jsx(IcPlusButton, { sx: { width: "20px", height: "20px" } }), _jsx(Typography, { sx: {
|
|
331
|
+
...typography.labelMedium,
|
|
332
|
+
color: colors.onSurface,
|
|
333
|
+
whiteSpace: "nowrap",
|
|
334
|
+
}, children: "Add section" })] })] })] }), activeSection?.description && (_jsx(Box, { sx: {
|
|
335
|
+
width: "100%",
|
|
336
|
+
px: isMobile ? "18px" : "24px",
|
|
337
|
+
pt: "32px", // Space between tabs and text
|
|
338
|
+
pb: "0px", // Tiny space before filter menu
|
|
339
|
+
}, children: _jsx(Typography, { sx: {
|
|
340
|
+
...typography.bodyMedium,
|
|
341
|
+
color: colors.onSurface, // Subtle grey color for description
|
|
342
|
+
textAlign: "center",
|
|
343
|
+
whiteSpace: "pre-wrap"
|
|
344
|
+
}, children: activeSection.description }) })), _jsxs(Menu, { anchorEl: menuAnchorEl, open: Boolean(menuAnchorEl) && openMenuIndex !== null, onClose: () => {
|
|
345
|
+
setMenuAnchorEl(null);
|
|
346
|
+
setOpenMenuIndex(null);
|
|
347
|
+
}, slotProps: {
|
|
348
|
+
paper: {
|
|
349
|
+
sx: {
|
|
350
|
+
backgroundColor: colors.surface,
|
|
351
|
+
border: "1px solid",
|
|
352
|
+
borderColor: colors.outlineVariant,
|
|
353
|
+
borderRadius: "8px",
|
|
354
|
+
boxShadow: "0px 4px 12px rgba(0,0,0,0.08)",
|
|
355
|
+
minWidth: "105px",
|
|
356
|
+
mt: "4px",
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}, children: [_jsxs(MenuItem, { onClick: () => {
|
|
360
|
+
if (openMenuIndex !== null)
|
|
361
|
+
handleEditSection(openMenuIndex);
|
|
362
|
+
}, sx: { display: "flex", alignItems: "center", py: "10px", px: "16px" }, children: [_jsx(IcPencilIconDark, { sx: { width: "20px", height: "20px", color: colors.onSurface, mr: "8px" } }), _jsx(Typography, { sx: { ...typography.bodyMedium, color: colors.onSurface }, children: "Edit" })] }), _jsxs(MenuItem, { onClick: () => {
|
|
363
|
+
if (openMenuIndex !== null)
|
|
364
|
+
handleDeleteSection(openMenuIndex);
|
|
365
|
+
}, sx: { display: "flex", alignItems: "center", py: "10px", px: "16px" }, children: [_jsx(IcTrashIcon, { sx: { width: "20px", height: "20px", color: colors.error, mr: "8px" } }), _jsx(Typography, { sx: { ...typography.bodyMedium, color: colors.error }, children: "Delete" })] })] }), isDragging && dragIndex !== null && (_jsx(Box, { sx: {
|
|
366
|
+
position: "fixed",
|
|
367
|
+
top: cursorPos.y - 14,
|
|
368
|
+
left: cursorPos.x + 12,
|
|
369
|
+
pointerEvents: "none",
|
|
370
|
+
zIndex: 9999,
|
|
371
|
+
backgroundColor: colors.surface,
|
|
372
|
+
border: "1px solid",
|
|
373
|
+
borderColor: colors.outlineVariant,
|
|
374
|
+
borderRadius: "6px",
|
|
375
|
+
px: "10px",
|
|
376
|
+
py: "6px",
|
|
377
|
+
boxShadow: "0px 4px 12px rgba(0,0,0,0.12)",
|
|
378
|
+
display: "flex",
|
|
379
|
+
alignItems: "center",
|
|
380
|
+
gap: "6px",
|
|
381
|
+
}, children: _jsx(Typography, { sx: {
|
|
382
|
+
...typography.bodyMedium,
|
|
383
|
+
color: colors.onSurface,
|
|
384
|
+
lineHeight: 1,
|
|
385
|
+
whiteSpace: "nowrap",
|
|
386
|
+
}, children: sections[dragIndex]?.label }) })), isCreateSectionDialogOpen && (_jsx(HBaseDialog, { title: "Add section", description:
|
|
387
|
+
// ADDED onKeyDown to stop propagation to the background gallery
|
|
388
|
+
_jsxs(Stack, { spacing: "12px", onKeyDown: (e) => e.stopPropagation(), children: [_jsxs(Box, { sx: { backgroundColor: colors.onSurfaceVariant2, py: "8px", px: "16px", borderRadius: "4px" }, children: [_jsx(Typography, { sx: { ...typography.bodySmall, color: colors.onSurfaceVariant1 }, children: "Section name" }), _jsx(TextField, { autoFocus: true, placeholder: "Enter section name", type: "text", fullWidth: true, variant: "standard", InputProps: { disableUnderline: true }, value: sectionName, onChange: (e) => setSectionName(e.target.value), sx: { "& .MuiInputBase-input": { padding: 0, marginTop: "4px", ...typography.bodyMedium } } })] }), _jsxs(Box, { sx: { backgroundColor: colors.onSurfaceVariant2, py: "8px", px: "16px", borderRadius: "4px" }, children: [_jsx(Typography, { sx: { ...typography.bodySmall, color: colors.onSurfaceVariant1 }, children: "Description (Optional)" }), _jsx(TextField, { placeholder: "Add a description...", type: "text", fullWidth: true, multiline: true, rows: 3, variant: "standard", InputProps: { disableUnderline: true }, value: sectionDescription, onChange: (e) => setSectionDescription(e.target.value), sx: { "& .MuiInputBase-input": { padding: 0, marginTop: "4px", ...typography.bodyMedium } } })] })] }), action: _jsxs(_Fragment, { children: [_jsx(PositiveButton, { text: "Cancel", onClick: () => setIsCreateSectionDialogOpen(false) }), _jsx(PositiveButton, { text: "Save", disabled: !sectionName.trim(), onClick: () => {
|
|
389
|
+
onAddSection(sectionName, sectionDescription);
|
|
390
|
+
setIsCreateSectionDialogOpen(false);
|
|
391
|
+
} })] }) })), isEditDialogOpen && selectedSectionIndex !== null && (_jsx(HBaseDialog, { title: "Edit section", description:
|
|
392
|
+
// ADDED onKeyDown to stop propagation to the background gallery
|
|
393
|
+
_jsxs(Stack, { spacing: "12px", onKeyDown: (e) => e.stopPropagation(), children: [_jsxs(Box, { sx: { backgroundColor: colors.onSurfaceVariant2, py: "8px", px: "16px", borderRadius: "4px" }, children: [_jsx(Typography, { sx: { ...typography.bodySmall, color: colors.onSurfaceVariant1 }, children: "Section name" }), _jsx(TextField, { autoFocus: true, placeholder: "Enter section name", type: "text", fullWidth: true, variant: "standard", InputProps: { disableUnderline: true }, value: sectionName, onChange: (e) => setSectionName(e.target.value), sx: { "& .MuiInputBase-input": { padding: 0, marginTop: "4px", ...typography.bodyMedium } } })] }), _jsxs(Box, { sx: { backgroundColor: colors.onSurfaceVariant2, py: "8px", px: "16px", borderRadius: "4px" }, children: [_jsx(Typography, { sx: { ...typography.bodySmall, color: colors.onSurfaceVariant1 }, children: "Description (Optional)" }), _jsx(TextField, { placeholder: "Add a description...", type: "text", fullWidth: true, multiline: true, rows: 3, variant: "standard", InputProps: { disableUnderline: true }, value: sectionDescription, onChange: (e) => setSectionDescription(e.target.value), sx: { "& .MuiInputBase-input": { padding: 0, marginTop: "4px", ...typography.bodyMedium } } })] })] }), action: _jsxs(_Fragment, { children: [_jsx(PositiveButton, { text: "Cancel", onClick: () => setIsEditDialogOpen(false) }), _jsx(PositiveButton, { text: "Save", disabled: !sectionName.trim(), onClick: () => {
|
|
394
|
+
if (onEditSection) {
|
|
395
|
+
onEditSection(selectedSectionIndex, sectionName, sectionDescription);
|
|
396
|
+
}
|
|
397
|
+
setIsEditDialogOpen(false);
|
|
398
|
+
} })] }) })), isDeleteDialogOpen && selectedSectionIndex !== null && (_jsx(HBaseDialog, { title: "Delete section?", description: "Permanently delete this section and its photos.", action: _jsxs(_Fragment, { children: [_jsx(PositiveButton, { text: "Cancel", onClick: () => setIsDeleteDialogOpen(false) }), _jsx(NegativeButton, { text: "Delete", onClick: () => {
|
|
399
|
+
// 1. Fire the actual delete function
|
|
400
|
+
if (onDeleteSection) {
|
|
401
|
+
onDeleteSection(sections[selectedSectionIndex].id);
|
|
402
|
+
}
|
|
403
|
+
// 2. Adjust the active tab if you are deleting the one you are currently viewing
|
|
404
|
+
const reorderedLength = sections.length - 1;
|
|
405
|
+
const newActive = activeSectionIndex >= reorderedLength
|
|
406
|
+
? Math.max(0, reorderedLength - 1)
|
|
407
|
+
: activeSectionIndex === selectedSectionIndex
|
|
408
|
+
? Math.max(0, selectedSectionIndex - 1)
|
|
409
|
+
: activeSectionIndex;
|
|
410
|
+
onSectionChange(newActive);
|
|
411
|
+
setIsDeleteDialogOpen(false);
|
|
412
|
+
} })] }) }))] }));
|
|
413
|
+
};
|
|
414
|
+
export default AlbumSectionTabs;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type FC } from "react";
|
|
2
|
+
import { AlbumSection } from "./AlbumSectionTabs";
|
|
3
|
+
interface Props {
|
|
4
|
+
sections: AlbumSection[];
|
|
5
|
+
activeSectionIndex: number;
|
|
6
|
+
onSectionChange: (index: number) => void;
|
|
7
|
+
selectedCounts?: Record<string, number>;
|
|
8
|
+
onLoadMore?: () => void;
|
|
9
|
+
isLoadingMoreSections?: boolean;
|
|
10
|
+
hasMoreSections?: boolean;
|
|
11
|
+
isEditorSelectionMode?: boolean;
|
|
12
|
+
}
|
|
13
|
+
declare const AlbumSectionTabsSelectMode: FC<Props>;
|
|
14
|
+
export default AlbumSectionTabsSelectMode;
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useRef, useState, useEffect } from "react";
|
|
3
|
+
import { Box, Typography, Skeleton } from "@mui/material"; // Added Skeleton
|
|
4
|
+
import useHonchoTypography from '../../../themes/honchoTheme';
|
|
5
|
+
import useColors from '../../../themes/colors';
|
|
6
|
+
import useIsMobile from '../../../utils/isMobile';
|
|
7
|
+
import { IcChevronArrowDarkColor, IcChevronArrowLightColor } from "../svg/IcChevron";
|
|
8
|
+
const AlbumSectionTabsSelectMode = ({ sections, activeSectionIndex, onSectionChange, selectedCounts = {}, onLoadMore, isLoadingMoreSections = false, hasMoreSections = false, isEditorSelectionMode = false, }) => {
|
|
9
|
+
const isMobile = useIsMobile();
|
|
10
|
+
const colors = useColors();
|
|
11
|
+
const typography = useHonchoTypography();
|
|
12
|
+
// --- Pagination / Scroll Logic ---
|
|
13
|
+
const scrollRef = useRef(null);
|
|
14
|
+
const [showLeftButton, setShowLeftButton] = useState(false);
|
|
15
|
+
const [showRightButton, setShowRightButton] = useState(false);
|
|
16
|
+
// NEW: Prevent firing multiple load requests at the same scroll position
|
|
17
|
+
const isLoadingMoreRef = useRef(false);
|
|
18
|
+
const checkScrollButtons = () => {
|
|
19
|
+
const el = scrollRef.current;
|
|
20
|
+
if (!el)
|
|
21
|
+
return;
|
|
22
|
+
const { scrollLeft, scrollWidth, clientWidth } = el;
|
|
23
|
+
setShowLeftButton(scrollLeft > 0);
|
|
24
|
+
setShowRightButton(Math.ceil(scrollLeft + clientWidth) < scrollWidth);
|
|
25
|
+
// NEW: Trigger load-more when within 80px of the right edge
|
|
26
|
+
const nearRightEdge = scrollLeft + clientWidth >= scrollWidth - 80;
|
|
27
|
+
if (nearRightEdge && hasMoreSections && !isLoadingMoreSections && !isLoadingMoreRef.current) {
|
|
28
|
+
isLoadingMoreRef.current = true;
|
|
29
|
+
if (onLoadMore)
|
|
30
|
+
onLoadMore();
|
|
31
|
+
}
|
|
32
|
+
if (!nearRightEdge) {
|
|
33
|
+
isLoadingMoreRef.current = false;
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
checkScrollButtons();
|
|
38
|
+
window.addEventListener("resize", checkScrollButtons);
|
|
39
|
+
return () => window.removeEventListener("resize", checkScrollButtons);
|
|
40
|
+
}, [sections, hasMoreSections, isLoadingMoreSections]);
|
|
41
|
+
const handleScroll = (direction) => {
|
|
42
|
+
if (scrollRef.current) {
|
|
43
|
+
const scrollAmount = 200;
|
|
44
|
+
scrollRef.current.scrollBy({
|
|
45
|
+
left: direction === "left" ? -scrollAmount : scrollAmount,
|
|
46
|
+
behavior: "smooth",
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
const onScroll = () => {
|
|
51
|
+
checkScrollButtons();
|
|
52
|
+
};
|
|
53
|
+
// Auto-scroll to active tab when changed
|
|
54
|
+
useEffect(() => {
|
|
55
|
+
if (!scrollRef.current)
|
|
56
|
+
return;
|
|
57
|
+
const timeout = setTimeout(() => {
|
|
58
|
+
const activeTabNode = scrollRef.current?.querySelector(`[data-index="${activeSectionIndex}"]`);
|
|
59
|
+
if (activeTabNode) {
|
|
60
|
+
activeTabNode.scrollIntoView({
|
|
61
|
+
behavior: "smooth",
|
|
62
|
+
block: "nearest",
|
|
63
|
+
inline: "center",
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}, 50);
|
|
67
|
+
return () => clearTimeout(timeout);
|
|
68
|
+
}, [activeSectionIndex]);
|
|
69
|
+
return (_jsxs(Box, { sx: {
|
|
70
|
+
borderBottom: "1px solid",
|
|
71
|
+
borderColor: isEditorSelectionMode ? colors.onSurfaceVariantDark : colors.outlineVariant,
|
|
72
|
+
width: "100%",
|
|
73
|
+
position: "relative",
|
|
74
|
+
left: "50%",
|
|
75
|
+
right: "50%",
|
|
76
|
+
marginLeft: "-50vw",
|
|
77
|
+
marginRight: "-50vw",
|
|
78
|
+
backgroundColor: isEditorSelectionMode ? colors.onBackground : colors.surface,
|
|
79
|
+
display: "flex",
|
|
80
|
+
alignItems: "center",
|
|
81
|
+
}, children: [!isMobile && showLeftButton && (_jsx(Box, { sx: {
|
|
82
|
+
position: "absolute",
|
|
83
|
+
left: 0,
|
|
84
|
+
top: 0,
|
|
85
|
+
bottom: "1px",
|
|
86
|
+
display: "flex",
|
|
87
|
+
alignItems: "center",
|
|
88
|
+
background: isEditorSelectionMode ? colors.onBackground : colors.surface,
|
|
89
|
+
paddingRight: "24px",
|
|
90
|
+
paddingLeft: "16px",
|
|
91
|
+
zIndex: 2,
|
|
92
|
+
}, children: isEditorSelectionMode ?
|
|
93
|
+
_jsx(IcChevronArrowLightColor, { sx: {
|
|
94
|
+
width: "20px",
|
|
95
|
+
height: "20px",
|
|
96
|
+
color: colors.onSurface,
|
|
97
|
+
transform: "rotate(180deg)",
|
|
98
|
+
} }) :
|
|
99
|
+
_jsx(IcChevronArrowDarkColor, { sx: {
|
|
100
|
+
width: "20px",
|
|
101
|
+
height: "20px",
|
|
102
|
+
color: colors.onSurface,
|
|
103
|
+
transform: "rotate(90deg)",
|
|
104
|
+
} }) })), _jsxs(Box, { ref: scrollRef, onScroll: onScroll, sx: {
|
|
105
|
+
display: "flex",
|
|
106
|
+
flexDirection: "row",
|
|
107
|
+
alignItems: "flex-end",
|
|
108
|
+
px: isMobile ? "18px" : "24px",
|
|
109
|
+
gap: "24px",
|
|
110
|
+
overflowX: "auto",
|
|
111
|
+
width: "100%",
|
|
112
|
+
"&::-webkit-scrollbar": { display: "none" },
|
|
113
|
+
msOverflowStyle: "none",
|
|
114
|
+
scrollbarWidth: "none",
|
|
115
|
+
}, children: [sections.map((section, index) => {
|
|
116
|
+
const isActive = index === activeSectionIndex;
|
|
117
|
+
const selectedCount = selectedCounts[section.id] || 0;
|
|
118
|
+
return (_jsxs(Box, { "data-index": index, onClick: () => onSectionChange(index), sx: {
|
|
119
|
+
display: "flex",
|
|
120
|
+
alignItems: "center",
|
|
121
|
+
pb: "12px",
|
|
122
|
+
pt: "12px",
|
|
123
|
+
cursor: "pointer",
|
|
124
|
+
borderBottom: isActive ? "2px solid" : "2px solid transparent",
|
|
125
|
+
borderColor: (isEditorSelectionMode ? (isActive ? colors.background : "transparent") : (isActive ? colors.onSurface : "transparent")),
|
|
126
|
+
whiteSpace: "nowrap",
|
|
127
|
+
transition: "all 0.2s ease-in-out",
|
|
128
|
+
}, children: [_jsx(Typography, { sx: {
|
|
129
|
+
...typography.bodyMedium,
|
|
130
|
+
color: (isEditorSelectionMode ? (isActive ? colors.background : colors.background) : (isActive ? colors.onSurface : colors.onSurfaceVariant1)),
|
|
131
|
+
}, children: section.label }), selectedCount > 0 && (_jsx(Box, { sx: {
|
|
132
|
+
ml: "6px",
|
|
133
|
+
backgroundColor: isEditorSelectionMode ? colors.background : colors.onSurface,
|
|
134
|
+
color: isEditorSelectionMode ? colors.onSurface : colors.surface,
|
|
135
|
+
borderRadius: "10px",
|
|
136
|
+
minWidth: "18px",
|
|
137
|
+
height: "18px",
|
|
138
|
+
display: "flex",
|
|
139
|
+
alignItems: "center",
|
|
140
|
+
justifyContent: "center",
|
|
141
|
+
px: "5px",
|
|
142
|
+
}, children: _jsx(Typography, { sx: {
|
|
143
|
+
...typography.labelSmall,
|
|
144
|
+
color: isEditorSelectionMode ? colors.onSurface : colors.surface,
|
|
145
|
+
lineHeight: 1,
|
|
146
|
+
fontSize: "11px",
|
|
147
|
+
// fontWeight: 600,
|
|
148
|
+
}, children: selectedCount }) }))] }, section.id));
|
|
149
|
+
}), isLoadingMoreSections && (_jsx(Box, { sx: {
|
|
150
|
+
flexShrink: 0,
|
|
151
|
+
display: "flex",
|
|
152
|
+
alignItems: "center",
|
|
153
|
+
height: "44px",
|
|
154
|
+
px: "4px",
|
|
155
|
+
opacity: 0.4,
|
|
156
|
+
}, children: _jsx(Skeleton, { variant: "rectangular", width: 80, height: 24 }) }))] }), !isMobile && showRightButton && (_jsx(Box, { onClick: () => handleScroll("right"), sx: {
|
|
157
|
+
position: "absolute",
|
|
158
|
+
right: 0,
|
|
159
|
+
top: 0,
|
|
160
|
+
bottom: "1px",
|
|
161
|
+
display: "flex",
|
|
162
|
+
alignItems: "center",
|
|
163
|
+
background: isEditorSelectionMode ? colors.onBackground : colors.surface,
|
|
164
|
+
paddingLeft: "24px",
|
|
165
|
+
paddingRight: "16px",
|
|
166
|
+
zIndex: 2,
|
|
167
|
+
}, children: isEditorSelectionMode ?
|
|
168
|
+
_jsx(IcChevronArrowLightColor, { sx: {
|
|
169
|
+
width: "20px",
|
|
170
|
+
height: "20px",
|
|
171
|
+
color: colors.onSurface,
|
|
172
|
+
} }) :
|
|
173
|
+
_jsx(IcChevronArrowDarkColor, { sx: {
|
|
174
|
+
width: "20px",
|
|
175
|
+
height: "20px",
|
|
176
|
+
color: colors.onSurface,
|
|
177
|
+
transform: "rotate(270deg)",
|
|
178
|
+
} }) }))] }));
|
|
179
|
+
};
|
|
180
|
+
export default AlbumSectionTabsSelectMode;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import React, { ReactElement } from "react";
|
|
2
|
+
interface Props {
|
|
3
|
+
title: React.ReactNode;
|
|
4
|
+
description: React.ReactNode | ReactElement;
|
|
5
|
+
onClose?: () => void;
|
|
6
|
+
action?: React.ReactNode;
|
|
7
|
+
paddingTop?: string;
|
|
8
|
+
hasFullWidthContent?: boolean;
|
|
9
|
+
isCentered?: boolean;
|
|
10
|
+
}
|
|
11
|
+
export declare function HBaseDialog(props: Props): import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
export declare function HBaseDialogMiddle(props: Props): import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
interface ButtonProps {
|
|
14
|
+
text: string;
|
|
15
|
+
onClick: () => void;
|
|
16
|
+
color?: string;
|
|
17
|
+
backgroundColor?: string;
|
|
18
|
+
backgroundColorHover?: string;
|
|
19
|
+
padding?: string;
|
|
20
|
+
disabled?: boolean;
|
|
21
|
+
}
|
|
22
|
+
export declare function PositiveButton(props: ButtonProps): import("react/jsx-runtime").JSX.Element;
|
|
23
|
+
export declare function NegativeButton(props: ButtonProps): import("react/jsx-runtime").JSX.Element;
|
|
24
|
+
export {};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Button, Dialog, DialogActions, DialogContent, IconButton, Stack, Typography, Box, } from "@mui/material";
|
|
3
|
+
import useColors from '../../../themes/colors';
|
|
4
|
+
import { CloseOutlined } from "@mui/icons-material";
|
|
5
|
+
export function HBaseDialog(props) {
|
|
6
|
+
const colors = useColors();
|
|
7
|
+
return (_jsxs(Dialog, { disableScrollLock: true, open: true, onClose: () => { }, "aria-labelledby": "responsive-dialog-title", PaperProps: {
|
|
8
|
+
sx: {
|
|
9
|
+
borderRadius: "28px",
|
|
10
|
+
// Shrink the max-width and width if it is centered
|
|
11
|
+
maxWidth: props.isCentered
|
|
12
|
+
? { xs: 328, sm: "260px", md: "260px" }
|
|
13
|
+
: { xs: 328, sm: "456px", md: "456px" },
|
|
14
|
+
width: props.isCentered
|
|
15
|
+
? { xs: "328px", sm: "260px", md: "260px" }
|
|
16
|
+
: { xs: "328px", sm: "456px", md: "456px" },
|
|
17
|
+
margin: { xs: 0, sm: "auto" },
|
|
18
|
+
},
|
|
19
|
+
}, children: [_jsx(DialogContent, { sx: { padding: props.hasFullWidthContent
|
|
20
|
+
? { xs: "24px 0 0 0", sm: "24px 0 0 0" }
|
|
21
|
+
: { xs: "24px 24px 0 24px", sm: "24px 24px 0 24px" }
|
|
22
|
+
}, children: _jsxs(Stack, { spacing: 2, direction: "column", children: [_jsxs(Stack, { direction: "row", alignItems: "center", justifyContent: props.isCentered ? "center" : "space-between", position: props.isCentered ? "relative" : undefined, sx: {
|
|
23
|
+
px: props.hasFullWidthContent
|
|
24
|
+
? { xs: "24px", sm: "24px" }
|
|
25
|
+
: 0
|
|
26
|
+
}, children: [_jsx(Typography, { color: colors.onSurface, textAlign: props.isCentered ? "center" : "left", variant: "labelLarge", children: props.title }), props.onClose && (props.isCentered ? (_jsx(Box, { sx: { position: "absolute", right: 0 }, children: _jsx(CloseButton, { onClick: props.onClose }) })) : (_jsx(CloseButton, { onClick: props.onClose })))] }), _jsx(Typography, { variant: "bodyMedium", textAlign: props.isCentered ? "center" : "left", color: colors.onSurface, children: props.description })] }) }), props.action && (_jsx(DialogActions, { sx: { padding: 3, pt: props.paddingTop || "24px" }, children: _jsx(Stack, { direction: "row", justifyContent: props.isCentered ? "center" : "flex-end", alignItems: "center", gap: 1, sx: props.isCentered ? { width: "100%" } : {}, children: props.action }) }))] }));
|
|
27
|
+
}
|
|
28
|
+
export function HBaseDialogMiddle(props) {
|
|
29
|
+
const colors = useColors();
|
|
30
|
+
return (_jsx(Dialog, { disableScrollLock: true, open: true, onClose: () => { }, "aria-labelledby": "responsive-dialog-title", PaperProps: {
|
|
31
|
+
sx: {
|
|
32
|
+
borderRadius: "28px",
|
|
33
|
+
maxWidth: { xs: 328, sm: "456px", md: "456px" },
|
|
34
|
+
width: { xs: "328px", sm: "456px", md: "456px" },
|
|
35
|
+
//maxHeight: 306,
|
|
36
|
+
margin: { xs: 0, sm: "auto" },
|
|
37
|
+
pb: "24px"
|
|
38
|
+
},
|
|
39
|
+
}, children: _jsx(DialogContent, { sx: { padding: props.hasFullWidthContent
|
|
40
|
+
? { xs: "24px 0 0 0", sm: "24px 0 0 0" }
|
|
41
|
+
: { xs: "24px 24px 0 24px", sm: "24px 24px 0 24px" }
|
|
42
|
+
}, children: _jsxs(Stack, { spacing: 2, direction: "column", alignItems: "center", children: [_jsxs(Stack, { direction: "row", alignItems: "center", justifyContent: props.onClose ? "space-between" : "center", sx: {
|
|
43
|
+
px: props.hasFullWidthContent
|
|
44
|
+
? { xs: "24px", sm: "24px" }
|
|
45
|
+
: 0,
|
|
46
|
+
width: "100%"
|
|
47
|
+
}, children: [_jsx(Typography, { color: colors.onSurface, variant: "labelLarge", children: props.title }), props.onClose && (_jsx(CloseButton, { onClick: props.onClose }))] }), _jsx(Typography, { variant: "bodyMedium", color: colors.onSurface, textAlign: "center", children: props.description }), props.action && (_jsx(Stack, { direction: "row", justifyContent: "center", alignItems: "center", gap: 1, sx: { pt: 1 }, children: props.action }))] }) }) }));
|
|
48
|
+
}
|
|
49
|
+
export function PositiveButton(props) {
|
|
50
|
+
const colors = useColors();
|
|
51
|
+
return (_jsx(Button, { variant: "text", disabled: props.disabled, sx: {
|
|
52
|
+
padding: props.padding,
|
|
53
|
+
":hover": {
|
|
54
|
+
backgroundColor: "transparent",
|
|
55
|
+
},
|
|
56
|
+
}, onClick: props.onClick, children: _jsx(Typography, { variant: "buttonMedium",
|
|
57
|
+
// Change color if disabled so the UI reflects the locked state
|
|
58
|
+
color: props.disabled ? "text.disabled" : colors.onSurface, children: props.text }) }));
|
|
59
|
+
}
|
|
60
|
+
export function NegativeButton(props) {
|
|
61
|
+
const colors = useColors();
|
|
62
|
+
return (_jsx(Button, { variant: "text", disabled: props.disabled, sx: {
|
|
63
|
+
borderRadius: 100,
|
|
64
|
+
// Change color if disabled so the UI reflects the locked state
|
|
65
|
+
color: props.disabled ? "text.disabled" : (props.color || colors.error),
|
|
66
|
+
backgroundColor: props.backgroundColor || "transparent",
|
|
67
|
+
padding: props.padding,
|
|
68
|
+
":hover": {
|
|
69
|
+
backgroundColor: props.backgroundColorHover || "transparent",
|
|
70
|
+
},
|
|
71
|
+
}, onClick: props.onClick, children: props.text }));
|
|
72
|
+
}
|
|
73
|
+
function CloseButton(props) {
|
|
74
|
+
return (_jsx(IconButton, { onClick: props.onClick, children: _jsx(CloseOutlined, { htmlColor: "black" }) }));
|
|
75
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { SvgIconProps } from '@mui/material';
|
|
2
|
+
export declare function IcChevronDown(props: SvgIconProps): import("react/jsx-runtime").JSX.Element;
|
|
3
|
+
export declare function IcChevronUp(props: SvgIconProps): import("react/jsx-runtime").JSX.Element;
|
|
4
|
+
export declare function IcChevronArrowDarkColor(props: SvgIconProps): import("react/jsx-runtime").JSX.Element;
|
|
5
|
+
export declare function IcChevronArrowLightColor(props: SvgIconProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { SvgIcon } from '@mui/material';
|
|
3
|
+
export function IcChevronDown(props) {
|
|
4
|
+
return (_jsx(SvgIcon, { ...props, viewBox: "0 0 20 20", children: _jsx("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: _jsx("path", { d: "M4.16406 7.5L9.9974 13.3333L15.8307 7.5", stroke: "#656369", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) }) }));
|
|
5
|
+
}
|
|
6
|
+
;
|
|
7
|
+
export function IcChevronUp(props) {
|
|
8
|
+
return (_jsx(SvgIcon, { ...props, viewBox: "0 0 20 20", children: _jsxs("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [_jsx("g", { clipPath: "url(#clip0_25667_16969)", children: _jsx("path", { d: "M9.9974 1.66797C12.0818 3.94993 13.2664 6.91133 13.3307 10.0013C13.2664 13.0913 12.0818 16.0527 9.9974 18.3346M9.9974 1.66797C7.913 3.94993 6.72844 6.91133 6.66406 10.0013C6.72844 13.0913 7.913 16.0527 9.9974 18.3346M9.9974 1.66797C5.39502 1.66797 1.66406 5.39893 1.66406 10.0013C1.66406 14.6037 5.39502 18.3346 9.9974 18.3346M9.9974 1.66797C14.5998 1.66797 18.3307 5.39893 18.3307 10.0013C18.3307 14.6037 14.5998 18.3346 9.9974 18.3346M2.08075 7.5013H17.9141M2.08073 12.5013H17.9141", stroke: "white", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) }), _jsx("defs", { children: _jsx("clipPath", { id: "clip0_25667_16969", children: _jsx("rect", { width: "20", height: "20", fill: "white" }) }) })] }) }));
|
|
9
|
+
}
|
|
10
|
+
export function IcChevronArrowDarkColor(props) {
|
|
11
|
+
return (_jsx(SvgIcon, { ...props, viewBox: "0 0 20 20", children: _jsx("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: _jsx("path", { d: "M4.16406 7.5L9.9974 13.3333L15.8307 7.5", stroke: "#1C1B1F", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) }) }));
|
|
12
|
+
}
|
|
13
|
+
export function IcChevronArrowLightColor(props) {
|
|
14
|
+
return (_jsx(SvgIcon, { ...props, viewBox: "0 0 20 20", children: _jsx("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: _jsx("path", { d: "M7.5 15.8307L13.3333 9.9974L7.5 4.16406", stroke: "white", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) }) }));
|
|
15
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { SvgIcon } from '@mui/material';
|
|
3
|
+
export function IcPencilIconWhite(props) {
|
|
4
|
+
return (_jsx(SvgIcon, { ...props, viewBox: "0 0 20 20", children: _jsx("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: _jsx("path", { d: "M14.5289 8.57532L11.4247 5.47109M2.5 17.5L5.12647 17.2082C5.44736 17.1725 5.6078 17.1547 5.75777 17.1061C5.89082 17.0631 6.01744 17.0022 6.13419 16.9252C6.26579 16.8384 6.37994 16.7243 6.60824 16.496L16.8571 6.24715C17.7143 5.38993 17.7143 4.00012 16.8571 3.14291C15.9999 2.2857 14.6101 2.2857 13.7529 3.14291L3.50401 13.3918C3.27571 13.6201 3.16155 13.7342 3.07478 13.8658C2.99779 13.9826 2.93693 14.1092 2.89386 14.2422C2.84531 14.3922 2.82748 14.5526 2.79183 14.8735L2.5 17.5Z", stroke: "white", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) }) }));
|
|
5
|
+
}
|
|
6
|
+
;
|
|
7
|
+
export function IcPencilIconDark(props) {
|
|
8
|
+
return (_jsx(SvgIcon, { ...props, viewBox: "0 0 20 20", children: _jsx("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: _jsx("path", { d: "M14.5289 8.57532L11.4247 5.47109M2.5 17.5L5.12647 17.2082C5.44736 17.1725 5.6078 17.1547 5.75777 17.1061C5.89082 17.0631 6.01744 17.0022 6.13419 16.9252C6.26579 16.8384 6.37994 16.7243 6.60824 16.496L16.8571 6.24715C17.7143 5.38993 17.7143 4.00012 16.8571 3.14291C15.9999 2.2857 14.6101 2.2857 13.7529 3.14291L3.50401 13.3918C3.27571 13.6201 3.16155 13.7342 3.07478 13.8658C2.99779 13.9826 2.93693 14.1092 2.89386 14.2422C2.84531 14.3922 2.82748 14.5526 2.79183 14.8735L2.5 17.5Z", stroke: "#1C1B1F", strokeWidth: "1.25", strokeLinecap: "round", strokeLinejoin: "round" }) }) }));
|
|
9
|
+
}
|
|
10
|
+
;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { SvgIcon } from "@mui/material";
|
|
3
|
+
export default function IcPlusButton(props) {
|
|
4
|
+
return (_jsx(SvgIcon, { ...props, children: _jsx("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: _jsx("path", { d: "M10.0013 4.16602V15.8327M4.16797 9.99935H15.8346", stroke: "#1C1B1F", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) }) }));
|
|
5
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { SvgIcon } from '@mui/material';
|
|
3
|
+
export function IcTrashIcon(props) {
|
|
4
|
+
return (_jsx(SvgIcon, { ...props, viewBox: "0 0 20 20", children: _jsx("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: _jsx("path", { d: "M7.5 2.5H12.5M2.5 5H17.5M15.8333 5L15.2489 13.7661C15.1612 15.0813 15.1174 15.7389 14.8333 16.2375C14.5833 16.6765 14.206 17.0294 13.7514 17.2497C13.235 17.5 12.5759 17.5 11.2578 17.5H8.74221C7.42409 17.5 6.76503 17.5 6.24861 17.2497C5.79396 17.0294 5.41674 16.6765 5.16665 16.2375C4.88259 15.7389 4.83875 15.0813 4.75107 13.7661L4.16667 5", stroke: "#DC362E", strokeWidth: "1.25", strokeLinecap: "round", strokeLinejoin: "round" }) }) }));
|
|
5
|
+
}
|
|
6
|
+
;
|
package/dist/index.d.ts
CHANGED
|
@@ -35,11 +35,14 @@ export { default as HModalDialog } from './components/modal/HModalDialog';
|
|
|
35
35
|
export { default as HModalRename } from './components/modal/HModalRename';
|
|
36
36
|
export { default as HTabColorAdjustmentMobile } from './components/editor/HTabColorAdjustmentMobile';
|
|
37
37
|
export { default as HTabPresetMobile } from './components/editor/HTabPresetMobile';
|
|
38
|
+
export { default as AlbumSectionTabsSelectMode } from './components/editor/SectionAlbum/AlbumSectionTabsSelectMode';
|
|
39
|
+
export { default as AlbumSectionTabs } from './components/editor/SectionAlbum/AlbumSectionTabs';
|
|
38
40
|
export { useAdjustmentHistory, type UseAdjustmentHistoryReturn, type HistoryInfo, type HistoryActions, type HistoryConfig } from './hooks/useAdjustmentHistory';
|
|
39
41
|
export { useAdjustmentHistoryBatch, type UseAdjustmentHistoryBatchReturn, type BatchAdjustmentState, type ImageAdjustmentConfig, type BatchHistoryActions, type BatchHistoryState, type HistoryAdjustmentBatch, type HistoryAdjustmentEntry } from './hooks/useAdjustmentHistoryBatch';
|
|
40
42
|
export { usePreset, type UsePresetReturn, type PresetInfo, type PresetActions, type PresetOptions } from './hooks/usePreset';
|
|
41
43
|
export { usePaging, type UsePagingReturn, type PagingInfo, type PagingActions, type PagingOptions } from './hooks/usePaging';
|
|
42
44
|
export { default as useColors } from './themes/colors';
|
|
45
|
+
export { default as useColorsSecond } from './themes/colours';
|
|
43
46
|
export { default as useHonchoTypography } from './themes/honchoTheme';
|
|
44
47
|
export { default as useIsMobile } from './utils/isMobile';
|
|
45
48
|
export { default as useSliderEvents } from './components/editor/sliderComponents/useSliderEvents';
|
package/dist/index.js
CHANGED
|
@@ -37,6 +37,8 @@ export { default as HModalDialog } from './components/modal/HModalDialog';
|
|
|
37
37
|
export { default as HModalRename } from './components/modal/HModalRename';
|
|
38
38
|
export { default as HTabColorAdjustmentMobile } from './components/editor/HTabColorAdjustmentMobile';
|
|
39
39
|
export { default as HTabPresetMobile } from './components/editor/HTabPresetMobile';
|
|
40
|
+
export { default as AlbumSectionTabsSelectMode } from './components/editor/SectionAlbum/AlbumSectionTabsSelectMode';
|
|
41
|
+
export { default as AlbumSectionTabs } from './components/editor/SectionAlbum/AlbumSectionTabs';
|
|
40
42
|
// --- History Hooks ---
|
|
41
43
|
export { useAdjustmentHistory } from './hooks/useAdjustmentHistory';
|
|
42
44
|
export { useAdjustmentHistoryBatch } from './hooks/useAdjustmentHistoryBatch';
|
|
@@ -46,6 +48,7 @@ export { usePreset } from './hooks/usePreset';
|
|
|
46
48
|
export { usePaging } from './hooks/usePaging';
|
|
47
49
|
// --- Theme & Utils ---
|
|
48
50
|
export { default as useColors } from './themes/colors';
|
|
51
|
+
export { default as useColorsSecond } from './themes/colours';
|
|
49
52
|
export { default as useHonchoTypography } from './themes/honchoTheme';
|
|
50
53
|
export { default as useIsMobile } from './utils/isMobile';
|
|
51
54
|
export { default as useSliderEvents } from './components/editor/sliderComponents/useSliderEvents';
|
package/dist/themes/colors.d.ts
CHANGED
|
@@ -3,10 +3,12 @@ interface Colors {
|
|
|
3
3
|
surface: string;
|
|
4
4
|
onSurfaceVariant: string;
|
|
5
5
|
onSurfaceVariant1: string;
|
|
6
|
+
onSurfaceVariantDark: string;
|
|
6
7
|
outlineVariant: string;
|
|
7
8
|
error: string;
|
|
8
9
|
onBackground: string;
|
|
9
10
|
background: string;
|
|
11
|
+
surfaceVariant2: string;
|
|
10
12
|
}
|
|
11
13
|
export default function useColors(): Colors;
|
|
12
14
|
export {};
|
package/dist/themes/colors.js
CHANGED
|
@@ -4,9 +4,11 @@ export default function useColors() {
|
|
|
4
4
|
surface: "#FFFFFF",
|
|
5
5
|
onSurfaceVariant: "#949494",
|
|
6
6
|
onSurfaceVariant1: "#656369",
|
|
7
|
+
onSurfaceVariantDark: "#2E2E2E",
|
|
7
8
|
outlineVariant: "#EDEDED",
|
|
8
9
|
error: "#DC362E",
|
|
9
10
|
onBackground: "#000000",
|
|
10
|
-
background: "#FFFFFF"
|
|
11
|
+
background: "#FFFFFF",
|
|
12
|
+
surfaceVariant2: "#F6F6F6"
|
|
11
13
|
};
|
|
12
14
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
interface Colors {
|
|
2
|
+
onSurface: string;
|
|
3
|
+
surface: string;
|
|
4
|
+
onSurfaceVariant: string;
|
|
5
|
+
onSurfaceVariant1: string;
|
|
6
|
+
onSurfaceVariant2: string;
|
|
7
|
+
onSurfaceVariantDark: string;
|
|
8
|
+
outlineVariant: string;
|
|
9
|
+
error: string;
|
|
10
|
+
onBackground: string;
|
|
11
|
+
background: string;
|
|
12
|
+
}
|
|
13
|
+
export default function useColorsSecond(): Colors;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export default function useColorsSecond() {
|
|
2
|
+
return {
|
|
3
|
+
onSurface: "#1C1B1F",
|
|
4
|
+
surface: "#FFFFFF",
|
|
5
|
+
onSurfaceVariant: "#949494",
|
|
6
|
+
onSurfaceVariant1: "#656369",
|
|
7
|
+
onSurfaceVariant2: "#F6F6F6",
|
|
8
|
+
onSurfaceVariantDark: "#2E2E2E",
|
|
9
|
+
outlineVariant: "#EDEDED",
|
|
10
|
+
error: "#DC362E",
|
|
11
|
+
onBackground: "#000000",
|
|
12
|
+
background: "#FFFFFF"
|
|
13
|
+
};
|
|
14
|
+
}
|