Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
2 changes: 1 addition & 1 deletion src/cms/cms.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ CMS.registerWidget("url-image", UrlImageControl, UrlImagePreview);

CMS.registerPreviewTemplate("index", IndexPagePreview);
CMS.registerPreviewTemplate("about", AboutPagePreview);
CMS.registerPreviewTemplate("idea", IdeaPostPreview);
CMS.registerPreviewTemplate("ideas", IdeaPostPreview);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice catch!


// Decap exposes a number of lifecycle stages we can hook into and register.
CMS.registerEventListener({
Expand Down
26 changes: 0 additions & 26 deletions src/cms/preview-templates/IdeaPostPreview.js

This file was deleted.

88 changes: 88 additions & 0 deletions src/cms/preview-templates/IdeaPostPreview.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import React from "react";

import {
IdeaPostTemplate,
IdeaPostTemplateProps,
} from "../../templates/idea-post";
import { ImmutableLike, fromImmutable } from "../utils/immutable";

interface PreviewProps {
entry?: ImmutableLike;
value?: unknown;
}

/**
* Normalize CMS form data into the shape IdeaPostTemplate expects.
* Decap gives us raw widget values which differ from resolved Gatsby data:
* - relation widgets return value_field strings, not resolved objects
* - single select widgets return a string, not an array
*/
function normalizeCmsData(
raw: Record<string, unknown>,
): Partial<IdeaPostTemplateProps> {
const v = raw as Partial<IdeaPostTemplateProps>;

// program: single select string → array

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

non-blocking, but worth noting down: this comment made me go look at how program is setup in config.yml, and turns out it doesn't have a multiple: true. Returning a string when the select is single is totally the right thing to do here for the preview. but more importantly though, we should add multiple:true to program if we allow multiple selections in the admin site

const program = v.program;
const normalizedProgram = program
? Array.isArray(program)
? program
: [String(program)]
: undefined;

// authors: relation gives ["name1", "name2"] → [{ name, contactId }]
const authors = v.authors
? (v.authors as unknown as string[]).map((a) =>
typeof a === "string" ? { name: a, contactId: "" } : a,
)
: undefined;

// date: datetime widget returns a Date/object, template expects a string
const rawDate = raw.date;
const date = rawDate
? typeof rawDate === "string"
? rawDate
: new Date(rawDate as string | number).toLocaleDateString("en-US", {
year: "numeric",
month: "long",
day: "2-digit",
Comment on lines +45 to +48

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: maybe add timeZone: "UTC" here to avoid cases where Aug 10 locally is already Aug 11 in UTC

})
: undefined;

return {
...v,
authors,
date,
isPreview: true,
program: normalizedProgram,
};
}

const IdeaPostPreview: React.FC<PreviewProps> = ({ entry, value }) => {
const raw = value ?? (entry?.get("data") as ImmutableLike | undefined);
const v = fromImmutable<Record<string, unknown>>(raw) ?? {};
return (
<>
<div
style={{
background: "#fffbe6",
border: "1px solid #ffe58f",
borderRadius: 4,
color: "#874d00",
fontSize: 12,
margin: 8,
padding: "6px 12px",
}}
>
Previews are approximate/under development — content and styling
may differ from production, and not all functionality will be
available.
</div>
<IdeaPostTemplate
{...(normalizeCmsData(v) as IdeaPostTemplateProps)}
/>
</>
);
};

export default IdeaPostPreview;
71 changes: 44 additions & 27 deletions src/templates/idea-post.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,18 +41,20 @@ const {
tagRowLabel,
} = require("../style/idea-post.module.css");

export const IdeaPostTemplate: React.FC<
IdeaPostNode & {
onExpandDescription?: (
content: string,
label: string,
sectionKey: string,
) => void;
}
> = ({
export type IdeaPostTemplateProps = IdeaPostNode & {
isPreview?: boolean;
onExpandDescription?: (
content: string,
label: string,
sectionKey: string,
) => void;
};

export const IdeaPostTemplate: React.FC<IdeaPostTemplateProps> = ({
authors,
date,
introduction,
isPreview,

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't love these isPreview checks, and kind of wish that the gatsby components didn't need to know anything about the Decap previews, but it's probably a worthwhile tradeoff, since designing to avoid it would force bigger changes (or make previews onerous to maintain).

As far as gatsby is concerned this is just some visual noise since isPreview should never be true outside of Decap.

nextSteps,
onExpandDescription,
preliminaryFindings,
Expand Down Expand Up @@ -121,27 +123,34 @@ export const IdeaPostTemplate: React.FC<
</Button>
</div>
</div>

<ContactModal
authors={authors}
primaryContact={primaryContact}
title={title}
open={contactModalOpen}
onClose={() => setContactModalOpen(false)}
/>
{!isPreview && (
<ContactModal
authors={authors}
primaryContact={primaryContact}
title={title}
open={contactModalOpen}
onClose={() => setContactModalOpen(false)}
/>
)}

{/* Tag row */}
{tags && tags.length > 0 && (
<div className={tagRow}>
<span className={tagRowLabel}>Topics</span>
{tags.map((t) => (
<TagPopover
key={t}
tag={t}
currentSlug={slug}
className={tag}
/>
))}
{tags.map((t) =>
isPreview ? (
<span key={t} className={tag}>
{t}
</span>
) : (
<TagPopover
key={t}
tag={t}
currentSlug={slug}
className={tag}
/>
),
)}
</div>
)}

Expand Down Expand Up @@ -214,8 +223,16 @@ export const IdeaPostTemplate: React.FC<
{relatedIdeas!.map((idea) => {
if (!idea.slug && !idea.title) return null;
return (
<li key={idea.slug}>
<Link to={idea.slug}>{idea.title}</Link>
<li key={idea.slug || idea.title}>
{/* Gatsby's Link needs the app runtime
the Decap preview iframe lacks */}
{isPreview ? (
<a href={idea.slug}>{idea.title}</a>
) : (
<Link to={idea.slug}>
{idea.title}
</Link>
)}
</li>
);
})}
Expand Down
Loading