Compare commits
2 Commits
187ce1b57f
...
8d2e889770
Author | SHA1 | Date |
---|---|---|
|
8d2e889770 | |
|
4b26a6caee |
|
@ -22,26 +22,67 @@ export async function generateMetadata({
|
||||||
pb.autoCancellation(true);
|
pb.autoCancellation(true);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
title: `${post.title}`,
|
title: `${post.title} | FastPocket`,
|
||||||
description: `${post.subtitle}`,
|
authors: [
|
||||||
|
{
|
||||||
|
name: post.author || "Samuel Wyndham",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
description: post.description,
|
||||||
|
keywords: post.keywords,
|
||||||
|
openGraph: {
|
||||||
|
title: `${post.title} | FastPocket`,
|
||||||
|
description: post.description,
|
||||||
|
type: "article",
|
||||||
|
url: `https://${siteURL}/blogs/${post.slug}`,
|
||||||
|
publishedTime: post.created,
|
||||||
|
modifiedTime: post.updated,
|
||||||
|
authors: [`https://${siteURL}/about`],
|
||||||
|
images: [
|
||||||
|
{
|
||||||
|
url: `${post.imageUrl}`,
|
||||||
|
width: 1024,
|
||||||
|
height: 576,
|
||||||
|
alt: post.title,
|
||||||
|
type: "image/png",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
twitter: {
|
||||||
|
card: "summary_large_image",
|
||||||
|
site: "@meinbiz",
|
||||||
|
creator: "@meinbiz",
|
||||||
|
title: `${post.title} | FastPocket`,
|
||||||
|
description: post.description,
|
||||||
|
images: [
|
||||||
|
{
|
||||||
|
url: `${post.imageUrl}`,
|
||||||
|
width: 1024,
|
||||||
|
height: 576,
|
||||||
|
alt: post.title,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
alternates: {
|
alternates: {
|
||||||
canonical: `https://${siteURL}/blogs/${slug}`,
|
canonical: `https://${siteURL}/blogs/${post.slug}`,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const generateStaticParams = async () => {
|
export const generateStaticParams = async () => {
|
||||||
const posts = await getPostMetadata();
|
const posts = await getPostMetadata();
|
||||||
return posts.map((post) => ({
|
console.log("static posts", posts.length);
|
||||||
|
const mappedPosts = posts.map((post) => ({
|
||||||
slug: post.slug,
|
slug: post.slug,
|
||||||
id: post.id,
|
|
||||||
}));
|
}));
|
||||||
|
return mappedPosts;
|
||||||
};
|
};
|
||||||
|
|
||||||
const PostPage = async (props: any) => {
|
const PostPage = async (props: any) => {
|
||||||
|
console.log("params", props.params);
|
||||||
const post = await pb
|
const post = await pb
|
||||||
.collection("blog")
|
.collection("blog")
|
||||||
.getFirstListItem(`slug="${props.params.slug}"`, {
|
.getFirstListItem(`slug="` + props.params.slug + `"`, {
|
||||||
requestKey: "post",
|
requestKey: "post",
|
||||||
});
|
});
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -8,6 +8,7 @@ import Footer from "@/components/Footer";
|
||||||
export default async function BlogsPage() {
|
export default async function BlogsPage() {
|
||||||
const postMetadata = await getPostMetadata();
|
const postMetadata = await getPostMetadata();
|
||||||
|
|
||||||
|
console.log("blogs", postMetadata.length);
|
||||||
const postPreviews = postMetadata
|
const postPreviews = postMetadata
|
||||||
.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime())
|
.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime())
|
||||||
.map((post) => <BlogCard key={post.slug} {...(post as any)} />);
|
.map((post) => <BlogCard key={post.slug} {...(post as any)} />);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
/* eslint-disable @next/next/no-before-interactive-script-outside-document */
|
||||||
import "./globals.css";
|
import "./globals.css";
|
||||||
import type { Metadata } from "next";
|
|
||||||
import "../app/globals.css";
|
import "../app/globals.css";
|
||||||
import { Arimo, Indie_Flower } from "next/font/google";
|
import { Arimo, Indie_Flower } from "next/font/google";
|
||||||
import { ToastContainer } from "react-toastify";
|
import { ToastContainer } from "react-toastify";
|
||||||
|
@ -8,8 +8,8 @@ import Header from "@/components/Header";
|
||||||
import { cookies } from "next/headers";
|
import { cookies } from "next/headers";
|
||||||
import { isAuthenticated } from "@/lib/auth";
|
import { isAuthenticated } from "@/lib/auth";
|
||||||
import { GTagProvider, PHProvider, ThemeProvider } from "./providers";
|
import { GTagProvider, PHProvider, ThemeProvider } from "./providers";
|
||||||
import { title } from "@/constants";
|
|
||||||
import Script from "next/script";
|
import Script from "next/script";
|
||||||
|
import dynamic from "next/dynamic";
|
||||||
|
|
||||||
const raleway = Arimo({
|
const raleway = Arimo({
|
||||||
variable: "--body-font",
|
variable: "--body-font",
|
||||||
|
@ -27,11 +27,6 @@ const indieFlower = Indie_Flower({
|
||||||
subsets: ["latin"],
|
subsets: ["latin"],
|
||||||
});
|
});
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
|
||||||
title: title,
|
|
||||||
description: title,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default async function RootLayout({
|
export default async function RootLayout({
|
||||||
children,
|
children,
|
||||||
}: {
|
}: {
|
||||||
|
@ -64,18 +59,20 @@ export default async function RootLayout({
|
||||||
theme="colored"
|
theme="colored"
|
||||||
/>
|
/>
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
|
<Script
|
||||||
|
id="promotekit-jq"
|
||||||
|
src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"
|
||||||
|
strategy="beforeInteractive"
|
||||||
|
/>
|
||||||
<Script
|
<Script
|
||||||
id="promotekit-js"
|
id="promotekit-js"
|
||||||
async
|
async
|
||||||
src="https://cdn.promotekit.com/promotekit.js"
|
src="https://cdn.promotekit.com/promotekit.js"
|
||||||
data-promotekit="41c8e339-d2aa-414b-88b8-31b6d6346e2b"
|
data-promotekit="41c8e339-d2aa-414b-88b8-31b6d6346e2b"
|
||||||
/>
|
/>
|
||||||
<Script
|
|
||||||
id="promotekit-jq"
|
|
||||||
src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"
|
|
||||||
/>
|
|
||||||
<Script
|
<Script
|
||||||
id="promotekit"
|
id="promotekit"
|
||||||
|
async
|
||||||
dangerouslySetInnerHTML={{
|
dangerouslySetInnerHTML={{
|
||||||
__html: `
|
__html: `
|
||||||
$(document).ready(function(){
|
$(document).ready(function(){
|
||||||
|
|
|
@ -12,6 +12,56 @@ import CardsFeature from "@/sections/Features/CardsFeature";
|
||||||
import FAQ from "@/sections/FAQ/RightAlignedBorderBottomFAQ";
|
import FAQ from "@/sections/FAQ/RightAlignedBorderBottomFAQ";
|
||||||
import VerticalTabsFeature from "@/sections/Features/VerticalTabsFeature";
|
import VerticalTabsFeature from "@/sections/Features/VerticalTabsFeature";
|
||||||
|
|
||||||
|
import { Metadata } from "next";
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: "Pocketbase, Stripe, Next.js, Boilerplate | FastPocket",
|
||||||
|
description:
|
||||||
|
"FastPocket - Is a boilerplate codebase for everyone to build a product quickly.",
|
||||||
|
keywords: [
|
||||||
|
"pocketbase",
|
||||||
|
"stripe",
|
||||||
|
"next.js",
|
||||||
|
"boilerplate",
|
||||||
|
"template",
|
||||||
|
"codebase",
|
||||||
|
],
|
||||||
|
openGraph: {
|
||||||
|
url: "https://fastpocket.dev",
|
||||||
|
type: "website",
|
||||||
|
title: "Pocketbase, Stripe, Next.js, Boilerplate | FastPocket",
|
||||||
|
description:
|
||||||
|
"FastPocket - Is a boilerplate codebase for everyone to build a product quickly.",
|
||||||
|
images: [
|
||||||
|
{
|
||||||
|
url: "https://fastpocket.dev/images/home/thumbnail.png",
|
||||||
|
width: 1200,
|
||||||
|
height: 630,
|
||||||
|
alt: "fastpocket.degv",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
twitter: {
|
||||||
|
card: "summary_large_image",
|
||||||
|
title: "Pocketbase, Stripe, Next.js, Boilerplate | FastPocket",
|
||||||
|
description:
|
||||||
|
"fastpocket.dev - Programming blog for everyone to learn Elastic Stack, Next.js, Python, JavaScript, React, Machine Learning, Data Science, and more.",
|
||||||
|
creator: "@meinbiz",
|
||||||
|
site: "@meinbiz",
|
||||||
|
images: [
|
||||||
|
{
|
||||||
|
url: "https://fastpocket.dev/images/home/thumbnail.png",
|
||||||
|
width: 1200,
|
||||||
|
height: 630,
|
||||||
|
alt: "fastpocket.degv",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
alternates: {
|
||||||
|
canonical: "https://fastpocket.dev",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
import getPostMetadata from "@/utils/getPostMetaData";
|
||||||
|
import { MetadataRoute } from "next";
|
||||||
|
|
||||||
|
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
|
||||||
|
const defaultPages = [
|
||||||
|
{
|
||||||
|
url: "https://fastpocket.dev",
|
||||||
|
lastModified: new Date(),
|
||||||
|
changeFrequency: "daily",
|
||||||
|
priority: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: "https://fastpocket.dev/about",
|
||||||
|
lastModified: new Date(),
|
||||||
|
changeFrequency: "monthly",
|
||||||
|
priority: 0.9
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: "https://fastpocket.dev/pricing",
|
||||||
|
lastModified: new Date(),
|
||||||
|
changeFrequency: "monthly",
|
||||||
|
priority: 0.9
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: "https://fastpocket.dev/blogs",
|
||||||
|
lastModified: new Date(),
|
||||||
|
changeFrequency: "monthly",
|
||||||
|
priority: 0.9
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: "https://fastpocket.dev/whatsnew",
|
||||||
|
lastModified: new Date(),
|
||||||
|
changeFrequency: "monthly",
|
||||||
|
priority: 0.9
|
||||||
|
}
|
||||||
|
// other pages
|
||||||
|
];
|
||||||
|
|
||||||
|
const postSlugs = await getPostMetadata();
|
||||||
|
|
||||||
|
const sitemap = [
|
||||||
|
...defaultPages,
|
||||||
|
...postSlugs.map((e: any) => ({
|
||||||
|
url: `https://fastpocket.dev/blogs/${e.slug}`,
|
||||||
|
lastModified: e.modified,
|
||||||
|
changeFrequency: "daily",
|
||||||
|
priority: 0.8
|
||||||
|
} as any))
|
||||||
|
];
|
||||||
|
|
||||||
|
return sitemap;
|
||||||
|
}
|
|
@ -5,7 +5,7 @@ import Navigation from "@/components/Navigation";
|
||||||
import ModalSignUp from "@/components/Modals/ModalSignUp";
|
import ModalSignUp from "@/components/Modals/ModalSignUp";
|
||||||
import ModalSignIn from "@/components/Modals/ModalSignIn";
|
import ModalSignIn from "@/components/Modals/ModalSignIn";
|
||||||
import { getAuthCookie, getUser, logout } from "@/app/actions";
|
import { getAuthCookie, getUser, logout } from "@/app/actions";
|
||||||
import { SourceModal, User } from "@/types";
|
import { User } from "@/types";
|
||||||
import { AppRouterInstance } from "next/dist/shared/lib/app-router-context.shared-runtime";
|
import { AppRouterInstance } from "next/dist/shared/lib/app-router-context.shared-runtime";
|
||||||
import pb from "@/lib/pocketbase";
|
import pb from "@/lib/pocketbase";
|
||||||
import { useTheme } from "next-themes";
|
import { useTheme } from "next-themes";
|
||||||
|
@ -32,7 +32,7 @@ export default function Header({ isUserLoggedIn }: HeaderProps) {
|
||||||
return (
|
return (
|
||||||
<header className="absolute w-full z-30">
|
<header className="absolute w-full z-30">
|
||||||
<div className="max-w-5xl mx-auto px-4 sm:px-6 md:pt-6">
|
<div className="max-w-5xl mx-auto px-4 sm:px-6 md:pt-6">
|
||||||
<div className="flex items-center justify-between h-20 items-center">
|
<div className="flex items-center justify-between h-20">
|
||||||
<Navigation isUserLoggedIn={isUserLoggedIn} />
|
<Navigation isUserLoggedIn={isUserLoggedIn} />
|
||||||
|
|
||||||
{/* Desktop navigation */}
|
{/* Desktop navigation */}
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
/** @type {import('next-sitemap').IConfig} */
|
||||||
|
module.exports = {
|
||||||
|
siteUrl: process.env.SITE_URL || 'https://fastpocket.dev',
|
||||||
|
generateRobotsTxt: true, // (optional)
|
||||||
|
generateRobotsTxt: true,
|
||||||
|
}
|
|
@ -24,6 +24,7 @@
|
||||||
"gray-matter": "^4.0.3",
|
"gray-matter": "^4.0.3",
|
||||||
"next": "^14.1.0",
|
"next": "^14.1.0",
|
||||||
"next-qrcode": "^2.5.1",
|
"next-qrcode": "^2.5.1",
|
||||||
|
"next-sitemap": "^4.2.3",
|
||||||
"next-themes": "^0.2.1",
|
"next-themes": "^0.2.1",
|
||||||
"node-fetch-commonjs": "^3.3.2",
|
"node-fetch-commonjs": "^3.3.2",
|
||||||
"pocketbase": "^0.18.0",
|
"pocketbase": "^0.18.0",
|
||||||
|
@ -81,6 +82,11 @@
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@corex/deepmerge": {
|
||||||
|
"version": "4.0.43",
|
||||||
|
"resolved": "https://registry.npmjs.org/@corex/deepmerge/-/deepmerge-4.0.43.tgz",
|
||||||
|
"integrity": "sha512-N8uEMrMPL0cu/bdboEWpQYb/0i2K5Qn8eCsxzOmxSggJbbQte7ljMRoXm917AbntqTGOzdTu+vP3KOOzoC70HQ=="
|
||||||
|
},
|
||||||
"node_modules/@emotion/hash": {
|
"node_modules/@emotion/hash": {
|
||||||
"version": "0.9.1",
|
"version": "0.9.1",
|
||||||
"resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.1.tgz",
|
"resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.1.tgz",
|
||||||
|
@ -3625,6 +3631,37 @@
|
||||||
"react": ">=17.0.0"
|
"react": ">=17.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/next-sitemap": {
|
||||||
|
"version": "4.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/next-sitemap/-/next-sitemap-4.2.3.tgz",
|
||||||
|
"integrity": "sha512-vjdCxeDuWDzldhCnyFCQipw5bfpl4HmZA7uoo3GAaYGjGgfL4Cxb1CiztPuWGmS+auYs7/8OekRS8C2cjdAsjQ==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://github.com/iamvishnusankar/next-sitemap.git"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"@corex/deepmerge": "^4.0.43",
|
||||||
|
"@next/env": "^13.4.3",
|
||||||
|
"fast-glob": "^3.2.12",
|
||||||
|
"minimist": "^1.2.8"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"next-sitemap": "bin/next-sitemap.mjs",
|
||||||
|
"next-sitemap-cjs": "bin/next-sitemap.cjs"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.18"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"next": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/next-sitemap/node_modules/@next/env": {
|
||||||
|
"version": "13.5.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@next/env/-/env-13.5.6.tgz",
|
||||||
|
"integrity": "sha512-Yac/bV5sBGkkEXmAX5FWPS9Mmo2rthrOPRQQNfycJPkjUAUclomCPH7QFVCDQ4Mp2k2K1SSM6m0zrxYrOwtFQw=="
|
||||||
|
},
|
||||||
"node_modules/next-themes": {
|
"node_modules/next-themes": {
|
||||||
"version": "0.2.1",
|
"version": "0.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.2.1.tgz",
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
# *
|
||||||
|
User-agent: *
|
||||||
|
Allow: /
|
||||||
|
|
||||||
|
# Host
|
||||||
|
Host: https://fastpocket.dev
|
||||||
|
|
||||||
|
# Sitemaps
|
||||||
|
Sitemap: https://fastpocket.dev/sitemap.xml
|
|
@ -2,7 +2,7 @@ import pb from '@/lib/pocketbase';
|
||||||
|
|
||||||
const getPostMetadata = async () => {
|
const getPostMetadata = async () => {
|
||||||
try {
|
try {
|
||||||
return (await (pb.collection("blog").getList(1, 50))).items
|
return (await (pb.collection("blog").getFullList({requestKey:'blogs'})))
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue