Logo & Chat Persistance & Supplier UI for mobilr
This commit is contained in:
parent
04468a2d47
commit
8354a90698
BIN
public/banner.png
Normal file
BIN
public/banner.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 27 KiB |
BIN
public/icon.png
Normal file
BIN
public/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 36 KiB |
BIN
public/logo.png
Normal file
BIN
public/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 36 KiB |
@ -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",
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user