diff --git a/src/components/SectionRecentArticles.js b/src/components/SectionRecentArticles.js
index 8f74dfb6..df6f0ec8 100644
--- a/src/components/SectionRecentArticles.js
+++ b/src/components/SectionRecentArticles.js
@@ -77,7 +77,7 @@ const useStyles = makeStyles(() => ({
}));
const SectionRecentArticles = (props) => {
- const { articles } = props;
+ const { articles, viewMore } = props;
const classes = useStyles();
return (
@@ -93,40 +93,42 @@ const SectionRecentArticles = (props) => {
Latest
-
-
-
+
- View more
-
-
-
+
+ View more
+
+
+
+ )}
@@ -184,6 +186,7 @@ const SectionRecentArticles = (props) => {
SectionRecentArticles.propTypes = {
articles: PropTypes.array,
+ viewMore: PropTypes.boolean,
};
export default SectionRecentArticles;
diff --git a/src/components/SpecialProjects/MoreArticles.js b/src/components/SpecialProjects/MoreArticles.js
new file mode 100644
index 00000000..22b4470d
--- /dev/null
+++ b/src/components/SpecialProjects/MoreArticles.js
@@ -0,0 +1,197 @@
+// base imports
+import React from "react";
+import PropTypes from "prop-types";
+import { DateTime } from "luxon";
+
+// Material UI imports
+import { makeStyles } from "@mui/styles";
+import Grid from "@mui/material/Grid";
+import Link from "@mui/material/Link";
+import Typography from "@mui/material/Typography";
+import Badge from "../Badge";
+
+const useStyles = makeStyles((theme) => ({
+ article: {
+ paddingTop: "0!important",
+ marginBottom: 20,
+ },
+ lastArticle: {
+ marginBottom: 20,
+ },
+ articleTitle: {
+ color: "#000 !important",
+ fontSize: "1em",
+ fontWeight: "700",
+ "&:hover": {
+ color: "#225C9D !important",
+ textDecoration: "none",
+ },
+ },
+ articlePublication: {
+ color: "rgba(0, 0, 0, 0.6)",
+ marginTop: 25,
+ marginBottom: 8,
+ position: "relative",
+ },
+ articleGrid: {
+ borderBottom: "1px solid",
+ borderBottomColor: "#DCDCDC",
+ paddingBottom: 20,
+ flexDirection: "column",
+ flexWrap: "nowrap",
+ columnGap: "16px",
+ rowGap: "8px",
+ [theme.breakpoints.down("md")]: {
+ flexDirection: "column",
+ },
+ },
+ em: {
+ fontSize: "0.81em",
+ fontStyle: "italic",
+ },
+ authors: {
+ color: "rgba(0, 0, 0, 0.6)",
+ fontFamily: "Lexend",
+ fontSize: "10px",
+ fontWeight: "700",
+ textTransform: "uppercase",
+ },
+ grid: {
+ marginTop: 20,
+ marginBottom: 60,
+ },
+ gridTitle: {
+ borderBottom: "1px solid #000",
+ marginBottom: 32,
+ width: "100%",
+ },
+ link: {
+ textDecoration: "none !important",
+ },
+ more: {
+ textDecoration: "none",
+ width: 200,
+ "&:active, & :focus, &:hover": {
+ color: "#FF0033",
+ textDecoration: "underline",
+ },
+ },
+ moreText: {
+ backgroundColor: "#FFE5EA",
+ borderRadius: 2,
+ color: "#FF0033",
+ fontWeight: 500,
+ padding: 6,
+ },
+}));
+
+function MoreArticles({ articles, topics }) {
+ const classes = useStyles();
+
+ const drawArticle = (article) => {
+ return (
+
+
+
+ {article.badge && }
+
+
+ {article.title}
+
+
+
+ {DateTime.fromISO(article.date)
+ .setZone("America/New_York")
+ .setLocale("en-us")
+ .toLocaleString(DateTime.DATE_FULL)}
+
+
+
+
+ );
+ };
+
+ const columns = [[], [], []];
+
+ articles.forEach((article, index) => {
+ columns[index % 3].push(article);
+ });
+
+ return (
+
+
+
+ More
+
+
+
+ {columns.map((col, colIndex) => (
+
+
+ {col.map((article) => drawArticle(article))}
+
+
+ ))}
+
+ {topics && topics.length > 0 && (
+
+
+
+ View more
+
+
+
+ )}
+
+ );
+}
+
+MoreArticles.propTypes = {
+ articles: PropTypes.array,
+ topics: PropTypes.array,
+};
+
+export default MoreArticles;
diff --git a/src/layouts/advanced.js b/src/layouts/advanced.js
index c4033162..e4dff6f6 100644
--- a/src/layouts/advanced.js
+++ b/src/layouts/advanced.js
@@ -7,6 +7,7 @@ import PropTypes from "prop-types";
import Box from "@mui/material/Box";
import Container from "@mui/material/Container";
import Grid from "@mui/material/Grid";
+import Typography from "@mui/material/Typography";
// components
import components, { Layout } from "../components/index";
@@ -24,12 +25,13 @@ import SpotlightArticles from "../components/Homepage/SpotlightArticles";
import AroundGlobe from "../components/Homepage/AroundGlobe";
import PolicyTracker from "../components/Homepage/PolicyTracker";
import Announcements from "../components/Homepage/Announcements";
+import MoreArticles from "../components/SpecialProjects/MoreArticles";
const Advanced = (props) => {
const { path, page, featured, articles } = props;
const latest =
- path === "/"
+ (path === "/" || (page && page.layout === "project")) && articles
? articles.filter(
(article) => featured.find((a) => a._id === article._id) == null
)
@@ -193,6 +195,43 @@ const Advanced = (props) => {
>
+ ) : page && page.layout === "project" ? (
+ <>
+
+
+ {page.title}
+
+
+ {featured && (
+
+
+
+
+ )}
+
+
+
+
+
+
+
+
+ >
) : (
<>
{path === "/tracker" ? (
diff --git a/src/pages/[...slug].js b/src/pages/[...slug].js
index a412aa37..743544dd 100644
--- a/src/pages/[...slug].js
+++ b/src/pages/[...slug].js
@@ -51,7 +51,7 @@ export async function getStaticProps(props) {
);
let [page] = await client.fetch(
- `*[!(_id in path("drafts.**")) && _type in ["advanced", "page", "post"] && (slug.current == "${slug}" || stackbit_url_path == "/${slug}")]{_id, _type, stackbit_url_path, trackerText, _createdAt, _updatedAt, badge, date, slug, title, body, toc, tocTitle, featuredImage, seo, disableNewsletterSignup, authors[]->{slug, name, photo, bio}, heroContent, layout, sections, sidebar_content[type == "sidebar_about"]{staff[]->, board[]->, masthead[]->}, relatedTopics[]->{displayName, name, type, slug, stackbit_model_type}, relatedArticles[]->{date,badge,title,slug,authors[]->{firstName, lastName}},relatedCommentary[]->}`
+ `*[!(_id in path("drafts.**")) && _type in ["advanced", "page", "post"] && (slug.current == "${slug}" || stackbit_url_path == "/${slug}")]{_id, _type, stackbit_url_path, trackerText, _createdAt, _updatedAt, badge, date, slug, title, body, toc, tocTitle, featuredImage, seo, disableNewsletterSignup, authors[]->{slug, name, photo, bio}, heroContent, layout, sections, sidebar_content[type == "sidebar_about"]{staff[]->, board[]->, masthead[]->}, relatedTopics[]->{displayName, name, type, slug, stackbit_model_type}, relatedArticles[]->{date,badge,title,slug,authors[]->{firstName, lastName}},relatedCommentary[]->,featuredPosts[]->{_id, title, author, badge, date, featuredImage, category, date, type, slug, stackbit_model_type},projectTopics[]->{_id}}`
);
let path;
@@ -83,6 +83,11 @@ export async function getStaticProps(props) {
const articlesQuery = `*[!(_id in path("drafts.**")) && _type == "post"]{ title, date, slug, badge, 'key': slug } | order(date desc)`;
articles = await client.fetch(articlesQuery);
+ } else if (page && page.layout === "project") {
+ const refs = page.projectTopics.map((ref) => `references("${ref._id}")`).join(" || ");
+ articles = await client.fetch(
+ `*[!(_id in path("drafts.**")) && (${refs}) && _type=="post"]{ _id, title, slug, featuredImage, date, badge } | order(date desc)[0...29]`
+ )
}
return {
@@ -91,6 +96,7 @@ export async function getStaticProps(props) {
articles: articles.length ? articles : null,
_type: page ? page._type : null,
authors: authors.length ? authors : null,
+ featured: page ? page.featuredPosts : null,
path: path,
data: { config, topics },
},
diff --git a/studio/schemas/advanced.js b/studio/schemas/advanced.js
index bfd31170..bfda2be2 100644
--- a/studio/schemas/advanced.js
+++ b/studio/schemas/advanced.js
@@ -10,29 +10,43 @@ export default {
description: 'The title of the page.',
validation: (Rule) => Rule.required(),
},
+ {
+ type: 'string',
+ name: 'layout',
+ title: 'Layout',
+ hidden: false,
+ validation: (Rule) => Rule.required(),
+ options: {
+ list: [{ title: 'Advanced', value: 'advanced' }, { title: 'Special Project', value: 'project' }],
+ },
+ },
{
type: 'string',
name: 'heroContent',
title: 'Hero Content',
description: 'The text in the page hero.',
+ hidden: ({document}) => document?.layout !== 'advanced',
},
{
type: 'string',
name: 'heroLinkText',
title: 'Hero Link Text',
description: 'The text displayed on the hero link.',
+ hidden: ({document}) => document?.layout !== 'advanced',
},
{
type: 'string',
name: 'heroLinkUrl',
title: 'Hero Link URL',
description: 'The URL for the hero link.',
+ hidden: ({document}) => document?.layout !== 'advanced',
},
{
type: 'text',
name: 'trackerText',
title: 'Policy tracker intro text',
- description: 'Add the introduction text for the Policy Tracker for the homepage'
+ description: 'Add the introduction text for the Policy Tracker for the homepage',
+ hidden: ({document}) => document?.layout !== 'advanced',
},
// {
// name: "featuredTopics",
@@ -87,6 +101,37 @@ export default {
type: 'section_podcast',
},
],
+ hidden: ({document}) => document?.layout !== 'advanced',
+ },
+ {
+ title: 'Project topics',
+ name: 'projectTopics',
+ type: 'array',
+ of: [
+ {
+ type: 'reference',
+ to: [{ type: 'topic' }],
+ options: {
+ disableNew: true,
+ },
+ },
+ ],
+ hidden: ({document}) => document?.layout !== 'project',
+ },
+ {
+ type: 'array',
+ name: 'featuredPosts',
+ of: [
+ {
+ title: 'Posts',
+ type: 'reference',
+ to: [{type: 'post'}],
+ options: {
+ disableNew: true,
+ },
+ },
+ ],
+ hidden: ({document}) => document?.layout !== 'project',
},
{
type: 'string',
@@ -101,16 +146,6 @@ export default {
title: 'Seo',
validation: null,
},
- {
- type: 'string',
- name: 'layout',
- title: 'Layout',
- hidden: false,
- validation: (Rule) => Rule.required(),
- options: {
- list: ['advanced'],
- },
- },
{
type: 'string',
name: 'stackbit_url_path',