🚀 MyZubster NFT Dashboard – A Complete Frontend for Tari NFTs
After building the backend Rust template for Tari NFTs and dockerizing it, I wanted to create a user-friendly interface that anyone could use. The result is MyZubster NFT Dashboard – a complete React frontend for managing NFT collections on Tari.
📸 The Dashboard in Action
The dashboard is clean, dark-themed (GitHub style), and packed with features:
- 🔐 Wallet Connection – Connect your Tari wallet
- 🏗️ Create Collection – Create new NFT collections with name and symbol
- 🎨 Mint NFT – Mint NFTs with immutable and mutable metadata
- 🖼️ NFT Gallery – View all NFTs in a collection
🛠️ Tech Stack
| Technology | Purpose |
|---|---|
| React 19 | UI Framework |
| TypeScript | Type Safety |
| Vite | Build Tool |
| CSS3 | Styling (Dark Mode) |
🧩 Component Architecture
src/
├── components/
│ ├── ConnectWallet.tsx # Wallet connection UI
│ ├── CreateCollection.tsx # Create new NFT collection
│ ├── MintNFT.tsx # Mint NFTs
│ └── NFTGallery.tsx # Display NFT gallery
├── hooks/
│ └── useTariWallet.ts # Wallet connection logic
├── App.tsx # Main dashboard
└── App.css # Global styles
text
🔐 ConnectWallet – Wallet Connection
tsx
const ConnectWallet: React.FC = () => {
const { isConnected, isLoading, connectWallet, disconnectWallet } = useTariWallet();
return (
<div className="card">
<h3>🔐 Connessione Wallet</h3>
{!isConnected ? (
<button onClick={connectWallet} disabled={isLoading}>
{isLoading ? '⏳ Connessione in corso...' : '🔗 Connetti Wallet Tari'}
</button>
) : (
<div>
<p className="status-connected">✅ Wallet connesso con successo!</p>
<button className="danger" onClick={disconnectWallet}>
🔌 Disconnetti
</button>
</div>
)}
</div>
);
};
🏗️ CreateCollection – NFT Collection Creation
Users can create a new NFT collection by entering a name and symbol.
tsx
const CreateCollection: React.FC = () => {
const { isConnected } = useTariWallet();
const [name, setName] = useState('');
const [symbol, setSymbol] = useState('');
const handleCreateCollection = async () => {
// Calls the 'new' function on the Tari template
// Simulated for now, ready for real integration
await new Promise(resolve => setTimeout(resolve, 2000));
setResult({ success: true, message: `✅ Collezione "${name}" creata!` });
};
return (
<div className="card">
<h3>🏗️ Crea Nuova Collezione NFT</h3>
<input placeholder="Nome della collezione" value={name} onChange={...} />
<input placeholder="Simbolo (es. ART)" value={symbol} onChange={...} />
<button onClick={handleCreateCollection} disabled={!isConnected}>
🚀 Crea Collezione
</button>
</div>
);
};
🎨 MintNFT – NFT Minting
Mint new NFTs with custom ID, immutable data (e.g., image URL), and mutable data (e.g., status).
tsx
const MintNFT: React.FC = () => {
const { isConnected } = useTariWallet();
const [componentAddress, setComponentAddress] = useState('');
const [nftId, setNftId] = useState('');
const [immutableData, setImmutableData] = useState('');
const [mutableData, setMutableData] = useState('');
const handleMintNFT = async () => {
// Calls the 'mint' function on the Tari component
await new Promise(resolve => setTimeout(resolve, 2000));
setResult({ success: true, message: `✅ NFT "${nftId}" mintato!` });
};
return (
<div className="card">
<h3>🎨 Minta un Nuovo NFT</h3>
<input placeholder="Indirizzo della collezione" value={componentAddress} onChange={...} />
<input placeholder="ID NFT (es. nft-001)" value={nftId} onChange={...} />
<input placeholder="Dati immutabili (es. URL immagine)" value={immutableData} onChange={...} />
<input placeholder="Dati mutabili (es. disponibile)" value={mutableData} onChange={...} />
<button onClick={handleMintNFT} disabled={!isConnected}>
🎨 Minta NFT
</button>
</div>
);
};
🖼️ NFTGallery – NFT Gallery
Display NFTs in a clean grid layout with image previews and metadata.
tsx
const NFTGallery: React.FC = () => {
const [nfts, setNfts] = useState<NFT[]>([]);
const [componentAddress, setComponentAddress] = useState('');
const fetchNFTs = async () => {
// Fetches NFTs from the blockchain using IndexerProvider
// Simulated with mock data for now
const mockNFTs: NFT[] = [
{ id: 'nft-001', immutableData: 'https://example.com/nft1.png', mutableData: 'Disponibile' },
{ id: 'nft-002', immutableData: 'https://example.com/nft2.png', mutableData: 'In vendita' },
{ id: 'nft-003', immutableData: 'https://example.com/nft3.png', mutableData: 'Venduto' },
];
setNfts(mockNFTs);
};
return (
<div className="card">
<h3>🖼️ Galleria NFT</h3>
<input placeholder="Indirizzo della collezione" value={componentAddress} onChange={...} />
<button onClick={fetchNFTs}>🔍 Cerca NFT</button>
<div className="grid">
{nfts.map((nft) => (
<NFTCard key={nft.id} nft={nft} />
))}
</div>
</div>
);
};
🎨 UI Design
The dashboard features a dark theme inspired by GitHub:
Background: #0d1117
Cards: #161b22 with #30363d borders
Accent: #58a6ff (blue) and #3fb950 (green)
Typography: System font stack
📦 How to Run the Dashboard
Clone the repository
bash
git clone https://github.com/DanielIoni-creator/tari-nft-template.git
cd tari-nft-template/myzubster-frontend
Install dependencies
bash
npm install
Start the development server
bash
npm run dev
Build for production
bash
npm run build
🔗 Links
GitHub: https://github.com/DanielIoni-creator/tari-nft-template
Docker Hub: https://hub.docker.com/repository/docker/myzubster/tari-nft-template
Backend Template: https://dev.to/danielioni/i-built-an-nft-template-for-tari-monero-sidechain-heres-how-33k
Why Monero Over Bitcoin: https://dev.to/danielioni/myzubster-tech-guide-why-monero-not-bitcoin-is-the-future-of-private-digital-assets-2f5m
🚀 Next Steps
Integrate real wallet connection with tari.js
Deploy on VPS for public access
Add advanced features (royalty, whitelist, limited minting)
Build community around MyZubster
🗣️ Let's Discuss
If you're a Rust, React, or blockchain developer interested in Tari and Monero, I'd love to hear your feedback!
📖 Dev.to: https://dev.to/danielioni
🐦 Twitter: https://x.com/myzubster
💼 LinkedIn: https://www.linkedin.com/in/daniel-ioni-62b2b9423/
🐙 GitHub: https://github.com/DanielIoni-creator
Built with ❤️ for the Monero and Tari community.


Top comments (0)