pretty much finish web
This commit is contained in:
@@ -17,6 +17,11 @@ const config = {
|
|||||||
protocol: "https",
|
protocol: "https",
|
||||||
port: '',
|
port: '',
|
||||||
hostname: "m.media-amazon.com"
|
hostname: "m.media-amazon.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
protocol: "https",
|
||||||
|
port: '',
|
||||||
|
hostname: "storage.thatalex.dev"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+109
-4
@@ -17,6 +17,7 @@
|
|||||||
"@trpc/next": "^10.37.1",
|
"@trpc/next": "^10.37.1",
|
||||||
"@trpc/react-query": "^10.37.1",
|
"@trpc/react-query": "^10.37.1",
|
||||||
"@trpc/server": "^10.37.1",
|
"@trpc/server": "^10.37.1",
|
||||||
|
"grommet-icons": "^4.11.0",
|
||||||
"next": "^13.5.4",
|
"next": "^13.5.4",
|
||||||
"next-auth": "^4.23.0",
|
"next-auth": "^4.23.0",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
@@ -74,6 +75,27 @@
|
|||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@emotion/is-prop-valid": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-61Mf7Ufx4aDxx1xlDeOm8aFFigGHE4z+0sKCa+IHCeZKiyP9RLD0Mmx7m8b9/Cf37f7NAvQOOJAbQQGVr5uERw==",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@emotion/memoize": "^0.8.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@emotion/memoize": {
|
||||||
|
"version": "0.8.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz",
|
||||||
|
"integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==",
|
||||||
|
"peer": true
|
||||||
|
},
|
||||||
|
"node_modules/@emotion/unitless": {
|
||||||
|
"version": "0.8.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz",
|
||||||
|
"integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==",
|
||||||
|
"peer": true
|
||||||
|
},
|
||||||
"node_modules/@eslint-community/eslint-utils": {
|
"node_modules/@eslint-community/eslint-utils": {
|
||||||
"version": "4.4.0",
|
"version": "4.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
|
||||||
@@ -650,6 +672,12 @@
|
|||||||
"integrity": "sha512-MMzuxN3GdFwskAnb6fz0orFvhfqi752yjaXylr0Rp4oDg5H0Zn1IuyRhDVvYOwAXoJirx2xuS16I3WjxnAIHiQ==",
|
"integrity": "sha512-MMzuxN3GdFwskAnb6fz0orFvhfqi752yjaXylr0Rp4oDg5H0Zn1IuyRhDVvYOwAXoJirx2xuS16I3WjxnAIHiQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/stylis": {
|
||||||
|
"version": "4.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/stylis/-/stylis-4.2.2.tgz",
|
||||||
|
"integrity": "sha512-Rm17MsTpQQP5Jq4BF7CdrxJsDufoiL/q5IbJZYZmOZAJALyijgF7BzLgobXUqraNcQdqFYLYGeglDp6QzaxPpg==",
|
||||||
|
"peer": true
|
||||||
|
},
|
||||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||||
"version": "6.8.0",
|
"version": "6.8.0",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.8.0.tgz",
|
||||||
@@ -1270,6 +1298,15 @@
|
|||||||
"node": ">= 6"
|
"node": ">= 6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/camelize": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==",
|
||||||
|
"peer": true,
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/caniuse-lite": {
|
"node_modules/caniuse-lite": {
|
||||||
"version": "1.0.30001551",
|
"version": "1.0.30001551",
|
||||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001551.tgz",
|
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001551.tgz",
|
||||||
@@ -1418,6 +1455,26 @@
|
|||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/css-color-keywords": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==",
|
||||||
|
"peer": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/css-to-react-native": {
|
||||||
|
"version": "3.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.2.0.tgz",
|
||||||
|
"integrity": "sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"camelize": "^1.0.0",
|
||||||
|
"css-color-keywords": "^1.0.0",
|
||||||
|
"postcss-value-parser": "^4.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/cssesc": {
|
"node_modules/cssesc": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
|
||||||
@@ -1433,8 +1490,7 @@
|
|||||||
"node_modules/csstype": {
|
"node_modules/csstype": {
|
||||||
"version": "3.1.2",
|
"version": "3.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz",
|
||||||
"integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==",
|
"integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"node_modules/damerau-levenshtein": {
|
"node_modules/damerau-levenshtein": {
|
||||||
"version": "1.0.8",
|
"version": "1.0.8",
|
||||||
@@ -2467,6 +2523,16 @@
|
|||||||
"integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
|
"integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/grommet-icons": {
|
||||||
|
"version": "4.11.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/grommet-icons/-/grommet-icons-4.11.0.tgz",
|
||||||
|
"integrity": "sha512-ArXf2XyXmpk5JsQ8NudzNz3mbWv+TeZkPiyog2s9yoNAWTlIr3vzNjr97uon/Xm4Uiq2kiHkvO4i2fG1u6EaDg==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.6.0 || ^17.0.0 || ^18.0.0",
|
||||||
|
"react-dom": "^16.6.0 || ^17.0.0 || ^18.0.0",
|
||||||
|
"styled-components": ">= 5.x"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/has": {
|
"node_modules/has": {
|
||||||
"version": "1.0.4",
|
"version": "1.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz",
|
||||||
@@ -3761,8 +3827,7 @@
|
|||||||
"node_modules/postcss-value-parser": {
|
"node_modules/postcss-value-parser": {
|
||||||
"version": "4.2.0",
|
"version": "4.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
|
||||||
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
|
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"node_modules/preact": {
|
"node_modules/preact": {
|
||||||
"version": "10.18.1",
|
"version": "10.18.1",
|
||||||
@@ -4208,6 +4273,12 @@
|
|||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/shallowequal": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==",
|
||||||
|
"peer": true
|
||||||
|
},
|
||||||
"node_modules/shebang-command": {
|
"node_modules/shebang-command": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
||||||
@@ -4366,6 +4437,34 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/styled-components": {
|
||||||
|
"version": "6.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.1.0.tgz",
|
||||||
|
"integrity": "sha512-VWNfYYBuXzuLS/QYEeoPgMErP26WL+dX9//rEh80B2mmlS1yRxRxuL5eax4m6ybYEUoHWlTy2XOU32767mlMkg==",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@emotion/is-prop-valid": "^1.2.1",
|
||||||
|
"@emotion/unitless": "^0.8.0",
|
||||||
|
"@types/stylis": "^4.0.2",
|
||||||
|
"css-to-react-native": "^3.2.0",
|
||||||
|
"csstype": "^3.1.2",
|
||||||
|
"postcss": "^8.4.31",
|
||||||
|
"shallowequal": "^1.1.0",
|
||||||
|
"stylis": "^4.3.0",
|
||||||
|
"tslib": "^2.5.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 16"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/styled-components"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">= 16.8.0",
|
||||||
|
"react-dom": ">= 16.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/styled-jsx": {
|
"node_modules/styled-jsx": {
|
||||||
"version": "5.1.1",
|
"version": "5.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz",
|
||||||
@@ -4388,6 +4487,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/stylis": {
|
||||||
|
"version": "4.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.0.tgz",
|
||||||
|
"integrity": "sha512-E87pIogpwUsUwXw7dNyU4QDjdgVMy52m+XEOPEKUn161cCzWjjhPSQhByfd1CcNvrOLnXQ6OnnZDwnJrz/Z4YQ==",
|
||||||
|
"peer": true
|
||||||
|
},
|
||||||
"node_modules/sucrase": {
|
"node_modules/sucrase": {
|
||||||
"version": "3.34.0",
|
"version": "3.34.0",
|
||||||
"resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.34.0.tgz",
|
"resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.34.0.tgz",
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
"@trpc/next": "^10.37.1",
|
"@trpc/next": "^10.37.1",
|
||||||
"@trpc/react-query": "^10.37.1",
|
"@trpc/react-query": "^10.37.1",
|
||||||
"@trpc/server": "^10.37.1",
|
"@trpc/server": "^10.37.1",
|
||||||
|
"grommet-icons": "^4.11.0",
|
||||||
"next": "^13.5.4",
|
"next": "^13.5.4",
|
||||||
"next-auth": "^4.23.0",
|
"next-auth": "^4.23.0",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
|
|||||||
@@ -1,16 +1,9 @@
|
|||||||
// This is your Prisma schema file,
|
|
||||||
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
|
||||||
|
|
||||||
generator client {
|
generator client {
|
||||||
provider = "prisma-client-js"
|
provider = "prisma-client-js"
|
||||||
}
|
}
|
||||||
|
|
||||||
datasource db {
|
datasource db {
|
||||||
provider = "sqlite"
|
provider = "sqlite"
|
||||||
// NOTE: When using mysql or sqlserver, uncomment the @db.Text annotations in model Account below
|
|
||||||
// Further reading:
|
|
||||||
// https://next-auth.js.org/adapters/prisma#create-the-prisma-schema
|
|
||||||
// https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference#string
|
|
||||||
url = env("DATABASE_URL")
|
url = env("DATABASE_URL")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ type HeaderItemProps = {
|
|||||||
newWindow?: boolean
|
newWindow?: boolean
|
||||||
}
|
}
|
||||||
export default function HeaderItem(props: HeaderItemProps) {
|
export default function HeaderItem(props: HeaderItemProps) {
|
||||||
console.log(props, props.newWindow ? "_blank" : "self")
|
|
||||||
if (props.onClick) {
|
if (props.onClick) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -1,18 +1,25 @@
|
|||||||
import Image from "next/image"
|
import Image from "next/image"
|
||||||
|
import Link from 'next/link';
|
||||||
|
|
||||||
type ReviewCardProps = {
|
type ReviewCardProps = {
|
||||||
title: string,
|
title: string,
|
||||||
image: string,
|
image: string,
|
||||||
url: string
|
url: string,
|
||||||
|
showText: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function ReviewCard(props: ReviewCardProps) {
|
export default function ReviewCard(props: ReviewCardProps) {
|
||||||
return (
|
return (
|
||||||
<>
|
<Link href={props.url}>
|
||||||
<div className="inline pr-4 pb-2">
|
<div className="inline">
|
||||||
<Image alt={props.title + " cover"} width="160" height="160" src={props.image} />
|
<Image alt={props.title + " cover"} width="160" height="160" src={props.image} className="p-2" />
|
||||||
|
{
|
||||||
|
props.showText ?
|
||||||
<p className="font-bold pt-2 text-center">{props.title}</p>
|
<p className="font-bold pt-2 text-center">{props.title}</p>
|
||||||
|
:
|
||||||
|
""
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</>
|
</Link>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import { Twitter, LinkedinOption, MailOption } from "grommet-icons"
|
||||||
|
import Link from 'next/link';
|
||||||
|
|
||||||
|
export default function Footer() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="absolute bottom-0 left-0 w-full bg-gray-900 p-2 text-white">
|
||||||
|
<p className="text-center">
|
||||||
|
<Link href="mailto:alex@alexavfrantz.com">
|
||||||
|
<p className="hover:text-gray-500 hover:underline hover:cursor-pointer">
|
||||||
|
alex@alexavfrantz.com
|
||||||
|
</p>
|
||||||
|
</Link>
|
||||||
|
</p>
|
||||||
|
<p className="text-center">
|
||||||
|
© Alex Frantz, 2023
|
||||||
|
</p>
|
||||||
|
<p className="text-center">
|
||||||
|
<Link href="https://twitter.com/avvex__" target="_blank" rel="noreferrer">
|
||||||
|
<Twitter color='plain' className="pr-2" size="30" />
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
<Link href="https://linkedin.com/in/thatalex" target="_blank" rel="noreferrer">
|
||||||
|
<LinkedinOption className="pr-2" size="30" />
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
<Link href="mailto:alex@alexavfrantz.com" target="_blank" rel="noreferrer">
|
||||||
|
<MailOption className="pr-2" size="30" />
|
||||||
|
</Link>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import Link from "next/link";
|
|
||||||
import {useSession, signIn, signOut} from 'next-auth/react';
|
import {useSession, signIn, signOut} from 'next-auth/react';
|
||||||
|
import Head from 'next/head';
|
||||||
import HeaderItem from "./HeaderItem";
|
import HeaderItem from "./HeaderItem";
|
||||||
|
|
||||||
export default function Header() {
|
export default function Header() {
|
||||||
@@ -12,7 +12,6 @@ export default function Header() {
|
|||||||
<div className="inline-block pb-2">
|
<div className="inline-block pb-2">
|
||||||
<HeaderItem content="home" linkTo="/" />
|
<HeaderItem content="home" linkTo="/" />
|
||||||
<HeaderItem content="reviews" linkTo="/reviews" />
|
<HeaderItem content="reviews" linkTo="/reviews" />
|
||||||
<HeaderItem content="contact" linkTo="/contact" />
|
|
||||||
<HeaderItem content={status == "unauthenticated" ? "login" : "logout" } onClick={status == "authenticated" ? signOut : signIn} linkTo="" />
|
<HeaderItem content={status == "unauthenticated" ? "login" : "logout" } onClick={status == "authenticated" ? signOut : signIn} linkTo="" />
|
||||||
</div>
|
</div>
|
||||||
<hr />
|
<hr />
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import { Html, Head, Main, NextScript } from 'next/document'
|
||||||
|
|
||||||
|
export default function Document() {
|
||||||
|
return (
|
||||||
|
<Html>
|
||||||
|
<Head>
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" />
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Poppins&display=swap" rel="stylesheet" />
|
||||||
|
</Head>
|
||||||
|
<body>
|
||||||
|
<Main />
|
||||||
|
<NextScript />
|
||||||
|
</body>
|
||||||
|
</Html>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
import { signIn, signOut, useSession } from "next-auth/react";
|
|
||||||
import Head from "next/head";
|
|
||||||
import Link from "next/link";
|
|
||||||
|
|
||||||
import { api } from "@/utils/api";
|
|
||||||
|
|
||||||
export default function Home() {
|
|
||||||
const hello = api.post.hello.useQuery({ text: "from tRPC" });
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Head>
|
|
||||||
<title>Create T3 App</title>
|
|
||||||
<meta name="description" content="Generated by create-t3-app" />
|
|
||||||
<link rel="icon" href="/favicon.ico" />
|
|
||||||
</Head>
|
|
||||||
<main className=" flex min-h-screen flex-col items-center justify-center bg-gradient-to-b from-[#2e026d] to-[#15162c]">
|
|
||||||
<div className="container flex flex-col items-center justify-center gap-12 px-4 py-16 ">
|
|
||||||
<h1 className="text-5xl font-extrabold tracking-tight text-white sm:text-[5rem]">
|
|
||||||
Create <span className="text-[hsl(280,100%,70%)]">T3</span> App
|
|
||||||
</h1>
|
|
||||||
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 md:gap-8">
|
|
||||||
<Link
|
|
||||||
className="flex max-w-xs flex-col gap-4 rounded-xl bg-white/10 p-4 text-white hover:bg-white/20"
|
|
||||||
href="https://create.t3.gg/en/usage/first-steps"
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
<h3 className="text-2xl font-bold">First Steps →</h3>
|
|
||||||
<div className="text-lg">
|
|
||||||
Just the basics - Everything you need to know to set up your
|
|
||||||
database and authentication.
|
|
||||||
</div>
|
|
||||||
</Link>
|
|
||||||
<Link
|
|
||||||
className="flex max-w-xs flex-col gap-4 rounded-xl bg-white/10 p-4 text-white hover:bg-white/20"
|
|
||||||
href="https://create.t3.gg/en/introduction"
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
<h3 className="text-2xl font-bold">Documentation →</h3>
|
|
||||||
<div className="text-lg">
|
|
||||||
Learn more about Create T3 App, the libraries it uses, and how
|
|
||||||
to deploy it.
|
|
||||||
</div>
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
<div className="flex flex-col items-center gap-2">
|
|
||||||
<p className="text-2xl text-white">
|
|
||||||
{hello.data ? hello.data.greeting : "Loading tRPC query..."}
|
|
||||||
</p>
|
|
||||||
<AuthShowcase />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function AuthShowcase() {
|
|
||||||
const { data: sessionData } = useSession();
|
|
||||||
|
|
||||||
const { data: secretMessage } = api.post.getSecretMessage.useQuery(
|
|
||||||
undefined, // no input
|
|
||||||
{ enabled: sessionData?.user !== undefined }
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="flex flex-col items-center justify-center gap-4">
|
|
||||||
<p className="text-center text-2xl text-white">
|
|
||||||
{sessionData && <span>Logged in as {sessionData.user?.name}</span>}
|
|
||||||
{secretMessage && <span> - {secretMessage}</span>}
|
|
||||||
</p>
|
|
||||||
<button
|
|
||||||
className="rounded-full bg-white/10 px-10 py-3 font-semibold text-white no-underline transition hover:bg-white/20"
|
|
||||||
onClick={sessionData ? () => void signOut() : () => void signIn()}
|
|
||||||
>
|
|
||||||
{sessionData ? "Sign out" : "Sign in"}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
+3
-3
@@ -1,13 +1,13 @@
|
|||||||
import { signIn, signOut, useSession } from "next-auth/react";
|
|
||||||
import Head from "next/head"
|
|
||||||
import Header from "@/components/header";
|
import Header from "@/components/header";
|
||||||
|
import Footer from "@/components/footer";
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
return (
|
return (
|
||||||
<main className="min-h-screen bg-black color-white">
|
<main className="min-h-screen bg-black">
|
||||||
<div className="w-1/2 mx-auto text-white">
|
<div className="w-1/2 mx-auto text-white">
|
||||||
<Header />
|
<Header />
|
||||||
<p>test</p>
|
<p>test</p>
|
||||||
|
<Footer />
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,17 +1,47 @@
|
|||||||
import {useRouter} from 'next/router';
|
import {useRouter} from 'next/router';
|
||||||
import {useState, useEffect} from 'react'
|
import Header from '@/components/header';
|
||||||
|
import Footer from "@/components/footer";
|
||||||
|
import Image from 'next/image';
|
||||||
import {api} from '@/utils/api'
|
import {api} from '@/utils/api'
|
||||||
import { useSession } from 'next-auth/react';
|
import Link from 'next/link';
|
||||||
|
|
||||||
export default function ReviewPage() {
|
export default function ReviewPage() {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const name = router.query.name as string
|
const name = router.query.name as string
|
||||||
const {data: bookData} = api.post.getOne.useQuery(name)
|
const {data: bookData} = api.post.getOne.useQuery(name)
|
||||||
const [view,setView] = useState(null)
|
|
||||||
|
|
||||||
|
if (bookData) {
|
||||||
return (
|
return (
|
||||||
<>
|
<main className="min-h-screen bg-black text-white">
|
||||||
<p>Post: {router.query.name}</p>
|
<Header />
|
||||||
</>
|
<div className="mx-auto w-1/2 text-center flex justify-center text-white">
|
||||||
|
<Image src={bookData.image} width="150" height="150" alt={`${bookData.name} ${bookData.type} cover`} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mx-auto w-1/2 text-center">
|
||||||
|
<h1 className="text-2xl font-bold">{bookData.name}</h1>
|
||||||
|
<hr />
|
||||||
|
{bookData.reviewContents}
|
||||||
|
</div>
|
||||||
|
<Footer />
|
||||||
|
</main>
|
||||||
)
|
)
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<main className="min-h-screen bg-black text-white flex flex-col justify-center items-centers">
|
||||||
|
<Header />
|
||||||
|
<div className="text-center text-2xl font-bold">
|
||||||
|
<p>Well, that's not good..</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="text-center">
|
||||||
|
<p>You've reached a page that doesn't exist. Lets fix that.</p>
|
||||||
|
<Link href="/" className="hover:underline hover:cursor-pointer hover:text-gray-500">
|
||||||
|
Head Home
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
<Footer />
|
||||||
|
</main>
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
import {useSession, getSession} from 'next-auth/react';
|
import {useSession, getSession} from 'next-auth/react';
|
||||||
import {useState, useEffect, FormEvent} from 'react';
|
import {useState, useEffect} from 'react';
|
||||||
|
import type {FormEvent} from 'react';
|
||||||
import Header from '@/components/header';
|
import Header from '@/components/header';
|
||||||
|
import Footer from "@/components/footer";
|
||||||
import Router from 'next/router';
|
import Router from 'next/router';
|
||||||
import { api } from "@/utils/api";
|
import { api } from "@/utils/api";
|
||||||
|
|
||||||
@@ -12,17 +14,23 @@ export default function Page() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (status == "unauthenticated") {
|
if (status == "unauthenticated") {
|
||||||
console.log('user is unauthenticated!')
|
console.log('user is unauthenticated!')
|
||||||
Router.replace('/')
|
Router.replace('/').catch(() => {
|
||||||
|
console.error("Failed to reroute user!")
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
}
|
}
|
||||||
}, [status])
|
}, [status])
|
||||||
|
|
||||||
|
function sanitizeTitleForLink(title: string) {
|
||||||
|
return title.replaceAll(" ", "-").toLowerCase()
|
||||||
|
}
|
||||||
|
|
||||||
function onSubmit(event: FormEvent<HTMLFormElement>) {
|
function onSubmit(event: FormEvent<HTMLFormElement>) {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
|
|
||||||
const object = {
|
const object = {
|
||||||
name: event.target.title.value,
|
name: sanitizeTitleForLink(event.target.title.value),
|
||||||
reviewContents: event.target.review.value,
|
reviewContents: event.target.review.value,
|
||||||
image: event.target.image.value,
|
image: event.target.image.value,
|
||||||
type: event.target.type.value
|
type: event.target.type.value
|
||||||
@@ -48,11 +56,12 @@ export default function Page() {
|
|||||||
<input name="type" type="text" /><br />
|
<input name="type" type="text" /><br />
|
||||||
|
|
||||||
<label className="font-bold">Review</label><br />
|
<label className="font-bold">Review</label><br />
|
||||||
<textarea name="review" />
|
<textarea name="review" /><br />
|
||||||
|
|
||||||
<button type="submit">submit</button>
|
<button type="submit">submit</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
<Footer />
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import Header from "@/components/header"
|
import Header from "@/components/header"
|
||||||
|
import Footer from "@/components/footer";
|
||||||
import ReviewCard from "@/components/ReviewCard"
|
import ReviewCard from "@/components/ReviewCard"
|
||||||
import {useSession} from 'next-auth/react';
|
import {useSession} from 'next-auth/react';
|
||||||
import {useState, useEffect} from 'react';
|
import {useState, useEffect} from 'react';
|
||||||
|
import Link from 'next/link';
|
||||||
import { api } from "@/utils/api";
|
import { api } from "@/utils/api";
|
||||||
|
|
||||||
type GenericItemType = {
|
type GenericItemType = {
|
||||||
@@ -13,35 +15,72 @@ export default function Reviews() {
|
|||||||
const { data: sessionData, status } = useSession();
|
const { data: sessionData, status } = useSession();
|
||||||
const {data: itemData} = api.post.getAll.useQuery()
|
const {data: itemData} = api.post.getAll.useQuery()
|
||||||
const [list, setList] = useState<null | JSX.Element[]>(null)
|
const [list, setList] = useState<null | JSX.Element[]>(null)
|
||||||
|
const [type, setType] = useState("Book")
|
||||||
|
|
||||||
|
function onCatClick() {
|
||||||
|
// probably gonna rework this eventually if needed
|
||||||
|
switch(type) {
|
||||||
|
case 'Book':
|
||||||
|
setType("Movie")
|
||||||
|
break;
|
||||||
|
case 'Movie':
|
||||||
|
setType("TV")
|
||||||
|
break;
|
||||||
|
case 'TV':
|
||||||
|
setType("Game")
|
||||||
|
break;
|
||||||
|
case 'Game':
|
||||||
|
setType("Book")
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function sanitizeTitleForLink(title: string) {
|
||||||
|
return title.replaceAll(" ", "-").toLowerCase()
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (itemData) {
|
if (itemData) {
|
||||||
|
const filteredArray = itemData.filter(v => v.type == type.toLowerCase())
|
||||||
|
|
||||||
setList(
|
setList(
|
||||||
itemData?.map((v: GenericItemType) => {
|
filteredArray.map((v: GenericItemType, k) => {
|
||||||
return <ReviewCard title={v.name} url={`/reviews/${v.name}`} image={v.image} />
|
return <ReviewCard
|
||||||
|
key={k}
|
||||||
|
title={v.name}
|
||||||
|
url={`/reviews/${sanitizeTitleForLink(v.name)}`}
|
||||||
|
image={v.image}
|
||||||
|
showText={false}
|
||||||
|
/>
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}, [itemData])
|
}, [itemData, type])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main className="min-h-screen bg-black color-white">
|
<main className="min-h-screen bg-black color-white">
|
||||||
<div className="w-1/2 mx-auto text-white">
|
|
||||||
<Header />
|
<Header />
|
||||||
|
<div className="w-1/2 mx-auto text-white">
|
||||||
{
|
{
|
||||||
status == "authenticated" ?
|
status == "authenticated" ?
|
||||||
<p className="text-center font-bold">
|
<p className="text-center font-bold">
|
||||||
<a href="/reviews/create">
|
<Link href="/reviews/create">
|
||||||
Create
|
Create
|
||||||
</a>
|
</Link>
|
||||||
</p>
|
</p>
|
||||||
:
|
:
|
||||||
""
|
""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<p className="text-center font-bold text-2xl hover:cursor-pointer hover:underline pb-2" onClick={onCatClick}>
|
||||||
|
{type}
|
||||||
|
</p>
|
||||||
|
|
||||||
<div className="flex flex-wrap justify-center">
|
<div className="flex flex-wrap justify-center">
|
||||||
{list}
|
{list}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<Footer />
|
||||||
</main>
|
</main>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,7 @@
|
|||||||
@tailwind base;
|
@tailwind base;
|
||||||
@tailwind components;
|
@tailwind components;
|
||||||
@tailwind utilities;
|
@tailwind utilities;
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: 'Poppins', sans-serif
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user