Project init

This commit is contained in:
Xevion
2022-12-17 15:57:05 -06:00
parent 35b2011040
commit ea0785cc97
24 changed files with 2710 additions and 0 deletions

11
.env.example Normal file
View File

@@ -0,0 +1,11 @@
# Since .env is gitignored, you can use .env.example to build a new `.env` file when you clone the repo.
# Keep this file up-to-date when you add new variables to `.env`.
# This file will be committed to version control, so make sure not to have any secrets in it.
# If you are cloning this repo, create a copy of this file named `.env` and populate it with your secrets.
# When adding additional env variables, the schema in /env/schema.mjs should be updated accordingly
# Example:
# SERVERVAR=foo
# NEXT_PUBLIC_CLIENTVAR=bar

11
.eslintrc.json Normal file
View File

@@ -0,0 +1,11 @@
{
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": "./tsconfig.json"
},
"plugins": ["@typescript-eslint"],
"extends": ["next/core-web-vitals", "plugin:@typescript-eslint/recommended"],
"rules": {
"@typescript-eslint/consistent-type-imports": "warn"
}
}

42
.gitignore vendored Normal file
View File

@@ -0,0 +1,42 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# database
/prisma/db.sqlite
/prisma/db.sqlite-journal
# next.js
/.next/
/out/
next-env.d.ts
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*
# local env files
# do not commit any .env files to git, except for the .env.example file. https://create.t3.gg/en/usage/env-variables#using-environment-variables
.env
.env*.local
# vercel
.vercel
# typescript
*.tsbuildinfo

28
README.md Normal file
View File

@@ -0,0 +1,28 @@
# Create T3 App
This is a [T3 Stack](https://create.t3.gg/) project bootstrapped with `create-t3-app`.
## What's next? How do I make an app with this?
We try to keep this project as simple as possible, so you can start with just the scaffolding we set up for you, and add additional things later when they become necessary.
If you are not familiar with the different technologies used in this project, please refer to the respective docs. If you still are in the wind, please join our [Discord](https://t3.gg/discord) and ask for help.
- [Next.js](https://nextjs.org)
- [NextAuth.js](https://next-auth.js.org)
- [Prisma](https://prisma.io)
- [Tailwind CSS](https://tailwindcss.com)
- [tRPC](https://trpc.io)
## Learn More
To learn more about the [T3 Stack](https://create.t3.gg/), take a look at the following resources:
- [Documentation](https://create.t3.gg/)
- [Learn the T3 Stack](https://create.t3.gg/en/faq#what-learning-resources-are-currently-available) — Check out these awesome tutorials
You can check out the [create-t3-app GitHub repository](https://github.com/t3-oss/create-t3-app) — your feedback and contributions are welcome!
## How do I deploy this?
Follow our deployment guides for [Vercel](https://create.t3.gg/en/deployment/vercel) and [Docker](https://create.t3.gg/en/deployment/docker) for more information.

17
next.config.mjs Normal file
View File

@@ -0,0 +1,17 @@
// @ts-check
/**
* Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation.
* This is especially useful for Docker builds.
*/
!process.env.SKIP_ENV_VALIDATION && (await import("./src/env/server.mjs"));
/** @type {import("next").NextConfig} */
const config = {
reactStrictMode: true,
swcMinify: true,
i18n: {
locales: ["en"],
defaultLocale: "en",
},
};
export default config;

44
package.json Normal file
View File

@@ -0,0 +1,44 @@
{
"name": "100prisoners",
"version": "0.1.0",
"private": true,
"scripts": {
"build": "next build",
"dev": "next dev",
"lint": "next lint",
"start": "next start"
},
"dependencies": {
"@tanstack/react-query": "^4.16.0",
"@trpc/client": "^10.0.0",
"@trpc/next": "^10.0.0",
"@trpc/react-query": "^10.0.0",
"@trpc/server": "^10.0.0",
"@types/chance": "^1.1.3",
"chance": "^1.1.9",
"next": "13.0.2",
"react": "18.2.0",
"react-dom": "18.2.0",
"sass": "^1.57.0",
"superjson": "1.9.1",
"zod": "^3.18.0"
},
"devDependencies": {
"@types/node": "^18.0.0",
"@types/react": "^18.0.14",
"@types/react-dom": "^18.0.5",
"@typescript-eslint/eslint-plugin": "^5.33.0",
"@typescript-eslint/parser": "^5.33.0",
"autoprefixer": "^10.4.7",
"eslint": "^8.26.0",
"eslint-config-next": "13.0.2",
"postcss": "^8.4.14",
"prettier": "^2.7.1",
"prettier-plugin-tailwindcss": "^0.1.13",
"tailwindcss": "^3.2.0",
"typescript": "^4.8.4"
},
"ct3aMetadata": {
"initVersion": "6.11.4"
}
}

6
postcss.config.cjs Normal file
View File

@@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
};

4
prettier.config.cjs Normal file
View File

@@ -0,0 +1,4 @@
/** @type {import("prettier").Config} */
module.exports = {
plugins: [require.resolve("prettier-plugin-tailwindcss")],
};

BIN
public/favicon.ico Normal file
View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

35
src/env/client.mjs vendored Normal file
View File

@@ -0,0 +1,35 @@
// @ts-check
import { clientEnv, clientSchema } from "./schema.mjs";
const _clientEnv = clientSchema.safeParse(clientEnv);
export const formatErrors = (
/** @type {import('zod').ZodFormattedError<Map<string,string>,string>} */
errors,
) =>
Object.entries(errors)
.map(([name, value]) => {
if (value && "_errors" in value)
return `${name}: ${value._errors.join(", ")}\n`;
})
.filter(Boolean);
if (!_clientEnv.success) {
console.error(
"❌ Invalid environment variables:\n",
...formatErrors(_clientEnv.error.format()),
);
throw new Error("Invalid environment variables");
}
for (let key of Object.keys(_clientEnv.data)) {
if (!key.startsWith("NEXT_PUBLIC_")) {
console.warn(
`❌ Invalid public environment variable name: ${key}. It must begin with 'NEXT_PUBLIC_'`,
);
throw new Error("Invalid public environment variable name");
}
}
export const env = _clientEnv.data;

29
src/env/schema.mjs vendored Normal file
View File

@@ -0,0 +1,29 @@
// @ts-check
import { z } from "zod";
/**
* Specify your server-side environment variables schema here.
* This way you can ensure the app isn't built with invalid env vars.
*/
export const serverSchema = z.object({
NODE_ENV: z.enum(["development", "test", "production"]),
});
/**
* Specify your client-side environment variables schema here.
* This way you can ensure the app isn't built with invalid env vars.
* To expose them to the client, prefix them with `NEXT_PUBLIC_`.
*/
export const clientSchema = z.object({
// NEXT_PUBLIC_CLIENTVAR: z.string(),
});
/**
* You can't destruct `process.env` as a regular object, so you have to do
* it manually here. This is because Next.js evaluates this at build time,
* and only used environment variables are included in the build.
* @type {{ [k in keyof z.infer<typeof clientSchema>]: z.infer<typeof clientSchema>[k] | undefined }}
*/
export const clientEnv = {
// NEXT_PUBLIC_CLIENTVAR: process.env.NEXT_PUBLIC_CLIENTVAR,
};

27
src/env/server.mjs vendored Normal file
View File

@@ -0,0 +1,27 @@
// @ts-check
/**
* This file is included in `/next.config.mjs` which ensures the app isn't built with invalid env vars.
* It has to be a `.mjs`-file to be imported there.
*/
import { serverSchema } from "./schema.mjs";
import { env as clientEnv, formatErrors } from "./client.mjs";
const _serverEnv = serverSchema.safeParse(process.env);
if (!_serverEnv.success) {
console.error(
"❌ Invalid environment variables:\n",
...formatErrors(_serverEnv.error.format()),
);
throw new Error("Invalid environment variables");
}
for (let key of Object.keys(_serverEnv.data)) {
if (key.startsWith("NEXT_PUBLIC_")) {
console.warn("❌ You are exposing a server-side env-variable:", key);
throw new Error("You are exposing a server-side env-variable");
}
}
export const env = { ..._serverEnv.data, ...clientEnv };

11
src/pages/_app.tsx Normal file
View File

@@ -0,0 +1,11 @@
import { type AppType } from "next/app";
import { trpc } from "../utils/trpc";
import "../styles/globals.scss";
const MyApp: AppType = ({ Component, pageProps }) => {
return <Component {...pageProps} />;
};
export default trpc.withTRPC(MyApp);

View File

@@ -0,0 +1,17 @@
import { createNextApiHandler } from "@trpc/server/adapters/next";
import { env } from "../../../env/server.mjs";
import { createContext } from "../../../server/trpc/context";
import { appRouter } from "../../../server/trpc/router/_app";
// export API handler
export default createNextApiHandler({
router: appRouter,
createContext,
onError:
env.NODE_ENV === "development"
? ({ path, error }) => {
console.error(`❌ tRPC failed on ${path}: ${error}`);
}
: undefined,
});

53
src/pages/index.tsx Normal file
View File

@@ -0,0 +1,53 @@
import {type NextPage} from "next";
import Head from "next/head";
import BoxGraphic from "../components/BoxGraphic";
import Chance from "chance";
import {range} from "../utils/helpers";
const chance = new Chance();
const Home: NextPage = () => {
const sources = range(0, 100);
const destinations = chance.shuffle(sources);
const boxes = sources.map((e, i) => [e, destinations[i]])
return (
<>
<Head>
<title>100prisoners.com</title>
<link rel="icon" href="/favicon.ico"/>
</Head>
<main className="flex min-h-screen flex-col items-center bg-white">
<div className="mt-8 px-3 w-[50rem] space-y-3">
<h1 className="text-4xl mb-2">100Prisoners.com</h1>
<div>
This website is dedicated to exploring the intriguing 100 prisoners problem, a mathematical
challenge that seems astronomically impossible at first, yet can leverage mathematics to raise
the chances one hundred octillion.
<br/>
<br/>
This thought experiment presents a scenario in which a group of 100 prisoners are tasked with
finding their own numbered slip among a collection of 100 boxes, each containing a random
permutation of the numbers 1 through 100. The prisoners are allowed to open 50 boxes each in an
attempt to find their own number, and all of the prisoners must be successful in order to be set
free. This problem raises questions about strategy and probability in search of a solution.
</div>
<div className="grid grid-cols-10 w-full space-y-2">
{boxes.map(([source, destination]) =>
<div className="col-span-1 px-2">
<div key={source} className="box aspect-square relative">
<span className="absolute left-6 top-8 cursor-pointer">{destination}</span>
<BoxGraphic className="transition-all cursor-pointer relative z-30">
{source + 1}
</BoxGraphic>
</div>
</div>
)}
</div>
</div>
</main>
</>
);
};
export default Home;

View File

@@ -0,0 +1,26 @@
import { type inferAsyncReturnType } from "@trpc/server";
import { type CreateNextContextOptions } from "@trpc/server/adapters/next";
/**
* Replace this with an object if you want to pass things to createContextInner
*/
type CreateContextOptions = Record<string, never>;
/** Use this helper for:
* - testing, so we dont have to mock Next.js' req/res
* - trpc's `createSSGHelpers` where we don't have req/res
* @see https://create.t3.gg/en/usage/trpc#-servertrpccontextts
**/
export const createContextInner = async (opts: CreateContextOptions) => {
return {};
};
/**
* This is the actual context you'll use in your router
* @link https://trpc.io/docs/context
**/
export const createContext = async (opts: CreateNextContextOptions) => {
return await createContextInner({});
};
export type Context = inferAsyncReturnType<typeof createContext>;

View File

@@ -0,0 +1,9 @@
import { router } from "../trpc";
import { exampleRouter } from "./example";
export const appRouter = router({
example: exampleRouter,
});
// export type definition of API
export type AppRouter = typeof appRouter;

View File

@@ -0,0 +1,13 @@
import { z } from "zod";
import { router, publicProcedure } from "../trpc";
export const exampleRouter = router({
hello: publicProcedure
.input(z.object({ text: z.string().nullish() }).nullish())
.query(({ input }) => {
return {
greeting: `Hello ${input?.text ?? "world"}`,
};
}),
});

15
src/server/trpc/trpc.ts Normal file
View File

@@ -0,0 +1,15 @@
import { initTRPC } from "@trpc/server";
import superjson from "superjson";
import { type Context } from "./context";
const t = initTRPC.context<Context>().create({
transformer: superjson,
errorFormatter({ shape }) {
return shape;
},
});
export const router = t.router;
export const publicProcedure = t.procedure;

2
src/utils/helpers.ts Normal file
View File

@@ -0,0 +1,2 @@
export const range = (start: number, stop: number, step = 1) =>
Array.from({length: (stop - start) / step + 1}, (_, i) => start + i * step);

42
src/utils/trpc.ts Normal file
View File

@@ -0,0 +1,42 @@
import { httpBatchLink, loggerLink } from "@trpc/client";
import { createTRPCNext } from "@trpc/next";
import { type inferRouterInputs, type inferRouterOutputs } from "@trpc/server";
import superjson from "superjson";
import { type AppRouter } from "../server/trpc/router/_app";
const getBaseUrl = () => {
if (typeof window !== "undefined") return ""; // browser should use relative url
if (process.env.VERCEL_URL) return `https://${process.env.VERCEL_URL}`; // SSR should use vercel url
return `http://localhost:${process.env.PORT ?? 3000}`; // dev SSR should use localhost
};
export const trpc = createTRPCNext<AppRouter>({
config() {
return {
transformer: superjson,
links: [
loggerLink({
enabled: (opts) =>
process.env.NODE_ENV === "development" ||
(opts.direction === "down" && opts.result instanceof Error),
}),
httpBatchLink({
url: `${getBaseUrl()}/api/trpc`,
}),
],
};
},
ssr: false,
});
/**
* Inference helper for inputs
* @example type HelloInput = RouterInputs['example']['hello']
**/
export type RouterInputs = inferRouterInputs<AppRouter>;
/**
* Inference helper for outputs
* @example type HelloOutput = RouterOutputs['example']['hello']
**/
export type RouterOutputs = inferRouterOutputs<AppRouter>;

12
tailwind.config.cjs Normal file
View File

@@ -0,0 +1,12 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ["./src/**/*.{js,ts,jsx,tsx}"],
theme: {
extend: {
fontFamily: {
playfair: ["\"Playfair Display\"", "serif"]
}
},
},
plugins: [],
};

21
tsconfig.json Normal file
View File

@@ -0,0 +1,21 @@
{
"compilerOptions": {
"target": "es2017",
"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,
"noUncheckedIndexedAccess": true
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "**/*.cjs", "**/*.mjs"],
"exclude": ["node_modules"]
}

2235
yarn.lock Normal file
View File

File diff suppressed because it is too large Load Diff