From 0e64caa61a48f6735b82fac4cb57dc642b900436 Mon Sep 17 00:00:00 2001 From: Colby Fayock Date: Fri, 5 May 2023 14:58:23 -0400 Subject: [PATCH 01/11] init app --- jsconfig.json | 1 + next.config.js | 4 + package.json | 5 +- pnpm-lock.yaml | 60 ++++- src/app/[...uriNodes]/page.js | 47 ++++ src/app/favicon.ico | Bin 0 -> 25931 bytes src/app/globals.css | 107 ++++++++ src/app/layout.js | 14 ++ src/app/page.js | 102 ++++++++ src/app/page.module.css | 229 ++++++++++++++++++ .../Container/Container.module.scss | 2 +- src/components/Footer/Footer.js | 2 +- src/components/Layout/Layout.js | 2 +- src/components/Nav/Nav.js | 2 +- src/hooks/use-page-metadata.js | 2 +- src/lib/apollo-client.js | 2 +- src/lib/nodes.js | 97 ++++++++ src/{pages => pages.original}/404.js | 0 src/{pages => pages.original}/500.js | 0 .../[slugParent]/[[...slugChild]].js | 2 +- src/{pages => pages.original}/_app.js | 2 +- src/{pages => pages.original}/_document.js | 0 .../authors/[slug].js | 0 src/{pages => pages.original}/categories.js | 2 +- .../categories/[slug].js | 0 src/{pages => pages.original}/index.js | 2 +- src/{pages => pages.original}/posts.js | 0 src/{pages => pages.original}/posts/[slug].js | 2 +- .../posts/page/[page].js | 0 src/{pages => pages.original}/search.js | 0 src/templates/archive.js | 148 +++++------ src/templates/page.js | 192 +++++++++++++++ 32 files changed, 932 insertions(+), 96 deletions(-) create mode 100644 src/app/[...uriNodes]/page.js create mode 100644 src/app/favicon.ico create mode 100644 src/app/globals.css create mode 100644 src/app/layout.js create mode 100644 src/app/page.js create mode 100644 src/app/page.module.css create mode 100644 src/lib/nodes.js rename src/{pages => pages.original}/404.js (100%) rename src/{pages => pages.original}/500.js (100%) rename src/{pages => pages.original}/[slugParent]/[[...slugChild]].js (99%) rename src/{pages => pages.original}/_app.js (95%) rename src/{pages => pages.original}/_document.js (100%) rename src/{pages => pages.original}/authors/[slug].js (100%) rename src/{pages => pages.original}/categories.js (97%) rename src/{pages => pages.original}/categories/[slug].js (100%) rename src/{pages => pages.original}/index.js (97%) rename src/{pages => pages.original}/posts.js (100%) rename src/{pages => pages.original}/posts/[slug].js (99%) rename src/{pages => pages.original}/posts/page/[page].js (100%) rename src/{pages => pages.original}/search.js (100%) create mode 100644 src/templates/page.js diff --git a/jsconfig.json b/jsconfig.json index e1d04480..32daa2c7 100644 --- a/jsconfig.json +++ b/jsconfig.json @@ -2,6 +2,7 @@ "compilerOptions": { "baseUrl": "./src", "paths": { + "@/*": ["./*"], "public/*": ["../public/*"] } } diff --git a/next.config.js b/next.config.js index bfa4447c..183575bd 100644 --- a/next.config.js +++ b/next.config.js @@ -5,6 +5,10 @@ const sitemap = require('./plugins/sitemap'); /** @type {import('next').NextConfig} */ const nextConfig = { + experimental: { + appDir: true, + }, + reactStrictMode: true, swcMinify: true, diff --git a/package.json b/package.json index a743b723..66803438 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,8 @@ "style.css": "^1.0.3" }, "devDependencies": { + "@types/node": "20.0.0", + "@types/react": "18.2.5", "eslint": "8.39.0", "eslint-config-next": "^13.4.0", "eslint-config-prettier": "^8.8.0", @@ -48,7 +50,8 @@ "husky": "^8.0.3", "lint-staged": "^13.2.2", "playwright": "^1.33.0", - "prettier": "2.8.8" + "prettier": "2.8.8", + "typescript": "5.0.4" }, "repository": { "type": "git", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5800b2e7..05f1ea86 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2,6 +2,8 @@ lockfileVersion: 5.4 specifiers: '@apollo/client': ^3.7.14 + '@types/node': 20.0.0 + '@types/react': 18.2.5 date-fns: ^2.30.0 dotenv: ^16.0.3 eslint: 8.39.0 @@ -28,6 +30,7 @@ specifiers: rss: ^1.2.2 sass: ^1.62.1 style.css: ^1.0.3 + typescript: 5.0.4 dependencies: '@apollo/client': 3.7.14_gdcq4dv6opitr3wbfwyjmanyra @@ -50,8 +53,10 @@ dependencies: style.css: 1.0.3 devDependencies: + '@types/node': 20.0.0 + '@types/react': 18.2.5 eslint: 8.39.0 - eslint-config-next: 13.4.0_eslint@8.39.0 + eslint-config-next: 13.4.0_iacogk7kkaymxepzhgcbytyi7q eslint-config-prettier: 8.8.0_eslint@8.39.0 eslint-plugin-prettier: 4.2.1_5pokp25ua6t5ubushhw3tqituq eslint-plugin-react: 7.32.2_eslint@8.39.0 @@ -59,6 +64,7 @@ devDependencies: lint-staged: 13.2.2 playwright: 1.33.0 prettier: 2.8.8 + typescript: 5.0.4 packages: @@ -307,11 +313,31 @@ packages: resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} dev: true + /@types/node/20.0.0: + resolution: {integrity: sha512-cD2uPTDnQQCVpmRefonO98/PPijuOnnEy5oytWJFPY1N9aJCz2wJ5kSGWO+zJoed2cY2JxQh6yBuUq4vIn61hw==} + dev: true + /@types/nprogress/0.2.0: resolution: {integrity: sha512-1cYJrqq9GezNFPsWTZpFut/d4CjpZqA0vhqDUPFWYKF1oIyBz5qnoYMzR+0C/T96t3ebLAC1SSnwrVOm5/j74A==} dev: false - /@typescript-eslint/parser/5.59.2_eslint@8.39.0: + /@types/prop-types/15.7.5: + resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==} + dev: true + + /@types/react/18.2.5: + resolution: {integrity: sha512-RuoMedzJ5AOh23Dvws13LU9jpZHIc/k90AgmK7CecAYeWmSr3553L4u5rk4sWAPBuQosfT7HmTfG4Rg5o4nGEA==} + dependencies: + '@types/prop-types': 15.7.5 + '@types/scheduler': 0.16.3 + csstype: 3.1.2 + dev: true + + /@types/scheduler/0.16.3: + resolution: {integrity: sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==} + dev: true + + /@typescript-eslint/parser/5.59.2_iacogk7kkaymxepzhgcbytyi7q: resolution: {integrity: sha512-uq0sKyw6ao1iFOZZGk9F8Nro/8+gfB5ezl1cA06SrqbgJAt0SRoFhb9pXaHvkrxUpZaoLxt8KlovHNk8Gp6/HQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -323,9 +349,10 @@ packages: dependencies: '@typescript-eslint/scope-manager': 5.59.2 '@typescript-eslint/types': 5.59.2 - '@typescript-eslint/typescript-estree': 5.59.2 + '@typescript-eslint/typescript-estree': 5.59.2_typescript@5.0.4 debug: 4.3.4 eslint: 8.39.0 + typescript: 5.0.4 transitivePeerDependencies: - supports-color dev: true @@ -343,7 +370,7 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /@typescript-eslint/typescript-estree/5.59.2: + /@typescript-eslint/typescript-estree/5.59.2_typescript@5.0.4: resolution: {integrity: sha512-+j4SmbwVmZsQ9jEyBMgpuBD0rKwi9RxRpjX71Brr73RsYnEr3Lt5QZ624Bxphp8HUkSKfqGnPJp1kA5nl0Sh7Q==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: @@ -358,7 +385,8 @@ packages: globby: 11.1.0 is-glob: 4.0.3 semver: 7.5.0 - tsutils: 3.21.0 + tsutils: 3.21.0_typescript@5.0.4 + typescript: 5.0.4 transitivePeerDependencies: - supports-color dev: true @@ -705,6 +733,10 @@ packages: which: 2.0.2 dev: true + /csstype/3.1.2: + resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==} + dev: true + /damerau-levenshtein/1.0.8: resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} dev: true @@ -926,7 +958,7 @@ packages: engines: {node: '>=10'} dev: true - /eslint-config-next/13.4.0_eslint@8.39.0: + /eslint-config-next/13.4.0_iacogk7kkaymxepzhgcbytyi7q: resolution: {integrity: sha512-FkO3QRyUEKAHM4ie0xAcxo7fQ8gWevuLqgf6/g1Y6zWybqSa4FNeJr4hqqTbP25xIRgUUIPILBlx9RSH4C6+gQ==} peerDependencies: eslint: ^7.23.0 || ^8.0.0 @@ -937,7 +969,7 @@ packages: dependencies: '@next/eslint-plugin-next': 13.4.0 '@rushstack/eslint-patch': 1.2.0 - '@typescript-eslint/parser': 5.59.2_eslint@8.39.0 + '@typescript-eslint/parser': 5.59.2_iacogk7kkaymxepzhgcbytyi7q eslint: 8.39.0 eslint-import-resolver-node: 0.3.7 eslint-import-resolver-typescript: 3.5.5_dcxjpn7zkhfkza34okghut2zbm @@ -945,6 +977,7 @@ packages: eslint-plugin-jsx-a11y: 6.7.1_eslint@8.39.0 eslint-plugin-react: 7.32.2_eslint@8.39.0 eslint-plugin-react-hooks: 4.6.0_eslint@8.39.0 + typescript: 5.0.4 transitivePeerDependencies: - eslint-import-resolver-webpack - supports-color @@ -1014,7 +1047,7 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 5.59.2_eslint@8.39.0 + '@typescript-eslint/parser': 5.59.2_iacogk7kkaymxepzhgcbytyi7q debug: 3.2.7 eslint: 8.39.0 eslint-import-resolver-node: 0.3.7 @@ -1033,7 +1066,7 @@ packages: '@typescript-eslint/parser': optional: true dependencies: - '@typescript-eslint/parser': 5.59.2_eslint@8.39.0 + '@typescript-eslint/parser': 5.59.2_iacogk7kkaymxepzhgcbytyi7q array-includes: 3.1.6 array.prototype.flat: 1.3.1 array.prototype.flatmap: 1.3.1 @@ -2809,13 +2842,14 @@ packages: /tslib/2.5.0: resolution: {integrity: sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==} - /tsutils/3.21.0: + /tsutils/3.21.0_typescript@5.0.4: resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} engines: {node: '>= 6'} peerDependencies: typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' dependencies: tslib: 1.14.1 + typescript: 5.0.4 dev: true /type-check/0.4.0: @@ -2843,6 +2877,12 @@ packages: is-typed-array: 1.1.10 dev: true + /typescript/5.0.4: + resolution: {integrity: sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==} + engines: {node: '>=12.20'} + hasBin: true + dev: true + /unbox-primitive/1.0.2: resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} dependencies: diff --git a/src/app/[...uriNodes]/page.js b/src/app/[...uriNodes]/page.js new file mode 100644 index 00000000..ffe07293 --- /dev/null +++ b/src/app/[...uriNodes]/page.js @@ -0,0 +1,47 @@ +import { getNodeByUri, getTemplateDataByNode } from '@/lib/nodes'; + +import { default as TemplatePage } from '@/templates/page'; + +const templates = { + Page: TemplatePage, +}; + +export default async function Page({ params = {} }) { + const { uriNodes } = params; + + let resolvedUri = null; + + if ( uriNodes) { + resolvedUri = uriNodes.join('/'); + } + + const node = await getNodeByUri(resolvedUri) + + const Component = templates[node.__typename] || templates.Page; + const { template } = Component; + + const nodeData = await getTemplateDataByNode({ + template, + node + }); + + const data = typeof template.transformer === 'function' ? template.transformer(nodeData?.data) : nodeData?.data; + + return ; +} + + // if (!node || node.isRestricted) { + // return { + // notFound: true, + // }; + // } + + // const breadcrumbs = Array.isArray(data.ancestors) ? [...data.ancestors] : []; + // breadcrumbs.reverse(); + + // return { + // props: { + // data, + // breadcrumbs, + // }, + // }; \ No newline at end of file diff --git a/src/app/favicon.ico b/src/app/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..718d6fea4835ec2d246af9800eddb7ffb276240c GIT binary patch literal 25931 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 LrJugUA?W`A8`#=m literal 0 HcmV?d00001 diff --git a/src/app/globals.css b/src/app/globals.css new file mode 100644 index 00000000..d4f491e1 --- /dev/null +++ b/src/app/globals.css @@ -0,0 +1,107 @@ +:root { + --max-width: 1100px; + --border-radius: 12px; + --font-mono: ui-monospace, Menlo, Monaco, 'Cascadia Mono', 'Segoe UI Mono', + 'Roboto Mono', 'Oxygen Mono', 'Ubuntu Monospace', 'Source Code Pro', + 'Fira Mono', 'Droid Sans Mono', 'Courier New', monospace; + + --foreground-rgb: 0, 0, 0; + --background-start-rgb: 214, 219, 220; + --background-end-rgb: 255, 255, 255; + + --primary-glow: conic-gradient( + from 180deg at 50% 50%, + #16abff33 0deg, + #0885ff33 55deg, + #54d6ff33 120deg, + #0071ff33 160deg, + transparent 360deg + ); + --secondary-glow: radial-gradient( + rgba(255, 255, 255, 1), + rgba(255, 255, 255, 0) + ); + + --tile-start-rgb: 239, 245, 249; + --tile-end-rgb: 228, 232, 233; + --tile-border: conic-gradient( + #00000080, + #00000040, + #00000030, + #00000020, + #00000010, + #00000010, + #00000080 + ); + + --callout-rgb: 238, 240, 241; + --callout-border-rgb: 172, 175, 176; + --card-rgb: 180, 185, 188; + --card-border-rgb: 131, 134, 135; +} + +@media (prefers-color-scheme: dark) { + :root { + --foreground-rgb: 255, 255, 255; + --background-start-rgb: 0, 0, 0; + --background-end-rgb: 0, 0, 0; + + --primary-glow: radial-gradient(rgba(1, 65, 255, 0.4), rgba(1, 65, 255, 0)); + --secondary-glow: linear-gradient( + to bottom right, + rgba(1, 65, 255, 0), + rgba(1, 65, 255, 0), + rgba(1, 65, 255, 0.3) + ); + + --tile-start-rgb: 2, 13, 46; + --tile-end-rgb: 2, 5, 19; + --tile-border: conic-gradient( + #ffffff80, + #ffffff40, + #ffffff30, + #ffffff20, + #ffffff10, + #ffffff10, + #ffffff80 + ); + + --callout-rgb: 20, 20, 20; + --callout-border-rgb: 108, 108, 108; + --card-rgb: 100, 100, 100; + --card-border-rgb: 200, 200, 200; + } +} + +* { + box-sizing: border-box; + padding: 0; + margin: 0; +} + +html, +body { + max-width: 100vw; + overflow-x: hidden; +} + +body { + color: rgb(var(--foreground-rgb)); + background: linear-gradient( + to bottom, + transparent, + rgb(var(--background-end-rgb)) + ) + rgb(var(--background-start-rgb)); +} + +a { + color: inherit; + text-decoration: none; +} + +@media (prefers-color-scheme: dark) { + html { + color-scheme: dark; + } +} diff --git a/src/app/layout.js b/src/app/layout.js new file mode 100644 index 00000000..3e3a9a26 --- /dev/null +++ b/src/app/layout.js @@ -0,0 +1,14 @@ +import './globals.css' + +export const metadata = { + title: 'Create Next App', + description: 'Generated by create next app', +} + +export default function RootLayout({ children }) { + return ( + + {children} + + ) +} diff --git a/src/app/page.js b/src/app/page.js new file mode 100644 index 00000000..01946f79 --- /dev/null +++ b/src/app/page.js @@ -0,0 +1,102 @@ +import Image from 'next/image' +import { Inter } from 'next/font/google' +import styles from './page.module.css' + +const inter = Inter({ subsets: ['latin'] }) + +export default function Home() { + return ( +
+
+

+ Get started by editing  + app/page.tsx +

+ +
+ +
+ Next.js Logo +
+ + +
+ ) +} diff --git a/src/app/page.module.css b/src/app/page.module.css new file mode 100644 index 00000000..9411a5e6 --- /dev/null +++ b/src/app/page.module.css @@ -0,0 +1,229 @@ +.main { + display: flex; + flex-direction: column; + justify-content: space-between; + align-items: center; + padding: 6rem; + min-height: 100vh; +} + +.description { + display: inherit; + justify-content: inherit; + align-items: inherit; + font-size: 0.85rem; + max-width: var(--max-width); + width: 100%; + z-index: 2; + font-family: var(--font-mono); +} + +.description a { + display: flex; + justify-content: center; + align-items: center; + gap: 0.5rem; +} + +.description p { + position: relative; + margin: 0; + padding: 1rem; + background-color: rgba(var(--callout-rgb), 0.5); + border: 1px solid rgba(var(--callout-border-rgb), 0.3); + border-radius: var(--border-radius); +} + +.code { + font-weight: 700; + font-family: var(--font-mono); +} + +.grid { + display: grid; + grid-template-columns: repeat(4, minmax(25%, auto)); + width: var(--max-width); + max-width: 100%; +} + +.card { + padding: 1rem 1.2rem; + border-radius: var(--border-radius); + background: rgba(var(--card-rgb), 0); + border: 1px solid rgba(var(--card-border-rgb), 0); + transition: background 200ms, border 200ms; +} + +.card span { + display: inline-block; + transition: transform 200ms; +} + +.card h2 { + font-weight: 600; + margin-bottom: 0.7rem; +} + +.card p { + margin: 0; + opacity: 0.6; + font-size: 0.9rem; + line-height: 1.5; + max-width: 30ch; +} + +.center { + display: flex; + justify-content: center; + align-items: center; + position: relative; + padding: 4rem 0; +} + +.center::before { + background: var(--secondary-glow); + border-radius: 50%; + width: 480px; + height: 360px; + margin-left: -400px; +} + +.center::after { + background: var(--primary-glow); + width: 240px; + height: 180px; + z-index: -1; +} + +.center::before, +.center::after { + content: ''; + left: 50%; + position: absolute; + filter: blur(45px); + transform: translateZ(0); +} + +.logo { + position: relative; +} +/* Enable hover only on non-touch devices */ +@media (hover: hover) and (pointer: fine) { + .card:hover { + background: rgba(var(--card-rgb), 0.1); + border: 1px solid rgba(var(--card-border-rgb), 0.15); + } + + .card:hover span { + transform: translateX(4px); + } +} + +@media (prefers-reduced-motion) { + .card:hover span { + transform: none; + } +} + +/* Mobile */ +@media (max-width: 700px) { + .content { + padding: 4rem; + } + + .grid { + grid-template-columns: 1fr; + margin-bottom: 120px; + max-width: 320px; + text-align: center; + } + + .card { + padding: 1rem 2.5rem; + } + + .card h2 { + margin-bottom: 0.5rem; + } + + .center { + padding: 8rem 0 6rem; + } + + .center::before { + transform: none; + height: 300px; + } + + .description { + font-size: 0.8rem; + } + + .description a { + padding: 1rem; + } + + .description p, + .description div { + display: flex; + justify-content: center; + position: fixed; + width: 100%; + } + + .description p { + align-items: center; + inset: 0 0 auto; + padding: 2rem 1rem 1.4rem; + border-radius: 0; + border: none; + border-bottom: 1px solid rgba(var(--callout-border-rgb), 0.25); + background: linear-gradient( + to bottom, + rgba(var(--background-start-rgb), 1), + rgba(var(--callout-rgb), 0.5) + ); + background-clip: padding-box; + backdrop-filter: blur(24px); + } + + .description div { + align-items: flex-end; + pointer-events: none; + inset: auto 0 0; + padding: 2rem; + height: 200px; + background: linear-gradient( + to bottom, + transparent 0%, + rgb(var(--background-end-rgb)) 40% + ); + z-index: 1; + } +} + +/* Tablet and Smaller Desktop */ +@media (min-width: 701px) and (max-width: 1120px) { + .grid { + grid-template-columns: repeat(2, 50%); + } +} + +@media (prefers-color-scheme: dark) { + .vercelLogo { + filter: invert(1); + } + + .logo { + filter: invert(1) drop-shadow(0 0 0.3rem #ffffff70); + } +} + +@keyframes rotate { + from { + transform: rotate(360deg); + } + to { + transform: rotate(0deg); + } +} diff --git a/src/components/Container/Container.module.scss b/src/components/Container/Container.module.scss index fbde7823..f301cdf4 100644 --- a/src/components/Container/Container.module.scss +++ b/src/components/Container/Container.module.scss @@ -1,4 +1,4 @@ -@import "styles/settings/__settings"; +@import "@/styles/settings/__settings"; .container { max-width: 60rem; diff --git a/src/components/Footer/Footer.js b/src/components/Footer/Footer.js index 90204ff3..760716a6 100644 --- a/src/components/Footer/Footer.js +++ b/src/components/Footer/Footer.js @@ -1,6 +1,6 @@ import Link from 'next/link'; -import useSite from 'hooks/use-site'; +import useSite from '@/hooks/use-site'; import { postPathBySlug } from 'lib/posts'; import { categoryPathBySlug } from 'lib/categories'; diff --git a/src/components/Layout/Layout.js b/src/components/Layout/Layout.js index 3a02b613..f9c44468 100644 --- a/src/components/Layout/Layout.js +++ b/src/components/Layout/Layout.js @@ -2,7 +2,7 @@ import { useRouter } from 'next/router'; import { Helmet } from 'react-helmet'; import styles from './Layout.module.scss'; -import useSite from 'hooks/use-site'; +import useSite from '@/hooks/use-site'; import { helmetSettingsFromMetadata } from 'lib/site'; import Nav from 'components/Nav'; diff --git a/src/components/Nav/Nav.js b/src/components/Nav/Nav.js index 0e953b02..8f119e24 100644 --- a/src/components/Nav/Nav.js +++ b/src/components/Nav/Nav.js @@ -2,7 +2,7 @@ import { useEffect, useRef, useState, useCallback } from 'react'; import Link from 'next/link'; import { FaSearch } from 'react-icons/fa'; -import useSite from 'hooks/use-site'; +import useSite from '@/hooks/use-site'; import useSearch, { SEARCH_STATE_LOADED } from 'hooks/use-search'; import { postPathBySlug } from 'lib/posts'; import { findMenuByLocation, MENU_LOCATION_NAVIGATION_DEFAULT } from 'lib/menus'; diff --git a/src/hooks/use-page-metadata.js b/src/hooks/use-page-metadata.js index f9811e9b..dc11dd05 100644 --- a/src/hooks/use-page-metadata.js +++ b/src/hooks/use-page-metadata.js @@ -1,7 +1,7 @@ import { useContext } from 'react'; import { useRouter } from 'next/router'; -import { SiteContext } from 'hooks/use-site'; +import { SiteContext } from '@/hooks/use-site'; import { constructPageMetadata } from 'lib/site'; diff --git a/src/lib/apollo-client.js b/src/lib/apollo-client.js index 3ae424a5..bef82c3c 100644 --- a/src/lib/apollo-client.js +++ b/src/lib/apollo-client.js @@ -1,6 +1,6 @@ import { ApolloClient, HttpLink, InMemoryCache } from '@apollo/client'; -import { removeLastTrailingSlash } from 'lib/util'; +import { removeLastTrailingSlash } from '@/lib/util'; let client; /** diff --git a/src/lib/nodes.js b/src/lib/nodes.js new file mode 100644 index 00000000..4e47da76 --- /dev/null +++ b/src/lib/nodes.js @@ -0,0 +1,97 @@ +import { gql } from '@apollo/client'; + +import { getApolloClient } from '@/lib/apollo-client'; + +/** + * getNodeByUri + */ + +export async function getNodeByUri(uri) { + const apolloClient = await getApolloClient(); + + const data = await apolloClient.query({ + query: gql` + query GetNode($uri: String!) { + nodeByUri(uri: $uri) { + __typename + id + isContentNode + isTermNode + uri + ...Category + ...ContentType + ...Page + ...Post + ...User + } + } + fragment Page on Page { + id + isContentNode + isFrontPage + isPostsPage + isPreview + isPrivacyPage + isRestricted + isRevision + isTermNode + title + } + fragment ContentType on ContentType { + id + isContentNode + isFrontPage + isPostsPage + isRestricted + isTermNode + name + } + fragment Category on Category { + id + isContentNode + isRestricted + isTermNode + name + } + fragment User on User { + id + email + isContentNode + isRestricted + isTermNode + name + } + fragment Post on Post { + id + isContentNode + isPreview + isRestricted + isRevision + isSticky + isTermNode + title + } + `, + variables: { + uri, + }, + possibleTypes: { + Node: ['Category', 'ContentType', 'Page', 'Post', 'User'], + }, + }); + + return data.data.nodeByUri; +} + +/** + * getTemplateDataByNode + */ + +export async function getTemplateDataByNode({ node, template }) { + const apolloClient = await getApolloClient(); + return apolloClient.query({ + query: template.query, + variables: template.variables(node), + }); +} + diff --git a/src/pages/404.js b/src/pages.original/404.js similarity index 100% rename from src/pages/404.js rename to src/pages.original/404.js diff --git a/src/pages/500.js b/src/pages.original/500.js similarity index 100% rename from src/pages/500.js rename to src/pages.original/500.js diff --git a/src/pages/[slugParent]/[[...slugChild]].js b/src/pages.original/[slugParent]/[[...slugChild]].js similarity index 99% rename from src/pages/[slugParent]/[[...slugChild]].js rename to src/pages.original/[slugParent]/[[...slugChild]].js index 2a22cab0..2a6d144c 100644 --- a/src/pages/[slugParent]/[[...slugChild]].js +++ b/src/pages.original/[slugParent]/[[...slugChild]].js @@ -4,7 +4,7 @@ import { Helmet } from 'react-helmet'; import { getPageByUri, getAllPages, getBreadcrumbsByUri } from 'lib/pages'; import { WebpageJsonLd } from 'lib/json-ld'; import { helmetSettingsFromMetadata } from 'lib/site'; -import useSite from 'hooks/use-site'; +import useSite from '@/hooks/use-site'; import usePageMetadata from 'hooks/use-page-metadata'; import Layout from 'components/Layout'; diff --git a/src/pages/_app.js b/src/pages.original/_app.js similarity index 95% rename from src/pages/_app.js rename to src/pages.original/_app.js index a90a30bd..5a6aafd5 100644 --- a/src/pages/_app.js +++ b/src/pages.original/_app.js @@ -1,6 +1,6 @@ import NextApp from 'next/app'; -import { SiteContext, useSiteContext } from 'hooks/use-site'; +import { SiteContext, useSiteContext } from '@/hooks/use-site'; import { SearchProvider } from 'hooks/use-search'; import { getSiteMetadata } from 'lib/site'; diff --git a/src/pages/_document.js b/src/pages.original/_document.js similarity index 100% rename from src/pages/_document.js rename to src/pages.original/_document.js diff --git a/src/pages/authors/[slug].js b/src/pages.original/authors/[slug].js similarity index 100% rename from src/pages/authors/[slug].js rename to src/pages.original/authors/[slug].js diff --git a/src/pages/categories.js b/src/pages.original/categories.js similarity index 97% rename from src/pages/categories.js rename to src/pages.original/categories.js index 1e8eb828..8f46602f 100644 --- a/src/pages/categories.js +++ b/src/pages.original/categories.js @@ -1,7 +1,7 @@ import Link from 'next/link'; import { Helmet } from 'react-helmet'; -import useSite from 'hooks/use-site'; +import useSite from '@/hooks/use-site'; import { getAllCategories, categoryPathBySlug } from 'lib/categories'; import { WebpageJsonLd } from 'lib/json-ld'; diff --git a/src/pages/categories/[slug].js b/src/pages.original/categories/[slug].js similarity index 100% rename from src/pages/categories/[slug].js rename to src/pages.original/categories/[slug].js diff --git a/src/pages/index.js b/src/pages.original/index.js similarity index 97% rename from src/pages/index.js rename to src/pages.original/index.js index 4fdf15ce..9c5e1e6e 100644 --- a/src/pages/index.js +++ b/src/pages.original/index.js @@ -1,4 +1,4 @@ -import useSite from 'hooks/use-site'; +import useSite from '@/hooks/use-site'; import { getPaginatedPosts } from 'lib/posts'; import { WebsiteJsonLd } from 'lib/json-ld'; diff --git a/src/pages/posts.js b/src/pages.original/posts.js similarity index 100% rename from src/pages/posts.js rename to src/pages.original/posts.js diff --git a/src/pages/posts/[slug].js b/src/pages.original/posts/[slug].js similarity index 99% rename from src/pages/posts/[slug].js rename to src/pages.original/posts/[slug].js index e32502bc..58ba6f0d 100644 --- a/src/pages/posts/[slug].js +++ b/src/pages.original/posts/[slug].js @@ -6,7 +6,7 @@ import { categoryPathBySlug } from 'lib/categories'; import { formatDate } from 'lib/datetime'; import { ArticleJsonLd } from 'lib/json-ld'; import { helmetSettingsFromMetadata } from 'lib/site'; -import useSite from 'hooks/use-site'; +import useSite from '@/hooks/use-site'; import usePageMetadata from 'hooks/use-page-metadata'; import Layout from 'components/Layout'; diff --git a/src/pages/posts/page/[page].js b/src/pages.original/posts/page/[page].js similarity index 100% rename from src/pages/posts/page/[page].js rename to src/pages.original/posts/page/[page].js diff --git a/src/pages/search.js b/src/pages.original/search.js similarity index 100% rename from src/pages/search.js rename to src/pages.original/search.js diff --git a/src/templates/archive.js b/src/templates/archive.js index fb6ec8ef..a8f1912e 100644 --- a/src/templates/archive.js +++ b/src/templates/archive.js @@ -1,85 +1,85 @@ -import { Helmet } from 'react-helmet'; +// import { Helmet } from 'react-helmet'; -import { WebpageJsonLd } from 'lib/json-ld'; -import { helmetSettingsFromMetadata } from 'lib/site'; -import useSite from 'hooks/use-site'; +// import { WebpageJsonLd } from 'lib/json-ld'; +// import { helmetSettingsFromMetadata } from 'lib/site'; +// import useSite from '@/hooks/use-site'; -import Layout from 'components/Layout'; -import Header from 'components/Header'; -import Section from 'components/Section'; -import Container from 'components/Container'; -import SectionTitle from 'components/SectionTitle'; -import PostCard from 'components/PostCard'; -import Pagination from 'components/Pagination/Pagination'; +// import Layout from 'components/Layout'; +// import Header from 'components/Header'; +// import Section from 'components/Section'; +// import Container from 'components/Container'; +// import SectionTitle from 'components/SectionTitle'; +// import PostCard from 'components/PostCard'; +// import Pagination from 'components/Pagination/Pagination'; -import styles from 'styles/templates/Archive.module.scss'; +// import styles from 'styles/templates/Archive.module.scss'; -const DEFAULT_POST_OPTIONS = {}; +// const DEFAULT_POST_OPTIONS = {}; -export default function TemplateArchive({ - title = 'Archive', - Title, - posts, - postOptions = DEFAULT_POST_OPTIONS, - slug, - metadata, - pagination, -}) { - const { metadata: siteMetadata = {} } = useSite(); +// export default function TemplateArchive({ +// title = 'Archive', +// Title, +// posts, +// postOptions = DEFAULT_POST_OPTIONS, +// slug, +// metadata, +// pagination, +// }) { +// const { metadata: siteMetadata = {} } = useSite(); - if (process.env.WORDPRESS_PLUGIN_SEO !== true) { - metadata.title = `${title} - ${siteMetadata.title}`; - metadata.og.title = metadata.title; - metadata.twitter.title = metadata.title; - } +// if (process.env.WORDPRESS_PLUGIN_SEO !== true) { +// metadata.title = `${title} - ${siteMetadata.title}`; +// metadata.og.title = metadata.title; +// metadata.twitter.title = metadata.title; +// } - const helmetSettings = helmetSettingsFromMetadata(metadata); +// const helmetSettings = helmetSettingsFromMetadata(metadata); - return ( - - +// return ( +// +// - +// -
- -

{Title || title}

- {metadata.description && ( -

- )} - -

+//
+// +//

{Title || title}

+// {metadata.description && ( +//

+// )} +// +//

-
- - Posts - {Array.isArray(posts) && ( - <> -
    - {posts.map((post) => { - return ( -
  • - -
  • - ); - })} -
- {pagination && ( - - )} - - )} -
-
-
- ); -} +//
+// +// Posts +// {Array.isArray(posts) && ( +// <> +//
    +// {posts.map((post) => { +// return ( +//
  • +// +//
  • +// ); +// })} +//
+// {pagination && ( +// +// )} +// +// )} +//
+//
+//
+// ); +// } diff --git a/src/templates/page.js b/src/templates/page.js new file mode 100644 index 00000000..6e5f0aa7 --- /dev/null +++ b/src/templates/page.js @@ -0,0 +1,192 @@ +import { gql } from '@apollo/client'; + +import Section from '@/components/Section'; +import Container from '@/components/Container'; + +// import Link from 'next/link'; +// import { Helmet } from 'react-helmet'; + +import { mapPageData } from '@/lib/pages'; +// import { WebpageJsonLd } from 'lib/json-ld'; +// import { helmetSettingsFromMetadata } from 'lib/site'; +// import useSite from 'hooks/use-site'; +// import usePageMetadata from 'hooks/use-page-metadata'; + +// import Layout from 'components/Layout'; +// import Header from 'components/Header'; +// import Content from 'components/Content'; + +// import FeaturedImage from 'components/FeaturedImage'; +// import Breadcrumbs from 'components/Breadcrumbs'; + +import { QUERY_PAGE_BY_URI } from '@/data/pages'; + +// import styles from 'styles/pages/Page.module.scss'; + +export default function Page({ data: page, breadcrumbs }) { + console.log('page', page) + const { children, content, description, featuredImage, metaTitle, slug, title } = page; + + // const { metadata: siteMetadata = {} } = useSite(); + + // const { metadata } = usePageMetadata({ + // metadata: { + // ...page, + // title: metaTitle, + // description: description || page.og?.description || `Read more about ${title}`, + // }, + // }); + + // if (process.env.WORDPRESS_PLUGIN_SEO !== true) { + // metadata.title = `${title} - ${siteMetadata.title}`; + // metadata.og.title = metadata.title; + // metadata.twitter.title = metadata.title; + // } + + // const hasChildren = Array.isArray(children) && children.length > 0; + + // const helmetSettings = helmetSettingsFromMetadata(metadata); + + return ( +
+ +
+ +
+ ) + + // return ( + // + // + + // + + //
+ // {Array.isArray(breadcrumbs) && } + // {featuredImage && ( + // + // )} + //

{title}

+ //
+ + // + //
+ // + //
+ // + //
+ + // {hasChildren && ( + //
+ // + // + // + //
+ // )} + //
+ //
+ // ); +} + +Page.template = { + query: gql` + query PageByUri($uri: ID!) { + page(id: $uri, idType: URI) { + children { + edges { + node { + id + slug + uri + ... on Page { + id + title + } + } + } + } + content + featuredImage { + node { + altText + caption + id + sizes + sourceUrl + srcSet + } + } + id + menuOrder + parent { + node { + id + slug + uri + ... on Page { + title + } + } + } + slug + title + uri + } + } + `, + transformer: (data) => { + const page = { ...data.page }; + + if (page.featuredImage) { + page.featuredImage = page.featuredImage.node; + } + + if (page.parent) { + page.parent = page.parent.node; + } + + if (page.children) { + page.children = page.children.edges.map(({ node }) => node); + } + + return page; + }, + variables: ({ uri }) => { + return { + uri, + }; + }, +}; \ No newline at end of file From 860e8f01a0c2ea13f55f01db39de51077399b49a Mon Sep 17 00:00:00 2001 From: Colby Fayock Date: Sat, 6 May 2023 20:15:11 -0400 Subject: [PATCH 02/11] moar --- next.config.js | 3 +- package.json | 4 +- plugins/sitemap.js | 42 ---- plugins/util.js | 1 + pnpm-lock.yaml | 29 --- public/android-chrome-192x192.png | Bin 1163 -> 0 bytes public/android-chrome-512x512.png | Bin 2453 -> 0 bytes public/favicon-16x16.png | Bin 232 -> 0 bytes public/favicon-32x32.png | Bin 340 -> 0 bytes public/favicon.ico | Bin 15406 -> 0 bytes public/sitemap.jpg | 1 - .../app/apple-icon.png | Bin src/app/favicon.ico | Bin 25931 -> 15406 bytes src/app/globals.css | 107 -------- .../favicon-1024x1024.png => src/app/icon.png | Bin src/app/layout.js | 86 ++++++- src/app/page.js | 150 +++++------- src/app/page.module.css | 229 ------------------ src/app/robots.js | 12 + src/app/sitemap.js | 32 +++ src/components/FeaturedImage/FeaturedImage.js | 2 +- src/components/Footer/Footer.js | 24 +- src/components/Header/Header.js | 2 +- src/components/JSONLD/JSONLD.js | 13 + src/components/JSONLD/index.js | 1 + src/components/Layout/Layout.js | 76 ------ src/components/Layout/index.js | 1 - src/components/Metadata/Metadata.js | 6 +- src/components/Nav/Nav.js | 114 ++++----- src/components/Nav/Nav.module.scss | 11 +- src/components/NavListItem/NavListItem.js | 23 +- .../NavListItem/NavListItem.module.scss | 1 - src/components/PostCard/PostCard.js | 4 +- src/components/Section/Section.js | 10 +- src/data/pages.js | 1 + src/data/posts.js | 2 + src/data/site.js | 7 + src/hooks/use-page-metadata.js | 2 +- src/hooks/use-search.js | 4 +- src/hooks/use-site.js | 4 +- src/lib/categories.js | 2 +- src/lib/json-ld.js | 6 +- src/lib/menus.js | 121 +++------ src/lib/pages.js | 17 +- src/lib/posts.js | 6 +- src/lib/site.js | 106 ++++---- src/lib/users.js | 18 +- src/pages.original/404.js | 6 +- src/pages.original/500.js | 6 +- .../[slugParent]/[[...slugChild]].js | 20 +- src/pages.original/_app.js | 14 +- src/pages.original/authors/[slug].js | 10 +- src/pages.original/categories.js | 14 +- src/pages.original/categories/[slug].js | 8 +- src/pages.original/index.js | 75 ------ src/pages.original/posts.js | 2 +- src/pages.original/posts/[slug].js | 24 +- src/pages.original/posts/page/[page].js | 4 +- src/styles/_variables.module.scss | 5 - src/styles/globals.scss | 3 +- .../layout.module.scss} | 0 src/templates/archive.js | 18 +- src/templates/page.js | 15 +- 63 files changed, 491 insertions(+), 1013 deletions(-) delete mode 100644 plugins/sitemap.js delete mode 100644 public/android-chrome-192x192.png delete mode 100644 public/android-chrome-512x512.png delete mode 100644 public/favicon-16x16.png delete mode 100644 public/favicon-32x32.png delete mode 100644 public/favicon.ico delete mode 100644 public/sitemap.jpg rename public/apple-touch-icon.png => src/app/apple-icon.png (100%) delete mode 100644 src/app/globals.css rename public/favicon-1024x1024.png => src/app/icon.png (100%) delete mode 100644 src/app/page.module.css create mode 100644 src/app/robots.js create mode 100644 src/app/sitemap.js create mode 100644 src/components/JSONLD/JSONLD.js create mode 100644 src/components/JSONLD/index.js delete mode 100644 src/components/Layout/Layout.js delete mode 100644 src/components/Layout/index.js delete mode 100644 src/components/NavListItem/NavListItem.module.scss delete mode 100644 src/pages.original/index.js delete mode 100644 src/styles/_variables.module.scss rename src/{components/Layout/Layout.module.scss => styles/layout.module.scss} (100%) diff --git a/next.config.js b/next.config.js index 183575bd..9683784b 100644 --- a/next.config.js +++ b/next.config.js @@ -1,6 +1,5 @@ const indexSearch = require('./plugins/search-index'); const feed = require('./plugins/feed'); -const sitemap = require('./plugins/sitemap'); // const socialImages = require('./plugins/socialImages'); TODO: failing to run on Netlify /** @type {import('next').NextConfig} */ @@ -40,7 +39,7 @@ const nextConfig = { }; module.exports = () => { - const plugins = [indexSearch, feed, sitemap]; + const plugins = [indexSearch, feed]; return plugins.reduce((acc, plugin) => plugin(acc), nextConfig); }; diff --git a/package.json b/package.json index 66803438..d1f146f5 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,6 @@ "he": "^1.2.0", "loader-utils": "^3.2.1", "next": "13.4.0", - "nextjs-progressbar": "^0.0.16", "parameterize": "^1.0.0", "path": "^0.12.7", "react": "18.2.0", @@ -36,8 +35,7 @@ "react-helmet": "^6.1.0", "react-icons": "^4.8.0", "rss": "^1.2.2", - "sass": "^1.62.1", - "style.css": "^1.0.3" + "sass": "^1.62.1" }, "devDependencies": { "@types/node": "20.0.0", diff --git a/plugins/sitemap.js b/plugins/sitemap.js deleted file mode 100644 index 21fd98f1..00000000 --- a/plugins/sitemap.js +++ /dev/null @@ -1,42 +0,0 @@ -const path = require('path'); -const { getSitemapData, generateSitemap, generateRobotsTxt } = require('./util'); - -const WebpackPluginCompiler = require('./plugin-compiler'); - -module.exports = function sitemap(nextConfig = {}) { - const { env, outputDirectory, outputName, verbose = false } = nextConfig; - - const plugin = { - name: 'Sitemap', - outputDirectory: outputDirectory || './public', - outputName: outputName || 'sitemap.xml', - getData: getSitemapData, - generate: generateSitemap, - postcreate: generateRobotsTxt, - }; - - const { WORDPRESS_GRAPHQL_ENDPOINT } = env; - - return Object.assign({}, nextConfig, { - webpack(config, options) { - if (config.watchOptions) { - config.watchOptions.ignored.push(path.join('**', plugin.outputDirectory, plugin.outputName)); - } - - config.plugins.push( - new WebpackPluginCompiler({ - url: WORDPRESS_GRAPHQL_ENDPOINT, - plugin, - verbose, - nextConfig, - }) - ); - - if (typeof nextConfig.webpack === 'function') { - return nextConfig.webpack(config, options); - } - - return config; - }, - }); -}; diff --git a/plugins/util.js b/plugins/util.js index f8f37181..44bc65db 100644 --- a/plugins/util.js +++ b/plugins/util.js @@ -153,6 +153,7 @@ async function getSiteMetadata(apolloClient, process, verbose = false) { try { const data = await apolloClient.query({ query }); + console.log('data', data) metadata = { ...data.data.generalSettings }; if (!metadata.language || metadata.language === '') { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 05f1ea86..b9a3dcc0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -18,7 +18,6 @@ specifiers: lint-staged: ^13.2.2 loader-utils: ^3.2.1 next: 13.4.0 - nextjs-progressbar: ^0.0.16 parameterize: ^1.0.0 path: ^0.12.7 playwright: ^1.33.0 @@ -29,7 +28,6 @@ specifiers: react-icons: ^4.8.0 rss: ^1.2.2 sass: ^1.62.1 - style.css: ^1.0.3 typescript: 5.0.4 dependencies: @@ -41,7 +39,6 @@ dependencies: he: 1.2.0 loader-utils: 3.2.1 next: 13.4.0_txdvpvppf2ilsh27xadmwrzlmm - nextjs-progressbar: 0.0.16_next@13.4.0+react@18.2.0 parameterize: 1.0.0 path: 0.12.7 react: 18.2.0 @@ -50,7 +47,6 @@ dependencies: react-icons: 4.8.0_react@18.2.0 rss: 1.2.2 sass: 1.62.1 - style.css: 1.0.3 devDependencies: '@types/node': 20.0.0 @@ -317,10 +313,6 @@ packages: resolution: {integrity: sha512-cD2uPTDnQQCVpmRefonO98/PPijuOnnEy5oytWJFPY1N9aJCz2wJ5kSGWO+zJoed2cY2JxQh6yBuUq4vIn61hw==} dev: true - /@types/nprogress/0.2.0: - resolution: {integrity: sha512-1cYJrqq9GezNFPsWTZpFut/d4CjpZqA0vhqDUPFWYKF1oIyBz5qnoYMzR+0C/T96t3ebLAC1SSnwrVOm5/j74A==} - dev: false - /@types/prop-types/15.7.5: resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==} dev: true @@ -2098,19 +2090,6 @@ packages: - babel-plugin-macros dev: false - /nextjs-progressbar/0.0.16_next@13.4.0+react@18.2.0: - resolution: {integrity: sha512-GV0fD38EMD3vSDCmkq+tObmoup6QA91a6a9MxGuhJZuRk/9TNsrHGnIQQQ/sggkMkXuT4fBgF6jRjFwScDT3zA==} - peerDependencies: - next: '>= 6.0.0' - react: '>= 16.0.0' - dependencies: - '@types/nprogress': 0.2.0 - next: 13.4.0_txdvpvppf2ilsh27xadmwrzlmm - nprogress: 0.2.0 - prop-types: 15.8.1 - react: 18.2.0 - dev: false - /normalize-path/3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} @@ -2129,10 +2108,6 @@ packages: path-key: 4.0.0 dev: true - /nprogress/0.2.0: - resolution: {integrity: sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==} - dev: false - /object-assign/4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} @@ -2749,10 +2724,6 @@ packages: engines: {node: '>=8'} dev: true - /style.css/1.0.3: - resolution: {integrity: sha512-gek0b2UUoC2u1apcSFlEBdX3VxgKo+iAui/nTtpRBmkUlKbdYgtBU8t4tv0OAIZxNIl50htVGNWyafD1g4dlDg==} - dev: false - /styled-jsx/5.1.1_react@18.2.0: resolution: {integrity: sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==} engines: {node: '>= 12.0.0'} diff --git a/public/android-chrome-192x192.png b/public/android-chrome-192x192.png deleted file mode 100644 index c5592d1daf76e105c8d31d352e8a4eb9bd855974..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1163 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 diff --git a/public/favicon-16x16.png b/public/favicon-16x16.png deleted file mode 100644 index 47a8e06c638b8edad830b087ffeb14a6c6b94eea..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 232 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbL!eSlAhE0CrHY*ua32kI9o3GxeO zIREXDvmDpy;|JC*ZLN(B^|mrI@VU0J6)5lG>Eak7ad~dPDN}<1!;uw_0(So2zja;m zX4U9zrE6v$s_gm49RGe2qfgnx*5{de85|*33Y3dPub=oJ^G(R3$WJRP^AzLa+sv)C SYozXj-0SJ;=d#Wzp$P!oOgm)& diff --git a/public/favicon-32x32.png b/public/favicon-32x32.png deleted file mode 100644 index bb3d7acdd29f2027681be0e27fd0274794d12efc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 340 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dy$pJngu0WdBAT6Wh9?%Yjk|4ie zhK20E-#x!}dehX-gkU#I6=@OPFZb^r*gI=RZB;?8f$r|<6K??3Hh8)?hFF}wdp?}2 z#X-RJBHyz$lRw}6uf^`NrwYHN8_^7Q13~(_PCiuhH7L!C@}lJ9QIV8~Q6e7?OiH8FkRqe;_4~W`)Sc5g_nv$9zI&RnSN-okXYak%f1P#C-e>K7k1=(o z-ZV5A$|ln>)|e&6n5L$}dCN3oE>hRpT5O+ZOwUYXTIhoc8ijg_(JpOV;FFBlm=KIH z)I9=!D&Q&Y^&m->Q~4W|v#};gv83)w8U1S|{n8E_Y51C8<2!ZDX-cvBqY3)QVtvY; zPNcE7#KwD$Czn%5Xxmz%zcZmdOI0_W?t{84ofG;ns{RePgr-oX2xy*Z0;_@MrywB$ zAp)5qz+2mNg3FF^4to9`L7w|99pyaAeQe|m%6a*fGug^?4D^F)eNe8YoXdsm!$`IK%GF$n z=A`E!s}H^ORj%h!)?q9wzjDM{$PJ8E@}avH#6_EPCR91=k#<<(G1%{gxj>@%{9%a?FF77pX!7>E45nyJyTKdlP@*nQZw;;T zdNvETxn3CqS%^T0z^I8p3s<5Sb~_0BBm^Nyh(L%yh(L(I{}KVMWfp^WuzQ%G{kf$e z?f*NP%1RrpA3=Og=<8f--z}gHKNfJko!Lt=T>tFX33rvA!{ie8^jBENw5b z>+4X@k;YqIzazb?*zmnaAH}GdgVz?FItZofxyEw}_M>*_D zx71FojmOFAE8mFg07jXT}Rgt3Rg`OGZM?pdaLIgqtLIgqtLIgqtLIfN|;4hJv^7sG% diff --git a/public/sitemap.jpg b/public/sitemap.jpg deleted file mode 100644 index 66dc9051..00000000 --- a/public/sitemap.jpg +++ /dev/null @@ -1 +0,0 @@ -undefined \ No newline at end of file diff --git a/public/apple-touch-icon.png b/src/app/apple-icon.png similarity index 100% rename from public/apple-touch-icon.png rename to src/app/apple-icon.png diff --git a/src/app/favicon.ico b/src/app/favicon.ico index 718d6fea4835ec2d246af9800eddb7ffb276240c..34361d2dbf746cf576c896bfe33a95f82e93deb3 100644 GIT binary patch literal 15406 zcmeI2U5HIl6vy`%LOvSd$*7q`qtN6*J|Z!sH7L!C@}lJ9QIV8~Q6e7?OiH8FkRqe;_4~W`)Sc5g_nv$9zI&RnSN-okXYak%f1P#C-e>K7k1=(o z-ZV5A$|ln>)|e&6n5L$}dCN3oE>hRpT5O+ZOwUYXTIhoc8ijg_(JpOV;FFBlm=KIH z)I9=!D&Q&Y^&m->Q~4W|v#};gv83)w8U1S|{n8E_Y51C8<2!ZDX-cvBqY3)QVtvY; zPNcE7#KwD$Czn%5Xxmz%zcZmdOI0_W?t{84ofG;ns{RePgr-oX2xy*Z0;_@MrywB$ zAp)5qz+2mNg3FF^4to9`L7w|99pyaAeQe|m%6a*fGug^?4D^F)eNe8YoXdsm!$`IK%GF$n z=A`E!s}H^ORj%h!)?q9wzjDM{$PJ8E@}avH#6_EPCR91=k#<<(G1%{gxj>@%{9%a?FF77pX!7>E45nyJyTKdlP@*nQZw;;T zdNvETxn3CqS%^T0z^I8p3s<5Sb~_0BBm^Nyh(L%yh(L(I{}KVMWfp^WuzQ%G{kf$e z?f*NP%1RrpA3=Og=<8f--z}gHKNfJko!Lt=T>tFX33rvA!{ie8^jBENw5b z>+4X@k;YqIzazb?*zmnaAH}GdgVz?FItZofxyEw}_M>*_D zx71FojmOFAE8mFg07jXT}Rgt3Rg`OGZM?pdaLIgqtLIgqtLIgqtLIfN|;4hJv^7sG% literal 25931 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 LrJugUA?W`A8`#=m diff --git a/src/app/globals.css b/src/app/globals.css deleted file mode 100644 index d4f491e1..00000000 --- a/src/app/globals.css +++ /dev/null @@ -1,107 +0,0 @@ -:root { - --max-width: 1100px; - --border-radius: 12px; - --font-mono: ui-monospace, Menlo, Monaco, 'Cascadia Mono', 'Segoe UI Mono', - 'Roboto Mono', 'Oxygen Mono', 'Ubuntu Monospace', 'Source Code Pro', - 'Fira Mono', 'Droid Sans Mono', 'Courier New', monospace; - - --foreground-rgb: 0, 0, 0; - --background-start-rgb: 214, 219, 220; - --background-end-rgb: 255, 255, 255; - - --primary-glow: conic-gradient( - from 180deg at 50% 50%, - #16abff33 0deg, - #0885ff33 55deg, - #54d6ff33 120deg, - #0071ff33 160deg, - transparent 360deg - ); - --secondary-glow: radial-gradient( - rgba(255, 255, 255, 1), - rgba(255, 255, 255, 0) - ); - - --tile-start-rgb: 239, 245, 249; - --tile-end-rgb: 228, 232, 233; - --tile-border: conic-gradient( - #00000080, - #00000040, - #00000030, - #00000020, - #00000010, - #00000010, - #00000080 - ); - - --callout-rgb: 238, 240, 241; - --callout-border-rgb: 172, 175, 176; - --card-rgb: 180, 185, 188; - --card-border-rgb: 131, 134, 135; -} - -@media (prefers-color-scheme: dark) { - :root { - --foreground-rgb: 255, 255, 255; - --background-start-rgb: 0, 0, 0; - --background-end-rgb: 0, 0, 0; - - --primary-glow: radial-gradient(rgba(1, 65, 255, 0.4), rgba(1, 65, 255, 0)); - --secondary-glow: linear-gradient( - to bottom right, - rgba(1, 65, 255, 0), - rgba(1, 65, 255, 0), - rgba(1, 65, 255, 0.3) - ); - - --tile-start-rgb: 2, 13, 46; - --tile-end-rgb: 2, 5, 19; - --tile-border: conic-gradient( - #ffffff80, - #ffffff40, - #ffffff30, - #ffffff20, - #ffffff10, - #ffffff10, - #ffffff80 - ); - - --callout-rgb: 20, 20, 20; - --callout-border-rgb: 108, 108, 108; - --card-rgb: 100, 100, 100; - --card-border-rgb: 200, 200, 200; - } -} - -* { - box-sizing: border-box; - padding: 0; - margin: 0; -} - -html, -body { - max-width: 100vw; - overflow-x: hidden; -} - -body { - color: rgb(var(--foreground-rgb)); - background: linear-gradient( - to bottom, - transparent, - rgb(var(--background-end-rgb)) - ) - rgb(var(--background-start-rgb)); -} - -a { - color: inherit; - text-decoration: none; -} - -@media (prefers-color-scheme: dark) { - html { - color-scheme: dark; - } -} diff --git a/public/favicon-1024x1024.png b/src/app/icon.png similarity index 100% rename from public/favicon-1024x1024.png rename to src/app/icon.png diff --git a/src/app/layout.js b/src/app/layout.js index 3e3a9a26..1be0b453 100644 --- a/src/app/layout.js +++ b/src/app/layout.js @@ -1,14 +1,90 @@ -import './globals.css' +import { getSiteMetadata } from '@/lib/site'; -export const metadata = { - title: 'Create Next App', - description: 'Generated by create next app', +import Nav from '@/components/Nav'; +import Main from '@/components/Main'; +import Footer from '@/components/Footer'; + +import '@/styles/globals.scss'; +import styles from '@/styles/layout.module.scss'; + +export async function generateMetadata({ params, searchParams }, parent) { + const metadata = await getSiteMetadata(); + + return { + title: { + default: metadata.title, + template: process.env.WORDPRESS_PLUGIN_SEO === true ? '%s' : `%s - ${metadata.title}`, + }, + description: metadata.description, + openGraph: { + title: metadata.title, + description: metadata.description, + url: metadata.url, + siteName: metadata.title, + images: [ + // { + // url: 'https://nextjs.org/og.png', + // width: 800, + // height: 600, + // }, + ], + locale: metadata.language, + type: 'website', + }, + }; } export default function RootLayout({ children }) { return ( - {children} + +
+
+ ) } + + + + +// const helmetSettings = { + +// ...helmetSettingsFromMetadata(metadata, { +// setTitle: false, +// link: [ +// { +// rel: 'alternate', +// type: 'application/rss+xml', +// href: '/feed.xml', +// }, + +// // Favicon sizes and manifest generated via https://favicon.io/ + +// { +// rel: 'apple-touch-icon', +// sizes: '180x180', +// href: '/apple-touch-icon.png', +// }, +// { +// rel: 'icon', +// type: 'image/png', +// sizes: '16x16', +// href: '/favicon-16x16.png', +// }, +// { +// rel: 'icon', +// type: 'image/png', +// sizes: '32x32', +// href: '/favicon-32x32.png', +// }, +// { +// rel: 'manifest', +// href: '/site.webmanifest', +// }, +// ], +// }), +// }; \ No newline at end of file diff --git a/src/app/page.js b/src/app/page.js index 01946f79..c45730b0 100644 --- a/src/app/page.js +++ b/src/app/page.js @@ -1,102 +1,66 @@ -import Image from 'next/image' -import { Inter } from 'next/font/google' -import styles from './page.module.css' +import { getSiteMetadata } from '@/lib/site'; +import { getPaginatedPosts } from '@/lib/posts'; -const inter = Inter({ subsets: ['latin'] }) +import Header from '@/components/Header'; +import Section from '@/components/Section'; +import Container from '@/components/Container'; +import PostCard from '@/components/PostCard'; +// import Pagination from '@/components/Pagination'; -export default function Home() { - return ( -
-
-

- Get started by editing  - app/page.tsx -

- -
+import styles from '@/styles/pages/Home.module.scss'; -
- Next.js Logo -
+export default async function Home() { + const [metadata, { posts, pagination }] = await Promise.all([ + getSiteMetadata(), + getPaginatedPosts({ + queryIncludes: 'archive', + }) + ]); - -
+
+ +

Posts

+
    + {posts.map((post) => { + return ( +
  • + +
  • + ); + })} +
+ {/* {pagination && ( + + )} */} +
+
+ ) } diff --git a/src/app/page.module.css b/src/app/page.module.css deleted file mode 100644 index 9411a5e6..00000000 --- a/src/app/page.module.css +++ /dev/null @@ -1,229 +0,0 @@ -.main { - display: flex; - flex-direction: column; - justify-content: space-between; - align-items: center; - padding: 6rem; - min-height: 100vh; -} - -.description { - display: inherit; - justify-content: inherit; - align-items: inherit; - font-size: 0.85rem; - max-width: var(--max-width); - width: 100%; - z-index: 2; - font-family: var(--font-mono); -} - -.description a { - display: flex; - justify-content: center; - align-items: center; - gap: 0.5rem; -} - -.description p { - position: relative; - margin: 0; - padding: 1rem; - background-color: rgba(var(--callout-rgb), 0.5); - border: 1px solid rgba(var(--callout-border-rgb), 0.3); - border-radius: var(--border-radius); -} - -.code { - font-weight: 700; - font-family: var(--font-mono); -} - -.grid { - display: grid; - grid-template-columns: repeat(4, minmax(25%, auto)); - width: var(--max-width); - max-width: 100%; -} - -.card { - padding: 1rem 1.2rem; - border-radius: var(--border-radius); - background: rgba(var(--card-rgb), 0); - border: 1px solid rgba(var(--card-border-rgb), 0); - transition: background 200ms, border 200ms; -} - -.card span { - display: inline-block; - transition: transform 200ms; -} - -.card h2 { - font-weight: 600; - margin-bottom: 0.7rem; -} - -.card p { - margin: 0; - opacity: 0.6; - font-size: 0.9rem; - line-height: 1.5; - max-width: 30ch; -} - -.center { - display: flex; - justify-content: center; - align-items: center; - position: relative; - padding: 4rem 0; -} - -.center::before { - background: var(--secondary-glow); - border-radius: 50%; - width: 480px; - height: 360px; - margin-left: -400px; -} - -.center::after { - background: var(--primary-glow); - width: 240px; - height: 180px; - z-index: -1; -} - -.center::before, -.center::after { - content: ''; - left: 50%; - position: absolute; - filter: blur(45px); - transform: translateZ(0); -} - -.logo { - position: relative; -} -/* Enable hover only on non-touch devices */ -@media (hover: hover) and (pointer: fine) { - .card:hover { - background: rgba(var(--card-rgb), 0.1); - border: 1px solid rgba(var(--card-border-rgb), 0.15); - } - - .card:hover span { - transform: translateX(4px); - } -} - -@media (prefers-reduced-motion) { - .card:hover span { - transform: none; - } -} - -/* Mobile */ -@media (max-width: 700px) { - .content { - padding: 4rem; - } - - .grid { - grid-template-columns: 1fr; - margin-bottom: 120px; - max-width: 320px; - text-align: center; - } - - .card { - padding: 1rem 2.5rem; - } - - .card h2 { - margin-bottom: 0.5rem; - } - - .center { - padding: 8rem 0 6rem; - } - - .center::before { - transform: none; - height: 300px; - } - - .description { - font-size: 0.8rem; - } - - .description a { - padding: 1rem; - } - - .description p, - .description div { - display: flex; - justify-content: center; - position: fixed; - width: 100%; - } - - .description p { - align-items: center; - inset: 0 0 auto; - padding: 2rem 1rem 1.4rem; - border-radius: 0; - border: none; - border-bottom: 1px solid rgba(var(--callout-border-rgb), 0.25); - background: linear-gradient( - to bottom, - rgba(var(--background-start-rgb), 1), - rgba(var(--callout-rgb), 0.5) - ); - background-clip: padding-box; - backdrop-filter: blur(24px); - } - - .description div { - align-items: flex-end; - pointer-events: none; - inset: auto 0 0; - padding: 2rem; - height: 200px; - background: linear-gradient( - to bottom, - transparent 0%, - rgb(var(--background-end-rgb)) 40% - ); - z-index: 1; - } -} - -/* Tablet and Smaller Desktop */ -@media (min-width: 701px) and (max-width: 1120px) { - .grid { - grid-template-columns: repeat(2, 50%); - } -} - -@media (prefers-color-scheme: dark) { - .vercelLogo { - filter: invert(1); - } - - .logo { - filter: invert(1) drop-shadow(0 0 0.3rem #ffffff70); - } -} - -@keyframes rotate { - from { - transform: rotate(360deg); - } - to { - transform: rotate(0deg); - } -} diff --git a/src/app/robots.js b/src/app/robots.js new file mode 100644 index 00000000..9e10ed0e --- /dev/null +++ b/src/app/robots.js @@ -0,0 +1,12 @@ +import { getSiteMetadata } from '@/lib/site'; + +export default async function robots() { + const metadata = await getSiteMetadata(); + + return { + rules: { + userAgent: '*' + }, + sitemap: `${metadata.url}/sitemap.xml` + }; +} \ No newline at end of file diff --git a/src/app/sitemap.js b/src/app/sitemap.js new file mode 100644 index 00000000..c5631fcc --- /dev/null +++ b/src/app/sitemap.js @@ -0,0 +1,32 @@ +import { getSiteMetadata } from '@/lib/site'; +import { getAllPages } from '@/lib/pages'; +import { getAllPosts } from '@/lib/posts'; + +export default async function sitemap() { + const metadata = await getSiteMetadata(); + const { pages: allPages } = await getAllPages(); + const { posts: allPosts } = await getAllPosts(); + + const pages = allPages.map(({ modified, uri }) => { + return { + url: `${metadata.url}${uri}`, + lastModified: modified + } + }); + + const posts = allPosts.map(({ modified, uri }) => { + return { + url: `${metadata.url}${uri}`, + lastModified: modified + } + }); + + return [ + { + url: metadata.url, + lastModified: new Date(), + }, + ...pages, + ...posts + ]; +} \ No newline at end of file diff --git a/src/components/FeaturedImage/FeaturedImage.js b/src/components/FeaturedImage/FeaturedImage.js index ac9f1a0f..79e4f08d 100644 --- a/src/components/FeaturedImage/FeaturedImage.js +++ b/src/components/FeaturedImage/FeaturedImage.js @@ -1,6 +1,6 @@ import ClassName from 'models/classname'; -import Image from 'components/Image'; +import Image from '@/components/Image'; import styles from './FeaturedImage.module.scss'; diff --git a/src/components/Footer/Footer.js b/src/components/Footer/Footer.js index 760716a6..47371e7d 100644 --- a/src/components/Footer/Footer.js +++ b/src/components/Footer/Footer.js @@ -1,16 +1,26 @@ import Link from 'next/link'; -import useSite from '@/hooks/use-site'; -import { postPathBySlug } from 'lib/posts'; -import { categoryPathBySlug } from 'lib/categories'; +import { getSiteMetadata } from '@/lib/site'; +import { getRecentPosts, postPathBySlug } from '@/lib/posts'; +import { getCategories, categoryPathBySlug } from '@/lib/categories'; -import Section from 'components/Section'; -import Container from 'components/Container'; +import Section from '@/components/Section'; +import Container from '@/components/Container'; import styles from './Footer.module.scss'; -const Footer = () => { - const { metadata = {}, recentPosts = [], categories = [] } = useSite(); +async function Footer() { + const metadata = await getSiteMetadata(); + + const { posts: recentPosts } = await getRecentPosts({ + count: 5, + queryIncludes: 'index', + }); + + const { categories } = await getCategories({ + count: 5, + }); + const { title } = metadata; const hasRecentPosts = Array.isArray(recentPosts) && recentPosts.length > 0; diff --git a/src/components/Header/Header.js b/src/components/Header/Header.js index df73a924..99b03226 100644 --- a/src/components/Header/Header.js +++ b/src/components/Header/Header.js @@ -1,4 +1,4 @@ -import Container from 'components/Container'; +import Container from '@/components/Container'; import styles from './Header.module.scss'; diff --git a/src/components/JSONLD/JSONLD.js b/src/components/JSONLD/JSONLD.js new file mode 100644 index 00000000..aab5c33d --- /dev/null +++ b/src/components/JSONLD/JSONLD.js @@ -0,0 +1,13 @@ +const JSONLD = ({ }) => { + return ( + - - ); -} - export function WebpageJsonLd({ title = '', description = '', siteTitle = '', slug = '' }) { const { homepage = '' } = config; const path = pagePathBySlug(slug); @@ -119,20 +96,3 @@ export function AuthorJsonLd({ author = {} }) { ); } - -export function LogoJsonLd() { - const { homepage = '', faviconPath = '/favicon.ico' } = config; - - const jsonLd = { - '@context': 'https://schema.org', - '@type': 'Organization', - url: `${homepage}`, - logo: `${homepage}${faviconPath}`, - }; - - return ( - - - - ); -} diff --git a/src/lib/site.js b/src/lib/site.js index 4dd6a6fd..33fa0fe7 100644 --- a/src/lib/site.js +++ b/src/lib/site.js @@ -25,10 +25,11 @@ export async function getSiteMetadata() { } const { generalSettings } = siteData?.data || {}; - let { title, description, language, url } = generalSettings; + let { title, description, language } = generalSettings; const settings = { ...generalSettings, + url: process.env.WORDPRESS_SITE_URL }; // It looks like the value of `language` when US English is set diff --git a/src/pages.original/404.js b/src/pages.original/404.js index 526cb1b2..26852591 100644 --- a/src/pages.original/404.js +++ b/src/pages.original/404.js @@ -5,7 +5,7 @@ import Layout from '@/components/Layout'; import Section from '@/components/Section'; import Container from '@/components/Container'; -import styles from 'styles/pages/Error.module.scss'; +import styles from '@/styles/pages/Error.module.scss'; export default function Custom404() { return ( diff --git a/src/pages.original/500.js b/src/pages.original/500.js index 7625891e..4e459058 100644 --- a/src/pages.original/500.js +++ b/src/pages.original/500.js @@ -5,7 +5,7 @@ import Layout from '@/components/Layout'; import Section from '@/components/Section'; import Container from '@/components/Container'; -import styles from 'styles/pages/Error.module.scss'; +import styles from '@/styles/pages/Error.module.scss'; export default function Custom500() { return ( diff --git a/src/pages.original/[slugParent]/[[...slugChild]].js b/src/pages.original/[slugParent]/[[...slugChild]].js index c4d7fbf5..0c5ffd06 100644 --- a/src/pages.original/[slugParent]/[[...slugChild]].js +++ b/src/pages.original/[slugParent]/[[...slugChild]].js @@ -15,7 +15,7 @@ import Container from '@/components/Container'; import FeaturedImage from '@/components/FeaturedImage'; import Breadcrumbs from '@/components/Breadcrumbs'; -import styles from 'styles/pages/Page.module.scss'; +import styles from '@/styles/pages/Page.module.scss'; export default function Page({ page, breadcrumbs }) { const { title, metaTitle, description, slug, content, featuredImage, children } = page; diff --git a/src/pages.original/categories.js b/src/pages.original/categories.js index 18b7c2e5..f0fccff1 100644 --- a/src/pages.original/categories.js +++ b/src/pages.original/categories.js @@ -11,7 +11,7 @@ import Section from '@/components/Section'; import Container from '@/components/Container'; import SectionTitle from '@/components/SectionTitle'; -import styles from 'styles/pages/Categories.module.scss'; +import styles from '@/styles/pages/Categories.module.scss'; export default function Categories({ categories }) { const { metadata = {} } = useSite(); diff --git a/src/pages.original/posts/[slug].js b/src/pages.original/posts/[slug].js index b8d02585..8db92c67 100644 --- a/src/pages.original/posts/[slug].js +++ b/src/pages.original/posts/[slug].js @@ -17,7 +17,7 @@ import Content from '@/components/Content'; import Metadata from '@/components/Metadata'; import FeaturedImage from '@/components/FeaturedImage'; -import styles from 'styles/pages/Post.module.scss'; +import styles from '@/styles/pages/Post.module.scss'; export default function Post({ post, socialImage, related }) { const { diff --git a/src/templates/archive.js b/src/templates/archive.js index 45da8940..5d13838d 100644 --- a/src/templates/archive.js +++ b/src/templates/archive.js @@ -12,7 +12,7 @@ // import PostCard from '@/components/PostCard'; // import Pagination from '@/components/Pagination/Pagination'; -// import styles from 'styles/templates/Archive.module.scss'; +// import styles from '@/styles/templates/Archive.module.scss'; // const DEFAULT_POST_OPTIONS = {}; diff --git a/src/templates/page.js b/src/templates/page.js index c5a049bb..9f755229 100644 --- a/src/templates/page.js +++ b/src/templates/page.js @@ -1,32 +1,29 @@ +import Link from 'next/link'; import { gql } from '@apollo/client'; +import { getSiteMetadata } from '@/lib/site'; + import Section from '@/components/Section'; import Container from '@/components/Container'; - -// import Link from 'next/link'; -// import { Helmet } from 'react-helmet'; +import Header from '@/components/Header'; +import Content from '@/components/Content'; +import FeaturedImage from '@/components/FeaturedImage'; +import Breadcrumbs from '@/components/Breadcrumbs'; +import JSONLD from '@/components/JSONLD'; // import { WebpageJsonLd } from '@/lib/json-ld'; // import { helmetSettingsFromMetadata } from '@/lib/site'; -// import useSite from 'hooks/use-site'; // import usePageMetadata from 'hooks/use-page-metadata'; -// import Layout from '@/components/Layout'; -// import Header from '@/components/Header'; -// import Content from '@/components/Content'; - -// import FeaturedImage from '@/components/FeaturedImage'; -// import Breadcrumbs from '@/components/Breadcrumbs'; - -import { QUERY_PAGE_BY_URI } from '@/data/pages'; +import styles from '@/styles/pages/Page.module.scss'; -// import styles from 'styles/pages/Page.module.scss'; +export default async function Page({ data, breadcrumbs }) { + const { children, content, description, featuredImage, metaTitle, title, uri } = data; -export default function Page({ data: page, breadcrumbs }) { - console.log('page', page) - const { children, content, description, featuredImage, metaTitle, slug, title } = page; + const metadata = await getSiteMetadata(); - // const { metadata: siteMetadata = {} } = useSite(); + const hasChildren = Array.isArray(children) && children.length > 0; + console.log('data', data) // const { metadata } = usePageMetadata({ // metadata: { @@ -36,88 +33,72 @@ export default function Page({ data: page, breadcrumbs }) { // }, // }); + // console.log('metadata', metadata) + // if (process.env.WORDPRESS_PLUGIN_SEO !== true) { // metadata.title = `${title} - ${siteMetadata.title}`; // metadata.og.title = metadata.title; // metadata.twitter.title = metadata.title; // } - // const hasChildren = Array.isArray(children) && children.length > 0; - - // const helmetSettings = helmetSettingsFromMetadata(metadata); - + return ( -
- -
- -
- ) - - // return ( - // - // - - // - - //
- // {Array.isArray(breadcrumbs) && } - // {featuredImage && ( - // - // )} - //

{title}

- //
- - // - //
- // - //
- // - //
- - // {hasChildren && ( - //
- // - // - // - //
- // )} - //
- //
- // ); + <> +
+ {Array.isArray(breadcrumbs) && } + {featuredImage && ( + + )} +

{title}

+
+ + +
+ +
+ +
+ + {hasChildren && ( +
+ + + +
+ )} +
+ + + + ); } Page.template = { @@ -128,7 +109,6 @@ Page.template = { edges { node { id - slug uri ... on Page { id @@ -143,6 +123,10 @@ Page.template = { altText caption id + mediaDetails { + height + width + } sizes sourceUrl srcSet @@ -153,14 +137,12 @@ Page.template = { parent { node { id - slug uri ... on Page { title } } } - slug title uri } diff --git a/src/templates/post.js b/src/templates/post.js new file mode 100644 index 00000000..069a9a8e --- /dev/null +++ b/src/templates/post.js @@ -0,0 +1,191 @@ +import { gql } from '@apollo/client'; + +import Section from '@/components/Section'; +import Container from '@/components/Container'; + +// import Link from 'next/link'; +// import { Helmet } from 'react-helmet'; + +// import { WebpageJsonLd } from '@/lib/json-ld'; +// import { helmetSettingsFromMetadata } from '@/lib/site'; +// import useSite from 'hooks/use-site'; +// import usePageMetadata from 'hooks/use-page-metadata'; + +// import Layout from '@/components/Layout'; +// import Header from '@/components/Header'; +// import Content from '@/components/Content'; + +// import FeaturedImage from '@/components/FeaturedImage'; +// import Breadcrumbs from '@/components/Breadcrumbs'; + +import { QUERY_PAGE_BY_URI } from '@/data/pages'; + +import styles from '@/styles/pages/Page.module.scss'; + +export default function Page({ data: page, breadcrumbs }) { + console.log('page', page) + const { children, content, description, featuredImage, metaTitle, slug, title } = page; + + // const { metadata: siteMetadata = {} } = useSite(); + + // const { metadata } = usePageMetadata({ + // metadata: { + // ...page, + // title: metaTitle, + // description: description || page.og?.description || `Read more about ${title}`, + // }, + // }); + + // if (process.env.WORDPRESS_PLUGIN_SEO !== true) { + // metadata.title = `${title} - ${siteMetadata.title}`; + // metadata.og.title = metadata.title; + // metadata.twitter.title = metadata.title; + // } + + // const hasChildren = Array.isArray(children) && children.length > 0; + + // const helmetSettings = helmetSettingsFromMetadata(metadata); + + return ( +
+ +
+ +
+ ) + + // return ( + // + // + + // + + //
+ // {Array.isArray(breadcrumbs) && } + // {featuredImage && ( + // + // )} + //

{title}

+ //
+ + // + //
+ // + //
+ // + //
+ + // {hasChildren && ( + //
+ // + // + // + //
+ // )} + //
+ //
+ // ); +} + +Page.template = { + query: gql` + query PageByUri($uri: ID!) { + page(id: $uri, idType: URI) { + children { + edges { + node { + id + slug + uri + ... on Page { + id + title + } + } + } + } + content + featuredImage { + node { + altText + caption + id + sizes + sourceUrl + srcSet + } + } + id + menuOrder + parent { + node { + id + slug + uri + ... on Page { + title + } + } + } + slug + title + uri + } + } + `, + transformer: (data) => { + const page = { ...data.page }; + + if (page.featuredImage) { + page.featuredImage = page.featuredImage.node; + } + + if (page.parent) { + page.parent = page.parent.node; + } + + if (page.children) { + page.children = page.children.edges.map(({ node }) => node); + } + + return page; + }, + variables: ({ uri }) => { + return { + uri, + }; + }, +}; \ No newline at end of file From cca3ee72150cd8a89f3ce5d0d7d9d40e37d7e3cb Mon Sep 17 00:00:00 2001 From: Colby Fayock Date: Sun, 7 May 2023 14:17:23 -0400 Subject: [PATCH 04/11] post --- next.config.js | 6 +- src/app/[...uriNodes]/page.js | 26 +- src/app/feed.xml/route.js | 16 +- src/app/layout.js | 7 +- src/app/page.js | 37 ++- src/app/robots.js | 6 +- src/app/sitemap.js | 12 +- src/app/wp-search.json/route.js | 4 +- src/components/FeaturedImage/FeaturedImage.js | 4 +- src/components/Footer/Footer.js | 12 +- src/components/JSONLD/JSONLD.js | 9 +- src/components/Nav/Nav.js | 214 +------------ src/components/Nav/Nav.module.scss | 96 ------ src/components/NavSearch/NavSearch.js | 215 +++++++++++++ .../NavSearch/NavSearch.module.scss | 102 ++++++ src/components/NavSearch/index.js | 1 + src/components/PostCard/PostCard.js | 6 +- src/components/Section/Section.js | 8 +- src/data/site.js | 6 +- src/hooks/use-site.js | 2 +- src/lib/datetime.js | 12 +- src/lib/json-ld.js | 48 --- src/lib/menus.js | 18 +- src/lib/nodes.js | 17 +- src/lib/posts.js | 12 +- src/lib/request.js | 21 ++ src/lib/site.js | 11 +- src/lib/users.js | 6 +- .../[slugParent]/[[...slugChild]].js | 176 ----------- src/pages.original/_app.js | 51 --- src/pages.original/_document.js | 43 --- src/pages.original/posts/[slug].js | 198 ------------ src/templates/page.js | 32 +- src/templates/post.js | 293 ++++++++++-------- 34 files changed, 633 insertions(+), 1094 deletions(-) create mode 100644 src/components/NavSearch/NavSearch.js create mode 100644 src/components/NavSearch/NavSearch.module.scss create mode 100644 src/components/NavSearch/index.js create mode 100644 src/lib/request.js delete mode 100644 src/pages.original/[slugParent]/[[...slugChild]].js delete mode 100644 src/pages.original/_app.js delete mode 100644 src/pages.original/_document.js delete mode 100644 src/pages.original/posts/[slug].js diff --git a/next.config.js b/next.config.js index 53e1ee80..86a74b94 100644 --- a/next.config.js +++ b/next.config.js @@ -13,11 +13,11 @@ const nextConfig = { remotePatterns: [ { protocol: wordpressProtocol, - hostname: wordpressHost + hostname: wordpressHost, }, ], }, - + reactStrictMode: true, swcMinify: true, @@ -45,7 +45,7 @@ const nextConfig = { WORDPRESS_GRAPHQL_ENDPOINT: process.env.WORDPRESS_GRAPHQL_ENDPOINT, WORDPRESS_MENU_LOCATION_NAVIGATION: process.env.WORDPRESS_MENU_LOCATION_NAVIGATION || 'PRIMARY', WORDPRESS_PLUGIN_SEO: parseEnvValue(process.env.WORDPRESS_PLUGIN_SEO, false), - WORDPRESS_SITE_URL: pkg.homepage + WORDPRESS_SITE_URL: pkg.homepage, }, }; diff --git a/src/app/[...uriNodes]/page.js b/src/app/[...uriNodes]/page.js index 5800bee4..9b542377 100644 --- a/src/app/[...uriNodes]/page.js +++ b/src/app/[...uriNodes]/page.js @@ -1,6 +1,7 @@ import { notFound } from 'next/navigation'; import { getNodeByUri, getTemplateDataByNode } from '@/lib/nodes'; +import { getSiteMetadata } from '@/lib/site'; import { default as TemplatePage } from '@/templates/page'; import { default as TemplatePost } from '@/templates/post'; @@ -15,11 +16,11 @@ export default async function Page({ params = {} }) { let resolvedUri = null; - if ( uriNodes) { + if (uriNodes) { resolvedUri = uriNodes.join('/'); } - const node = await getNodeByUri(resolvedUri) + const node = await getNodeByUri(resolvedUri); if (!node || node.isRestricted) { notFound(); @@ -27,17 +28,16 @@ export default async function Page({ params = {} }) { const Component = templates[node.__typename] || templates.Page; const { template } = Component; - - const nodeData = await getTemplateDataByNode({ - template, - node - }); - const data = typeof template.transformer === 'function' ? template.transformer(nodeData?.data) : nodeData?.data; + const [nodeData, metadata] = await Promise.all([ + getTemplateDataByNode({ + template, + node, + }), + getSiteMetadata(), + ]); - const breadcrumbs = Array.isArray(data.ancestors) ? [...data.ancestors] : []; - - breadcrumbs.reverse(); + const data = typeof template.transformer === 'function' ? template.transformer(nodeData?.data) : nodeData?.data; - return ; -} \ No newline at end of file + return ; +} diff --git a/src/app/feed.xml/route.js b/src/app/feed.xml/route.js index 82b47e0b..5d8ca7a8 100644 --- a/src/app/feed.xml/route.js +++ b/src/app/feed.xml/route.js @@ -18,7 +18,7 @@ export async function GET() { language: metadata.language, pubDate: new Date(), }); - + posts.slice(0, MAX_POSTS).map((post) => { feed.item({ title: post.title, @@ -31,11 +31,9 @@ export async function GET() { }); }); - return new Response(feed.xml({ indent: true }), - { - headers: { - 'Content-Type': 'application/atom+xml; charset=utf-8', - }, - } - ); -} \ No newline at end of file + return new Response(feed.xml({ indent: true }), { + headers: { + 'Content-Type': 'application/atom+xml; charset=utf-8', + }, + }); +} diff --git a/src/app/layout.js b/src/app/layout.js index 1be0b453..6631f8af 100644 --- a/src/app/layout.js +++ b/src/app/layout.js @@ -45,12 +45,9 @@ export default function RootLayout({ children }) { - ) + ); } - - - // const helmetSettings = { // ...helmetSettingsFromMetadata(metadata, { @@ -87,4 +84,4 @@ export default function RootLayout({ children }) { // }, // ], // }), -// }; \ No newline at end of file +// }; diff --git a/src/app/page.js b/src/app/page.js index 8739d2a5..834eae95 100644 --- a/src/app/page.js +++ b/src/app/page.js @@ -10,16 +10,16 @@ import JSONLD from '@/components/JSONLD'; import styles from '@/styles/pages/Home.module.scss'; -export default async function Home() { +export default async function Home() { const [metadata, { posts, pagination }] = await Promise.all([ getSiteMetadata(), getPaginatedPosts({ queryIncludes: 'archive', - }) + }), ]); pagination.basePath = '/posts'; - + return ( <>
@@ -40,7 +40,7 @@ export default async function Home() {

Posts

- +
    {posts.map((post) => { return ( @@ -62,18 +62,21 @@ export default async function Home() {
- + - ) + ); } diff --git a/src/app/robots.js b/src/app/robots.js index 9e10ed0e..81f37b38 100644 --- a/src/app/robots.js +++ b/src/app/robots.js @@ -5,8 +5,8 @@ export default async function robots() { return { rules: { - userAgent: '*' + userAgent: '*', }, - sitemap: `${metadata.url}/sitemap.xml` + sitemap: `${metadata.url}/sitemap.xml`, }; -} \ No newline at end of file +} diff --git a/src/app/sitemap.js b/src/app/sitemap.js index c5631fcc..1fd393ad 100644 --- a/src/app/sitemap.js +++ b/src/app/sitemap.js @@ -10,15 +10,15 @@ export default async function sitemap() { const pages = allPages.map(({ modified, uri }) => { return { url: `${metadata.url}${uri}`, - lastModified: modified - } + lastModified: modified, + }; }); const posts = allPosts.map(({ modified, uri }) => { return { url: `${metadata.url}${uri}`, - lastModified: modified - } + lastModified: modified, + }; }); return [ @@ -27,6 +27,6 @@ export default async function sitemap() { lastModified: new Date(), }, ...pages, - ...posts + ...posts, ]; -} \ No newline at end of file +} diff --git a/src/app/wp-search.json/route.js b/src/app/wp-search.json/route.js index 0d9bac41..ccd65c01 100644 --- a/src/app/wp-search.json/route.js +++ b/src/app/wp-search.json/route.js @@ -15,7 +15,7 @@ export async function GET() { return { title, date: post.date, - url: post.uri + url: post.uri, }; }); @@ -30,4 +30,4 @@ export async function GET() { }, } ); -} \ No newline at end of file +} diff --git a/src/components/FeaturedImage/FeaturedImage.js b/src/components/FeaturedImage/FeaturedImage.js index e02698ee..01c69439 100644 --- a/src/components/FeaturedImage/FeaturedImage.js +++ b/src/components/FeaturedImage/FeaturedImage.js @@ -5,7 +5,7 @@ import styles from './FeaturedImage.module.scss'; const FeaturedImage = ({ data, ...props }) => { let className = styles.featuredImage; - if ( props.className ) { + if (props.className) { className = `${className} ${props.className}`; } @@ -23,4 +23,4 @@ const FeaturedImage = ({ data, ...props }) => { ); }; -export default FeaturedImage; \ No newline at end of file +export default FeaturedImage; diff --git a/src/components/Footer/Footer.js b/src/components/Footer/Footer.js index 3e6e1309..f138b184 100644 --- a/src/components/Footer/Footer.js +++ b/src/components/Footer/Footer.js @@ -1,7 +1,7 @@ import Link from 'next/link'; import { getSiteMetadata } from '@/lib/site'; -import { getRecentPosts, postPathBySlug } from '@/lib/posts'; +import { getRecentPosts } from '@/lib/posts'; import { getCategories, categoryPathBySlug } from '@/lib/categories'; import Section from '@/components/Section'; @@ -15,10 +15,10 @@ async function Footer() { getRecentPosts({ count: 5, queryIncludes: 'index', - }), + }), getCategories({ count: 5, - }) + }), ]); const { title } = metadata; @@ -40,10 +40,10 @@ async function Footer() {
    {recentPosts.map((post) => { - const { id, slug, title } = post; + const { id, uri, title } = post; return (
  • - {title} + {title}
  • ); })} @@ -94,6 +94,6 @@ async function Footer() { ); -}; +} export default Footer; diff --git a/src/components/JSONLD/JSONLD.js b/src/components/JSONLD/JSONLD.js index b910f3e3..47137495 100644 --- a/src/components/JSONLD/JSONLD.js +++ b/src/components/JSONLD/JSONLD.js @@ -1,4 +1,4 @@ -const JSONLD = ({ data, metadata }) => { +const JSONLD = ({ data = {}, metadata = {} }) => { return ( - - ); -} - export function WebpageJsonLd({ title = '', description = '', siteTitle = '', slug = '' }) { const { homepage = '' } = config; const path = pagePathBySlug(slug); diff --git a/src/lib/menus.js b/src/lib/menus.js index 93d2d81e..01eb9791 100644 --- a/src/lib/menus.js +++ b/src/lib/menus.js @@ -12,7 +12,7 @@ export async function getMenuItemsByLocation(location) { const data = await apolloClient.query({ query: gql` query MenuItemsByLocation($location: MenuLocationEnum) { - menuItems(where: {location: $location}) { + menuItems(where: { location: $location }) { nodes { key: id parentId @@ -23,21 +23,21 @@ export async function getMenuItemsByLocation(location) { } `, variables: { - location - } + location, + }, }); const { nodes } = data.data.menuItems; - const topLevelItem = nodes.filter(({ parentId }) => !parentId) + const topLevelItem = nodes.filter(({ parentId }) => !parentId); - const menuItems = topLevelItem.map(item => { - const children = nodes.filter(node => node.parentId === item.key); + const menuItems = topLevelItem.map((item) => { + const children = nodes.filter((node) => node.parentId === item.key); return { ...item, - children - } + children, + }; }); return menuItems; -} \ No newline at end of file +} diff --git a/src/lib/nodes.js b/src/lib/nodes.js index 4e47da76..8bb3e57d 100644 --- a/src/lib/nodes.js +++ b/src/lib/nodes.js @@ -1,16 +1,12 @@ -import { gql } from '@apollo/client'; - -import { getApolloClient } from '@/lib/apollo-client'; +import { gql } from '@/lib/request'; /** * getNodeByUri */ export async function getNodeByUri(uri) { - const apolloClient = await getApolloClient(); - - const data = await apolloClient.query({ - query: gql` + const data = await gql({ + query: ` query GetNode($uri: String!) { nodeByUri(uri: $uri) { __typename @@ -75,9 +71,6 @@ export async function getNodeByUri(uri) { variables: { uri, }, - possibleTypes: { - Node: ['Category', 'ContentType', 'Page', 'Post', 'User'], - }, }); return data.data.nodeByUri; @@ -88,10 +81,8 @@ export async function getNodeByUri(uri) { */ export async function getTemplateDataByNode({ node, template }) { - const apolloClient = await getApolloClient(); - return apolloClient.query({ + return gql({ query: template.query, variables: template.variables(node), }); } - diff --git a/src/lib/posts.js b/src/lib/posts.js index 759870b9..5ab5b545 100644 --- a/src/lib/posts.js +++ b/src/lib/posts.js @@ -18,14 +18,6 @@ import { QUERY_POST_PER_PAGE, } from 'data/posts'; -/** - * postPathBySlug - */ - -export function postPathBySlug(slug) { - return `/posts/${slug}`; -} - /** * getPostBySlug */ @@ -322,7 +314,7 @@ export async function getRelatedPosts(categories, postId, count = 5) { const filtered = posts.filter(({ postId: id }) => id !== postId); const sorted = sortObjectsByDate(filtered); - related.posts = sorted.map((post) => ({ title: post.title, slug: post.slug })); + related.posts = sorted.map((post) => ({ title: post.title, uri: post.uri })); } if (!Array.isArray(related.posts) || related.posts.length === 0) { @@ -334,6 +326,8 @@ export async function getRelatedPosts(categories, postId, count = 5) { return related.posts.slice(0, count); } + console.log('related', related); + return related; } diff --git a/src/lib/request.js b/src/lib/request.js new file mode 100644 index 00000000..4916da52 --- /dev/null +++ b/src/lib/request.js @@ -0,0 +1,21 @@ +import { removeLastTrailingSlash } from '@/lib/util'; + +export async function gql({ query, variables }) { + const url = removeLastTrailingSlash(process.env.WORDPRESS_GRAPHQL_ENDPOINT); + + const data = await fetch(url, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + query, + variables, + }), + next: { + tags: [query], + }, + }).then((r) => r.json()); + + return data; +} diff --git a/src/lib/site.js b/src/lib/site.js index 33fa0fe7..f429bf81 100644 --- a/src/lib/site.js +++ b/src/lib/site.js @@ -1,4 +1,4 @@ -import { getApolloClient } from '@/lib/apollo-client'; +import { gql } from '@/lib/request'; import { decodeHtmlEntities, removeExtraSpaces } from '@/lib/util'; @@ -9,16 +9,13 @@ import { QUERY_SITE_DATA, QUERY_SEO_DATA } from 'data/site'; */ export async function getSiteMetadata() { - const apolloClient = getApolloClient(); - let siteData; let seoData; try { - siteData = await apolloClient.query({ + siteData = await gql({ query: QUERY_SITE_DATA, }); - console.log('siteData', siteData) } catch (e) { console.log(`[site][getSiteMetadata] Failed to query site data: ${e.message}`); throw e; @@ -29,7 +26,7 @@ export async function getSiteMetadata() { const settings = { ...generalSettings, - url: process.env.WORDPRESS_SITE_URL + url: process.env.WORDPRESS_SITE_URL, }; // It looks like the value of `language` when US English is set @@ -48,7 +45,7 @@ export async function getSiteMetadata() { // if (process.env.WORDPRESS_PLUGIN_SEO === true) { // try { - // seoData = await apolloClient.query({ + // seoData = await gql({ // query: QUERY_SEO_DATA, // }); // } catch (e) { diff --git a/src/lib/users.js b/src/lib/users.js index 45cd3905..43777593 100644 --- a/src/lib/users.js +++ b/src/lib/users.js @@ -32,7 +32,7 @@ export async function getUserBySlug(slug) { export function authorPathByName(name) { // @TODO - console.warn('authorPathByName UPDATE TO NODE URI') + console.warn('authorPathByName UPDATE TO NODE URI'); return `/authors/${name}`; } @@ -44,7 +44,7 @@ export async function getUserByNameSlug(name) { const { users } = await getAllUsers(); // @TODO - console.warn('getUserByNameSlug fix match') + console.warn('getUserByNameSlug fix match'); // const user = users.find((user) => parameterize(user.name) === name); return { @@ -58,7 +58,7 @@ export async function getUserByNameSlug(name) { export function userSlugByName(name) { // @TODO - console.warn('userSlugByName FIX NODE URI') + console.warn('userSlugByName FIX NODE URI'); return name; } diff --git a/src/pages.original/[slugParent]/[[...slugChild]].js b/src/pages.original/[slugParent]/[[...slugChild]].js deleted file mode 100644 index 0c5ffd06..00000000 --- a/src/pages.original/[slugParent]/[[...slugChild]].js +++ /dev/null @@ -1,176 +0,0 @@ -import Link from 'next/link'; -import { Helmet } from 'react-helmet'; - -import { getPageByUri, getAllPages, getBreadcrumbsByUri } from '@/lib/pages'; -import { WebpageJsonLd } from '@/lib/json-ld'; -import { helmetSettingsFromMetadata } from '@/lib/site'; -import useSite from '@/hooks/use-site'; -import usePageMetadata from 'hooks/use-page-metadata'; - -import Layout from '@/components/Layout'; -import Header from '@/components/Header'; -import Content from '@/components/Content'; -import Section from '@/components/Section'; -import Container from '@/components/Container'; -import FeaturedImage from '@/components/FeaturedImage'; -import Breadcrumbs from '@/components/Breadcrumbs'; - -import styles from '@/styles/pages/Page.module.scss'; - -export default function Page({ page, breadcrumbs }) { - const { title, metaTitle, description, slug, content, featuredImage, children } = page; - - const { metadata: siteMetadata = {} } = useSite(); - - const { metadata } = usePageMetadata({ - metadata: { - ...page, - title: metaTitle, - description: description || page.og?.description || `Read more about ${title}`, - }, - }); - - if (process.env.WORDPRESS_PLUGIN_SEO !== true) { - metadata.title = `${title} - ${siteMetadata.title}`; - metadata.og.title = metadata.title; - metadata.twitter.title = metadata.title; - } - - const hasChildren = Array.isArray(children) && children.length > 0; - const hasBreadcrumbs = Array.isArray(breadcrumbs) && breadcrumbs.length > 0; - - const helmetSettings = helmetSettingsFromMetadata(metadata); - - return ( - - - - - -
    - {hasBreadcrumbs && } - {featuredImage && ( - - )} -

    {title}

    -
    - - -
    - -
    - -
    - - {hasChildren && ( -
    - - - -
    - )} -
    -
    - ); -} - -export async function getStaticProps({ params = {} } = {}) { - const { slugParent, slugChild } = params; - - // We can use the URI to look up our page and subsequently its ID, so - // we can first contruct our URI from the page params - - let pageUri = `/${slugParent}/`; - - // We only want to apply deeper paths to the URI if we actually have - // existing children - - if (Array.isArray(slugChild) && slugChild.length > 0) { - pageUri = `${pageUri}${slugChild.join('/')}/`; - } - - const { page } = await getPageByUri(pageUri); - - if (!page) { - return { - props: {}, - notFound: true, - }; - } - - // In order to show the proper breadcrumbs, we need to find the entire - // tree of pages. Rather than querying every segment, the query should - // be cached for all pages, so we can grab that and use it to create - // our trail - - const { pages } = await getAllPages({ - queryIncludes: 'index', - }); - - const breadcrumbs = getBreadcrumbsByUri(pageUri, pages); - - return { - props: { - page, - breadcrumbs, - }, - }; -} - -export async function getStaticPaths() { - const { pages } = await getAllPages({ - queryIncludes: 'index', - }); - - // Take all the pages and create path params. The slugParent will always be - // the top level parent page, where the slugChild will be an array of the - // remaining segments to make up the path or URI - - // We also filter out the `/` homepage as it will conflict with index.js if - // as they have the same path, which will fail the build - - const paths = pages - .filter(({ uri }) => typeof uri === 'string' && uri !== '/') - .map(({ uri }) => { - const segments = uri.split('/').filter((seg) => seg !== ''); - - return { - params: { - slugParent: segments.shift(), - slugChild: segments, - }, - }; - }); - - return { - paths, - fallback: 'blocking', - }; -} diff --git a/src/pages.original/_app.js b/src/pages.original/_app.js deleted file mode 100644 index 450fe8bf..00000000 --- a/src/pages.original/_app.js +++ /dev/null @@ -1,51 +0,0 @@ -import NextApp from 'next/app'; - -import { SiteContext, useSiteContext } from '@/hooks/use-site'; -import { SearchProvider } from 'hooks/use-search'; - -import { getSiteMetadata } from '@/lib/site'; -import { getRecentPosts } from '@/lib/posts'; -import { getCategories } from '@/lib/categories'; - -import 'styles/globals.scss'; -import 'styles/wordpress.scss'; - -function App({ Component, pageProps = {}, metadata, recentPosts, categories }) { - const site = useSiteContext({ - metadata, - recentPosts, - categories, - menus, - }); - - return ( - - - - - - ); -} - -App.getInitialProps = async function (appContext) { - const appProps = await NextApp.getInitialProps(appContext); - - const { posts: recentPosts } = await getRecentPosts({ - count: 5, - queryIncludes: 'index', - }); - - const { categories } = await getCategories({ - count: 5, - }); - - - return { - ...appProps, - metadata: await getSiteMetadata(), - recentPosts, - categories, - }; -}; - -export default App; diff --git a/src/pages.original/_document.js b/src/pages.original/_document.js deleted file mode 100644 index ca763ea8..00000000 --- a/src/pages.original/_document.js +++ /dev/null @@ -1,43 +0,0 @@ -/* eslint-disable @next/next/no-document-import-in-page */ -import Document, { Html, Head, Main, NextScript } from 'next/document'; -import { Helmet } from 'react-helmet'; - -// Via https://github.com/vercel/next.js/blob/canary/examples/with-react-helmet/pages/_document.js - -export default class MyDocument extends Document { - static async getInitialProps(...args) { - const documentProps = await super.getInitialProps(...args); - // see https://github.com/nfl/react-helmet#server-usage for more information - // 'head' was occupied by 'renderPage().head', we cannot use it - return { ...documentProps, helmet: Helmet.renderStatic() }; - } - - // should render on - get helmetHtmlAttrComponents() { - return this.props.helmet.htmlAttributes.toComponent(); - } - - // should render on - get helmetBodyAttrComponents() { - return this.props.helmet.bodyAttributes.toComponent(); - } - - // should render on - get helmetHeadComponents() { - return Object.keys(this.props.helmet) - .filter((el) => el !== 'htmlAttributes' && el !== 'bodyAttributes') - .map((el) => this.props.helmet[el].toComponent()); - } - - render() { - return ( - - {this.helmetHeadComponents} - -
    - - - - ); - } -} diff --git a/src/pages.original/posts/[slug].js b/src/pages.original/posts/[slug].js deleted file mode 100644 index 8db92c67..00000000 --- a/src/pages.original/posts/[slug].js +++ /dev/null @@ -1,198 +0,0 @@ -import Link from 'next/link'; -import { Helmet } from 'react-helmet'; - -import { getPostBySlug, getRecentPosts, getRelatedPosts, postPathBySlug } from '@/lib/posts'; -import { categoryPathBySlug } from '@/lib/categories'; -import { formatDate } from '@/lib/datetime'; -import { ArticleJsonLd } from '@/lib/json-ld'; -import { helmetSettingsFromMetadata } from '@/lib/site'; -import useSite from '@/hooks/use-site'; -import usePageMetadata from 'hooks/use-page-metadata'; - -import Layout from '@/components/Layout'; -import Header from '@/components/Header'; -import Section from '@/components/Section'; -import Container from '@/components/Container'; -import Content from '@/components/Content'; -import Metadata from '@/components/Metadata'; -import FeaturedImage from '@/components/FeaturedImage'; - -import styles from '@/styles/pages/Post.module.scss'; - -export default function Post({ post, socialImage, related }) { - const { - title, - metaTitle, - description, - content, - date, - author, - categories, - modified, - featuredImage, - isSticky = false, - } = post; - - const { metadata: siteMetadata = {}, homepage } = useSite(); - - if (!post.og) { - post.og = {}; - } - - post.og.imageUrl = `${homepage}${socialImage}`; - post.og.imageSecureUrl = post.og.imageUrl; - post.og.imageWidth = 2000; - post.og.imageHeight = 1000; - - const { metadata } = usePageMetadata({ - metadata: { - ...post, - title: metaTitle, - description: description || post.og?.description || `Read more about ${title}`, - }, - }); - - if (process.env.WORDPRESS_PLUGIN_SEO !== true) { - metadata.title = `${title} - ${siteMetadata.title}`; - metadata.og.title = metadata.title; - metadata.twitter.title = metadata.title; - } - - const metadataOptions = { - compactCategories: false, - }; - - const { posts: relatedPostsList, title: relatedPostsTitle } = related || {}; - - const helmetSettings = helmetSettingsFromMetadata(metadata); - - return ( - - - - - -
    - {featuredImage && ( - - )} -

    - -

    - - -
    - -
    - -
    -
    - -
    - -

    Last updated on {formatDate(modified)}.

    - {Array.isArray(relatedPostsList) && relatedPostsList.length > 0 && ( -
    - {relatedPostsTitle.name ? ( - - More from {relatedPostsTitle.name} - - ) : ( - More Posts - )} -
      - {relatedPostsList.map((post) => ( -
    • - {post.title} -
    • - ))} -
    -
    - )} -
    -
    -
    - ); -} - -export async function getStaticProps({ params = {} } = {}) { - const { post } = await getPostBySlug(params?.slug); - - if (!post) { - return { - props: {}, - notFound: true, - }; - } - - const { categories, databaseId: postId } = post; - - const props = { - post, - socialImage: `${process.env.OG_IMAGE_DIRECTORY}/${params?.slug}.png`, - }; - - const { category: relatedCategory, posts: relatedPosts } = (await getRelatedPosts(categories, postId)) || {}; - const hasRelated = relatedCategory && Array.isArray(relatedPosts) && relatedPosts.length; - - if (hasRelated) { - props.related = { - posts: relatedPosts, - title: { - name: relatedCategory.name || null, - link: categoryPathBySlug(relatedCategory.slug), - }, - }; - } - - return { - props, - }; -} - -export async function getStaticPaths() { - // Only render the most recent posts to avoid spending unecessary time - // querying every single post from WordPress - - // Tip: this can be customized to use data or analytitcs to determine the - // most popular posts and render those instead - - const { posts } = await getRecentPosts({ - count: process.env.POSTS_PRERENDER_COUNT, // Update this value in next.config.js! - queryIncludes: 'index', - }); - - const paths = posts - .filter(({ slug }) => typeof slug === 'string') - .map(({ slug }) => ({ - params: { - slug, - }, - })); - - return { - paths, - fallback: 'blocking', - }; -} diff --git a/src/templates/page.js b/src/templates/page.js index 9f755229..12da9678 100644 --- a/src/templates/page.js +++ b/src/templates/page.js @@ -1,7 +1,6 @@ import Link from 'next/link'; -import { gql } from '@apollo/client'; -import { getSiteMetadata } from '@/lib/site'; +import { getAllPages, getBreadcrumbsByUri } from '@/lib/pages'; import Section from '@/components/Section'; import Container from '@/components/Container'; @@ -11,19 +10,19 @@ import FeaturedImage from '@/components/FeaturedImage'; import Breadcrumbs from '@/components/Breadcrumbs'; import JSONLD from '@/components/JSONLD'; -// import { WebpageJsonLd } from '@/lib/json-ld'; -// import { helmetSettingsFromMetadata } from '@/lib/site'; -// import usePageMetadata from 'hooks/use-page-metadata'; - import styles from '@/styles/pages/Page.module.scss'; -export default async function Page({ data, breadcrumbs }) { - const { children, content, description, featuredImage, metaTitle, title, uri } = data; +export default async function Page({ data, metadata }) { + const { children, content, description, featuredImage, title, uri } = data; - const metadata = await getSiteMetadata(); + const [{ pages }] = await Promise.all([ + getAllPages({ + queryIncludes: 'index', + }), + ]); const hasChildren = Array.isArray(children) && children.length > 0; - console.log('data', data) + const breadcrumbs = getBreadcrumbsByUri(uri, pages); // const { metadata } = usePageMetadata({ // metadata: { @@ -41,14 +40,11 @@ export default async function Page({ data, breadcrumbs }) { // metadata.twitter.title = metadata.title; // } - return ( <>
    {Array.isArray(breadcrumbs) && } - {featuredImage && ( - - )} + {featuredImage && }

    {title}

    @@ -75,9 +71,7 @@ export default async function Page({ data, breadcrumbs }) { {children.map((child) => { return (
  • - - {child.title} - + {child.title}
  • ); })} @@ -102,7 +96,7 @@ export default async function Page({ data, breadcrumbs }) { } Page.template = { - query: gql` + query: ` query PageByUri($uri: ID!) { page(id: $uri, idType: URI) { children { @@ -170,4 +164,4 @@ Page.template = { uri, }; }, -}; \ No newline at end of file +}; diff --git a/src/templates/post.js b/src/templates/post.js index 069a9a8e..317c1217 100644 --- a/src/templates/post.js +++ b/src/templates/post.js @@ -1,38 +1,50 @@ -import { gql } from '@apollo/client'; +import Link from 'next/link'; + +import { getRelatedPosts } from '@/lib/posts'; +import { categoryPathBySlug } from '@/lib/categories'; +import { formatDate } from '@/lib/datetime'; +import { updateUserAvatar } from '@/lib/users'; import Section from '@/components/Section'; import Container from '@/components/Container'; +import Header from '@/components/Header'; +import Content from '@/components/Content'; +import FeaturedImage from '@/components/FeaturedImage'; +import Metadata from '@/components/Metadata'; +import JSONLD from '@/components/JSONLD'; -// import Link from 'next/link'; -// import { Helmet } from 'react-helmet'; - -// import { WebpageJsonLd } from '@/lib/json-ld'; -// import { helmetSettingsFromMetadata } from '@/lib/site'; -// import useSite from 'hooks/use-site'; -// import usePageMetadata from 'hooks/use-page-metadata'; +import styles from '@/styles/pages/Post.module.scss'; -// import Layout from '@/components/Layout'; -// import Header from '@/components/Header'; -// import Content from '@/components/Content'; +export default async function Post({ data, metadata }) { + const { author, categories, content, date, excerpt, id, isSticky = false, featuredImage, modified, title } = data; -// import FeaturedImage from '@/components/FeaturedImage'; -// import Breadcrumbs from '@/components/Breadcrumbs'; + const datePublished = new Date(date); + const dateModified = modified ? new Date(modified) : new Date(date); -import { QUERY_PAGE_BY_URI } from '@/data/pages'; + const [{ category: relatedCategory, posts: relatedPosts }] = await Promise.all([getRelatedPosts(categories, id)]); -import styles from '@/styles/pages/Page.module.scss'; + let related; -export default function Page({ data: page, breadcrumbs }) { - console.log('page', page) - const { children, content, description, featuredImage, metaTitle, slug, title } = page; + if (relatedCategory && Array.isArray(relatedPosts) && relatedPosts.length) { + related = { + posts: relatedPosts, + title: { + name: relatedCategory.name || null, + link: categoryPathBySlug(relatedCategory.slug), + }, + }; + } - // const { metadata: siteMetadata = {} } = useSite(); + // post.og.imageUrl = `${homepage}${socialImage}`; + // post.og.imageSecureUrl = post.og.imageUrl; + // post.og.imageWidth = 2000; + // post.og.imageHeight = 1000; // const { metadata } = usePageMetadata({ // metadata: { - // ...page, + // ...post, // title: metaTitle, - // description: description || page.og?.description || `Read more about ${title}`, + // description: description || post.og?.description || `Read more about ${title}`, // }, // }); @@ -42,150 +54,177 @@ export default function Page({ data: page, breadcrumbs }) { // metadata.twitter.title = metadata.title; // } - // const hasChildren = Array.isArray(children) && children.length > 0; - - // const helmetSettings = helmetSettingsFromMetadata(metadata); - return ( -
    - -
    +
    + {featuredImage && } +

    + - -

    - ) - - // return ( - // - // - - // - - //
    - // {Array.isArray(breadcrumbs) && } - // {featuredImage && ( - // - // )} - //

    {title}

    - //
    - - // - //
    - // - //
    - // - //
    - - // {hasChildren && ( - //
    - // - // - // - //
    - // )} - //
    - //
    - // ); +
+ + +
+ +
+ +
+
+ +
+ +

Last updated on {formatDate(modified)}.

+ {Array.isArray(related?.posts) && related.posts.length > 0 && ( +
+ {related.title?.name ? ( + + More from {related.title.name} + + ) : ( + More Posts + )} +
    + {related.posts.map((post) => ( +
  • + {post.title} +
  • + ))} +
+
+ )} +
+
+ + `${name}`), + copyrightYear: datePublished.getFullYear(), + author: { + '@type': 'Person', + name: author?.name, + }, + }} + metadata={metadata} + /> + + ); } -Page.template = { - query: gql` - query PageByUri($uri: ID!) { - page(id: $uri, idType: URI) { - children { +Post.template = { + query: ` + query PostByUri($uri: ID!) { + post(id: $uri, idType: URI) { + author { + node { + avatar { + height + url + width + } + id + name + slug + } + } + id + categories { edges { node { + databaseId id + name slug - uri - ... on Page { - id - title - } } } } content + date + excerpt featuredImage { node { altText caption - id - sizes + mediaDetails { + height + width + } sourceUrl srcSet - } - } - id - menuOrder - parent { - node { + sizes id - slug - uri - ... on Page { - title - } } } - slug + modified + databaseId title - uri + slug + isSticky } } `, transformer: (data) => { - const page = { ...data.page }; + const post = { ...data.post }; + + // Clean up the author object to avoid someone having to look an extra + // level deeper into the node + + if (post.author) { + post.author = { + ...post.author.node, + }; + } + + // The URL by default that comes from Gravatar / WordPress is not a secure + // URL. This ends up redirecting to https, but it gives mixed content warnings + // as the HTML shows it as http. Replace the url to avoid those warnings + // and provide a secure URL by default - if (page.featuredImage) { - page.featuredImage = page.featuredImage.node; + if (post.author?.avatar) { + post.author.avatar = updateUserAvatar(post.author.avatar); } - if (page.parent) { - page.parent = page.parent.node; + // Clean up the categories to make them more easy to access + + if (post.categories) { + post.categories = post.categories.edges.map(({ node }) => node); } - if (page.children) { - page.children = page.children.edges.map(({ node }) => node); + // Clean up the featured image to make them more easy to access + + if (post.featuredImage) { + post.featuredImage = post.featuredImage.node; } - return page; + return post; }, variables: ({ uri }) => { return { uri, }; }, -}; \ No newline at end of file +}; From 2c7cf7f02494db756d885687b448fa7a6cbf8fb9 Mon Sep 17 00:00:00 2001 From: Colby Fayock Date: Sun, 7 May 2023 21:47:43 -0400 Subject: [PATCH 05/11] author page --- package.json | 1 - pnpm-lock.yaml | 11 +- src/app/[...uriNodes]/page.js | 19 ++- src/app/layout.js | 3 +- src/app/wp-search.json/route.js | 2 +- src/components/Metadata/Metadata.js | 3 +- src/components/Nav/Nav.module.scss | 2 - src/components/NavSearch/NavSearch.js | 9 +- .../NavSearch/NavSearch.module.scss | 4 +- src/components/Pagination/Pagination.js | 2 +- src/data/posts.js | 64 +------ src/data/users.js | 55 ------ src/hooks/use-search.js | 70 +++----- src/lib/datetime.js | 2 - src/lib/json-ld.js | 22 --- src/lib/posts.js | 43 +---- src/lib/site.js | 5 +- src/lib/users.js | 155 ----------------- src/pages.original/authors/[slug].js | 91 ---------- ...Archive.module.scss => Author.module.scss} | 0 .../{pages => templates}/Page.module.scss | 0 .../{pages => templates}/Post.module.scss | 0 src/templates/author.js | 157 ++++++++++++++++++ src/templates/page.js | 2 +- src/templates/post.js | 4 +- 25 files changed, 216 insertions(+), 510 deletions(-) delete mode 100644 src/data/users.js delete mode 100644 src/pages.original/authors/[slug].js rename src/styles/templates/{Archive.module.scss => Author.module.scss} (100%) rename src/styles/{pages => templates}/Page.module.scss (100%) rename src/styles/{pages => templates}/Post.module.scss (100%) create mode 100644 src/templates/author.js diff --git a/package.json b/package.json index b8994d0f..fbb95cd9 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,6 @@ }, "dependencies": { "@apollo/client": "^3.7.14", - "date-fns": "^2.30.0", "fuse.js": "^6.6.2", "graphql": "^16.6.0", "he": "^1.2.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0953c5a0..79a68df6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,7 +4,6 @@ specifiers: '@apollo/client': ^3.7.14 '@types/node': 20.0.0 '@types/react': 18.2.5 - date-fns: ^2.30.0 dotenv: ^16.0.3 eslint: 8.39.0 eslint-config-next: ^13.4.0 @@ -28,7 +27,6 @@ specifiers: dependencies: '@apollo/client': 3.7.14_gdcq4dv6opitr3wbfwyjmanyra - date-fns: 2.30.0 fuse.js: 6.6.2 graphql: 16.6.0 he: 1.2.0 @@ -97,6 +95,7 @@ packages: engines: {node: '>=6.9.0'} dependencies: regenerator-runtime: 0.13.11 + dev: true /@eslint-community/eslint-utils/4.4.0_eslint@8.39.0: resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} @@ -723,13 +722,6 @@ packages: resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} dev: true - /date-fns/2.30.0: - resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==} - engines: {node: '>=0.11'} - dependencies: - '@babel/runtime': 7.21.5 - dev: false - /debug/3.2.7: resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} peerDependencies: @@ -2372,6 +2364,7 @@ packages: /regenerator-runtime/0.13.11: resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} + dev: true /regexp.prototype.flags/1.5.0: resolution: {integrity: sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==} diff --git a/src/app/[...uriNodes]/page.js b/src/app/[...uriNodes]/page.js index 9b542377..4e4a86de 100644 --- a/src/app/[...uriNodes]/page.js +++ b/src/app/[...uriNodes]/page.js @@ -3,26 +3,29 @@ import { notFound } from 'next/navigation'; import { getNodeByUri, getTemplateDataByNode } from '@/lib/nodes'; import { getSiteMetadata } from '@/lib/site'; +import { default as TemplateAuthor } from '@/templates/author'; import { default as TemplatePage } from '@/templates/page'; import { default as TemplatePost } from '@/templates/post'; const templates = { + User: TemplateAuthor, Page: TemplatePage, Post: TemplatePost, }; -export default async function Page({ params = {} }) { - const { uriNodes } = params; - - let resolvedUri = null; +// By default, certain pages like the User type pages restrict +// public access, but for the use case, users are authors +// and without custom functionality, wouldn't be able to +// display, hence the bypass option for types +// @TODO add section to readme explaining, add to nextconfig? - if (uriNodes) { - resolvedUri = uriNodes.join('/'); - } +const bypassRestricted = ['User']; +export default async function Page({ params = {} }) { + const resolvedUri = params.uriNodes ? params.uriNodes.join('/') : null; const node = await getNodeByUri(resolvedUri); - if (!node || node.isRestricted) { + if (!node || (node.isRestricted && !bypassRestricted.includes(node.__typename))) { notFound(); } diff --git a/src/app/layout.js b/src/app/layout.js index 6631f8af..bd8fa028 100644 --- a/src/app/layout.js +++ b/src/app/layout.js @@ -7,7 +7,8 @@ import Footer from '@/components/Footer'; import '@/styles/globals.scss'; import styles from '@/styles/layout.module.scss'; -export async function generateMetadata({ params, searchParams }, parent) { +// export async function generateMetadata({ params, searchParams }, parent) { +export async function generateMetadata() { const metadata = await getSiteMetadata(); return { diff --git a/src/app/wp-search.json/route.js b/src/app/wp-search.json/route.js index ccd65c01..30dee4de 100644 --- a/src/app/wp-search.json/route.js +++ b/src/app/wp-search.json/route.js @@ -15,7 +15,7 @@ export async function GET() { return { title, date: post.date, - url: post.uri, + uri: post.uri, }; }); diff --git a/src/components/Metadata/Metadata.js b/src/components/Metadata/Metadata.js index 531ebad1..6ba99dde 100644 --- a/src/components/Metadata/Metadata.js +++ b/src/components/Metadata/Metadata.js @@ -1,7 +1,6 @@ import Link from 'next/link'; import { categoryPathBySlug } from '@/lib/categories'; -import { authorPathByName } from '@/lib/users'; import { formatDate } from '@/lib/datetime'; import ClassName from 'models/classname'; @@ -33,7 +32,7 @@ const Metadata = ({ className, author, date, categories, options = DEFAULT_METAD /> )} By{' '} - + {author.name} diff --git a/src/components/Nav/Nav.module.scss b/src/components/Nav/Nav.module.scss index 97bd87b1..e32fd670 100644 --- a/src/components/Nav/Nav.module.scss +++ b/src/components/Nav/Nav.module.scss @@ -1,7 +1,6 @@ @import "styles/settings/__settings"; .nav { - width: 100%; border-bottom: 1px solid $color-gray-100; padding: 0 1rem; @@ -13,7 +12,6 @@ padding-bottom: 0; margin: 0; } - } .navSection { diff --git a/src/components/NavSearch/NavSearch.js b/src/components/NavSearch/NavSearch.js index d62bcec4..2e5e0f38 100644 --- a/src/components/NavSearch/NavSearch.js +++ b/src/components/NavSearch/NavSearch.js @@ -1,6 +1,7 @@ 'use client'; import { useState, useEffect, useCallback, useRef } from 'react'; +import Link from 'next/link'; import { FaSearch } from 'react-icons/fa'; import useSearch, { SEARCH_STATE_LOADED } from '@/hooks/use-search'; @@ -15,11 +16,7 @@ const NavSearch = () => { const [searchVisibility, setSearchVisibility] = useState(SEARCH_HIDDEN); - console.log('searchVisibility', searchVisibility); - - const { query, results, search, clearSearch, state } = {}; - - useSearch({ + const { query, results, search, clearSearch, state } = useSearch({ maxResults: 5, }); @@ -191,7 +188,7 @@ const NavSearch = () => {
    {results.map(({ uri, title }, index) => { return ( -
  • +
  • {title} diff --git a/src/components/NavSearch/NavSearch.module.scss b/src/components/NavSearch/NavSearch.module.scss index 329aef16..8934eef0 100644 --- a/src/components/NavSearch/NavSearch.module.scss +++ b/src/components/NavSearch/NavSearch.module.scss @@ -1,7 +1,6 @@ @import "styles/settings/__settings"; .navSearch { - form { display: flex; align-items: center; @@ -47,7 +46,6 @@ } } } - } .navSearchResults { @@ -99,4 +97,4 @@ } } } -} \ No newline at end of file +} diff --git a/src/components/Pagination/Pagination.js b/src/components/Pagination/Pagination.js index 65b54493..4671219b 100644 --- a/src/components/Pagination/Pagination.js +++ b/src/components/Pagination/Pagination.js @@ -6,7 +6,7 @@ import styles from './Pagination.module.scss'; const MAX_NUM_PAGES = 9; -const Pagination = ({ pagesCount, currentPage, basePath, addCanonical = true }) => { +const Pagination = ({ pagesCount, currentPage, basePath }) => { const path = `${basePath}/page/`; const hasPreviousPage = pagesCount > 1 && currentPage > 1; diff --git a/src/data/posts.js b/src/data/posts.js index 41b9706a..d876436d 100644 --- a/src/data/posts.js +++ b/src/data/posts.js @@ -53,7 +53,7 @@ export const QUERY_ALL_POSTS_ARCHIVE = gql` } id name - slug + uri } } excerpt @@ -79,7 +79,7 @@ export const QUERY_ALL_POSTS = gql` } id name - slug + uri } } content @@ -186,7 +186,7 @@ export const QUERY_POSTS_BY_CATEGORY_ID_ARCHIVE = gql` } id name - slug + uri } } excerpt @@ -212,7 +212,7 @@ export const QUERY_POSTS_BY_CATEGORY_ID = gql` } id name - slug + uri } } content @@ -238,62 +238,6 @@ export const QUERY_POSTS_BY_CATEGORY_ID = gql` } `; -export const QUERY_POSTS_BY_AUTHOR_SLUG_INDEX = gql` - ${POST_FIELDS} - query PostByAuthorSlugIndex($slug: String!) { - posts(where: { authorName: $slug, hasPassword: false }) { - edges { - node { - ...PostFields - } - } - } - } -`; - -export const QUERY_POSTS_BY_AUTHOR_SLUG_ARCHIVE = gql` - ${POST_FIELDS} - query PostByAuthorSlugArchive($slug: String!) { - posts(where: { authorName: $slug, hasPassword: false }) { - edges { - node { - ...PostFields - excerpt - } - } - } - } -`; - -export const QUERY_POSTS_BY_AUTHOR_SLUG = gql` - ${POST_FIELDS} - query PostByAuthorSlug($slug: String!) { - posts(where: { authorName: $slug, hasPassword: false }) { - edges { - node { - ...PostFields - excerpt - featuredImage { - node { - altText - caption - id - mediaDetails { - height - width - } - sizes - sourceUrl - srcSet - } - } - modified - } - } - } - } -`; - export const QUERY_POST_SEO_BY_SLUG = gql` query PostSEOBySlug($slug: ID!) { post(id: $slug, idType: SLUG) { diff --git a/src/data/users.js b/src/data/users.js deleted file mode 100644 index 6798d972..00000000 --- a/src/data/users.js +++ /dev/null @@ -1,55 +0,0 @@ -import { gql } from '@apollo/client'; - -export const QUERY_ALL_USERS = gql` - query AllUsers { - users(first: 10000) { - edges { - node { - avatar { - height - width - url - } - description - id - name - roles { - nodes { - name - } - } - slug - } - } - } - } -`; - -export const QUERY_ALL_USERS_SEO = gql` - query AllUsersSeo { - users(first: 10000) { - edges { - node { - id - seo { - metaDesc - metaRobotsNofollow - metaRobotsNoindex - title - social { - youTube - wikipedia - twitter - soundCloud - pinterest - mySpace - linkedIn - instagram - facebook - } - } - } - } - } - } -`; diff --git a/src/hooks/use-search.js b/src/hooks/use-search.js index a51ccdf2..b942155b 100644 --- a/src/hooks/use-search.js +++ b/src/hooks/use-search.js @@ -1,4 +1,6 @@ -import { useState, createContext, useContext, useEffect } from 'react'; +'use client'; + +import { useState, useEffect } from 'react'; import Fuse from 'fuse.js'; import { getSearchData } from '@/lib/search'; @@ -10,16 +12,10 @@ export const SEARCH_STATE_READY = 'READY'; export const SEARCH_STATE_ERROR = 'ERROR'; export const SEARCH_STATE_LOADED = 'LOADED'; -export const SearchContext = createContext(); - -export const SearchProvider = (props) => { - const search = useSearchState(); - return ; -}; - -export function useSearchState() { +export default function useSearch({ defaultQuery = null, maxResults } = {}) { const [state, setState] = useState(SEARCH_STATE_READY); const [data, setData] = useState(null); + const [query, setQuery] = useState(defaultQuery); let client; @@ -30,53 +26,40 @@ export function useSearchState() { }); } + let results = []; + + // If we have a query, make a search. Otherwise, don't modify the + // results to avoid passing back empty results + + if (client && query) { + results = client.search(query).map(({ item }) => item); + } + + if (maxResults && results.length > maxResults) { + results = results.slice(0, maxResults); + } + // On load, we want to immediately pull in the search index, which we're // storing clientside and gets built at compile time useEffect(() => { (async function getData() { setState(SEARCH_STATE_LOADING); - - let searchData; - try { - searchData = await getSearchData(); + const searchData = await getSearchData(); + setData(searchData); + setState(SEARCH_STATE_LOADED); } catch (e) { setState(SEARCH_STATE_ERROR); return; } - - setData(searchData); - setState(SEARCH_STATE_LOADED); })(); + return () => { + setData(undefined); + setState(SEARCH_STATE_READY); + }; }, []); - return { - state, - data, - client, - }; -} - -export default function useSearch({ defaultQuery = null, maxResults } = {}) { - const search = useContext(SearchContext); - const { client } = search || {}; - - const [query, setQuery] = useState(defaultQuery); - - let results = []; - - // If we have a query, make a search. Otherwise, don't modify the - // results to avoid passing back empty results - - if (client && query) { - results = client.search(query).map(({ item }) => item); - } - - if (maxResults && results.length > maxResults) { - results = results.slice(0, maxResults); - } - // If the defaultQuery argument changes, the hook should reflect // that update and set that as the new state @@ -99,7 +82,8 @@ export default function useSearch({ defaultQuery = null, maxResults } = {}) { } return { - ...search, + state, + data, query, results, search: handleSearch, diff --git a/src/lib/datetime.js b/src/lib/datetime.js index 3ccd9fd5..0fe4a46f 100644 --- a/src/lib/datetime.js +++ b/src/lib/datetime.js @@ -1,5 +1,3 @@ -import { format } from 'date-fns'; - /** * formatDate */ diff --git a/src/lib/json-ld.js b/src/lib/json-ld.js index 9aac33b5..90053b12 100644 --- a/src/lib/json-ld.js +++ b/src/lib/json-ld.js @@ -1,6 +1,5 @@ import { Helmet } from 'react-helmet'; -import { authorPathByName } from '@/lib/users'; import { pagePathBySlug } from '@/lib/pages'; import config from '../../package.json'; @@ -27,24 +26,3 @@ export function WebpageJsonLd({ title = '', description = '', siteTitle = '', sl ); } - -export function AuthorJsonLd({ author = {} }) { - const { homepage = '' } = config; - const { name, avatar, description } = author; - const path = authorPathByName(name); - - const jsonLd = { - '@context': 'https://schema.org', - '@type': 'Person', - name: name, - image: avatar?.url, - url: `${homepage}${path}`, - description: description, - }; - - return ( - - - - ); -} diff --git a/src/lib/posts.js b/src/lib/posts.js index 5ab5b545..55673c9e 100644 --- a/src/lib/posts.js +++ b/src/lib/posts.js @@ -8,9 +8,6 @@ import { QUERY_ALL_POSTS_ARCHIVE, QUERY_ALL_POSTS, QUERY_POST_BY_SLUG, - QUERY_POSTS_BY_AUTHOR_SLUG_INDEX, - QUERY_POSTS_BY_AUTHOR_SLUG_ARCHIVE, - QUERY_POSTS_BY_AUTHOR_SLUG, QUERY_POSTS_BY_CATEGORY_ID_INDEX, QUERY_POSTS_BY_CATEGORY_ID_ARCHIVE, QUERY_POSTS_BY_CATEGORY_ID, @@ -138,42 +135,6 @@ export async function getAllPosts(options = {}) { }; } -/** - * getPostsByAuthorSlug - */ - -const postsByAuthorSlugIncludesTypes = { - all: QUERY_POSTS_BY_AUTHOR_SLUG, - archive: QUERY_POSTS_BY_AUTHOR_SLUG_ARCHIVE, - index: QUERY_POSTS_BY_AUTHOR_SLUG_INDEX, -}; - -export async function getPostsByAuthorSlug({ slug, ...options }) { - const { queryIncludes = 'index' } = options; - - const apolloClient = getApolloClient(); - - let postData; - - try { - postData = await apolloClient.query({ - query: postsByAuthorSlugIncludesTypes[queryIncludes], - variables: { - slug, - }, - }); - } catch (e) { - console.log(`[posts][getPostsByAuthorSlug] Failed to query post data: ${e.message}`); - throw e; - } - - const posts = postData?.data.posts.edges.map(({ node = {} }) => node); - - return { - posts: Array.isArray(posts) && posts.map(mapPostData), - }; -} - /** * getPostsByCategoryId */ @@ -259,7 +220,7 @@ export function mapPostData(post = {}) { // Clean up the author object to avoid someone having to look an extra // level deeper into the node - + console.log('data.author', data.author); if (data.author) { data.author = { ...data.author.node, @@ -326,8 +287,6 @@ export async function getRelatedPosts(categories, postId, count = 5) { return related.posts.slice(0, count); } - console.log('related', related); - return related; } diff --git a/src/lib/site.js b/src/lib/site.js index f429bf81..e49a7eeb 100644 --- a/src/lib/site.js +++ b/src/lib/site.js @@ -2,7 +2,7 @@ import { gql } from '@/lib/request'; import { decodeHtmlEntities, removeExtraSpaces } from '@/lib/util'; -import { QUERY_SITE_DATA, QUERY_SEO_DATA } from 'data/site'; +import { QUERY_SITE_DATA } from 'data/site'; /** * getSiteMetadata @@ -10,7 +10,6 @@ import { QUERY_SITE_DATA, QUERY_SEO_DATA } from 'data/site'; export async function getSiteMetadata() { let siteData; - let seoData; try { siteData = await gql({ @@ -22,7 +21,7 @@ export async function getSiteMetadata() { } const { generalSettings } = siteData?.data || {}; - let { title, description, language } = generalSettings; + let { language } = generalSettings; const settings = { ...generalSettings, diff --git a/src/lib/users.js b/src/lib/users.js index 43777593..a7c322c6 100644 --- a/src/lib/users.js +++ b/src/lib/users.js @@ -1,158 +1,3 @@ -import { getApolloClient } from '@/lib/apollo-client'; - -import { QUERY_ALL_USERS, QUERY_ALL_USERS_SEO } from 'data/users'; - -// const ROLES_AUTHOR = ['author', 'administrator']; - -/** - * postPathBySlug - */ - -export function authorPathBySlug(slug) { - return `/authors/${slug}`; -} - -/** - * getUserBySlug - */ - -export async function getUserBySlug(slug) { - const { users } = await getAllUsers(); - - const user = users.find((user) => user.slug === slug); - - return { - user, - }; -} - -/** - * authorPathByName - */ - -export function authorPathByName(name) { - // @TODO - console.warn('authorPathByName UPDATE TO NODE URI'); - return `/authors/${name}`; -} - -/** - * getUserByNameSlug - */ - -export async function getUserByNameSlug(name) { - const { users } = await getAllUsers(); - - // @TODO - console.warn('getUserByNameSlug fix match'); - // const user = users.find((user) => parameterize(user.name) === name); - - return { - user: {}, - }; -} - -/** - * userSlugByName - */ - -export function userSlugByName(name) { - // @TODO - console.warn('userSlugByName FIX NODE URI'); - return name; -} - -/** - * getAllUsers - */ - -export async function getAllUsers() { - const apolloClient = getApolloClient(); - - let usersData; - let seoData; - - try { - usersData = await apolloClient.query({ - query: QUERY_ALL_USERS, - }); - } catch (e) { - console.log(`[users][getAllUsers] Failed to query users data: ${e.message}`); - throw e; - } - - let users = usersData?.data.users.edges.map(({ node = {} }) => node).map(mapUserData); - - // If the SEO plugin is enabled, look up the data - // and apply it to the default settings - - if (process.env.WORDPRESS_PLUGIN_SEO === true) { - try { - seoData = await apolloClient.query({ - query: QUERY_ALL_USERS_SEO, - }); - } catch (e) { - console.log(`[users][getAllUsers] Failed to query SEO plugin: ${e.message}`); - console.log('Is the SEO Plugin installed? If not, disable WORDPRESS_PLUGIN_SEO in next.config.js.'); - throw e; - } - - users = users.map((user) => { - const data = { ...user }; - const { id } = data; - - const seo = seoData?.data?.users.edges.map(({ node = {} }) => node).find((node) => node.id === id)?.seo; - - return { - ...data, - title: seo.title, - description: seo.metaDesc, - robots: { - nofollow: seo.metaRobotsNofollow, - noindex: seo.metaRobotsNoindex, - }, - social: seo.social, - }; - }); - } - - return { - users, - }; -} - -/** - * getAllAuthors - */ - -export async function getAllAuthors() { - const { users } = await getAllUsers(); - - // TODO: Roles aren't showing in response - we should be filtering here - - // const authors = users.filter(({ roles }) => { - // const userRoles = roles.map(({ name }) => name); - // const authorRoles = userRoles.filter(role => ROLES_AUTHOR.includes(role)); - // return authorRoles.length > 0; - // }); - - return { - authors: users, - }; -} - -/** - * mapUserData - */ - -export function mapUserData(user) { - return { - ...user, - roles: [...user.roles.nodes], - avatar: user.avatar && updateUserAvatar(user.avatar), - }; -} - /** * updateUserAvatar */ diff --git a/src/pages.original/authors/[slug].js b/src/pages.original/authors/[slug].js deleted file mode 100644 index b799bcc2..00000000 --- a/src/pages.original/authors/[slug].js +++ /dev/null @@ -1,91 +0,0 @@ -import { getUserByNameSlug } from '@/lib/users'; -import { getPostsByAuthorSlug } from '@/lib/posts'; -import { AuthorJsonLd } from '@/lib/json-ld'; -import usePageMetadata from 'hooks/use-page-metadata'; - -import TemplateArchive from 'templates/archive'; -import Title from '@/components/Title'; - -export default function Author({ user, posts }) { - const { title, name, avatar, description, slug } = user; - - const { metadata } = usePageMetadata({ - metadata: { - ...user, - title, - description: description || user.og?.description || `Read ${posts.length} posts from ${name}`, - }, - }); - - const postOptions = { - excludeMetadata: ['author'], - }; - - return ( - <> - - } - posts={posts} - postOptions={postOptions} - slug={slug} - metadata={metadata} - /> - - ); -} - -export async function getStaticProps({ params = {} } = {}) { - const { user } = await getUserByNameSlug(params?.slug); - - if (!user) { - return { - props: {}, - notFound: true, - }; - } - - const { posts } = await getPostsByAuthorSlug({ - slug: user?.slug, - queryIncludes: 'archive', - }); - - return { - props: { - user, - posts, - }, - }; -} - -export async function getStaticPaths() { - // By default, we don't render any Author pages as they're - // we're considering them non-critical pages - - // To enable pre-rendering of Author pages: - - // 1. Add import to the top of the file - // - // import { getAllAuthors, userSlugByName } from '@/lib/users'; - - // 2. Uncomment the below - // - // const { authors } = await getAllAuthors(); - - // const paths = authors.map((author) => { - // const { name } = author; - // return { - // params: { - // slug: userSlugByName(name), - // }, - // }; - // }); - - // 3. Update `paths` in the return statement below to reference the `paths` constant above - - return { - paths: [], - fallback: 'blocking', - }; -} diff --git a/src/styles/templates/Archive.module.scss b/src/styles/templates/Author.module.scss similarity index 100% rename from src/styles/templates/Archive.module.scss rename to src/styles/templates/Author.module.scss diff --git a/src/styles/pages/Page.module.scss b/src/styles/templates/Page.module.scss similarity index 100% rename from src/styles/pages/Page.module.scss rename to src/styles/templates/Page.module.scss diff --git a/src/styles/pages/Post.module.scss b/src/styles/templates/Post.module.scss similarity index 100% rename from src/styles/pages/Post.module.scss rename to src/styles/templates/Post.module.scss diff --git a/src/templates/author.js b/src/templates/author.js new file mode 100644 index 00000000..0d833f47 --- /dev/null +++ b/src/templates/author.js @@ -0,0 +1,157 @@ +import { updateUserAvatar } from '@/lib/users'; + +import Section from '@/components/Section'; +import Container from '@/components/Container'; +import Header from '@/components/Header'; +import SectionTitle from '@/components/SectionTitle'; +import PostCard from '@/components/PostCard'; +import JSONLD from '@/components/JSONLD'; + +import styles from '@/styles/templates/Author.module.scss'; + +export default async function Author({ data, metadata }) { + const { avatar, description, name, posts, uri } = data; + + // const { metadata } = usePageMetadata({ + // metadata: { + // ...user, + // title, + // description: description || user.og?.description || `Read ${posts.length} posts from ${name}`, + // }, + // }); + + // if (process.env.WORDPRESS_PLUGIN_SEO !== true) { + // metadata.title = `${title} - ${siteMetadata.title}`; + // metadata.og.title = metadata.title; + // metadata.twitter.title = metadata.title; + // } + + return ( + <> +
    + +

    {name}

    + {description && ( +

    + )} + +

    + +
    + + Posts + {Array.isArray(posts) && ( + <> +
      + {posts.map((post) => { + return ( +
    • + +
    • + ); + })} +
    + {/* {pagination && ( + + )} */} + + )} +
    +
    + + + + ); +} + +Author.template = { + query: ` + query UserByUri($uri: ID!) { + user(id: $uri, idType: URI) { + avatar { + height + width + url + } + description + id + name + posts { + edges { + node { + categories { + edges { + node { + databaseId + id + name + slug + } + } + } + date + excerpt + id + isSticky + modified + postId + title + uri + } + } + } + roles { + nodes { + name + } + } + uri + } + } + `, + transformer: (data) => { + return { + ...data.user, + avatar: data.user.avatar && updateUserAvatar(data.user.avatar), + posts: data.user.posts.edges.map(({ node: post }) => { + return { + ...post, + categories: post.categories.edges.map(({ node }) => { + return { + ...node, + }; + }), + }; + }), + roles: [...data.user.roles.nodes], + }; + }, + variables: ({ uri }) => { + return { + uri, + }; + }, +}; diff --git a/src/templates/page.js b/src/templates/page.js index 12da9678..3c9fd188 100644 --- a/src/templates/page.js +++ b/src/templates/page.js @@ -10,7 +10,7 @@ import FeaturedImage from '@/components/FeaturedImage'; import Breadcrumbs from '@/components/Breadcrumbs'; import JSONLD from '@/components/JSONLD'; -import styles from '@/styles/pages/Page.module.scss'; +import styles from '@/styles/templates/Page.module.scss'; export default async function Page({ data, metadata }) { const { children, content, description, featuredImage, title, uri } = data; diff --git a/src/templates/post.js b/src/templates/post.js index 317c1217..73870f95 100644 --- a/src/templates/post.js +++ b/src/templates/post.js @@ -13,7 +13,7 @@ import FeaturedImage from '@/components/FeaturedImage'; import Metadata from '@/components/Metadata'; import JSONLD from '@/components/JSONLD'; -import styles from '@/styles/pages/Post.module.scss'; +import styles from '@/styles/templates/Post.module.scss'; export default async function Post({ data, metadata }) { const { author, categories, content, date, excerpt, id, isSticky = false, featuredImage, modified, title } = data; @@ -148,7 +148,7 @@ Post.template = { } id name - slug + uri } } id From 09238a8ec1f85bcb697de3efca0724f86569f37e Mon Sep 17 00:00:00 2001 From: Colby Fayock Date: Sun, 7 May 2023 22:38:12 -0400 Subject: [PATCH 06/11] category --- package.json | 3 +- pnpm-lock.yaml | 19 +++ src/app/[...uriNodes]/page.js | 5 +- src/app/feed.xml/route.js | 4 +- src/app/page.js | 2 +- src/components/Footer/Footer.js | 6 +- src/components/Metadata/Metadata.js | 7 +- src/components/Nav/Nav.module.scss | 1 + src/components/NavSearch/NavSearch.js | 6 +- .../NavSearch/NavSearch.module.scss | 11 +- src/data/categories.js | 58 +------ src/data/menus.js | 2 +- src/data/pages.js | 6 - src/data/posts.js | 97 +---------- src/hooks/use-search.js | 39 +---- src/lib/categories.js | 118 +------------- src/lib/json-ld.js | 28 ---- src/lib/pages.js | 8 - src/lib/posts.js | 98 +----------- src/lib/search.js | 9 -- src/pages.original/categories.js | 66 -------- src/pages.original/categories/[slug].js | 73 --------- src/pages.original/posts.js | 34 ---- src/templates/archive.js | 85 ---------- src/templates/author.js | 4 +- src/templates/category.js | 151 ++++++++++++++++++ src/templates/post.js | 7 +- 27 files changed, 218 insertions(+), 729 deletions(-) delete mode 100644 src/lib/json-ld.js delete mode 100644 src/lib/search.js delete mode 100644 src/pages.original/categories.js delete mode 100644 src/pages.original/categories/[slug].js delete mode 100644 src/pages.original/posts.js delete mode 100644 src/templates/archive.js create mode 100644 src/templates/category.js diff --git a/package.json b/package.json index fbb95cd9..e997cca9 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,8 @@ "react-dom": "18.2.0", "react-icons": "^4.8.0", "rss": "^1.2.2", - "sass": "^1.62.1" + "sass": "^1.62.1", + "swr": "^2.1.5" }, "devDependencies": { "@types/node": "20.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 79a68df6..4a9204e9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -24,6 +24,7 @@ specifiers: react-icons: ^4.8.0 rss: ^1.2.2 sass: ^1.62.1 + swr: ^2.1.5 dependencies: '@apollo/client': 3.7.14_gdcq4dv6opitr3wbfwyjmanyra @@ -38,6 +39,7 @@ dependencies: react-icons: 4.8.0_react@18.2.0 rss: 1.2.2 sass: 1.62.1 + swr: 2.1.5_react@18.2.0 devDependencies: '@types/node': 20.0.0 @@ -2691,6 +2693,15 @@ packages: engines: {node: '>= 0.4'} dev: true + /swr/2.1.5_react@18.2.0: + resolution: {integrity: sha512-/OhfZMcEpuz77KavXST5q6XE9nrOBOVcBLWjMT+oAE/kQHyE3PASrevXCtQDZ8aamntOfFkbVJp7Il9tNBQWrw==} + peerDependencies: + react: ^16.11.0 || ^17.0.0 || ^18.0.0 + dependencies: + react: 18.2.0 + use-sync-external-store: 1.2.0_react@18.2.0 + dev: false + /symbol-observable/4.0.0: resolution: {integrity: sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==} engines: {node: '>=0.10'} @@ -2805,6 +2816,14 @@ packages: punycode: 2.3.0 dev: true + /use-sync-external-store/1.2.0_react@18.2.0: + resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + dependencies: + react: 18.2.0 + dev: false + /util/0.10.4: resolution: {integrity: sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==} dependencies: diff --git a/src/app/[...uriNodes]/page.js b/src/app/[...uriNodes]/page.js index 4e4a86de..3da997b2 100644 --- a/src/app/[...uriNodes]/page.js +++ b/src/app/[...uriNodes]/page.js @@ -4,19 +4,22 @@ import { getNodeByUri, getTemplateDataByNode } from '@/lib/nodes'; import { getSiteMetadata } from '@/lib/site'; import { default as TemplateAuthor } from '@/templates/author'; +import { default as TemplateCategory } from '@/templates/category'; import { default as TemplatePage } from '@/templates/page'; import { default as TemplatePost } from '@/templates/post'; const templates = { - User: TemplateAuthor, + Category: TemplateCategory, Page: TemplatePage, Post: TemplatePost, + User: TemplateAuthor, }; // By default, certain pages like the User type pages restrict // public access, but for the use case, users are authors // and without custom functionality, wouldn't be able to // display, hence the bypass option for types + // @TODO add section to readme explaining, add to nextconfig? const bypassRestricted = ['User']; diff --git a/src/app/feed.xml/route.js b/src/app/feed.xml/route.js index 5d8ca7a8..4a51532e 100644 --- a/src/app/feed.xml/route.js +++ b/src/app/feed.xml/route.js @@ -22,8 +22,8 @@ export async function GET() { posts.slice(0, MAX_POSTS).map((post) => { feed.item({ title: post.title, - guid: `${metadata.url}/posts/${post.slug}`, - url: `${metadata.url}/posts/${post.slug}`, + guid: `${metadata.url}${post.uri}`, + url: `${metadata.url}${post.uri}`, date: post.date, description: post.excerpt, author: post.author.name, diff --git a/src/app/page.js b/src/app/page.js index 834eae95..97d9fac4 100644 --- a/src/app/page.js +++ b/src/app/page.js @@ -44,7 +44,7 @@ export default async function Home() {
      {posts.map((post) => { return ( -
    • +
    • ); diff --git a/src/components/Footer/Footer.js b/src/components/Footer/Footer.js index f138b184..2fd8785f 100644 --- a/src/components/Footer/Footer.js +++ b/src/components/Footer/Footer.js @@ -2,7 +2,7 @@ import Link from 'next/link'; import { getSiteMetadata } from '@/lib/site'; import { getRecentPosts } from '@/lib/posts'; -import { getCategories, categoryPathBySlug } from '@/lib/categories'; +import { getCategories } from '@/lib/categories'; import Section from '@/components/Section'; import Container from '@/components/Container'; @@ -57,10 +57,10 @@ async function Footer() {
        {categories.map((category) => { - const { id, slug, name } = category; + const { id, name, uri } = category; return (
      • - {name} + {name}
      • ); })} diff --git a/src/components/Metadata/Metadata.js b/src/components/Metadata/Metadata.js index 6ba99dde..6d33ba02 100644 --- a/src/components/Metadata/Metadata.js +++ b/src/components/Metadata/Metadata.js @@ -1,6 +1,5 @@ import Link from 'next/link'; -import { categoryPathBySlug } from '@/lib/categories'; import { formatDate } from '@/lib/datetime'; import ClassName from 'models/classname'; @@ -49,7 +48,7 @@ const Metadata = ({ className, author, date, categories, options = DEFAULT_METAD
      • {compactCategories && (

        name).join(', ')}> - {categories[0].name} + {categories[0].name} {categories.length > 1 && ' and more'}

        )} @@ -57,8 +56,8 @@ const Metadata = ({ className, author, date, categories, options = DEFAULT_METAD
          {categories.map((category) => { return ( -
        • - {category.name} +
        • + {category.name}
        • ); })} diff --git a/src/components/Nav/Nav.module.scss b/src/components/Nav/Nav.module.scss index e32fd670..6c999603 100644 --- a/src/components/Nav/Nav.module.scss +++ b/src/components/Nav/Nav.module.scss @@ -59,6 +59,7 @@ } .navSearch { + height: 100%; flex-grow: 0; margin-left: 1em; } diff --git a/src/components/NavSearch/NavSearch.js b/src/components/NavSearch/NavSearch.js index 2e5e0f38..f3c8dd32 100644 --- a/src/components/NavSearch/NavSearch.js +++ b/src/components/NavSearch/NavSearch.js @@ -4,7 +4,7 @@ import { useState, useEffect, useCallback, useRef } from 'react'; import Link from 'next/link'; import { FaSearch } from 'react-icons/fa'; -import useSearch, { SEARCH_STATE_LOADED } from '@/hooks/use-search'; +import useSearch from '@/hooks/use-search'; const SEARCH_VISIBLE = 'visible'; const SEARCH_HIDDEN = 'hidden'; @@ -16,11 +16,11 @@ const NavSearch = () => { const [searchVisibility, setSearchVisibility] = useState(SEARCH_HIDDEN); - const { query, results, search, clearSearch, state } = useSearch({ + const { isLoading, error, query, results, clearSearch, search } = useSearch({ maxResults: 5, }); - const searchIsLoaded = state === SEARCH_STATE_LOADED; + const searchIsLoaded = results && !isLoading && !error; // When the search visibility changes, we want to add an event listener that allows us to // detect when someone clicks outside of the search box, allowing us to close the results diff --git a/src/components/NavSearch/NavSearch.module.scss b/src/components/NavSearch/NavSearch.module.scss index 8934eef0..7fdf486e 100644 --- a/src/components/NavSearch/NavSearch.module.scss +++ b/src/components/NavSearch/NavSearch.module.scss @@ -1,6 +1,8 @@ @import "styles/settings/__settings"; .navSearch { + height: 100%; + form { display: flex; align-items: center; @@ -12,7 +14,7 @@ @media (min-width: 480px) { justify-content: flex-end; - margin-right: -1rem; + padding: 0; } } @@ -21,13 +23,18 @@ } button { + height: 100%; font-size: 1.2em; background: none; - padding: 1.045em; border: none; + padding: 1em; outline: none; cursor: pointer; + @media (min-width: 480px) { + padding: 0 0.5em; + } + &[disabled] { svg { fill: $color-gray-200; diff --git a/src/data/categories.js b/src/data/categories.js index 7bba6423..a8111c1e 100644 --- a/src/data/categories.js +++ b/src/data/categories.js @@ -1,6 +1,4 @@ -import { gql } from '@apollo/client'; - -export const QUERY_ALL_CATEGORIES = gql` +export const QUERY_ALL_CATEGORIES = ` query AllCategories { categories(first: 10000) { edges { @@ -9,59 +7,7 @@ export const QUERY_ALL_CATEGORIES = gql` description id name - slug - } - } - } - } -`; - -export const QUERY_CATEGORY_BY_SLUG = gql` - query CategoryBySlug($slug: ID!) { - category(id: $slug, idType: SLUG) { - databaseId - description - id - name - slug - } - } -`; - -export const QUERY_CATEGORY_SEO_BY_SLUG = gql` - query CategorySEOBySlug($slug: ID!) { - category(id: $slug, idType: SLUG) { - id - seo { - canonical - metaDesc - metaRobotsNofollow - metaRobotsNoindex - opengraphAuthor - opengraphDescription - opengraphModifiedTime - opengraphPublishedTime - opengraphPublisher - opengraphTitle - opengraphType - title - twitterDescription - twitterTitle - twitterImage { - altText - sourceUrl - mediaDetails { - width - height - } - } - opengraphImage { - altText - sourceUrl - mediaDetails { - height - width - } + uri } } } diff --git a/src/data/menus.js b/src/data/menus.js index 4c079833..c035a727 100644 --- a/src/data/menus.js +++ b/src/data/menus.js @@ -20,7 +20,7 @@ export const QUERY_ALL_MENUS = gql` } } name - slug + uri locations } } diff --git a/src/data/pages.js b/src/data/pages.js index 56f5ba21..1a2218b5 100644 --- a/src/data/pages.js +++ b/src/data/pages.js @@ -6,7 +6,6 @@ export const PAGE_FIELDS = gql` edges { node { id - slug uri ... on Page { id @@ -21,14 +20,12 @@ export const PAGE_FIELDS = gql` parent { node { id - slug uri ... on Page { title } } } - slug title uri } @@ -95,7 +92,6 @@ export const QUERY_PAGE_BY_URI = gql` edges { node { id - slug uri ... on Page { id @@ -124,14 +120,12 @@ export const QUERY_PAGE_BY_URI = gql` parent { node { id - slug uri ... on Page { title } } } - slug title uri } diff --git a/src/data/posts.js b/src/data/posts.js index d876436d..913f0a99 100644 --- a/src/data/posts.js +++ b/src/data/posts.js @@ -9,16 +9,14 @@ export const POST_FIELDS = gql` databaseId id name - slug + uri } } } - databaseId date isSticky modified postId - slug title uri } @@ -105,58 +103,6 @@ export const QUERY_ALL_POSTS = gql` } `; -export const QUERY_POST_BY_SLUG = gql` - query PostBySlug($slug: ID!) { - post(id: $slug, idType: SLUG) { - author { - node { - avatar { - height - url - width - } - id - name - slug - } - } - id - categories { - edges { - node { - databaseId - id - name - slug - } - } - } - content - date - excerpt - featuredImage { - node { - altText - caption - mediaDetails { - height - width - } - sourceUrl - srcSet - sizes - id - } - } - modified - databaseId - title - slug - isSticky - } - } -`; - export const QUERY_POSTS_BY_CATEGORY_ID_INDEX = gql` ${POST_FIELDS} query PostsByCategoryId($categoryId: Int!) { @@ -238,47 +184,6 @@ export const QUERY_POSTS_BY_CATEGORY_ID = gql` } `; -export const QUERY_POST_SEO_BY_SLUG = gql` - query PostSEOBySlug($slug: ID!) { - post(id: $slug, idType: SLUG) { - id - seo { - canonical - metaDesc - metaRobotsNofollow - metaRobotsNoindex - opengraphAuthor - opengraphDescription - opengraphModifiedTime - opengraphPublishedTime - opengraphPublisher - opengraphTitle - opengraphType - readingTime - title - twitterDescription - twitterTitle - twitterImage { - altText - sourceUrl - mediaDetails { - width - height - } - } - opengraphImage { - altText - sourceUrl - mediaDetails { - height - width - } - } - } - } - } -`; - export const QUERY_POST_PER_PAGE = gql` query PostPerPage { allSettings { diff --git a/src/hooks/use-search.js b/src/hooks/use-search.js index b942155b..506d28b3 100644 --- a/src/hooks/use-search.js +++ b/src/hooks/use-search.js @@ -1,22 +1,18 @@ 'use client'; import { useState, useEffect } from 'react'; +import useSWR from 'swr'; import Fuse from 'fuse.js'; -import { getSearchData } from '@/lib/search'; +const SEARCH_KEYS = ['uri', 'title']; -const SEARCH_KEYS = ['slug', 'title']; - -export const SEARCH_STATE_LOADING = 'LOADING'; -export const SEARCH_STATE_READY = 'READY'; -export const SEARCH_STATE_ERROR = 'ERROR'; -export const SEARCH_STATE_LOADED = 'LOADED'; +const fetcher = (url) => fetch(url).then((res) => res.json()); export default function useSearch({ defaultQuery = null, maxResults } = {}) { - const [state, setState] = useState(SEARCH_STATE_READY); - const [data, setData] = useState(null); const [query, setQuery] = useState(defaultQuery); + const { data, error, isLoading } = useSWR('/wp-search.json', fetcher); + let client; if (data) { @@ -39,27 +35,6 @@ export default function useSearch({ defaultQuery = null, maxResults } = {}) { results = results.slice(0, maxResults); } - // On load, we want to immediately pull in the search index, which we're - // storing clientside and gets built at compile time - - useEffect(() => { - (async function getData() { - setState(SEARCH_STATE_LOADING); - try { - const searchData = await getSearchData(); - setData(searchData); - setState(SEARCH_STATE_LOADED); - } catch (e) { - setState(SEARCH_STATE_ERROR); - return; - } - })(); - return () => { - setData(undefined); - setState(SEARCH_STATE_READY); - }; - }, []); - // If the defaultQuery argument changes, the hook should reflect // that update and set that as the new state @@ -82,8 +57,8 @@ export default function useSearch({ defaultQuery = null, maxResults } = {}) { } return { - state, - data, + error, + isLoading, query, results, search: handleSearch, diff --git a/src/lib/categories.js b/src/lib/categories.js index 06713d83..6827e49a 100644 --- a/src/lib/categories.js +++ b/src/lib/categories.js @@ -1,23 +1,13 @@ -import { getApolloClient } from '@/lib/apollo-client'; +import { gql } from '@/lib/request'; -import { QUERY_ALL_CATEGORIES, QUERY_CATEGORY_BY_SLUG, QUERY_CATEGORY_SEO_BY_SLUG } from 'data/categories'; - -/** - * categoryPathBySlug - */ - -export function categoryPathBySlug(slug) { - return `/categories/${slug}`; -} +import { QUERY_ALL_CATEGORIES } from 'data/categories'; /** * getAllCategories */ export async function getAllCategories() { - const apolloClient = getApolloClient(); - - const data = await apolloClient.query({ + const data = await gql({ query: QUERY_ALL_CATEGORIES, }); @@ -28,99 +18,6 @@ export async function getAllCategories() { }; } -/** - * getCategoryBySlug - */ - -export async function getCategoryBySlug(slug) { - const apolloClient = getApolloClient(); - const apiHost = new URL(process.env.WORDPRESS_GRAPHQL_ENDPOINT).host; - - let categoryData; - let seoData; - - try { - categoryData = await apolloClient.query({ - query: QUERY_CATEGORY_BY_SLUG, - variables: { - slug, - }, - }); - } catch (e) { - console.log(`[categories][getCategoryBySlug] Failed to query category data: ${e.message}`); - throw e; - } - - if (!categoryData?.data.category) return { category: undefined }; - - const category = mapCategoryData(categoryData?.data.category); - - // If the SEO plugin is enabled, look up the data - // and apply it to the default settings - - if (process.env.WORDPRESS_PLUGIN_SEO === true) { - try { - seoData = await apolloClient.query({ - query: QUERY_CATEGORY_SEO_BY_SLUG, - variables: { - slug, - }, - }); - } catch (e) { - console.log(`[categories][getCategoryBySlug] Failed to query SEO plugin: ${e.message}`); - console.log('Is the SEO Plugin installed? If not, disable WORDPRESS_PLUGIN_SEO in next.config.js.'); - throw e; - } - - const { seo = {} } = seoData?.data?.category || {}; - - category.title = seo.title; - category.description = seo.metaDesc; - - // The SEO plugin by default includes a canonical link, but we don't want to use that - // because it includes the WordPress host, not the site host. We manage the canonical - // link along with the other metadata, but explicitly check if there's a custom one - // in here by looking for the API's host in the provided canonical link - - if (seo.canonical && !seo.canonical.includes(apiHost)) { - category.canonical = seo.canonical; - } - - category.og = { - author: seo.opengraphAuthor, - description: seo.opengraphDescription, - image: seo.opengraphImage, - modifiedTime: seo.opengraphModifiedTime, - publishedTime: seo.opengraphPublishedTime, - publisher: seo.opengraphPublisher, - title: seo.opengraphTitle, - type: seo.opengraphType, - }; - - category.article = { - author: category.og.author, - modifiedTime: category.og.modifiedTime, - publishedTime: category.og.publishedTime, - publisher: category.og.publisher, - }; - - category.robots = { - nofollow: seo.metaRobotsNofollow, - noindex: seo.metaRobotsNoindex, - }; - - category.twitter = { - description: seo.twitterDescription, - image: seo.twitterImage, - title: seo.twitterTitle, - }; - } - - return { - category, - }; -} - /** * getCategories */ @@ -131,12 +28,3 @@ export async function getCategories({ count } = {}) { categories: categories.slice(0, count), }; } - -/** - * mapCategoryData - */ - -export function mapCategoryData(category = {}) { - const data = { ...category }; - return data; -} diff --git a/src/lib/json-ld.js b/src/lib/json-ld.js deleted file mode 100644 index 90053b12..00000000 --- a/src/lib/json-ld.js +++ /dev/null @@ -1,28 +0,0 @@ -import { Helmet } from 'react-helmet'; - -import { pagePathBySlug } from '@/lib/pages'; - -import config from '../../package.json'; - -export function WebpageJsonLd({ title = '', description = '', siteTitle = '', slug = '' }) { - const { homepage = '' } = config; - const path = pagePathBySlug(slug); - - const jsonLd = { - '@context': 'http://schema.org', - '@type': 'WebPage', - name: title, - description: description, - url: `${homepage}${path}`, - publisher: { - '@type': 'ProfilePage', - name: siteTitle, - }, - }; - - return ( - - - - ); -} diff --git a/src/lib/pages.js b/src/lib/pages.js index 700a0638..d5b268f7 100644 --- a/src/lib/pages.js +++ b/src/lib/pages.js @@ -8,14 +8,6 @@ import { QUERY_PAGE_SEO_BY_URI, } from 'data/pages'; -/** - * pagePathBySlug - */ - -export function pagePathBySlug(slug) { - return `/${slug}`; -} - /** * getPageByUri */ diff --git a/src/lib/posts.js b/src/lib/posts.js index 55673c9e..87c2ad1d 100644 --- a/src/lib/posts.js +++ b/src/lib/posts.js @@ -7,108 +7,12 @@ import { QUERY_ALL_POSTS_INDEX, QUERY_ALL_POSTS_ARCHIVE, QUERY_ALL_POSTS, - QUERY_POST_BY_SLUG, QUERY_POSTS_BY_CATEGORY_ID_INDEX, QUERY_POSTS_BY_CATEGORY_ID_ARCHIVE, QUERY_POSTS_BY_CATEGORY_ID, - QUERY_POST_SEO_BY_SLUG, QUERY_POST_PER_PAGE, } from 'data/posts'; -/** - * getPostBySlug - */ - -export async function getPostBySlug(slug) { - const apolloClient = getApolloClient(); - const apiHost = new URL(process.env.WORDPRESS_GRAPHQL_ENDPOINT).host; - - let postData; - let seoData; - - try { - postData = await apolloClient.query({ - query: QUERY_POST_BY_SLUG, - variables: { - slug, - }, - }); - } catch (e) { - console.log(`[posts][getPostBySlug] Failed to query post data: ${e.message}`); - throw e; - } - - if (!postData?.data.post) return { post: undefined }; - - const post = [postData?.data.post].map(mapPostData)[0]; - - // If the SEO plugin is enabled, look up the data - // and apply it to the default settings - - if (process.env.WORDPRESS_PLUGIN_SEO === true) { - try { - seoData = await apolloClient.query({ - query: QUERY_POST_SEO_BY_SLUG, - variables: { - slug, - }, - }); - } catch (e) { - console.log(`[posts][getPostBySlug] Failed to query SEO plugin: ${e.message}`); - console.log('Is the SEO Plugin installed? If not, disable WORDPRESS_PLUGIN_SEO in next.config.js.'); - throw e; - } - - const { seo = {} } = seoData?.data?.post || {}; - - post.metaTitle = seo.title; - post.metaDescription = seo.metaDesc; - post.readingTime = seo.readingTime; - - // The SEO plugin by default includes a canonical link, but we don't want to use that - // because it includes the WordPress host, not the site host. We manage the canonical - // link along with the other metadata, but explicitly check if there's a custom one - // in here by looking for the API's host in the provided canonical link - - if (seo.canonical && !seo.canonical.includes(apiHost)) { - post.canonical = seo.canonical; - } - - post.og = { - author: seo.opengraphAuthor, - description: seo.opengraphDescription, - image: seo.opengraphImage, - modifiedTime: seo.opengraphModifiedTime, - publishedTime: seo.opengraphPublishedTime, - publisher: seo.opengraphPublisher, - title: seo.opengraphTitle, - type: seo.opengraphType, - }; - - post.article = { - author: post.og.author, - modifiedTime: post.og.modifiedTime, - publishedTime: post.og.publishedTime, - publisher: post.og.publisher, - }; - - post.robots = { - nofollow: seo.metaRobotsNofollow, - noindex: seo.metaRobotsNoindex, - }; - - post.twitter = { - description: seo.twitterDescription, - image: seo.twitterImage, - title: seo.twitterTitle, - }; - } - - return { - post, - }; -} - /** * getAllPosts */ @@ -220,7 +124,7 @@ export function mapPostData(post = {}) { // Clean up the author object to avoid someone having to look an extra // level deeper into the node - console.log('data.author', data.author); + if (data.author) { data.author = { ...data.author.node, diff --git a/src/lib/search.js b/src/lib/search.js deleted file mode 100644 index fa42b646..00000000 --- a/src/lib/search.js +++ /dev/null @@ -1,9 +0,0 @@ -/** - * getSearchData - */ - -export async function getSearchData() { - const response = await fetch('/wp-search.json'); - const json = await response.json(); - return json; -} diff --git a/src/pages.original/categories.js b/src/pages.original/categories.js deleted file mode 100644 index f0fccff1..00000000 --- a/src/pages.original/categories.js +++ /dev/null @@ -1,66 +0,0 @@ -import Link from 'next/link'; -import { Helmet } from 'react-helmet'; - -import useSite from '@/hooks/use-site'; -import { getAllCategories, categoryPathBySlug } from '@/lib/categories'; -import { WebpageJsonLd } from '@/lib/json-ld'; - -import Layout from '@/components/Layout'; -import Header from '@/components/Header'; -import Section from '@/components/Section'; -import Container from '@/components/Container'; -import SectionTitle from '@/components/SectionTitle'; - -import styles from '@/styles/pages/Categories.module.scss'; - -export default function Categories({ categories }) { - const { metadata = {} } = useSite(); - const { title: siteTitle } = metadata; - const title = 'Categories'; - const slug = 'categories'; - let metaDescription = `Read ${categories.length} categories at ${siteTitle}.`; - - return ( - - - Categories - - - - - - - -
          - -

          Categories

          -
          -
          - -
          - - All Categories -
            - {categories.map((category) => { - return ( -
          • - {category.name} -
          • - ); - })} -
          -
          -
          -
          - ); -} - -export async function getStaticProps() { - const { categories } = await getAllCategories(); - - return { - props: { - categories, - }, - }; -} diff --git a/src/pages.original/categories/[slug].js b/src/pages.original/categories/[slug].js deleted file mode 100644 index 22f6be9c..00000000 --- a/src/pages.original/categories/[slug].js +++ /dev/null @@ -1,73 +0,0 @@ -import { getCategoryBySlug } from '@/lib/categories'; -import { getPostsByCategoryId } from '@/lib/posts'; -import usePageMetadata from 'hooks/use-page-metadata'; - -import TemplateArchive from 'templates/archive'; -import Title from '@/components/Title'; - -export default function Category({ category, posts }) { - const { name, description, slug } = category; - - const { metadata } = usePageMetadata({ - metadata: { - ...category, - description: description || category.og?.description || `Read ${posts.length} posts from ${name}`, - }, - }); - - return } posts={posts} slug={slug} metadata={metadata} />; -} - -export async function getStaticProps({ params = {} } = {}) { - const { category } = await getCategoryBySlug(params?.slug); - - if (!category) { - return { - props: {}, - notFound: true, - }; - } - - const { posts } = await getPostsByCategoryId({ - categoryId: category.databaseId, - queryIncludes: 'archive', - }); - - return { - props: { - category, - posts, - }, - }; -} - -export async function getStaticPaths() { - // By default, we don't render any Category pages as - // we're considering them non-critical pages - - // To enable pre-rendering of Category pages: - - // 1. Add import to the top of the file - // - // import { getAllCategories, getCategoryBySlug } from '@/lib/categories'; - - // 2. Uncomment the below - // - // const { categories } = await getAllCategories(); - - // const paths = categories.map((category) => { - // const { slug } = category; - // return { - // params: { - // slug, - // }, - // }; - // }); - - // 3. Update `paths` in the return statement below to reference the `paths` constant above - - return { - paths: [], - fallback: 'blocking', - }; -} diff --git a/src/pages.original/posts.js b/src/pages.original/posts.js deleted file mode 100644 index 61adc7d1..00000000 --- a/src/pages.original/posts.js +++ /dev/null @@ -1,34 +0,0 @@ -import usePageMetadata from 'hooks/use-page-metadata'; - -import { getPaginatedPosts } from '@/lib/posts'; - -import TemplateArchive from 'templates/archive'; - -export default function Posts({ posts, pagination }) { - const title = 'All Posts'; - const slug = 'posts'; - - const { metadata } = usePageMetadata({ - metadata: { - title, - description: false, - }, - }); - - return ; -} - -export async function getStaticProps() { - const { posts, pagination } = await getPaginatedPosts({ - queryIncludes: 'archive', - }); - return { - props: { - posts, - pagination: { - ...pagination, - basePath: '/posts', - }, - }, - }; -} diff --git a/src/templates/archive.js b/src/templates/archive.js deleted file mode 100644 index 5d13838d..00000000 --- a/src/templates/archive.js +++ /dev/null @@ -1,85 +0,0 @@ -// import { Helmet } from 'react-helmet'; - -// import { WebpageJsonLd } from '@/lib/json-ld'; -// import { helmetSettingsFromMetadata } from '@/lib/site'; -// import useSite from '@/hooks/use-site'; - -// import Layout from '@/components/Layout'; -// import Header from '@/components/Header'; -// import Section from '@/components/Section'; -// import Container from '@/components/Container'; -// import SectionTitle from '@/components/SectionTitle'; -// import PostCard from '@/components/PostCard'; -// import Pagination from '@/components/Pagination/Pagination'; - -// import styles from '@/styles/templates/Archive.module.scss'; - -// const DEFAULT_POST_OPTIONS = {}; - -// export default function TemplateArchive({ -// title = 'Archive', -// Title, -// posts, -// postOptions = DEFAULT_POST_OPTIONS, -// slug, -// metadata, -// pagination, -// }) { -// const { metadata: siteMetadata = {} } = useSite(); - -// if (process.env.WORDPRESS_PLUGIN_SEO !== true) { -// metadata.title = `${title} - ${siteMetadata.title}`; -// metadata.og.title = metadata.title; -// metadata.twitter.title = metadata.title; -// } - -// const helmetSettings = helmetSettingsFromMetadata(metadata); - -// return ( -// -// - -// - -//
          -// -//

          {Title || title}

          -// {metadata.description && ( -//

          -// )} -// -//

          - -//
          -// -// Posts -// {Array.isArray(posts) && ( -// <> -//
            -// {posts.map((post) => { -// return ( -//
          • -// -//
          • -// ); -// })} -//
          -// {pagination && ( -// -// )} -// -// )} -//
          -//
          -//
          -// ); -// } diff --git a/src/templates/author.js b/src/templates/author.js index 0d833f47..8c7bfeaf 100644 --- a/src/templates/author.js +++ b/src/templates/author.js @@ -50,7 +50,7 @@ export default async function Author({ data, metadata }) {
            {posts.map((post) => { return ( -
          • +
          • +
            + +

            {name}

            + {description && ( +

            + )} + +

            + +
            + + Posts + {Array.isArray(posts) && ( + <> +
              + {posts.map((post) => { + return ( +
            • + +
            • + ); + })} +
            + {/* {pagination && ( + + )} */} + + )} +
            +
            + + + + ); +} + +Category.template = { + query: ` + query CategoryByUri($uri: ID!) { + category(id: $uri, idType: URI) { + description + id + name + posts { + edges { + node { + author { + node { + avatar { + height + url + width + } + id + name + uri + } + } + categories { + edges { + node { + databaseId + id + name + uri + } + } + } + date + excerpt + id + isSticky + modified + postId + title + uri + } + } + } + uri + } + } + `, + transformer: (data) => { + return { + ...data.category, + posts: data.category.posts.edges.map(({ node: post }) => { + return { + ...post, + author: post.author.node, + categories: post.categories.edges.map(({ node }) => { + return { + ...node, + }; + }), + }; + }), + }; + }, + variables: ({ uri }) => { + return { + uri, + }; + }, +}; diff --git a/src/templates/post.js b/src/templates/post.js index 73870f95..50426b10 100644 --- a/src/templates/post.js +++ b/src/templates/post.js @@ -1,7 +1,6 @@ import Link from 'next/link'; import { getRelatedPosts } from '@/lib/posts'; -import { categoryPathBySlug } from '@/lib/categories'; import { formatDate } from '@/lib/datetime'; import { updateUserAvatar } from '@/lib/users'; @@ -30,7 +29,7 @@ export default async function Post({ data, metadata }) { posts: relatedPosts, title: { name: relatedCategory.name || null, - link: categoryPathBySlug(relatedCategory.slug), + link: relatedCategory.uri, }, }; } @@ -158,7 +157,7 @@ Post.template = { databaseId id name - slug + uri } } } @@ -182,7 +181,7 @@ Post.template = { modified databaseId title - slug + uri isSticky } } From 12dde425f47754eb7b1ebb9c708828c9c7905aed Mon Sep 17 00:00:00 2001 From: Colby Fayock Date: Sun, 21 May 2023 12:38:01 -0400 Subject: [PATCH 07/11] error pages --- src/app/error.js | 33 +++++++++++++++++++++++++ src/app/not-found.js | 25 +++++++++++++++++++ src/pages.original/404.js | 36 --------------------------- src/pages.original/500.js | 39 ------------------------------ src/styles/pages/Error.module.scss | 9 ++++--- 5 files changed, 64 insertions(+), 78 deletions(-) create mode 100644 src/app/error.js create mode 100644 src/app/not-found.js delete mode 100644 src/pages.original/404.js delete mode 100644 src/pages.original/500.js diff --git a/src/app/error.js b/src/app/error.js new file mode 100644 index 00000000..8f5ec74a --- /dev/null +++ b/src/app/error.js @@ -0,0 +1,33 @@ +'use client'; + +import Link from 'next/link'; + +import Section from '@/components/Section'; +import Container from '@/components/Container'; +import Button from '@/components/Button'; + +import styles from '@/styles/pages/Error.module.scss'; + +export const metadata = { + title: 'Error', +}; + +export default function Error({ error, reset }) { + return ( +
            + +

            Something went wrong!

            +
            + Details +

            {error?.message}

            +
            +

            + +

            +

            + Or go back to home +

            +
            +
            + ); +} diff --git a/src/app/not-found.js b/src/app/not-found.js new file mode 100644 index 00000000..458f10f1 --- /dev/null +++ b/src/app/not-found.js @@ -0,0 +1,25 @@ +import Link from 'next/link'; + +import Section from '@/components/Section'; +import Container from '@/components/Container'; + +import styles from '@/styles/pages/Error.module.scss'; + +export const metadata = { + title: '404 - Page Not Found', +}; + +export default function NotFound() { + return ( +
            + +

            Page Not Found

            +

            404

            +

            The page you were looking for could not be found.

            +

            + Back to home +

            +
            +
            + ); +} diff --git a/src/pages.original/404.js b/src/pages.original/404.js deleted file mode 100644 index 26852591..00000000 --- a/src/pages.original/404.js +++ /dev/null @@ -1,36 +0,0 @@ -import Link from 'next/link'; -import { Helmet } from 'react-helmet'; - -import Layout from '@/components/Layout'; -import Section from '@/components/Section'; -import Container from '@/components/Container'; - -import styles from '@/styles/pages/Error.module.scss'; - -export default function Custom404() { - return ( - - - 404 - Page Not Found - - -
            - -

            Page Not Found

            -

            404

            -

            The page you were looking for could not be found.

            -

            - Go back home -

            -
            -
            -
            - ); -} - -// Next.js method to ensure a static page gets rendered -export async function getStaticProps() { - return { - props: {}, - }; -} diff --git a/src/pages.original/500.js b/src/pages.original/500.js deleted file mode 100644 index 4e459058..00000000 --- a/src/pages.original/500.js +++ /dev/null @@ -1,39 +0,0 @@ -import Link from 'next/link'; -import { Helmet } from 'react-helmet'; - -import Layout from '@/components/Layout'; -import Section from '@/components/Section'; -import Container from '@/components/Container'; - -import styles from '@/styles/pages/Error.module.scss'; - -export default function Custom500() { - return ( - - - 500 - Internal Error - - -
            - -

            Internal Error

            -

            500

            -

            - Uh oh, something went wrong. Please try refreshing the page or clearing site data. If the problem persists, - reach out to let us know! -

            -

            - Go back home -

            -
            -
            -
            - ); -} - -// Next.js method to ensure a static page gets rendered -export async function getStaticProps() { - return { - props: {}, - }; -} diff --git a/src/styles/pages/Error.module.scss b/src/styles/pages/Error.module.scss index 3f7f19a8..63aa09cb 100644 --- a/src/styles/pages/Error.module.scss +++ b/src/styles/pages/Error.module.scss @@ -1,9 +1,6 @@ @import "styles/settings/__settings"; .center { - display: flex; - flex-direction: column; - align-items: center; text-align: center; } @@ -15,4 +12,10 @@ .errorMessage { max-width: 40em; + margin: 1.2em auto; +} + +.errorRefresh { + font-size: 0.8em; + margin-top: 3em; } From c1d2de22bf7226357e4daa4c56e85ce2f0e64326 Mon Sep 17 00:00:00 2001 From: Colby Fayock Date: Tue, 23 May 2023 13:00:20 -0400 Subject: [PATCH 08/11] og --- package.json | 2 +- pnpm-lock.yaml | 68 ++++++++++----------- src/app/[...uriNodes]/opengraph-image.js | 77 ++++++++++++++++++++++++ src/app/opengraph-image.js | 77 ++++++++++++++++++++++++ 4 files changed, 189 insertions(+), 35 deletions(-) create mode 100644 src/app/[...uriNodes]/opengraph-image.js create mode 100644 src/app/opengraph-image.js diff --git a/package.json b/package.json index e997cca9..c5f2e37a 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "fuse.js": "^6.6.2", "graphql": "^16.6.0", "he": "^1.2.0", - "next": "13.4.0", + "next": "13.4.3", "parameterize": "^1.0.0", "path": "^0.12.7", "react": "18.2.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4a9204e9..acec346b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -15,7 +15,7 @@ specifiers: he: ^1.2.0 husky: ^8.0.3 lint-staged: ^13.2.2 - next: 13.4.0 + next: 13.4.3 parameterize: ^1.0.0 path: ^0.12.7 prettier: 2.8.8 @@ -31,7 +31,7 @@ dependencies: fuse.js: 6.6.2 graphql: 16.6.0 he: 1.2.0 - next: 13.4.0_txdvpvppf2ilsh27xadmwrzlmm + next: 13.4.3_txdvpvppf2ilsh27xadmwrzlmm parameterize: 1.0.0 path: 0.12.7 react: 18.2.0 @@ -164,8 +164,8 @@ packages: resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} dev: true - /@next/env/13.4.0: - resolution: {integrity: sha512-LKofmUuxwGXk2OZJSSJ2SlJE62s6z+56aRsze7chc5TPoVouLR9liTiSWxzYuVzuxk0ui2wtIjyR2tcgS1dIyw==} + /@next/env/13.4.3: + resolution: {integrity: sha512-pa1ErjyFensznttAk3EIv77vFbfSYT6cLzVRK5jx4uiRuCQo+m2wCFAREaHKIy63dlgvOyMlzh6R8Inu8H3KrQ==} dev: false /@next/eslint-plugin-next/13.4.0: @@ -174,8 +174,8 @@ packages: glob: 7.1.7 dev: true - /@next/swc-darwin-arm64/13.4.0: - resolution: {integrity: sha512-C39AGL3ANXA+P3cFclQjFZaJ4RHPmuBhskmyy0N3VyCntDmRrNkS4aXeNY4Xwure9IL1nuw02D8bM55I+FsbuQ==} + /@next/swc-darwin-arm64/13.4.3: + resolution: {integrity: sha512-yx18udH/ZmR4Bw4M6lIIPE3JxsAZwo04iaucEfA2GMt1unXr2iodHUX/LAKNyi6xoLP2ghi0E+Xi1f4Qb8f1LQ==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] @@ -183,8 +183,8 @@ packages: dev: false optional: true - /@next/swc-darwin-x64/13.4.0: - resolution: {integrity: sha512-nj6nx6o7rnBXjo1woZFWLk7OUs7y0SQ0k65SX62kc88GqXtYi3BCqbBznjOX8qtrO//NmtAde/Jd5qkjSgINUQ==} + /@next/swc-darwin-x64/13.4.3: + resolution: {integrity: sha512-Mi8xJWh2IOjryAM1mx18vwmal9eokJ2njY4nDh04scy37F0LEGJ/diL6JL6kTXi0UfUCGbMsOItf7vpReNiD2A==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] @@ -192,8 +192,8 @@ packages: dev: false optional: true - /@next/swc-linux-arm64-gnu/13.4.0: - resolution: {integrity: sha512-FBYL7kpzI2KG3lv8gO4xVYmWcFohptjzD9RCLdXsAz+Kqz5VCJILF21DoRcz4Nwj/jMe0SO7l5kBVW4POl4EaQ==} + /@next/swc-linux-arm64-gnu/13.4.3: + resolution: {integrity: sha512-aBvtry4bxJ1xwKZ/LVPeBGBwWVwxa4bTnNkRRw6YffJnn/f4Tv4EGDPaVeYHZGQVA56wsGbtA6nZMuWs/EIk4Q==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] @@ -201,8 +201,8 @@ packages: dev: false optional: true - /@next/swc-linux-arm64-musl/13.4.0: - resolution: {integrity: sha512-S3htBbcovnLMgVn0z1ThrP1iAeEM43fw8B7S3KyHTAGe0I21ww4rvUkLdgPCqLNvMpv899lmG7NU5rs6rTkGvg==} + /@next/swc-linux-arm64-musl/13.4.3: + resolution: {integrity: sha512-krT+2G3kEsEUvZoYte3/2IscscDraYPc2B+fDJFipPktJmrv088Pei/RjrhWm5TMIy5URYjZUoDZdh5k940Dyw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] @@ -210,8 +210,8 @@ packages: dev: false optional: true - /@next/swc-linux-x64-gnu/13.4.0: - resolution: {integrity: sha512-H8GhCgQwFl6iWJ6azQ2tG/GY8BUg1nhPtg4Tp2kIPljdyQypTGJe8oRnPDx0N48WWvB2fNeA7LNEwzVuSidH2w==} + /@next/swc-linux-x64-gnu/13.4.3: + resolution: {integrity: sha512-AMdFX6EKJjC0G/CM6hJvkY8wUjCcbdj3Qg7uAQJ7PVejRWaVt0sDTMavbRfgMchx8h8KsAudUCtdFkG9hlEClw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] @@ -219,8 +219,8 @@ packages: dev: false optional: true - /@next/swc-linux-x64-musl/13.4.0: - resolution: {integrity: sha512-mztVybRPY39NfPOA3QrRQKzYuw7A/D8ElR6ruvM1cBsXMEfF5xTzdZqfTtrE/gNTPUFug9FJPpiRpkZ4mDUl8w==} + /@next/swc-linux-x64-musl/13.4.3: + resolution: {integrity: sha512-jySgSXE48shaLtcQbiFO9ajE9mqz7pcAVLnVLvRIlUHyQYR/WyZdK8ehLs65Mz6j9cLrJM+YdmdJPyV4WDaz2g==} engines: {node: '>= 10'} cpu: [x64] os: [linux] @@ -228,8 +228,8 @@ packages: dev: false optional: true - /@next/swc-win32-arm64-msvc/13.4.0: - resolution: {integrity: sha512-mdVh/n0QqT2uXqn8kaTywUoLxY1OYqTpiKbt5b51pDwOStqgbIbqBqG0A7XDaiqWa7RKwllOYxPlPm16EDfWUA==} + /@next/swc-win32-arm64-msvc/13.4.3: + resolution: {integrity: sha512-5DxHo8uYcaADiE9pHrg8o28VMt/1kR8voDehmfs9AqS0qSClxAAl+CchjdboUvbCjdNWL1MISCvEfKY2InJ3JA==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] @@ -237,8 +237,8 @@ packages: dev: false optional: true - /@next/swc-win32-ia32-msvc/13.4.0: - resolution: {integrity: sha512-GNRqT2mqxxH0x9VthFqziBj8X8HsoBUougmLe3kOouRq/jF73LpKXG0Qs2MYkylqvv/Wg31EYjFNcJnBi1Nimg==} + /@next/swc-win32-ia32-msvc/13.4.3: + resolution: {integrity: sha512-LaqkF3d+GXRA5X6zrUjQUrXm2MN/3E2arXBtn5C7avBCNYfm9G3Xc646AmmmpN3DJZVaMYliMyCIQCMDEzk80w==} engines: {node: '>= 10'} cpu: [ia32] os: [win32] @@ -246,8 +246,8 @@ packages: dev: false optional: true - /@next/swc-win32-x64-msvc/13.4.0: - resolution: {integrity: sha512-0AkvhUBUqeb4WKN75IW1KjPkN3HazQFA0OpMuTK+6ptJUXMaMwDDcF3sIPCI741BJ2fpODB7BPM4C63hXWEypg==} + /@next/swc-win32-x64-msvc/13.4.3: + resolution: {integrity: sha512-jglUk/x7ZWeOJWlVoKyIAkHLTI+qEkOriOOV+3hr1GyiywzcqfI7TpFSiwC7kk1scOiH7NTFKp8mA3XPNO9bDw==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -2022,8 +2022,8 @@ packages: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} dev: true - /next/13.4.0_txdvpvppf2ilsh27xadmwrzlmm: - resolution: {integrity: sha512-y3E+2ZjiVrphkz7zcJvd2rEG6miOekI8krPfWV4AZZ9TaF0LDuFdP/f+RQ5M9wRvsz6GWw8k8+7jsO860GxSqg==} + /next/13.4.3_txdvpvppf2ilsh27xadmwrzlmm: + resolution: {integrity: sha512-FV3pBrAAnAIfOclTvncw9dDohyeuEEXPe5KNcva91anT/rdycWbgtu3IjUj4n5yHnWK8YEPo0vrUecHmnmUNbA==} engines: {node: '>=16.8.0'} hasBin: true peerDependencies: @@ -2043,7 +2043,7 @@ packages: sass: optional: true dependencies: - '@next/env': 13.4.0 + '@next/env': 13.4.3 '@swc/helpers': 0.5.1 busboy: 1.6.0 caniuse-lite: 1.0.30001482 @@ -2054,15 +2054,15 @@ packages: styled-jsx: 5.1.1_react@18.2.0 zod: 3.21.4 optionalDependencies: - '@next/swc-darwin-arm64': 13.4.0 - '@next/swc-darwin-x64': 13.4.0 - '@next/swc-linux-arm64-gnu': 13.4.0 - '@next/swc-linux-arm64-musl': 13.4.0 - '@next/swc-linux-x64-gnu': 13.4.0 - '@next/swc-linux-x64-musl': 13.4.0 - '@next/swc-win32-arm64-msvc': 13.4.0 - '@next/swc-win32-ia32-msvc': 13.4.0 - '@next/swc-win32-x64-msvc': 13.4.0 + '@next/swc-darwin-arm64': 13.4.3 + '@next/swc-darwin-x64': 13.4.3 + '@next/swc-linux-arm64-gnu': 13.4.3 + '@next/swc-linux-arm64-musl': 13.4.3 + '@next/swc-linux-x64-gnu': 13.4.3 + '@next/swc-linux-x64-musl': 13.4.3 + '@next/swc-win32-arm64-msvc': 13.4.3 + '@next/swc-win32-ia32-msvc': 13.4.3 + '@next/swc-win32-x64-msvc': 13.4.3 transitivePeerDependencies: - '@babel/core' - babel-plugin-macros diff --git a/src/app/[...uriNodes]/opengraph-image.js b/src/app/[...uriNodes]/opengraph-image.js new file mode 100644 index 00000000..0495507e --- /dev/null +++ b/src/app/[...uriNodes]/opengraph-image.js @@ -0,0 +1,77 @@ +import { ImageResponse } from 'next/server'; + +import { getSiteMetadata } from '@/lib/site'; + +export const runtime = 'edge'; + +export const alt = 'About Acme'; + +export const size = { + width: 1200, + height: 630, +}; + +export const contentType = 'image/png'; + +export default async function Image({ params }) { + const metadata = await getSiteMetadata(); + + let website = metadata.url.replace(/https?:\/\//, ''); + + if ( website[website.length - 1] === '/' ) { + website = website.slice(0, website.length - 1); + } + + return new ImageResponse( + ( +
            +
            +
            + Post Title Post Title Post Title Post TitlePost Title Post Title Post Title Post Title Post Title +
            +
            +
            + { website } +
            +
            + + ), + { + // For convenience, we can re-use the exported opengraph-image + // size config to also set the ImageReponse's width and height. + ...size, + }, + ); +} \ No newline at end of file diff --git a/src/app/opengraph-image.js b/src/app/opengraph-image.js new file mode 100644 index 00000000..0495507e --- /dev/null +++ b/src/app/opengraph-image.js @@ -0,0 +1,77 @@ +import { ImageResponse } from 'next/server'; + +import { getSiteMetadata } from '@/lib/site'; + +export const runtime = 'edge'; + +export const alt = 'About Acme'; + +export const size = { + width: 1200, + height: 630, +}; + +export const contentType = 'image/png'; + +export default async function Image({ params }) { + const metadata = await getSiteMetadata(); + + let website = metadata.url.replace(/https?:\/\//, ''); + + if ( website[website.length - 1] === '/' ) { + website = website.slice(0, website.length - 1); + } + + return new ImageResponse( + ( +
            +
            +
            + Post Title Post Title Post Title Post TitlePost Title Post Title Post Title Post Title Post Title +
            +
            +
            + { website } +
            +
            + + ), + { + // For convenience, we can re-use the exported opengraph-image + // size config to also set the ImageReponse's width and height. + ...size, + }, + ); +} \ No newline at end of file From abcfd0d4d3062d680938c5bbb6ebfd8fedd0b589 Mon Sep 17 00:00:00 2001 From: Colby Fayock Date: Wed, 24 May 2023 12:17:45 -0400 Subject: [PATCH 09/11] og image not working in catch all --- src/app/[...uriNodes]/opengraph-image.js | 77 ------------------------ 1 file changed, 77 deletions(-) delete mode 100644 src/app/[...uriNodes]/opengraph-image.js diff --git a/src/app/[...uriNodes]/opengraph-image.js b/src/app/[...uriNodes]/opengraph-image.js deleted file mode 100644 index 0495507e..00000000 --- a/src/app/[...uriNodes]/opengraph-image.js +++ /dev/null @@ -1,77 +0,0 @@ -import { ImageResponse } from 'next/server'; - -import { getSiteMetadata } from '@/lib/site'; - -export const runtime = 'edge'; - -export const alt = 'About Acme'; - -export const size = { - width: 1200, - height: 630, -}; - -export const contentType = 'image/png'; - -export default async function Image({ params }) { - const metadata = await getSiteMetadata(); - - let website = metadata.url.replace(/https?:\/\//, ''); - - if ( website[website.length - 1] === '/' ) { - website = website.slice(0, website.length - 1); - } - - return new ImageResponse( - ( -
            -
            -
            - Post Title Post Title Post Title Post TitlePost Title Post Title Post Title Post Title Post Title -
            -
            -
            - { website } -
            -
            - - ), - { - // For convenience, we can re-use the exported opengraph-image - // size config to also set the ImageReponse's width and height. - ...size, - }, - ); -} \ No newline at end of file From c1b24c4e41ddf49cea9db40833f1a5ddcdd21b72 Mon Sep 17 00:00:00 2001 From: Colby Fayock Date: Wed, 24 May 2023 12:24:19 -0400 Subject: [PATCH 10/11] lint --- src/app/opengraph-image.js | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/app/opengraph-image.js b/src/app/opengraph-image.js index 0495507e..cd8eca5c 100644 --- a/src/app/opengraph-image.js +++ b/src/app/opengraph-image.js @@ -13,15 +13,15 @@ export const size = { export const contentType = 'image/png'; -export default async function Image({ params }) { +export default async function Image() { const metadata = await getSiteMetadata(); let website = metadata.url.replace(/https?:\/\//, ''); - if ( website[website.length - 1] === '/' ) { + if (website[website.length - 1] === '/') { website = website.slice(0, website.length - 1); } - + return new ImageResponse( (
            + >
            Post Title Post Title Post Title Post TitlePost Title Post Title Post Title Post Title Post Title @@ -63,15 +63,14 @@ export default async function Image({ params }) { paddingBottom: 40, }} > - { website } + {website}
            - ), { // For convenience, we can re-use the exported opengraph-image // size config to also set the ImageReponse's width and height. ...size, - }, + } ); -} \ No newline at end of file +} From f32156d58b61e529d363d1723d5714453fa9164e Mon Sep 17 00:00:00 2001 From: Colby Fayock Date: Thu, 25 May 2023 08:40:14 -0400 Subject: [PATCH 11/11] dynamic og image for uri nodes --- src/app/[...uriNodes]/page.js | 19 +- .../[...path]/route.js} | 23 ++- src/data/pages.js | 14 +- src/data/posts.js | 18 +- src/lib/pages.js | 174 +++++++++--------- src/lib/posts.js | 14 +- 6 files changed, 142 insertions(+), 120 deletions(-) rename src/app/{opengraph-image.js => opengraph/[...path]/route.js} (70%) diff --git a/src/app/[...uriNodes]/page.js b/src/app/[...uriNodes]/page.js index 3da997b2..1e230132 100644 --- a/src/app/[...uriNodes]/page.js +++ b/src/app/[...uriNodes]/page.js @@ -8,7 +8,7 @@ import { default as TemplateCategory } from '@/templates/category'; import { default as TemplatePage } from '@/templates/page'; import { default as TemplatePost } from '@/templates/post'; -const templates = { +export const templates = { Category: TemplateCategory, Page: TemplatePage, Post: TemplatePost, @@ -24,6 +24,23 @@ const templates = { const bypassRestricted = ['User']; +export async function generateMetadata({ params }) { + return { + title: 'test', + openGraph: { + images: [ + { + url: `/opengraph/${params.uriNodes.join('/')}`, + width: 1200, + height: 630, + type: 'image/png', + alt: 'test', + }, + ], + }, + }; +} + export default async function Page({ params = {} }) { const resolvedUri = params.uriNodes ? params.uriNodes.join('/') : null; const node = await getNodeByUri(resolvedUri); diff --git a/src/app/opengraph-image.js b/src/app/opengraph/[...path]/route.js similarity index 70% rename from src/app/opengraph-image.js rename to src/app/opengraph/[...path]/route.js index cd8eca5c..7199f012 100644 --- a/src/app/opengraph-image.js +++ b/src/app/opengraph/[...path]/route.js @@ -1,6 +1,9 @@ import { ImageResponse } from 'next/server'; import { getSiteMetadata } from '@/lib/site'; +import { getNodeByUri, getTemplateDataByNode } from '@/lib/nodes'; + +import { templates } from '@/app/[...uriNodes]/page'; export const runtime = 'edge'; @@ -13,8 +16,22 @@ export const size = { export const contentType = 'image/png'; -export default async function Image() { - const metadata = await getSiteMetadata(); +export async function GET(request, { params }) { + const resolvedUri = `/${params.path.join('/')}`; + const node = await getNodeByUri(resolvedUri); + + const Component = templates[node.__typename] || templates.Page; + const { template } = Component; + + const [nodeData, metadata] = await Promise.all([ + getTemplateDataByNode({ + template, + node, + }), + getSiteMetadata(), + ]); + + const data = typeof template.transformer === 'function' ? template.transformer(nodeData?.data) : nodeData?.data; let website = metadata.url.replace(/https?:\/\//, ''); @@ -53,7 +70,7 @@ export default async function Image() { textAlign: 'center', }} > - Post Title Post Title Post Title Post TitlePost Title Post Title Post Title Post Title Post Title + {data.title}