Refactor Reader component by removing hardcoded title; enhance layout responsiveness in Marketplace and Home_Banner components; add context menu functionality with hooks; improve Recent_Card interactivity; clean up Recent_Creation and Recent_Design components; update HoverCards for better accessibility.

This commit is contained in:
pious2847 2025-04-29 13:12:00 +00:00
parent 7edddfb532
commit 6dda74f583
10 changed files with 283 additions and 96 deletions

View File

@ -63,7 +63,6 @@ export default function Reader() {
content: (
<>
<h1 className="text-4xl font-bold mb-8 text-center">BRUTAL</h1>
<div className="space-y-6 text-center max-w-3xl">
<p className="text-lg">
&quot;Wade Harper! What is up, old friend! It&#39;s been too long,
@ -94,7 +93,6 @@ export default function Reader() {
videoSrc: "/videos/background2.mp4",
content: (
<>
<h1 className="text-4xl font-bold mb-8 text-center">BRUTAL</h1>
<div className="space-y-6 text-center max-w-3xl">
<p className="text-lg">
Man, yes! Didn&#39;t I tell you not to question this man! I knew

View File

@ -130,8 +130,6 @@
background-size: cover;
background-position: center center;
background-blend-mode: multiply;
height: 170px;
width: 1045px;
border-radius: 10px;
padding: 8px;
display: flex;
@ -165,23 +163,7 @@
font-family: Arial, Helvetica, sans-serif;
}
.hero_img {
background-color: #010313D9;
background-image: url("/images/89f1cacd4041e59eb162ffcb0f8080dc179fe415.png");
background-repeat: no-repeat;
background-size: cover;
background-position: center center;
background-blend-mode: multiply;
height: 170px;
width: 100%;
border-radius: 10px;
padding: 8px;
display: flex;
justify-content: space-between;
align-items: center;
padding-left: 40px;
padding-right: 40px;
}
.hero_text {
display: flex;

View File

@ -31,54 +31,71 @@ const Page: React.FC = () => {
const [selectedCategory, setSelectedCategory] = useState<string>(
categories[0]
);
const handleCategoryClick = (category: string) => {
setSelectedCategory(category);
};
return (
<div className="w-full h-full flex flex-col py-4 items-center justify-start bg-white">
<div className="w-[1280px] h-[282px] bg-slate-400 rounded-md">
<Image
src="/images/Banner.png"
alt="advertizers"
width={1280}
height={282}
/>
</div>
<div className="w-full px-4 bg-[#F3F3F3] mt-6 p-4 flex justify-center items-center">
<div className="flex flex-wrap gap-4">
{categories.map((category) => (
<button
key={category}
className={`px-5 py-2 rounded-md cursor-pointer duration-300 ${
selectedCategory === category
? "bg-black text-white"
: "bg-white text-black"
}`}
onClick={() => handleCategoryClick(category)}
>
{category}
</button>
))}
<div className="w-full flex flex-col py-4 items-center justify-start bg-white">
{/* Banner - responsive width */}
<div className="w-full max-w-7xl px-4 sm:px-6">
<div className="w-full bg-slate-400 rounded-md overflow-hidden">
<Image
src="/images/Banner.png"
alt="advertizers"
width={1280}
height={282}
className="w-full h-auto object-cover"
priority
/>
</div>
</div>
<div className="w-[1280px] m-6 grid sm:grid-cols-1 md:grid-cols-5 gap-2">
{images.map((image, index) => (
<div
key={index}
className="flex w-full h-full flex-col items-center justify-start rounded-md"
>
<Image
key={index}
src={image}
alt="advertizers"
width={1290}
height={280}
/>
<button className="px-15 py-1 border border-slate-800 rounded cursor-pointer">
List in Ebook
</button>
{/* Categories - scrollable on mobile */}
<div className="w-full bg-[#F3F3F3] mt-6 py-4 px-2">
<div className="overflow-x-auto max-w-7xl mx-auto">
<div className="flex flex-nowrap md:flex-wrap min-w-max md:min-w-0 gap-2 md:gap-4 px-2">
{categories.map((category) => (
<button
key={category}
className={`px-3 md:px-5 py-2 rounded-md whitespace-nowrap text-sm md:text-base cursor-pointer transition duration-300 ${
selectedCategory === category
? "bg-black text-white"
: "bg-white text-black"
}`}
onClick={() => handleCategoryClick(category)}
>
{category}
</button>
))}
</div>
))}
</div>
</div>
{/* Image grid - responsive columns */}
<div className="w-full max-w-7xl px-4 sm:px-6 my-6">
<div className="grid grid-cols-2 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 gap-3 md:gap-4">
{images.map((image, index) => (
<div
key={index}
className="flex flex-col items-center justify-start rounded-md"
>
<div className="w-full mb-2 rounded-md overflow-hidden">
<Image
src={image}
alt={`advertizers-${index}`}
width={300}
height={200}
className="w-full h-auto object-cover"
/>
</div>
<button className="px-3 py-1 text-sm md:text-base border border-slate-800 rounded cursor-pointer hover:bg-slate-100 transition-colors">
List in Ebook
</button>
</div>
))}
</div>
</div>
</div>
);

View File

@ -0,0 +1,54 @@
import React from "react";
import {
ContextMenu,
ContextMenuContent,
ContextMenuItem,
ContextMenuTrigger,
} from "@/components/ui/context-menu";
import { useContextMenuTriggers } from "@/hooks/useContextMenuTriggers";
const ContextMenuExample: React.FC = () => {
const { handlers } = useContextMenuTriggers({
longPressDelay: 500, // 500ms for long press
doubleClickDelay: 300 // 300ms for double click detection
});
return (
<div className="p-4">
<h2 className="text-xl font-bold mb-4">Context Menu Example</h2>
<p className="mb-4">
This component demonstrates how to use the context menu with:
</p>
<ul className="list-disc pl-6 mb-4">
<li>Right-click (desktop)</li>
<li>Long press (mobile - 500ms)</li>
<li>Double click (mobile and desktop)</li>
</ul>
<div className="mt-6">
<ContextMenu>
<ContextMenuTrigger asChild>
<div
className="bg-blue-100 p-6 rounded-lg shadow-md cursor-pointer text-center"
{...handlers}
>
<p className="font-medium">
Try right-click, long press, or double click me!
</p>
<p className="text-sm text-gray-500 mt-2">
Works on both desktop and mobile devices
</p>
</div>
</ContextMenuTrigger>
<ContextMenuContent>
<ContextMenuItem>Option 1</ContextMenuItem>
<ContextMenuItem>Option 2</ContextMenuItem>
<ContextMenuItem>Option 3</ContextMenuItem>
</ContextMenuContent>
</ContextMenu>
</div>
</div>
);
};
export default ContextMenuExample;

View File

@ -2,18 +2,18 @@ import React from "react";
export const Home_Banner: React.FC = () => {
return (
<div className="hero_img">
<div className="hero_text">
<h3>Bring Your Story to Life</h3>
<p>
<div className="hero_img flex flex-wrap gap-3 md:flex-nowrap h-fit md:h-[170px] w-full px-4 md:px-6 py-6 md:py-0 bg-gradient-to-r from-blue-500 to-purple-600">
<div className="hero_text w-full md:w-1/2 flex flex-col justify-center">
<h3 className="text-2xl md:text-3xl font-bold mb-2 text-white">Bring Your Story to Life</h3>
<p className="text-sm md:text-base mb-4 text-white opacity-90 max-w-md">
Start creating your own ebook today share your voice, inspire
readers, and publish to the world in just a few clicks.
</p>
<button>Create an ebook</button>
<button className="bg-white text-blue-600 hover:bg-blue-50 transition-colors rounded-md py-2 px-4 text-sm md:text-base font-medium w-fit">Create an ebook</button>
</div>
<div className="hero_cards">
<div className="card_1"></div>
<div className="card_2"></div>
<div className="hero_cards w-full md:w-1/2">
<div className="card_1 "></div>
<div className="card_2 "></div>
<div className="card_3"></div>
</div>
</div>

View File

@ -1,31 +1,64 @@
import React, { forwardRef } from "react";
import Image from "next/image";
import React from "react";
interface RecentCardProps {
export interface Recent_CardProps {
image: string;
title: string;
tag: string;
description: string;
// Add additional props for event handlers
onClick?: React.MouseEventHandler<HTMLDivElement>;
onTouchStart?: React.TouchEventHandler<HTMLDivElement>;
onTouchEnd?: React.TouchEventHandler<HTMLDivElement>;
onTouchMove?: React.TouchEventHandler<HTMLDivElement>;
}
const Recent_Card: React.FC<RecentCardProps> = ({ image, title, tag, description }) => {
const Recent_Card = forwardRef<HTMLDivElement, Recent_CardProps>(({
image,
title,
tag,
description,
onClick,
onTouchStart,
onTouchEnd,
onTouchMove,
...props
}, ref) => {
return (
<div className="flex flex-col justify-start items-start">
<div className="recent_card flex justify-center items-center">
<div
ref={ref}
className="w-full h-full flex flex-col bg-white rounded-lg overflow-hidden shadow-sm hover:shadow-md transition-shadow cursor-pointer"
onClick={onClick}
onTouchStart={onTouchStart}
onTouchEnd={onTouchEnd}
onTouchMove={onTouchMove}
{...props}
>
{/* Image container with consistent aspect ratio */}
<div className="relative w-full pt-[75%]">
<Image
src={image}
alt="image"
className="card_img"
width={100}
height={100}
alt={title}
fill
className="object-cover"
sizes="(max-width: 640px) 100vw, (max-width: 768px) 50vw, (max-width: 1024px) 33vw, 20vw"
/>
<div className="absolute top-2 left-2">
<span className="bg-black text-white text-xs px-2 py-1 rounded">
{tag}
</span>
</div>
</div>
{/* Content section */}
<div className="p-3 flex flex-col flex-grow">
<h4 className="font-medium text-sm mb-1 line-clamp-1">{title}</h4>
<p className="text-xs text-gray-500">{description}</p>
</div>
<h3 className="text-[14px] font-[400] text-slate-900">{title}</h3>
<p className="text-[10px] font-[400] text-slate-400">
{tag} <span> {description}</span>
</p>
</div>
);
};
});
Recent_Card.displayName = "Recent_Card";
export default Recent_Card;

View File

@ -1,3 +1,4 @@
'use client'
import React from "react";
import { FaSlidersH } from "react-icons/fa";
import Recent_Card from "./Recent_Card";
@ -8,17 +9,22 @@ import {
ContextMenuTrigger,
} from "@/components/ui/context-menu"
import Link from "next/link";
import { useContextMenuTriggers } from "@/hooks/useContextMenuTriggers";
const Recent_Creation: React.FC = () => {
// Use our custom hook for the first card with context menu
const { handlers } = useContextMenuTriggers({
longPressDelay: 500, // 500ms for long press
doubleClickDelay: 300 // 300ms for double click detection
});
return (
<div className="recent_container">
<div className="recent_title">
<div className="recent_container w-full">
<div className="recent_title w-full">
<h3 className="text-[16px] font-[700]">Recent creations</h3>
<FaSlidersH className="text-[20px] recent_icon" />
</div>
<div className="grid sm:grid-cols-2 md:grid-cols-5 gap-4 mt-2">
<div className="grid sm:grid-cols-2 md:grid-cols-5 gap-4 mt-2 w-full">
<ContextMenu>
<ContextMenuTrigger asChild>
<Recent_Card
@ -26,6 +32,8 @@ const Recent_Creation: React.FC = () => {
title="Good morning Gabe Hager!"
tag="Ebook"
description="Edited 13 mins ago"
// Add our event handlers for mobile support
{...handlers}
/>
</ContextMenuTrigger>
<ContextMenuContent>

View File

@ -29,7 +29,7 @@ export default function HoverCards({
return (
<HoverCard>
<HoverCardTrigger asChild>
<p className="text-blue-400 cursor-pointer underline">{triggerText}</p>
<span className="text-blue-400 cursor-pointer underline inline">{triggerText}</span>
</HoverCardTrigger>
<HoverCardContent className="w-80">
<div className="max-w-xs bg-white rounded-lg overflow-hidden shadow-lg">

View File

@ -73,7 +73,7 @@ export default function RecentDesign() {
</span>
{/* Action Buttons */}
<div className="ml-auto">
{/* <div className="ml-auto">
<Button variant="ghost" size="icon" className="h-10 w-10 p-1">
<div className="flex items-center gap-0.5 md:gap-1 pr-5">
<Button variant="ghost" size="icon" className="h-7 w-7 md:h-8 md:w-8 p-0 hover:bg-[#e6e6e8]">
@ -84,7 +84,7 @@ export default function RecentDesign() {
</Button>
</div>
</Button>
</div>
</div> */}
</div>
))}
</div>

View File

@ -0,0 +1,95 @@
'use client'
import { useRef, useCallback, useState } from 'react';
interface UseContextMenuTriggersProps {
longPressDelay?: number;
doubleClickDelay?: number;
}
export const useContextMenuTriggers = ({
longPressDelay = 500, // Default long press delay in ms
doubleClickDelay = 300, // Default double click delay in ms
}: UseContextMenuTriggersProps = {}) => {
const [isLongPressing, setIsLongPressing] = useState(false);
const longPressTimerRef = useRef<NodeJS.Timeout | null>(null);
const lastClickTimeRef = useRef<number>(0);
const targetRef = useRef<HTMLElement | null>(null);
// Function to simulate a right-click event
const simulateRightClick = useCallback((element: HTMLElement) => {
// Create and dispatch a custom contextmenu event
const contextMenuEvent = new MouseEvent('contextmenu', {
bubbles: true,
cancelable: true,
clientX: element.getBoundingClientRect().left + element.offsetWidth / 2,
clientY: element.getBoundingClientRect().top + element.offsetHeight / 2,
});
element.dispatchEvent(contextMenuEvent);
}, []);
// Handle touch start (for long press)
const handleTouchStart = useCallback((e: React.TouchEvent) => {
if (e.touches.length === 1) {
const element = e.currentTarget as HTMLElement;
targetRef.current = element;
// Clear any existing timer
if (longPressTimerRef.current) {
clearTimeout(longPressTimerRef.current);
}
setIsLongPressing(true);
// Start a timer for long press
longPressTimerRef.current = setTimeout(() => {
if (isLongPressing && targetRef.current) {
simulateRightClick(targetRef.current);
}
}, longPressDelay);
}
}, [longPressDelay, isLongPressing, simulateRightClick]);
// Handle touch end (cancel long press)
const handleTouchEnd = useCallback(() => {
if (longPressTimerRef.current) {
clearTimeout(longPressTimerRef.current);
}
setIsLongPressing(false);
}, []);
// Handle touch move (cancel long press if moving)
const handleTouchMove = useCallback(() => {
if (longPressTimerRef.current) {
clearTimeout(longPressTimerRef.current);
}
setIsLongPressing(false);
}, []);
// Handle double click
const handleClick = useCallback((e: React.MouseEvent) => {
const currentTime = new Date().getTime();
const element = e.currentTarget as HTMLElement;
// Check if this is a double click
if (currentTime - lastClickTimeRef.current < doubleClickDelay) {
// Double click detected
simulateRightClick(element);
lastClickTimeRef.current = 0; // Reset to prevent triple-click issues
} else {
// First click
lastClickTimeRef.current = currentTime;
}
}, [doubleClickDelay, simulateRightClick]);
return {
handlers: {
onTouchStart: handleTouchStart,
onTouchEnd: handleTouchEnd,
onTouchMove: handleTouchMove,
onClick: handleClick,
},
simulateRightClick,
};
};