desktop version production ready, need to add CV

This commit is contained in:
gbrochar 2020-11-21 17:59:28 +01:00
bovenliggende 7550f624f6
commit a5c7f120a8
24 gewijzigde bestanden met toevoegingen van 320 en 61 verwijderingen

Bestand weergeven

@ -1,6 +0,0 @@
{
"watch": ["src/server"],
"ext": "ts,json",
"ignore": ["src/**/*.spec.ts"],
"exec": "ts-node ./src/server/main.ts"
}

34
package-lock.json gegenereerd
Bestand weergeven

@ -1292,6 +1292,12 @@
"@types/range-parser": "*"
}
},
"@types/howler": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/@types/howler/-/howler-2.2.1.tgz",
"integrity": "sha512-1MiSldngr+eAO4lDPtjzl4Nf2GmRh8VDHIpNBIkyd25L22JExVlI6w3fjSM7+FNc1e1WZAPNq7/flkw685byfg==",
"dev": true
},
"@types/json-schema": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz",
@ -1347,6 +1353,16 @@
"@types/react": "*"
}
},
"@types/react-howler": {
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/@types/react-howler/-/react-howler-3.7.2.tgz",
"integrity": "sha512-2R2nypBTD8L1vHL7Sz5Pn7L5I0v5+UIp5y4ZnZ3r7uggqghVf1DLo/pJ9e7g2A+PWq/xZJXvzrF9ZQSdwrQyEQ==",
"dev": true,
"requires": {
"@types/howler": "*",
"@types/react": "*"
}
},
"@types/serve-static": {
"version": "1.13.8",
"resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.8.tgz",
@ -3327,6 +3343,11 @@
"integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==",
"dev": true
},
"howler": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/howler/-/howler-2.2.1.tgz",
"integrity": "sha512-0iIXvuBO/81CcrQ/HSSweYmbT50fT2mIc9XMFb+kxIfk2pW/iKzDbX1n3fZmDXMEIpYvyyfrB+gXwPYSDqUxIQ=="
},
"http-cache-semantics": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz",
@ -4331,7 +4352,6 @@
"version": "15.7.2",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
"integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
"dev": true,
"requires": {
"loose-envify": "^1.4.0",
"object-assign": "^4.1.1",
@ -4447,11 +4467,19 @@
"scheduler": "^0.20.1"
}
},
"react-howler": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/react-howler/-/react-howler-5.0.0.tgz",
"integrity": "sha512-0JJapjFv0rd7sAZ9l9TuKVN2m4aRN3/yQYzRKQpaoK0FXldzM6LuP2XN/QetlubAqHF5F3wrk29QF0gngj+gRQ==",
"requires": {
"howler": "^2.2.0",
"prop-types": "^15.5.6"
}
},
"react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
"dev": true
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
},
"read-pkg": {
"version": "4.0.1",

Bestand weergeven

@ -22,7 +22,7 @@
"dev:client:types": "tsc --emitDeclarationOnly --watch --preserveWatchOutput --pretty --project config/tsconfig.client.json",
"dev:client:js": "webpack --config config/webpack.client.dev.js",
"dev:client": "concurrently \"npm:dev:client:types\" \"npm:dev:client:js\"",
"dev:start": "mkdir -p dev/server && touch dev/server/bundle.js && nodemon dev/server/bundle.js",
"dev:start": "mkdir -p dist/server && touch dist/server/bundle.js && nodemon dist/server/bundle.js",
"dev": "rm -rf dist && concurrently \"npm:dev:server\" \"npm:dev:client\" \"npm:dev:start\"",
"start": "node dist/server/bundle.js"
},
@ -43,6 +43,7 @@
"@types/express": "^4.17.9",
"@types/react": "^16.14.0",
"@types/react-dom": "^16.9.9",
"@types/react-howler": "^3.7.2",
"@typescript-eslint/eslint-plugin": "^4.8.1",
"@typescript-eslint/parser": "^4.8.1",
"babel-loader": "^8.2.1",
@ -52,6 +53,7 @@
"eslint-config-google": "^0.14.0",
"eslint-plugin-react": "^7.21.5",
"eslint-webpack-plugin": "^2.4.0",
"howler": "^2.2.1",
"nodemon": "^2.0.6",
"ts-node": "^9.0.0",
"typescript": "^4.1.2",
@ -65,6 +67,7 @@
"express": "^4.17.1",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-howler": "^5.0.0",
"shadertoy-react": "^1.1.1"
}
}

Bestand weergeven

@ -13,6 +13,11 @@ body {
overflow: hidden;
}
img {
width: 100%;
height: auto;
}
.shader {
padding: 0;
margin: 0;
@ -21,6 +26,7 @@ body {
}
.tile {
background-color: #000000;
display: inline-block;
vertical-align: top;
padding: 0;
@ -38,6 +44,28 @@ body {
width: 100%;
}
.tile-player {
animation: player 2s infinite;
}
.player-text {
color: #ebdbb2;
}
.loader {
border: 12px solid #ebdbb2;
border-top: 12px solid #458588;
border-radius: 50%;
height: 120px;
width: 120px;
animation: spin 2s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
#whoami {
background-color: #1d2021;
color: #ebdbb2;
@ -118,4 +146,15 @@ body {
71.42% {background-color: #d65d0e;}
85.71% {background-color: #cc241d;}
100% {background-color: #b16286;}
}
@keyframes player {
0% {background-color: #b1628633;}
14.28% {background-color: #45858833;}
28.57% {background-color: #689d6a33;}
42.85% {background-color: #98971a33;}
57.14% {background-color: #d7992133;}
71.42% {background-color: #d65d0e33;}
85.71% {background-color: #cc241d33;}
100% {background-color: #b1628633;}
}

Binair bestand niet weergegeven.

Voor

Breedte:  |  Hoogte:  |  Grootte: 2.4 MiB

Na

Breedte:  |  Hoogte:  |  Grootte: 544 KiB

Binair bestand niet weergegeven.

Voor

Breedte:  |  Hoogte:  |  Grootte: 2.6 MiB

Na

Breedte:  |  Hoogte:  |  Grootte: 781 KiB

Binair bestand niet weergegeven.

Voor

Breedte:  |  Hoogte:  |  Grootte: 2.4 MiB

Na

Breedte:  |  Hoogte:  |  Grootte: 778 KiB

Binair bestand niet weergegeven.

Voor

Breedte:  |  Hoogte:  |  Grootte: 2.2 MiB

Na

Breedte:  |  Hoogte:  |  Grootte: 724 KiB

Binair bestand niet weergegeven.

Voor

Breedte:  |  Hoogte:  |  Grootte: 2.3 MiB

Na

Breedte:  |  Hoogte:  |  Grootte: 700 KiB

Binair bestand niet weergegeven.

Voor

Breedte:  |  Hoogte:  |  Grootte: 2.3 MiB

Na

Breedte:  |  Hoogte:  |  Grootte: 735 KiB

Binair bestand niet weergegeven.

Voor

Breedte:  |  Hoogte:  |  Grootte: 2.6 MiB

Na

Breedte:  |  Hoogte:  |  Grootte: 874 KiB

Binair bestand niet weergegeven.

Voor

Breedte:  |  Hoogte:  |  Grootte: 2.8 MiB

Na

Breedte:  |  Hoogte:  |  Grootte: 850 KiB

Binair bestand niet weergegeven.

Voor

Breedte:  |  Hoogte:  |  Grootte: 3.3 MiB

Na

Breedte:  |  Hoogte:  |  Grootte: 1012 KiB

Binair bestand niet weergegeven.

Voor

Breedte:  |  Hoogte:  |  Grootte: 1.8 MiB

Na

Breedte:  |  Hoogte:  |  Grootte: 556 KiB

Binair bestand niet weergegeven.

Voor

Breedte:  |  Hoogte:  |  Grootte: 1.2 MiB

Na

Breedte:  |  Hoogte:  |  Grootte: 366 KiB

Binair bestand niet weergegeven.

Voor

Breedte:  |  Hoogte:  |  Grootte: 1.4 MiB

Na

Breedte:  |  Hoogte:  |  Grootte: 487 KiB

Binair bestand niet weergegeven.

Voor

Breedte:  |  Hoogte:  |  Grootte: 1.0 MiB

Binair bestand niet weergegeven.

Voor

Breedte:  |  Hoogte:  |  Grootte: 242 KiB

Bestand weergeven

@ -3,12 +3,13 @@ import React, {useState, useEffect} from 'react';
interface ClickMeProps {
windowSize: number;
setTrigger: any;
setBusy: any;
}
/**
* @return {jsx} a presentation of me
*/
export default function ClickMe({windowSize, setTrigger}: ClickMeProps) {
export default function ClickMe({windowSize, setTrigger, setBusy}: ClickMeProps) {
const [buttonClass, setButtonClass] = useState('');
useEffect(() => {
@ -29,11 +30,13 @@ export default function ClickMe({windowSize, setTrigger}: ClickMeProps) {
id='clickme'>
<button
type='button'
onClick={() => setTrigger(Math.random())}
onClick={() => {
setTrigger(Math.random());
setBusy(true);
}}
className={'d-inline btn btn-clickme ' + buttonClass}>
Click me !
</button>
<br />
</div>
);
};
};

Bestand weergeven

@ -27,11 +27,13 @@ export default function DownloadCV({windowSize}: DownloadCVProps) {
justify-content-center'
id='downloadcv'>
<a
href='https://git.gaetanbrochard.dev/gbrochar/expo-web'
href='/static/pdfs/CV_Gaetan_Brochard_2020.pdf'
download
rel="noopener noreferrer"
target="_blank"
className={'d-inline btn btn-mine ' + buttonClass}>
Download my CV
</a>
<br />
</div>
);
};
};

Bestand weergeven

@ -0,0 +1,46 @@
import React, {useState} from 'react';
import ReactHowler from 'react-howler';
interface PlayerProps {
src: string;
}
/**
* @return {jsx} The root component
*/
export default function Player({src}: PlayerProps) {
const [play, setPlay] = useState(false);
const [playText, setPlayText] = useState('Play');
function handlePlay() {
setPlay(!play);
if (play) {
setPlayText('Play');
} else {
setPlayText('Pause');
}
}
return (
<React.Fragment>
<ReactHowler
src={[src]}
playing={play}/>
<div
className='
tile-child tile-player d-flex
flex-column
align-items-center
justify-content-center'
id='clickme'>
<div className='lead player-text mb-4'>{src.split('/')[3].split('.')[0]}</div>
<button
type='button'
onClick={() => handlePlay()}
className={'d-inline btn btn-clickme btn-lg'}>
{playText}
</button>
</div>
</React.Fragment>
);
}

Bestand weergeven

@ -4,6 +4,7 @@ import WhoAmI from './WhoAmI';
import Git from './Git';
import DownloadCV from './DownloadCV';
import ClickMe from './ClickMe';
import Player from './Player';
/**
* @return {jsx} The root component
@ -12,7 +13,67 @@ export default function Root() {
const [windowSize, setWindowSize] = useState(0);
const [trigger, setTrigger] = useState(0);
const [content, setContent]: any = useState([]);
const [busy, setBusy]: any = useState(true);
const loader: Array<any> = [];
for (let i = 0; i < 5; i++) {
loader.push(
<div className='tile'>
<div
className='
tile-child
d-flex
flex-column
align-items-center
justify-content-center'>
<div className='d-inline loader'></div>
</div>
</div>);
}
loader.push(<div className='tile'><WhoAmI /></div>);
loader.push(
<div className='tile'>
<Git windowSize={windowSize} />
</div>);
for (let i = 0; i < 2; i++) {
loader.push(
<div className='tile'>
<div
className='
tile-child
d-flex
flex-column
align-items-center
justify-content-center'>
<div className='d-inline loader'></div>
</div>
</div>);
}
loader.push(
<div className='tile'>
<DownloadCV windowSize={windowSize} />
</div>);
loader.push(
<div className='tile'>
<ClickMe
windowSize={windowSize}
setTrigger={setTrigger}
setBusy={setBusy} />
</div>);
for (let i = 0; i < 5; i++) {
loader.push(
<div className='tile'>
<div
className='
tile-child
d-flex
flex-column
align-items-center
justify-content-center'>
<div className='d-inline loader'></div>
</div>
</div>);
}
const Shaders = [
'BaseRaymarching',
'Collapse',
@ -24,6 +85,16 @@ export default function Root() {
'BaseLattice',
];
const Sounds = [
'Collapse.mp3',
'Droplets.mp3',
'Heavy Ropes.mp3',
'Inception.mp3',
'Menstom.mp3',
'Speechless.mp3',
'Triangle.mp3',
];
const handleWindowResize = useCallback((_event) => {
setWindowSize(window.innerWidth);
}, []);
@ -35,52 +106,127 @@ export default function Root() {
}, [handleWindowResize]);
useEffect(() => {
let newContent = [];
let randomContent = [];
let shadersRandom = [];
let imagesRandom = [];
const newContent = [];
const randomContent = [];
const shadersRandom: Array<any> = [];
const imagesRandom: Array<any> = [];
const soundsRandom: Array<any> = [];
shadersRandom.push(Math.floor(Math.random() * 8));
shadersRandom.push(Math.floor(Math.random() * 8));
newContent.push(<div className='tile'><Shader name={Shaders[shadersRandom[0]]} /></div>);
newContent.push(<div className='tile'><Shader name={Shaders[shadersRandom[1]]} /></div>);
newContent.push(<div className='tile'><Shader name={Shaders[shadersRandom[2]]} /></div>);
newContent.push(<div className='tile'><Shader name={Shaders[shadersRandom[3]]} /></div>);
newContent.push(<div className='tile'><Shader name={Shaders[shadersRandom[4]]} /></div>);
for (let i = 0; i < 3; i++) {
shadersRandom.push(Math.floor(Math.random() * 8));
while (shadersRandom.indexOf(
shadersRandom[shadersRandom.length - 1]) !=
shadersRandom.length - 1) {
shadersRandom[shadersRandom.length - 1] += 1;
if (shadersRandom[shadersRandom.length - 1] == 8) {
shadersRandom[shadersRandom.length - 1] = 1;
}
}
}
for (let i = 0; i < 3; i++) {
shadersRandom[i] =
<div className='tile'>
<Shader name={Shaders[shadersRandom[i]]} />
</div>;
}
for (let i = 0; i < 7; i++) {
imagesRandom.push(Math.floor(Math.random() * 12) + 1);
while (imagesRandom.indexOf(
imagesRandom[imagesRandom.length - 1]) !=
imagesRandom.length - 1) {
imagesRandom[imagesRandom.length - 1] += 1;
if (imagesRandom[imagesRandom.length - 1] == 13) {
imagesRandom[imagesRandom.length - 1] = 1;
}
}
}
for (let i = 0; i < 7; i++) {
imagesRandom[i] =
<div className='tile'>
<img
src={'/static/images/' +
imagesRandom[i].toString() +
'.jpg'}>
</img>
</div>;
}
for (let i = 0; i < 2; i++) {
soundsRandom.push(Math.floor(Math.random() * 7));
}
if (soundsRandom[0] == soundsRandom[1]) {
soundsRandom[1] += 1;
if (soundsRandom[1] == 7) {
soundsRandom[1] = 0;
}
}
soundsRandom[0] = Sounds[soundsRandom[0]];
soundsRandom[1] = Sounds[soundsRandom[1]];
for (let i = 0; i < soundsRandom.length; i++) {
soundsRandom[i] =
<div className='tile'>
<Player src={'/static/sounds/' + soundsRandom[i]}/>
</div>;
}
while (shadersRandom.length ||
imagesRandom.length ||
soundsRandom.length) {
const random = Math.floor(Math.random() * 4);
if (random == 0) {
if (shadersRandom.length > 0) {
randomContent.push(shadersRandom[0]);
shadersRandom.shift();
}
} else if (random == 1) {
if (soundsRandom.length > 0) {
randomContent.push(soundsRandom[0]);
soundsRandom.shift();
}
} else {
if (imagesRandom.length > 0) {
randomContent.push(imagesRandom[0]);
imagesRandom.shift();
}
}
}
newContent.push(randomContent[0]);
newContent.push(randomContent[1]);
newContent.push(randomContent[2]);
newContent.push(randomContent[3]);
newContent.push(randomContent[4]);
newContent.push(<div className='tile'><WhoAmI /></div>);
newContent.push(<div className='tile'><Git windowSize={windowSize} /></div>);
newContent.push(<div className='tile'><Shader name={Shaders[shadersRandom[5]]} /></div>);
newContent.push(<div className='tile'><Shader name={Shaders[shadersRandom[6]]} /></div>);
newContent.push(<div className='tile'><DownloadCV windowSize={windowSize} /></div>);
newContent.push(<div className='tile'><ClickMe windowSize={windowSize} setTrigger={setTrigger} /></div>);
newContent.push(<div className='tile'><Shader name={Shaders[shadersRandom[7]]} /></div>);
newContent.push(<div className='tile'><Shader name={Shaders[shadersRandom[8]]} /></div>);
newContent.push(<div className='tile'><Shader name={Shaders[shadersRandom[9]]} /></div>);
newContent.push(<div className='tile'><Shader name={Shaders[shadersRandom[10]]} /></div>);
newContent.push(<div className='tile'><Shader name={Shaders[shadersRandom[11]]} /></div>);
newContent.push(
<div className='tile'>
<Git windowSize={windowSize} />
</div>);
newContent.push(randomContent[5]);
newContent.push(randomContent[6]);
newContent.push(
<div className='tile'>
<DownloadCV windowSize={windowSize} />
</div>);
newContent.push(
<div className='tile'>
<ClickMe
windowSize={windowSize}
setTrigger={setTrigger}
setBusy={setBusy} />
</div>);
newContent.push(randomContent[7]);
newContent.push(randomContent[8]);
newContent.push(randomContent[9]);
newContent.push(randomContent[10]);
newContent.push(randomContent[11]);
setContent(newContent);
setBusy(false);
}, [trigger]);
return (
<div id='root'>
{content}
{/* <div className='tile'><Shader name={Shaders[0]} /></div>
<div className='tile'><Shader name={Shaders[0]} /></div>
<div className='tile'><Shader name={Shaders[0]} /></div>
<div className='tile'><Shader name={Shaders[0]} /></div>
<div className='tile'><Shader name={Shaders[0]} /></div>
<div className='tile'><WhoAmI /></div>
<div className='tile'><Git windowSize={windowSize} /></div>
<div className='tile'><Shader name={Shaders[0]} /></div>
<div className='tile'><Shader name={Shaders[0]} /></div>
<div className='tile'><DownloadCV windowSize={windowSize} /></div>
<div className='tile'><ClickMe windowSize={windowSize} setTrigger={setTrigger} /></div>
<div className='tile'><Shader name={Shaders[0]} /></div>
<div className='tile'><Shader name={Shaders[0]} /></div>
<div className='tile'><Shader name={Shaders[0]} /></div>
<div className='tile'><Shader name={Shaders[0]} /></div>
<div className='tile'><Shader name={Shaders[0]} /></div> */}
{busy ? loader : content}
</div>
);
}

Bestand weergeven

@ -3,13 +3,13 @@ import path from 'path';
const app = express();
app.set('view engine', 'ejs')
app.set('view engine', 'ejs');
app.use('/static', express.static(path.join(__dirname, '../../public')));
app.use('/js', express.static(path.join(__dirname, '../../dist/client')));
app.get('/', (_req, res) => {
res.render('index');
})
});
app.listen(3000);
app.listen(3000);

Bestand weergeven

@ -16,8 +16,6 @@
"node_modules",
"config",
"views",
"build",
"dev",
"dist"
]
}