diff --git a/build/social-web/style-feed-stage-rtl.css b/build/social-web/style-feed-stage-rtl.css index d22ce0d123..43a53c6f72 100644 --- a/build/social-web/style-feed-stage-rtl.css +++ b/build/social-web/style-feed-stage-rtl.css @@ -1,5 +1,5 @@ .page{display:flex;flex-direction:column;height:100%;min-width:0}.header{flex-shrink:0;padding:var(--wpds-spacing-60,24px)}.header.has-border{border-bottom:var(--wpds-border-width-focus,1px) solid var(--wpds-color-stroke-surface-neutral,#ddd)}.title-row{gap:var(--wpds-spacing-40,16px);justify-content:space-between}.title-group,.title-row{align-items:center;display:flex}.title-group{gap:var(--wpds-spacing-30,12px)}.title{color:var(--wpds-color-fg-primary,#1e1e1e);font-size:var(--wpds-font-size-large,20px);font-weight:500;margin:0}.sub-title{color:var(--wpds-color-fg-secondary,#757575);font-size:var(--wpds-font-size-small,13px);margin:var(--wpds-spacing-20,8px) 0 0}.content{display:flex;flex:1;flex-direction:column;gap:var(--wpds-spacing-60,24px);overflow:auto}.content.padded{padding:var(--wpds-spacing-60,24px)}.content.constrained{margin:0 auto;max-width:960px;width:100%}.content.full{padding:0} .dataviews-view-table .activitypub-avatar-field__image{height:32px;width:32px} -.activitypub-feed-content{border-bottom:var(--wpds-border-width-control,1px) solid var(--wpds-color-stroke-neutral-weak,#dcdcde);color:var(--wpds-color-fg-primary,#2c3338);line-height:1.6;max-width:100%;min-width:0;overflow-wrap:break-word;word-wrap:break-word}.activitypub-feed-content:last-child{border-bottom:none}.activitypub-feed-content>:first-child{margin-top:0}.activitypub-feed-content>:last-child{margin-bottom:0} +.activitypub-feed-content{border-bottom:var(--wpds-border-width-control,1px) solid var(--wpds-color-stroke-neutral-weak,#dcdcde);color:var(--wpds-color-fg-primary,#2c3338);line-height:1.6;max-width:100%;min-width:0;overflow-wrap:break-word;word-wrap:break-word}.activitypub-feed-content:last-child{border-bottom:none}.activitypub-feed-content>:first-child{margin-top:0}.activitypub-feed-content>:last-child{margin-bottom:0}.activitypub-feed-content__image,.activitypub-feed-excerpt__image{border-radius:4px;display:block;height:auto;margin-top:1em;max-height:300px;max-width:300px;width:auto} .activitypub-mutual{background:#dcdcde;border-radius:3px;color:#50575e;display:inline-block;font-size:11px;font-weight:600;padding:2px 8px;text-transform:uppercase} .app-layout[data-section=feed] .inspector-region{width:50%}.dataviews-footer:empty{border:0;padding:0}.dataviews-view-list .dataviews-view-list__item{cursor:pointer}.dataviews-view-list .dataviews-view-list__field{width:100%}.wp-block-gallery.has-nested-images{display:flex;flex-wrap:wrap;gap:var(--wp--style--gallery-gap-default,var(--gallery-block--gutter-size,var(--wp--style--block-gap,.5em)))}.activitypub-feed-post-meta{align-items:center;color:var(--wpds-color-fg-secondary,#646970);display:flex;font-size:var(--wpds-font-size-small,13px);gap:var(--wpds-spacing-20,8px);margin-bottom:var(--wpds-spacing-30,12px)}.activitypub-feed-post-meta .activitypub-feed-avatar{background-color:var(--wpds-color-bg-neutral-weak,#f0f0f1);border-radius:50%;flex-shrink:0;height:var(--wpds-spacing-50,20px);-o-object-fit:cover;object-fit:cover;width:var(--wpds-spacing-50,20px)}.activitypub-feed-post-meta .author{color:var(--wpds-color-fg-primary,#1d2327);font-weight:var(--wpds-font-weight-medium,500)}.activitypub-feed-post-meta .separator{color:var(--wpds-color-fg-tertiary,#c3c4c7)}.activitypub-feed-post-meta .date{color:var(--wpds-color-fg-secondary,#646970)}.activitypub-feed-post-title{color:var(--wpds-color-fg-primary,#1d2327);font-size:inherit;font-weight:400;line-height:1.4;margin:0 0 var(--wpds-spacing-30,12px);max-width:100%;overflow-wrap:break-word;word-wrap:break-word}.activitypub-feed-post-title>*{margin:0}.activitypub-feed-excerpt{color:var(--wpds-color-fg-secondary,#50575e);font-size:var(--wpds-font-size-small,13px);line-height:1.6;margin-top:var(--wpds-spacing-15,6px);max-width:100%;overflow-wrap:break-word;word-wrap:break-word}.dataviews-view-list .activitypub-feed-post-title{font-size:1.3em;font-weight:var(--wpds-font-weight-semibold,600)}.activitypub-inspector{height:100%;overflow:auto}.activitypub-inspector-loading{padding:var(--wpds-spacing-50,20px);text-align:center}.activitypub-inspector-card{background:transparent!important;border:none!important;border-radius:0!important;box-shadow:none!important;margin-bottom:var(--wpds-spacing-60,24px)!important;padding:0!important}.activitypub-inspector-card .components-card__header{border:none!important;border-bottom:var(--wpds-border-width-control,1px) solid var(--wpds-color-stroke-neutral-weak,#dcdcde)!important;border-radius:0!important;padding:var(--wpds-spacing-60,24px) var(--wpds-spacing-60,24px) var(--wpds-spacing-40,16px)!important}.activitypub-inspector-card .components-card__body{padding:var(--wpds-spacing-40,16px) var(--wpds-spacing-60,24px) 0!important}.activitypub-inspector-comments-card{border-top:var(--wpds-border-width-control,1px) solid var(--wpds-color-stroke-neutral-weak,#dcdcde)!important;margin-top:var(--wpds-spacing-60,24px)!important;padding-top:var(--wpds-spacing-60,24px)!important}.activitypub-inspector-comments-card .components-card__header{border-bottom:none!important;font-size:var(--wpds-font-size-medium,16px);font-weight:var(--wpds-font-weight-semibold,600);padding-bottom:var(--wpds-spacing-30,12px)!important}.activitypub-inspector-header{align-items:center;display:flex;gap:var(--wpds-spacing-30,12px);width:100%}.activitypub-inspector-close{flex-shrink:0;margin-right:auto}.activitypub-inspector-avatar{background-color:var(--wpds-color-bg-neutral-weak,#f0f0f1);border-radius:50%;flex-shrink:0;height:var(--wpds-spacing-120,48px);-o-object-fit:cover;object-fit:cover;width:var(--wpds-spacing-120,48px)}.activitypub-inspector-author{display:flex;flex-direction:column;gap:var(--wpds-spacing-10,4px)}.activitypub-inspector-author-name{color:var(--wpds-color-fg-primary,#1d2327);font-size:var(--wpds-font-size-small,14px);font-weight:var(--wpds-font-weight-semibold,600);text-decoration:none}.activitypub-inspector-author-name:hover{color:var(--wpds-color-fg-brand,#135e96);text-decoration:underline}.activitypub-inspector-meta{align-items:center;display:flex;font-size:var(--wpds-font-size-small,13px);gap:var(--wpds-spacing-15,6px)}.activitypub-inspector-webfinger{color:var(--wpds-color-fg-secondary,#646970)}.activitypub-inspector-separator{color:var(--wpds-color-fg-tertiary,#c3c4c7)}.activitypub-inspector-timestamp{color:var(--wpds-color-fg-secondary,#646970);text-decoration:none}.activitypub-inspector-timestamp:hover{color:var(--wpds-color-fg-brand,#135e96);text-decoration:underline}.activitypub-inspector-card .components-card__body h2{color:var(--wpds-color-fg-primary,#1d2327);font-size:var(--wpds-font-size-large,20px);font-weight:var(--wpds-font-weight-semibold,600);line-height:1.4;margin:0 0 var(--wpds-spacing-40,16px)}.activitypub-inspector-card .components-card__body>div{color:var(--wpds-color-fg-primary,#2c3338);line-height:1.6;margin-bottom:var(--wpds-spacing-40,16px)}.activitypub-inspector-card .components-card__body>div img{height:auto;max-width:100%}.activitypub-inspector-link{margin-top:var(--wpds-spacing-40,16px)}.activitypub-inspector-comment{border-bottom:var(--wpds-border-width-control,1px) solid var(--wpds-color-stroke-neutral-weak,#f0f0f1);margin-bottom:var(--wpds-spacing-50,20px);padding-bottom:var(--wpds-spacing-50,20px)}.activitypub-inspector-comment:last-child{border-bottom:none;margin-bottom:0;padding-bottom:0}.activitypub-inspector-comment-meta{margin-bottom:var(--wpds-spacing-20,8px)}.activitypub-inspector-comment-meta strong{color:var(--wpds-color-fg-primary,#1d2327);font-size:var(--wpds-font-size-small,14px)}.activitypub-inspector-comment-date{color:var(--wpds-color-fg-secondary,#646970);font-size:var(--wpds-font-size-small,13px);margin-right:var(--wpds-spacing-20,8px)}.activitypub-inspector-tags{border-top:var(--wpds-border-width-control,1px) solid var(--wpds-color-stroke-neutral-weak,#dcdcde);display:flex;flex-wrap:wrap;gap:var(--wpds-spacing-20,8px);margin-top:var(--wpds-spacing-40,16px);padding-top:var(--wpds-spacing-40,16px)}.activitypub-inspector-tag{font-size:var(--wpds-font-size-small,13px);min-height:0;padding:var(--wpds-spacing-10,4px) var(--wpds-spacing-20,8px)}.activitypub-inspector-tag:hover{background-color:var(--wpds-color-bg-interactive-hover,#f0f0f1);color:var(--wpds-color-fg-interactive-hover,#2c3338)}.activitypub-feed-content a,.activitypub-inspector-card .components-card__body a{color:var(--wpds-color-fg-brand,#135e96);text-decoration:none;word-wrap:break-word;overflow-wrap:break-word}.activitypub-feed-content a:hover,.activitypub-inspector-card .components-card__body a:hover{text-decoration:underline}.activitypub-feed-content a .invisible,.activitypub-inspector-card .components-card__body a .invisible{display:none}.activitypub-feed-content a .ellipsis:after,.activitypub-inspector-card .components-card__body a .ellipsis:after{content:"…"} diff --git a/build/social-web/style-feed-stage.css b/build/social-web/style-feed-stage.css index 441025b142..53c0c7a33a 100644 --- a/build/social-web/style-feed-stage.css +++ b/build/social-web/style-feed-stage.css @@ -1,5 +1,5 @@ .page{display:flex;flex-direction:column;height:100%;min-width:0}.header{flex-shrink:0;padding:var(--wpds-spacing-60,24px)}.header.has-border{border-bottom:var(--wpds-border-width-focus,1px) solid var(--wpds-color-stroke-surface-neutral,#ddd)}.title-row{gap:var(--wpds-spacing-40,16px);justify-content:space-between}.title-group,.title-row{align-items:center;display:flex}.title-group{gap:var(--wpds-spacing-30,12px)}.title{color:var(--wpds-color-fg-primary,#1e1e1e);font-size:var(--wpds-font-size-large,20px);font-weight:500;margin:0}.sub-title{color:var(--wpds-color-fg-secondary,#757575);font-size:var(--wpds-font-size-small,13px);margin:var(--wpds-spacing-20,8px) 0 0}.content{display:flex;flex:1;flex-direction:column;gap:var(--wpds-spacing-60,24px);overflow:auto}.content.padded{padding:var(--wpds-spacing-60,24px)}.content.constrained{margin:0 auto;max-width:960px;width:100%}.content.full{padding:0} .dataviews-view-table .activitypub-avatar-field__image{height:32px;width:32px} -.activitypub-feed-content{border-bottom:var(--wpds-border-width-control,1px) solid var(--wpds-color-stroke-neutral-weak,#dcdcde);color:var(--wpds-color-fg-primary,#2c3338);line-height:1.6;max-width:100%;min-width:0;overflow-wrap:break-word;word-wrap:break-word}.activitypub-feed-content:last-child{border-bottom:none}.activitypub-feed-content>:first-child{margin-top:0}.activitypub-feed-content>:last-child{margin-bottom:0} +.activitypub-feed-content{border-bottom:var(--wpds-border-width-control,1px) solid var(--wpds-color-stroke-neutral-weak,#dcdcde);color:var(--wpds-color-fg-primary,#2c3338);line-height:1.6;max-width:100%;min-width:0;overflow-wrap:break-word;word-wrap:break-word}.activitypub-feed-content:last-child{border-bottom:none}.activitypub-feed-content>:first-child{margin-top:0}.activitypub-feed-content>:last-child{margin-bottom:0}.activitypub-feed-content__image,.activitypub-feed-excerpt__image{border-radius:4px;display:block;height:auto;margin-top:1em;max-height:300px;max-width:300px;width:auto} .activitypub-mutual{background:#dcdcde;border-radius:3px;color:#50575e;display:inline-block;font-size:11px;font-weight:600;padding:2px 8px;text-transform:uppercase} .app-layout[data-section=feed] .inspector-region{width:50%}.dataviews-footer:empty{border:0;padding:0}.dataviews-view-list .dataviews-view-list__item{cursor:pointer}.dataviews-view-list .dataviews-view-list__field{width:100%}.wp-block-gallery.has-nested-images{display:flex;flex-wrap:wrap;gap:var(--wp--style--gallery-gap-default,var(--gallery-block--gutter-size,var(--wp--style--block-gap,.5em)))}.activitypub-feed-post-meta{align-items:center;color:var(--wpds-color-fg-secondary,#646970);display:flex;font-size:var(--wpds-font-size-small,13px);gap:var(--wpds-spacing-20,8px);margin-bottom:var(--wpds-spacing-30,12px)}.activitypub-feed-post-meta .activitypub-feed-avatar{background-color:var(--wpds-color-bg-neutral-weak,#f0f0f1);border-radius:50%;flex-shrink:0;height:var(--wpds-spacing-50,20px);-o-object-fit:cover;object-fit:cover;width:var(--wpds-spacing-50,20px)}.activitypub-feed-post-meta .author{color:var(--wpds-color-fg-primary,#1d2327);font-weight:var(--wpds-font-weight-medium,500)}.activitypub-feed-post-meta .separator{color:var(--wpds-color-fg-tertiary,#c3c4c7)}.activitypub-feed-post-meta .date{color:var(--wpds-color-fg-secondary,#646970)}.activitypub-feed-post-title{color:var(--wpds-color-fg-primary,#1d2327);font-size:inherit;font-weight:400;line-height:1.4;margin:0 0 var(--wpds-spacing-30,12px);max-width:100%;overflow-wrap:break-word;word-wrap:break-word}.activitypub-feed-post-title>*{margin:0}.activitypub-feed-excerpt{color:var(--wpds-color-fg-secondary,#50575e);font-size:var(--wpds-font-size-small,13px);line-height:1.6;margin-top:var(--wpds-spacing-15,6px);max-width:100%;overflow-wrap:break-word;word-wrap:break-word}.dataviews-view-list .activitypub-feed-post-title{font-size:1.3em;font-weight:var(--wpds-font-weight-semibold,600)}.activitypub-inspector{height:100%;overflow:auto}.activitypub-inspector-loading{padding:var(--wpds-spacing-50,20px);text-align:center}.activitypub-inspector-card{background:transparent!important;border:none!important;border-radius:0!important;box-shadow:none!important;margin-bottom:var(--wpds-spacing-60,24px)!important;padding:0!important}.activitypub-inspector-card .components-card__header{border:none!important;border-bottom:var(--wpds-border-width-control,1px) solid var(--wpds-color-stroke-neutral-weak,#dcdcde)!important;border-radius:0!important;padding:var(--wpds-spacing-60,24px) var(--wpds-spacing-60,24px) var(--wpds-spacing-40,16px)!important}.activitypub-inspector-card .components-card__body{padding:var(--wpds-spacing-40,16px) var(--wpds-spacing-60,24px) 0!important}.activitypub-inspector-comments-card{border-top:var(--wpds-border-width-control,1px) solid var(--wpds-color-stroke-neutral-weak,#dcdcde)!important;margin-top:var(--wpds-spacing-60,24px)!important;padding-top:var(--wpds-spacing-60,24px)!important}.activitypub-inspector-comments-card .components-card__header{border-bottom:none!important;font-size:var(--wpds-font-size-medium,16px);font-weight:var(--wpds-font-weight-semibold,600);padding-bottom:var(--wpds-spacing-30,12px)!important}.activitypub-inspector-header{align-items:center;display:flex;gap:var(--wpds-spacing-30,12px);width:100%}.activitypub-inspector-close{flex-shrink:0;margin-left:auto}.activitypub-inspector-avatar{background-color:var(--wpds-color-bg-neutral-weak,#f0f0f1);border-radius:50%;flex-shrink:0;height:var(--wpds-spacing-120,48px);-o-object-fit:cover;object-fit:cover;width:var(--wpds-spacing-120,48px)}.activitypub-inspector-author{display:flex;flex-direction:column;gap:var(--wpds-spacing-10,4px)}.activitypub-inspector-author-name{color:var(--wpds-color-fg-primary,#1d2327);font-size:var(--wpds-font-size-small,14px);font-weight:var(--wpds-font-weight-semibold,600);text-decoration:none}.activitypub-inspector-author-name:hover{color:var(--wpds-color-fg-brand,#135e96);text-decoration:underline}.activitypub-inspector-meta{align-items:center;display:flex;font-size:var(--wpds-font-size-small,13px);gap:var(--wpds-spacing-15,6px)}.activitypub-inspector-webfinger{color:var(--wpds-color-fg-secondary,#646970)}.activitypub-inspector-separator{color:var(--wpds-color-fg-tertiary,#c3c4c7)}.activitypub-inspector-timestamp{color:var(--wpds-color-fg-secondary,#646970);text-decoration:none}.activitypub-inspector-timestamp:hover{color:var(--wpds-color-fg-brand,#135e96);text-decoration:underline}.activitypub-inspector-card .components-card__body h2{color:var(--wpds-color-fg-primary,#1d2327);font-size:var(--wpds-font-size-large,20px);font-weight:var(--wpds-font-weight-semibold,600);line-height:1.4;margin:0 0 var(--wpds-spacing-40,16px)}.activitypub-inspector-card .components-card__body>div{color:var(--wpds-color-fg-primary,#2c3338);line-height:1.6;margin-bottom:var(--wpds-spacing-40,16px)}.activitypub-inspector-card .components-card__body>div img{height:auto;max-width:100%}.activitypub-inspector-link{margin-top:var(--wpds-spacing-40,16px)}.activitypub-inspector-comment{border-bottom:var(--wpds-border-width-control,1px) solid var(--wpds-color-stroke-neutral-weak,#f0f0f1);margin-bottom:var(--wpds-spacing-50,20px);padding-bottom:var(--wpds-spacing-50,20px)}.activitypub-inspector-comment:last-child{border-bottom:none;margin-bottom:0;padding-bottom:0}.activitypub-inspector-comment-meta{margin-bottom:var(--wpds-spacing-20,8px)}.activitypub-inspector-comment-meta strong{color:var(--wpds-color-fg-primary,#1d2327);font-size:var(--wpds-font-size-small,14px)}.activitypub-inspector-comment-date{color:var(--wpds-color-fg-secondary,#646970);font-size:var(--wpds-font-size-small,13px);margin-left:var(--wpds-spacing-20,8px)}.activitypub-inspector-tags{border-top:var(--wpds-border-width-control,1px) solid var(--wpds-color-stroke-neutral-weak,#dcdcde);display:flex;flex-wrap:wrap;gap:var(--wpds-spacing-20,8px);margin-top:var(--wpds-spacing-40,16px);padding-top:var(--wpds-spacing-40,16px)}.activitypub-inspector-tag{font-size:var(--wpds-font-size-small,13px);min-height:0;padding:var(--wpds-spacing-10,4px) var(--wpds-spacing-20,8px)}.activitypub-inspector-tag:hover{background-color:var(--wpds-color-bg-interactive-hover,#f0f0f1);color:var(--wpds-color-fg-interactive-hover,#2c3338)}.activitypub-feed-content a,.activitypub-inspector-card .components-card__body a{color:var(--wpds-color-fg-brand,#135e96);text-decoration:none;word-wrap:break-word;overflow-wrap:break-word}.activitypub-feed-content a:hover,.activitypub-inspector-card .components-card__body a:hover{text-decoration:underline}.activitypub-feed-content a .invisible,.activitypub-inspector-card .components-card__body a .invisible{display:none}.activitypub-feed-content a .ellipsis:after,.activitypub-inspector-card .components-card__body a .ellipsis:after{content:"…"} diff --git a/includes/class-attachments.php b/includes/class-attachments.php index 01b21c1306..e36c9d70d7 100644 --- a/includes/class-attachments.php +++ b/includes/class-attachments.php @@ -182,6 +182,15 @@ private static function import_files_for_object( $attachments, $object_id, $obje self::append_files_to_content( $object_id, $files, $object_type ); } + // Add inline mappings to the returned files. + // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- We only need the new URL, not the old one. + foreach ( $inline_mappings as $old_url => $new_url ) { + $files[] = array( + 'url' => $new_url, + 'mime_type' => 'image/*', + ); + } + return $files; } diff --git a/includes/class-post-types.php b/includes/class-post-types.php index 77b77b332e..9d30701de3 100644 --- a/includes/class-post-types.php +++ b/includes/class-post-types.php @@ -406,6 +406,17 @@ public static function register_post_post_type() { 'sanitize_callback' => 'absint', ) ); + + \register_post_meta( + Posts::POST_TYPE, + '_activitypub_featured_image_url', + array( + 'type' => 'string', + 'single' => true, + 'description' => 'URL of the featured image from ActivityPub attachments.', + 'sanitize_callback' => 'sanitize_url', + ) + ); } /** @@ -691,6 +702,27 @@ public static function register_ap_post_actor_rest_field() { ), ) ); + + \register_rest_field( + Posts::POST_TYPE, + 'featured_image', + array( + /** + * Get the featured image for an ap_post. + * + * @param array $response Prepared response array. + * @return string|null The image URL or null if not found. + */ + 'get_callback' => function ( $response ) { + return \get_post_meta( $response['id'], '_activitypub_featured_image_url', true ) ?: null; + }, + 'schema' => array( + 'description' => 'Featured image URL from ActivityPub attachments', + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + ) + ); } /** diff --git a/includes/collection/class-posts.php b/includes/collection/class-posts.php index 3b981f7fb7..3a9a4c41ec 100644 --- a/includes/collection/class-posts.php +++ b/includes/collection/class-posts.php @@ -143,6 +143,7 @@ public static function update( $activity, $recipients ) { self::add_taxonomies( $post_id, $activity['object'] ); // Always delete existing attachments on update in case filter value changed. + \delete_post_meta( $post_id, '_activitypub_featured_image_url' ); Attachments::delete_ap_posts_directory( $post_id ); self::maybe_import_attachments( $activity['object'], $post_id ); @@ -325,7 +326,22 @@ private static function maybe_import_attachments( $activity_object, $post_id ) { $store_locally = \apply_filters( 'activitypub_store_attachments_locally', true, $activity_object, $post_id ); if ( $store_locally ) { - Attachments::import_post_files( $activity_object['attachment'], $post_id ); + $files = Attachments::import_post_files( $activity_object['attachment'], $post_id ); + + // Save the featured image URL as post meta for efficient retrieval. + if ( ! empty( $files ) ) { + foreach ( $files as $file ) { + // Check if this is an image file. + if ( isset( $file['mime_type'] ) && 0 === strpos( $file['mime_type'], 'image/' ) ) { + \update_post_meta( + $post_id, + '_activitypub_featured_image_url', + $file['url'] + ); + break; // Only save the first image. + } + } + } } } diff --git a/src/social-web/components/fields/content/index.tsx b/src/social-web/components/fields/content/index.tsx index 06b1e65e36..89552fee96 100644 --- a/src/social-web/components/fields/content/index.tsx +++ b/src/social-web/components/fields/content/index.tsx @@ -36,6 +36,7 @@ export const contentField: Field< FeedPost > = { // Check if this is a Note type const isNote = objectTypeName === 'Note'; + const hasFeaturedImage = !! item.featured_image; if ( isNote ) { // Show full content for Notes (HTML) @@ -47,6 +48,14 @@ export const contentField: Field< FeedPost > = { className="activitypub-feed-content" dangerouslySetInnerHTML={ { __html: content || '

\u00A0

' } } /> + { hasFeaturedImage && ( + { + ) } ); } @@ -54,6 +63,22 @@ export const contentField: Field< FeedPost > = { // Show excerpt for Articles and other types (plain text) const plainText = contentField.getValue( { item } ).trim(); - return
{ plainText || '\u00A0' }
; + if ( ! plainText && ! hasFeaturedImage ) { + return
{ '\u00A0' }
; + } + + return ( +
+ { plainText &&
{ plainText }
} + { hasFeaturedImage && ( + { + ) } +
+ ); }, }; diff --git a/src/social-web/components/fields/content/style.scss b/src/social-web/components/fields/content/style.scss index 355f3762b5..151e7ed84d 100644 --- a/src/social-web/components/fields/content/style.scss +++ b/src/social-web/components/fields/content/style.scss @@ -20,4 +20,26 @@ > *:last-child { margin-bottom: 0; } + + &__image { + display: block; + width: auto; + max-width: 300px; + max-height: 300px; + height: auto; + margin-top: 1em; + border-radius: 4px; + } +} + +.activitypub-feed-excerpt { + &__image { + display: block; + width: auto; + max-width: 300px; + max-height: 300px; + height: auto; + margin-top: 1em; + border-radius: 4px; + } } diff --git a/src/social-web/components/fields/featured-image/index.tsx b/src/social-web/components/fields/featured-image/index.tsx new file mode 100644 index 0000000000..edcdf0e4b9 --- /dev/null +++ b/src/social-web/components/fields/featured-image/index.tsx @@ -0,0 +1,31 @@ +/** + * Featured Image field for DataViews. + * + * Displays the featured image from ActivityPub attachments. + */ + +import { __ } from '@wordpress/i18n'; +import type { Field } from '@wordpress/dataviews'; +import type { FeedPost } from '../../../types'; +import './style.scss'; + +export const featuredImageField: Field< FeedPost > = { + id: 'featured_image', + label: __( 'Image', 'activitypub' ), + enableHiding: true, + enableSorting: false, + getValue: ( { item }: { item: FeedPost } ) => item.featured_image || '', + render: ( { item }: { item: FeedPost } ) => { + if ( ! item.featured_image ) { + return null; + } + + const altText = item.title?.rendered || __( 'Post Thumbnail', 'activitypub' ); + + return ( +
+ { +
+ ); + }, +}; diff --git a/src/social-web/components/fields/featured-image/style.scss b/src/social-web/components/fields/featured-image/style.scss new file mode 100644 index 0000000000..b4493292d7 --- /dev/null +++ b/src/social-web/components/fields/featured-image/style.scss @@ -0,0 +1,18 @@ +// Target the featured image field wrapper in the list view +.dataviews-view-list__fields .dataviews-view-list__field:has(.activitypub-featured-image) { + order: 999; // Push to the end (right side) + margin-left: auto; // Align to the right +} + +.activitypub-featured-image { + max-width: 120px; + + img { + width: 100%; + height: auto; + display: block; + border-radius: 4px; + object-fit: cover; + max-height: 120px; + } +} diff --git a/src/social-web/hooks/use-feed.ts b/src/social-web/hooks/use-feed.ts index 887611b955..4706902f69 100644 --- a/src/social-web/hooks/use-feed.ts +++ b/src/social-web/hooks/use-feed.ts @@ -44,6 +44,7 @@ export function useFeed( { 'actor_info', 'status', 'link', + 'featured_image', 'ap_object_type', 'ap_tag', ], diff --git a/src/social-web/types.ts b/src/social-web/types.ts index 90a772b59d..8cd0122670 100644 --- a/src/social-web/types.ts +++ b/src/social-web/types.ts @@ -86,6 +86,7 @@ export interface FeedPost { }; comment_status: string; ping_status: string; + featured_image?: string; ap_object_type?: number[]; ap_tag?: number[]; actor_info?: ActorInfo;