mirror of
https://github.com/oxen-io/oxen-website.git
synced 2023-12-13 21:00:18 +01:00
commit
f92def3cd3
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -16,6 +16,7 @@
|
|||
|
||||
# production
|
||||
/build
|
||||
/public/rss
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
|
|
5
assets/svgs/socials/rss.svg
Normal file
5
assets/svgs/socials/rss.svg
Normal file
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-12 -10 44 44">
|
||||
<path
|
||||
d="M6.503 20.752c0 1.794-1.456 3.248-3.251 3.248-1.796 0-3.252-1.454-3.252-3.248 0-1.794 1.456-3.248 3.252-3.248 1.795.001 3.251 1.454 3.251 3.248zm-6.503-12.572v4.811c6.05.062 10.96 4.966 11.022 11.009h4.817c-.062-8.71-7.118-15.758-15.839-15.82zm0-3.368c10.58.046 19.152 8.594 19.183 19.188h4.817c-.03-13.231-10.755-23.954-24-24v4.812z" />
|
||||
</svg>
|
After Width: | Height: | Size: 480 B |
|
@ -7,6 +7,7 @@ import { useDispatch, useSelector } from 'react-redux';
|
|||
import { v4 as uuid } from 'uuid';
|
||||
import GithubSVG from '../../assets/svgs/socials/github.svg';
|
||||
import RedditSVG from '../../assets/svgs/socials/reddit.svg';
|
||||
import RssSVG from '../../assets/svgs/socials/rss.svg';
|
||||
import SessionSVG from '../../assets/svgs/socials/session.svg';
|
||||
import TelegramSVG from '../../assets/svgs/socials/telegram.svg';
|
||||
import TwitterSVG from '../../assets/svgs/socials/twitter.svg';
|
||||
|
@ -77,10 +78,10 @@ export function SideMenuInner() {
|
|||
</Contained>
|
||||
|
||||
{isDesktop ? (
|
||||
<div className="px-6 pb-3">
|
||||
<div className="px-3 pb-3">
|
||||
<SocialsRow />
|
||||
|
||||
<div className="flex items-center justify-between font-medium whitespace-nowrap">
|
||||
<div className="flex items-center justify-between px-3 font-medium whitespace-nowrap">
|
||||
<a
|
||||
href="/downloads/oxen-media-kit.zip"
|
||||
target="_blank"
|
||||
|
@ -123,42 +124,45 @@ const SocialsRow = () => {
|
|||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
'flex pt-3 pb-3',
|
||||
'flex pt-4 pb-4',
|
||||
isTablet ? 'justify-start space-x-5 px-6' : 'justify-between',
|
||||
)}
|
||||
>
|
||||
<a href="https://t.me/Oxen_Community" target="_blank" rel="noreferrer">
|
||||
<TelegramSVG className="h-12 placeholder-current duration-300 border rounded-full cursor-pointer fill-current stroke-current tablet:h-10 hover:bg-primary hover:text-secondary border-primary" />
|
||||
<TelegramSVG className="h-10 placeholder-current duration-300 border rounded-full cursor-pointer fill-current stroke-current hover:bg-primary hover:text-secondary border-primary" />
|
||||
</a>
|
||||
<a href="https://twitter.com/Oxen_io" target="_blank" rel="noreferrer">
|
||||
<TwitterSVG className="h-12 placeholder-current duration-300 border rounded-full cursor-pointer fill-current stroke-current tablet:h-10 hover:bg-primary hover:text-secondary border-primary" />
|
||||
<TwitterSVG className="h-10 placeholder-current duration-300 border rounded-full cursor-pointer fill-current stroke-current hover:bg-primary hover:text-secondary border-primary" />
|
||||
</a>
|
||||
<a href="https://github.com/oxen-io" target="_blank" rel="noreferrer">
|
||||
<GithubSVG className="h-12 placeholder-current duration-300 border rounded-full cursor-pointer fill-current stroke-current tablet:h-10 hover:bg-primary hover:text-secondary border-primary" />
|
||||
<GithubSVG className="h-10 placeholder-current duration-300 border rounded-full cursor-pointer fill-current stroke-current hover:bg-primary hover:text-secondary border-primary" />
|
||||
</a>
|
||||
{/* <a
|
||||
href="https://discord.com/invite/67GXfD6"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
<DiscordSVG className="h-12 placeholder-current duration-300 border rounded-full cursor-pointer fill-current stroke-current tablet:h-10 hover:bg-primary hover:text-secondary border-primary" />
|
||||
<DiscordSVG className="h-10 placeholder-current duration-300 border rounded-full cursor-pointer fill-current stroke-current hover:bg-primary hover:text-secondary border-primary" />
|
||||
</a> */}
|
||||
<a
|
||||
href="https://www.youtube.com/channel/UCN7LL0dEffQ7FSjbY5wwlnw"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
<YouTubeSVG className="h-12 placeholder-current duration-300 border rounded-full cursor-pointer fill-current stroke-current tablet:h-10 hover:bg-primary hover:text-secondary border-primary" />
|
||||
<YouTubeSVG className="h-10 placeholder-current duration-300 border rounded-full cursor-pointer fill-current stroke-current hover:bg-primary hover:text-secondary border-primary" />
|
||||
</a>
|
||||
<a
|
||||
href="https://www.reddit.com/r/oxen_io/"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
<RedditSVG className="h-12 placeholder-current duration-300 border rounded-full cursor-pointer fill-current stroke-current tablet:h-10 hover:bg-primary hover:text-secondary border-primary" />
|
||||
<RedditSVG className="h-10 placeholder-current duration-300 border rounded-full cursor-pointer fill-current stroke-current hover:bg-primary hover:text-secondary border-primary" />
|
||||
</a>
|
||||
<a href="https://sessiongroups.com/" target="_blank" rel="noreferrer">
|
||||
<SessionSVG className="h-12 placeholder-current duration-300 border rounded-full cursor-pointer fill-current stroke-current tablet:h-10 hover:bg-primary hover:text-secondary border-primary" />
|
||||
<SessionSVG className="h-10 placeholder-current duration-300 border rounded-full cursor-pointer fill-current stroke-current hover:bg-primary hover:text-secondary border-primary" />
|
||||
</a>
|
||||
<a href="/feed" target="_self" rel="noreferrer">
|
||||
<RssSVG className="h-10 placeholder-current duration-300 border rounded-full cursor-pointer fill-current stroke-current hover:bg-primary hover:text-secondary border-primary" />
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -34,6 +34,19 @@ const nextConfig = {
|
|||
},
|
||||
];
|
||||
},
|
||||
async rewrites() {
|
||||
return [
|
||||
{
|
||||
source: '/feed',
|
||||
destination: '/api/feed/rss',
|
||||
},
|
||||
{
|
||||
// The /:slug part is a generic parameter handler to catch all other cases
|
||||
source: '/feed/:slug',
|
||||
destination: '/api/feed/:slug',
|
||||
},
|
||||
];
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = withPlugins([withFonts, withSvgr], nextConfig);
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@ant-design/icons": "^4.2.2",
|
||||
"@contentful/rich-text-html-renderer": "^15.0.0",
|
||||
"@contentful/rich-text-plain-text-renderer": "^15.0.0",
|
||||
"@contentful/rich-text-react-renderer": "^15.0.0",
|
||||
"@tailwindcss/aspect-ratio": "^0.2.0",
|
||||
|
@ -29,6 +30,7 @@
|
|||
"date-fns": "^2.23.0",
|
||||
"dotenv": "^8.2.0",
|
||||
"eslint-plugin-jsx-a11y": "^6.3.1",
|
||||
"feed": "^4.2.2",
|
||||
"global": "^4.4.0",
|
||||
"groq": "^1.149.16",
|
||||
"himalaya": "^1.1.0",
|
||||
|
|
|
@ -24,6 +24,27 @@ export default class CustomDocument extends Document<any> {
|
|||
sizes="16x16"
|
||||
href="/favicon-16x16.png"
|
||||
/>
|
||||
<link
|
||||
key="rss-feed"
|
||||
rel="alternative"
|
||||
type="application/rss+xml"
|
||||
title="RSS feed for just-be.dev"
|
||||
href="/feed"
|
||||
/>
|
||||
<link
|
||||
key="atom-feed"
|
||||
rel="alternative"
|
||||
type="application/atom+xml"
|
||||
title="Atom feed for just-be.dev"
|
||||
href="/feed/atom"
|
||||
/>
|
||||
<link
|
||||
key="json-feed"
|
||||
rel="alternative"
|
||||
type="application/feed+json"
|
||||
title="JSON feed for just-be.dev"
|
||||
href="/feed/json"
|
||||
/>
|
||||
<link rel="manifest" href="/site.webmanifest" />
|
||||
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5" />
|
||||
<meta name="theme-color" content="#ffffff" />
|
||||
|
|
8
pages/api/feed/atom.ts
Normal file
8
pages/api/feed/atom.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
import { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { readFileSync } from 'fs';
|
||||
|
||||
export default async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
res.statusCode = 200;
|
||||
res.setHeader('content-type', 'application/atom+xml');
|
||||
res.end(readFileSync('./public/rss/atom.xml'));
|
||||
};
|
8
pages/api/feed/json.ts
Normal file
8
pages/api/feed/json.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
import { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { readFileSync } from 'fs';
|
||||
|
||||
export default async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
res.statusCode = 200;
|
||||
res.setHeader('content-type', 'application/feed+json');
|
||||
res.end(readFileSync('./public/rss/feed.json'));
|
||||
};
|
8
pages/api/feed/rss.ts
Normal file
8
pages/api/feed/rss.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
import { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { readFileSync } from 'fs';
|
||||
|
||||
export default async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
res.statusCode = 200;
|
||||
res.setHeader('content-type', 'application/xml');
|
||||
res.end(readFileSync('./public/rss/feed.xml'));
|
||||
};
|
|
@ -1,10 +1,15 @@
|
|||
import { GetStaticProps, GetStaticPropsContext } from 'next';
|
||||
import Head from 'next/head';
|
||||
import React from 'react';
|
||||
|
||||
import { IPost } from '../types/cms';
|
||||
import { CMS, METADATA } from '../constants';
|
||||
import { CmsApi } from '../services/cms';
|
||||
import generateRSSFeed from '../utils/rss';
|
||||
|
||||
import { HomeHero } from '../components/HomeHero';
|
||||
import { HomeHeroBubble } from '../components/HomeHeroBubble';
|
||||
import { METADATA } from '../constants';
|
||||
|
||||
const Index = () => {
|
||||
export default function Index() {
|
||||
const imageURL = `${METADATA.OXEN_HOST_URL}/site-banner.png`;
|
||||
return (
|
||||
<>
|
||||
|
@ -43,6 +48,35 @@ const Index = () => {
|
|||
<HomeHeroBubble />
|
||||
</>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
export default Index;
|
||||
export const getStaticProps: GetStaticProps = async (
|
||||
context: GetStaticPropsContext,
|
||||
) => {
|
||||
if (process.env.NEXT_PUBLIC_SITE_ENV !== 'development') {
|
||||
const cms = new CmsApi();
|
||||
const posts: IPost[] = [];
|
||||
let page = 1;
|
||||
let foundAllPosts = false;
|
||||
|
||||
// Contentful only allows 100 at a time
|
||||
while (!foundAllPosts) {
|
||||
const { entries: _posts } = await cms.fetchBlogEntries(100, page);
|
||||
|
||||
if (_posts.length === 0) {
|
||||
foundAllPosts = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
posts.push(..._posts);
|
||||
page++;
|
||||
}
|
||||
|
||||
generateRSSFeed(posts);
|
||||
}
|
||||
|
||||
return {
|
||||
props: {},
|
||||
revalidate: CMS.CONTENT_REVALIDATE_RATE,
|
||||
};
|
||||
};
|
||||
|
|
57
utils/rss.ts
Normal file
57
utils/rss.ts
Normal file
|
@ -0,0 +1,57 @@
|
|||
import { Feed } from 'feed';
|
||||
import { mkdirSync, writeFileSync } from 'fs';
|
||||
import { documentToHtmlString } from '@contentful/rich-text-html-renderer';
|
||||
import { IPost } from '../types/cms';
|
||||
import { METADATA } from '../constants';
|
||||
|
||||
const baseUrl = METADATA.OXEN_HOST_URL;
|
||||
const categories = [
|
||||
'Privacy',
|
||||
'decentralisation',
|
||||
'decentralised',
|
||||
'Open Source',
|
||||
'Private messaging',
|
||||
'Onion routing',
|
||||
'Cryptocurrency',
|
||||
'Digital finance',
|
||||
'Privacy Tools',
|
||||
];
|
||||
const date = new Date();
|
||||
const feed = new Feed({
|
||||
title: METADATA.TITLE_SUFFIX,
|
||||
description: METADATA.SITE_META_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
|
||||
image: `${baseUrl}/android-chrome-192x192.png`,
|
||||
favicon: `${baseUrl}/favicon.ico`,
|
||||
copyright: `All rights reserved ${date.getFullYear()}, OPTF`,
|
||||
updated: date, // optional, default = today
|
||||
generator: 'Next.js using Feed for Node.js', // optional, default = 'Feed for Node.js'
|
||||
feedLinks: {
|
||||
rss2: `${baseUrl}/rss/feed.xml`,
|
||||
json: `${baseUrl}/rss/feed.json`,
|
||||
atom: `${baseUrl}/rss/atom.xml`,
|
||||
},
|
||||
});
|
||||
categories.forEach(category => {
|
||||
feed.addCategory(category);
|
||||
});
|
||||
|
||||
export default function generateRSSFeed(posts: IPost[]) {
|
||||
posts.forEach(post => {
|
||||
feed.addItem({
|
||||
title: post.title,
|
||||
id: post.id,
|
||||
link: `${baseUrl}/blog/${post.slug}`,
|
||||
description: post.description,
|
||||
content: documentToHtmlString(post.body),
|
||||
date: new Date(post.publishedDate),
|
||||
});
|
||||
});
|
||||
|
||||
mkdirSync(`./public/rss`, { recursive: true });
|
||||
writeFileSync(`./public/rss/feed.xml`, feed.rss2());
|
||||
writeFileSync(`./public/rss/feed.json`, feed.json1());
|
||||
writeFileSync(`./public/rss/atom.xml`, feed.atom1());
|
||||
}
|
26
yarn.lock
26
yarn.lock
|
@ -1414,6 +1414,14 @@
|
|||
exec-sh "^0.3.2"
|
||||
minimist "^1.2.0"
|
||||
|
||||
"@contentful/rich-text-html-renderer@^15.0.0":
|
||||
version "15.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@contentful/rich-text-html-renderer/-/rich-text-html-renderer-15.2.0.tgz#112bb9f748b5bc4df9d2e2065cb9f6d6e9ca085a"
|
||||
integrity sha512-htcPzKiKsfINv6wkHtx38Vw0QLeGwzRTLe8dNHU2lvGZ+tgmqsgmt6C0XcpBbdon98Afl8xdToOpZdfQImI8NA==
|
||||
dependencies:
|
||||
"@contentful/rich-text-types" "^15.1.0"
|
||||
escape-html "^1.0.3"
|
||||
|
||||
"@contentful/rich-text-plain-text-renderer@^15.0.0":
|
||||
version "15.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@contentful/rich-text-plain-text-renderer/-/rich-text-plain-text-renderer-15.1.0.tgz#d6deb9f78de24b606d96dffd00abe8e2f957801e"
|
||||
|
@ -6573,7 +6581,7 @@ escape-goat@^2.0.0:
|
|||
resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-2.1.1.tgz#1b2dc77003676c457ec760b2dc68edb648188675"
|
||||
integrity sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==
|
||||
|
||||
escape-html@~1.0.3:
|
||||
escape-html@^1.0.3, escape-html@~1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
|
||||
integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=
|
||||
|
@ -7201,6 +7209,13 @@ fb-watchman@^2.0.0:
|
|||
dependencies:
|
||||
bser "2.1.1"
|
||||
|
||||
feed@^4.2.2:
|
||||
version "4.2.2"
|
||||
resolved "https://registry.yarnpkg.com/feed/-/feed-4.2.2.tgz#865783ef6ed12579e2c44bbef3c9113bc4956a7e"
|
||||
integrity sha512-u5/sxGfiMfZNtJ3OvQpXcvotFpYkL0n9u9mM2vkui2nGo8b4wvDkJ8gAkYqbA8QpGyFCv3RK0Z+Iv+9veCS9bQ==
|
||||
dependencies:
|
||||
xml-js "^1.6.11"
|
||||
|
||||
figgy-pudding@^3.5.1:
|
||||
version "3.5.2"
|
||||
resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.2.tgz#b4eee8148abb01dcf1d1ac34367d59e12fa61d6e"
|
||||
|
@ -14035,7 +14050,7 @@ sass-loader@^10.0.5:
|
|||
schema-utils "^3.0.0"
|
||||
semver "^7.3.2"
|
||||
|
||||
sax@~1.2.4:
|
||||
sax@^1.2.4, sax@~1.2.4:
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
|
||||
integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
|
||||
|
@ -16674,6 +16689,13 @@ xdg-basedir@^4.0.0:
|
|||
resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13"
|
||||
integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==
|
||||
|
||||
xml-js@^1.6.11:
|
||||
version "1.6.11"
|
||||
resolved "https://registry.yarnpkg.com/xml-js/-/xml-js-1.6.11.tgz#927d2f6947f7f1c19a316dd8eea3614e8b18f8e9"
|
||||
integrity sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==
|
||||
dependencies:
|
||||
sax "^1.2.4"
|
||||
|
||||
xml-name-validator@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a"
|
||||
|
|
Loading…
Reference in a new issue