@frontity/twentytwenty-theme
Version:
The WordPress Twenty Twenty starter theme for Frontity
161 lines (143 loc) • 4.37 kB
JavaScript
import { styled, connect } from "frontity";
import { useEffect } from "react";
import FeaturedMedia from "./featured-media";
import {
EntryContent,
Post as _Post,
PostHeader,
PostInner,
PostTitle,
PostCaption,
SectionContainer,
} from "./post-item";
import PostCategories from "./post-categories";
import PostMeta from "./post-meta";
import PostTags from "./post-tags";
/**
* The Post component that the TwentyTwenty theme uses for rendering any kind of
* "post type" (posts, pages, attachments, etc.).
*
* It doesn't receive any prop but the Frontity store, which it receives from
* {@link connect}. The current Frontity state is used to know which post type
* should be rendered.
*
* @param props - The Frontity store (state, actions, and libraries).
*
* @example
* ```js
* <Switch>
* <Post when={data.isPostType} />
* </Switch>
* ```
*
* @returns The {@link Post} element rendered.
*/
const Post = ({ state, actions, libraries }) => {
// Get information about the current URL.
const data = state.source.get(state.router.link);
// Get the data of the post.
const post = state.source[data.type][data.id];
// Get the html2react component.
const Html2React = libraries.html2react.Component;
// Get all categories
const allCategories = state.source.category;
/**
* The item's categories is an array of each category id. So, we'll look up
* the details of each category in allCategories.
*/
const categories =
post.categories && post.categories.map((catId) => allCategories[catId]);
// Get all tags
const allTags = state.source.tag;
/**
* The item's categories is an array of each tag id. So, we'll look up the
* details of each tag in allTags.
*/
const tags = post.tags && post.tags.map((tagId) => allTags[tagId]);
/**
* Once the post has loaded in the DOM, prefetch both the
* home posts and the list component so if the user visits
* the home page, everything is ready and it loads instantly.
*/
useEffect(() => {
actions.source.fetch("/");
}, [actions.source]);
// Load the post, but only if the data is ready.
return data.isReady ? (
<PostArticle>
<Header>
<SectionContainer>
{/* If the post has categories, render the categories */}
{post.categories && <PostCategories categories={categories} />}
<PostTitle
as="h1"
className="heading-size-1"
dangerouslySetInnerHTML={{ __html: post.title.rendered }}
/>
{/* If the post has a caption (like attachments), render it */}
{post.caption && (
<PostCaption
dangerouslySetInnerHTML={{ __html: post.caption.rendered }}
/>
)}
{/* The post's metadata like author, publish date, and comments */}
<PostMeta item={post} />
</SectionContainer>
</Header>
{/*
* If the want to show featured media in the
* list of featured posts, we render the media.
*/}
{state.theme.featuredMedia.showOnPost && (
<FeaturedImage id={post.featured_media} isSinglePost={true} />
)}
{/* If the post has a description (like attachments), we render it */}
{post.description && (
<PostInner size="thin">
<EntryContent
dangerouslySetInnerHTML={{ __html: post.description.rendered }}
/>
</PostInner>
)}
{/* If the post has content, we render it */}
{post.content && (
<PostInner size="thin">
<EntryContent>
<Html2React html={post.content.rendered} />
</EntryContent>
{/* If the post has tags, render it */}
{post.tags && <PostTags tags={tags} />}
</PostInner>
)}
</PostArticle>
) : null;
};
export default connect(Post);
const Header = styled(PostHeader)`
background-color: #fff;
margin: 0;
padding: 4rem 0;
@media (min-width: 700px) {
padding: 8rem 0;
}
`;
const PostArticle = styled(_Post)`
padding-top: 0 !important;
`;
const FeaturedImage = styled(FeaturedMedia)`
margin-top: 0 !important;
position: relative;
> div {
position: relative;
}
&:before {
background: #fff;
content: "";
display: block;
position: absolute;
bottom: 50%;
left: 0;
right: 0;
top: 0;
}
`;