feat: implemented link previews (frontend files) (#3074)

* feat: implmented link previews (frontend files)

* chore: updated frontend side for Link Previews

* chore: updated frontend gen types with the renamed (server) service file

* fix: passing errors

* chore: switched to using generated type instead of separate fields

* fix: passing linter error

* chore: updated Link.tsx

* chore: using `useResponsiveWidth` to render for different devices

* chore: refactored Link.tsx
This commit is contained in:
Mehad Nadeem 2024-03-16 19:51:16 +05:00 committed by GitHub
parent 14479347d8
commit 9c1e2f8137
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 85 additions and 8 deletions

View file

@ -1,18 +1,92 @@
import { Tooltip, Card, AspectRatio, Box } from "@mui/joy";
import { Link as MLink } from "@mui/joy";
import { useEffect, useState } from "react";
import { linkServiceClient } from "@/grpcweb";
import useResponsiveWidth from "@/hooks/useResponsiveWidth";
import { LinkMetadata } from "@/types/proto/api/v2/link_service";
interface Props {
url: string;
text?: string;
}
const Link: React.FC<Props> = ({ text, url }: Props) => {
const [linkMetadata, setLinkMetadata] = useState<LinkMetadata | undefined>();
const { md } = useResponsiveWidth();
const fetchUrlMetadata = async () => {
try {
const response = await linkServiceClient.getLinkMetadata({ link: url }, {});
setLinkMetadata(response.metadata);
} catch (error) {
console.error("Error fetching URL metadata:", error);
return null;
}
};
useEffect(() => {
fetchUrlMetadata();
}, [url]);
return (
<a
className="text-blue-600 dark:text-blue-400 cursor-pointer underline break-all hover:opacity-80 decoration-1"
href={url}
target="_blank"
rel="noopener noreferrer"
<>
{md ? (
<div>
<Tooltip
placement="top-end"
variant="solid"
sx={{}}
title={
<Box
sx={{
display: "flex",
flexDirection: "row",
maxWidth: 450,
maxHeight: 300,
}}
>
{text || url}
{linkMetadata?.image ? (
<a href={url} target="_blank" rel="noopener noreferrer" className="flex w-full">
<Card variant="outlined" orientation="vertical" sx={{ width: "100%" }}>
<AspectRatio ratio={"21/9"} objectFit="cover" variant="plain">
<img src={linkMetadata?.image} alt={linkMetadata?.title} className="pointer-events-none" />
</AspectRatio>
<div className="flex-1 overflow-auto w-full">
<div className="flex flex-col justify-between ">
<div>
<h3 className="text-2xl font-semibold tracking-tight truncate">{linkMetadata?.title}</h3>
{linkMetadata?.description && <p className="text-sm truncate">{linkMetadata?.description}</p>}
</div>
</div>
</div>
</Card>
</a>
) : (
<Card variant="soft" orientation="vertical" sx={{ width: "100%" }}>
<div className="flex-1 overflow-auto w-full">
<div className="flex flex-col justify-between ">
<div>
<h3 className="text-2xl font-semibold tracking-tight">{linkMetadata?.title}</h3>
<p className="text-sm text-black/50 dark:text-white/50">No Preview</p>
</div>
</div>
</div>
</Card>
)}
</Box>
}
>
<MLink href={url} underline="none" sx={{ fontWeight: "lg" }}>
{url || text}
</MLink>
</Tooltip>
</div>
) : (
<MLink href={url} underline="none" sx={{ fontWeight: "lg" }}>
{url || text}
</MLink>
)}
</>
);
};

View file

@ -2,6 +2,7 @@ import { createChannel, createClientFactory, FetchTransport } from "nice-grpc-we
import { ActivityServiceDefinition } from "./types/proto/api/v2/activity_service";
import { AuthServiceDefinition } from "./types/proto/api/v2/auth_service";
import { InboxServiceDefinition } from "./types/proto/api/v2/inbox_service";
import { LinkServiceDefinition } from "./types/proto/api/v2/link_service";
import { MemoServiceDefinition } from "./types/proto/api/v2/memo_service";
import { ResourceServiceDefinition } from "./types/proto/api/v2/resource_service";
import { TagServiceDefinition } from "./types/proto/api/v2/tag_service";
@ -38,3 +39,5 @@ export const inboxServiceClient = clientFactory.create(InboxServiceDefinition, c
export const activityServiceClient = clientFactory.create(ActivityServiceDefinition, channel);
export const webhookServiceClient = clientFactory.create(WebhookServiceDefinition, channel);
export const linkServiceClient = clientFactory.create(LinkServiceDefinition, channel);