update content; add fonts; add ParticleNetworkAnimation
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
|
||||
};
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -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>
|
@ -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>
|
@ -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+ */
|
||||
}
|
@ -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>
|
||||
|
@ -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
|
Loading…
Reference in New Issue