diff --git a/src/app/favicon.ico b/src/app/favicon.ico
deleted file mode 100644
index 718d6fe..0000000
Binary files a/src/app/favicon.ico and /dev/null differ
diff --git a/src/app/favicon.svg b/src/app/favicon.svg
new file mode 100644
index 0000000..624ad8e
--- /dev/null
+++ b/src/app/favicon.svg
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/app/globals.css b/src/app/globals.css
index 2fdbe6b..c809749 100644
--- a/src/app/globals.css
+++ b/src/app/globals.css
@@ -3,10 +3,54 @@
@custom-variant dark (&:is(.dark *));
@theme inline {
+ /* Background and Foreground */
+ --color-background: #ffffff; /* White */
+ --color-foreground-primary: #0353f0; /* Light Blue */
+ --color-foreground-secondary: #000b21; /* Dark Blue */
+ --color-foreground-neutral: #121212; /* Very Dark Blue */
+
+ /* Primary Colors */
+ --color-primary-50: #edf7ff;
+ --color-primary-100: #d6ecff;
+ --color-primary-200: #b6e0ff;
+ --color-primary-300: #84cdff;
+ --color-primary-400: #44b1ff;
+ --color-primary-500: #218bff;
+ --color-primary-600: #096cff;
+ --color-primary-700: #0355f0;
+ --color-primary-800: #0443c3;
+ --color-primary-900: #0f3d99;
+ --color-primary-950: #0f265c;
+
+ /* Secondary Colors */
+ --color-secondary-50: #e9f7ff;
+ --color-secondary-100: #ceedff;
+ --color-secondary-200: #a7e1ff;
+ --color-secondary-300: #6bd2ff;
+ --color-secondary-400: #26b6ff;
+ --color-secondary-500: #008bff;
+ --color-secondary-600: #0061ff;
+ --color-secondary-700: #0046ff;
+ --color-secondary-800: #003be6;
+ --color-secondary-900: #0033b3;
+ --color-secondary-950: #000821;
+
+ /* Neutral Colors */
+ --color-neutral-50: #f6f6f6;
+ --color-neutral-100: #e7e7e7;
+ --color-neutral-200: #d1d1d1;
+ --color-neutral-300: #b0b0b0;
+ --color-neutral-400: #888888;
+ --color-neutral-500: #6d6d6d;
+ --color-neutral-600: #5d5d5d;
+ --color-neutral-700: #4f4f4f;
+ --color-neutral-800: #454545;
+ --color-neutral-900: #3d3d3d;
+ --color-neutral-950: #121212;
+
+ /* Additional colors */
--color-background: var(--background);
--color-foreground: var(--foreground);
- --font-sans: var(--font-geist-sans);
- --font-mono: var(--font-geist-mono);
--color-sidebar-ring: var(--sidebar-ring);
--color-sidebar-border: var(--sidebar-border);
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
@@ -36,10 +80,100 @@
--color-popover: var(--popover);
--color-card-foreground: var(--card-foreground);
--color-card: var(--card);
+
+ /* Font Family */
+ --font-sans: Inter, sans-serif;
+ --font-sans: var(--font-geist-sans);
+ --font-mono: var(--font-geist-mono);
+
+ /* DIsplay TextSizes */
+ --text-display-large: 57px;
+ --text-display-large--line-height: 64px;
+ --text-display-large--letter-spacing: -0.25px;
+ --text-display-medium: 45px;
+ --text-display-medium--line-height: 52px;
+ --text-display-medium--letter-spacing: 0px;
+ --text-display-small: 32px;
+ --text-display-small--line-height: 44px;
+ --text-display-small--letter-spacing: 0px;
+
+ /* Heading TextSizes */
+ --text-headline-xl-large: 44px;
+ --text-headline-xl-large--line-height: 100%;
+ --text-headline-xl-large--letter-spacing: 0px;
+ --text-headline-x-large: 40px;
+ --text-headline-x-large--line-height: 100%;
+ --text-headline-x-large--letter-spacing: 0px;
+ --text-headline-large: 32px;
+ --text-headline-large--line-height: 40px;
+ --text-headline-large--letter-spacing: 0px;
+ --text-headline-medium: 28px;
+ --text-headline-medium--line-height: 36px;
+ --text-headline-medium--letter-spacing: 0px;
+ --text-headline-small: 24px;
+ --text-headline-small--line-height: 32px;
+ --text-headline-small--letter-spacing: 0px;
+
+ /* Title TextSizes */
+ --text-title-large: 22px;
+ --text-title-large--line-height: 28px;
+ --text-title-large--letter-spacing: 0px;
+ --text-title-medium: 16px;
+ --text-title-medium--line-height: 20px;
+ --text-title-medium--letter-spacing: 0.15px;
+ --text-title-small: 14px;
+ --text-title-small--line-height: 20px;
+ --text-title-small--letter-spacing: 0.1px;
+
+ /* Logo TextSizes */
+ --text-logo: 20.5px;
+ --text-logo--line-height: 26px;
+ --text-logo--letter-spacing: 0px;
+
+ /* Body TextSizes */
+ --text-body-large: 16px;
+ --text-body-large--line-height: 24px;
+ --text-body-large--letter-spacing: 0px;
+ --text-body-medium: 14px;
+ --text-body-medium--line-height: 18px;
+ --text-body-medium--letter-spacing: 0.25px;
+ --text-body-small: 12px;
+ --text-body-small--line-height: 16px;
+ --text-body-small--letter-spacing: 0.4px;
+ --text-body-18px-large: 18px;
+ --text-body-18px-large--line-height: 26px;
+ --text-body-18px-large--letter-spacing: 0px;
+
+ /* Label TextSizes */
+ --text-label-large: 14px;
+ --text-label-large--line-height: 100%;
+ --text-label-large--letter-spacing: 0px;
+ --text-label-medium: 14px;
+ --text-label-medium--line-height: 20px;
+ --text-label-medium--letter-spacing: 0.1px;
+ --text-label-small: 11px;
+ --text-label-small--line-height: 16px;
+ --text-label-small--letter-spacing: 0.5px;
+
+ /* Font Weights */
+ --font-weight-light: 400;
+ --font-weight-medium: 500;
+ --font-weight-bold: 700;
+
+ /* Radius */
+ --radius-x-large: 28px;
+ --radius-large: 16px;
+ --radius-base: 12px;
+ --radius-small: 8px;
+ --radius-x-small: 4px;
--radius-sm: calc(var(--radius) - 4px);
--radius-md: calc(var(--radius) - 2px);
--radius-lg: var(--radius);
--radius-xl: calc(var(--radius) + 4px);
+
+ /* Shadow */
+ --shadow-large: 0px 20px 16px 0px #00000014;
+ --shadow-base: 0px 12px 16px 0px #0000000a;
}
:root {
@@ -75,6 +209,10 @@
--sidebar-accent-foreground: oklch(0.205 0 0);
--sidebar-border: oklch(0.922 0 0);
--sidebar-ring: oklch(0.708 0 0);
+
+ * {
+ /* outline: 1px solid black; */
+ }
}
.dark {
@@ -111,13 +249,32 @@
--sidebar-ring: oklch(0.556 0 0);
}
-@layer base {
- * {
- @apply border-border outline-ring/50;
- }
- body {
- @apply bg-background text-foreground;
- }
+* {
+ @apply border-border outline-ring/50;
+}
+
+body {
+ @apply bg-background text-foreground;
+}
+
+html::-webkit-scrollbar {
+ display: none;
+ width: 0px;
+}
+
+html {
+ scrollbar-width: none;
+}
+
+html {
+ -ms-overflow-style: none;
+}
+
+html {
+ overflow-y: scroll;
+ overflow-x: hidden;
+ scroll-behavior: smooth;
+ -webkit-overflow-scrolling: touch;
}
.splide__pagination {
@@ -138,24 +295,6 @@
background: #b0b0b0 !important;
}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@media (max-width: 1024px) {
.splide__pagination__page {
width: 20px !important;
diff --git a/src/app/how-it-works/page.tsx b/src/app/how-it-works/page.tsx
new file mode 100644
index 0000000..1267af1
--- /dev/null
+++ b/src/app/how-it-works/page.tsx
@@ -0,0 +1,30 @@
+import Navbar from "@/components/common/Navbar";
+import FaqSection from "@/components/layout/FaqSection";
+import Footer from "@/components/layout/Footer";
+import StepByStepSection from "@/components/layout/StepByStepSection";
+
+export default function Page() {
+
+ return (
+ <>
+
+
+
+
+ Building More
+
+ Than an e-Library
+
+ A decentralized world where stories live on-chain and creators stay in control. Powered by StarkNet, our platform gives writers the freedom to publish without intermediaries and gives readers direct access to original, verifiable content they can truly own.
+
+
+
+
+
+
+
+ >
+ )
+}
diff --git a/src/app/landing-page/page.tsx b/src/app/landing-page/page.tsx
deleted file mode 100644
index 14a744a..0000000
--- a/src/app/landing-page/page.tsx
+++ /dev/null
@@ -1,23 +0,0 @@
-import Hero from "@/components/landingpage/Hero";
-import Tagline from "@/components/landingpage/Tagline";
-import Nft from "@/components/landingpage/Nft";
-import Authors from "@/components/landingpage/Authors";
-import Banner from "@/components/landingpage/Banner";
-import Community from "@/components/landingpage/Community";
-import Partener from "@/components/landingpage/Partener";
-import Footer from "@/components/landingpage/Footer";
-
-export default function landing() {
- return (
- <>
-
-
-
-
-
-
-
-
- >
- );
-}
\ No newline at end of file
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index 33feb3d..f718305 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -1,10 +1,17 @@
+import { Providers } from "@/components/blockchain/Providers";
import type { Metadata } from "next";
+import { Inter } from "next/font/google";
import "./globals.css";
-import { Providers } from "@/components/blockchain/Providers";
+
+const inter = Inter({
+ subsets: ['latin'],
+ weight: ['400', '500', '700'],
+ display: 'swap',
+});
export const metadata: Metadata = {
title: "ChainLib",
- description: "An E-Libray Platform",
+ description: "An E-Library Platform",
};
export default function RootLayout({
@@ -13,8 +20,8 @@ export default function RootLayout({
children: React.ReactNode;
}>) {
return (
-
-
+
+
{children}
diff --git a/src/app/login/page.tsx b/src/app/login/page.tsx
new file mode 100644
index 0000000..e1130da
--- /dev/null
+++ b/src/app/login/page.tsx
@@ -0,0 +1,6 @@
+
+export default function page() {
+ return (
+
+ )
+}
diff --git a/src/app/page.tsx b/src/app/page.tsx
index c5ed238..03e8b13 100644
--- a/src/app/page.tsx
+++ b/src/app/page.tsx
@@ -1,23 +1,28 @@
+import Navbar from '@/components/common/Navbar';
+import Authors from "@/components/landingpage/Authors";
+import Banner from "@/components/landingpage/Banner";
+import Community from "@/components/landingpage/Community";
+import Hero from "@/components/landingpage/Hero";
+import Nft from "@/components/landingpage/Nft";
+import Partners from "@/components/landingpage/Partners";
+import Tagline from "@/components/landingpage/Tagline";
+import Footer from '@/components/layout/Footer';
import React from "react";
-import LandingPage from "@/app/landing-page/page";
-// import { redirect } from "next/navigation";
-import About from "./about-us/page";
+
+// import About from "./about-us/page";
export default function Home() {
return (
<>
-
-
-
-
-
- {/*
*/}
-
- Lorem ipsum dolor, sit amet consectetur adipisicing elit. Sint et, sit
- exercitationem repudiandae assumenda veniam reiciendis, doloribus itaque
- aperiam aut consectetur, mollitia quo aliquam labore non minus recusandae!
- Laboriosam, necessitatibus!
-
+
+
+
+
+
+
+
+
+
>
);
}
diff --git a/src/app/signup/page.tsx b/src/app/signup/page.tsx
new file mode 100644
index 0000000..3112cb3
--- /dev/null
+++ b/src/app/signup/page.tsx
@@ -0,0 +1,6 @@
+
+export default function page() {
+ return (
+
Signup and connect your wallet
+ )
+}
diff --git a/src/components/animation/index.ts b/src/components/animation/index.ts
new file mode 100644
index 0000000..5251cff
--- /dev/null
+++ b/src/components/animation/index.ts
@@ -0,0 +1,11 @@
+import { Variants } from "framer-motion";
+
+export const animateFn = (variants: Variants, custom: number | null = null) => {
+ return {
+ initial: "initial",
+ animate: "enter",
+ exit: "exit",
+ custom,
+ variants,
+ };
+};
diff --git a/src/components/blockchain/Providers.tsx b/src/components/blockchain/Providers.tsx
index 6701ac3..0b9abc8 100644
--- a/src/components/blockchain/Providers.tsx
+++ b/src/components/blockchain/Providers.tsx
@@ -7,8 +7,8 @@ import {
StarknetConfig,
argent,
braavos,
- useInjectedConnectors,
jsonRpcProvider,
+ useInjectedConnectors,
voyager,
} from "@starknet-react/core";
diff --git a/src/components/common/AnimatedContent.tsx b/src/components/common/AnimatedContent.tsx
new file mode 100644
index 0000000..2900026
--- /dev/null
+++ b/src/components/common/AnimatedContent.tsx
@@ -0,0 +1,21 @@
+import { IOnboardStepContentProps } from "@/types";
+
+export function AnimatedStepContent({ header, handleClick, message, index, length }: IOnboardStepContentProps) {
+
+ return (
+
handleClick(index)} className="cursor-pointer grid grid-cols-[2.5rem_auto] gap-6 lg:gap-10 place-content-start place-items-start max-w-md">
+
+
{index + 1}
+ {index + 1 < length &&
}
+
+
+
+ {header}
+
+
+ {message}
+
+
+
+ )
+}
diff --git a/src/components/common/AnimatedImage.tsx b/src/components/common/AnimatedImage.tsx
new file mode 100644
index 0000000..91cbae1
--- /dev/null
+++ b/src/components/common/AnimatedImage.tsx
@@ -0,0 +1,18 @@
+import { IOnboardStepImageProps } from "@/types";
+import Image from "next/image";
+
+export function AnimatedStepImage({ className = "", ImageSrc, handleClick, alt, step, index }: IOnboardStepImageProps) {
+ const isActive = step === index;
+
+ return (
+
handleClick(index)} className={`cursor-pointer ${className} absolute inset-0 flex items-center justify-center sm:justify-end transition-[transform_opacity] duration-1000 ease-in-out`}
+ style={{ transform: `rotate(${isActive ? 0 : 45}deg) scale(${isActive ? 1 : 0})`, opacity: `${isActive ? 100 : 0}%` }}
+ >
+
+
+
+
+
+ )
+}
diff --git a/src/components/common/Button.tsx b/src/components/common/Button.tsx
index aa29f37..9fbaabc 100644
--- a/src/components/common/Button.tsx
+++ b/src/components/common/Button.tsx
@@ -1,8 +1,11 @@
-
-
-function Button(){
- return(
-
Buttons
+import Link from "next/link";
+import { ReactNode } from "react";
+
+function Button({ children, href, className }: { className: string, children: ReactNode, href: string }) {
+ return (
+
+
{children}
+
)
}
diff --git a/src/components/common/LoginStep.tsx b/src/components/common/LoginStep.tsx
new file mode 100644
index 0000000..8efade7
--- /dev/null
+++ b/src/components/common/LoginStep.tsx
@@ -0,0 +1,35 @@
+"use client"
+
+import { loginSteps } from '@/data'
+import { Ref, useState } from 'react'
+import { AnimatedStepContent } from './AnimatedContent'
+import { AnimatedStepImage } from './AnimatedImage'
+
+export default function LoginStep({ readerRef }: { readerRef: Ref
}) {
+ // The first step is at 0, same with the index
+ const [step, setStep] = useState(0)
+
+ const handleClick = (index: number) => {
+ if (loginSteps.length > index + 1) {
+ setStep(() => index + 1)
+ } else {
+ setStep(() => 0)
+ }
+ }
+
+ return (
+
+
+ {loginSteps.map(({ ImageSrc, alt }, index) => (
))}
+
+
+
+
+ {loginSteps.map(({ message, header }, index) => (
))}
+
+
+
+ )
+}
diff --git a/src/components/common/Logo.tsx b/src/components/common/Logo.tsx
new file mode 100644
index 0000000..61c82d5
--- /dev/null
+++ b/src/components/common/Logo.tsx
@@ -0,0 +1,13 @@
+import Image from "next/image";
+import Link from "next/link";
+
+export default function Logo() {
+ return (
+
+
+
+
+ ChainLib
+
+ )
+}
diff --git a/src/components/common/Modal.tsx b/src/components/common/Modal.tsx
index 4ed36e3..119e362 100644
--- a/src/components/common/Modal.tsx
+++ b/src/components/common/Modal.tsx
@@ -1,7 +1,7 @@
"use client";
-import { useState, useEffect } from 'react';
import { useRouter } from 'next/navigation';
+import { useEffect, useState } from 'react';
import { FiUser, FiX } from 'react-icons/fi';
interface ProfileCompletionModalProps {
@@ -48,37 +48,37 @@ export default function ProfileCompletionModal({
return (
-
e.stopPropagation()}
>
-
-
+
Unlock Your Full Potential
- You're almost there! Complete your profile so we can tailor your
+ You`'`re almost there! Complete your profile so we can tailor your
experience and connect you with the right opportunities.
-
+
-
- I'll do it later
+ I`'`ll do it later
-
diff --git a/src/components/common/NavLink.tsx b/src/components/common/NavLink.tsx
new file mode 100644
index 0000000..8facfd2
--- /dev/null
+++ b/src/components/common/NavLink.tsx
@@ -0,0 +1,12 @@
+"use client"
+
+import Link from "next/link";
+import { usePathname } from "next/navigation";
+import { ReactNode } from "react";
+
+export default function NavLink({ children, href }: { children: ReactNode, href: string }) {
+ const pathname = usePathname()
+ return (
+ {children}
+ )
+}
diff --git a/src/components/common/NavMenuButton.tsx b/src/components/common/NavMenuButton.tsx
new file mode 100644
index 0000000..4b67fd9
--- /dev/null
+++ b/src/components/common/NavMenuButton.tsx
@@ -0,0 +1,26 @@
+"use client"
+
+import { AnimatePresence } from "framer-motion"
+import { useState } from "react"
+import NavMenu from "../ui/NavMenu"
+
+export default function NavMenuButton() {
+ const [openMenu, setOpenMenu] = useState(false)
+
+ function handleMenuClick() {
+ setOpenMenu(t => !t)
+ }
+ return (
+ <>
+
+
+
+
+
+
+
+ {openMenu && }
+
+ >
+ )
+}
diff --git a/src/components/common/NavSearchBar.tsx b/src/components/common/NavSearchBar.tsx
new file mode 100644
index 0000000..5992102
--- /dev/null
+++ b/src/components/common/NavSearchBar.tsx
@@ -0,0 +1,44 @@
+"use client"
+
+import clsx from "clsx"
+import { FormEvent, useEffect, useRef, useState } from "react"
+import { BiSolidSearch } from "react-icons/bi"
+
+function NavSearchBar() {
+ const [active, setActive] = useState(false)
+
+ const searchRef = useRef(null)
+
+ useEffect(() => {
+ function handleClickOutside(event: MouseEvent) {
+ if (searchRef.current && !(searchRef.current).contains(event.target as Node)) {
+ setActive(false)
+ }
+ }
+
+ document.addEventListener("mousedown", handleClickOutside)
+ return () => document.removeEventListener("mousedown", handleClickOutside)
+ }, [])
+
+ const handleSubmit = (e: FormEvent) => {
+ e.preventDefault()
+ setActive(false)
+ }
+
+ return (
+
+ )
+}
+
+export default NavSearchBar
\ No newline at end of file
diff --git a/src/components/common/Navbar.tsx b/src/components/common/Navbar.tsx
new file mode 100644
index 0000000..e085f5c
--- /dev/null
+++ b/src/components/common/Navbar.tsx
@@ -0,0 +1,32 @@
+
+import { links } from "@/data";
+import { ILink } from "@/types";
+import Button from "./Button";
+import Logo from "./Logo";
+import NavLink from "./NavLink";
+import NavMenuButton from "./NavMenuButton";
+import NavSearchBar from "./NavSearchBar";
+
+function Navbar() {
+ return (
+
+
+
+
+
+ {links.map(({ link, href }: ILink, index: number) => ({link} ))}
+
+
+
+
+ Login
+ SignUp
+
+
+
+
+
+ )
+}
+
+export default Navbar
\ No newline at end of file
diff --git a/src/components/common/SearchBar.tsx b/src/components/common/SearchBar.tsx
index 6f2586f..357dd74 100644
--- a/src/components/common/SearchBar.tsx
+++ b/src/components/common/SearchBar.tsx
@@ -34,4 +34,4 @@ function SearchBar({ placeholder = "Search...", onSearch }: SearchBarProps) {
);
}
-export default SearchBar;
\ No newline at end of file
+export default SearchBar
diff --git a/src/components/common/SelectChoiceButton.tsx b/src/components/common/SelectChoiceButton.tsx
new file mode 100644
index 0000000..229db84
--- /dev/null
+++ b/src/components/common/SelectChoiceButton.tsx
@@ -0,0 +1,13 @@
+export default function SelectChoiceButton({ writerIsActive, scrollToSection }: { writerIsActive: boolean, scrollToSection: (value: string) => void }) {
+
+ return (
+
+ scrollToSection("writer")} className={`${writerIsActive ? "bg-primary-300" : "bg-primary-50"} text-body-medium font-light rounded-x-large px-6 flex justify-center cursor-pointer items-center py-3`} type="button">
+ For Writers
+
+ scrollToSection("reader")} className={`${!writerIsActive ? "bg-primary-300" : "bg-primary-50"} text-body-medium font-light rounded-x-large px-6 cursor-pointer flex justify-center items-center py-3`} type="button">
+ Readers
+
+
+ )
+}
diff --git a/src/components/common/SignupStep.tsx b/src/components/common/SignupStep.tsx
new file mode 100644
index 0000000..b6cef5e
--- /dev/null
+++ b/src/components/common/SignupStep.tsx
@@ -0,0 +1,39 @@
+"use client"
+
+import { signupSteps } from '@/data';
+import { Ref, useState } from 'react';
+import { AnimatedStepContent } from './AnimatedContent';
+import { AnimatedStepImage } from './AnimatedImage';
+
+export default function SignupStep({ writerRef }: { writerRef: Ref }) {
+ // The first step is at 0, same with the index
+ const [step, setStep] = useState(0)
+
+ const handleClick = (index: number) => {
+ if (signupSteps.length > index + 1) {
+ setStep(() => index + 1)
+ } else {
+ setStep(() => 0)
+ }
+ }
+
+ return (
+
+
+
+ {signupSteps.map(({ message, header }, index) => (
))}
+
+
+
+
+ {signupSteps.map(({ ImageSrc, alt }, index) => (
))}
+
+
+ )
+}
+
+
+
+
diff --git a/src/components/common/Upload.tsx b/src/components/common/Upload.tsx
index 5ed877c..f2184bb 100644
--- a/src/components/common/Upload.tsx
+++ b/src/components/common/Upload.tsx
@@ -1,7 +1,7 @@
"use client"
-import { useState, useRef, type DragEvent, type ChangeEvent } from "react"
import Image from "next/image"
+import { useRef, useState, type ChangeEvent, type DragEvent } from "react"
interface FileUploadProps {
supportedFormats: string
@@ -10,9 +10,9 @@ interface FileUploadProps {
containerHeight?: string
}
-export function FileUpload({
- supportedFormats,
- icon,
+export function FileUpload({
+ supportedFormats,
+ icon,
acceptedFileTypes,
containerHeight = "h-44"
}: FileUploadProps) {
@@ -111,9 +111,8 @@ export function FileUpload({
{!file ? (
{icon === "image" ? (
-
) : (
-
{preview ? (
-
+
) : (
diff --git a/src/components/landingpage/Authors.tsx b/src/components/landingpage/Authors.tsx
index 4f25728..7b3099b 100644
--- a/src/components/landingpage/Authors.tsx
+++ b/src/components/landingpage/Authors.tsx
@@ -1,8 +1,8 @@
"use client";
-import React from 'react';
-import Image from 'next/image';
import { motion } from 'framer-motion';
+import Image from 'next/image';
+import React from 'react';
type AuthorCardProps = {
name: string;
@@ -52,30 +52,30 @@ const AuthorCard = ({ name, image, verified = false }: AuthorCardProps) => (
export default function TopAuthorsSection() {
const authors = [
- {
- name: "Elizabeth Joe",
- image: "/Eliazerbert.png",
- verified: true
+ {
+ name: "Elizabeth Joe",
+ image: "/Eliazerbert.png",
+ verified: true
},
- {
- name: "Alex Paul",
- image: "/alex.png",
- verified: true
+ {
+ name: "Alex Paul",
+ image: "/alex.png",
+ verified: true
},
- {
- name: "Samson Tersoor",
- image: "/samson.png",
- verified: true
+ {
+ name: "Samson Tersoor",
+ image: "/samson.png",
+ verified: true
},
- {
- name: "Vamika Maya",
- image: "/maya.png",
- verified: true
+ {
+ name: "Vamika Maya",
+ image: "/maya.png",
+ verified: true
},
- {
- name: "Faith Musa",
- image: "/faith.png",
- verified: true
+ {
+ name: "Faith Musa",
+ image: "/faith.png",
+ verified: true
}
];
@@ -83,12 +83,12 @@ export default function TopAuthorsSection() {
Top Authors For This Week
-
This week's most-read and most-loved authors don't miss their latest work
+
This week`'`s most-read and most-loved authors don`'`t miss their latest work
-
+
{authors.map((author, index) => (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
© 2025 ChainLib. All rights reserved.
-
-
-
- );
-}
\ No newline at end of file
diff --git a/src/components/landingpage/Hero.tsx b/src/components/landingpage/Hero.tsx
index 358df83..e732e57 100644
--- a/src/components/landingpage/Hero.tsx
+++ b/src/components/landingpage/Hero.tsx
@@ -1,7 +1,7 @@
"use client";
-import Image from "next/image";
import { motion } from "framer-motion";
+import Image from "next/image";
const peopleImages = [
{ id: 1, src: "/hero1.png", alt: "Person 1" },
@@ -13,7 +13,7 @@ const peopleImages = [
export default function Hero() {
return (
-
+
A Decentralized Library for the Future of Digital Publishing
-
+
{peopleImages.map((person, index) => (
))}
@@ -68,6 +67,6 @@ export default function Hero() {
Get Started
-
+
);
}
diff --git a/src/components/landingpage/Partener.tsx b/src/components/landingpage/Partners.tsx
similarity index 100%
rename from src/components/landingpage/Partener.tsx
rename to src/components/landingpage/Partners.tsx
diff --git a/src/components/landingpage/Tagline.tsx b/src/components/landingpage/Tagline.tsx
index 25d3a07..c0aa602 100644
--- a/src/components/landingpage/Tagline.tsx
+++ b/src/components/landingpage/Tagline.tsx
@@ -1,13 +1,13 @@
"use client";
-import React from 'react';
+import { motion } from "framer-motion";
import Image from 'next/image';
+import React from 'react';
import { FaLock } from "react-icons/fa";
-import { motion } from "framer-motion";
export default function DecentralizedELibrary() {
return (
-
+
);
}
diff --git a/src/components/layout/FaqSection.tsx b/src/components/layout/FaqSection.tsx
new file mode 100644
index 0000000..996c9b6
--- /dev/null
+++ b/src/components/layout/FaqSection.tsx
@@ -0,0 +1,76 @@
+"use client"
+
+import { Dispatch, SetStateAction, useState } from "react";
+import { BiMinusCircle, BiPlusCircle } from "react-icons/bi";
+
+const faqItems = [
+ {
+ question: "How to create an account on ChaineLib",
+ answer: "Get a unique NFT-powered author profile with your bio, genres, and publishing rights.\n\nGet a unique NFT-powered author profile with your bio, genres, and publishing rights."
+ },
+ {
+ question: "How to create an account on ChaineLib",
+ answer: "Get a unique NFT-powered author profile with your bio, genres, and publishing rights.\n\nGet a unique NFT-powered author profile with your bio, genres, and publishing rights."
+ },
+ {
+ question: "How to create an account on ChaineLib",
+ answer: "Get a unique NFT-powered author profile with your bio, genres, and publishing rights.\n\nGet a unique NFT-powered author profile with your bio, genres, and publishing rights."
+ },
+ {
+ question: "How to create an account on ChaineLib",
+ answer: "Get a unique NFT-powered author profile with your bio, genres, and publishing rights.\n\nGet a unique NFT-powered author profile with your bio, genres, and publishing rights."
+ },
+ {
+ question: "How to create an account on ChaineLib",
+ answer: "Get a unique NFT-powered author profile with your bio, genres, and publishing rights.\n\nGet a unique NFT-powered author profile with your bio, genres, and publishing rights."
+ },
+];
+
+export default function FaqSection() {
+ const [clicked, setClicked] = useState(1);
+
+ return (
+
+
+ You Got Questions?
+
+
+
+ {faqItems.map((item, index) => (
+
+ ))}
+
+
+ )
+}
+
+
+function FaqItem({ question, answer, index, setClicked, clicked }: { question: string, answer: string, index: number, setClicked: Dispatch
>, clicked: number }) {
+ function handleClick() {
+ if (index === clicked) { setClicked(0) }
+ else { setClicked(index) }
+ }
+
+ return (
+
+
+
+ {question}
+
+
+ {clicked === index ? : }
+
+
+
+ {answer}
+
+
+ )
+}
diff --git a/src/components/layout/Footer.tsx b/src/components/layout/Footer.tsx
index f1f436c..67aadb5 100644
--- a/src/components/layout/Footer.tsx
+++ b/src/components/layout/Footer.tsx
@@ -1,10 +1,52 @@
+import { FooterLink } from "@/data";
+import Link from "next/link";
+import { BiLogoLinkedin, BiLogoTelegram } from "react-icons/bi";
+import { FaXTwitter } from "react-icons/fa6";
+import Logo from "../common/Logo";
+export default function Footer() {
+ const currentYear = new Date().getFullYear();
-function Footer (){
- return(
- Footer
- )
-}
+ return (
+
+
+
+
+
+ © {currentYear} {" "}ChainLib. All rights reserved
+
+
+
+ {FooterLink.map(({ link, href }, index) => {link})}
+
-export default Footer;
\ No newline at end of file
+
+
+
+ 2025 {" "}ChainLib. All rights reserved
+
+
+
+ )
+}
diff --git a/src/components/layout/Sidenavbar.tsx b/src/components/layout/Sidenavbar.tsx
index f48fdc5..fd9e025 100644
--- a/src/components/layout/Sidenavbar.tsx
+++ b/src/components/layout/Sidenavbar.tsx
@@ -1,11 +1,11 @@
"use client"
-import type * as React from "react"
-import { useState, useEffect } from "react"
-import Link from "next/link"
+import { Menu, X } from "lucide-react"
import Image from "next/image"
+import Link from "next/link"
import { usePathname } from "next/navigation"
-import { Menu, X } from "lucide-react"
+import type * as React from "react"
+import { useEffect, useState } from "react"
import { cn } from "../../lib/utils"
type SidebarItem = {
@@ -28,13 +28,13 @@ export function Sidebar() {
setIsMobile(mobile)
setIsOpen(!mobile) // Open on desktop, closed on mobile
}
-
+
// Initial check
checkScreenSize()
-
+
// Add event listener
window.addEventListener('resize', checkScreenSize)
-
+
// Cleanup
return () => window.removeEventListener('resize', checkScreenSize)
}, [])
@@ -95,7 +95,7 @@ export function Sidebar() {
{/* Sidebar */}
-
-
- {sidebarItems.map((item, index) => {
+ {sidebarItems.map((item) => {
const isActive = pathname === item.href;
const isSignOut = item.label === "Sign Out";
-
+
return (
isMobile && setIsOpen(false)}
>
-
@@ -152,10 +152,10 @@ export function Sidebar() {
-
+
{/* Overlay for mobile when sidebar is open */}
{isOpen && isMobile && (
-
setIsOpen(false)}
/>
diff --git a/src/components/layout/StepByStepSection.tsx b/src/components/layout/StepByStepSection.tsx
new file mode 100644
index 0000000..1cf04d4
--- /dev/null
+++ b/src/components/layout/StepByStepSection.tsx
@@ -0,0 +1,36 @@
+"use client"
+
+import { useRef, useState } from "react";
+import LoginStep from "../common/LoginStep";
+import SelectChoiceButton from "../common/SelectChoiceButton";
+import SignupStep from "../common/SignupStep";
+
+export default function StepByStepSection() {
+ const [writerIsActive, setWriterIsActive] = useState(true)
+ const writerRef = useRef
(null)
+ const readerRef = useRef(null)
+
+ const scrollToSection = (section: string) => {
+ if (section === "writer") {
+ writerRef.current?.scrollIntoView({ behavior: "smooth", block: "center" });
+ setWriterIsActive(() => true)
+ } else {
+ readerRef.current?.scrollIntoView({ behavior: "smooth", block: "nearest" });
+ setWriterIsActive(() => false)
+ }
+ };
+
+ return (
+
+
+
+
+ {/* Signup steps */}
+
+
+
+ {/* Login Steps */}
+
+
+ )
+}
diff --git a/src/components/ui/NavMenu.tsx b/src/components/ui/NavMenu.tsx
new file mode 100644
index 0000000..45d7418
--- /dev/null
+++ b/src/components/ui/NavMenu.tsx
@@ -0,0 +1,40 @@
+import { links } from "@/data";
+import { motion } from "framer-motion";
+import Link from "next/link";
+import { animateFn } from "../animation";
+
+
+
+export default function NavMenu() {
+ const opacity = {
+ initial: {
+ y: "100%",
+ },
+ animate: (i: number) => ({
+ y: "0%",
+ transition: { duration: 0.5, delay: 0.01 * i + 0.3 },
+ }),
+ exit: {
+ y: "100%",
+ transition: { duration: 0.2 },
+ },
+ };
+
+ return (
+
+
+ {links.map(({ link, href }, index) =>
+ (
+ {link}
+ )
+ )}
+
+
+ )
+}
diff --git a/src/data.ts b/src/data.ts
new file mode 100644
index 0000000..0f891b9
--- /dev/null
+++ b/src/data.ts
@@ -0,0 +1,173 @@
+import { IFooterLinks, ILink, IOnboardStepProps } from "./types";
+
+export const links: ILink[] = [
+ { link: "Home", href: "/" },
+ { link: "Books", href: "/books/bookId" },
+ { link: "How It Works", href: "/how-it-works" },
+ { link: "About ChainLib", href: "/about-us" },
+];
+
+export const FooterLink: IFooterLinks[] = [
+ { link: "Explore", href: "/explore" },
+ { link: "Home", href: "/" },
+ { link: "Books", href: "/books" },
+ { link: "How It Works", href: "/how-it-works" },
+ { link: "About", href: "/about-us" },
+ { link: "Legal", href: "/legal" },
+ { link: "Privacy Policy", href: "/privacy-policy" },
+ { link: "Terms Of Service", href: "/terms-of-service" },
+];
+
+export const signupSteps: IOnboardStepProps[] = [
+ {
+ alt: "Sign up and connect wallet image",
+ header: "Sign Up & Connect Wallet",
+ message:
+ "Join ChainLib as a writer by connecting your StarkNet wallet(e.g., Braavos or Argent).",
+ ImageSrc: "./SignupSteps/SignUpStep1.svg",
+ },
+ {
+ message:
+ "Get a Unique NFT-powered author profile with your bio, genres, and publishing rights",
+ alt: "Sign up and connect wallet image",
+ header: "Create Your Author Identity",
+ ImageSrc: "./SignupSteps/SignUpStep2.svg",
+ },
+ {
+ message:
+ "Sign a smart contract that outlines ownership rights and revenue sharing.",
+ alt: "Sign up and connect wallet image",
+ header: "Agree To Terms",
+ ImageSrc: "./SignupSteps/SignUpStep3.svg",
+ },
+ {
+ message:
+ "Access your personal dashboard to manage books, track earnings and engage with readers.",
+ alt: "Sign up and connect wallet image",
+ header: "Set Up Your Dashboard",
+ ImageSrc: "./SignupSteps/SignUpStep4.svg",
+ },
+ {
+ message:
+ "Upload your book, add metadata(title, genre, price), and mint it as a content NFT.",
+ alt: "Sign up and connect wallet image",
+ header: "Publish your Books",
+ ImageSrc: "./SignupSteps/SignUpStep5.svg",
+ },
+ {
+ message:
+ "Earn instantly from purchases or subscriptions no middleman, full transparency",
+ alt: "Sign up and connect wallet image",
+ header: "Get Paid Directly",
+ ImageSrc: "./SignupSteps/SignUpStep6.svg",
+ },
+];
+
+export const relatedBooks = [
+ {
+ id: "1",
+ title: "Native Invisibility",
+ author: "Darrin Collins",
+ price: 10,
+ rating: 4.5,
+ coverImage: "/images/bookCover1.png",
+ isVerified: true,
+ },
+ {
+ id: "2",
+ title: "Native Invisibility",
+ author: "Darrin Collins",
+ price: 10,
+ rating: 4.5,
+ coverImage: "/images/bookCover1.png",
+ isVerified: true,
+ },
+ {
+ id: "3",
+ title: "Native Invisibility",
+ author: "Darrin Collins",
+ price: 10,
+ rating: 4.5,
+ coverImage: "/images/bookCover1.png",
+ isVerified: true,
+ },
+ {
+ id: "4",
+ title: "Native Invisibility",
+ author: "Darrin Collins",
+ price: 10,
+ rating: 4.5,
+ coverImage: "/images/bookCover1.png",
+ isVerified: true,
+ },
+];
+
+export const loginSteps: IOnboardStepProps[] = [
+ {
+ message: "Sign up quickly with your wallet and start exploring.",
+ alt: "Sign up and connect wallet image",
+ header: "Join & Connect Wallet",
+ ImageSrc: "./LoginSteps/LoginStep1.svg",
+ },
+ {
+ message:
+ "Choose your favorite genre, set reading goals and follow your favorite author",
+ alt: "Sign up and connect wallet image",
+ header: "Personalize Your Profile",
+ ImageSrc: "./LoginSteps/LoginStep2.svg",
+ },
+ {
+ message:
+ "Browse trending titles, new releases, and exclusive collections curated for you",
+ alt: "Sign up and connect wallet image",
+ header: "Discover Content",
+ ImageSrc: "./LoginSteps/LoginStep3.svg",
+ },
+ {
+ message:
+ "Read online , offline, or own a special edition NFT of your favorite book",
+ alt: "Sign up and connect wallet image",
+ header: "Read or Collect",
+ ImageSrc: "./LoginSteps/LoginStep4.svg",
+ },
+ {
+ message:
+ "Leave reviews, earn achievements, join book clubs, and climb the reader ranks",
+ alt: "Sign up and connect wallet image",
+ header: "Engage & Level Up",
+ ImageSrc: "./LoginSteps/LoginStep5.svg",
+ },
+ {
+ message: "Support Authors Directly",
+ alt: "Sign up and connect wallet image",
+ header:
+ "Every read and purchase supports the creator. Collect, recommend, and enjoy the community",
+ ImageSrc: "./LoginSteps/LoginStep6.svg",
+ },
+];
+
+export const bookData = [
+ {
+ title: "Native Invisibility",
+ author: "Darrin Collins",
+ authorImage: "/author1.svg",
+ rating: 4.5,
+ reviews: 109,
+ description:
+ '"Native Invisibility" delves into the complex and often insidious ways in which Indigenous peoples and their unique experiences are rendered unseen and unheard in the modern era.',
+ price: 12,
+ strikeCount: "193 STRK",
+ genre: "Fiction",
+ category: "Comic",
+ pageCount: "21 Pages",
+ language: "English",
+ publishDate: "12 April, 2025",
+ isbn: "978-3-16-148410-0",
+ publisherNote:
+ "Native Invisibility unveils the crucial ways Indigenous cultures are often unseen in our modern world. This vital book fosters understanding and action for recognition and justice.",
+ authorBio:
+ "Darrin Collins is a dedicated researcher and writer deeply committed to exploring issues of cultural visibility, marginalization, and the intersection of identity and technology. His work in Native Invisibility reflects a long-standing interest in amplifying underrepresented voices and fostering a more nuanced understanding of diverse experiences in the contemporary world.",
+ isVerified: true,
+ coverImage: "/images/bookCover1.png",
+ },
+];
diff --git a/src/types.ts b/src/types.ts
new file mode 100644
index 0000000..8cfb226
--- /dev/null
+++ b/src/types.ts
@@ -0,0 +1,34 @@
+export interface ILink {
+ link: string;
+ href: string;
+}
+
+export interface IFooterLinks {
+ link: string;
+ href: string;
+}
+
+export interface IOnboardStepContentProps {
+ header: string;
+ message: string;
+ index: number;
+ handleClick: (index: number) => void;
+ length: number;
+}
+
+export interface IOnboardStepImageProps {
+ alt: string;
+ className?: string;
+ ImageSrc: string;
+ index: number;
+ handleClick: (index: number) => void;
+ length: number;
+ step: number;
+}
+
+export interface IOnboardStepProps {
+ alt: string;
+ ImageSrc: string;
+ header: string;
+ message: string;
+}