main
psoubrie 2023-10-31 19:26:23 +00:00
commit 3ec0a3c486
47 changed files with 5159 additions and 0 deletions

View File

@ -0,0 +1,29 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/typescript-node
{
"name": "Node.js & TypeScript",
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
"image": "mcr.microsoft.com/devcontainers/typescript-node:1-20-bullseye",
"customizations": {
"vscode": {
"extensions": [
"bradlc.vscode-tailwindcss"
]
}
}
// Features to add to the dev container. More info: https://containers.dev/features.
// "features": {},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],
// Use 'postCreateCommand' to run commands after the container is created.
// "postCreateCommand": "yarn install",
// Configure tool-specific properties.
// "customizations": {},
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
// "remoteUser": "root"
}

14
.env.example Normal file
View File

@ -0,0 +1,14 @@
# Since the ".env" file is gitignored, you can use the ".env.example" file 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 environment variables, the schema in "/src/env.mjs"
# should be updated accordingly.
# Example:
# SERVERVAR="foo"
# NEXT_PUBLIC_CLIENTVAR="bar"

36
.eslintrc.cjs Normal file
View File

@ -0,0 +1,36 @@
/** @type {import("eslint").Linter.Config} */
const config = {
parser: "@typescript-eslint/parser",
parserOptions: {
project: true,
},
plugins: ["@typescript-eslint"],
extends: [
"next/core-web-vitals",
"plugin:@typescript-eslint/recommended-type-checked",
"plugin:@typescript-eslint/stylistic-type-checked",
],
rules: {
// These opinionated rules are enabled in stylistic-type-checked above.
// Feel free to reconfigure them to your own preference.
"@typescript-eslint/array-type": "off",
"@typescript-eslint/consistent-type-definitions": "off",
"@typescript-eslint/consistent-type-imports": [
"warn",
{
prefer: "type-imports",
fixStyle: "inline-type-imports",
},
],
"@typescript-eslint/no-unused-vars": ["warn", { argsIgnorePattern: "^_" }],
"@typescript-eslint/no-misused-promises": [
2,
{
checksVoidReturn: { attributes: false },
},
],
},
};
module.exports = config;

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), [Netlify](https://create.t3.gg/en/deployment/netlify) and [Docker](https://create.t3.gg/en/deployment/docker) for more information.

22
next.config.mjs Normal file
View File

@ -0,0 +1,22 @@
/**
* Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. This is especially useful
* for Docker builds.
*/
await import("./src/env.mjs");
/** @type {import("next").NextConfig} */
const config = {
reactStrictMode: true,
/**
* If you are using `appDir` then you must comment the below `i18n` config out.
*
* @see https://github.com/vercel/next.js/issues/41980
*/
i18n: {
locales: ["en"],
defaultLocale: "en",
},
};
export default config;

4627
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

40
package.json Normal file
View File

@ -0,0 +1,40 @@
{
"name": "typescript-node",
"version": "0.1.0",
"private": true,
"scripts": {
"build": "next build",
"dev": "next dev",
"lint": "next lint",
"start": "next start"
},
"dependencies": {
"@radix-ui/react-icons": "^1.3.0",
"@t3-oss/env-nextjs": "^0.7.0",
"next": "^13.5.4",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-pageflip": "^2.0.3",
"zod": "^3.22.4"
},
"devDependencies": {
"@types/eslint": "^8.44.2",
"@types/node": "^18.16.0",
"@types/react": "^18.2.20",
"@types/react-dom": "^18.2.7",
"@typescript-eslint/eslint-plugin": "^6.3.0",
"@typescript-eslint/parser": "^6.3.0",
"autoprefixer": "^10.4.14",
"eslint": "^8.47.0",
"eslint-config-next": "^13.5.4",
"postcss": "^8.4.27",
"prettier": "^3.0.0",
"prettier-plugin-tailwindcss": "^0.5.1",
"tailwindcss": "^3.3.3",
"typescript": "^5.1.6"
},
"ct3aMetadata": {
"initVersion": "7.22.0"
},
"packageManager": "npm@9.8.1"
}

8
postcss.config.cjs Normal file
View File

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

6
prettier.config.mjs Normal file
View File

@ -0,0 +1,6 @@
/** @type {import('prettier').Config & import('prettier-plugin-tailwindcss').options} */
const config = {
plugins: ["prettier-plugin-tailwindcss"],
};
export default config;

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 632 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 215 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 227 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 315 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 365 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 437 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 331 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 556 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 494 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 432 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 288 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 255 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 229 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 235 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 278 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 461 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 234 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 496 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 189 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 266 KiB

View File

@ -0,0 +1,91 @@
import { ChevronLeftIcon, ChevronRightIcon } from '@radix-ui/react-icons';
import React, { useRef, useCallback } from 'react';
import HTMLFlipBook from 'react-pageflip';
interface FlipbookProps {
children: React.ReactNode[];
width: number;
height: number;
className?: React.ComponentProps<'div'>['className'];
}
interface PageFlip {
getCurrentPageIndex(): number;
getPageCount(): number;
flip(page: number): void;
flipPrev(): void;
flipNext(): void;
}
export default function Flipbook(props: FlipbookProps) {
const flipbook = useRef<{ pageFlip(): PageFlip } | null>(null);
// Function to flip pages
const flipPage = useCallback((direction: 'next' | 'prev') => {
const flipbookCurrent = flipbook.current;
if (flipbookCurrent) {
const pageFlipObj = flipbookCurrent.pageFlip();
const currentPageIndex = pageFlipObj.getCurrentPageIndex();
const pageCount = pageFlipObj.getPageCount();
if (direction === 'next') {
if (currentPageIndex + 2 === pageCount) {
pageFlipObj.flip(0);
} else {
pageFlipObj.flipNext();
}
} else if (direction === 'prev') {
if (currentPageIndex === 0) {
pageFlipObj.flip(pageCount - 1);
} else {
pageFlipObj.flipPrev(); // Add this method to handle the previous page flip
}
}
}
}, [flipbook]);
// Handler for the next button
const nextButtonClick = useCallback(() => {
flipPage('next');
}, [flipPage]);
// Handler for the previous button
const prevButtonClick = useCallback(() => {
flipPage('prev');
}, [flipPage]);
return (
<div className={`flex justify-center items-center ${props.className}`}>
<button onClick={prevButtonClick}>
<ChevronLeftIcon height={50} width={50}/>
</button>
<HTMLFlipBook
usePortrait={false}
className="text-black"
width={props.width} height={props.height}
size="fixed"
style={{}}
minHeight={100} maxHeight={500}
minWidth={100} maxWidth={500}
startPage={0} startZIndex={0}
drawShadow
flippingTime={1000}
autoSize
maxShadowOpacity={1}
showCover={false}
mobileScrollSupport
clickEventForward
useMouseEvents
swipeDistance={20}
showPageCorners
disableFlipByClick={false}
ref={flipbook}
>
{props.children}
</HTMLFlipBook>
<button onClick={nextButtonClick}>
<ChevronRightIcon height={50} width={50}/>
</button>
</div>
);
}

83
src/components/Slider.tsx Normal file
View File

@ -0,0 +1,83 @@
import { ChevronLeftIcon, ChevronRightIcon } from "@radix-ui/react-icons";
import { useKeenSlider } from "keen-slider/react";
import { useState, type MouseEvent } from "react";
interface SliderProps {
className?: React.ComponentProps<'div'>['className'];
children?: React.ReactNode;
}
export default function Slider({ className, children }: SliderProps) {
const [currentSlide, setCurrentSlide] = useState(0);
const [loaded, setLoaded] = useState(false);
const [sliderRef, instanceRef] = useKeenSlider<HTMLDivElement>({
initial: 0,
slideChanged(slider) {
setCurrentSlide(slider.track.details.rel);
},
created() {
setLoaded(true);
},
});
const goPrev = (e: MouseEvent<unknown>) => {
e.stopPropagation();
if (currentSlide !== 0) {
instanceRef.current?.prev();
}
};
const goNext = (e: MouseEvent<unknown>) => {
e.stopPropagation();
if (instanceRef.current && currentSlide !== instanceRef.current.track.details.slides.length - 1) {
instanceRef.current.next();
}
};
return (
<div className={`${className} relative`}>
<div>
<div ref={sliderRef} className="flex overflow-hidden relative w-full">
{children}
</div>
{loaded && instanceRef.current && (
<>
<Arrow left onClick={goPrev} disabled={currentSlide === 0} />
<Arrow onClick={goNext} disabled={instanceRef.current ? currentSlide === instanceRef.current.track.details.slides.length - 1 : true} />
</>
)}
</div>
{loaded && instanceRef.current && (
<div className="flex justify-center py-2">
{Array.from({ length: instanceRef.current.track.details.slides.length }, (_, idx) => (
<button
key={idx}
onClick={() => instanceRef.current?.moveToIdx(idx)}
className={`w-2.5 h-2.5 bg-white rounded-full m-1 cursor-pointer ${currentSlide === idx ? "opacity-30" : ""}`}
></button>
))}
</div>
)}
</div>
);
}
interface ArrowProps {
disabled: boolean;
left?: boolean;
onClick: (e: MouseEvent<unknown>) => void;
}
function Arrow({ disabled, left, onClick }: ArrowProps) {
const Icon = left ? ChevronLeftIcon : ChevronRightIcon;
const position = left ? '-left-10' : 'left-auto -right-10';
return (
<Icon
onClick={onClick}
height={50}
width={50}
className={`absolute ${position} top-1/2 cursor-pointer -translate-y-1/2 ${disabled ? "opacity-30" : ""}`}
/>
);
}

40
src/env.mjs Normal file
View File

@ -0,0 +1,40 @@
import { createEnv } from "@t3-oss/env-nextjs";
import { z } from "zod";
export const env = createEnv({
/**
* Specify your server-side environment variables schema here. This way you can ensure the app
* isn't built with invalid env vars.
*/
server: {
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_`.
*/
client: {
// NEXT_PUBLIC_CLIENTVAR: z.string(),
},
/**
* You can't destruct `process.env` as a regular object in the Next.js edge runtimes (e.g.
* middlewares) or client-side so we need to destruct manually.
*/
runtimeEnv: {
NODE_ENV: process.env.NODE_ENV,
// NEXT_PUBLIC_CLIENTVAR: process.env.NEXT_PUBLIC_CLIENTVAR,
},
/**
* Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation.
* This is especially useful for Docker builds.
*/
skipValidation: !!process.env.SKIP_ENV_VALIDATION,
/**
* Makes it so that empty strings are treated as undefined.
* `SOME_VAR: z.string()` and `SOME_VAR=''` will throw an error.
*/
emptyStringAsUndefined: true,
});

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

@ -0,0 +1,9 @@
import { type AppType } from "next/dist/shared/lib/utils";
import "~/styles/globals.css";
const MyApp: AppType = ({ Component, pageProps }) => {
return <Component {...pageProps} />;
};
export default MyApp;

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

@ -0,0 +1,32 @@
import Head from "next/head";
import Image from "next/image";
import Flipbook from "~/components/Flipbook";
export default function Home() {
return (
<>
<Head>
<title>Create T3 App</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="icon" href="/favicon.ico" />
</Head>
<main className="">
<Flipbook className="" width={350} height={460}>
<div className="bg-gray-300">
<div className="flex justify-center items-center h-full">
<a href="/download/GabrielDalle_Magazine.pdf" target="_blank" className="border-my-red border-[3px] p-4 rounded-full flex gap-2 cursor-pointer hover:border-black hover:bg-white font-mono font-bold text-sm tracking-wide">
PDF DOWNLOAD
</a>
</div>
</div>
{Array.from(Array(24), (_, i) => (
<div className="bg-white" key={i}>
<Image key={i} alt="pdf page" height={468} width={350} src={`/projects/fizik/pdf/page${i + 1}.png`} />
</div>
))}
<div className="bg-gray-300" />
</Flipbook>
</main>
</>
);
}

3
src/styles/globals.css Normal file
View File

@ -0,0 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

14
tailwind.config.ts Normal file
View File

@ -0,0 +1,14 @@
import { type Config } from "tailwindcss";
import { fontFamily } from "tailwindcss/defaultTheme";
export default {
content: ["./src/**/*.tsx"],
theme: {
extend: {
fontFamily: {
sans: ["var(--font-sans)", ...fontFamily.sans],
},
},
},
plugins: [],
} satisfies Config;

35
tsconfig.json Normal file
View File

@ -0,0 +1,35 @@
{
"compilerOptions": {
"target": "es2017",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"checkJs": 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,
"baseUrl": ".",
"paths": {
"~/*": ["./src/*"]
},
"plugins": [{ "name": "next" }]
},
"include": [
".eslintrc.cjs",
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
"**/*.cjs",
"**/*.mjs",
".next/types/**/*.ts"
],
"exclude": ["node_modules"]
}