@flamingo-stack/openframe-frontend-core 0.0.558 → 0.0.559-1837.4923.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.
Files changed (108) hide show
  1. package/dist/{chunk-R3OCP4A7.cjs → chunk-5ILANKGZ.cjs} +62 -62
  2. package/dist/{chunk-R3OCP4A7.cjs.map → chunk-5ILANKGZ.cjs.map} +1 -1
  3. package/dist/{chunk-E26KVZJM.js → chunk-5JQ7GAMW.js} +2 -2
  4. package/dist/{chunk-N3OGB543.cjs → chunk-6I5CZG3H.cjs} +9 -9
  5. package/dist/{chunk-N3OGB543.cjs.map → chunk-6I5CZG3H.cjs.map} +1 -1
  6. package/dist/{chunk-5JHJX7OX.js → chunk-6P4PUMIQ.js} +4 -4
  7. package/dist/{chunk-IHXUZBBV.js → chunk-6WGTYKIQ.js} +13 -3
  8. package/dist/{chunk-IHXUZBBV.js.map → chunk-6WGTYKIQ.js.map} +1 -1
  9. package/dist/{chunk-ZSZ24UY6.js → chunk-6ZJJFIY6.js} +2 -2
  10. package/dist/{chunk-XL2G2HHJ.cjs → chunk-7A47C36F.cjs} +4 -4
  11. package/dist/{chunk-XL2G2HHJ.cjs.map → chunk-7A47C36F.cjs.map} +1 -1
  12. package/dist/{chunk-FCCSHC3H.cjs → chunk-AMQAO3LO.cjs} +26 -26
  13. package/dist/{chunk-FCCSHC3H.cjs.map → chunk-AMQAO3LO.cjs.map} +1 -1
  14. package/dist/{chunk-3TKG7SW6.cjs → chunk-AWJ4Q6LE.cjs} +39 -39
  15. package/dist/{chunk-3TKG7SW6.cjs.map → chunk-AWJ4Q6LE.cjs.map} +1 -1
  16. package/dist/{chunk-CWQSUYVV.cjs → chunk-BFVGW6Z4.cjs} +3 -3
  17. package/dist/{chunk-CWQSUYVV.cjs.map → chunk-BFVGW6Z4.cjs.map} +1 -1
  18. package/dist/{chunk-VNWGXQJD.cjs → chunk-BXBTVN3I.cjs} +20 -20
  19. package/dist/{chunk-VNWGXQJD.cjs.map → chunk-BXBTVN3I.cjs.map} +1 -1
  20. package/dist/{chunk-Z5FN5VTC.js → chunk-D72LUV2H.js} +2 -2
  21. package/dist/{chunk-GYQHUJWR.cjs → chunk-D763VJW3.cjs} +14 -14
  22. package/dist/{chunk-GYQHUJWR.cjs.map → chunk-D763VJW3.cjs.map} +1 -1
  23. package/dist/{chunk-DV4CSNZD.js → chunk-HRHLYPWR.js} +2 -2
  24. package/dist/{chunk-XDMRN3SG.cjs → chunk-IRY6MVME.cjs} +86 -86
  25. package/dist/{chunk-XDMRN3SG.cjs.map → chunk-IRY6MVME.cjs.map} +1 -1
  26. package/dist/{chunk-FVHFBEXH.js → chunk-ISAEZK3W.js} +2 -2
  27. package/dist/{chunk-R3TXAMMB.cjs → chunk-JQV3DKAO.cjs} +14 -4
  28. package/dist/chunk-JQV3DKAO.cjs.map +1 -0
  29. package/dist/{chunk-S3NZZKNU.js → chunk-JU2O4P5Q.js} +2 -2
  30. package/dist/{chunk-DNPQ2U7P.js → chunk-KHIZSJ2G.js} +2 -2
  31. package/dist/{chunk-DHSIAIFG.cjs → chunk-LIBI7LBS.cjs} +11 -11
  32. package/dist/{chunk-DHSIAIFG.cjs.map → chunk-LIBI7LBS.cjs.map} +1 -1
  33. package/dist/{chunk-SI64DC72.cjs → chunk-PC5HDZKJ.cjs} +31 -31
  34. package/dist/{chunk-SI64DC72.cjs.map → chunk-PC5HDZKJ.cjs.map} +1 -1
  35. package/dist/{chunk-YUVCH2LX.js → chunk-QWDX32FH.js} +5 -5
  36. package/dist/{chunk-4VLGJEKQ.js → chunk-RV56535I.js} +2 -2
  37. package/dist/{chunk-UVGFICZT.js → chunk-VBUBXVG4.js} +6 -6
  38. package/dist/{chunk-5WQPOH27.cjs → chunk-WK7LWQBI.cjs} +5 -5
  39. package/dist/{chunk-5WQPOH27.cjs.map → chunk-WK7LWQBI.cjs.map} +1 -1
  40. package/dist/{chunk-LM6NDYGD.js → chunk-WRVZ72H6.js} +2 -2
  41. package/dist/{chunk-53GNFRVQ.cjs → chunk-WSVCPL6F.cjs} +7 -7
  42. package/dist/{chunk-53GNFRVQ.cjs.map → chunk-WSVCPL6F.cjs.map} +1 -1
  43. package/dist/{chunk-C5HQCF4R.js → chunk-YAKUL5TA.js} +4 -4
  44. package/dist/components/case-studies/index.cjs +8 -8
  45. package/dist/components/case-studies/index.js +2 -2
  46. package/dist/components/chat/index.cjs +2 -2
  47. package/dist/components/chat/index.js +1 -1
  48. package/dist/components/contact/index.cjs +3 -3
  49. package/dist/components/contact/index.js +2 -2
  50. package/dist/components/docs/index.cjs +5 -5
  51. package/dist/components/docs/index.js +4 -4
  52. package/dist/components/embeds/index.cjs +3 -3
  53. package/dist/components/embeds/index.js +2 -2
  54. package/dist/components/faq/index.cjs +3 -3
  55. package/dist/components/faq/index.js +2 -2
  56. package/dist/components/features/index.cjs +4 -2
  57. package/dist/components/features/index.cjs.map +1 -1
  58. package/dist/components/features/index.js +3 -1
  59. package/dist/components/features/video-bites-shared.cjs +9 -0
  60. package/dist/components/features/video-bites-shared.cjs.map +1 -1
  61. package/dist/components/features/video-bites-shared.d.ts +9 -0
  62. package/dist/components/features/video-bites-shared.d.ts.map +1 -1
  63. package/dist/components/features/video-bites-shared.js +9 -1
  64. package/dist/components/features/video-bites-shared.js.map +1 -1
  65. package/dist/components/features/video-bites-strip.d.ts +5 -1
  66. package/dist/components/features/video-bites-strip.d.ts.map +1 -1
  67. package/dist/components/help-center-pages/index.cjs +22 -22
  68. package/dist/components/help-center-pages/index.js +13 -13
  69. package/dist/components/index.cjs +133 -131
  70. package/dist/components/index.cjs.map +1 -1
  71. package/dist/components/index.js +13 -11
  72. package/dist/components/index.js.map +1 -1
  73. package/dist/components/meeting-scheduler/index.cjs +28 -28
  74. package/dist/components/meeting-scheduler/index.js +3 -3
  75. package/dist/components/navigation/index.cjs +2 -2
  76. package/dist/components/navigation/index.js +1 -1
  77. package/dist/components/onboarding-guides/index.cjs +5 -5
  78. package/dist/components/onboarding-guides/index.js +4 -4
  79. package/dist/components/related-content/index.cjs +3 -3
  80. package/dist/components/related-content/index.js +2 -2
  81. package/dist/components/tickets/index.cjs +6 -6
  82. package/dist/components/tickets/index.js +5 -5
  83. package/dist/components/ui/index.cjs +2 -2
  84. package/dist/components/ui/index.js +1 -1
  85. package/dist/index.cjs +4 -2
  86. package/dist/index.cjs.map +1 -1
  87. package/dist/index.js +3 -1
  88. package/dist/types/video-processing.d.ts +1 -0
  89. package/dist/types/video-processing.d.ts.map +1 -1
  90. package/package.json +1 -1
  91. package/src/components/features/__tests__/video-bites-shared.test.ts +53 -0
  92. package/src/components/features/video-bites-shared.ts +17 -0
  93. package/src/components/features/video-bites-strip.tsx +7 -2
  94. package/src/types/video-processing.ts +1 -0
  95. package/dist/chunk-R3TXAMMB.cjs.map +0 -1
  96. /package/dist/{chunk-E26KVZJM.js.map → chunk-5JQ7GAMW.js.map} +0 -0
  97. /package/dist/{chunk-5JHJX7OX.js.map → chunk-6P4PUMIQ.js.map} +0 -0
  98. /package/dist/{chunk-ZSZ24UY6.js.map → chunk-6ZJJFIY6.js.map} +0 -0
  99. /package/dist/{chunk-Z5FN5VTC.js.map → chunk-D72LUV2H.js.map} +0 -0
  100. /package/dist/{chunk-DV4CSNZD.js.map → chunk-HRHLYPWR.js.map} +0 -0
  101. /package/dist/{chunk-FVHFBEXH.js.map → chunk-ISAEZK3W.js.map} +0 -0
  102. /package/dist/{chunk-S3NZZKNU.js.map → chunk-JU2O4P5Q.js.map} +0 -0
  103. /package/dist/{chunk-DNPQ2U7P.js.map → chunk-KHIZSJ2G.js.map} +0 -0
  104. /package/dist/{chunk-YUVCH2LX.js.map → chunk-QWDX32FH.js.map} +0 -0
  105. /package/dist/{chunk-4VLGJEKQ.js.map → chunk-RV56535I.js.map} +0 -0
  106. /package/dist/{chunk-UVGFICZT.js.map → chunk-VBUBXVG4.js.map} +0 -0
  107. /package/dist/{chunk-LM6NDYGD.js.map → chunk-WRVZ72H6.js.map} +0 -0
  108. /package/dist/{chunk-C5HQCF4R.js.map → chunk-YAKUL5TA.js.map} +0 -0
@@ -0,0 +1,53 @@
1
+ import { describe, expect, it } from 'vitest'
2
+ import {
3
+ sortBitesByCreatedAtDesc,
4
+ sortBitesByFeaturedAtDesc,
5
+ } from '../video-bites-shared'
6
+ import type { VideoTeaser } from '../../../types/video-processing'
7
+
8
+ const bite = (overrides: Partial<VideoTeaser>): VideoTeaser => ({
9
+ url: `https://cdn.example/${Math.abs(JSON.stringify(overrides).length)}.mp4`,
10
+ ...overrides,
11
+ })
12
+
13
+ describe('sortBitesByCreatedAtDesc', () => {
14
+ it('orders newest created_at first', () => {
15
+ const a = bite({ created_at: '2026-01-01T00:00:00Z' })
16
+ const b = bite({ created_at: '2026-02-01T00:00:00Z' })
17
+ expect([a, b].sort(sortBitesByCreatedAtDesc)).toEqual([b, a])
18
+ })
19
+
20
+ it('sorts bites without created_at last', () => {
21
+ const dated = bite({ created_at: '2026-01-01T00:00:00Z' })
22
+ const undated = bite({})
23
+ expect([undated, dated].sort(sortBitesByCreatedAtDesc)).toEqual([dated, undated])
24
+ })
25
+ })
26
+
27
+ describe('sortBitesByFeaturedAtDesc', () => {
28
+ it('ranks a recently-featured OLD bite above a newer un-restamped one', () => {
29
+ // The 2026-08-18 homepage regression: an old clip starred today must
30
+ // outrank clips created later but featured earlier.
31
+ const oldClipFeaturedToday = bite({
32
+ created_at: '2026-07-14T00:00:00Z',
33
+ featured_at: '2026-08-18T00:00:00Z',
34
+ })
35
+ const newerClipNoStamp = bite({ created_at: '2026-07-17T00:00:00Z' })
36
+ expect([newerClipNoStamp, oldClipFeaturedToday].sort(sortBitesByFeaturedAtDesc)).toEqual([
37
+ oldClipFeaturedToday,
38
+ newerClipNoStamp,
39
+ ])
40
+ })
41
+
42
+ it('falls back to created_at for legacy bites without featured_at', () => {
43
+ const a = bite({ created_at: '2026-01-01T00:00:00Z' })
44
+ const b = bite({ created_at: '2026-02-01T00:00:00Z' })
45
+ expect([a, b].sort(sortBitesByFeaturedAtDesc)).toEqual([b, a])
46
+ })
47
+
48
+ it('sorts bites with neither timestamp last', () => {
49
+ const stamped = bite({ featured_at: '2026-01-01T00:00:00Z' })
50
+ const bare = bite({})
51
+ expect([bare, stamped].sort(sortBitesByFeaturedAtDesc)).toEqual([stamped, bare])
52
+ })
53
+ })
@@ -60,3 +60,20 @@ export function sortBitesByCreatedAtDesc(a: VideoTeaser, b: VideoTeaser): number
60
60
  if (!b.created_at) return -1
61
61
  return new Date(b.created_at).getTime() - new Date(a.created_at).getTime()
62
62
  }
63
+
64
+ /**
65
+ * FEATURED-recency comparator: `featured_at` (stamped when an admin stars the
66
+ * bite) with `created_at` fallback for bites featured before the stamp
67
+ * existed; missing dates sort last. The comparator FEATURED surfaces (the
68
+ * cross-entity aggregation + its strips) must use — ranking those surfaces by
69
+ * `created_at` made featuring any older bite a silent no-op once the surface
70
+ * cap filled with newer bites.
71
+ */
72
+ export function sortBitesByFeaturedAtDesc(a: VideoTeaser, b: VideoTeaser): number {
73
+ const ta = a.featured_at ?? a.created_at
74
+ const tb = b.featured_at ?? b.created_at
75
+ if (!ta && !tb) return 0
76
+ if (!ta) return 1
77
+ if (!tb) return -1
78
+ return new Date(tb).getTime() - new Date(ta).getTime()
79
+ }
@@ -88,6 +88,10 @@ export interface VideoBitesStripProps {
88
88
  showChevrons?: boolean;
89
89
  /** Section-level navigation fallback (per-bite `href`/`onNavigate` win). */
90
90
  onBiteNavigate?: (bite: VideoBiteStripItem, index: number) => void;
91
+ /** Ordering comparator. Default `sortBitesByCreatedAtDesc`; FEATURED
92
+ * surfaces pass `sortBitesByFeaturedAtDesc` so display order matches the
93
+ * featured-recency ranking their server aggregation is capped by. */
94
+ sortComparator?: (a: VideoBiteStripItem, b: VideoBiteStripItem) => number;
91
95
  className?: string;
92
96
  }
93
97
 
@@ -110,12 +114,13 @@ export function VideoBitesStrip({
110
114
  cardHeightMobile = 300,
111
115
  showChevrons = true,
112
116
  onBiteNavigate,
117
+ sortComparator = sortBitesByCreatedAtDesc,
113
118
  className,
114
119
  }: VideoBitesStripProps): React.ReactElement | null {
115
120
  const items = useMemo(() => {
116
121
  const filtered = filterPublished ? bites.filter(b => b.published) : [...bites];
117
- return filtered.sort(sortBitesByCreatedAtDesc);
118
- }, [bites, filterPublished]);
122
+ return filtered.sort(sortComparator);
123
+ }, [bites, filterPublished, sortComparator]);
119
124
 
120
125
  // Preconnect Mux/Supabase origins once so first hover starts fast.
121
126
  const warmup = useVideoWarmup<HTMLDivElement>({ videoUrl: items[0]?.url || null });
@@ -19,6 +19,7 @@ export interface VideoTeaser {
19
19
  thumbnail_url?: string // Optional thumbnail image URL for video preview. If not provided, video player will show first frame automatically.
20
20
  published?: boolean // Controls visibility on public preview page (default: false, admin must select)
21
21
  featured?: boolean // Opts the bite into cross-entity featured pulls (homepage/configured surfaces). Independent of `published`.
22
+ featured_at?: string // ISO timestamp stamped when an admin features the bite (cleared on unfeature). Featured surfaces rank by THIS (fallback created_at) — ranking by created_at alone made featuring an old bite invisible under the surface cap.
22
23
  source?: 'manual' | 'ai_generated' // Track origin of teaser
23
24
  created_at?: string // ISO timestamp for sorting (newer items first)
24
25
  start_time_ms?: number // Vizard extraction: clip start offset in the source video