diff --git a/.idea/dictionaries/Schme.xml b/.idea/dictionaries/Schme.xml index 7256af4..899d7ff 100644 --- a/.idea/dictionaries/Schme.xml +++ b/.idea/dictionaries/Schme.xml @@ -1,7 +1,9 @@ + opacify raleway + transparentize \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml index 47a5585..753b593 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -2,63 +2,43 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + - - + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - @@ -139,7 +122,10 @@ - + + + + diff --git a/src/content/en.ts b/src/content/en.ts index fa9c46c..1eab10c 100644 --- a/src/content/en.ts +++ b/src/content/en.ts @@ -1,5 +1,6 @@ import { Portfolio } from "../model/portfolio"; -import me from "../static/media/me.jpg"; + +import me from "../static/media/me-2.jpg"; import forex from "../static/media/forex.gif"; import myNotes from "../static/media/my-notes.jpg"; import processSimulator from "../static/media/process-simulator.jpg"; @@ -13,13 +14,14 @@ import ledVideo from "../static/media/led720.mp4"; export const portfolio: Portfolio = { config: { - showMore: "Show details", - showLess: "Show less", - aPictureOf: "a picture of", - cvName: "Curriculum vitae" + showMore: `Show details`, + showLess: `Show less`, + aPictureOf: `a picture of`, + cvName: `Curriculum vitae`, + lastEdit: new Date(2019, 12, 22) }, header: { - name: "András Schmelczer", + name: `András Schmelczer`, picture: me, about: [ `I have always been fascinated by the engineering feats that surround us. @@ -31,115 +33,134 @@ export const portfolio: Portfolio = { }, timeline: [ { - title: "Predicting foreign exchange rates", - date: "2019 Autumn", + title: `Predicting foreign exchange rates`, + date: `2019 Autumn`, 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." + `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", + date: `2019 November`, + title: `My Notes`, picture: myNotes, - description: "A minimalist note organizer and editor powered by Markwon.", + description: `A minimalist note organizer and editor powered by Markwon.`, more: [ { - type: "a", - href: "https://github.com/schmelczerandras/my-notes", - text: "MyNotes on GitHub" + 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." + `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", + 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.", + 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." + `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", + 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.", + 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." + `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", + date: `2018 July - August`, + title: `City simulation`, picture: citySimulation, - description: - "Simulating a city where car crashes are more frequent than usual.", + 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." + `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", + date: `2018 June`, + title: `Photo color grader`, picture: color, - description: - "An innovative (at least I thought so) color grader web application.", + 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" } + `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", + date: `2017 autumn`, - title: "Platform game", + 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).", + 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." + `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", + date: `2016 summer`, + title: `Photos`, picture: photos, - description: "A simple web page where you can view my photos.", - link: "schmelczer.dev/photos" + description: `A simple web page where you can view my photos.`, + link: `schmelczer.dev/photos` }, { - date: "2016 spring", - title: "Lights synchronised to music", + 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.", + 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: ledVideo } + `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: ledVideo } ] } ], footer: { - email: "andras.schmelczer@schdesign.hu", - cv: "/static/media/andras_schmelczer_cv.pdf" + email: `andras.schmelczer@schdesign.hu`, + cv: `/static/media/andras_schmelczer_cv.pdf` } }; diff --git a/src/framework/helper.ts b/src/framework/helper.ts new file mode 100644 index 0000000..a9b26d8 --- /dev/null +++ b/src/framework/helper.ts @@ -0,0 +1,27 @@ +export const mixColorsToRGB = ( + hexColorA: string, + hexColorB: string, + qA: number +): string => { + const colorA = hexToRGB(hexColorA); + const colorB = hexToRGB(hexColorB); + const mixedColor: [number, number, number] = [ + colorA[0] * qA + colorB[0] * (1 - qA), + colorA[1] * qA + colorB[1] * (1 - qA), + colorA[2] * qA + colorB[2] * (1 - qA) + ]; + + return RGBToHex(mixedColor); +}; + +const hexToRGB = (hex: string): [number, number, number] => { + const [r1, r2, g1, g2, b1, b2] = hex; + return [ + Number.parseInt(r1 + r2, 16), + Number.parseInt(g1 + g2, 16), + Number.parseInt(b1 + b2, 16) + ]; +}; + +const RGBToHex = (rgb: [number, number, number]): string => + rgb.map(n => Math.round(n).toString(16)).join(""); diff --git a/src/framework/helpers.ts b/src/framework/helpers.ts deleted file mode 100644 index 68af962..0000000 --- a/src/framework/helpers.ts +++ /dev/null @@ -1,2 +0,0 @@ -export const show = (e: HTMLElement) => (e.style.display = "block"); -export const hide = (e: HTMLElement) => (e.style.display = "none"); diff --git a/src/model/portfolio.ts b/src/model/portfolio.ts index 571a8e4..65a2c5c 100644 --- a/src/model/portfolio.ts +++ b/src/model/portfolio.ts @@ -13,6 +13,7 @@ export interface Config { showLess: string; aPictureOf: string; cvName: string; + lastEdit: Date; } export interface Header { diff --git a/src/page/about/about.html.ts b/src/page/about/about.html.ts new file mode 100644 index 0000000..9827889 --- /dev/null +++ b/src/page/about/about.html.ts @@ -0,0 +1,13 @@ +import { Header } from "../../model/portfolio"; +import { html } from "../../model/misc"; + +export const generate = ( + { name, picture, about }: Header, + aPictureOf: string +): html => ` +
+
+ ${aPictureOf} ${name} +

${name}

+
+
`; diff --git a/src/page/about/about.scss b/src/page/about/about.scss index 0e61083..52bae84 100644 --- a/src/page/about/about.scss +++ b/src/page/about/about.scss @@ -4,21 +4,17 @@ #about { header { @include center-children(); - margin-top: $normal-margin; h1, img { - font: $title-font; - } - - h1 { - text-align: center; + @include title-font(); } img { @include square(4ch); border-radius: 100%; margin-right: 1.5ex; + cursor: pointer; } } diff --git a/src/page/about/about.ts b/src/page/about/about.ts index e4a4479..d2f5e69 100644 --- a/src/page/about/about.ts +++ b/src/page/about/about.ts @@ -1,20 +1,16 @@ import { PageContent } from "../content/content"; import { Header } from "../../model/portfolio"; -import "./about.scss"; import { PageElement } from "../../framework/page-element"; import { createElement } from "../../framework/element-factory"; +import { generate } from "./about.html"; +import "./about.scss"; + export class PageHeader extends PageElement { - public constructor({ name, picture, about }: Header, aPictureOf: string) { - const root = createElement(` -
-
- ${aPictureOf} ${name} -

${name}

-
-
- `); - const content = new PageContent(about); + public constructor(header: Header, aPictureOf: string) { + const root = createElement(generate(header, aPictureOf)); + const content = new PageContent(header.about); + root.appendChild(content.getElement()); super([content]); this.setElement(root); diff --git a/src/page/content/content.scss b/src/page/content/content.scss index b216882..a442235 100644 --- a/src/page/content/content.scss +++ b/src/page/content/content.scss @@ -2,7 +2,12 @@ .content { margin-top: $small-margin; + * { - margin-top: 1ch; + margin-top: $line-height; + } + + p { + text-align: left; } } diff --git a/src/page/footer/footer.html.ts b/src/page/footer/footer.html.ts new file mode 100644 index 0000000..9cf8dfd --- /dev/null +++ b/src/page/footer/footer.html.ts @@ -0,0 +1,9 @@ +import { Footer } from "../../model/portfolio"; +import { html } from "../../model/misc"; + +export const generate = ({ email, cv }: Footer, cvName: string): html => ` + +`; diff --git a/src/page/footer/footer.scss b/src/page/footer/footer.scss index 0fb0a7d..00015a5 100644 --- a/src/page/footer/footer.scss +++ b/src/page/footer/footer.scss @@ -3,5 +3,4 @@ footer { @include card(); @include center-children(); - margin-top: $normal-margin; } diff --git a/src/page/footer/footer.ts b/src/page/footer/footer.ts index 9dbf646..3b0ba34 100644 --- a/src/page/footer/footer.ts +++ b/src/page/footer/footer.ts @@ -1,18 +1,13 @@ import { Footer } from "../../model/portfolio"; -import "./footer.scss"; import { PageElement } from "../../framework/page-element"; import { createElement } from "../../framework/element-factory"; +import "./footer.scss"; +import { generate } from "./footer.html"; + export class PageFooter extends PageElement { - constructor({ email, cv }: Footer, cvName: string) { + constructor(footer: Footer, cvName: string) { super(); - this.setElement( - createElement(` - - `) - ); + this.setElement(createElement(generate(footer, cvName))); } } diff --git a/src/page/image-viewer/image-viewer.html.ts b/src/page/image-viewer/image-viewer.html.ts new file mode 100644 index 0000000..c65c751 --- /dev/null +++ b/src/page/image-viewer/image-viewer.html.ts @@ -0,0 +1,9 @@ +import { html } from "../../model/misc"; +import cancel from "../../static/icons/cancel.svg"; + +export const generate = (): html => ` +
+ currently opened photo + cancel +
+`; diff --git a/src/page/image-viewer/image-viewer.scss b/src/page/image-viewer/image-viewer.scss index e69de29..088bf66 100644 --- a/src/page/image-viewer/image-viewer.scss +++ b/src/page/image-viewer/image-viewer.scss @@ -0,0 +1,30 @@ +@import "../../style/vars"; +@import "../../style/mixins"; + +.photo-viewer { + @include center-children(); + display: none; + + position: fixed; + width: 100%; + height: 100%; + left: 0; + top: 0; + margin: 0; + z-index: 2; + background-color: rgba(0, 0, 0, 0.75); + + #photo { + max-width: 90vw; + max-height: 80vh; + } + + #cancel { + @include square($icon-size); + position: absolute; + padding: $normal-margin; + right: 0; + top: 0; + cursor: pointer; + } +} diff --git a/src/page/image-viewer/image-viewer.ts b/src/page/image-viewer/image-viewer.ts index 1989c2a..b9425d8 100644 --- a/src/page/image-viewer/image-viewer.ts +++ b/src/page/image-viewer/image-viewer.ts @@ -1,28 +1,24 @@ -import "./image-viewer.scss"; -import cancel from "../../static/icons/cancel.svg"; -import { html } from "../../model/misc"; import { createElement } from "../../framework/element-factory"; import { PageElement } from "../../framework/page-element"; -import { hide, show } from "../../framework/helpers"; + +import "./image-viewer.scss"; +import { generate } from "./image-viewer.html"; +import { mixColorsToRGB } from "../../framework/helper"; export class PageImageViewer extends PageElement { - private static template: html = ` -
- currently opened photo - cancel -
- `; - public constructor() { super(); - const root = createElement(PageImageViewer.template); - (root.querySelector("#cancel") as HTMLElement).onclick = () => hide(root); + const root = createElement(generate()); + (root.querySelector("#cancel") as HTMLElement).onclick = () => + PageImageViewer.hide(root); this.setElement(root); } public onAfterLoad(parent: HTMLElement) { super.onAfterLoad(parent); + document.body.addEventListener("keydown", this.handleKeydown.bind(this)); + const images = Array.prototype.slice.call(parent.querySelectorAll("img")); images .filter( @@ -38,6 +34,22 @@ export class PageImageViewer extends PageElement { "#photo" ) as HTMLImageElement).src = (event.target as HTMLImageElement).src; - show(this.getElement()); + PageImageViewer.show(this.getElement()); + } + + private handleKeydown(event: KeyboardEvent) { + if (event.key === "Escape") { + PageImageViewer.hide(this.getElement()); + } + } + + private static show(e: HTMLElement) { + e.style.display = "flex"; + console.log("#" + mixColorsToRGB("00000", "ffd6d6", 0.75)); + document.body.parentElement.style.backgroundColor = + "#" + mixColorsToRGB("00000", "ffd6d6", 0.75); + } + private static hide(e: HTMLElement) { + e.style.display = "none"; } } diff --git a/src/page/timeline/timeline-element/timeline-element.html.ts b/src/page/timeline/timeline-element/timeline-element.html.ts new file mode 100644 index 0000000..cb7e4e8 --- /dev/null +++ b/src/page/timeline/timeline-element/timeline-element.html.ts @@ -0,0 +1,37 @@ +import { TimelineElement } from "../../../model/portfolio"; +import { html } from "../../../model/misc"; + +export const generate = ( + { date, title, picture, description, more, link }: TimelineElement, + showMore: string, + showLess: string +): html => ` +
+
+

${date}

+
+
+

${title}

+

${date}

+ ${picture} +

${description}

+ ${ + more + ? ` +
+ + ` + : "" + } + ${ + link + ? ` + ${link}` + : "" + } +
+
+`; diff --git a/src/page/timeline/timeline-element/timeline-element.scss b/src/page/timeline/timeline-element/timeline-element.scss index 94d89ac..4456755 100644 --- a/src/page/timeline/timeline-element/timeline-element.scss +++ b/src/page/timeline/timeline-element/timeline-element.scss @@ -6,7 +6,7 @@ .date-narrow-screen, .date-wide-screen { - font: $text-font; + @include insignificant-font(); } .line { @@ -31,7 +31,8 @@ .date-wide-screen { position: relative; - top: calc(33% + #{$icon-size} + 1ch); + top: calc(33% + #{$icon-size} + 2ch); + transform: rotate(30deg); margin: 0 $normal-margin 0 calc(#{$line-width} + 1ex); width: 100px; } @@ -43,9 +44,14 @@ .card { @include card(); + overflow: hidden; + + & > *:not(:first-child) { + margin-top: $line-height; + } h2 { - font: $sub-title-font; + @include sub-title-font(); } .date-narrow-screen { @@ -57,23 +63,40 @@ color: $light-text-color; } + img { + cursor: pointer; + } + + .description { + font-style: italic; + } + #more { overflow: hidden; height: 0; - transition: height $transition-time; + margin-top: 0; + transition: height $slow-transition-time; } .buttons { position: relative; + margin-top: $small-margin; + * { - position: absolute; - left: 50%; - transform: translateX(-50%); - transition: opacity $transition-time; + transition: opacity $slow-transition-time; + } + + #show-more { + opacity: 1; } #show-less { opacity: 0; + visibility: hidden; + position: absolute; + left: 50%; + top: 50%; + transform: translateX(-50%) translateY(-50%); } } } diff --git a/src/page/timeline/timeline-element/timeline-element.ts b/src/page/timeline/timeline-element/timeline-element.ts index 738f6c7..317c185 100644 --- a/src/page/timeline/timeline-element/timeline-element.ts +++ b/src/page/timeline/timeline-element/timeline-element.ts @@ -3,49 +3,21 @@ import { PageContent } from "../../content/content"; import "./timeline-element.scss"; import { PageElement } from "../../../framework/page-element"; import { createElement } from "../../../framework/element-factory"; +import { generate } from "./timeline-element.html"; export class PageTimelineElement extends PageElement { private isOpen; private more: HTMLElement; public constructor( - { date, title, picture, description, more, link }: TimelineElement, + timelineElement: TimelineElement, showMore: string, showLess: string ) { - const root = createElement(` -
-
-

${date}

-
-
-

${title}

-

${date}

- ${picture} -

${description}

- ${ - more - ? ` -
- - ` - : "" - } - ${ - link - ? ` - ${link}` - : "" - } -
-
- `); + const root = createElement(generate(timelineElement, showMore, showLess)); - if (more) { - const content = new PageContent(more); + if (timelineElement.more) { + const content = new PageContent(timelineElement.more); super([content]); this.isOpen = false; this.more = root.querySelector("#more"); @@ -67,17 +39,27 @@ export class PageTimelineElement extends PageElement { ) as HTMLElement; if (this.isOpen) { this.more.style.height = "0"; - showMore.style.opacity = "1"; - showLess.style.opacity = "0"; + PageTimelineElement.show(showMore); + PageTimelineElement.hide(showLess); } else { this.openMoreToFullHeight(); - showMore.style.opacity = "0"; - showLess.style.opacity = "1"; + PageTimelineElement.hide(showMore); + PageTimelineElement.show(showLess); } this.isOpen = !this.isOpen; } + private static hide(element: HTMLElement) { + element.style.opacity = "0"; + setTimeout(() => (element.style.visibility = "hidden"), 350); + } + + private static show(element: HTMLElement) { + element.style.visibility = "visible"; + element.style.opacity = "1"; + } + private openMoreToFullHeight() { this.more.style.height = `${this.more.scrollHeight.toString()}px`; } diff --git a/src/page/timeline/timeline.html.ts b/src/page/timeline/timeline.html.ts new file mode 100644 index 0000000..363f312 --- /dev/null +++ b/src/page/timeline/timeline.html.ts @@ -0,0 +1,5 @@ +import { html } from "../../model/misc"; + +export const generate = (): html => ` +
+`; diff --git a/src/page/timeline/timeline.scss b/src/page/timeline/timeline.scss index 1e5f1bf..0af2b02 100644 --- a/src/page/timeline/timeline.scss +++ b/src/page/timeline/timeline.scss @@ -1,5 +1 @@ @import "../../style/vars"; - -#timeline { - margin-top: $normal-margin; -} diff --git a/src/page/timeline/timeline.ts b/src/page/timeline/timeline.ts index 041c6d3..7d1f606 100644 --- a/src/page/timeline/timeline.ts +++ b/src/page/timeline/timeline.ts @@ -3,6 +3,7 @@ import "./timeline.scss"; import { PageElement } from "../../framework/page-element"; import { createElement } from "../../framework/element-factory"; import { PageTimelineElement } from "./timeline-element/timeline-element"; +import { generate } from "./timeline.html"; export class PageTimeline extends PageElement { public constructor( @@ -10,7 +11,7 @@ export class PageTimeline extends PageElement { showMore: string, showLess: string ) { - const root = createElement(`
`); + const root = createElement(generate()); const elements = timeline.map( e => new PageTimelineElement(e, showMore, showLess) ); diff --git a/favicon.ico b/src/static/favicon.ico similarity index 100% rename from favicon.ico rename to src/static/favicon.ico diff --git a/src/static/fonts/open_sans/open-sans-v17-latin_latin-ext-300italic.eot b/src/static/fonts/open_sans/open-sans-v17-latin_latin-ext-300italic.eot deleted file mode 100644 index 561c63a..0000000 Binary files a/src/static/fonts/open_sans/open-sans-v17-latin_latin-ext-300italic.eot and /dev/null differ diff --git a/src/static/fonts/open_sans/open-sans-v17-latin_latin-ext-300italic.svg b/src/static/fonts/open_sans/open-sans-v17-latin_latin-ext-300italic.svg deleted file mode 100644 index c7a44b0..0000000 --- a/src/static/fonts/open_sans/open-sans-v17-latin_latin-ext-300italic.svg +++ /dev/null @@ -1,345 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/static/fonts/open_sans/open-sans-v17-latin_latin-ext-300italic.ttf b/src/static/fonts/open_sans/open-sans-v17-latin_latin-ext-300italic.ttf deleted file mode 100644 index 23cb368..0000000 Binary files a/src/static/fonts/open_sans/open-sans-v17-latin_latin-ext-300italic.ttf and /dev/null differ diff --git a/src/static/fonts/open_sans/open-sans-v17-latin_latin-ext-300italic.woff b/src/static/fonts/open_sans/open-sans-v17-latin_latin-ext-300italic.woff deleted file mode 100644 index 420766e..0000000 Binary files a/src/static/fonts/open_sans/open-sans-v17-latin_latin-ext-300italic.woff and /dev/null differ diff --git a/src/static/fonts/open_sans/open-sans-v17-latin_latin-ext-300italic.woff2 b/src/static/fonts/open_sans/open-sans-v17-latin_latin-ext-300italic.woff2 deleted file mode 100644 index 15d4f09..0000000 Binary files a/src/static/fonts/open_sans/open-sans-v17-latin_latin-ext-300italic.woff2 and /dev/null differ diff --git a/src/static/fonts/open_sans_italic/open-sans-v17-latin-ext_latin-italic.eot b/src/static/fonts/open_sans_italic/open-sans-v17-latin-ext_latin-italic.eot new file mode 100644 index 0000000..0cf3006 Binary files /dev/null and b/src/static/fonts/open_sans_italic/open-sans-v17-latin-ext_latin-italic.eot differ diff --git a/src/static/fonts/open_sans_italic/open-sans-v17-latin-ext_latin-italic.svg b/src/static/fonts/open_sans_italic/open-sans-v17-latin-ext_latin-italic.svg new file mode 100644 index 0000000..e6a951f --- /dev/null +++ b/src/static/fonts/open_sans_italic/open-sans-v17-latin-ext_latin-italic.svg @@ -0,0 +1,349 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/static/fonts/open_sans_italic/open-sans-v17-latin-ext_latin-italic.ttf b/src/static/fonts/open_sans_italic/open-sans-v17-latin-ext_latin-italic.ttf new file mode 100644 index 0000000..4228eaf Binary files /dev/null and b/src/static/fonts/open_sans_italic/open-sans-v17-latin-ext_latin-italic.ttf differ diff --git a/src/static/fonts/open_sans_italic/open-sans-v17-latin-ext_latin-italic.woff b/src/static/fonts/open_sans_italic/open-sans-v17-latin-ext_latin-italic.woff new file mode 100644 index 0000000..edac093 Binary files /dev/null and b/src/static/fonts/open_sans_italic/open-sans-v17-latin-ext_latin-italic.woff differ diff --git a/src/static/fonts/open_sans_italic/open-sans-v17-latin-ext_latin-italic.woff2 b/src/static/fonts/open_sans_italic/open-sans-v17-latin-ext_latin-italic.woff2 new file mode 100644 index 0000000..7584008 Binary files /dev/null and b/src/static/fonts/open_sans_italic/open-sans-v17-latin-ext_latin-italic.woff2 differ diff --git a/src/static/icons/cancel.svg b/src/static/icons/cancel.svg index aa443f4..1d7600f 100644 --- a/src/static/icons/cancel.svg +++ b/src/static/icons/cancel.svg @@ -1,4 +1,4 @@ - + diff --git a/src/static/media/me-2.jpg b/src/static/media/me-2.jpg new file mode 100644 index 0000000..16e1ab4 Binary files /dev/null and b/src/static/media/me-2.jpg differ diff --git a/og-image.jpg b/src/static/og-image.jpg similarity index 100% rename from og-image.jpg rename to src/static/og-image.jpg diff --git a/src/style/fonts.scss b/src/style/fonts.scss index ce1d1ac..55a3677 100644 --- a/src/style/fonts.scss +++ b/src/style/fonts.scss @@ -21,28 +21,29 @@ format("svg"); /* Legacy iOS */ } -/* open-sans-300italic - latin_latin-ext */ +/* open-sans-italic - latin-ext_latin */ @font-face { font-family: "Open Sans"; font-style: italic; - font-weight: 300; - src: url("../static/fonts/open_sans/open-sans-v17-latin_latin-ext-300italic.eot"); /* IE9 Compat Modes */ - src: local("Open Sans Light Italic"), local("OpenSans-LightItalic"), - url("../static/fonts/open_sans/open-sans-v17-latin_latin-ext-300italic.eot?#iefix") + font-weight: 400; + src: url("../static/fonts/open_sans_italic/open-sans-v17-latin-ext_latin-italic.eot"); /* IE9 Compat Modes */ + src: local("Open Sans Italic"), local("OpenSans-Italic"), + url("../static/fonts/open_sans_italic/open-sans-v17-latin-ext_latin-italic.eot?#iefix") format("embedded-opentype"), /* IE6-IE8 */ - url("../static/fonts/open_sans/open-sans-v17-latin_latin-ext-300italic.woff2") + url("../static/fonts/open_sans_italic/open-sans-v17-latin-ext_latin-italic.woff2") format("woff2"), /* Super Modern Browsers */ - url("../static/fonts/open_sans/open-sans-v17-latin_latin-ext-300italic.woff") + url("../static/fonts/open_sans_italic/open-sans-v17-latin-ext_latin-italic.woff") format("woff"), /* Modern Browsers */ - url("../static/fonts/open_sans/open-sans-v17-latin_latin-ext-300italic.ttf") + url("../static/fonts/open_sans_italic/open-sans-v17-latin-ext_latin-italic.ttf") format("truetype"), /* Safari, Android, iOS */ - url("../static/fonts/open_sans/open-sans-v17-latin_latin-ext-300italic.svg#OpenSans") + url("../static/fonts/open_sans_italic/open-sans-v17-latin-ext_latin-italic.svg#OpenSans") format("svg"); /* Legacy iOS */ } + /* open-sans-regular - latin_latin-ext */ @font-face { font-family: "Open Sans"; diff --git a/src/style/mixins.scss b/src/style/mixins.scss index cd55772..8fb3373 100644 --- a/src/style/mixins.scss +++ b/src/style/mixins.scss @@ -15,7 +15,7 @@ @media (max-width: $breakpoint-width) { & { - transition: box-shadow $transition-time; + transition: box-shadow $fast-transition-time; &:hover { box-shadow: 0 0 3px rgba(0, 0, 0, 0.05); @@ -28,3 +28,21 @@ width: $size; height: $size; } + +@mixin title-font() { + font: 400 3.33rem "Raleway", serif; +} + +@mixin sub-title-font() { + font: 400 2rem "Raleway", serif; +} + +@mixin main-font() { + font: 400 18px "Open sans", sans-serif; + line-height: 1.5; +} + +@mixin insignificant-font() { + font: 400 16px "Open sans", sans-serif; + font-style: italic; +} diff --git a/src/style/vars.scss b/src/style/vars.scss index 589195b..1115042 100644 --- a/src/style/vars.scss +++ b/src/style/vars.scss @@ -1,31 +1,29 @@ @import "fonts"; - -$background: linear-gradient(90deg, #fff9e0 0, #ffd6d6 100vw); +$background-start: #fff9e0; +$background-end: #ffd6d6; +$background: linear-gradient(90deg, $background-start 0, $background-end 100vw); $normal-text-color: #31343f; $light-text-color: #7a7d8e; $inverse-text-color: #ffffff; $card-color: #ffffff; -$accent-color: #5264bf; -$light-accent-color: #e5e5ff; +$accent-color: #aa4465; $scrollbar-color: #ffd6d6; -$transition-time: 220ms; +$fast-transition-time: 220ms; +$slow-transition-time: 350ms; $line-width: 3px; $border-radius: 5px; $breakpoint-width: 900px; $normal-margin: 35px; $small-margin: 25px; +$line-height: 2ch; $icon-size: 25px; $body-width: 765px; -$title-font: 400 3.33rem "Raleway", sans-serif; -$sub-title-font: 400 2rem "Raleway", sans-serif; -$text-font: 400 18px "Open sans", sans-serif; - @media (max-width: $breakpoint-width) { $line-width: 2px; $normal-margin: 25px; diff --git a/src/styles.scss b/src/styles.scss index 3a6cb9f..8ce4b7e 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -1,4 +1,5 @@ @import "style/vars"; +@import "style/mixins"; * { margin: 0; @@ -28,14 +29,22 @@ html { } } +html { + background-color: $background-end; +} + body { width: $body-width; margin: auto; - font: $text-font; + @include main-font(); + + & > * { + margin-top: $normal-margin; + } &::-webkit-scrollbar-track, &::-webkit-scrollbar { - background-color: $scrollbar-color; + background-color: transparent; width: 12px; } &::-webkit-scrollbar-thumb { @@ -48,27 +57,53 @@ img, video { width: 100%; height: auto; + object-fit: contain; + border-radius: $border-radius; } a { - display: inline-block; - position: relative; + @include insignificant-font(); text-decoration: none; + position: relative; cursor: pointer; - border-bottom: solid $line-width $light-accent-color; + color: $accent-color; + display: inline-block; + overflow: hidden; + + $border-shift: 10px; + + transition: transform $slow-transition-time; + + &:before { + content: ""; + display: block; + position: absolute; + width: 100%; + height: $line-width; + bottom: 0; + z-index: 1; + background: linear-gradient( + 90deg, + $card-color 0, + transparentize($card-color, 1) 4px, + transparentize($card-color, 1) calc(100% - 4px), + $card-color 100% + ); + } &:after { content: ""; - width: 0; - height: $line-width; - position: absolute; - left: 0; - bottom: -$line-width; - background-color: $accent-color; - transition: width $transition-time; + display: block; + width: calc(100% + #{$border-shift}); + height: 100%; + z-index: 0; + border-bottom: $line-width dotted $accent-color; + transition: transform $slow-transition-time; + } - &:hover { - width: 100%; + &:hover { + &:after { + transform: translateX(-$border-shift); } } } diff --git a/src/ts/parser.ts b/src/ts/parser.ts deleted file mode 100644 index fdf3756..0000000 --- a/src/ts/parser.ts +++ /dev/null @@ -1,46 +0,0 @@ -/*import { parseContent } from "../page/content/content"; - - - - - 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 onResize = () => { - const elements = document.getElementsByClassName("collapsed"); - Array.prototype.forEach.call(elements, element => { - if (isOpen(element)) { - element.style.height = "auto"; - setTimeout(() => open(element), 100); - } - }); - }; - - const handleEscape = event => { - if (event.key === "Escape") { - hideFrame(); - } - }; -}; -*/ diff --git a/tsconfig.json b/tsconfig.json index f7dca47..8d79fe0 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -5,6 +5,7 @@ "module": "es6", "target": "es5", "sourceMap": true, - "allowJs": true + "allowJs": true, + "downlevelIteration": true } } diff --git a/webpack.config.js b/webpack.config.js index 3b6539d..1e98212 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -20,7 +20,7 @@ module.exports = { module: { rules: [ { - test: /\.(png|svg|jpe?g|gif|mp4)$/, + test: /\.(png|svg|jpe?g|gif|mp4)$/i, use: { loader: "file-loader", query: { @@ -59,7 +59,8 @@ module.exports = { name: "[name].[ext]", outputPath: "static/fonts/" } - } + }, + include: /fonts/ }, { test: /\.ts$/,