feat: launch mira
This commit is contained in:
parent
7738bc285b
commit
0b4fe83f17
|
|
@ -11,5 +11,6 @@ NEXT_PUBLIC_GITHUB_LINK="https://github.com/Crossbell-Box/xlog"
|
|||
NEXT_PUBLIC_CSB_IO="https://crossbell.io"
|
||||
NEXT_PUBLIC_CSB_SCAN="https://scan.crossbell.io"
|
||||
NEXT_PUBLIC_IPFS_GATEWAY="https://ipfs.4everland.xyz/ipfs/"
|
||||
NEXT_PUBLIC_MIRA_LINK="https://mira.crossbell.io"
|
||||
|
||||
REDIS_URL=
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
},
|
||||
"Earn": {
|
||||
"subtitle": "Earn tokens and rights",
|
||||
"description": "Great content deserves to be rewarded, and a blockchain offers the wonderful opportunity for creators to be rewarded transparently and fairly. An xLog DAO further promotes the growth of our community."
|
||||
"description": "Great content deserves to be rewarded, and a blockchain offers the wonderful opportunity for creators to be rewarded transparently and fairly. An xLog DAO will further promote the growth of our community."
|
||||
}
|
||||
},
|
||||
"Easy to get started text": "xLog supports <strong>web3 wallets</strong> and <strong>email</strong> connections, allowing you to quickly create a customized blog with features like a custom domain, subscriptions, comments, NFT minting, RSS feeds, and AI enhancements in just 5 minutes - with no application or costs required.",
|
||||
|
|
|
|||
|
|
@ -148,5 +148,18 @@
|
|||
"Preview your Mirror.xyz entries": "预览你的 Mirror.xyz 条目",
|
||||
"Please select .md files, multiple files are supported, and front matter is supported.":
|
||||
"请选择 .md 文件,支持多个文件,支持 front matter。",
|
||||
"Achievements": "成就"
|
||||
"Achievements": "成就",
|
||||
"Tokens": "代币",
|
||||
"1 MIRA ≈ 1 USDC, swap easily on cross-chain bridge and Uniswap.": "1 MIRA ≈ 1 USDC,可以在跨链桥和 Uniswap 上轻松兑换。",
|
||||
"In the early stage, xLog will use $MIRA to motivate creators.": "在早期阶段,xLog 将使用 $MIRA 激励创作者。",
|
||||
"You can obtain $MIRA through the following ways:": "你可以通过以下方式获得 $MIRA:",
|
||||
"Creator incentive program." : "创作者激励计划。",
|
||||
"Participate in events.": "参加活动。",
|
||||
"Swap from USDC.": "从 USDC 兑换。",
|
||||
"Swap to USDC": "兑换到 USDC",
|
||||
"Free Claim": "免费领取",
|
||||
"$XLOG is related to xLog DAO, but it's too early now, please stay tuned.": "$XLOG 与 xLog DAO 相关,但现在还为时尚早,敬请期待。",
|
||||
"Stay tuned": "敬请期待",
|
||||
"This is a token used for interaction on the Crossbell blockchain, which can be claimed for free from the faucet, so there's no need to worry about its balance.": "这是一个用于 Crossbell 区块链上交互的代币,可以从水龙头免费领取,所以不用担心它的余额。",
|
||||
"Balance": "余额"
|
||||
}
|
||||
|
|
@ -23,7 +23,7 @@
|
|||
},
|
||||
"Earn": {
|
||||
"subtitle": "赚取代币和权利",
|
||||
"description": "优秀的内容应该得到奖励,而区块链为创作者提供了透明公正的奖励机会。xLog DAO 进一步促进了我们社区的发展。"
|
||||
"description": "优秀的内容应该得到奖励,而区块链为创作者提供了透明公正的奖励机会。xLog DAO 将进一步促进我们社区的发展。"
|
||||
}
|
||||
},
|
||||
"Features": "特色",
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import { Avatar } from "~/components/ui/Avatar"
|
|||
import { CharacterFloatCard } from "./CharacterFloatCard"
|
||||
import { UniLink } from "../ui/UniLink"
|
||||
import { getSiteLink } from "~/lib/helpers"
|
||||
import { CSB_SCAN } from "~/lib/env"
|
||||
import { CSB_SCAN, MIRA_LINK } from "~/lib/env"
|
||||
import { parsePageId } from "~/models/page.model"
|
||||
|
||||
export const PatronModal: React.FC<{
|
||||
|
|
@ -156,22 +156,24 @@ export const PatronModal: React.FC<{
|
|||
className="inline-flex flex-col items-center w-[12.5%]"
|
||||
key={index}
|
||||
>
|
||||
<CharacterFloatCard siteId={tip.character?.handle}>
|
||||
<UniLink
|
||||
href={getSiteLink({
|
||||
subdomain: tip.character?.handle || "",
|
||||
})}
|
||||
>
|
||||
<Avatar
|
||||
className="relative align-middle border-2 border-white"
|
||||
images={
|
||||
tip.character?.metadata?.content?.avatars || []
|
||||
}
|
||||
name={tip.character?.metadata?.content?.name}
|
||||
size={50}
|
||||
/>
|
||||
</UniLink>
|
||||
</CharacterFloatCard>
|
||||
<div className="text-left">
|
||||
<CharacterFloatCard siteId={tip.character?.handle}>
|
||||
<UniLink
|
||||
href={getSiteLink({
|
||||
subdomain: tip.character?.handle || "",
|
||||
})}
|
||||
>
|
||||
<Avatar
|
||||
className="relative align-middle border-2 border-white"
|
||||
images={
|
||||
tip.character?.metadata?.content?.avatars || []
|
||||
}
|
||||
name={tip.character?.metadata?.content?.name}
|
||||
size={50}
|
||||
/>
|
||||
</UniLink>
|
||||
</CharacterFloatCard>
|
||||
</div>
|
||||
<UniLink
|
||||
href={`${CSB_SCAN}/tx/${tip.transactionHash}`}
|
||||
className="inline-flex items-center mt-1 text-center w-full"
|
||||
|
|
@ -224,7 +226,9 @@ export const PatronModal: React.FC<{
|
|||
<p>1 Mira ≈ 1 USDC</p>
|
||||
<p className="flex items-center justify-center">
|
||||
<i className="i-mingcute:question-line mr-1 text-sm" />
|
||||
{t("What is Mira? Where can I get some?")}
|
||||
<UniLink href={MIRA_LINK}>
|
||||
{t("What is Mira? Where can I get some?")}
|
||||
</UniLink>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -273,7 +273,7 @@ export const Reactions: React.FC<{
|
|||
)}
|
||||
</div>
|
||||
{size !== "sm" && (
|
||||
<div className="xlog-reactions-tip flex items-center opacity-0 pointer-events-none">
|
||||
<div className="xlog-reactions-tip flex items-center">
|
||||
<Button
|
||||
variant="tip"
|
||||
className={`flex items-center mr-2 ${
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ export const getServerSideProps = async (ctx: any) => {
|
|||
...(await serverSideTranslations(languageDetector(ctx), [
|
||||
"common",
|
||||
"dashboard",
|
||||
"index",
|
||||
])),
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -139,6 +139,12 @@ export function DashboardLayout({
|
|||
icon: "i-mingcute-trophy-line",
|
||||
text: "Achievements",
|
||||
},
|
||||
{
|
||||
href: `/dashboard/${subdomain}/tokens`,
|
||||
isActive: ({ href, pathname }) => href === pathname,
|
||||
icon: "i-mingcute-pig-money-line",
|
||||
text: "Tokens",
|
||||
},
|
||||
{
|
||||
href: `/dashboard/${subdomain}/settings/general`,
|
||||
isActive: ({ pathname }) =>
|
||||
|
|
|
|||
|
|
@ -286,7 +286,7 @@ export const SiteHeader: React.FC<{
|
|||
<span className="xlog-site-follow-count block sm:inline-block whitespace-nowrap">
|
||||
<FollowingCount siteId={site?.username} />
|
||||
</span>
|
||||
<span className="xlog-site-patron opacity-0 pointer-events-none">
|
||||
<span className="xlog-site-patron">
|
||||
<PatronButton site={site} />
|
||||
</span>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -17,3 +17,5 @@ export const CSB_XCHAR =
|
|||
process.env.NEXT_PUBLIC_CSB_XCHAR || "https://xchar.app"
|
||||
export const IPFS_GATEWAY =
|
||||
process.env.NEXT_PUBLIC_IPFS_GATEWAY || "https://ipfs.4everland.xyz/ipfs/"
|
||||
export const MIRA_LINK =
|
||||
process.env.NEXT_PUBLIC_MIRA_LINK || "https://mira.crossbell.io"
|
||||
|
|
|
|||
|
|
@ -696,3 +696,14 @@ export async function mintAchievement(input: {
|
|||
}) {
|
||||
return indexer.mintAchievement(input.characterId, input.achievementId)
|
||||
}
|
||||
|
||||
export async function getMiraBalance(address: string, contract: Contract) {
|
||||
const decimals = await contract.getMiraTokenDecimals()
|
||||
const result = await contract.getMiraBalance(address)
|
||||
result.data = (
|
||||
BigInt(result.data) /
|
||||
BigInt(10) ** BigInt(decimals?.data || 18)
|
||||
).toString()
|
||||
|
||||
return result
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,21 +1,12 @@
|
|||
import { DashboardLayout } from "~/components/dashboard/DashboardLayout"
|
||||
import { DashboardMain } from "~/components/dashboard/DashboardMain"
|
||||
import { UniLink } from "~/components/ui/UniLink"
|
||||
import { Image } from "~/components/ui/Image"
|
||||
import type { ReactElement } from "react"
|
||||
import { useGetAchievements, useGetSite } from "~/queries/site"
|
||||
import { useGetAchievements } from "~/queries/site"
|
||||
import { useDate } from "~/hooks/useDate"
|
||||
import { useTranslation } from "next-i18next"
|
||||
import { getServerSideProps as getLayoutServerSideProps } from "~/components/dashboard/DashboardLayout.server"
|
||||
import { GetServerSideProps } from "next"
|
||||
import { serverSidePropsHandler } from "~/lib/server-side-props"
|
||||
import { useGetPagesBySite } from "~/queries/page"
|
||||
import { CharacterFloatCard } from "~/components/common/CharacterFloatCard"
|
||||
import { useEffect, useState } from "react"
|
||||
import { Avatar } from "~/components/ui/Avatar"
|
||||
import { cn } from "~/lib/utils"
|
||||
import { getSiteLink } from "~/lib/helpers"
|
||||
import { getStorage, setStorage } from "~/lib/storage"
|
||||
import { useAccountState } from "@crossbell/connect-kit"
|
||||
import { AchievementItem } from "~/components/common/AchievementItem"
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,152 @@
|
|||
import { DashboardLayout } from "~/components/dashboard/DashboardLayout"
|
||||
import { DashboardMain } from "~/components/dashboard/DashboardMain"
|
||||
import type { ReactElement } from "react"
|
||||
import { useDate } from "~/hooks/useDate"
|
||||
import { useTranslation } from "next-i18next"
|
||||
import { getServerSideProps as getLayoutServerSideProps } from "~/components/dashboard/DashboardLayout.server"
|
||||
import { GetServerSideProps } from "next"
|
||||
import { serverSidePropsHandler } from "~/lib/server-side-props"
|
||||
import {
|
||||
useAccountState,
|
||||
useAccountBalance,
|
||||
useWalletClaimCSBModal,
|
||||
useClaimCSBStatus,
|
||||
} from "@crossbell/connect-kit"
|
||||
import { useGetMiraBalance } from "~/queries/site"
|
||||
import { Button } from "~/components/ui/Button"
|
||||
import { MIRA_LINK } from "~/lib/env"
|
||||
import { UniLink } from "~/components/ui/UniLink"
|
||||
import { useRouter } from "next/router"
|
||||
|
||||
export const getServerSideProps: GetServerSideProps = serverSidePropsHandler(
|
||||
async (ctx) => {
|
||||
const { props: layoutProps } = await getLayoutServerSideProps(ctx)
|
||||
|
||||
return {
|
||||
props: {
|
||||
...layoutProps,
|
||||
},
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
export default function TokensPage() {
|
||||
const router = useRouter()
|
||||
const { t } = useTranslation(["dashboard", "index"])
|
||||
const subdomain = router.query.subdomain as string
|
||||
|
||||
const address = useAccountState((s) => s.wallet?.address)
|
||||
const miraBalance = useGetMiraBalance(address)
|
||||
const csbBalance = useAccountBalance()
|
||||
const claimCSBStatus = useClaimCSBStatus()
|
||||
const claimCSBModal = useWalletClaimCSBModal()
|
||||
|
||||
const tokens = [
|
||||
{
|
||||
name: "MIRA",
|
||||
balance: miraBalance.data?.data || 0,
|
||||
description: (
|
||||
<>
|
||||
<p>
|
||||
{t(
|
||||
"1 MIRA ≈ 1 USDC, swap easily on cross-chain bridge and Uniswap.",
|
||||
)}
|
||||
</p>
|
||||
<p>
|
||||
{t("In the early stage, xLog will use $MIRA to motivate creators.")}
|
||||
</p>
|
||||
<p>{t("You can obtain $MIRA through the following ways:")}</p>
|
||||
<ul className="ml-2">
|
||||
<li>
|
||||
1.{" "}
|
||||
<UniLink className="underline" href="">
|
||||
{t("Creator incentive program.")}
|
||||
</UniLink>
|
||||
</li>
|
||||
<li>
|
||||
2.{" "}
|
||||
<UniLink
|
||||
className="underline"
|
||||
href={`/dashboard/${subdomain}/events`}
|
||||
>
|
||||
{t("Participate in events.")}
|
||||
</UniLink>
|
||||
</li>
|
||||
<li>
|
||||
3.{" "}
|
||||
<UniLink className="underline" href={MIRA_LINK}>
|
||||
{t("Swap from USDC.")}
|
||||
</UniLink>
|
||||
</li>
|
||||
</ul>
|
||||
</>
|
||||
),
|
||||
buttons: (
|
||||
<>
|
||||
<Button onClick={() => window.open(MIRA_LINK)}>
|
||||
{t("Swap to USDC")}
|
||||
</Button>
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "CSB",
|
||||
balance: csbBalance?.balance?.formatted || 0,
|
||||
description: (
|
||||
<>
|
||||
{t(
|
||||
"This is a token used for interaction on the Crossbell blockchain, which can be claimed for free from the faucet, so there's no need to worry about its balance.",
|
||||
)}
|
||||
</>
|
||||
),
|
||||
buttons: (
|
||||
<>
|
||||
<Button
|
||||
isDisabled={!claimCSBStatus.isEligibleToClaim}
|
||||
onClick={() => claimCSBModal.show()}
|
||||
>
|
||||
{claimCSBStatus.errorMsg || t("Free Claim")}
|
||||
</Button>
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "XLOG",
|
||||
description: t(
|
||||
"$XLOG is related to xLog DAO, but it's too early now, please stay tuned.",
|
||||
),
|
||||
balance: t("Stay tuned"),
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<DashboardMain title="Tokens">
|
||||
<div className="min-w-[270px] max-w-screen-lg flex flex-col space-y-8">
|
||||
<div className="text-sm text-zinc-500 leading-relaxed">
|
||||
{t("features.Earn.description", { ns: "index" })}
|
||||
</div>
|
||||
{tokens.map((token) => {
|
||||
return (
|
||||
<div key={token.name} className="space-y-4">
|
||||
<div className="text-2xl font-medium text-accent">
|
||||
${token.name}
|
||||
</div>
|
||||
<div className="text-zinc-500 text-sm space-y-1">
|
||||
{token.description}
|
||||
</div>
|
||||
<div className="text-lg">
|
||||
{t("Balance")}:{" "}
|
||||
<span className="font-bold">{token.balance}</span>
|
||||
</div>
|
||||
<div>{token.buttons}</div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</DashboardMain>
|
||||
)
|
||||
}
|
||||
|
||||
TokensPage.getLayout = (page: ReactElement) => {
|
||||
return <DashboardLayout title="Tokens">{page}</DashboardLayout>
|
||||
}
|
||||
|
|
@ -409,3 +409,15 @@ export const useMintAchievement = () => {
|
|||
},
|
||||
)
|
||||
}
|
||||
|
||||
export const useGetMiraBalance = (address?: string) => {
|
||||
const contract = useContract()
|
||||
return useQuery(["getMiraBalance", address], async () => {
|
||||
if (!address) {
|
||||
return {
|
||||
data: "0",
|
||||
}
|
||||
}
|
||||
return siteModel.getMiraBalance(address, contract)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue