mirror of https://github.com/usememos/memos
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
77 lines
2.5 KiB
TypeScript
77 lines
2.5 KiB
TypeScript
import { Link as MLink, Tooltip } from "@mui/joy";
|
|
import { useState } from "react";
|
|
import { markdownServiceClient } from "@/grpcweb";
|
|
import { workspaceStore } from "@/store/v2";
|
|
import { LinkMetadata } from "@/types/proto/api/v1/markdown_service";
|
|
import { WorkspaceMemoRelatedSetting } from "@/types/proto/api/v1/workspace_setting_service";
|
|
import { WorkspaceSettingKey } from "@/types/proto/store/workspace_setting";
|
|
|
|
interface Props {
|
|
url: string;
|
|
text?: string;
|
|
}
|
|
|
|
const getFaviconWithGoogleS2 = (url: string) => {
|
|
try {
|
|
const urlObject = new URL(url);
|
|
return `https://www.google.com/s2/favicons?sz=128&domain=${urlObject.hostname}`;
|
|
} catch (error) {
|
|
return undefined;
|
|
}
|
|
};
|
|
|
|
const Link: React.FC<Props> = ({ text, url }: Props) => {
|
|
const workspaceMemoRelatedSetting =
|
|
workspaceStore.getWorkspaceSettingByKey(WorkspaceSettingKey.MEMO_RELATED).memoRelatedSetting ||
|
|
WorkspaceMemoRelatedSetting.fromPartial({});
|
|
const [initialized, setInitialized] = useState<boolean>(false);
|
|
const [showTooltip, setShowTooltip] = useState<boolean>(false);
|
|
const [linkMetadata, setLinkMetadata] = useState<LinkMetadata | undefined>();
|
|
|
|
const handleMouseEnter = async () => {
|
|
if (!workspaceMemoRelatedSetting.enableLinkPreview) {
|
|
return;
|
|
}
|
|
|
|
setShowTooltip(true);
|
|
if (!initialized) {
|
|
try {
|
|
const linkMetadata = await markdownServiceClient.getLinkMetadata({ link: url });
|
|
setLinkMetadata(linkMetadata);
|
|
} catch (error) {
|
|
console.error("Error fetching URL metadata:", error);
|
|
}
|
|
setInitialized(true);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<Tooltip
|
|
variant="outlined"
|
|
title={
|
|
linkMetadata && (
|
|
<div className="w-full max-w-64 sm:max-w-96 p-1 flex flex-col">
|
|
<div className="w-full flex flex-row justify-start items-center gap-1">
|
|
<img className="w-5 h-5 rounded" src={getFaviconWithGoogleS2(url)} alt={linkMetadata?.title} />
|
|
<h3 className="text-base truncate dark:opacity-90">{linkMetadata?.title}</h3>
|
|
</div>
|
|
{linkMetadata.description && (
|
|
<p className="mt-1 w-full text-sm leading-snug opacity-80 line-clamp-3">{linkMetadata.description}</p>
|
|
)}
|
|
</div>
|
|
)
|
|
}
|
|
open={showTooltip}
|
|
arrow
|
|
>
|
|
<MLink underline="always" target="_blank" href={url} rel="noopener noreferrer">
|
|
<span onMouseEnter={handleMouseEnter} onMouseLeave={() => setShowTooltip(false)}>
|
|
{text || url}
|
|
</span>
|
|
</MLink>
|
|
</Tooltip>
|
|
);
|
|
};
|
|
|
|
export default Link;
|