Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
NEXT_PUBLIC_MOCHI_PROFILE_API_HOST="https://api-preview.mochi-profile.console.so"
39 changes: 39 additions & 0 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: Release

on:
push:
branches:
- main
- preview

permissions:
contents: read # for checkout

jobs:
release:
permissions:
contents: write # to be able to publish a GitHub release
issues: write # to be able to comment on released issues
pull-requests: write # to be able to comment on released pull requests
id-token: write # to enable use of OIDC for npm provenance
name: release
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3 # v3
with:
fetch-depth: 0 # to be able to checkout any commit
persist-credentials: false # <--- this
- uses: pnpm/action-setup@v2
with:
version: 6.32.9
- uses: actions/setup-node@v3 # v3
with:
cache: pnpm
node-version: 18
- name: Install dependencies
run: pnpm install
# pinned version updated automatically by Renovate.
# details at https://semantic-release.gitbook.io/semantic-release/usage/installation#global-installation
- run: pnpm dlx semantic-release@21.0.2
env:
GITHUB_TOKEN: ${{ secrets.GH_PAT }}
19 changes: 19 additions & 0 deletions .github/workflows/vercel-preview.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
name: Vercel Preview Deployment
env:
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
on:
release:
types: [prereleased]
jobs:
Deploy-Preview:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Merge to Preview
uses: devmasx/merge-branch@master
with:
type: now
from_branch: preview
target_branch: preview-release
github_token: ${{ secrets.GITHUB_TOKEN }}
20 changes: 20 additions & 0 deletions .github/workflows/vercel-prod.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: Vercel Production Deployment
env:
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
on:
workflow_dispatch:
release:
types: [released]
jobs:
Deploy-Production:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Merge to Prod
uses: devmasx/merge-branch@master
with:
type: now
from_branch: main
target_branch: prod-release
github_token: ${{ secrets.GITHUB_TOKEN }}
1 change: 1 addition & 0 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
public-hoist-pattern[]=*@mochi-ui/*
27 changes: 27 additions & 0 deletions .releaserc
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"branches": [
"main",
{
"name": "preview",
"prerelease": "rc"
}
],
"plugins": [
"@semantic-release/commit-analyzer",
[
"@semantic-release/npm",
{
"npmPublish": false,
}
],
[
"@semantic-release/github",
{
"successComment": false
}
],
["@semantic-release/git", {
"assets": ["package.json"]
}]
]
}
25 changes: 25 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
RELEASE_BRANCH=main
BETA_BRANCH=preview
DEVELOP_BRANCH=develop

.PHONY: release
release:
git checkout $(BETA_BRANCH) && git pull origin $(BETA_BRANCH) && \
git checkout $(RELEASE_BRANCH) && git pull origin $(RELEASE_BRANCH) && \
git merge $(BETA_BRANCH) --no-edit --no-ff && \
git push origin $(RELEASE_BRANCH) && \
git checkout $(DEVELOP_BRANCH)

.PHONY: release-preview
release-preview: sync-release
git checkout $(DEVELOP_BRANCH) && git pull origin $(DEVELOP_BRANCH) && \
git checkout $(BETA_BRANCH) && git pull origin $(BETA_BRANCH) && \
git merge $(DEVELOP_BRANCH) --no-edit --no-ff && \
git push origin $(BETA_BRANCH) && \
git checkout $(DEVELOP_BRANCH) && git push origin $(DEVELOP_BRANCH)

.PHONY: sync-release
sync-release:
git checkout $(RELEASE_BRANCH) && git pull origin $(RELEASE_BRANCH) && \
git checkout $(BETA_BRANCH) && git pull origin $(BETA_BRANCH) && \
git merge $(RELEASE_BRANCH) --no-edit --no-ff
37 changes: 37 additions & 0 deletions app/[server]/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import type { Metadata } from "next";
import { notFound } from "next/navigation";
import { serverList } from "@/constants/servers";

type Props = {
params: { server: string };
};

export async function generateMetadata(props: Props): Promise<Metadata> {
const {
params: { server },
} = props;
const serverName = serverList.find((s) => s.id === server)?.name;

if (!serverName) return {};

return {
title: `${serverName} Earning`,
openGraph: {
title: `${serverName} Earning`,
},
};
}

export default function Layout({
children,
...props
}: { children: React.ReactNode } & Props) {
const {
params: { server },
} = props;
const serverInfo = serverList.find((s) => s.id === server);

if (!serverInfo) return notFound();

return <>{children}</>;
}
217 changes: 217 additions & 0 deletions app/[server]/nft/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
"use client";

import { Footer } from "@/components/footer";
import { LoginPopover } from "@/components/login-popover";
import { Logo } from "@/components/logo";
import { NFTList } from "@/components/nft/nft-list";
import ProfileDropdown from "@/components/profile-dropdown";
import { Button, Separator, TopBar, Typography, toast } from "@mochi-ui/core";
import { ArrowTopRightLine } from "@mochi-ui/icons";
import { useLoginWidget } from "@mochi-web3/login-widget";
import Image from "next/image";
import { Suspense, useState } from "react";

const NFT = () => {
const { isLoggedIn } = useLoginWidget();
const [state, setState] = useState<"init" | "minted">("init");

return (
<div className="overflow-y-auto h-[calc(100vh-56px)]">
<div className="max-w-6xl pt-12 pb-16 px-4 mx-auto space-y-4">
<Typography level="h4" fontWeight="lg" className="pb-6 text-center">
NFT Farmer Event
</Typography>
<div className="rounded-2xl border border-neutral-outline-border p-2 grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="p-6 space-y-6 flex flex-col">
<div className="text-center space-y-1">
<Typography level="h6" fontWeight="lg">
Treasure Chest
</Typography>
<Typography level="p4">Lucky --</Typography>
</div>
<div className="flex items-center justify-center flex-1">
<Image
src="/nft/treasure-chest.png"
alt=""
width={128}
height={128}
/>
</div>
<div className="grid grid-cols-2 gap-2">
<div className="rounded bg-background-level2 px-3 py-1.5 flex items-center space-x-2">
<Image
src="/svg/rocket-launch.svg"
alt=""
width={24}
height={24}
/>
<Typography level="h7" fontWeight="lg">
--
</Typography>
</div>
<div className="rounded bg-background-level2 px-3 py-1.5 flex items-center space-x-2">
<Image src="/svg/hourglass.svg" alt="" width={24} height={24} />
<Typography level="h7" fontWeight="lg">
--
</Typography>
</div>
</div>
</div>
<div className="rounded-lg bg-background-level1 p-6 space-y-4 flex flex-col">
<div className="text-right">
<Button variant="link" className="h-fit pl-0 pr-0">
Whitelist
<ArrowTopRightLine className="w-4 h-4" />
</Button>
</div>
<div className="pb-4 flex-1">
<Typography level="p4">
The Dwarves NFT collection takes you to the magical world of the
Norse dwarves, where brave warriors, skilled blacksmiths, and
clever inventors live. Each NFT in the collection is a unique
piece of art, representing a different aspect of Norse dwarf
culture.
</Typography>
</div>
<Separator />
<div className="grid grid-cols-3 sm:grid-cols-5 sm:px-2 gap-x-4">
{[
{
title: "Tier 1",
percent: 0.5,
},
{
title: "Tier 2",
percent: 2.5,
},
{
title: "Tier 3",
percent: 12,
},
{
title: "Tier 4",
percent: 35,
},
{
title: "Tier 5",
percent: 50,
},
].map((each) => (
<div key={each.title} className="pt-3 pb-4 space-y-0.5">
<Typography level="p5" className="text-text-tertiary">
{each.title}
</Typography>
<Typography level="h7" fontWeight="lg">
{each.percent}%
</Typography>
</div>
))}
</div>
{isLoggedIn ? (
state === "minted" ? (
<Button
size="lg"
onClick={() => {
setState("init");
}}
>
Claim
</Button>
) : (
<Button
size="lg"
onClick={() => {
toast({
scheme: "success",
title: "Congratulations! Mint succeeded!",
description:
"Claim your NFT and start using it to redeem rewards.",
});
setState("minted");
}}
>
Mint (2)
</Button>
)
) : (
<Button size="lg">Login</Button>
)}
</div>
</div>
</div>
<div className="bg-background-level1">
<div className="max-w-6xl py-16 px-4 mx-auto space-y-8">
<Typography level="h4" fontWeight="lg" className="pb-6 text-center">
Dwarves NFT Collection
</Typography>
<div className="grid grid-cols-1 md:grid-cols-2 gap-16">
<div className="flex items-center justify-center">
<div className="grid grid-cols-3 w-fit h-fit">
{[
"/nft/tool.png",
"/nft/crow-feathers.png",
"/nft/voluspa.png",
"/nft/vidar-boots.png",
"/nft/thor-hammer.png",
"/nft/golden-apple.png",
"/nft/anvil.png",
"/nft/stone.png",
"/nft/wood.png",
].map((src) => (
<Image key={src} src={src} alt="" width={128} height={128} />
))}
</div>
</div>
<div className="flex flex-col justify-center">
<Typography className="text-xl font-semibold pt-4">
About
</Typography>
<Typography level="p4" className="py-4">
The Dwarves NFT collection takes you to the magical world of the
Norse dwarves, where brave warriors, skilled blacksmiths, and
clever inventors live. Each NFT in the collection is a unique
piece of art, representing a different aspect of Norse dwarf
culture.
</Typography>
<Typography className="text-xl font-semibold pt-4">
How to mint
</Typography>
<div className="py-4 grid grid-cols-1 lg:grid-cols-2 gap-3">
{[
"Connect your wallet",
"Check the whitelist and mint",
"Confirm the transaction",
"Receive your NFTs",
].map((each, index) => (
<Typography key={each} level="p4">
{index + 1}. {each}
</Typography>
))}
</div>
</div>
</div>
</div>
</div>
<div className="max-w-6xl pb-24 px-4 mx-auto">
<NFTList />
</div>
<Footer />
</div>
);
};

export default function Page() {
const { isLoggedIn } = useLoginWidget();

return (
<main>
<TopBar
leftSlot={<Logo />}
rightSlot={!isLoggedIn ? <LoginPopover /> : <ProfileDropdown />}
/>
<Suspense>
<NFT />
</Suspense>
</main>
);
}
Loading