Add final touches

This commit is contained in:
Schmelczer András 2020-01-10 20:10:59 +01:00
parent b1fd2f372f
commit 0429ea7f72
64 changed files with 576 additions and 444 deletions

View file

@ -2,6 +2,8 @@
<profile version="1.0"> <profile version="1.0">
<option name="myName" value="Project Default" /> <option name="myName" value="Project Default" />
<inspection_tool class="CssInvalidAtRule" enabled="false" level="ERROR" enabled_by_default="false" /> <inspection_tool class="CssInvalidAtRule" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="CssInvalidFunction" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="JSBitwiseOperatorUsage" enabled="false" level="WARNING" enabled_by_default="false" /> <inspection_tool class="JSBitwiseOperatorUsage" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SassScssResolvedByNameOnly" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
</profile> </profile>
</component> </component>

101
.idea/workspace.xml generated
View file

@ -2,13 +2,68 @@
<project version="4"> <project version="4">
<component name="ChangeListManager"> <component name="ChangeListManager">
<list default="true" id="8edc47ab-1265-4111-9771-536b24cc9310" name="Default Changelist" comment=""> <list default="true" id="8edc47ab-1265-4111-9771-536b24cc9310" name="Default Changelist" comment="">
<change afterPath="$PROJECT_DIR$/src/framework/helper/animations/animations.scss" afterDir="false" /> <change afterPath="$PROJECT_DIR$/src/framework/framework.scss" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/framework/index.scss" afterDir="false" /> <change afterPath="$PROJECT_DIR$/src/framework/styles/dark-mode/dark-mode.scss" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/framework/styles/index.scss" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/framework/styles/wrapper.scss" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/static/media/my-notes.png" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/style/_id.scss" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/style/configured-responsive.scss" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/style/include.scss" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/inspectionProfiles/Project_Default.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/inspectionProfiles/Project_Default.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" /> <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/framework/helper/animations.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/framework/helper/animations/animations.ts" afterDir="false" /> <change beforePath="$PROJECT_DIR$/README.md" beforeDir="false" afterPath="$PROJECT_DIR$/README.md" afterDir="false" />
<change beforePath="$PROJECT_DIR$/custom.d.ts" beforeDir="false" afterPath="$PROJECT_DIR$/custom.d.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/package.json" beforeDir="false" afterPath="$PROJECT_DIR$/package.json" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/framework/container-page.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/framework/container-page.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/framework/event-broadcaster.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/framework/events/event-broadcaster.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/framework/helper/animations/animations.scss" beforeDir="false" afterPath="$PROJECT_DIR$/src/framework/styles/animations/animations.scss" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/framework/helper/animations/animations.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/framework/styles/animations/animations.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/framework/helper/create-element.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/framework/helper/create-element.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/framework/helper/dark-mode.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/framework/styles/dark-mode/dark-mode.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/framework/index.scss" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/src/framework/page-element.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/framework/page-element.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/framework/page-event.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/framework/events/page-event.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/framework/primitives/implementations/anchor.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/framework/primitives/implementations/anchor.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/framework/primitives/implementations/image.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/framework/primitives/implementations/image.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/framework/primitives/implementations/text.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/framework/primitives/implementations/text.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/framework/primitives/implementations/video.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/framework/primitives/implementations/video.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/framework/primitives/primitive.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/framework/primitives/primitive.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/framework/primitives/primitives.scss" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/src/index.html" beforeDir="false" afterPath="$PROJECT_DIR$/src/index.html" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/index.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/index.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/model/misc.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/framework/model/misc.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/model/portfolio.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/model/portfolio.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/page/about/about.html.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/page/about/about.html.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/page/about/about.scss" beforeDir="false" afterPath="$PROJECT_DIR$/src/page/about/about.scss" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/page/about/about.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/page/about/about.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/page/background/background.html.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/page/background/blob.html.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/page/background/background.scss" beforeDir="false" afterPath="$PROJECT_DIR$/src/page/background/background.scss" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/page/background/background.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/page/background/background.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/page/background/blob.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/page/background/blob.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/page/content/content.html.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/page/content/content.html.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/page/content/content.scss" beforeDir="false" afterPath="$PROJECT_DIR$/src/page/content/content.scss" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/page/footer/footer.html.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/page/footer/footer.html.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/page/footer/footer.scss" beforeDir="false" afterPath="$PROJECT_DIR$/src/page/footer/footer.scss" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/page/image-viewer/image-viewer.html.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/page/image-viewer/image-viewer.html.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/page/image-viewer/image-viewer.scss" beforeDir="false" afterPath="$PROJECT_DIR$/src/page/image-viewer/image-viewer.scss" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/page/image-viewer/image-viewer.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/page/image-viewer/image-viewer.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/page/index.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/page/index.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/page/theme-switcher/theme-switcher.html.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/page/theme-switcher/theme-switcher.html.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/page/theme-switcher/theme-switcher.scss" beforeDir="false" afterPath="$PROJECT_DIR$/src/page/theme-switcher/theme-switcher.scss" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/page/theme-switcher/theme-switcher.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/page/theme-switcher/theme-switcher.ts" afterDir="false" /> <change beforePath="$PROJECT_DIR$/src/page/theme-switcher/theme-switcher.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/page/theme-switcher/theme-switcher.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/page/timeline/timeline-element/timeline-element.html.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/page/timeline/timeline-element/timeline-element.html.ts" afterDir="false" /> <change beforePath="$PROJECT_DIR$/src/page/timeline/timeline-element/timeline-element.html.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/page/timeline/timeline-element/timeline-element.html.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/page/timeline/timeline-element/timeline-element.scss" beforeDir="false" afterPath="$PROJECT_DIR$/src/page/timeline/timeline-element/timeline-element.scss" afterDir="false" /> <change beforePath="$PROJECT_DIR$/src/page/timeline/timeline-element/timeline-element.scss" beforeDir="false" afterPath="$PROJECT_DIR$/src/page/timeline/timeline-element/timeline-element.scss" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/page/timeline/timeline-element/timeline-element.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/page/timeline/timeline-element/timeline-element.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/page/timeline/timeline.html.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/page/timeline/timeline.html.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/page/timeline/timeline.scss" beforeDir="false" afterPath="$PROJECT_DIR$/src/page/timeline/timeline.scss" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/page/timeline/timeline.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/page/timeline/timeline.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/portfolio.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/portfolio.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/static/media/my-notes.jpg" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/src/style/a.scss" beforeDir="false" afterPath="$PROJECT_DIR$/src/style/a.scss" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/style/fonts.scss" beforeDir="false" afterPath="$PROJECT_DIR$/src/style/fonts.scss" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/style/mixins.scss" beforeDir="false" afterPath="$PROJECT_DIR$/src/style/mixins.scss" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/style/vars.scss" beforeDir="false" afterPath="$PROJECT_DIR$/src/style/vars.scss" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/styles.scss" beforeDir="false" afterPath="$PROJECT_DIR$/src/styles.scss" afterDir="false" /> <change beforePath="$PROJECT_DIR$/src/styles.scss" beforeDir="false" afterPath="$PROJECT_DIR$/src/styles.scss" afterDir="false" />
<change beforePath="$PROJECT_DIR$/webpack.config.js" beforeDir="false" afterPath="$PROJECT_DIR$/webpack.config.js" afterDir="false" /> <change beforePath="$PROJECT_DIR$/webpack.config.js" beforeDir="false" afterPath="$PROJECT_DIR$/webpack.config.js" afterDir="false" />
</list> </list>
@ -29,6 +84,9 @@
<component name="Git.Settings"> <component name="Git.Settings">
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" /> <option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
</component> </component>
<component name="HighlightingSettingsPerFile">
<setting file="file://$PROJECT_DIR$/src/style/configured-responsive.scss" root0="FORCE_HIGHLIGHTING" />
</component>
<component name="ProjectId" id="1UhDrRKewMzhTrQJ4npWjp729uJ" /> <component name="ProjectId" id="1UhDrRKewMzhTrQJ4npWjp729uJ" />
<component name="ProjectLevelVcsManager" settingsEditedManually="true"> <component name="ProjectLevelVcsManager" settingsEditedManually="true">
<ConfirmationsSetting value="2" id="Add" /> <ConfirmationsSetting value="2" id="Add" />
@ -62,11 +120,11 @@
<recent name="$PROJECT_DIR$" /> <recent name="$PROJECT_DIR$" />
</key> </key>
<key name="MoveFile.RECENT_KEYS"> <key name="MoveFile.RECENT_KEYS">
<recent name="$PROJECT_DIR$/src/framework/events" />
<recent name="$PROJECT_DIR$/src/framework/model" />
<recent name="$PROJECT_DIR$/src/framework/styles/dark-mode" />
<recent name="$PROJECT_DIR$/src/framework/styles" />
<recent name="$PROJECT_DIR$/src/framework/helper/animations" /> <recent name="$PROJECT_DIR$/src/framework/helper/animations" />
<recent name="$PROJECT_DIR$/src/framework/helper" />
<recent name="$PROJECT_DIR$/src/framework/primitives/implementations" />
<recent name="C:\Projects\portfolio\CompiledCV\src\static\fonts" />
<recent name="C:\Projects\portfolio\CompiledCV\src\static\cv" />
</key> </key>
</component> </component>
<component name="ServiceViewManager"> <component name="ServiceViewManager">
@ -124,7 +182,8 @@
<workItem from="1578392333248" duration="21735000" /> <workItem from="1578392333248" duration="21735000" />
<workItem from="1578472848376" duration="13670000" /> <workItem from="1578472848376" duration="13670000" />
<workItem from="1578556192921" duration="3098000" /> <workItem from="1578556192921" duration="3098000" />
<workItem from="1578559306201" duration="30000" /> <workItem from="1578559306201" duration="8231000" />
<workItem from="1578641947739" duration="23098000" />
</task> </task>
<servers /> <servers />
</component> </component>
@ -147,4 +206,30 @@
<component name="VcsManagerConfiguration"> <component name="VcsManagerConfiguration">
<option name="ADD_EXTERNAL_FILES_SILENTLY" value="true" /> <option name="ADD_EXTERNAL_FILES_SILENTLY" value="true" />
</component> </component>
<component name="WindowStateProjectService">
<state x="1515" y="215" width="800" height="684" key="#Inspections" timestamp="1578563668907">
<screen x="0" y="27" width="2560" height="1053" />
</state>
<state x="1515" y="215" width="800" height="684" key="#Inspections/0.27.2560.1053@0.27.2560.1053" timestamp="1578563668907" />
<state x="1648" y="359" width="545" height="410" key="#com.intellij.fileTypes.FileTypeChooser" timestamp="1578643626511">
<screen x="0" y="27" width="2560" height="1053" />
</state>
<state x="1648" y="359" width="545" height="410" key="#com.intellij.fileTypes.FileTypeChooser/0.27.2560.1053@0.27.2560.1053" timestamp="1578643626511" />
<state x="1653" y="303" width="524" height="508" key="#com.intellij.refactoring.safeDelete.UnsafeUsagesDialog" timestamp="1578646728957">
<screen x="0" y="27" width="2560" height="1053" />
</state>
<state x="1653" y="303" width="524" height="508" key="#com.intellij.refactoring.safeDelete.UnsafeUsagesDialog/0.27.2560.1053@0.27.2560.1053" timestamp="1578646728957" />
<state x="1664" y="411" width="502" height="292" key="ANALYSIS_DLG_com.intellij.analysis.BaseAnalysisAction$1" timestamp="1578563647005">
<screen x="0" y="27" width="2560" height="1053" />
</state>
<state x="1664" y="411" width="502" height="292" key="ANALYSIS_DLG_com.intellij.analysis.BaseAnalysisAction$1/0.27.2560.1053@0.27.2560.1053" timestamp="1578563647005" />
<state x="1072" y="473" width="415" height="167" key="com.intellij.openapi.vcs.update.UpdateOrStatusOptionsDialogupdate-v2" timestamp="1578659707248">
<screen x="0" y="27" width="2560" height="1053" />
</state>
<state x="1072" y="473" width="415" height="167" key="com.intellij.openapi.vcs.update.UpdateOrStatusOptionsDialogupdate-v2/0.27.2560.1053@0.27.2560.1053" timestamp="1578659707248" />
<state x="1603" y="289" width="774" height="677" key="find.popup" timestamp="1578682206106">
<screen x="0" y="27" width="2560" height="1053" />
</state>
<state x="1603" y="289" width="774" height="677" key="find.popup/0.27.2560.1053@0.27.2560.1053" timestamp="1578682206106" />
</component>
</project> </project>

View file

@ -6,7 +6,7 @@ An easily configurable portfolio.
## Configuration ## Configuration
- The actual content is in [portfolio.ts](src/portfolio.ts). - The actual content is in [portfolio.ts](src/portfolio.ts).
- The assets referenced by this file should be located in [src/static](src/static). - The assets referenced by that file should be located in [src/static](src/static).
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/2.5/hu/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/2.5/hu/88x31.png" /></a><br />This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/2.5/hu/">Creative Commons Attribution-NonCommercial-ShareAlike 2.5 Hungary License</a>.

32
custom.d.ts vendored
View file

@ -1,47 +1,47 @@
declare module "*.svg" { declare module '*.svg' {
import { url } from "src/model/misc"; import { url } from 'src/framework/model/misc';
const content: url; const content: url;
export default content; export default content;
} }
declare module "*.png" { declare module '*.png' {
import { ResponsiveImage } from "src/model/misc"; import { ResponsiveImage } from 'src/framework/model/misc';
const content: ResponsiveImage; const content: ResponsiveImage;
export default content; export default content;
} }
declare module "*.jpg" { declare module '*.jpg' {
import { ResponsiveImage } from "src/model/misc"; import { ResponsiveImage } from 'src/framework/model/misc';
const content: ResponsiveImage; const content: ResponsiveImage;
export default content; export default content;
} }
declare module "*.jpeg" { declare module '*.jpeg' {
import { ResponsiveImage } from "src/model/misc"; import { ResponsiveImage } from 'src/framework/model/misc';
const content: ResponsiveImage; const content: ResponsiveImage;
export default content; export default content;
} }
declare module "*.gif" { declare module '*.gif' {
import { url } from "src/model/misc"; import { url } from 'src/framework/model/misc';
const content: url; const content: url;
export default content; export default content;
} }
declare module "*.mp4" { declare module '*.mp4' {
import { url } from "src/model/misc"; import { url } from 'src/framework/model/misc';
const content: url; const content: url;
export default content; export default content;
} }
declare module "*.webm" { declare module '*.webm' {
import { url } from "src/model/misc"; import { url } from 'src/framework/model/misc';
const content: url; const content: url;
export default content; export default content;
} }
declare module "*.pdf" { declare module '*.pdf' {
import { url } from "src/model/misc"; import { url } from 'src/framework/model/misc';
const content: url; const content: url;
export default content; export default content;
} }

View file

@ -55,9 +55,7 @@
"typescript": "^3.7.3", "typescript": "^3.7.3",
"webpack": "^4.41.4", "webpack": "^4.41.4",
"webpack-cli": "^3.3.10", "webpack-cli": "^3.3.10",
"webpack-dev-server": "^3.10.1" "webpack-dev-server": "^3.10.1",
}, "cssnano": "latest"
"dependencies": {
"sass": "latest"
} }
} }

View file

@ -1,5 +1,5 @@
import { PageElement } from './page-element'; import { PageElement } from './page-element';
import { PageEventType } from './page-event'; import { PageEventType } from './events/page-event';
export class ContainerPage extends PageElement { export class ContainerPage extends PageElement {
public constructor(rootElement: HTMLElement, children: Array<PageElement>) { public constructor(rootElement: HTMLElement, children: Array<PageElement>) {

View file

@ -0,0 +1 @@
@forward "styles/index";

View file

@ -1,4 +1,4 @@
import { html } from '../../model/misc'; import { html } from '../model/misc';
export const createElement = (from: html): HTMLElement => { export const createElement = (from: html): HTMLElement => {
// won't work for all elements, eg.: <td> // won't work for all elements, eg.: <td>

View file

@ -1,2 +0,0 @@
@import 'primitives/primitives';
@import 'helper/animations/animations';

View file

@ -1,5 +1,5 @@
import { PageEvent, PageEventType } from './page-event'; import { PageEvent, PageEventType } from './events/page-event';
import { EventBroadcaster } from './event-broadcaster'; import { EventBroadcaster } from './events/event-broadcaster';
export abstract class PageElement implements EventBroadcaster { export abstract class PageElement implements EventBroadcaster {
protected eventBroadcaster: EventBroadcaster; protected eventBroadcaster: EventBroadcaster;

View file

@ -1,5 +1,5 @@
import { Primitive } from '../primitive'; import { Primitive } from '../primitive';
import { html, url } from '../../../model/misc'; import { html, url } from '../../model/misc';
export class Anchor implements Primitive { export class Anchor implements Primitive {
public constructor( public constructor(
@ -8,10 +8,12 @@ export class Anchor implements Primitive {
) {} ) {}
public toHTML(): html { public toHTML(): html {
return `<a class="primitive-anchor" return `
href="${this.href}" <a class="primitive-anchor"
rel="noreferrer" href="${this.href}"
target="_blank" rel="noreferrer"
>${this.text}</a>`; target="_blank"
>${this.text}</a>
`;
} }
} }

View file

@ -1,5 +1,5 @@
import { Primitive } from '../primitive'; import { Primitive } from '../primitive';
import { html, ResponsiveImage } from '../../../model/misc'; import { html, ResponsiveImage } from '../../model/misc';
import { last } from '../../helper/last'; import { last } from '../../helper/last';
export class Image implements Primitive { export class Image implements Primitive {
@ -11,7 +11,7 @@ export class Image implements Primitive {
public toHTML(disableInnerShadow = false): html { public toHTML(disableInnerShadow = false): html {
return ` return `
${!disableInnerShadow ? `<div class="figure-container">` : ''} ${!disableInnerShadow ? `<div class="figure-container">` : ''}
<img <img tabindex="0"
srcset="${this.image.srcSet}" srcset="${this.image.srcSet}"
src="${last(this.image.images)?.path}" src="${last(this.image.images)?.path}"
alt="${this.alt}" alt="${this.alt}"

View file

@ -1,5 +1,5 @@
import { Primitive } from '../primitive'; import { Primitive } from '../primitive';
import { html } from '../../../model/misc'; import { html } from '../../model/misc';
export class Text implements Primitive { export class Text implements Primitive {
public constructor(private readonly text: string) {} public constructor(private readonly text: string) {}

View file

@ -1,5 +1,5 @@
import { Primitive } from '../primitive'; import { Primitive } from '../primitive';
import { url } from '../../../model/misc'; import { url } from '../../model/misc';
export class Video implements Primitive { export class Video implements Primitive {
public constructor( public constructor(
@ -11,7 +11,9 @@ export class Video implements Primitive {
public toHTML(disableInnerShadow = false): string { public toHTML(disableInnerShadow = false): string {
return ` return `
${!disableInnerShadow ? `<div class="figure-container">` : ''} ${!disableInnerShadow ? `<div class="figure-container">` : ''}
<video ${this.options} poster="${this.poster}"> <video ${this.options} ${
this.poster ? `poster="${this.poster}` : ''
}" >
<source src="${this.webm}" type="video/webm"/> <source src="${this.webm}" type="video/webm"/>
<source src="${this.mp4}" type="video/mp4"/> <source src="${this.mp4}" type="video/mp4"/>
</video> </video>

View file

@ -1,6 +1,4 @@
import { html } from '../../model/misc'; import { html } from '../model/misc';
import './primitives.scss';
export interface Primitive { export interface Primitive {
toHTML(): html; toHTML(): html;

View file

@ -1,27 +0,0 @@
@import '../../style/vars';
@import '../../style/mixins';
@include responsive() using ($vars) {
.figure-container {
font-size: 0;
box-shadow: inset map_get($vars, $shadow1), inset map_get($vars, $shadow2);
pointer-events: none;
cursor: pointer;
* {
pointer-events: all;
position: relative;
z-index: -2;
}
}
.primitive-text,
.primitive-anchor,
.figure-container {
margin-top: map_get($vars, $line-height);
}
.primitive-text {
text-align: left;
}
}

View file

@ -0,0 +1,5 @@
@mixin in-dark-mode() {
&[theme='dark'] {
@content;
}
}

View file

@ -0,0 +1,3 @@
@forward 'animations/animations';
@forward 'dark-mode/dark-mode';
@forward 'wrapper';

View file

@ -0,0 +1,38 @@
@use 'dark-mode/dark-mode' as *;
$breakpoint-width: 925px !default;
$small-screen-light-theme-variables: () !default;
$small-screen-dark-theme-variables: () !default;
$large-screen-light-theme-variables: () !default;
$large-screen-dark-theme-variables: () !default;
@mixin on-small-screen() {
@media (max-width: $breakpoint-width) {
@content;
}
}
@mixin on-large-screen() {
@media (min-width: $breakpoint-width) {
@content;
}
}
@mixin responsive() {
html {
@include on-small-screen {
@content ($small-screen-light-theme-variables);
@include in-dark-mode {
@content ($small-screen-dark-theme-variables);
}
}
}
@include on-large-screen {
html {
@content ($large-screen-light-theme-variables);
@include in-dark-mode {
@content ($large-screen-dark-theme-variables);
}
}
}
}

View file

@ -14,7 +14,6 @@
<meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover" /> <meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover" />
<meta name="theme-color" content="#b7455e" /> <meta name="theme-color" content="#b7455e" />
<title>Portfolio - András Schmelczer</title> <title>Portfolio - András Schmelczer</title>
</head> </head>
<body> <body>

View file

@ -1,9 +1,9 @@
import "./static/no-change/favicon.ico"; import { create } from './page/index';
import "./static/no-change/og-image.jpg"; import { portfolio } from './portfolio';
import "./styles.scss"; import './static/no-change/favicon.ico';
import './static/no-change/og-image.jpg';
import { create } from "./page/index"; import './styles.scss';
import { portfolio } from "./portfolio";
create(portfolio); create(portfolio);

View file

@ -1,4 +1,4 @@
import { url } from './misc'; import { url } from '../framework/model/misc';
import { Primitive } from '../framework/primitives/primitive'; import { Primitive } from '../framework/primitives/primitive';
import { Image } from '../framework/primitives/implementations/image'; import { Image } from '../framework/primitives/implementations/image';
import { Anchor } from '../framework/primitives/implementations/anchor'; import { Anchor } from '../framework/primitives/implementations/anchor';

View file

@ -1,5 +1,5 @@
import { Header } from '../../model/portfolio'; import { Header } from '../../model/portfolio';
import { html } from '../../model/misc'; import { html } from '../../framework/model/misc';
import './about.scss'; import './about.scss';

View file

@ -1,23 +1,16 @@
@import '../../style/mixins'; @use '../../style/include' as *;
@import '../../style/vars';
@include responsive() using ($vars) { @include responsive() using ($vars) {
#about { section#about {
@include card-base($vars); @include card-base($vars);
background-color: map_get($vars, $accent-color);
background-color: map_get($vars, $important-card-color); font-size: 0;
* {
color: map_get($vars, $important-card-text-color);
}
$img-size: 125px; $img-size: 125px;
h1, h1,
img, img,
.placeholder, .placeholder {
& { @include title-font($vars);
@include title-font();
} }
img { img {
@ -26,19 +19,18 @@
} }
p { p {
@include main-font(); @include main-font($vars);
text-align: justify; text-align: justify;
margin-top: map_get($vars, $small-margin);
} }
h1 { h1 {
hyphens: none; hyphens: none;
} }
@include on-small-screen { p,
h1 { h1 {
margin-top: map_get($vars, $small-margin); color: map_get($vars, $very-light-text-color);
} margin-top: map_get($vars, $small-margin);
} }
@include on-large-screen { @include on-large-screen {
@ -69,6 +61,7 @@
h1 { h1 {
text-align: left; text-align: left;
margin-top: 0;
} }
} }
} }

View file

@ -1,6 +1,5 @@
import { PageContent } from '../content/content'; import { PageContent } from '../content/content';
import { Header } from '../../model/portfolio'; import { Header } from '../../model/portfolio';
import { PageElement } from '../../framework/page-element';
import { generate } from './about.html'; import { generate } from './about.html';
import { createElement } from '../../framework/helper/create-element'; import { createElement } from '../../framework/helper/create-element';

View file

@ -1,9 +1,7 @@
@import '../../style/vars'; @use '../../style/include' as *;
@import '../../style/mixins';
@include responsive() using ($vars) { @include responsive() using ($vars) {
div.background-element { div.background-element {
position: -webkit-sticky;
position: absolute; position: absolute;
left: 0; left: 0;
top: 0; top: 0;
@ -24,9 +22,9 @@
} }
} }
transition: transform map_get($vars, $long-transition-time), transition: transform map_get($vars, $transition-time),
opacity map_get($vars, $long-transition-time), opacity map_get($vars, $transition-time),
background-color map_get($vars, $long-transition-time); background-color map_get($vars, $transition-time);
will-change: transform, opacity; will-change: transform, opacity;
animation: fade-in 1s linear; animation: fade-in 1s linear;

View file

@ -1,5 +1,5 @@
import { PageElement } from '../../framework/page-element'; import { PageElement } from '../../framework/page-element';
import { PageEvent, PageEventType } from '../../framework/page-event'; import { PageEvent, PageEventType } from '../../framework/events/page-event';
import { Blob } from './blob'; import { Blob } from './blob';
import { Random } from '../../framework/helper/random'; import { Random } from '../../framework/helper/random';
import { getHeight } from '../../framework/helper/get-height'; import { getHeight } from '../../framework/helper/get-height';
@ -15,13 +15,17 @@ export class PageBackground extends PageElement {
} }
protected handleEvent(event: PageEvent, parent: PageElement) { protected handleEvent(event: PageEvent, parent: PageElement) {
if (event.type === PageEventType.onLoad) { switch (event.type) {
this.bindListeners(parent); case PageEventType.onLoad:
} else if (event.type === PageEventType.onBodyDimensionsChanged) { this.bindListeners(parent);
this.resize(parent, event.data?.deltaHeight); break;
} else if (event.type === PageEventType.pageThemeChanged) { case PageEventType.onBodyDimensionsChanged:
Blob.changeTheme(event.data); this.resize(parent, event.data?.deltaHeight);
this.blobs.forEach(b => b.decideColor()); break;
case PageEventType.pageThemeChanged:
Blob.changeTheme(event.data);
this.blobs.forEach(b => b.decideColor());
break;
} }
} }

View file

@ -1,4 +1,4 @@
import { html } from '../../model/misc'; import { html } from '../../framework/model/misc';
import './background.scss'; import './background.scss';
export const generate = (): html => ` export const generate = (): html => `

View file

@ -1,14 +1,15 @@
import { mixColors } from '../../framework/helper/mix-colors'; import { mixColors } from '../../framework/helper/mix-colors';
import { createElement } from '../../framework/helper/create-element'; import { createElement } from '../../framework/helper/create-element';
import { Random } from '../../framework/helper/random'; import { Random } from '../../framework/helper/random';
import { generate } from './background.html'; import { generate } from './blob.html';
export class Blob { export class Blob {
private static readonly creatorRandom = new Random(44); private static readonly creatorRandom = new Random(44);
private static colorPickerRandom = new Random(132); private static readonly darkColors = ['#2c477a'];
private static readonly lightColors = ['#fff9e0', '#ffd6d6']; private static readonly lightColors = ['#fff9e0', '#ffd6d6'];
private static readonly darkColors = ['#2C477A']; private static colorPickerRandom = new Random(132);
private static isDarkThemed = false; private static isDarkThemed = false;
private static zMin: number; private static zMin: number;
private static zMax: number; private static zMax: number;
private static perspective: number; private static perspective: number;

View file

@ -1,5 +1,5 @@
import { Content } from '../../model/portfolio'; import { Content } from '../../model/portfolio';
import { html } from '../../model/misc'; import { html } from '../../framework/model/misc';
import './content.scss'; import './content.scss';

View file

@ -1,8 +1,11 @@
@import '../../style/vars'; @use '../../style/include' as *;
@import '../../style/mixins';
@include responsive() using ($vars) { @include responsive() using ($vars) {
.content { .content {
margin-top: map_get($vars, $small-margin); margin-top: map_get($vars, $small-margin);
:first-child {
margin-top: 0;
}
} }
} }

View file

@ -1,5 +1,5 @@
import { Footer } from '../../model/portfolio'; import { Footer } from '../../model/portfolio';
import { html } from '../../model/misc'; import { html } from '../../framework/model/misc';
import './footer.scss'; import './footer.scss';

View file

@ -1,21 +1,20 @@
@import '../../style/mixins'; @use '../../style/include' as *;
@import '../../style/vars';
@include responsive() using ($vars) { @include responsive() using ($vars) {
footer#page-footer { footer#page-footer {
text-align: center; text-align: center;
margin: map_get($vars, $large-margin) auto 0 auto; margin-top: map_get($vars, $large-margin);
width: 100%; width: 100%;
h2 { h2 {
@include title-font(); @include title-font($vars);
} }
ul { ul {
margin-top: map_get($vars, $normal-margin);
list-style: none; list-style: none;
display: inline-block; display: inline-block;
margin-top: map_get($vars, $normal-margin);
text-align: left; text-align: left;
li { li {
@ -29,10 +28,11 @@
img, img,
svg { svg {
@include max-square(map_get($vars, $icon-size)); @include max-square(map_get($vars, $icon-size));
margin-right: map_get($vars, $small-margin);
* { * {
fill: map_get($vars, $normal-text-color); fill: map_get($vars, $normal-text-color);
} }
margin-right: map_get($vars, $small-margin);
} }
a { a {
@ -44,13 +44,17 @@
aside.other { aside.other {
@include center-children(); @include center-children();
flex-direction: column; flex-direction: column;
margin: map_get($vars, $large-margin) auto map_get($vars, $line-height) margin: map_get($vars, $large-margin) auto 0 auto;
auto; padding-bottom: map_get($vars, $line-height);
width: map_get($vars, $body-width); width: map_get($vars, $body-width);
h6 { h6 {
@include special-text-font($vars);
display: inline; display: inline;
&,
* {
@include special-text-font($vars);
color: map_get($vars, $normal-text-color);
}
opacity: 0.75; opacity: 0.75;
} }
} }

View file

@ -1,4 +1,4 @@
import { html } from '../../model/misc'; import { html } from '../../framework/model/misc';
import cancel from '../../static/icons/cancel.svg'; import cancel from '../../static/icons/cancel.svg';
import './image-viewer.scss'; import './image-viewer.scss';
@ -6,6 +6,6 @@ import './image-viewer.scss';
export const generate = (): html => ` export const generate = (): html => `
<section id="image-viewer"> <section id="image-viewer">
<div id="container"></div> <div id="container"></div>
<img id="cancel" src="${cancel}" alt="cancel"/> <img tabindex="0" id="cancel" src="${cancel}" alt="cancel"/>
</section> </section>
`; `;

View file

@ -1,8 +1,7 @@
@import '../../style/vars'; @use '../../style/include' as *;
@import '../../style/mixins';
@include responsive() using ($vars) { @include responsive() using ($vars) {
#image-viewer { section#image-viewer {
@include center-children(); @include center-children();
display: none; display: none;
position: fixed; position: fixed;

View file

@ -1,7 +1,7 @@
import { PageElement } from '../../framework/page-element'; import { PageElement } from '../../framework/page-element';
import { generate } from './image-viewer.html'; import { generate } from './image-viewer.html';
import { PageEvent, PageEventType } from '../../framework/page-event'; import { PageEvent, PageEventType } from '../../framework/events/page-event';
import { createElement } from '../../framework/helper/create-element'; import { createElement } from '../../framework/helper/create-element';
export class PageImageViewer extends PageElement { export class PageImageViewer extends PageElement {
@ -11,24 +11,19 @@ export class PageImageViewer extends PageElement {
} }
protected handleEvent(event: PageEvent, parent: PageElement) { protected handleEvent(event: PageEvent, parent: PageElement) {
if (event.type !== PageEventType.onLoad) { if (event.type === PageEventType.onLoad) {
return; document.body.addEventListener('keydown', this.handleKeydown.bind(this));
}
document.body.addEventListener('keydown', this.handleKeydown.bind(this)); const media = Array.prototype.slice.call(
parent.element.querySelectorAll('img')
const media = Array.prototype.slice.call(
parent.element.querySelectorAll('img, video')
);
media
.filter(
(e: HTMLElement) =>
e.parentElement !== this.element && !e.classList.contains('no-open')
)
.forEach(
(e: HTMLImageElement) => (e.onclick = this.handleClick.bind(this))
); );
media
.filter((e: HTMLElement) => e.parentElement !== this.element)
.forEach(
(e: HTMLImageElement) => (e.onclick = this.handleClick.bind(this))
);
}
} }
private handleClick(event: Event) { private handleClick(event: Event) {

View file

@ -19,4 +19,20 @@ export const create = ({ header, timeline, footer }: Portfolio) => {
new PageBackground(pageHeader, pageFooter), new PageBackground(pageHeader, pageFooter),
]), ]),
]).setAsMain(); ]).setAsMain();
addSupportForTabNavigation();
removeUnnecessaryOutlines();
}; };
const addSupportForTabNavigation = () =>
(document.onkeydown = e => {
if (e.key === ' ') {
(document.activeElement as HTMLElement)?.click();
e.preventDefault();
}
});
const removeUnnecessaryOutlines = () =>
(document.onclick = e => {
(e.target as HTMLElement)?.blur();
});

View file

@ -1,7 +1,7 @@
import { html } from '../../model/misc'; import { html } from '../../framework/model/misc';
import './theme-switcher.scss'; import './theme-switcher.scss';
export const generate = (): html => ` export const generate = (): html => `
<input id="theme-switcher" type="checkbox" name="switch-theme"/> <input id="theme-switcher" aria-label="color-theme-switch" type="checkbox" name="switch-theme"/>
`; `;

View file

@ -1,5 +1,4 @@
@import '../../style/mixins'; @use '../../style/include' as *;
@import '../../style/vars';
@include responsive using($vars) { @include responsive using($vars) {
input[type='checkbox']#theme-switcher { input[type='checkbox']#theme-switcher {
@ -14,11 +13,12 @@
margin-top: map_get($vars, $normal-margin); margin-top: map_get($vars, $normal-margin);
} }
&::-ms-check {
display: none;
}
background-color: map_get($vars, $accent-color); background-color: map_get($vars, $accent-color);
z-index: 10;
cursor: pointer; cursor: pointer;
-webkit-appearance: none; -webkit-appearance: none;
-moz-appearance: none; -moz-appearance: none;
@ -33,10 +33,12 @@
inset 0 0 1px rgba(0, 0, 0, 0.4); inset 0 0 1px rgba(0, 0, 0, 0.4);
&:before { &:before {
// moon + sun
@include square($icon-size); @include square($icon-size);
} }
&:after { &:after {
// sun blocking moon
@include square($icon-size * 0.8); @include square($icon-size * 0.8);
} }
@ -50,8 +52,8 @@
top: 50%; top: 50%;
transform: translateY(-50%); transform: translateY(-50%);
transition: transform map_get($vars, $long-transition-time), transition: transform map_get($vars, $transition-time),
background-color map_get($vars, $long-transition-time); background-color map_get($vars, $transition-time);
} }
&:not(:checked) { &:not(:checked) {
@ -59,16 +61,16 @@
transform: translateY(-50%) translateX(3 * $margin + $icon-size); transform: translateY(-50%) translateX(3 * $margin + $icon-size);
animation: shine 3s linear alternate infinite; animation: shine 3s linear alternate infinite;
background-color: map_get($vars, $theme-switcher-foreground); background-color: map_get($vars, $sun-color);
@keyframes shine { @keyframes shine {
from { from {
filter: brightness(1.01); filter: brightness(1.01);
box-shadow: 0 0 4px 2px map_get($vars, $theme-switcher-foreground); box-shadow: 0 0 4px 2px map_get($vars, $sun-color);
} }
to { to {
filter: brightness(1.1); filter: brightness(1.1);
box-shadow: 0 0 15px 2px map_get($vars, $theme-switcher-foreground); box-shadow: 0 0 15px 2px map_get($vars, $sun-color);
} }
} }
} }
@ -90,9 +92,5 @@
transform: translateY(-50%) translateX($margin + $icon-size * 0.33); transform: translateY(-50%) translateX($margin + $icon-size * 0.33);
} }
} }
&:focus {
outline: 0;
}
} }
} }

View file

@ -5,13 +5,13 @@ import {
isSystemLevelDarkModeEnabled, isSystemLevelDarkModeEnabled,
turnOnDarkMode, turnOnDarkMode,
turnOnLightMode, turnOnLightMode,
} from '../../framework/helper/dark-mode'; } from '../../framework/styles/dark-mode/dark-mode';
import { PageEvent, PageEventType } from '../../framework/page-event'; import { PageEvent, PageEventType } from '../../framework/events/page-event';
import { EventBroadcaster } from '../../framework/event-broadcaster'; import { EventBroadcaster } from '../../framework/events/event-broadcaster';
import { import {
turnOffAnimations, turnOffAnimations,
turnOnAnimations, turnOnAnimations,
} from '../../framework/helper/animations/animations'; } from '../../framework/styles/animations/animations';
export class PageThemeSwitcher extends PageElement { export class PageThemeSwitcher extends PageElement {
private static readonly LOCAL_STORAGE_KEY = 'dark-mode'; private static readonly LOCAL_STORAGE_KEY = 'dark-mode';
@ -62,9 +62,12 @@ export class PageThemeSwitcher extends PageElement {
} }
private static loadFromLocalStorage(): boolean | null { private static loadFromLocalStorage(): boolean | null {
return JSON.parse( try {
window.localStorage?.getItem(PageThemeSwitcher.LOCAL_STORAGE_KEY) || return JSON.parse(
'null' window.localStorage?.getItem(PageThemeSwitcher.LOCAL_STORAGE_KEY)
); );
} catch {
return null;
}
} }
} }

View file

@ -1,5 +1,5 @@
import { TimelineElement } from '../../../model/portfolio'; import { TimelineElement } from '../../../model/portfolio';
import { html } from '../../../model/misc'; import { html } from '../../../framework/model/misc';
import './timeline-element.scss'; import './timeline-element.scss';
@ -22,8 +22,8 @@ export const generate = (
? ` ? `
<div class="more"></div> <div class="more"></div>
<div class="buttons"> <div class="buttons">
<a class="show-more">${showMore}</a> <a tabindex="0" class="show-more">${showMore}</a>
<a class="show-less">${showLess}</a> <a tabindex="0" class="show-less">${showLess}</a>
</div> </div>
` `
: '' : ''

View file

@ -1,5 +1,4 @@
@import '../../../style/mixins'; @use '../../../style/include' as *;
@import '../../../style/vars';
@mixin q-dependent-line-container($vars, $q) { @mixin q-dependent-line-container($vars, $q) {
.line { .line {
@ -18,7 +17,7 @@
} }
@include responsive() using ($vars) { @include responsive() using ($vars) {
.timeline-element { section.timeline-element {
display: flex; display: flex;
width: map_get($vars, $body-width); width: map_get($vars, $body-width);
margin: auto; margin: auto;
@ -32,9 +31,13 @@
border-left: map_get($vars, $line-width) solid border-left: map_get($vars, $line-width) solid
map_get($vars, $accent-color); map_get($vars, $accent-color);
&:before { &:before,
&:after {
content: ''; content: '';
position: absolute; position: absolute;
}
&:before {
left: 0; left: 0;
bottom: 0; bottom: 0;
border-left: map_get($vars, $line-width) solid border-left: map_get($vars, $line-width) solid
@ -42,12 +45,10 @@
} }
&:after { &:after {
content: '';
@include square(map_get($vars, $icon-size)); @include square(map_get($vars, $icon-size));
border-radius: 1000px; border-radius: 1000px;
border: map_get($vars, $line-width) solid border: map_get($vars, $line-width) solid
map_get($vars, $accent-color); map_get($vars, $accent-color);
position: absolute;
left: -1 * map_get($vars, $icon-size) / 2 + left: -1 * map_get($vars, $icon-size) / 2 +
map_get($vars, $line-width) / 2; map_get($vars, $line-width) / 2;
} }
@ -88,18 +89,19 @@
.card { .card {
@include card-base($vars); @include card-base($vars);
border-radius: map_get($vars, $border-radius); border-radius: map_get($vars, $border-radius);
background-color: map_get($vars, $card-color); background-color: map_get($vars, $card-color);
overflow: hidden;
& > *:not(:first-child) { & > *:not(:first-child) {
margin-top: map_get($vars, $line-height); margin-top: map_get($vars, $line-height);
} }
.content {
margin-top: 0;
}
h2 { h2 {
@include sub-title-font(); @include sub-title-font($vars);
} }
& > p { & > p {
@ -110,16 +112,16 @@
.more { .more {
overflow: hidden; overflow: hidden;
height: 0; height: 0;
margin-top: 0; transition: height map_get($vars, $transition-time);
transition: height map_get($vars, $long-transition-time);
} }
.buttons { .buttons {
position: relative; position: relative;
margin-top: map_get($vars, $small-margin); margin-top: map_get($vars, $line-height);
* { .show-more,
transition: opacity map_get($vars, $long-transition-time); .show-less {
transition: opacity map_get($vars, $transition-time);
} }
.show-more { .show-more {
@ -127,9 +129,9 @@
} }
.show-less { .show-less {
@include absolute-center();
opacity: 0; opacity: 0;
visibility: hidden; visibility: hidden;
@include absolute-center();
} }
} }
} }

View file

@ -2,11 +2,11 @@ import { TimelineElement } from '../../../model/portfolio';
import { PageContent } from '../../content/content'; import { PageContent } from '../../content/content';
import { PageElement } from '../../../framework/page-element'; import { PageElement } from '../../../framework/page-element';
import { generate } from './timeline-element.html'; import { generate } from './timeline-element.html';
import { PageEventType } from '../../../framework/page-event'; import { PageEventType } from '../../../framework/events/page-event';
import { createElement } from '../../../framework/helper/create-element'; import { createElement } from '../../../framework/helper/create-element';
export class PageTimelineElement extends PageElement { export class PageTimelineElement extends PageElement {
private isOpen; private isOpen: boolean;
private more: HTMLElement; private more: HTMLElement;
public constructor( public constructor(
@ -56,7 +56,7 @@ export class PageTimelineElement extends PageElement {
this.eventBroadcaster?.broadcastEvent({ this.eventBroadcaster?.broadcastEvent({
type: PageEventType.onBodyDimensionsChanged, type: PageEventType.onBodyDimensionsChanged,
}), }),
350 250
); );
} }
@ -64,7 +64,7 @@ export class PageTimelineElement extends PageElement {
element.style.opacity = '0'; element.style.opacity = '0';
setTimeout(() => { setTimeout(() => {
element.style.visibility = 'hidden'; element.style.visibility = 'hidden';
}, 350); }, 250);
} }
private static show(element: HTMLElement) { private static show(element: HTMLElement) {

View file

@ -1,5 +1,5 @@
import { html } from "../../model/misc"; import { html } from '../../framework/model/misc';
import "./timeline.scss"; import './timeline.scss';
export const generate = (): html => ` export const generate = (): html => `
<main id="timeline"></main> <main id="timeline"></main>

View file

@ -1,8 +1,7 @@
@import '../../style/vars'; @use '../../style/include' as *;
@import '../../style/mixins';
@include responsive() using ($vars) { @include responsive() using ($vars) {
#timeline { main#timeline {
@include on-large-screen { @include on-large-screen {
// workaround for IE // workaround for IE
& > :first-child { & > :first-child {

View file

@ -1,5 +1,4 @@
import { Timeline } from '../../model/portfolio'; import { Timeline } from '../../model/portfolio';
import { PageElement } from '../../framework/page-element';
import { PageTimelineElement } from './timeline-element/timeline-element'; import { PageTimelineElement } from './timeline-element/timeline-element';
import { generate } from './timeline.html'; import { generate } from './timeline.html';
import { createElement } from '../../framework/helper/create-element'; import { createElement } from '../../framework/helper/create-element';

View file

@ -5,10 +5,9 @@ import { Video } from './framework/primitives/implementations/video';
import { Anchor } from './framework/primitives/implementations/anchor'; import { Anchor } from './framework/primitives/implementations/anchor';
import me from './static/media/me.jpg'; import me from './static/media/me.jpg';
import forexGIF from './static/media/forex.gif';
import forexMP4 from './static/media/forex.mp4'; import forexMP4 from './static/media/forex.mp4';
import forexWEBM from './static/media/forex.webm'; import forexWEBM from './static/media/forex.webm';
import myNotes from './static/media/my-notes.jpg'; import myNotes from './static/media/my-notes.png';
import processSimulator from './static/media/process-simulator.jpg'; import processSimulator from './static/media/process-simulator.jpg';
import processSimulatorInput from './static/media/process-simulator-input.jpg'; import processSimulatorInput from './static/media/process-simulator-input.jpg';
import citySimulation from './static/media/simulation.jpg'; import citySimulation from './static/media/simulation.jpg';
@ -19,6 +18,7 @@ import led from './static/media/led.jpg';
import cv from './static/cv/andras_schmelczer_cv_2020_01.pdf'; import cv from './static/cv/andras_schmelczer_cv_2020_01.pdf';
import ledMP4 from './static/media/led.mp4'; import ledMP4 from './static/media/led.mp4';
import ledWEBM from './static/media/led.webm'; import ledWEBM from './static/media/led.webm';
import { last } from './framework/helper/last';
export const portfolio: Portfolio = { export const portfolio: Portfolio = {
header: { header: {
@ -44,10 +44,10 @@ export const portfolio: Portfolio = {
title: `Predicting foreign exchange rates`, title: `Predicting foreign exchange rates`,
date: `2019 Autumn`, date: `2019 Autumn`,
figure: new Video( figure: new Video(
forexGIF, null,
forexMP4, forexMP4,
forexWEBM, forexWEBM,
`autoplay loop muted playsinline` `autoplay loop muted playsinline controls`
), ),
description: new Text( description: new Text(
`From the animation we can see that my algorithm does a somewhat acceptable job at `From the animation we can see that my algorithm does a somewhat acceptable job at
@ -74,13 +74,13 @@ export const portfolio: Portfolio = {
`A minimalist note organizer and editor powered by Markwon.` `A minimalist note organizer and editor powered by Markwon.`
), ),
more: [ more: [
new Text(
`A basic android app for creating and filtering notes written in markdown.`
),
new Anchor( new Anchor(
`https://github.com/schmelczerandras/my-notes`, `https://github.com/schmelczerandras/my-notes`,
`MyNotes on GitHub` `MyNotes on GitHub`
), ),
new Text(
`A basic android app for creating and filtering notes written in markdown.`
),
new Text( new Text(
`It was my homework for BME's Android and web development course. `It was my homework for BME's Android and web development course.
It was also my first experience with Android development.` It was also my first experience with Android development.`
@ -211,7 +211,12 @@ export const portfolio: Portfolio = {
{ {
date: `2016 spring`, date: `2016 spring`,
title: `Lights synchronised to music`, title: `Lights synchronised to music`,
figure: new Video(led.src, ledMP4, ledWEBM, `controls`), figure: new Video(
last(led.images).path,
ledMP4,
ledWEBM,
`controls playsinline preload="none"`
),
description: new Text( description: new Text(
`A full stack application with a built-in `A full stack application with a built-in
music player which music controls the color of some RGB LED strips.` music player which music controls the color of some RGB LED strips.`
@ -233,15 +238,15 @@ export const portfolio: Portfolio = {
footer: { footer: {
title: `Learn more`, title: `Learn more`,
curiumVitaes: [ curiumVitaes: [
{ name: `Curriculum vitae (en)`, url: cv }, { name: `Curriculum vitae`, url: cv },
{ name: `Önéletrajz (hu)`, url: cv }, /*{ name: `Önéletrajz (hu)`, url: cv },*/
], ],
email: `andras@schmelczer.dev`, email: `andras@schmelczer.dev`,
lastEditText: `Last modified on `, lastEditText: `Last modified on `,
lastEdit: new Date(2020, 0, 6), // months are 0 indexed lastEdit: new Date(2020, 0, 10), // months are 0 indexed
gitHub: new Anchor( gitHub: new Anchor(
`https://github.com/schmelczerandras/timeline`, `https://github.com/schmelczerandras/timeline`,
`Find this page on GitHub.` `Find this on GitHub`
), ),
}, },
}; };

Binary file not shown.

Before

Width:  |  Height:  |  Size: 213 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 MiB

6
src/style/_id.scss Normal file
View file

@ -0,0 +1,6 @@
$_id_value: 0;
@function id() {
$_id_value: $_id_value + 1 !global;
@return $_id_value;
}

View file

@ -1,48 +1,48 @@
@import 'vars'; @use 'sass:color';
@import 'mixins'; @use 'include' as i;
@include responsive() using ($vars) { @include i.responsive() using ($vars) {
a { a {
@include special-text-font($vars); $border-shift: 10px;
$line-width: 2px;
@include i.special-text-font($vars);
text-decoration: none; text-decoration: none;
position: relative;
cursor: pointer; cursor: pointer;
position: relative;
display: inline-block; display: inline-block;
overflow: hidden; overflow: hidden;
$border-shift: 10px; padding-bottom: $line-width;
transition: transform map_get($vars, $long-transition-time);
&:before {
content: '';
display: block;
position: absolute;
width: 100%;
height: map_get($vars, $line-width);
bottom: 0;
z-index: 1;
background: linear-gradient(
90deg,
map_get($vars, $card-color) 0,
transparentize(map_get($vars, $card-color), 1) 4px,
transparentize(map_get($vars, $card-color), 1) calc(100% - 4px),
map_get($vars, $card-color) 100%
);
}
&:before,
&:after { &:after {
content: ''; content: '';
display: block; display: block;
position: absolute;
bottom: 0;
}
&:before {
width: calc(100% + #{$border-shift}); width: calc(100% + #{$border-shift});
z-index: 0; border-bottom: $line-width dashed map_get($vars, i.$accent-color);
border-bottom: map_get($vars, $line-width) dashed transition: transform map_get($vars, i.$transition-time);
map_get($vars, $accent-color); }
transition: transform map_get($vars, $long-transition-time);
&:after {
width: 100%;
height: $line-width;
background: linear-gradient(
90deg,
map_get($vars, i.$card-color) 0,
color.adjust(map_get($vars, i.$card-color), $alpha: -1) 4px,
color.adjust(map_get($vars, i.$card-color), $alpha: -1) calc(100% - 4px),
map_get($vars, i.$card-color) 100%
);
} }
&:hover { &:hover {
&:after { &:before {
transform: translateX(-$border-shift); transform: translateX(-$border-shift);
} }
} }

View file

@ -0,0 +1,7 @@
@use 'vars';
@forward "../framework/framework" with (
$small-screen-light-theme-variables: vars.$small-screen-light-theme-variables,
$small-screen-dark-theme-variables: vars.$small-screen-dark-theme-variables,
$large-screen-light-theme-variables: vars.$large-screen-light-theme-variables,
$large-screen-dark-theme-variables: vars.$large-screen-dark-theme-variables,
);

View file

@ -1,6 +1,4 @@
// https://google-webfonts-helper.herokuapp.com/fonts/montserrat?subsets=latin // https://google-webfonts-helper.herokuapp.com/fonts/montserrat?subsets=latin
// add font-display: swap;
/*
/* lato-regular - latin */ /* lato-regular - latin */
@font-face { @font-face {
font-family: 'Lato'; font-family: 'Lato';

7
src/style/include.scss Normal file
View file

@ -0,0 +1,7 @@
@forward "configured-responsive";
@forward "mixins";
@forward "vars" hide
$small-screen-light-theme-variables,
$small-screen-dark-theme-variables,
$large-screen-light-theme-variables,
$large-screen-dark-theme-variables;

View file

@ -1,35 +1,5 @@
@import 'vars'; @use "configured-responsive";
@use "vars";
@mixin on-small-screen() {
@media (max-width: $breakpoint-width) {
@content;
}
}
@mixin on-large-screen() {
@media (min-width: $breakpoint-width) {
@content;
}
}
@mixin responsive() {
html {
@include on-small-screen {
@content (map_merge($small-screen-variables, $light-theme-variables));
&[theme='dark'] {
@content (map_merge($small-screen-variables, $dark-theme-variables));
}
}
}
@include on-large-screen {
html {
@content (map_merge($large-screen-variables, $light-theme-variables));
&[theme='dark'] {
@content (map_merge($large-screen-variables, $dark-theme-variables));
}
}
}
}
@mixin center-children() { @mixin center-children() {
display: flex; display: flex;
@ -46,17 +16,9 @@
@mixin card-base($vars) { @mixin card-base($vars) {
text-align: center; text-align: center;
padding: map_get($vars, $normal-margin); padding: map_get($vars, vars.$normal-margin);
box-shadow: map_get($vars, $shadow1), map_get($vars, $shadow2); box-shadow: map_get($vars, vars.$shadow);
z-index: 1; z-index: 1;
@include on-large-screen {
transition: box-shadow map_get($vars, $long-transition-time),
background-color map_get($vars, $long-transition-time);
&:hover {
box-shadow: map_get($vars, $shadow3), map_get($vars, $shadow2);
}
}
} }
@mixin square($size) { @mixin square($size) {
@ -69,29 +31,32 @@
max-height: $size; max-height: $size;
} }
@mixin title-font() { @mixin title-font($vars) {
font: 400 3.5rem 'Montserrat', serif; font: 400 3.5rem 'Montserrat', serif;
font-style: normal; font-style: normal;
color: map_get($vars, vars.$normal-text-color);
line-height: 1; line-height: 1;
@include on-small-screen { @include configured-responsive.on-small-screen {
font-size: 3rem; font-size: 3rem;
line-height: 1.1; line-height: 1.1;
} }
} }
@mixin sub-title-font() { @mixin sub-title-font($vars) {
font: 400 2rem 'Montserrat', serif; font: 400 2rem 'Montserrat', serif;
color: map_get($vars, vars.$normal-text-color);
font-style: normal; font-style: normal;
} }
@mixin main-font() { @mixin main-font($vars) {
font: 400 1.25rem 'Lato', sans-serif; font: 400 1.25rem 'Lato', sans-serif;
color: map_get($vars, vars.$normal-text-color);
line-height: 1.6; line-height: 1.6;
} }
@mixin special-text-font($vars) { @mixin special-text-font($vars) {
font: 400 1.1rem 'Lato', sans-serif; font: 400 1.1rem 'Lato', sans-serif;
color: map_get($vars, $special-text-color); color: map_get($vars, vars.$special-text-color);
font-style: italic; font-style: italic;
} }

View file

@ -1,115 +1,108 @@
@import 'fonts'; @use 'fonts';
@use "id" as *;
$_id_value: 0; /* KEYS */
@function id() {
$_id_value: $_id_value + 1 !global;
@return $_id_value;
}
/* NAMES */
$background: id(); $background: id();
$normal-text-color: id(); $normal-text-color: id();
$light-text-color: id(); $very-light-text-color: id();
$important-card-text-color: id();
$inverse-text-color: id();
$card-color: id();
$important-card-color: id();
$theme-switcher-background: id();
$theme-switcher-foreground: id();
$special-text-color: id(); $special-text-color: id();
$card-color: id();
$sun-color: id();
$accent-color: id(); $accent-color: id();
$scrollbar-color: id();
$short-transition-time: id(); $transition-time: id();
$long-transition-time: id();
$line-width: id();
$border-radius: id(); $border-radius: id();
$breakpoint-width: id(); $line-width: id();
$large-margin: id();
$normal-margin: id();
$small-margin: id();
$line-height: id();
$shadow1: id();
$shadow2: id();
$shadow3: id();
$body-width: id(); $body-width: id();
$small-margin: id();
$normal-margin: id();
$large-margin: id();
$icon-size: id(); $icon-size: id();
$line-height: id();
$shadow: id();
$inset-shadow: id();
/**/ /**/
$breakpoint-width: 925px;
$universal-variables: ( $universal-variables: (
$short-transition-time: 220ms, $transition-time: 250ms,
$long-transition-time: 350ms,
$line-width: 3px, $line-width: 3px,
$line-height: 18px, $line-height: 18px,
$theme-switcher-foreground: #f7f78c,
$accent-color: #b7455e, $accent-color: #b7455e,
$important-card-color: #b7405a, $sun-color: #f7f78c,
$shadow3: 0 0 15px 4px rgba(0, 0, 0, 0.1), $very-light-text-color: #ffffff,
); );
$large-screen-variables: map_merge( $large-screen-variables: (
( $border-radius: 15px,
$border-radius: 15px, $large-margin: 70px,
$large-margin: 70px, $normal-margin: 45px,
$normal-margin: 45px, $small-margin: 25px,
$small-margin: 25px, $shadow: (
$shadow1: 0 0 10px 2px rgba(0, 0, 0, 0.075), 0 0 10px 2px rgba(0, 0, 0, 0.075),
$shadow2: 0 0 1px rgba(0, 0, 0, 0.2), 0 0 1px rgba(0, 0, 0, 0.2),
$icon-size: 35px,
$body-width: 765px,
), ),
$universal-variables $inset-shadow: (
inset 0 0 10px 2px rgba(0, 0, 0, 0.075),
inset 0 0 1px rgba(0, 0, 0, 0.2),
),
$icon-size: 35px,
$body-width: 765px,
); );
$small-screen-variables: map_merge( $small-screen-variables: (
( $border-radius: 10px,
$border-radius: 10px, $large-margin: 60px,
$large-margin: 60px, $normal-margin: 30px,
$normal-margin: 30px, $small-margin: 15px,
$small-margin: 15px, $shadow: (
$shadow1: 0 0 10px 2px rgba(0, 0, 0, 0.05), 0 0 10px 2px rgba(0, 0, 0, 0.05),
$shadow2: 0 0 1px rgba(0, 0, 0, 0.125), 0 0 1px rgba(0, 0, 0, 0.125),
$icon-size: 25px,
$body-width: 90%,
), ),
$universal-variables $inset-shadow: (
inset 0 0 10px 2px rgba(0, 0, 0, 0.05),
inset 0 0 1px rgba(0, 0, 0, 0.125),
),
$icon-size: 25px,
$body-width: 90%,
); );
$light-theme-variables: map_merge( $light-theme-variables: (
( $background: #ffffff,
$background: #ffffff, $normal-text-color: #31343f,
$normal-text-color: #31343f, $card-color: #ffffff,
$light-text-color: #7a7d8e, $special-text-color: map_get($universal-variables, $accent-color),
$inverse-text-color: #ffffff,
$card-color: #ffffff,
$important-card-text-color: #ffffff,
$special-text-color: map_get($universal-variables, $accent-color),
$scrollbar-color: #ffd6d6,
),
$universal-variables
); );
$dark-theme-variables: map_merge( $dark-theme-variables: (
( $background: #242638,
$background: #242638, $normal-text-color: #ffffff,
$normal-text-color: #ffffff, $card-color: #263551,
$light-text-color: #fff9e0, $special-text-color: #ffffff,
$inverse-text-color: #242638, $shadow: (
$card-color: #263551, 0 0 10px 2px rgba(0, 0, 0, 0.175),
$special-text-color: #ffffff, 0 0 1px rgba(0, 0, 0, 0.4),
$important-card-text-color: #fff9e0, ),
$scrollbar-color: #ffd6d6, $inset-shadow: (
$shadow1: 0 0 10px 2px rgba(0, 0, 0, 0.175), inset 0 0 10px 2px rgba(0, 0, 0, 0.175),
$shadow2: 0 0 1px rgba(0, 0, 0, 0.4), inset 0 0 1px rgba(0, 0, 0, 0.4),
), ),
$universal-variables );
$small-screen-light-theme-variables: map_merge(
$universal-variables,
map_merge($small-screen-variables, $light-theme-variables)
);
$small-screen-dark-theme-variables: map_merge(
$universal-variables,
map_merge($small-screen-variables, $dark-theme-variables)
);
$large-screen-light-theme-variables: map_merge(
$universal-variables,
map_merge($large-screen-variables, $light-theme-variables)
);
$large-screen-dark-theme-variables: map_merge(
$universal-variables,
map_merge($large-screen-variables, $dark-theme-variables)
); );

View file

@ -1,91 +1,120 @@
@import 'style/vars'; @use 'style/include' as *;
@import 'style/mixins'; @use 'style/a';
@import 'style/a'; @use 'framework/styles/index';
@import 'framework/index';
@include responsive() using ($vars) { @include responsive() using ($vars) {
& { & {
background-color: map_get($vars, $background);
transition: background-color map_get($vars, $long-transition-time);
height: 100%; height: 100%;
background-color: map_get($vars, $background);
transition: background-color map_get($vars, $transition-time);
touch-action: manipulation;
@include on-small-screen { @include on-small-screen {
font-size: 0.8em; font-size: 0.8em;
} }
} }
body { :focus {
@include main-font(); outline: none;
//noinspection CssInvalidFunction &:not(:hover) {
padding: env(safe-area-inset-top, 20px) env(safe-area-inset-right, 20px) outline: map_get($vars, $accent-color) solid 2px;
env(safe-area-inset-bottom, 20px) env(safe-area-inset-left, 20px); outline-offset: 4px;
}
}
height: 100%; ::-moz-selection {
overflow: hidden; background-color: map_get($vars, $accent-color);
color: map_get($vars, $very-light-text-color);
}
::selection {
background-color: map_get($vars, $accent-color);
color: map_get($vars, $very-light-text-color);
} }
*, *,
*::before, *::before,
*::after { *::after {
@include main-font($vars);
margin: 0; margin: 0;
padding: 0; padding: 0;
box-sizing: border-box; box-sizing: border-box;
color: map_get($vars, $normal-text-color); transition: background-color map_get($vars, $transition-time),
transition: background-color map_get($vars, $long-transition-time), color map_get($vars, $transition-time);
color map_get($vars, $long-transition-time);
hyphens: auto; hyphens: auto;
:focus { touch-action: manipulation;
/* border: 2px solid map_get($vars, $accent-color);
outline: 0;
border-radius: map_get($vars, $border-radius);*/
}
} }
img, img,
video { video,
.figure-container {
width: 100%; width: 100%;
height: auto; height: auto;
object-fit: contain; object-fit: contain;
} }
::-moz-selection { .figure-container {
background: map_get($vars, $accent-color); font-size: 0;
color: map_get($vars, $inverse-text-color); box-shadow: map_get($vars, $inset-shadow);
} pointer-events: none;
::selection { cursor: pointer;
background: map_get($vars, $accent-color);
color: map_get($vars, $inverse-text-color);
}
.main { * {
height: 100vh; pointer-events: all;
overflow-y: scroll; position: relative;
overflow-x: hidden; z-index: -2;
will-change: transform;
-webkit-overflow-scrolling: touch;
perspective: 5px;
perspective-origin: center center;
noscript {
@include square(100%);
@include center-children();
} }
}
@include on-large-screen { .primitive-text,
&::-webkit-scrollbar-track, .primitive-anchor,
&::-webkit-scrollbar { .figure-container {
background-color: transparent; margin-top: map_get($vars, $line-height);
width: 12px; }
.primitive-text {
text-align: left;
}
body {
height: 100%;
overflow: hidden;
//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);
.main {
height: 100vh; // to take mobile nav-bar into account
overflow-y: scroll;
overflow-x: hidden;
will-change: transform;
perspective: 5px;
perspective-origin: center center;
noscript {
@include square(100%);
@include center-children();
} }
&::-webkit-scrollbar-thumb {
background-color: map_get($vars, $accent-color); @include on-large-screen {
border-radius: map_get($vars, $border-radius); &::-webkit-scrollbar-track,
&::-webkit-scrollbar {
background-color: transparent;
width: 12px;
}
&::-webkit-scrollbar-thumb {
background-color: map_get($vars, $accent-color);
border-radius: map_get($vars, $border-radius);
}
} }
} }
} }

View file

@ -16,10 +16,15 @@ module.exports = {
}, },
devServer: { devServer: {
host: '0.0.0.0', host: '0.0.0.0',
// disableHostCheck: true, disableHostCheck: true,
}, },
optimization: { optimization: {
minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})], minimizer: [
new TerserJSPlugin({
sourceMap: !isProduction,
}),
new OptimizeCSSAssetsPlugin({}),
],
}, },
plugins: [ plugins: [
new CleanWebpackPlugin(), new CleanWebpackPlugin(),