Feat/ghost integration #1

Merged
Mayur7887 merged 6 commits from feat/ghost-integration into main 2026-07-20 07:44:55 +00:00
13 changed files with 80 additions and 136 deletions
Showing only changes of commit e6d6b60713 - Show all commits
+1
View File
@@ -51,3 +51,4 @@ pnpm-debug.log*
/playwright/.cache/ /playwright/.cache/
.vercel .vercel
.env*.local
+1
Submodule CampaignX_Sigil added at 2a984adfb3
+3 -16
View File
@@ -31,16 +31,7 @@
<header> <header>
<div class="wrap nav"> <div class="wrap nav">
<a class="logo" href="../../index.html" aria-label="LynkedUp Pro home"> <a class="logo" href="../../index.html" aria-label="LynkedUp Pro home">
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true"> <img src="../../img/lynkedup-logo.png" alt="" width="195" height="42" decoding="async">
<defs>
<linearGradient id="lgA" x1="0" y1="0" x2="1" y2="1">
<stop offset="0" stop-color="#5BD9EE"/><stop offset="1" stop-color="#1B7E9B"/>
</linearGradient>
</defs>
<path d="M8.8 5.6 3.4 8.75v6.5L8.8 18.4l5.4-3.15v-6.5Z" stroke="#17607A" stroke-width="1.7"/>
<path d="M15.2 5.6 9.8 8.75v6.5l5.4 3.15 5.4-3.15v-6.5Z" stroke="url(#lgA)" stroke-width="1.7"/>
</svg>
<span>LynkedUp&nbsp;<b>Pro</b></span>
</a> </a>
<nav class="nav-links" aria-label="Primary"> <nav class="nav-links" aria-label="Primary">
<a href="../../index.html#product">Product</a> <a href="../../index.html#product">Product</a>
@@ -272,12 +263,8 @@
<div class="foot-grid"> <div class="foot-grid">
<div class="foot-col brand"> <div class="foot-col brand">
<a class="logo" href="../../index.html" aria-label="LynkedUp Pro home"> <a class="logo" href="../../index.html" aria-label="LynkedUp Pro home">
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true"> <img src="../../img/lynkedup-logo.png" alt="" width="195" height="42" decoding="async">
<path d="M8.8 5.6 3.4 8.75v6.5L8.8 18.4l5.4-3.15v-6.5Z" stroke="#17607A" stroke-width="1.7"/> </a>
<path d="M15.2 5.6 9.8 8.75v6.5l5.4 3.15 5.4-3.15v-6.5Z" stroke="#2EC5DD" stroke-width="1.7"/>
</svg>
<span>LynkedUp&nbsp;<b>Pro</b></span>
</a>
<p class="foot-tag">The construction CRM that does the paperwork.</p> <p class="foot-tag">The construction CRM that does the paperwork.</p>
<span class="tag">16990 Dallas Pkwy, Suite 206<br>Dallas, TX 75248<br>(866) 259-6533<br>Info@LynkedUpPro.com</span> <span class="tag">16990 Dallas Pkwy, Suite 206<br>Dallas, TX 75248<br>(866) 259-6533<br>Info@LynkedUpPro.com</span>
<div class="foot-social" aria-label="Social links"> <div class="foot-social" aria-label="Social links">
+3 -16
View File
@@ -10,16 +10,7 @@
<header> <header>
<div class="wrap nav"> <div class="wrap nav">
<a class="logo" href="../../index.html" aria-label="LynkedUp Pro home"> <a class="logo" href="../../index.html" aria-label="LynkedUp Pro home">
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true"> <img src="../../img/lynkedup-logo.png" alt="" width="195" height="42" decoding="async">
<defs>
<linearGradient id="lgA" x1="0" y1="0" x2="1" y2="1">
<stop offset="0" stop-color="#5BD9EE"/><stop offset="1" stop-color="#1B7E9B"/>
</linearGradient>
</defs>
<path d="M8.8 5.6 3.4 8.75v6.5L8.8 18.4l5.4-3.15v-6.5Z" stroke="#17607A" stroke-width="1.7"/>
<path d="M15.2 5.6 9.8 8.75v6.5l5.4 3.15 5.4-3.15v-6.5Z" stroke="url(#lgA)" stroke-width="1.7"/>
</svg>
<span>LynkedUp&nbsp;<b>Pro</b></span>
</a> </a>
<nav class="nav-links" aria-label="Primary"> <nav class="nav-links" aria-label="Primary">
<a href="../../index.html#product">Product</a> <a href="../../index.html#product">Product</a>
@@ -191,12 +182,8 @@
<div class="foot-grid"> <div class="foot-grid">
<div class="foot-col brand"> <div class="foot-col brand">
<a class="logo" href="../../index.html" aria-label="LynkedUp Pro home"> <a class="logo" href="../../index.html" aria-label="LynkedUp Pro home">
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true"> <img src="../../img/lynkedup-logo.png" alt="" width="195" height="42" decoding="async">
<path d="M8.8 5.6 3.4 8.75v6.5L8.8 18.4l5.4-3.15v-6.5Z" stroke="#17607A" stroke-width="1.7"/> </a>
<path d="M15.2 5.6 9.8 8.75v6.5l5.4 3.15 5.4-3.15v-6.5Z" stroke="#2EC5DD" stroke-width="1.7"/>
</svg>
<span>LynkedUp&nbsp;<b>Pro</b></span>
</a>
<p class="foot-tag">The construction CRM that does the paperwork.</p> <p class="foot-tag">The construction CRM that does the paperwork.</p>
<span class="tag">16990 Dallas Pkwy, Suite 206<br>Dallas, TX 75248<br>(866) 259-6533<br>Info@LynkedUpPro.com</span> <span class="tag">16990 Dallas Pkwy, Suite 206<br>Dallas, TX 75248<br>(866) 259-6533<br>Info@LynkedUpPro.com</span>
<div class="foot-social" aria-label="Social links"> <div class="foot-social" aria-label="Social links">
+3 -16
View File
@@ -31,16 +31,7 @@
<header> <header>
<div class="wrap nav"> <div class="wrap nav">
<a class="logo" href="../../index.html" aria-label="LynkedUp Pro home"> <a class="logo" href="../../index.html" aria-label="LynkedUp Pro home">
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true"> <img src="../../img/lynkedup-logo.png" alt="" width="195" height="42" decoding="async">
<defs>
<linearGradient id="lgA" x1="0" y1="0" x2="1" y2="1">
<stop offset="0" stop-color="#5BD9EE"/><stop offset="1" stop-color="#1B7E9B"/>
</linearGradient>
</defs>
<path d="M8.8 5.6 3.4 8.75v6.5L8.8 18.4l5.4-3.15v-6.5Z" stroke="#17607A" stroke-width="1.7"/>
<path d="M15.2 5.6 9.8 8.75v6.5l5.4 3.15 5.4-3.15v-6.5Z" stroke="url(#lgA)" stroke-width="1.7"/>
</svg>
<span>LynkedUp&nbsp;<b>Pro</b></span>
</a> </a>
<nav class="nav-links" aria-label="Primary"> <nav class="nav-links" aria-label="Primary">
<a href="../../index.html#product">Product</a> <a href="../../index.html#product">Product</a>
@@ -273,12 +264,8 @@
<div class="foot-grid"> <div class="foot-grid">
<div class="foot-col brand"> <div class="foot-col brand">
<a class="logo" href="../../index.html" aria-label="LynkedUp Pro home"> <a class="logo" href="../../index.html" aria-label="LynkedUp Pro home">
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true"> <img src="../../img/lynkedup-logo.png" alt="" width="195" height="42" decoding="async">
<path d="M8.8 5.6 3.4 8.75v6.5L8.8 18.4l5.4-3.15v-6.5Z" stroke="#17607A" stroke-width="1.7"/> </a>
<path d="M15.2 5.6 9.8 8.75v6.5l5.4 3.15 5.4-3.15v-6.5Z" stroke="#2EC5DD" stroke-width="1.7"/>
</svg>
<span>LynkedUp&nbsp;<b>Pro</b></span>
</a>
<p class="foot-tag">The construction CRM that does the paperwork.</p> <p class="foot-tag">The construction CRM that does the paperwork.</p>
<span class="tag">16990 Dallas Pkwy, Suite 206<br>Dallas, TX 75248<br>(866) 259-6533<br>Info@LynkedUpPro.com</span> <span class="tag">16990 Dallas Pkwy, Suite 206<br>Dallas, TX 75248<br>(866) 259-6533<br>Info@LynkedUpPro.com</span>
<div class="foot-social" aria-label="Social links"> <div class="foot-social" aria-label="Social links">
+3 -16
View File
@@ -22,16 +22,7 @@
<header> <header>
<div class="wrap nav"> <div class="wrap nav">
<a class="logo" href="../index.html" aria-label="LynkedUp Pro home"> <a class="logo" href="../index.html" aria-label="LynkedUp Pro home">
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true"> <img src="../img/lynkedup-logo.png" alt="" width="195" height="42" decoding="async">
<defs>
<linearGradient id="lgA" x1="0" y1="0" x2="1" y2="1">
<stop offset="0" stop-color="#5BD9EE"/><stop offset="1" stop-color="#1B7E9B"/>
</linearGradient>
</defs>
<path d="M8.8 5.6 3.4 8.75v6.5L8.8 18.4l5.4-3.15v-6.5Z" stroke="#17607A" stroke-width="1.7"/>
<path d="M15.2 5.6 9.8 8.75v6.5l5.4 3.15 5.4-3.15v-6.5Z" stroke="url(#lgA)" stroke-width="1.7"/>
</svg>
<span>LynkedUp&nbsp;<b>Pro</b></span>
</a> </a>
<nav class="nav-links" aria-label="Primary"> <nav class="nav-links" aria-label="Primary">
<a href="../index.html#product">Product</a> <a href="../index.html#product">Product</a>
@@ -193,12 +184,8 @@
<div class="foot-grid"> <div class="foot-grid">
<div class="foot-col brand"> <div class="foot-col brand">
<a class="logo" href="../index.html" aria-label="LynkedUp Pro home"> <a class="logo" href="../index.html" aria-label="LynkedUp Pro home">
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true"> <img src="../img/lynkedup-logo.png" alt="" width="195" height="42" decoding="async">
<path d="M8.8 5.6 3.4 8.75v6.5L8.8 18.4l5.4-3.15v-6.5Z" stroke="#17607A" stroke-width="1.7"/> </a>
<path d="M15.2 5.6 9.8 8.75v6.5l5.4 3.15 5.4-3.15v-6.5Z" stroke="#2EC5DD" stroke-width="1.7"/>
</svg>
<span>LynkedUp&nbsp;<b>Pro</b></span>
</a>
<p class="foot-tag">The construction CRM that does the paperwork.</p> <p class="foot-tag">The construction CRM that does the paperwork.</p>
<span class="tag">16990 Dallas Pkwy, Suite 206<br>Dallas, TX 75248<br>(866) 259-6533<br>Info@LynkedUpPro.com</span> <span class="tag">16990 Dallas Pkwy, Suite 206<br>Dallas, TX 75248<br>(866) 259-6533<br>Info@LynkedUpPro.com</span>
<div class="foot-social" aria-label="Social links"> <div class="foot-social" aria-label="Social links">
+3 -16
View File
@@ -31,16 +31,7 @@
<header> <header>
<div class="wrap nav"> <div class="wrap nav">
<a class="logo" href="../../index.html" aria-label="LynkedUp Pro home"> <a class="logo" href="../../index.html" aria-label="LynkedUp Pro home">
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true"> <img src="../../img/lynkedup-logo.png" alt="" width="195" height="42" decoding="async">
<defs>
<linearGradient id="lgA" x1="0" y1="0" x2="1" y2="1">
<stop offset="0" stop-color="#5BD9EE"/><stop offset="1" stop-color="#1B7E9B"/>
</linearGradient>
</defs>
<path d="M8.8 5.6 3.4 8.75v6.5L8.8 18.4l5.4-3.15v-6.5Z" stroke="#17607A" stroke-width="1.7"/>
<path d="M15.2 5.6 9.8 8.75v6.5l5.4 3.15 5.4-3.15v-6.5Z" stroke="url(#lgA)" stroke-width="1.7"/>
</svg>
<span>LynkedUp&nbsp;<b>Pro</b></span>
</a> </a>
<nav class="nav-links" aria-label="Primary"> <nav class="nav-links" aria-label="Primary">
<a href="../../index.html#product">Product</a> <a href="../../index.html#product">Product</a>
@@ -271,12 +262,8 @@
<div class="foot-grid"> <div class="foot-grid">
<div class="foot-col brand"> <div class="foot-col brand">
<a class="logo" href="../../index.html" aria-label="LynkedUp Pro home"> <a class="logo" href="../../index.html" aria-label="LynkedUp Pro home">
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true"> <img src="../../img/lynkedup-logo.png" alt="" width="195" height="42" decoding="async">
<path d="M8.8 5.6 3.4 8.75v6.5L8.8 18.4l5.4-3.15v-6.5Z" stroke="#17607A" stroke-width="1.7"/> </a>
<path d="M15.2 5.6 9.8 8.75v6.5l5.4 3.15 5.4-3.15v-6.5Z" stroke="#2EC5DD" stroke-width="1.7"/>
</svg>
<span>LynkedUp&nbsp;<b>Pro</b></span>
</a>
<p class="foot-tag">The construction CRM that does the paperwork.</p> <p class="foot-tag">The construction CRM that does the paperwork.</p>
<span class="tag">16990 Dallas Pkwy, Suite 206<br>Dallas, TX 75248<br>(866) 259-6533<br>Info@LynkedUpPro.com</span> <span class="tag">16990 Dallas Pkwy, Suite 206<br>Dallas, TX 75248<br>(866) 259-6533<br>Info@LynkedUpPro.com</span>
<div class="foot-social" aria-label="Social links"> <div class="foot-social" aria-label="Social links">
+3 -16
View File
@@ -37,16 +37,7 @@
<header> <header>
<div class="wrap nav"> <div class="wrap nav">
<a class="logo" href="./index.html" aria-label="LynkedUp Pro home"> <a class="logo" href="./index.html" aria-label="LynkedUp Pro home">
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true"> <img src="./img/lynkedup-logo.png" alt="" width="195" height="42" decoding="async">
<defs>
<linearGradient id="lgA" x1="0" y1="0" x2="1" y2="1">
<stop offset="0" stop-color="#5BD9EE"/><stop offset="1" stop-color="#1B7E9B"/>
</linearGradient>
</defs>
<path d="M8.8 5.6 3.4 8.75v6.5L8.8 18.4l5.4-3.15v-6.5Z" stroke="#17607A" stroke-width="1.7"/>
<path d="M15.2 5.6 9.8 8.75v6.5l5.4 3.15 5.4-3.15v-6.5Z" stroke="url(#lgA)" stroke-width="1.7"/>
</svg>
<span>LynkedUp&nbsp;<b>Pro</b></span>
</a> </a>
<nav class="nav-links" aria-label="Primary"> <nav class="nav-links" aria-label="Primary">
<a href="./index.html#product">Product</a> <a href="./index.html#product">Product</a>
@@ -579,12 +570,8 @@
<div class="foot-grid"> <div class="foot-grid">
<div class="foot-col brand"> <div class="foot-col brand">
<a class="logo" href="./index.html" aria-label="LynkedUp Pro home"> <a class="logo" href="./index.html" aria-label="LynkedUp Pro home">
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true"> <img src="./img/lynkedup-logo.png" alt="" width="195" height="42" decoding="async">
<path d="M8.8 5.6 3.4 8.75v6.5L8.8 18.4l5.4-3.15v-6.5Z" stroke="#17607A" stroke-width="1.7"/> </a>
<path d="M15.2 5.6 9.8 8.75v6.5l5.4 3.15 5.4-3.15v-6.5Z" stroke="#2EC5DD" stroke-width="1.7"/>
</svg>
<span>LynkedUp&nbsp;<b>Pro</b></span>
</a>
<p class="foot-tag">The construction CRM that does the paperwork.</p> <p class="foot-tag">The construction CRM that does the paperwork.</p>
<span class="tag">16990 Dallas Pkwy, Suite 206<br>Dallas, TX 75248<br>(866) 259-6533<br>Info@LynkedUpPro.com</span> <span class="tag">16990 Dallas Pkwy, Suite 206<br>Dallas, TX 75248<br>(866) 259-6533<br>Info@LynkedUpPro.com</span>
<div class="foot-social" aria-label="Social links"> <div class="foot-social" aria-label="Social links">
+3 -16
View File
@@ -53,16 +53,7 @@
<header> <header>
<div class="wrap nav"> <div class="wrap nav">
<a class="logo" href="#top" aria-label="LynkedUp Pro home"> <a class="logo" href="#top" aria-label="LynkedUp Pro home">
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true"> <img src="./img/lynkedup-logo.png" alt="" width="195" height="42" decoding="async">
<defs>
<linearGradient id="lgA" x1="0" y1="0" x2="1" y2="1">
<stop offset="0" stop-color="#5BD9EE"/><stop offset="1" stop-color="#1B7E9B"/>
</linearGradient>
</defs>
<path d="M8.8 5.6 3.4 8.75v6.5L8.8 18.4l5.4-3.15v-6.5Z" stroke="#17607A" stroke-width="1.7"/>
<path d="M15.2 5.6 9.8 8.75v6.5l5.4 3.15 5.4-3.15v-6.5Z" stroke="url(#lgA)" stroke-width="1.7"/>
</svg>
<span>LynkedUp&nbsp;<b>Pro</b></span>
</a> </a>
<nav class="nav-links" aria-label="Primary"> <nav class="nav-links" aria-label="Primary">
<a href="#product">Product</a> <a href="#product">Product</a>
@@ -1227,12 +1218,8 @@
<div class="foot-grid"> <div class="foot-grid">
<div class="foot-col brand"> <div class="foot-col brand">
<a class="logo" href="#top" aria-label="LynkedUp Pro home"> <a class="logo" href="#top" aria-label="LynkedUp Pro home">
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true"> <img src="./img/lynkedup-logo.png" alt="" width="195" height="42" decoding="async">
<path d="M8.8 5.6 3.4 8.75v6.5L8.8 18.4l5.4-3.15v-6.5Z" stroke="#17607A" stroke-width="1.7"/> </a>
<path d="M15.2 5.6 9.8 8.75v6.5l5.4 3.15 5.4-3.15v-6.5Z" stroke="#2EC5DD" stroke-width="1.7"/>
</svg>
<span>LynkedUp&nbsp;<b>Pro</b></span>
</a>
<p class="foot-tag">The construction CRM that does the paperwork.</p> <p class="foot-tag">The construction CRM that does the paperwork.</p>
<span class="tag">16990 Dallas Pkwy, Suite 206<br>Dallas, TX 75248<br>(866) 259-6533<br>Info@LynkedUpPro.com</span> <span class="tag">16990 Dallas Pkwy, Suite 206<br>Dallas, TX 75248<br>(866) 259-6533<br>Info@LynkedUpPro.com</span>
<div class="foot-social" aria-label="Social links"> <div class="foot-social" aria-label="Social links">
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

+52 -6
View File
@@ -27,6 +27,40 @@ function truncate(text: string, max: number): string {
return `${cut.slice(0, lastSpace > 0 ? lastSpace : max).trimEnd()}`; return `${cut.slice(0, lastSpace > 0 ? lastSpace : max).trimEnd()}`;
} }
/**
* Upgrades a Ghost-hosted `http://` URL to `https://`.
*
* Ghost builds asset URLs from its own configured `url` setting. If that is set
* to http (as api.lynkedup.dev currently is), every image comes back insecure and
* browsers block it as mixed content on our HTTPS pages — silently, before the
* server's 301 to https can help.
*
* Only the configured Ghost host is upgraded: an arbitrary external http image in
* post content may genuinely have no https, and forcing it would break it.
*/
export function secureGhostUrl(url: string | null, ghostHost: string): string | null {
if (!url || !url.startsWith("http://")) return url;
try {
const parsed = new URL(url);
if (parsed.host !== ghostHost) return url;
parsed.protocol = "https:";
return parsed.toString();
} catch {
return url;
}
}
/** Applies {@link secureGhostUrl} to src/srcset/href attributes inside post HTML. */
function secureHtmlUrls(html: string, ghostHost: string): string {
return html.replace(
/(\s(?:src|href)=")(http:\/\/[^"]+)(")/gi,
(match, pre: string, url: string, post: string) => {
const secure = secureGhostUrl(url, ghostHost);
return secure ? `${pre}${secure}${post}` : match;
}
);
}
/** /**
* Rewrites a Ghost image URL to a resized variant. Ghost serves derivatives from * Rewrites a Ghost image URL to a resized variant. Ghost serves derivatives from
* `/content/images/size/w<width>/...`; any non-Ghost or already-sized URL is * `/content/images/size/w<width>/...`; any non-Ghost or already-sized URL is
@@ -77,12 +111,13 @@ function resolveExcerpt(post: GhostPost, plain: string): string {
function resolveSeo( function resolveSeo(
post: GhostPost, post: GhostPost,
config: GhostConfig, config: GhostConfig,
ghostHost: string,
title: string, title: string,
excerpt: string excerpt: string
): PostSeo { ): PostSeo {
const metaTitle = post.meta_title?.trim() || `${title} - LynkedUp Pro Blog`; const metaTitle = post.meta_title?.trim() || `${title} - LynkedUp Pro Blog`;
const metaDescription = post.meta_description?.trim() || excerpt; const metaDescription = post.meta_description?.trim() || excerpt;
const ogImage = ghostImage(post.og_image || post.feature_image, 1200); const ogImage = secureGhostUrl(ghostImage(post.og_image || post.feature_image, 1200), ghostHost);
return { return {
metaTitle, metaTitle,
@@ -92,7 +127,7 @@ function resolveSeo(
ogImage, ogImage,
twitterTitle: post.twitter_title?.trim() || metaTitle, twitterTitle: post.twitter_title?.trim() || metaTitle,
twitterDescription: post.twitter_description?.trim() || metaDescription, twitterDescription: post.twitter_description?.trim() || metaDescription,
twitterImage: ghostImage(post.twitter_image, 1200) || ogImage, twitterImage: secureGhostUrl(ghostImage(post.twitter_image, 1200), ghostHost) || ogImage,
// Ghost's canonical_url wins when an editor has set one (e.g. syndicated // Ghost's canonical_url wins when an editor has set one (e.g. syndicated
// posts); otherwise the canonical is this site's own URL for the slug. // posts); otherwise the canonical is this site's own URL for the slug.
canonicalUrl: post.canonical_url?.trim() || `${config.siteUrl}/blog/${post.slug}/`, canonicalUrl: post.canonical_url?.trim() || `${config.siteUrl}/blog/${post.slug}/`,
@@ -106,9 +141,20 @@ const DATE_FORMAT = new Intl.DateTimeFormat("en-US", {
timeZone: "UTC", timeZone: "UTC",
}); });
/** The Ghost host (e.g. "api.lynkedup.dev"), for upgrading its http asset URLs. */
function ghostHostFrom(config: GhostConfig): string {
try {
return new URL(config.apiUrl).host;
} catch {
return "";
}
}
export function normalizePost(post: GhostPost, config: GhostConfig): BlogPost { export function normalizePost(post: GhostPost, config: GhostConfig): BlogPost {
const html = post.html ?? ""; const ghostHost = ghostHostFrom(config);
const plain = toPlainText(html); const rawHtml = post.html ?? "";
const html = secureHtmlUrls(rawHtml, ghostHost);
const plain = toPlainText(rawHtml);
const title = post.title?.trim() || "Untitled"; const title = post.title?.trim() || "Untitled";
const excerpt = resolveExcerpt(post, plain); const excerpt = resolveExcerpt(post, plain);
const tags = resolveTags(post); const tags = resolveTags(post);
@@ -120,7 +166,7 @@ export function normalizePost(post: GhostPost, config: GhostConfig): BlogPost {
title, title,
html, html,
excerpt, excerpt,
featureImage: post.feature_image, featureImage: secureGhostUrl(post.feature_image, ghostHost),
featureImageAlt: post.feature_image_alt?.trim() || title, featureImageAlt: post.feature_image_alt?.trim() || title,
author: resolveAuthor(post), author: resolveAuthor(post),
publishedAt: validDate, publishedAt: validDate,
@@ -129,7 +175,7 @@ export function normalizePost(post: GhostPost, config: GhostConfig): BlogPost {
readingTime: resolveReadingTime(post, plain), readingTime: resolveReadingTime(post, plain),
tags, tags,
primaryTagLabel: (tags[0]?.name || "Field notes").toUpperCase(), primaryTagLabel: (tags[0]?.name || "Field notes").toUpperCase(),
seo: resolveSeo(post, config, title, excerpt), seo: resolveSeo(post, config, ghostHost, title, excerpt),
}; };
} }
+2 -2
View File
@@ -91,8 +91,8 @@
} }
.nav{display:flex;align-items:center;gap:28px;height:60px} .nav{display:flex;align-items:center;gap:28px;height:60px}
.logo{display:flex;align-items:center;gap:10px;font-weight:700;font-size:17px;letter-spacing:-.01em} .logo{display:flex;align-items:center;gap:10px;font-weight:700;font-size:17px;letter-spacing:-.01em}
.logo svg{width:24px;height:24px} /* Wordmark lockup (195x42): fix the height and let width follow the aspect ratio. */
.logo span b{color:var(--amber);font-weight:700} .logo img{height:26px;width:auto;display:block}
.nav-links{display:flex;gap:26px;margin-left:auto} .nav-links{display:flex;gap:26px;margin-left:auto}
.nav-links a{font-size:14px;color:var(--dim);transition:color .12s ease;position:relative} .nav-links a{font-size:14px;color:var(--dim);transition:color .12s ease;position:relative}
.nav-links a::before{ .nav-links a::before{
+3 -16
View File
@@ -22,16 +22,7 @@
<header> <header>
<div class="wrap nav"> <div class="wrap nav">
<a class="logo" href="../index.html" aria-label="LynkedUp Pro home"> <a class="logo" href="../index.html" aria-label="LynkedUp Pro home">
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true"> <img src="../img/lynkedup-logo.png" alt="" width="195" height="42" decoding="async">
<defs>
<linearGradient id="lgA" x1="0" y1="0" x2="1" y2="1">
<stop offset="0" stop-color="#5BD9EE"/><stop offset="1" stop-color="#1B7E9B"/>
</linearGradient>
</defs>
<path d="M8.8 5.6 3.4 8.75v6.5L8.8 18.4l5.4-3.15v-6.5Z" stroke="#17607A" stroke-width="1.7"/>
<path d="M15.2 5.6 9.8 8.75v6.5l5.4 3.15 5.4-3.15v-6.5Z" stroke="url(#lgA)" stroke-width="1.7"/>
</svg>
<span>LynkedUp&nbsp;<b>Pro</b></span>
</a> </a>
<nav class="nav-links" aria-label="Primary"> <nav class="nav-links" aria-label="Primary">
<a href="../index.html#product">Product</a> <a href="../index.html#product">Product</a>
@@ -309,12 +300,8 @@
<div class="foot-grid"> <div class="foot-grid">
<div class="foot-col brand"> <div class="foot-col brand">
<a class="logo" href="../index.html" aria-label="LynkedUp Pro home"> <a class="logo" href="../index.html" aria-label="LynkedUp Pro home">
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true"> <img src="../img/lynkedup-logo.png" alt="" width="195" height="42" decoding="async">
<path d="M8.8 5.6 3.4 8.75v6.5L8.8 18.4l5.4-3.15v-6.5Z" stroke="#17607A" stroke-width="1.7"/> </a>
<path d="M15.2 5.6 9.8 8.75v6.5l5.4 3.15 5.4-3.15v-6.5Z" stroke="#2EC5DD" stroke-width="1.7"/>
</svg>
<span>LynkedUp&nbsp;<b>Pro</b></span>
</a>
<p class="foot-tag">The construction CRM that does the paperwork.</p> <p class="foot-tag">The construction CRM that does the paperwork.</p>
<span class="tag">16990 Dallas Pkwy, Suite 206<br>Dallas, TX 75248<br>(866) 259-6533<br>Info@LynkedUpPro.com</span> <span class="tag">16990 Dallas Pkwy, Suite 206<br>Dallas, TX 75248<br>(866) 259-6533<br>Info@LynkedUpPro.com</span>
<div class="foot-social" aria-label="Social links"> <div class="foot-social" aria-label="Social links">