Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
Binary file added dapp/public/images/bg-image.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added dapp/public/images/trajectifi-logo-text.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added dapp/public/images/trajectifi-logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
44 changes: 44 additions & 0 deletions dapp/src/app/components/navbar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
"use client";

import { useState } from "react";
import Link from "next/link";
import {
Search as SearchIcon,
Bell as BellIcon,
HelpCircle as HelpIcon
} from "lucide-react";

export default function Navbar() {
const [searchQuery, setSearchQuery] = useState("");

return (
<nav className="flex items-center justify-between px-6 py-4 border-b border-gray-800">
<div className="flex-1"></div>
<div className="flex items-center space-x-4">
<div className="relative">
<div className="absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none">
<SearchIcon className="w-4 h-4 text-gray-400" />
</div>
<input
type="text"
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className="bg-gray-800 text-white rounded-lg pl-10 pr-4 py-2 w-full focus:outline-none focus:ring-2 focus:ring-purple-500"
placeholder="Search"
/>
</div>
<button className="p-2 rounded-full hover:bg-gray-800">
<BellIcon className="w-6 h-6" />
</button>
<button className="p-2 rounded-full hover:bg-gray-800">
<HelpIcon className="w-6 h-6" />
</button>
<Link href="#" className="ml-4">
<button className="bg-purple-600 hover:bg-purple-700 text-white px-4 py-2 rounded-lg">
Connect Wallet
</button>
</Link>
</div>
</nav>
);
}
163 changes: 163 additions & 0 deletions dapp/src/app/components/sidebar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
"use client";
import Image from "next/image";
import trajectifylogo from "../../../public/images/trajectifi-logo.png";
import trajectword from "../../../public/images/trajectifi-logo-text.png";

import { useState, useEffect } from "react";
import Link from "next/link";
import {
LayoutGrid as AssetsIcon,
CreditCard as LoanIcon,
Search as SearchIcon,
} from "lucide-react";

export default function Sidebar() {
const [isCollapsed, setIsCollapsed] = useState(true); // Default to collapsed
const [isHovered, setIsHovered] = useState(false);

// Auto-collapse on mobile, maintain collapsed state on larger screens
useEffect(() => {
const handleResize = () => {
if (window.innerWidth < 768) {
setIsCollapsed(true);
}
};

// Set initial state
handleResize();

window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
}, []);

// Toggle sidebar expanded/collapsed state
const toggleSidebar = () => {
setIsCollapsed(!isCollapsed);
};

// Determine if sidebar should be expanded
const expanded = !isCollapsed || isHovered;

return (
<aside
className={`bg-[#080a1f] border-r border-gray-800 transition-all duration-300 flex flex-col ${
expanded ? "w-60" : "w-16"
} h-screen sticky top-0`}
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
onClick={toggleSidebar}
>
<div className="p-4 flex items-center">
<Link
href="/"
className="flex items-center"
onClick={(e) => e.stopPropagation()}
>
{expanded ? (
<div className="flex items-center space-x-2">
<Image
src={trajectifylogo}
width={40}
height={40}
alt="trajectify-logo"
/>
<Image
src={trajectword}
width={70}
height={40}
alt="trajectify-logo-text"
/>
</div>
) : (
<Image
src={trajectifylogo}
width={40}
height={40}
alt="trajectify-logo"
/>
)}
</Link>
</div>

<div className="mt-6 px-3">
{expanded && (
<div className="relative mb-4" onClick={(e) => e.stopPropagation()}>
<div className="absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none">
<SearchIcon className="w-4 h-4 text-gray-400" />
</div>
<input
type="text"
className="bg-gray-800 text-white rounded-lg pl-10 pr-4 py-2 w-full focus:outline-none focus:ring-2 focus:ring-purple-500"
placeholder="Search"
/>
</div>
)}

<nav className="space-y-1">
<SidebarItem
href="/my_assets"
icon={<AssetsIcon />}
text="My Assets"
expanded={expanded}
active={true}
/>
<SidebarItem
href="/get-loan"
icon={<LoanIcon />}
text="Get a Loan"
expanded={expanded}
/>
<SidebarItem
href="/give-loan"
icon={<LoanIcon />}
text="Give a Loan"
expanded={expanded}
/>
</nav>
</div>
</aside>
);
}

interface SidebarItemProps {
href: string;
icon: React.ReactNode;
text: string;
expanded: boolean;
active?: boolean;
}

interface SidebarItemProps {
href: string;
icon: React.ReactNode;
text: string;
expanded: boolean;
active?: boolean;
}

function SidebarItem({
href,
icon,
text,
expanded,
active = false,
}: SidebarItemProps) {
return (
<Link
href={href}
className={`flex items-center justify-center p-3 rounded-lg ${
active ? "bg-purple-600 text-white" : "text-gray-300 hover:bg-gray-800"
}`}
onClick={(e) => e.stopPropagation()}
>
{expanded ? (
<div className="flex items-center w-full">
<span className="text-xl">{icon}</span>
<span className="ml-3">{text}</span>
</div>
) : (
<span className="text-xl flex justify-center">{icon}</span>
)}
</Link>
);
}
13 changes: 9 additions & 4 deletions dapp/src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,18 @@

@media (prefers-color-scheme: dark) {
:root {
--background: #0a0a0a;
--background: #080a1f;
--foreground: #ededed;
}
}

body {
color: var(--foreground);
background: #06071B;
font-family: Arial, Helvetica, sans-serif;
color: rgb(var(--foreground-rgb));
background-color: #b56203;
}

@layer utilities {
.text-balance {
text-wrap: balance;
}
}
47 changes: 14 additions & 33 deletions dapp/src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
"use client";
// import type { Metadata } from "next";
import React, { useState } from "react";
import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import "./globals.css";
import { Header, Sidebar } from "@/components";
import Navbar from "../app/components/navbar";
import Sidebar from "../app/components/sidebar";

const geistSans = Geist({
variable: "--font-geist-sans",
Expand All @@ -15,47 +14,29 @@ const geistMono = Geist_Mono({
subsets: ["latin"],
});

// export const metadata: Metadata = {
// title: "Create Next App",
// description: "Generated by create next app",
// };
export const metadata: Metadata = {
title: "Trajectifi",
description: "Trajectifi DApp",
};

export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
const [sidebarOpen, setSidebarOpen] = useState(false);
const toggleSidebar = () => {
setSidebarOpen(!sidebarOpen);
};
return (
<html lang="en">
<body
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
className={`${geistSans.variable} ${geistMono.variable} antialiased bg-[#080a1f] text-white`}
>
<div className="flex h-screen">
{/* Mobile sidebar overlay */}
{sidebarOpen && (
<div
className="fixed inset-0 z-20 bg-[#06071B] transition-opacity lg:hidden"
onClick={() => setSidebarOpen(false)}
/>
)}

{/* Sidebar */}
<Sidebar open={sidebarOpen} setOpen={setSidebarOpen} />

{/* Main content */}
<div className="flex flex-col flex-1 overflow-hidden">
<Header toggleSidebar={toggleSidebar} />

<main className="flex-1 overflow-y-auto p-4 md:p-6">
<div className="max-w-7xl mx-auto">{children}</div>
</main>
<div className="flex min-h-screen">
<Sidebar />
<div className="flex-1">
<Navbar />
<main>{children}</main>
</div>
</div>
</body>
</html>
);
}
}
54 changes: 54 additions & 0 deletions dapp/src/app/my_assets/components/CollectionSidebar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// src/app/my_assets/components/CollectionsSidebar.tsx
import Image from "next/image";
import React from "react";
import { Collection } from "../../types";

interface CollectionsSidebarProps {
collections: Collection[];
searchQuery: string;
toggleCollection: (id: string) => void;
setSearchQuery: (query: string) => void;
}

export const CollectionsSidebar = ({
collections,
searchQuery,
toggleCollection,
setSearchQuery,
}: CollectionsSidebarProps) => (
<div className="w-56 bg-[#080a1f] rounded-lg p-4">
<h3 className="text-lg font-medium mb-4">Collections</h3>

<div className="relative mb-4">
<input
type="text"
placeholder="Search to filter"
className="w-full bg-[#121428] border-none rounded-lg py-2 px-8 text-sm"
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
/>
<svg className="absolute left-2 top-2.5 w-4 h-4 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>
</svg>
</div>

<div className="space-y-5">
{collections.map(collection => (
<div key={collection.id} className="flex items-center gap-3">
<input
type="checkbox"
checked={collection.selected}
onChange={() => toggleCollection(collection.id)}
className="w-4 h-4 rounded accent-purple-600"
/>
<div className="flex items-center gap-2">
<div className="flex items-center justify-center">
<Image src={collection.icon} alt={collection.name} width={32} height={32} className="rounded-full" />
</div>
<span className="text-sm">{collection.name}</span>
</div>
</div>
))}
</div>
</div>
);
Loading