Use the node short description in link preview metadata
Hop-State: A_06FPEC5CSW59V0KHWX0W1ER Hop-Proposal: R_06FPEC4XSJJ03M62S8AA9P0 Hop-Task: T_06FPEBTP53BQJHKGSPK894G Hop-Attempt: AT_06FPEBTP50KTCJ3YT789R78
This commit is contained in:
+9
-11
@@ -13,26 +13,24 @@ const sairaCondensed = Saira_Condensed({
|
||||
variable: "--font-saira",
|
||||
});
|
||||
|
||||
import { db } from "@/db";
|
||||
import { getLocalNode } from "@/lib/node/local-node";
|
||||
import { buildNodeLinkMetadata, DEFAULT_NODE_DESCRIPTION } from "@/lib/node/metadata";
|
||||
|
||||
export async function generateMetadata(): Promise<Metadata> {
|
||||
let title = "Synapsis";
|
||||
let node = null;
|
||||
|
||||
try {
|
||||
const node = await db.query.nodes.findFirst();
|
||||
if (node?.name) {
|
||||
title = node.name;
|
||||
}
|
||||
node = await getLocalNode();
|
||||
} catch (e) {
|
||||
console.error("Failed to fetch node info for metadata", e);
|
||||
}
|
||||
|
||||
return {
|
||||
title: {
|
||||
default: title,
|
||||
template: `%s | ${title}`,
|
||||
},
|
||||
description: "Synapsis is designed to function like a global signal layer rather than a culture-bound platform. Anyone can run their own node and still participate in a shared, interconnected network, with global identity, clean terminology, and a modern interface that feels current rather than experimental.",
|
||||
...buildNodeLinkMetadata(
|
||||
node,
|
||||
process.env.NEXT_PUBLIC_NODE_NAME || "Synapsis",
|
||||
process.env.NEXT_PUBLIC_NODE_DESCRIPTION || DEFAULT_NODE_DESCRIPTION
|
||||
),
|
||||
manifest: "/manifest.json",
|
||||
icons: {
|
||||
icon: "/api/favicon",
|
||||
|
||||
@@ -1,14 +1,20 @@
|
||||
import { db } from '@/db';
|
||||
|
||||
export async function isLocalNodeNsfw(): Promise<boolean> {
|
||||
export async function getLocalNode() {
|
||||
const domain = process.env.NEXT_PUBLIC_NODE_DOMAIN || process.env.NODE_DOMAIN || 'localhost:43821';
|
||||
let node = await db.query.nodes.findFirst({ where: { domain } });
|
||||
|
||||
if (!node) {
|
||||
const localNodes = await db.query.nodes.findMany({ limit: 2 });
|
||||
if (localNodes.length === 1) node = localNodes[0];
|
||||
}
|
||||
|
||||
return node ?? null;
|
||||
}
|
||||
|
||||
export async function isLocalNodeNsfw(): Promise<boolean> {
|
||||
try {
|
||||
let node = await db.query.nodes.findFirst({ where: { domain } });
|
||||
if (!node) {
|
||||
const localNodes = await db.query.nodes.findMany({ limit: 2 });
|
||||
if (localNodes.length === 1) node = localNodes[0];
|
||||
}
|
||||
const node = await getLocalNode();
|
||||
return node?.isNsfw === true;
|
||||
} catch (error) {
|
||||
console.error('Local node NSFW lookup failed:', error);
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { buildNodeLinkMetadata } from './metadata';
|
||||
|
||||
describe('buildNodeLinkMetadata', () => {
|
||||
it('uses the node short description everywhere link previews read it', () => {
|
||||
const metadata = buildNodeLinkMetadata({
|
||||
name: 'Example Node',
|
||||
description: 'A concise description of this community.',
|
||||
});
|
||||
|
||||
expect(metadata.description).toBe('A concise description of this community.');
|
||||
expect(metadata.openGraph).toMatchObject({
|
||||
title: 'Example Node',
|
||||
description: 'A concise description of this community.',
|
||||
});
|
||||
expect(metadata.twitter).toMatchObject({
|
||||
title: 'Example Node',
|
||||
description: 'A concise description of this community.',
|
||||
});
|
||||
});
|
||||
|
||||
it('uses configured fallbacks when node branding is blank', () => {
|
||||
const metadata = buildNodeLinkMetadata(
|
||||
{ name: ' ', description: ' ' },
|
||||
'Fallback Node',
|
||||
'Fallback description'
|
||||
);
|
||||
|
||||
expect(metadata.description).toBe('Fallback description');
|
||||
expect(metadata.openGraph).toMatchObject({
|
||||
title: 'Fallback Node',
|
||||
description: 'Fallback description',
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,36 @@
|
||||
import type { Metadata } from 'next';
|
||||
|
||||
export const DEFAULT_NODE_DESCRIPTION = 'A swarm social network node.';
|
||||
|
||||
type NodeBranding = {
|
||||
name?: string | null;
|
||||
description?: string | null;
|
||||
};
|
||||
|
||||
export function buildNodeLinkMetadata(
|
||||
node?: NodeBranding | null,
|
||||
fallbackName = 'Synapsis',
|
||||
fallbackDescription = DEFAULT_NODE_DESCRIPTION
|
||||
): Pick<Metadata, 'title' | 'description' | 'openGraph' | 'twitter'> {
|
||||
const title = node?.name?.trim() || fallbackName;
|
||||
const description = node?.description?.trim() || fallbackDescription;
|
||||
|
||||
return {
|
||||
title: {
|
||||
default: title,
|
||||
template: `%s | ${title}`,
|
||||
},
|
||||
description,
|
||||
openGraph: {
|
||||
type: 'website',
|
||||
siteName: title,
|
||||
title,
|
||||
description,
|
||||
},
|
||||
twitter: {
|
||||
card: 'summary',
|
||||
title,
|
||||
description,
|
||||
},
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user