Logo & Chat Persistance & Supplier UI for mobilr

This commit is contained in:
root 2026-02-16 17:21:38 +05:00
parent 04468a2d47
commit 8354a90698
12 changed files with 157 additions and 102 deletions

BIN
public/banner.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

BIN
public/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

BIN
public/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

View File

@ -17,6 +17,10 @@ const geistMono = Geist_Mono({
export const metadata: Metadata = {
title: "JUNOHUB | Modern Commerce Infrastructure",
description: "The world's most advanced encrypted ecosystem for vendors and suppliers.",
icons: {
icon: "/icon.png",
apple: "/logo.png",
},
appleWebApp: {
capable: true,
statusBarStyle: "default",

View File

@ -4,8 +4,9 @@ import { signIn } from "next-auth/react"
import { useState } from "react"
import { useRouter } from "next/navigation"
import { motion } from "framer-motion"
import { Mail, Lock, Loader2, Zap, Shield } from "lucide-react"
import { Mail, Lock, Loader2, Shield } from "lucide-react"
import Link from "next/link"
import Image from "next/image"
export default function LoginPage() {
const router = useRouter()
@ -107,8 +108,14 @@ export default function LoginPage() {
<div className="bg-white/5 backdrop-blur-xl rounded-2xl md:rounded-3xl p-6 md:p-8 border border-white/10">
<div className="text-center mb-10">
<div className="inline-flex items-center justify-center gap-3 mb-4">
<div className="w-12 h-12 rounded-2xl bg-indigo-500/40 border border-white/20 flex items-center justify-center backdrop-blur-sm">
<Zap className="w-6 h-6 text-white fill-white" />
<div className="w-14 h-14 rounded-2xl bg-indigo-500/10 border border-white/10 flex items-center justify-center backdrop-blur-sm overflow-hidden shadow-lg shadow-indigo-500/20">
<Image
src="/logo.png"
alt="JUNOHUB Logo"
width={56}
height={56}
className="object-cover"
/>
</div>
<h1 className="text-2xl font-bold tracking-tight text-white">JUNOHUB</h1>
</div>

View File

@ -17,6 +17,7 @@ import {
User
} from "lucide-react"
import { useRouter } from "next/navigation"
import Image from "next/image"
const steps = [
{ id: 1, title: "Business Info", icon: Building2 },
@ -319,9 +320,15 @@ export default function OnboardingClient() {
return (
<div className="min-h-screen flex flex-col auth-glass-dark">
<nav className="h-16 md:h-20 bg-slate-900/50 border-b border-white/10 flex items-center px-4 md:px-10 justify-between shrink-0 backdrop-blur-xl">
<div className="flex items-center gap-2">
<div className="w-7 h-7 md:w-8 md:h-8 rounded-lg bg-indigo-500/40 border border-white/20 flex items-center justify-center backdrop-blur-sm">
<Layout className="w-4 h-4 md:w-5 md:h-5 text-white" />
<div className="flex items-center gap-3">
<div className="w-10 h-10 md:w-12 md:h-12 rounded-xl bg-indigo-500/10 border border-white/10 flex items-center justify-center backdrop-blur-sm overflow-hidden shadow-sm">
<Image
src="/logo.png"
alt="JUNOHUB Logo"
width={48}
height={48}
className="object-cover"
/>
</div>
<span className="font-bold text-white tracking-tight text-lg md:text-xl">JUNOHUB</span>
</div>

View File

@ -2,10 +2,11 @@
import { useState, Suspense } from "react"
import { motion } from "framer-motion"
import { Mail, Lock, Loader2, User, ShoppingBag, Truck, Zap } from "lucide-react"
import { Mail, Lock, Loader2, User, ShoppingBag, Truck } from "lucide-react"
import Link from "next/link"
import { useRouter, useSearchParams } from "next/navigation"
import { signIn } from "next-auth/react"
import Image from "next/image"
function SignupFormContent() {
const [loading, setLoading] = useState(false)
@ -53,8 +54,14 @@ function SignupFormContent() {
<div className="bg-white/5 backdrop-blur-xl rounded-2xl md:rounded-3xl p-6 md:p-8 border border-white/10">
<div className="text-center mb-8">
<div className="inline-flex items-center justify-center gap-3 mb-4">
<div className="w-12 h-12 rounded-2xl bg-indigo-500/40 border border-white/20 flex items-center justify-center backdrop-blur-sm">
<Zap className="w-6 h-6 text-white fill-white" />
<div className="w-14 h-14 rounded-2xl bg-indigo-500/10 border border-white/10 flex items-center justify-center backdrop-blur-sm overflow-hidden shadow-lg shadow-indigo-500/20">
<Image
src="/logo.png"
alt="JUNOHUB Logo"
width={56}
height={56}
className="object-cover"
/>
</div>
<h1 className="text-2xl font-bold tracking-tight text-white">JUNOHUB</h1>
</div>

View File

@ -1,26 +1,21 @@
"use client"
import { useState, useEffect } from "react"
import { createPortal } from "react-dom"
import { usePathname } from "next/navigation"
import { motion, AnimatePresence } from "framer-motion"
import { X, Menu, Zap } from "lucide-react"
import { X, Menu } from "lucide-react"
import { Sidebar } from "./Sidebar"
import { useTheme } from "./ThemeProvider"
import { cn } from "@/lib/utils"
import Image from "next/image"
export function MobileSidebar() {
const { theme } = useTheme()
const isLight = theme === "light"
const [isOpen, setIsOpen] = useState(false)
const [mounted, setMounted] = useState(false)
const pathname = usePathname()
useEffect(() => {
const timer = setTimeout(() => setMounted(true), 0)
return () => clearTimeout(timer)
}, [])
// Close sidebar when route changes
useEffect(() => {
@ -57,7 +52,6 @@ export function MobileSidebar() {
</button>
{/* Mobile Sidebar Overlay */}
{mounted && createPortal(
<AnimatePresence>
{isOpen && (
<>
@ -67,7 +61,7 @@ export function MobileSidebar() {
exit={{ opacity: 0 }}
key="sidebar-backdrop"
transition={{ duration: 0.2 }}
className="fixed inset-0 bg-black/60 backdrop-blur-sm z-[999] md:hidden pointer-events-auto"
className="fixed inset-0 bg-black/60 backdrop-blur-sm z-[9999] md:hidden pointer-events-auto"
onClick={() => setIsOpen(false)}
/>
<motion.div
@ -77,7 +71,7 @@ export function MobileSidebar() {
key="sidebar-content"
transition={{ type: "spring", damping: 25, stiffness: 200 }}
className={cn(
"fixed inset-y-0 left-0 w-72 backdrop-blur-xl border-r z-[1000] md:hidden flex flex-col pointer-events-auto",
"fixed inset-y-0 left-0 w-72 backdrop-blur-xl border-r z-[10000] md:hidden flex flex-col pointer-events-auto",
isLight
? "bg-white/95 border-slate-200"
: "bg-slate-900/95 border-white/10"
@ -90,12 +84,18 @@ export function MobileSidebar() {
)}>
<div className="flex items-center gap-2">
<div className={cn(
"w-8 h-8 rounded-lg flex items-center justify-center backdrop-blur-sm border shadow-sm",
"w-9 h-9 rounded-xl overflow-hidden flex items-center justify-center shadow-md border",
isLight
? "bg-indigo-50 border-indigo-100"
: "bg-indigo-500/40 border-white/20"
? "border-slate-200"
: "border-white/10"
)}>
<Zap className={cn("w-5 h-5", isLight ? "text-indigo-600" : "text-white")} />
<Image
src="/logo.png"
alt="JUNOHUB Logo"
width={36}
height={36}
className="object-cover"
/>
</div>
<h1 className={cn(
"text-xl font-bold tracking-tight",
@ -122,9 +122,7 @@ export function MobileSidebar() {
</motion.div>
</>
)}
</AnimatePresence>,
document.body
)}
</AnimatePresence>
</>
)
}

View File

@ -19,6 +19,7 @@ import {
} from "lucide-react"
import { cn } from "@/lib/utils"
import { useTheme } from "@/components/ThemeProvider"
import Image from "next/image"
const routes = [
{
@ -101,10 +102,16 @@ export function Sidebar({ showLogo = true, className }: SidebarProps) {
{showLogo && (
<div className="px-6 py-2 flex items-center mb-6">
<div className={cn(
"w-8 h-8 rounded-lg border flex items-center justify-center mr-3 backdrop-blur-sm",
isLight ? "bg-indigo-50 border-indigo-100" : "bg-indigo-500/40 border-white/20"
"w-10 h-10 rounded-xl overflow-hidden flex items-center justify-center mr-3 shadow-md border",
isLight ? "border-slate-200" : "border-white/10"
)}>
<Zap className={cn("w-5 h-5", isLight ? "text-indigo-600 fill-indigo-600" : "text-white fill-white")} />
<Image
src="/logo.png"
alt="JUNOHUB Logo"
width={40}
height={40}
className="object-cover"
/>
</div>
<h1 className={cn("text-xl font-bold tracking-tight", isLight ? "text-slate-900" : "text-white")}>JUNOHUB</h1>
</div>

View File

@ -2,7 +2,8 @@
import Link from "next/link"
import { motion } from "framer-motion"
import { Twitter, Github, Linkedin, Mail, Zap } from "lucide-react"
import { Twitter, Github, Linkedin, Mail } from "lucide-react"
import Image from "next/image"
export function LandingFooter() {
return (
@ -13,9 +14,15 @@ export function LandingFooter() {
<div className="container mx-auto px-6">
<div className="grid grid-cols-1 md:grid-cols-4 gap-12 mb-16">
<div className="col-span-1 md:col-span-1">
<Link href="/" className="flex items-center gap-2 mb-6 group">
<div className="w-10 h-10 rounded-xl bg-indigo-600 flex items-center justify-center text-white shadow-lg shadow-indigo-500/20 group-hover:scale-110 transition-transform">
<Zap className="w-6 h-6 fill-white" />
<Link href="/" className="flex items-center gap-3 mb-6 group">
<div className="w-10 h-10 rounded-xl bg-indigo-600/10 border border-white/10 flex items-center justify-center backdrop-blur-sm overflow-hidden shadow-lg shadow-indigo-500/20 group-hover:scale-110 transition-transform">
<Image
src="/logo.png"
alt="JUNOHUB Logo"
width={40}
height={40}
className="object-cover"
/>
</div>
<span className="text-xl font-black tracking-tighter text-white">JUNOHUB</span>
</Link>

View File

@ -3,8 +3,9 @@
import { useState, useEffect } from "react"
import Link from "next/link"
import { motion, AnimatePresence } from "framer-motion"
import { Menu, X, ArrowRight, Zap } from "lucide-react"
import { Menu, X, ArrowRight } from "lucide-react"
import { cn } from "@/lib/utils"
import Image from "next/image"
interface LandingNavbarProps {
isLoggedIn: boolean
@ -44,9 +45,15 @@ export function LandingNavbar({ isLoggedIn }: LandingNavbarProps) {
)}
>
{/* Logo */}
<Link href="/" className="flex items-center gap-2 group">
<div className="w-10 h-10 rounded-xl bg-gradient-to-tr from-indigo-600 to-indigo-400 flex items-center justify-center text-white shadow-lg shadow-indigo-500/20 group-hover:scale-110 transition-transform">
<Zap className="w-6 h-6 fill-white" />
<Link href="/" className="flex items-center gap-3 group">
<div className="w-10 h-10 rounded-xl bg-indigo-600/10 border border-white/10 flex items-center justify-center backdrop-blur-sm overflow-hidden shadow-lg shadow-indigo-500/20 group-hover:scale-110 transition-transform">
<Image
src="/logo.png"
alt="JUNOHUB Logo"
width={40}
height={40}
className="object-cover"
/>
</div>
<span className="text-xl font-black tracking-tighter text-white">JUNOHUB</span>
</Link>

View File

@ -6,27 +6,38 @@ import { ChatCrypto } from "@/lib/chat-crypto"
export const PRIVATE_KEY_STORAGE_KEY = "juno_chat_private_key"
export const PUBLIC_KEY_STORAGE_KEY = "juno_chat_public_key"
export function useChatCrypto() {
export function useChatCrypto(userId?: string) {
const [privateKey, setPrivateKey] = useState<string | null>(null)
const [hasKeys, setHasKeys] = useState(false)
const [loading, setLoading] = useState(true)
const privateKeyKey = userId ? `${PRIVATE_KEY_STORAGE_KEY}_${userId}` : PRIVATE_KEY_STORAGE_KEY
const publicKeyKey = userId ? `${PUBLIC_KEY_STORAGE_KEY}_${userId}` : PUBLIC_KEY_STORAGE_KEY
useEffect(() => {
const stored = localStorage.getItem(PRIVATE_KEY_STORAGE_KEY)
if (!userId) {
setLoading(false)
return
}
const stored = localStorage.getItem(privateKeyKey)
if (stored) {
setPrivateKey(stored)
setHasKeys(true)
} else {
setPrivateKey(null)
setHasKeys(false)
}
setLoading(false)
}, [])
}, [userId, privateKeyKey])
const setupKeys = useCallback(async () => {
if (!userId) throw new Error("User ID required for chat setup")
setLoading(true)
try {
const keys = await ChatCrypto.generateKeyPair()
localStorage.setItem(PRIVATE_KEY_STORAGE_KEY, keys.privateKey)
localStorage.setItem(PUBLIC_KEY_STORAGE_KEY, keys.publicKey)
localStorage.setItem(privateKeyKey, keys.privateKey)
localStorage.setItem(publicKeyKey, keys.publicKey)
setPrivateKey(keys.privateKey)
setHasKeys(true)
@ -45,12 +56,12 @@ export function useChatCrypto() {
} finally {
setLoading(false)
}
}, [])
}, [userId, privateKeyKey, publicKeyKey])
const getStoredPublicKey = useCallback((): string | null => {
if (typeof window === "undefined") return null
return localStorage.getItem(PUBLIC_KEY_STORAGE_KEY)
}, [])
if (typeof window === "undefined" || !userId) return null
return localStorage.getItem(publicKeyKey)
}, [userId, publicKeyKey])
return {
privateKey,