commit 4bf1908ef33f2d5b6a9af954f9560e27d5f8d798
parent e8c129eee9ff487468bf41ab8dfd226931d7f7a3
Author: Oscar Benedito <oscar@oscarbenedito.com>
Date: Sun, 30 Aug 2020 14:52:26 +0200
Composer moved to future-proof URL
The appropriate redirect has been set up.
The composer will now be on a subfolder dedicated to personal projects.
As it has become a project completely unrelated to the website, it is
now a static file and doesn't use any Hugo features. It will probably be
added to a more fitted repository, but I will keep it on the website for
now.
Diffstat:
6 files changed, 193 insertions(+), 205 deletions(-)
diff --git a/assets/css/composer.css b/assets/css/composer.css
@@ -1,74 +0,0 @@
-:root {
- --font-family: 'serif';
- --nav-height: 3em;
- --text-color: #000;
- --bg-color: #fff;
- --nav-color: hsl(0, 0%, 46%);
-}
-.toggled {
- --text-color: hsl(0, 0%, 93%);
- --bg-color: hsl(0, 0%, 13%);
- --nav-color: hsl(0, 0%, 56%);
-}
-@media (prefers-color-scheme: dark) {
- :root {
- --text-color: hsl(0, 0%, 93%);
- --bg-color: hsl(0, 0%, 13%);
- --nav-color: hsl(0, 0%, 56%);
- }
-}
-@media (prefers-color-scheme: dark) {
- .toggled {
- --text-color: #000;
- --bg-color: #fff;
- --nav-color: hsl(0, 0%, 46%);
- }
-}
-.mono {
- --font-family: 'mono';
-}
-html {
- background-color: var(--bg-color);
-}
-textarea {
- line-height: 1.4em;
- font-family: var(--font-family);
- padding: 1em calc((100% - 720px)/2);
- background-color: var(--bg-color);
- color: var(--text-color);
- margin: 0;
- height: calc(100% - var(--nav-height));
- font-size: 1.2em;
- box-sizing: border-box;
- resize: none;
- right: 0;
- top: var(--nav-height);
- bottom: 0;
- left: 0;
- width: 100%;
- position: fixed;
- border: 0;
- outline: 0;
-}
-nav {
- text-align: center;
- height: var(--nav-height);
- line-height: var(--nav-height);
- font-size: 1.2em;
- opacity: 0;
- color: var(--nav-color);
- background-color: var(--bg-color);
- position: fixed;
- top: 0;
- right: 0;
- left: 0;
- z-index: 1;
-}
-nav a {
- color: var(--nav-color);
- text-decoration: none;
- cursor: pointer;
-}
-nav:hover {
- opacity: 1;
-}
diff --git a/assets/js/composer.js b/assets/js/composer.js
@@ -1,109 +0,0 @@
-/*
-Copyright (C) 2019 Oscar Benedito
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU Affero General Public License as
-published by the Free Software Foundation, either version 3 of the
-License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU Affero General Public License for more details.
-
-You should have received a copy of the GNU Affero General Public License
-along with this program. If not, see <https://www.gnu.org/licenses/>.
-
-This file is based on code from the writeFreely project. You can find the
-source code at <https://github.com/writeas/writefreely>
-*/
-var $composer = document.getElementById('composer');
-var $wordcount = document.getElementById('word-count');
-var key;
-var typingTimer;
-var typingInterval = 200;
-function updateWordCount() {
- var words = 0;
- var content = $composer.value.trim();
- if (content != '') {
- words = content.replace(/\s+/gi, ' ').split(' ').length;
- }
- minutes = Math.floor(words/140);
- $wordcount.textContent = words + ' word' + (words != 1 ? 's' : '') + ' · ' + minutes + ' minute' + (minutes != 1 ? 's' : '');
-}
-function loadContents() {
- var content = localStorage.getItem(key);
- if (content != null) {
- $composer.value = content;
- }
-}
-var updateContents = function() {
- if ($composer.value == '') {
- localStorage.removeItem(key);
- }
- else {
- localStorage.setItem(key, $composer.value);
- }
- updateWordCount();
-}
-var resetTimer = function() {
- clearTimeout(typingTimer);
- typingTimer = setTimeout(updateContents, typingInterval);
-}
-function downloadData(filename, text) {
- var text = localStorage.getItem(key);
- if (text != null && text != '') {
- var tmpElement = document.createElement('a');
- tmpElement.setAttribute('href', 'data:text/markdown;charset=utf-8,' + encodeURIComponent(text));
- tmpElement.setAttribute('download', key + '.md');
- tmpElement.style.display = 'none';
-
- document.body.appendChild(tmpElement);
- tmpElement.click();
- document.body.removeChild(tmpElement);
- }
-}
-var saveEvent = function(event) {
- if (event.keyCode == 83 && (event.metaKey || event.ctrlKey)) {
- clearTimeout(typingTimer);
- event.preventDefault();
- updateContents();
- if (event.shiftKey)
- downloadData();
- }
-}
-function toggleTheme() {
- if (localStorage && localStorage.getItem('theme') == 'toggled') {
- localStorage.removeItem('theme');
- } else if (localStorage) {
- localStorage.setItem('theme', 'toggled');
- }
- document.documentElement.classList.toggle('toggled');
-}
-function toggleFont() {
- if (localStorage && localStorage.getItem('font') == 'mono') {
- localStorage.removeItem('font');
- } else if (localStorage) {
- localStorage.setItem('font', 'mono');
- }
- document.documentElement.classList.toggle('mono');
-}
-
-key = (new URLSearchParams(window.location.search)).get('key');
-if (key == '' || key == null) {
- key = 'null';
-}
-key = 'k-' + key;
-if (localStorage && localStorage.getItem('theme') == 'toggled') {
- document.documentElement.classList.toggle('toggled');
-}
-if (localStorage && localStorage.getItem('font') == 'mono') {
- document.documentElement.classList.toggle('mono');
-}
-$composer.addEventListener('keyup input', resetTimer);
-$composer.addEventListener('keydown', resetTimer);
-$composer.addEventListener('input', resetTimer);
-window.addEventListener('beforeunload', updateContents);
-window.addEventListener('keydown', saveEvent);
-loadContents();
-updateWordCount();
diff --git a/content/composer.md b/content/composer.md
@@ -1,4 +1,4 @@
---
-title: Composer
-type: composer
+canonical: "/projects/composer/composer.html"
+type: redirect
---
diff --git a/layouts/composer/single.html b/layouts/composer/single.html
@@ -1,20 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
- <head>
- {{ partial "head-base.html" . }}
- <style>
-{{ (resources.Get "css/composer.css").Content | safeCSS }}
- </style>
- </head>
- <body>
- <nav>
- <span id="word-count">0 words · 0 minutes</span> · <a onclick="toggleTheme()">Toggle theme</a> · <a onclick="toggleFont()">Toggle font</a>
- </nav>
- <textarea id="composer" placeholder="Start writing..." autofocus></textarea>
- <script type="text/javascript">
-{{ printf "// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later" | safeJS }}
-{{ (resources.Get "js/composer.js").Content | safeJS }}
-{{ printf "// @license-end" | safeJS }}
- </script>
- </body>
-</html>
diff --git a/layouts/redirect/single.html b/layouts/redirect/single.html
@@ -0,0 +1 @@
+<!DOCTYPE html><html><head><meta http-equiv="refresh" content="0; url='{{ .Params.canonical }}'"/><link rel="canonical" href="{{ .Params.canonical }}"/></head><body><p>This page has been moved to <a href="{{ .Params.canonical }}">{{ .Params.canonical }}</a>.</p></body></html>
diff --git a/static/projects/composer/composer.html b/static/projects/composer/composer.html
@@ -0,0 +1,190 @@
+<!DOCTYPE html>
+<!--
+ Composer by Oscar Benedito <oscar@oscarbenedito.com>
+
+ Minimalistic interface to write without distractions. It is a standalone HTML
+ file. It will save your progress as long as you don't delete browser data.
+-->
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <meta name="author" content="Oscar Benedito">
+ <title>Composer</title>
+ <style>
+:root {
+ --font-family: 'serif';
+ --nav-height: 3em;
+ --text-color: #000;
+ --bg-color: #fff;
+ --nav-color: hsl(0, 0%, 46%);
+}
+.toggled {
+ --text-color: hsl(0, 0%, 93%);
+ --bg-color: hsl(0, 0%, 13%);
+ --nav-color: hsl(0, 0%, 56%);
+}
+@media (prefers-color-scheme: dark) {
+ :root {
+ --text-color: hsl(0, 0%, 93%);
+ --bg-color: hsl(0, 0%, 13%);
+ --nav-color: hsl(0, 0%, 56%);
+ }
+}
+@media (prefers-color-scheme: dark) {
+ .toggled {
+ --text-color: #000;
+ --bg-color: #fff;
+ --nav-color: hsl(0, 0%, 46%);
+ }
+}
+.mono {
+ --font-family: 'mono';
+}
+html {
+ background-color: var(--bg-color);
+}
+textarea {
+ line-height: 1.4em;
+ font-family: var(--font-family);
+ padding: 1em calc((100% - 720px)/2);
+ background-color: var(--bg-color);
+ color: var(--text-color);
+ margin: 0;
+ height: calc(100% - var(--nav-height));
+ font-size: 1.2em;
+ box-sizing: border-box;
+ resize: none;
+ right: 0;
+ top: var(--nav-height);
+ bottom: 0;
+ left: 0;
+ width: 100%;
+ position: fixed;
+ border: 0;
+ outline: 0;
+}
+nav {
+ text-align: center;
+ height: var(--nav-height);
+ line-height: var(--nav-height);
+ font-size: 1.2em;
+ opacity: 0;
+ color: var(--nav-color);
+ background-color: var(--bg-color);
+ position: fixed;
+ top: 0;
+ right: 0;
+ left: 0;
+ z-index: 1;
+}
+nav a {
+ color: var(--nav-color);
+ text-decoration: none;
+ cursor: pointer;
+}
+nav:hover {
+ opacity: 1;
+}
+ </style>
+ </head>
+ <body>
+ <nav>
+ <span id="word-count">0 words · 0 minutes</span> · <a onclick="toggleTheme()">Toggle theme</a> · <a onclick="toggleFont()">Toggle font</a>
+ </nav>
+ <textarea id="composer" placeholder="Start writing..." autofocus></textarea>
+ <script type="text/javascript">
+// @license magnet:?xt=urn:btih:90dc5c0be029de84e523b9b3922520e79e0e6f08&dn=cc0.txt CC0-1.0
+var $composer = document.getElementById('composer');
+var $wordcount = document.getElementById('word-count');
+var key;
+var typingTimer;
+var typingInterval = 200;
+function updateWordCount() {
+ var words = 0;
+ var content = $composer.value.trim();
+ if (content != '') {
+ words = content.replace(/\s+/gi, ' ').split(' ').length;
+ }
+ minutes = Math.floor(words/140);
+ $wordcount.textContent = words + ' word' + (words != 1 ? 's' : '') + ' · ' + minutes + ' minute' + (minutes != 1 ? 's' : '');
+}
+function loadContents() {
+ var content = localStorage.getItem(key);
+ if (content != null) {
+ $composer.value = content;
+ }
+}
+var updateContents = function() {
+ if ($composer.value == '') {
+ localStorage.removeItem(key);
+ }
+ else {
+ localStorage.setItem(key, $composer.value);
+ }
+ updateWordCount();
+}
+var resetTimer = function() {
+ clearTimeout(typingTimer);
+ typingTimer = setTimeout(updateContents, typingInterval);
+}
+function downloadData(filename, text) {
+ var text = localStorage.getItem(key);
+ if (text != null && text != '') {
+ var tmpElement = document.createElement('a');
+ tmpElement.setAttribute('href', 'data:text/markdown;charset=utf-8,' + encodeURIComponent(text));
+ tmpElement.setAttribute('download', key + '.md');
+ tmpElement.style.display = 'none';
+
+ document.body.appendChild(tmpElement);
+ tmpElement.click();
+ document.body.removeChild(tmpElement);
+ }
+}
+var saveEvent = function(event) {
+ if (event.keyCode == 83 && (event.metaKey || event.ctrlKey)) {
+ clearTimeout(typingTimer);
+ event.preventDefault();
+ updateContents();
+ if (event.shiftKey)
+ downloadData();
+ }
+}
+function toggleTheme() {
+ if (localStorage && localStorage.getItem('theme') == 'toggled') {
+ localStorage.removeItem('theme');
+ } else if (localStorage) {
+ localStorage.setItem('theme', 'toggled');
+ }
+ document.documentElement.classList.toggle('toggled');
+}
+function toggleFont() {
+ if (localStorage && localStorage.getItem('font') == 'mono') {
+ localStorage.removeItem('font');
+ } else if (localStorage) {
+ localStorage.setItem('font', 'mono');
+ }
+ document.documentElement.classList.toggle('mono');
+}
+key = (new URLSearchParams(window.location.search)).get('key');
+if (key == '' || key == null) {
+ key = 'null';
+}
+key = 'k-' + key;
+if (localStorage && localStorage.getItem('theme') == 'toggled') {
+ document.documentElement.classList.toggle('toggled');
+}
+if (localStorage && localStorage.getItem('font') == 'mono') {
+ document.documentElement.classList.toggle('mono');
+}
+$composer.addEventListener('keyup input', resetTimer);
+$composer.addEventListener('keydown', resetTimer);
+$composer.addEventListener('input', resetTimer);
+window.addEventListener('beforeunload', updateContents);
+window.addEventListener('keydown', saveEvent);
+loadContents();
+updateWordCount();
+// @license-end
+ </script>
+ </body>
+</html>