`
- : ""
+ : ''
}
- ${link ? PageContent.parseTypedContent(link) : ""}
+ ${link ? link.toHTML() : ''}
`;
diff --git a/src/page/timeline/timeline-element/timeline-element.scss b/src/page/timeline/timeline-element/timeline-element.scss
index 36d9afa..1350f30 100644
--- a/src/page/timeline/timeline-element/timeline-element.scss
+++ b/src/page/timeline/timeline-element/timeline-element.scss
@@ -76,8 +76,9 @@
@include sub-title-font();
}
- .description {
+ & > p {
font-style: italic;
+ text-align: center;
}
.more {
diff --git a/src/page/timeline/timeline-element/timeline-element.ts b/src/page/timeline/timeline-element/timeline-element.ts
index 0cca8b4..e9f137a 100644
--- a/src/page/timeline/timeline-element/timeline-element.ts
+++ b/src/page/timeline/timeline-element/timeline-element.ts
@@ -18,16 +18,15 @@ export class PageTimelineElement extends PageElement {
if (timelineElement.more) {
const content = new PageContent(timelineElement.more);
- super([content]);
+ super(root, [content]);
this.isOpen = false;
this.more = root.querySelector('.more');
- this.more.appendChild(content.getElement());
+ this.more.appendChild(content.element);
window.addEventListener('resize', this.handleResize.bind(this));
root
.querySelector('.buttons')
.addEventListener('click', this.toggleOpen.bind(this));
- } else super();
- this.setElement(root);
+ } else super(root);
}
private toggleOpen() {
@@ -38,8 +37,8 @@ export class PageTimelineElement extends PageElement {
PageTimelineElement.hide(showLess);
this.closeMore();
} else {
- PageTimelineElement.hide(showMore);
PageTimelineElement.show(showLess);
+ PageTimelineElement.hide(showMore);
this.openMore();
}
diff --git a/src/page/timeline/timeline.ts b/src/page/timeline/timeline.ts
index e688697..f7dfd54 100644
--- a/src/page/timeline/timeline.ts
+++ b/src/page/timeline/timeline.ts
@@ -1,21 +1,15 @@
-import { TimelineElement } from '../../model/portfolio';
+import { Timeline } from '../../model/portfolio';
import { PageElement } from '../../framework/page-element';
import { PageTimelineElement } from './timeline-element/timeline-element';
import { generate } from './timeline.html';
import { createElement } from '../../framework/helper/create-element';
+import { ContainerPage } from '../../framework/container-page';
-export class PageTimeline extends PageElement {
- public constructor(
- timeline: Array,
- showMore: string,
- showLess: string
- ) {
- const root = createElement(generate());
- const elements = timeline.map(
- e => new PageTimelineElement(e, showMore, showLess)
+export class PageTimeline extends ContainerPage {
+ public constructor({ elements, showMoreText, showLessText }: Timeline) {
+ super(
+ createElement(generate()),
+ elements.map(e => new PageTimelineElement(e, showMoreText, showLessText))
);
- elements.map(e => e.getElement()).forEach(e => root.appendChild(e));
- super(elements);
- this.setElement(root);
}
}
diff --git a/src/portfolio.ts b/src/portfolio.ts
index 42699c7..2807b06 100644
--- a/src/portfolio.ts
+++ b/src/portfolio.ts
@@ -1,6 +1,11 @@
import { Portfolio } from './model/portfolio';
+import { Text } from './framework/primitives/implementations/text';
+import { Image } from './framework/primitives/implementations/image';
+import { Video } from './framework/primitives/implementations/video';
+import { Anchor } from './framework/primitives/implementations/anchor';
import me from './static/media/me.jpg';
+import forexGIF from './static/media/forex.gif';
import forexMP4 from './static/media/forex.mp4';
import forexWEBM from './static/media/forex.webm';
import myNotes from './static/media/my-notes.jpg';
@@ -16,196 +21,227 @@ import ledMP4 from './static/media/led.mp4';
import ledWEBM from './static/media/led.webm';
export const portfolio: Portfolio = {
- config: {
- showMore: `Show details`,
- showLess: `Show less`,
- },
header: {
name: `András Schmelczer`,
- picture: {
- type: `img`,
- image: me,
- alt: `a picture of me`,
- },
+ picture: new Image(me, `a picture of 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.`,
+ new Text(
+ `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 starting my sixth semester at the
+ Budapest University of Technology and Economics, I feel I am getting closer to it every day.`
+ ),
+ new Text(
+ `You can see some of the more interesting projects I have worked on below.`
+ ),
],
},
- timeline: [
- {
- title: `Predicting foreign exchange rates`,
- date: `2019 Autumn`,
- figure: {
- type: `video`,
- options: `autoplay loop muted playsinline`,
- webm: forexWEBM,
- mp4: forexMP4,
+ timeline: {
+ showMoreText: `Show details`,
+ showLessText: `Show less`,
+ elements: [
+ {
+ title: `Predicting foreign exchange rates`,
+ date: `2019 Autumn`,
+ figure: new Video(
+ forexGIF,
+ forexMP4,
+ forexWEBM,
+ `autoplay loop muted playsinline`
+ ),
+ description: new Text(
+ `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: [
+ new Text(
+ `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.`
+ ),
+ new Text(
+ `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.`
+ ),
+ ],
},
- 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`,
- figure: {
- type: `img`,
- image: myNotes,
- alt: `two screenshots of the application`,
+ {
+ date: `2019 November`,
+ title: `My Notes`,
+ figure: new Image(myNotes, `two screenshots of the application`),
+ description: new Text(
+ `A minimalist note organizer and editor powered by Markwon.`
+ ),
+ more: [
+ new Anchor(
+ `https://github.com/schmelczerandras/my-notes`,
+ `MyNotes on GitHub`
+ ),
+ new Text(
+ `A basic android app for creating and filtering notes written in markdown.`
+ ),
+ new Text(
+ `It was my homework for BME's Android and web development course.
+ It was also my first experience with Android development.`
+ ),
+ ],
},
- 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`,
- figure: {
- type: `img`,
- image: processSimulator,
- alt: `a screenshot of the simulator`,
+ {
+ date: `2018 October - November`,
+ title: `Simulating the cooling system of a nuclear facility`,
+ figure: new Image(processSimulator, `a screenshot of the simulator`),
+ description: new Text(
+ `Dynamically calculating the temperatures and flow velocities
+ in a fluid based cooling system based on a simple model.`
+ ),
+ more: [
+ new Text(
+ `A simulated system can contain reactors (heaters / coolers), pumps, heat exchangers,
+ drains sources, and of course, pipes.`
+ ),
+ new Text(
+ `The algorithm takes advantages of graphs and matrices to get to a next time frame.`
+ ),
+ new Text(
+ `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.`
+ ),
+ ],
},
- 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`,
- figure: {
- type: `img`,
- image: processSimulatorInput,
- alt: `a picture of the simulator's UI`,
+ {
+ date: `2018 October - November`,
+ title: `Graph editing application`,
+ figure: new Image(
+ processSimulatorInput,
+ `a picture of the simulator's UI`
+ ),
+ description: new Text(
+ `An intuitive editor to create and edit input files for the nuclear facility simulator.`
+ ),
+ more: [
+ new Text(
+ `Nodes can be moved with drag&drop gestures. Editing the parameters of elements
+ can be done on the right panel.`
+ ),
+ new Text(
+ `The UI is built with JavaFX. The output can be exported as JSON or
+ directly uploaded to the simulation backend.`
+ ),
+ ],
},
- 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`,
- figure: {
- type: `img`,
- image: citySimulation,
- alt: `a picture of a low-poly city`,
+ {
+ date: `2018 July - August`,
+ title: `City simulation`,
+ figure: new Image(citySimulation, `a picture of a low-poly city`),
+ description: new Text(
+ `Simulating a city where car crashes are more frequent than usual.`
+ ),
+ more: [
+ new Text(
+ `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.`
+ ),
+ new Text(
+ `This was created for a Cybersecurity challenge. With the help of this program
+ the contestants could instantly see the effect of their work.`
+ ),
+ new Text(
+ `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.`
+ ),
+ new Text(
+ `The program is made with Unity using C# as the scripting language. The models and animations
+ were also made by me using Blender.`
+ ),
+ ],
},
- 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`,
- figure: {
- type: `img`,
- image: color,
- alt: `a picture of the app`,
+ {
+ date: `2018 June`,
+ title: `Photo color grader`,
+ figure: new Image(color, `a picture of the app`),
+ description: new Text(
+ `An innovative (at least I thought so) color grader web application.`
+ ),
+ more: [
+ new Text(
+ `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.`
+ ),
+ new Text(
+ `You can select some colors and then apply transformations to the other colors as a
+ function of their distance to the selected color.`
+ ),
+ new Text(
+ `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).`
+ ),
+ new Anchor('color', `schmelczer.dev/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`,
- figure: {
- type: `img`,
- image: platform,
- alt: `a picture of the app`,
+ {
+ date: `2017 autumn`,
+ title: `Platform game`,
+ figure: new Image(platform, `a picture of the app`),
+ description: new Text(
+ `A 3D game written in C with the help of SDL 1.2 (I haven't heard of GPU programming at the time).`
+ ),
+ more: [
+ new Text(
+ `The maps are randomly generated and fully destroyable.
+ The player is getting chased by flying enemies. Overall, I find it a really enjoyable game.`
+ ),
+ new Text(
+ `I did this as a homework for my Basics of Programming course.`
+ ),
+ ],
},
- 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`,
- figure: {
- type: `img`,
- image: photos,
- alt: `a picture of the website`,
+ {
+ date: `2016 summer`,
+ title: `Photos`,
+ figure: new Image(photos, `a picture of the website`),
+ description: new Text(
+ `A simple web page where you can view my photos.`
+ ),
+ link: new Anchor(`photos`, `schmelczer.dev/photos`),
},
- description: `A simple web page where you can view my photos.`,
- link: { type: `a`, href: `photos`, text: `schmelczer.dev/photos` },
- },
- {
- date: `2016 spring`,
- title: `Lights synchronised to music`,
- figure: {
- type: `img`,
- image: led,
- alt: `a picture from the video`,
+ {
+ date: `2016 spring`,
+ title: `Lights synchronised to music`,
+ figure: new Video(led.src, ledMP4, ledWEBM, `controls`),
+ description: new Text(
+ `A full stack application with a built-in
+ music player which music controls the color of some RGB LED strips.`
+ ),
+ more: [
+ new Text(
+ `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.`
+ ),
+ new Text(
+ `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.`
+ ),
+ ],
},
- 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`, mp4: ledMP4, webm: ledWEBM, options: 'controls' },
- ],
- },
- ],
+ ],
+ },
footer: {
title: `Learn more`,
- cv,
- email: `schmelczerandras@gmail.com`,
- cvName: `Curriculum vitae`,
- lastEditName: `Last modified on `,
- lastEdit: new Date(2020, 0, 2), // months are 0 indexed
+ curiumVitaes: [
+ { name: `Curriculum vitae (en)`, url: cv },
+ { name: `Önéletrajz (hu)`, url: cv },
+ ],
+ email: `andras@schmelczer.dev`,
+ lastEditText: `Last modified on `,
+ lastEdit: new Date(2020, 0, 6), // months are 0 indexed
+ gitHub: new Anchor(
+ `https://github.com/schmelczerandras/timeline`,
+ `Find this page on GitHub.`
+ ),
},
};
diff --git a/src/style/vars.scss b/src/style/vars.scss
index eb2f3eb..4f6d69f 100644
--- a/src/style/vars.scss
+++ b/src/style/vars.scss
@@ -1,6 +1,6 @@
@import 'fonts';
-$background: white;
+$background: #ffffff;
$normal-text-color: #31343f;
$light-text-color: #7a7d8e;
diff --git a/src/styles.scss b/src/styles.scss
index ac04083..5cf2b4f 100644
--- a/src/styles.scss
+++ b/src/styles.scss
@@ -1,6 +1,7 @@
@import 'style/vars';
@import 'style/mixins';
@import 'style/a';
+@import 'framework/primitives/primitives';
* {
margin: 0;
@@ -27,6 +28,7 @@ html {
body {
@include main-font();
height: 100%;
+ //noinspection CssInvalidFunction
padding: env(safe-area-inset-top, 20px) env(safe-area-inset-right, 20px)
env(safe-area-inset-bottom, 20px) env(safe-area-inset-left, 20px);
diff --git a/webpack.config.js b/webpack.config.js
index 1ceacd9..ef757ef 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -5,6 +5,7 @@ const TerserJSPlugin = require('terser-webpack-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const HtmlWebpackInlineSourcePlugin = require('html-webpack-inline-source-plugin');
+const Sharp = require('responsive-loader/sharp');
const isProduction = process.env.NODE_ENV === 'production';
@@ -14,7 +15,7 @@ module.exports = {
},
devServer: {
host: '0.0.0.0',
- // disableHostCheck: true
+ // disableHostCheck: true,
},
optimization: {
minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})],
@@ -23,8 +24,15 @@ module.exports = {
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
xhtml: true,
- minify: true,
template: './src/index.html',
+ minify: {
+ collapseWhitespace: true,
+ removeComments: true,
+ removeRedundantAttributes: true,
+ removeScriptTypeAttributes: true,
+ removeStyleLinkTypeAttributes: true,
+ useShortDoctype: true,
+ },
inlineSource: '.(js|css)$',
}),
new HtmlWebpackInlineSourcePlugin(),
@@ -42,14 +50,14 @@ module.exports = {
test: /\.(jpe?g|png)$/i,
loader: 'responsive-loader',
options: {
- adapter: require('responsive-loader/sharp'),
+ adapter: Sharp,
outputPath: 'static/',
- sizes: [300, 600, 1200, 2000],
+ sizes: [200, 400, 800, 1200, 2000],
placeholder: false,
},
},
{
- test: /\.(webm|mp4)$/i,
+ test: /\.(webm|mp4|gif)$/i,
use: [
{
loader: 'file-loader',