Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: SEO updates, author, mdx math, type fixes #41

Merged
merged 17 commits into from
Aug 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
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
6 changes: 5 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
#Next
NEXT_PUBLIC_BASE_URL=https://localhost:3000

#Analytics
#Umami Analytics
NEXT_PUBLIC_UMAMI_SCRIPT_URL=
NEXT_PUBLIC_UMAMI_WEBSITE_ID=

#Plausible Analytics
NEXT_PUBLIC_PLAUSIBLE_DOMAIN=
NEXT_PUBLIC_PLAUSIBLE_SCRIPT_URL=

#Email
EMAIL_API_BASE=
NEXT_PUBLIC_EMAIL_API_KEY=
Expand Down
16 changes: 15 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.7.0] - 2023-08-19

### Added

- Convertkit newsletter provider
- Plausible analytics provider
- Math and Katex support
- Author content definition
- Tweet MDX component
- YT Video MDX component
- Newsletter CTA MDX component
- Documentation updates
- Announcement banner

### Changed

- Small SEO updates
- Codebase and type fixes
- Design updates

## [0.6.0] - 2023-07-16

Expand Down
65 changes: 52 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
![Image2](/screenshots/garden2.png)
[More screenshots here](/screenshots/)

[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/git/external?repository-url=https://github.com/thedevdavid/digital-garden)
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fthedevdavid%2Fdigital-garden%2F)

An open source blogging (digital gardening) template for developers using [Next.js](https://nextjs.org/) app router, MDX, [Contentlayer](https://contentlayer.dev/), [Tailwind CSS](https://tailwindcss.com/), [@shadcn/ui](https://ui.shadcn.com/) , [Lucide Icons](https://lucide.dev/icons), and more.

Expand All @@ -18,14 +18,18 @@ If you love this template and/or use it, please give it a star on GitHub. This w
- [Motivation](#motivation)
- [Getting Started](#getting-started)
- [Writing content](#writing-content)
- [Frontmatter](#frontmatter)
- [Deployment](#deployment)
- [Customization](#customization)
- [Fonts](#fonts)
- [Colors](#colors)
- [Metadata](#metadata)
- [Navigation](#navigation)
- [Social links](#social-links)
- [Analytics](#analytics)
- [Vercel](#vercel)
- [Umami](#umami)
- [Plausible](#plausible)
- [Other analytics providers](#other-analytics-providers)
- [Newsletter subscription](#newsletter-subscription)
- [MailerLite](#mailerlite)
Expand Down Expand Up @@ -73,6 +77,19 @@ Editing list pages is done in the `lib` folder.
- `/projects` - `lib/projects-data.ts`
- `/social` - `lib/social-data.ts`

#### Frontmatter

Frontmatter is used to define metadata for pages and posts. It's located at the top of the file and is written in YAML. You can define the following fields:

- `title` - The title of the page/post
- `description` - The description of the page/post
- `publishedDate` - The date of the post (not used on pages)
- `lastUpdatedDate` - The date of the page/post
- `tags` - List of tags for the post. You can add new tags by adding them to the `tagOptions` list. (not used on pages)
- `series` - The series of the post. A series has a title and an order number for a post. (not used on pages)
- `author` - The author of the post. An author has a name, and image. (not used on pages)
- `status` - Whether the page/post is published or draft

### Deployment

You can deploy the project with [Vercel](https://vercel.com/) or any other hosting provider. If you want to use Vercel, you can use the button at the top of this README.
Expand Down Expand Up @@ -106,8 +123,14 @@ Images and other media files are located in `public/` directory. You can use the

You can change the metadata and author details in `utils/metadata.ts`. This will be used around the site for titles, social links, social handles, SEO, etc.

#### Navigation

You can edit navigation links in `lib/navigation-links.ts`.

#### Social links

You can edit social links in `lib/social-data.ts`. You can also add new social links by adding them to the file. Using the platform name as the key and the URL as the value. The `SocialButton` component will automatically add the icon for the platform if it's supported in [simple-icons](https://simpleicons.org/).

### Analytics

#### Vercel
Expand All @@ -121,6 +144,13 @@ Umami is a simple, easy to use, web analytics solution with self-hosting option!
Configure:
Set `NEXT_PUBLIC_UMAMI_SCRIPT_URL` & `NEXT_PUBLIC_UMAMI_WEBSITE_ID` environment variables on your `.env.local` file and on Vercel dashboard.

#### Plausible

Plausible is a simple, lightweight, open-source alternative to Google Analytics. You can read more about it on [Plausible website](https://plausible.io/).

Configure:
Set `NEXT_PUBLIC_PLAUSIBLE_DOMAIN` & `NEXT_PUBLIC_PLAUSIBLE_SCRIPT_URL` environment variables on your `.env.local` file and on Vercel dashboard. If you're concerned about ad blockers, you can proxy the plausible script through your own domain. You can read more about it [here](https://plausible.io/docs/proxy/guides/nextjs).

#### Other analytics providers

Supporting other analytics providers are in progress. Feel free to open an issue if you have any suggestions or a PR if you want to implement it yourself.
Expand Down Expand Up @@ -151,13 +181,14 @@ You can choose between 3 different hero variants to use in `app/(site)/page.tsx`

#### Image optimization

Optimize images in seconds for free with ImageOptim. Install on your Mac, then open the `public` folder in Finder. Select all images, right-click, and choose "Open with > ImageOptim". This will optimize all images in the folder.
I recommend optimizing images fast for free with [ImageOptim](https://imageoptim.com/mac). Install on your Mac, then open the `public` folder in Finder. Select all images, right-click, and choose "Open with > ImageOptim". This will optimize all images in the folder.

Note: DO NOT overdo it. You can easily make images look bad with lossy compression algorithms.

## Examples

- [https://davidlevai.com/](https://davidlevai.com/)
- [https://davidlevai.com/](https://davidlevai.com/) - My own digital garden
- [https://dragonsandcodes.com/](https://dragonsandcodes.com/) - Simple modifications

**Create a PR and add your blog to this list if you're using the template!**

Expand All @@ -180,7 +211,7 @@ Note: DO NOT overdo it. You can easily make images look bad with lossy compressi
- [x] projects page
- [x] about section on homepage
- [x] search & command bar
- [x] Analytics: Vercel, Umami
- [x] Analytics: Vercel, Umami, Plausible
- [x] Post series
- [x] Not found page
- [x] contributing docs
Expand All @@ -190,38 +221,46 @@ Note: DO NOT overdo it. You can easily make images look bad with lossy compressi
- [x] Social sharing buttons
- [x] Tags
- [x] newsletter integration (form, api route, keys, thank you/welcome page, MailerLite provider)
- [x] more MDX components (katex, math)
- [x] author content definition
- [x] SEO improvements
- [ ] Other newsletter providers (Convertkit, Substack, Buttondown, Mailchimp, etc)
- [ ] Other analytics providers (fathom, simplelytics, plausible, etc)
- [ ] CLI and/or recipes
- [ ] Other analytics providers (fathom, simplelytics, etc)
- [ ] RTL Support
- [ ] Post series page
- [ ] prev/next post links
- [ ] related posts
- [ ] related/similar posts
- [ ] Donate component & page
- [ ] CLI and/or recipes
- [ ] Newsletter previous issues page
- [ ] Layouts/templates system
- [ ] Notion data source
- [ ] Sanity data source
- [ ] hero title and subtitle text HTML support(?)
- [ ] Design improvements (whitespace, layout, etc.)
- [ ] error, and loading pages
- [ ] lightbox for images
- [ ] implement content security policies
- [ ] Code preview component
- [ ] Code highlight improvements (copy code, theme)
- [ ] `manifest.json`
- [ ] Rich project cards
- [ ] Landing page/offer page/freebie page
- [ ] CV template
- [ ] Authenticated pages and/or hidden content (behind email address)
- [ ] 100 lighthouse score
- [ ] Command bar fuzzy search in content
- [ ] Pagination
- [ ] SEO improvements
- [ ] Accessibility audit
- [ ] more MDX components (oembed)
- [ ] error, and loading pages
- [ ] TypeScript fixes
- [ ] Redesign social page (link in bio)
- [ ] Redesign uses page
- [ ] Redesign projects page
- [ ] general refactor
- [ ] general cleanup
- [ ] implement content security policies
- [ ] implement a videoask-like solution for the hero section
- [ ] RSS feed improvements (image, description, etc.)
- [ ] custom admin CMS(?)
- [ ] hero title and subtitle text HTML support(?)
- [ ] Pagination (?)
- [ ] multi-author support (?)
- [ ] Post like counter (?)
- [ ] Visitor counter (?)
Expand Down
2 changes: 1 addition & 1 deletion app/(site)/[slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { notFound } from "next/navigation";
import { allPages } from "contentlayer/generated";
import { format, parseISO } from "date-fns";

import { Mdx } from "@/components/mdx-components";
import { Mdx } from "@/components/mdx";

interface PageProps {
params: {
Expand Down
6 changes: 5 additions & 1 deletion app/(site)/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import siteMetadata from "@/lib/metadata";
import { cn } from "@/lib/utils";
import Footer from "@/components/footer";
import { Navigation } from "@/components/navigation";

Expand All @@ -17,7 +19,9 @@ export default function RootLayout({ children }: RootLayoutProps) {
</a>
<Navigation />
<div className="order-last mt-[calc(theme(spacing.16)-theme(spacing.3))]"></div>
<main id="main-content">{children}</main>
<main className={cn("mt-20", siteMetadata.activeAnnouncement && "mt-32 pt-28 md:pt-0")} id="main-content">
{children}
</main>
<Footer />
<div
className="absolute inset-x-0 -top-40 -z-10 transform-gpu overflow-hidden blur-3xl sm:-top-80"
Expand Down
28 changes: 13 additions & 15 deletions app/(site)/page.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
import Image from "next/image";
import Link from "next/link";
import { notFound } from "next/navigation";
import { allPages, allPosts } from "@/.contentlayer/generated";
import { compareDesc } from "date-fns";
import { allPages, allPosts } from "contentlayer/generated";
import { ArrowRight } from "lucide-react";

import { defaultAuthor } from "@/lib/metadata";
import { cn } from "@/lib/utils";
import siteMetadata, { defaultAuthor } from "@/lib/metadata";
import { sortByDate } from "@/lib/utils";
import { HeroImage } from "@/components/hero-image";
import { HeroMinimal } from "@/components/hero-minimal";
import { HeroSimple } from "@/components/hero-simple";
import { HeroVideo } from "@/components/hero-video";
import { Sidebar } from "@/components/home-sidebar";
import { Mdx } from "@/components/mdx-components";
import { Mdx } from "@/components/mdx";
import NewsletterSubscribe from "@/components/newsletter-subscribe";
import PostPreview from "@/components/post-preview";

Expand All @@ -30,10 +28,8 @@ export default async function Home() {
const aboutPage = await getAboutPage();
const posts = allPosts
.filter((post) => post.status === "published")
.sort((a, b) =>
compareDesc(new Date(a.lastUpdatedDate || a.publishedDate), new Date(b.lastUpdatedDate || b.publishedDate))
)
.slice(0, 8);
.sort(sortByDate)
.slice(0, siteMetadata.postsOnHomePage);

return (
<div className="pb-10">
Expand Down Expand Up @@ -61,12 +57,14 @@ export default async function Home() {
</aside>
</div>
</div>
<NewsletterSubscribe
title="I also write deep dives in email"
description="I write about coding, design, digital nomad life, and solopreneurship. Join over 1,000 other developers in
{siteMetadata.newsletterUrl && (
<NewsletterSubscribe
title="I also write deep dives in email"
description="I write about coding, design, digital nomad life, and solopreneurship. Join over 1,000 other developers in
getting better in business. Unsubscribe whenever."
buttonText="Send me the emails"
/>
buttonText="Send me the emails"
/>
)}
{aboutPage && (
<div className="container max-w-6xl">
<h2 className="mb-8 font-heading text-4xl font-bold">Who&apos;s this girl again?</h2>
Expand Down
4 changes: 3 additions & 1 deletion app/(site)/posts/[slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { cn } from "@/lib/utils";
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@/components/ui/accordion";
import { Card, CardContent, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
import { Separator } from "@/components/ui/separator";
import { Mdx } from "@/components/mdx-components";
import { Mdx } from "@/components/mdx";
import { PostSeriesBox } from "@/components/post-series-box";
import { SocialShare } from "@/components/social-share";
import { TableOfContents } from "@/components/table-of-contents";
Expand Down Expand Up @@ -59,6 +59,8 @@ export async function generateMetadata({ params }: PostProps): Promise<Metadata>
return {
title: post.title,
description: post.description,
authors: [{ name: post?.author?.name || defaultAuthor.name, url: defaultAuthor.website }],
keywords: post.tags,
};
}

Expand Down
10 changes: 3 additions & 7 deletions app/(site)/posts/page.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Metadata } from "next";
import { allPosts } from "@/.contentlayer/generated";
import { compareDesc } from "date-fns";
import { allPosts } from "contentlayer/generated";

import { defaultAuthor } from "@/lib/metadata";
import { sortByDate } from "@/lib/utils";
import PostPreview from "@/components/post-preview";

export async function generateMetadata(): Promise<Metadata> {
Expand All @@ -13,11 +13,7 @@ export async function generateMetadata(): Promise<Metadata> {
}

export default function Blog() {
const posts = allPosts
.filter((post) => post.status === "published")
.sort((a, b) =>
compareDesc(new Date(a.lastUpdatedDate || a.publishedDate), new Date(b.lastUpdatedDate || b.publishedDate))
);
const posts = allPosts.filter((post) => post.status === "published").sort(sortByDate);

return (
<div className="container mb-4">
Expand Down
6 changes: 3 additions & 3 deletions app/(site)/tags/[slug]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Metadata } from "next";
import { notFound } from "next/navigation";
import { allPosts, Post } from "@/.contentlayer/generated";
import { compareDesc } from "date-fns";
import { allPosts, Post } from "contentlayer/generated";

import { sortByDate } from "@/lib/utils";
import PostPreview from "@/components/post-preview";

// Get sorted articles from the contentlayer
Expand Down Expand Up @@ -33,7 +33,7 @@ export default async function TagPage({ params }: { params: { slug: string } })
const posts = allPosts
.filter((post) => post.status === "published")
.filter((post) => post.tags?.includes(tag))
.sort((a, b) => compareDesc(new Date(a.publishedDate), new Date(b.publishedDate)));
.sort(sortByDate);

if (!posts) {
notFound();
Expand Down
2 changes: 1 addition & 1 deletion app/(site)/tags/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Metadata } from "next";
import Link from "next/link";
import { notFound } from "next/navigation";
import { allPosts } from "@/.contentlayer/generated";
import { allPosts } from "contentlayer/generated";

import siteMetadata from "@/lib/metadata";
import { getTagsWithCount } from "@/lib/utils";
Expand Down
14 changes: 8 additions & 6 deletions app/(social)/social/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Image from "next/image";
import { Mail } from "lucide-react";

import { defaultAuthor } from "@/lib/metadata";
import siteMetadata, { defaultAuthor } from "@/lib/metadata";
import { projects } from "@/lib/projects-data";
import { CopyButton } from "@/components/copy-button";
import NewsletterSubscribe from "@/components/newsletter-subscribe";
Expand Down Expand Up @@ -39,12 +39,14 @@ export default async function SocialPage() {
<Signature />
</div>
</div>
<NewsletterSubscribe
title="I also write deep dives in email"
description="I write about coding, design, digital nomad life, and solopreneurship. Join over 1,000 other developers in
{siteMetadata.newsletterUrl && (
<NewsletterSubscribe
title="I also write deep dives in email"
description="I write about coding, design, digital nomad life, and solopreneurship. Join over 1,000 other developers in
getting better in business. Unsubscribe whenever."
buttonText="Send me the emails"
/>
buttonText="Send me the emails"
/>
)}
</>
);
}
2 changes: 1 addition & 1 deletion app/feed.xml/route.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { allPosts } from "@/.contentlayer/generated";
import { allPosts } from "contentlayer/generated";
import RSS from "rss";

import siteMetadata, { BASE_URL, defaultAuthor } from "@/lib/metadata";
Expand Down
Loading