mirror of
https://github.com/CompeyDev/blog.devcomp.xyz.git
synced 2024-12-12 04:40:41 +00:00
OG cover image support for blog post meta
This commit is contained in:
parent
88b5366c92
commit
40f3fb1c8e
5 changed files with 44 additions and 25 deletions
|
@ -1,19 +1,21 @@
|
||||||
---
|
---
|
||||||
import path from "path";
|
|
||||||
interface Props {
|
interface Props {
|
||||||
id?: string;
|
id?: string;
|
||||||
src: string;
|
src: ImageMetadata | string;
|
||||||
class?: string;
|
class?: string;
|
||||||
alt?: string;
|
alt?: string;
|
||||||
position?: string;
|
position?: string;
|
||||||
basePath?: string;
|
basePath?: string;
|
||||||
}
|
}
|
||||||
import { Image } from "astro:assets";
|
|
||||||
|
import path from "path";
|
||||||
import { url } from "../../utils/url-utils";
|
import { url } from "../../utils/url-utils";
|
||||||
|
|
||||||
const { id, src, alt, position = "center", basePath = "/" } = Astro.props;
|
const { id, src: img, alt, position = "center", basePath = "/" } = Astro.props;
|
||||||
const className = Astro.props.class;
|
const className = Astro.props.class;
|
||||||
|
|
||||||
|
const src = typeof img === "string" ? img : img.src;
|
||||||
|
|
||||||
const isLocal = !(
|
const isLocal = !(
|
||||||
src.startsWith("/") ||
|
src.startsWith("/") ||
|
||||||
src.startsWith("http") ||
|
src.startsWith("http") ||
|
||||||
|
@ -24,23 +26,23 @@ const isPublic = src.startsWith("/");
|
||||||
|
|
||||||
// TODO temporary workaround for images dynamic import
|
// TODO temporary workaround for images dynamic import
|
||||||
// https://github.com/withastro/astro/issues/3373
|
// https://github.com/withastro/astro/issues/3373
|
||||||
let img: ImageMetadata;
|
let optimizedImg: ImageMetadata;
|
||||||
if (isLocal) {
|
if (isLocal && typeof img === "string") {
|
||||||
const files = import.meta.glob<ImageMetadata>("../../**", {
|
const files = import.meta.glob<ImageMetadata>("../../**", {
|
||||||
import: "default",
|
import: "default",
|
||||||
});
|
});
|
||||||
const normalizedPath = path
|
const normalizedPath = path
|
||||||
.normalize(path.join("../../", basePath, src))
|
.normalize(path.join("../../", basePath, src))
|
||||||
.replace(/\\/g, "/");
|
.replace(/\\/g, "/");
|
||||||
img = await files[normalizedPath]();
|
optimizedImg = await files[normalizedPath]();
|
||||||
}
|
}
|
||||||
|
|
||||||
const imageClass = "w-full h-full object-cover";
|
const imageClass = "w-full h-full object-cover";
|
||||||
const imageStyle = `object-position: ${position}`;
|
const imageStyle = `object-position: ${position}`;
|
||||||
---
|
---
|
||||||
<div class:list={[className, 'overflow-hidden relative']}>
|
<div id="image-wrapper" class:list={[className, 'overflow-hidden relative']}>
|
||||||
<div class="transition absolute inset-0 dark:bg-black/10 bg-opacity-50 pointer-events-none"></div>
|
<div class="transition absolute inset-0 dark:bg-black/10 bg-opacity-50 pointer-events-none"></div>
|
||||||
{isLocal && <Image src={img!} alt={alt || ""} class={imageClass} style={imageStyle}/>}
|
{isLocal && <img src={optimizedImg!.src} alt={alt || ""} class={imageClass} style={imageStyle}/>}
|
||||||
{!isLocal && <img src={isPublic ? url(src) : src} alt={alt || ""} class={imageClass} style={imageStyle}/>}
|
{!isLocal && <img src={isPublic ? url(src) : src} alt={alt || ""} class={imageClass} style={imageStyle}/>}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
import { defineCollection, z } from "astro:content";
|
import { defineCollection, z } from "astro:content";
|
||||||
|
|
||||||
const postsCollection = defineCollection({
|
const postsCollection = defineCollection({
|
||||||
schema: z.object({
|
schema: ({ image }) =>
|
||||||
title: z.string(),
|
z.object({
|
||||||
published: z.date(),
|
title: z.string(),
|
||||||
draft: z.boolean().optional(),
|
published: z.date(),
|
||||||
description: z.string().optional(),
|
draft: z.boolean().optional(),
|
||||||
image: z.string().optional(),
|
description: z.string().optional(),
|
||||||
tags: z.array(z.string()).optional(),
|
image: image().optional(),
|
||||||
category: z.string().optional(),
|
tags: z.array(z.string()).optional(),
|
||||||
}),
|
category: z.string().optional(),
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
export const collections = {
|
export const collections = {
|
||||||
posts: postsCollection,
|
posts: postsCollection,
|
||||||
|
|
|
@ -22,9 +22,10 @@ interface Props {
|
||||||
title: string;
|
title: string;
|
||||||
banner: string;
|
banner: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
|
cover?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
let { title, banner, description } = Astro.props;
|
let { title, banner, description, cover } = Astro.props;
|
||||||
|
|
||||||
const isHomePage = pathsEqual(Astro.url.pathname, "/");
|
const isHomePage = pathsEqual(Astro.url.pathname, "/");
|
||||||
|
|
||||||
|
@ -56,11 +57,11 @@ const myFade = {
|
||||||
// why doing this in Layout instead of GlobalStyles: https://github.com/withastro/astro/issues/6728#issuecomment-1502203757
|
// why doing this in Layout instead of GlobalStyles: https://github.com/withastro/astro/issues/6728#issuecomment-1502203757
|
||||||
const configHue = siteConfig.themeColor.hue;
|
const configHue = siteConfig.themeColor.hue;
|
||||||
if (!banner || typeof banner !== "string" || banner.trim() === "") {
|
if (!banner || typeof banner !== "string" || banner.trim() === "") {
|
||||||
banner = siteConfig.banner.src;
|
banner = cover ?? siteConfig.banner.src;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO don't use post cover as banner for now
|
// TODO don't use post cover as banner for now
|
||||||
banner = siteConfig.banner.src;
|
// banner = siteConfig.banner.src;
|
||||||
|
|
||||||
const enableBanner = siteConfig.banner.enable;
|
const enableBanner = siteConfig.banner.enable;
|
||||||
|
|
||||||
|
@ -91,6 +92,7 @@ const siteLang = siteConfig.lang.replace("_", "-");
|
||||||
<meta property="og:url" content={Astro.url}>
|
<meta property="og:url" content={Astro.url}>
|
||||||
<meta property="og:title" content={pageTitle}>
|
<meta property="og:title" content={pageTitle}>
|
||||||
<meta property="og:description" content={description || pageTitle}>
|
<meta property="og:description" content={description || pageTitle}>
|
||||||
|
<meta property="og:image" content={banner}>
|
||||||
|
|
||||||
<meta name="twitter:card" content="summary_large_image">
|
<meta name="twitter:card" content="summary_large_image">
|
||||||
<meta property="twitter:url" content={Astro.url}>
|
<meta property="twitter:url" content={Astro.url}>
|
||||||
|
|
|
@ -11,14 +11,15 @@ interface Props {
|
||||||
title: string;
|
title: string;
|
||||||
banner?: string;
|
banner?: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
|
cover?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { title, banner, description } = Astro.props;
|
const { title, banner, description, cover } = Astro.props;
|
||||||
const isHomePage = pathsEqual(Astro.url.pathname, "/");
|
const isHomePage = pathsEqual(Astro.url.pathname, "/");
|
||||||
const enableBanner = siteConfig.banner.enable;
|
const enableBanner = siteConfig.banner.enable;
|
||||||
---
|
---
|
||||||
|
|
||||||
<Layout title={title} banner={banner} description={description}>
|
<Layout title={title} banner={banner ?? siteConfig.banner.src} cover={cover} description={description}>
|
||||||
<slot slot="head" name="head"></slot>
|
<slot slot="head" name="head"></slot>
|
||||||
<div class="max-w-[var(--page-width)] min-h-screen grid grid-cols-[17.5rem_auto] grid-rows-[auto_auto_1fr_auto] lg:grid-rows-[auto_1fr_auto]
|
<div class="max-w-[var(--page-width)] min-h-screen grid grid-cols-[17.5rem_auto] grid-rows-[auto_auto_1fr_auto] lg:grid-rows-[auto_1fr_auto]
|
||||||
mx-auto gap-4 relative px-0 md:px-4"
|
mx-auto gap-4 relative px-0 md:px-4"
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
---
|
---
|
||||||
import path from "path";
|
import path from "path";
|
||||||
|
import { getImage } from "astro:assets";
|
||||||
import { getCollection } from "astro:content";
|
import { getCollection } from "astro:content";
|
||||||
import License from "@components/misc/License.astro";
|
import License from "@components/misc/License.astro";
|
||||||
import Markdown from "@components/misc/Markdown.astro";
|
import Markdown from "@components/misc/Markdown.astro";
|
||||||
|
@ -43,8 +44,20 @@ const jsonLd = {
|
||||||
datePublished: formatDateToYYYYMMDD(entry.data.published),
|
datePublished: formatDateToYYYYMMDD(entry.data.published),
|
||||||
// TODO include cover image here
|
// TODO include cover image here
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let coverImageUrl: string | undefined;
|
||||||
|
|
||||||
|
if (entry.data.image) {
|
||||||
|
coverImageUrl = await getImage({
|
||||||
|
src: entry.data.image,
|
||||||
|
width: 1200,
|
||||||
|
height: 630,
|
||||||
|
}).then(img => img.src);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(coverImageUrl);
|
||||||
---
|
---
|
||||||
<MainGridLayout banner={entry.data.image} title={entry.data.title} description={entry.data.description}>
|
<MainGridLayout banner={coverImageUrl} cover={coverImageUrl} title={entry.data.title} description={entry.data.description}>
|
||||||
<script slot="head" type="application/ld+json" set:html={JSON.stringify(jsonLd)}></script>
|
<script slot="head" type="application/ld+json" set:html={JSON.stringify(jsonLd)}></script>
|
||||||
<div class="flex w-full rounded-[var(--radius-large)] overflow-hidden relative mb-4">
|
<div class="flex w-full rounded-[var(--radius-large)] overflow-hidden relative mb-4">
|
||||||
<div id="post-container" class:list={["card-base z-10 px-6 md:px-9 pt-6 pb-4 relative w-full ",
|
<div id="post-container" class:list={["card-base z-10 px-6 md:px-9 pt-6 pb-4 relative w-full ",
|
||||||
|
@ -94,7 +107,7 @@ const jsonLd = {
|
||||||
<!-- always show cover as long as it has one -->
|
<!-- always show cover as long as it has one -->
|
||||||
|
|
||||||
{entry.data.image &&
|
{entry.data.image &&
|
||||||
<ImageWrapper src={entry.data.image} basePath={path.join("content/posts/", getDir(entry.id))} class="mb-8 rounded-xl banner-container onload-animation"/>
|
<ImageWrapper src={entry.data.image} basePath={path.join("content/posts/", getDir(entry.id))} id="cover" class="mb-8 rounded-xl banner-container onload-animation"/>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue