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

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,14 +1,15 @@
import { mixColors } from '../../framework/helper/mix-colors';
import { createElement } from '../../framework/helper/create-element';
import { Random } from '../../framework/helper/random';
import { generate } from './background.html';
import { generate } from './blob.html';
export class Blob {
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 darkColors = ['#2C477A'];
private static colorPickerRandom = new Random(132);
private static isDarkThemed = false;
private static zMin: number;
private static zMax: number;
private static perspective: number;

View file

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

View file

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

View file

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

View file

@ -1,21 +1,20 @@
@import '../../style/mixins';
@import '../../style/vars';
@use '../../style/include' as *;
@include responsive() using ($vars) {
footer#page-footer {
text-align: center;
margin: map_get($vars, $large-margin) auto 0 auto;
margin-top: map_get($vars, $large-margin);
width: 100%;
h2 {
@include title-font();
@include title-font($vars);
}
ul {
margin-top: map_get($vars, $normal-margin);
list-style: none;
display: inline-block;
margin-top: map_get($vars, $normal-margin);
text-align: left;
li {
@ -29,10 +28,11 @@
img,
svg {
@include max-square(map_get($vars, $icon-size));
margin-right: map_get($vars, $small-margin);
* {
fill: map_get($vars, $normal-text-color);
}
margin-right: map_get($vars, $small-margin);
}
a {
@ -44,13 +44,17 @@
aside.other {
@include center-children();
flex-direction: column;
margin: map_get($vars, $large-margin) auto map_get($vars, $line-height)
auto;
margin: map_get($vars, $large-margin) auto 0 auto;
padding-bottom: map_get($vars, $line-height);
width: map_get($vars, $body-width);
h6 {
@include special-text-font($vars);
display: inline;
&,
* {
@include special-text-font($vars);
color: map_get($vars, $normal-text-color);
}
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 './image-viewer.scss';
@ -6,6 +6,6 @@ import './image-viewer.scss';
export const generate = (): html => `
<section id="image-viewer">
<div id="container"></div>
<img id="cancel" src="${cancel}" alt="cancel"/>
<img tabindex="0" id="cancel" src="${cancel}" alt="cancel"/>
</section>
`;

View file

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

View file

@ -1,7 +1,7 @@
import { PageElement } from '../../framework/page-element';
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';
export class PageImageViewer extends PageElement {
@ -11,24 +11,19 @@ export class PageImageViewer extends PageElement {
}
protected handleEvent(event: PageEvent, parent: PageElement) {
if (event.type !== PageEventType.onLoad) {
return;
}
if (event.type === PageEventType.onLoad) {
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, video')
);
media
.filter(
(e: HTMLElement) =>
e.parentElement !== this.element && !e.classList.contains('no-open')
)
.forEach(
(e: HTMLImageElement) => (e.onclick = this.handleClick.bind(this))
const media = Array.prototype.slice.call(
parent.element.querySelectorAll('img')
);
media
.filter((e: HTMLElement) => e.parentElement !== this.element)
.forEach(
(e: HTMLImageElement) => (e.onclick = this.handleClick.bind(this))
);
}
}
private handleClick(event: Event) {

View file

@ -19,4 +19,20 @@ export const create = ({ header, timeline, footer }: Portfolio) => {
new PageBackground(pageHeader, pageFooter),
]),
]).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';
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';
@import '../../style/vars';
@use '../../style/include' as *;
@include responsive using($vars) {
input[type='checkbox']#theme-switcher {
@ -14,11 +13,12 @@
margin-top: map_get($vars, $normal-margin);
}
&::-ms-check {
display: none;
}
background-color: map_get($vars, $accent-color);
z-index: 10;
cursor: pointer;
-webkit-appearance: none;
-moz-appearance: none;
@ -33,10 +33,12 @@
inset 0 0 1px rgba(0, 0, 0, 0.4);
&:before {
// moon + sun
@include square($icon-size);
}
&:after {
// sun blocking moon
@include square($icon-size * 0.8);
}
@ -50,8 +52,8 @@
top: 50%;
transform: translateY(-50%);
transition: transform map_get($vars, $long-transition-time),
background-color map_get($vars, $long-transition-time);
transition: transform map_get($vars, $transition-time),
background-color map_get($vars, $transition-time);
}
&:not(:checked) {
@ -59,16 +61,16 @@
transform: translateY(-50%) translateX(3 * $margin + $icon-size);
animation: shine 3s linear alternate infinite;
background-color: map_get($vars, $theme-switcher-foreground);
background-color: map_get($vars, $sun-color);
@keyframes shine {
from {
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 {
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);
}
}
&:focus {
outline: 0;
}
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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