diff --git a/bookwyrm/static/js/forms.js b/bookwyrm/static/js/forms.js
index 08066f137..4a075506e 100644
--- a/bookwyrm/static/js/forms.js
+++ b/bookwyrm/static/js/forms.js
@@ -47,12 +47,11 @@
.querySelectorAll("[data-remove]")
.forEach((node) => node.addEventListener("click", removeInput));
- // Get the element, add a keypress listener...
+ // Get element, add a keypress listener...
document.getElementById("subjects").addEventListener("keypress", function (e) {
- // e.target is the element where it listens!
- // if e.target is input field within the "subjects" div, do stuff
+ // Linstening to element e.target
+ // If e.target is an input field within "subjects" div preventDefault()
if (e.target && e.target.nodeName == "INPUT") {
- // Item found, prevent default
if (event.keyCode == 13) {
event.preventDefault();
}
diff --git a/bookwyrm/templates/embed-layout.html b/bookwyrm/templates/embed-layout.html
index c619bf2dc..865203627 100644
--- a/bookwyrm/templates/embed-layout.html
+++ b/bookwyrm/templates/embed-layout.html
@@ -12,6 +12,7 @@
+
diff --git a/bookwyrm/templates/layout.html b/bookwyrm/templates/layout.html
index e6f8a6f84..ba53685f4 100644
--- a/bookwyrm/templates/layout.html
+++ b/bookwyrm/templates/layout.html
@@ -14,6 +14,7 @@
+
{% block opengraph %}
{% include 'snippets/opengraph.html' %}
diff --git a/bookwyrm/templates/manifest.json b/bookwyrm/templates/manifest.json
new file mode 100644
index 000000000..83ad77789
--- /dev/null
+++ b/bookwyrm/templates/manifest.json
@@ -0,0 +1,14 @@
+{% load static %}
+{
+ "name": "{{ site.name }}",
+ "description": "{{ site.description }}",
+ "icons": [
+ {
+ "src": "{% if site.logo %}{{ media_full_url }}{{ site.logo }}{% else %}{% static 'images/logo.png' %}{% endif %}",
+ "type": "image/png",
+ "sizes": "512x512"
+ }
+ ],
+ "start_url": "/",
+ "display": "standalone"
+}
diff --git a/bookwyrm/urls.py b/bookwyrm/urls.py
index 05972ee73..0759012fe 100644
--- a/bookwyrm/urls.py
+++ b/bookwyrm/urls.py
@@ -34,6 +34,12 @@ urlpatterns = [
"robots.txt",
TemplateView.as_view(template_name="robots.txt", content_type="text/plain"),
),
+ path(
+ "manifest.json",
+ TemplateView.as_view(
+ template_name="manifest.json", content_type="application/json"
+ ),
+ ),
# federation endpoints
re_path(r"^inbox/?$", views.Inbox.as_view(), name="inbox"),
re_path(rf"{LOCAL_USER_PATH}/inbox/?$", views.Inbox.as_view(), name="user_inbox"),
diff --git a/dev-tools/Dockerfile b/dev-tools/Dockerfile
index 9abc7491e..7063aab1b 100644
--- a/dev-tools/Dockerfile
+++ b/dev-tools/Dockerfile
@@ -1,14 +1,14 @@
FROM python:3.9
-
-ENV PYTHONUNBUFFERED 1
-
-RUN mkdir /app
WORKDIR /app
-COPY package.json requirements.txt .stylelintrc.js .stylelintignore /app/
-RUN pip install -r requirements.txt
+ENV PYTHONUNBUFFERED=1
+ENV NPM_CONFIG_UPDATE_NOTIFIER=false
+ENV PIP_ROOT_USER_ACTION=ignore PIP_DISABLE_PIP_VERSION_CHECK=1
-RUN apt-get update && apt-get install -y curl
-RUN curl -sL https://deb.nodesource.com/setup_18.x | bash -
-RUN apt-get install -y nodejs && apt-get clean
-RUN npm install .
+COPY nodejs.sources /etc/apt/sources.list.d/
+COPY package.json requirements.txt .stylelintrc.js .stylelintignore /app/
+
+RUN apt-get update && \
+ apt-get install -y nodejs && \
+ pip install -r requirements.txt && \
+ npm install .
diff --git a/dev-tools/nodejs.sources b/dev-tools/nodejs.sources
new file mode 100644
index 000000000..1e0c3ba40
--- /dev/null
+++ b/dev-tools/nodejs.sources
@@ -0,0 +1,34 @@
+Types: deb
+URIs: https://deb.nodesource.com/node_18.x
+Suites: nodistro
+Components: main
+Signed-By:
+ -----BEGIN PGP PUBLIC KEY BLOCK-----
+ .
+ mQENBFdDN1ABCADaNd/I3j3tn40deQNgz7hB2NvT+syXe6k4ZmdiEcOfBvFrkS8B
+ hNS67t93etHsxEy7E0qwsZH32bKazMqe9zDwoa3aVImryjh6SHC9lMtW27JPHFeM
+ Srkt9YmH1WMwWcRO6eSY9B3PpazquhnvbammLuUojXRIxkDroy6Fw4UKmUNSRr32
+ 9Ej87jRoR1B2/57Kfp2Y4+vFGGzSvh3AFQpBHq51qsNHALU6+8PjLfIt+5TPvaWR
+ TB+kAZnQZkaIQM2nr1n3oj6ak2RATY/+kjLizgFWzgEfbCrbsyq68UoY5FPBnu4Z
+ E3iDZpaIqwKr0seUC7iA1xM5eHi5kty1oB7HABEBAAG0Ik5Tb2xpZCA8bnNvbGlk
+ LWdwZ0Bub2Rlc291cmNlLmNvbT6JATgEEwECACIFAldDN1ACGwMGCwkIBwMCBhUI
+ AgkKCwQWAgMBAh4BAheAAAoJEC9ZtfmbG+C0y7wH/i4xnab36dtrYW7RZwL8i6Sc
+ NjMx4j9+U1kr/F6YtqWd+JwCbBdar5zRghxPcYEq/qf7MbgAYcs1eSOuTOb7n7+o
+ xUwdH2iCtHhKh3Jr2mRw1ks7BbFZPB5KmkxHaEBfLT4d+I91ZuUdPXJ+0SXs9gzk
+ Dbz65Uhoz3W03aiF8HeL5JNARZFMbHHNVL05U1sTGTCOtu+1c/33f3TulQ/XZ3Y4
+ hwGCpLe0Tv7g7Lp3iLMZMWYPEa0a7S4u8he5IEJQLd8bE8jltcQvrdr3Fm8kI2Jg
+ BJmUmX4PSfhuTCFaR/yeCt3UoW883bs9LfbTzIx9DJGpRIu8Y0IL3b4sj/GoZVq5
+ AQ0EV0M3UAEIAKrTaC62ayzqOIPa7nS90BHHck4Z33a2tZF/uof38xNOiyWGhT8u
+ JeFoTTHn5SQq5Ftyu4K3K2fbbpuu/APQF05AaljzVkDGNMW4pSkgOasdysj831cu
+ ssrHX2RYS22wg80k6C/Hwmh5F45faEuNxsV+bPx7oPUrt5n6GMx84vEP3i1+FDBi
+ 0pt/B/QnDFBXki1BGvJ35f5NwDefK8VaInxXP3ZN/WIbtn5dqxppkV/YkO7GiJlp
+ Jlju9rf3kKUIQzKQWxFsbCAPIHoWv7rH9RSxgDithXtG6Yg5R1aeBbJaPNXL9wpJ
+ YBJbiMjkAFaz4B95FOqZm3r7oHugiCGsHX0AEQEAAYkBHwQYAQIACQUCV0M3UAIb
+ DAAKCRAvWbX5mxvgtE/OB/0VN88DR3Y3fuqy7lq/dthkn7Dqm9YXdorZl3L152eE
+ IF882aG8FE3qZdaLGjQO4oShAyNWmRfSGuoH0XERXAI9n0r8m4mDMxE6rtP7tHet
+ y/5M8x3CTyuMgx5GLDaEUvBusnTD+/v/fBMwRK/cZ9du5PSG4R50rtst+oYyC2ao
+ x4I2SgjtF/cY7bECsZDplzatN3gv34PkcdIg8SLHAVlL4N5tzumDeizRspcSyoy2
+ K2+hwKU4C4+dekLLTg8rjnRROvplV2KtaEk6rxKtIRFDCoQng8wfJuIMrDNKvqZw
+ FRGt7cbvW5MCnuH8MhItOl9Uxp1wHp6gtav/h8Gp6MBa
+ =MARt
+ -----END PGP PUBLIC KEY BLOCK-----