mirror of
https://github.com/D4M13N-D3V/neroshitron.git
synced 2025-06-16 05:09:17 +00:00
feat:search + tags
This commit is contained in:
parent
812c01e518
commit
b12d3e1752
@ -2,11 +2,39 @@ import { NextResponse } from "next/server";
|
||||
import { createClient } from "@/utils/supabase/server";
|
||||
|
||||
|
||||
export async function GET(request: Request) {
|
||||
export async function POST(request: Request) {
|
||||
const supabase = createClient();
|
||||
const url = new URL(request.url);
|
||||
const search = url.searchParams.get("search");
|
||||
const data = await request.json();
|
||||
const tags = data.tags;
|
||||
if(tags.length === 0){
|
||||
let { data: galleries, error } = await supabase
|
||||
.from('galleries')
|
||||
.select('*')
|
||||
.ilike('name', `%${search}%`)
|
||||
.ilike('description', `%${search}%`);
|
||||
|
||||
return NextResponse.json(galleries);
|
||||
}
|
||||
else{
|
||||
// Rest of the code...
|
||||
let { data: galleries, error } = await supabase
|
||||
.from('galleries')
|
||||
.select('*')
|
||||
return NextResponse.json(galleries)
|
||||
.from('galleries')
|
||||
.select('*')
|
||||
.contains('tags', tags)
|
||||
.ilike('name', `%${search}%`)
|
||||
.ilike('description', `%${search}%`)
|
||||
.order('created_at', { ascending: false });
|
||||
|
||||
return NextResponse.json(galleries);
|
||||
return NextResponse.json(galleries);
|
||||
}
|
||||
}
|
||||
|
||||
// const tagsResponse = await fetch(`/api/galleries/tags?search=${search}`);
|
||||
// const tagsData = await tagsResponse.json();
|
||||
// const galleriesWithTagData = galleriesData.map((gallery: any) => {
|
||||
// const tags = tagsData.filter((tag: any) => gallery.tags.includes(tag.id));
|
||||
// return { ...gallery, tags };
|
||||
// });
|
12
app/api/galleries/tags/route.ts
Normal file
12
app/api/galleries/tags/route.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { createClient } from "@/utils/supabase/server";
|
||||
|
||||
|
||||
export async function GET(request: Request) {
|
||||
const supabase = createClient();
|
||||
let { data: tags, error } = await supabase
|
||||
.from('tags')
|
||||
.select('*')
|
||||
return NextResponse.json(tags)
|
||||
}
|
||||
|
@ -18,7 +18,10 @@ function PageComponent() {
|
||||
const [user, setUser] = useState<User | null>(null);
|
||||
const [loading, setLoading] = useState<boolean>(true);
|
||||
const [selectedGallery, setSelectedGallery] = useState<string | null>(null);
|
||||
const [tags, setTags] = useState<any[]>([]);
|
||||
const [search, setSearch] = useState<string>('');
|
||||
const [galleryColumns, setColumns] = useState<number>(0);
|
||||
const [selectedTags, setSelectedTags] = useState<number[]>([]);
|
||||
const generateRandomString = function (length:number) {
|
||||
let result = '';
|
||||
let characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||
@ -43,58 +46,122 @@ function PageComponent() {
|
||||
}
|
||||
|
||||
const getData = async () => {
|
||||
const galleriesResponse = await fetch('/api/galleries');
|
||||
const galleriesData = await galleriesResponse.json();
|
||||
let { data: { user } } = await supabase.auth.getUser();
|
||||
const galleriesResponse = await fetch(`/api/galleries?search=`+search, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ tags:selectedTags })
|
||||
});
|
||||
console.log(galleriesResponse)
|
||||
const galleriesData = await galleriesResponse.json();
|
||||
const tagsResponse = await fetch(`/api/galleries/tags`);
|
||||
const tagsData = await tagsResponse.json();
|
||||
setGalleries(galleriesData);
|
||||
setTags(tagsData);
|
||||
setUser(user);
|
||||
setLoading(false);
|
||||
}
|
||||
useEffect(() => {
|
||||
getData();
|
||||
|
||||
}, []);
|
||||
return ( ( user ? (
|
||||
<div className="w-full h-full flex justify-center">
|
||||
}, [selectedTags,search]);
|
||||
|
||||
const handleTagClick = (tag: number) => {
|
||||
if (selectedTags.includes(tag)) {
|
||||
setSelectedTags(selectedTags.filter((selectedTag) => selectedTag !== tag));
|
||||
} else {
|
||||
setSelectedTags([...selectedTags, tag]);
|
||||
}
|
||||
console.log(selectedTags)
|
||||
};
|
||||
|
||||
return (
|
||||
user ? (
|
||||
<div className="w-full h-full flex justify-center ">
|
||||
<div className="flex-1 w-full h-full flex flex-col gap-20">
|
||||
<>
|
||||
<>
|
||||
<div className="absolute pl-8 w-2/4 left-1/2 h-full overflow-hidden z-20 animate-flip-up animate-ease-out">
|
||||
<section className="neroshi-blue-900 h-50 p-8 pt-20 opacity-30 hover:opacity-100">
|
||||
<div className="container mx-auto py-8">
|
||||
<input
|
||||
className="w-full text-neroshi-blue-950 h-16 px-3 rounded mb-8 focus:outline-none focus:shadow-outline text-xl px-8 shadow-lg"
|
||||
type="search"
|
||||
placeholder="Search..."
|
||||
onChange={(e) => setSearch(e.target.value)}
|
||||
/>
|
||||
<nav className="grid grid-cols-4 gap-4">
|
||||
{tags.map((tag, index) => (
|
||||
<a
|
||||
key={index}
|
||||
className={`rounded-lg no-underline text-white py-3 px-4 font-medium text-center ${
|
||||
selectedTags.includes(tag.id) ? 'bg-neroshi-blue-950 hover:bg-neroshi-blue-900' : 'bg-neroshi-blue-800 hover:bg-neroshi-blue-700'
|
||||
}`}
|
||||
href="#"
|
||||
onClick={() => handleTagClick(tag.id)}
|
||||
>
|
||||
{tag.name}
|
||||
</a>
|
||||
))}
|
||||
</nav>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div className="absolute w-full h-full overflow-hidden z-0 animate-flip-up animate-ease-out">
|
||||
<img src="gallery_girl.png" className="float-right object-cover h-screen w-3/6" alt="Background" />
|
||||
</div>
|
||||
<div className="absolute items-center w-3/5 h-full ml-10 z-0 overflow-hidden animate-in animate-ease-out">
|
||||
<div className="grid grid-cols-3 gap-y-36 gap-x-10 h-full overflow-y-auto no-scrollbar pt-20">
|
||||
{galleries.map((gallery, index) => (
|
||||
<div className="absolute w-full h-full overflow-hidden z-0 animate-flip-up animate-ease-out">
|
||||
<img
|
||||
src="gallery_girl.png"
|
||||
className="float-right object-cover h-screen w-3/6"
|
||||
alt="Background"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<GalleryThumbnail key={index} id={gallery.id} title={gallery.name} columns={gallery.columns} subscription={gallery.tier as string} onSelect={selectGallery}></GalleryThumbnail>
|
||||
))}
|
||||
<div className="pt-10">
|
||||
</div>
|
||||
<div className="pt-10">
|
||||
<div className="absolute items-center w-2/4 h-full ml-10 z-0 overflow-hidden animate-in animate-ease-out">
|
||||
<div className="grid grid-cols-3 gap-y-36 gap-x-10 h-full overflow-y-auto no-scrollbar pt-20">
|
||||
{galleries && galleries.map((gallery, index) => (
|
||||
<GalleryThumbnail
|
||||
key={index}
|
||||
id={gallery.id}
|
||||
title={gallery.name}
|
||||
columns={gallery.columns}
|
||||
subscription={gallery.tier as string}
|
||||
onSelect={selectGallery}
|
||||
></GalleryThumbnail>
|
||||
))}
|
||||
<div className="pt-10"></div>
|
||||
<div className="pt-10"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
</div>
|
||||
{(isOpen ? (
|
||||
{isOpen ? (
|
||||
<>
|
||||
|
||||
|
||||
<div className={`fixed inset-0 transition-opacity z-30 ${isOpen ? 'animate-in' : 'fade-out'}`} aria-hidden="true">
|
||||
<div className="absolute inset-0 bg-neroshi-blue-900 opacity-70 z-30" onClick={()=>setIsOpen(false)} >
|
||||
</div>
|
||||
<div className="absolute inset-0 overflow-y-auto overflow-x-hidden no-scrollbar pt-2 w-full p-20 z-30">
|
||||
<Gallery id={selectedGallery as string} columns={galleryColumns} closeMenu={() => closeGallery()}></Gallery>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</>
|
||||
): null)}
|
||||
</div>
|
||||
|
||||
) : (
|
||||
<h1>loading</h1>
|
||||
)));
|
||||
<div
|
||||
className={`fixed inset-0 transition-opacity z-30 ${
|
||||
isOpen ? "animate-in" : "fade-out"
|
||||
}`}
|
||||
aria-hidden="true"
|
||||
>
|
||||
<div
|
||||
className="absolute inset-0 bg-neroshi-blue-900 opacity-70 z-30"
|
||||
onClick={() => setIsOpen(false)}
|
||||
></div>
|
||||
<div className="absolute inset-0 overflow-y-auto overflow-x-hidden no-scrollbar pt-2 w-full p-20 z-30">
|
||||
<Gallery
|
||||
id={selectedGallery as string}
|
||||
columns={galleryColumns}
|
||||
closeMenu={() => closeGallery()}
|
||||
></Gallery>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
) : null}
|
||||
</div>
|
||||
) : (
|
||||
<h1>loading</h1>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export default PageComponent;
|
@ -2,6 +2,7 @@ import { use, useState } from 'react';
|
||||
import { useEffect } from 'react';
|
||||
import { render } from 'react-dom';
|
||||
import Masonry from 'react-masonry-css';
|
||||
import PanZoom from 'react-easy-panzoom';
|
||||
|
||||
interface GalleryProps {
|
||||
id: string;
|
||||
@ -173,23 +174,24 @@ const Gallery = ({ id, columns, closeMenu }: GalleryProps) => {
|
||||
Back
|
||||
</button>
|
||||
|
||||
<div
|
||||
className="z-30 pb-10"
|
||||
style={{
|
||||
display: selectedImage ? "flex" : "block",
|
||||
alignItems: "flex-start",
|
||||
}}
|
||||
>
|
||||
<>
|
||||
{renderButtons()}
|
||||
{selectedImage ? (
|
||||
{selectedImage ? (<PanZoom>
|
||||
|
||||
<img
|
||||
src={images[currentIndex]}
|
||||
style={{ objectFit: "contain", maxWidth: "100%", maxHeight: "calc(100vh - 20px)" }}
|
||||
style={{ objectFit: "contain", maxWidth: "100%", maxHeight: "calc(100vh - 20px)", pointerEvents:"none" }}
|
||||
className="cursor-pointer animate-in w-full h-auto"
|
||||
onClick={() => close()}
|
||||
/>
|
||||
</PanZoom>
|
||||
) : (
|
||||
<div
|
||||
className="z-30 pb-10"
|
||||
style={{
|
||||
display: selectedImage ? "flex" : "block",
|
||||
alignItems: "flex-start",
|
||||
}}
|
||||
>
|
||||
<Masonry
|
||||
breakpointCols={columns}
|
||||
className="my-masonry-grid"
|
||||
@ -205,9 +207,10 @@ const Gallery = ({ id, columns, closeMenu }: GalleryProps) => {
|
||||
/>
|
||||
))}
|
||||
</Masonry>
|
||||
<>
|
||||
</>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
20
package-lock.json
generated
20
package-lock.json
generated
@ -18,6 +18,7 @@
|
||||
"prop-types": "^15.8.1",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"react-easy-panzoom": "^0.4.4",
|
||||
"react-masonry-css": "^1.0.16",
|
||||
"react-responsive-masonry": "^2.2.0",
|
||||
"simplex-noise": "^4.0.1",
|
||||
@ -2154,6 +2155,17 @@
|
||||
"react": "^18.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-easy-panzoom": {
|
||||
"version": "0.4.4",
|
||||
"resolved": "https://registry.npmjs.org/react-easy-panzoom/-/react-easy-panzoom-0.4.4.tgz",
|
||||
"integrity": "sha512-1zgT6boDVPcrR3Egcz8KEVpM3fs50o22iIWPRlAqvev0/4nw5RnUNFsvmOJ/b5M2nd8MDGknLmyfBdhjoLB6+g==",
|
||||
"dependencies": {
|
||||
"warning": "4.0.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-is": {
|
||||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
@ -2775,6 +2787,14 @@
|
||||
"uuid": "dist/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/warning": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
|
||||
"integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/webidl-conversions": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||
|
@ -19,6 +19,7 @@
|
||||
"prop-types": "^15.8.1",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"react-easy-panzoom": "^0.4.4",
|
||||
"react-masonry-css": "^1.0.16",
|
||||
"react-responsive-masonry": "^2.2.0",
|
||||
"simplex-noise": "^4.0.1",
|
||||
|
Loading…
x
Reference in New Issue
Block a user