update content; add fonts; add ParticleNetworkAnimation

2.0
adb-sh 2 years ago
parent ac9ae16067
commit f0c6b1fdce

@ -0,0 +1,315 @@
/**
* Particle Network Animation https://codepen.io/franky/pen/LGMWPK
* Inspiration: https://github.com/JulianLaval/canvas-particle-network
*/
class ParticleNetworkAnimation {
constructor(element, options) {
this.$el = element;
this.container = element;
//this.canvas = document.createElement('canvas');
this.canvas = element;
this.sizeCanvas();
//this.container.appendChild(this.canvas);
this.ctx = this.canvas.getContext('2d');
this.particleNetwork = new ParticleNetwork(this, options);
this.bindUiActions();
return this;
}
bindUiActions() {
window.addEventListener('resize', () => {
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
this.sizeCanvas();
this.particleNetwork.createParticles();
});
}
sizeCanvas() {
this.canvas.width = this.container.offsetWidth;
this.canvas.height = this.container.offsetHeight;
}
}
class Particle{
constructor(parent, x, y) {
this.network = parent;
this.canvas = parent.canvas;
this.ctx = parent.ctx;
this.particleColor = returnRandomArrayitem(this.network.options.particleColors);
this.radius = getLimitedRandom(1.5, 2.5);
this.opacity = 0;
this.x = x || Math.random() * this.canvas.width;
this.y = y || Math.random() * this.canvas.height;
this.velocity = {
x: (Math.random() - 0.5) * parent.options.velocity,
y: (Math.random() - 0.5) * parent.options.velocity
};
}
update(){
if (this.opacity < 1) {
this.opacity += 0.01;
} else {
this.opacity = 1;
}
// Change dir if outside map
if (this.x > this.canvas.width + 100 || this.x < -100) {
this.velocity.x = -this.velocity.x;
}
if (this.y > this.canvas.height + 100 || this.y < -100) {
this.velocity.y = -this.velocity.y;
}
// Update position
this.x += this.velocity.x;
this.y += this.velocity.y;
}
draw(){
// Draw particle
this.ctx.beginPath();
this.ctx.fillStyle = this.particleColor;
this.ctx.globalAlpha = this.opacity;
this.ctx.arc(this.x, this.y, this.radius, 0, 2 * Math.PI);
this.ctx.fill();
}
}
class ParticleNetwork{
constructor(parent, options = {
velocity: 2, // the higher the faster
density: 10000, // the lower the denser
netLineDistance: 200,
netLineColor: '#929292',
particleColors: ['#aaa'] // ['#6D4E5C', '#aaa', '#FFC458' ]
}) {
this.options = options;
this.canvas = parent.canvas;
this.ctx = parent.ctx;
this.init();
}
init(){
// Create particle objects
this.createParticles(false);
// Update canvas
this.animationFrame = requestAnimationFrame(this.update.bind(this));
this.bindUiActions();
}
createParticles(isInitial) {
// Initialise / reset particles
let me = this;
this.particles = [];
let quantity = this.canvas.width * this.canvas.height / this.options.density;
if (isInitial) {
let counter = 0;
clearInterval(this.createIntervalId);
this.createIntervalId = setInterval(function() {
if (counter < quantity - 1) {
// Create particle object
this.particles.push(new Particle(this));
}
else {
clearInterval(me.createIntervalId);
}
counter++;
}.bind(this), 250);
}
else {
// Create particle objects
for (let i = 0; i < quantity; i++) {
this.particles.push(new Particle(this));
}
}
}
createInteractionParticle() {
// Add interaction particle
this.interactionParticle = new Particle(this);
this.interactionParticle.velocity = {
x: 0,
y: 0
};
this.particles.push(this.interactionParticle);
return this.interactionParticle;
}
removeInteractionParticle() {
// Find it
let index = this.particles.indexOf(this.interactionParticle);
if (index > -1) {
// Remove it
this.interactionParticle = undefined;
this.particles.splice(index, 1);
}
}
update() {
if (this.canvas) {
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
this.ctx.globalAlpha = 1;
// Draw connections
for (let i = 0; i < this.particles.length; i++) {
for (let j = this.particles.length - 1; j > i; j--) {
let distance, p1 = this.particles[i], p2 = this.particles[j];
// check very simply if the two points are even a candidate for further measurements
distance = Math.min(Math.abs(p1.x - p2.x), Math.abs(p1.y - p2.y));
if (distance > this.options.netLineDistance) {
continue;
}
// the two points seem close enough, now let's measure precisely
distance = Math.sqrt(
Math.pow(p1.x - p2.x, 2) +
Math.pow(p1.y - p2.y, 2)
);
if (distance > this.options.netLineDistance) {
continue;
}
this.ctx.beginPath();
this.ctx.strokeStyle = this.options.netLineColor;
this.ctx.globalAlpha = (this.options.netLineDistance - distance) / this.options.netLineDistance * p1.opacity * p2.opacity;
this.ctx.lineWidth = 0.7;
this.ctx.moveTo(p1.x, p1.y);
this.ctx.lineTo(p2.x, p2.y);
this.ctx.stroke();
}
}
// Draw particles
this.particles.forEach(k => {
k.update();
k.draw();
})
if (this.options.velocity !== 0) {
this.animationFrame = requestAnimationFrame(this.update.bind(this));
}
}
else {
cancelAnimationFrame(this.animationFrame);
}
}
bindUiActions() {
// Mouse / touch event handling
this.spawnQuantity = 3;
this.mouseIsDown = false;
this.touchIsMoving = false;
this.onMouseMove = function(e) {
if (!this.interactionParticle) {
this.createInteractionParticle();
}
this.interactionParticle.x = e.offsetX;
this.interactionParticle.y = e.offsetY;
}.bind(this);
this.onTouchMove = function(e) {
e.preventDefault();
this.touchIsMoving = true;
if (!this.interactionParticle) {
this.createInteractionParticle();
}
this.interactionParticle.x = e.changedTouches[0].clientX;
this.interactionParticle.y = e.changedTouches[0].clientY;
}.bind(this);
this.onMouseDown = function() {
this.mouseIsDown = true;
let counter = 0;
let quantity = this.spawnQuantity;
let intervalId = setInterval(function() {
if (this.mouseIsDown) {
if (counter === 1) {
quantity = 1;
}
for (let i = 0; i < quantity; i++) {
if (this.interactionParticle) {
this.particles.push(new Particle(this, this.interactionParticle.x, this.interactionParticle.y));
}
}
}
else {
clearInterval(intervalId);
}
counter++;
}.bind(this), 50);
}.bind(this);
this.onTouchStart = function(e) {
e.preventDefault();
setTimeout(function() {
if (!this.touchIsMoving) {
for (let i = 0; i < this.spawnQuantity; i++) {
this.particles.push(new Particle(this, e.changedTouches[0].clientX, e.changedTouches[0].clientY));
}
}
}.bind(this), 200);
}.bind(this);
this.onMouseUp = function() {
this.mouseIsDown = false;
}.bind(this);
this.onMouseOut = function() {
this.removeInteractionParticle();
}.bind(this);
this.onTouchEnd = function(e) {
e.preventDefault();
this.touchIsMoving = false;
this.removeInteractionParticle();
}.bind(this);
this.canvas.addEventListener('mousemove', this.onMouseMove);
this.canvas.addEventListener('touchmove', this.onTouchMove);
//this.canvas.addEventListener('mousedown', this.onMouseDown);
this.canvas.addEventListener('touchstart', this.onTouchStart);
this.canvas.addEventListener('mouseup', this.onMouseUp);
this.canvas.addEventListener('mouseout', this.onMouseOut);
this.canvas.addEventListener('touchend', this.onTouchEnd);
}
unbindUiActions() {
if (this.canvas) {
this.canvas.removeEventListener('mousemove', this.onMouseMove);
this.canvas.removeEventListener('touchmove', this.onTouchMove);
this.canvas.removeEventListener('mousedown', this.onMouseDown);
this.canvas.removeEventListener('touchstart', this.onTouchStart);
this.canvas.removeEventListener('mouseup', this.onMouseUp);
this.canvas.removeEventListener('mouseout', this.onMouseOut);
this.canvas.removeEventListener('touchend', this.onTouchEnd);
}
}
}
let getLimitedRandom = function(min, max, roundToInteger) {
let number = Math.random() * (max - min) + min;
if (roundToInteger) {
number = Math.round(number);
}
return number;
};
let returnRandomArrayitem = function(array) {
return array[Math.floor(Math.random()*array.length)];
};
export {
ParticleNetworkAnimation
};

@ -0,0 +1,122 @@
<template>
<div class="particle-network-animation">
<canvas ref="pna" ></canvas>
<slot />
</div>
</template>
<script>
import { ParticleNetworkAnimation } from '../ParticleNetworkAnimation';
export default {
name: 'BannerWrapperNetwork',
props: {
options: {
type: Object,
default: () => ({
velocity: 0.5, // the higher the faster
density: 30000, // the lower the denser
netLineDistance: 120,
netLineColor: '#ccc',
particleColors: ['#ccc']
}),
},
},
mounted(){
new ParticleNetworkAnimation(this.$refs.pna, this.options);
},
};
</script>
<style scoped lang="scss">
.particle-network-animation {
position: relative;
top: 0;
left: 0;
right: 0;
box-shadow: var(--shadow200);
&.white{
background-color: #fff;
}
&.no-shadow{
box-shadow: none;
}
&::before {
z-index: -2;
content: '';
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-position: center center;
background-size: cover;
opacity: 0.2;
}
canvas{
position: absolute;
height: 100%;
width: 100%;
top: 0;
left: 0;
}
.wrapper{
//pointer-events: none;
}
}
.glow {
z-index: -1;
position: fixed;
top: 50%;
left: 50%;
background-image: radial-gradient(circle closest-side, rgba(255, 255, 255, 0.025), transparent);
}
$duration: 25s;
.glow-1 {
width: 150vw;
height: 150vh;
margin-top: -75vh;
margin-left: -75vw;
animation: glow-1-move $duration linear infinite both;
}
@keyframes glow-1-move {
from {
transform: translate(-100%, 100%);
}
to {
transform: translate(100%, -100%);
}
}
.glow-2 {
width: 100vw;
height: 100vh;
margin-top: -50vh;
margin-left: -50vw;
animation: glow-2-move $duration linear $duration / 3 infinite both;
}
@keyframes glow-2-move {
from {
transform: translate(-100%, 0%);
}
to {
transform: translate(100%, 100%);
}
}
.glow-3 {
width: 120vw;
height: 120vh;
margin-top: -60vh;
margin-left: -60vw;
animation: glow-3-move $duration linear $duration / 3 * 2 infinite both;
}
@keyframes glow-3-move {
from {
transform: translate(100%, 100%);
}
to {
transform: translate(0%, -100%);
}
}
</style>

@ -1,11 +1,16 @@
<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>
<slot
v-for="page of $site.pages
.filter(page => page.regularPath.match(new RegExp(`^${ path }.`)))
.slice(0, limit)
"
:page="page"
>
<li>
<router-link :to="page.regularPath">{{ page.title }}</router-link>
</li>
</slot>
</ul>
</template>

@ -0,0 +1,29 @@
<template>
<div>
<div class="row">
<StickyWrapper class="col-auto mx-4">
<router-link to="/projects" class="btn btn-outline-light">Projects</router-link>
</StickyWrapper>
<div class="col">
<FolderList path="/projects/" v-slot="{ page }">
<div class="card m-2">
<div class="card-header"><router-link :to="page.regularPath">{{ page.title }}</router-link></div>
<div class="card-body">
{{ page.frontmatter.excerpt }}
</div>
</div>
</FolderList>
</div>
</div>
</div>
</template>
<script>
export default {
name: "HomeContent"
}
</script>
<style scoped>
</style>

@ -1,7 +1,7 @@
<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-git" href="https://git.cybre.town/adb" target="_blank" rel="noopener noreferrer" />
<a class="col-auto btn bi-mastodon" href="https://social.cybre.town/@adb" 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" />
@ -17,7 +17,8 @@
display: flex;
justify-content: center;
a.btn {
font-size: 2.5rem;
font-size: calc(1.5rem + 1vw);
max-font-size: 2.5rem;
}
}

@ -26,10 +26,11 @@ export default {
<style lang="scss">
.TextScramble {
font-size: 2.5rem;
font-weight: lighter;
font-family: "Roboto Thin", monospace;
font-size: calc(1.5rem + 1vw);
max-font-size: 2.5rem;
text-align: center;
font-family: "Roboto Mono", monospace;
font-weight: 100;
.dud {
color: #166161;
}

@ -10,16 +10,16 @@
<div v-if="$page.frontmatter?.sidebar" class="container">
<div class="row">
<div class="col-xl-4 p-4">
<div class="card">
<div class="card toc">
<div class="card-header">
<b>/{{ $page.path.split('/')[1] }}/</b>
<router-link :to="`/${$page.path.split('/')[1]}/`"><b>/{{ $page.path.split('/')[1] }}/</b></router-link>
</div>
<div class="card-body">
<FolderList :path="`/${$page.path.split('/')[1]}/`" />
</div>
</div>
</div>
<Content class="col-xl p-4" />
<Content class="col-xl-8 p-4" />
</div>
</div>
<div v-else>
@ -43,6 +43,8 @@ import FolderList from "../components/FolderList";
import "bootstrap-icons/font/bootstrap-icons.scss";
import "./main.scss";
import "@vuepress/theme-default/styles/code.styl";
export default {
components: { SiteFooter, SiteHeader, FolderList },
};
@ -56,11 +58,11 @@ header {
font-size: 1.2rem;
}
main {
padding: 8rem 0 2rem 0;
.sticky-sidebar {
padding: 5rem 0 2rem 0;
background-color: #1f262b;
.toc {
position: sticky;
top: 4rem;
top: 5rem;
}
background-color: #1f262b;
}
</style>

@ -0,0 +1,19 @@
/* roboto-mono-100 - latin */
@font-face {
font-family: 'Roboto Mono';
font-style: normal;
font-weight: 100;
src: local(''),
url('../assets/fonts/roboto-mono-v22-latin-100.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
url('../assets/fonts/roboto-mono-v22-latin-100.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
}
/* roboto-mono-regular - latin */
@font-face {
font-family: 'Roboto Mono';
font-style: normal;
font-weight: 400;
src: local(''),
url('../assets/fonts/roboto-mono-v22-latin-regular.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
url('../assets/fonts/roboto-mono-v22-latin-regular.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
}

@ -2,6 +2,10 @@ $dark-body-bg: #1f262b;
@import "bootstrap/scss/bootstrap";
@import "bootstrap-darkmode/scss/darktheme";
@import "fonts.css";
html, body {
background-color: $dark-body-bg;
@ -9,6 +13,7 @@ html, body {
img {
max-width: 100% !important;
border-radius: .25rem;
}
table {
@ -21,3 +26,13 @@ table {
color: $light !important;
}
}
h1, h2, h3, h4, h5 {
margin-top: 1em;
}
:not(pre) > code {
background-color: #aaa2;
border-radius: .4rem;
padding: .2rem .4rem;
}

@ -1,18 +1,22 @@
---
home: true
---
<StickyWrapper>
<TextScramble :phrases="[
'Hey!',
'Welcome to adb.sh :D',
'I do web development', 'hosting free services', 'DJing / music', 'electronics'
]" />
<SocialIcons />
<div class="row my-4 justify-content-center">
<router-link class="col-auto mx-2 btn btn-outline-light" to="/music" >music</router-link>
<router-link class="col-auto mx-2 btn btn-outline-light" to="/projects" >projects</router-link>
<BannerWrapperNetwork>
<div>
<StickyWrapper>
<TextScramble :phrases="[
'Hey!',
'Welcome to adb.sh :D',
'I do web development', 'networking / hosting', 'electronics', 'DJing / music',
]" />
<SocialIcons />
<div class="row my-4 justify-content-center">
<router-link class="col-auto mx-2 btn btn-outline-light" to="/projects" >projects</router-link>
<router-link class="col-auto mx-2 btn btn-outline-light" to="/music" >music</router-link>
</div>
</StickyWrapper>
</div>
</StickyWrapper>
</BannerWrapperNetwork>
----
@ -35,7 +39,7 @@ home: true
| service | URL |
| - | - |
| Nextcloud | [cloud.adb.sh](https://git.cybre.town) |
| Nextcloud | [cloud.adb.sh](https://cloud.adb.sh) |
| Matrix | [element.adb.sh](https://element.adb.sh) |
| Mail | [mail.adb.sh](https://mail.adb.sh) |
| Gotify UP | [push.cybre.town](https://push.cybre.town) |
@ -44,6 +48,7 @@ home: true
| service | URL |
| - | - |
| Cybre Town | [cybre.town](https://cybre.town) |
| Strobe Town | [strobe.town](https://strobe.town) |
| Strobe Town - Tickets (Pretix) | [tickets.strobe.town](https://tickets.strobe.town) |
| Strobe Town - Music (Funkwhale) | [music.strobe.town](https://music.strobe.town) |
@ -52,3 +57,14 @@ home: true
- Matrix: [@adb:adb.sh](https://matrix.to/#/@adb:adb.sh)
- Mail: info [at] this.domain
<script>
import StickyWrapper from "../.vuepress/components/StickyWrapper";
export default {
components: {StickyWrapper}
}
</script>

@ -5,10 +5,14 @@ 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>
<iframe width="100%" height="540" 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>
watch on [YouTube](https://youtu.be/A0nvVXpzJD8)
### 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>
<iframe width="100%" height="540" 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>
watch on [YouTube](https://youtu.be/6bOJGkaX_5s)

@ -1,5 +1,7 @@
---
sidebar: true
excerpt: "Art-Net to DMX PCB"
imgUrl: "https://social.cybre.town/system/media_attachments/files/105/520/482/627/757/197/original/ba1084550d15d53f.jpeg"
---
# ArtNet-Node

@ -1,7 +1,13 @@
---
sidebar: true
---
# Projects
<FolderList path="/projects/" />
<FolderList path="/projects/" v-slot="{ page }" class="m-0 p-0">
<div class="card my-2">
<div class="card-header"><router-link :to="page.regularPath">{{ page.title }}</router-link></div>
<div class="card-body">
{{ page.frontmatter.excerpt }}
</div>
</div>
</FolderList>

@ -1,5 +1,7 @@
---
sidebar: true
excerpt: "a simple matrix webapp for mobile and desktop"
imgUrl: "https://chat.adb.sh/media/screenshot-desktop.png"
---
# **[chat]** *matrix-chat*

@ -1,5 +1,7 @@
---
sidebar: true
excerpt: "I'm running my services on my own server, because it's fun :D"
imgUrl: "https://social.cybre.town/system/media_attachments/files/106/116/563/016/082/536/original/968136dcb22aca7e.jpg"
---
# My Server Rack

@ -0,0 +1,126 @@
---
sidebar: true
excerpt: "a complete working docker-compose setup for the matrix synapse server with postgres"
---
# docker-compose matrix-synapse
a complete working docker-compose setup for the matrix synapse server with postgres
## clone the repo
```bash
git clone https://git.cybre.town/adb/docker-compose_matrix_synapse/
```
## create config files
* Change `your.domain` in the `create_config.sh` file and simply run the script from terminal.
* A temporary docker container will be created, that will configure the configs for you.
* You will find your finished configs at `/var/lib/docker/volumes/synapse-data/_data`.
* Copy this files to `./synapse_data/` in your docker-compose working directory.
for more details have a look at: [hub.docker.com/r/matrixdotorg/synapse](https://hub.docker.com/r/matrixdotorg/synapse)
## configure `./synapse_data/homserver.yaml`
### database
* comment the standard sqlite3 config
* just below add:
```yaml
database:
name: psycopg2
args:
user: matrix
password: your-secret-pw
database: synapse
host: db
cp_min: 5
cp_max: 10
```
* change the password
### registration
* to enable user registration comment out this line: `enable_registration: true`
## configure `docker-compose.yml`
* change the postgres password to the password you've set before.
## create docker containers
```bash
cd /your/docker-compose/working/directory
docker-compose -p matrix up -d
```
If you can see the congrats page at `http://127.0.0.1:8008/` everything is working. This might take a few minutes, as the database has to be created.
## nginx config
To manage SSL/TLS I'm using nginx.
Just add another path to your working SSL v-host server, like this:
```nginx
#matrix server
#For the federation port
listen 8448 ssl default_server;
listen [::]:8448 ssl default_server;
location /_matrix {
proxy_pass http://127.0.0.1:8008;
proxy_set_header X-Forwarded-For $remote_addr;
# Nginx by default only allows file uploads up to 1M in size
# Increase client_max_body_size to match max_upload_size defined in homeserver.yaml
client_max_body_size 10M;
}
```
The full v-host server config might look like:
```nginx
server {
server_name your.domain;
#main web server
listen [::]:443 ssl ipv6only=on;
listen 443 ssl;
root /var/www/your.domain;
index index.html;
#matrix server
#For the federation port
listen 8448 ssl default_server;
listen [::]:8448 ssl default_server;
location /_matrix {
proxy_pass http://127.0.0.1:8008;
proxy_set_header X-Forwarded-For $remote_addr;
# Nginx by default only allows file uploads up to 1M in size
# Increase client_max_body_size to match max_upload_size defined in homeserver.yaml
client_max_body_size 10M;
}
ssl_certificate /etc/letsencrypt/live/your.domain/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/your.domain/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
}
server {
if ($host = your.domain) {
return 302 https://$host$request_uri;
}
listen 80;
listen [::]:80;
server_name your.domain;
return 404;
}
```
//and that's it, good luck :D

@ -1,5 +1,6 @@
---
sidebar: true
excerpt: "a simple webdav client in Vue3"
---
# vuedav

Loading…
Cancel
Save