Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
VITE_GRAPHQL_ENDPOINT=https://admin.e-multicontent.com/graphql
VITE_ARTIFACT_ROUTE_HYDRATION=true
VITE_BACKEND_PROFILE=full
VITE_SITE_URL=https://e-multicontent.com
STOREFRONT_ARTIFACT_SITE_KEY=e-multi
STOREFRONT_ARTIFACT_MODE=off
CMS_TAILWIND_SOURCE_API_URL=https://admin.e-multicontent.com/wp-json/funkycommerce-tailwind/v1
CMS_TAILWIND_BOOTSTRAP=true
CMS_TAILWIND_REQUIRED=true
STOREFRONT_ARTIFACT_SIGNING_SECRET=e200a0a19a618dd149af13f7f6a83124a0b57e50251506692a1e07d908f04a54
34 changes: 0 additions & 34 deletions apps/storefront/.env.example

This file was deleted.

105 changes: 53 additions & 52 deletions apps/storefront/src/components/CmsPageContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -245,47 +245,47 @@ export function CmsPageContent({
? `${window.location.origin}${pathname === "/" ? "" : pathname.replace(/\/+$/, "")}`
: page.seo.canonical || page.seo.opengraphUrl || `${window.location.origin}${pathname}`}
languageCode={contentLanguageCode}
keywords={page.seo.keywords || undefined}
siteName={page.seo.siteName || undefined}
appendSiteName={false}
robots={
robots
|| (
homePath
? "index, follow"
: page.seo.robotsSource === "explicit"
? page.seo.robots
: fallbackRobots || page.seo.robots
)
keywords={page.seo.keywords || undefined}
siteName={page.seo.siteName || undefined}
appendSiteName={false}
robots={
robots
|| (
homePath
? "index, follow"
: page.seo.robotsSource === "explicit"
? page.seo.robots
: fallbackRobots || page.seo.robots
)
}
opengraphType={page.seo.opengraphType === "article" ? "article" : "website"}
opengraphTitle={page.seo.opengraphTitle || undefined}
opengraphDescription={page.seo.opengraphDescription || undefined}
image={page.featuredImage
? {
url: page.featuredImage.sourceUrl,
alt: page.featuredImage.altText || page.title,
width: page.featuredImage.width,
height: page.featuredImage.height,
}
opengraphType={page.seo.opengraphType === "article" ? "article" : "website"}
opengraphTitle={page.seo.opengraphTitle || undefined}
opengraphDescription={page.seo.opengraphDescription || undefined}
image={page.featuredImage
? {
url: page.featuredImage.sourceUrl,
alt: page.featuredImage.altText || page.title,
width: page.featuredImage.width,
height: page.featuredImage.height,
}
: page.seo.opengraphImage
? { url: page.seo.opengraphImage, alt: page.title }
: undefined}
opengraphPublishedTime={page.seo.opengraphPublishedTime || undefined}
opengraphModifiedTime={page.seo.opengraphModifiedTime || undefined}
opengraphAuthor={page.seo.opengraphAuthor || undefined}
opengraphPublisher={page.seo.opengraphPublisher || undefined}
twitterTitle={page.seo.twitterTitle || undefined}
twitterDescription={page.seo.twitterDescription || undefined}
schema={{
pageType: page.seo.pageType || undefined,
articleType: page.seo.articleType || undefined,
}}
breadcrumbs={page.seo.breadcrumbs}
translations={page.translations.map((translation) => ({
languageCode: translation.languageCode,
url: translation.uri,
}))}
: page.seo.opengraphImage
? { url: page.seo.opengraphImage, alt: page.title }
: undefined}
opengraphPublishedTime={page.seo.opengraphPublishedTime || undefined}
opengraphModifiedTime={page.seo.opengraphModifiedTime || undefined}
opengraphAuthor={page.seo.opengraphAuthor || undefined}
opengraphPublisher={page.seo.opengraphPublisher || undefined}
twitterTitle={page.seo.twitterTitle || undefined}
twitterDescription={page.seo.twitterDescription || undefined}
schema={{
pageType: page.seo.pageType || undefined,
articleType: page.seo.articleType || undefined,
}}
breadcrumbs={page.seo.breadcrumbs}
translations={page.translations.map((translation) => ({
languageCode: translation.languageCode,
url: translation.uri,
}))}
/>

{breadcrumbs.length > 1 ? <Breadcrumbs items={breadcrumbs} includeStructuredData={false} /> : null}
Expand Down Expand Up @@ -372,7 +372,8 @@ function NestedWordPressShortcodes({ html, slots }: { html: string; slots: Neste

return (
<>
<div ref={contentRef} className="wp-content-fragment" dangerouslySetInnerHTML={{ __html: html }} />

<div ref={contentRef} className="wp-content-fragment asas" dangerouslySetInnerHTML={{ __html: html }} />
{slots.map(({ marker, content }, index) => (
<DeferredShortcodePortal
key={marker.slotId}
Expand Down Expand Up @@ -429,18 +430,18 @@ function DeferredShortcodePortal({
active
? content
: (
<div
role="status"
aria-label={`Loading ${marker.name} section`}
data-deferred-cms-shortcode={marker.name}
className="flex min-h-24 items-center justify-center"
>
<div className="relative inline-flex items-center justify-center">
<div className="absolute h-6 w-6 animate-spin rounded-full border-2 border-zinc-300 border-t-zinc-900 dark:border-zinc-600 dark:border-t-zinc-100" />
<span className="sr-only">Loading {marker.name}</span>
</div>
<div
role="status"
aria-label={`Loading ${marker.name} section`}
data-deferred-cms-shortcode={marker.name}
className="flex min-h-24 items-center justify-center"
>
<div className="relative inline-flex items-center justify-center">
<div className="absolute h-6 w-6 animate-spin rounded-full border-2 border-zinc-300 border-t-zinc-900 dark:border-zinc-600 dark:border-t-zinc-100" />
<span className="sr-only">Loading {marker.name}</span>
</div>
),
</div>
),
target,
marker.slotId,
);
Expand Down
219 changes: 219 additions & 0 deletions apps/storefront/src/components/ElevenLabsExistingMarkupAssets.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@

import { useEffect } from "react";
import { graphqlRequest } from "@funky/sdk";
import "./ElevenLabsHeadlessReader.css";

type AssetsResponse = {
elwrHeadlessAssets: {
css: string | null;
scriptUrl: string | null;
styleUrl: string | null;
} | null;
};

type ReaderResponse = {
post: {
elwrReaderHtml: string | null;
} | null;
};

const ASSETS_QUERY = `
query ElevenLabsAssets {
elwrHeadlessAssets {
css
scriptUrl
styleUrl
}
}
`;

const READER_QUERY = `
query ElevenLabsReaderColor($id: ID!) {
post(id: $id, idType: DATABASE_ID) {
elwrReaderHtml
}
}
`;

type Props = {
postId?: number;
};

function extractReaderColor(html: string): string | null {
const doc = new DOMParser().parseFromString(html, "text/html");

const reader = doc.querySelector<HTMLElement>(".elwr-reader");
if (!reader) return null;

const color = reader.style
.getPropertyValue("--elwr-color")
.trim();

// Accept only hex colors from the backend.
return /^#[0-9a-fA-F]{3,8}$/.test(color) ? color : null;
}

function applyReaderColor(color: string) {
document.querySelectorAll<HTMLElement>(".elwr-reader").forEach(
(reader) => {
reader.style.setProperty("--elwr-color", color);
}
);
}

export function ElevenLabsExistingMarkupAssets({
postId,
}: Props) {
useEffect(() => {
let cancelled = false;
let observer: MutationObserver | null = null;

async function loadAssets() {
try {
const { data, errors } =
await graphqlRequest<AssetsResponse>(ASSETS_QUERY);

if (errors?.length) {
throw new Error(
errors.map((error) => error.message).join("; ")
);
}

if (cancelled || !data?.elwrHeadlessAssets) {
return;
}

const { css, scriptUrl, styleUrl } =
data.elwrHeadlessAssets;

// 1. Load the plugin's original CSS.
if (styleUrl) {
let link = document.getElementById(
"elevenlabs-reader-stylesheet"
) as HTMLLinkElement | null;

if (!link) {
link = document.createElement("link");
link.id = "elevenlabs-reader-stylesheet";
link.rel = "stylesheet";
document.head.appendChild(link);
}

if (link.href !== styleUrl) {
link.href = styleUrl;
}
}

// 2. Inject WordPress dynamic CSS.
if (css) {
let style = document.getElementById(
"elevenlabs-dynamic-css"
) as HTMLStyleElement | null;

if (!style) {
style = document.createElement("style");
style.id = "elevenlabs-dynamic-css";
document.head.appendChild(style);
}

style.textContent = css;
}

// 3. Restore the WordPress admin color if
// the frontend sanitizer removed it.
if (Number.isInteger(postId) && (postId ?? 0) > 0) {
try {
const readerResult =
await graphqlRequest<ReaderResponse>(
READER_QUERY,
{ id: String(postId) }
);

if (readerResult.errors?.length) {
throw new Error(
readerResult.errors
.map((error) => error.message)
.join("; ")
);
}

if (cancelled) return;

const html =
readerResult.data?.post?.elwrReaderHtml;

const color = html
? extractReaderColor(html)
: null;

if (color) {
applyReaderColor(color);

// Also handle reader markup mounted later.
observer = new MutationObserver(() => {
applyReaderColor(color);
});

observer.observe(document.body, {
childList: true,
subtree: true,
});

console.info(
"[ELWR] WordPress admin color:",
color
);
} else {
console.warn(
"[ELWR] No admin color found in reader HTML"
);
}
} catch (error) {
console.warn(
"[ELWR] Could not restore reader color:",
error
);
}
}

if (cancelled) return;

// 4. Load the plugin's JavaScript.
if (scriptUrl) {
let script = document.getElementById(
"elevenlabs-reader-script"
) as HTMLScriptElement | null;

if (!script) {
script = document.createElement("script");
script.id = "elevenlabs-reader-script";
script.async = true;
script.src = scriptUrl;
document.body.appendChild(script);
}
}

console.info("[ELWR] Assets loaded", {
css: Boolean(css),
styleUrl,
scriptUrl,
postId,
});
} catch (error) {
console.error(
"[ELWR] Failed to load assets:",
error
);
}
}

loadAssets();

return () => {
cancelled = true;
observer?.disconnect();
};
}, [postId]);

return null;
}
Loading
Loading