mirror of
https://github.com/hanzoai/next.js.git
synced 2026-09-24 17:00:51 +00:00
remove with-fauna example (#80440)
This commit is contained in:
@@ -1 +0,0 @@
|
||||
FAUNA_CLIENT_SECRET=
|
||||
@@ -1,40 +0,0 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.*
|
||||
.yarn/*
|
||||
!.yarn/patches
|
||||
!.yarn/plugins
|
||||
!.yarn/releases
|
||||
!.yarn/versions
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# next.js
|
||||
/.next/
|
||||
/out/
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
*.pem
|
||||
|
||||
# debug
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# local env files
|
||||
.env*.local
|
||||
|
||||
# vercel
|
||||
.vercel
|
||||
|
||||
# typescript
|
||||
*.tsbuildinfo
|
||||
next-env.d.ts
|
||||
@@ -1,41 +0,0 @@
|
||||
# Fauna Guestbook Starter
|
||||
|
||||
This Guestbook Application example shows you how to use [Fauna](https://docs.fauna.com/) in your Next.js project.
|
||||
|
||||
## Deploy your own
|
||||
|
||||
[](https://vercel.com/new/clone?repository-url=https://github.com/vercel/next.js/tree/canary/examples/with-fauna&project-name=fauna-nextjs-guestbook&repository-name=fauna-nextjs-guestbook&demo-title=Next.js%20Fauna%20Guestbook%20App&demo-description=A%20simple%20guestbook%20application%20built%20with%20Next.js%20and%20Fauna&integration-ids=oac_Erlbqm8Teb1y4WhioE3r2utY)
|
||||
|
||||
## How to use
|
||||
|
||||
Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init), [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/), or [pnpm](https://pnpm.io) to bootstrap the example:
|
||||
|
||||
```bash
|
||||
npx create-next-app --example with-fauna with-fauna-app
|
||||
```
|
||||
|
||||
```bash
|
||||
yarn create next-app --example with-fauna with-fauna-app
|
||||
```
|
||||
|
||||
```bash
|
||||
pnpm create next-app --example with-fauna with-fauna-app
|
||||
```
|
||||
|
||||
### Setting Up Your Fauna Database
|
||||
|
||||
Head over to [Fauna Dashboard](https://dashboard.fauna.com/) and create a new database. You can name it whatever you want, but for this example, we'll use `nextjs-guestbook`. Next, create a new collection called `Entry` in your new database.
|
||||
Finally create a new database access key to connect to your database.
|
||||
|
||||
Watch [this video](https://www.youtube.com/watch?v=8YJcG2fUPyE&t=43s&ab_channel=FaunaInc.) to learn how to connect to your database.
|
||||
|
||||
### Run locally
|
||||
|
||||
Install packages, set up if needed, then run the development server:
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Your app should be up and running on [http://localhost:3000](http://localhost:3000)!
|
||||
@@ -1,22 +0,0 @@
|
||||
"use server";
|
||||
|
||||
import { revalidatePath } from "next/cache";
|
||||
import { createEntry } from "@/lib/fauna";
|
||||
|
||||
export async function createEntryAction(prevState: any, formData: FormData) {
|
||||
const name = formData.get("name") as string;
|
||||
const message = formData.get("message") as string;
|
||||
try {
|
||||
await createEntry(name, message);
|
||||
revalidatePath("/");
|
||||
return {
|
||||
successMessage: "Thank you for signing the guest book",
|
||||
errorMessage: null,
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
successMessage: null,
|
||||
errorMessage: "Something went wrong. Please try again",
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
@@ -1,50 +0,0 @@
|
||||
import cn from "classnames";
|
||||
import formatDate from "date-fns/format";
|
||||
import EntryForm from "@/components/EntryForm";
|
||||
import { EntryType } from "./page";
|
||||
|
||||
const EntryItem = ({ entry }: { entry: EntryType }) => (
|
||||
<div className="flex flex-col space-y-2">
|
||||
<div className="prose dark:prose-dark w-full">{entry.message}</div>
|
||||
<div className="flex items-center space-x-3">
|
||||
<p className="text-sm text-gray-500">{entry.name}</p>
|
||||
<span className="text-gray-200 dark:text-gray-800">/</span>
|
||||
<p className="text-sm text-gray-400 dark:text-gray-600">
|
||||
{formatDate(
|
||||
new Date(entry.createdAt.isoString),
|
||||
"d MMM yyyy 'at' h:mm bb",
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
export default async function GuestbookPage({
|
||||
entries,
|
||||
}: {
|
||||
entries: EntryType[];
|
||||
}) {
|
||||
return (
|
||||
<main className="max-w-4xl mx-auto p-4">
|
||||
<div
|
||||
className={cn(
|
||||
"border border-blue-200 rounded p-6",
|
||||
"my-4 w-full dark:border-gray-800 bg-blue-50",
|
||||
"dark:bg-blue-opaque",
|
||||
)}
|
||||
>
|
||||
<h5 className={cn("text-lg md:text-xl font-bold", "text-gray-900")}>
|
||||
Sign the Guestbook
|
||||
</h5>
|
||||
<p className="my-1 text-gray-800">
|
||||
Share a message for a future visitor.
|
||||
</p>
|
||||
<EntryForm />
|
||||
</div>
|
||||
|
||||
<div className="mt-4 space-y-8 px-2">
|
||||
{entries?.map((entry) => <EntryItem key={entry.id} entry={entry} />)}
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
import "./globals.css";
|
||||
|
||||
export const metadata: {
|
||||
title: string;
|
||||
description: string;
|
||||
} = {
|
||||
title: "Next.js + Fauna example",
|
||||
description: "Generated by Next.js",
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body>{children}</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import { getAllEntries } from "@/lib/fauna";
|
||||
import GuestbookPage from "./guestbook-page";
|
||||
|
||||
export type EntryType = {
|
||||
id: string;
|
||||
name: string;
|
||||
message: string;
|
||||
createdAt: {
|
||||
isoString: string;
|
||||
};
|
||||
};
|
||||
|
||||
export default async function Page() {
|
||||
const entries = (await getAllEntries()) as EntryType[];
|
||||
return <GuestbookPage entries={entries} />;
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import cn from "classnames";
|
||||
import { createEntryAction } from "@/actions/entry";
|
||||
// @ts-ignore
|
||||
import { useActionState } from "react";
|
||||
// @ts-ignore
|
||||
import { useFormStatus } from "react-dom";
|
||||
import LoadingSpinner from "@/components/LoadingSpinner";
|
||||
import SuccessMessage from "@/components/SuccessMessage";
|
||||
import ErrorMessage from "@/components/ErrorMessage";
|
||||
|
||||
const inputClasses = cn(
|
||||
"block py-2 bg-white dark:bg-gray-800",
|
||||
"rounded-md border-gray-300 focus:ring-blue-500",
|
||||
"focus:border-blue-500 text-gray-900 dark:text-gray-100",
|
||||
);
|
||||
|
||||
const initialState = {
|
||||
successMessage: null,
|
||||
errorMessage: null,
|
||||
};
|
||||
|
||||
export default function EntryForm() {
|
||||
// useActionState is available with React 19 (Next.js App Router)
|
||||
const [state, formAction] = useActionState(createEntryAction, initialState);
|
||||
const { pending } = useFormStatus();
|
||||
|
||||
return (
|
||||
<>
|
||||
<form className="relative flex my-4" action={formAction}>
|
||||
<input
|
||||
required
|
||||
className={cn(inputClasses, "w-1/3 mr-2 px-4")}
|
||||
aria-label="Your name"
|
||||
placeholder="Your name..."
|
||||
name="name"
|
||||
/>
|
||||
<input
|
||||
required
|
||||
className={cn(inputClasses, "pl-4 pr-32 flex-grow")}
|
||||
aria-label="Your message"
|
||||
placeholder="Your message..."
|
||||
name="message"
|
||||
/>
|
||||
<button
|
||||
className={cn(
|
||||
"flex items-center justify-center",
|
||||
"absolute right-1 top-1 px-4 font-bold h-8",
|
||||
"bg-gray-100 dark:bg-gray-700 text-gray-900",
|
||||
"dark:text-gray-100 rounded w-28",
|
||||
)}
|
||||
type="submit"
|
||||
disabled={pending}
|
||||
>
|
||||
{pending ? <LoadingSpinner /> : "Sign"}
|
||||
</button>
|
||||
</form>
|
||||
{state?.successMessage ? (
|
||||
<SuccessMessage>{state.successMessage}</SuccessMessage>
|
||||
) : null}
|
||||
{state?.errorMessage ? (
|
||||
<ErrorMessage>{state.errorMessage}</ErrorMessage>
|
||||
) : null}
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
export default function ErrorMessage({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<p className="flex items-center text-sm font-bold text-red-800 dark:text-red-400">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
className="mr-2 h-4 w-4"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
{children}
|
||||
</p>
|
||||
);
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
export default function LoadingSpinner() {
|
||||
return (
|
||||
<svg
|
||||
className="animate-spin h-5 w-5 text-gray-900 dark:text-gray-100"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<circle
|
||||
className="opacity-25"
|
||||
cx="12"
|
||||
cy="12"
|
||||
r="10"
|
||||
stroke="currentColor"
|
||||
strokeWidth="4"
|
||||
/>
|
||||
<path
|
||||
className="opacity-75"
|
||||
fill="currentColor"
|
||||
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
export default function SuccessMessage({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<p className="flex items-center text-sm font-bold text-green-700 dark:text-green-400">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
className="mr-2 h-4 w-4"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
{children}
|
||||
</p>
|
||||
);
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/actions/*": ["actions/*"],
|
||||
"@/components/*": ["components/*"],
|
||||
"@/lib/*": ["lib/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
import "server-only";
|
||||
import { Client, fql, QuerySuccess, QueryValueObject } from "fauna";
|
||||
|
||||
const client = new Client({
|
||||
secret: process.env.FAUNA_CLIENT_SECRET,
|
||||
});
|
||||
|
||||
export const getAllEntries = async () => {
|
||||
try {
|
||||
const dbresponse: QuerySuccess<QueryValueObject> = await client.query(fql`
|
||||
Entry.all()
|
||||
`);
|
||||
return dbresponse.data.data;
|
||||
} catch (error: any) {
|
||||
throw new Error(error.message);
|
||||
}
|
||||
};
|
||||
|
||||
export const createEntry = async (name: string, message: string) => {
|
||||
try {
|
||||
const dbresponse = await client.query(fql`
|
||||
Entry.create({
|
||||
name: ${name},
|
||||
message: ${message},
|
||||
createdAt: Time.now(),
|
||||
})`);
|
||||
return dbresponse.data;
|
||||
} catch (error: any) {
|
||||
throw new Error(error.message);
|
||||
}
|
||||
};
|
||||
@@ -1,3 +0,0 @@
|
||||
const nextConfig = {};
|
||||
|
||||
module.exports = nextConfig;
|
||||
@@ -1,25 +0,0 @@
|
||||
{
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next",
|
||||
"build": "yarn setup && next build",
|
||||
"start": "next start",
|
||||
"setup": "node ./scripts/setup.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"classnames": "2.3.1",
|
||||
"date-fns": "2.28.0",
|
||||
"fauna": "^1.2.0",
|
||||
"next": "canary",
|
||||
"react": "rc",
|
||||
"react-dom": "rc",
|
||||
"server-only": "^0.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"autoprefixer": "^10.4.16",
|
||||
"postcss": "^8.4.31",
|
||||
"request": "^2.88.2",
|
||||
"stream-to-promise": "3.0.0",
|
||||
"tailwindcss": "^3.3.3"
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
};
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 8.5 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 12 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 6.5 KiB |
@@ -1,12 +0,0 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
content: [
|
||||
"./app/**/*.{js,ts,jsx,tsx,mdx}",
|
||||
"./pages/**/*.{js,ts,jsx,tsx,mdx}",
|
||||
"./components/**/*.{js,ts,jsx,tsx,mdx}",
|
||||
],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [],
|
||||
};
|
||||
@@ -1,28 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve",
|
||||
"incremental": true,
|
||||
"plugins": [
|
||||
{
|
||||
"name": "next"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"@/*": ["./*"]
|
||||
}
|
||||
},
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
@@ -78,7 +78,6 @@
|
||||
"with-emotion-swc": true,
|
||||
"with-eslint": true,
|
||||
"with-facebook-pixel": true,
|
||||
"with-fauna": true,
|
||||
"with-fela": true,
|
||||
"with-fingerprintjs-pro": true,
|
||||
"with-firebase": true,
|
||||
|
||||
Reference in New Issue
Block a user