chore:readme

This commit is contained in:
Damien Ostler 2024-05-26 13:08:59 -04:00
parent 5b06ac56ff
commit c9e044baaa
109 changed files with 61 additions and 272 deletions

View File

@ -30,4 +30,47 @@ You will need to register and sign up, the first account on the appwrite instanc
1) Open your terminal and navigate to the root folder of the git repository. 1) Open your terminal and navigate to the root folder of the git repository.
2) Run the command `npm update`. 2) Run the command `npm update`.
3) Once the depedencies are pulled and installed you can run the command `npm run dev` to run the application in development mode. 3) Once the depedencies are pulled and installed you can run the command `npm run dev` to run the application in development mode.
4) Open http://localhost:3000/ 4) Open http://localhost:3000/
### React Components
##### Gallery Component
The `Gallery` component is a React component used to display a gallery of images. It fetches images from an API and displays them in a Masonry layout.
###### Props
- `id` (number): The ID of the gallery to fetch images from.
- `closeMenu` (function): A function to close the menu.
###### State
- `isSingle` (boolean): A state to check if only a single image is to be displayed.
- `loaded` (object): A state to keep track of loaded images.
- `selectedImage` (string | null): A state to keep track of the selected image.
- `images` (string[]): A state to store the fetched images.
- `galleryId` (number): A state to store the gallery ID.
###### Functions
- `getData`: An async function to fetch images from the API.
- `generateRandomString`: A function to generate a random string of a given length.
- `handleDownload`: A function to handle the download of an image.
###### Usage
The example below will load the images of the the gallery with an ID of `58201557-b392-471e-ac55-dcf6171cd18d` and will call the function for `setIsOpen(false)` when the back button is clicked.
```tsx
<Gallery id={"58201557-b392-471e-ac55-dcf6171cd18d"} closeMenu={() => setIsOpen(false)}></Gallery>
```
##### GalleryThumbnail Component
The `GalleryThumbnail` component is a React component used to display a thumbnail of a gallery. It fetches the thumbnail image from an API and displays it. When clicked, it triggers a callback function with the gallery ID.
###### Props
- `id` (string): The ID of the gallery to fetch the thumbnail for.
- `onSelect` (function): A function to be called when the thumbnail is clicked. The gallery ID is passed as an argument.
###### State
- `galleryId` (string): A state to store the gallery ID.
- `thumbnailUrl` (string): A state to store the fetched thumbnail URL.
- `isLoading` (boolean): A state to keep track of the loading status.
###### Functions
- `openGallery`: A function to call the `onSelect` prop with the gallery ID.
- `getData`: An async function to fetch the thumbnail from the API.
###### Usage
This will render a thumbnail for the gallery with the ID of "1". When the thumbnail is clicked, it will log the gallery ID to the console.
```tsx
<GalleryThumbnail id="1" onSelect={(id) => console.log(id)} />
```

View File

@ -18,7 +18,7 @@ function PageComponent() {
const [galleries, setGalleries] = useState<any[]>([]); // replace any with your gallery type const [galleries, setGalleries] = useState<any[]>([]); // replace any with your gallery type
const [user, setUser] = useState<User | null>(null); const [user, setUser] = useState<User | null>(null);
const [loading, setLoading] = useState<boolean>(true); const [loading, setLoading] = useState<boolean>(true);
const [selectedGallery, setSelectedGallery] = useState<number | null>(null); const [selectedGallery, setSelectedGallery] = useState<string | null>(null);
const generateRandomString = function (length:number) { const generateRandomString = function (length:number) {
let result = ''; let result = '';
let characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; let characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
@ -29,7 +29,7 @@ function PageComponent() {
return result; return result;
} }
const selectGallery = (gallery:number) => { const selectGallery = (gallery:string) => {
setRandomIds([generateRandomString(3), generateRandomString(3), generateRandomString(3), generateRandomString(3)]); setRandomIds([generateRandomString(3), generateRandomString(3), generateRandomString(3), generateRandomString(3)]);
setSelectedGallery(gallery); setSelectedGallery(gallery);
setIsOpen(true); setIsOpen(true);
@ -71,7 +71,7 @@ function PageComponent() {
<div key={randomIds[3]} className="absolute items-center w-3/5 h-full ml-10 z-2 overflow-hidden nimate-fade animate-ease-out"> <div key={randomIds[3]} className="absolute items-center w-3/5 h-full ml-10 z-2 overflow-hidden nimate-fade animate-ease-out">
<div className="grid grid-cols-3 gap-x-10 h-full overflow-y-auto no-scrollbar pt-36"> <div className="grid grid-cols-3 gap-x-10 h-full overflow-y-auto no-scrollbar pt-36">
{galleries.map((gallery, index) => ( {galleries.map((gallery, index) => (
<GalleryThumbnail key={index} id={gallery.id} onSelect={() => selectGallery(gallery.id)}></GalleryThumbnail> <GalleryThumbnail key={index} id={gallery.id} onSelect={selectGallery}></GalleryThumbnail>
))} ))}
</div> </div>
</div> </div>
@ -86,7 +86,7 @@ function PageComponent() {
<div className="absolute inset-0 bg-neroshi-blue-900 opacity-70" onClick={()=>setIsOpen(false)} > <div className="absolute inset-0 bg-neroshi-blue-900 opacity-70" onClick={()=>setIsOpen(false)} >
</div> </div>
<div className="absolute inset-0 overflow-y-auto overflow-x-hidden no-scrollbar pt-20 w-full p-20"> <div className="absolute inset-0 overflow-y-auto overflow-x-hidden no-scrollbar pt-20 w-full p-20">
<Gallery id={selectedGallery as number} closeMenu={() => setIsOpen(false)}></Gallery> <Gallery id={selectedGallery as string} closeMenu={() => setIsOpen(false)}></Gallery>
</div> </div>
</div> </div>

View File

@ -3,7 +3,7 @@ import { useEffect } from 'react';
import Masonry from 'react-masonry-css'; import Masonry from 'react-masonry-css';
interface GalleryProps { interface GalleryProps {
id: number; id: string;
closeMenu: () => void; closeMenu: () => void;
} }
@ -13,7 +13,7 @@ const Gallery = ({ id, closeMenu }: GalleryProps) => {
const [loaded, setLoaded] = useState({}) const [loaded, setLoaded] = useState({})
const [selectedImage, setSelectedImage] = useState<string | null>(null); const [selectedImage, setSelectedImage] = useState<string | null>(null);
const [images, setImages] = useState<string[]>([]); const [images, setImages] = useState<string[]>([]);
const [galleryId, setGalleryId] = useState(id as number); const [galleryId, setGalleryId] = useState(id as string);
console.log(id) console.log(id)
const getData = async () => { const getData = async () => {
const thumbnailResponse = await fetch('/api/galleries/'+String(galleryId)+'/images'); const thumbnailResponse = await fetch('/api/galleries/'+String(galleryId)+'/images');
@ -42,7 +42,7 @@ const Gallery = ({ id, closeMenu }: GalleryProps) => {
useEffect(() => { useEffect(() => {
getData(); getData();
if (images.length === 1) { if (images.length === 1) {
setIsSingle(true); setIsSingle(true);
setSelectedImage(images[0]); setSelectedImage(images[0]);
} }
}, [selectedImage]); }, [selectedImage]);

View File

@ -1,15 +1,16 @@
import { useState, useEffect } from 'react'; import { useState, useEffect } from 'react';
interface GalleryThumbnailProps { interface GalleryThumbnailProps {
id: number; id: string;
onSelect: (id:number) => void; onSelect: (id:string) => void;
} }
const GalleryThumbnail = ({ id, onSelect }: GalleryThumbnailProps) => { const GalleryThumbnail = ({ id, onSelect }: GalleryThumbnailProps) => {
const [galleryId, setGalleryId] = useState(id as number); const [galleryId, setGalleryId] = useState<string>(id);
const [thumbnailUrl, setThumbnailUrl] = useState('' as string); const [thumbnailUrl, setThumbnailUrl] = useState<string>('');
const [isLoading, setIsLoading] = useState(true); const [isLoading, setIsLoading] = useState<boolean>(true);
const toggleModal = () => {
const openGallery = () => {
onSelect(galleryId); onSelect(galleryId);
}; };
@ -32,7 +33,7 @@ const GalleryThumbnail = ({ id, onSelect }: GalleryThumbnailProps) => {
className={`aspect-content rounded-3xl`} className={`aspect-content rounded-3xl`}
src={thumbnailUrl} src={thumbnailUrl}
alt="" alt=""
onClick={toggleModal} onClick={openGallery}
style={{ width: '20rem', height: '20rem', objectFit: 'cover' }} style={{ width: '20rem', height: '20rem', objectFit: 'cover' }}
/>} />}
</div> </div>

View File

@ -1,255 +0,0 @@
import { cn } from "@/utils/cn";
import React, { useEffect, useRef } from "react";
import { createNoise3D } from "simplex-noise";
import { motion } from "framer-motion";
interface VortexProps {
children?: any;
className?: string;
containerClassName?: string;
particleCount?: number;
rangeY?: number;
baseHue?: number;
baseSpeed?: number;
rangeSpeed?: number;
baseRadius?: number;
rangeRadius?: number;
backgroundColor?: string;
}
export const Vortex = (props: VortexProps) => {
const canvasRef = useRef<HTMLCanvasElement>(null);
const containerRef = useRef(null);
const particleCount = props.particleCount || 700;
const particlePropCount = 9;
const particlePropsLength = particleCount * particlePropCount;
const rangeY = props.rangeY || 100;
const baseTTL = 50;
const rangeTTL = 150;
const baseSpeed = props.baseSpeed || 0.0;
const rangeSpeed = props.rangeSpeed || 1.5;
const baseRadius = props.baseRadius || 1;
const rangeRadius = props.rangeRadius || 2;
const baseHue = props.baseHue || 220;
const rangeHue = 100;
const noiseSteps = 3;
const xOff = 0.00125;
const yOff = 0.00125;
const zOff = 0.0005;
const backgroundColor = props.backgroundColor || "#000000";
let tick = 0;
const noise3D = createNoise3D();
let particleProps = new Float32Array(particlePropsLength);
let center: [number, number] = [0, 0];
const HALF_PI: number = 0.5 * Math.PI;
const TAU: number = 2 * Math.PI;
const TO_RAD: number = Math.PI / 180;
const rand = (n: number): number => n * Math.random();
const randRange = (n: number): number => n - rand(2 * n);
const fadeInOut = (t: number, m: number): number => {
let hm = 0.5 * m;
return Math.abs(((t + hm) % m) - hm) / hm;
};
const lerp = (n1: number, n2: number, speed: number): number =>
(1 - speed) * n1 + speed * n2;
const setup = () => {
const canvas = canvasRef.current;
const container = containerRef.current;
if (canvas && container) {
const ctx = canvas.getContext("2d");
if (ctx) {
resize(canvas, ctx);
initParticles();
draw(canvas, ctx);
}
}
};
const initParticles = () => {
tick = 0;
// simplex = new SimplexNoise();
particleProps = new Float32Array(particlePropsLength);
for (let i = 0; i < particlePropsLength; i += particlePropCount) {
initParticle(i);
}
};
const initParticle = (i: number) => {
const canvas = canvasRef.current;
if (!canvas) return;
let x, y, vx, vy, life, ttl, speed, radius, hue;
x = rand(canvas.width);
y = center[1] + randRange(rangeY);
vx = 0;
vy = 0;
life = 0;
ttl = baseTTL + rand(rangeTTL);
speed = baseSpeed + rand(rangeSpeed);
radius = baseRadius + rand(rangeRadius);
hue = baseHue + rand(rangeHue);
particleProps.set([x, y, vx, vy, life, ttl, speed, radius, hue], i);
};
const draw = (canvas: HTMLCanvasElement, ctx: CanvasRenderingContext2D) => {
tick++;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = backgroundColor;
ctx.fillRect(0, 0, canvas.width, canvas.height);
drawParticles(ctx);
renderGlow(canvas, ctx);
renderToScreen(canvas, ctx);
window.requestAnimationFrame(() => draw(canvas, ctx));
};
const drawParticles = (ctx: CanvasRenderingContext2D) => {
for (let i = 0; i < particlePropsLength; i += particlePropCount) {
updateParticle(i, ctx);
}
};
const updateParticle = (i: number, ctx: CanvasRenderingContext2D) => {
const canvas = canvasRef.current;
if (!canvas) return;
let i2 = 1 + i,
i3 = 2 + i,
i4 = 3 + i,
i5 = 4 + i,
i6 = 5 + i,
i7 = 6 + i,
i8 = 7 + i,
i9 = 8 + i;
let n, x, y, vx, vy, life, ttl, speed, x2, y2, radius, hue;
x = particleProps[i];
y = particleProps[i2];
n = noise3D(x * xOff, y * yOff, tick * zOff) * noiseSteps * TAU;
vx = lerp(particleProps[i3], Math.cos(n), 0.5);
vy = lerp(particleProps[i4], Math.sin(n), 0.5);
life = particleProps[i5];
ttl = particleProps[i6];
speed = particleProps[i7];
x2 = x + vx * speed;
y2 = y + vy * speed;
radius = particleProps[i8];
hue = particleProps[i9];
drawParticle(x, y, x2, y2, life, ttl, radius, hue, ctx);
life++;
particleProps[i] = x2;
particleProps[i2] = y2;
particleProps[i3] = vx;
particleProps[i4] = vy;
particleProps[i5] = life;
(checkBounds(x, y, canvas) || life > ttl) && initParticle(i);
};
const drawParticle = (
x: number,
y: number,
x2: number,
y2: number,
life: number,
ttl: number,
radius: number,
hue: number,
ctx: CanvasRenderingContext2D
) => {
ctx.save();
ctx.lineCap = "round";
ctx.lineWidth = radius;
ctx.strokeStyle = `hsla(${hue},100%,60%,${fadeInOut(life, ttl)})`;
ctx.beginPath();
ctx.moveTo(x, y);
ctx.lineTo(x2, y2);
ctx.stroke();
ctx.closePath();
ctx.restore();
};
const checkBounds = (x: number, y: number, canvas: HTMLCanvasElement) => {
return x > canvas.width || x < 0 || y > canvas.height || y < 0;
};
const resize = (
canvas: HTMLCanvasElement,
ctx?: CanvasRenderingContext2D
) => {
const { innerWidth, innerHeight } = window;
canvas.width = innerWidth;
canvas.height = innerHeight;
center[0] = 0.5 * canvas.width;
center[1] = 0.5 * canvas.height;
};
const renderGlow = (
canvas: HTMLCanvasElement,
ctx: CanvasRenderingContext2D
) => {
ctx.save();
ctx.filter = "blur(8px) brightness(200%)";
ctx.globalCompositeOperation = "lighter";
ctx.drawImage(canvas, 0, 0);
ctx.restore();
ctx.save();
ctx.filter = "blur(4px) brightness(200%)";
ctx.globalCompositeOperation = "lighter";
ctx.drawImage(canvas, 0, 0);
ctx.restore();
};
const renderToScreen = (
canvas: HTMLCanvasElement,
ctx: CanvasRenderingContext2D
) => {
ctx.save();
ctx.globalCompositeOperation = "lighter";
ctx.drawImage(canvas, 0, 0);
ctx.restore();
};
useEffect(() => {
setup();
window.addEventListener("resize", () => {
const canvas = canvasRef.current;
const ctx = canvas?.getContext("2d");
if (canvas && ctx) {
resize(canvas, ctx);
}
});
}, []);
return (
<div className={cn("relative h-full w-full", props.containerClassName)}>
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
ref={containerRef}
className="absolute h-full w-full inset-0 z-0 bg-transparent flex items-center justify-center"
>
<canvas ref={canvasRef}></canvas>
</motion.div>
<div className={cn("relative z-10", props.className)}>
{props.children}
</div>
</div>
);
};

View File

@ -72,7 +72,7 @@ services:
DASHBOARD_PASSWORD: ${DASHBOARD_PASSWORD} DASHBOARD_PASSWORD: ${DASHBOARD_PASSWORD}
volumes: volumes:
# https://github.com/supabase/supabase/issues/12661 # https://github.com/supabase/supabase/issues/12661
- ./volumes/api/kong.yml:/home/kong/temp.yml:ro - ./volumes/api/kong.yml:kong/temp.yml:ro
auth: auth:
container_name: supabase-auth container_name: supabase-auth

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More