Skip to content

Commit

Permalink
Implement Comprehensive Artworks and Messaging Features
Browse files Browse the repository at this point in the history
- Add new artworks page with dynamic gallery and infinite scrolling
- Implement art card, modal, and sidebar components for artwork browsing
- Create messaging interface with chat list and conversation components
- Update header navigation and localization with new menu items
- Enhance user experience with interactive art exploration features
  • Loading branch information
bluefishhh93 committed Feb 9, 2025
1 parent 50584ca commit 756660c
Show file tree
Hide file tree
Showing 19 changed files with 683 additions and 144 deletions.
31 changes: 25 additions & 6 deletions src/app/(public)/[locale]/_header/auth-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
import { Separator } from '@/components/ui/separator';
import { Skeleton } from '@/components/ui/skeleton';
import useAuthClient from '@/hooks/useAuth-client';
import { CircleUserRoundIcon, Palette, SettingsIcon } from 'lucide-react'; // Import Skeleton from shadcn/ui
import { BookOpen, CircleUserRoundIcon, MessageCircle, Palette, SettingsIcon, UserRoundPen, WalletMinimal } from 'lucide-react';
import { useTranslations } from 'next-intl';
import Link from 'next/link';

Expand Down Expand Up @@ -66,18 +66,37 @@ export default function AuthButton() {
text={t('settings')}
href='/settings'
/>
<DropdownItemWithIcon
icon={<Palette className='w-6 h-6' />}
<DropdownItemWithIcon
icon={<UserRoundPen className='w-6 h-6' />}
text={t('artists')}
href='/artists'
/>
<DropdownItemWithIcon
icon={<Palette className='w-6 h-6' />}
text={t('creator')}
href='/creator'
/>



<DropdownItemWithIcon
icon={<WalletMinimal className='w-6 h-6' />}
text={t('wallet')}
href='/wallet'
/>
<DropdownItemWithIcon
icon={<MessageCircle className='w-6 h-6' />}
text={t('messages')}
href='/messages'
/>
<DropdownItemWithIcon
icon={<BookOpen className='w-6 h-6' />}
text={t('my_blogs')}
href='/my-blogs'
/>

<Separator className='mt-6' />

<SignOutItem dropdown />
</DropdownMenuContent>

</DropdownMenu>
</div>
);
Expand Down
47 changes: 21 additions & 26 deletions src/app/(public)/[locale]/_header/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,14 @@ import ThemeSwitcher from './theme-switcher';
const listMenu = [
{ href: '/', label: 'home' },
{ href: '/about', label: 'about' },
{ href: '/contact', label: 'contact' }
{ href: '/contact', label: 'contact' },
{ href: '/artworks', label: 'artworks' },
{ href: '/discover', label: 'discover' },
{ href: '/social', label: 'community' },

];


export default function Header() {
const t = useTranslations('header');
const [isScrolled, setIsScrolled] = useState(false);
Expand Down Expand Up @@ -50,54 +55,44 @@ export default function Header() {
)}
>
<div className='container mx-auto px-4 sm:px-6 lg:px-8'>
<div className='flex items-center justify-between h-16'>
<div className='flex items-center justify-between h-20'>
<div className='flex-shrink-0'>
<Link
href='/'
className={cn(
'text-2xl font-bold',
'text-2xl font-bold tracking-tight',
isScrolled
? 'text-white'
? 'text-gray-900 dark:text-white'
: 'text-gray-800 dark:text-gray-200'
)}
>
<div className='relative w-14 h-14'>
<Image
src='/logo.svg'
alt='logo'
className='object-fill dark:invert dark:brightness-0 dark:contrast-200'
fill
priority
/>
</div>
<Image src='/logo.svg' alt='logo' width={70} height={70} />
</Link>
</div>
<nav className='hidden md:flex items-center w-full space-x-5'>
<div className='flex-shrink-0' />
{/* List menu ở giữa */}
<div className='flex flex-row space-x-3 justify-start flex-grow'>
<nav className='hidden md:flex items-center justify-center w-full'>


<div className='flex flex-row space-x-8'>
{listMenu.map(({ href, label }) => (
<Link
key={href}
href={href}
className={cn(
'transition-colors duration-200',
'transition-all duration-200 text-sm uppercase tracking-wider hover:opacity-70',
isScrolled
? 'text-gray-200 hover:text-white'
: 'text-gray-700 hover:text-gray-900 dark:text-gray-200 dark:hover:text-white'
? 'text-gray-900 dark:text-white'
: 'text-gray-800 dark:text-gray-200'
)}
>
{t(label)}
</Link>
))}
</div>
{/* Settings và AuthButton ở cuối */}
<div className='flex flex-row space-x-2'>
<Settings />
<AuthButton />
</div>
</nav>

<div className='flex flex-row space-x-4'>
<Settings />
<AuthButton />
</div>
<div className='flex flex-row space-x-2 md:hidden '>
<HeaderButton>
<ThemeSwitcher />
Expand Down
17 changes: 11 additions & 6 deletions src/app/(public)/[locale]/artists/collections/page.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
'use client';

import { useState, useCallback } from 'react';
Expand Down Expand Up @@ -37,35 +38,38 @@ export default function Collections() {
id: '1',
name: 'Summer Collection',
description: 'Artworks inspired by summer',
coverImage: '/images/demo.jpg',
coverImage: '/demo.jpg',
artworks: [
{
id: 'a1',
title: 'Beach Sunset',
imageUrl: '/images/demo.jpg'
imageUrl: '/demo.jpg'
},
{
id: 'a2',
title: 'Tropical Paradise',
imageUrl: '/images/demo.jpg'
imageUrl: '/demo.jpg'
}
]
},
{
id: '2',
name: 'Abstract Series',
description: 'A collection of abstract artworks',
coverImage: '/images/demo.jpg',
coverImage: '/demo.jpg',
artworks: [
{
id: 'a3',

title: 'Colorful Shapes',
imageUrl: '/images/demo.jpg'
imageUrl: '/demo.jpg'

},
{
id: 'a4',
title: 'Geometric Patterns',
imageUrl: '/images/demo.jpg'
imageUrl: '/demo.jpg'

}
]
}
Expand All @@ -76,6 +80,7 @@ export default function Collections() {
description: ''
});

// eslint-disable-next-line @typescript-eslint/no-unused-vars
const [editingCollection, setEditingCollection] = useState<string | null>(
null
);
Expand Down
9 changes: 6 additions & 3 deletions src/app/(public)/[locale]/artists/manage/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,27 +46,30 @@ export default function ManageArtworks() {
artist: 'John Doe',
status: 'Available',
price: 500,
imageUrl: '/images/demo.jpg'
imageUrl: '/demo.jpg'
},
{
id: '2',

title: 'Mountain View',
artist: 'Jane Smith',
status: 'Sold',
price: 750,
imageUrl: '/images/demo.jpg'
imageUrl: '/demo.jpg'
},
{
id: '3',
title: 'Abstract Thoughts',
artist: 'Bob Johnson',
status: 'Hidden',
price: 1000,
imageUrl: '/images/demo.jpg'

imageUrl: '/demo.jpg'
}
// Add more artwork entries here...
]);


const [searchTerm, setSearchTerm] = useState('');
const [currentPage, setCurrentPage] = useState(1);
const [statusFilter, setStatusFilter] = useState('All');
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
'use client';
import { fetchArtPiecesByRange } from '@/app/(public)/[locale]/gallery/api';
import ArtCard from '@/app/(public)/[locale]/gallery/components/art-card';
import ArtModal from '@/app/(public)/[locale]/gallery/components/art-modal';
import ArtFeed from '@/app/(public)/[locale]/gallery/components/art-feed';
import { fetchArtPiecesByRange } from '@/app/(public)/[locale]/artworks/api';
import ArtCard from '@/app/(public)/[locale]/artworks/components/art-card';
import ArtModal from '@/app/(public)/[locale]/artworks/components/art-modal';
import ArtFeed from '@/app/(public)/[locale]/artworks/components/art-feed';
import { ArtPiece } from '@/types/marketplace';
import { List, Masonry, useInfiniteLoader } from 'masonic';
import { useCallback, useMemo, useState } from 'react';
import FloatingSidebar from './components/art-sidebar';
import { AnimatePresence, motion } from 'framer-motion';

export default function Gallery({ artworks }: { artworks: ArtPiece[] }) {
export default function Artworks({ artworks }: { artworks: ArtPiece[] }) {
const [artPieces, setArtPieces] = useState<ArtPiece[]>(artworks);
const [masonryLayout, setMasonryLayout] = useState<boolean>(true);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { fetchArtPiecesByRange } from '@/app/(public)/[locale]/gallery/api';
import { fetchArtPiecesByRange } from '@/app/(public)/[locale]/artworks/api';
import { ArtPiece } from '@/types/marketplace';
import dynamic from 'next/dynamic';
import { LoadingComponent } from '@/components/ui.custom/loading';
const Gallery = dynamic(
() => import('@/app/(public)/[locale]/gallery/gallery'),

const Artworks = dynamic(
() => import('@/app/(public)/[locale]/artworks/artworks'),
{
ssr: false,
loading(loadingProps) {

return (
<LoadingComponent
error={loadingProps.error}
Expand All @@ -19,12 +21,15 @@ const Gallery = dynamic(
}
);

const GalleryPage = async () => {
const ArtworksPage = async () => {
const initialData = (await fetchArtPiecesByRange(0, 20)) as ArtPiece[];
return (

<>
<Gallery artworks={initialData} />
<Artworks artworks={initialData} />
</>

);
};
export default GalleryPage;
export default ArtworksPage;

5 changes: 3 additions & 2 deletions src/app/(public)/[locale]/discover/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export default function DiscoverPage() {
id: "1",
title: "Modern Art Exhibition 2024",
author: "Johny Dang",
thumbnail: "/modern_c1_plan.png",
thumbnail: "/demo.jpg",
category: "Modern Art",
description: "Contemporary mixed media portrait artwork by Johny Dang",
likes: 1234,
Expand Down Expand Up @@ -103,9 +103,10 @@ export default function DiscoverPage() {
className="object-cover transition-transform"
/>
<div className="absolute inset-0 bg-gradient-to-t from-black/60 to-transparent" />
<Badge className="absolute top-4 right-4 bg-white/90">Featured</Badge>
<Badge className="absolute top-4 right-4 bg-gray-300">Featured</Badge>
</div>
<div className="p-4">

<h3 className="text-xl font-semibold mb-2">{gallery.title}</h3>
<p className="text-gray-500 mb-4">{gallery.description}</p>
<div className="flex items-center gap-4 text-sm text-gray-600">
Expand Down
Loading

0 comments on commit 756660c

Please sign in to comment.