Skip to content

Commit

Permalink
feat(website): automatically publish latest blog posts to website (#1…
Browse files Browse the repository at this point in the history
…3027)

Co-authored-by: wolfderechter <[email protected]>
Co-authored-by: Daniel Wang <[email protected]>
  • Loading branch information
3 people authored Feb 15, 2023
1 parent edbdd3d commit 9fbf102
Show file tree
Hide file tree
Showing 6 changed files with 252 additions and 101 deletions.
255 changes: 157 additions & 98 deletions packages/website/components/BlogSection.tsx
Original file line number Diff line number Diff line change
@@ -1,56 +1,161 @@
const posts = [
{
title: "Taiko Ambassador Program",
href: "https://mirror.xyz/labs.taiko.eth/BvcEyYeVIiHnjc-i5qf3zR4s67Jc6nz_R6OSGj5rzOE",
description:
"Ethereum has come a long way in its seven-year life — changing the world, in our opinion — but it is only just getting started.",
date: "Jan 04, 2023",
datetime: "2023-01-04",
imageUrl:
"https://mirror-media.imgix.net/publication-images/5Ed-TXJIB3LTC2HJdPuEN.png?height=512&width=1024&h=512&w=1024&auto=compress",
readingTime: "2 min",
author: {
name: "finestone",
imageUrl: "https://avatars.githubusercontent.com/u/36642873?v=4",
},
},
{
title: "Taiko Alpha-1 Testnet is Live",
href: "https://mirror.xyz/labs.taiko.eth/-lahy4KbGkeAcqhs0ETG3Up3oTVzZ0wLoE1eK_ao5h4",
description:
"Today, the Taiko Alpha-1 testnet (a1) is live - our first public testnet! We’ve codenamed this testnet, Snæfellsjökull.",
date: "Dec 27, 2022",
datetime: "2022-12-27",
imageUrl:
"https://mirror-media.imgix.net/publication-images/4qVW-dWhNmMQr61g91hGt.png?height=512&width=1024&h=512&w=1024&auto=compress",
readingTime: "4 min",
author: {
name: "finestone",
imageUrl: "https://avatars.githubusercontent.com/u/36642873?v=4",
},
},
{
title: "Rollup Decentralization",
href: "https://mirror.xyz/labs.taiko.eth/sxR3iKyD-GvTuyI9moCg4_ggDI4E4CqnvhdwRq5yL0A",
description:
"This post explores definitions and high-level ideas of rollup decentralization. It does not cover deep technical detail about decentralizing rollup implementations.",
date: "Dec 20, 2022",
datetime: "2022-12-20",
imageUrl:
"https://mirror-media.imgix.net/publication-images/NTeYUqYqHo4NqrRGJHvfO.png?height=512&width=1024&h=512&w=1024&auto=compress",
readingTime: "9 min",
author: {
name: "finestone",
imageUrl: "https://avatars.githubusercontent.com/u/36642873?v=4",
},
},
];
import React, { useEffect, useState } from "react";
import { getPosts } from "./getPosts";

interface Content {
body: string;
timestamp: number;
title: string;
}

interface Authorship {
contributor: string;
signingKey: {
crv: string;
ext: boolean;
key_ops: string[];
kty: string;
x: string;
y: string;
};
signature: string;
signingKeySignature: string;
signingKeyMessage: string;
algorithm: {
name: string;
hash: string;
};
}

interface Wnft {
chainId: number;
description: string;
fee: number;
fundingRecipient: string;
imageURI: string;
mediaAssetId: number;
name: string;
nonce: number;
owner: string;
price: number;
proxyAddress: string;
renderer: string;
supply: number;
symbol: string;
}

interface Post {
OriginalDigest: string;
content: Content;
authorship: Authorship;
digest: string;
version: string;
wnft: Wnft;
}

function getReadingTime(text) {
const wordsPerMinute = 200;
const wordCount = text.split(" ").length;
const readingTime = Math.round(wordCount / wordsPerMinute);
return readingTime;
}

function getDate(timestamp: string): string {
let date = new Date(Number(timestamp) * 1000);
return date.toLocaleDateString("en-US", {
year: "numeric",
month: "short",
day: "numeric",
});
}

function getDateTime(timestamp: string): string {
let date = new Date(parseInt(timestamp) * 1000);
return `${date.getFullYear()}-${(date.getMonth() + 1)
.toString()
.padStart(2, "0")}-${date.getDate().toString().padStart(2, "0")}`;
}

function checkIfPostAreSet(posts) {
if (posts.length > 0) {
return posts.map((post: Post) => (
<div
key={post.content.title}
className="flex flex-col overflow-hidden rounded-lg shadow-lg"
>
<div className="flex-shrink-0">
<a
href={"https://mirror.xyz/labs.taiko.eth/" + post.OriginalDigest}
target="_blank"
>
<img
className="w-full h-40 sm:h-64 lg:h-36 xl:h-48 object-cover object-top"
src={`https://ipfs.io/ipfs/${post.wnft.imageURI}`}
alt=""
/>
</a>
</div>
<div className="flex flex-1 flex-col justify-between bg-white p-6 dark:bg-neutral-800">
<div className="flex-1">
<a
href={"https://mirror.xyz/labs.taiko.eth/" + post.OriginalDigest}
target="_blank"
className="mt-2 block"
>
<div className="text-xl font-semibold text-neutral-900 dark:text-neutral-200">
{post.content.title}
</div>
<div className="mt-3 text-base text-neutral-500 dark:text-neutral-300">
{post.wnft.description}
</div>
</a>
</div>
<div className="mt-6 flex items-center">
<div className="ml-3">
<div className="flex space-x-1 text-sm text-neutral-500 dark:text-neutral-400">
<time dateTime={getDateTime(`${post.content.timestamp}`)}>
{getDate(`${post.content.timestamp}`)}
</time>
<span aria-hidden="true">&middot;</span>
<span>{getReadingTime(post.content.body) + " min read"}</span>
</div>
</div>
</div>
</div>
</div>
));
} else {
const amountOfPostsToDisplay = 3;
return [...Array(amountOfPostsToDisplay)].map((v, i) => (
<div
key={i}
className="flex flex-col overflow-hidden rounded-lg shadow-lg"
>
<div className="h-80 animate-pulse">
<div className="h-full w-full bg-neutral-800"></div>
</div>
</div>
));
}
}

export default function BlogSection(): JSX.Element {
const [posts, setPosts] = useState<Object[]>([]);

useEffect(() => {
getPosts.then((result : Post[]) => {
// only use the last three
result = result.sort((a, b) => b.content.timestamp - a.content.timestamp);
result = result.slice(0, 3);

setPosts(result);
});
// getting the information of the post via the arweave GraphQL and SDK
});

export default function BlogSection() {
return (
<div className="relative bg-neutral-50 px-4 pt-16 pb-20 sm:px-6 lg:px-8 lg:pt-24 lg:pb-28 dark:bg-neutral-900">
<div className="relative bg-neutral-50 px-4 pt-16 pb-20 sm:px-6 lg:px-8 lg:pt-24 lg:pb-28 dark:bg-neutral-800">
<div className="absolute inset-0">
<div className="h-1/3 bg-white sm:h-2/3 dark:bg-neutral-900" />
<div className="h-1/3 bg-white sm:h-2/3 dark:bg-[#1B1B1D]" />
</div>
<div className="relative mx-auto max-w-7xl">
<div className="text-center">
Expand All @@ -64,55 +169,9 @@ export default function BlogSection() {
</a>
</div>
</div>

<div className="mx-auto mt-12 grid max-w-lg gap-5 lg:max-w-none lg:grid-cols-3">
{posts.map((post) => (
<div
key={post.title}
className="flex flex-col overflow-hidden rounded-lg shadow-lg"
>
<div className="flex-shrink-0">
<a href={post.href} target="_blank">
<img
className="h-54 w-full object-cover"
src={post.imageUrl}
alt=""
/>
</a>
</div>
<div className="flex flex-1 flex-col justify-between bg-white p-6 dark:bg-neutral-800">
<div className="flex-1">
<a href={post.href} target="_blank" className="mt-2 block">
<div className="text-xl font-semibold text-neutral-900 dark:text-neutral-200">
{post.title}
</div>
<div className="mt-3 text-base text-neutral-500 dark:text-neutral-300">
{post.description}
</div>
</a>
</div>
<div className="mt-6 flex items-center">
<div className="flex-shrink-0">
<span className="sr-only">{post.author.name}</span>
<img
className="h-10 w-10 rounded-full"
src={post.author.imageUrl}
alt=""
/>
</div>
<div className="ml-3">
<div className="text-sm font-medium text-[#fc0fc0]">
{post.author.name}
</div>
<div className="flex space-x-1 text-sm text-neutral-500 dark:text-neutral-400">
<time dateTime={post.datetime}>{post.date}</time>
<span aria-hidden="true">&middot;</span>
<span>{post.readingTime} read</span>
</div>
</div>
</div>
</div>
</div>
))}
{checkIfPostAreSet(posts)}
</div>
</div>
</div>
Expand Down
73 changes: 73 additions & 0 deletions packages/website/components/getPosts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import Arweave from "arweave";

const arweave = Arweave.init({
host: "arweave.net",
port: 443,
protocol: "https",
});

export const getPosts = new Promise<Array<Object>>((resolve, reject) => {
async function getTransanctionIds() {
await fetch('https://arweave.net/graphql', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
query: `
query {
transactions(
first: 100
sort: HEIGHT_DESC
tags: [
{
name: "Contributor"
values: ["0x5b796c4B197B6DfD413f177059C27963EB80af0F","0x2b1F13149C7F89622BBfB46Ae1e3ECc573Bb9331","0x381636D0E4eD0fa6aCF07D8fd821909Fb63c0d10"]
},
{
name: "App-Name"
values: "MirrorXYZ"
}
]
) {
edges {
node {
id
tags {
name
value
}
}
}
}
}
`})
}).then((res) => res.json())
.then((response) => {
getPosts(response);
})
.catch();
}

async function getPosts(response) {
const posts = []
Promise.all(response.data.transactions.edges.map((edge) => {
const transactionId = edge.node.id;
arweave.transactions
.getData(`${transactionId}`, { decode: true, string: true }).then((response: string) => JSON.parse(response))
.then((data) => {
// Check if the posts have the required keys
if (data.hasOwnProperty('wnft')) {

// add the original digest
data["OriginalDigest"] = edge.node.tags[4].value;
posts.push(data);
}

}).catch();
}))
resolve(posts);
}
getTransanctionIds();
})
1 change: 1 addition & 0 deletions packages/website/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"start": "pnpm next start"
},
"dependencies": {
"arweave": "^1.12.6",
"next": "^13.1.6",
"next-themes": "^0.2.1",
"nextra": "^2.2.14",
Expand Down
2 changes: 1 addition & 1 deletion packages/website/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/website/styles.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@tailwind utilities;
Loading

0 comments on commit 9fbf102

Please sign in to comment.