mobile-friendly view and scss->sass
Some checks failed
/ image_build (push) Has been cancelled

This commit is contained in:
2026-03-07 23:19:21 -06:00
parent e8a8da31ac
commit db845bf6c6
26 changed files with 243 additions and 273 deletions

0
.idea/jsLibraryMappings.xml generated Normal file
View File

View 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";

View File

@@ -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
View 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

View File

@@ -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;
}

View File

Before

Width:  |  Height:  |  Size: 13 MiB

After

Width:  |  Height:  |  Size: 13 MiB

View File

Before

Width:  |  Height:  |  Size: 5.6 MiB

After

Width:  |  Height:  |  Size: 5.6 MiB

1
src/img/blog-box.svg Normal file
View 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
View 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

View File

@@ -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;
}

View File

@@ -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";

View File

@@ -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
View 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

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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 = [

View File

@@ -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
View 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

View File

@@ -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
View 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

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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>
</>
}

View File

@@ -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
View File

@@ -0,0 +1,8 @@
.link
color: white
text-decoration: none
text-align: center
&:hover
opacity: 90%
&:active
opacity: 80%

View File

@@ -1,13 +0,0 @@
.link {
color: white;
text-decoration: none;
text-align: center;
}
.link:hover {
opacity: 90%;
}
.link:active {
opacity: 80%;
}