diff --git a/.gitignore b/.gitignore index bfa6a22..16acd49 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ -# Created by .ignore support plugin (hsz.mobi) +node_modules +dist +package-lock.json diff --git a/.idea/watcherTasks.xml b/.idea/watcherTasks.xml new file mode 100644 index 0000000..b5e959a --- /dev/null +++ b/.idea/watcherTasks.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml index 12103d1..fec098c 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -2,16 +2,30 @@ - - - - + - - - - - + + + + + + + + + + + + + + + + + + + + + + @@ -35,13 +50,22 @@ + + + + + + + + + @@ -72,7 +96,8 @@ - + + diff --git a/custom.d.ts b/custom.d.ts new file mode 100644 index 0000000..d623c6f --- /dev/null +++ b/custom.d.ts @@ -0,0 +1,24 @@ +declare module "*.svg" { + const content: string; + export default content; +} + +declare module "*.png" { + const content: string; + export default content; +} + +declare module "*.jpg" { + const content: string; + export default content; +} + +declare module "*.jpeg" { + const content: string; + export default content; +} + +declare module "*.gif" { + const content: string; + export default content; +} diff --git a/index.html b/index.html deleted file mode 100644 index 5beaf06..0000000 --- a/index.html +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - - - - - - Portfolio - - - - - - -
- currently opened photo -
-
- -
- a picture of me -

-
- -
- -
- - - - - - - diff --git a/js/content.js b/js/content.js deleted file mode 100644 index bd50621..0000000 --- a/js/content.js +++ /dev/null @@ -1,157 +0,0 @@ -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 `

${element}

`; - } else if (element.type === 'a') { - return ` ${element.text} `; - } else if (element.type === 'video') { - return ``; - } 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) => ` -
-
- ${date ? `

${date}

` : ''} -
-
-

${title}

- ${date ? `

${date}

` : ''} - ${picture ? `${picture}` : ''} - ${description ? `

${description}

` : ''} - ${more ? ` - - - ${showMore} - - ` - : (link ? `${link}` : '')} -
-
- `; - - 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; -}; diff --git a/js/main.js b/js/main.js deleted file mode 100644 index e75f2d3..0000000 --- a/js/main.js +++ /dev/null @@ -1,15 +0,0 @@ -(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'; -})(); diff --git a/package.json b/package.json new file mode 100644 index 0000000..e0460a0 --- /dev/null +++ b/package.json @@ -0,0 +1,35 @@ +{ + "name": "portfolio", + "version": "1.0.0", + "description": "An easily configurable portfolio.", + "private": true, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "build": "webpack" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/schmelczerandras/timeline.git" + }, + "keywords": [], + "author": "", + "license": "ISC", + "bugs": { + "url": "https://github.com/schmelczerandras/timeline/issues" + }, + "homepage": "https://github.com/schmelczerandras/timeline#readme", + "devDependencies": { + "clean-webpack-plugin": "^3.0.0", + "css-loader": "^3.4.0", + "file-loader": "^5.0.2", + "html-webpack-plugin": "^3.2.0", + "node-sass": "^4.13.0", + "prettier": "^1.19.1", + "sass-loader": "^8.0.0", + "style-loader": "^1.0.2", + "ts-loader": "^6.2.1", + "typescript": "^3.7.3", + "webpack": "^4.41.4", + "webpack-cli": "^3.3.10" + } +} diff --git a/content-en.json b/src/content/en.ts similarity index 56% rename from content-en.json rename to src/content/en.ts index bf30b2a..cafb688 100644 --- a/content-en.json +++ b/src/content/en.ts @@ -1,116 +1,138 @@ -{ - "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.jpg", - "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 the 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" - } -} +import me from "../static/me.jpg"; +import forex from "../static/forex.gif"; +import myNotes from "../static/my-notes.jpg"; +import processSimulator from "../static/process-simulator.jpg"; +import processSimulatorInput from "../static/process-simulator-input.jpg"; +import citySimulation from "../static/simulation.jpg"; +import color from "../static/color.jpg"; +import platform from "../static/platform.png"; +import photos from "../static/photos.jpg"; +import led from "../static/led.jpg"; + +export const content = { + config: { + showMore: "Show details", + showLess: "Show less" + }, + header: { + name: "András Schmelczer", + picture: me, + 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: forex, + 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: myNotes, + 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: processSimulator, + 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: processSimulatorInput, + 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: citySimulation, + 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 the 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: color, + 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: platform, + 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: photos, + description: "A simple web page where you can view my photos.", + link: "schmelczer.dev/photos" + }, + { + date: "2016 spring", + title: "Lights synchronised to music", + picture: led, + 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" + } +}; diff --git a/content-hu.json b/src/content/hu.js similarity index 98% rename from content-hu.json rename to src/content/hu.js index 8ccf347..a71fc99 100644 --- a/content-hu.json +++ b/src/content/hu.js @@ -1,93 +1,94 @@ -{ - "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" - } -} +/*{ + "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" + } +} +*/ diff --git a/src/index.html b/src/index.html new file mode 100644 index 0000000..3025e8b --- /dev/null +++ b/src/index.html @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + Portfolio + + +
+ currently opened photo +
+
+ +
+ a picture of me +

+
+ +
+ +
+ + + + diff --git a/static/avoid.jpg b/src/static/avoid.jpg similarity index 100% rename from static/avoid.jpg rename to src/static/avoid.jpg diff --git a/static/color.jpg b/src/static/color.jpg similarity index 100% rename from static/color.jpg rename to src/static/color.jpg diff --git a/static/forex.gif b/src/static/forex.gif similarity index 100% rename from static/forex.gif rename to src/static/forex.gif diff --git a/static/led.jpg b/src/static/led.jpg similarity index 100% rename from static/led.jpg rename to src/static/led.jpg diff --git a/static/led720.mp4 b/src/static/led720.mp4 similarity index 100% rename from static/led720.mp4 rename to src/static/led720.mp4 diff --git a/static/me.jpg b/src/static/me.jpg similarity index 100% rename from static/me.jpg rename to src/static/me.jpg diff --git a/static/my-notes.jpg b/src/static/my-notes.jpg similarity index 100% rename from static/my-notes.jpg rename to src/static/my-notes.jpg diff --git a/static/og-image.jpg b/src/static/og-image.jpg similarity index 100% rename from static/og-image.jpg rename to src/static/og-image.jpg diff --git a/static/og.jpg b/src/static/og.jpg similarity index 100% rename from static/og.jpg rename to src/static/og.jpg diff --git a/static/photos.jpg b/src/static/photos.jpg similarity index 100% rename from static/photos.jpg rename to src/static/photos.jpg diff --git a/static/platform.png b/src/static/platform.png similarity index 100% rename from static/platform.png rename to src/static/platform.png diff --git a/static/process-simulator-input.jpg b/src/static/process-simulator-input.jpg similarity index 100% rename from static/process-simulator-input.jpg rename to src/static/process-simulator-input.jpg diff --git a/static/process-simulator.jpg b/src/static/process-simulator.jpg similarity index 100% rename from static/process-simulator.jpg rename to src/static/process-simulator.jpg diff --git a/static/simulation.jpg b/src/static/simulation.jpg similarity index 100% rename from static/simulation.jpg rename to src/static/simulation.jpg diff --git a/css/elements.css b/src/styles/elements.scss similarity index 95% rename from css/elements.css rename to src/styles/elements.scss index 0d73b0a..fea9512 100644 --- a/css/elements.css +++ b/src/styles/elements.scss @@ -1,173 +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) - 1.5 * var(--line-width)); - 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; - } -} +/* 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) - 1.5 * var(--line-width)); + 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; + } +} diff --git a/src/styles/index.scss b/src/styles/index.scss new file mode 100644 index 0000000..5fe7048 --- /dev/null +++ b/src/styles/index.scss @@ -0,0 +1,3 @@ +@import "main"; +@import "elements"; +@import "page"; diff --git a/css/main.css b/src/styles/main.scss similarity index 96% rename from css/main.css rename to src/styles/main.scss index 10948fb..abda749 100644 --- a/css/main.css +++ b/src/styles/main.scss @@ -1,28 +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; - } -} +@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; + } +} diff --git a/css/page.css b/src/styles/page.scss similarity index 92% rename from css/page.css rename to src/styles/page.scss index 07c5d4f..0216114 100644 --- a/css/page.css +++ b/src/styles/page.scss @@ -1,130 +1,130 @@ -* { - margin: 0; - box-sizing: content-box; - color: var(--text-color); -} - -html { - background-color: #31343f; - background: var(--bg-color); -} - -body { - width: var(--width); - 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.125em "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; - } -} +* { + margin: 0; + box-sizing: content-box; + color: var(--text-color); +} + +html { + background-color: #31343f; + background: var(--bg-color); +} + +body { + width: var(--width); + 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.125em "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; + } +} diff --git a/src/ts/index.ts b/src/ts/index.ts new file mode 100644 index 0000000..7659d2c --- /dev/null +++ b/src/ts/index.ts @@ -0,0 +1,19 @@ +import { createPageFactory } from "./parser"; +import { content } from "../content/en"; + +import "../styles/index.scss"; + +(async () => { + const ids = { + pictureId: "header-pic", + nameId: "name", + aboutId: "about", + timelineId: "timeline", + emailId: "email", + photoViewerId: "photo-viewer", + photoId: "photo" + }; + + await createPageFactory(ids)(content); + document.body.style.visibility = "visible"; +})(); diff --git a/src/ts/parser.ts b/src/ts/parser.ts new file mode 100644 index 0000000..8bdbd36 --- /dev/null +++ b/src/ts/parser.ts @@ -0,0 +1,168 @@ +export const createPageFactory = ({ + nameId, + pictureId, + aboutId, + timelineId, + emailId, + photoId, + photoViewerId +}) => { + const createPage = content => { + const { config, header, timeline, footer } = content; + 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 `

${element}

`; + } else if (element.type === "a") { + return ` ${element.text} `; + } else if (element.type === "video") { + return ``; + } 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 + ) => ` +
+
+ ${date ? `

${date}

` : ""} +
+
+

${title}

+ ${date ? `

${date}

` : ""} + ${ + picture + ? `${picture}` + : "" + } + ${description ? `

${description}

` : ""} + ${ + more + ? ` + + + ${showMore} + + ` + : link + ? `${link}` + : "" + } +
+
+ `; + + 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 as any).toggleLongDescription = toggleLongDescriptionFactory(config); + (window as any).showPhoto = showPhoto; + + (window as any).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 createIdFactory = () => { + let id = 0; + return () => id++; + }; + const createId = createIdFactory(); + + const idToButtonId = id => `button_${id}`; + + const idToActivityId = id => `activity_${id}`; + + return createPage; +}; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..f7dca47 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "outDir": "./dist/", + "noImplicitAny": false, + "module": "es6", + "target": "es5", + "sourceMap": true, + "allowJs": true + } +} diff --git a/webpack.config.js b/webpack.config.js new file mode 100644 index 0000000..1c91461 --- /dev/null +++ b/webpack.config.js @@ -0,0 +1,48 @@ +const path = require("path"); +const HtmlWebpackPlugin = require("html-webpack-plugin"); +const { CleanWebpackPlugin } = require("clean-webpack-plugin"); + +module.exports = { + mode: "development", + devtool: "inline-source-map", + plugins: [ + new CleanWebpackPlugin(), + new HtmlWebpackPlugin({ + hash: true, + xhtml: true, + template: "./src/index.html" + }) + ], + entry: { + index: "./src/ts/index.ts" + }, + module: { + rules: [ + { + test: /\.s[ac]ss$/i, + use: ["style-loader", "css-loader", "sass-loader"] + }, + { + test: /\.tsx?$/, + use: "ts-loader", + exclude: /node_modules/ + }, + { + test: /\.(png|svg|jpe?g|gif)$/, + use: { + loader: "file-loader", + query: { + outputPath: "images" + } + } + } + ] + }, + resolve: { + extensions: [".ts"] + }, + output: { + filename: "[name].bundle.js", + path: path.resolve(__dirname, "dist") + } +};