refactor(posts): return the card display domain from the backend
Compute the bare display host once in LinkCardMetadata (via Laravel's Uri::host + Str::chopStart) and return it as card.domain, so the LinkCard component renders it directly instead of parsing the URL client-side. The component is now purely presentational.
This commit is contained in:
parent
7c79b331f6
commit
925fd85b95
4 changed files with 22 additions and 15 deletions
|
|
@ -4,6 +4,9 @@
|
|||
|
||||
namespace App\Services\Social\LinkCard;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Support\Uri;
|
||||
|
||||
final readonly class LinkCardMetadata
|
||||
{
|
||||
public function __construct(
|
||||
|
|
@ -14,15 +17,29 @@ public function __construct(
|
|||
) {}
|
||||
|
||||
/**
|
||||
* @return array{uri: string, title: string, description: string, image: ?string}
|
||||
* @return array{uri: string, domain: string, title: string, description: string, image: ?string}
|
||||
*/
|
||||
public function toArray(): array
|
||||
{
|
||||
return [
|
||||
'uri' => $this->uri,
|
||||
'domain' => $this->domain(),
|
||||
'title' => $this->title,
|
||||
'description' => $this->description,
|
||||
'image' => $this->imageUrl,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* The bare display host for the card (e.g. "nyt.com" from
|
||||
* "https://www.nyt.com/x"), so the frontend renders it without parsing URLs.
|
||||
*/
|
||||
private function domain(): string
|
||||
{
|
||||
$host = Uri::of($this->uri)->host();
|
||||
|
||||
return $host === null || $host === ''
|
||||
? $this->uri
|
||||
: Str::chopStart($host, 'www.');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,7 @@
|
|||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
|
||||
import type { LinkCard } from '@/composables/useLinkCard';
|
||||
|
||||
const props = defineProps<{ card: LinkCard }>();
|
||||
|
||||
const domain = computed(() => {
|
||||
try {
|
||||
const { hostname } = new URL(props.card.uri);
|
||||
|
||||
return hostname.startsWith('www.') ? hostname.slice(4) : hostname;
|
||||
} catch {
|
||||
return props.card.uri;
|
||||
}
|
||||
});
|
||||
defineProps<{ card: LinkCard }>();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
@ -25,7 +13,7 @@ const domain = computed(() => {
|
|||
class="aspect-[1.91/1] w-full object-cover"
|
||||
/>
|
||||
<div class="px-3 py-2">
|
||||
<div class="text-[13px] text-neutral-500 dark:text-neutral-400">{{ domain }}</div>
|
||||
<div class="text-[13px] text-neutral-500 dark:text-neutral-400">{{ card.domain }}</div>
|
||||
<div
|
||||
v-if="card.title"
|
||||
class="mt-0.5 text-[15px] font-semibold text-neutral-900 dark:text-neutral-100 line-clamp-2"
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import type { MediaItem } from '@/types/media';
|
|||
|
||||
export interface LinkCard {
|
||||
uri: string;
|
||||
domain: string;
|
||||
title: string;
|
||||
description: string;
|
||||
image: string | null;
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
->assertOk()
|
||||
->assertJson([
|
||||
'uri' => 'https://example.com',
|
||||
'domain' => 'example.com',
|
||||
'title' => 'Example',
|
||||
'description' => 'Desc',
|
||||
'image' => 'https://example.com/card.png',
|
||||
|
|
|
|||
Loading…
Reference in a new issue