mirror of
https://github.com/MaggieAppleton/digital-gardeners.git
synced 2024-11-23 18:13:38 +01:00
Merge pull request #73 from MaggieAppleton/ma/new-interface
This commit is contained in:
commit
1d7be78e38
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
/node_modules
|
||||
node_modules
|
||||
/.next
|
||||
.next
|
47
components/Card.js
Normal file
47
components/Card.js
Normal file
|
@ -0,0 +1,47 @@
|
|||
import { motion } from "framer-motion";
|
||||
import Link from "next/link";
|
||||
import Image from "next/image";
|
||||
|
||||
export default function Card({ post }) {
|
||||
return (
|
||||
<motion.li
|
||||
className="w-60 mr-10 mb-14 space-y-2 opacity-80"
|
||||
key={post.filePath}
|
||||
whileHover={{
|
||||
scale: 1.02,
|
||||
opacity: 1,
|
||||
transition: {
|
||||
duration: 0.3,
|
||||
ease: "easeInOut",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Link
|
||||
as={`/posts/${post.filePath.replace(/\.md?$/, "")}`}
|
||||
href={`/posts/[slug]`}
|
||||
>
|
||||
<a>
|
||||
{post.data.image && (
|
||||
<Image
|
||||
className="rounded-md"
|
||||
src={post.data.image}
|
||||
width={250}
|
||||
height={200}
|
||||
alt={post.data.title}
|
||||
/>
|
||||
)}
|
||||
<h3 className="text-coolGray-600 leading-tight mt-2">
|
||||
{post.data.title}
|
||||
</h3>
|
||||
</a>
|
||||
</Link>
|
||||
<motion.div>
|
||||
{post.data.tools &&
|
||||
post.data.tools.map((tool) => <p>{tool}</p>)}
|
||||
</motion.div>
|
||||
<svg className="h-4 w-4 text-coolGray-600" viewBox="0 0 20 20">
|
||||
<path d="M12.95 10.707l.707-.707L8 4.343 6.586 5.757 10.828 10l-4.242 4.243L8 15.657l4.95-4.95z" />
|
||||
</svg>
|
||||
</motion.li>
|
||||
);
|
||||
}
|
7
components/Container.js
Normal file
7
components/Container.js
Normal file
|
@ -0,0 +1,7 @@
|
|||
export default function Container({ children }) {
|
||||
return (
|
||||
<div className="container flex flex-col sm:flex-row max-w-full">
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
9
components/Layout.js
Normal file
9
components/Layout.js
Normal file
|
@ -0,0 +1,9 @@
|
|||
import { motion } from "framer-motion";
|
||||
|
||||
export default function Layout({ children }) {
|
||||
return (
|
||||
<div className="container mt-24 mb-6 px-6 md:mx-auto h-full">
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
50
components/Sidemenu.js
Normal file
50
components/Sidemenu.js
Normal file
|
@ -0,0 +1,50 @@
|
|||
import { motion } from "framer-motion";
|
||||
import Link from "next/link";
|
||||
|
||||
export default function Sidemenu() {
|
||||
return (
|
||||
<motion.div
|
||||
initial="hidden"
|
||||
animate="visible"
|
||||
variants={{
|
||||
hidden: { opacity: 0, x: -50 },
|
||||
visible: {
|
||||
opacity: 1,
|
||||
x: 0,
|
||||
transition: {
|
||||
delay: 0.6,
|
||||
ease: "easeInOut",
|
||||
duration: 1,
|
||||
},
|
||||
},
|
||||
}}
|
||||
className="flex flex-col space-y-3 mt-28 ml-6 w-60 mr-12"
|
||||
>
|
||||
<Link href="/what">
|
||||
<a className="text-teal-700 hover:text-teal-900 text-base opacity-80 hover:opacity-100 transition-all duration-350 leading-tight font-bold">
|
||||
What's a Digital Garden?
|
||||
</a>
|
||||
</Link>
|
||||
<Link href="/directory">
|
||||
<a className="text-teal-700 hover:text-teal-900 text-base opacity-80 hover:opacity-100 transition-all duration-350 leading-tight">
|
||||
Garden Directory
|
||||
</a>
|
||||
</Link>
|
||||
<Link href="/tools">
|
||||
<a className="text-teal-700 hover:text-teal-900 text-base opacity-80 hover:opacity-100 transition-all duration-350 leading-tight">
|
||||
Tools for Gardening
|
||||
</a>
|
||||
</Link>
|
||||
<Link href="/tutorials">
|
||||
<a className="text-teal-700 hover:text-teal-900 text-base opacity-80 hover:opacity-100 transition-all duration-350 leading-tight">
|
||||
Gardening Tutorials and Guides
|
||||
</a>
|
||||
</Link>
|
||||
<Link href="/theory">
|
||||
<a className="text-teal-700 hover:text-teal-900 text-base opacity-80 hover:opacity-100 transition-all duration-350 leading-tight">
|
||||
Gardening Theory and Navel-Gazing
|
||||
</a>
|
||||
</Link>
|
||||
</motion.div>
|
||||
);
|
||||
}
|
5
next.config.js
Normal file
5
next.config.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
module.exports = {
|
||||
images: {
|
||||
domains: ["via.placeholder.com"],
|
||||
},
|
||||
};
|
27
package.json
Normal file
27
package.json
Normal file
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next",
|
||||
"dev:watch": "next-remote-watch ./posts",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"postbuild": "node ./scripts/build-search.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tailwindcss/typography": "^0.4.1",
|
||||
"algoliasearch": "^4.10.5",
|
||||
"dotenv": "^10.0.0",
|
||||
"framer-motion": "^4.1.17",
|
||||
"gray-matter": "^4.0.2",
|
||||
"next": "latest",
|
||||
"next-mdx-remote": "^3.0.1",
|
||||
"next-remote-watch": "1.0.0",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"autoprefixer": "^10.3.4",
|
||||
"postcss": "^8.3.6",
|
||||
"tailwindcss": "^2.2.9"
|
||||
}
|
||||
}
|
7
pages/_app.js
Normal file
7
pages/_app.js
Normal file
|
@ -0,0 +1,7 @@
|
|||
import '../styles/tailwind.css'
|
||||
|
||||
function MyApp({Component, pageProps}) {
|
||||
return <Component {...pageProps} />
|
||||
}
|
||||
|
||||
export default MyApp;
|
9
pages/directory.js
Normal file
9
pages/directory.js
Normal file
|
@ -0,0 +1,9 @@
|
|||
import Layout from "../components/Layout";
|
||||
|
||||
export default function Directory() {
|
||||
return (
|
||||
<Layout>
|
||||
<div>hello</div>
|
||||
</Layout>
|
||||
);
|
||||
}
|
80
pages/index.js
Normal file
80
pages/index.js
Normal file
|
@ -0,0 +1,80 @@
|
|||
import fs from "fs";
|
||||
import matter from "gray-matter";
|
||||
import Link from "next/link";
|
||||
import path from "path";
|
||||
import Container from "../components/Container";
|
||||
import Layout from "../components/Layout";
|
||||
import Sidemenu from "../components/Sidemenu";
|
||||
import Card from "../components/Card";
|
||||
import { gardensFilePath, GARDENS_PATH } from "../utils/mdUtils";
|
||||
import { motion } from "framer-motion";
|
||||
|
||||
export default function Index({ posts }) {
|
||||
return (
|
||||
<Container>
|
||||
<Sidemenu />
|
||||
<Layout>
|
||||
<motion.div
|
||||
initial="hidden"
|
||||
animate="visible"
|
||||
variants={{
|
||||
hidden: { opacity: 0, y: -50 },
|
||||
visible: {
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
transition: {
|
||||
delay: 0.1,
|
||||
ease: "easeInOut",
|
||||
duration: 0.7,
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
<h1 className="sm:text-4xl text-coolGray-700 mb-6 font-semibold">
|
||||
Garden of Digital Gardens
|
||||
</h1>
|
||||
<p className="text-xl text-coolGray-600 font-serif font-light max-w-5xl leading-tight">
|
||||
A collection of digital gardens, tools, and resources
|
||||
for gardeners
|
||||
</p>
|
||||
</motion.div>
|
||||
<motion.ul
|
||||
initial="hidden"
|
||||
animate="show"
|
||||
variants={{
|
||||
hidden: { opacity: 0, y: 50 },
|
||||
show: {
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
transition: {
|
||||
delay: 0.6,
|
||||
ease: "easeInOut",
|
||||
duration: 0.7,
|
||||
},
|
||||
},
|
||||
}}
|
||||
className="flex flex-wrap mt-24"
|
||||
>
|
||||
{posts.map((post) => (
|
||||
<Card post={post} />
|
||||
))}
|
||||
</motion.ul>
|
||||
</Layout>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
export function getStaticProps() {
|
||||
const posts = gardensFilePath.map((filePath) => {
|
||||
const source = fs.readFileSync(path.join(GARDENS_PATH, filePath));
|
||||
const { content, data } = matter(source);
|
||||
|
||||
return {
|
||||
content,
|
||||
data,
|
||||
filePath,
|
||||
};
|
||||
});
|
||||
|
||||
return { props: { posts } };
|
||||
}
|
78
pages/posts/[slug].js
Normal file
78
pages/posts/[slug].js
Normal file
|
@ -0,0 +1,78 @@
|
|||
import fs from "fs";
|
||||
import matter from "gray-matter";
|
||||
import { MDXRemote } from "next-mdx-remote";
|
||||
import { serialize } from "next-mdx-remote/serialize";
|
||||
import dynamic from "next/dynamic";
|
||||
import Head from "next/head";
|
||||
import Link from "next/link";
|
||||
import path from "path";
|
||||
import Layout from "../../components/Layout";
|
||||
import { gardensFilePath, GARDENS_PATH } from "../../utils/mdUtils";
|
||||
|
||||
// Custom components/renderers to pass to MDX.
|
||||
// Since the MDX files aren't loaded by webpack, they have no knowledge of how
|
||||
// to handle import statements. Instead, you must include components in scope
|
||||
// here.
|
||||
const components = {
|
||||
// It also works with dynamically-imported components, which is especially
|
||||
// useful for conditionally loading components for certain routes.
|
||||
// See the notes in README.md for more details.
|
||||
Head,
|
||||
};
|
||||
|
||||
export default function GardenPage({ source, frontMatter }) {
|
||||
return (
|
||||
<Layout>
|
||||
<header>
|
||||
<nav>
|
||||
<Link href="/">
|
||||
<a>Go back home</a>
|
||||
</Link>
|
||||
</nav>
|
||||
</header>
|
||||
<div>
|
||||
<h1>{frontMatter.title}</h1>
|
||||
{frontMatter.description && <p>{frontMatter.description}</p>}
|
||||
</div>
|
||||
<main>
|
||||
<MDXRemote {...source} components={components} />
|
||||
</main>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
|
||||
export const getStaticProps = async ({ params }) => {
|
||||
const gardenFilePath = path.join(GARDENS_PATH, `${params.slug}.md`);
|
||||
const source = fs.readFileSync(gardenFilePath);
|
||||
|
||||
const { content, data } = matter(source);
|
||||
|
||||
const mdxSource = await serialize(content, {
|
||||
// Optionally pass remark/rehype plugins
|
||||
mdxOptions: {
|
||||
remarkPlugins: [],
|
||||
rehypePlugins: [],
|
||||
},
|
||||
scope: data,
|
||||
});
|
||||
|
||||
return {
|
||||
props: {
|
||||
source: mdxSource,
|
||||
frontMatter: data,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export const getStaticPaths = async () => {
|
||||
const paths = gardensFilePath
|
||||
// Remove file extensions for page paths
|
||||
.map((path) => path.replace(/\.md?$/, ""))
|
||||
// Map the path into the static paths object required by Next.js
|
||||
.map((slug) => ({ params: { slug } }));
|
||||
|
||||
return {
|
||||
paths,
|
||||
fallback: false,
|
||||
};
|
||||
};
|
9
pages/theory.js
Normal file
9
pages/theory.js
Normal file
|
@ -0,0 +1,9 @@
|
|||
import Layout from "../components/Layout";
|
||||
|
||||
export default function Theory() {
|
||||
return (
|
||||
<Layout>
|
||||
<div>hello</div>
|
||||
</Layout>
|
||||
);
|
||||
}
|
9
pages/tools.js
Normal file
9
pages/tools.js
Normal file
|
@ -0,0 +1,9 @@
|
|||
import Layout from "../components/Layout";
|
||||
|
||||
export default function Tools() {
|
||||
return (
|
||||
<Layout>
|
||||
<div>hello</div>
|
||||
</Layout>
|
||||
);
|
||||
}
|
9
pages/tutorials.js
Normal file
9
pages/tutorials.js
Normal file
|
@ -0,0 +1,9 @@
|
|||
import Layout from "../components/Layout";
|
||||
|
||||
export default function Tutorials() {
|
||||
return (
|
||||
<Layout>
|
||||
<div>hello</div>
|
||||
</Layout>
|
||||
);
|
||||
}
|
9
pages/what.js
Normal file
9
pages/what.js
Normal file
|
@ -0,0 +1,9 @@
|
|||
import Layout from "../components/Layout";
|
||||
|
||||
export default function What() {
|
||||
return (
|
||||
<Layout>
|
||||
<div>hello</div>
|
||||
</Layout>
|
||||
);
|
||||
}
|
6
postcss.config.js
Normal file
6
postcss.config.js
Normal file
|
@ -0,0 +1,6 @@
|
|||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
10
posts/gardens/andy-matuschak.md
Normal file
10
posts/gardens/andy-matuschak.md
Normal file
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
title: Andy Matuschak
|
||||
description: Algorithms that make themselves known
|
||||
topics: ['evergreen notes', 'education', 'tools for thought']
|
||||
url: https://notes.andymatuschak.org/
|
||||
image: https://via.placeholder.com/200x250
|
||||
tools: ['mystery system']
|
||||
---
|
||||
|
||||
|
5
posts/gardens/bill-seitz.md
Normal file
5
posts/gardens/bill-seitz.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Bill Seitz
|
||||
image: https://via.placeholder.com/250
|
||||
tools: ['']
|
||||
---
|
7
posts/gardens/buster-benson.md
Normal file
7
posts/gardens/buster-benson.md
Normal file
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
title: Buster Benson
|
||||
image: https://via.placeholder.com/250
|
||||
tools: ['']
|
||||
---
|
||||
|
||||
This is an example post
|
5
posts/gardens/gwern-branden.md
Normal file
5
posts/gardens/gwern-branden.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Gwern Branden
|
||||
image: https://via.placeholder.com/200x250
|
||||
tools: ['']
|
||||
---
|
6
posts/gardens/joel-hooks.md
Normal file
6
posts/gardens/joel-hooks.md
Normal file
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
title: Joel Hooks
|
||||
description:
|
||||
image: https://via.placeholder.com/250x200
|
||||
tools: ['next.js']
|
||||
---
|
5
posts/gardens/tom-critchlow.md
Normal file
5
posts/gardens/tom-critchlow.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Tom Critchlow
|
||||
image: https://via.placeholder.com/250x100
|
||||
tools: ['jekyll']
|
||||
---
|
23
scripts/build-search.js
Normal file
23
scripts/build-search.js
Normal file
|
@ -0,0 +1,23 @@
|
|||
const dotenv = require("dotenv");
|
||||
const fetch = require("node-fetch");
|
||||
const algoliasearch = require("algoliasearch/lite");
|
||||
|
||||
async function getAllBlogPosts() {
|
||||
// write your code to fetch your data
|
||||
}
|
||||
|
||||
(async function () {
|
||||
// initialize environment variables
|
||||
dotenv.config();
|
||||
|
||||
try {
|
||||
// fetch your data
|
||||
const posts = await getAllBlogPosts();
|
||||
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
})();
|
||||
|
||||
// To be continued: https://www.contentful.com/blog/2021/07/02/add-algolia-instantsearch-to-nextjs-app/
|
39
styles/tailwind.css
Normal file
39
styles/tailwind.css
Normal file
|
@ -0,0 +1,39 @@
|
|||
/* @import url(/fonts/stylesheet.css); */
|
||||
@import url("https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,200;0,400;0,600;1,400&family=Source+Serif+Pro:wght@300;400&display=swap");
|
||||
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@layer base {
|
||||
h1 {
|
||||
@apply text-3xl;
|
||||
@apply leading-none;
|
||||
}
|
||||
h2 {
|
||||
@apply text-2xl;
|
||||
@apply leading-none;
|
||||
}
|
||||
h3 {
|
||||
@apply text-xl;
|
||||
@apply leading-none;
|
||||
}
|
||||
p {
|
||||
@apply text-base;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
height: 100%;
|
||||
background-repeat: no-repeat;
|
||||
background-attachment: fixed;
|
||||
background-color: rgb(243, 250, 218);
|
||||
background: linear-gradient(
|
||||
180deg,
|
||||
rgb(245, 255, 247) 0%,
|
||||
rgb(246, 255, 240) 70%,
|
||||
rgb(213, 240, 218) 100%
|
||||
);
|
||||
}
|
||||
|
||||
/* https://tailwindcss.com/docs/adding-base-styles */
|
48
tailwind.config.js
Normal file
48
tailwind.config.js
Normal file
|
@ -0,0 +1,48 @@
|
|||
const defaultTheme = require("tailwindcss/defaultTheme");
|
||||
const colors = require("tailwindcss/colors");
|
||||
|
||||
module.exports = {
|
||||
purge: [
|
||||
"./pages/**/*.{js,ts,jsx,tsx}",
|
||||
"./components/**/*.{js,ts,jsx,tsx}",
|
||||
],
|
||||
darkMode: false, // or 'media' or 'class'
|
||||
theme: {
|
||||
extend: {
|
||||
fontFamily: {
|
||||
sans: ["Poppins", ...defaultTheme.fontFamily.sans],
|
||||
serif: ["Source Serif Pro", ...defaultTheme.fontFamily.mono],
|
||||
},
|
||||
fontSize: {
|
||||
// Set in Perfect Fourth typescale (1.33)
|
||||
base: "1em",
|
||||
lg: "1.333em",
|
||||
xl: "1.777em",
|
||||
"2xl": "2.369em",
|
||||
"3xl": "3.157em",
|
||||
"4xl": "4.2em",
|
||||
"5xl": "5.61em",
|
||||
},
|
||||
colors: {
|
||||
...colors,
|
||||
primary: colors.blue["500"],
|
||||
secondary: colors.blue["700"],
|
||||
accent: colors.blue["800"],
|
||||
success: colors.green["500"],
|
||||
warning: colors.orange["500"],
|
||||
error: colors.red["500"],
|
||||
},
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [
|
||||
require("@tailwindcss/typography"),
|
||||
// https://github.com/tailwindlabs/tailwindcss-typography
|
||||
],
|
||||
};
|
||||
|
||||
// https://tailwindcss.com/docs/theme
|
||||
|
||||
//https://github.com/tailwindlabs/tailwindcss/blob/master/stubs/defaultConfig.stub.js#L7
|
12
utils/mdUtils.js
Normal file
12
utils/mdUtils.js
Normal file
|
@ -0,0 +1,12 @@
|
|||
import fs from "fs";
|
||||
import path from "path";
|
||||
|
||||
// POSTS_PATH is useful when you want to get the path to a specific file
|
||||
export const GARDENS_PATH = path.join(process.cwd(), "posts", "gardens");
|
||||
export const TOOLS_PATH = path.join(process.cwd(), "posts", "tools");
|
||||
|
||||
// patternFilePath is the list of all mdx files inside the POSTS_PATH directory
|
||||
export const gardensFilePath = fs
|
||||
.readdirSync(GARDENS_PATH)
|
||||
// Only include md(x) files
|
||||
.filter((path) => /\.md?$/.test(path));
|
Loading…
Reference in a new issue