feat(backend): og image and meta tags
This commit is contained in:
parent
287230c996
commit
4806ad5499
54
components/MetaTags.tsx
Normal file
54
components/MetaTags.tsx
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
import { GenericResource } from "@lib/types.ts";
|
||||||
|
import { Head } from "$fresh/runtime.ts";
|
||||||
|
|
||||||
|
function generateJsonLd(resource: GenericResource): string {
|
||||||
|
const baseSchema: Record<string, unknown> = {
|
||||||
|
"@context": "https://schema.org",
|
||||||
|
"@type": resource.type.charAt(0).toUpperCase() + resource.type.slice(1), // Converts type to PascalCase
|
||||||
|
name: resource.name,
|
||||||
|
description: resource.content || resource.meta?.average || "",
|
||||||
|
keywords: resource.tags?.join(", ") || "",
|
||||||
|
image: resource.meta?.image || "/images/og-image.jpg",
|
||||||
|
};
|
||||||
|
|
||||||
|
if (resource.meta?.author) {
|
||||||
|
baseSchema.author = {
|
||||||
|
"@type": "Person",
|
||||||
|
name: resource.meta.author,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resource.meta?.date) {
|
||||||
|
baseSchema.datePublished = new Date(resource.meta.date).toISOString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resource.meta?.rating) {
|
||||||
|
baseSchema.aggregateRating = {
|
||||||
|
"@type": "AggregateRating",
|
||||||
|
ratingValue: resource.meta.rating,
|
||||||
|
bestRating: 10, // Assuming a scale of 1 to 10
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return JSON.stringify(baseSchema, null, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function MetaTags({ resource }: { resource: GenericResource }) {
|
||||||
|
const jsonLd = generateJsonLd(resource);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Head>
|
||||||
|
<meta property="og:title" content={resource.name} />
|
||||||
|
<meta property="og:type" content={resource.type} />
|
||||||
|
<meta
|
||||||
|
property="og:image"
|
||||||
|
content={resource.meta?.image || "/images/og-image.jpg"}
|
||||||
|
/>
|
||||||
|
<script
|
||||||
|
type="application/ld+json"
|
||||||
|
dangerouslySetInnerHTML={{ __html: jsonLd }}
|
||||||
|
/>
|
||||||
|
</Head>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
@ -9,6 +9,7 @@ import { renderMarkdown } from "@lib/documents.ts";
|
|||||||
import { RedirectSearchHandler } from "@islands/Search.tsx";
|
import { RedirectSearchHandler } from "@islands/Search.tsx";
|
||||||
import PageHero from "@components/PageHero.tsx";
|
import PageHero from "@components/PageHero.tsx";
|
||||||
import { Star } from "@components/Stars.tsx";
|
import { Star } from "@components/Stars.tsx";
|
||||||
|
import { MetaTags } from "@components/MetaTags.tsx";
|
||||||
|
|
||||||
export const handler: Handlers<{ article: Article; session: unknown }> = {
|
export const handler: Handlers<{ article: Article; session: unknown }> = {
|
||||||
async GET(_, ctx) {
|
async GET(_, ctx) {
|
||||||
@ -34,6 +35,7 @@ export default function Greet(
|
|||||||
>
|
>
|
||||||
<RedirectSearchHandler />
|
<RedirectSearchHandler />
|
||||||
<KMenu type="main" context={{ type: "article" }} />
|
<KMenu type="main" context={{ type: "article" }} />
|
||||||
|
<MetaTags resource={article} />
|
||||||
|
|
||||||
<PageHero image={article.meta.image} thumbnail={article.meta.thumbnail}>
|
<PageHero image={article.meta.image} thumbnail={article.meta.thumbnail}>
|
||||||
<PageHero.Header>
|
<PageHero.Header>
|
||||||
|
@ -8,6 +8,7 @@ import { RedirectSearchHandler } from "@islands/Search.tsx";
|
|||||||
import { Recommendations } from "@islands/Recommendations.tsx";
|
import { Recommendations } from "@islands/Recommendations.tsx";
|
||||||
import PageHero from "@components/PageHero.tsx";
|
import PageHero from "@components/PageHero.tsx";
|
||||||
import { Star } from "@components/Stars.tsx";
|
import { Star } from "@components/Stars.tsx";
|
||||||
|
import { MetaTags } from "@components/MetaTags.tsx";
|
||||||
|
|
||||||
export default async function Greet(
|
export default async function Greet(
|
||||||
props: PageProps<{ movie: Movie; session: Record<string, string> }>,
|
props: PageProps<{ movie: Movie; session: Record<string, string> }>,
|
||||||
@ -24,6 +25,7 @@ export default async function Greet(
|
|||||||
<MainLayout url={props.url} title={`Movie > ${movie.name}`} context={movie}>
|
<MainLayout url={props.url} title={`Movie > ${movie.name}`} context={movie}>
|
||||||
<RedirectSearchHandler />
|
<RedirectSearchHandler />
|
||||||
<KMenu type="main" context={movie} />
|
<KMenu type="main" context={movie} />
|
||||||
|
<MetaTags resource={movie} />
|
||||||
<PageHero
|
<PageHero
|
||||||
image={movie.meta.image}
|
image={movie.meta.image}
|
||||||
thumbnail={movie.meta.thumbnail}
|
thumbnail={movie.meta.thumbnail}
|
||||||
|
@ -10,6 +10,7 @@ import PageHero from "@components/PageHero.tsx";
|
|||||||
import { Star } from "@components/Stars.tsx";
|
import { Star } from "@components/Stars.tsx";
|
||||||
import { renderMarkdown } from "@lib/documents.ts";
|
import { renderMarkdown } from "@lib/documents.ts";
|
||||||
import { isValidRecipe } from "@lib/recipeSchema.ts";
|
import { isValidRecipe } from "@lib/recipeSchema.ts";
|
||||||
|
import { MetaTags } from "@components/MetaTags.tsx";
|
||||||
|
|
||||||
export const handler: Handlers<{ recipe: Recipe; session: unknown } | null> = {
|
export const handler: Handlers<{ recipe: Recipe; session: unknown } | null> = {
|
||||||
async GET(_, ctx) {
|
async GET(_, ctx) {
|
||||||
@ -79,6 +80,7 @@ export default function Greet(
|
|||||||
>
|
>
|
||||||
<RedirectSearchHandler />
|
<RedirectSearchHandler />
|
||||||
<KMenu type="main" context={recipe} />
|
<KMenu type="main" context={recipe} />
|
||||||
|
<MetaTags resource={recipe} />
|
||||||
|
|
||||||
<PageHero image={recipe.meta?.image} thumbnail={recipe.meta?.thumbnail}>
|
<PageHero image={recipe.meta?.image} thumbnail={recipe.meta?.thumbnail}>
|
||||||
<PageHero.Header>
|
<PageHero.Header>
|
||||||
|
@ -7,6 +7,7 @@ import { RedirectSearchHandler } from "@islands/Search.tsx";
|
|||||||
import { KMenu } from "@islands/KMenu.tsx";
|
import { KMenu } from "@islands/KMenu.tsx";
|
||||||
import PageHero from "@components/PageHero.tsx";
|
import PageHero from "@components/PageHero.tsx";
|
||||||
import { Star } from "@components/Stars.tsx";
|
import { Star } from "@components/Stars.tsx";
|
||||||
|
import { MetaTags } from "@components/MetaTags.tsx";
|
||||||
|
|
||||||
export const handler: Handlers<{ serie: Series; session: unknown }> = {
|
export const handler: Handlers<{ serie: Series; session: unknown }> = {
|
||||||
async GET(_, ctx) {
|
async GET(_, ctx) {
|
||||||
@ -29,6 +30,7 @@ export default function Greet(
|
|||||||
<RedirectSearchHandler />
|
<RedirectSearchHandler />
|
||||||
<KMenu type="main" context={serie} />
|
<KMenu type="main" context={serie} />
|
||||||
|
|
||||||
|
<MetaTags resource={serie} />
|
||||||
<PageHero image={serie.meta.image} thumbnail={serie.meta.thumbnail}>
|
<PageHero image={serie.meta.image} thumbnail={serie.meta.thumbnail}>
|
||||||
<PageHero.Header>
|
<PageHero.Header>
|
||||||
<PageHero.BackLink href="/series" />
|
<PageHero.BackLink href="/series" />
|
||||||
|
BIN
static/og-image.jpg
Executable file
BIN
static/og-image.jpg
Executable file
Binary file not shown.
After Width: | Height: | Size: 185 KiB |
Loading…
x
Reference in New Issue
Block a user