Skip to content

Commit

Permalink
set up new card and grid components for blogs. set up new param page …
Browse files Browse the repository at this point in the history
…for blog. set up new landing page for blogs. use bloggrid on homepage. clean up metadata generator on events and studios pages.generate keystatic content for forceprime blog post
  • Loading branch information
4eyes52 committed Sep 2, 2024
1 parent 00e2a3f commit dd24838
Show file tree
Hide file tree
Showing 11 changed files with 259 additions and 25 deletions.
18 changes: 18 additions & 0 deletions apps/nextjs/keystatic.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,5 +153,23 @@ export default config({
),
},
}),
blogs: collection({
label: "Blogs",
slugField: "title",
path: "src/content/blogs/*",
format: { contentField: "content" },
columns: ["title", "subtitle"],
schema: {
author: fields.text({ label: "Author" }),
publishDate: fields.datetime({ label: "Published Date" }),
title: fields.slug({ name: { label: "Title" } }),
image: fields.image({
label: "Banner Image",
directory: "public/content/blogs",
}),
subtitle: fields.text({ label: "Subtitle" }),
content: fields.markdoc({ label: "Content" }),
},
}),
},
});
Binary file not shown.
30 changes: 30 additions & 0 deletions apps/nextjs/src/app/(app)/blogs/BlogCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import Image from "next/image";
import Link from "next/link";

import { Badge, Card } from "@realms-world/ui";
import type { CollectionEntry } from "@/utils/keystatic";


export const BlogCard = ({ blog, slug }: { blog: CollectionEntry<'blogs'>, slug: string }) => {
return (
<Card>
<Link href={`/blog/${slug}`} className="flex flex-col">
<Image
className="min-h-[400px] w-full rounded-l object-cover"
src={`/content/blogs/${slug}/${blog.image}`}
width={500}
height={500}
alt={blog.title}
/>
<div className="align-center p-4">
<Badge> {blog.publishDate}</Badge>

<h4 className="my-4 text-2xl">{blog.title}</h4>
<p>{blog.subtitle}</p>
</div>
</Link>
</Card>
);
};

export default BlogCard;
15 changes: 15 additions & 0 deletions apps/nextjs/src/app/(app)/blogs/BlogGrid.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { BlogCard } from "./BlogCard";
import { reader } from "@/utils/keystatic";

export const BlogGrid = async () => {
const blogs = await reader.collections.blogs.all();


return (
<div className="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3">
{blogs.map((blog, index) => (
<BlogCard key={index} blog={blog.entry} slug={blog.slug} />
))}
</div>
);
};
14 changes: 14 additions & 0 deletions apps/nextjs/src/app/(app)/blogs/[id]/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
"use client";
import { PageLayout } from "../../../_components/PageLayout";
import React from "react";
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {


return (
<PageLayout>{children}</PageLayout>
);
}
111 changes: 111 additions & 0 deletions apps/nextjs/src/app/(app)/blogs/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import type { Metadata } from "next";
import Image from "next/image";
import Link from "next/link";
import {
Breadcrumb,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbList,
BreadcrumbSeparator,
Button,
} from "@realms-world/ui";
import React from "react";
import Markdoc from "@markdoc/markdoc";
import { reader } from "@/utils/keystatic";

export async function generateMetadata({
params,
}: {
params: { id: string };
}): Promise<Metadata> {
let blog = await reader.collections.blogs.read(params.id);

return {
title: `${blog?.title}`,
description: `${blog?.subtitle} - Created for Adventurers by Bibliotheca DAO`,
openGraph: {
title: `${blog?.title} - Created for Adventurers by Bibliotheca DAO`,
images: [
{
url: `/content/blogs/${params.id}/${blog?.image}`,
width: 800,
height: 600,
},
],
},
twitter: {
card: "summary_large_image",
title: `${blog?.title}`,
description: `${blog?.subtitle} - Created for Adventurers by Bibliotheca DAO`,
siteId: "1467726470533754880",
creator: "@bibliothecadao",
creatorId: "1467726470533754880",
images: [`/content/blogs/${params.id}/${blog?.image}`],
},
};
}

export default async function Page({ params }: { params: { id: string } }) {
const blog = await reader.collections.blogs.read(params.id);
if (!blog) {
return <div>No Blog Found</div>;
}
const { node } = await blog.content();
const errors = Markdoc.validate(node);
if (errors.length) {
console.error(errors);
throw new Error('Invalid content');
}
const renderable = Markdoc.transform(node);

return (
<>
<div>
<Breadcrumb>
<BreadcrumbList>
<BreadcrumbItem>
<BreadcrumbLink href="/">Home</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbLink href="/blogs">Blog</BreadcrumbLink>
</BreadcrumbItem>
</BreadcrumbList>
</Breadcrumb>
<div className="my-12 text-left">
<h1 className="text-4xl font-bold">{blog?.title}</h1>
<p className="mt-2 text-xl">{blog?.subtitle}</p>
<div className="mt-8 text-xl font-bold">
<span>Posted on </span>
<time dateTime={blog?.publishDate || ''}>
{new Date(blog?.publishDate || '').toLocaleDateString()}
</time>
<span> by </span>
<span>{blog?.author}</span>
</div>
</div>
<Image
alt={blog?.title}
src={`/content/blogs/${params.id}/${blog?.image}`}
width={900}
className="w-full object-cover"
height={600}
/>
<article className="prose prose-lg mx-auto mt-6 max-w-5xl px-6 pb-6 text-xl prose-headings:text-bright-yellow prose-p:font-thin prose-p:text-bright-yellow prose-a:text-flamingo prose-strong:text-bright-yellow prose-ul:text-bright-yellow md:mt-12">
<div className="article-container">
{Markdoc.renderers.react(renderable, React)}
</div>
</article>

<hr />
<div className="container mx-auto px-10">
<div className="mt-6">
<Button variant={"outline"} asChild>
<Link href={"/blogs"}>back</Link>
</Button>
</div>
</div>
</div>
</>
);
}
19 changes: 19 additions & 0 deletions apps/nextjs/src/app/(app)/blogs/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import type { Metadata } from "next";

import { PageLayout } from "../../_components/PageLayout";
import { BlogGrid } from "./BlogGrid";

export const metadata: Metadata = {
title: "Realms World Blog",
description:
"Latest news from Realms Autonomous World- Created for adventurers by Bibliotheca DAO",
};

export default async function Page() {
return (
<PageLayout title="Blogs">
<div className="pb-8 md:text-2xl">Realms World Blog</div>
<BlogGrid />
</PageLayout>
);
}
12 changes: 5 additions & 7 deletions apps/nextjs/src/app/(app)/events/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,18 @@ import Link from "next/link";
import { PageLayout } from "@/app/_components/PageLayout";
import React from "react";
import Markdoc from "@markdoc/markdoc";

import { games } from "@realms-world/constants";
import { Button } from "@realms-world/ui";
import { reader } from "@/utils/keystatic";

export function generateMetadata({

export async function generateMetadata({
params,
}: {
params: { id: string };
}): Metadata {
const name = games.find((game) => game.id === params.id)?.name ?? "Game";

}): Promise<Metadata> {
let event = await reader.collections.events.read(params.id);
return {
title: `${name}`,
title: `${event?.name}`,
description: `${params.id} - Created for Adventurers by Bibliotheca DAO`,
};
}
Expand Down
5 changes: 2 additions & 3 deletions apps/nextjs/src/app/(app)/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,12 @@ import { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious

import { PageLayout } from "../_components/PageLayout";
import { Partners } from "../_components/Partners";
import PostGrid from "./blog/PostGrid";
import { BlogGrid } from "./blogs/BlogGrid";
import CollectionsList from "./collection/CollectionsList";
import { EventGrid } from "./events/EventGrid";
import Image from "next/image"
import { reader } from "@/utils/keystatic";


export default async function Home() {
const games = await reader.collections.games.all();
const carouselItems = games
Expand Down Expand Up @@ -83,7 +82,7 @@ export default async function Home() {
<hr />
<div className="my-24">
<h3 className="mb-4 text-xl">News</h3>
<PostGrid />
<BlogGrid />
</div>

<hr className="my-8 border" />
Expand Down
24 changes: 9 additions & 15 deletions apps/nextjs/src/app/(app)/studios/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@ import { ChevronLeft } from "lucide-react";
import { reader } from "@/utils/keystatic";
import Markdoc from "@markdoc/markdoc";
import React from "react";

import type { Game } from "@realms-world/constants";
import { getGamesByStudio, studios } from "@realms-world/constants";
import {
Button,
Tabs,
Expand All @@ -19,25 +16,22 @@ import {
TabsTrigger,
} from "@realms-world/ui";

export function generateMetadata({

export async function generateMetadata({
params,
}: {
params: { id: string };
}): Metadata {
const name = Object.values(studios).find(
(studio) => studio.id === params.id,
)?.name;

}): Promise<Metadata> {
let studio = await reader.collections.studios.read(params.id);
return {
title: `${name}`,
description: `${name} Profile - A game studio of the Realms Autonomous World`,
title: `${studio?.title}`,
description: `${params.id} Profile - A game studio of the Realms Autonomous World`,
openGraph: {
title: `${name}`,
description: `${name} Profile - A studio of the Realms Autonomous World`,
title: `${studio?.title}`,
description: `${params.id} Profile - A game studio of the Realms Autonomous World`,
},
};
}

export default async function Page({ params }: { params: { id: string } }) {
const studio = await reader.collections.studios.read(params.id);

Expand All @@ -53,7 +47,7 @@ export default async function Page({ params }: { params: { id: string } }) {
const studioGames = await Promise.all(studio.games.map(async (game) => {
return (await reader.collections.games.read(game ?? "")) ?? "";
}));
console.log(studioGames)

const tabs = [
{
name: "Details",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
author: Secretive
publishDate: 2024-06-06T08:15:00.000Z
title: Discover Force Prime Heroes in the Realms.World
image: image.webp
subtitle: Slay your way to the top of Force Prime, Adventurer
---
With a new gameplay season starting, we proudly welcome *Force Prime Heroes* to [Realms.World](https://realms.world/games/force-prime-heroes)

Inspired by the legendary *Heroes of Might and Magic* series, players are cast onto a monster-filled map with one ultimate goal: to figure out how to raid and kill the Bone Dragon. Grand Season Two is just starting and players will find two major updates. Your hero is now upgradable: use four stats to customise your character build. This season also introduces the first single player campaign.

## Feel the Force, 24/7

Force Prime Heroes is in open beta and is seeking Adventurers to compete. As you play you accrue points and play for prizes ($2000 STRK this Season). There are weekly tournaments and blitz tournaments - [follow Force Prime on X for ongoing updates](https://x.com/ForcePrime_io). Launch the fully onchain game from their [website](http://forceprime.io) or [Realms.World](https://realms.world/games/force-prime-heroes).

Force Prime Heroes is played alone (at the moment...) with competition for the top spots on the global leaderboard. Players strategically traverse the game map, forge formidable armies, vanquish hordes of monsters, and uncover the most effective path to confront the final boss.

With multiple maps, a single player campaign mode and a player-base growing in size, Force Prime Heroes will bring out your competitive slayer side. The developers at Force Prime Studios have an ambitious roadmap and will continue to role out new features, season by season.

## Legendary beginnings

Force Prime Heroes is the debut title from Force Prime, a web3 studio helmed by veterans of web2 gaming. Recognising onchain gaming as an open space for creating new kinds of player experience, the team has fully embraced the concept, leveraging the Cairo VM and Dojo stack.

Realms.World is the hub of the Realms onchain gaming ecosystem. Here you will find several games in development, many with their sights set on mainnet on L2 and/or L3 in the coming months. Games in the Realms ecosystem will lean into composability of assets from across game worlds - like surly Squire Blobert, and captured Loot Survivor beasts.

## Game worlds are the fabric of the Realms

Force Prime Heroes is a vibrant game world complete with its own lore, characters, physics, and rules. There are several studios terraforming game worlds linked with the Realms onchain reality - including Banners, Eternum, Grugs Lair, Loot Survivor, Mississippi, Paved, Underware and zKorp (see them all [here](https://realms.world/studios)).

Force Prime Heroes, like the other worlds, maintains its own distinct style and setting, but is open to expansion and modification by players and developers. As the Realms ecosystem unfolds, players will hop between game worlds enjoying both the studio's original vision and the mash-ups and modifications that gamers and developers create.

## Prepare your campaign

- Follow Force Prime on X [for ongoing updates.](https://x.com/ForcePrime_io/status/1787866521986801795)
- Game guide: ​[https://fp-heroes.gitbook.io/how-to-play/](https://fp-heroes.gitbook.io/how-to-play/)
- Play here: [forceprime.io](https://forceprime.io/) or [Realms.World](https://realms.world/games/force-prime-heroes)

0 comments on commit dd24838

Please sign in to comment.