Refactor js
12
.idea/CompiledCV.iml
generated
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/temp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/tmp" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
9
.idea/dictionaries/andras.xml
generated
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<component name="ProjectDictionaryState">
|
||||
<dictionary name="andras">
|
||||
<words>
|
||||
<w>andrás</w>
|
||||
<w>forex</w>
|
||||
<w>schmelczer</w>
|
||||
</words>
|
||||
</dictionary>
|
||||
</component>
|
||||
6
.idea/misc.xml
generated
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="JavaScriptSettings">
|
||||
<option name="languageLevel" value="ES6" />
|
||||
</component>
|
||||
</project>
|
||||
8
.idea/modules.xml
generated
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/CompiledCV.iml" filepath="$PROJECT_DIR$/.idea/CompiledCV.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
60
.idea/workspace.xml
generated
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="8edc47ab-1265-4111-9771-536b24cc9310" name="Default Changelist" comment="" />
|
||||
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||
</component>
|
||||
<component name="FileTemplateManagerImpl">
|
||||
<option name="RECENT_TEMPLATES">
|
||||
<list>
|
||||
<option value="JavaScript File" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectId" id="1UhDrRKewMzhTrQJ4npWjp729uJ" />
|
||||
<component name="PropertiesComponent">
|
||||
<property name="WebServerToolWindowFactoryState" value="false" />
|
||||
<property name="last_opened_file_path" value="$PROJECT_DIR$" />
|
||||
<property name="prettierjs.PrettierConfiguration.Package" value="/usr/local/lib/node_modules/prettier" />
|
||||
</component>
|
||||
<component name="RecentsManager">
|
||||
<key name="CopyFile.RECENT_KEYS">
|
||||
<recent name="$PROJECT_DIR$" />
|
||||
</key>
|
||||
</component>
|
||||
<component name="RunDashboard">
|
||||
<option name="ruleStates">
|
||||
<list>
|
||||
<RuleState>
|
||||
<option name="name" value="ConfigurationTypeDashboardGroupingRule" />
|
||||
</RuleState>
|
||||
<RuleState>
|
||||
<option name="name" value="StatusDashboardGroupingRule" />
|
||||
</RuleState>
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="SvnConfiguration">
|
||||
<configuration />
|
||||
</component>
|
||||
<component name="TaskManager">
|
||||
<task active="true" id="Default" summary="Default task">
|
||||
<changelist id="8edc47ab-1265-4111-9771-536b24cc9310" name="Default Changelist" comment="" />
|
||||
<created>1575800131097</created>
|
||||
<option name="number" value="Default" />
|
||||
<option name="presentableId" value="Default" />
|
||||
<updated>1575800131097</updated>
|
||||
<workItem from="1575800132288" duration="1444000" />
|
||||
<workItem from="1576164066512" duration="3000" />
|
||||
<workItem from="1576250286627" duration="21557000" />
|
||||
</task>
|
||||
<servers />
|
||||
</component>
|
||||
<component name="TypeScriptGeneratedFilesManager">
|
||||
<option name="version" value="1" />
|
||||
</component>
|
||||
</project>
|
||||
3
README.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# Timeline
|
||||
|
||||
An easily configurable portfolio.
|
||||
116
content-en.json
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
{
|
||||
"config": {
|
||||
"showMore": "Show details",
|
||||
"showLess": "Show less"
|
||||
},
|
||||
"header": {
|
||||
"name": "András Schmelczer",
|
||||
"picture": "/static/me.jpg",
|
||||
"about": [
|
||||
"I have always been fascinated by the engineering feats that surround us. When I realized that someday I might be able to contribute to these achievements, I knew that is what I need to aim for. As I am finishing my fifth semester at the Budapest University of Technology and Economics, I feel I am getting closer to it every day.",
|
||||
"You can see some of the more interesting projects I have worked on below."
|
||||
]
|
||||
},
|
||||
"timeline": [
|
||||
{
|
||||
"date": "2019 Autumn",
|
||||
"title": "Predicting foreign exchange rates",
|
||||
"picture": "/static/forex.gif",
|
||||
"description": "From the animation we can see that my algorithm does a somewhat acceptable job at predicting (blue graph) the EUR/USD rates (green graph).",
|
||||
"more": [
|
||||
"In a nutshell, the algorithm (written with Python - NumPy, SciPy, Flask), extrapolates in the frequency domain. The steps are the following: smoothing the input values, differentiating, applying a short-time Fourier-transformation with overlapped (and Hanning-windowed) windows, extrapolating and then applying the inverse of these transformations to the extrapolated values.",
|
||||
"Of course, there is still plenty of room for improvement, but even with this simple algorithm a mostly profitable trading strategy is viable. In my free time I may put more work into it."
|
||||
]
|
||||
},
|
||||
{
|
||||
"date": "2019 November",
|
||||
"title": "My Notes",
|
||||
"picture": "/static/my-notes.png",
|
||||
"description": "A minimalist note organizer and editor powered by Markwon.",
|
||||
"more": [
|
||||
{ "type": "a", "href": "https://github.com/schmelczerandras/my-notes", "text": "MyNotes on GitHub" },
|
||||
"A basic android app for creating and filtering notes written in markdown.",
|
||||
"It was my homework for BME's Android and web development course. It was also my first experience with Android development."
|
||||
]
|
||||
},
|
||||
{
|
||||
"date": "2018 October - November",
|
||||
"title": "Simulating the cooling system of a nuclear facility",
|
||||
"picture": "/static/process-simulator.jpg",
|
||||
"description": "Dynamically calculating the temperatures and flow velocities in a fluid based cooling system based on a simple model.",
|
||||
"more": [
|
||||
"A simulated system can contain reactors (heaters / coolers), pumps, heat exchangers, drains sources, and of course, pipes.",
|
||||
"The algorithm takes advantages of graphs and matrices to get to a next time frame.",
|
||||
"Python is used for the backend along with Flask and NumPy. A REST API facilitates the communication between the layers. For drawing the frontend HTML5 canvas is utilized."
|
||||
]
|
||||
},
|
||||
{
|
||||
"date": "2018 October - November",
|
||||
"title": "Graph editing application",
|
||||
"picture": "/static/process-simulator-input.jpg",
|
||||
"description": "An intuitive editor to create and edit input files for the nuclear facility simulator.",
|
||||
"more": [
|
||||
"Nodes can be moved with drag&drop gestures. Editing the parameters of elements can be done on the right panel.",
|
||||
"The UI is built with JavaFX. The output can be exported as JSON or directly uploaded to the simulation backend."
|
||||
]
|
||||
},
|
||||
{
|
||||
"date": "2018 July-August",
|
||||
"title": "City simulation",
|
||||
"picture": "/static/simulation.jpg",
|
||||
"description": "Simulating a city where car crashes are more frequent than usual.",
|
||||
"more": [
|
||||
"Through a REST API the state of the traffic lights can be changed. The drivers follow the instructions of the traffic lights, so if a mistake is made, there will be collisions. There is also support for displaying tweets on a HUD.",
|
||||
"This was created for a Cybersecurity challenge. With the help of this program tha contestants could instantly see the effect of their work.",
|
||||
"The most interesting aspect of this project was building it in a server-client architecture. The decisions of the agents is calculated server-side. The real challenge was broadcasting these decisions in a fault-tolerant way using minimal bandwidth.",
|
||||
"The program is made with Unity using C# as the scripting language. The models and animations were also made by me using Blender."
|
||||
]
|
||||
},
|
||||
{
|
||||
"date": "2018 June",
|
||||
"title": "Photo color grader",
|
||||
"picture": "/static/color.jpg",
|
||||
"description": "An innovative (at least I thought so) color grader web application.",
|
||||
"more": [
|
||||
"The most noteworthy feature of this application is the color selector UI. This program is only intended as a proof-of-concept, I wanted to experiment with some ideas and this was the outcome. ",
|
||||
"You can select some colors and then apply transformations to the other colors as a function of their distance to the selected color.",
|
||||
"By clicking on a colored circle you can change its settings. New circles can be created by clicking in the large circle (and they can also be moved by drag&drop).",
|
||||
{ "type": "a", "href": "color", "text": "schmelczer.dev/color" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"date": "2017 autumn",
|
||||
|
||||
"title": "Platform game",
|
||||
"picture": "/static/platform.png",
|
||||
"description": "A 3D game written in C with the help of SDL 1.2 (I haven't heard of GPU programming at the time).",
|
||||
"more": [
|
||||
"The maps are randomly generated and fully destroyable. The player is getting chased by flying enemies. Overall, I find it a really enjoyable game.",
|
||||
"I did this as a homework for my Basics of Programming course."
|
||||
]
|
||||
},
|
||||
{
|
||||
"date": "2016 summer",
|
||||
"title": "Photos",
|
||||
"picture": "/static/photos.jpg",
|
||||
"description": "A simple web page where you can view my photos.",
|
||||
"link": "schmelczer.dev/photos"
|
||||
},
|
||||
{
|
||||
"date": "2016 spring",
|
||||
"title": "Lights synchronised to music",
|
||||
"picture": "/static/led.jpg",
|
||||
"description": "A full stack application with a built-in music player which music controls the color of some RGB LED strips.",
|
||||
"more": [
|
||||
"This was my first non-trivial project which got finished. Obviously, it is rather far from perfect, but I am still proud that I was able to build it on my own.",
|
||||
"The backend logic is written in Python the FFT is provided by NumPy. A quite simple frontend for accessing the music player and changing the settings also got built using vanilla web development technologies.",
|
||||
"Below is a video showing the system in work.",
|
||||
{ "type": "video", "src": "static/led720.mp4" }
|
||||
]
|
||||
}
|
||||
],
|
||||
"footer": {
|
||||
"email": "andras.schmelczer@schdesign.hu",
|
||||
"cv": "/static/andras_schmelczer_cv.pdf"
|
||||
}
|
||||
}
|
||||
93
content-hu.json
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
{
|
||||
"header": {
|
||||
"name": "Schmelczer András",
|
||||
"picture": "/static/me.jpg",
|
||||
"about": [
|
||||
"Mind a szoftverfejlesztés, mind pedig a design fontos számomra. Élvezem a problémák megoldását. Motivál, hogy hasznos és érdekes projektekben vegyek részt. Szeretek tanulni.",
|
||||
|
||||
"2017-ben kezdtem tanulmányaimat a Budapesti Műszaki és Gazdaságtudományi Egyetem mérnökinformatikus szakán. Azóta is minden félévemet kiváló eredménnyel zártam. Tavaly csatlakoztam a Simonyi Károly Szakkollégium schdesign köréhez. Korábban a Pécsi Tudományegyetem Gyakorló Gimnáziumába jártam, mialatt angol komplex C1-es nyelvvizsgát is szereztem.",
|
||||
|
||||
"Az alábbiakban összeszedtem pár izgalmasabb projektemet. A képekből természetesen csak a megoldások megjelenítés részét lehet látni. Emellett azonban igyekeztem a háttérben zajló folyamatokról is írni, hiszen az igazi kihívások általában ott rejlenek."
|
||||
]
|
||||
},
|
||||
"timeline": [
|
||||
{
|
||||
"date": "2018 október - november",
|
||||
"title": "Atomreaktor hűtőrendszerének szimulációja",
|
||||
"picture": "/static/process-simulator.jpg",
|
||||
"description": "Egy csőrendszerben lévő víz hőmérsékletének és áramlásának dinamikus számítása.",
|
||||
"more": [
|
||||
"A reaktorok (vízmelegítők), szivattyúk, hőcserélők adataiból és a csőrendszer felépítéséből kiszámolja az alkalmazás, hogy melyik időpillanatban hol, mennyi víz folyik, és az milyen meleg.",
|
||||
"Ezt egy érdekes gráfelméleti algoritmussal, illetve egy mátrix ügyes manipulálásával éri el.",
|
||||
"A szimuláció backendje python Flask-ben lett írva. Ezzel kommunikálni egy REST API-n keresztül lehet. A megjelenítés HTML5 canvas segítségével történik."
|
||||
]
|
||||
},
|
||||
{
|
||||
"date": "2018 október - november",
|
||||
"title": "Gráf szerkesztő alkalmazás",
|
||||
"picture": "/static/process-simulator-input.jpg",
|
||||
"description": "A fentebb látható szoftverhez tartozó csőrendszert lehet vele létrehozni.",
|
||||
"more": [
|
||||
"A grafikus és felhasználóbarát szerkesztőprogram a végeredményt megfelelő JSON formátumba alakítja, amit a szimulátor már könnyedén fel tud dolgozni.",
|
||||
"Szerkeszteni klikkeléssel, illetve drag & droppal lehetséges. Az alkalmazásban továbbá lehet a vízmelegítők, szivattyúk stb. paramétereit is beállítani.",
|
||||
"Java-ban lett írva, a megjelenítést a JavaFX biztosítja."
|
||||
]
|
||||
},
|
||||
{
|
||||
"date": "2018 július - augusztus",
|
||||
"title": "Közlekedés szimuláció",
|
||||
"picture": "/static/sim.jpg",
|
||||
"description": "A modellek Blenderben, a szimuláció Unityben készült.",
|
||||
"more": [
|
||||
"Egy versenyhez készült program. REST API-kon keresztül lehet a lámpák színét változtatni és a szimulációt befolyásolni, (akár még tweet-et is lehet beküldeni), az autók pedig ettől függően közlekednek, esetlegesen karamboloznak és felrobbannak.",
|
||||
"Az egész érdekessége, hogy egy szerver-kliens architektúrát valósít meg, a szervezés egyszerűbbé tétele végett. Izgalmas kihívás volt a netes kommunikációból fakadó laggot kompenzálni.",
|
||||
"Az összes képen látható modellt és animációt én készítettem. A scriptelés C# segítségével történt."
|
||||
]
|
||||
},
|
||||
{
|
||||
"date": "2018 június",
|
||||
"title": "Színszerkesztő",
|
||||
"picture": "/static/szinezo.jpg",
|
||||
"description": "Egy innovatív color grader képekhez.",
|
||||
"more": [
|
||||
"Ki lehet választani bizonyos színeket, és a többi színt az előbbiektől lévő távolságának függvényében lehet módosítani, telitettséget, színezettségét változtatni.",
|
||||
"Egyelőre proof of concept stádiumban van, viszont tervezem befejezni.",
|
||||
"A színes gombokra való kattintással lehet az opciók közt váltani. Színes gombot a nagy körbe való kattintással lehet létrehozni (mozgatni pedig drag & droppal).",
|
||||
{ "type": "a", "href": "/szinezo", "text": "schmelczer.hu/szinezo" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"date": "2017 ősz",
|
||||
"title": "Platform játék",
|
||||
"picture": "/static/platform.png",
|
||||
"description": "Írtam egy 3D-s játékot C-ben az SDL 1.2 segítségével.",
|
||||
"more": [
|
||||
"A pályák véletlenszerűen generálódnak, menthetők és rombolhatók is. A játékost repülő ellenségek üldözik.",
|
||||
"Ez volt a Programozás alapjai I. tárgyhoz készített házifeladatom. Összességében egy élvezhető játék lett.",
|
||||
{ "type": "a", "href": "/platform", "text": "schmelczer.hu/platform" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"date": "2016 nyár",
|
||||
"title": "Fényképek",
|
||||
"picture": "/static/kepek.jpg",
|
||||
"description": "Csináltam egy oldalt, ahol a fényképeimet lehet megnézni.",
|
||||
"link": "schmelczer.hu/kepek"
|
||||
},
|
||||
{
|
||||
"date": "2016 tavasz",
|
||||
"title": "Zenére világító ledsorok",
|
||||
"picture": "/static/LED.jpg",
|
||||
"description": "Egy alkalmazást készítettem, amivel RGB ledsorok színét lehet a zene ritmusára változtatni.",
|
||||
"more": [
|
||||
"Ez volt az első nagyobb projektem, ez természetesen a megvalósítás minőségén is érezhető. Ettől független büszke vagyok a végeredményre.",
|
||||
"Pythonban lett írva, amivel egy webes frontenden keresztül lehet kommunikálni. Továbbá beépítésre került egy zenelejátszó is a programba.",
|
||||
"A működő rendszerről készítettem egy videót, ami alább tekinthető meg.",
|
||||
{ "type": "video", "src": "static/led720.mp4" }
|
||||
]
|
||||
}
|
||||
],
|
||||
"footer": {
|
||||
"email": "andras.schmelczer@schdesign.hu"
|
||||
}
|
||||
}
|
||||
173
css/elements.css
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
/* X sign visible in the photo viewer mode. */
|
||||
#exit {
|
||||
position: absolute;
|
||||
width: var(--exit-size);
|
||||
height: var(--exit-size);
|
||||
top: var(--exit-size);
|
||||
right: var(--exit-size);
|
||||
cursor: pointer;
|
||||
}
|
||||
#exit:before,
|
||||
#exit:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: var(--line-width);
|
||||
height: calc(var(--exit-size) * 1.4142);
|
||||
background: white;
|
||||
border-radius: var(--border-radius);
|
||||
top: calc(var(--exit-size) * -0.4142 / 2);
|
||||
left: 50%;
|
||||
}
|
||||
#exit:before {
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
#exit:after {
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
/**/
|
||||
|
||||
/* Links with interactive underline. */
|
||||
a {
|
||||
text-decoration: none;
|
||||
position: relative;
|
||||
border-bottom: solid 3px var(--light-accent-color);
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
}
|
||||
a:after {
|
||||
content: "";
|
||||
height: var(--line-width);
|
||||
background-color: var(--accent-color);
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: calc(-1 * var(--line-width));
|
||||
width: 0;
|
||||
transition: width var(--transition-time);
|
||||
}
|
||||
a:hover:after {
|
||||
width: 100%;
|
||||
}
|
||||
/**/
|
||||
|
||||
/* Line with circle for the timeline sections. */
|
||||
.line {
|
||||
margin-left: calc(var(--dot-size) / 2);
|
||||
margin-right: var(--line-height);
|
||||
border-left: var(--line-width) solid var(--text-color);
|
||||
position: relative;
|
||||
}
|
||||
.line:before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: calc(-1 / 2 * var(--dot-size) - 4px);
|
||||
background: var(--bg-color);
|
||||
top: 33%;
|
||||
width: var(--dot-size);
|
||||
height: var(--dot-size);
|
||||
border-radius: 100%;
|
||||
border: var(--line-width) var(--text-color) solid;
|
||||
}
|
||||
/**/
|
||||
|
||||
/* Activity cards. */
|
||||
.card {
|
||||
border-radius: var(--border-radius);
|
||||
text-align: center;
|
||||
padding: var(--margin);
|
||||
box-shadow: 0 0 5px rgba(0, 0, 0, 0.125);
|
||||
transition: box-shadow;
|
||||
transition-duration: var(--transition-time);
|
||||
background: var(--card-color);
|
||||
}
|
||||
.card:hover {
|
||||
box-shadow: 0 0 3px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
/**/
|
||||
|
||||
/* Dates related to the lines and cards. */
|
||||
.date-narrow-screen,
|
||||
.date-wide-screen {
|
||||
font: 400 1em "Open sans", sans-serif;
|
||||
}
|
||||
.date-narrow-screen {
|
||||
display: none;
|
||||
margin: 0;
|
||||
margin-top: calc(var(--line-height) / 2.25) !important;
|
||||
color: var(--light-text-color);
|
||||
}
|
||||
.date-wide-screen {
|
||||
position: relative;
|
||||
top: calc(33% + var(--dot-size) + 1ch);
|
||||
margin: 0 var(--margin) 0 calc(var(--line-width) + 1ex);
|
||||
width: 100px;
|
||||
}
|
||||
/**/
|
||||
|
||||
/* The photo viewer */
|
||||
#photo-viewer {
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background: var(--photo-viewer-color);
|
||||
z-index: -3;
|
||||
opacity: 0;
|
||||
transition: opacity var(--transition-time);
|
||||
}
|
||||
|
||||
/* #photo */
|
||||
#photo-viewer > img {
|
||||
max-width: 80vw;
|
||||
max-height: 80vh;
|
||||
}
|
||||
/**/
|
||||
|
||||
/* Scrollbar. */
|
||||
body::-webkit-scrollbar-track,
|
||||
body::-webkit-scrollbar {
|
||||
background-color: var(--scroll-color);
|
||||
width: 12px;
|
||||
}
|
||||
body::-webkit-scrollbar-thumb {
|
||||
background-color: var(--accent-color);
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
/**/
|
||||
|
||||
/* Selections. */
|
||||
::-moz-selection {
|
||||
background: var(--accent-color);
|
||||
color: white;
|
||||
}
|
||||
::selection {
|
||||
background: var(--accent-color);
|
||||
color: white;
|
||||
}
|
||||
/**/
|
||||
|
||||
/* Absolute centering parent. */
|
||||
.center {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
/**/
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.line {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Disable animation. */
|
||||
.card:hover {
|
||||
box-shadow: 0 0 5px rgba(0, 0, 0, 0.125);
|
||||
}
|
||||
|
||||
.date-narrow-screen {
|
||||
display: block;
|
||||
}
|
||||
.date-wide-screen {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
28
css/main.css
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
@import url('https://fonts.googleapis.com/css?family=Open+Sans:400,400i|Raleway&subset=latin-ext');
|
||||
|
||||
:root {
|
||||
--photo-viewer-color: rgba(0, 0, 0, 0.75);
|
||||
--accent-color: #5264bf;
|
||||
--light-accent-color: #e5e5ff;
|
||||
--scroll-color: #ffd6d6;
|
||||
--bg-color:linear-gradient(90deg, #fff9e0 0, #ffd6d6 100%);
|
||||
--card-color: white;
|
||||
--text-color: #31343f;
|
||||
--light-text-color: #7a7d8e;
|
||||
--dot-size: 25px;
|
||||
--line-width: 3px;
|
||||
--exit-size: 25px;
|
||||
--line-height: 15px;
|
||||
--smaller-margin: 25px;
|
||||
--margin: 35px;
|
||||
--border-radius: 5px;
|
||||
--transition-time: 200ms;
|
||||
--width: 765px;
|
||||
}
|
||||
@media (max-width: 900px) {
|
||||
:root {
|
||||
--exit-size: 20px;
|
||||
--margin: 25px;
|
||||
--smaller-margin: 20px;
|
||||
}
|
||||
}
|
||||
131
css/page.css
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
* {
|
||||
margin: 0;
|
||||
box-sizing: content-box;
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
html {
|
||||
background-color: #31343f;
|
||||
background: var(--bg-color);
|
||||
}
|
||||
|
||||
body {
|
||||
width: var(--width);
|
||||
font-size: 0.9em;
|
||||
margin: auto;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
header,
|
||||
footer,
|
||||
#timeline,
|
||||
#about > p:first-of-type,
|
||||
#timeline > section:not(:first-of-type) > .card {
|
||||
margin-top: var(--margin);
|
||||
}
|
||||
|
||||
#header-pic,
|
||||
h1 {
|
||||
font: 400 3.33em "Raleway", sans-serif;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#header-pic {
|
||||
height: 4ch;
|
||||
border-radius: 100%;
|
||||
margin-right: 1.5ex;
|
||||
}
|
||||
|
||||
p,
|
||||
a {
|
||||
font: 400 1.25em "Open sans", sans-serif;
|
||||
}
|
||||
|
||||
#about > p {
|
||||
text-align: justify;
|
||||
hyphens: auto;
|
||||
}
|
||||
|
||||
#timeline > section {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.card {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
#about > p,
|
||||
.card > *:not(:first-child):not(:last-child),
|
||||
.collapsed > *:not(:first-child) {
|
||||
margin-top: var(--line-height);
|
||||
}
|
||||
|
||||
h2 {
|
||||
font: 400 2em "Raleway", sans-serif;
|
||||
}
|
||||
|
||||
.card img,
|
||||
video {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
img {
|
||||
user-select: none;
|
||||
border-radius: var(--border-radius);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.description {
|
||||
font-style: italic;
|
||||
margin-bottom: var(--smaller-margin);
|
||||
}
|
||||
|
||||
.collapsed > p {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.collapsed {
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
transition: height var(--transition-time);
|
||||
}
|
||||
.collapsed > *:last-child {
|
||||
margin-bottom: var(--smaller-margin);
|
||||
}
|
||||
|
||||
footer {
|
||||
margin-bottom: var(--margin);
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
body {
|
||||
width: 85%;
|
||||
font-size: 0.85em;
|
||||
}
|
||||
|
||||
#photo {
|
||||
max-width: 94vw;
|
||||
}
|
||||
|
||||
.card {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
header {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
h1,
|
||||
#header-pic {
|
||||
font-size: 3em;
|
||||
}
|
||||
|
||||
#header-pic {
|
||||
height: 5.5ch;
|
||||
margin: 0.75ex 0 0.5ex 0;
|
||||
}
|
||||
|
||||
#about > p {
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
BIN
favicon.ico
Normal file
|
After Width: | Height: | Size: 14 KiB |
48
index.html
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
|
||||
<meta property="og:image:width" content="1744" />
|
||||
<meta property="og:image:height" content="913" />
|
||||
<meta
|
||||
property="og:description"
|
||||
content="This is my portfolio where you can see my previous projects on a timeline."
|
||||
/>
|
||||
<meta property="og:title" content="András Schmelczer" />
|
||||
<meta property="og:url" content="https://schmelczer.dev/" />
|
||||
<meta
|
||||
property="og:image"
|
||||
content="https://schmelczer.dev/static/og-image.jpg"
|
||||
/>
|
||||
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<meta name="theme-color" content="#31343F" />
|
||||
|
||||
<title>Portfolio</title>
|
||||
|
||||
<link rel="stylesheet" href="css/main.css" />
|
||||
<link rel="stylesheet" href="css/elements.css" />
|
||||
<link rel="stylesheet" href="css/page.css" />
|
||||
</head>
|
||||
<body>
|
||||
<section class="center" id="photo-viewer">
|
||||
<img id="photo" alt="currently opened photo" src=""/>
|
||||
<div id="exit"></div>
|
||||
</section>
|
||||
|
||||
<header class="center">
|
||||
<img id="header-pic" alt="a picture of me" src=""/>
|
||||
<h1 id="name"></h1>
|
||||
</header>
|
||||
|
||||
<section id="about"></section>
|
||||
|
||||
<main id="timeline"></main>
|
||||
|
||||
<footer class="card center"><a id="email"></a></footer>
|
||||
</body>
|
||||
|
||||
<script src="js/content.js"></script>
|
||||
<script src="js/main.js"></script>
|
||||
</html>
|
||||
157
js/content.js
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
const createPageFactory = ({
|
||||
nameId,
|
||||
pictureId,
|
||||
aboutId,
|
||||
timelineId,
|
||||
emailId,
|
||||
photoId,
|
||||
photoViewerId,
|
||||
}) => {
|
||||
const createPage = async (src) => {
|
||||
const {config, header, timeline, footer} = await getData(src);
|
||||
processHeader(header);
|
||||
processTimeline(timeline, config);
|
||||
processFooter(footer);
|
||||
setupGlobals(config);
|
||||
};
|
||||
|
||||
const processHeader = ({name, picture, about}) => {
|
||||
document.title = name;
|
||||
getElement(nameId).textContent = name;
|
||||
getElement(pictureId).src = picture;
|
||||
getElement(pictureId).onclick = () => showPhoto(picture);
|
||||
getElement(aboutId).innerHTML = listToHtml(about);
|
||||
};
|
||||
|
||||
const listToHtml = list => list.map(element => {
|
||||
if (!element.type || element.type === 'p') {
|
||||
return `<p>${element}</p>`;
|
||||
} else if (element.type === 'a') {
|
||||
return `<a href="${element.href}" target="_blank"> ${element.text} </a>`;
|
||||
} else if (element.type === 'video') {
|
||||
return `<video controls><source src="${element.src}" /></video>`;
|
||||
} else return '';
|
||||
}).join('\n');
|
||||
|
||||
const processTimeline = (timeline, {showMore}) => {
|
||||
getElement(timelineId).innerHTML = timeline.map(
|
||||
element => timelineElementToHTML(element, createId(), showMore)
|
||||
).join('\n');
|
||||
};
|
||||
|
||||
const timelineElementToHTML = ({date, title, picture, description, more, link}, id, showMore) => `
|
||||
<section>
|
||||
<div class="line">
|
||||
${date ? `<p class="date-wide-screen">${date}</p>` : ''}
|
||||
</div>
|
||||
<div class="card">
|
||||
<h2>${title}</h2>
|
||||
${date ? `<p class="date-narrow-screen">${date}</p>` : ''}
|
||||
${picture ? `<img src="${picture}" onclick="showPhoto('${picture}');" alt="${picture}"/>` : ''}
|
||||
${description ? `<p class="description">${description}</p>` : ''}
|
||||
${more ? `
|
||||
<div class="collapsed" id="${idToActivityId(id)}">
|
||||
${listToHtml(more)}
|
||||
</div>
|
||||
<a id="${idToButtonId(id)}" onclick="toggleLongDescription(${id})">
|
||||
${showMore}
|
||||
</a>
|
||||
`
|
||||
: (link ? `<a href="http://${link}" target="_blank">${link}</a>` : '')}
|
||||
</div>
|
||||
</section>
|
||||
`;
|
||||
|
||||
const processFooter = ({email}) => {
|
||||
getElement(emailId).href = `mailto:${email}`;
|
||||
getElement(emailId).textContent = email;
|
||||
};
|
||||
|
||||
const hideFrame = () => {
|
||||
getElement(photoViewerId).style['z-index'] = -1;
|
||||
getElement(photoViewerId).style.opacity = '0';
|
||||
};
|
||||
|
||||
const showPhoto = src => {
|
||||
getElement(photoId).src = src;
|
||||
getElement(photoViewerId).style['z-index'] = 1000;
|
||||
getElement(photoViewerId).style.opacity = '1';
|
||||
};
|
||||
|
||||
const setupGlobals = config => {
|
||||
window.toggleLongDescription = toggleLongDescriptionFactory(config);
|
||||
window.showPhoto = showPhoto;
|
||||
|
||||
window.hideFrame = hideFrame;
|
||||
getElement(photoViewerId).addEventListener('click', hideFrame);
|
||||
|
||||
window.addEventListener('resize', onResize);
|
||||
document.body.addEventListener('keydown', handleEscape);
|
||||
};
|
||||
|
||||
const toggleLongDescriptionFactory = ({showMore, showLess}) => (id) => {
|
||||
const button = getElement(idToButtonId(id));
|
||||
const element = getElement(idToActivityId(id));
|
||||
|
||||
if (isClosed(element)) {
|
||||
open(element);
|
||||
button.textContent = showLess;
|
||||
} else {
|
||||
close(element);
|
||||
button.textContent = showMore;
|
||||
}
|
||||
};
|
||||
|
||||
const onResize = () => {
|
||||
const elements = document.getElementsByClassName('collapsed');
|
||||
Array.prototype.forEach.call(elements, element => {
|
||||
if (isOpen(element)) {
|
||||
element.style.height = 'auto';
|
||||
setTimeout(() => open(element), 100);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const isClosed = element => ['0px', '0', 0, ''].includes(element.style.height);
|
||||
|
||||
const isOpen = element => !isClosed(element);
|
||||
|
||||
const close = element => element.style.height = '0';
|
||||
|
||||
const open = element => element.style.height = `${element.scrollHeight}px`;
|
||||
|
||||
const handleEscape = event => {
|
||||
if (event.key === 'Escape') {
|
||||
hideFrame();
|
||||
}
|
||||
};
|
||||
|
||||
const getElementFactory = () => {
|
||||
const foundElements = {};
|
||||
return id => {
|
||||
if (!(id in foundElements)) {
|
||||
foundElements[id] = document.getElementById(id);
|
||||
}
|
||||
return foundElements[id];
|
||||
}
|
||||
};
|
||||
const getElement = getElementFactory();
|
||||
|
||||
const getData = async (src) => await (await fetch(src, {
|
||||
method: 'GET',
|
||||
mode: 'cors',
|
||||
cache: 'no-cache'
|
||||
})).json();
|
||||
|
||||
const createIdFactory = () => {
|
||||
let id = 0;
|
||||
return () => id++;
|
||||
};
|
||||
const createId = createIdFactory();
|
||||
|
||||
const idToButtonId = (id) => `button_${id}`;
|
||||
|
||||
const idToActivityId = (id) => `activity_${id}`;
|
||||
|
||||
return createPage;
|
||||
};
|
||||
15
js/main.js
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
(async () => {
|
||||
const src = 'content-en.json';
|
||||
const ids = {
|
||||
pictureId: 'header-pic',
|
||||
nameId: 'name',
|
||||
aboutId: 'about',
|
||||
timelineId: 'timeline',
|
||||
emailId: 'email',
|
||||
photoViewerId: 'photo-viewer',
|
||||
photoId: 'photo'
|
||||
};
|
||||
|
||||
await createPageFactory(ids)(src);
|
||||
document.body.style.visibility = 'visible';
|
||||
})();
|
||||
BIN
static/avoid.jpg
Normal file
|
After Width: | Height: | Size: 93 KiB |
BIN
static/color.jpg
Normal file
|
After Width: | Height: | Size: 570 KiB |
BIN
static/forex.gif
Normal file
|
After Width: | Height: | Size: 475 KiB |
BIN
static/led.jpg
Normal file
|
After Width: | Height: | Size: 95 KiB |
BIN
static/led720.mp4
Normal file
BIN
static/me.jpg
Normal file
|
After Width: | Height: | Size: 135 KiB |
BIN
static/my-notes.png
Executable file
|
After Width: | Height: | Size: 2 MiB |
BIN
static/og-image.jpg
Normal file
|
After Width: | Height: | Size: 227 KiB |
BIN
static/photos.jpg
Normal file
|
After Width: | Height: | Size: 366 KiB |
BIN
static/platform.png
Normal file
|
After Width: | Height: | Size: 45 KiB |
BIN
static/process-simulator-input.jpg
Normal file
|
After Width: | Height: | Size: 105 KiB |
BIN
static/process-simulator.jpg
Normal file
|
After Width: | Height: | Size: 144 KiB |
BIN
static/simulation.jpg
Normal file
|
After Width: | Height: | Size: 457 KiB |