on master help sign in
get grants count, initial api for tag sorting
commitd3438c497751588395668d0b5055480e2c3692a2 authorGavin Atkinson <gvnatknsn@protonmail.com> dateWed 23 Jun 2021, 11:19 (5 years ago) parent068d267
5 files changed+186−16
content/grants/_index.md−7 lib/lib.js+79 pages/grants.js+94 pages/index.js+8−4 styles/globals.css+5−5
content/grants/_index.mddeleted−7
@@ -1,7 +0,0 @@
1−+++
2−title = "Grants"
3−sort_by = "date"
4−template = "grants/list.html"
5−page_template = "grants/grant.html"
6−aliases = ["/community/grants"]
7−+++
lib/lib.js+79
@@ -14,6 +14,8 @@ const directories = {
1414 blog: join(process.cwd(), "content/blog"),
1515 events: join(process.cwd(), "content/events"),
1616 docs: join(process.cwd(), "content/docs"),
17+ grants: join(process.cwd(), "content/grants"),
18+ media: join(process.cwd(), "content/media"),
1719};
1820
1921export function getPostSlugs(key) {
@@ -195,3 +197,80 @@ export const getPage = (path) => {
195197 }
196198 }
197199};
200+
201+// Returns an array of unique grants categories
202+export function getGrantsCategories() {
203+ const paths = fs.readdirSync(directories.grants);
204+ const uniqueCategories = paths
205+ // Get only markdown files
206+ .filter((path) => parse(path).ext === ".md")
207+ // Parse frontmatter
208+ .map((path) =>
209+ matter(fs.readFileSync(join(directories.grants, path)), options)
210+ )
211+ // Each markdown file has an array of categories. Collapse these arrays into one array.
212+ .reduce((acc, metadata) => {
213+ return [...acc, ...metadata.data.taxonomies.grant_category];
214+ }, [])
215+ // Deduplicate single array of categories such that the output is an array where each category is represented only once.
216+ .reduce((acc, uniqueItem) => {
217+ if (acc.includes(uniqueItem)) {
218+ return acc;
219+ }
220+ return [...acc, uniqueItem];
221+ }, []);
222+ return uniqueCategories;
223+}
224+
225+// Returns an array of unique grants types
226+export function getGrantsTypes() {
227+ const paths = fs.readdirSync(directories.grants);
228+ const uniqueTypes = paths
229+ // Get only markdown files
230+ .filter((path) => parse(path).ext === ".md")
231+ // Parse frontmatter
232+ .map((path) =>
233+ matter(fs.readFileSync(join(directories.grants, path)), options)
234+ )
235+ // Each markdown file has an array of categories. Collapse these arrays into one array.
236+ .reduce((acc, metadata) => {
237+ return [...acc, ...metadata.data.taxonomies.grant_type];
238+ }, [])
239+ // Deduplicate single array of categories such that the output is an array where each category is represented only once.
240+ .reduce((acc, uniqueItem) => {
241+ if (acc.includes(uniqueItem)) {
242+ return acc;
243+ }
244+ return [...acc, uniqueItem];
245+ }, []);
246+ return uniqueTypes;
247+}
248+
249+export function getOpenGrantsCount() {
250+ const paths = fs.readdirSync(directories.grants);
251+ const count = paths
252+ // Get only markdown files
253+ .filter((path) => parse(path).ext === ".md")
254+ // Parse frontmatter
255+ .map((path) =>
256+ matter(fs.readFileSync(join(directories.grants, path)), options)
257+ )
258+ // Count non-completed grants
259+ .reduce((acc, metadata) => {
260+ if (metadata.data.extra.completed) {
261+ return acc;
262+ }
263+ return acc + 1;
264+ }, 0);
265+ return count;
266+}
267+
268+/*
269+ * types = an array of strings
270+ */
271+export function getGrantsByCategories(types) {}
272+
273+/*
274+ * types = an array of strings
275+ */
276+export function getGrantsByTypes(types) {}
pages/grants.jsnew file+94
@@ -0,0 +1,94 @@
1+import Head from "next/head";
2+import Link from "next/link";
3+import { useState } from "react";
4+import Container from "../components/Container";
5+import Footer from "../components/Footer";
6+import Header from "../components/Header";
7+import SingleColumn from "../components/SingleColumn";
8+import BackgroundImage from "../components/BackgroundImage";
9+import {
10+ getAllPosts,
11+ formatDate,
12+ getGrantsCategories,
13+ getGrantsTypes,
14+} from "../lib/lib";
15+
16+export default function Grants({ posts }) {
17+ return (
18+ <Container>
19+ <SingleColumn>
20+ <Header />
21+ <section className="layout-wide">
22+ <div className="measure">
23+ <h2 className="pb-16">Urbit Grants</h2>
24+ <p className="pb-6">
25+ Urbit is a community project. While anyone can contribute, we help
26+ focus development and reward exceptional contribution through our
27+ grants program.
28+ </p>
29+ <p>We reward contributors in four different ways:</p>
30+ </div>
31+ </section>
32+ <section className="layout-wide">
33+ {posts.map((post) => {
34+ return (
35+ <div key={post.slug} className="mb-24 cursor-pointer">
36+ <Link href={`/grants/${post.slug}`}>
37+ <div>
38+ {
39+ // Not all blog posts have images
40+ post.extra.image ? (
41+ <BackgroundImage
42+ src={post.extra.image}
43+ style={{ height: "720px" }}
44+ className="w-full rounded-lg"
45+ />
46+ ) : null
47+ }
48+ <h2 className="mt-4">{post.title}</h2>
49+ <div className="flex items-baseline">
50+ {post.extra.author ? (
51+ <div className="type-ui text-gray mt-4">
52+ {post.extra.author}
53+ </div>
54+ ) : null}
55+ {post.extra.author && post.extra.ship ? (
56+ <div className="mx-1 text-gray">•</div>
57+ ) : null}
58+ {post.extra.ship ? (
59+ <div className="type-ui text-gray font-mono">
60+ {post.extra.ship}
61+ </div>
62+ ) : null}
63+ </div>
64+
65+ <div className="type-ui text-gray mt-2">
66+ {formatDate(new Date(post.date))}
67+ </div>
68+ </div>
69+ </Link>
70+ </div>
71+ );
72+ })}
73+ </section>
74+ </SingleColumn>
75+ <Footer />
76+ </Container>
77+ );
78+}
79+
80+export async function getStaticProps() {
81+ const categories = getGrantsCategories();
82+ const types = getGrantsTypes();
83+
84+ console.log(categories, types);
85+
86+ // const posts = getAllPosts(
87+ // ["title", "slug", "date", "description", "extra"],
88+ // "grants"
89+ // );
90+
91+ return {
92+ props: { posts: [] },
93+ };
94+}
pages/index.js+8−4
@@ -9,10 +9,10 @@ import BackgroundImage from "../components/BackgroundImage";
99import TabCarousel from "../components/TabCarousel";
1010import NewsletterSignup from "../components/NewletterSignup";
1111import PostPreview from "../components/PostPreview";
12−import { getAllPosts, formatDate } from "../lib/lib";
12+import { getAllPosts, formatDate, getOpenGrantsCount } from "../lib/lib";
1313import { contact } from "../lib/constants";
1414
15−export default function Home({ posts, events }) {
15+export default function Home({ posts, events, openGrantsCount }) {
1616 const [tab, setTab] = useState(0);
1717
1818 return (
@@ -60,7 +60,9 @@ export default function Home({ posts, events }) {
6060 <div className="flex flex-col md:flex-row md:items-center measure pb-12">
6161 <h2 className="m-0 p-0 mr-4 md:mb-0 mb-4">Urbit Grants</h2>
6262 <div>
63− <button className="bg-green text-white badge-lg">32 Open</button>
63+ <button className="bg-green text-white badge-lg">
64+ {openGrantsCount} Open
65+ </button>
6466 </div>
6567 </div>
6668 <div className="flex flex-col md:flex-row w-full items-center bg-washedGreen px-8 py-8 rounded-xl">
@@ -263,6 +265,8 @@ export default function Home({ posts, events }) {
263265}
264266
265267export async function getStaticProps() {
268+ const openGrantsCount = getOpenGrantsCount();
269+
266270 const posts = getAllPosts(
267271 ["title", "slug", "date", "description", "extra"],
268272 "blog"
@@ -271,6 +275,6 @@ export async function getStaticProps() {
271275 const events = getAllPosts(["title", "slug", "date", "extra"], "events");
272276
273277 return {
274− props: { posts, events },
278+ props: { posts, events, openGrantsCount },
275279 };
276280}
styles/globals.css+5−5
@@ -31,22 +31,22 @@ p a {
3131
3232h1,
3333.type-h1 {
34− @apply text-4xl md:text-5xl lg:text-6xl tracking-tight font-bold leading-tight;
34+ @apply text-4xl md:text-5xl lg:text-6xl font-bold leading-relaxed;
3535}
3636
3737h2,
3838.type-h2 {
39− @apply text-3xl md:text-4xl lg:text-5xl font-bold leading-tight;
39+ @apply text-3xl md:text-4xl lg:text-5xl font-bold;
4040}
4141
4242h3,
4343.type-h3 {
44− @apply text-lg md:text-xl lg:text-2xl font-semibold leading-normal;
44+ @apply text-lg md:text-xl lg:text-2xl font-semibold;
4545}
4646
4747h4,
4848.type-ui {
49− @apply text-base md:text-lg lg:text-xl font-semibold leading-normal;
49+ @apply text-base md:text-lg lg:text-xl font-semibold;
5050}
5151
5252p,
@@ -55,7 +55,7 @@ p,
5555}
5656
5757.type-sub {
58− @apply text-sm lg:text-base font-semibold leading-normal;
58+ @apply text-sm lg:text-base font-semibold;
5959}
6060
6161caption,