Merge pull request 'feature/slider-docs' (#7) from feature/slider-docs into main
Reviewed-on: http://35.207.46.142/Wodey/woedii/pulls/7
270
app/docs/page.tsx
Normal file
@ -0,0 +1,270 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import React from "react";
|
||||||
|
import ReactMarkdown, { Components } from "react-markdown";
|
||||||
|
import remarkGfm from "remark-gfm";
|
||||||
|
|
||||||
|
const ReadmePage = () => {
|
||||||
|
const readmeContent = `
|
||||||
|
## 📘 WODEY Deliverables Overview
|
||||||
|
|
||||||
|
Welcome to your WODEY UI/UX design package. This page provides everything your team needs to understand, preview, and implement the design assets developed for the WODEY Publishing Ecosystem.
|
||||||
|
|
||||||
|
## 📂 What’s Included
|
||||||
|
|
||||||
|
Your deliverables include high-fidelity UI mockups, design system components, and documentation that collectively represent the full user journey across all major WODEY touchpoints.
|
||||||
|
|
||||||
|
| Section | Description |
|
||||||
|
| --------------------- | ------------------------------------------------------------------------------------------------------- |
|
||||||
|
| 01_Homepage | The landing experience for www.wodey.books including hero sections, genre browsing, and ebook discovery |
|
||||||
|
| 02_Author Studio | UI for authors to create, edit, preview, and publish multimedia ebooks |
|
||||||
|
| 03_Reader App | Reader-facing immersive interface with scroll & flip view modes |
|
||||||
|
| 04_Artist Marketplace | Asset browsing, upload flow, and commission request screens |
|
||||||
|
| 05_Advertiser Portal | Campaign setup, keyword targeting, and performance dashboards |
|
||||||
|
| 06_WODEY_Wallet | Revenue dashboard tracking ebook sales and ad earnings |
|
||||||
|
| 07_Design System | Colors, typography, button states, spacing, and reusable components |
|
||||||
|
| 08_Prototype_Flow | Clickable user journey demo |
|
||||||
|
|
||||||
|
## 🛠 How to Use These Files
|
||||||
|
|
||||||
|
Preview the Screens: Scroll through the design sections in logical flow
|
||||||
|
|
||||||
|
Download Assets: Use the "Download All Mockups" button to access the .zip file
|
||||||
|
|
||||||
|
## 🔗 Links
|
||||||
|
|
||||||
|
[Live Preview URL](https://woedii.yoursoftwareengineers.com)
|
||||||
|
|
||||||
|
[Download Full Zip File by clicking on the download icon](https://woedii.yoursoftwareengineers.com/slider)
|
||||||
|
|
||||||
|
## 🤝 Support
|
||||||
|
|
||||||
|
If you need help integrating these designs into code or want to schedule a handoff session, please contact:
|
||||||
|
|
||||||
|
UI/UX Design Lead: Daphne Augustine ([daphne@yoursoftwareengineers.com](mailto:daphne@yoursoftwareengineers.com))
|
||||||
|
|
||||||
|
Development Lead: Yussif Yahuza ([yussif@yoursoftwareengineers.com](mailto:yussif@yoursoftwareengineers.com))
|
||||||
|
`;
|
||||||
|
|
||||||
|
const components: Components = {
|
||||||
|
h1: ({ node, ...props }) => (
|
||||||
|
<h1
|
||||||
|
style={{
|
||||||
|
fontSize: "2.2em",
|
||||||
|
fontWeight: "600",
|
||||||
|
marginTop: "1.2em",
|
||||||
|
marginBottom: "0.6em",
|
||||||
|
borderBottom: "1px solid #eaeaea",
|
||||||
|
paddingBottom: "0.3em",
|
||||||
|
}}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
h2: ({ node, ...props }) => (
|
||||||
|
<h2
|
||||||
|
style={{
|
||||||
|
fontSize: "1.8em",
|
||||||
|
fontWeight: "600",
|
||||||
|
marginTop: "1.2em",
|
||||||
|
marginBottom: "0.6em",
|
||||||
|
borderBottom: "1px solid #eaeaea",
|
||||||
|
paddingBottom: "0.3em",
|
||||||
|
}}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
h3: ({ node, ...props }) => (
|
||||||
|
<h3
|
||||||
|
style={{
|
||||||
|
fontSize: "1.5em",
|
||||||
|
fontWeight: "600",
|
||||||
|
marginTop: "1.2em",
|
||||||
|
marginBottom: "0.6em",
|
||||||
|
}}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
p: ({ node, ...props }) => (
|
||||||
|
<p style={{ marginBottom: "1.2em", lineHeight: "1.8" }} {...props} />
|
||||||
|
),
|
||||||
|
a: ({ node, ...props }) => (
|
||||||
|
<a
|
||||||
|
style={{ color: "#0366d6", textDecoration: "none", fontWeight: "500" }}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
ul: ({ node, ...props }) => (
|
||||||
|
<ul
|
||||||
|
style={{
|
||||||
|
paddingLeft: "1.5em",
|
||||||
|
marginBottom: "1.2em",
|
||||||
|
listStyleType: "disc",
|
||||||
|
}}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
ol: ({ node, ...props }) => (
|
||||||
|
<ol
|
||||||
|
style={{
|
||||||
|
paddingLeft: "1.5em",
|
||||||
|
marginBottom: "1.2em",
|
||||||
|
listStyleType: "decimal",
|
||||||
|
}}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
li: ({ node, ...props }) => (
|
||||||
|
<li style={{ marginBottom: "0.4em" }} {...props} />
|
||||||
|
),
|
||||||
|
table: ({ node, ...props }) => (
|
||||||
|
<table
|
||||||
|
style={{
|
||||||
|
width: "100%",
|
||||||
|
borderCollapse: "collapse",
|
||||||
|
marginBottom: "1.2em",
|
||||||
|
boxShadow: "0 1px 3px rgba(0,0,0,0.08)",
|
||||||
|
border: "1px solid #dfe2e5",
|
||||||
|
}}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
th: ({ node, ...props }) => (
|
||||||
|
<th
|
||||||
|
style={{
|
||||||
|
border: "1px solid #dfe2e5",
|
||||||
|
padding: "0.6em 0.8em",
|
||||||
|
textAlign: "left",
|
||||||
|
backgroundColor: "#f6f8fa",
|
||||||
|
fontWeight: "600",
|
||||||
|
}}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
td: ({ node, ...props }) => (
|
||||||
|
<td
|
||||||
|
style={{
|
||||||
|
border: "1px solid #dfe2e5",
|
||||||
|
padding: "0.6em 0.8em",
|
||||||
|
textAlign: "left",
|
||||||
|
}}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
pre: ({ node, children, ...props }) => (
|
||||||
|
<pre
|
||||||
|
style={{
|
||||||
|
backgroundColor: "#f6f8fa",
|
||||||
|
padding: "1em",
|
||||||
|
borderRadius: "6px",
|
||||||
|
overflowX: "auto",
|
||||||
|
fontSize: "0.9em",
|
||||||
|
lineHeight: "1.5",
|
||||||
|
}}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</pre>
|
||||||
|
),
|
||||||
|
code: (props) => {
|
||||||
|
// Using `props: any` and casting to bypass TypeScript error with `inline` prop.
|
||||||
|
const {
|
||||||
|
node,
|
||||||
|
inline: isInline,
|
||||||
|
className,
|
||||||
|
children,
|
||||||
|
// Destructure known non-HTML props from react-markdown to prevent them from being spread onto the <code> tag
|
||||||
|
index,
|
||||||
|
siblingCount,
|
||||||
|
ordered,
|
||||||
|
checked,
|
||||||
|
style: _style, // if style is passed in props, avoid conflict with style object below
|
||||||
|
...htmlProps // Spread remaining props, assuming they are valid HTML attributes for <code>
|
||||||
|
} = props as any;
|
||||||
|
|
||||||
|
const codeStyleBase = {
|
||||||
|
fontFamily:
|
||||||
|
'SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace',
|
||||||
|
};
|
||||||
|
|
||||||
|
if (isInline) {
|
||||||
|
return (
|
||||||
|
<code
|
||||||
|
className={className}
|
||||||
|
style={{
|
||||||
|
...codeStyleBase,
|
||||||
|
backgroundColor: "rgba(27,31,35,0.07)", // Slightly adjusted for better visibility
|
||||||
|
padding: "0.2em 0.4em",
|
||||||
|
margin: "0 0.1em",
|
||||||
|
fontSize: "85%",
|
||||||
|
borderRadius: "3px",
|
||||||
|
}}
|
||||||
|
{...htmlProps}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</code>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For block code (inside <pre>)
|
||||||
|
return (
|
||||||
|
<code
|
||||||
|
className={className} // className might contain "language-js" etc.
|
||||||
|
style={{
|
||||||
|
...codeStyleBase,
|
||||||
|
// Most styling for block code is handled by the <pre> wrapper
|
||||||
|
// However, ensure no extra padding/margin if pre handles it
|
||||||
|
padding: 0,
|
||||||
|
backgroundColor: "transparent", // Pre has the background
|
||||||
|
}}
|
||||||
|
{...htmlProps}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</code>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
padding: "2rem",
|
||||||
|
fontFamily:
|
||||||
|
'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif',
|
||||||
|
lineHeight: "1.7",
|
||||||
|
color: "#24292e",
|
||||||
|
backgroundColor: "#ffffff",
|
||||||
|
maxWidth: "800px",
|
||||||
|
margin: "40px auto",
|
||||||
|
boxShadow: "0 4px 12px rgba(0,0,0,0.08)",
|
||||||
|
borderRadius: "8px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ReactMarkdown components={components} remarkPlugins={[remarkGfm]}>
|
||||||
|
{readmeContent}
|
||||||
|
</ReactMarkdown>
|
||||||
|
<a
|
||||||
|
href="http://35.207.46.142/Wodey/woedii"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
style={{
|
||||||
|
display: "inline-block",
|
||||||
|
marginTop: "2.5rem",
|
||||||
|
padding: "0.8rem 1.6rem",
|
||||||
|
backgroundColor: "#0366d6",
|
||||||
|
color: "white",
|
||||||
|
textDecoration: "none",
|
||||||
|
borderRadius: "6px",
|
||||||
|
fontWeight: "600",
|
||||||
|
textAlign: "center",
|
||||||
|
transition: "background-color 0.2s ease-in-out",
|
||||||
|
}}
|
||||||
|
onMouseOver={(e) => (e.currentTarget.style.backgroundColor = "#005cc5")}
|
||||||
|
onMouseOut={(e) => (e.currentTarget.style.backgroundColor = "#0366d6")}
|
||||||
|
>
|
||||||
|
Go to Project Repo
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ReadmePage;
|
||||||
64
app/slider/page.tsx
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
import ImageSlider from "@/components/custom/ImageSlider";
|
||||||
|
|
||||||
|
const SliderPage = () => {
|
||||||
|
const images = [
|
||||||
|
"/assets/1.png",
|
||||||
|
"/assets/2.png",
|
||||||
|
"/assets/3.png",
|
||||||
|
"/assets/4.png",
|
||||||
|
"/assets/5.png",
|
||||||
|
"/assets/6.png",
|
||||||
|
"/assets/7.png",
|
||||||
|
"/assets/8.png",
|
||||||
|
"/assets/9.png",
|
||||||
|
"/assets/10.png",
|
||||||
|
"/assets/11.png",
|
||||||
|
"/assets/12.png",
|
||||||
|
"/assets/13.png",
|
||||||
|
"/assets/14.png",
|
||||||
|
"/assets/15.png",
|
||||||
|
"/assets/16.png",
|
||||||
|
"/assets/17.png",
|
||||||
|
"/assets/18.png",
|
||||||
|
"/assets/19.png",
|
||||||
|
"/assets/20.png",
|
||||||
|
"/assets/21.png",
|
||||||
|
"/assets/22.png",
|
||||||
|
"/assets/23.png",
|
||||||
|
"/assets/24.png",
|
||||||
|
"/assets/25.png",
|
||||||
|
"/assets/26.png",
|
||||||
|
"/assets/27.png",
|
||||||
|
"/assets/28.png",
|
||||||
|
"/assets/29.png",
|
||||||
|
"/assets/30.png",
|
||||||
|
"/assets/31.png",
|
||||||
|
"/assets/32.png",
|
||||||
|
"/assets/33.png",
|
||||||
|
"/assets/34.png",
|
||||||
|
"/assets/35.png",
|
||||||
|
"/assets/36.png",
|
||||||
|
"/assets/37.png",
|
||||||
|
"/assets/38.png",
|
||||||
|
"/assets/39.png",
|
||||||
|
"/assets/40.png",
|
||||||
|
"/assets/41.png",
|
||||||
|
"/assets/42.png",
|
||||||
|
"/assets/43.png",
|
||||||
|
"/assets/44.png",
|
||||||
|
"/assets/45.png",
|
||||||
|
"/assets/46.png",
|
||||||
|
"/assets/47.png",
|
||||||
|
"/assets/48.png",
|
||||||
|
"/assets/49.png",
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="container mx-auto px-4 py-8">
|
||||||
|
<h1 className="text-3xl font-bold text-center mb-8">Image Slider</h1>
|
||||||
|
<ImageSlider images={images} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SliderPage;
|
||||||
176
components/custom/ImageSlider.tsx
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useState, useEffect } from "react";
|
||||||
|
import Image from "next/image";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { ChevronLeft, ChevronRight, ArrowLeft, Download } from "lucide-react"; // Added Download
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
|
import JSZip from "jszip";
|
||||||
|
import { saveAs } from "file-saver";
|
||||||
|
|
||||||
|
interface ImageSliderProps {
|
||||||
|
images: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const ImageSlider: React.FC<ImageSliderProps> = ({ images }) => {
|
||||||
|
const [currentIndex, setCurrentIndex] = useState(0);
|
||||||
|
const [isDownloading, setIsDownloading] = useState(false);
|
||||||
|
const [isHovered, setIsHovered] = useState(false); // New state for hover
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const goToPrevious = () => {
|
||||||
|
const isFirstImage = currentIndex === 0;
|
||||||
|
const newIndex = isFirstImage ? images.length - 1 : currentIndex - 1;
|
||||||
|
setCurrentIndex(newIndex);
|
||||||
|
};
|
||||||
|
|
||||||
|
const goToNext = () => {
|
||||||
|
const isLastImage = currentIndex === images.length - 1;
|
||||||
|
const newIndex = isLastImage ? 0 : currentIndex + 1;
|
||||||
|
setCurrentIndex(newIndex);
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let timer: NodeJS.Timeout;
|
||||||
|
if (!isHovered) {
|
||||||
|
// Only set timer if not hovered
|
||||||
|
timer = setTimeout(() => {
|
||||||
|
goToNext();
|
||||||
|
}, 5000); // Change image every 5 seconds
|
||||||
|
}
|
||||||
|
return () => clearTimeout(timer);
|
||||||
|
}, [currentIndex, images.length, isHovered, goToNext]); // Added isHovered and goToNext to dependency array
|
||||||
|
|
||||||
|
const handleDownloadAll = async () => {
|
||||||
|
if (!images || images.length === 0) return;
|
||||||
|
setIsDownloading(true);
|
||||||
|
const zip = new JSZip();
|
||||||
|
try {
|
||||||
|
for (let i = 0; i < images.length; i++) {
|
||||||
|
const response = await fetch(images[i]);
|
||||||
|
const blob = await response.blob();
|
||||||
|
// Extract filename from path, or use index as fallback
|
||||||
|
const filename =
|
||||||
|
images[i].substring(images[i].lastIndexOf("/") + 1) ||
|
||||||
|
`image_${i + 1}.png`;
|
||||||
|
zip.file(filename, blob);
|
||||||
|
}
|
||||||
|
const zipBlob = await zip.generateAsync({ type: "blob" });
|
||||||
|
saveAs(zipBlob, "images.zip");
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error zipping images:", error);
|
||||||
|
// Handle error (e.g., show a notification to the user)
|
||||||
|
} finally {
|
||||||
|
setIsDownloading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!images || images.length === 0) {
|
||||||
|
return <p>No images to display.</p>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="relative w-full max-w-2xl mx-auto flex flex-col items-center rounded-lg shadow-lg bg-gray-100 dark:bg-gray-700 p-4"
|
||||||
|
onMouseEnter={() => setIsHovered(true)} // Set hovered to true
|
||||||
|
onMouseLeave={() => setIsHovered(false)} // Set hovered to false
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="icon"
|
||||||
|
onClick={() => router.back()}
|
||||||
|
className="absolute top-4 left-4 text-black bg-black bg-opacity-50 hover:bg-opacity-75 z-10" // Added z-10
|
||||||
|
aria-label="Go back"
|
||||||
|
>
|
||||||
|
<ArrowLeft className="h-6 w-6" />
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="icon"
|
||||||
|
onClick={handleDownloadAll}
|
||||||
|
disabled={isDownloading}
|
||||||
|
className="absolute top-4 right-4 bg-black bg-opacity-50 text-black hover:bg-opacity-75 z-10"
|
||||||
|
aria-label="Download all images"
|
||||||
|
>
|
||||||
|
{isDownloading ? (
|
||||||
|
<svg
|
||||||
|
className="animate-spin h-5 w-5 text-white"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<circle
|
||||||
|
className="opacity-25"
|
||||||
|
cx="12"
|
||||||
|
cy="12"
|
||||||
|
r="10"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth="4"
|
||||||
|
></circle>
|
||||||
|
<path
|
||||||
|
className="opacity-75"
|
||||||
|
fill="currentColor"
|
||||||
|
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
||||||
|
></path>
|
||||||
|
</svg>
|
||||||
|
) : (
|
||||||
|
<Download className="h-6 w-6" />
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
<div className="relative w-full overflow-hidden rounded-t-lg mt-12">
|
||||||
|
{" "}
|
||||||
|
{/* Added mt-12 to make space for back button */}
|
||||||
|
<div
|
||||||
|
className="flex transition-transform duration-500 ease-in-out"
|
||||||
|
style={{ transform: `translateX(-${currentIndex * 100}%)` }}
|
||||||
|
>
|
||||||
|
{images.map((src, index) => (
|
||||||
|
<div key={index} className="w-full flex-shrink-0 h-96 relative">
|
||||||
|
<Image
|
||||||
|
src={src}
|
||||||
|
alt={`Slide ${index + 1}`}
|
||||||
|
fill // Changed from layout="fill"
|
||||||
|
objectFit="contain"
|
||||||
|
priority={index === 0}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="icon"
|
||||||
|
className="absolute top-1/2 left-2 transform -translate-y-1/2 bg-black bg-opacity-50 text-white hover:bg-opacity-75"
|
||||||
|
onClick={goToPrevious}
|
||||||
|
>
|
||||||
|
<ChevronLeft className="h-6 w-6" />
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="icon"
|
||||||
|
className="absolute top-1/2 right-2 transform -translate-y-1/2 bg-black bg-opacity-50 text-white hover:bg-opacity-75"
|
||||||
|
onClick={goToNext}
|
||||||
|
>
|
||||||
|
<ChevronRight className="h-6 w-6" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center justify-center space-x-2 pt-4 pb-1">
|
||||||
|
{" "}
|
||||||
|
{/* Changed py-4 to pt-4 pb-1 to move dots lower */}
|
||||||
|
{images.map((_, index) => (
|
||||||
|
<button
|
||||||
|
key={index}
|
||||||
|
className={`w-3 h-3 rounded-full ${
|
||||||
|
currentIndex === index
|
||||||
|
? "bg-blue-500"
|
||||||
|
: "bg-gray-400 hover:bg-gray-500"
|
||||||
|
}`}
|
||||||
|
onClick={() => setCurrentIndex(index)}
|
||||||
|
aria-label={`Go to slide ${index + 1}`}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ImageSlider;
|
||||||
@ -1,9 +1,14 @@
|
|||||||
import { Bell, Menu } from 'lucide-react';
|
import { Bell, Menu } from "lucide-react";
|
||||||
import { Search } from 'lucide-react';
|
import { Search } from "lucide-react";
|
||||||
import { Input } from '@/components/ui/input';
|
import { Input } from "@/components/ui/input";
|
||||||
import { Dispatch, SetStateAction } from 'react';
|
import { Dispatch, SetStateAction } from "react";
|
||||||
|
import Link from "next/link";
|
||||||
|
|
||||||
export default function Navbar({ setDrawerOpen }: { setDrawerOpen?: Dispatch<SetStateAction<boolean>> }) {
|
export default function Navbar({
|
||||||
|
setDrawerOpen,
|
||||||
|
}: {
|
||||||
|
setDrawerOpen?: Dispatch<SetStateAction<boolean>>;
|
||||||
|
}) {
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center justify-between w-full h-[52px] xs:h-[56px] sm:h-[64px] md:h-[75px] bg-white px-2 xs:px-3 sm:px-4 md:px-6 lg:px-10">
|
<div className="flex items-center justify-between w-full h-[52px] xs:h-[56px] sm:h-[64px] md:h-[75px] bg-white px-2 xs:px-3 sm:px-4 md:px-6 lg:px-10">
|
||||||
{/* Hamburger menu for mobile */}
|
{/* Hamburger menu for mobile */}
|
||||||
@ -29,7 +34,10 @@ export default function Navbar({ setDrawerOpen }: { setDrawerOpen?: Dispatch<Set
|
|||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-1 xs:gap-2 sm:gap-3 md:gap-4 lg:gap-6">
|
<div className="flex items-center gap-1 xs:gap-2 sm:gap-3 md:gap-4 lg:gap-6">
|
||||||
<div className="relative cursor-pointer">
|
<div className="relative cursor-pointer">
|
||||||
<Bell size={16} className="text-[#222] xs:text-[18px] sm:text-[20px] md:text-[22px]" />
|
<Bell
|
||||||
|
size={16}
|
||||||
|
className="text-[#222] xs:text-[18px] sm:text-[20px] md:text-[22px]"
|
||||||
|
/>
|
||||||
<span className="absolute top-[-2px] right-0 w-1 h-1 xs:w-1.5 xs:h-1.5 sm:w-2 sm:h-2 bg-[#FF3B30] rounded-full border-[1.5px] border-white" />
|
<span className="absolute top-[-2px] right-0 w-1 h-1 xs:w-1.5 xs:h-1.5 sm:w-2 sm:h-2 bg-[#FF3B30] rounded-full border-[1.5px] border-white" />
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center cursor-pointer">
|
<div className="flex items-center cursor-pointer">
|
||||||
@ -40,7 +48,11 @@ export default function Navbar({ setDrawerOpen }: { setDrawerOpen?: Dispatch<Set
|
|||||||
+
|
+
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<Link href="/creator">Creator</Link>
|
||||||
|
<Link href="/marketplace/artists">Marketplace</Link>
|
||||||
|
<Link href="/slider">Slider</Link>
|
||||||
|
<Link href="/docs">Docs</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +1,12 @@
|
|||||||
'use client';
|
"use client";
|
||||||
|
|
||||||
import Image from 'next/image';
|
import Image from "next/image";
|
||||||
import { Input } from '@/components/ui/input';
|
import { Input } from "@/components/ui/input";
|
||||||
import { Bell, Heart, ShoppingCart, SquarePen, Menu } from 'lucide-react';
|
import { Bell, Heart, ShoppingCart, SquarePen, Menu } from "lucide-react";
|
||||||
import { Avatar, AvatarImage, AvatarFallback } from '@/components/ui/avatar';
|
import { Avatar, AvatarImage, AvatarFallback } from "@/components/ui/avatar";
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from "@/components/ui/button";
|
||||||
import { useState } from 'react';
|
import { useState } from "react";
|
||||||
|
import Link from "next/link";
|
||||||
|
|
||||||
function MarketplaceNavbar() {
|
function MarketplaceNavbar() {
|
||||||
const [isMenuOpen, setIsMenuOpen] = useState(false);
|
const [isMenuOpen, setIsMenuOpen] = useState(false);
|
||||||
@ -15,12 +16,20 @@ function MarketplaceNavbar() {
|
|||||||
<div className="container-main h-[56px] flex items-center justify-between px-4 md:px-6">
|
<div className="container-main h-[56px] flex items-center justify-between px-4 md:px-6">
|
||||||
{/* Logo and Brand */}
|
{/* Logo and Brand */}
|
||||||
<div className="flex items-center gap-2 min-w-[120px] md:min-w-[180px]">
|
<div className="flex items-center gap-2 min-w-[120px] md:min-w-[180px]">
|
||||||
<Image src="/marketplacelogo.png" alt="Woedii Logo" width={40} height={40} className="object-contain" />
|
<Image
|
||||||
<span className="text-white text-xl md:text-2xl ml-1 font-normal">Wodey</span>
|
src="/marketplacelogo.png"
|
||||||
|
alt="Woedii Logo"
|
||||||
|
width={40}
|
||||||
|
height={40}
|
||||||
|
className="object-contain"
|
||||||
|
/>
|
||||||
|
<span className="text-white text-xl md:text-2xl ml-1 font-normal">
|
||||||
|
Wodey
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Mobile Menu Button */}
|
{/* Mobile Menu Button */}
|
||||||
<button
|
<button
|
||||||
className="md:hidden text-white"
|
className="md:hidden text-white"
|
||||||
onClick={() => setIsMenuOpen(!isMenuOpen)}
|
onClick={() => setIsMenuOpen(!isMenuOpen)}
|
||||||
>
|
>
|
||||||
@ -29,8 +38,23 @@ function MarketplaceNavbar() {
|
|||||||
|
|
||||||
{/* Search Bar - Hidden on mobile */}
|
{/* Search Bar - Hidden on mobile */}
|
||||||
<div className="hidden md:flex flex-1 justify-center">
|
<div className="hidden md:flex flex-1 justify-center">
|
||||||
<div className="flex items-center bg-[#F2F4F8] rounded-[8px] px-4" style={{ width: 400, height: 40, gap: 8 }}>
|
<div
|
||||||
<svg className="text-[#6B7280] mr-2" width="18" height="18" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="8.5" cy="8.5" r="5.75"/><path d="M16 16l-3.5-3.5"/></svg>
|
className="flex items-center bg-[#F2F4F8] rounded-[8px] px-4"
|
||||||
|
style={{ width: 400, height: 40, gap: 8 }}
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
className="text-[#6B7280] mr-2"
|
||||||
|
width="18"
|
||||||
|
height="18"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth="2"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
>
|
||||||
|
<circle cx="8.5" cy="8.5" r="5.75" />
|
||||||
|
<path d="M16 16l-3.5-3.5" />
|
||||||
|
</svg>
|
||||||
<Input
|
<Input
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Search images, videos, fonts, graphics and more"
|
placeholder="Search images, videos, fonts, graphics and more"
|
||||||
@ -72,7 +96,10 @@ function MarketplaceNavbar() {
|
|||||||
</div>
|
</div>
|
||||||
{/* Create Button */}
|
{/* Create Button */}
|
||||||
<a href="/creator">
|
<a href="/creator">
|
||||||
<Button className="flex items-center gap-2 bg-[#0093A5] text-white px-3 md:px-5 py-2 rounded-lg font-medium text-sm md:text-base transition-colors ml-2 md:ml-4 hover:bg-[#007a87] cursor-pointer" type="button">
|
<Button
|
||||||
|
className="flex items-center gap-2 bg-[#0093A5] text-white px-3 md:px-5 py-2 rounded-lg font-medium text-sm md:text-base transition-colors ml-2 md:ml-4 hover:bg-[#007a87] cursor-pointer"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
<SquarePen size={18} />
|
<SquarePen size={18} />
|
||||||
<span className="hidden sm:inline">Create</span>
|
<span className="hidden sm:inline">Create</span>
|
||||||
</Button>
|
</Button>
|
||||||
@ -80,11 +107,32 @@ function MarketplaceNavbar() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Mobile Menu */}
|
{/* Mobile Menu */}
|
||||||
<div className={`absolute top-[56px] left-0 right-0 bg-[#010313] z-50 md:hidden transition-all duration-300 ease-in-out transform ${isMenuOpen ? 'translate-y-0 opacity-100' : '-translate-y-4 opacity-0 pointer-events-none'}`}>
|
<div
|
||||||
|
className={`absolute top-[56px] left-0 right-0 bg-[#010313] z-50 md:hidden transition-all duration-300 ease-in-out transform ${
|
||||||
|
isMenuOpen
|
||||||
|
? "translate-y-0 opacity-100"
|
||||||
|
: "-translate-y-4 opacity-0 pointer-events-none"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
<div className="container-main py-4">
|
<div className="container-main py-4">
|
||||||
{/* Mobile Search */}
|
{/* Mobile Search */}
|
||||||
<div className="flex items-center bg-[#F2F4F8] rounded-[8px] px-4 mb-4" style={{ height: 40, gap: 8 }}>
|
<div
|
||||||
<svg className="text-[#6B7280] mr-2" width="18" height="18" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="8.5" cy="8.5" r="5.75"/><path d="M16 16l-3.5-3.5"/></svg>
|
className="flex items-center bg-[#F2F4F8] rounded-[8px] px-4 mb-4"
|
||||||
|
style={{ height: 40, gap: 8 }}
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
className="text-[#6B7280] mr-2"
|
||||||
|
width="18"
|
||||||
|
height="18"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeWidth="2"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
>
|
||||||
|
<circle cx="8.5" cy="8.5" r="5.75" />
|
||||||
|
<path d="M16 16l-3.5-3.5" />
|
||||||
|
</svg>
|
||||||
<Input
|
<Input
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Search..."
|
placeholder="Search..."
|
||||||
@ -137,6 +185,16 @@ function MarketplaceSecondaryMenu() {
|
|||||||
<li className="cursor-pointer">Audios</li>
|
<li className="cursor-pointer">Audios</li>
|
||||||
<li className="cursor-pointer">Gifs</li>
|
<li className="cursor-pointer">Gifs</li>
|
||||||
<li className="cursor-pointer">Fonts</li>
|
<li className="cursor-pointer">Fonts</li>
|
||||||
|
<li className="cursor-pointer">
|
||||||
|
<Link href="/slider" className="text-white hover:text-gray-300">
|
||||||
|
Slider
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
<li className="cursor-pointer">
|
||||||
|
<Link href="/docs" className="text-white hover:text-gray-300">
|
||||||
|
Docs
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
38
docs/deliverables.md
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
📘 WODEY Deliverables Overview
|
||||||
|
|
||||||
|
Welcome to your WODEY UI/UX design package. This page provides everything your team needs to understand, preview, and implement the design assets developed for the WODEY Publishing Ecosystem.
|
||||||
|
|
||||||
|
📂 What’s Included
|
||||||
|
|
||||||
|
Your deliverables include high-fidelity UI mockups, design system components, and documentation that collectively represent the full user journey across all major WODEY touchpoints.
|
||||||
|
|
||||||
|
| Section | Description |
|
||||||
|
| --------------------- | ------------------------------------------------------------------------------------------------------- |
|
||||||
|
| 01_Homepage | The landing experience for www.wodey.books including hero sections, genre browsing, and ebook discovery |
|
||||||
|
| 02_Author Studio | UI for authors to create, edit, preview, and publish multimedia ebooks |
|
||||||
|
| 03_Reader App | Reader-facing immersive interface with scroll & flip view modes |
|
||||||
|
| 04_Artist Marketplace | Asset browsing, upload flow, and commission request screens |
|
||||||
|
| 05_Advertiser Portal | Campaign setup, keyword targeting, and performance dashboards |
|
||||||
|
| 06_WODEY_Wallet | Revenue dashboard tracking ebook sales and ad earnings |
|
||||||
|
| 07_DesignS ystem | Colors, typography, button states, spacing, and reusable components |
|
||||||
|
| 08_Prototype_Flow | Clickable user journey demo |
|
||||||
|
|
||||||
|
🛠 How to Use These Files
|
||||||
|
|
||||||
|
Preview the Screens: Scroll through the design sections in logical flow
|
||||||
|
|
||||||
|
Download Assets: Use the "Download All Mockups" button to access the .zip file
|
||||||
|
|
||||||
|
🔗 Links
|
||||||
|
|
||||||
|
[Live Preview URL](https://woedii.yoursoftwareengineers.com)
|
||||||
|
|
||||||
|
[Download Full Zip File by clicking on the download icon](https://woedii.yoursoftwareengineers.com/slider)
|
||||||
|
|
||||||
|
🤝 Support
|
||||||
|
|
||||||
|
If you need help integrating these designs into code or want to schedule a handoff session, please contact:
|
||||||
|
|
||||||
|
UI/UX Design Lead: Daphne Augustine ([daphne@yoursoftwareengineers.com](mailto:daphne@yoursoftwareengineers.com))
|
||||||
|
|
||||||
|
Development Lead: Yussif Yahuza ([yussif@yoursoftwareengineers.com](mailto:yussif@yoursoftwareengineers.com))
|
||||||
@ -18,17 +18,22 @@
|
|||||||
"@radix-ui/react-tooltip": "^1.2.4",
|
"@radix-ui/react-tooltip": "^1.2.4",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
|
"file-saver": "^2.0.5",
|
||||||
"iconsax-react": "^0.0.8",
|
"iconsax-react": "^0.0.8",
|
||||||
|
"jszip": "^3.10.1",
|
||||||
"lucide-react": "^0.503.0",
|
"lucide-react": "^0.503.0",
|
||||||
"next": "15.3.1",
|
"next": "15.3.1",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-dom": "^19.0.0",
|
"react-dom": "^19.0.0",
|
||||||
"react-icons": "^5.5.0",
|
"react-icons": "^5.5.0",
|
||||||
|
"react-markdown": "^10.1.0",
|
||||||
|
"remark-gfm": "^4.0.1",
|
||||||
"tailwind-merge": "^3.2.0"
|
"tailwind-merge": "^3.2.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/eslintrc": "^3",
|
"@eslint/eslintrc": "^3",
|
||||||
"@tailwindcss/postcss": "^4",
|
"@tailwindcss/postcss": "^4",
|
||||||
|
"@types/file-saver": "^2.0.7",
|
||||||
"@types/node": "^20",
|
"@types/node": "^20",
|
||||||
"@types/react": "^19",
|
"@types/react": "^19",
|
||||||
"@types/react-dom": "^19",
|
"@types/react-dom": "^19",
|
||||||
|
|||||||
975
pnpm-lock.yaml
BIN
public/assets/1.png
Normal file
|
After Width: | Height: | Size: 331 KiB |
BIN
public/assets/10.png
Normal file
|
After Width: | Height: | Size: 226 KiB |
BIN
public/assets/11.png
Normal file
|
After Width: | Height: | Size: 452 KiB |
BIN
public/assets/12.png
Normal file
|
After Width: | Height: | Size: 236 KiB |
BIN
public/assets/13.png
Normal file
|
After Width: | Height: | Size: 206 KiB |
BIN
public/assets/14.png
Normal file
|
After Width: | Height: | Size: 231 KiB |
BIN
public/assets/15.png
Normal file
|
After Width: | Height: | Size: 590 KiB |
BIN
public/assets/16.png
Normal file
|
After Width: | Height: | Size: 576 KiB |
BIN
public/assets/17.png
Normal file
|
After Width: | Height: | Size: 261 KiB |
BIN
public/assets/18.png
Normal file
|
After Width: | Height: | Size: 321 KiB |
BIN
public/assets/19.png
Normal file
|
After Width: | Height: | Size: 313 KiB |
BIN
public/assets/2.png
Normal file
|
After Width: | Height: | Size: 88 KiB |
BIN
public/assets/20.png
Normal file
|
After Width: | Height: | Size: 360 KiB |
BIN
public/assets/21.png
Normal file
|
After Width: | Height: | Size: 248 KiB |
BIN
public/assets/22.png
Normal file
|
After Width: | Height: | Size: 224 KiB |
BIN
public/assets/23.png
Normal file
|
After Width: | Height: | Size: 227 KiB |
BIN
public/assets/24.png
Normal file
|
After Width: | Height: | Size: 254 KiB |
BIN
public/assets/25.png
Normal file
|
After Width: | Height: | Size: 225 KiB |
BIN
public/assets/26.png
Normal file
|
After Width: | Height: | Size: 226 KiB |
BIN
public/assets/27.png
Normal file
|
After Width: | Height: | Size: 225 KiB |
BIN
public/assets/28.png
Normal file
|
After Width: | Height: | Size: 225 KiB |
BIN
public/assets/29.png
Normal file
|
After Width: | Height: | Size: 224 KiB |
BIN
public/assets/3.png
Normal file
|
After Width: | Height: | Size: 355 KiB |
BIN
public/assets/30.png
Normal file
|
After Width: | Height: | Size: 229 KiB |
BIN
public/assets/31.png
Normal file
|
After Width: | Height: | Size: 226 KiB |
BIN
public/assets/32.png
Normal file
|
After Width: | Height: | Size: 223 KiB |
BIN
public/assets/33.png
Normal file
|
After Width: | Height: | Size: 233 KiB |
BIN
public/assets/34.png
Normal file
|
After Width: | Height: | Size: 225 KiB |
BIN
public/assets/35.png
Normal file
|
After Width: | Height: | Size: 226 KiB |
BIN
public/assets/36.png
Normal file
|
After Width: | Height: | Size: 228 KiB |
BIN
public/assets/37.png
Normal file
|
After Width: | Height: | Size: 227 KiB |
BIN
public/assets/38.png
Normal file
|
After Width: | Height: | Size: 227 KiB |
BIN
public/assets/39.png
Normal file
|
After Width: | Height: | Size: 224 KiB |
BIN
public/assets/4.png
Normal file
|
After Width: | Height: | Size: 81 KiB |
BIN
public/assets/40.png
Normal file
|
After Width: | Height: | Size: 225 KiB |
BIN
public/assets/41.png
Normal file
|
After Width: | Height: | Size: 224 KiB |
BIN
public/assets/42.png
Normal file
|
After Width: | Height: | Size: 224 KiB |
BIN
public/assets/43.png
Normal file
|
After Width: | Height: | Size: 225 KiB |
BIN
public/assets/44.png
Normal file
|
After Width: | Height: | Size: 1.4 MiB |
BIN
public/assets/45.png
Normal file
|
After Width: | Height: | Size: 655 KiB |
BIN
public/assets/46.png
Normal file
|
After Width: | Height: | Size: 321 KiB |
BIN
public/assets/47.png
Normal file
|
After Width: | Height: | Size: 1.0 MiB |
BIN
public/assets/48.png
Normal file
|
After Width: | Height: | Size: 680 KiB |
BIN
public/assets/49.png
Normal file
|
After Width: | Height: | Size: 1.0 MiB |
BIN
public/assets/5.png
Normal file
|
After Width: | Height: | Size: 74 KiB |
BIN
public/assets/6.png
Normal file
|
After Width: | Height: | Size: 353 KiB |
BIN
public/assets/7.png
Normal file
|
After Width: | Height: | Size: 232 KiB |
BIN
public/assets/8.png
Normal file
|
After Width: | Height: | Size: 248 KiB |
BIN
public/assets/9.png
Normal file
|
After Width: | Height: | Size: 267 KiB |