wave canvas styling fix + links righthand bar
This commit is contained in:
@@ -1,90 +1,42 @@
|
|||||||
import {motion} from "framer-motion";
|
import {motion} from "framer-motion";
|
||||||
import "./canvas.scss";
|
import "./canvas.scss";
|
||||||
import {Canvas as ThreeCanvas, useFrame} from "@react-three/fiber";
|
import {Canvas as ThreeCanvas, useFrame} from "@react-three/fiber";
|
||||||
import React, {useMemo, useRef} from "react";
|
import React, {useMemo, useRef, useState} from "react";
|
||||||
import {Mesh, Vector3} from "three";
|
import {Mesh, Vector3} from "three";
|
||||||
import {Moon} from "./Moon";
|
import {Moon} from "./Moon";
|
||||||
|
import {Stars} from "./Stars";
|
||||||
|
|
||||||
type Coordinate = [number, number, number];
|
|
||||||
export default function Canvas() {
|
export default function Canvas() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main>
|
<main>
|
||||||
<ThreeCanvas gl={{antialias: true, alpha: true}} >
|
<ThreeCanvas gl={{antialias: true, alpha: true}} >
|
||||||
<Sphere/>
|
<Sphere/>
|
||||||
<Frame/>
|
|
||||||
<Moon radius={8} color="pink" step={0.01}/>
|
<Moon radius={8} color="pink" step={0.01}/>
|
||||||
<Moon radius={6} color="grey" step={0.02}/>
|
<Moon radius={6} color="grey" step={0.02}/>
|
||||||
<Moon radius={4} color="green" step={0.03}/>
|
<Moon radius={4} color="green" step={0.03}/>
|
||||||
<Stars/>
|
<Stars/>
|
||||||
<directionalLight color="#E3A857" args={[1,10]} position={[100,10,100]} />
|
<directionalLight color="#E3A857" args={[1,10]} position={[100,10,100]} />
|
||||||
</ThreeCanvas>
|
</ThreeCanvas>
|
||||||
<motion.h1 className="welcome" animate={{ rotate: 360 }}>
|
<motion.h2 className="welcome" animate={{ rotate: 360 }}>
|
||||||
Welcome to my blog
|
Welcome to my blog
|
||||||
</motion.h1>
|
</motion.h2>
|
||||||
</main>
|
</main>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function Frame() {
|
function Sphere() {
|
||||||
useFrame(state => {
|
useFrame(state => {
|
||||||
const { x, y } = state.pointer
|
const { x, y } = state.pointer
|
||||||
|
|
||||||
// Smoothly interpolate the camera position
|
// Smoothly interpolate the camera position
|
||||||
// We multiply by a factor (e.g., 5) to increase the range of movement
|
// We multiply by a factor (e.g., 5) to increase the range of movement
|
||||||
state.camera.position.lerp(new Vector3(x * 10, y * 10, 5), 0.1)
|
state.camera.position.lerp(new Vector3(x * 10, y * 10, 5), 0.1)
|
||||||
|
|
||||||
// Always keep the camera looking at the center
|
// Always keep the camera looking at the center
|
||||||
state.camera.lookAt(0, 0, 0)
|
state.camera.lookAt(0, 0, 0)
|
||||||
})
|
})
|
||||||
|
|
||||||
return <></>
|
return <mesh position={[0,0,0]}>
|
||||||
}
|
<sphereGeometry />
|
||||||
|
<meshPhysicalMaterial color="blue" iridescence={.5} />
|
||||||
function Sphere() {
|
</mesh>
|
||||||
const meshRef = useRef<Mesh>(null);
|
|
||||||
|
|
||||||
useFrame(() => {
|
|
||||||
if(meshRef.current) {
|
|
||||||
meshRef.current.rotation.y += 0.01
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<mesh ref={meshRef} position={[0,0,0]}>
|
|
||||||
<sphereGeometry />
|
|
||||||
<meshPhysicalMaterial color="blue" iridescence={.5} />
|
|
||||||
</mesh>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const RADIUS = 20;
|
|
||||||
const COUNT = 100;
|
|
||||||
function Stars() {
|
|
||||||
const positions = useMemo(() => {
|
|
||||||
const positions: Coordinate[] = [];
|
|
||||||
for(let i = 0; i < COUNT; i++) {
|
|
||||||
const u = Math.random();
|
|
||||||
const v = Math.random();
|
|
||||||
|
|
||||||
const theta = 2 * Math.PI * u;
|
|
||||||
const phi = Math.acos(2 * v - 1);
|
|
||||||
|
|
||||||
// x = r*sin(theta)*cos(phi)
|
|
||||||
// x = r*sin(theta)*sin(phi)
|
|
||||||
// z = r*cos(phi)
|
|
||||||
positions.push([
|
|
||||||
RADIUS * Math.sin(phi) * Math.cos(theta),
|
|
||||||
RADIUS * Math.sin(phi) * Math.sin(theta),
|
|
||||||
RADIUS * Math.cos(phi),
|
|
||||||
])
|
|
||||||
}
|
|
||||||
return positions;
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return positions.map(coord => <mesh position={coord}>
|
|
||||||
<sphereGeometry args={[.1]} />
|
|
||||||
<meshBasicMaterial />
|
|
||||||
</mesh>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
33
src/index/Stars.tsx
Normal file
33
src/index/Stars.tsx
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import {useMemo} from "react";
|
||||||
|
|
||||||
|
const RADIUS = 20;
|
||||||
|
const COUNT = 100;
|
||||||
|
type Coordinate = [number, number, number];
|
||||||
|
export function Stars() {
|
||||||
|
const positions = useMemo(() => {
|
||||||
|
const positions: Coordinate[] = [];
|
||||||
|
for(let i = 0; i < COUNT; i++) {
|
||||||
|
const u = Math.random();
|
||||||
|
const v = Math.random();
|
||||||
|
|
||||||
|
const theta = 2 * Math.PI * u;
|
||||||
|
const phi = Math.acos(2 * v - 1);
|
||||||
|
|
||||||
|
// x = r*sin(theta)*cos(phi)
|
||||||
|
// x = r*sin(theta)*sin(phi)
|
||||||
|
// z = r*cos(phi)
|
||||||
|
positions.push([
|
||||||
|
RADIUS * Math.sin(phi) * Math.cos(theta),
|
||||||
|
RADIUS * Math.sin(phi) * Math.sin(theta),
|
||||||
|
RADIUS * Math.cos(phi),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
return positions;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return positions.map(coord => <mesh position={coord}>
|
||||||
|
<sphereGeometry args={[.1]} />
|
||||||
|
<meshBasicMaterial />
|
||||||
|
</mesh>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -12,5 +12,5 @@ main {
|
|||||||
.welcome {
|
.welcome {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 50%;
|
top: calc(50% + 50px);
|
||||||
}
|
}
|
||||||
21
src/nav/Links.tsx
Normal file
21
src/nav/Links.tsx
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import React, {useState} from "react";
|
||||||
|
import {Link} from "../router/Link";
|
||||||
|
import {motion} from "framer-motion";
|
||||||
|
|
||||||
|
export function Links() {
|
||||||
|
const [links, setLinks] = useState(["About", "Articles"]);
|
||||||
|
|
||||||
|
return <div className="links">
|
||||||
|
{ links.map(() => /* add spacers for flexbox */ <div/> )}
|
||||||
|
<Title/>
|
||||||
|
{ links.map(link => <Link href={`/${link}`}><h3>{link}</h3></Link>) }
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
function Title() {
|
||||||
|
return (
|
||||||
|
<Link href="/" className="name">
|
||||||
|
<motion.h1 className="name">Tymur Arsentiev</motion.h1>
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -6,15 +6,16 @@ import wave from "../img/menu-wave.svg";
|
|||||||
import "./nav.scss";
|
import "./nav.scss";
|
||||||
import {motion} from "framer-motion";
|
import {motion} from "framer-motion";
|
||||||
import {Link} from "../router/Link";
|
import {Link} from "../router/Link";
|
||||||
|
import {Path} from "../router/router";
|
||||||
|
import {Links} from "./Links";
|
||||||
|
|
||||||
export default function Nav() {
|
export default function Nav() {
|
||||||
const [active, setActive] = useState(false);
|
const [active, setActive] = useState(false);
|
||||||
|
|
||||||
return <>
|
return <>
|
||||||
<nav className="header">
|
<nav>
|
||||||
<MenuButton active={active} setActive={setActive}/>
|
<MenuButton active={active} setActive={setActive}/>
|
||||||
<Title/>
|
<Links/>
|
||||||
<Link href="/about" className="nav-item">About</Link>
|
|
||||||
</nav>
|
</nav>
|
||||||
<Menu active={active}/>
|
<Menu active={active}/>
|
||||||
<img className="wave" alt="wave" src={wave}/>
|
<img className="wave" alt="wave" src={wave}/>
|
||||||
@@ -34,11 +35,3 @@ function MenuButton(props : { active: boolean, setActive: (_:boolean) => void })
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function Title() {
|
|
||||||
return (
|
|
||||||
<Link href="/" className="name">
|
|
||||||
<motion.h1>Tymur Arsentiev</motion.h1>
|
|
||||||
</Link>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,16 +1,16 @@
|
|||||||
$padding: 15px;
|
$padding: 15px;
|
||||||
$menu: #282c34;
|
$menu: #282c34;
|
||||||
|
|
||||||
.menu-btn:hover {
|
.menu-btn>button:hover {
|
||||||
opacity: 90%;
|
opacity: 90%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu-btn:active {
|
.menu-btn>button:active {
|
||||||
opacity: 80%;
|
opacity: 80%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu-btn {
|
.menu-btn {
|
||||||
justify-self: center;
|
align-self: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -19,29 +19,35 @@ $menu: #282c34;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.name {
|
nav {
|
||||||
position: absolute;
|
|
||||||
font-weight: bold;
|
|
||||||
left: 50%;
|
|
||||||
transform: translateX(-50%);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.header {
|
|
||||||
background-color: $menu;
|
background-color: $menu;
|
||||||
padding: $padding;
|
padding: $padding;
|
||||||
display: flex;
|
display: flex;
|
||||||
font-size: calc(10px + 2vmin);
|
justify-content: center;
|
||||||
color: white;
|
}
|
||||||
min-height: 3 * $padding;
|
|
||||||
|
nav>a{
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.name>h1 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.name {
|
.name {
|
||||||
align-self: center;
|
margin: auto;
|
||||||
flex-grow: 1;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wave {
|
.wave {
|
||||||
user-select: none;
|
user-select: none;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.links {
|
||||||
|
display: flex;
|
||||||
|
flex-grow: 1;
|
||||||
|
gap: 15px;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user