keystone-design-bootstrap 1.0.44 → 1.0.45
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/package.json +1 -1
- package/src/design_system/sections/social-media-grid.aman.tsx +9 -3
- package/src/design_system/sections/social-media-grid.barelux.tsx +9 -3
- package/src/design_system/sections/social-media-grid.tsx +9 -3
- package/src/types/api/social-post.ts +2 -0
- package/src/utils/photo-helpers.ts +13 -0
package/package.json
CHANGED
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
import { PhotoWithFallback } from '../elements';
|
|
2
|
+
import { isVideoUrl } from '../../utils/photo-helpers';
|
|
2
3
|
import type { SocialPost } from '../../types/api/social-post';
|
|
3
4
|
|
|
4
|
-
/** Get display image URLs from post
|
|
5
|
+
/** Get display image URLs from post (excludes video URLs so img/PhotoWithFallback don't break) */
|
|
5
6
|
function getPostImageUrls(post: SocialPost): string[] {
|
|
6
|
-
|
|
7
|
+
const videoSet = post.video_urls?.length ? new Set(post.video_urls) : null;
|
|
8
|
+
const isVideo = (url: string) => isVideoUrl(url) || (videoSet !== null && videoSet.has(url));
|
|
9
|
+
if (post.image_urls?.length) {
|
|
10
|
+
return post.image_urls.filter((url) => !isVideo(url));
|
|
11
|
+
}
|
|
7
12
|
const attachments = post.photo_attachments || [];
|
|
8
13
|
const sorted = [...attachments].sort((a, b) => (a.sort_order ?? 0) - (b.sort_order ?? 0));
|
|
9
14
|
return sorted
|
|
10
15
|
.map((pa) => pa.photo?.large_url || pa.photo?.original_url || pa.photo?.medium_url || pa.photo?.thumbnail_url)
|
|
11
|
-
.filter((url): url is string => Boolean(url))
|
|
16
|
+
.filter((url): url is string => Boolean(url))
|
|
17
|
+
.filter((url) => !isVideo(url));
|
|
12
18
|
}
|
|
13
19
|
|
|
14
20
|
interface SocialMediaGridProps {
|
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
import { PhotoWithFallback } from '../elements';
|
|
2
|
+
import { isVideoUrl } from '../../utils/photo-helpers';
|
|
2
3
|
import type { SocialPost } from '../../types/api/social-post';
|
|
3
4
|
|
|
4
|
-
/** Get display image URLs from post
|
|
5
|
+
/** Get display image URLs from post (excludes video URLs so img/PhotoWithFallback don't break) */
|
|
5
6
|
function getPostImageUrls(post: SocialPost): string[] {
|
|
6
|
-
|
|
7
|
+
const videoSet = post.video_urls?.length ? new Set(post.video_urls) : null;
|
|
8
|
+
const isVideo = (url: string) => isVideoUrl(url) || (videoSet !== null && videoSet.has(url));
|
|
9
|
+
if (post.image_urls?.length) {
|
|
10
|
+
return post.image_urls.filter((url) => !isVideo(url));
|
|
11
|
+
}
|
|
7
12
|
const attachments = post.photo_attachments || [];
|
|
8
13
|
const sorted = [...attachments].sort((a, b) => (a.sort_order ?? 0) - (b.sort_order ?? 0));
|
|
9
14
|
return sorted
|
|
10
15
|
.map((pa) => pa.photo?.large_url || pa.photo?.original_url || pa.photo?.medium_url || pa.photo?.thumbnail_url)
|
|
11
|
-
.filter((url): url is string => Boolean(url))
|
|
16
|
+
.filter((url): url is string => Boolean(url))
|
|
17
|
+
.filter((url) => !isVideo(url));
|
|
12
18
|
}
|
|
13
19
|
|
|
14
20
|
interface SocialMediaGridProps {
|
|
@@ -6,16 +6,22 @@ import { ArrowLeft, ArrowRight } from '@untitledui/icons';
|
|
|
6
6
|
import { Carousel } from '../elements/carousel/carousel-base';
|
|
7
7
|
import { Button, PaginationPageMinimalCenter, PhotoWithFallback, RoundButton } from '../elements';
|
|
8
8
|
import { cx } from '../../utils/cx';
|
|
9
|
+
import { isVideoUrl } from '../../utils/photo-helpers';
|
|
9
10
|
import type { SocialPost } from '../../types/api/social-post';
|
|
10
11
|
|
|
11
|
-
/** Get display image URLs from post
|
|
12
|
+
/** Get display image URLs from post (excludes video URLs so img/PhotoWithFallback don't break) */
|
|
12
13
|
function getPostImageUrls(post: SocialPost): string[] {
|
|
13
|
-
|
|
14
|
+
const videoSet = post.video_urls?.length ? new Set(post.video_urls) : null;
|
|
15
|
+
const isVideo = (url: string) => isVideoUrl(url) || (videoSet !== null && videoSet.has(url));
|
|
16
|
+
if (post.image_urls?.length) {
|
|
17
|
+
return post.image_urls.filter((url) => !isVideo(url));
|
|
18
|
+
}
|
|
14
19
|
const attachments = post.photo_attachments || [];
|
|
15
20
|
const sorted = [...attachments].sort((a, b) => (a.sort_order ?? 0) - (b.sort_order ?? 0));
|
|
16
21
|
return sorted
|
|
17
22
|
.map((pa) => pa.photo?.large_url || pa.photo?.original_url || pa.photo?.medium_url || pa.photo?.thumbnail_url)
|
|
18
|
-
.filter((url): url is string => Boolean(url))
|
|
23
|
+
.filter((url): url is string => Boolean(url))
|
|
24
|
+
.filter((url) => !isVideo(url));
|
|
19
25
|
}
|
|
20
26
|
|
|
21
27
|
interface SocialMediaGridProps {
|
|
@@ -11,6 +11,8 @@ export interface SocialPost {
|
|
|
11
11
|
updated_at: string;
|
|
12
12
|
/** Image URLs from photo_attachments (preferred for display) */
|
|
13
13
|
image_urls?: string[];
|
|
14
|
+
/** Video URLs from photo_attachments (exclude these when choosing img src) */
|
|
15
|
+
video_urls?: string[];
|
|
14
16
|
/** Photo attachments (same pattern as blog post, team member, etc.) */
|
|
15
17
|
photo_attachments?: PhotoAttachment[];
|
|
16
18
|
/** Legacy; prefer image_urls / photo_attachments */
|
|
@@ -4,6 +4,19 @@
|
|
|
4
4
|
|
|
5
5
|
import type { WebsitePhotos } from '../types/api/website-photos';
|
|
6
6
|
|
|
7
|
+
/** Video file extensions treated as video (match backend ExternalPhotoService.video_url?) */
|
|
8
|
+
const VIDEO_EXTENSIONS = ['.mp4', '.mov', '.webm', '.m4v', '.avi', '.mkv', '.flv', '.wmv'];
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* True if the URL looks like a video by path extension. Used to avoid using video URLs in img src.
|
|
12
|
+
*/
|
|
13
|
+
export function isVideoUrl(url: string | null | undefined): boolean {
|
|
14
|
+
if (!url || typeof url !== 'string') return false;
|
|
15
|
+
const path = url.split('?')[0] ?? '';
|
|
16
|
+
const ext = path.slice(path.lastIndexOf('.')).toLowerCase();
|
|
17
|
+
return VIDEO_EXTENSIONS.includes(ext);
|
|
18
|
+
}
|
|
19
|
+
|
|
7
20
|
export interface PhotoAttachment {
|
|
8
21
|
id: number;
|
|
9
22
|
photo: {
|