1
0
Fork 0
This commit is contained in:
Moritz Ruth 2020-04-07 15:52:52 +02:00
parent 82447b6a92
commit e55d5feced
No known key found for this signature in database
GPG key ID: FE38A0B03AA331BA
28 changed files with 2006 additions and 1543 deletions

View file

@ -1,15 +0,0 @@
body {
font-family: "Alata", sans-serif;
}
.page-enter-active, .page-leave-active {
transition: 500ms ease opacity;
}
.page-enter, .page-leave-to {
opacity: 0;
}
.page-enter-to, .page-leave {
opacity: 1;
}

10
assets/js/footerItems.js Normal file
View file

@ -0,0 +1,10 @@
export const footerItems = [
{
label: "Legal Notice",
to: "/legal-notice"
},
{
label: "Privacy Policy",
to: "/privacy-policy"
}
];

View file

@ -0,0 +1,7 @@
import _kebabCase from "lodash.kebabcase";
export function toModifierClasses(base, classes) {
return Object.entries(classes)
.filter(([, value]) => Boolean(value))
.map(([key]) => `${base}--${_kebabCase(key)}`);
}

View file

@ -0,0 +1,6 @@
$background: black;
$background-c: white;
$pink: #BB2081;
$pink-c: white;
$blue: #14AAD8;
$blue-c: white;

View file

@ -0,0 +1,8 @@
@mixin content($padding: 20px) {
$width: 800px;
max-width: calc(100vw - #{$padding} * 2);
width: $width;
padding: 0 $padding;
margin: 0 auto;
}

View file

@ -0,0 +1,11 @@
@mixin mobile() {
@media (max-width: 800px) {
@content;
}
}
@mixin notMobile() {
@media (min-width: 801px) {
@content;
}
}

View file

@ -0,0 +1 @@
$navigation-bar: 5;

View file

@ -0,0 +1,48 @@
@use "../screenSize";
%heading--1, %heading--2, %heading--3, %heading--4, %heading--5, %heading--6 {
margin-top: 1rem;
margin-bottom: 1rem;
font-weight: bold;
display: block;
}
%heading--1 {
font-size: 3.8rem;
@include screenSize.mobile {
font-size: 2.7rem;
}
}
%heading--2 {
font-size: 3rem;
@include screenSize.mobile {
font-size: 2.5rem;
}
}
%heading--3 {
font-size: 2.6rem;
@include screenSize.mobile {
font-size: 2.2rem;
}
}
%heading--4 {
font-size: 2.2rem;
@include screenSize.mobile {
font-size: 2rem;
}
}
%heading--5 {
font-size: 1.8rem;
}
%heading--6 {
font-size: 1.4rem;
}

View file

@ -0,0 +1,11 @@
%link {
color: var(--colors-link);
text-decoration: none;
transition: 100ms linear opacity;
opacity: 1;
&:hover {
opacity: 0.8;
}
}

View file

@ -0,0 +1,7 @@
%paragraph {
margin: 20px 0;
li {
margin-left: 20px;
}
}

View file

@ -0,0 +1,22 @@
@use "link";
@use "heading";
@use "paragraph";
$_elements: (
"paragraph": ("p", "ul"),
"link": "a",
"heading--1": "h1",
"heading--2": "h2",
"heading--3": "h3",
"heading--4": "h4",
"heading--5": "h5",
"heading--6": "h6",
);
@each $class, $tags in $_elements {
@each $tag in $tags {
#{$tag}.formatted, .formatted #{$tag}, .#{$class} {
@extend %#{$class};
}
}
}

67
assets/styles/global.scss Normal file
View file

@ -0,0 +1,67 @@
@use "./colors";
@use "./content";
@use "./formatted";
// General
html, body {
font-family: "Alata", sans-serif;
font-size: 16px;
padding: 0;
margin: 0;
width: 100vw;
overflow-x: hidden;
min-height: 100vh;
background: colors.$background;
color: colors.$background-c;
}
// Transitions
.page-enter-active, .page-leave-active {
transition: 500ms ease opacity;
}
.page-enter, .page-leave-to {
opacity: 0;
}
.page-enter-to, .page-leave {
opacity: 1;
}
// Other
.content {
@include content.content();
}
.link {
position: relative;
text-decoration: none;
color: colors.$background-c;
&:hover, &:focus {
outline: none;
&::after {
background-position: 0 0;
}
}
&::after {
content: "";
position: absolute;
height: 2px;
top: 102%;
left: 0;
right: 0;
background: linear-gradient(90deg, colors.$pink 0%, colors.$blue 100%) 100% 0;
background-size: 260% 100%;
transition: 500ms ease background-position;
}
}

View file

@ -1,10 +1,30 @@
<template> <template>
<div class="animated-logo"> <div class="animated-logo">
<svg class="animated-logo__svg" xmlns="http://www.w3.org/2000/svg" viewBox="76.75 182.661 358.5 146.679"> <svg class="animated-logo__svg" xmlns="http://www.w3.org/2000/svg" viewBox="76.75 182.661 358.5 146.679">
<path class="animated-logo__m1" d=" M 121.75 182.749 L 166.75 329.339 L 76.75 329.339 L 121.75 182.749 Z " fill-rule="evenodd" fill="currentColor"/> <path
<path class="animated-logo__m2" d=" M 206.75 182.749 L 251.75 329.339 L 161.75 329.339 L 206.75 182.749 Z " fill-rule="evenodd" fill="currentColor"/> class="animated-logo__m1"
<path class="animated-logo__r1" d=" M 327.25 182.705 L 372.25 329.295 L 282.25 329.295 L 327.25 182.705 Z " fill-rule="evenodd" fill="currentColor"/> d=" M 121.75 182.749 L 166.75 329.339 L 76.75 329.339 L 121.75 182.749 Z "
<path class="animated-logo__r2" d=" M 390.537 329.339 L 345.25 182.837 L 435.25 182.661 L 390.537 329.339 Z " fill-rule="evenodd" fill="currentColor"/> fill-rule="evenodd"
fill="currentColor"
/>
<path
class="animated-logo__m2"
d=" M 206.75 182.749 L 251.75 329.339 L 161.75 329.339 L 206.75 182.749 Z "
fill-rule="evenodd"
fill="currentColor"
/>
<path
class="animated-logo__r1"
d=" M 327.25 182.705 L 372.25 329.295 L 282.25 329.295 L 327.25 182.705 Z "
fill-rule="evenodd"
fill="currentColor"
/>
<path
class="animated-logo__r2"
d=" M 390.537 329.339 L 345.25 182.837 L 435.25 182.661 L 390.537 329.339 Z "
fill-rule="evenodd"
fill="currentColor"
/>
</svg> </svg>
<div class="animated-logo__name"> <div class="animated-logo__name">
Moritz Ruth Moritz Ruth
@ -21,7 +41,7 @@
$slide-length: 37.5%; $slide-length: 37.5%;
.animated-logo { .animated-logo {
width: 250px; width: 300px;
max-width: 60vw; max-width: 60vw;
animation: scaleUp $scale-up-duration ease-out both; animation: scaleUp $scale-up-duration ease-out both;
@ -34,7 +54,7 @@
} }
.animated-logo__name { .animated-logo__name {
font-size: 2rem; font-size: 2.3rem;
animation: fadeIn $slide-duration $scale-up-duration ease both; animation: fadeIn $slide-duration $scale-up-duration ease both;
text-align: center; text-align: center;
} }

View file

@ -0,0 +1,74 @@
<template>
<a
class="external-link link"
rel="noopener"
target="_blank"
:href="href"
>
<template v-if="this.$slots.default && this.$slots.default[0] && this.$slots.default[0].text">
<slot/>
</template>
<template v-else>
{{ label }}
</template>
<ExternalIcon class="external-link__icon"/>
</a>
</template>
<style scoped lang="scss">
.external-link {
padding-right: 2px;
overflow-wrap: break-word;
}
.external-link__icon {
margin-left: 3px;
width: 15px;
position: relative;
top: 2px;
}
</style>
<script>
import ExternalIcon from "@/assets/icons/external.svg";
export default {
name: "ExternalLink",
components: { ExternalIcon },
props: {
href: {
type: String,
required: true
},
showProtocol: {
type: Boolean,
default: false
},
showQuery: {
type: Boolean,
default: false
}
},
computed: {
label() {
// eslint-disable-next-line import/no-extraneous-dependencies
const url = new (process.server ? require("url").URL : window.URL)(this.href);
let label = "";
if (this.showProtocol) {
label += url.protocol;
label += "//";
}
label += url.host + url.pathname;
if (this.showQuery) {
label += url.search;
}
return label;
}
}
};
</script>

47
components/MyFooter.vue Normal file
View file

@ -0,0 +1,47 @@
<template>
<footer class="my-footer">
<nuxt-link
v-for="item in $options.items"
class="my-footer__link link"
:key="item.label"
:to="item.to"
@click.native.passive="open = false"
>
{{ item.label }}
</nuxt-link>
</footer>
</template>
<style lang="scss">
@use "~@/assets/styles/screenSize";
@use "~@/assets/styles/colors";
.my-footer {
display: flex;
justify-content: center;
align-items: center;
width: 100vw;
height: 100px;
}
.my-footer__link:not(:last-child) {
margin-right: 20px;
}
@include screenSize.mobile {
.my-footer__link:not(:last-child) {
margin-right: 0;
margin-bottom: 20px;
}
}
</style>
<script>
import { footerItems } from "@/assets/js/footerItems";
export default {
name: "MyFooter",
items: footerItems
};
</script>

View file

@ -0,0 +1,323 @@
<template>
<div class="navigation-bar" :class="classes">
<div class="navigation-bar__placeholder"></div>
<nav class="navigation-bar__content">
<div class="navigation-bar__title-container">
<span
class="navigation-bar__title"
:class="{ 'navigation-bar__title--show': showTitle }"
>
{{ title }}
</span>
</div>
<div class="navigation-bar__toggle" @click="open = !open">
<span></span>
<span></span>
<span></span>
</div>
<div class="navigation-bar__links">
<div
v-for="item in $options.items"
class="navigation-bar__link-container"
:key="item.label"
>
<nuxt-link
v-if="item.to"
class="navigation-bar__link"
:to="item.to"
@click.native.passive="open = false"
>
{{ item.label }}
</nuxt-link>
<a
v-else
class="navigation-bar__link"
:key="item.label"
rel="noopener"
:href="item.href"
@click.passive="open = false"
>
{{ item.label }}
</a>
</div>
</div>
</nav>
</div>
</template>
<style lang="scss">
@use "~@/assets/styles/screenSize";
@use "~@/assets/styles/colors";
@use "~@/assets/styles/content";
@use "~@/assets/styles/z-indexes";
body {
--navigation-bar-height: 80px;
}
.navigation-bar__placeholder {
height: var(--navigation-bar-height);
}
.navigation-bar__content {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: z-indexes.$navigation-bar;
height: var(--navigation-bar-height);
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 30px;
.navigation-bar--show-background & {
background: colors.$background;
}
}
.navigation-bar__toggle {
position: relative;
z-index: 1;
& > span {
display: block;
background-color: colors.$background-c;
width: 30px;
height: 2px;
transition: 200ms linear;
transition-property: opacity, transform;
&:nth-child(2) {
margin-top: 8px;
}
&:nth-child(3) {
margin-top: 8px;
}
}
}
.navigation-bar__title-container {
height: 100%;
overflow: hidden;
display: flex;
align-items: center;
}
.navigation-bar__title {
font-size: 1.4rem;
display: block;
opacity: 0;
transform: translateY(10px);
transition: 200ms ease;
transition-property: opacity, transform;
&.navigation-bar__title--show {
opacity: 1;
transform: translateY(0);
}
}
.navigation-bar__links {
position: fixed;
top: 0;
left: 0;
z-index: 0;
width: 100vw;
height: 100vh;
background: colors.$background;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
opacity: 0;
pointer-events: none;
transition: 200ms ease opacity;
border: none;
}
.navigation-bar__link-container {
position: relative;
background: white;
&:not(:last-child) {
margin-bottom: 10px;
}
&::before {
content: "";
display: block;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
background: linear-gradient(135deg, colors.$blue 25%, colors.$pink, colors.$blue 75%);
background-size: 400% 400%;
animation: 1s infinite linear reverse navigation-bar__gradient;
pointer-events: none;
mix-blend-mode: multiply;
opacity: 0;
transition: 200ms opacity ease;
}
&:hover, &:focus-within {
&::before {
opacity: 1;
}
.navigation-bar__link {
outline: none;
transform: translate(-5px, -5px);
}
}
}
.navigation-bar__link {
display: block;
color: colors.$background-c;
text-decoration: none;
font-size: 1.4rem;
background: black;
padding: 10px;
transition: 200ms transform ease;
}
@keyframes navigation-bar__gradient {
from {
background-position: 0 0;
}
to {
background-position: 100% 100%;
}
}
.navigation-bar--open {
.navigation-bar__toggle > span {
&:nth-child(1) {
transform: translateY(10px) rotate(45deg);
}
&:nth-child(2) {
opacity: 0;
}
&:nth-child(3) {
transform: translateY(-10px) rotate(-45deg);
}
}
.navigation-bar__links {
opacity: 1;
pointer-events: auto;
}
}
@include screenSize.notMobile {
body {
--navigation-bar-height: 100px;
}
.navigation-bar__content {
@include content.content(40px);
}
.navigation-bar__title {
font-size: 2.5rem;
}
.navigation-bar__toggle {
display: none;
}
.navigation-bar__links {
position: static;
width: auto;
height: auto;
opacity: 1;
pointer-events: auto;
flex-direction: row;
}
.navigation-bar__link-container:not(:last-child) {
margin-bottom: 0;
margin-right: 40px;
}
}
</style>
<script>
import { toModifierClasses } from "@/assets/js/toModifierClasses";
const ITEMS = [
{
label: "Start",
to: "/"
},
{
label: "Projects",
to: "/projects"
}
];
export default {
name: "NavigationBar",
props: {
backgroundAfterScroll: {
type: Boolean,
default: false
},
title: {
type: String,
default: ""
}
},
data: () => ({
open: false,
scrollPosition: 0
}),
computed: {
showTitle: vm => vm.scrollPosition > 60,
showBackground: vm => vm.backgroundAfterScroll ? vm.scrollPosition > 0 : true,
classes() {
const { open, showBackground } = this;
return toModifierClasses("navigation-bar", {
open,
showBackground
});
}
},
mounted() {
const scrollListener = () => {
this.scrollPosition = window.scrollY;
};
window.addEventListener("scroll", scrollListener, { passive: true });
this.$on("hook:beforeDestroy", () => {
window.removeEventListener("scroll", scrollListener);
});
scrollListener();
},
items: ITEMS
};
</script>

View file

@ -1,96 +0,0 @@
<template>
<div class="project">
<h2 class="heading--3">
{{ title }}
</h2>
<span class="project__type">{{ type }}</span>
<div class="project__description">
<slot/>
</div>
<hr class="project__divider"/>
<div class="project__buttons">
<KButton v-if="link" :href="link">
Open
<template v-slot:suffix>
<ArrowRightIcon/>
</template>
</KButton>
<KButton v-if="github" :href="`https://github.com/${github}`">
GitHub
<template v-slot:prefix>
<GitHubIcon/>
</template>
</KButton>
<KButton v-if="npm" :href="`https://www.npmjs.com/package/${npm}`">
NPM
<template v-slot:prefix>
<NPMIcon style="width: 30px; top: 4px"/>
</template>
</KButton>
</div>
</div>
</template>
<style scoped lang="scss">
.project__type {
margin-top: -1rem;
margin-bottom: 1rem;
display: block;
}
.project__description {
font-size: 1.2rem;
}
.project__divider {
margin-top: 20px;
margin-bottom: 10px;
width: 175px;
height: 1px;
background-color: black;
border: none;
}
.project__buttons {
display: flex;
& > *:not(:last-child) {
margin-right: 5px;
}
}
</style>
<script>
import KButton from "kiste/components/KButton.vue";
import ArrowRightIcon from "@/assets/icons/arrow_right.svg";
import GitHubIcon from "@/assets/icons/github.svg";
import NPMIcon from "@/assets/icons/npm.svg";
export default {
name: "GProject",
components: { KButton, ArrowRightIcon, GitHubIcon, NPMIcon },
props: {
title: {
type: String,
required: true
},
type: {
type: String,
required: true
},
link: {
type: String,
default: null
},
github: {
type: String,
default: null
},
npm: {
type: String,
default: null
}
}
};
</script>

View file

@ -1,22 +1,23 @@
<template> <template>
<div class="default-layout fill-screen"> <div class="default-layout">
<KApp>
<nuxt/> <nuxt/>
<KFooter/> <MyFooter/>
</KApp>
</div> </div>
</template> </template>
<style scoped lang="scss"> <style scoped lang="scss">
.default-layout {
min-height: 100vh;
width: 100vw;
overflow-x: hidden;
}
</style> </style>
<script> <script>
import KApp from "kiste/components/KApp.vue"; import MyFooter from "@/components/MyFooter";
import KFooter from "kiste/components/KFooter.vue";
export default { export default {
name: "DefaultLayout", name: "DefaultLayout",
components: { KApp, KFooter } components: { MyFooter }
}; };
</script> </script>

13
layouts/empty.vue Normal file
View file

@ -0,0 +1,13 @@
<template>
<nuxt/>
</template>
<style>
</style>
<script>
export default {
name: "EmptyLayout"
};
</script>

View file

@ -1,18 +0,0 @@
<template>
<KApp>
<nuxt/>
</KApp>
</template>
<style>
</style>
<script>
import KApp from "kiste/components/KApp.vue";
export default {
name: "WithoutFooterLayout",
components: { KApp }
};
</script>

View file

@ -18,7 +18,7 @@ export default {
/* /*
** Global CSS ** Global CSS
*/ */
css: ["@/assets/global.scss"], css: ["@/assets/styles/global.scss"],
layoutTransition: "page", layoutTransition: "page",
/* /*
@ -30,8 +30,7 @@ export default {
*/ */
buildModules: [ buildModules: [
// Doc: https://github.com/nuxt-community/eslint-module // Doc: https://github.com/nuxt-community/eslint-module
"@nuxtjs/eslint-module", "@nuxtjs/eslint-module"
"kiste/nuxt"
], ],
/* /*
** Nuxt.js modules ** Nuxt.js modules
@ -41,32 +40,6 @@ export default {
"@nuxtjs/pwa" "@nuxtjs/pwa"
], ],
kiste: {
theme: {
contentPadding: "10px"
},
navigationItems: [
{
label: "Home",
to: "/"
},
{
label: "Projects",
to: "/projects"
}
],
footerItems: [
{
label: "Legal Notice",
to: "/legal-notice"
},
{
label: "Privacy Policy",
to: "/privacy-policy"
}
]
},
// https://pwa.nuxtjs.org/modules/workbox.html // https://pwa.nuxtjs.org/modules/workbox.html
workbox: { workboxExtensions: ["@/assets/js/font-sw.js"] }, workbox: { workboxExtensions: ["@/assets/js/font-sw.js"] },
@ -77,17 +50,17 @@ export default {
mobileApp: false, mobileApp: false,
name: "Moritz Ruth", name: "Moritz Ruth",
author: "Moritz Ruth", author: "Moritz Ruth",
description: "The official website of Moritz Ruth", description: "Moritz Ruth is a web developer, photograph and digital creator.",
lang: "en", lang: "en",
themeColor: "#ffffff" themeColor: "#000000"
}, },
// https://developer.mozilla.org/en-US/docs/Web/Manifest // https://developer.mozilla.org/en-US/docs/Web/Manifest
manifest: { manifest: {
name: "Moritz Ruth", name: "Moritz Ruth",
short_name: "Moritz Ruth", short_name: "Moritz Ruth",
background_color: "#ffffff", background_color: "#000000",
display: "browser", display: "browser",
description: "The official website of Moritz Ruth" description: "Moritz Ruth is a web developer, photograph and digital creator."
} }
}, },

View file

@ -5,30 +5,30 @@
"author": "Moritz Ruth", "author": "Moritz Ruth",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "nuxt", "dev": "HOST=0.0.0.0 nuxt",
"generate": "nuxt generate", "generate": "nuxt generate",
"start": "serve dist", "start": "serve dist",
"lint": "eslint --ext .js,.vue --ignore-path .gitignore ." "lint": "eslint --ext .js,.vue --ignore-path .gitignore ."
}, },
"dependencies": { "dependencies": {
"@nuxtjs/pwa": "^3.0.0-beta.19", "@nuxtjs/pwa": "^3.0.0-beta.20",
"kiste": "^1.2.7", "lodash.kebabcase": "^4.1.1",
"nuxt": "^2.11.0", "nuxt": "^2.12.2",
"shaped.js": "^1.0.3",
"vue": "^2.6.11", "vue": "^2.6.11",
"vue-ripple-directive": "^2.0.1" "vue-ripple-directive": "^2.0.1"
}, },
"devDependencies": { "devDependencies": {
"@moritzruth/eslint-config": "^1.0.6", "@moritzruth/eslint-config": "^1.0.9",
"@nuxtjs/eslint-module": "^1.1.0", "@nuxtjs/eslint-module": "^1.1.0",
"babel-eslint": "^10.0.3", "babel-eslint": "^10.1.0",
"eslint": "^6.8.0", "eslint": "^6.8.0",
"eslint-import-resolver-webpack": "^0.12.1", "eslint-import-resolver-webpack": "^0.12.1",
"eslint-plugin-nuxt": "^0.5.0", "eslint-plugin-nuxt": "^0.5.2",
"fibers": "^4.0.2", "fibers": "^4.0.2",
"sass": "^1.24.4", "sass": "^1.26.3",
"sass-loader": "^8.0.1", "sass-loader": "^8.0.2",
"serve": "^11.3.0", "serve": "^11.3.0",
"shaped.js": "^1.0.2",
"svg-to-vue-component": "^0.3.8" "svg-to-vue-component": "^0.3.8"
} }
} }

View file

@ -1,173 +1,109 @@
<template> <template>
<div class="index-page"> <div class="index-page">
<KNavigationBar background-after-scroll/> <NavigationBar background-after-scroll title="Start"/>
<AnimatedLogo/>
<canvas class="index-page__background" ref="canvas"/> <canvas class="index-page__background" ref="canvas"/>
<main class="index-page__content"> <div class="index-page__content">
<div class="index-page__socials"> <AnimatedLogo/>
<a class="index-page__social-link" href="https://github.com/moritzruth" title="GitHub">
<GitHubIcon class="index-page__social-icon"/>
</a>
<a class="index-page__social-link" href="https://twitter.com/moritzruth_dev" title="Twitter">
<TwitterIcon class="index-page__social-icon"/>
</a>
<a class="index-page__social-link" href="https://instagram.com/moritzruth_dev" title="Instagram">
<InstagramIcon class="index-page__social-icon"/>
</a>
<a class="index-page__social-link" href="mailto:dev@moritz-ruth.de" title="Email">
<EmailIcon class="index-page__social-icon"/>
</a>
</div> </div>
</main> <footer class="index-page__footer">
<KFooter class="index-page__footer"/> <nuxt-link
v-for="item in $options.footerItems"
class="index-page__footer-link"
:key="item.label"
:to="item.to"
@click.native.passive="open = false"
>
{{ item.label }}
</nuxt-link>
</footer>
</div> </div>
</template> </template>
<style scoped lang="scss"> <style lang="scss">
@use "~kiste/css/mixins/screenSize"; @use "~@/assets/styles/screenSize";
@use "~@/assets/styles/colors";
.index-page { .index-page {
display: flex; background: black;
justify-content: center; width: 100vw;
align-items: center;
flex-direction: column;
height: calc(100vh - var(--x-navbar-height));
} }
.index-page__background { .index-page__background {
position: fixed; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
right: 0; right: 0;
bottom: 0; bottom: 0;
width: 100vw;
height: 100vh;
z-index: -1;
animation: appear 2s 1.2s linear both;
} }
@keyframes appear { .index-page__content {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.index-page__socials {
position: absolute;
bottom: 20px;
left: 0;
right: 0;
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
}
.index-page__social-link { height: calc(100vh - var(--navigation-bar-height));
color: black;
&:not(:last-child) {
margin-right: 15px;
}
}
.index-page__social-icon {
width: 40px;
transition: 200ms linear opacity;
&:hover {
opacity: 0.8;
}
} }
.index-page__footer { .index-page__footer {
position: absolute; position: fixed;
padding: 20px 0;
margin-bottom: 10px;
@include screenSize.notMobile {
top: unset;
bottom: 0; bottom: 0;
left: 0;
right: 0; right: 0;
width: fit-content;
padding: 20px; padding: 20px;
margin: 0;
flex-direction: row; opacity: 0.5;
transition: 200ms linear opacity;
&:hover {
opacity: 1;
} }
.index-page__footer-link {
text-decoration: none;
color: colors.$background-c;
&:not(:last-child) {
margin-right: 20px;
}
}
}
@include screenSize.mobile {
} }
</style> </style>
<script> <script>
import KNavigationBar from "kiste/components/KNavigationBar.vue";
import KFooter from "kiste/components/KFooter.vue";
import { Canvas } from "shaped.js"; import { Canvas } from "shaped.js";
import AnimatedLogo from "@/components/AnimatedLogo.vue"; import AnimatedLogo from "@/components/AnimatedLogo";
import GitHubIcon from "@/assets/icons/github.svg"; import NavigationBar from "@/components/NavigationBar";
import TwitterIcon from "@/assets/icons/twitter.svg"; import { footerItems } from "@/assets/js/footerItems";
import InstagramIcon from "@/assets/icons/instagram.svg";
import EmailIcon from "@/assets/icons/email.svg";
const COLORS = [ const COLORS = [
"rgba(0, 0, 0, 0.8)", "#BB2081",
"rgba(0, 255, 150, 0.8)", "#14AAD8",
"rgba(0, 255, 150, 0.2)", "#ffffff"
"rgba(0, 150, 255, 0.8)",
"rgba(0, 150, 255, 0.2)"
]; ];
const LINES = [ const LINES = [
{ {
minCount: 8, minCount: 8,
probability: 1 / 10000, probability: 1 / 20000,
height: 2, height: 1,
length: 100, length: 100,
speed: [-0.2, 0.2], speed: [-0.1, 0.4],
colors: COLORS colors: COLORS
}, },
{ {
minCount: 8, probability: 1 / 10000,
probability: 1 / 50000,
height: 5, height: 5,
length: [20, 200], length: 5,
speed: [0.2, 0.3], speed: [-0.4, 0.4],
colors: COLORS,
randomizeYAfterLeave: true
},
{
probability: 1 / 50000,
height: 50,
length: 50,
speed: [0.2, 0.5],
colors: COLORS colors: COLORS
}, },
{ {
probability: 1 / 5000, probability: 1 / 10000,
height: 3,
length: 3,
speed: [-1, 1],
colors: COLORS
},
{
minCount: 8,
probability: 1 / 50000,
height: [20, 200],
length: [20, 200],
speed: [0.2, 0.3],
colors: COLORS,
randomizeYAfterLeave: true
},
{
probability: 1 / 5000,
height: [20, 200], height: [20, 200],
length: 2, length: 2,
speed: [-0.2, 0.2], speed: [-0.2, 0.2],
@ -177,31 +113,32 @@
export default { export default {
name: "IndexPage", name: "IndexPage",
layout: "none", layout: "empty",
components: { AnimatedLogo, GitHubIcon, TwitterIcon, InstagramIcon, EmailIcon, KNavigationBar, KFooter }, components: { NavigationBar, AnimatedLogo },
mounted() { mounted() {
let nextConfig = 0; let configIndex = 0;
if (localStorage !== undefined) { if (localStorage !== undefined) {
const rawValue = localStorage.getItem("nextBackground"); const rawValue = localStorage.getItem("nextBackground");
if (rawValue) { if (rawValue) {
try { try {
nextConfig = JSON.parse(rawValue); configIndex = JSON.parse(rawValue);
// eslint-disable-next-line no-empty } catch {
} catch {} // ignored
}
} }
} }
if (nextConfig > LINES.length - 1) { if (configIndex > LINES.length - 1) {
nextConfig = 0; configIndex = 0;
} }
if (localStorage !== undefined) { if (localStorage !== undefined) {
localStorage.setItem("nextBackground", nextConfig + 1); localStorage.setItem("nextBackground", JSON.stringify(configIndex + 1));
} }
const config = LINES[nextConfig]; const config = LINES[configIndex];
const backgroundCanvas = new Canvas(this.$refs.canvas, { const backgroundCanvas = new Canvas(this.$refs.canvas, {
lines: config, lines: config,
fillWindowSize: true fillWindowSize: true
@ -210,6 +147,7 @@
this.$once("hook:beforeDestroy", () => { this.$once("hook:beforeDestroy", () => {
backgroundCanvas.destroy(); backgroundCanvas.destroy();
}); });
} },
footerItems
}; };
</script> </script>

View file

@ -1,6 +1,5 @@
<template> <template>
<div class="legal-notice-page"> <div class="legal-notice-page">
<KNavigationBar title="Legal Notice"/>
<div class="content"> <div class="content">
<h1 class="heading--1"> <h1 class="heading--1">
Legal Notice Legal Notice
@ -59,7 +58,6 @@
class="link" class="link"
href="https://datenschutz-generator.de/?l=de" href="https://datenschutz-generator.de/?l=de"
rel="noopener" rel="noopener"
title="Rechtstext von Dr. Schwenke - für weitere Informationen bitte anklicken."
target="_blank" target="_blank"
>Erstellt mit kostenlosem Datenschutz-Generator.de von Dr. Thomas Schwenke</a> >Erstellt mit kostenlosem Datenschutz-Generator.de von Dr. Thomas Schwenke</a>
</div> </div>
@ -67,11 +65,8 @@
</template> </template>
<script> <script>
import KNavigationBar from "kiste/components/KNavigationBar.vue";
export default { export default {
name: "LegalNoticePage", name: "LegalNoticePage",
components: { KNavigationBar }, head: () => ({ htmlAttrs: { lang: "de" } })
head: { htmlAttrs: { lang: "de" } }
}; };
</script> </script>

View file

@ -1,26 +1,26 @@
<template> <template>
<div class="privacy-policy-page"> <div class="privacy-policy-page">
<KNavigationBar title="Datenschutzerklärung"/> <NavigationBar title="Datenschutz"/>
<div class="content"> <div class="content formatted">
<h1 class="heading--1"> <h1>
Datenschutzerklärung Datenschutzerklärung
</h1> </h1>
<p class="paragraph"> <p>
Verantwortlicher im Sinne der Datenschutzgesetze, insbesondere der EU-Datenschutzgrundverordnung (DSGVO), ist: Verantwortlicher im Sinne der Datenschutzgesetze, insbesondere der EU-Datenschutzgrundverordnung (DSGVO), ist:
</p> </p>
<p class="paragraph"> <p>
Moritz Ruth<br> Moritz Ruth<br>
Zum Galgenberg 19<br> Zum Galgenberg 19<br>
66539 Neunkirchen<br> 66539 Neunkirchen<br>
Deutschland Deutschland
</p> </p>
<h2 class="heading--2"> <h2>
Ihre Betroffenenrechte Ihre Betroffenenrechte
</h2> </h2>
<p class="paragraph"> <p>
Unter den angegebenen Kontaktdaten unseres Datenschutzbeauftragten können Sie jederzeit folgende Rechte ausüben: Unter den angegebenen Kontaktdaten unseres Datenschutzbeauftragten können Sie jederzeit folgende Rechte ausüben:
</p> </p>
<ul class="paragraph"> <ul>
<li>Auskunft über Ihre bei uns gespeicherten Daten und deren Verarbeitung (Art. 15 DSGVO),</li> <li>Auskunft über Ihre bei uns gespeicherten Daten und deren Verarbeitung (Art. 15 DSGVO),</li>
<li>Berichtigung unrichtiger personenbezogener Daten (Art. 16 DSGVO),</li> <li>Berichtigung unrichtiger personenbezogener Daten (Art. 16 DSGVO),</li>
<li>Löschung Ihrer bei uns gespeicherten Daten (Art. 17 DSGVO),</li> <li>Löschung Ihrer bei uns gespeicherten Daten (Art. 17 DSGVO),</li>
@ -34,260 +34,262 @@
abgeschlossen haben (Art. 20 DSGVO). abgeschlossen haben (Art. 20 DSGVO).
</li> </li>
</ul> </ul>
<p class="paragraph"> <p>
Sofern Sie uns eine Einwilligung erteilt haben, können Sie diese jederzeit mit Wirkung für die Zukunft Sofern Sie uns eine Einwilligung erteilt haben, können Sie diese jederzeit mit Wirkung für die Zukunft
widerrufen. widerrufen.
</p> </p>
<p class="paragraph"> <p>
Sie können sich jederzeit mit einer Beschwerde an eine Aufsichtsbehörde wenden, z. B. an die zuständige Sie können sich jederzeit mit einer Beschwerde an eine Aufsichtsbehörde wenden, z. B. an die zuständige
Aufsichtsbehörde des Bundeslands Ihres Wohnsitzes oder an die für uns als verantwortliche Stelle zuständige Aufsichtsbehörde des Bundeslands Ihres Wohnsitzes oder an die für uns als verantwortliche Stelle zuständige
Behörde. Behörde.
</p> </p>
<p class="paragraph"> <p>
Eine Liste der Aufsichtsbehörden (für den nichtöffentlichen Bereich) mit Anschrift finden Sie unter: Eine Liste der Aufsichtsbehörden (für den nichtöffentlichen Bereich) mit Anschrift finden Sie unter:
<KExternalLink href="https://www.bfdi.bund.de/DE/Infothek/Anschriften_Links/anschriften_links-node.html"/>. <ExternalLink href="https://www.bfdi.bund.de/DE/Infothek/Anschriften_Links/anschriften_links-node.html"/>.
</p> </p>
<h2 class="heading--2"> <h2>
Erfassung allgemeiner Informationen beim Besuch unserer Website Erfassung allgemeiner Informationen beim Besuch unserer Website
</h2> </h2>
<h3 class="heading--3"> <h3>
Art und Zweck der Verarbeitung Art und Zweck der Verarbeitung
</h3> </h3>
<p class="paragraph"> <p>
Wenn Sie auf unsere Website zugreifen, d.h., wenn Sie sich nicht registrieren oder anderweitig Informationen Wenn Sie auf unsere Website zugreifen, d.h., wenn Sie sich nicht registrieren oder anderweitig Informationen
übermitteln, werden automatisch Informationen allgemeiner Natur erfasst. Diese Informationen (Server-Logfiles) übermitteln, werden automatisch Informationen allgemeiner Natur erfasst. Diese Informationen (Server-Logfiles)
beinhalten etwa die Art des Webbrowsers, das verwendete Betriebssystem, den Domainnamen Ihres beinhalten etwa die Art des Webbrowsers, das verwendete Betriebssystem, den Domainnamen Ihres
Internet-Service-Providers, Ihre IP-Adresse und ähnliches. Internet-Service-Providers, Ihre IP-Adresse und ähnliches.
</p> </p>
<p class="paragraph"> <p>
Sie werden insbesondere zu folgenden Zwecken verarbeitet Sie werden insbesondere zu folgenden Zwecken verarbeitet
</p> </p>
<ul class="paragraph"> <ul>
<li>Sicherstellung eines problemlosen Verbindungsaufbaus der Website,</li> <li>Sicherstellung eines problemlosen Verbindungsaufbaus der Website,</li>
<li>Sicherstellung einer reibungslosen Nutzung unserer Website,</li> <li>Sicherstellung einer reibungslosen Nutzung unserer Website,</li>
<li>Auswertung der Systemsicherheit und -stabilität sowie</li> <li>Auswertung der Systemsicherheit und -stabilität sowie</li>
<li>zu weiteren administrativen Zwecken.</li> <li>zu weiteren administrativen Zwecken.</li>
</ul> </ul>
<p class="paragraph"> <p>
Wir verwenden Ihre Daten nicht, um Rückschlüsse auf Ihre Person zu ziehen. Informationen dieser Art werden von Wir verwenden Ihre Daten nicht, um Rückschlüsse auf Ihre Person zu ziehen. Informationen dieser Art werden von
uns ggfs. statistisch ausgewertet, um unseren Internetauftritt und die dahinterstehende Technik zu uns ggfs. statistisch ausgewertet, um unseren Internetauftritt und die dahinterstehende Technik zu
optimieren. optimieren.
</p> </p>
<h3 class="heading--3"> <h3>
Rechtsgrundlage Rechtsgrundlage
</h3> </h3>
<p class="paragraph"> <p>
Die Verarbeitung erfolgt gemäß Art. 6 Abs. 1 lit. f DSGVO auf Basis unseres berechtigten Interesses an der Die Verarbeitung erfolgt gemäß Art. 6 Abs. 1 lit. f DSGVO auf Basis unseres berechtigten Interesses an der
Verbesserung der Stabilität und Funktionalität unserer Website. Verbesserung der Stabilität und Funktionalität unserer Website.
</p> </p>
<h3 class="heading--3"> <h3>
Empfänger Empfänger
</h3> </h3>
<p class="paragraph"> <p>
Empfänger der Daten sind ggf. technische Dienstleister, die für den Betrieb und die Wartung unserer Webseite als Empfänger der Daten sind ggf. technische Dienstleister, die für den Betrieb und die Wartung unserer Webseite als
Auftragsverarbeiter tätig werden. Auftragsverarbeiter tätig werden.
</p> </p>
<h3 class="heading--3"> <h3>
Speicherdauer Speicherdauer
</h3> </h3>
<p class="paragraph"> <p>
Die Daten werden gelöscht, sobald diese für den Zweck der Erhebung nicht mehr erforderlich sind. Dies ist für Die Daten werden gelöscht, sobald diese für den Zweck der Erhebung nicht mehr erforderlich sind. Dies ist für
die Daten, die der Bereitstellung der Webseite dienen, grundsätzlich der Fall, wenn die jeweilige Sitzung die Daten, die der Bereitstellung der Webseite dienen, grundsätzlich der Fall, wenn die jeweilige Sitzung
beendet ist. beendet ist.
</p> </p>
<h3 class="heading--3"> <h3>
Bereitstellung vorgeschrieben oder erforderlich Bereitstellung vorgeschrieben oder erforderlich
</h3> </h3>
<p class="paragraph"> <p>
Die Bereitstellung der vorgenannten personenbezogenen Daten ist weder gesetzlich noch vertraglich Die Bereitstellung der vorgenannten personenbezogenen Daten ist weder gesetzlich noch vertraglich
vorgeschrieben. Ohne die IP-Adresse ist jedoch der Dienst und die Funktionsfähigkeit unserer Website nicht vorgeschrieben. Ohne die IP-Adresse ist jedoch der Dienst und die Funktionsfähigkeit unserer Website nicht
gewährleistet. Zudem können einzelne Dienste und Services nicht verfügbar oder eingeschränkt sein. Aus diesem gewährleistet. Zudem können einzelne Dienste und Services nicht verfügbar oder eingeschränkt sein. Aus diesem
Grund ist ein Widerspruch ausgeschlossen. Grund ist ein Widerspruch ausgeschlossen.
</p> </p>
<h2 class="heading--2"> <h2>
Verwendung von Scriptbibliotheken (Google Webfonts) Verwendung von Scriptbibliotheken (Google Webfonts)
</h2> </h2>
<h3 class="heading--3"> <h3>
Art und Zweck der Verarbeitung Art und Zweck der Verarbeitung
</h3> </h3>
<p class="paragraph"> <p>
Um unsere Inhalte browserübergreifend korrekt und grafisch ansprechend darzustellen, verwenden wir auf dieser Um unsere Inhalte browserübergreifend korrekt und grafisch ansprechend darzustellen, verwenden wir auf dieser
Website Google Web Fonts der Google LLC (1600 Amphitheatre Parkway, Mountain View, CA 94043, USA; nachfolgend Website Google Web Fonts der Google LLC (1600 Amphitheatre Parkway, Mountain View, CA 94043, USA; nachfolgend
Google) zur Darstellung von Schriften. Google) zur Darstellung von Schriften.
</p> </p>
<p class="paragraph"> <p>
Die Datenschutzrichtlinie des Bibliothekbetreibers Google finden Sie hier: Die Datenschutzrichtlinie des Bibliothekbetreibers Google finden Sie hier:
<KExternalLink href="https://www.google.com/policies/privacy/"/> <ExternalLink href="https://www.google.com/policies/privacy/"/>
</p> </p>
<h3 class="heading--3"> <h3>
Rechtsgrundlage Rechtsgrundlage
</h3> </h3>
<p class="paragraph"> <p>
Rechtsgrundlage für die Einbindung von Google Webfonts und dem damit verbundenen Datentransfer zu Google ist Rechtsgrundlage für die Einbindung von Google Webfonts und dem damit verbundenen Datentransfer zu Google ist
Ihre Einwilligung (Art. 6 Abs. 1 lit. a DSGVO). Ihre Einwilligung (Art. 6 Abs. 1 lit. a DSGVO).
</p> </p>
<h3 class="heading--3"> <h3>
Empfänger Empfänger
</h3> </h3>
<p class="paragraph"> <p>
Der Aufruf von Scriptbibliotheken oder Schriftbibliotheken löst automatisch eine Verbindung zum Betreiber der Der Aufruf von Scriptbibliotheken oder Schriftbibliotheken löst automatisch eine Verbindung zum Betreiber der
Bibliothek aus. Dabei ist es theoretisch möglich aktuell allerdings auch unklar ob und ggf. zu welchen Zwecken Bibliothek aus. Dabei ist es theoretisch möglich aktuell allerdings auch unklar ob und ggf. zu welchen Zwecken
dass der Betreiber in diesem Fall Google Daten erhebt. dass der Betreiber in diesem Fall Google Daten erhebt.
</p> </p>
<h3 class="heading--3"> <h3>
Speicherdauer Speicherdauer
</h3> </h3>
<p class="paragraph"> <p>
Wir erheben keine personenbezogenen Daten, durch die Einbindung von Google Webfonts. Wir erheben keine personenbezogenen Daten, durch die Einbindung von Google Webfonts.
</p> </p>
<p class="paragraph"> <p>
Weitere Informationen zu Google Web Fonts finden Sie unter Weitere Informationen zu Google Web Fonts finden Sie unter
<KExternalLink href="https://developers.google.com/fonts/faq"/> und in der Datenschutzerklärung von Google: <ExternalLink href="https://developers.google.com/fonts/faq"/> und in der Datenschutzerklärung von Google:
<KExternalLink href="https://www.google.com/policies/privacy/"/>. <ExternalLink href="https://www.google.com/policies/privacy/"/>.
</p> </p>
<h3 class="heading--3"> <h3>
Drittlandtransfer Drittlandtransfer
</h3> </h3>
<p class="paragraph"> <p>
Google verarbeitet Ihre Daten in den USA und hat sich dem EU_US Privacy Shield unterworfen Google verarbeitet Ihre Daten in den USA und hat sich dem EU_US Privacy Shield unterworfen
<KExternalLink href="https://www.privacyshield.gov/EU-US-Framework"/>. <ExternalLink href="https://www.privacyshield.gov/EU-US-Framework"/>.
</p> </p>
<h3 class="heading--3"> <h3>
Bereitstellung vorgeschrieben oder erforderlich Bereitstellung vorgeschrieben oder erforderlich
</h3> </h3>
<p class="paragraph"> <p>
Die Bereitstellung der personenbezogenen Daten ist weder gesetzlich, noch vertraglich vorgeschrieben. Allerdings Die Bereitstellung der personenbezogenen Daten ist weder gesetzlich, noch vertraglich vorgeschrieben. Allerdings
kann ggfs. die korrekte Darstellung der Inhalte durch Standardschriften nicht möglich sein. kann ggfs. die korrekte Darstellung der Inhalte durch Standardschriften nicht möglich sein.
</p> </p>
<h3 class="heading--3"> <h3>
Widerruf der Einwilligung Widerruf der Einwilligung
</h3> </h3>
<p class="paragraph"> <p>
Zur Darstellung der Inhalte wird regelmäßig die Programmiersprache JavaScript verwendet. Sie können der Zur Darstellung der Inhalte wird regelmäßig die Programmiersprache JavaScript verwendet. Sie können der
Datenverarbeitung daher widersprechen, indem Sie die Ausführung von JavaScript in Ihrem Browser deaktivieren Datenverarbeitung daher widersprechen, indem Sie die Ausführung von JavaScript in Ihrem Browser deaktivieren
oder einen JavaScript-Blocker installieren. Bitte beachten Sie, dass es hierdurch zu Funktionseinschränkungen oder einen JavaScript-Blocker installieren. Bitte beachten Sie, dass es hierdurch zu Funktionseinschränkungen
auf der Website kommen kann. auf der Website kommen kann.
</p> </p>
<h2 class="heading--2"> <h2>
Eingebettete YouTube-Videos Eingebettete YouTube-Videos
</h2> </h2>
<h3 class="heading--3"> <h3>
Art und Zweck der Verarbeitung Art und Zweck der Verarbeitung
</h3> </h3>
<p class="paragraph"> <p>
Auf einigen unserer Webseiten betten wir YouTube-Videos ein. Betreiber der entsprechenden Plugins ist die Auf einigen unserer Webseiten betten wir YouTube-Videos ein. Betreiber der entsprechenden Plugins ist die
YouTube, LLC, 901 Cherry Ave., San Bruno, CA 94066, USA (nachfolgend YouTube). Wenn Sie eine Seite mit dem YouTube, LLC, 901 Cherry Ave., San Bruno, CA 94066, USA (nachfolgend YouTube). Wenn Sie eine Seite mit dem
YouTube-Plugin besuchen, wird eine Verbindung zu Servern von YouTube hergestellt. Dabei wird YouTube mitgeteilt, YouTube-Plugin besuchen, wird eine Verbindung zu Servern von YouTube hergestellt. Dabei wird YouTube mitgeteilt,
welche Seiten Sie besuchen. Wenn Sie in Ihrem YouTube-Account eingeloggt sind, kann YouTube Ihr Surfverhalten welche Seiten Sie besuchen. Wenn Sie in Ihrem YouTube-Account eingeloggt sind, kann YouTube Ihr Surfverhalten
Ihnen persönlich zuzuordnen. Dies verhindern Sie, indem Sie sich vorher aus Ihrem YouTube-Account ausloggen. Ihnen persönlich zuzuordnen. Dies verhindern Sie, indem Sie sich vorher aus Ihrem YouTube-Account ausloggen.
</p> </p>
<p class="paragraph"> <p>
Wird ein YouTube-Video gestartet, setzt der Anbieter Cookies ein, die Hinweise über das Nutzerverhalten sammeln. Wird ein YouTube-Video gestartet, setzt der Anbieter Cookies ein, die Hinweise über das Nutzerverhalten sammeln.
</p> </p>
<p class="paragraph"> <p>
Weitere Informationen zu Zweck und Umfang der Datenerhebung und ihrer Verarbeitung durch YouTube erhalten Sie in Weitere Informationen zu Zweck und Umfang der Datenerhebung und ihrer Verarbeitung durch YouTube erhalten Sie in
den Datenschutzerklärungen des Anbieters, Dort erhalten Sie auch weitere Informationen zu Ihren diesbezüglichen den Datenschutzerklärungen des Anbieters, Dort erhalten Sie auch weitere Informationen zu Ihren diesbezüglichen
Rechten und Einstellungsmöglichkeiten zum Schutze Ihrer Privatsphäre Rechten und Einstellungsmöglichkeiten zum Schutze Ihrer Privatsphäre
(<KExternalLink href="https://policies.google.com/privacy"/>). Google verarbeitet Ihre Daten in den USA und hat (<ExternalLink href="https://policies.google.com/privacy"/>). Google verarbeitet Ihre Daten in den USA und hat
sich dem EU-US Privacy Shield unterworfen <KExternalLink href="https://www.privacyshield.gov/EU-US-Framework"/>. sich dem EU-US Privacy Shield unterworfen <ExternalLink href="https://www.privacyshield.gov/EU-US-Framework"/>.
</p> </p>
<h3 class="heading--3"> <h3>
Rechtsgrundlage Rechtsgrundlage
</h3> </h3>
<p class="paragraph"> <p>
Rechtsgrundlage für die Einbindung von YouTube und dem damit verbundenen Datentransfer zu Google ist Ihre Rechtsgrundlage für die Einbindung von YouTube und dem damit verbundenen Datentransfer zu Google ist Ihre
Einwilligung (Art. 6 Abs. 1 lit. a DSGVO). Einwilligung (Art. 6 Abs. 1 lit. a DSGVO).
</p> </p>
<h3 class="heading--3"> <h3>
Empfänger Empfänger
</h3> </h3>
<p class="paragraph"> <p>
Der Aufruf von YouTube löst automatisch eine Verbindung zu Google aus. Der Aufruf von YouTube löst automatisch eine Verbindung zu Google aus.
</p> </p>
<h3 class="heading--3"> <h3>
Speicherdauer und Widerruf der Einwilligung: Speicherdauer und Widerruf der Einwilligung:
</h3> </h3>
<p class="paragraph"> <p>
Wer das Speichern von Cookies für das Google-Ad-Programm deaktiviert hat, wird auch beim Anschauen von Wer das Speichern von Cookies für das Google-Ad-Programm deaktiviert hat, wird auch beim Anschauen von
YouTube-Videos mit keinen solchen Cookies rechnen müssen. YouTube legt aber auch in anderen Cookies YouTube-Videos mit keinen solchen Cookies rechnen müssen. YouTube legt aber auch in anderen Cookies
nicht-personenbezogene Nutzungsinformationen ab. Möchten Sie dies verhindern, so müssen Sie das Speichern von nicht-personenbezogene Nutzungsinformationen ab. Möchten Sie dies verhindern, so müssen Sie das Speichern von
Cookies im Browser blockieren. Cookies im Browser blockieren.
</p> </p>
<p class="paragraph"> <p>
Weitere Informationen zum Datenschutz bei YouTube finden Sie in der Datenschutzerklärung des Anbieters unter: Weitere Informationen zum Datenschutz bei YouTube finden Sie in der Datenschutzerklärung des Anbieters unter:
<KExternalLink href="https://www.google.de/intl/de/policies/privacy/"/> <ExternalLink href="https://www.google.de/intl/de/policies/privacy/"/>
</p> </p>
<h3 class="heading--3"> <h3>
Drittlandtransfer Drittlandtransfer
</h3> </h3>
<p class="paragraph"> <p>
Google verarbeitet Ihre Daten in den USA und hat sich dem EU_US Privacy Shield unterworfen Google verarbeitet Ihre Daten in den USA und hat sich dem EU_US Privacy Shield unterworfen
<KExternalLink href="https://www.privacyshield.gov/EU-US-Framework"/>. <ExternalLink href="https://www.privacyshield.gov/EU-US-Framework"/>.
</p> </p>
<h3 class="heading--3"> <h3>
Bereitstellung vorgeschrieben oder erforderlich Bereitstellung vorgeschrieben oder erforderlich
</h3> </h3>
<p class="paragraph"> <p>
Die Bereitstellung Ihrer personenbezogenen Daten erfolgt freiwillig, allein auf Basis Ihrer Einwilligung. Sofern Die Bereitstellung Ihrer personenbezogenen Daten erfolgt freiwillig, allein auf Basis Ihrer Einwilligung. Sofern
Sie den Zugriff unterbinden, kann es hierdurch zu Funktionseinschränkungen auf der Website kommen. Sie den Zugriff unterbinden, kann es hierdurch zu Funktionseinschränkungen auf der Website kommen.
</p> </p>
<h2 class="heading--2"> <h2>
SSL-Verschlüsselung SSL-Verschlüsselung
</h2> </h2>
<p class="paragraph"> <p>
Um die Sicherheit Ihrer Daten bei der Übertragung zu schützen, verwenden wir dem aktuellen Stand der Technik Um die Sicherheit Ihrer Daten bei der Übertragung zu schützen, verwenden wir dem aktuellen Stand der Technik
entsprechende Verschlüsselungsverfahren (z. B. SSL) über HTTPS. entsprechende Verschlüsselungsverfahren (z. B. SSL) über HTTPS.
</p> </p>
<h2 class="heading--2"> <h2>
Änderung unserer Datenschutzbestimmungen Änderung unserer Datenschutzbestimmungen
</h2> </h2>
<p class="paragraph"> <p>
Wir behalten uns vor, diese Datenschutzerklärung anzupassen, damit sie stets den aktuellen rechtlichen Wir behalten uns vor, diese Datenschutzerklärung anzupassen, damit sie stets den aktuellen rechtlichen
Anforderungen entspricht oder um Änderungen unserer Leistungen in der Datenschutzerklärung umzusetzen, z.B. bei Anforderungen entspricht oder um Änderungen unserer Leistungen in der Datenschutzerklärung umzusetzen, z.B. bei
der Einführung neuer Services. Für Ihren erneuten Besuch gilt dann die neue Datenschutzerklärung. der Einführung neuer Services. Für Ihren erneuten Besuch gilt dann die neue Datenschutzerklärung.
</p> </p>
<h2 class="heading--2"> <h2>
Fragen an den Datenschutzbeauftragten Fragen an den Datenschutzbeauftragten
</h2> </h2>
<p class="paragraph"> <p>
Wenn Sie Fragen zum Datenschutz haben, schreiben Sie uns bitte eine E-Mail oder wenden Sie sich direkt an die Wenn Sie Fragen zum Datenschutz haben, schreiben Sie uns bitte eine E-Mail oder wenden Sie sich direkt an die
für den Datenschutz verantwortliche Person: für den Datenschutz verantwortliche Person:
</p> </p>
<p class="paragraph"> <p>
Moritz Ruth<br> Moritz Ruth<br>
Zum Galgenberg 19<br> Zum Galgenberg 19<br>
66539 Neunkirchen<br> 66539 Neunkirchen<br>
Deutschland Deutschland
</p> </p>
<p class="paragraph"> <p>
<b>Telefon</b>: +49 176 46146329 <b>Telefon</b>: +49 176 46146329
</p> </p>
<p class="paragraph"> <p>
<b>E-Mail</b>: <a class="link" href="mailto:legal@moritz-ruth.de">legal@moritz-ruth.de</a> <b>E-Mail</b>: <a class="link" href="mailto:legal@moritz-ruth.de">legal@moritz-ruth.de</a>
</p> </p>
<p class="paragraph"> <p>
Die Datenschutzerklärung wurde mithilfe der activeMind AG erstellt, den Experten für Die Datenschutzerklärung wurde mithilfe der activeMind AG erstellt, den Experten für
<KExternalLink <ExternalLink
href="https://www.activemind.de/datenschutz/datenschutzhinweis-generator/" href="https://www.activemind.de/datenschutz/datenschutzhinweis-generator/"
> >
externe Datenschutzbeauftragte externe Datenschutzbeauftragte
</KExternalLink> (Version #2019-04-10). </ExternalLink>.
</p> </p>
</div> </div>
</div> </div>
</template> </template>
<style scoped lang="scss"> <style scoped lang="scss">
.privacy-policy-page {
overflow-y: auto;
}
</style> </style>
<script> <script>
import KNavigationBar from "kiste/components/KNavigationBar.vue"; import ExternalLink from "@/components/ExternalLink";
import KExternalLink from "kiste/components/KExternalLink.vue"; import NavigationBar from "@/components/NavigationBar";
export default { export default {
name: "PrivacyPolicyPage", name: "PrivacyPolicyPage",
components: { KNavigationBar, KExternalLink }, components: { NavigationBar, ExternalLink },
head: { htmlAttrs: { lang: "de" } } head: () => ({ htmlAttrs: { lang: "de" } })
}; };
</script> </script>

View file

@ -1,100 +0,0 @@
<template>
<div class="projects-page">
<KNavigationBar title="Projects" background-after-scroll/>
<div class="content">
<h1 class="heading--1">
Projects
</h1>
<GProject
type="JavaScript library"
title="shaped.js"
github="moritzruth/shaped.js"
npm="shaped.js"
>
Generate beautiful moving shapes using a canvas element which can for example be used for backgrounds.
See it in action <nuxt-link class="link" to="/">on the home page</nuxt-link>.
Every time you reload the page, it shows another variation.
</GProject>
<GProject
type="App (english)"
title="RelaxYourEyes"
link="https://relaxyoureyes.moritz-ruth.de"
github="moritzruth/relaxyoureyes"
>
A timer which reminds you to relax your eyes every 20 minutes.
</GProject>
<GProject
type="App (german)"
title="Schweredruck-Simulation"
link="https://app.moritz-ruth.de/schweredruck-simulation"
github="moritzruth/schweredruck-simulation"
>
Simulate and calculate the hydrostatic pressure in different liquids.
</GProject>
<GProject
type="Website"
title="cryptic-game.net"
link="https://test.cryptic-game.net"
github="cryptic-game/website/tree/vueWebsite"
>
I am responsible for the new (not yet released) website of the
<a class="link" href="https://github.com/cryptic-game">Cryptic game</a>.
(Just the website, not the game itself.)
</GProject>
<GProject
type="Vue.js/Nuxt.js plugin"
title="Kiste"
github="moritzruth/kiste"
npm="kiste"
>
A collection of UI components and styles used for example by this website.
</GProject>
<GProject
type="Node.js Library"
title="log-groups"
github="moritzruth/log-groups"
npm="log-groups"
>
A pretty console logging library for printing grouped messages with Node.js.
</GProject>
<GProject
type="Node.js script"
title="Zimmerlampe"
github="moritzruth/zimmerlampe"
>
A simple script I use for controlling my Stairville CLB4 as room lamp.
</GProject>
<GProject
type="Node.js library"
title="node-enttec-open-dmx-usb"
github="moritzruth/node-enttec-open-dmx-usb"
>
A Node.js library for sending DMX data through the
<a class="link" href="https://www.enttec.co.uk/en/product/controls/dmx-usb-interfaces/open-dmx-usb/">
Enttec Open DMX USB Interface</a>.
</GProject>
<GProject
type="Configuration"
title="eslint-config"
github="moritzruth/eslint-config"
npm="@moritzruth/eslint-config"
>
My personal ESLint configuration I use in all of my projects.
</GProject>
</div>
</div>
</template>
<style scoped lang="scss">
</style>
<script>
import KNavigationBar from "kiste/components/KNavigationBar.vue";
import GProject from "@/components/pages/projects/GProject.vue";
export default {
name: "ProjectsPage",
components: { GProject, KNavigationBar }
};
</script>

View file

@ -8,6 +8,7 @@ module.exports = {
alias: { alias: {
"@": path.resolve(__dirname), "@": path.resolve(__dirname),
"~": path.resolve(__dirname) "~": path.resolve(__dirname)
} },
extensions: [".vue", ".js"]
} }
}; };

2169
yarn.lock

File diff suppressed because it is too large Load diff