@loafmarkets/ui 0.1.402 → 0.1.403

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/index.mjs CHANGED
@@ -18881,13 +18881,14 @@ var CloseButton3 = styled10.button`
18881
18881
  var MainImageContainer = styled10.div`
18882
18882
  position: relative;
18883
18883
  flex: 1;
18884
+ min-height: 0;
18884
18885
  display: flex;
18885
18886
  align-items: center;
18886
18887
  justify-content: center;
18887
- padding: 80px 20px 140px;
18888
+ padding: 20px 20px 160px;
18888
18889
 
18889
18890
  @media (max-width: 768px) {
18890
- padding: 60px 0 110px;
18891
+ padding: 10px 0 130px;
18891
18892
  }
18892
18893
  `;
18893
18894
  var MainImage = styled10.img`
@@ -18899,8 +18900,11 @@ var MainImage = styled10.img`
18899
18900
  opacity: ${(p) => p.$visible ? 1 : 0};
18900
18901
  pointer-events: ${(p) => p.$visible ? "auto" : "none"};
18901
18902
  transition: opacity 300ms ease;
18902
- /* Inset box excludes the bottom thumbnail strip so margin:auto centres the image in the
18903
- space ABOVE the thumbnails (absolute ignores the parent's padding). */
18903
+ /* All slides share the same absolute box so switching only crossfades opacity
18904
+ no relative↔absolute size jump (the "grow then shrink" on navigation).
18905
+ The inset box excludes the bottom thumbnail strip so margin:auto centres the image
18906
+ in the space ABOVE the thumbnails (absolute positioning ignores the parent's padding,
18907
+ which otherwise let the image sink behind the thumbnails / "lean down"). */
18904
18908
  position: absolute;
18905
18909
  top: 24px;
18906
18910
  left: 24px;
@@ -19094,9 +19098,11 @@ function PropertyPhotoGallery({
19094
19098
  isOpen,
19095
19099
  onClose,
19096
19100
  startIndex = 0,
19101
+ startWithVideo = false,
19097
19102
  title = "28 Derby Street, Vaucluse",
19098
19103
  subtitle = "Elara \u2014 Luxury Harbour Residence",
19099
- images
19104
+ images,
19105
+ videoUrl
19100
19106
  }) {
19101
19107
  const galleryImages = images?.length ? images : DEFAULT_IMAGES;
19102
19108
  if (!isOpen) return null;
@@ -19105,16 +19111,19 @@ function PropertyPhotoGallery({
19105
19111
  {
19106
19112
  galleryImages,
19107
19113
  startIndex,
19114
+ startWithVideo,
19108
19115
  title,
19109
19116
  subtitle,
19110
- onClose
19117
+ onClose,
19118
+ videoUrl
19111
19119
  },
19112
- `${startIndex}-${galleryImages.length}`
19120
+ `${startIndex}-${galleryImages.length}-${startWithVideo}`
19113
19121
  );
19114
19122
  }
19115
- function GalleryContent({ galleryImages, startIndex, title, subtitle, onClose }) {
19123
+ function GalleryContent({ galleryImages, startIndex, startWithVideo, title, subtitle, onClose, videoUrl }) {
19116
19124
  const [currentIndex, setCurrentIndex] = useState(() => clampIndex(startIndex, galleryImages.length));
19117
19125
  const [activeHotspotId, setActiveHotspotId] = useState(null);
19126
+ const [showVideo, setShowVideo] = useState(startWithVideo ?? false);
19118
19127
  const sliderRef = useRef(null);
19119
19128
  const [isDragging, setIsDragging] = useState(false);
19120
19129
  const wasDraggingRef = useRef(false);
@@ -19164,7 +19173,7 @@ function GalleryContent({ galleryImages, startIndex, title, subtitle, onClose })
19164
19173
  ] }),
19165
19174
  /* @__PURE__ */ jsx(CloseButton3, { onClick: onClose, "aria-label": "Close gallery", children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", width: "22", height: "22", fill: "none", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsx("path", { d: "M6 6l12 12M6 18L18 6" }) }) })
19166
19175
  ] }),
19167
- /* @__PURE__ */ jsxs(SliderContainer, { onClick: (event) => event.stopPropagation(), children: [
19176
+ !showVideo && /* @__PURE__ */ jsxs(SliderContainer, { onClick: (event) => event.stopPropagation(), children: [
19168
19177
  /* @__PURE__ */ jsxs(
19169
19178
  SliderTrack,
19170
19179
  {
@@ -19227,7 +19236,21 @@ function GalleryContent({ galleryImages, startIndex, title, subtitle, onClose })
19227
19236
  children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", width: "22", height: "22", fill: "none", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsx("path", { d: "M15 18l-6-6 6-6" }) })
19228
19237
  }
19229
19238
  ),
19230
- galleryImages.map((image, idx) => /* @__PURE__ */ jsx(MainImage, { src: image.src, alt: image.alt, $visible: idx === currentIndex }, image.alt)),
19239
+ showVideo && videoUrl ? /* @__PURE__ */ jsx(GalleryVideoWrap, { children: /* @__PURE__ */ jsx(
19240
+ "video",
19241
+ {
19242
+ autoPlay: true,
19243
+ loop: true,
19244
+ playsInline: true,
19245
+ muted: true,
19246
+ controls: true,
19247
+ onVolumeChange: (e) => {
19248
+ if (!e.currentTarget.muted) e.currentTarget.muted = true;
19249
+ },
19250
+ style: { objectFit: "contain", borderRadius: 12, boxShadow: "0 30px 80px rgba(0,0,0,0.55)" },
19251
+ children: /* @__PURE__ */ jsx("source", { src: videoUrl, type: "video/mp4" })
19252
+ }
19253
+ ) }) : galleryImages.map((image, idx) => /* @__PURE__ */ jsx(MainImage, { src: image.src, alt: image.alt, $visible: idx === currentIndex }, image.alt)),
19231
19254
  galleryImages[currentIndex]?.hotspots?.map((hotspot) => /* @__PURE__ */ jsx(
19232
19255
  Hotspot,
19233
19256
  {
@@ -19272,11 +19295,83 @@ function GalleryContent({ galleryImages, startIndex, title, subtitle, onClose })
19272
19295
  ]
19273
19296
  }
19274
19297
  ),
19275
- /* @__PURE__ */ jsx(ThumbnailStrip, { onClick: (event) => event.stopPropagation(), children: galleryImages.map((image, idx) => /* @__PURE__ */ jsx(Thumbnail3, { $active: idx === currentIndex, onClick: () => setCurrentIndex(idx), "aria-label": `Preview ${image.label}`, children: /* @__PURE__ */ jsx("img", { src: image.src, alt: image.alt }) }, image.alt)) })
19298
+ /* @__PURE__ */ jsxs(ThumbnailStrip, { onClick: (event) => event.stopPropagation(), children: [
19299
+ galleryImages.map((image, idx) => /* @__PURE__ */ jsx(Thumbnail3, { $active: !showVideo && idx === currentIndex, onClick: () => {
19300
+ setShowVideo(false);
19301
+ setCurrentIndex(idx);
19302
+ }, "aria-label": `Preview ${image.label}`, children: /* @__PURE__ */ jsx("img", { src: image.src, alt: image.alt }) }, image.alt)),
19303
+ videoUrl && /* @__PURE__ */ jsxs(Fragment, { children: [
19304
+ /* @__PURE__ */ jsx(ThumbnailDivider, {}),
19305
+ /* @__PURE__ */ jsxs(VideoBtn, { $active: showVideo, onClick: () => setShowVideo(true), children: [
19306
+ /* @__PURE__ */ jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
19307
+ /* @__PURE__ */ jsx("rect", { x: "2", y: "4", width: "14", height: "16", rx: "2" }),
19308
+ /* @__PURE__ */ jsx("path", { d: "M16 8l6-4v16l-6-4z" })
19309
+ ] }),
19310
+ "Video"
19311
+ ] })
19312
+ ] })
19313
+ ] })
19276
19314
  ]
19277
19315
  }
19278
19316
  );
19279
19317
  }
19318
+ var GalleryVideoWrap = styled10.div`
19319
+ position: absolute;
19320
+ inset: 0;
19321
+ display: flex;
19322
+ align-items: center;
19323
+ justify-content: center;
19324
+ padding: 20px 20px 160px;
19325
+
19326
+ video {
19327
+ max-width: 90%;
19328
+ max-height: 100%;
19329
+ }
19330
+
19331
+ /* Property videos stay permanently muted — remove the volume + mute buttons
19332
+ from the native player (Chrome/Edge/Safari/iOS/Android). Firefox ignores
19333
+ these and is covered by the onVolumeChange force-mute fallback. */
19334
+ video::-webkit-media-controls-mute-button,
19335
+ video::-webkit-media-controls-volume-slider,
19336
+ video::-webkit-media-controls-volume-control-container {
19337
+ display: none !important;
19338
+ }
19339
+
19340
+ @media (max-width: 768px) {
19341
+ padding: 10px 0 130px;
19342
+
19343
+ video {
19344
+ max-width: 100%;
19345
+ }
19346
+ }
19347
+ `;
19348
+ var ThumbnailDivider = styled10.div`
19349
+ width: 1px;
19350
+ height: 48px;
19351
+ background: rgba(255, 255, 255, 0.15);
19352
+ flex-shrink: 0;
19353
+ align-self: center;
19354
+ `;
19355
+ var VideoBtn = styled10.button`
19356
+ display: flex;
19357
+ align-items: center;
19358
+ gap: 6px;
19359
+ padding: 8px 14px;
19360
+ border-radius: 8px;
19361
+ border: 1px solid ${(p) => p.$active ? "var(--color-accent, #E6C87E)" : "rgba(255, 255, 255, 0.2)"};
19362
+ background: ${(p) => p.$active ? "rgba(240, 185, 11, 0.15)" : "rgba(255, 255, 255, 0.08)"};
19363
+ color: ${(p) => p.$active ? "var(--color-accent, #E6C87E)" : "#fff"};
19364
+ font-size: 0.82rem;
19365
+ font-weight: 500;
19366
+ cursor: pointer;
19367
+ flex-shrink: 0;
19368
+ transition: all 0.2s ease;
19369
+
19370
+ &:hover {
19371
+ background: rgba(255, 255, 255, 0.15);
19372
+ border-color: rgba(255, 255, 255, 0.3);
19373
+ }
19374
+ `;
19280
19375
  var slideIn2 = keyframes`
19281
19376
  from { transform: translateX(110%); opacity: 0; }
19282
19377
  to { transform: translateX(0); opacity: 1; }