1
0
Fork 0
mirror of https://github.com/Findus23/lw1.at.git synced 2024-09-16 12:13:44 +02:00

convert to typescript

This commit is contained in:
Lukas Winkler 2020-12-21 21:43:14 +01:00
parent 2ff9524ab3
commit 7358470f10
Signed by: lukas
GPG key ID: 54DE4D798D244853
21 changed files with 1163 additions and 851 deletions

4
.eslintignore Normal file
View file

@ -0,0 +1,4 @@
# don't ever lint node_modules
node_modules
# don't lint build output (make sure it's set to your correct build folder name)
dist

32
.eslintrc.js Normal file
View file

@ -0,0 +1,32 @@
module.exports = {
root: true,
"parser": "vue-eslint-parser",
plugins: [
'@typescript-eslint',
"html"
],
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
"plugin:vue/essential",
"plugin:vue/base",
],
parserOptions: {
parser: '@typescript-eslint/parser',
ecmaVersion: 6,
sourceType: "module",
ecmaFeatures: {
jsx: true
}
},
rules: {
semi: "error",
"no-mixed-spaces-and-tabs": 0,
"vue/no-side-effects-in-computed-properties": 0,
"vue/no-unused-vars": 0, //maybe warn instead
"no-undef": 0,
"@typescript-eslint/ban-ts-comment": 0,
"@typescript-eslint/no-var-requires": 0
},
};

View file

@ -4,9 +4,8 @@
"version": "1.0.0",
"author": "Lukas Winkler <l.winkler23@mailbox.org>",
"private": true,
"scripts": {
"build": "NODE_ENV=\"production\" TS_NODE_PROJECT=\"tsconfig-for-webpack-config.json\" webpack --config webpack.prod.ts",
"build": "NODE_ENV=\"production\" TS_NODE_PROJECT=\"tsconfig-for-webpack-config.json\" webpack --config webpack.prod.ts --progress",
"dev": "TS_NODE_PROJECT=\"tsconfig-for-webpack-config.json\" webpack serve --config webpack.dev.ts --hot",
"json": "TS_NODE_PROJECT=\"tsconfig-for-webpack-config.json\" webpack --config webpack.prod.ts --profile --json > stats.json"
},
@ -37,6 +36,8 @@
"@types/webpack": "^4.41.25",
"@types/webpack-dev-server": "^3.11.1",
"@types/webpack-subresource-integrity": "^1.2.0",
"@typescript-eslint/eslint-plugin": "^4.10.0",
"@typescript-eslint/parser": "^4.10.0",
"autoprefixer": "^10.0.1",
"babel-eslint": "^10.0.1",
"babel-loader": "^8.0.0-beta.0",
@ -45,9 +46,10 @@
"compression-webpack-plugin": "^7.1.0",
"cross-env": "^7.0.0",
"css-loader": "^5.0.1",
"eslint": "^7.4.0",
"eslint": "^7.16.0",
"eslint-loader": "^4.0.2",
"eslint-plugin-html": "^6.0.0",
"eslint-plugin-vue": "^7.3.0",
"file-loader": "^6.0.0",
"html-webpack-plugin": "^4.3.0",
"image-webpack-loader": "^7.0.1",
@ -59,6 +61,7 @@
"prerender-spa-plugin": "^3.0.0-beta.2",
"sass-loader": "^10.0.3",
"sharp": "^0.26.1",
"ts-loader": "^8.0.12",
"ts-node": "^9.1.1",
"typescript": "^4.1.3",
"vue-loader": "^15.2.4",

View file

@ -4,34 +4,39 @@
</div>
</template>
<script>
export default {
name: 'app',
props: ["language"],
};
<script lang="ts">
import Vue, {PropType} from "vue";
import {Language} from "./types";
export default Vue.extend({
name: 'app',
props: {
language: String as PropType<Language>
},
});
</script>
<style lang="scss">
@import "../node_modules/normalize.css/normalize";
@import "variables";
@import "../node_modules/milligram/src/Color";
@import "../node_modules/milligram/src/Vars";
@import "../node_modules/milligram/src/Base";
@import "../node_modules/milligram/src/Blockquote";
@import "../node_modules/milligram/src/Blocks";
/*@import "../node_modules/milligram/src/Button";*/
@import "../node_modules/milligram/src/Code";
@import "../node_modules/milligram/src/Divider";
@import "../node_modules/milligram/src/Form";
@import "../node_modules/milligram/src/Grid";
@import "../node_modules/milligram/src/Images";
@import "../node_modules/milligram/src/Label";
@import "../node_modules/milligram/src/Link";
@import "../node_modules/milligram/src/List";
@import "../node_modules/milligram/src/Navbar";
@import "../node_modules/milligram/src/Spacing";
@import "../node_modules/milligram/src/Table";
@import "../node_modules/milligram/src/Typography";
@import "../node_modules/milligram/src/Utility";
@import "../node_modules/normalize.css/normalize";
@import "variables";
@import "../node_modules/milligram/src/Color";
@import "../node_modules/milligram/src/Vars";
@import "../node_modules/milligram/src/Base";
@import "../node_modules/milligram/src/Blockquote";
@import "../node_modules/milligram/src/Blocks";
/*@import "../node_modules/milligram/src/Button";*/
@import "../node_modules/milligram/src/Code";
@import "../node_modules/milligram/src/Divider";
@import "../node_modules/milligram/src/Form";
@import "../node_modules/milligram/src/Grid";
@import "../node_modules/milligram/src/Images";
@import "../node_modules/milligram/src/Label";
@import "../node_modules/milligram/src/Link";
@import "../node_modules/milligram/src/List";
@import "../node_modules/milligram/src/Navbar";
@import "../node_modules/milligram/src/Spacing";
@import "../node_modules/milligram/src/Table";
@import "../node_modules/milligram/src/Typography";
@import "../node_modules/milligram/src/Utility";
</style>

View file

@ -85,7 +85,8 @@
<path d="M2807-894.7v-10.6l-8 5.3z" fill="transparent"></path>
</svg>
</a>
<a rel="me noopener" href="https://git.lw1.at/lw1" target="_blank" :aria-label="gitlabText" data-balloon-pos="up">
<a rel="me noopener" href="https://git.lw1.at/lw1" target="_blank" :aria-label="gitlabText"
data-balloon-pos="up">
<!-- License - http://fontawesome.io/license (SIL OFL 1.1) -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 54 54">
<title>{{gitlabText}}</title>
@ -123,69 +124,74 @@
</nav>
</template>
<script>
export default {
name: "contact",
props: ["language"],
computed: {
english() {
return this.language === "en"
},
githubText() {
return this.english ? "view my code on GitHub" : "Schau meinen Code auf GitHub an"
},
keybaseText() {
return this.english ? "View Profile on Keybase.io" : "Profil auf Keybase.io"
},
mastodonText() {
return this.english ? "Follow me on Mastodon" : "Folg mir bei Mastodon"
},
twitterText() {
return this.english ? "Follow me on Twitter" : "Folg mir bei Twitter"
},
matrixText() {
return this.english ? "Contact me via matrix.org (riot.im)" : "Kontaktiere mich über matrix.org (riot.im)"
},
nextcloudText() {
return this.english ? "share files with me via Nextcloud" : "Teile Dateien mit mir über Nextcloud"
},
peertubeText() {
return this.english ? "view my videos on PeerTube" : "Schaue meine Videos auf PeerTube an"
},
gitlabText() {
return this.english ? "view my code on GitLab" : "Schaue meinen Code auf GitLab an"
},
guidesText() {
return this.english ? "view my guides" : "Lies meine Anleitungen"
},
emailText() {
return this.english ? "write me an E-Mail (hi@lw1.at)" : "Schreib mir eine E-Mail (hi@lw1.at)"
},
<script lang="ts">
import Vue, {PropType} from "vue";
import {Language} from "./types";
export default Vue.extend({
name: "contact",
props: {
language: String as PropType<Language>
},
computed: {
english(): boolean {
return this.language === "en";
},
};
githubText(): string {
return this.english ? "view my code on GitHub" : "Schau meinen Code auf GitHub an";
},
keybaseText(): string {
return this.english ? "View Profile on Keybase.io" : "Profil auf Keybase.io";
},
mastodonText(): string {
return this.english ? "Follow me on Mastodon" : "Folg mir bei Mastodon";
},
twitterText(): string {
return this.english ? "Follow me on Twitter" : "Folg mir bei Twitter";
},
matrixText(): string {
return this.english ? "Contact me via matrix.org (riot.im)" : "Kontaktiere mich über matrix.org (riot.im)";
},
nextcloudText(): string {
return this.english ? "share files with me via Nextcloud" : "Teile Dateien mit mir über Nextcloud";
},
peertubeText(): string {
return this.english ? "view my videos on PeerTube" : "Schaue meine Videos auf PeerTube an";
},
gitlabText(): string {
return this.english ? "view my code on GitLab" : "Schaue meinen Code auf GitLab an";
},
guidesText(): string {
return this.english ? "view my guides" : "Lies meine Anleitungen";
},
emailText(): string {
return this.english ? "write me an E-Mail (hi@lw1.at)" : "Schreib mir eine E-Mail (hi@lw1.at)";
},
},
});
</script>
<style lang="scss">
@import "variables";
@import "variables";
.contact {
display: flex;
justify-content: space-around;
.contact {
display: flex;
justify-content: space-around;
svg {
width: 45px;
height: 45px;
color: $consoleBackground;
transition: color .2s;
padding: 5px;
svg {
width: 45px;
height: 45px;
color: $consoleBackground;
transition: color .2s;
padding: 5px;
&.keybase .line {
fill: currentColor;
}
}
a:hover svg {
outline: 1px solid $consoleBackground;
}
&.keybase .line {
fill: currentColor;
}
}
a:hover svg {
outline: 1px solid $consoleBackground;
}
}
</style>

View file

@ -5,43 +5,56 @@
</div>
</template>
<script>
import {decode, isBlurhashValid} from "blurhash";
<script lang="ts">
export default {
name: "HashImage",
props: ["img", "small"],
mounted() {
if (isBlurhashValid(this.img.hash).result) {
const canvas = this.$refs.myCanvas;
const pixels = decode(this.img.hash, 30, 15);
import Vue, {PropType} from "vue";
import {decode, isBlurhashValid} from "blurhash";
import {ImageObject} from "./types";
const ctx = canvas.getContext("2d");
const imageData = new ImageData(pixels, 30, 15);
ctx.scale(10, 10);
ctx.putImageData(imageData, 0, 0);
ctx.drawImage(canvas, 0, 0);
}
},
computed: {
height() {
return this.small ? 150 : 600;
},
width() {
return this.small ? 300 : 1200;
},
absolutePath() {
return "/" + this.img.path;
}
export default Vue.extend({
name: "HashImage",
props: {
small: Boolean,
img: Object as PropType<ImageObject>
},
mounted(): void {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const that = this as any;
const img = that.img as ImageObject;
const hash: string = img.hash;
if (isBlurhashValid(hash).result) {
const canvas = that.$refs.myCanvas;
const pixels = decode(hash, 30, 15);
const ctx = canvas.getContext("2d");
const imageData = new ImageData(pixels, 30, 15);
ctx.scale(10, 10);
ctx.putImageData(imageData, 0, 0);
ctx.drawImage(canvas, 0, 0);
}
};
},
computed: {
height() {
return this.small ? 150 : 600;
},
width() {
return this.small ? 300 : 1200;
},
absolutePath() {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const that = this as any;
const img = that.img as ImageObject;
return "/" + img.path;
}
}
});
</script>
<style>
canvas {
position: absolute;
top: 0;
left: 0;
width: 100%;
}
canvas {
position: absolute;
top: 0;
left: 0;
width: 100%;
}
</style>

View file

@ -2,13 +2,13 @@
<div id="imprint">
<div class="backButton">
<router-link :to="{ name: 'Overview', params: { language: language }}">
<span class="arrow"></span> {{language==="de" ? "Zurück zur Hauptseite":"Back to the main page"}}
<span class="arrow"></span> {{ language === "de" ? "Zurück zur Hauptseite" : "Back to the main page" }}
</router-link>
</div>
<div class="languageSelector">
<router-link :to="{ name: (language==='de' ? 'Imprint':'Impressum')}" rel="alternate"
:hreflang="language==='de' ? 'en':'de'">
{{language==="de" ? "English":"Deutsch"}}
{{ language === "de" ? "English" : "Deutsch" }}
</router-link>
</div>
<h1 v-if="language==='de'">Impressum</h1>
@ -282,22 +282,27 @@
</div>
</template>
<script>
export default {
name: "imprint",
props: ["language"]
};
<script lang="ts">
import Vue, {PropType} from "vue";
import {Language} from "./types";
export default Vue.extend({
name: "imprint",
props: {
language: String as PropType<Language>
},
});
</script>
<style lang="scss">
#imprint {
.mainText {
text-align: left;
}
#imprint {
.mainText {
text-align: left;
}
h2 {
font-size: 3rem;
}
h2 {
font-size: 3rem;
}
}
}
</style>

View file

@ -16,110 +16,114 @@
</header>
</template>
<script>
export default {
name: "intro",
props: ["language"],
};
<script lang="ts">
import Vue from "vue";
export default Vue.extend({
name: "intro",
props: ["language"],
});
</script>
<style lang="scss">
@import "variables";
$liberapay: #f6c915;
$bitcoin: #f7931a;
$flattr: #595959;
@import "variables";
.donate-buttons {
display: flex;
align-items: flex-start;
justify-content: center;
margin-bottom: 16px;
$liberapay: #f6c915;
$bitcoin: #f7931a;
$flattr: #595959;
a {
margin: 0 16px;
height: 32px;
display: inline-block;
.donate-buttons {
display: flex;
align-items: flex-start;
justify-content: center;
margin-bottom: 16px;
img, svg {
border-radius: 5px;
height: 100%;
transition: .2s;
}
a {
margin: 0 16px;
height: 32px;
display: inline-block;
&:hover img {
filter: brightness(1.3);
}
&:not(.image) {
padding: 4px 6px;
text-decoration: none;
transition: .2s;
border-radius: 4px;
display: inline-block;
color: white;
font-size: 12px;
font-weight: 700;
}
svg, span {
vertical-align: middle;
}
}
.liberapay-btn {
background-color: $liberapay;
&:hover {
background-color: lighten($liberapay, 10%);
}
}
.bitcoin {
background-color: $bitcoin;
&:hover {
background-color: lighten($bitcoin, 10%);
}
}
.flattr {
background-color: $flattr;
&:hover {
background-color: lighten($flattr, 10%);
}
svg {
fill: white;
height: 15px;
margin-top: 2px;
}
}
img, svg {
border-radius: 5px;
height: 100%;
transition: .2s;
}
.introduction {
text-align: left;
margin-bottom: 10px;
padding: 0 10px;
&:hover img {
filter: brightness(1.3);
}
h1 {
font-family: $consoleFont;
color: black !important;
div {
font-size: 24px;
line-height: 28px;
}
&:not(.image) {
padding: 4px 6px;
text-decoration: none;
transition: .2s;
border-radius: 4px;
display: inline-block;
color: white;
font-size: 12px;
font-weight: 700;
}
@media screen and (max-width: 480px) {
h1 {
text-align: left;
padding: 0 10px;
}
.languageSelector {
right: 10px;
}
svg, span {
vertical-align: middle;
}
}
.liberapay-btn {
background-color: $liberapay;
&:hover {
background-color: lighten($liberapay, 10%);
}
}
.bitcoin {
background-color: $bitcoin;
&:hover {
background-color: lighten($bitcoin, 10%);
}
}
.flattr {
background-color: $flattr;
&:hover {
background-color: lighten($flattr, 10%);
}
svg {
fill: white;
height: 15px;
margin-top: 2px;
}
}
}
.introduction {
text-align: left;
margin-bottom: 10px;
padding: 0 10px;
}
h1 {
font-family: $consoleFont;
color: black !important;
div {
font-size: 24px;
line-height: 28px;
}
}
@media screen and (max-width: 480px) {
h1 {
text-align: left;
padding: 0 10px;
}
.languageSelector {
right: 10px;
}
}
</style>

View file

@ -16,7 +16,7 @@
</div>
<div class="modal-body" ref="test">
<h1>{{ translate(element.title) }}
<div v-if="element.subtitle">{{translate(element.subtitle)}}</div>
<div v-if="element.subtitle">{{ translate(element.subtitle) }}</div>
</h1>
<div :class="{'modal-linkbar':true, try:element.try}">
<a v-bind:href="element.url" v-if="element.url" target="_blank">
@ -26,7 +26,7 @@
<path d="M54.22083 161.88751C75.49125 69.74037 157.61638.879 255.99447-.0344V71.2784c-58.68038.82679-108.44983 38.32148-127.51646 90.6032H54.22378z"></path>
<path d="M183.32848 154.61394L93.60991 255.96317-.0104 154.45508"></path>
</svg>
<span>{{language==="de" ? "Ausprobieren": "Try it out!"}}</span>
<span>{{ language === "de" ? "Ausprobieren" : "Try it out!" }}</span>
</div>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 420 420">
<title>Website</title>
@ -98,255 +98,268 @@
</transition>
</template>
<script>
import LicenseIcons from "./LicenseIcons.vue";
import HashImage from "./HashImage.vue";
<script lang="ts">
import LicenseIcons from "./LicenseIcons.vue";
import HashImage from "./HashImage.vue";
import Vue, {PropType} from "vue";
import {Article, Language, translatableString} from "./types";
export default {
data() {
return {
title: null,
element: null,
sentReadmore: false
};
},
props: ['language', 'data'],
mounted() {
document.body.style.overflow = "hidden";
this.id = this.$route.params.id;
this.element = this.data.find(elem => elem.id === this.id);
if (!this.element) {
this.$router.replace("/");
return false;
}
document.title = this.translate(this.element.title) + " - lw1.at";
this.$nextTick(function() {
_paq.push(['setDocumentTitle', document.title]);
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
});
this.$refs.container.focus();
},
methods: {
translate: function(value) {
if (typeof value === "object") {
return value[this.language];
} else {
return value;
}
},
readmore: function() {
this.sentReadmore = true;
if (typeof _paq != "undefined") {
_paq.push(['trackEvent', 'Feedback', 'readmore', this.id]);
} else {
console.info("Feedback not sent as Matomo isn't loaded");
}
}
},
head: {
title: function() {
if (this.element) {
return {inner: this.translate(this.element.title)};
}
}
},
components: {
HashImage,
LicenseIcons
export default Vue.extend({
data() {
return {
title: "",
element: undefined as Article | undefined,
sentReadmore: false as boolean,
id: ""
};
},
props: {
language: String as PropType<Language>,
data: Array as PropType<Article[]>
},
mounted() {
document.body.style.overflow = "hidden";
this.id = this.$route.params.id;
this.element = this.data.find(elem => elem.id === this.id);
if (!this.element) {
this.$router.replace("/");
return false;
}
};
document.title = this.translate(this.element.title) + " - lw1.at";
this.$nextTick(function () {
const _paq = window._paq;
_paq.push(['setDocumentTitle', document.title]);
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
});
const container=this.$refs.container as HTMLDivElement;
container.focus();
},
methods: {
translate: function (value: translatableString): string {
if (typeof value === "object") {
return value[this.language];
} else {
return value;
}
},
readmore: function (): void {
this.sentReadmore = true;
if (typeof window._paq != "undefined") {
window._paq.push(['trackEvent', 'Feedback', 'readmore', this.id]);
} else {
console.info("Feedback not sent as Matomo isn't loaded");
}
}
},
// head: {
// title: function (): string {
// if (this.element) {
// return {inner: this.translate(this.element.title)};
// }
// }
// },
components: {
HashImage,
LicenseIcons
}
});
</script>
<style lang="scss">
@import "variables";
@import "variables";
.closeButton {
position: absolute;
font-size: 22px;
line-height: 22px;
top: 10px;
right: 10px;
padding: 10px;
cursor: pointer;
transition: color 0.2s;
.closeButton {
position: absolute;
font-size: 22px;
line-height: 22px;
top: 10px;
right: 10px;
padding: 10px;
cursor: pointer;
transition: color 0.2s;
color: $color-primary;
z-index: 2000;
&:hover {
color: darkgrey;
}
}
.modal-mask {
background-color: rgba(0, 0, 0, 0.5);
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
overflow: auto;
-webkit-overflow-scrolling: touch;
padding: 0 20px;
@media (max-width: 40.0rem) {
padding: 0 10px;
}
z-index: 1000;
transition: opacity .3s ease;
}
.modal-container {
position: relative;
max-width: 1000px;
/*
@media (max-width: 40.0rem) {
width: 100%;
padding: 20px;
}
*/
margin: 50px auto 0;
background-color: #fff;
border-radius: $borderRadius;
.imagewrapper {
padding-bottom: 50%;
&.seperator {
border-bottom: solid 1px #ddd;
}
img {
display: block;
width: 100%;
border-top-left-radius: $borderRadius;
border-top-right-radius: $borderRadius;
height: auto;
position: absolute;
left: 0;
top: 0;
z-index: 1100;
background: white;
}
}
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23);
&:focus {
outline: none;
}
}
.modal-header h3 {
margin-top: 0;
color: #42b983;
}
h1 {
margin: 0 5px;
}
.modal-body {
padding: 20px 30px;
margin: 20px 0;
text-align: left;
}
.modal-default-button {
float: right;
}
/*
* The following styles are auto-applied to elements with
* transition="modal" when their visibility is toggled
* by Vue.js.
*
* You can easily play with the modal transition by editing
* these styles.
*/
.modal-enter {
opacity: 0;
}
.modal-leave-active {
opacity: 0;
}
/*.modal-enter .modal-container,*/
/*.modal-leave-active .modal-container {*/
/*transform: scale(0.8);*/
/*}*/
.modal-linkbar {
display: flex;
justify-content: space-around;
&.try {
margin-top: 40px;
}
a {
position: relative;
padding: 16px;
> svg {
width: 36px;
height: 36px;
display: block;
color: black;
}
svg, span {
transition: .2s;
}
display: block;
&:hover {
svg {
color: $color-primary;
z-index: 2000;
}
&:hover {
color: darkgrey;
}
.try-it-out {
color: $color-primary;
}
}
.modal-mask {
background-color: rgba(0, 0, 0, 0.5);
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
overflow: auto;
-webkit-overflow-scrolling: touch;
padding: 0 20px;
@media (max-width: 40.0rem) {
padding: 0 10px;
}
z-index: 1000;
transition: opacity .3s ease;
}
.try-it-out {
position: absolute;
top: -40px;
left: 23px;
right: -150px;
vertical-align: top;
color: black;
.modal-container {
svg {
display: inline-block;
position: relative;
max-width: 1000px;
/*
@media (max-width: 40.0rem) {
width: 100%;
padding: 20px;
}
*/
margin: 50px auto 0;
background-color: #fff;
border-radius: $borderRadius;
top: 20px;
}
.imagewrapper {
padding-bottom: 50%;
span {
&.seperator {
border-bottom: solid 1px #ddd;
}
img {
display: block;
width: 100%;
border-top-left-radius: $borderRadius;
border-top-right-radius: $borderRadius;
height: auto;
position: absolute;
left: 0;
top: 0;
z-index: 1100;
background: white;
}
}
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23);
&:focus {
outline: none;
}
}
}
}
}
.modal-header h3 {
margin-top: 0;
color: #42b983;
}
iframe {
width: 100%;
height: 400px;
border: none;
border-radius: $borderRadius;
display: block;
margin-bottom: 15px;
}
h1 {
margin: 0 5px;
}
.modal-body {
padding: 20px 30px;
margin: 20px 0;
text-align: left;
}
.modal-default-button {
float: right;
}
/*
* The following styles are auto-applied to elements with
* transition="modal" when their visibility is toggled
* by Vue.js.
*
* You can easily play with the modal transition by editing
* these styles.
*/
.modal-enter {
opacity: 0;
}
.modal-leave-active {
opacity: 0;
}
/*.modal-enter .modal-container,*/
/*.modal-leave-active .modal-container {*/
/*transform: scale(0.8);*/
/*}*/
.modal-linkbar {
display: flex;
justify-content: space-around;
&.try {
margin-top: 40px;
}
a {
position: relative;
padding: 16px;
> svg {
width: 36px;
height: 36px;
display: block;
color: black;
}
svg, span {
transition: .2s;
}
display: block;
&:hover {
svg {
color: $color-primary;
}
.try-it-out {
color: $color-primary;
}
}
.try-it-out {
position: absolute;
top: -40px;
left: 23px;
right: -150px;
vertical-align: top;
color: black;
svg {
display: inline-block;
position: relative;
top: 20px;
}
span {
}
}
}
}
iframe {
width: 100%;
height: 400px;
border: none;
border-radius: $borderRadius;
display: block;
margin-bottom: 15px;
}
.note {
background-color: $consoleBackground;
color: $consoleOrange;
font-family: $consoleFont;
text-align: center;
/*background-color: #fdbc4b;*/
padding: 15px;
margin-bottom: 15px;
}
.note {
background-color: $consoleBackground;
color: $consoleOrange;
font-family: $consoleFont;
text-align: center;
/*background-color: #fdbc4b;*/
padding: 15px;
margin-bottom: 15px;
}
</style>

View file

@ -21,39 +21,41 @@
</a>
</template>
<script>
export default {
name: "license-icons",
props: ["id", "url"]
};
<script lang="ts">
import Vue from "vue";
export default Vue.extend({
name: "license-icons",
props: ["id", "url"]
});
</script>
<style lang="scss" scoped>
svg {
color: black;
svg {
color: black;
path {
fill: white;
stroke: currentColor;
stroke-width: 15.349;
stroke-linecap: round;
}
path {
fill: white;
stroke: currentColor;
stroke-width: 15.349;
stroke-linecap: round;
}
text {
font-family: Arial, sans-serif;
fill: currentColor;
text-align: start;
line-height: 125%;
font-weight: 700;
font-size: 124.104px
}
}
text {
font-family: Arial, sans-serif;
fill: currentColor;
text-align: start;
line-height: 125%;
font-weight: 700;
font-size: 124.104px
}
}
.MIT text {
font-size: 124.104px;
}
.MIT text {
font-size: 124.104px;
}
.GPL text {
font-size: 109.871px;
}
.GPL text {
font-size: 109.871px;
}
</style>

View file

@ -1,7 +1,7 @@
export default class MatomoTracker {
init() {
if (typeof _paq === 'undefined' && !window.__PRERENDER_INJECTED) { // should only occur with hot reloading
let _paq = window._paq || [];
init(): void {
if (!window.__PRERENDER_INJECTED) { // should only occur with hot reloading
const _paq = window._paq || [];
_paq.push(['setRequestMethod', 'POST']);
_paq.push(['enableHeartBeatTimer']);
@ -9,16 +9,18 @@ export default class MatomoTracker {
_paq.push(["setDoNotTrack", true]);
}
_paq.push(['disableCookies']);
(function() {
let u = (process.env.NODE_ENV === "production") ? "https://matomo.lw1.at/" : "//localhost/piwik/";
(function () {
const u = (process.env.NODE_ENV === "production") ? "https://matomo.lw1.at/" : "//localhost/piwik/";
_paq.push(['setTrackerUrl', u + ((process.env.NODE_ENV === "production") ? 'statistics.php' : 'piwik.php')]);
_paq.push(['setSiteId', (process.env.NODE_ENV === "production") ? 14 : 5]);
let d = document, g = d.createElement('script'), s = d.getElementsByTagName('script')[0];
const d = document, g = d.createElement('script'), s = d.getElementsByTagName('script')[0];
g.type = 'text/javascript';
g.async = true;
g.defer = true;
g.src = u + ((process.env.NODE_ENV === "production") ? 'statistics.js' : 'piwik.js');
s.parentNode.insertBefore(g, s);
if (s.parentNode) {
s.parentNode.insertBefore(g, s);
}
})();
window._paq = _paq;
} else {
@ -26,3 +28,12 @@ export default class MatomoTracker {
}
}
}
declare global {
interface Window {
_paq: paq;
__PRERENDER_INJECTED: boolean
}
}
declare type paq = [[unknown, unknown, unknown, unknown] | [unknown, unknown, unknown] | [unknown, unknown] | [unknown]]

View file

@ -3,7 +3,7 @@
<div class="languageSelector">
<router-link :to="{ name: 'Overview', params: { language: otherLanguage }}"
rel="alternate" :hreflang="otherLanguage">
{{language==="de" ? "English":"Deutsch"}}
{{ language === "de" ? "English" : "Deutsch" }}
</router-link>
</div>
<intro :language="language"></intro>
@ -11,19 +11,19 @@
<div id="filterwrapper">
<button class="button-outline" @click="filter=false;search=''"
:class="filter ? '' : 'active'">
{{language==="de"?"Alle Projekte":"All Projects"}}
{{ language === "de" ? "Alle Projekte" : "All Projects" }}
</button>
<button v-for="(tag, key, index) in filterTags"
<button v-for="(tag, key, index) in filterTags" :key="key"
:class="['button-outline',(filter === key)?'active':'']"
@click="filter=key">
{{translate(tag.name)}}
{{ translate(tag.name) }}
</button>
</div>
<div id="searchwrapper">
<input title="test" v-model="search" :placeholder="language==='de'?'Suchen...':'Search...'"/>
</div>
<div v-if="noResults" id="noresults">
{{language==="de"?"Keine Ergebnisse":"No results"}}!
{{ language === "de" ? "Keine Ergebnisse" : "No results" }}!
</div>
<div id="blockwrapper">
<router-link v-for="element in elements" :key="element.id" class="card"
@ -39,8 +39,8 @@
{{ formatDate(element.date) }}
</div>
<div class="tagwrapper">
<div class="tag"
v-for="tag in element.tags">{{translate(tags[tag].name)}}
<div class="tag" :key="tag"
v-for="tag in element.tags">{{ translate(tags[tag].name) }}
</div>
</div>
@ -48,11 +48,12 @@
</router-link>
</div>
<router-link class="toImprint" :to="{ name: (language==='de' ? 'Impressum':'Imprint')}">
{{language==="de" ? "Impressum":"Imprint"}}
{{ language === "de" ? "Impressum" : "Imprint" }}
</router-link>
<a href="https://keyoxide.org/63DB263BACE368B5C5F79CE494AFBE7C2656A5B5" class="gpg" target="_blank" rel="noopener">
GPG: 63DB 263B ACE3 68B5 C5F7 9CE4 94AF BE7C 2656 A5B5
</a>
<a href="https://keyoxide.org/63DB263BACE368B5C5F79CE494AFBE7C2656A5B5" class="gpg" target="_blank"
rel="noopener">
GPG: 63DB 263B ACE3 68B5 C5F7 9CE4 94AF BE7C 2656 A5B5
</a>
<router-link :to="{ name: 'itemModal',params:{id:'classiccounter'} }"><img
src="https://matomo.lw1.at/index.php?module=ClassicCounter&action=svg&idSite=14"
alt="Matomo visit counter"
@ -64,286 +65,298 @@
</div>
</template>
<script>
import Intro from "./Intro.vue";
import Contact from "./Contact.vue";
import HashImage from "./HashImage.vue";
<script lang="ts">
import Intro from "./Intro.vue";
import Contact from "./Contact.vue";
import HashImage from "./HashImage.vue";
import Vue, {PropType} from "vue";
import {Article, Language, Tags, translatableString, YamlImport} from "./types";
const yaml = require('./tags.yaml');
yaml.data.forEach((part, index, array) => {
part.dateObj = new Date(part.date);
array[index] = part;
});
const data = yaml.data;
const tags = yaml.tags;
// eslint-disable-next-line @typescript-eslint/no-var-requires
const yaml: YamlImport = require('./tags.yaml');
yaml.data.forEach((part, index, array) => {
part.dateObj = new Date(part.date);
array[index] = part;
});
export default {
components: {Intro, Contact, HashImage},
name: 'overview',
data() {
return {
data: data,
tags: tags,
filter: false,
search: "",
noResults: false
};
const data = yaml.data;
const tags = yaml.tags;
export default Vue.extend({
components: {Intro, Contact, HashImage},
name: 'overview',
data() {
return {
data: data,
tags: tags as Tags,
filter: "",
search: "",
noResults: false
};
},
props: {
language: String as PropType<Language>
},
computed: {
elements(): Article[] {
let filtered = this.data.filter(item => {
return this.filterContains(item) && this.filterSearch(item);
});
if (filtered.length === 0) {
filtered = this.data;
this.noResults = true;
} else {
this.noResults = false;
}
return filtered.sort((a, b) => {
return b.dateObj.valueOf() - a.dateObj.valueOf();
});
},
props: ["language"],
computed: {
elements() {
let filtered = this.data.filter(item => {
return this.filterContains(item) && this.filterSearch(item);
});
if (filtered.length === 0) {
filtered = this.data;
this.noResults = true;
} else {
this.noResults = false;
}
return filtered.sort((a, b) => {
return b.dateObj - a.dateObj;
});
},
filterTags() {
return Object.keys(this.tags).reduce((filtered, key) => {
if (!this.tags[key].hidden) {