From 5e3466f88bd8072312dc8b517cf1f461161f7e62 Mon Sep 17 00:00:00 2001 From: William Grant Date: Sun, 19 Sep 2021 09:50:37 +1000 Subject: [PATCH 1/8] updated metadata constants --- constants/metadata.tsx | 66 +++++++++++++++++++++++++++++++++----- pages/_app.tsx | 2 +- pages/blog/[[...page]].tsx | 16 ++++++--- pages/faq.tsx | 11 ++++--- pages/index.tsx | 28 ++++++---------- pages/roadmap.tsx | 11 ++++--- pages/tag/[...slug].tsx | 16 ++++++--- utils/metadata.ts | 6 ++-- utils/rss.ts | 6 ++-- 9 files changed, 109 insertions(+), 53 deletions(-) diff --git a/constants/metadata.tsx b/constants/metadata.tsx index 1802008..6879480 100644 --- a/constants/metadata.tsx +++ b/constants/metadata.tsx @@ -1,20 +1,70 @@ +export interface IMetadata { + DESCRIPTION: string; + TYPE?: string; + OG_IMAGE?: { + URL: string; + WIDTH: number; + HEIGHT: number; + ALT: string; + }; + TAGS?: string[]; + ARTICLE_SECTION?: string; + PUBLISHED_TIME?: string; +} + const METADATA = { - OXEN_HOST_URL: 'https://oxen.io', - TITLE_SUFFIX: 'Oxen | Privacy made simple.', - SITE_META_DESCRIPTION: + HOST_URL: 'https://oxen.io', + SITE_NAME: 'Oxen', + TITLE: 'Oxen | Privacy made simple.', + DESCRIPTION: 'Oxen is built by the OPTF, a passionate team of advocates, creatives, and engineers building a world where the internet is open, software is free and accessible, and your privacy is protected. The OPTF also builds other platforms using Oxen technology, and supports other developers in building on Oxen.', - ROADMAP: { - DESCRIPTION: "View Oxen's plan for the future here.", + TAGS: [ + 'Privacy', + 'decentralisation', + 'decentralised', + 'Open Source', + 'Private messaging', + 'Onion routing', + 'Cryptocurrency', + 'Digital finance', + 'Privacy Tools', + ], + OG_TYPE: 'website', + OG_IMAGE: { + URL: '/site-banner.png', + WIDTH: 800, + HEIGHT: 450, + ALT: 'Oxen Logo Blue Background', }, + LOCALE: 'en_US', + FAVICON: { + MEDIUM: '/favicon-32x32.png', + SMALL: '/favicon-16x16.png', + APPLE_TOUCH_ICON: '/apple-touch-icon.png', + }, + MANIFEST: '/site.webmanifest', + MASK_ICON: { PATH: '/safari-pinned-tab.svg', COLOR: '#5bbad5' }, + MSAPPLICATION_TILECOLOR: '#343132', + THEME_COLOR: '#ffffff', 404: { DESCRIPTION: "Oopsy, here's our 404 page.", }, - BLOG: { + BLOG_PAGE: { + TYPE: 'article', DESCRIPTION: "View Oxen's Blog Updates Here", - URL: 'https://oxen.io/blog', + URL: 'https://oxen.io/blog', // TODO Remove }, - FAQ: { + ROADMAP_PAGE: { + DESCRIPTION: "View Oxen's plan for the future here.", + }, + FAQ_PAGE: { DESCRIPTION: 'View Some Frequently Asked Questions here', + OG_IMAGE: { + URL: '/img/faq.png', + WIDTH: 1920, + HEIGHT: 1080, + ALT: 'Question mark with server boxes surrounding it', + }, }, }; diff --git a/pages/_app.tsx b/pages/_app.tsx index e216815..d9ea378 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -58,7 +58,7 @@ function App({ Component, pageProps }: AppProps) { - {METADATA.TITLE_SUFFIX} + {METADATA.TITLE} {pageTitle} - + - - + + - + diff --git a/pages/faq.tsx b/pages/faq.tsx index 2237fe2..3786982 100644 --- a/pages/faq.tsx +++ b/pages/faq.tsx @@ -39,17 +39,17 @@ function FAQ(props: Props) { NAVIGATION.SIDE_MENU_ITEMS[SideMenuItem.FAQ].href, ); const imagePathLocal = 'img/faq.png'; - const imageURL = `${METADATA.OXEN_HOST_URL}/${imagePathLocal}`; + const imageURL = `${METADATA.HOST_URL}/${imagePathLocal}`; return ( <> {pageTitle} - + @@ -59,7 +59,10 @@ function FAQ(props: Props) { - + diff --git a/pages/index.tsx b/pages/index.tsx index 105b5a3..69ad2ee 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -10,36 +10,26 @@ import { HomeHero } from '../components/HomeHero'; import { HomeHeroBubble } from '../components/HomeHeroBubble'; export default function Index() { - const imageURL = `${METADATA.OXEN_HOST_URL}/site-banner.png`; + const imageURL = `${METADATA.HOST_URL}/site-banner.png`; return ( <> - {METADATA.TITLE_SUFFIX} - - + {METADATA.TITLE} + + - + - + - - + + diff --git a/pages/roadmap.tsx b/pages/roadmap.tsx index b683ed7..f5cf524 100644 --- a/pages/roadmap.tsx +++ b/pages/roadmap.tsx @@ -24,17 +24,20 @@ function Roadmap() { const pageURL = generateURL( NAVIGATION.SIDE_MENU_ITEMS[SideMenuItem.ROADMAP].href, ); - const imageURL = `${METADATA.OXEN_HOST_URL}/site-banner.png`; + const imageURL = `${METADATA.HOST_URL}/site-banner.png`; return ( <> {pageTitle} - + @@ -45,7 +48,7 @@ function Roadmap() { diff --git a/pages/tag/[...slug].tsx b/pages/tag/[...slug].tsx index 74176dc..aa03a7c 100644 --- a/pages/tag/[...slug].tsx +++ b/pages/tag/[...slug].tsx @@ -49,20 +49,26 @@ export default function Tag(props: Props): ReactElement { <> {pageTitle} - + - - + + - + diff --git a/utils/metadata.ts b/utils/metadata.ts index de125fa..3af7a9e 100644 --- a/utils/metadata.ts +++ b/utils/metadata.ts @@ -2,11 +2,9 @@ import { METADATA } from '../constants'; import { titleCase } from './text'; export function generateTitle(prefix: string) { - return prefix - ? `${titleCase(prefix)} - ${METADATA.TITLE_SUFFIX}` - : METADATA.TITLE_SUFFIX; + return prefix ? `${titleCase(prefix)} - ${METADATA.TITLE}` : METADATA.TITLE; } export function generateURL(prefix: string) { - return prefix ? `${METADATA.OXEN_HOST_URL}${prefix}` : METADATA.OXEN_HOST_URL; + return prefix ? `${METADATA.HOST_URL}${prefix}` : METADATA.HOST_URL; } diff --git a/utils/rss.ts b/utils/rss.ts index 5dbe3b7..ccd9a3f 100644 --- a/utils/rss.ts +++ b/utils/rss.ts @@ -4,7 +4,7 @@ import { documentToHtmlString } from '@contentful/rich-text-html-renderer'; import { IPost } from '../types/cms'; import { METADATA } from '../constants'; -const baseUrl = METADATA.OXEN_HOST_URL; +const baseUrl = METADATA.HOST_URL; const categories = [ 'Privacy', 'decentralisation', @@ -18,8 +18,8 @@ const categories = [ ]; const date = new Date(); const feed = new Feed({ - title: METADATA.TITLE_SUFFIX, - description: METADATA.SITE_META_DESCRIPTION, + title: METADATA.TITLE, + description: METADATA.DESCRIPTION, id: baseUrl, link: baseUrl, language: 'en', // optional, used only in RSS 2.0, possible values: http://www.w3.org/TR/REC-html40/struct/dirlang.html#langcodes From cc02dc57988d2fc33163c6aadc82267f31d57ceb Mon Sep 17 00:00:00 2001 From: William Grant Date: Sun, 19 Sep 2021 10:21:42 +1000 Subject: [PATCH 2/8] added CustomHead component, updated _app and _document --- components/CustomHead.tsx | 199 ++++++++++++++++++++++++++++++++++++++ pages/_app.tsx | 16 +-- pages/_document.tsx | 65 +++---------- utils/metadata.ts | 1 + 4 files changed, 219 insertions(+), 62 deletions(-) create mode 100644 components/CustomHead.tsx diff --git a/components/CustomHead.tsx b/components/CustomHead.tsx new file mode 100644 index 0000000..ab63a9b --- /dev/null +++ b/components/CustomHead.tsx @@ -0,0 +1,199 @@ +import { ReactElement } from 'react'; +import Head from 'next/head'; +import { useRouter } from 'next/router'; +import METADATA, { IMetadata } from '../constants/metadata'; +import { isLocal } from '..//utils/links'; +import { titleCase } from '../utils/text'; + +interface Props { + title?: string; + metadata?: IMetadata; +} + +export default function CustomHead(props: Props): ReactElement { + const router = useRouter(); + const { title, metadata } = props; + const pageTitle = + title && title.length > 0 + ? `${titleCase(title)} - ${METADATA.TITLE}` + : METADATA.TITLE; + const pageUrl = `${METADATA.HOST_URL}${router.asPath}`; + const imageUrl = (() => { + if (!metadata?.OG_IMAGE?.URL) + return `${METADATA.HOST_URL}${METADATA.OG_IMAGE.URL}`; + if (metadata?.OG_IMAGE?.URL && isLocal(metadata.OG_IMAGE.URL)) { + return `${METADATA.HOST_URL}${metadata.OG_IMAGE.URL}`; + } else { + return `${metadata?.OG_IMAGE?.URL}`; + } + })(); + const tags = metadata?.TAGS ? metadata?.TAGS : METADATA.TAGS; + const renderTags = (() => { + const keywords = ; + if (metadata?.TYPE !== 'article') return keywords; + return ( + <> + {tags.map((tag, index) => { + return ( + + ); + })} + + {metadata?.PUBLISHED_TIME && ( + + )} + {keywords} + + ); + })(); + const renderLdJSON = (() => { + const ldjson = `{ + "@context": "https://schema.org", + "@graph": [ + { + "@type": "WebSite", + "@id": "${METADATA.HOST_URL}/#website", + "url": "${pageUrl}", + "name": "${METADATA.SITE_NAME}", + "description": "${METADATA.DESCRIPTION}" + }, + { + "@type": "ImageObject", + "@id": "${pageUrl}#primaryimage", + "url": "${imageUrl}", + "width": "${String( + metadata?.OG_IMAGE?.WIDTH ?? METADATA.OG_IMAGE.WIDTH, + )}", + "height": "${String( + metadata?.OG_IMAGE?.HEIGHT ?? METADATA.OG_IMAGE.HEIGHT, + )}" + }, + { + "@type": "WebPage", + "@id": "${pageUrl}#webpage", + "url": "${pageUrl}", + "inLanguage": "${METADATA.LOCALE}", + "name": "${pageTitle}", + "isPartOf": { "@id": "${METADATA.HOST_URL}/#website" }, + "primaryImageOfPage": { + "@id": "${pageUrl}#primaryimage" + }, + "datePublished": "${metadata?.PUBLISHED_TIME ?? ''}", + "description": "${METADATA.DESCRIPTION}" + } + ] + }`; + return ( +