diff --git a/.changeset/smooth-chairs-bow.md b/.changeset/smooth-chairs-bow.md
new file mode 100644
index 000000000..1ef49363c
--- /dev/null
+++ b/.changeset/smooth-chairs-bow.md
@@ -0,0 +1,5 @@
+---
+"nostrudel": patch
+---
+
+Fix link cards breaking lines
diff --git a/src/components/embed-types/common.tsx b/src/components/embed-types/common.tsx
index bb55a436e..9c7f5581a 100644
--- a/src/components/embed-types/common.tsx
+++ b/src/components/embed-types/common.tsx
@@ -2,6 +2,7 @@ import { Link } from "@chakra-ui/react";
import OpenGraphCard from "../open-graph-card";
import { isVideoURL } from "../../helpers/url";
+import OpenGraphLink from "../open-graph-link";
export function renderVideoUrl(match: URL) {
if (!isVideoURL(match)) return null;
@@ -23,6 +24,6 @@ export function renderGenericUrl(match: URL) {
);
}
-export function renderOpenGraphUrl(match: URL) {
- return ;
+export function renderOpenGraphUrl(match: URL, isEndOfLine: boolean) {
+ return isEndOfLine ? : ;
}
diff --git a/src/components/open-graph-link.tsx b/src/components/open-graph-link.tsx
new file mode 100644
index 000000000..7ce7868b1
--- /dev/null
+++ b/src/components/open-graph-link.tsx
@@ -0,0 +1,12 @@
+import { Link, LinkProps } from "@chakra-ui/react";
+import useOpenGraphData from "../hooks/use-open-graph-data";
+
+export default function OpenGraphLink({ url, ...props }: { url: URL } & Omit) {
+ const { value: data } = useOpenGraphData(url);
+
+ return (
+
+ {data?.ogTitle?.trim() ?? data?.dcTitle?.trim() ?? decodeURI(url.toString())}
+
+ );
+}
diff --git a/src/helpers/embeds.ts b/src/helpers/embeds.ts
index 1e7b1474a..7add63f79 100644
--- a/src/helpers/embeds.ts
+++ b/src/helpers/embeds.ts
@@ -4,7 +4,7 @@ import { getMatchLink } from "./regexp";
export type EmbedableContent = (string | JSX.Element)[];
export type EmbedType = {
regexp: RegExp;
- render: (match: RegExpMatchArray) => JSX.Element | string | null;
+ render: (match: RegExpMatchArray, isEndOfLine: boolean) => JSX.Element | string | null;
name: string;
getLocation?: (match: RegExpMatchArray) => { start: number; end: number };
};
@@ -35,7 +35,8 @@ export function embedJSX(content: EmbedableContent, embed: EmbedType): Embedable
const before = str.slice(0, start - cursor);
const after = str.slice(end - cursor, str.length);
- let render = embed.render(match);
+ const isEndOfLine = /^\p{Z}*(\n|$)/iu.test(after);
+ let render = embed.render(match, isEndOfLine);
if (render === null) continue;
if (typeof render !== "string" && !render.props.key) {
@@ -68,18 +69,18 @@ export function embedJSX(content: EmbedableContent, embed: EmbedType): Embedable
.flat();
}
-export type LinkEmbedHandler = (link: URL) => JSX.Element | string | null;
+export type LinkEmbedHandler = (link: URL, isEndOfLine: boolean) => JSX.Element | string | null;
export function embedUrls(content: EmbedableContent, handlers: LinkEmbedHandler[]) {
return embedJSX(content, {
name: "embedUrls",
regexp: getMatchLink(),
- render: (match) => {
+ render: (match, isEndOfLine) => {
try {
const url = new URL(match[0]);
for (const handler of handlers) {
try {
- const content = handler(url);
+ const content = handler(url, isEndOfLine);
if (content) return content;
} catch (e) {}
}