Merge branch 'master' of https://github.com/lucasPDY/oxen-website into add-faq
This commit is contained in:
commit
4fc0d4c30e
|
@ -13,7 +13,7 @@ interface Props {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function CardGrid({ rows, children }: Props) {
|
export function CardGrid({ rows, children }: Props) {
|
||||||
const { isMobile, isDesktop, isHuge } = useContext(ScreenContext);
|
const { isDesktop, isHuge } = useContext(ScreenContext);
|
||||||
|
|
||||||
const [ref, { width }] = useMeasure();
|
const [ref, { width }] = useMeasure();
|
||||||
const widthOfCardPx = 200;
|
const widthOfCardPx = 200;
|
||||||
|
@ -37,25 +37,7 @@ export function CardGrid({ rows, children }: Props) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{isMobile ? (
|
{
|
||||||
<div className="">
|
|
||||||
<HorizontalScrollable>
|
|
||||||
{children.map(child => (
|
|
||||||
<div
|
|
||||||
key={uuid()}
|
|
||||||
style={{
|
|
||||||
width: '80vw',
|
|
||||||
minWidth: '275px',
|
|
||||||
maxWidth: '330px',
|
|
||||||
}}
|
|
||||||
className="py-4"
|
|
||||||
>
|
|
||||||
{child}
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</HorizontalScrollable>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<Contained>
|
<Contained>
|
||||||
<div ref={ref} className={classNames('flex flex-col', spacingY)}>
|
<div ref={ref} className={classNames('flex flex-col', spacingY)}>
|
||||||
{_.chunk(cards, grouping).map(group => (
|
{_.chunk(cards, grouping).map(group => (
|
||||||
|
@ -69,7 +51,7 @@ export function CardGrid({ rows, children }: Props) {
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</Contained>
|
</Contained>
|
||||||
)}
|
}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,8 +60,8 @@ export function MobileHeader() {
|
||||||
<TriangleSVG
|
<TriangleSVG
|
||||||
onClick={() => toggleSideMenu()}
|
onClick={() => toggleSideMenu()}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'h-3 fill-current text-primary transform outline-none duration-300 cursor-pointer',
|
'h-4 fill-current text-primary transform outline-none duration-300 cursor-pointer',
|
||||||
sideMenuExpanded ? 'rotate-180' : '-rotate-60',
|
sideMenuExpanded ? 'rotate-90' : '',
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
@ -71,8 +71,8 @@ export function MobileHeader() {
|
||||||
<TriangleSVG
|
<TriangleSVG
|
||||||
onClick={() => toggleMobileMenu()}
|
onClick={() => toggleMobileMenu()}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'h-4 transform outline-none duration-300 cursor-pointer',
|
'h-4 fill-current text-primary transform outline-none duration-300 cursor-pointer',
|
||||||
headerMobileMenuExpanded ? '-rotate-90' : 'rotate-90',
|
headerMobileMenuExpanded ? 'rotate-90' : '',
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<MobileMenu />
|
<MobileMenu />
|
||||||
|
|
|
@ -59,7 +59,7 @@ export function SideMenuInner() {
|
||||||
{!isDesktop && (
|
{!isDesktop && (
|
||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'flex flex-col pt-8 font-medium uppercase font-prompt text-lg',
|
'flex flex-col pt-8 pl-6 font-medium uppercase font-prompt text-lg',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{_.chunk(NAVIGATION.MENU_ITEMS, 2).map(group => (
|
{_.chunk(NAVIGATION.MENU_ITEMS, 2).map(group => (
|
||||||
|
@ -80,28 +80,32 @@ export function SideMenuInner() {
|
||||||
<div className="px-6 pb-3">
|
<div className="px-6 pb-3">
|
||||||
<SocialsRow />
|
<SocialsRow />
|
||||||
|
|
||||||
<div className="flex items-center justify-between font-medium text-secondary whitespace-nowrap">
|
<div className="flex items-center justify-between font-medium whitespace-nowrap">
|
||||||
View Oxen on{' '}
|
<a
|
||||||
<div className="flex items-center">
|
href="/downloads/oxen-media-kit.zip"
|
||||||
<a
|
target="_blank"
|
||||||
href="https://www.coingecko.com/en/coins/oxen"
|
className="flex items-center space-x-1 hover:underline hover:text-secondary"
|
||||||
target="_blank"
|
>
|
||||||
rel="dofollow"
|
<span>Media Kit</span>
|
||||||
className="flex items-center mx-2 space-x-1 font-bold hover:underline"
|
</a>
|
||||||
>
|
<a
|
||||||
<img className="h-5" src="/img/coingecko.png" />
|
href="https://coinmarketcap.com/currencies/oxen/"
|
||||||
<span>CoinGecko</span>
|
target="_blank"
|
||||||
</a>
|
rel="nofollow"
|
||||||
<a
|
className="flex items-center space-x-1 hover:underline hover:text-secondary"
|
||||||
href="https://coinmarketcap.com/currencies/oxen/"
|
>
|
||||||
target="_blank"
|
<img className="h-5" src="/img/coinmarketcap.png" />
|
||||||
rel="dofollow"
|
<span>CMC</span>
|
||||||
className="flex items-center mx-2 space-x-1 font-bold hover:underline"
|
</a>
|
||||||
>
|
<a
|
||||||
<img className="h-5" src="/img/coinmarketcap.png" />
|
href="https://www.coingecko.com/en/coins/oxen"
|
||||||
<span>CMC</span>
|
target="_blank"
|
||||||
</a>
|
rel="nofollow"
|
||||||
</div>
|
className="flex items-center space-x-1 hover:underline hover:text-secondary"
|
||||||
|
>
|
||||||
|
<img className="h-5" src="/img/coingecko.png" />
|
||||||
|
<span>CoinGecko</span>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
|
@ -114,13 +118,13 @@ export function SideMenuInner() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const SocialsRow = () => {
|
const SocialsRow = () => {
|
||||||
const { isDesktop } = useContext(ScreenContext);
|
const { isTablet } = useContext(ScreenContext);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'flex pt-3 pb-3 space-x-3 justify-between',
|
'flex pt-3 pb-3',
|
||||||
isDesktop && 'justify-between',
|
isTablet ? 'justify-start space-x-5 px-6' : 'justify-between',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<a href="https://t.me/Oxen_Community" target="_blank" rel="noreferrer">
|
<a href="https://t.me/Oxen_Community" target="_blank" rel="noreferrer">
|
||||||
|
|
|
@ -1,6 +1,18 @@
|
||||||
const METADATA = {
|
const METADATA = {
|
||||||
OXEN_HOST_URL: 'https://oxen.io',
|
OXEN_HOST_URL: 'https://oxen.io',
|
||||||
TITLE_SUFFIX: 'Oxen | Privacy made simple.',
|
TITLE_SUFFIX: 'Oxen | Privacy made simple.',
|
||||||
|
SITE_META_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.",
|
||||||
|
},
|
||||||
|
404: {
|
||||||
|
DESCRIPTION: "Oopsy, here's our 404 page.",
|
||||||
|
},
|
||||||
|
BLOG: {
|
||||||
|
DESCRIPTION: "View Oxen's Blog Updates Here",
|
||||||
|
URL: 'https://oxen.io/blog',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default METADATA;
|
export default METADATA;
|
||||||
|
|
|
@ -127,8 +127,6 @@ const NAVIGATION = {
|
||||||
SIDE_MENU_ITEMS,
|
SIDE_MENU_ITEMS,
|
||||||
BLOG_REGEX: /^\/(blog)([?tag=[\w-]*)?([?&]page=[0-9]{1,3})?/,
|
BLOG_REGEX: /^\/(blog)([?tag=[\w-]*)?([?&]page=[0-9]{1,3})?/,
|
||||||
POST_REGEX: /^\/(blog\/)(([\w-]{1,100})|(\[slug\]))$/,
|
POST_REGEX: /^\/(blog\/)(([\w-]{1,100})|(\[slug\]))$/,
|
||||||
SITE_META_DESCRIPTION:
|
|
||||||
'Oxen is built by the Loki Foundation, 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 Loki Foundation also builds other platforms using Oxen technology, and supports other developers in building on Oxen.',
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default NAVIGATION;
|
export default NAVIGATION;
|
||||||
|
|
|
@ -2,9 +2,9 @@ import classNames from 'classnames';
|
||||||
import Head from 'next/head';
|
import Head from 'next/head';
|
||||||
import React, { useContext } from 'react';
|
import React, { useContext } from 'react';
|
||||||
// import _404 from '../assets/svgs/404.svg';
|
// import _404 from '../assets/svgs/404.svg';
|
||||||
import { UI } from '../constants';
|
import { UI, METADATA } from '../constants';
|
||||||
import { ScreenContext } from '../contexts/screen';
|
import { ScreenContext } from '../contexts/screen';
|
||||||
import { generateTitle } from '../utils/metadata';
|
import { generateTitle, generateURL } from '../utils/metadata';
|
||||||
|
|
||||||
function oxen404() {
|
function oxen404() {
|
||||||
const { isMobile, isTablet, isDesktop, isHuge } = useContext(ScreenContext);
|
const { isMobile, isTablet, isDesktop, isHuge } = useContext(ScreenContext);
|
||||||
|
@ -47,10 +47,24 @@ function oxen404() {
|
||||||
width: '9rem',
|
width: '9rem',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const pageTitle = generateTitle('404');
|
||||||
|
const pageURL = generateURL('/404');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center justify-center flex-grow h-full">
|
<div className="flex items-center justify-center flex-grow h-full">
|
||||||
<Head>
|
<Head>
|
||||||
<title>{generateTitle('404')}</title>
|
<title>{pageTitle}</title>
|
||||||
|
<meta name="description" content={METADATA['404'].DESCRIPTION}></meta>
|
||||||
|
<meta property="og:title" content={pageTitle} key="ogtitle" />
|
||||||
|
<meta
|
||||||
|
property="og:description"
|
||||||
|
content={METADATA['404'].DESCRIPTION}
|
||||||
|
key="ogdesc"
|
||||||
|
/>
|
||||||
|
<meta property="og:type" content="website" />
|
||||||
|
<meta property="og:url" content={pageURL} />
|
||||||
|
|
||||||
|
<link rel="canonical" href={pageURL}></link>
|
||||||
</Head>
|
</Head>
|
||||||
|
|
||||||
<div style={wrapperStyles} className="flex items-center flex-grow">
|
<div style={wrapperStyles} className="flex items-center flex-grow">
|
||||||
|
@ -65,13 +79,13 @@ function oxen404() {
|
||||||
<div style={_404SectionStyles} className="absolute left-0 z-50">
|
<div style={_404SectionStyles} className="absolute left-0 z-50">
|
||||||
<h1
|
<h1
|
||||||
style={_404TitleStyles}
|
style={_404TitleStyles}
|
||||||
className="-mb-4 text-opacity-25 font-sans text-primary text-8xl"
|
className="-mb-4 font-sans text-opacity-25 text-primary text-8xl"
|
||||||
>
|
>
|
||||||
404
|
404
|
||||||
</h1>
|
</h1>
|
||||||
<p
|
<p
|
||||||
style={_404TextStyles}
|
style={_404TextStyles}
|
||||||
className="text-4xl tracking-tight font-sans text-primary"
|
className="font-sans text-4xl tracking-tight text-primary"
|
||||||
>
|
>
|
||||||
Nothing found here.
|
Nothing found here.
|
||||||
</p>
|
</p>
|
||||||
|
|
|
@ -4,11 +4,11 @@ import React, { useEffect } from 'react';
|
||||||
import { useDispatch } from 'react-redux';
|
import { useDispatch } from 'react-redux';
|
||||||
import { Contained } from '../components/Contained';
|
import { Contained } from '../components/Contained';
|
||||||
import { RichBody } from '../components/RichBody';
|
import { RichBody } from '../components/RichBody';
|
||||||
import { NAVIGATION } from '../constants';
|
import { NAVIGATION, METADATA } from '../constants';
|
||||||
import { CmsApi, unslugify } from '../services/cms';
|
import { CmsApi, unslugify } from '../services/cms';
|
||||||
import { PageType, setPageType, SideMenuItem } from '../state/navigation';
|
import { PageType, setPageType, SideMenuItem } from '../state/navigation';
|
||||||
import { ISplitPage } from '../types/cms';
|
import { ISplitPage } from '../types/cms';
|
||||||
import { generateTitle } from '../utils/metadata';
|
import { generateTitle, generateURL } from '../utils/metadata';
|
||||||
|
|
||||||
interface IPath {
|
interface IPath {
|
||||||
params: { page: string; isRoadmap?: boolean };
|
params: { page: string; isRoadmap?: boolean };
|
||||||
|
@ -19,7 +19,6 @@ export async function getStaticPaths() {
|
||||||
// Hardcoded in navigation constants.
|
// Hardcoded in navigation constants.
|
||||||
// Contentful can edit entries but cannot add/remove
|
// Contentful can edit entries but cannot add/remove
|
||||||
// without touching code.
|
// without touching code.
|
||||||
|
|
||||||
const paths: IPath[] = Object.values(NAVIGATION.SIDE_MENU_ITEMS).map(
|
const paths: IPath[] = Object.values(NAVIGATION.SIDE_MENU_ITEMS).map(
|
||||||
item => ({
|
item => ({
|
||||||
params: { page: item.href },
|
params: { page: item.href },
|
||||||
|
@ -30,8 +29,8 @@ export async function getStaticPaths() {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getStaticProps({ params }) {
|
export async function getStaticProps({ params }) {
|
||||||
const id = unslugify(String(params?.page) ?? '');
|
const href = params?.page ?? '';
|
||||||
|
const id = unslugify(String(href));
|
||||||
// Roadmap page is special 👁️👄👁️
|
// Roadmap page is special 👁️👄👁️
|
||||||
if (SideMenuItem[id] == [SideMenuItem.ROADMAP]) {
|
if (SideMenuItem[id] == [SideMenuItem.ROADMAP]) {
|
||||||
// query all FAQ items from contentful
|
// query all FAQ items from contentful
|
||||||
|
@ -39,6 +38,7 @@ export async function getStaticProps({ params }) {
|
||||||
props: {
|
props: {
|
||||||
page: null,
|
page: null,
|
||||||
isRoadmap: true,
|
isRoadmap: true,
|
||||||
|
href: `/${href}`, // the '/' is removed from the href from getStaticPaths(), so let's add it back here
|
||||||
},
|
},
|
||||||
revalidate: 60,
|
revalidate: 60,
|
||||||
};
|
};
|
||||||
|
@ -57,7 +57,6 @@ export async function getStaticProps({ params }) {
|
||||||
|
|
||||||
const cms = new CmsApi();
|
const cms = new CmsApi();
|
||||||
const page = await cms.fetchPageById(SideMenuItem[id]);
|
const page = await cms.fetchPageById(SideMenuItem[id]);
|
||||||
|
|
||||||
if (!page) {
|
if (!page) {
|
||||||
return { notFound: true };
|
return { notFound: true };
|
||||||
}
|
}
|
||||||
|
@ -66,6 +65,7 @@ export async function getStaticProps({ params }) {
|
||||||
props: {
|
props: {
|
||||||
page,
|
page,
|
||||||
isRoadmap: false,
|
isRoadmap: false,
|
||||||
|
href: `/${href}`,
|
||||||
},
|
},
|
||||||
revalidate: 60,
|
revalidate: 60,
|
||||||
};
|
};
|
||||||
|
@ -74,25 +74,54 @@ export async function getStaticProps({ params }) {
|
||||||
function Page({
|
function Page({
|
||||||
page,
|
page,
|
||||||
isRoadmap,
|
isRoadmap,
|
||||||
|
href,
|
||||||
}: {
|
}: {
|
||||||
page: ISplitPage | null;
|
page: ISplitPage | null;
|
||||||
isRoadmap?: boolean;
|
isRoadmap?: boolean;
|
||||||
|
href: string;
|
||||||
}) {
|
}) {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
dispatch(setPageType(PageType.NORMAL));
|
dispatch(setPageType(PageType.NORMAL));
|
||||||
}, []);
|
}, []);
|
||||||
|
const pageTitle = generateTitle(
|
||||||
|
isRoadmap
|
||||||
|
? NAVIGATION.SIDE_MENU_ITEMS[SideMenuItem.ROADMAP].label
|
||||||
|
: page?.label,
|
||||||
|
);
|
||||||
|
|
||||||
|
const pageDescription = isRoadmap
|
||||||
|
? METADATA.ROADMAP.DESCRIPTION
|
||||||
|
: page?.title;
|
||||||
|
|
||||||
|
const pageURL = generateURL(
|
||||||
|
isRoadmap ? NAVIGATION.SIDE_MENU_ITEMS[SideMenuItem.ROADMAP].href : href,
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Head>
|
<Head>
|
||||||
<title>
|
<title>{pageTitle}</title>
|
||||||
{generateTitle(
|
<meta name="description" content={pageDescription}></meta>
|
||||||
isRoadmap
|
<meta property="og:title" content={pageTitle} key="ogtitle" />
|
||||||
? NAVIGATION.SIDE_MENU_ITEMS[SideMenuItem.ROADMAP].label
|
<meta
|
||||||
: page?.label,
|
property="og:description"
|
||||||
)}
|
content={pageDescription}
|
||||||
</title>
|
key="ogdesc"
|
||||||
|
/>
|
||||||
|
<meta property="og:type" content="website" />
|
||||||
|
<meta
|
||||||
|
property="og:image"
|
||||||
|
content={page?.hero?.imageUrl}
|
||||||
|
key="ogimage"
|
||||||
|
/>
|
||||||
|
<meta property="og:url" content={pageURL} />
|
||||||
|
|
||||||
|
<link rel="canonical" href={pageURL}></link>
|
||||||
|
<meta name="twitter:card" content="summary_large_image" />
|
||||||
|
<meta name="twitter:title" content={pageTitle} />
|
||||||
|
<meta name="twitter:description" content={pageDescription} />
|
||||||
|
<meta name="twitter:image" content={page?.hero?.imageUrl} />
|
||||||
</Head>
|
</Head>
|
||||||
|
|
||||||
<div className="bg-alt">
|
<div className="bg-alt">
|
||||||
|
|
|
@ -63,6 +63,9 @@ function App({ Component, pageProps }: AppProps) {
|
||||||
name="viewport"
|
name="viewport"
|
||||||
content="width=device-width, initial-scale=1, maximum-scale=1"
|
content="width=device-width, initial-scale=1, maximum-scale=1"
|
||||||
></meta>
|
></meta>
|
||||||
|
<meta property="og:site_name" content="Oxen" key="ogsitename" />
|
||||||
|
<meta property="og:locale" content="en_US" />
|
||||||
|
<meta name="apple-itunes-app" content="app-id=1547745078" />
|
||||||
</Head>
|
</Head>
|
||||||
|
|
||||||
<Layout>
|
<Layout>
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { Article } from '../../components/article/Article';
|
||||||
import { CmsApi } from '../../services/cms';
|
import { CmsApi } from '../../services/cms';
|
||||||
import { PageType, setPageType, setPostTitle } from '../../state/navigation';
|
import { PageType, setPageType, setPostTitle } from '../../state/navigation';
|
||||||
import { IPost } from '../../types/cms';
|
import { IPost } from '../../types/cms';
|
||||||
import { generateTitle } from '../../utils/metadata';
|
import { generateTitle, generateURL } from '../../utils/metadata';
|
||||||
|
|
||||||
interface IPath {
|
interface IPath {
|
||||||
params: { slug: string };
|
params: { slug: string };
|
||||||
|
@ -43,7 +43,7 @@ export async function getStaticProps({ params }) {
|
||||||
|
|
||||||
const cms = new CmsApi();
|
const cms = new CmsApi();
|
||||||
const post = await cms.fetchBlogBySlug(String(params?.slug) ?? '');
|
const post = await cms.fetchBlogBySlug(String(params?.slug) ?? '');
|
||||||
|
const url = generateURL(params?.slug ? `/blog/${params?.slug}` : '/blog');
|
||||||
if (!post) {
|
if (!post) {
|
||||||
return { notFound: true };
|
return { notFound: true };
|
||||||
}
|
}
|
||||||
|
@ -51,13 +51,14 @@ export async function getStaticProps({ params }) {
|
||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
post,
|
post,
|
||||||
|
url,
|
||||||
},
|
},
|
||||||
revalidate: 60,
|
revalidate: 60,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parallax on bg as mouse moves
|
// Parallax on bg as mouse moves
|
||||||
function Post({ post }: { post: IPost }) {
|
function Post({ post, url }: { post: IPost; url: string }) {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -66,28 +67,30 @@ function Post({ post }: { post: IPost }) {
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const pageTitle = generateTitle(post?.title);
|
const pageTitle = generateTitle(post?.title);
|
||||||
|
const imageURL = post?.featureImage?.imageUrl;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Head>
|
<Head>
|
||||||
<title>{pageTitle}</title>
|
<title>{pageTitle}</title>
|
||||||
|
<meta name="description" content={post?.description}></meta>
|
||||||
<meta name="image_src" content={post?.featureImage?.imageUrl} />
|
|
||||||
<meta name="image_url" content={post?.featureImage?.imageUrl} />
|
|
||||||
<meta name="keywords" content={post?.tags?.join(' ')} />
|
|
||||||
<meta
|
|
||||||
property="og:image"
|
|
||||||
content={post?.featureImage?.imageUrl}
|
|
||||||
key="ogimage"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<meta property="og:site_name" content="oxen.io" key="ogsitename" />
|
|
||||||
<meta property="og:title" content={pageTitle} key="ogtitle" />
|
<meta property="og:title" content={pageTitle} key="ogtitle" />
|
||||||
<meta
|
<meta
|
||||||
property="og:description"
|
property="og:description"
|
||||||
content={post?.description}
|
content={post?.description}
|
||||||
key="ogdesc"
|
key="ogdesc"
|
||||||
/>
|
/>
|
||||||
|
<meta property="og:type" content="article" />
|
||||||
|
<meta name="image_src" content={imageURL} />
|
||||||
|
<meta name="image_url" content={imageURL} />
|
||||||
|
<meta name="keywords" content={post?.tags?.join(' ')} />
|
||||||
|
<meta property="og:image" content={imageURL} key="ogimage" />
|
||||||
|
<meta property="og:url" content={url} />
|
||||||
|
<link rel="canonical" href={url}></link>{' '}
|
||||||
|
<meta name="twitter:card" content="summary_large_image" />
|
||||||
|
<meta name="twitter:title" content={pageTitle} />
|
||||||
|
<meta name="twitter:description" content={post?.description} />
|
||||||
|
<meta name="twitter:image" content={imageURL} />
|
||||||
</Head>
|
</Head>
|
||||||
|
|
||||||
<div className="bg-alt">
|
<div className="bg-alt">
|
||||||
|
|
|
@ -9,7 +9,7 @@ import { ArticleCardFeature } from '../../components/cards/ArticleCardFeature';
|
||||||
import { CardGrid } from '../../components/cards/CardGrid';
|
import { CardGrid } from '../../components/cards/CardGrid';
|
||||||
import { Contained } from '../../components/Contained';
|
import { Contained } from '../../components/Contained';
|
||||||
import { TagBlock } from '../../components/TagBlock';
|
import { TagBlock } from '../../components/TagBlock';
|
||||||
import { CMS } from '../../constants';
|
import { CMS, METADATA } from '../../constants';
|
||||||
import { CmsApi } from '../../services/cms';
|
import { CmsApi } from '../../services/cms';
|
||||||
import { PageType, setPageType } from '../../state/navigation';
|
import { PageType, setPageType } from '../../state/navigation';
|
||||||
import { IPost } from '../../types/cms';
|
import { IPost } from '../../types/cms';
|
||||||
|
@ -131,10 +131,28 @@ const Blog = (props: Props) => {
|
||||||
</Contained>
|
</Contained>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const pageTitle = generateTitle('Blog');
|
||||||
|
const featuredImageURL = featuredPost?.featureImage?.imageUrl;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Head>
|
<Head>
|
||||||
<title>{generateTitle('Blog')}</title>
|
<title>{pageTitle}</title>
|
||||||
|
<meta name="description" content={METADATA.BLOG.DESCRIPTION}></meta>
|
||||||
|
<meta property="og:title" content={pageTitle} key="ogtitle" />
|
||||||
|
<meta
|
||||||
|
property="og:description"
|
||||||
|
content={METADATA.BLOG.DESCRIPTION}
|
||||||
|
key="ogdesc"
|
||||||
|
/>
|
||||||
|
<meta property="og:type" content="website" />
|
||||||
|
<meta property="og:image" content={featuredImageURL} key="ogimage" />
|
||||||
|
<meta property="og:url" content={METADATA.BLOG.URL} />
|
||||||
|
<link rel="canonical" href={METADATA.BLOG.URL}></link>
|
||||||
|
<meta name="twitter:card" content="summary_large_image" />
|
||||||
|
<meta name="twitter:title" content={pageTitle} />
|
||||||
|
<meta name="twitter:description" content={METADATA.BLOG.DESCRIPTION} />
|
||||||
|
<meta name="twitter:image" content={featuredImageURL} />
|
||||||
</Head>
|
</Head>
|
||||||
|
|
||||||
<div className="flex flex-col w-full mt-12 mb-6 space-y-6 bg-alt">
|
<div className="flex flex-col w-full mt-12 mb-6 space-y-6 bg-alt">
|
||||||
|
|
|
@ -2,26 +2,40 @@ import Head from 'next/head';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { HomeHero } from '../components/HomeHero';
|
import { HomeHero } from '../components/HomeHero';
|
||||||
import { HomeHeroBubble } from '../components/HomeHeroBubble';
|
import { HomeHeroBubble } from '../components/HomeHeroBubble';
|
||||||
import { METADATA, NAVIGATION } from '../constants';
|
import { METADATA } from '../constants';
|
||||||
|
|
||||||
const Index = () => {
|
const Index = () => {
|
||||||
|
const imageURL = `${METADATA.OXEN_HOST_URL}/site-banner.png`;
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Head>
|
<Head>
|
||||||
<title>{METADATA.TITLE_SUFFIX}</title>
|
<title>{METADATA.TITLE_SUFFIX}</title>
|
||||||
|
<meta
|
||||||
|
name="description"
|
||||||
|
content={METADATA.SITE_META_DESCRIPTION}
|
||||||
|
></meta>
|
||||||
<meta
|
<meta
|
||||||
property="og:title"
|
property="og:title"
|
||||||
content="Oxen - Privacy should be simple."
|
content={METADATA.TITLE_SUFFIX}
|
||||||
key="title"
|
key="ogtitle"
|
||||||
/>
|
/>
|
||||||
<meta property="og:image" content={'site-banner.png'} key="ogimage" />
|
|
||||||
<meta property="og:site_name" content="oxen.io" key="ogsitename" />
|
|
||||||
<meta property="og:title" content={'Oxen'} key="ogtitle" />
|
|
||||||
<meta
|
<meta
|
||||||
property="og:description"
|
property="og:description"
|
||||||
content={NAVIGATION.SITE_META_DESCRIPTION}
|
content={METADATA.SITE_META_DESCRIPTION}
|
||||||
key="ogdesc"
|
key="ogdesc"
|
||||||
/>
|
/>
|
||||||
|
<meta property="og:type" content="website" />
|
||||||
|
<meta property="og:image" content={imageURL} key="ogimage" />
|
||||||
|
<meta property="og:url" content={METADATA.OXEN_HOST_URL} />
|
||||||
|
|
||||||
|
<link rel="canonical" href={METADATA.OXEN_HOST_URL}></link>
|
||||||
|
<meta name="twitter:card" content="summary_large_image" />
|
||||||
|
<meta name="twitter:title" content={METADATA.TITLE_SUFFIX} />
|
||||||
|
<meta
|
||||||
|
name="twitter:description"
|
||||||
|
content={METADATA.SITE_META_DESCRIPTION}
|
||||||
|
/>
|
||||||
|
<meta name="twitter:image" content={imageURL} />
|
||||||
</Head>
|
</Head>
|
||||||
|
|
||||||
{/* Only visible when no pages are open */}
|
{/* Only visible when no pages are open */}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import Head from 'next/head';
|
import Head from 'next/head';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useMeasure } from 'react-use';
|
import { useMeasure } from 'react-use';
|
||||||
import { NAVIGATION } from '../constants';
|
import { NAVIGATION, METADATA } from '../constants';
|
||||||
import { SideMenuItem } from '../state/navigation';
|
import { SideMenuItem } from '../state/navigation';
|
||||||
import { generateTitle } from '../utils/metadata';
|
import { generateTitle, generateURL } from '../utils/metadata';
|
||||||
|
|
||||||
function Roadmap() {
|
function Roadmap() {
|
||||||
const [ref, { width, height }] = useMeasure();
|
const [ref, { width, height }] = useMeasure();
|
||||||
|
@ -18,14 +18,36 @@ function Roadmap() {
|
||||||
console.log('roadmap ➡️ width:', width);
|
console.log('roadmap ➡️ width:', width);
|
||||||
console.log('roadmap ➡️ ratio:', aspectRatio);
|
console.log('roadmap ➡️ ratio:', aspectRatio);
|
||||||
|
|
||||||
|
const pageTitle = generateTitle(
|
||||||
|
NAVIGATION.SIDE_MENU_ITEMS[SideMenuItem.ROADMAP].label,
|
||||||
|
);
|
||||||
|
const pageURL = generateURL(
|
||||||
|
NAVIGATION.SIDE_MENU_ITEMS[SideMenuItem.ROADMAP].href,
|
||||||
|
);
|
||||||
|
const imageURL = `${METADATA.OXEN_HOST_URL}/site-banner.png`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Head>
|
<Head>
|
||||||
<title>
|
<title>{pageTitle}</title>
|
||||||
{generateTitle(
|
<meta name="description" content={METADATA.ROADMAP.DESCRIPTION}></meta>
|
||||||
NAVIGATION.SIDE_MENU_ITEMS[SideMenuItem.ROADMAP].label,
|
<meta property="og:title" content={pageTitle} key="ogtitle" />
|
||||||
)}
|
<meta
|
||||||
</title>
|
property="og:description"
|
||||||
|
content={METADATA.ROADMAP.DESCRIPTION}
|
||||||
|
key="ogdesc"
|
||||||
|
/>
|
||||||
|
<meta property="og:type" content="website" />
|
||||||
|
<meta property="og:url" content={pageURL} />
|
||||||
|
|
||||||
|
<link rel="canonical" href={pageURL}></link>
|
||||||
|
<meta name="twitter:card" content="summary_large_image" />
|
||||||
|
<meta name="twitter:title" content={pageTitle} />
|
||||||
|
<meta
|
||||||
|
name="twitter:description"
|
||||||
|
content={METADATA.ROADMAP.DESCRIPTION}
|
||||||
|
/>
|
||||||
|
<meta name="twitter:image" content={imageURL} />
|
||||||
</Head>
|
</Head>
|
||||||
|
|
||||||
<div className="mx-4">
|
<div className="mx-4">
|
||||||
|
@ -46,7 +68,7 @@ function Roadmap() {
|
||||||
</h2>
|
</h2>
|
||||||
<img
|
<img
|
||||||
style={{ maxHeight: horizontal ? '90%' : 'auto' }}
|
style={{ maxHeight: horizontal ? '90%' : 'auto' }}
|
||||||
src={`img/session-${horizontal ? 'x' : 'y'}.jpg`}
|
src={`img/session-${horizontal ? 'x' : 'y'}.png`}
|
||||||
className="w-full rounded-md"
|
className="w-full rounded-md"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 472 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.7 MiB |
Binary file not shown.
Before Width: | Height: | Size: 267 KiB |
Binary file not shown.
After Width: | Height: | Size: 873 KiB |
|
@ -6,3 +6,7 @@ export function generateTitle(prefix: string) {
|
||||||
? `${titleCase(prefix)} - ${METADATA.TITLE_SUFFIX}`
|
? `${titleCase(prefix)} - ${METADATA.TITLE_SUFFIX}`
|
||||||
: METADATA.TITLE_SUFFIX;
|
: METADATA.TITLE_SUFFIX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function generateURL(prefix: string) {
|
||||||
|
return prefix ? `${METADATA.OXEN_HOST_URL}${prefix}` : METADATA.OXEN_HOST_URL;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue