mirror of
https://github.com/hazemKrimi/hamdi-portfolio.git
synced 2026-05-01 18:30:27 +00:00
Add files via upload
This commit is contained in:
Generated
+14683
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"name": "hamdi-halleb",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"node-sass": "^4.13.0",
|
||||
"react": "^16.12.0",
|
||||
"react-dom": "^16.12.0",
|
||||
"react-scripts": "3.3.0",
|
||||
"react-spring": "^8.0.27"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"test": "react-scripts test",
|
||||
"eject": "react-scripts eject"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": "react-app"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not op_mini all"
|
||||
],
|
||||
"development": [
|
||||
"last 1 chrome version",
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%PUBLIC_URL%/logo.png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<meta
|
||||
name="description"
|
||||
content="Personal Portfolio of Hamdi Halleb"
|
||||
/>
|
||||
<title>Hamdi Halleb</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
</body>
|
||||
</html>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
+30
@@ -0,0 +1,30 @@
|
||||
import React, { lazy, Suspense } from 'react';
|
||||
import Loading from './components/loading/Loading';
|
||||
import './App.scss';
|
||||
|
||||
const Nav = lazy(() => import("./components/nav/Nav"));
|
||||
const Welcome = lazy(() => import("./components/welcome/Welcome"));
|
||||
const Background = lazy(() => import("./components/background/Background"));
|
||||
const About = lazy(() => import("./components/about/About"));
|
||||
const AboutText = lazy(() => import("./components/about/AboutText"));
|
||||
const Portrait = lazy(() => import("./components/portrait/Portrait"));
|
||||
const SkillsText = lazy(() => import("./components/skills/SkillsText"));
|
||||
const Skills = lazy(() => import("./components/skills/Skills"));
|
||||
|
||||
const App = () => {
|
||||
return (
|
||||
<Suspense fallback={<Loading />}>
|
||||
<Nav />
|
||||
<Background>
|
||||
<Portrait />
|
||||
<AboutText />
|
||||
<Skills />
|
||||
</Background>
|
||||
<Welcome />
|
||||
<About />
|
||||
<SkillsText />
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
@@ -0,0 +1,13 @@
|
||||
@import url('https://fonts.googleapis.com/css?family=Montserrat|Work+Sans&display=swap');
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: Montserrat;
|
||||
overflow: hidden;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import React, { useContext } from 'react';
|
||||
import './About.scss';
|
||||
import { useTransition, animated } from 'react-spring';
|
||||
import { MainContext } from '../../contexts/MainContext';
|
||||
|
||||
const About = () => {
|
||||
const { current, previous } = useContext(MainContext);
|
||||
const about = current === "about";
|
||||
|
||||
const transition = useTransition(about, null, {
|
||||
from: { transform: previous === "welcome" ? "translateX(-300%) translateY(0%)" : "translateX(0%) translateY(-300%)", opacity: 0 },
|
||||
enter: { transform: "translateX(0%) translateY(0%)", opacity: 1 },
|
||||
leave: { transform: current === "welcome" ? "translateX(-300%) translateY(0%)" : "translateX(0%) translateY(-300%)", opacity: 0 }
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
{
|
||||
transition.map(({ item, key, props }) =>
|
||||
item &&
|
||||
<animated.div key={key} id="about" style={props}>
|
||||
<div className="container">
|
||||
<h1>
|
||||
ABOUT MYSELF
|
||||
<span></span>
|
||||
</h1>
|
||||
</div>
|
||||
</animated.div>
|
||||
)
|
||||
}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default About;
|
||||
@@ -0,0 +1,28 @@
|
||||
@import '../../App.scss';
|
||||
|
||||
#about {
|
||||
height: 100vh;
|
||||
width: 90vw;
|
||||
position: absolute;
|
||||
top: 35%;
|
||||
left: 12.5%;
|
||||
|
||||
.container {
|
||||
margin-top: 5%;
|
||||
|
||||
h1 {
|
||||
display: inline-block;
|
||||
font-weight: 600;
|
||||
font-size: 3rem;
|
||||
|
||||
span {
|
||||
position: relative;
|
||||
left: -50%;
|
||||
border: 3px solid #D8B269;
|
||||
box-sizing: content-box;
|
||||
padding: 3px 100px 3px 135px;
|
||||
margin-left: 3%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import React, { useContext } from 'react';
|
||||
import { MainContext } from '../../contexts/MainContext';
|
||||
import { useTransition, animated } from 'react-spring';
|
||||
import './AboutText.scss';
|
||||
|
||||
const AboutText = () => {
|
||||
const { current, previous } = useContext(MainContext);
|
||||
const aboutText = current === "about";
|
||||
|
||||
const transition = useTransition(aboutText, null, {
|
||||
from: { transform: previous === "welcome" ? "translateX(300%) translateY(0%)" : "translateX(0%) translateY(-200%)", opacity: 0 },
|
||||
enter: { transform: "translateX(0%) translateY(0%)", opacity: 1 },
|
||||
leave: { transform: current === "welcome" ? "translateX(300%) translateY(0%)" : "translateX(0%) translateY(-200%)", opacity: 0 }
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
{
|
||||
transition.map(({ item, key, props }) => (
|
||||
item &&
|
||||
<animated.p id="about-text" key={key} style={props}>
|
||||
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.
|
||||
At vero eos et accusam et justo duo dolores et ea rebum.
|
||||
Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.
|
||||
At vero eos et accusam et.
|
||||
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.
|
||||
At vero eos et accusam et justo duo dolores et ea rebum.
|
||||
Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.
|
||||
At vero eos et accusam et.
|
||||
</animated.p>
|
||||
))
|
||||
}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default AboutText;
|
||||
@@ -0,0 +1,10 @@
|
||||
@import '../../App.scss';
|
||||
|
||||
#about-text {
|
||||
position: absolute;
|
||||
top: 0%;
|
||||
left: 0%;
|
||||
color: #D8B269;
|
||||
margin: 10% 20%;
|
||||
line-height: 1.5;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import React from 'react';
|
||||
import { useSpring, animated } from 'react-spring';
|
||||
import './Background.scss';
|
||||
|
||||
const Background = ({ children }) => {
|
||||
const blackSpring = useSpring({
|
||||
from: {
|
||||
transform: "translateX(200%)",
|
||||
opacity: 0
|
||||
},
|
||||
to: {
|
||||
transform: "translateX(0%)",
|
||||
opacity: 1
|
||||
},
|
||||
config: {
|
||||
velocity: 10
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<animated.div id="background" style={blackSpring}>
|
||||
{children}
|
||||
</animated.div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Background;
|
||||
@@ -0,0 +1,10 @@
|
||||
@import '../../App.scss';
|
||||
|
||||
#background {
|
||||
height: 100vh;
|
||||
width: 50%;
|
||||
position: absolute;
|
||||
top: 0%;
|
||||
left: 50%;
|
||||
background: #050A0D;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import React from 'react';
|
||||
import { useSpring, animated, config } from 'react-spring';
|
||||
|
||||
const Loading = () => {
|
||||
const spring = useSpring({
|
||||
from: {
|
||||
x: 0
|
||||
},
|
||||
to: async next => {
|
||||
while (1) {
|
||||
await next({ x: 900 });
|
||||
await next({ x: 0 });
|
||||
}
|
||||
},
|
||||
config: config.slow,
|
||||
duration: 1000
|
||||
});
|
||||
return (
|
||||
<div style={{ height: "100vh" }}>
|
||||
<animated.svg width="3rem" height="3rem" viewBox="0 0 110.692 98.157" strokeDashoffset={spring.x} style={{ position: "relative", top: "40%", left: "50%" }}>
|
||||
<path
|
||||
d="M80.402 75.676l.116-29L80.705 0l27.1 46.693-27.1 46.7H26.512L26.904 0 0 46.668l79.873.025"
|
||||
fill="none"
|
||||
stroke="#050b0d"
|
||||
strokeMiterlimit={10}
|
||||
strokeWidth={2}
|
||||
strokeDasharray={900}
|
||||
/>
|
||||
</animated.svg>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Loading;
|
||||
@@ -0,0 +1,60 @@
|
||||
import React, { useContext } from 'react';
|
||||
import { useTransition, animated } from 'react-spring';
|
||||
import { MainContext } from '../../contexts/MainContext';
|
||||
|
||||
const Logo = () => {
|
||||
const { current } = useContext(MainContext);
|
||||
const welcome = current === "welcome";
|
||||
|
||||
const transition = useTransition(welcome, null, {
|
||||
initial: {
|
||||
top: "40%",
|
||||
left: "50%",
|
||||
width: "3rem",
|
||||
height: "3rem"
|
||||
},
|
||||
from: {
|
||||
top: "-100%",
|
||||
left: "11.5%",
|
||||
width: "3rem",
|
||||
height: "3rem",
|
||||
opacity: 0
|
||||
},
|
||||
enter: {
|
||||
top: "15%",
|
||||
left: "11.5%",
|
||||
width: "2.5rem",
|
||||
height: "2.5rem",
|
||||
opacity: 1
|
||||
},
|
||||
leave: {
|
||||
top: "-40%",
|
||||
left: "12%",
|
||||
width: "2.5rem",
|
||||
height: "2.5rem",
|
||||
opacity: 0
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
{
|
||||
transition.map(({ item, key, props }) => (
|
||||
item &&
|
||||
<animated.svg key={key} width={props.width} height={props.height} viewBox="0 0 110.692 98.157" style={{ position: "absolute", ...props }}>
|
||||
<path
|
||||
d="M80.402 75.676l.116-29L80.705 0l27.1 46.693-27.1 46.7H26.512L26.904 0 0 46.668l79.873.025"
|
||||
fill="none"
|
||||
stroke="#050b0d"
|
||||
strokeMiterlimit={10}
|
||||
strokeWidth={2}
|
||||
strokeDasharray={900}
|
||||
/>
|
||||
</animated.svg>
|
||||
))
|
||||
}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default Logo;
|
||||
@@ -0,0 +1,128 @@
|
||||
import React, { useContext } from 'react';
|
||||
import { useSpring, animated } from 'react-spring';
|
||||
import './Nav.scss';
|
||||
import { MainContext } from '../../contexts/MainContext';
|
||||
|
||||
const Polygon = ({ location, current }) => (
|
||||
<svg id="nav-polygon" width="3rem" height="3rem" viewBox="0 0 90 78">
|
||||
<g fill="none">
|
||||
<path d="M67.5 0L90 39 67.5 78h-45L0 39 22.5 0z" />
|
||||
<text
|
||||
transform="translate(36 50)"
|
||||
fill="#d8b269"
|
||||
fontSize={35}
|
||||
fontFamily="Montserrat"
|
||||
fontWeight={300}
|
||||
>
|
||||
<tspan x={0} y={0} style={{ userSelect: "none" }}>
|
||||
{location.findIndex(route => route === current) + 1}
|
||||
</tspan>
|
||||
</text>
|
||||
<path
|
||||
d="M23.655 2L2.31 39l21.346 37h42.69L87.69 39 66.345 2h-42.69M22.5 0h45L90 39 67.5 78h-45L0 39 22.5 0z"
|
||||
fill="#d8b269"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
|
||||
const Menu = ({ location, current }) => (
|
||||
<div id="nav-menu">
|
||||
{
|
||||
location.map(route => (
|
||||
<svg key={route} width="1rem" height="1rem" viewBox="0 0 18.975 1.617">
|
||||
<path fill={route === current ? "#d8b269" : "#b8bcbe"} d="M0 0h18.975v1.617H0z" />
|
||||
</svg>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
)
|
||||
|
||||
const UpArrow = ({ location, current, previousLocation }) => (
|
||||
<svg width="1.5rem" height="1.5rem" viewBox="0 0 47.414 25.414" onClick={() => previousLocation()}>
|
||||
<defs>
|
||||
<clipPath id="clip-path">
|
||||
<path fill="none" d="M0 0h25.414v47.414H0z" />
|
||||
</clipPath>
|
||||
<style>
|
||||
{`.nav-arrow-up{fill:none;stroke:${location.findIndex(route => route === current) > 0 ? "#d8b269" : "#b8bcbe"};stroke-width:4px}`}
|
||||
</style>
|
||||
</defs>
|
||||
<g
|
||||
transform="rotate(-90 12.707 12.707)"
|
||||
clipPath="url(#clip-path)"
|
||||
>
|
||||
<path
|
||||
className="nav-arrow-up"
|
||||
transform="translate(.707 .707)"
|
||||
d="M0 0l23 25"
|
||||
/>
|
||||
<path
|
||||
className="nav-arrow-up"
|
||||
transform="translate(1.707 23.707)"
|
||||
d="M0 23L21 0"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
|
||||
const DownArrow = ({ location, current, nextLocation }) => (
|
||||
<svg width="1.5rem" height="1.5rem" viewBox="0 0 47.414 25.414" onClick={() => nextLocation()}>
|
||||
<defs>
|
||||
<clipPath id="clip-path">
|
||||
<path fill="none" d="M0 0h25.414v47.414H0z" />
|
||||
</clipPath>
|
||||
<style>
|
||||
{`.nav-arrow-down{fill:none;stroke:${location.findIndex(route => route === current) < location.length - 1 ? "#d8b269" : "#b8bcbe"};stroke-width:4px}`}
|
||||
</style>
|
||||
</defs>
|
||||
<g
|
||||
transform="rotate(90 23.707 23.707)"
|
||||
clipPath="url(#clip-path)"
|
||||
>
|
||||
<path
|
||||
id="nav-arrow-down_svg__Line_2"
|
||||
className="nav-arrow-down"
|
||||
transform="translate(.707 .707)"
|
||||
d="M0 0l23 25"
|
||||
/>
|
||||
<path
|
||||
id="nav-arrow-down_svg__Line_3"
|
||||
className="nav-arrow-down"
|
||||
transform="translate(1.707 23.707)"
|
||||
d="M0 23L21 0"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
|
||||
const Nav = () => {
|
||||
const { location, current, nextLocation, previousLocation } = useContext(MainContext);
|
||||
|
||||
const spring = useSpring({
|
||||
from: {
|
||||
transform: "translateY(100%)"
|
||||
},
|
||||
to: {
|
||||
transform: "translateY(0%)"
|
||||
},
|
||||
duration: 5000,
|
||||
delay: 250
|
||||
});
|
||||
|
||||
return (
|
||||
<animated.nav style={{ transform: spring.transform }}>
|
||||
<div id="nav-label">
|
||||
<Polygon current={current} location={location}/>
|
||||
<Menu current={current} location={location}/>
|
||||
<h2>{current}</h2>
|
||||
</div>
|
||||
<div id="nav-arrows">
|
||||
<UpArrow current={current} location={location} previousLocation={previousLocation}/>
|
||||
<DownArrow current={current} location={location} nextLocation={nextLocation}/>
|
||||
</div>
|
||||
</animated.nav>
|
||||
);
|
||||
}
|
||||
|
||||
export default Nav;
|
||||
@@ -0,0 +1,58 @@
|
||||
@import '../../App.scss';
|
||||
|
||||
nav {
|
||||
height: 100vh;
|
||||
width: 10vw;
|
||||
padding: 1rem 0rem;
|
||||
position: fixed;
|
||||
z-index: 3;
|
||||
top: 0%;
|
||||
left: 0%;
|
||||
display: grid;
|
||||
grid-template-rows: 1fr auto;
|
||||
grid-row-gap: .5rem;
|
||||
justify-items: center;
|
||||
align-items: center;
|
||||
|
||||
#nav-label {
|
||||
margin-top: 6rem;
|
||||
align-self: center;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
grid-row-gap: .5rem;
|
||||
justify-items: center;
|
||||
align-items: center;
|
||||
|
||||
#nav-menu {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
justify-items: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#nav-polygon {
|
||||
align-self: flex-end;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin-top: 3rem;
|
||||
font-weight: 200;
|
||||
color: #B8BCBE;
|
||||
transform: rotate(270deg);
|
||||
text-transform: capitalize;
|
||||
}
|
||||
}
|
||||
|
||||
#nav-arrows {
|
||||
align-self: flex-end;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
justify-items: center;
|
||||
align-items: center;
|
||||
grid-row-gap: .5rem;
|
||||
|
||||
* {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
import React, { useContext } from 'react';
|
||||
import { useTransition, animated } from 'react-spring';
|
||||
import { MainContext } from '../../contexts/MainContext';
|
||||
import './Portrait.scss'
|
||||
|
||||
const Portrait = () => {
|
||||
const { current } = useContext(MainContext);
|
||||
const welcome = current === "welcome";
|
||||
|
||||
const transition = useTransition(welcome, null, {
|
||||
initial: null,
|
||||
from: { transform: "translateY(-200%)", opacity: 0 },
|
||||
enter: { transform: "translateY(0%)", opacity: 1 },
|
||||
leave: { transform: "translateY(-200%)", opacity: 0 }
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
{
|
||||
transition.map(({ item, key, props }) => (
|
||||
item &&
|
||||
<animated.svg id="portrait" key={key} width="30rem" height="30rem" viewBox="0 0 660 720.128" style={props}>
|
||||
<defs>
|
||||
<style>
|
||||
{
|
||||
".cls-1{fill:#d8b269}.cls-2{fill:#bf9563}.cls-3,.cls-4,.cls-6,.cls-8{fill:none}.cls-3,.cls-4{stroke:#bf9563;stroke-width:4px;stroke-miterlimit:10}.cls-4{stroke:#050a0d;stroke-width:9px}.cls-5{fill:#050a0d}.cls-6{stroke:#d8b269;stroke-width:5px}.cls-7{stroke:none}"
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<g
|
||||
transform="translate(-1110 -210)"
|
||||
>
|
||||
<g transform="translate(1148.151 220.998)">
|
||||
<g>
|
||||
<g>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M248.5 383.209l-102.545-26.342-46.1-140.178 1.581-8.919-55.449-25.89L14 190.347v70.559l49.862 34.809 19.757 3.763 23.52 87.493-12.23 62.092 207.915 99.724 31.986-21.637 13.171-83.73 4.5-51.329-14.6 7.112z"
|
||||
transform="translate(12.342 160.342)"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M96.758 336.558l58.329 21.642-23.52 11.289 64.915 15.993 47.04-48.921 65.385-25.4 12.7 17.4 12.23-16.464 43.032 51.838 2.822-83.824-14.112-33.868 7.526-57.369-40.454-52.684-17.874-51.745-96.431-31.065L57 126.78 91.809 171 57 239.657l7.15 77.843L57 239.657z"
|
||||
transform="translate(50.25 47.059)"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M166.14 234.511l50.8-24.461 14.112 5.645 12.23-5.645 27.283 24.461-39.513 7.526z"
|
||||
transform="translate(146.466 185.176)"
|
||||
/>
|
||||
<path
|
||||
className="cls-2"
|
||||
d="M166.14 234.591l50.539-13.171 14.827 4.553 11.76-6.19 27.3 14.808-27.3-24.461-12.23 5.889-13.7-5.889z" transform="translate(146.466 185.247)"
|
||||
/>
|
||||
<path
|
||||
className="cls-3"
|
||||
d="M197.4 245.165l23.427-38.886-42.711-68.847L198.889 115l42.986 11.722"
|
||||
transform="translate(172.405 96.382)"
|
||||
/>
|
||||
<path
|
||||
className="cls-4"
|
||||
d="M206.418 241.288l21.638-35.75-43.276-69.618 21.638-23.52 58.329 16.934"
|
||||
transform="translate(157.899 97.09)"
|
||||
/>
|
||||
<path
|
||||
className="cls-5"
|
||||
d="M20.7 353.737L0 220.145 47.04 86.553l86.553-72.441L249.309 0l148.645 69.618-14.582 95.961-12.7-38.572-106.31-35.75-174.046 85.612 40.454 47.98-31.987 64.444 6.586 64.444-48.922-15.993z"
|
||||
/>
|
||||
<path
|
||||
className="cls-4"
|
||||
d="M134.928 135.364l56.9-18.974 58.329 23.5"
|
||||
transform="translate(82.951 86.331)"
|
||||
/>
|
||||
<path
|
||||
className="cls-3"
|
||||
d="M129.531 129.089L184.2 110.7l56.568 22.851"
|
||||
transform="translate(90.144 98.35)"
|
||||
/>
|
||||
<path
|
||||
className="cls-5"
|
||||
d="M56.142 194.062L60 200.279l83.976-61.625 26.26 61.625 91.735-14.5 8.4-48.674 14.706-4.714-3.935-7.012h28.943l-3.062 7.012 34.9 53.388 66.166 22.972v-81.36l-56.447-8-41.558 5.984h-28.94l-14.272 4.025-16.106-10.01-104.69 4.056-4.228 8.941z"
|
||||
transform="translate(52.895 105.252)"
|
||||
/>
|
||||
<path
|
||||
className="cls-2"
|
||||
d="M76.113 250.562l29.616 90 205.581 45.963-1.994 22.711-36.992-2.822L99.218 371.3 59.63 200.38z"
|
||||
transform="translate(52.569 176.651)"
|
||||
/>
|
||||
<path
|
||||
className="cls-2"
|
||||
d="M76.738 209.637L42.249 189.88l-22.579 9.878v44.067l11.91 8.618-3.763-42.806 15.053-7.207 38.892 21.318z"
|
||||
transform="translate(17.341 167.395)"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
className="cls-6"
|
||||
>
|
||||
<path
|
||||
className="cls-7"
|
||||
d="M0 0h600v600H0z"
|
||||
transform="translate(1110 210)"
|
||||
/>
|
||||
<path
|
||||
className="cls-8"
|
||||
d="M2.5 2.5h595v595H2.5z"
|
||||
transform="translate(1110 210)"
|
||||
/>
|
||||
</g>
|
||||
<g
|
||||
className="cls-6"
|
||||
>
|
||||
<path
|
||||
className="cls-7"
|
||||
d="M0 0h600v600H0z"
|
||||
transform="translate(1170 276)"
|
||||
/>
|
||||
<path
|
||||
className="cls-8"
|
||||
d="M2.5 2.5h595v595H2.5z"
|
||||
transform="translate(1170 276)"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
</animated.svg>
|
||||
))
|
||||
}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default Portrait;
|
||||
@@ -0,0 +1,7 @@
|
||||
@import '../../App.scss';
|
||||
|
||||
#portrait {
|
||||
position: absolute;
|
||||
top: 15%;
|
||||
left: 15%;
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
import React, { useState, useContext } from 'react';
|
||||
import { useSpring, useTransition, animated } from 'react-spring';
|
||||
import { MainContext } from '../../contexts/MainContext';
|
||||
import './Skills.scss';
|
||||
|
||||
const Stat = () => {
|
||||
const spring = useSpring({
|
||||
from: { left: "5%", width: "100%" },
|
||||
to: { left: "100%", width: "0%" },
|
||||
delay: 700
|
||||
});
|
||||
|
||||
return (
|
||||
<div id="stat">
|
||||
<svg width="400px" height="40px" viewBox="0 0 657 30" style={{ position: "relative", zIndex: 2 }}>
|
||||
<g clipPath="url(#clip)">
|
||||
<path
|
||||
d="M630.75 30l-5.25-9h-98l-5.25 9h-17.5l-5.25-9h-96l-5.25 9h-17.5l-5.25-9h-96l-5.25 9h-17.5l-5.25-9h-96l-5.25 9h-17.5l-5.25-9h-96l-5.25 9H8.75L0 15 8.75 0h17.5l4.667 8h97.167l4.667-8h17.5l4.667 8h97.167l4.667-8h17.5l4.667 8h97.167l4.667-8h17.5l4.667 8h97.167l4.667-8h17.5l4.667 8h99.167l4.667-8h17.5l8.75 15-8.75 15z"
|
||||
fill="#d8b269"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
<animated.div
|
||||
style={{
|
||||
position: "relative",
|
||||
transform: "translateY(-108%)",
|
||||
left: spring.left,
|
||||
width: spring.width,
|
||||
height: "40px",
|
||||
backgroundColor: "#050a0d",
|
||||
zIndex: 3
|
||||
}}
|
||||
></animated.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const Skills = () => {
|
||||
const { current, previous } = useContext(MainContext);
|
||||
const skill = current === "skills";
|
||||
|
||||
const mainTransition = useTransition(skill, null, {
|
||||
from: { transform: previous === "about" ? "translateX(300%) translateY(0%)" : "translateX(0%) translateY(-200%)", opacity: 0 },
|
||||
enter: { transform: "translateX(0%) translateY(0%)", opacity: 1 },
|
||||
leave: { transform: current === "about" ? "translateX(300%) translateY(0%)" : "translateX(0%) translateY(-200%)", opacity: 0 }
|
||||
});
|
||||
|
||||
const [skills] = useState([
|
||||
{
|
||||
id: 1,
|
||||
name: "Graphic Design",
|
||||
tools: [
|
||||
{ name: "Adobe Xd", id: 1 },
|
||||
{ name: "Adobe Xd", id: 2 },
|
||||
{ name: "Adobe Xd", id: 3 }
|
||||
],
|
||||
show: true
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "Photography",
|
||||
tools: [
|
||||
{ name: "Adobe Xd", id: 1 },
|
||||
{ name: "Adobe Xd", id: 2 },
|
||||
{ name: "Adobe Xd", id: 3 }
|
||||
],
|
||||
show: false
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Web and Mobile Development",
|
||||
tools: [
|
||||
{ name: "Adobe Xd", id: 1 },
|
||||
{ name: "Adobe Xd", id: 2 },
|
||||
{ name: "Adobe Xd", id: 3 }
|
||||
],
|
||||
show: false
|
||||
},
|
||||
]);
|
||||
|
||||
const skillTransition = useTransition(skills, skill => skill.id, {
|
||||
from: { opacity: 0 },
|
||||
enter: { opacity: 1 },
|
||||
leave: { opacity: 0 }
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
{
|
||||
mainTransition.map(({ item, key, props }) =>
|
||||
item &&
|
||||
<animated.div id="skills" key={key} style={props}>
|
||||
{skillTransition.map(({ item: { show, name, tools }, key, props }) => (
|
||||
item && show &&
|
||||
<animated.div style={props} key={key}>
|
||||
<h2 style={{ display: "inline", color: "#f2f2f2", marginBottom: "20px" }}>
|
||||
{name}
|
||||
</h2>
|
||||
<div id="skill-stats">
|
||||
{
|
||||
tools.map(({ name, id }) =>
|
||||
<div key={id}>
|
||||
<h4 style={{ color: "#f2f2f2", margin: "10px 0px" }}>
|
||||
{name}
|
||||
</h4>
|
||||
<Stat />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
</animated.div>
|
||||
))}
|
||||
</animated.div>
|
||||
)
|
||||
}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default Skills;
|
||||
@@ -0,0 +1,22 @@
|
||||
@import '../../App.scss';
|
||||
|
||||
#skills {
|
||||
position: absolute;
|
||||
top: 0%;
|
||||
left: 0%;
|
||||
margin: 10% 20%;
|
||||
|
||||
h2 {
|
||||
font-size: 40px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
#skill-stats {
|
||||
margin-top: 70px;
|
||||
|
||||
h4 {
|
||||
font-size: 20px;
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import React, { useContext } from 'react';
|
||||
import { useTransition, animated } from 'react-spring';
|
||||
import './SkillsText.scss';
|
||||
import { MainContext } from '../../contexts/MainContext';
|
||||
|
||||
const SkillsText = () => {
|
||||
const { current, previous } = useContext(MainContext);
|
||||
const skillsText = current === "skills";
|
||||
|
||||
const transition = useTransition(skillsText, null, {
|
||||
from: { transform: previous === "about" ? "translateX(-300%) translateY(0%)" : "translateX(0%) translateY(-300%)", opacity: 0 },
|
||||
enter: { transform: "translateX(0%) translateY(0%)", opacity: 1 },
|
||||
leave: { transform: current === "about" ? "translateX(-300%) translateY(0%)" : "translateX(0%) translateY(-300%)", opacity: 0 }
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
{
|
||||
transition.map(({ item, key, props }) =>
|
||||
item &&
|
||||
<animated.div key={key} id="skills-text" style={props}>
|
||||
<div className="container">
|
||||
<h1>
|
||||
WHAT
|
||||
<span>CAN I DO</span>
|
||||
</h1>
|
||||
</div>
|
||||
</animated.div>
|
||||
)
|
||||
}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default SkillsText;
|
||||
@@ -0,0 +1,26 @@
|
||||
@import '../../App.scss';
|
||||
|
||||
#skills-text {
|
||||
height: 100vh;
|
||||
width: 90vw;
|
||||
position: absolute;
|
||||
top: 35%;
|
||||
left: 12.5%;
|
||||
|
||||
.container {
|
||||
margin-top: 5%;
|
||||
|
||||
h1 {
|
||||
display: inline-block;
|
||||
font-weight: 600;
|
||||
font-size: 3rem;
|
||||
|
||||
span {
|
||||
border: 3px solid #D8B269;
|
||||
box-sizing: content-box;
|
||||
padding: 2px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
import React, { useContext } from 'react';
|
||||
import Logo from '../logo/Logo';
|
||||
import { useTransition, animated } from 'react-spring';
|
||||
import './Welcome.scss';
|
||||
import { MainContext } from '../../contexts/MainContext';
|
||||
|
||||
const Welcome = () => {
|
||||
const { current } = useContext(MainContext);
|
||||
const welcome = current === 'welcome';
|
||||
|
||||
const transition = useTransition(welcome, null, {
|
||||
initial: {
|
||||
transform: "translateX(-300%) translateY(0%)",
|
||||
opacity: 1
|
||||
},
|
||||
from: { transform: "translateX(0%) translateY(-300%)", opacity: 0 },
|
||||
enter: { transform: "translateX(0%) translateY(0%)", opacity: 1 },
|
||||
leave: { transform: "translateX(0%) translateY(-300%)", opacity: 1 }
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<Logo />
|
||||
{
|
||||
transition.map(({ item, key, props }) =>
|
||||
item &&
|
||||
<animated.div key={key} id="welcome" style={props}>
|
||||
<div className="container">
|
||||
<h3>Welcome</h3>
|
||||
<div id="description">
|
||||
<h4>My name is</h4>
|
||||
<h1>HAMDI <span>HALLEB</span></h1>
|
||||
<h3>Graphic Designer-Photographer-Developer</h3>
|
||||
</div>
|
||||
</div>
|
||||
</animated.div>
|
||||
)
|
||||
}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default Welcome;
|
||||
@@ -0,0 +1,47 @@
|
||||
@import '../../App.scss';
|
||||
|
||||
#welcome {
|
||||
height: 100vh;
|
||||
width: 90vw;
|
||||
|
||||
.container {
|
||||
position: absolute;
|
||||
top: 35%;
|
||||
left: 12.5%;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
grid-row-gap: 3rem;
|
||||
|
||||
h3 {
|
||||
font-weight: 200;
|
||||
color: #D8B269;
|
||||
}
|
||||
|
||||
#description {
|
||||
display: grid;
|
||||
grid-row-gap: .5rem;
|
||||
align-items: center;
|
||||
justify-items: flex-start;
|
||||
|
||||
h4 {
|
||||
font-weight: 200;
|
||||
color: #B8BCBE;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-weight: 600;
|
||||
font-size: 3rem;
|
||||
|
||||
span {
|
||||
border: 3px solid #D8B269;
|
||||
box-sizing: content-box;
|
||||
padding: 3px 30px 0px 1px;
|
||||
}
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-family: "Work Sans", Montserrat;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import React, { createContext, useState } from 'react';
|
||||
|
||||
export const MainContext = createContext();
|
||||
|
||||
const MainContextProvider = ({ children }) => {
|
||||
const location = [
|
||||
'welcome',
|
||||
'about',
|
||||
'skills',
|
||||
'wins',
|
||||
'work',
|
||||
'portfolio',
|
||||
'blog',
|
||||
'contact'
|
||||
];
|
||||
|
||||
const [previous, setPrevious] = useState('');
|
||||
const [current, setCurrent] = useState('welcome');
|
||||
|
||||
const nextLocation = () => {
|
||||
let index = location.findIndex(route => route === current);
|
||||
if (index < location.length - 1) {
|
||||
setPrevious(current);
|
||||
setCurrent(location[index + 1]);
|
||||
}
|
||||
};
|
||||
const previousLocation = () => {
|
||||
let index = location.findIndex(route => route === current);
|
||||
if (index > 0) {
|
||||
setPrevious(current);
|
||||
setCurrent(location[index - 1]);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<MainContext.Provider value={{ location, current, previous, nextLocation, previousLocation }}>
|
||||
{children}
|
||||
</MainContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export default MainContextProvider;
|
||||
@@ -0,0 +1,10 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import MainContextProvider from './contexts/MainContext';
|
||||
import App from './App';
|
||||
|
||||
ReactDOM.render(
|
||||
<MainContextProvider>
|
||||
<App />
|
||||
</MainContextProvider>,
|
||||
document.getElementById('root'));
|
||||
Reference in New Issue
Block a user