Add log in, images page, start mum's sim
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
const nextConfig = {
|
||||
swcMinify: true,
|
||||
reactStrictMode: true,
|
||||
output: "standalone"
|
||||
output: "standalone",
|
||||
};
|
||||
|
||||
export default nextConfig;
|
||||
|
||||
1423
package-lock.json
generated
1423
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -18,18 +18,23 @@
|
||||
"@types/node": "^20.11.30",
|
||||
"@types/react": "^18.2.73",
|
||||
"@types/react-dom": "^18.2.23",
|
||||
"@typescript-eslint/eslint-plugin": "^7.4.0",
|
||||
"@typescript-eslint/eslint-plugin": "^6.21.0",
|
||||
"autoprefixer": "^10.4.19",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-next": "14.1.4",
|
||||
"exif-reader": "^2.0.1",
|
||||
"framer-motion": "^11.0.23",
|
||||
"glob": "^10.3.12",
|
||||
"million": "^3.0.6",
|
||||
"next": "14.1.4",
|
||||
"next-auth": "^4.24.7",
|
||||
"postcss": "^8.4.38",
|
||||
"radash": "^12.1.0",
|
||||
"react": "^18.2.0",
|
||||
"react-datocms": "^5.0.3",
|
||||
"react-dom": "^18.2.0",
|
||||
"server-only": "^0.0.1",
|
||||
"sharp": "^0.33.3",
|
||||
"tailwind-scrollbar": "^3.1.0",
|
||||
"tailwindcss": "^3.4.3",
|
||||
"typescript": "^5.4.3"
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>
|
||||
|
Before Width: | Height: | Size: 1.3 KiB |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 283 64"><path fill="black" d="M141 16c-11 0-19 7-19 18s9 18 20 18c7 0 13-3 16-7l-7-5c-2 3-6 4-9 4-5 0-9-3-10-7h28v-3c0-11-8-18-19-18zm-9 15c1-4 4-7 9-7s8 3 9 7h-18zm117-15c-11 0-19 7-19 18s9 18 20 18c6 0 12-3 16-7l-8-5c-2 3-5 4-8 4-5 0-9-3-11-7h28l1-3c0-11-8-18-19-18zm-10 15c2-4 5-7 10-7s8 3 9 7h-19zm-39 3c0 6 4 10 10 10 4 0 7-2 9-5l8 5c-3 5-9 8-17 8-11 0-19-7-19-18s8-18 19-18c8 0 14 3 17 8l-8 5c-2-3-5-5-9-5-6 0-10 4-10 10zm83-29v46h-9V5h9zM37 0l37 64H0L37 0zm92 5-27 48L74 5h10l18 30 17-30h10zm59 12v10l-3-1c-6 0-10 4-10 10v15h-9V17h9v9c0-5 6-9 13-9z"/></svg>
|
||||
|
Before Width: | Height: | Size: 629 B |
@@ -4,6 +4,7 @@ import "./globals.css";
|
||||
|
||||
import NavBar from '@/components/navbar';
|
||||
import Footer from '@/components/footer';
|
||||
import LogIn from "@/components/auth/login";
|
||||
|
||||
const inter = Inter({
|
||||
subsets: ['latin'],
|
||||
@@ -23,7 +24,7 @@ export default function RootLayout({
|
||||
return (
|
||||
<html className={`${inter.variable} font-sans`} lang="en">
|
||||
<body className="min-h-screen flex flex-col bg-dracula-bg">
|
||||
<NavBar/>
|
||||
<NavBar LogIn={<LogIn/>}/>
|
||||
<main className="px-6 py-4 w-full mx-auto flex-1 align-middle lg:max-w-5xl">
|
||||
{children}
|
||||
</main>
|
||||
|
||||
@@ -1,31 +1,9 @@
|
||||
import Sim from '@/components/sim';
|
||||
|
||||
export default function Home(): JSX.Element {
|
||||
const len = Array.from({length: 0});
|
||||
return (
|
||||
<div>
|
||||
{len.map(() =>
|
||||
<p className='prose prose-invert max-w-none'>
|
||||
Excepteur aliquip voluptate minim quis velit id. Do quis incididunt tempor deserunt consectetur est velit reprehenderit pariatur aliquip mollit elit magna. Do occaecat ex labore tempor laboris ut. Sit aliquip ex consequat in adipisicing duis tempor. Esse adipisicing aliqua exercitation ullamco do. Do nostrud ullamco tempor amet cillum ex Lorem irure culpa proident.
|
||||
|
||||
Consequat dolor officia velit non pariatur ea quis duis tempor. Nisi adipisicing elit exercitation tempor aute deserunt consectetur. Labore proident excepteur enim minim ullamco labore. Ad ea minim in ut.
|
||||
|
||||
Minim laborum sit laborum commodo esse sint veniam deserunt. Nisi voluptate cupidatat consequat quis aute ex ut nisi enim aliquip consequat. Culpa dolore labore anim ut. Veniam pariatur velit nulla sit culpa.
|
||||
|
||||
Dolor incididunt ut consequat nostrud nostrud sit quis nostrud aliquip. Do officia voluptate qui qui officia quis in in laborum reprehenderit adipisicing. Exercitation ex proident cupidatat ut culpa. Ullamco officia deserunt esse commodo sint est ut labore tempor. Pariatur commodo proident voluptate excepteur ipsum velit consequat officia cillum eu nulla tempor duis. Consequat deserunt tempor nostrud quis officia aliqua mollit ea duis veniam.
|
||||
|
||||
Consectetur sint est ad voluptate quis nisi adipisicing cillum in. Non nostrud et proident nisi eu ullamco eiusmod et excepteur esse exercitation adipisicing exercitation ex. Dolore sit esse voluptate aliquip non eiusmod ex proident adipisicing voluptate aute sit culpa. Consequat non labore aute consectetur magna. Irure anim tempor aliquip mollit do nisi reprehenderit nulla cupidatat amet.
|
||||
|
||||
Ea sunt aliqua proident sit labore quis eiusmod velit adipisicing cillum aute magna. Incididunt ullamco labore cupidatat do veniam pariatur mollit duis dolor velit ut enim. Occaecat voluptate culpa cupidatat nulla veniam dolore quis consequat ea. Cupidatat non commodo occaecat incididunt nostrud eu aute nostrud pariatur velit ullamco aliqua et. Velit culpa qui ipsum ex. Eu irure veniam excepteur eu. Magna Lorem do elit non.
|
||||
|
||||
Ut fugiat eiusmod culpa ipsum enim do. In ipsum aute mollit nostrud incididunt laborum do voluptate amet tempor labore aute anim. Ea eiusmod consequat occaecat qui Lorem non esse.
|
||||
|
||||
Officia aute et aliqua laborum reprehenderit. Lorem excepteur deserunt dolor eu pariatur consequat veniam. Labore sint fugiat labore aliquip cupidatat cillum adipisicing ullamco eu amet consequat. Reprehenderit et est magna nostrud.
|
||||
|
||||
Amet mollit Lorem enim officia voluptate ipsum reprehenderit commodo aliqua adipisicing id culpa deserunt. Consequat nulla tempor tempor nisi deserunt nulla magna dolor duis id nostrud laborum dolor. Exercitation aute anim in aliqua sunt ea laborum anim dolore veniam pariatur. Voluptate enim tempor officia minim excepteur fugiat ullamco.
|
||||
|
||||
Do labore Lorem in officia incididunt velit id laborum ut magna pariatur officia cillum. Voluptate dolor ullamco commodo occaecat ex magna ex esse. Aliqua velit sint eu ipsum dolore in incididunt mollit eiusmod voluptate. Pariatur do voluptate adipisicing voluptate anim ad ipsum. Lorem qui nisi officia ullamco sunt duis enim amet ea cillum deserunt quis. Eu sunt sit enim ipsum.
|
||||
</p>
|
||||
)}
|
||||
|
||||
</div>
|
||||
<>
|
||||
<Sim/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
68
src/app/photos/page.tsx
Normal file
68
src/app/photos/page.tsx
Normal file
@@ -0,0 +1,68 @@
|
||||
import Image from "next/image";
|
||||
import { glob } from "glob";
|
||||
import sharp from 'sharp';
|
||||
import exifReader from 'exif-reader';
|
||||
import { pick } from 'radash';
|
||||
|
||||
type ImageData = {
|
||||
width: number,
|
||||
height: number,
|
||||
blur: string,
|
||||
src: string,
|
||||
exif: Partial<{
|
||||
ExposureProgram: number,
|
||||
ExposureBiasValue: number,
|
||||
FNumber: number,
|
||||
ISOSpeedRatings: number,
|
||||
FocalLength: number,
|
||||
DateTimeOriginal: Date,
|
||||
LensModel: string
|
||||
}>
|
||||
}
|
||||
|
||||
export async function getImages(): Promise<{images: ImageData[]}> {
|
||||
const photosGlob = await glob(`public/photos/**/*.{png,jpeg,jpg}`, {
|
||||
nodir: true,
|
||||
});
|
||||
const images = photosGlob.map(async (fileName) => {
|
||||
const { width, height, exif } = await sharp(fileName).metadata();
|
||||
const blur = await sharp(fileName)
|
||||
.resize({ width: 10, height: 10, fit: 'inside' })
|
||||
.toBuffer();
|
||||
const exifData = exif ? exifReader(exif) : undefined;
|
||||
return {
|
||||
width: width ?? 10,
|
||||
height: height ?? 10,
|
||||
blur: blur.toString('base64'),
|
||||
src: fileName.slice(6),
|
||||
exif: pick(exifData?.Photo ?? {}, ['ExposureProgram', 'ExposureBiasValue', 'FNumber', 'ISOSpeedRatings', 'FocalLength', 'DateTimeOriginal', 'LensModel'])
|
||||
};
|
||||
});
|
||||
|
||||
return { images: await Promise.all(images) };
|
||||
}
|
||||
|
||||
export default async function Home(): Promise<JSX.Element> {
|
||||
const { images } = await getImages();
|
||||
|
||||
|
||||
return (
|
||||
<div className="grid gap-2 grid-cols-3">
|
||||
{images.map((image) => (
|
||||
<div className="relative" key={image.src}>
|
||||
<Image
|
||||
alt={image.src}
|
||||
src={image.src}
|
||||
className="object-contain h-auto w-full"
|
||||
sizes="(min-width: 808px) 50vw, 100vw"
|
||||
loading="lazy"
|
||||
width={image.width}
|
||||
height={image.height}
|
||||
blurDataURL={`data:image/jpeg;base64,${image.blur}`}
|
||||
placeholder={`data:image/jpeg;base64,${image.blur}`}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -3,7 +3,7 @@ import { LoginButton } from "./login_button";
|
||||
import { LogoutButton } from "./logout_button";
|
||||
|
||||
/**
|
||||
* This is a server component, then the buttons are client
|
||||
* This is a server component, then the buttons are client side
|
||||
*/
|
||||
export default async function LogIn(): Promise<JSX.Element | undefined> {
|
||||
const session = await auth();
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
'use client';
|
||||
import { useState } from 'react';
|
||||
import Link from 'next/link';
|
||||
import { HomeModernIcon, Bars3Icon, XMarkIcon, UserCircleIcon } from '@heroicons/react/24/outline';
|
||||
import { HomeModernIcon, Bars3Icon, XMarkIcon } from '@heroicons/react/24/outline';
|
||||
import { AnimatePresence, m, LazyMotion, domAnimation } from "framer-motion";
|
||||
import LogIn from './auth/login';
|
||||
|
||||
const navigation = [
|
||||
{ name: 'Blog', href: '#', current: true },
|
||||
{ name: 'Projects', href: '#', current: false },
|
||||
{ name: 'Photos', href: '#', current: false },
|
||||
{ name: 'Photos', href: '/photos', current: false },
|
||||
{ name: 'CV', href: '#', current: false },
|
||||
{ name: 'Contact', href: '#', current: false },
|
||||
];
|
||||
|
||||
export default function NavBar(): JSX.Element {
|
||||
export default function NavBar({LogIn}: {LogIn: JSX.Element}): JSX.Element {
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
return (
|
||||
@@ -49,7 +48,7 @@ export default function NavBar(): JSX.Element {
|
||||
</div>
|
||||
<div>
|
||||
</div>
|
||||
<LogIn/>
|
||||
{LogIn}
|
||||
</div>
|
||||
</div>
|
||||
<AnimatePresence>
|
||||
|
||||
149
src/components/sim.tsx
Normal file
149
src/components/sim.tsx
Normal file
@@ -0,0 +1,149 @@
|
||||
"use client";
|
||||
|
||||
import { shuffle } from "radash";
|
||||
import { FormEvent, useState, useRef, useCallback, useEffect } from "react";
|
||||
|
||||
export default function Sim(): JSX.Element {
|
||||
const [outputs, setOutputs] = useState<
|
||||
{ runs: number; tickets: number; totalWin: number }[]
|
||||
>([]);
|
||||
|
||||
const workerRef = useRef<Worker>();
|
||||
|
||||
useEffect(() => {
|
||||
workerRef.current = new Worker(
|
||||
new URL("../workers/sim.ts", import.meta.url)
|
||||
);
|
||||
workerRef.current.onmessage = (event) =>
|
||||
console.log(`WebWorker Response => ${JSON.stringify(event.data)}`);
|
||||
return () => {
|
||||
workerRef.current?.terminate();
|
||||
};
|
||||
}, []);
|
||||
|
||||
function runCalc(opts: {
|
||||
prizes: number[];
|
||||
fee: number;
|
||||
ticketsAlreadySold: number;
|
||||
ticketsTotal: number;
|
||||
}): void {
|
||||
const totalPrizePool = opts.prizes.reduce((total, prize) => {
|
||||
return total + prize;
|
||||
}, 0);
|
||||
|
||||
const ticketsToBuy = 1;
|
||||
|
||||
const ret =
|
||||
(totalPrizePool - opts.fee * ticketsToBuy) / ticketsAlreadySold +
|
||||
ticketsToBuy;
|
||||
const worth = ret > opts.fee;
|
||||
return worth;
|
||||
}
|
||||
|
||||
const runSim = (
|
||||
runs: number,
|
||||
tickets: number
|
||||
): Promise<{ runs: number; tickets: number; totalWin: number }> => {
|
||||
return new Promise((resolve) => {
|
||||
const allWinnings = [];
|
||||
|
||||
for (let i = 0; i < runs; i++) {
|
||||
let winnings = 0;
|
||||
|
||||
const soldTickets = shuffle(
|
||||
Array.from({ length: tickets }).map((_, index) => index)
|
||||
);
|
||||
const prizes = shuffle([500, 350, 150]);
|
||||
|
||||
while (prizes.length > 0) {
|
||||
const drawnTicket = soldTickets.pop();
|
||||
if (drawnTicket) {
|
||||
const thisWin = prizes.pop() ?? 0;
|
||||
if (drawnTicket < tickets) {
|
||||
winnings += thisWin;
|
||||
}
|
||||
}
|
||||
}
|
||||
allWinnings.push(winnings);
|
||||
}
|
||||
const totalWin = allWinnings.reduce((total, win) => {
|
||||
return total + win;
|
||||
}, 0);
|
||||
|
||||
resolve({
|
||||
runs,
|
||||
tickets,
|
||||
totalWin,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
function onSubmit(event: FormEvent<HTMLFormElement>): void {
|
||||
event.preventDefault();
|
||||
const formData = new FormData(event.currentTarget);
|
||||
const opts = {
|
||||
prizes: formData.get("prizes"),
|
||||
prizes: formData.get("fee"),
|
||||
prizes: formData.get("ticketsAlreadySold"),
|
||||
prizes: formData.get("ticketsTotal"),
|
||||
};
|
||||
const wrapper = async (): Promise<void> => {
|
||||
if ((runs ?? 0) > 0 && (tickets ?? 0) > 0) {
|
||||
workerRef.current?.postMessage(opts);
|
||||
//const output = await runSim(runs, tickets);
|
||||
//setOutputs([...outputs, output]);
|
||||
}
|
||||
};
|
||||
void wrapper();
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<form className="text-white" onSubmit={onSubmit}>
|
||||
<label>Prizes</label>
|
||||
<br />
|
||||
<input className="text-black" type="text" name="prizes" />
|
||||
<br />
|
||||
<label>Fee</label>
|
||||
<br />
|
||||
<input className="text-black" type="text" name="fee" />
|
||||
<br />
|
||||
<label>Tickets sold</label>
|
||||
<br />
|
||||
<input className="text-black" type="text" name="ticketsAlreadySold" />
|
||||
<br />
|
||||
<label>Tickets total</label>
|
||||
<br />
|
||||
<input className="text-black" type="text" name="ticketsTotal" />
|
||||
<br />
|
||||
<button className="p-2 bg-dracula-bglighter rounded-sm" type="submit">
|
||||
Run
|
||||
</button>
|
||||
<br />
|
||||
</form>
|
||||
<br />
|
||||
{outputs.length ? (
|
||||
<table className={"text-white"}>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Runs</th>
|
||||
<th>Tickets</th>
|
||||
<th>Winnings</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{outputs.map((output, index) => {
|
||||
return (
|
||||
<tr key={index}>
|
||||
<td>{output.runs}</td>
|
||||
<td>{output.tickets}</td>
|
||||
<td>{output.totalWin}</td>
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
) : null}
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'server-only';
|
||||
import "server-only";
|
||||
import { getServerSession } from "next-auth";
|
||||
import CognitoProvider from "next-auth/providers/cognito";
|
||||
import type { GetServerSidePropsContext, NextApiRequest, NextApiResponse } from "next";
|
||||
|
||||
3
src/workers/sim.ts
Normal file
3
src/workers/sim.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
addEventListener('message', (event) => {
|
||||
postMessage({ received: true, ...event.data });
|
||||
});
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
|
||||
Reference in New Issue
Block a user