mirror of
https://github.com/hanzoai/bootnode.git
synced 2026-09-30 20:46:32 +00:00
Merge remote-tracking branch 'origin/main'
# Conflicts: # console/package.json # console/pnpm-lock.yaml # console/pnpm-workspace.yaml Co-authored-by: Hanzo Dev <[email protected]>
This commit is contained in:
@@ -13,7 +13,7 @@ import {
|
||||
Shield,
|
||||
Users,
|
||||
Zap,
|
||||
} from "lucide-react"
|
||||
} from "@luxfi/ui/icons"
|
||||
import { getBrand } from "@/lib/brand"
|
||||
|
||||
const brand = getBrand()
|
||||
|
||||
@@ -12,7 +12,7 @@ import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
|
||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
|
||||
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog"
|
||||
import { useAuth, ProtectedRoute, OrgBadge } from "@/lib/auth"
|
||||
import { Activity, Server, Globe, Users, Database, Zap, Shield, Network, MapPin, Plus, Settings, Trash2, Eye, BarChart3 } from "lucide-react"
|
||||
import { Activity, Server, Globe, Users, Database, Zap, Shield, Network, MapPin, Plus, Settings, Trash2, Eye, BarChart3 } from "@luxfi/ui/icons"
|
||||
import { getBrand } from "@/lib/brand"
|
||||
|
||||
// Donut Chart Component (Modern replacement for D3 donut)
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
Terminal,
|
||||
Webhook,
|
||||
Zap,
|
||||
} from "lucide-react"
|
||||
} from "@luxfi/ui/icons"
|
||||
import { getBrand } from "@/lib/brand"
|
||||
|
||||
export const metadata: Metadata = {
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
BookOpen,
|
||||
Calendar,
|
||||
Clock,
|
||||
} from "lucide-react"
|
||||
} from "@luxfi/ui/icons"
|
||||
import { getBrand } from "@/lib/brand"
|
||||
|
||||
export default function BlogPage() {
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
MapPin,
|
||||
Rocket,
|
||||
Zap,
|
||||
} from "lucide-react"
|
||||
} from "@luxfi/ui/icons"
|
||||
import { getBrand } from "@/lib/brand"
|
||||
|
||||
const brand = getBrand()
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
Globe,
|
||||
Network,
|
||||
Zap,
|
||||
} from "lucide-react"
|
||||
} from "@luxfi/ui/icons"
|
||||
|
||||
const CHAIN_EXPLORERS: Record<string, string> = {
|
||||
ethereum: "https://etherscan.io",
|
||||
|
||||
@@ -19,7 +19,7 @@ import {
|
||||
Globe,
|
||||
Search,
|
||||
Zap,
|
||||
} from "lucide-react"
|
||||
} from "@luxfi/ui/icons"
|
||||
|
||||
const CATEGORY_ORDER: ChainCategory[] = [
|
||||
"ethereum-l1",
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
Mail,
|
||||
MessageSquare,
|
||||
Send,
|
||||
} from "lucide-react"
|
||||
} from "@luxfi/ui/icons"
|
||||
import { getBrand } from "@/lib/brand"
|
||||
|
||||
const brand = getBrand()
|
||||
|
||||
@@ -19,7 +19,7 @@ import {
|
||||
RefreshCcw,
|
||||
TrendingUp,
|
||||
Globe
|
||||
} from "lucide-react"
|
||||
} from "@luxfi/ui/icons"
|
||||
|
||||
interface AnalyticsData {
|
||||
totalRequests: number
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
Check,
|
||||
X,
|
||||
Loader2,
|
||||
} from "lucide-react"
|
||||
} from "@luxfi/ui/icons"
|
||||
import { useApiKeys, useCreateApiKey, useDeleteApiKey } from "@/lib/hooks"
|
||||
|
||||
function getProjectId(): string {
|
||||
|
||||
@@ -6,7 +6,7 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/com
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { Input } from "@/components/ui/input"
|
||||
import { Image, Search, ExternalLink, Loader2 } from "lucide-react"
|
||||
import { Image, Search, ExternalLink, Loader2 } from "@luxfi/ui/icons"
|
||||
|
||||
interface NFT {
|
||||
contract: string
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { Coins, Image, Wallet } from "lucide-react"
|
||||
import { Coins, Image, Wallet } from "@luxfi/ui/icons"
|
||||
import Link from "next/link"
|
||||
|
||||
export default function AssetsPage() {
|
||||
|
||||
@@ -6,7 +6,7 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/com
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Input } from "@/components/ui/input"
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { Coins, Search, Loader2 } from "lucide-react"
|
||||
import { Coins, Search, Loader2 } from "@luxfi/ui/icons"
|
||||
|
||||
interface TokenMetadata {
|
||||
contract_address: string
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
DollarSign,
|
||||
Zap,
|
||||
Settings,
|
||||
} from "lucide-react"
|
||||
} from "@luxfi/ui/icons"
|
||||
import { useGasPolicies, useCreateGasPolicy, useDeleteGasPolicy, useGasPrices } from "@/lib/hooks"
|
||||
|
||||
export default function GasPoliciesPage() {
|
||||
|
||||
@@ -6,7 +6,7 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/com
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { Input } from "@/components/ui/input"
|
||||
import { Box, Plus, Loader2, X, Settings, Download, Scale } from "lucide-react"
|
||||
import { Box, Plus, Loader2, X, Settings, Download, Scale } from "@luxfi/ui/icons"
|
||||
|
||||
interface Cluster {
|
||||
id: string
|
||||
|
||||
@@ -7,7 +7,7 @@ import { DOKS_REGIONS, type LuxFleet } from "@/components/lux/region-data"
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Globe, Plus, RefreshCw, Zap } from "lucide-react"
|
||||
import { Globe, Plus, RefreshCw, Zap } from "@luxfi/ui/icons"
|
||||
|
||||
/** Convert LuxFleet[] to FleetRegion[] for the map component */
|
||||
function fleetsToRegions(fleets: LuxFleet[]): FleetRegion[] {
|
||||
|
||||
@@ -39,7 +39,7 @@ import {
|
||||
ChevronRight,
|
||||
Circle,
|
||||
AlertTriangle,
|
||||
} from "lucide-react"
|
||||
} from "@luxfi/ui/icons"
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Types
|
||||
|
||||
@@ -4,7 +4,7 @@ import { getApiUrl } from "@/lib/api"
|
||||
import { useState, useEffect } from "react"
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { Activity, Cpu, HardDrive, MemoryStick, Wifi, WifiOff, Loader2 } from "lucide-react"
|
||||
import { Activity, Cpu, HardDrive, MemoryStick, Wifi, WifiOff, Loader2 } from "@luxfi/ui/icons"
|
||||
|
||||
interface NodeHealth {
|
||||
id: string
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "@/components/ui/table"
|
||||
import { Globe, Loader2, RefreshCcw, ExternalLink, Activity, Zap, CheckCircle, AlertTriangle, XCircle, AlertCircle } from "lucide-react"
|
||||
import { Globe, Loader2, RefreshCcw, ExternalLink, Activity, Zap, CheckCircle, AlertTriangle, XCircle, AlertCircle } from "@luxfi/ui/icons"
|
||||
import Link from "next/link"
|
||||
import { getApiUrl, getAuthHeaders, load, loadError } from "@/lib/api"
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import { Input } from "@/components/ui/input"
|
||||
import {
|
||||
Server, ArrowLeft, Play, Square, Trash2, RefreshCcw, Copy, Check,
|
||||
Activity, HardDrive, Cpu, MemoryStick, Network, Loader2, Terminal
|
||||
} from "lucide-react"
|
||||
} from "@luxfi/ui/icons"
|
||||
|
||||
interface NodeDetails {
|
||||
id: string
|
||||
|
||||
@@ -7,7 +7,7 @@ import { Button } from "@/components/ui/button"
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { Input } from "@/components/ui/input"
|
||||
import { Select } from "@/components/ui/select"
|
||||
import { Server, Plus, ExternalLink, Loader2, X, Play, Square, Trash2, RefreshCcw, Activity, AlertTriangle, ChevronRight } from "lucide-react"
|
||||
import { Server, Plus, ExternalLink, Loader2, X, Play, Square, Trash2, RefreshCcw, Activity, AlertTriangle, ChevronRight, ArrowDown, ArrowUp } from "@luxfi/ui/icons"
|
||||
import Link from "next/link"
|
||||
import { getBrand } from "@/lib/brand"
|
||||
|
||||
@@ -940,8 +940,8 @@ export default function NodesPage() {
|
||||
{node.metrics?.network_rx !== undefined && (
|
||||
<div className="text-right hidden xl:block">
|
||||
<p className="text-sm font-medium">
|
||||
<span className="text-green-500">↓</span>{node.metrics.network_rx.toFixed(0)}
|
||||
<span className="text-blue-500 ml-1">↑</span>{node.metrics.network_tx?.toFixed(0) || 0} MB
|
||||
<ArrowDown className="inline size-3.5 text-green-500" aria-label="in" />{node.metrics.network_rx.toFixed(0)}
|
||||
<ArrowUp className="ml-1 inline size-3.5 text-blue-500" aria-label="out" />{node.metrics.network_tx?.toFixed(0) || 0} MB
|
||||
</p>
|
||||
<p className="text-xs text-muted-foreground">Network</p>
|
||||
</div>
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
ArrowUpRight,
|
||||
ArrowDownRight,
|
||||
Minus,
|
||||
} from "lucide-react"
|
||||
} from "@luxfi/ui/icons"
|
||||
|
||||
interface HealthOverview {
|
||||
total_services: number
|
||||
|
||||
@@ -5,7 +5,7 @@ import { useState, useEffect } from "react"
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { Server, Box, HardDrive, Copy, Loader2, Shield } from "lucide-react"
|
||||
import { Server, Box, HardDrive, Copy, Loader2, Shield } from "@luxfi/ui/icons"
|
||||
import Link from "next/link"
|
||||
|
||||
interface InfraStats {
|
||||
|
||||
@@ -24,7 +24,7 @@ import {
|
||||
CheckCircle2,
|
||||
XCircle,
|
||||
Minus,
|
||||
} from "lucide-react"
|
||||
} from "@luxfi/ui/icons"
|
||||
|
||||
interface ServiceInfo {
|
||||
name: string
|
||||
|
||||
@@ -6,7 +6,7 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/com
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { Input } from "@/components/ui/input"
|
||||
import { Copy, Loader2, X, HardDrive, Camera, CheckCircle, Clock, AlertCircle } from "lucide-react"
|
||||
import { Copy, Loader2, X, HardDrive, Camera, CheckCircle, Clock, AlertCircle } from "@luxfi/ui/icons"
|
||||
|
||||
interface Volume {
|
||||
id: string
|
||||
|
||||
@@ -6,7 +6,7 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/com
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { Input } from "@/components/ui/input"
|
||||
import { HardDrive, Plus, Loader2, X, Camera, Link2, Unlink, ArrowUpRight } from "lucide-react"
|
||||
import { HardDrive, Plus, Loader2, X, Camera, Link2, Unlink, ArrowUpRight } from "@luxfi/ui/icons"
|
||||
|
||||
interface Volume {
|
||||
id: string
|
||||
|
||||
@@ -9,7 +9,7 @@ import { Input } from "@/components/ui/input"
|
||||
import {
|
||||
TrendingUp, TrendingDown, Server, Coins, Search, ArrowUpRight,
|
||||
Loader2, Filter, ChevronRight, Zap, Shield, Globe, Star, Lock
|
||||
} from "lucide-react"
|
||||
} from "@luxfi/ui/icons"
|
||||
import Link from "next/link"
|
||||
|
||||
interface StakingData {
|
||||
|
||||
@@ -24,7 +24,7 @@ import {
|
||||
Wifi,
|
||||
XCircle,
|
||||
Zap,
|
||||
} from "lucide-react"
|
||||
} from "@luxfi/ui/icons"
|
||||
import { getApiUrl, getAuthHeaders } from "@/lib/api"
|
||||
|
||||
interface HealthCheck {
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
Loader2,
|
||||
ArrowUpRight,
|
||||
AlertCircle,
|
||||
} from "lucide-react"
|
||||
} from "@luxfi/ui/icons"
|
||||
|
||||
interface Tier {
|
||||
name: string
|
||||
|
||||
@@ -5,7 +5,7 @@ import { useEffect, useState } from "react"
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { Building, Users, Settings, Key, Loader2, CreditCard, AlertCircle } from "lucide-react"
|
||||
import { Building, Users, Settings, Key, Loader2, CreditCard, AlertCircle } from "@luxfi/ui/icons"
|
||||
import Link from "next/link"
|
||||
import { useAuth } from "@/lib/auth"
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import { Button } from "@/components/ui/button"
|
||||
import { Input } from "@/components/ui/input"
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { Switch } from "@/components/ui/switch"
|
||||
import { Building, Globe, Bell, Shield, Loader2, CheckCircle2, AlertCircle } from "lucide-react"
|
||||
import { Building, Globe, Bell, Shield, Loader2, CheckCircle2, AlertCircle } from "@luxfi/ui/icons"
|
||||
import { useAuth } from "@/lib/auth"
|
||||
|
||||
interface OrgSettings {
|
||||
|
||||
@@ -13,7 +13,7 @@ import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/u
|
||||
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
|
||||
import { useAuth } from "@/lib/auth"
|
||||
import { team as teamApi, TeamMember } from "@/lib/api"
|
||||
import { Users, UserPlus, Mail, Shield, Settings, Trash2, Loader2 } from "lucide-react"
|
||||
import { Users, UserPlus, Mail, Shield, Settings, Trash2, Loader2 } from "@luxfi/ui/icons"
|
||||
|
||||
export default function TeamPage() {
|
||||
const { user } = useAuth()
|
||||
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
Building,
|
||||
Loader2,
|
||||
AlertCircle
|
||||
} from "lucide-react"
|
||||
} from "@luxfi/ui/icons"
|
||||
|
||||
interface DashboardStats {
|
||||
api_requests: number
|
||||
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
EyeOff,
|
||||
LogOut,
|
||||
User,
|
||||
} from "lucide-react"
|
||||
} from "@luxfi/ui/icons"
|
||||
import { useAuth, OrgBadge } from "@/lib/auth"
|
||||
import { getApiUrl } from "@/lib/api"
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import { Input } from "@/components/ui/input"
|
||||
import {
|
||||
Wallet, Key, Shield, Server, Coins, Lock, Unlock, ExternalLink,
|
||||
Loader2, ChevronRight, Zap, AlertTriangle, Check, Copy, RefreshCcw
|
||||
} from "lucide-react"
|
||||
} from "@luxfi/ui/icons"
|
||||
import Link from "next/link"
|
||||
|
||||
interface Validator {
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
Globe,
|
||||
Database,
|
||||
Server,
|
||||
} from "lucide-react"
|
||||
} from "@luxfi/ui/icons"
|
||||
import { useChains } from "@/lib/hooks"
|
||||
import { getBrand } from "@/lib/brand"
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
Shield,
|
||||
Key,
|
||||
Users,
|
||||
} from "lucide-react"
|
||||
} from "@luxfi/ui/icons"
|
||||
import { useWallets, useCreateWallet } from "@/lib/hooks"
|
||||
import { getBrand } from "@/lib/brand"
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
Send,
|
||||
ChevronDown,
|
||||
ChevronUp,
|
||||
} from "lucide-react"
|
||||
} from "@luxfi/ui/icons"
|
||||
import {
|
||||
useWebhooks,
|
||||
useCreateWebhook,
|
||||
|
||||
@@ -2,7 +2,7 @@ import Link from "next/link"
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { Card, CardContent } from "@/components/ui/card"
|
||||
import { DocsLayout } from "@/components/docs-layout"
|
||||
import { ArrowRight } from "lucide-react"
|
||||
import { ArrowRight } from "@luxfi/ui/icons"
|
||||
import { docsConfig } from "@/lib/docs-config"
|
||||
|
||||
export const metadata = {
|
||||
|
||||
@@ -2,7 +2,7 @@ import Link from "next/link"
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { Card, CardContent } from "@/components/ui/card"
|
||||
import { DocsLayout } from "@/components/docs-layout"
|
||||
import { ArrowRight } from "lucide-react"
|
||||
import { ArrowRight } from "@luxfi/ui/icons"
|
||||
import { docsConfig } from "@/lib/docs-config"
|
||||
|
||||
export const metadata = {
|
||||
|
||||
@@ -2,7 +2,7 @@ import Link from "next/link"
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { DocsLayout } from "@/components/docs-layout"
|
||||
import { ArrowRight } from "lucide-react"
|
||||
import { ArrowRight } from "@luxfi/ui/icons"
|
||||
import { docsConfig } from "@/lib/docs-config"
|
||||
|
||||
export const metadata = {
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
Terminal,
|
||||
FileCode,
|
||||
ArrowRight,
|
||||
} from "lucide-react"
|
||||
} from "@luxfi/ui/icons"
|
||||
import { docsConfig } from "@/lib/docs-config"
|
||||
|
||||
const sections = [
|
||||
|
||||
@@ -2,7 +2,7 @@ import Link from "next/link"
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
|
||||
import { DocsLayout } from "@/components/docs-layout"
|
||||
import { ArrowRight } from "lucide-react"
|
||||
import { ArrowRight } from "@luxfi/ui/icons"
|
||||
import { docsConfig } from "@/lib/docs-config"
|
||||
|
||||
export const metadata = {
|
||||
|
||||
@@ -2,7 +2,7 @@ import Link from "next/link"
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
|
||||
import { DocsLayout } from "@/components/docs-layout"
|
||||
import { ArrowRight } from "lucide-react"
|
||||
import { ArrowRight } from "@luxfi/ui/icons"
|
||||
import { docsConfig } from "@/lib/docs-config"
|
||||
|
||||
export const metadata = {
|
||||
|
||||
@@ -2,7 +2,7 @@ import Link from "next/link"
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { Card, CardContent } from "@/components/ui/card"
|
||||
import { DocsLayout } from "@/components/docs-layout"
|
||||
import { ArrowRight } from "lucide-react"
|
||||
import { ArrowRight } from "@luxfi/ui/icons"
|
||||
import { docsConfig } from "@/lib/docs-config"
|
||||
|
||||
export const metadata = {
|
||||
|
||||
@@ -2,7 +2,7 @@ import Link from "next/link"
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
|
||||
import { DocsLayout } from "@/components/docs-layout"
|
||||
import { ArrowRight } from "lucide-react"
|
||||
import { ArrowRight } from "@luxfi/ui/icons"
|
||||
import { docsConfig } from "@/lib/docs-config"
|
||||
|
||||
export const metadata = {
|
||||
|
||||
@@ -2,7 +2,7 @@ import Link from "next/link"
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { Card, CardContent } from "@/components/ui/card"
|
||||
import { DocsLayout } from "@/components/docs-layout"
|
||||
import { ArrowRight } from "lucide-react"
|
||||
import { ArrowRight } from "@luxfi/ui/icons"
|
||||
import { docsConfig } from "@/lib/docs-config"
|
||||
|
||||
export const metadata = {
|
||||
|
||||
@@ -2,7 +2,7 @@ import Link from "next/link"
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
|
||||
import { DocsLayout } from "@/components/docs-layout"
|
||||
import { ArrowRight } from "lucide-react"
|
||||
import { ArrowRight } from "@luxfi/ui/icons"
|
||||
import { docsConfig } from "@/lib/docs-config"
|
||||
|
||||
export const metadata = {
|
||||
|
||||
@@ -21,7 +21,7 @@ import {
|
||||
Wallet,
|
||||
Webhook,
|
||||
Zap,
|
||||
} from "lucide-react"
|
||||
} from "@luxfi/ui/icons"
|
||||
|
||||
export default function HomePage() {
|
||||
const brand = getBrand()
|
||||
|
||||
@@ -20,7 +20,7 @@ import {
|
||||
HelpCircle,
|
||||
Minus,
|
||||
Zap,
|
||||
} from "lucide-react"
|
||||
} from "@luxfi/ui/icons"
|
||||
import { getBrand } from "@/lib/brand"
|
||||
|
||||
export const metadata: Metadata = {
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { Metadata } from "next"
|
||||
import { Navbar } from "@/components/navbar"
|
||||
import { Footer } from "@/components/footer"
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { Shield } from "lucide-react"
|
||||
import { Shield } from "@luxfi/ui/icons"
|
||||
import { getBrand } from "@/lib/brand"
|
||||
|
||||
const brand = getBrand()
|
||||
|
||||
@@ -19,7 +19,7 @@ import {
|
||||
Layers,
|
||||
Search,
|
||||
Zap,
|
||||
} from "lucide-react"
|
||||
} from "@luxfi/ui/icons"
|
||||
import { getBrand } from "@/lib/brand"
|
||||
import { docsConfig } from "@/lib/docs-config"
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ import {
|
||||
BarChart3,
|
||||
Braces,
|
||||
Palette,
|
||||
} from "lucide-react"
|
||||
} from "@luxfi/ui/icons"
|
||||
import { getBrand } from "@/lib/brand"
|
||||
|
||||
export default function ExplorerProductPage() {
|
||||
|
||||
@@ -20,7 +20,7 @@ import {
|
||||
Users,
|
||||
Wallet,
|
||||
Zap,
|
||||
} from "lucide-react"
|
||||
} from "@luxfi/ui/icons"
|
||||
import { getBrand } from "@/lib/brand"
|
||||
|
||||
export default function MPCProductPage() {
|
||||
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
Shield,
|
||||
Wifi,
|
||||
Zap,
|
||||
} from "lucide-react"
|
||||
} from "@luxfi/ui/icons"
|
||||
import { getBrand } from "@/lib/brand"
|
||||
import { docsConfig } from "@/lib/docs-config"
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ import {
|
||||
Settings,
|
||||
Wrench,
|
||||
Zap,
|
||||
} from "lucide-react"
|
||||
} from "@luxfi/ui/icons"
|
||||
import { getBrand } from "@/lib/brand"
|
||||
import { docsConfig } from "@/lib/docs-config"
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ import {
|
||||
Users,
|
||||
Wallet,
|
||||
Zap,
|
||||
} from "lucide-react"
|
||||
} from "@luxfi/ui/icons"
|
||||
import { getBrand } from "@/lib/brand"
|
||||
import { getSdkPackage } from "@/lib/sdk-package"
|
||||
import { docsConfig } from "@/lib/docs-config"
|
||||
|
||||
@@ -21,7 +21,7 @@ import {
|
||||
TestTube,
|
||||
Webhook,
|
||||
Zap,
|
||||
} from "lucide-react"
|
||||
} from "@luxfi/ui/icons"
|
||||
import { getBrand } from "@/lib/brand"
|
||||
import { docsConfig } from "@/lib/docs-config"
|
||||
|
||||
|
||||
@@ -1,7 +1,50 @@
|
||||
"use client"
|
||||
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
|
||||
import { useState } from "react"
|
||||
import { AppProvider, IdentityProvider } from "@luxfi/ui"
|
||||
import { QueryClient } from "@tanstack/react-query"
|
||||
import { useEffect, useState } from "react"
|
||||
|
||||
import { setReturnUrl } from "@/lib/iam"
|
||||
|
||||
// Brand + identity, both from the HOST.
|
||||
//
|
||||
// `AppProvider` (@luxfi/ui) mounts the @hanzo/gui engine on the host-resolved
|
||||
// theme row and carries the white-label — the same resolver lib/brand.ts now
|
||||
// reads its OIDC triple from, so there is one answer to "which brand is this"
|
||||
// and not two that can disagree.
|
||||
//
|
||||
// `IdentityProvider` reads the signed-in account and its org membership from
|
||||
// IAM. Credentials stay where they already are: lib/iam owns the PKCE flow and
|
||||
// localStorage["bootnode_token"] the bearer, so the chrome adds no second token
|
||||
// store and no second refresh timer — it borrows the bearer and two verbs.
|
||||
|
||||
const TOKEN_KEY = "bootnode_token"
|
||||
|
||||
const readToken = (): string | null => {
|
||||
if (typeof window === "undefined") return null
|
||||
try {
|
||||
return window.localStorage.getItem(TOKEN_KEY)
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
/** Sign-in goes through /login, which is what drives the SDK's PKCE redirect. */
|
||||
const signIn = (): void => {
|
||||
setReturnUrl(window.location.pathname + window.location.search)
|
||||
window.location.assign("/login")
|
||||
}
|
||||
|
||||
/** Sign-out drops the bearer and returns to the marketing root. */
|
||||
const signOut = (): void => {
|
||||
try {
|
||||
window.localStorage.removeItem(TOKEN_KEY)
|
||||
window.localStorage.removeItem("bootnode_project_id")
|
||||
} catch {
|
||||
/* storage disabled — the redirect below still ends the session in this tab */
|
||||
}
|
||||
window.location.assign("/")
|
||||
}
|
||||
|
||||
export function Providers({ children }: { children: React.ReactNode }) {
|
||||
const [queryClient] = useState(
|
||||
@@ -15,8 +58,17 @@ export function Providers({ children }: { children: React.ReactNode }) {
|
||||
},
|
||||
})
|
||||
)
|
||||
// `output: "export"` prerenders with no Host header, so the first paint is
|
||||
// the default row and the real host arrives after hydration — deterministic
|
||||
// on both sides, so there is no mismatch.
|
||||
const [host, setHost] = useState<string | undefined>(undefined)
|
||||
useEffect(() => setHost(window.location.host), [])
|
||||
|
||||
return (
|
||||
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
|
||||
<AppProvider host={host} queryClient={queryClient}>
|
||||
<IdentityProvider auth={{ token: readToken, signIn, signOut }}>
|
||||
{children}
|
||||
</IdentityProvider>
|
||||
</AppProvider>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
Network,
|
||||
Shield,
|
||||
ShieldCheck,
|
||||
} from "lucide-react"
|
||||
} from "@luxfi/ui/icons"
|
||||
import { getBrand } from "@/lib/brand"
|
||||
|
||||
const brand = getBrand()
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { Metadata } from "next"
|
||||
import { Navbar } from "@/components/navbar"
|
||||
import { Footer } from "@/components/footer"
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { FileText } from "lucide-react"
|
||||
import { FileText } from "@luxfi/ui/icons"
|
||||
import { getBrand } from "@/lib/brand"
|
||||
|
||||
const brand = getBrand()
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
Activity,
|
||||
Zap,
|
||||
RotateCw,
|
||||
} from "lucide-react"
|
||||
} from "@luxfi/ui/icons"
|
||||
import { useBrand } from "@/components/brand-logo"
|
||||
import { getBrandKey } from "@/lib/brand"
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"use client"
|
||||
|
||||
import { useMemo, useState } from "react"
|
||||
import { Check } from "@luxfi/ui/icons"
|
||||
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Input } from "@/components/ui/input"
|
||||
@@ -100,7 +101,7 @@ export function ChainOnboardingSelector({
|
||||
active ? "border-blue-600 bg-blue-600 text-white" : "border-zinc-300"
|
||||
}`}
|
||||
>
|
||||
{active ? "✓" : ""}
|
||||
{active ? <Check className="size-3" /> : null}
|
||||
</span>
|
||||
<span className="inline-flex h-6 w-6 items-center justify-center rounded-full bg-zinc-100 text-sm overflow-hidden">
|
||||
{item.icon.startsWith("/") ? (
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useState } from "react"
|
||||
import { cn } from "@/lib/utils"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { Check, Copy, Play } from "lucide-react"
|
||||
import { Check, Copy, Play } from "@luxfi/ui/icons"
|
||||
import { getBrand } from "@/lib/brand"
|
||||
|
||||
const CHAINS = ["Ethereum", "Solana", "Base", "Arbitrum", "Polygon"]
|
||||
|
||||
@@ -27,7 +27,7 @@ import {
|
||||
Sparkles,
|
||||
ArrowUpRight,
|
||||
Terminal,
|
||||
} from "lucide-react"
|
||||
} from "@luxfi/ui/icons"
|
||||
import { useBrand } from "@/components/brand-logo"
|
||||
import { AiChat } from "@/components/ai-chat"
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { useMemo, useState } from "react"
|
||||
import { useRouter } from "next/navigation"
|
||||
import { ArrowRight, Search } from "lucide-react"
|
||||
import { ArrowRight, Search } from "@luxfi/ui/icons"
|
||||
|
||||
import {
|
||||
Dialog,
|
||||
|
||||
@@ -20,7 +20,7 @@ import {
|
||||
Terminal,
|
||||
X,
|
||||
XCircle,
|
||||
} from "lucide-react"
|
||||
} from "@luxfi/ui/icons"
|
||||
import { getApiUrl, getAuthHeaders as getAuth } from "@/lib/api"
|
||||
|
||||
// ─── Types ─────────────────────────────────────────────
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
Package,
|
||||
FileCode,
|
||||
Clock,
|
||||
} from "lucide-react"
|
||||
} from "@luxfi/ui/icons"
|
||||
|
||||
const sidebarNav = [
|
||||
{ title: "Documentation", href: "/docs", icon: Book },
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import Link from "next/link"
|
||||
import { BrandLogo, useBrand } from "@/components/brand-logo"
|
||||
import { ExternalLink } from "lucide-react"
|
||||
import { ExternalLink } from "@luxfi/ui/icons"
|
||||
|
||||
// Footer, in lux.cloud's chrome: no tinted slab, just a hairline rule over the
|
||||
// page ground with 13px muted type. The four sitemap columns stay — dropping
|
||||
|
||||
@@ -26,7 +26,7 @@ import {
|
||||
RefreshCcw,
|
||||
Server,
|
||||
Users,
|
||||
} from "lucide-react"
|
||||
} from "@luxfi/ui/icons"
|
||||
import { FleetMap, type FleetRegion } from "@/components/lux/fleet-map"
|
||||
import {
|
||||
CHAIN_LABEL,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { useEffect, useState } from "react"
|
||||
import Link from "next/link"
|
||||
import { ArrowRight, Circle } from "lucide-react"
|
||||
import { ArrowRight, Circle } from "@luxfi/ui/icons"
|
||||
import {
|
||||
NETWORK_LABEL,
|
||||
fetchFleetOverview,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use client"
|
||||
|
||||
import { useState, useEffect, useRef, ReactNode } from "react"
|
||||
import { ChevronDown } from "lucide-react"
|
||||
import { ChevronDown } from "@luxfi/ui/icons"
|
||||
import { useMediaQuery } from "@/hooks/use-media-query"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
|
||||
@@ -34,7 +34,9 @@ import {
|
||||
MessageCircle,
|
||||
LifeBuoy,
|
||||
Activity,
|
||||
} from "lucide-react"
|
||||
} from "@luxfi/ui/icons"
|
||||
import { OrgSwitcher, UserMenu } from "@luxfi/ui"
|
||||
|
||||
import { BrandLogo } from "@/components/brand-logo"
|
||||
import { useBrand } from "@/components/brand-provider"
|
||||
import { CommandMenu } from "@/components/command-menu"
|
||||
@@ -487,28 +489,18 @@ export function Navbar() {
|
||||
and a poor thumb target. */}
|
||||
<div className="flex items-center gap-2.5 max-lg:flex-col max-lg:items-stretch max-lg:gap-2 [&_button]:max-lg:h-10 [&_a]:max-lg:h-10">
|
||||
<CommandMenu />
|
||||
{user ? (
|
||||
<>
|
||||
{/* Who you are signed in as. The old console header spent a
|
||||
dropdown on this plus an org switcher whose options changed
|
||||
nothing and a bell wired to no notification source. */}
|
||||
<span
|
||||
className="max-w-44 truncate text-[13px] text-muted-foreground max-lg:max-w-none"
|
||||
title={user.email}
|
||||
>
|
||||
{user.email}
|
||||
</span>
|
||||
<Button variant="outline" size="sm" onClick={() => { close(); logout() }}>
|
||||
Sign out
|
||||
</Button>
|
||||
</>
|
||||
) : (
|
||||
<Button variant="outline" size="sm" asChild onClick={close}>
|
||||
{/* Brand-derived: on lux.cloud this reads "Sign in with Lux ID",
|
||||
on zoo.cloud "Zoo ID" — from the same build. */}
|
||||
<Link href="/login">Sign in with {brand.iam.idLabel}</Link>
|
||||
</Button>
|
||||
)}
|
||||
{/* The account cluster is the SHARED chrome (@luxfi/ui), not a
|
||||
third copy of it. What was here was an email in a <span> and a
|
||||
Sign out button — no menu, no way to see or change which org you
|
||||
were acting in, and a "sign in" that only ever named the brand.
|
||||
The switchers below read IAM (get-account, get-organizations)
|
||||
and are the same controls the MPC dashboard and lux.market show,
|
||||
including the phone sheet, which this bar had no equivalent of.
|
||||
|
||||
They degrade honestly: signed out they offer sign-in rather than
|
||||
rendering an empty list that reads as an account with no orgs. */}
|
||||
<OrgSwitcher />
|
||||
<UserMenu />
|
||||
<Button size="sm" asChild onClick={close}>
|
||||
<Link href="/dashboard">Dashboard</Link>
|
||||
</Button>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import * as React from "react"
|
||||
import * as DialogPrimitive from "@radix-ui/react-dialog"
|
||||
import { X } from "lucide-react"
|
||||
import { X } from "@luxfi/ui/icons"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import * as React from "react"
|
||||
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"
|
||||
import { Check, ChevronRight, Circle } from "lucide-react"
|
||||
import { Check, ChevronRight, Circle } from "@luxfi/ui/icons"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import * as React from "react"
|
||||
import * as NavigationMenuPrimitive from "@radix-ui/react-navigation-menu"
|
||||
import { cva } from "class-variance-authority"
|
||||
import { ChevronDown } from "lucide-react"
|
||||
import { ChevronDown } from "@luxfi/ui/icons"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const NavigationMenu = React.forwardRef<
|
||||
|
||||
+39
-7
@@ -27,6 +27,8 @@
|
||||
// registering `https://<host>/auth/callback` on that brand's IAM. Nothing else
|
||||
// in the app carries a brand string, an issuer, or a client id.
|
||||
|
||||
import { resolveWhiteLabel } from "@luxfi/ui/white-label"
|
||||
|
||||
export type BrandKey = "bootnode" | "lux" | "zoo" | "hanzo" | "pars"
|
||||
|
||||
export type BrandConfig = {
|
||||
@@ -89,7 +91,9 @@ export type BrandConfig = {
|
||||
const API = "https://api.bootno.de"
|
||||
const WS = "wss://ws.bootno.de"
|
||||
|
||||
const BRANDS: Record<BrandKey, BrandConfig> = {
|
||||
// Presentation only. The OIDC triple is attached below, from the one shared
|
||||
// table — see CONSOLE_HOST.
|
||||
const BRANDS: Record<BrandKey, Omit<BrandConfig, "iam">> = {
|
||||
// DEFAULT. bootno.de, localhost, and any unmatched host resolve here.
|
||||
bootnode: {
|
||||
key: "bootnode",
|
||||
@@ -113,7 +117,6 @@ const BRANDS: Record<BrandKey, BrandConfig> = {
|
||||
defaultTheme: "dark",
|
||||
colors: { primary: "#f5f5f5", primaryForeground: "#000000", accent: "#a8a8ff", accentEnd: "#8bffd1" },
|
||||
social: { github: "https://github.com/bootnode" },
|
||||
iam: { url: "https://id.bootno.de", clientId: "bootnode-platform", domain: "id.bootno.de", idLabel: "Bootnode ID" },
|
||||
footerLinks: [],
|
||||
ecosystemApps: [],
|
||||
},
|
||||
@@ -140,7 +143,6 @@ const BRANDS: Record<BrandKey, BrandConfig> = {
|
||||
defaultTheme: "dark",
|
||||
colors: { primary: "#f5f5f5", primaryForeground: "#000000", accent: "#a8a8ff", accentEnd: "#8bffd1" },
|
||||
social: { github: "https://github.com/luxfi" },
|
||||
iam: { url: "https://lux.id", clientId: "lux-cloud", domain: "lux.id", idLabel: "Lux ID" },
|
||||
footerLinks: [],
|
||||
ecosystemApps: [],
|
||||
},
|
||||
@@ -171,7 +173,6 @@ const BRANDS: Record<BrandKey, BrandConfig> = {
|
||||
defaultTheme: "dark",
|
||||
colors: { primary: "#f5f5f5", primaryForeground: "#000000", accent: "#8bffd1", accentEnd: "#a8a8ff" },
|
||||
social: { github: "https://github.com/zooai" },
|
||||
iam: { url: "https://zoolabs.id", clientId: "zoo-cloud", domain: "zoolabs.id", idLabel: "Zoo ID" },
|
||||
footerLinks: [],
|
||||
ecosystemApps: [],
|
||||
},
|
||||
@@ -198,7 +199,6 @@ const BRANDS: Record<BrandKey, BrandConfig> = {
|
||||
defaultTheme: "dark",
|
||||
colors: { primary: "#f5f5f5", primaryForeground: "#000000", accent: "#a8a8ff", accentEnd: "#ff8bc0" },
|
||||
social: { github: "https://github.com/hanzoai" },
|
||||
iam: { url: "https://hanzo.id", clientId: "hanzo-web3", domain: "hanzo.id", idLabel: "Hanzo ID" },
|
||||
footerLinks: [],
|
||||
ecosystemApps: [],
|
||||
},
|
||||
@@ -225,7 +225,6 @@ const BRANDS: Record<BrandKey, BrandConfig> = {
|
||||
defaultTheme: "dark",
|
||||
colors: { primary: "#f5f5f5", primaryForeground: "#000000", accent: "#ffd18b", accentEnd: "#ff8bc0" },
|
||||
social: { github: "https://github.com/parsdao" },
|
||||
iam: { url: "https://pars.id", clientId: "pars-app", domain: "pars.id", idLabel: "Pars ID" },
|
||||
footerLinks: [],
|
||||
ecosystemApps: [],
|
||||
},
|
||||
@@ -247,6 +246,39 @@ const HOSTS: { host: string; key: BrandKey }[] = [
|
||||
|
||||
const DEFAULT_KEY: BrandKey = "bootnode"
|
||||
|
||||
// The host each brand's console is REGISTERED under — the one key into the
|
||||
// shared white-label table.
|
||||
//
|
||||
// Issuer, client id and IAM host are NOT this file's to know. They are the same
|
||||
// answer @luxfi/ui/white-label already gives every Lux surface from the Host
|
||||
// header, and a second copy here is a second thing to get wrong — which it was:
|
||||
// this table and that one disagreed about Zoo's issuer, and the surfaces on the
|
||||
// losing side of that disagreement reject every token they are handed.
|
||||
//
|
||||
// This file keeps what is genuinely its own: logos, taglines, palettes, footer
|
||||
// links, the ecosystem launcher, and the API origins that answer.
|
||||
const CONSOLE_HOST: Record<BrandKey, string> = {
|
||||
bootnode: "bootno.de",
|
||||
lux: "lux.cloud",
|
||||
zoo: "zoo.cloud",
|
||||
hanzo: "web3.hanzo.ai",
|
||||
pars: "cloud.pars.network",
|
||||
}
|
||||
|
||||
/** Presentation + the shared OIDC triple, resolved once per brand. */
|
||||
const RESOLVED = Object.fromEntries(
|
||||
(Object.keys(BRANDS) as BrandKey[]).map((key) => {
|
||||
const wl = resolveWhiteLabel(CONSOLE_HOST[key])
|
||||
return [
|
||||
key,
|
||||
{
|
||||
...BRANDS[key],
|
||||
iam: { url: wl.issuer, clientId: wl.clientId, domain: wl.iamDomain, idLabel: `${wl.name} ID` },
|
||||
},
|
||||
]
|
||||
})
|
||||
) as Record<BrandKey, BrandConfig>
|
||||
|
||||
/**
|
||||
* Resolve the brand key for a hostname. Pass one explicitly to resolve for a
|
||||
* host other than the current page; omit it in the browser to use
|
||||
@@ -264,5 +296,5 @@ export function getBrandKey(hostname?: string): BrandKey {
|
||||
|
||||
/** The active brand. Synchronous and total — every key has a complete entry. */
|
||||
export function getBrand(hostname?: string): BrandConfig {
|
||||
return BRANDS[getBrandKey(hostname)]
|
||||
return RESOLVED[getBrandKey(hostname)]
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ export interface LuxNode {
|
||||
pod_index: number
|
||||
phase: string
|
||||
ready: boolean
|
||||
external_ip: string | null
|
||||
ip: string | null
|
||||
rpc_reachable: boolean
|
||||
node_id: string | null
|
||||
version: string | null
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { NextConfig } from "next"
|
||||
import { withLuxUi } from "@luxfi/ui/next"
|
||||
|
||||
const nextConfig: NextConfig = {
|
||||
// Modern React & Next.js features
|
||||
@@ -32,4 +33,10 @@ const nextConfig: NextConfig = {
|
||||
// the legacy /admin -> /dashboard redirect is handled by public/_redirects.
|
||||
}
|
||||
|
||||
export default nextConfig
|
||||
// `withLuxUi` is the ONE place the @hanzo/gui engine's bundler wiring lives —
|
||||
// transpile list, react-native → react-native-web alias in both bundlers, the
|
||||
// platform defines, and the single-copy dedupe. Every Next surface needed the
|
||||
// identical incantation; the ones that hand-rolled it each transpiled a
|
||||
// different subset, which is how one app renders a Sheet and the next throws on
|
||||
// the same component.
|
||||
export default withLuxUi({ ...nextConfig, dir: __dirname } as never) as NextConfig
|
||||
|
||||
@@ -53,7 +53,11 @@
|
||||
"sonner": "catalog:",
|
||||
"tailwind-merge": "catalog:",
|
||||
"tailwindcss-animate": "catalog:",
|
||||
"zod": "catalog:"
|
||||
"zod": "catalog:",
|
||||
"@hanzo/gui": "catalog:",
|
||||
"@luxfi/ui": "catalog:",
|
||||
"geist": "catalog:",
|
||||
"react-native-web": "catalog:"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/postcss": "catalog:",
|
||||
|
||||
Reference in New Issue
Block a user