@opensite/ui 3.10.0 → 3.11.0
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/instagram-post-grid.cjs +287 -112
- package/dist/instagram-post-grid.d.cts +34 -11
- package/dist/instagram-post-grid.d.ts +34 -11
- package/dist/instagram-post-grid.js +287 -112
- package/dist/registry.cjs +290 -112
- package/dist/registry.js +290 -112
- package/package.json +2 -1
|
@@ -2,11 +2,9 @@
|
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
var React = require('react');
|
|
5
|
+
var mediaImmersive = require('@page-speed/media-immersive');
|
|
5
6
|
var clsx = require('clsx');
|
|
6
7
|
var tailwindMerge = require('tailwind-merge');
|
|
7
|
-
var img = require('@page-speed/img');
|
|
8
|
-
var video = require('@page-speed/video');
|
|
9
|
-
var pressable = require('@page-speed/pressable');
|
|
10
8
|
var icon = require('@page-speed/icon');
|
|
11
9
|
var jsxRuntime = require('react/jsx-runtime');
|
|
12
10
|
|
|
@@ -423,23 +421,276 @@ var Section = React__namespace.default.forwardRef(
|
|
|
423
421
|
}
|
|
424
422
|
);
|
|
425
423
|
Section.displayName = "Section";
|
|
426
|
-
|
|
424
|
+
var IG_TILE_WIDTH = 320;
|
|
425
|
+
var IG_TILE_STYLE = { width: "100%" };
|
|
426
|
+
var TITLE_MAX = 90;
|
|
427
|
+
function truncate(text, max = TITLE_MAX) {
|
|
428
|
+
const trimmed = text.trim();
|
|
429
|
+
if (trimmed.length <= max) return trimmed;
|
|
430
|
+
const slice = trimmed.slice(0, max);
|
|
431
|
+
const lastSpace = slice.lastIndexOf(" ");
|
|
432
|
+
const head = lastSpace > max * 0.6 ? slice.slice(0, lastSpace) : slice;
|
|
433
|
+
return `${head.trimEnd()}\u2026`;
|
|
434
|
+
}
|
|
435
|
+
function captionToString(caption) {
|
|
436
|
+
return typeof caption === "string" ? caption : "";
|
|
437
|
+
}
|
|
438
|
+
function toMediaItem(item) {
|
|
439
|
+
const isVideo = Boolean(item.isVideo && item.videoUrl);
|
|
440
|
+
const fullCaption = captionToString(item.caption);
|
|
441
|
+
const title = truncate(fullCaption) || item.imageAlt || "Instagram post";
|
|
442
|
+
const meta = {
|
|
443
|
+
href: item.href,
|
|
444
|
+
likeCount: item.likeCount,
|
|
445
|
+
commentCount: item.commentCount,
|
|
446
|
+
viewCount: item.viewCount,
|
|
447
|
+
date: item.date
|
|
448
|
+
};
|
|
449
|
+
return {
|
|
450
|
+
id: item.id,
|
|
451
|
+
type: isVideo ? "video" : "image",
|
|
452
|
+
poster: item.image,
|
|
453
|
+
// Video source only when the post is a real video (image posts ignore it).
|
|
454
|
+
src: isVideo ? item.videoUrl : void 0,
|
|
455
|
+
title,
|
|
456
|
+
caption: fullCaption || void 0,
|
|
457
|
+
kind: "Instagram",
|
|
458
|
+
meta
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
function openPermalink(item) {
|
|
462
|
+
if (typeof window === "undefined") return;
|
|
463
|
+
const href = item.meta?.href;
|
|
464
|
+
if (!href) return;
|
|
465
|
+
window.open(href, "_blank", "noopener,noreferrer");
|
|
466
|
+
}
|
|
467
|
+
function likeBadge(likeCount) {
|
|
468
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
469
|
+
"span",
|
|
470
|
+
{
|
|
471
|
+
"aria-label": `${likeCount.toLocaleString()} likes`,
|
|
472
|
+
style: {
|
|
473
|
+
display: "inline-flex",
|
|
474
|
+
alignItems: "center",
|
|
475
|
+
gap: 4,
|
|
476
|
+
padding: "3px 8px",
|
|
477
|
+
borderRadius: 999,
|
|
478
|
+
background: "rgba(8,12,24,0.65)",
|
|
479
|
+
backdropFilter: "blur(6px)",
|
|
480
|
+
WebkitBackdropFilter: "blur(6px)",
|
|
481
|
+
color: "#fff",
|
|
482
|
+
fontSize: 11,
|
|
483
|
+
fontWeight: 700,
|
|
484
|
+
lineHeight: 1
|
|
485
|
+
},
|
|
486
|
+
children: [
|
|
487
|
+
/* @__PURE__ */ jsxRuntime.jsx(DynamicIcon, { name: "lucide/heart", size: 13, "aria-hidden": "true" }),
|
|
488
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: likeCount.toLocaleString() })
|
|
489
|
+
]
|
|
490
|
+
}
|
|
491
|
+
);
|
|
492
|
+
}
|
|
493
|
+
var VIEWER_ACTIONS = [
|
|
494
|
+
{
|
|
495
|
+
id: "open-in-instagram",
|
|
496
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(DynamicIcon, { name: "lucide/external-link", size: 22, "aria-hidden": "true" }),
|
|
497
|
+
label: "Instagram",
|
|
498
|
+
ariaLabel: "Open in Instagram",
|
|
499
|
+
onPress: (item) => openPermalink(item)
|
|
500
|
+
}
|
|
501
|
+
];
|
|
502
|
+
function RailStat({
|
|
427
503
|
iconName,
|
|
428
504
|
count,
|
|
429
|
-
label
|
|
505
|
+
label,
|
|
506
|
+
onPress
|
|
430
507
|
}) {
|
|
431
508
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
432
|
-
"
|
|
509
|
+
"button",
|
|
433
510
|
{
|
|
434
|
-
|
|
511
|
+
type: "button",
|
|
435
512
|
"aria-label": `${count.toLocaleString()} ${label}`,
|
|
513
|
+
onClick: (e) => {
|
|
514
|
+
e.stopPropagation();
|
|
515
|
+
onPress();
|
|
516
|
+
},
|
|
517
|
+
style: {
|
|
518
|
+
display: "flex",
|
|
519
|
+
flexDirection: "column",
|
|
520
|
+
alignItems: "center",
|
|
521
|
+
gap: 5,
|
|
522
|
+
padding: 0,
|
|
523
|
+
border: "none",
|
|
524
|
+
background: "transparent",
|
|
525
|
+
color: "inherit",
|
|
526
|
+
cursor: "pointer",
|
|
527
|
+
font: "inherit"
|
|
528
|
+
},
|
|
436
529
|
children: [
|
|
437
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
438
|
-
|
|
530
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
531
|
+
"span",
|
|
532
|
+
{
|
|
533
|
+
style: {
|
|
534
|
+
width: 46,
|
|
535
|
+
height: 46,
|
|
536
|
+
borderRadius: "50%",
|
|
537
|
+
background: "var(--psmi-chrome-bg, rgba(255,255,255,0.14))",
|
|
538
|
+
backdropFilter: "blur(6px)",
|
|
539
|
+
WebkitBackdropFilter: "blur(6px)",
|
|
540
|
+
display: "flex",
|
|
541
|
+
alignItems: "center",
|
|
542
|
+
justifyContent: "center"
|
|
543
|
+
},
|
|
544
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(DynamicIcon, { name: iconName, size: 22, "aria-hidden": "true" })
|
|
545
|
+
}
|
|
546
|
+
),
|
|
547
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", style: { fontSize: 11, fontWeight: 600 }, children: count.toLocaleString() })
|
|
439
548
|
]
|
|
440
549
|
}
|
|
441
550
|
);
|
|
442
551
|
}
|
|
552
|
+
function InstagramViewerRail({ item }) {
|
|
553
|
+
const meta = item.meta ?? {};
|
|
554
|
+
const open = () => openPermalink(item);
|
|
555
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
556
|
+
"div",
|
|
557
|
+
{
|
|
558
|
+
style: {
|
|
559
|
+
position: "absolute",
|
|
560
|
+
right: 11,
|
|
561
|
+
bottom: 135,
|
|
562
|
+
display: "flex",
|
|
563
|
+
flexDirection: "column",
|
|
564
|
+
alignItems: "center",
|
|
565
|
+
gap: 18,
|
|
566
|
+
color: "var(--psmi-chrome-fg, #fff)",
|
|
567
|
+
zIndex: 3
|
|
568
|
+
},
|
|
569
|
+
children: [
|
|
570
|
+
typeof meta.likeCount === "number" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
571
|
+
RailStat,
|
|
572
|
+
{
|
|
573
|
+
iconName: "lucide/heart",
|
|
574
|
+
count: meta.likeCount,
|
|
575
|
+
label: "likes",
|
|
576
|
+
onPress: open
|
|
577
|
+
}
|
|
578
|
+
) : null,
|
|
579
|
+
typeof meta.commentCount === "number" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
580
|
+
RailStat,
|
|
581
|
+
{
|
|
582
|
+
iconName: "lucide/message-circle",
|
|
583
|
+
count: meta.commentCount,
|
|
584
|
+
label: "comments",
|
|
585
|
+
onPress: open
|
|
586
|
+
}
|
|
587
|
+
) : null,
|
|
588
|
+
typeof meta.viewCount === "number" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
589
|
+
RailStat,
|
|
590
|
+
{
|
|
591
|
+
iconName: "lucide/eye",
|
|
592
|
+
count: meta.viewCount,
|
|
593
|
+
label: "views",
|
|
594
|
+
onPress: open
|
|
595
|
+
}
|
|
596
|
+
) : null,
|
|
597
|
+
meta.href ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
598
|
+
"a",
|
|
599
|
+
{
|
|
600
|
+
href: meta.href,
|
|
601
|
+
target: "_blank",
|
|
602
|
+
rel: "noopener noreferrer",
|
|
603
|
+
"aria-label": "Open in Instagram",
|
|
604
|
+
onClick: (e) => e.stopPropagation(),
|
|
605
|
+
style: {
|
|
606
|
+
display: "flex",
|
|
607
|
+
flexDirection: "column",
|
|
608
|
+
alignItems: "center",
|
|
609
|
+
gap: 5,
|
|
610
|
+
padding: 0,
|
|
611
|
+
border: "none",
|
|
612
|
+
background: "transparent",
|
|
613
|
+
color: "inherit",
|
|
614
|
+
cursor: "pointer",
|
|
615
|
+
font: "inherit",
|
|
616
|
+
textDecoration: "none"
|
|
617
|
+
},
|
|
618
|
+
children: [
|
|
619
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
620
|
+
"span",
|
|
621
|
+
{
|
|
622
|
+
style: {
|
|
623
|
+
width: 46,
|
|
624
|
+
height: 46,
|
|
625
|
+
borderRadius: "50%",
|
|
626
|
+
background: "var(--psmi-chrome-bg, rgba(255,255,255,0.14))",
|
|
627
|
+
backdropFilter: "blur(6px)",
|
|
628
|
+
WebkitBackdropFilter: "blur(6px)",
|
|
629
|
+
display: "flex",
|
|
630
|
+
alignItems: "center",
|
|
631
|
+
justifyContent: "center"
|
|
632
|
+
},
|
|
633
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
634
|
+
DynamicIcon,
|
|
635
|
+
{
|
|
636
|
+
name: "lucide/external-link",
|
|
637
|
+
size: 22,
|
|
638
|
+
"aria-hidden": "true"
|
|
639
|
+
}
|
|
640
|
+
)
|
|
641
|
+
}
|
|
642
|
+
),
|
|
643
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", style: { fontSize: 11, fontWeight: 600 }, children: "Instagram" })
|
|
644
|
+
]
|
|
645
|
+
}
|
|
646
|
+
) : null
|
|
647
|
+
]
|
|
648
|
+
}
|
|
649
|
+
);
|
|
650
|
+
}
|
|
651
|
+
function InstagramFeedGrid({
|
|
652
|
+
mediaItems,
|
|
653
|
+
gridClassName,
|
|
654
|
+
itemClassName,
|
|
655
|
+
imageClassName,
|
|
656
|
+
optixFlowConfig
|
|
657
|
+
}) {
|
|
658
|
+
const { open } = mediaImmersive.useImmersiveFeed();
|
|
659
|
+
const posterImgProps = React.useMemo(() => {
|
|
660
|
+
const next = {};
|
|
661
|
+
if (imageClassName) next.className = imageClassName;
|
|
662
|
+
if (optixFlowConfig) next.optixFlowConfig = optixFlowConfig;
|
|
663
|
+
return Object.keys(next).length > 0 ? next : void 0;
|
|
664
|
+
}, [imageClassName, optixFlowConfig]);
|
|
665
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
666
|
+
"div",
|
|
667
|
+
{
|
|
668
|
+
className: cn(
|
|
669
|
+
"grid grid-cols-2 gap-2 sm:grid-cols-3 lg:grid-cols-4",
|
|
670
|
+
gridClassName
|
|
671
|
+
),
|
|
672
|
+
children: mediaItems.map((mediaItem) => {
|
|
673
|
+
const likeCount = mediaItem.meta?.likeCount;
|
|
674
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
675
|
+
mediaImmersive.ThumbnailCard,
|
|
676
|
+
{
|
|
677
|
+
item: mediaItem,
|
|
678
|
+
onOpen: open,
|
|
679
|
+
size: IG_TILE_WIDTH,
|
|
680
|
+
style: IG_TILE_STYLE,
|
|
681
|
+
className: itemClassName,
|
|
682
|
+
elevated: false,
|
|
683
|
+
showDuration: false,
|
|
684
|
+
glyphMode: "hover",
|
|
685
|
+
posterImgProps,
|
|
686
|
+
badgeSlot: typeof likeCount === "number" ? likeBadge(likeCount) : void 0
|
|
687
|
+
},
|
|
688
|
+
mediaItem.id
|
|
689
|
+
);
|
|
690
|
+
})
|
|
691
|
+
}
|
|
692
|
+
);
|
|
693
|
+
}
|
|
443
694
|
function InstagramPostGrid({
|
|
444
695
|
sectionId = "instagram-post-grid",
|
|
445
696
|
heading,
|
|
@@ -454,111 +705,17 @@ function InstagramPostGrid({
|
|
|
454
705
|
gridClassName,
|
|
455
706
|
itemClassName,
|
|
456
707
|
imageClassName,
|
|
708
|
+
optixFlowConfig,
|
|
457
709
|
background,
|
|
458
710
|
spacing,
|
|
459
711
|
pattern,
|
|
460
712
|
patternOpacity,
|
|
461
|
-
patternClassName
|
|
462
|
-
optixFlowConfig
|
|
713
|
+
patternClassName
|
|
463
714
|
}) {
|
|
464
|
-
const
|
|
465
|
-
if (itemsSlot) return
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
return visibleItems.map((item) => {
|
|
469
|
-
const altText = item.imageAlt || (typeof item.caption === "string" ? item.caption : "") || "Instagram post";
|
|
470
|
-
const showVideo = Boolean(item.isVideo && item.videoUrl);
|
|
471
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
472
|
-
pressable.Pressable,
|
|
473
|
-
{
|
|
474
|
-
href: item.href,
|
|
475
|
-
"aria-label": typeof item.caption === "string" && item.caption.length > 0 ? item.caption : "View Instagram post",
|
|
476
|
-
className: cn(
|
|
477
|
-
"group relative block aspect-square overflow-hidden rounded-md bg-muted",
|
|
478
|
-
item.className,
|
|
479
|
-
itemClassName
|
|
480
|
-
),
|
|
481
|
-
children: [
|
|
482
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
483
|
-
img.Img,
|
|
484
|
-
{
|
|
485
|
-
src: item.image,
|
|
486
|
-
alt: altText,
|
|
487
|
-
loading: "lazy",
|
|
488
|
-
className: cn(
|
|
489
|
-
"h-full w-full object-cover object-center transition-transform duration-300 group-hover:scale-105 motion-reduce:transform-none motion-reduce:transition-none",
|
|
490
|
-
imageClassName
|
|
491
|
-
),
|
|
492
|
-
optixFlowConfig
|
|
493
|
-
}
|
|
494
|
-
),
|
|
495
|
-
showVideo && /* @__PURE__ */ jsxRuntime.jsx(
|
|
496
|
-
video.Video,
|
|
497
|
-
{
|
|
498
|
-
src: item.videoUrl,
|
|
499
|
-
poster: item.image,
|
|
500
|
-
controls: false,
|
|
501
|
-
muted: true,
|
|
502
|
-
loop: true,
|
|
503
|
-
playsInline: true,
|
|
504
|
-
preload: "metadata",
|
|
505
|
-
onMouseEnter: (e) => {
|
|
506
|
-
void e.currentTarget.play().catch(() => void 0);
|
|
507
|
-
},
|
|
508
|
-
onMouseLeave: (e) => {
|
|
509
|
-
e.currentTarget.pause();
|
|
510
|
-
e.currentTarget.currentTime = 0;
|
|
511
|
-
},
|
|
512
|
-
className: cn(
|
|
513
|
-
"absolute inset-0 h-full w-full object-cover object-center opacity-0 transition-opacity duration-300 group-hover:opacity-100 motion-reduce:transition-none",
|
|
514
|
-
imageClassName
|
|
515
|
-
)
|
|
516
|
-
}
|
|
517
|
-
),
|
|
518
|
-
item.isVideo && /* @__PURE__ */ jsxRuntime.jsx(
|
|
519
|
-
"span",
|
|
520
|
-
{
|
|
521
|
-
className: "absolute right-2 top-2 text-white drop-shadow-md",
|
|
522
|
-
"aria-hidden": "true",
|
|
523
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(DynamicIcon, { name: "lucide/play", size: 18 })
|
|
524
|
-
}
|
|
525
|
-
),
|
|
526
|
-
(item.caption || item.date || typeof item.likeCount === "number" || typeof item.commentCount === "number" || typeof item.viewCount === "number") && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pointer-events-none absolute inset-x-0 bottom-0 flex flex-col gap-1 bg-linear-to-t from-black/70 to-transparent p-3 text-left text-white opacity-0 transition-opacity duration-300 group-hover:opacity-100 motion-reduce:transition-none", children: [
|
|
527
|
-
item.caption && (typeof item.caption === "string" ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "line-clamp-2 text-xs leading-snug wrap-break-word", children: item.caption }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "line-clamp-2 text-xs leading-snug", children: item.caption })),
|
|
528
|
-
(typeof item.likeCount === "number" || typeof item.commentCount === "number" || typeof item.viewCount === "number" || item.date) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 text-xs font-medium", children: [
|
|
529
|
-
typeof item.likeCount === "number" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
530
|
-
EngagementBadge,
|
|
531
|
-
{
|
|
532
|
-
iconName: "lucide/heart",
|
|
533
|
-
count: item.likeCount,
|
|
534
|
-
label: "likes"
|
|
535
|
-
}
|
|
536
|
-
),
|
|
537
|
-
typeof item.commentCount === "number" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
538
|
-
EngagementBadge,
|
|
539
|
-
{
|
|
540
|
-
iconName: "lucide/message-circle",
|
|
541
|
-
count: item.commentCount,
|
|
542
|
-
label: "comments"
|
|
543
|
-
}
|
|
544
|
-
),
|
|
545
|
-
typeof item.viewCount === "number" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
546
|
-
EngagementBadge,
|
|
547
|
-
{
|
|
548
|
-
iconName: "lucide/eye",
|
|
549
|
-
count: item.viewCount,
|
|
550
|
-
label: "views"
|
|
551
|
-
}
|
|
552
|
-
),
|
|
553
|
-
item.date && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-auto opacity-80", children: item.date })
|
|
554
|
-
] })
|
|
555
|
-
] })
|
|
556
|
-
]
|
|
557
|
-
},
|
|
558
|
-
item.id
|
|
559
|
-
);
|
|
560
|
-
});
|
|
561
|
-
}, [itemsSlot, items, itemClassName, imageClassName, optixFlowConfig]);
|
|
715
|
+
const mediaItems = React.useMemo(() => {
|
|
716
|
+
if (itemsSlot || !items) return [];
|
|
717
|
+
return items.filter((item) => Boolean(item.image)).map(toMediaItem);
|
|
718
|
+
}, [items, itemsSlot]);
|
|
562
719
|
if (!itemsSlot && (!items || items.length === 0)) {
|
|
563
720
|
return null;
|
|
564
721
|
}
|
|
@@ -596,16 +753,34 @@ function InstagramPostGrid({
|
|
|
596
753
|
}
|
|
597
754
|
) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: subheadingClassName, children: subheading }))
|
|
598
755
|
] }),
|
|
599
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
756
|
+
itemsSlot ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
600
757
|
"div",
|
|
601
758
|
{
|
|
602
759
|
className: cn(
|
|
603
760
|
"grid grid-cols-2 gap-2 sm:grid-cols-3 lg:grid-cols-4",
|
|
604
761
|
gridClassName
|
|
605
762
|
),
|
|
606
|
-
children:
|
|
763
|
+
children: itemsSlot
|
|
607
764
|
}
|
|
608
|
-
)
|
|
765
|
+
) : /* @__PURE__ */ jsxRuntime.jsxs(mediaImmersive.ImmersiveFeedProvider, { items: mediaItems, actions: VIEWER_ACTIONS, children: [
|
|
766
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
767
|
+
InstagramFeedGrid,
|
|
768
|
+
{
|
|
769
|
+
mediaItems,
|
|
770
|
+
gridClassName,
|
|
771
|
+
itemClassName,
|
|
772
|
+
imageClassName,
|
|
773
|
+
optixFlowConfig
|
|
774
|
+
}
|
|
775
|
+
),
|
|
776
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
777
|
+
mediaImmersive.ImmersiveViewer,
|
|
778
|
+
{
|
|
779
|
+
ariaLabel: "Instagram post viewer",
|
|
780
|
+
renderActions: ({ item }) => /* @__PURE__ */ jsxRuntime.jsx(InstagramViewerRail, { item })
|
|
781
|
+
}
|
|
782
|
+
)
|
|
783
|
+
] })
|
|
609
784
|
]
|
|
610
785
|
}
|
|
611
786
|
);
|
|
@@ -31,7 +31,15 @@ interface InstagramPostItem {
|
|
|
31
31
|
*/
|
|
32
32
|
imageAlt?: string;
|
|
33
33
|
/**
|
|
34
|
-
* Post caption (truncated for display)
|
|
34
|
+
* Post caption (truncated for display).
|
|
35
|
+
*
|
|
36
|
+
* NOTE: For immersive rendering the caption must be a **string** — the
|
|
37
|
+
* library's `MediaItem.title`/`caption` are string-typed, so a caption is
|
|
38
|
+
* flowed through as text. A rich `ReactNode` caption (hand-authored markup,
|
|
39
|
+
* only ever used by the legacy pre-immersive block) cannot be threaded into
|
|
40
|
+
* the immersive card/viewer; when supplied it is dropped and the tile/viewer
|
|
41
|
+
* title falls back to `imageAlt` (then `"Instagram post"`). Hydrated feeds
|
|
42
|
+
* always send plain strings, so this only affects hand-authored usage.
|
|
35
43
|
*/
|
|
36
44
|
caption?: React.ReactNode;
|
|
37
45
|
/**
|
|
@@ -140,17 +148,32 @@ interface InstagramPostGridProps {
|
|
|
140
148
|
sectionId?: string;
|
|
141
149
|
}
|
|
142
150
|
/**
|
|
143
|
-
* InstagramPostGrid displays a responsive
|
|
151
|
+
* InstagramPostGrid displays a website's Instagram feed as a responsive grid of
|
|
152
|
+
* vertical (9:16) tiles that open a fullscreen, swipeable immersive viewer.
|
|
144
153
|
*
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
*
|
|
150
|
-
*
|
|
154
|
+
* Composition is powered by `@page-speed/media-immersive`: each post maps to a
|
|
155
|
+
* `MediaItem` (photos are first-class images, reels are videos), tiles are
|
|
156
|
+
* `ThumbnailCard`s, and tapping one opens `ImmersiveViewer` — a TikTok/Reels-
|
|
157
|
+
* style pager. Per the annotated design, each tile shows a like-count pill
|
|
158
|
+
* top-left (only when a numeric like count exists — never fabricated), no
|
|
159
|
+
* duration timestamp, and a center glyph on hover only (a play triangle for
|
|
160
|
+
* reels, an expand icon for photos). The fullscreen viewer carries the caption
|
|
161
|
+
* plus a read-only engagement rail (likes/comments/views) and an explicit
|
|
162
|
+
* "Open in Instagram" egress rendered as a real `<a target="_blank"
|
|
163
|
+
* rel="noopener noreferrer">` (a crawlable, affordance-correct link — not a
|
|
164
|
+
* scripted `window.open` button); the old whole-tile link-out is REPLACED by
|
|
165
|
+
* opening the viewer, with the permalink egress living in the viewer.
|
|
151
166
|
*
|
|
152
|
-
*
|
|
153
|
-
*
|
|
167
|
+
* Consumer image concerns are honored: `imageClassName` and `optixFlowConfig`
|
|
168
|
+
* are forwarded onto each tile's poster image via the library's
|
|
169
|
+
* `posterImgProps` passthrough.
|
|
170
|
+
*
|
|
171
|
+
* Captions should be plain strings when used with immersive rendering; a rich
|
|
172
|
+
* `ReactNode` caption falls back to `imageAlt` (see the `caption` field doc).
|
|
173
|
+
*
|
|
174
|
+
* Posts without an image are skipped; an empty or missing `items` array renders
|
|
175
|
+
* nothing. Data is hydrated from the toastability Instagram feed — media URLs
|
|
176
|
+
* are the re-hosted MediaRecord CDN URLs, never expiring Instagram CDN URLs.
|
|
154
177
|
*
|
|
155
178
|
* @example
|
|
156
179
|
* ```tsx
|
|
@@ -169,6 +192,6 @@ interface InstagramPostGridProps {
|
|
|
169
192
|
* />
|
|
170
193
|
* ```
|
|
171
194
|
*/
|
|
172
|
-
declare function InstagramPostGrid({ sectionId, heading, subheading, items, itemsSlot, className, containerClassName, headerClassName, headingClassName, subheadingClassName, gridClassName, itemClassName, imageClassName, background, spacing, pattern, patternOpacity, patternClassName,
|
|
195
|
+
declare function InstagramPostGrid({ sectionId, heading, subheading, items, itemsSlot, className, containerClassName, headerClassName, headingClassName, subheadingClassName, gridClassName, itemClassName, imageClassName, optixFlowConfig, background, spacing, pattern, patternOpacity, patternClassName, }: InstagramPostGridProps): React.JSX.Element | null;
|
|
173
196
|
|
|
174
197
|
export { InstagramPostGrid, type InstagramPostGridProps, type InstagramPostItem };
|
|
@@ -31,7 +31,15 @@ interface InstagramPostItem {
|
|
|
31
31
|
*/
|
|
32
32
|
imageAlt?: string;
|
|
33
33
|
/**
|
|
34
|
-
* Post caption (truncated for display)
|
|
34
|
+
* Post caption (truncated for display).
|
|
35
|
+
*
|
|
36
|
+
* NOTE: For immersive rendering the caption must be a **string** — the
|
|
37
|
+
* library's `MediaItem.title`/`caption` are string-typed, so a caption is
|
|
38
|
+
* flowed through as text. A rich `ReactNode` caption (hand-authored markup,
|
|
39
|
+
* only ever used by the legacy pre-immersive block) cannot be threaded into
|
|
40
|
+
* the immersive card/viewer; when supplied it is dropped and the tile/viewer
|
|
41
|
+
* title falls back to `imageAlt` (then `"Instagram post"`). Hydrated feeds
|
|
42
|
+
* always send plain strings, so this only affects hand-authored usage.
|
|
35
43
|
*/
|
|
36
44
|
caption?: React.ReactNode;
|
|
37
45
|
/**
|
|
@@ -140,17 +148,32 @@ interface InstagramPostGridProps {
|
|
|
140
148
|
sectionId?: string;
|
|
141
149
|
}
|
|
142
150
|
/**
|
|
143
|
-
* InstagramPostGrid displays a responsive
|
|
151
|
+
* InstagramPostGrid displays a website's Instagram feed as a responsive grid of
|
|
152
|
+
* vertical (9:16) tiles that open a fullscreen, swipeable immersive viewer.
|
|
144
153
|
*
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
*
|
|
150
|
-
*
|
|
154
|
+
* Composition is powered by `@page-speed/media-immersive`: each post maps to a
|
|
155
|
+
* `MediaItem` (photos are first-class images, reels are videos), tiles are
|
|
156
|
+
* `ThumbnailCard`s, and tapping one opens `ImmersiveViewer` — a TikTok/Reels-
|
|
157
|
+
* style pager. Per the annotated design, each tile shows a like-count pill
|
|
158
|
+
* top-left (only when a numeric like count exists — never fabricated), no
|
|
159
|
+
* duration timestamp, and a center glyph on hover only (a play triangle for
|
|
160
|
+
* reels, an expand icon for photos). The fullscreen viewer carries the caption
|
|
161
|
+
* plus a read-only engagement rail (likes/comments/views) and an explicit
|
|
162
|
+
* "Open in Instagram" egress rendered as a real `<a target="_blank"
|
|
163
|
+
* rel="noopener noreferrer">` (a crawlable, affordance-correct link — not a
|
|
164
|
+
* scripted `window.open` button); the old whole-tile link-out is REPLACED by
|
|
165
|
+
* opening the viewer, with the permalink egress living in the viewer.
|
|
151
166
|
*
|
|
152
|
-
*
|
|
153
|
-
*
|
|
167
|
+
* Consumer image concerns are honored: `imageClassName` and `optixFlowConfig`
|
|
168
|
+
* are forwarded onto each tile's poster image via the library's
|
|
169
|
+
* `posterImgProps` passthrough.
|
|
170
|
+
*
|
|
171
|
+
* Captions should be plain strings when used with immersive rendering; a rich
|
|
172
|
+
* `ReactNode` caption falls back to `imageAlt` (see the `caption` field doc).
|
|
173
|
+
*
|
|
174
|
+
* Posts without an image are skipped; an empty or missing `items` array renders
|
|
175
|
+
* nothing. Data is hydrated from the toastability Instagram feed — media URLs
|
|
176
|
+
* are the re-hosted MediaRecord CDN URLs, never expiring Instagram CDN URLs.
|
|
154
177
|
*
|
|
155
178
|
* @example
|
|
156
179
|
* ```tsx
|
|
@@ -169,6 +192,6 @@ interface InstagramPostGridProps {
|
|
|
169
192
|
* />
|
|
170
193
|
* ```
|
|
171
194
|
*/
|
|
172
|
-
declare function InstagramPostGrid({ sectionId, heading, subheading, items, itemsSlot, className, containerClassName, headerClassName, headingClassName, subheadingClassName, gridClassName, itemClassName, imageClassName, background, spacing, pattern, patternOpacity, patternClassName,
|
|
195
|
+
declare function InstagramPostGrid({ sectionId, heading, subheading, items, itemsSlot, className, containerClassName, headerClassName, headingClassName, subheadingClassName, gridClassName, itemClassName, imageClassName, optixFlowConfig, background, spacing, pattern, patternOpacity, patternClassName, }: InstagramPostGridProps): React.JSX.Element | null;
|
|
173
196
|
|
|
174
197
|
export { InstagramPostGrid, type InstagramPostGridProps, type InstagramPostItem };
|