Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
7 changes: 4 additions & 3 deletions packages/ui/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,10 @@ A beautiful and modern web application for creating and managing Token-2022 toke
ui/
├── src/
│ ├── app/ # Next.js app directory
│ │ ├── create/ # Token creation pages
│ │ ├── manage/ # Token management pages
│ │ └── dashboard/ # Main dashboard
│ │ ├── dashboard/ # Main dashboard
│ │ │ ├── create/ # Token creation pages
│ │ │ └── manage/ # Token management pages
│ │ └── globals.css # Global styles
│ ├── components/ # Reusable UI components
│ │ ├── ui/ # Base UI components
│ │ ├── forms/ # Form components
Expand Down
7 changes: 6 additions & 1 deletion packages/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,13 @@
"@mosaic/sdk": "workspace:*",
"@radix-ui/react-dropdown-menu": "^2.0.6",
"@radix-ui/react-slot": "^1.0.2",
"@solana/wallet-adapter-base": "^0.9.27",
"@solana/wallet-adapter-react": "^0.15.39",
"@solana/wallet-adapter-react-ui": "^0.9.39",
"@solana/wallet-adapter-wallets": "^0.19.37",
"class-variance-authority": "^0.7.0",
"clsx": "^2.0.0",
"gill": "^0.10.2",
"lucide-react": "^0.294.0",
"next": "14.0.4",
"next-themes": "^0.2.1",
Expand All @@ -34,4 +39,4 @@
"tailwindcss": "^3.3.6",
"typescript": "^5.3.2"
}
}
}
7 changes: 7 additions & 0 deletions packages/ui/src/app/dashboard/create/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default function CreatePage() {
return (
<div className="flex-1">
Dashboard
</div>
)
}
7 changes: 7 additions & 0 deletions packages/ui/src/app/dashboard/manage/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default function ManagePage() {
return (
<div className="flex-1">
Dashboard
</div>
)
}
188 changes: 188 additions & 0 deletions packages/ui/src/app/dashboard/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
"use client";

import { useWallet } from "@solana/wallet-adapter-react";
import { useEffect, useState } from "react";
import { Button } from "@/components/ui/button";
import { Plus, Settings, Coins } from "lucide-react";
import Link from "next/link";
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";

export default function DashboardPage() {
const { connected, publicKey } = useWallet();
const [walletConnected, setWalletConnected] = useState(false);

useEffect(() => {
setWalletConnected(connected && !!publicKey);
}, [connected, publicKey]);

return walletConnected && publicKey ? <DashboardConnected publicKey={publicKey.toBase58()}/> : <DashboardDisconnected />;
}

function DashboardConnected({ publicKey } : { publicKey: string }) {
// Placeholder: Replace with actual token fetching logic
const [tokens, setTokens] = useState<any[]>([]);
const [loading, setLoading] = useState(true);

useEffect(() => {
// Simulate loading tokens
setTimeout(() => {
// Placeholder: Replace with actual token fetching
setTokens([]); // Empty array for "no tokens" state
setLoading(false);
}, 1000);
}, []);

if (loading) {
return (
<div className="flex-1 p-8">
<div className="flex items-center justify-center h-64">
<div className="text-center">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-primary mx-auto mb-4"></div>
<p className="text-muted-foreground">Loading your tokens...</p>
</div>
</div>
</div>
);
}

if (tokens.length === 0) {
return (
<div className="flex-1 p-8">
<div className="max-w-4xl mx-auto">
<div className="text-center mb-8">
<h2 className="text-3xl font-bold mb-4">Welcome to Mosaic</h2>
<p className="text-lg text-muted-foreground mb-8">
Create your first token to get started with tokenization on Solana
</p>
</div>

<div className="grid grid-cols-1 md:grid-cols-2 gap-6 mb-8">
<Card className="h-full flex flex-col">
<CardHeader>
<div className="flex items-center">
<Coins className="h-8 w-8 text-primary mr-3" />
<CardTitle>Stablecoin</CardTitle>
</div>
</CardHeader>
<CardContent className="flex-1">
<CardDescription>
Create a regulatory-compliant stablecoin with transfer restrictions and metadata management.
</CardDescription>
</CardContent>
<CardFooter>
<Link href="/dashboard/create/stablecoin" className="w-full">
<Button className="w-full">
<Plus className="h-4 w-4 mr-2" />
Create Stablecoin
</Button>
</Link>
</CardFooter>
</Card>

<Card className="h-full flex flex-col">
<CardHeader>
<div className="flex items-center">
<Coins className="h-8 w-8 text-primary mr-3" />
<CardTitle>Arcade Token</CardTitle>
</div>
</CardHeader>
<CardContent className="flex-1">
<CardDescription>
Deploy a gaming or utility token with custom extensions and features.
</CardDescription>
</CardContent>
<CardFooter>
<Link href="/dashboard/create/arcade-token" className="w-full">
<Button className="w-full">
<Plus className="h-4 w-4 mr-2" />
Create Arcade Token
</Button>
</Link>
</CardFooter>
</Card>
</div>

<div className="text-center">
<p className="text-sm text-muted-foreground">
Public Key: {publicKey.slice(0, 8)}...{publicKey.slice(-8)}
</p>
</div>
</div>
</div>
);
}

return (
<div className="flex-1 p-8">
<div className="max-w-6xl mx-auto">
<div className="flex items-center justify-between mb-8">
<div>
<h2 className="text-3xl font-bold mb-2">Your Tokens</h2>
<p className="text-muted-foreground">
Manage your created tokens and their extensions
</p>
</div>
<Link href="/create">
<Button>
<Plus className="h-4 w-4 mr-2" />
Create New Token
</Button>
</Link>
</div>

<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{tokens.map((token, index) => (
<Card key={index} className="h-full flex flex-col">
<CardHeader>
<div className="flex items-center justify-between">
<div className="flex items-center">
<Coins className="h-6 w-6 text-primary mr-3" />
<div>
<CardTitle className="text-lg">{token.name || `Token ${index + 1}`}</CardTitle>
<CardDescription>{token.symbol || 'TKN'}</CardDescription>
</div>
</div>
</div>
</CardHeader>
<CardContent className="flex-1">
<div className="space-y-2 text-sm">
<div className="flex justify-between">
<span className="text-muted-foreground">Supply:</span>
<span>{token.supply || '1,000,000'}</span>
</div>
<div className="flex justify-between">
<span className="text-muted-foreground">Type:</span>
<span>{token.type || 'Standard'}</span>
</div>
<div className="flex justify-between">
<span className="text-muted-foreground">Status:</span>
<span className="text-green-600">Active</span>
</div>
</div>
</CardContent>
<CardFooter>
<Link href={`/manage/${token.address || index}`} className="w-full">
<Button variant="outline" className="w-full">
<Settings className="h-4 w-4 mr-2" />
Manage
</Button>
</Link>
</CardFooter>
</Card>
))}
</div>
</div>
</div>
);
}

function DashboardDisconnected() {
return (
<div className="flex-1 flex flex-col items-center justify-center p-8">
<div className="text-center">
<h2 className="text-3xl font-bold mb-4">Welcome to Mosaic</h2>
<p className="mb-6">Please connect your Solana wallet to access the dashboard.</p>
</div>
</div>
);
}
43 changes: 23 additions & 20 deletions packages/ui/src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import type { Metadata } from "next"
import { Inter } from "next/font/google"
import { AR_One_Sans } from "next/font/google"
import "./globals.css"
import { ThemeProvider } from "@/components/theme-provider"
import { Header } from "@/components/layout/header"
import { Footer } from "@/components/layout/footer"
import { SolanaProvider } from "@/components/solana-provider"

const inter = Inter({ subsets: ["latin"] })
const ar = AR_One_Sans({ subsets: ["latin"] })

export const metadata: Metadata = {
title: "Mosaic - Tokenization Engine",
Expand All @@ -18,23 +19,25 @@ export default function RootLayout({
children: React.ReactNode
}) {
return (
<html lang="en" suppressHydrationWarning>
<body className={inter.className}>
<ThemeProvider
attribute="class"
defaultTheme="dark"
enableSystem
disableTransitionOnChange
>
<div className="flex min-h-screen flex-col bg-background">
<Header />
<main className="flex-1">
{children}
</main>
<Footer />
</div>
</ThemeProvider>
</body>
</html>
<SolanaProvider>
<html lang="en" suppressHydrationWarning>
<body className={ar.className}>
<ThemeProvider
attribute="class"
defaultTheme="dark"
enableSystem
disableTransitionOnChange
>
<div className="flex min-h-screen flex-col bg-background">
<Header />
<main className="flex-1">
{children}
</main>
<Footer />
</div>
</ThemeProvider>
</body>
</html>
</SolanaProvider>
)
}
23 changes: 17 additions & 6 deletions packages/ui/src/components/layout/header.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,28 @@
"use client"

import { ModeToggle } from "@/components/mode-toggle"
import { Button } from "@/components/ui/button"
import { useRouter, usePathname } from "next/navigation"
import { WalletMultiButton } from "@solana/wallet-adapter-react-ui"
import Link from "next/link"

export function Header() {
const router = useRouter()
const pathname = usePathname()

return (
<header className="sticky top-0 z-50 w-full border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
<div className="container flex h-16 items-center justify-between">
<div className="flex items-center space-x-2">
<h1 className="text-2xl font-bold">Mosaic</h1>
</div>
<div className="container flex h-20 items-center justify-between">
<Link className="flex items-center space-x-2" href={"/"}>
<h1 className="text-3xl font-bold">Mosaic</h1>
</Link>
<div className="flex items-center space-x-4">
<Button variant="outline">Get Started</Button>
{pathname === "/" ? (
<Button variant="outline" onClick={() => router.push("/dashboard")} className="p-6 text-lg">
Get Started
</Button>
) : (
<WalletMultiButton/>
)}
<ModeToggle />
</div>
</div>
Expand Down
6 changes: 3 additions & 3 deletions packages/ui/src/components/mode-toggle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ export function ModeToggle() {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline" size="icon">
<Sun className="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
<Moon className="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
<Button variant="outline" className="h-12 w-12 px-2">
<Sun className="h-[1.4rem] w-[1.4rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
<Moon className="absolute h-[1.4rem] w-[1.4rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
<span className="sr-only">Toggle theme</span>
</Button>
</DropdownMenuTrigger>
Expand Down
7 changes: 5 additions & 2 deletions packages/ui/src/components/sections/hero.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
"use client"
import { Button } from "@/components/ui/button"
import { Coins, Shield, Zap } from "lucide-react"
import { useRouter } from "next/navigation"

export function Hero() {
const router = useRouter()
return (
<section className="relative overflow-hidden bg-background py-24 sm:py-32">
<div className="container relative z-10 mx-auto px-4 sm:px-6 lg:px-8">
Expand All @@ -14,8 +17,8 @@ export function Hero() {
enterprise-grade security and compliance features.
</p>
<div className="mt-10 flex items-center justify-center gap-x-6">
<Button size="lg">
Create Token
<Button size="lg" onClick={() => router.push("/dashboard")}>
Tokenize!
</Button>
<Button variant="outline" size="lg">
Learn More
Expand Down
Loading
Loading