Minor improvements
This commit is contained in:
@@ -95,5 +95,5 @@
|
||||
"name": "Algiers"
|
||||
}
|
||||
],
|
||||
"color": "rgb(196,172,76)"
|
||||
"color": "rgb(100,100,100)"
|
||||
}
|
||||
|
||||
@@ -82,5 +82,5 @@
|
||||
"name": "Fábrica de Moneda de Ibagué"
|
||||
}
|
||||
],
|
||||
"color": "rgb(153,134.05714285714288,102)"
|
||||
"color": "rgb(45, 30, 20)"
|
||||
}
|
||||
|
||||
@@ -1,52 +1,26 @@
|
||||
import * as THREE from "three";
|
||||
import { useLoader } from "@react-three/fiber";
|
||||
import { CoinProps } from "@/types/coin";
|
||||
import { Suspense, useEffect, useMemo } from "react";
|
||||
import { useEffect, useMemo } from "react";
|
||||
|
||||
const SafeEdgeMaterial = ({
|
||||
color,
|
||||
edge,
|
||||
}: Pick<CoinProps, "edge" | "color">) => {
|
||||
try {
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
const edgeTexture: THREE.Texture = useLoader(
|
||||
THREE.TextureLoader,
|
||||
edge.picture,
|
||||
);
|
||||
edgeTexture.repeat = new THREE.Vector2(2, 1);
|
||||
edgeTexture.offset = new THREE.Vector2(0.5, 0);
|
||||
edgeTexture.wrapS = THREE.MirroredRepeatWrapping;
|
||||
edgeTexture.wrapT = THREE.MirroredRepeatWrapping;
|
||||
const SafeEdgeMaterial = ({ edge }: Pick<CoinProps, "edge">) => {
|
||||
const edgeTexture: THREE.Texture = useLoader(
|
||||
THREE.TextureLoader,
|
||||
edge.picture,
|
||||
);
|
||||
edgeTexture.repeat = new THREE.Vector2(4, 1);
|
||||
edgeTexture.offset = new THREE.Vector2(0.5, 0);
|
||||
edgeTexture.wrapS = THREE.MirroredRepeatWrapping;
|
||||
edgeTexture.wrapT = THREE.MirroredRepeatWrapping;
|
||||
|
||||
return (
|
||||
<Suspense
|
||||
fallback={
|
||||
<meshStandardMaterial
|
||||
metalness={1}
|
||||
roughness={0.5}
|
||||
color={color}
|
||||
attach="material-0"
|
||||
/>
|
||||
}
|
||||
>
|
||||
<meshStandardMaterial
|
||||
map={edgeTexture}
|
||||
metalness={1}
|
||||
roughness={0.5}
|
||||
attach="material-0"
|
||||
/>
|
||||
</Suspense>
|
||||
);
|
||||
} catch {
|
||||
return (
|
||||
<meshStandardMaterial
|
||||
metalness={1}
|
||||
roughness={0.5}
|
||||
color={color}
|
||||
attach="material-0"
|
||||
/>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<meshStandardMaterial
|
||||
map={edgeTexture}
|
||||
metalness={1}
|
||||
roughness={0.5}
|
||||
attach="material-0"
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const CoinInstance = ({
|
||||
@@ -55,16 +29,14 @@ export const CoinInstance = ({
|
||||
thickness,
|
||||
color,
|
||||
obverse,
|
||||
shape,
|
||||
reverse,
|
||||
edge,
|
||||
}: CoinProps) => {
|
||||
const sides = useMemo(() => {
|
||||
//const parsed = Number(/(\d+)/.exec(shape)?.[0]);
|
||||
//return Math.min(32, Math.max(4, isNaN(parsed) ? 32 : parsed));
|
||||
return 32;
|
||||
const parsed = Number(/(\d+)/.exec(shape)?.[0]);
|
||||
return Math.min(32, Math.max(4, isNaN(parsed) ? 32 : parsed));
|
||||
}, [shape]);
|
||||
//const edgeTexture = useLoader(THREE.TextureLoader, edge.picture);
|
||||
}, []);
|
||||
const obverseTexture: THREE.Texture = useLoader(
|
||||
THREE.TextureLoader,
|
||||
obverse.picture,
|
||||
@@ -92,13 +64,25 @@ export const CoinInstance = ({
|
||||
sides,
|
||||
]}
|
||||
/>
|
||||
<SafeEdgeMaterial color={color} edge={edge} />
|
||||
|
||||
{edge?.picture ? (
|
||||
<SafeEdgeMaterial edge={edge} />
|
||||
) : (
|
||||
<meshStandardMaterial
|
||||
metalness={1}
|
||||
roughness={0.5}
|
||||
color={color}
|
||||
attach="material-0"
|
||||
/>
|
||||
)}
|
||||
|
||||
<meshStandardMaterial
|
||||
metalness={1}
|
||||
roughness={0.5}
|
||||
map={obverseTexture}
|
||||
attach="material-1"
|
||||
/>
|
||||
|
||||
<meshStandardMaterial
|
||||
metalness={1}
|
||||
roughness={0.5}
|
||||
|
||||
@@ -5,6 +5,7 @@ import { InstancedMesh } from "three";
|
||||
import { useCylinder } from "@react-three/cannon";
|
||||
|
||||
export const CoinInstances = (coinProps: CoinProps) => {
|
||||
const didInit = useRef(false);
|
||||
const { count = 1, size = 16, thickness = 2, weight = 4 } = coinProps;
|
||||
|
||||
const [ref, { at }] = useCylinder(
|
||||
@@ -17,7 +18,10 @@ export const CoinInstances = (coinProps: CoinProps) => {
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
console.log("resetting");
|
||||
if (didInit.current) {
|
||||
return;
|
||||
}
|
||||
didInit.current = true;
|
||||
Array.from({ length: count }).forEach((_, index) => {
|
||||
at(index).position.set(
|
||||
8 * (Math.random() * 2 - 1),
|
||||
@@ -33,12 +37,7 @@ export const CoinInstances = (coinProps: CoinProps) => {
|
||||
}, [at, count]);
|
||||
|
||||
return (
|
||||
<instancedMesh
|
||||
receiveShadow
|
||||
castShadow
|
||||
ref={ref}
|
||||
args={[undefined, undefined, count]}
|
||||
>
|
||||
<instancedMesh ref={ref} args={[undefined, undefined, count]}>
|
||||
<CoinInstance {...coinProps} />
|
||||
</instancedMesh>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Canvas } from "@react-three/fiber";
|
||||
import { Canvas, PointLightProps } from "@react-three/fiber";
|
||||
import { OrbitControls } from "@react-three/drei";
|
||||
import { useRef } from "react";
|
||||
import { CoinInstances } from "./coin-instances";
|
||||
@@ -13,19 +13,33 @@ type Props = {
|
||||
const Plane = (props: PlaneProps) => {
|
||||
const [ref] = usePlane(() => ({ ...props }), useRef<Mesh>(null));
|
||||
return (
|
||||
<mesh ref={ref} receiveShadow>
|
||||
<mesh ref={ref}>
|
||||
<circleGeometry args={[64]} />
|
||||
<meshBasicMaterial color={"black"} />
|
||||
</mesh>
|
||||
);
|
||||
};
|
||||
|
||||
const Lightbulb = (props: PointLightProps) => (
|
||||
<>
|
||||
<pointLight {...props} />
|
||||
<mesh position={props.position}>
|
||||
<sphereGeometry args={[0.25]} />
|
||||
<meshBasicMaterial color="white" />
|
||||
</mesh>
|
||||
</>
|
||||
);
|
||||
|
||||
export const Pile = ({ coins }: Props) => (
|
||||
<Canvas shadows camera={{ position: [0, 16, 16] }}>
|
||||
<Canvas camera={{ position: [0, 16, 16] }}>
|
||||
<color attach="background" args={["#111"]} />
|
||||
<ambientLight />
|
||||
|
||||
<directionalLight castShadow position={[0, 1, 0]} />
|
||||
<Lightbulb position={[0, 16, 0]} />
|
||||
<Lightbulb position={[16, 0, 16]} />
|
||||
<Lightbulb position={[16, 0, -16]} />
|
||||
<Lightbulb position={[-16, 0, 16]} />
|
||||
<Lightbulb position={[-16, 0, -16]} />
|
||||
<Physics gravity={[0, -20, 0]}>
|
||||
<Plane rotation={[-Math.PI / 2, 0, 0]} position={[0, -2, 0]} />
|
||||
{coins.map((coinProps) => (
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { CoinProps } from "@/types/coin";
|
||||
import { Canvas, MeshProps, useFrame } from "@react-three/fiber";
|
||||
import { Suspense, useRef, useState } from "react";
|
||||
import { Suspense, useEffect, useRef, useState } from "react";
|
||||
import { CoinInstance } from "@/components/coin";
|
||||
import { Mesh } from "three";
|
||||
import { OrbitControls } from "@react-three/drei";
|
||||
import { BanknoteInstance } from "@/components/banknote";
|
||||
import { InfoBox } from "./info-box";
|
||||
|
||||
@@ -78,7 +77,7 @@ const Row = ({
|
||||
{types.map(
|
||||
(type, index) =>
|
||||
Math.abs(index - selectedIndex) <= 1 && (
|
||||
<Suspense key={type.id} fallback={"loading..."}>
|
||||
<Suspense key={type.id} fallback={null}>
|
||||
<SpinninType
|
||||
category={category}
|
||||
isSelected={selectedIndex === index}
|
||||
@@ -96,14 +95,28 @@ const Row = ({
|
||||
export const Showcase = (props: Props) => {
|
||||
const [selectedIndex, selectIndex] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
const onKeyDown = ({ key }: KeyboardEvent) => {
|
||||
switch (key) {
|
||||
case "ArrowLeft":
|
||||
return selectIndex((value) => Math.max(value - 1, 0));
|
||||
case "ArrowRight":
|
||||
return selectIndex((value) =>
|
||||
Math.min(value + 1, props.types.length - 1),
|
||||
);
|
||||
}
|
||||
};
|
||||
document.addEventListener("keydown", onKeyDown);
|
||||
return () => document.removeEventListener("keydown", onKeyDown);
|
||||
}, [props.types.length]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Canvas shadows>
|
||||
<Canvas>
|
||||
<color attach="background" args={["#111"]} />
|
||||
<ambientLight />
|
||||
<directionalLight position={[0, 0.125, 1]} />
|
||||
<Row {...props} selectedIndex={selectedIndex} />
|
||||
<OrbitControls />
|
||||
</Canvas>
|
||||
|
||||
<InfoBox
|
||||
|
||||
@@ -40,13 +40,17 @@ export const InfoBox = ({
|
||||
>
|
||||
<small>{type.issuer.name}</small>
|
||||
<h1 style={{ textAlign: "center" }}>{type.title}</h1>
|
||||
<p>{type.min_year + " - " + type.max_year}</p>
|
||||
<p>
|
||||
{type.min_year !== type.max_year
|
||||
? type.min_year + " - " + type.max_year
|
||||
: type.min_year}
|
||||
</p>
|
||||
<small>{(type.count ?? 1) + " in collection"}</small>
|
||||
{category === "coins" && (
|
||||
<>
|
||||
<p>{type.weight + "g"}</p>
|
||||
<p>{type.size + "mm"}</p>
|
||||
<p>{type.thickness + "mm"}</p>
|
||||
{type.weight && <p>{type.weight + "g"}</p>}
|
||||
{type.size && <p>{type.size + "mm"}</p>}
|
||||
{type.thickness && <p>{type.thickness + "mm"}</p>}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
@@ -66,6 +70,8 @@ export const InfoBox = ({
|
||||
{"<-"}
|
||||
</button>
|
||||
|
||||
<span>{selectedIndex + 1 + "/" + (maxIndex + 1)}</span>
|
||||
|
||||
<button
|
||||
disabled={selectedIndex >= maxIndex}
|
||||
style={{ flex: 1 }}
|
||||
|
||||
@@ -44,8 +44,6 @@ export const getStaticProps: GetStaticProps<Props> = async ({ params }) => {
|
||||
const coins = await getCountryCoins(params.country);
|
||||
const banknotes = await getCountryBanknotes(params.country);
|
||||
|
||||
console.log({ coins, banknotes });
|
||||
|
||||
return {
|
||||
props: {
|
||||
country: params.country,
|
||||
|
||||
@@ -8,10 +8,8 @@ html,
|
||||
body {
|
||||
max-width: 100vw;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
#scene-root {
|
||||
background-color: #111;
|
||||
color: white;
|
||||
}
|
||||
|
||||
#scene-root > div:first-child {
|
||||
|
||||
Reference in New Issue
Block a user