init 2.0
commit
9dd6214d62
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"name": "adb.sh_2.0",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"authors": {
|
||||||
|
"name": "",
|
||||||
|
"email": ""
|
||||||
|
},
|
||||||
|
"repository": "/adb.sh_2.0",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vuepress dev src",
|
||||||
|
"build": "vuepress build src"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"dart-sass": "^1.25.0",
|
||||||
|
"sass": "^1.54.9",
|
||||||
|
"sass-loader": "^10.3.1",
|
||||||
|
"vuepress": "^1.5.3",
|
||||||
|
"webpack": "^4.46.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@vuepress/plugin-search": "^1.9.7",
|
||||||
|
"@vuepress/theme-default": "^1.9.7",
|
||||||
|
"bootstrap": "^5.2.1",
|
||||||
|
"bootstrap-darkmode": "^5.0.1",
|
||||||
|
"bootstrap-icons": "^1.9.1"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2021 by Justin Windle (https://codepen.io/soulwire/pen/mErPAK)
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||||
|
and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||||
|
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
||||||
|
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export class TextScramble {
|
||||||
|
constructor(el) {
|
||||||
|
this.el = el
|
||||||
|
this.chars = '!<>-_\\/[]{}—=+*^?#________'
|
||||||
|
this.update = this.update.bind(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
setText(newText) {
|
||||||
|
const oldText = this.el.innerText
|
||||||
|
const length = Math.max(oldText.length, newText.length)
|
||||||
|
const promise = new Promise((resolve) => this.resolve = resolve)
|
||||||
|
this.queue = []
|
||||||
|
for (let i = 0; i < length; i++) {
|
||||||
|
const from = oldText[i] || ''
|
||||||
|
const to = newText[i] || ''
|
||||||
|
const start = Math.floor(Math.random() * 40)
|
||||||
|
const end = start + Math.floor(Math.random() * 40)
|
||||||
|
this.queue.push({from, to, start, end})
|
||||||
|
}
|
||||||
|
cancelAnimationFrame(this.frameRequest)
|
||||||
|
this.frame = 0
|
||||||
|
this.update()
|
||||||
|
return promise
|
||||||
|
}
|
||||||
|
|
||||||
|
update() {
|
||||||
|
let output = ''
|
||||||
|
let complete = 0
|
||||||
|
for (let i = 0, n = this.queue.length; i < n; i++) {
|
||||||
|
let {from, to, start, end, char} = this.queue[i]
|
||||||
|
if (this.frame >= end) {
|
||||||
|
complete++
|
||||||
|
output += to
|
||||||
|
} else if (this.frame >= start) {
|
||||||
|
if (!char || Math.random() < 0.28) {
|
||||||
|
char = this.randomChar()
|
||||||
|
this.queue[i].char = char
|
||||||
|
}
|
||||||
|
output += `<span class="dud">${char}</span>`
|
||||||
|
} else {
|
||||||
|
output += from
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.el.innerHTML = output
|
||||||
|
if (complete === this.queue.length) {
|
||||||
|
this.resolve()
|
||||||
|
} else {
|
||||||
|
this.frameRequest = requestAnimationFrame(this.update)
|
||||||
|
this.frame++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
randomChar() {
|
||||||
|
return this.chars[Math.floor(Math.random() * this.chars.length)]
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
<template>
|
||||||
|
<div v-if="active">
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
<div v-else class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
<div>
|
||||||
|
<slot name="lock">
|
||||||
|
<p v-if="name">Click to load external content from {{ name }}.</p>
|
||||||
|
<p v-else>Click to load external content.</p>
|
||||||
|
</slot>
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-primary" @click="active = true">load content</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "ExternalContentWrapper",
|
||||||
|
props: {
|
||||||
|
name: String,
|
||||||
|
},
|
||||||
|
data: () => ({
|
||||||
|
active: false,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
@ -0,0 +1,23 @@
|
|||||||
|
<template>
|
||||||
|
<ul>
|
||||||
|
<li v-for="page of $site.pages
|
||||||
|
.filter(page => page.regularPath.match(new RegExp(`^${ path }.`)))
|
||||||
|
.slice(0, limit)
|
||||||
|
">
|
||||||
|
<router-link :to="page.regularPath">{{ page.title }}</router-link>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "FolderList",
|
||||||
|
props: {
|
||||||
|
path: String,
|
||||||
|
limit: {
|
||||||
|
type: Number,
|
||||||
|
default: 8,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
@ -0,0 +1,36 @@
|
|||||||
|
<template>
|
||||||
|
<div class="SocialIcons row">
|
||||||
|
<a class="col-auto btn bi-github" href="https://github.com/adb-sh/" target="_blank" rel="noopener noreferrer" />
|
||||||
|
<a class="col-auto btn bi-git" href="https://git.adb.sh" target="_blank" rel="noopener noreferrer" />
|
||||||
|
<a class="col-auto btn bi-mastodon" href="https://social.cybre.town" target="_blank" rel="noopener noreferrer" />
|
||||||
|
<a class="col-auto btn bi-instagram" href="https://www.instagram.com/me.adb.sh" target="_blank" rel="noopener noreferrer" />
|
||||||
|
<a class="col-auto btn bi-spotify" href="https://open.spotify.com/user/op3q884heqao7laioz05ebaoz" target="_blank" rel="noopener noreferrer" />
|
||||||
|
<a class="col-auto btn bi-youtube" href="https://www.youtube.com/channel/UCoxRdN8T4aCR8tqDpOJAjOQ" target="_blank" rel="noopener noreferrer" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.SocialIcons {
|
||||||
|
position: relative;
|
||||||
|
user-select: none;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
a.btn {
|
||||||
|
font-size: 2.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.social_icons > div {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
height: min-content;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo-img {
|
||||||
|
fill: #fff;
|
||||||
|
height: 3rem;
|
||||||
|
margin: .75rem;
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,19 @@
|
|||||||
|
<template>
|
||||||
|
<div class="StickyWrapper">
|
||||||
|
<div class="content">
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.StickyWrapper {
|
||||||
|
position: relative;
|
||||||
|
height: 100vh;
|
||||||
|
.content {
|
||||||
|
position: sticky;
|
||||||
|
top: 50%;
|
||||||
|
transform: translate(0, -50%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,37 @@
|
|||||||
|
<script>
|
||||||
|
import { TextScramble } from "../TextScramble.mjs";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
phrases: Array,
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
const el = this.$refs.TextScramble;
|
||||||
|
const fx = new TextScramble(el);
|
||||||
|
|
||||||
|
let counter = 0
|
||||||
|
const next = () => {
|
||||||
|
fx.setText(this.phrases[counter]).then(() => setTimeout(next, 600));
|
||||||
|
counter = (counter + 1) % this.phrases.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="TextScramble my-4" ref="TextScramble"></div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.TextScramble {
|
||||||
|
font-size: 2.5rem;
|
||||||
|
font-weight: lighter;
|
||||||
|
font-family: "Roboto Thin", monospace;
|
||||||
|
text-align: center;
|
||||||
|
.dud {
|
||||||
|
color: #166161;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,50 @@
|
|||||||
|
module.exports = {
|
||||||
|
title: '0xADB',
|
||||||
|
description: 'Welcome to adb.sh',
|
||||||
|
head: [
|
||||||
|
['meta', { name: 'theme-color', content: '#3eaf7c' }],
|
||||||
|
['meta', { name: 'apple-mobile-web-app-capable', content: 'yes' }],
|
||||||
|
['meta', { name: 'apple-mobile-web-app-status-bar-style', content: 'black' }]
|
||||||
|
],
|
||||||
|
markdown: {
|
||||||
|
anchor: { permalink: false },
|
||||||
|
extendMarkdown: md => {
|
||||||
|
md.set({ breaks: true });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dest: "./dist",
|
||||||
|
themeConfig: {
|
||||||
|
repo: '',
|
||||||
|
editLinks: false,
|
||||||
|
docsDir: '',
|
||||||
|
editLinkText: '',
|
||||||
|
lastUpdated: false,
|
||||||
|
searchMaxSuggestions: 10,
|
||||||
|
test: [/.+.md/],
|
||||||
|
nav: [
|
||||||
|
{
|
||||||
|
text: 'projects',
|
||||||
|
link: '/projects',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'music',
|
||||||
|
link: '/music',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
sidebar: {
|
||||||
|
'/guide/': [
|
||||||
|
{
|
||||||
|
title: 'Guide',
|
||||||
|
collapsable: false,
|
||||||
|
children: [
|
||||||
|
'',
|
||||||
|
'using-vue',
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
'@vuepress/plugin-search',
|
||||||
|
],
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
import { ThemeConfig } from 'bootstrap-darkmode';
|
||||||
|
|
||||||
|
export const themeConfig = new ThemeConfig();
|
||||||
|
themeConfig.initTheme();
|
||||||
|
|
||||||
|
const matchPath = /(?<path>|.+)\/(?<filename>[-_\w]+)(?<filetype>|\/|\.html|\.md)$/;
|
||||||
|
|
||||||
|
export default ({
|
||||||
|
Vue, // the version of Vue being used in the VuePress app
|
||||||
|
options, // the options for the root Vue instance
|
||||||
|
router, // the router instance for the app
|
||||||
|
siteData // site metadata
|
||||||
|
}) => {
|
||||||
|
router.beforeEach((to, from, next) => {
|
||||||
|
if (!to.name) {
|
||||||
|
const { filename } = to.fullPath.match(matchPath).groups;
|
||||||
|
next(
|
||||||
|
siteData.pages
|
||||||
|
.find((page) => page.regularPath.match(matchPath)?.groups?.filename === filename)
|
||||||
|
?.regularPath
|
||||||
|
);
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
};
|
@ -0,0 +1,66 @@
|
|||||||
|
<template>
|
||||||
|
<section class="layout">
|
||||||
|
<header>
|
||||||
|
<div class="bg-darkmode-dark shadow">
|
||||||
|
<site-header class="container" />
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main class="content">
|
||||||
|
<div v-if="$page.frontmatter?.sidebar" class="container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xl-4 p-4">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<b>/{{ $page.path.split('/')[1] }}/</b>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<FolderList :path="`/${$page.path.split('/')[1]}/`" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Content class="col-xl p-4" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<div class="container">
|
||||||
|
<Content class="p-4" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer class="footer my-3">
|
||||||
|
<site-footer class="container" />
|
||||||
|
</footer>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import SiteHeader from "./SiteHeader";
|
||||||
|
import SiteFooter from "./SiteFooter";
|
||||||
|
import FolderList from "../components/FolderList";
|
||||||
|
|
||||||
|
import "bootstrap-icons/font/bootstrap-icons.scss";
|
||||||
|
import "./main.scss";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: { SiteFooter, SiteHeader, FolderList },
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
header {
|
||||||
|
position: fixed;
|
||||||
|
z-index: 10;
|
||||||
|
width: 100%;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
}
|
||||||
|
main {
|
||||||
|
padding: 8rem 0 2rem 0;
|
||||||
|
.sticky-sidebar {
|
||||||
|
position: sticky;
|
||||||
|
top: 4rem;
|
||||||
|
}
|
||||||
|
background-color: #1f262b;
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,14 @@
|
|||||||
|
<template>
|
||||||
|
<div class="m-4">
|
||||||
|
<h1>404 Not Found</h1>
|
||||||
|
<router-link class="btn btn-primary" to="/">Zur Startseite</router-link>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import "bootstrap/scss/bootstrap.scss";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "NotFound"
|
||||||
|
}
|
||||||
|
</script>
|
@ -0,0 +1,7 @@
|
|||||||
|
<template>
|
||||||
|
<div class="footer border-top py-2">
|
||||||
|
<span class="copyright">Copyright © {{ (new Date).getFullYear() }} Alban David Becker</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped></style>
|
@ -0,0 +1,66 @@
|
|||||||
|
<template>
|
||||||
|
<nav class="navbar px-4">
|
||||||
|
<router-link class="btn d-flex" to="/">
|
||||||
|
<div class="flex-column justify-content-center">
|
||||||
|
<b>{{ $site.title }}</b>
|
||||||
|
</div>
|
||||||
|
</router-link>
|
||||||
|
<div class="row align-items-center">
|
||||||
|
<SearchBox class="col-auto" />
|
||||||
|
<div v-for="nav of $site.themeConfig.nav" class="col-auto d-none d-xl-block">
|
||||||
|
<div v-if="nav.children || nav.path" class="category dropdown">
|
||||||
|
<router-link :to="nav.link" class="link btn">{{ nav.text }} <i class="bi-chevron-down" /></router-link>
|
||||||
|
<div class="dropdown-menu">
|
||||||
|
<router-link
|
||||||
|
v-for="site of (nav.children ?? [])
|
||||||
|
.concat(nav.path
|
||||||
|
? $site.pages
|
||||||
|
.filter(page => page.regularPath.match(new RegExp(`${nav.path}.`)))
|
||||||
|
.map(page => ({ text: page.title, link: page.regularPath }))
|
||||||
|
: []
|
||||||
|
)
|
||||||
|
"
|
||||||
|
:to="site.link"
|
||||||
|
class="dropdown-item"
|
||||||
|
>
|
||||||
|
{{ site.text }}
|
||||||
|
</router-link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-else class="site">
|
||||||
|
<router-link :to= "nav.link" class="link btn">{{ nav.text }}</router-link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import SearchBox from "@vuepress/plugin-search/SearchBox";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: { SearchBox },
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.header-title {
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-img {
|
||||||
|
height: 3.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown:hover .dropdown-menu {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-item {
|
||||||
|
}
|
||||||
|
|
||||||
|
.link {
|
||||||
|
color: rgb(27, 29, 29);
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
@ -0,0 +1,19 @@
|
|||||||
|
$dark-body-bg: #1f262b;
|
||||||
|
|
||||||
|
@import "bootstrap/scss/bootstrap";
|
||||||
|
@import "bootstrap-darkmode/scss/darktheme";
|
||||||
|
|
||||||
|
img {
|
||||||
|
max-width: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
@extend .table;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-box{
|
||||||
|
input {
|
||||||
|
background-color: $dark !important;
|
||||||
|
color: $light !important;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
---
|
||||||
|
home: true
|
||||||
|
---
|
||||||
|
<StickyWrapper>
|
||||||
|
<TextScramble :phrases="[
|
||||||
|
'Hey!',
|
||||||
|
'Welcome to adb.sh :D',
|
||||||
|
'I do web development', 'hosting free services', 'DJing / music', 'electronics'
|
||||||
|
]" />
|
||||||
|
<SocialIcons />
|
||||||
|
</StickyWrapper>
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
## services, i'm hosting
|
||||||
|
|
||||||
|
### public services
|
||||||
|
|
||||||
|
| service | URL |
|
||||||
|
| - | - |
|
||||||
|
| git | [git.cybre.town](https://git.cybre.town) |
|
||||||
|
| Mastodon | [social.cybre.town](https://social.cybre.town) |
|
||||||
|
| HedgeDoc | [md.cybre.town](https://md.cybre.town) |
|
||||||
|
| Jitsi | [jitsi.adb.sh](https://jitsi.adb.sh) |
|
||||||
|
| Frama Date | [polls.cybre.town](https://polls.cybre.town) |
|
||||||
|
| Searx | [searx.cybre.town](https://searx.cybre.town) |
|
||||||
|
|
||||||
|
### private services
|
||||||
|
|
||||||
|
| service | URL |
|
||||||
|
| - | - |
|
||||||
|
| nextcloud | [cloud.adb.sh](https://git.cybre.town) |
|
||||||
|
| matrix | [element.adb.sh](https://element.adb.sh) |
|
||||||
|
| mail | [mail.adb.sh](https://mail.adb.sh) |
|
||||||
|
|
||||||
|
|
||||||
|
## contact me
|
||||||
|
|
||||||
|
- matrix: [@adb:adb.sh](https://matrix.to/#/@adb:adb.sh)
|
||||||
|
- mail: [info@adb.sh](mailto:info@adb.sh)
|
@ -0,0 +1,14 @@
|
|||||||
|
# Music
|
||||||
|
|
||||||
|
i do music n stuff
|
||||||
|
|
||||||
|
## DJ sets
|
||||||
|
### Techno
|
||||||
|
<ExternalContentWrapper name="YouTube">
|
||||||
|
<iframe width="100%" height="auto" src="https://www.youtube-nocookie.com/embed/A0nvVXpzJD8" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
|
||||||
|
</ExternalContentWrapper>
|
||||||
|
|
||||||
|
### Melodic Techno
|
||||||
|
<ExternalContentWrapper name="YouTube">
|
||||||
|
<iframe width="100%" height="auto" src="https://www.youtube-nocookie.com/embed/6bOJGkaX_5s" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
|
||||||
|
</ExternalContentWrapper>
|
@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
sidebar: true
|
||||||
|
---
|
||||||
|
|
||||||
|
# ArtNet-Node
|
||||||
|
|
||||||
|
Art-Net to DMX PCB
|
@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
sidebar: true
|
||||||
|
---
|
||||||
|
|
||||||
|
# Projects
|
||||||
|
|
||||||
|
<FolderList path="/projects/" />
|
@ -0,0 +1,13 @@
|
|||||||
|
---
|
||||||
|
sidebar: true
|
||||||
|
---
|
||||||
|
|
||||||
|
# **[chat]** *matrix-chat*
|
||||||
|
|
||||||
|
a simple matrix webapp for mobile and desktop
|
||||||
|
|
||||||
|
![matrix-chat screenshot](https://chat.adb.sh/media/screenshot-desktop.png)
|
||||||
|
|
||||||
|
- stack: Vue3, matrix-js-sdk
|
||||||
|
- matrix.org: [matrix.org](https://matrix.org/docs/projects/client/chat)
|
||||||
|
- repo: [git.adb.sh](https://git.adb.sh/adb/matrix-chat)
|
@ -0,0 +1,11 @@
|
|||||||
|
---
|
||||||
|
sidebar: true
|
||||||
|
---
|
||||||
|
|
||||||
|
# My Server Rack
|
||||||
|
|
||||||
|
I'm running my services on my own server, because it's fun :D
|
||||||
|
|
||||||
|
![server rack](https://social.cybre.town/system/media_attachments/files/106/116/563/016/082/536/original/968136dcb22aca7e.jpg)
|
||||||
|
|
||||||
|
My main server is a HP ProLiant DL380 G8.
|
@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
sidebar: true
|
||||||
|
---
|
||||||
|
|
||||||
|
# vuedav
|
||||||
|
|
||||||
|
a simple webdav client in Vue3
|
||||||
|
|
||||||
|
- stack: Vue3, nginx, docker, nodejs, typescript
|
||||||
|
- repo: [git.adb.sh](https://git.adb.sh/adb/vuedav)
|
Loading…
Reference in New Issue