simulate Single Page App with websockets

This commit is contained in:
2023-01-29 18:04:16 -06:00
parent f99ad56e1d
commit 8b4a97bf73
11 changed files with 105 additions and 57 deletions

View File

@@ -7,7 +7,7 @@ server {
listen 8080; listen 8080;
server_name asimonson.com; server_name asimonson.com;
add_header Content-Security-Policy "default-src 'self' 'unsafe-inline' *.chesscomfiles.com *.chess.com *.googletagmanager.com cdn.jsdelivr.net www.google-analytics.com ajax.googleapis.com;"; add_header Content-Security-Policy "default-src 'self' 'unsafe-inline' *.cloudflare.com *.chesscomfiles.com *.chess.com *.googletagmanager.com cdn.jsdelivr.net www.google-analytics.com ajax.googleapis.com;";
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options 'nosniff'; add_header X-Content-Type-Options 'nosniff';
add_header X-Frame-Options 'SAMEORIGIN'; add_header X-Frame-Options 'SAMEORIGIN';

View File

@@ -1,3 +1,3 @@
[program:gunicorn] [program:gunicorn]
command=/usr/bin/gunicorn app:app -b localhost:5000 command=/usr/bin/gunicorn -k geventwebsocket.gunicorn.workers.GeventWebSocketWorker app:app -b localhost:5000
directory=/deploy/app directory=/deploy/app

View File

@@ -1,44 +1,62 @@
import flask import flask
from flask_minify import Minify from flask_minify import Minify
from flask_socketio import SocketIO
import json import json
proj = json.load(open('./static/json/projects.json', 'r')) proj = json.load(open("./static/json/projects.json", "r"))
timeline = json.load(open('./static/json/timeline.json', 'r')) timeline = json.load(open("./static/json/timeline.json", "r"))
pages = {
"home": {
"template": "home.html",
"title": "Andrew Simonson - Portfolio Home",
"description": "Andrew Simonson's Digital Portfolio home",
"canonical": "",
},
"projects": {
"template": "projects.html",
"projects": proj,
"title": "Andrew Simonson - Projects",
"description": "Recent projects by Andrew Simonson on his lovely portfolio website :)",
"canonical": "projects",
},
"about": {
"template": "about.html",
"timeline": timeline,
"title": "Andrew Simonson - About Me",
"description": "About Andrew Simonson",
"canonical": "about",
},
}
app = flask.Flask(__name__) app = flask.Flask(__name__)
Minify(app=app, html=True, js=True, cssless=True) Minify(app=app, html=True, js=True, cssless=True)
socketio = SocketIO(app)
@socketio.on("goto")
def goto(location):
sid = flask.request.sid
pagevars = pages[location]
output = [location, flask.render_template(pagevars["template"], var=pagevars), pagevars['title']]
socketio.emit("goto", output, to=sid)
@app.route("/") @app.route("/")
def home(): def home():
return flask.render_template( pagevars = pages["home"]
"home.html", return flask.render_template("header.html", var=pagevars)
title="Andrew Simonson - Portfolio Home",
description="Andrew Simonson's Digital portfolio home",
canonical="",
)
@app.route("/about")
def about():
return flask.render_template(
"about.html",
timeline=timeline,
title="Andrew Simonson - About Me",
description="About Andrew Simonson",
canonical="about",
)
@app.route("/projects") @app.route("/projects")
def projects(): def projects():
return flask.render_template( pagevars = pages["projects"]
"projects.html", return flask.render_template("header.html", var=pagevars)
projects=proj,
title="Andrew Simonson - Projects",
description="Recent projects by Andrew Simonson on his lovely portfolio website :)", @app.route("/about")
canonical="projects", def about():
) pagevars = pages["about"]
return flask.render_template("header.html", var=pagevars)
@app.route("/resume") @app.route("/resume")
@@ -54,9 +72,16 @@ def page404(e):
try: try:
message = e.length message = e.length
finally: finally:
pagevars = {
"template": "error.html",
"title": f"{eCode} - Simonson",
"description": "Error on Andrew Simonson's Digital Portfolio",
"canonical": "404",
}
return ( return (
flask.render_template( flask.render_template(
"error.html", "header.html",
var=pagevars,
error=eCode, error=eCode,
message=message, message=message,
title=f"{eCode} - Simonson Portfolio", title=f"{eCode} - Simonson Portfolio",
@@ -75,4 +100,4 @@ if __name__ == "__main__":
import sass import sass
sass.compile(dirname=("static/scss", "static/css"), output_style="compressed") sass.compile(dirname=("static/scss", "static/css"), output_style="compressed")
app.run(debug=True) socketio.run(app)

Binary file not shown.

View File

@@ -1 +1 @@
.line:not(:first-child){position:absolute;top:0;left:0}.line:nth-child(1){animation:clip 6000ms -600ms linear infinite,glitch1 2500ms -433ms linear infinite}@keyframes glitch1{0%{transform:translateX(0)}96%{transform:translateX(0);color:#fff}97%{transform:translateX(-1px);color:#4E9A26}98%{transform:translateX(4px);color:#AC1212}99%{transform:translateX(-1px);color:#fff}100%{transform:translateX(0)}}.line:nth-child(2){animation:clip 6000ms -1200ms linear infinite,glitch2 2500ms -234ms linear infinite}@keyframes glitch2{0%{transform:translateX(0)}96%{transform:translateX(0);color:#fff}97%{transform:translateX(-2px);color:#4E9A26}98%{transform:translateX(-1px);color:#AC1212}99%{transform:translateX(5px);color:#fff}100%{transform:translateX(0)}}.line:nth-child(3){animation:clip 6000ms -1800ms linear infinite,glitch3 2500ms -189ms linear infinite}@keyframes glitch3{0%{transform:translateX(0)}96%{transform:translateX(0);color:#fff}97%{transform:translateX(-4px);color:#4E9A26}98%{transform:translateX(2px);color:#AC1212}99%{transform:translateX(-2px);color:#fff}100%{transform:translateX(0)}}.line:nth-child(4){animation:clip 6000ms -2400ms linear infinite,glitch4 2500ms -105ms linear infinite}@keyframes glitch4{0%{transform:translateX(0)}96%{transform:translateX(0);color:#fff}97%{transform:translateX(-3px);color:#4E9A26}98%{transform:translateX(4px);color:#AC1212}99%{transform:translateX(1px);color:#fff}100%{transform:translateX(0)}}.line:nth-child(5){animation:clip 6000ms -3000ms linear infinite,glitch5 2500ms -89ms linear infinite}@keyframes glitch5{0%{transform:translateX(0)}96%{transform:translateX(0);color:#fff}97%{transform:translateX(-2px);color:#4E9A26}98%{transform:translateX(-2px);color:#AC1212}99%{transform:translateX(3px);color:#fff}100%{transform:translateX(0)}}.line:nth-child(6){animation:clip 6000ms -3600ms linear infinite,glitch6 2500ms -936ms linear infinite}@keyframes glitch6{0%{transform:translateX(0)}96%{transform:translateX(0);color:#fff}97%{transform:translateX(3px);color:#4E9A26}98%{transform:translateX(-4px);color:#AC1212}99%{transform:translateX(0px);color:#fff}100%{transform:translateX(0)}}.line:nth-child(7){animation:clip 6000ms -4200ms linear infinite,glitch7 2500ms -594ms linear infinite}@keyframes glitch7{0%{transform:translateX(0)}96%{transform:translateX(0);color:#fff}97%{transform:translateX(1px);color:#4E9A26}98%{transform:translateX(5px);color:#AC1212}99%{transform:translateX(-3px);color:#fff}100%{transform:translateX(0)}}.line:nth-child(8){animation:clip 6000ms -4800ms linear infinite,glitch8 2500ms -464ms linear infinite}@keyframes glitch8{0%{transform:translateX(0)}96%{transform:translateX(0);color:#fff}97%{transform:translateX(-2px);color:#4E9A26}98%{transform:translateX(5px);color:#AC1212}99%{transform:translateX(1px);color:#fff}100%{transform:translateX(0)}}.line:nth-child(9){animation:clip 6000ms -5400ms linear infinite,glitch9 2500ms -520ms linear infinite}@keyframes glitch9{0%{transform:translateX(0)}96%{transform:translateX(0);color:#fff}97%{transform:translateX(3px);color:#4E9A26}98%{transform:translateX(-2px);color:#AC1212}99%{transform:translateX(3px);color:#fff}100%{transform:translateX(0)}}.line:nth-child(10){animation:clip 6000ms -6000ms linear infinite,glitch10 2500ms -463ms linear infinite}@keyframes glitch10{0%{transform:translateX(0)}96%{transform:translateX(0);color:#fff}97%{transform:translateX(1px);color:#4E9A26}98%{transform:translateX(1px);color:#AC1212}99%{transform:translateX(-3px);color:#fff}100%{transform:translateX(0)}}@keyframes clip{0%{clip-path:polygon(0 100%, 100% 100%, 100% 120%, 0 120%)}100%{clip-path:polygon(0 -20%, 100% -20%, 100% 0%, 0 0)}} .line:not(:first-child){position:absolute;top:0;left:0}.line:nth-child(1){animation:clip 6000ms -600ms linear infinite,glitch1 2500ms -540ms linear infinite}@keyframes glitch1{0%{transform:translateX(0)}96%{transform:translateX(0);color:#fff}97%{transform:translateX(3px);color:#4E9A26}98%{transform:translateX(-3px);color:#AC1212}99%{transform:translateX(-3px);color:#fff}100%{transform:translateX(0)}}.line:nth-child(2){animation:clip 6000ms -1200ms linear infinite,glitch2 2500ms -210ms linear infinite}@keyframes glitch2{0%{transform:translateX(0)}96%{transform:translateX(0);color:#fff}97%{transform:translateX(1px);color:#4E9A26}98%{transform:translateX(-2px);color:#AC1212}99%{transform:translateX(-1px);color:#fff}100%{transform:translateX(0)}}.line:nth-child(3){animation:clip 6000ms -1800ms linear infinite,glitch3 2500ms -866ms linear infinite}@keyframes glitch3{0%{transform:translateX(0)}96%{transform:translateX(0);color:#fff}97%{transform:translateX(2px);color:#4E9A26}98%{transform:translateX(0px);color:#AC1212}99%{transform:translateX(4px);color:#fff}100%{transform:translateX(0)}}.line:nth-child(4){animation:clip 6000ms -2400ms linear infinite,glitch4 2500ms -60ms linear infinite}@keyframes glitch4{0%{transform:translateX(0)}96%{transform:translateX(0);color:#fff}97%{transform:translateX(-3px);color:#4E9A26}98%{transform:translateX(1px);color:#AC1212}99%{transform:translateX(1px);color:#fff}100%{transform:translateX(0)}}.line:nth-child(5){animation:clip 6000ms -3000ms linear infinite,glitch5 2500ms -221ms linear infinite}@keyframes glitch5{0%{transform:translateX(0)}96%{transform:translateX(0);color:#fff}97%{transform:translateX(0px);color:#4E9A26}98%{transform:translateX(-3px);color:#AC1212}99%{transform:translateX(-4px);color:#fff}100%{transform:translateX(0)}}.line:nth-child(6){animation:clip 6000ms -3600ms linear infinite,glitch6 2500ms -716ms linear infinite}@keyframes glitch6{0%{transform:translateX(0)}96%{transform:translateX(0);color:#fff}97%{transform:translateX(1px);color:#4E9A26}98%{transform:translateX(5px);color:#AC1212}99%{transform:translateX(-1px);color:#fff}100%{transform:translateX(0)}}.line:nth-child(7){animation:clip 6000ms -4200ms linear infinite,glitch7 2500ms -157ms linear infinite}@keyframes glitch7{0%{transform:translateX(0)}96%{transform:translateX(0);color:#fff}97%{transform:translateX(-1px);color:#4E9A26}98%{transform:translateX(-3px);color:#AC1212}99%{transform:translateX(-2px);color:#fff}100%{transform:translateX(0)}}.line:nth-child(8){animation:clip 6000ms -4800ms linear infinite,glitch8 2500ms -955ms linear infinite}@keyframes glitch8{0%{transform:translateX(0)}96%{transform:translateX(0);color:#fff}97%{transform:translateX(1px);color:#4E9A26}98%{transform:translateX(1px);color:#AC1212}99%{transform:translateX(-4px);color:#fff}100%{transform:translateX(0)}}.line:nth-child(9){animation:clip 6000ms -5400ms linear infinite,glitch9 2500ms -54ms linear infinite}@keyframes glitch9{0%{transform:translateX(0)}96%{transform:translateX(0);color:#fff}97%{transform:translateX(0px);color:#4E9A26}98%{transform:translateX(-3px);color:#AC1212}99%{transform:translateX(-1px);color:#fff}100%{transform:translateX(0)}}.line:nth-child(10){animation:clip 6000ms -6000ms linear infinite,glitch10 2500ms -857ms linear infinite}@keyframes glitch10{0%{transform:translateX(0)}96%{transform:translateX(0);color:#fff}97%{transform:translateX(3px);color:#4E9A26}98%{transform:translateX(1px);color:#AC1212}99%{transform:translateX(2px);color:#fff}100%{transform:translateX(0)}}@keyframes clip{0%{clip-path:polygon(0 100%, 100% 100%, 100% 120%, 0 120%)}100%{clip-path:polygon(0 -20%, 100% -20%, 100% 0%, 0 0)}}

View File

@@ -87,3 +87,26 @@ function toggleMenu() {
} }
} }
} }
let socket = io();
function emit(event) {
socket.emit(event);
}
function emitData(event, data) {
socket.emit(event, data)
}
socket.on('goto', (page) => {
pagename = page[0];
content = page[1];
let root = document.getElementById('root');
root.innerHTML = content;
root.querySelectorAll("script").forEach(x => {
eval(x.innerHTML);
});
document.querySelector('title').textContent = page[2];
if (pagename == 'home') pagename = '/';
history.pushState(null, null, pagename);
});

View File

@@ -1,4 +1,4 @@
{% extends "header.html" %} {% block content %} {% block content %}
<div class="foreground"> <div class="foreground">
<div class="col"> <div class="col">
<div id="aboutMe" data-aos="fade-up"> <div id="aboutMe" data-aos="fade-up">
@@ -41,10 +41,10 @@
<div id="skills" data-aos="fade-up"> <div id="skills" data-aos="fade-up">
<h2>Skills</h2> <h2>Skills</h2>
{% from 'partials/skills.html' import skills %} {% from 'partials/skills.html' import skills %}
{{ skills([ "Python", "JavaScript", "Java", "C", "C++", "MIPS Assembly", {{ skills([ "Python", "JavaScript", "Java", "C", "C++", "R", "MIPS Assembly",
"Processing", "P5.js", "SQL", "SQLite", "PostgreSQL", "SQLAlchemy", "Processing", "P5.js", "SQL", "SQLite", "PostgreSQL", "SQLAlchemy",
"HTML", "CSS", "Docker", "LaTeX", "ArcGIS", "Git", "Github", "Linux", "HTML", "CSS", "Docker", "LaTeX", "ArcGIS", "Git", "Github", "Linux",
"OKD4", "Kubernetes", "Angular", "Flask", "Jinja", "DOM Scraping", "OKD4", "Kubernetes", "Openshift", "Angular", "Flask", "Jinja", "DOM Scraping",
"Google API", "React", "Node.js", "ArcGIS", ]) }} "Google API", "React", "Node.js", "ArcGIS", ]) }}
</Skills> </Skills>
<div class="chess"> <div class="chess">
@@ -121,8 +121,8 @@
</div> </div>
<div class="timeline checkbox-client"> <div class="timeline checkbox-client">
{% from 'partials/timeline.html' import timeitem %} {% from 'partials/timeline.html' import timeitem %}
{% for i in timeline %} {% for i in var["timeline"] %}
{{ timeitem(i, timeline[i]["classes"], timeline[i]["date"], timeline[i]["content"])}} {{ timeitem(i, var["timeline"][i]["classes"], var["timeline"][i]["date"], var["timeline"][i]["content"])}}
{% endfor %} {% endfor %}
</div> </div>
<script>toggle('up')</script> <script>toggle('up')</script>

View File

@@ -1,4 +1,4 @@
{% extends "header.html" %} {% block content %} {% block content %}
<div class="fPage"> <div class="fPage">
<div class="heightBox"> <div class="heightBox">
<div class="neonBox"> <div class="neonBox">

View File

@@ -5,22 +5,22 @@
<link rel="icon" href="{{ url_for('static', filename='favicon.ico') }}" /> <link rel="icon" href="{{ url_for('static', filename='favicon.ico') }}" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" /> <meta name="theme-color" content="#000000" />
<meta name="description" content="{{ description }}" /> <meta name="description" content="{{ var['description'] }}" />
<meta property="og:title" content="Andrew Simonson" /> <meta property="og:title" content="Andrew Simonson" />
<meta name="og:description" content="{{ description }}" /> <meta name="og:description" content="{{ var['description'] }}" />
<meta property="og:type" content="website" /> <meta property="og:type" content="website" />
<meta <meta
property="og:image" property="og:image"
content="{{ url_for('static', filename='photos/sun.png') }}" content="https://asimonson.com{{ url_for('static', filename='photos/sun.png') }}"
/> />
<meta property="og:url" content="https://asimonson.com" /> <meta property="og:url" content="https://asimonson.com" />
<meta property="twitter:title" content="Andrew Simonson" /> <meta property="twitter:title" content="Andrew Simonson" />
<meta name="twitter:description" content="{{ description }}" /> <meta name="twitter:description" content="{{ var['description'] }}" />
<meta name="twitter:card" content="summary_large_image" /> <meta name="twitter:card" content="summary_large_image" />
<meta property="og:site_name" content="Andrew Simonson - Portfolio" /> <meta property="og:site_name" content="Andrew Simonson - Portfolio" />
<meta <meta
property="twitter:image" property="twitter:image"
content="{{ url_for('static', filename='photos/sun.png') }}" content="https://asimonson.com{{ url_for('static', filename='photos/sun.png') }}"
/> />
<meta name="twitter:image:alt" content="some example picture idk" /> <meta name="twitter:image:alt" content="some example picture idk" />
<meta name="twitter:site" content="@asimonson1125" /> <meta name="twitter:site" content="@asimonson1125" />
@@ -52,13 +52,14 @@
href="{{ url_for('static', filename='css/head.css') }}" href="{{ url_for('static', filename='css/head.css') }}"
/> />
<link rel="canonical" href="https://asimonson.com/{{ canonical }}" /> <link rel="canonical" href="https://asimonson.com/{{ var['canonical'] }}" />
<script src="https://cdn.jsdelivr.net/npm/p5@1.4.1/lib/p5.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/p5@1.4.1/lib/p5.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.min.js" integrity="sha512-eVL5Lb9al9FzgR63gDs1MxcDS2wFu3loYAgjIH0+Hg38tCS8Ag62dwKyH+wzDb+QauDpEZjXbMn11blw8cbTJQ==" crossorigin="anonymous"></script>
<script src="{{ url_for('static', filename='js/idler.js') }}"></script> <script src="{{ url_for('static', filename='js/idler.js') }}"></script>
<script src="{{ url_for('static', filename='js/checkbox.js') }}"></script> <script src="{{ url_for('static', filename='js/checkbox.js') }}"></script>
<script src="{{ url_for('static', filename='js/responsive.js') }}"></script> <script src="{{ url_for('static', filename='js/responsive.js') }}"></script>
<script src="{{ url_for('static', filename='js/chessbed.js') }}"></script> <script src="{{ url_for('static', filename='js/chessbed.js') }}"></script>
<title>{{ title }}</title> <title>{{ var['title'] }}</title>
</head> </head>
<body> <body>
@@ -87,23 +88,23 @@
<div class="navControl"> <div class="navControl">
<div class="navBar"> <div class="navBar">
<div class="navElement"> <div class="navElement">
<a href="/">Home</a> <p onclick="emitData('goto', 'home')">Home</p>
</div> </div>
<div class="navElement"> <div class="navElement">
<a href="Resume.pdf" target="_blank"> Resume </a> <a href="Resume.pdf" target="_blank"> Resume </a>
</div> </div>
<div class="navElement"> <div class="navElement">
<a href="/projects">Projects</a> <p onclick="emitData('goto', 'projects')">Projects</p>
</div> </div>
<!-- <a href="/activities">Activities</a> --> <!-- <a href="/activities">Activities</a> -->
<div class="navElement"> <div class="navElement">
<a href="/about">About Me</a> <p onclick="emitData('goto', 'about')">About Me</p>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div id="root">{% block content %}{% endblock %}</div> <div id="root">{% include var['template'] %}</div>
<div class="footer"> <div class="footer">
{% include 'partials/socials.html' %} {% include 'partials/socials.html' %}
</div> </div>

View File

@@ -1,4 +1,4 @@
{% extends "header.html" %} {% block content %} {% block content %}
<div class="homeground"> <div class="homeground">
<div class="relative"> <div class="relative">
<div class="flex"> <div class="flex">
@@ -8,14 +8,13 @@
</div> </div>
</div> </div>
<div class="onRight" data-aos="fade-up"> <div class="onRight" data-aos="fade-up">
<iframe <img
title="langstats"
src="{{ url_for('static', filename='readme-stats-vercel-01-25-2023.svg') }}" src="{{ url_for('static', filename='readme-stats-vercel-01-25-2023.svg') }}"
class="langstats" class="langstats"
></iframe> />
<div class="chess"> <div class="chess">
{% from 'partials/chess.html' import chess %} {% from 'partials/chess.html' import chess %} {{ chess('asimonson1125')
{{ chess('asimonson1125') }} }}
</div> </div>
</div> </div>
</div> </div>

View File

@@ -1,4 +1,4 @@
{% extends "header.html" %} {% block content %} {% block content %}
<div class="foreground"> <div class="foreground">
<div data-aos="fade-up"> <div data-aos="fade-up">
<h2 class="concentratedHead">Projects</h2> <h2 class="concentratedHead">Projects</h2>
@@ -37,8 +37,8 @@
</div> </div>
<div class="projectList centeredForeground checkbox-client"> <div class="projectList centeredForeground checkbox-client">
{% from 'partials/project.html' import project %} {% from 'partials/project.html' import project %}
{% for i in projects %} {% for i in var["projects"] %}
{{ project(i, projects[i]["classes"], projects[i]["status"], projects[i]["bgi"], projects[i]["content"], projects[i]["links"]) }} {{ project(i, var["projects"][i]["classes"], var["projects"][i]["status"], var["projects"][i]["bgi"], var["projects"][i]["content"], var["projects"][i]["links"]) }}
{% endfor %} {% endfor %}
</div> </div>
</div> </div>