This commit is contained in:
0
.idea/jsLibraryMappings.xml
generated
Normal file
0
.idea/jsLibraryMappings.xml
generated
Normal file
@@ -1,4 +1,4 @@
|
||||
import openingImage from "../img/IMG_20240725_175449_803.jpg";
|
||||
import openingImage from "../img/DSC_5633.jpg";
|
||||
import rainbow from "../img/IMG-0186.jpg";
|
||||
import japanese from "../img/IMG_20230531_000224_01.jpg";
|
||||
import computers from "../img/IMG_3071.jpg";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import "./about.scss";
|
||||
import "./about.sass";
|
||||
import {HTMLProps, lazy} from "react";
|
||||
import {Link} from "../router/Link";
|
||||
import {Path} from "../router/router";
|
||||
|
||||
82
src/about/about.sass
Normal file
82
src/about/about.sass
Normal file
@@ -0,0 +1,82 @@
|
||||
@use "../nav/nav"
|
||||
$paragraph: 20px
|
||||
$max-width: 600px
|
||||
$min-width: 400px
|
||||
|
||||
.about-page
|
||||
color: white
|
||||
display: flex
|
||||
justify-content: center
|
||||
|
||||
.title
|
||||
text-align: center
|
||||
margin: nav.$padding
|
||||
|
||||
.self
|
||||
width: 100%
|
||||
border-bottom: white 4px solid
|
||||
|
||||
|
||||
.about-container
|
||||
min-width: $min-width
|
||||
flex-shrink: 1
|
||||
display: flex
|
||||
flex-direction: column
|
||||
align-items: center
|
||||
font-family: Neuton, serif
|
||||
line-height: 40px
|
||||
|
||||
img:not(.self)
|
||||
border: 2px white solid
|
||||
|
||||
p
|
||||
text-indent: 30px
|
||||
padding: nav.$padding
|
||||
max-width: $max-width
|
||||
font-size: $paragraph
|
||||
|
||||
h1
|
||||
font-size: $paragraph * 2
|
||||
padding: nav.$padding
|
||||
|
||||
h2
|
||||
font-size: $paragraph * 1.5
|
||||
padding: nav.$padding
|
||||
|
||||
h3
|
||||
font-size: $paragraph * 1.1
|
||||
font-weight: bold
|
||||
|
||||
.edge
|
||||
background: #27213C
|
||||
flex-grow: 1
|
||||
min-width: 30%
|
||||
|
||||
.clothing, .computers
|
||||
margin: 15px 0
|
||||
display: flex
|
||||
flex-direction: row
|
||||
justify-content: center
|
||||
|
||||
|
||||
.clothing>img
|
||||
width: 33%
|
||||
|
||||
|
||||
.computers
|
||||
// select second
|
||||
img:not(:first-child)
|
||||
width: 20%
|
||||
|
||||
img
|
||||
width: 30%
|
||||
|
||||
.external-link
|
||||
text-decoration: underline !important
|
||||
|
||||
ul
|
||||
display: flex
|
||||
flex-direction: column
|
||||
font-size: $paragraph
|
||||
max-width: $max-width
|
||||
gap: 10px
|
||||
@@ -1,93 +0,0 @@
|
||||
@use "../nav/nav.scss";
|
||||
$paragraph: 20px;
|
||||
$max-width: 600px;
|
||||
|
||||
.about-page {
|
||||
color: white;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.title {
|
||||
text-align: center;
|
||||
margin: nav.$padding;
|
||||
}
|
||||
|
||||
.self {
|
||||
width: 100%;
|
||||
border-bottom: white 4px solid;
|
||||
}
|
||||
|
||||
.about-container {
|
||||
margin-top: 2 * nav.$padding;
|
||||
flex-shrink: 1;
|
||||
max-width: 75%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
font-family: Neuton;
|
||||
line-height: 40px;
|
||||
|
||||
img:not(.self) {
|
||||
border: 2px white solid;
|
||||
}
|
||||
|
||||
p {
|
||||
text-indent: 30px;
|
||||
margin: 10px;
|
||||
max-width: $max-width;
|
||||
font-size: $paragraph;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: $paragraph * 2;
|
||||
}
|
||||
h2 {
|
||||
font-size: $paragraph * 1.5;
|
||||
}
|
||||
h3 {
|
||||
font-size: $paragraph * 1.1;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.edge {
|
||||
background:#27213C;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.clothing, .computers {
|
||||
margin: 15px 0;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.clothing>img {
|
||||
width: 33%;
|
||||
}
|
||||
|
||||
.computers {
|
||||
// select second
|
||||
img:not(:first-child) {
|
||||
width: 20%;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 30%;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
.external-link {
|
||||
text-decoration: underline !important;
|
||||
}
|
||||
|
||||
ul {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
font-size: $paragraph;
|
||||
max-width: $max-width;
|
||||
gap: 10px;
|
||||
}
|
||||
|
Before Width: | Height: | Size: 13 MiB After Width: | Height: | Size: 13 MiB |
|
Before Width: | Height: | Size: 5.6 MiB After Width: | Height: | Size: 5.6 MiB |
1
src/img/blog-box.svg
Normal file
1
src/img/blog-box.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1440 320"><path fill="#282c34" fill-opacity="1" d="M0,192L30,186.7C60,181,120,171,180,149.3C240,128,300,96,360,106.7C420,117,480,171,540,186.7C600,203,660,181,720,154.7C780,128,840,96,900,122.7C960,149,1020,235,1080,245.3C1140,256,1200,192,1260,186.7C1320,181,1380,235,1410,261.3L1440,288L1440,0L1410,0C1380,0,1320,0,1260,0C1200,0,1140,0,1080,0C1020,0,960,0,900,0C840,0,780,0,720,0C660,0,600,0,540,0C480,0,420,0,360,0C300,0,240,0,180,0C120,0,60,0,30,0L0,0Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 524 B |
27
src/index.sass
Normal file
27
src/index.sass
Normal file
@@ -0,0 +1,27 @@
|
||||
$phone: 750px
|
||||
|
||||
html, body
|
||||
margin: 0
|
||||
padding: 0
|
||||
font-family: Inter, sans-serif
|
||||
-webkit-font-smoothing: antialiased
|
||||
-moz-osx-font-smoothing: grayscale
|
||||
|
||||
#root
|
||||
display: flex
|
||||
flex-direction: column
|
||||
min-height: 100vh
|
||||
background: black
|
||||
color: white
|
||||
|
||||
// disable image dragging
|
||||
img
|
||||
user-select: none
|
||||
pointer-events: none
|
||||
|
||||
button
|
||||
background: none
|
||||
border: none
|
||||
padding: 0
|
||||
color: white
|
||||
cursor: pointer
|
||||
@@ -1,30 +0,0 @@
|
||||
body {
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: black;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
||||
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
||||
sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
color: white;
|
||||
}
|
||||
|
||||
// disable image dragging
|
||||
img {
|
||||
user-select: none;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
||||
monospace;
|
||||
}
|
||||
|
||||
button {
|
||||
background: none;
|
||||
border: none;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import './index.scss';
|
||||
import './index.sass';
|
||||
import {RouterProvider} from "./router/RouterContext";
|
||||
import "@fontsource/inter"; // Defaults to weight 400
|
||||
import "@fontsource/neuton";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import "./canvas.sass";
|
||||
import {motion} from "framer-motion";
|
||||
import "./canvas.scss";
|
||||
import {Canvas as ThreeCanvas, useFrame} from "@react-three/fiber";
|
||||
import {Vector3} from "three";
|
||||
import {Moon} from "./Moon";
|
||||
@@ -9,7 +9,8 @@ export default function Canvas() {
|
||||
|
||||
return (
|
||||
<main className="canvas">
|
||||
<ThreeCanvas gl={{antialias: true, alpha: true}} >
|
||||
<section className="canvas-ctr">
|
||||
<ThreeCanvas shadows>
|
||||
<Sphere/>
|
||||
<Moon radius={8} color="pink" step={0.01}/>
|
||||
<Moon radius={6} color="grey" step={0.02}/>
|
||||
@@ -17,9 +18,10 @@ export default function Canvas() {
|
||||
<Stars/>
|
||||
<directionalLight color="#E3A857" args={[1,10]} position={[100,10,100]} />
|
||||
</ThreeCanvas>
|
||||
<motion.h2 className="welcome" animate={{ rotate: 360 }}>
|
||||
</section>
|
||||
<motion.h1 className="welcome" animate={{ rotate: 360 }}>
|
||||
Welcome to my blog
|
||||
</motion.h2>
|
||||
</motion.h1>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
|
||||
18
src/index/canvas.sass
Normal file
18
src/index/canvas.sass
Normal file
@@ -0,0 +1,18 @@
|
||||
@use "../index"
|
||||
|
||||
.canvas
|
||||
display: flex
|
||||
flex-direction: column
|
||||
justify-content: center
|
||||
align-items: center
|
||||
|
||||
.canvas-ctr
|
||||
width: 100%
|
||||
height: 100vh
|
||||
display: flex
|
||||
flex-direction: column
|
||||
flex-grow: 1
|
||||
|
||||
.welcome
|
||||
position: absolute
|
||||
font-family: Neuton, serif
|
||||
@@ -1,19 +0,0 @@
|
||||
.canvas {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
background: black;
|
||||
color: white;
|
||||
z-index: -999;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.welcome {
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
top: calc(50% + 50px);
|
||||
font-family: Neuton;
|
||||
font-size: 30px;
|
||||
}
|
||||
@@ -1,14 +1,13 @@
|
||||
import {Link} from "../router/Link";
|
||||
import {motion} from "framer-motion";
|
||||
import {ROUTES} from "../router/Route";
|
||||
import ResumePdf from "../img/resume.pdf";
|
||||
import {motion} from "motion/react";
|
||||
|
||||
export function Links() {
|
||||
|
||||
return <div className="links">
|
||||
<Spacers length={ROUTES.length + 1} />
|
||||
<Link href="/" className="name">
|
||||
<motion.h1 className="name">Tymur Arsentiev</motion.h1>
|
||||
<motion.h1>Tymur Arsentiev</motion.h1>
|
||||
</Link>
|
||||
{
|
||||
ROUTES.map(([path, name]) =>
|
||||
@@ -21,13 +20,4 @@ export function Links() {
|
||||
<h3>Resume</h3>
|
||||
</Link>
|
||||
</div>
|
||||
}
|
||||
|
||||
function Spacers(props: {length: number}) {
|
||||
const spacers = [];
|
||||
for (let i = 0; i < props.length; i++) {
|
||||
spacers.push(<div key={i}/>);
|
||||
}
|
||||
|
||||
return spacers;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import "./menu.scss";
|
||||
import {motion, animate} from "framer-motion";
|
||||
import "./menu.sass";
|
||||
import {animate, motion} from "framer-motion";
|
||||
import {useEffect} from "react";
|
||||
|
||||
const articles = [
|
||||
|
||||
@@ -1,34 +1,32 @@
|
||||
import {useState} from "react";
|
||||
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
|
||||
import {faBars} from "@fortawesome/free-solid-svg-icons/faBars";
|
||||
import {Menu} from "./Menu";
|
||||
import {ReactComponent as Wave} from "../img/menu-wave.svg";
|
||||
import "./nav.scss";
|
||||
import "./nav.sass";
|
||||
import {Links} from "./Links";
|
||||
import {Menu} from "./Menu";
|
||||
|
||||
export default function Nav() {
|
||||
const [active, setActive] = useState(false);
|
||||
|
||||
return <>
|
||||
return <div className="nav-ctr">
|
||||
<nav>
|
||||
<MenuButton active={active} setActive={setActive}/>
|
||||
<Links/>
|
||||
</nav>
|
||||
<Menu active={active}/>
|
||||
<Wave className="wave" />
|
||||
</>;
|
||||
<Menu active={active}/>
|
||||
</div>;
|
||||
}
|
||||
|
||||
function MenuButton(props : { active: boolean, setActive: (_:boolean) => void }) {
|
||||
const {active, setActive} = props;
|
||||
|
||||
return (
|
||||
<div className="menu-btn">
|
||||
<button>
|
||||
<FontAwesomeIcon icon={faBars} onClick={function() {
|
||||
setActive(!active);
|
||||
}}/>
|
||||
</button>
|
||||
</div>
|
||||
<button className="menu-btn link">
|
||||
<FontAwesomeIcon icon={faBars} onClick={function() {
|
||||
setActive(!active);
|
||||
}}/>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
13
src/nav/menu.sass
Normal file
13
src/nav/menu.sass
Normal file
@@ -0,0 +1,13 @@
|
||||
@use "nav"
|
||||
|
||||
.menu
|
||||
position: absolute
|
||||
display: flex
|
||||
flex-direction: column
|
||||
background: nav.$menu
|
||||
color: white
|
||||
width: 25%
|
||||
height: 100vh
|
||||
|
||||
div
|
||||
padding: nav.$padding
|
||||
@@ -1,16 +0,0 @@
|
||||
@use "./nav";
|
||||
|
||||
.menu {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: nav.$menu;
|
||||
z-index: 10;
|
||||
color: white;
|
||||
width: 25%;
|
||||
height: 100vh;
|
||||
|
||||
div {
|
||||
padding: nav.$padding;
|
||||
}
|
||||
}
|
||||
50
src/nav/nav.sass
Normal file
50
src/nav/nav.sass
Normal file
@@ -0,0 +1,50 @@
|
||||
@use "../index"
|
||||
$padding: 15px
|
||||
$menu: #282c34
|
||||
|
||||
.menu-btn
|
||||
align-self: center
|
||||
display: flex
|
||||
flex-direction: column
|
||||
align-items: center
|
||||
font-size: 30px
|
||||
|
||||
|
||||
// hide menu button and center links
|
||||
@media screen and (max-width: index.$phone)
|
||||
.menu-btn
|
||||
display: none
|
||||
position: absolute
|
||||
|
||||
.links
|
||||
justify-content: center
|
||||
|
||||
nav
|
||||
background-color: $menu
|
||||
padding: $padding
|
||||
display: flex
|
||||
align-items: center
|
||||
justify-content: center
|
||||
|
||||
.name
|
||||
margin: auto
|
||||
flex-grow: 1
|
||||
h1
|
||||
margin: auto 0
|
||||
font-size: 40px
|
||||
|
||||
|
||||
|
||||
.links
|
||||
flex-grow: 1
|
||||
justify-content: center
|
||||
align-items: center
|
||||
display: flex
|
||||
flex-wrap: wrap
|
||||
gap: 15px
|
||||
|
||||
|
||||
.wave
|
||||
user-select: none
|
||||
pointer-events: none
|
||||
position: absolute
|
||||
@@ -1,57 +0,0 @@
|
||||
$padding: 15px;
|
||||
$menu: #282c34;
|
||||
|
||||
.menu-btn>button:hover {
|
||||
opacity: 90%;
|
||||
}
|
||||
|
||||
.menu-btn>button:active {
|
||||
opacity: 80%;
|
||||
}
|
||||
|
||||
.menu-btn {
|
||||
align-self: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
button {
|
||||
font-size: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
nav {
|
||||
background-color: $menu;
|
||||
padding: $padding;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
nav>a{
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.name>h1 {
|
||||
margin: 0;
|
||||
font-size: 40px;
|
||||
}
|
||||
|
||||
.name {
|
||||
margin: auto;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.wave {
|
||||
user-select: none;
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.links {
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.nav {
|
||||
font-family: Inter;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import "./link.scss";
|
||||
import "./link.sass";
|
||||
|
||||
import React, {HTMLProps, ReactNode} from "react";
|
||||
import {useRouter} from "./RouterContext";
|
||||
@@ -7,7 +7,7 @@ import {Path} from "./router";
|
||||
export function Link(props: {href: Path, children : ReactNode, target?: '_blank' } & HTMLProps<HTMLAnchorElement>) {
|
||||
let {children, className, href} = props;
|
||||
const router = useRouter();
|
||||
className = `${className} link`;
|
||||
className = `${className ?? ""} link`.trim();
|
||||
|
||||
function onClick(event: React.MouseEvent) {
|
||||
// perform the default action if _blank
|
||||
|
||||
@@ -1,31 +1,40 @@
|
||||
import React, {PropsWithChildren} from "react";
|
||||
import {useRouter} from "./RouterContext";
|
||||
import {Path} from "./router";
|
||||
import {ArticlesList} from "../articles/ArticlesList";
|
||||
|
||||
const Canvas = React.lazy(() => import("../index/Canvas"));
|
||||
const About = React.lazy(() => import("../about/AboutPage"));
|
||||
|
||||
export const ROUTES: [Path, string][] = [
|
||||
type Route = [Path, string];
|
||||
type Routes = [Route, Route, Route];
|
||||
export const ROUTES: Routes = [
|
||||
["/", "Home"],
|
||||
["/about", "About"],
|
||||
["/articles", "Articles"]
|
||||
];
|
||||
|
||||
function Route(props: PropsWithChildren & {path: Path}) {
|
||||
const {path, children} = props;
|
||||
function Route(props: PropsWithChildren & {route: Route}) {
|
||||
const {route: [path], children} = props;
|
||||
const router = useRouter();
|
||||
|
||||
return <>{router.current === path && children}</>
|
||||
}
|
||||
|
||||
|
||||
const Canvas = React.lazy(() => import("../index/Canvas"));
|
||||
const About = React.lazy(() => import("../about/AboutPage"));
|
||||
|
||||
|
||||
export function Routes() {
|
||||
const [index, about, articles] = ROUTES;
|
||||
|
||||
return <>
|
||||
<Route path={ROUTES[0]![0]}>
|
||||
<Route route={index}>
|
||||
<Canvas/>
|
||||
</Route>
|
||||
<Route path={ROUTES[1]![0]}>
|
||||
<Route route={about}>
|
||||
<About/>
|
||||
</Route>
|
||||
<Route route={articles}>
|
||||
<ArticlesList/>
|
||||
</Route>
|
||||
</>
|
||||
}
|
||||
@@ -22,11 +22,11 @@ export function RouterProvider(props : PropsWithChildren) {
|
||||
}, []);
|
||||
|
||||
return <RouterContext.Provider value={{
|
||||
pushPage: function(newPath: Path) {
|
||||
pushPage(newPath: Path) {
|
||||
window.history.pushState(newPath,"", newPath);
|
||||
setPath(newPath as Path);
|
||||
},
|
||||
replacePage: function(newPath: Path) {
|
||||
replacePage(newPath: Path) {
|
||||
window.history.replaceState(newPath, "", newPath);
|
||||
setPath(newPath as Path);
|
||||
},
|
||||
|
||||
8
src/router/link.sass
Normal file
8
src/router/link.sass
Normal file
@@ -0,0 +1,8 @@
|
||||
.link
|
||||
color: white
|
||||
text-decoration: none
|
||||
text-align: center
|
||||
&:hover
|
||||
opacity: 90%
|
||||
&:active
|
||||
opacity: 80%
|
||||
@@ -1,13 +0,0 @@
|
||||
.link {
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.link:hover {
|
||||
opacity: 90%;
|
||||
}
|
||||
|
||||
.link:active {
|
||||
opacity: 80%;
|
||||
}
|
||||
Reference in New Issue
Block a user