Merge pull request #36 from sambecker/auth-integration

Nav auth integration
This commit is contained in:
Sam Becker 2024-01-07 00:46:40 -06:00 committed by GitHub
commit 756cbc7f1b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
58 changed files with 279 additions and 321 deletions

View File

@ -17,10 +17,10 @@
"@testing-library/react": "^14.1.2",
"@types/jest": "^29.5.11",
"@types/node": "^20.10.6",
"@types/react": "18.2.46",
"@types/react": "18.2.47",
"@types/react-dom": "18.2.18",
"@typescript-eslint/eslint-plugin": "^6.17.0",
"@typescript-eslint/parser": "^6.17.0",
"@typescript-eslint/eslint-plugin": "^6.18.0",
"@typescript-eslint/parser": "^6.18.0",
"@vercel/analytics": "^1.1.1",
"@vercel/blob": "^0.16.1",
"@vercel/postgres": "0.5.1",
@ -44,7 +44,7 @@
"react-dom": "18.2.0",
"react-icons": "^4.12.0",
"sonner": "^1.3.1",
"tailwindcss": "3.4.0",
"tailwindcss": "3.4.1",
"ts-exif-parser": "^0.2.2",
"typescript": "5.3.3"
}

126
pnpm-lock.yaml generated
View File

@ -16,7 +16,7 @@ dependencies:
version: 14.0.4
'@tailwindcss/forms':
specifier: ^0.5.7
version: 0.5.7(tailwindcss@3.4.0)
version: 0.5.7(tailwindcss@3.4.1)
'@testing-library/jest-dom':
specifier: ^6.2.0
version: 6.2.0(@types/jest@29.5.11)(jest@29.7.0)
@ -30,17 +30,17 @@ dependencies:
specifier: ^20.10.6
version: 20.10.6
'@types/react':
specifier: 18.2.46
version: 18.2.46
specifier: 18.2.47
version: 18.2.47
'@types/react-dom':
specifier: 18.2.18
version: 18.2.18
'@typescript-eslint/eslint-plugin':
specifier: ^6.17.0
version: 6.17.0(@typescript-eslint/parser@6.17.0)(eslint@8.56.0)(typescript@5.3.3)
specifier: ^6.18.0
version: 6.18.0(@typescript-eslint/parser@6.18.0)(eslint@8.56.0)(typescript@5.3.3)
'@typescript-eslint/parser':
specifier: ^6.17.0
version: 6.17.0(eslint@8.56.0)(typescript@5.3.3)
specifier: ^6.18.0
version: 6.18.0(eslint@8.56.0)(typescript@5.3.3)
'@vercel/analytics':
specifier: ^1.1.1
version: 1.1.1
@ -111,8 +111,8 @@ dependencies:
specifier: ^1.3.1
version: 1.3.1(react-dom@18.2.0)(react@18.2.0)
tailwindcss:
specifier: 3.4.0
version: 3.4.0
specifier: 3.4.1
version: 3.4.1
ts-exif-parser:
specifier: ^0.2.2
version: 0.2.2
@ -2118,13 +2118,13 @@ packages:
tslib: 2.6.2
dev: false
/@tailwindcss/forms@0.5.7(tailwindcss@3.4.0):
/@tailwindcss/forms@0.5.7(tailwindcss@3.4.1):
resolution: {integrity: sha512-QE7X69iQI+ZXwldE+rzasvbJiyV/ju1FGHH0Qn2W3FKbuYtqp8LKcy6iSw79fVUT5/Vvf+0XgLCeYVG+UV6hOw==}
peerDependencies:
tailwindcss: '>=3.0.0 || >= 3.0.0-alpha.1'
dependencies:
mini-svg-data-uri: 1.4.4
tailwindcss: 3.4.0
tailwindcss: 3.4.1
dev: false
/@testing-library/dom@9.3.3:
@ -2289,11 +2289,11 @@ packages:
/@types/react-dom@18.2.18:
resolution: {integrity: sha512-TJxDm6OfAX2KJWJdMEVTwWke5Sc/E/RlnPGvGfS0W7+6ocy2xhDVQVh/KvC2Uf7kACs+gDytdusDSdWfWkaNzw==}
dependencies:
'@types/react': 18.2.46
'@types/react': 18.2.47
dev: false
/@types/react@18.2.46:
resolution: {integrity: sha512-nNCvVBcZlvX4NU1nRRNV/mFl1nNRuTuslAJglQsq+8ldXe5Xv0Wd2f7WTE3jOxhLH2BFfiZGC6GCp+kHQbgG+w==}
/@types/react@18.2.47:
resolution: {integrity: sha512-xquNkkOirwyCgoClNk85BjP+aqnIS+ckAJ8i37gAbDs14jfW/J23f2GItAf33oiUPQnqNMALiFeoM9Y5mbjpVQ==}
dependencies:
'@types/prop-types': 15.7.11
'@types/scheduler': 0.16.8
@ -2326,8 +2326,8 @@ packages:
'@types/yargs-parser': 21.0.3
dev: false
/@typescript-eslint/eslint-plugin@6.17.0(@typescript-eslint/parser@6.17.0)(eslint@8.56.0)(typescript@5.3.3):
resolution: {integrity: sha512-Vih/4xLXmY7V490dGwBQJTpIZxH4ZFH6eCVmQ4RFkB+wmaCTDAx4dtgoWwMNGKLkqRY1L6rPqzEbjorRnDo4rQ==}
/@typescript-eslint/eslint-plugin@6.18.0(@typescript-eslint/parser@6.18.0)(eslint@8.56.0)(typescript@5.3.3):
resolution: {integrity: sha512-3lqEvQUdCozi6d1mddWqd+kf8KxmGq2Plzx36BlkjuQe3rSTm/O98cLf0A4uDO+a5N1KD2SeEEl6fW97YHY+6w==}
engines: {node: ^16.0.0 || >=18.0.0}
peerDependencies:
'@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha
@ -2338,11 +2338,11 @@ packages:
optional: true
dependencies:
'@eslint-community/regexpp': 4.10.0
'@typescript-eslint/parser': 6.17.0(eslint@8.56.0)(typescript@5.3.3)
'@typescript-eslint/scope-manager': 6.17.0
'@typescript-eslint/type-utils': 6.17.0(eslint@8.56.0)(typescript@5.3.3)
'@typescript-eslint/utils': 6.17.0(eslint@8.56.0)(typescript@5.3.3)
'@typescript-eslint/visitor-keys': 6.17.0
'@typescript-eslint/parser': 6.18.0(eslint@8.56.0)(typescript@5.3.3)
'@typescript-eslint/scope-manager': 6.18.0
'@typescript-eslint/type-utils': 6.18.0(eslint@8.56.0)(typescript@5.3.3)
'@typescript-eslint/utils': 6.18.0(eslint@8.56.0)(typescript@5.3.3)
'@typescript-eslint/visitor-keys': 6.18.0
debug: 4.3.4
eslint: 8.56.0
graphemer: 1.4.0
@ -2355,8 +2355,8 @@ packages:
- supports-color
dev: false
/@typescript-eslint/parser@6.17.0(eslint@8.56.0)(typescript@5.3.3):
resolution: {integrity: sha512-C4bBaX2orvhK+LlwrY8oWGmSl4WolCfYm513gEccdWZj0CwGadbIADb0FtVEcI+WzUyjyoBj2JRP8g25E6IB8A==}
/@typescript-eslint/parser@6.18.0(eslint@8.56.0)(typescript@5.3.3):
resolution: {integrity: sha512-v6uR68SFvqhNQT41frCMCQpsP+5vySy6IdgjlzUWoo7ALCnpaWYcz/Ij2k4L8cEsL0wkvOviCMpjmtRtHNOKzA==}
engines: {node: ^16.0.0 || >=18.0.0}
peerDependencies:
eslint: ^7.0.0 || ^8.0.0
@ -2365,10 +2365,10 @@ packages:
typescript:
optional: true
dependencies:
'@typescript-eslint/scope-manager': 6.17.0
'@typescript-eslint/types': 6.17.0
'@typescript-eslint/typescript-estree': 6.17.0(typescript@5.3.3)
'@typescript-eslint/visitor-keys': 6.17.0
'@typescript-eslint/scope-manager': 6.18.0
'@typescript-eslint/types': 6.18.0
'@typescript-eslint/typescript-estree': 6.18.0(typescript@5.3.3)
'@typescript-eslint/visitor-keys': 6.18.0
debug: 4.3.4
eslint: 8.56.0
typescript: 5.3.3
@ -2376,16 +2376,16 @@ packages:
- supports-color
dev: false
/@typescript-eslint/scope-manager@6.17.0:
resolution: {integrity: sha512-RX7a8lwgOi7am0k17NUO0+ZmMOX4PpjLtLRgLmT1d3lBYdWH4ssBUbwdmc5pdRX8rXon8v9x8vaoOSpkHfcXGA==}
/@typescript-eslint/scope-manager@6.18.0:
resolution: {integrity: sha512-o/UoDT2NgOJ2VfHpfr+KBY2ErWvCySNUIX/X7O9g8Zzt/tXdpfEU43qbNk8LVuWUT2E0ptzTWXh79i74PP0twA==}
engines: {node: ^16.0.0 || >=18.0.0}
dependencies:
'@typescript-eslint/types': 6.17.0
'@typescript-eslint/visitor-keys': 6.17.0
'@typescript-eslint/types': 6.18.0
'@typescript-eslint/visitor-keys': 6.18.0
dev: false
/@typescript-eslint/type-utils@6.17.0(eslint@8.56.0)(typescript@5.3.3):
resolution: {integrity: sha512-hDXcWmnbtn4P2B37ka3nil3yi3VCQO2QEB9gBiHJmQp5wmyQWqnjA85+ZcE8c4FqnaB6lBwMrPkgd4aBYz3iNg==}
/@typescript-eslint/type-utils@6.18.0(eslint@8.56.0)(typescript@5.3.3):
resolution: {integrity: sha512-ZeMtrXnGmTcHciJN1+u2CigWEEXgy1ufoxtWcHORt5kGvpjjIlK9MUhzHm4RM8iVy6dqSaZA/6PVkX6+r+ChjQ==}
engines: {node: ^16.0.0 || >=18.0.0}
peerDependencies:
eslint: ^7.0.0 || ^8.0.0
@ -2394,8 +2394,8 @@ packages:
typescript:
optional: true
dependencies:
'@typescript-eslint/typescript-estree': 6.17.0(typescript@5.3.3)
'@typescript-eslint/utils': 6.17.0(eslint@8.56.0)(typescript@5.3.3)
'@typescript-eslint/typescript-estree': 6.18.0(typescript@5.3.3)
'@typescript-eslint/utils': 6.18.0(eslint@8.56.0)(typescript@5.3.3)
debug: 4.3.4
eslint: 8.56.0
ts-api-utils: 1.0.3(typescript@5.3.3)
@ -2404,13 +2404,13 @@ packages:
- supports-color
dev: false
/@typescript-eslint/types@6.17.0:
resolution: {integrity: sha512-qRKs9tvc3a4RBcL/9PXtKSehI/q8wuU9xYJxe97WFxnzH8NWWtcW3ffNS+EWg8uPvIerhjsEZ+rHtDqOCiH57A==}
/@typescript-eslint/types@6.18.0:
resolution: {integrity: sha512-/RFVIccwkwSdW/1zeMx3hADShWbgBxBnV/qSrex6607isYjj05t36P6LyONgqdUrNLl5TYU8NIKdHUYpFvExkA==}
engines: {node: ^16.0.0 || >=18.0.0}
dev: false
/@typescript-eslint/typescript-estree@6.17.0(typescript@5.3.3):
resolution: {integrity: sha512-gVQe+SLdNPfjlJn5VNGhlOhrXz4cajwFd5kAgWtZ9dCZf4XJf8xmgCTLIqec7aha3JwgLI2CK6GY1043FRxZwg==}
/@typescript-eslint/typescript-estree@6.18.0(typescript@5.3.3):
resolution: {integrity: sha512-klNvl+Ql4NsBNGB4W9TZ2Od03lm7aGvTbs0wYaFYsplVPhr+oeXjlPZCDI4U9jgJIDK38W1FKhacCFzCC+nbIg==}
engines: {node: ^16.0.0 || >=18.0.0}
peerDependencies:
typescript: '*'
@ -2418,8 +2418,8 @@ packages:
typescript:
optional: true
dependencies:
'@typescript-eslint/types': 6.17.0
'@typescript-eslint/visitor-keys': 6.17.0
'@typescript-eslint/types': 6.18.0
'@typescript-eslint/visitor-keys': 6.18.0
debug: 4.3.4
globby: 11.1.0
is-glob: 4.0.3
@ -2431,8 +2431,8 @@ packages:
- supports-color
dev: false
/@typescript-eslint/utils@6.17.0(eslint@8.56.0)(typescript@5.3.3):
resolution: {integrity: sha512-LofsSPjN/ITNkzV47hxas2JCsNCEnGhVvocfyOcLzT9c/tSZE7SfhS/iWtzP1lKNOEfLhRTZz6xqI8N2RzweSQ==}
/@typescript-eslint/utils@6.18.0(eslint@8.56.0)(typescript@5.3.3):
resolution: {integrity: sha512-wiKKCbUeDPGaYEYQh1S580dGxJ/V9HI7K5sbGAVklyf+o5g3O+adnS4UNJajplF4e7z2q0uVBaTdT/yLb4XAVA==}
engines: {node: ^16.0.0 || >=18.0.0}
peerDependencies:
eslint: ^7.0.0 || ^8.0.0
@ -2440,9 +2440,9 @@ packages:
'@eslint-community/eslint-utils': 4.4.0(eslint@8.56.0)
'@types/json-schema': 7.0.15
'@types/semver': 7.5.6
'@typescript-eslint/scope-manager': 6.17.0
'@typescript-eslint/types': 6.17.0
'@typescript-eslint/typescript-estree': 6.17.0(typescript@5.3.3)
'@typescript-eslint/scope-manager': 6.18.0
'@typescript-eslint/types': 6.18.0
'@typescript-eslint/typescript-estree': 6.18.0(typescript@5.3.3)
eslint: 8.56.0
semver: 7.5.4
transitivePeerDependencies:
@ -2450,11 +2450,11 @@ packages:
- typescript
dev: false
/@typescript-eslint/visitor-keys@6.17.0:
resolution: {integrity: sha512-H6VwB/k3IuIeQOyYczyyKN8wH6ed8EwliaYHLxOIhyF0dYEIsN8+Bk3GE19qafeMKyZJJHP8+O1HiFhFLUNKSg==}
/@typescript-eslint/visitor-keys@6.18.0:
resolution: {integrity: sha512-1wetAlSZpewRDb2h9p/Q8kRjdGuqdTAQbkJIOUMLug2LBLG+QOjiWoSj6/3B/hA9/tVTFFdtiKvAYoYnSRW/RA==}
engines: {node: ^16.0.0 || >=18.0.0}
dependencies:
'@typescript-eslint/types': 6.17.0
'@typescript-eslint/types': 6.18.0
eslint-visitor-keys: 3.4.3
dev: false
@ -3476,11 +3476,11 @@ packages:
dependencies:
'@next/eslint-plugin-next': 14.0.4
'@rushstack/eslint-patch': 1.6.1
'@typescript-eslint/parser': 6.17.0(eslint@8.56.0)(typescript@5.3.3)
'@typescript-eslint/parser': 6.18.0(eslint@8.56.0)(typescript@5.3.3)
eslint: 8.56.0
eslint-import-resolver-node: 0.3.9
eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.17.0)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.56.0)
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.17.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0)
eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.18.0)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.56.0)
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.18.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0)
eslint-plugin-jsx-a11y: 6.8.0(eslint@8.56.0)
eslint-plugin-react: 7.33.2(eslint@8.56.0)
eslint-plugin-react-hooks: 4.6.0(eslint@8.56.0)
@ -3500,7 +3500,7 @@ packages:
- supports-color
dev: false
/eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.17.0)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.56.0):
/eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.18.0)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.56.0):
resolution: {integrity: sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg==}
engines: {node: ^14.18.0 || >=16.0.0}
peerDependencies:
@ -3510,8 +3510,8 @@ packages:
debug: 4.3.4
enhanced-resolve: 5.15.0
eslint: 8.56.0
eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.17.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0)
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.17.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0)
eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.18.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0)
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.18.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0)
fast-glob: 3.3.2
get-tsconfig: 4.7.2
is-core-module: 2.13.1
@ -3523,7 +3523,7 @@ packages:
- supports-color
dev: false
/eslint-module-utils@2.8.0(@typescript-eslint/parser@6.17.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0):
/eslint-module-utils@2.8.0(@typescript-eslint/parser@6.18.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0):
resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==}
engines: {node: '>=4'}
peerDependencies:
@ -3544,16 +3544,16 @@ packages:
eslint-import-resolver-webpack:
optional: true
dependencies:
'@typescript-eslint/parser': 6.17.0(eslint@8.56.0)(typescript@5.3.3)
'@typescript-eslint/parser': 6.18.0(eslint@8.56.0)(typescript@5.3.3)
debug: 3.2.7
eslint: 8.56.0
eslint-import-resolver-node: 0.3.9
eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.17.0)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.56.0)
eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.18.0)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.56.0)
transitivePeerDependencies:
- supports-color
dev: false
/eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.17.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0):
/eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.18.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0):
resolution: {integrity: sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==}
engines: {node: '>=4'}
peerDependencies:
@ -3563,7 +3563,7 @@ packages:
'@typescript-eslint/parser':
optional: true
dependencies:
'@typescript-eslint/parser': 6.17.0(eslint@8.56.0)(typescript@5.3.3)
'@typescript-eslint/parser': 6.18.0(eslint@8.56.0)(typescript@5.3.3)
array-includes: 3.1.7
array.prototype.findlastindex: 1.2.3
array.prototype.flat: 1.3.2
@ -3572,7 +3572,7 @@ packages:
doctrine: 2.1.0
eslint: 8.56.0
eslint-import-resolver-node: 0.3.9
eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.17.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0)
eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.18.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.56.0)
hasown: 2.0.0
is-core-module: 2.13.1
is-glob: 4.0.3
@ -6305,8 +6305,8 @@ packages:
resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
dev: false
/tailwindcss@3.4.0:
resolution: {integrity: sha512-VigzymniH77knD1dryXbyxR+ePHihHociZbXnLZHUyzf2MMs2ZVqlUrZ3FvpXP8pno9JzmILt1sZPD19M3IxtA==}
/tailwindcss@3.4.1:
resolution: {integrity: sha512-qAYmXRfk3ENzuPBakNK0SRrUDipP8NQnEY6772uDhflcQz5EhRdD7JNZxyrFHVQNCwULPBn6FNPp9brpO7ctcA==}
engines: {node: '>=14.0.0'}
hasBin: true
dependencies:

View File

@ -1,18 +0,0 @@
import FooterAuth from '@/site/FooterAuth';
import PageContentContainer from '@/components/PageContentContainer';
import { SessionProvider } from 'next-auth/react';
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<SessionProvider>
<PageContentContainer>
{children}
</PageContentContainer>
<FooterAuth />
</SessionProvider>
);
}

View File

@ -1,17 +0,0 @@
import FooterStatic from '@/site/FooterStatic';
import PageContentContainer from '@/components/PageContentContainer';
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<>
<PageContentContainer>
{children}
</PageContentContainer>
<FooterStatic />
</>
);
}

View File

@ -9,6 +9,10 @@ import ThemeProviderClient from '@/site/ThemeProviderClient';
import Nav from '@/site/Nav';
import ToasterWithThemes from '@/toast/ToasterWithThemes';
import PhotoEscapeHandler from '@/photo/PhotoEscapeHandler';
import Footer from '@/site/Footer';
import { Suspense } from 'react';
import FooterClient from '@/site/FooterClient';
import NavClient from '@/site/NavClient';
import '../site/globals.css';
@ -68,21 +72,31 @@ export default function RootLayout({
suppressHydrationWarning
>
<body className={ibmPlexMono.variable}>
<StateProvider>
<ThemeProviderClient>
<main className={clsx(
'px-3 pb-3',
'lg:px-6 lg:pb-6',
'mx-3 mb-3',
'lg:mx-6 lg:mb-6',
)}>
<Suspense fallback={<NavClient />}>
<Nav />
<StateProvider>
</Suspense>
<div className={clsx(
'min-h-[16rem] sm:min-h-[30rem]',
'mb-12',
)}>
{children}
</div>
<Suspense fallback={<FooterClient />}>
<Footer />
</Suspense>
</main>
</ThemeProviderClient>
</StateProvider>
<Analytics />
<SpeedInsights />
</main>
<PhotoEscapeHandler />
<ToasterWithThemes />
</ThemeProviderClient>
</body>
</html>
);

View File

@ -9,7 +9,7 @@ export const signInAction = async (
try {
await signIn('credentials', Object.fromEntries(formData));
} catch (error) {
if ((error as Error).message.includes(CREDENTIALS_SIGN_IN_ERROR)) {
if ((`${error}`).includes(CREDENTIALS_SIGN_IN_ERROR)) {
return CREDENTIALS_SIGN_IN_ERROR;
}
throw error;

4
src/cache/index.ts vendored
View File

@ -28,6 +28,8 @@ import { getBlobPhotoUrls, getBlobUploadUrls } from '@/services/blob';
import type { Session } from 'next-auth';
import { createCameraKey } from '@/camera';
import { PATHS_ADMIN } from '@/site/paths';
import { cache } from 'react';
import { auth } from '@/auth';
// Table key
const KEY_PHOTOS = 'photos';
@ -207,6 +209,8 @@ export const getUniqueFilmSimulationsCached =
[KEY_PHOTOS, KEY_FILM_SIMULATIONS],
);
export const authCached = cache(auth);
// No Store
export const getPhotoNoStore = (...args: Parameters<typeof getPhoto>) => {

View File

@ -1,11 +0,0 @@
export default function PageContentContainer({
children,
}: {
children: React.ReactNode
}) {
return (
<div className="min-h-[16rem] sm:min-h-[30rem]">
{children}
</div>
);
}

View File

@ -12,12 +12,15 @@ export default function RepoLink() {
href="http://github.com/sambecker/exif-photo-blog"
target="_blank"
className={clsx(
'flex items-center gap-1',
'text-black dark:text-white',
'flex items-center gap-0.5',
'text-main hover:text-main',
'hover:underline',
)}
>
<BiLogoGithub className="translate-y-[1px] hidden xs:inline-block" />
<BiLogoGithub
size={16}
className="translate-y-[0.5px] hidden xs:inline-block"
/>
exif-photo-blog
</Link>
</span>

9
src/site/Footer.tsx Normal file
View File

@ -0,0 +1,9 @@
import { authCached } from '@/cache';
import FooterClient from './FooterClient';
export default async function Footer() {
const session = await authCached();
return (
<FooterClient userEmail={session?.user?.email} />
);
}

View File

@ -1,60 +0,0 @@
'use client';
import { clsx } from 'clsx/lite';
import Link from 'next/link';
import { useSession } from 'next-auth/react';
import ThemeSwitcher from '@/site/ThemeSwitcher';
import SiteGrid from '../components/SiteGrid';
import { usePathname } from 'next/navigation';
import { isPathSignIn } from '@/site/paths';
import { signOutAction } from '@/auth/action';
import SubmitButtonWithStatus from '@/components/SubmitButtonWithStatus';
const LINK_STYLE = clsx(
'cursor-pointer',
'hover:text-gray-300',
'hover:dark:text-gray-600',
);
export default function FooterAuth() {
const { data: session, status } = useSession();
const path = usePathname();
return (
<SiteGrid
contentMain={<div className={clsx(
'flex items-center',
'my-8',
'text-dim',
)}>
<div className="flex gap-x-4 gap-y-1 flex-wrap items-center flex-grow">
{status === 'loading'
? <>Loading ...</>
: <>
{session?.user?.email && <div>
{session.user.email}
</div>}
{status === 'authenticated' &&
<form action={signOutAction}>
<SubmitButtonWithStatus
className={LINK_STYLE}
styleAsLink
>
Sign Out
</SubmitButtonWithStatus>
</form>}
{status === 'unauthenticated' &&
<Link
href="/sign-in"
className={LINK_STYLE}
>
Sign In
</Link>}
</>}
</div>
{!isPathSignIn(path) && <ThemeSwitcher />}
</div>}
/>
);
};

70
src/site/FooterClient.tsx Normal file
View File

@ -0,0 +1,70 @@
'use client';
import { clsx } from 'clsx/lite';
import SiteGrid from '../components/SiteGrid';
import ThemeSwitcher from '@/site/ThemeSwitcher';
import Link from 'next/link';
import { SHOW_REPO_LINK } from '@/site/config';
import RepoLink from '../components/RepoLink';
import { usePathname } from 'next/navigation';
import { isPathAdmin, isPathSignIn, pathForAdminPhotos } from './paths';
import SubmitButtonWithStatus from '@/components/SubmitButtonWithStatus';
import { signOutAction } from '@/auth/action';
import Spinner from '@/components/Spinner';
import AnimateItems from '@/components/AnimateItems';
export default function FooterClient({
userEmail,
}: {
userEmail?: string | null | undefined
}) {
const pathname = usePathname();
const showFooter = !isPathSignIn(pathname);
const shouldAnimate = !isPathAdmin(pathname);
return (
<SiteGrid
contentMain={
<AnimateItems
type={!shouldAnimate ? 'none' : 'bottom'}
distanceOffset={10}
items={showFooter
? [<div
key="footer"
className={clsx(
'flex items-center',
'text-dim min-h-[4rem]',
)}>
<div className="flex gap-x-4 gap-y-1 flex-grow flex-wrap h-4">
{isPathAdmin(pathname)
? <>
{userEmail === undefined &&
<Spinner />}
{userEmail && <>
<div>{userEmail}</div>
<form action={signOutAction}>
<SubmitButtonWithStatus styleAsLink>
Sign out
</SubmitButtonWithStatus>
</form>
</>}
</>
: <>
<Link href={pathForAdminPhotos()}>
Admin
</Link>
{SHOW_REPO_LINK &&
<RepoLink />}
</>}
</div>
<div className="flex items-center h-4">
<ThemeSwitcher />
</div>
</div>]
: []}
/>}
/>
);
}

View File

@ -1,47 +0,0 @@
'use client';
import { clsx } from 'clsx/lite';
import SiteGrid from '../components/SiteGrid';
import ThemeSwitcher from '@/site/ThemeSwitcher';
import { signOut } from 'next-auth/react';
import Link from 'next/link';
import { SHOW_REPO_LINK } from '@/site/config';
import RepoLink from '../components/RepoLink';
export default function FooterStatic({
showSignOut,
}: {
showSignOut?: boolean
}) {
return (
<SiteGrid
contentMain={<div className={clsx(
'my-8',
'flex items-center',
'text-dim',
)}>
<div className="flex gap-x-4 gap-y-1 flex-grow flex-wrap">
<Link
href="/admin/photos"
className="hover:text-gray-600 dark:hover:text-gray-400"
>
Admin
</Link>
{SHOW_REPO_LINK &&
<RepoLink />}
{showSignOut &&
<div
className={clsx(
'cursor-pointer',
'hover:text-gray-600 dark:hover:text-gray-400',
)}
onClick={() => signOut()}
>
Sign out
</div>}
</div>
<ThemeSwitcher />
</div>}
/>
);
}

View File

@ -1,82 +1,9 @@
'use client';
import { clsx } from 'clsx/lite';
import { usePathname } from 'next/navigation';
import Link from 'next/link';
import SiteGrid from '../components/SiteGrid';
import { SITE_DOMAIN_OR_TITLE } from '@/site/config';
import ViewSwitcher, { SwitcherSelection } from '@/site/ViewSwitcher';
import {
PATH_ADMIN,
PATH_ROOT,
isPathAdmin,
isPathGrid,
isPathProtected,
isPathSets,
isPathSignIn,
} from '@/site/paths';
import AnimateItems from '../components/AnimateItems';
export default function Nav({ showTextLinks }: { showTextLinks?: boolean }) {
const isLoggedIn = false;
const pathname = usePathname();
const showNav = !isPathSignIn(pathname);
const shouldAnimate = !isPathAdmin(pathname);
const renderLink = (
text: string,
linkOrAction: string | (() => void),
) =>
typeof linkOrAction === 'string'
? <Link href={linkOrAction}>{text}</Link>
: <button onClick={linkOrAction}>{text}</button>;
const switcherSelectionForPath = (): SwitcherSelection | undefined => {
if (pathname === PATH_ROOT) {
return 'full-frame';
} else if (isPathGrid(pathname)) {
return 'grid';
} else if (isPathSets(pathname)) {
return 'sets';
} else if (isPathProtected(pathname)) {
return 'admin';
}
};
import { authCached } from '@/cache';
import NavClient from './NavClient';
export default async function Nav() {
const session = await authCached();
return (
<SiteGrid
contentMain={
<AnimateItems
type={!shouldAnimate ? 'none' : 'bottom'}
distanceOffset={10}
items={showNav
? [<div
key="nav"
className={clsx(
'flex items-center',
'w-full min-h-[4rem]',
'leading-none',
)}>
<div className="flex flex-grow items-center gap-4">
<ViewSwitcher
currentSelection={switcherSelectionForPath()}
showAdmin={isLoggedIn}
/>
{showTextLinks && <>
{renderLink('Home', PATH_ROOT)}
{renderLink('Admin', PATH_ADMIN)}
</>}
</div>
<div className="hidden xs:block">
{renderLink(SITE_DOMAIN_OR_TITLE, PATH_ROOT)}
</div>
</div>]
: []}
/>
}
/>
<NavClient showAdmin={Boolean(session?.user?.email)} />
);
};
}

79
src/site/NavClient.tsx Normal file
View File

@ -0,0 +1,79 @@
'use client';
import { clsx } from 'clsx/lite';
import { usePathname } from 'next/navigation';
import Link from 'next/link';
import SiteGrid from '../components/SiteGrid';
import { SITE_DOMAIN_OR_TITLE } from '@/site/config';
import ViewSwitcher, { SwitcherSelection } from '@/site/ViewSwitcher';
import {
PATH_ROOT,
isPathAdmin,
isPathGrid,
isPathProtected,
isPathSets,
isPathSignIn,
} from '@/site/paths';
import AnimateItems from '../components/AnimateItems';
export default function NavClient({
showAdmin,
}: {
showAdmin?: boolean,
}) {
const pathname = usePathname();
const showNav = !isPathSignIn(pathname);
const shouldAnimate = !isPathAdmin(pathname);
const renderLink = (
text: string,
linkOrAction: string | (() => void),
) =>
typeof linkOrAction === 'string'
? <Link href={linkOrAction}>{text}</Link>
: <button onClick={linkOrAction}>{text}</button>;
const switcherSelectionForPath = (): SwitcherSelection | undefined => {
if (pathname === PATH_ROOT) {
return 'full-frame';
} else if (isPathGrid(pathname)) {
return 'grid';
} else if (isPathSets(pathname)) {
return 'sets';
} else if (isPathProtected(pathname)) {
return 'admin';
}
};
return (
<SiteGrid
contentMain={
<AnimateItems
type={!shouldAnimate ? 'none' : 'bottom'}
distanceOffset={10}
items={showNav
? [<div
key="nav"
className={clsx(
'flex items-center',
'w-full min-h-[4rem]',
'leading-none',
)}>
<div className="flex flex-grow items-center gap-4">
<ViewSwitcher
currentSelection={switcherSelectionForPath()}
showAdmin={showAdmin}
/>
</div>
<div className="hidden xs:block">
{renderLink(SITE_DOMAIN_OR_TITLE, PATH_ROOT)}
</div>
</div>]
: []}
/>
}
/>
);
};

View File

@ -2,7 +2,7 @@ import Switcher from '@/components/Switcher';
import SwitcherItem from '@/components/SwitcherItem';
import IconFullFrame from '@/site/IconFullFrame';
import IconGrid from '@/site/IconGrid';
import { PATH_GRID, PATH_SETS } from '@/site/paths';
import { PATH_ADMIN_PHOTOS, PATH_GRID, PATH_SETS } from '@/site/paths';
import { BiLockAlt } from 'react-icons/bi';
import IconSets from './IconSets';
@ -38,8 +38,8 @@ export default function ViewSwitcher({
/>
{showAdmin &&
<SwitcherItem
icon={<BiLockAlt size={15} className="-translate-y-[1px]" />}
href="/admin/photos"
icon={<BiLockAlt size={16} className="translate-y-[-0.5px]" />}
href={PATH_ADMIN_PHOTOS}
active={currentSelection === 'admin'}
/>}
</Switcher>

View File

@ -107,6 +107,11 @@
p-0 min-h-0
border-none active:bg-transparent shadow-none
}
a, .link {
@apply
hover:text-gray-600
hover:dark:text-gray-400
}
/* Common Utilities */
.text-main {
@apply