mirror of https://github.com/nealey/vail.git
A bit of UI work
This commit is contained in:
parent
0677d7171c
commit
7ba5ee836e
|
@ -2,82 +2,107 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Vail</title>
|
<title>Vail</title>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
|
||||||
|
<!-- Material Design Lite -->
|
||||||
|
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
|
||||||
|
<link rel="stylesheet" href="https://code.getmdl.io/1.3.0/material.teal-purple.min.css">
|
||||||
|
<script defer src="https://code.getmdl.io/1.3.0/material.min.js"></script>
|
||||||
|
|
||||||
|
<!-- Vail stuff -->
|
||||||
<script src="vail.js"></script>
|
<script src="vail.js"></script>
|
||||||
<link rel="stylesheet" href="vail.css">
|
<link rel="stylesheet" href="vail.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div>
|
<div class="mdl-layout mdl-js-layout">
|
||||||
|
<header class="mdl-layout__header mdl-layout__header--scroll">
|
||||||
|
<div class="mdl-layout__header-row">
|
||||||
|
<!-- Title -->
|
||||||
|
<span class="mdl-layout-title">Vail</span>
|
||||||
|
<!-- Add spacer, to align navigation to the right -->
|
||||||
|
<div class="mdl-layout-spacer"></div>
|
||||||
|
<!-- Navigation -->
|
||||||
|
<nav class="mdl-navigation">
|
||||||
|
<a class="mdl-navigation__link" href="">Link</a>
|
||||||
|
<a class="mdl-navigation__link" href="">Link</a>
|
||||||
|
<a class="mdl-navigation__link" href="">Link</a>
|
||||||
|
<a class="mdl-navigation__link" href="">Link</a>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<div class="mdl-layout__drawer">
|
||||||
|
<span class="mdl-layout-title">Title</span>
|
||||||
|
<nav class="mdl-navigation">
|
||||||
|
<a class="mdl-navigation__link" href="">Link</a>
|
||||||
|
<a class="mdl-navigation__link" href="">Link</a>
|
||||||
|
<a class="mdl-navigation__link" href="">Link</a>
|
||||||
|
<a class="mdl-navigation__link" href="">Link</a>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
<main class="mdl-layout__content">
|
||||||
|
<div class="flex">
|
||||||
|
<div class="mdl-card mdl-shadow--4dp">
|
||||||
|
<div class="mdl-card__title">
|
||||||
|
<h2 class="mdl-card__title-text">
|
||||||
|
Code Tree
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
<div class="mdl-card__supporting-text">
|
||||||
<img src="code-tree.png">
|
<img src="code-tree.png">
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div>
|
<div class="mdl-card mdl-shadow--4dp">
|
||||||
<table>
|
<div class="mdl-card__title">
|
||||||
|
<h2 class="mdl-card__title-text">
|
||||||
|
Input
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
<div class="mdl-tabs mdl-js-tabs mdl-js-ripple-effect">
|
||||||
|
<div class="mdl-tabs__tab-bar">
|
||||||
|
<a href="#iambic" class="mdl-tabs__tab is-active">Iambic</a>
|
||||||
|
<a href="#straight" class="mdl-tabs__tab">Straight Key</a>
|
||||||
|
</div>
|
||||||
|
<div class="mdl-tabs__panel is-active" id="iambic">
|
||||||
|
<table style="width: 100%; text-align: center;">
|
||||||
<tr>
|
<tr>
|
||||||
<th>Dot</th>
|
<td>
|
||||||
<td><code>,</code>, <code>w</code>, left mouse button</td>
|
<button class="key mdl-button mdl-js-button mdl-button--raised mdl-button--colored">
|
||||||
|
dit
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button class="key mdl-button mdl-js-button mdl-button--raised mdl-button--colored">
|
||||||
|
dah
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Dash</th>
|
<td>
|
||||||
<td><code>.</code>, <code>v</code>, right mouse button</td>
|
<code>.</code> or <code>⇧</code>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<code>/</code> or <code>z</code>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="mdl-tabs__panel" id="straight">
|
||||||
<div>
|
<button class="key mdl-button mdl-js-button mdl-button--raised mdl-button--colored">
|
||||||
<pre>
|
Key
|
||||||
a : .-
|
</button>
|
||||||
b : -...
|
</div>
|
||||||
c : -.-.
|
</div>
|
||||||
d : -..
|
|
||||||
e : .
|
|
||||||
f : ..-.
|
|
||||||
g : --.
|
|
||||||
h : ....
|
|
||||||
i : ..
|
|
||||||
j : .---
|
|
||||||
k : -.-
|
|
||||||
l : .-..
|
|
||||||
m : --
|
|
||||||
n : -.
|
|
||||||
o : ---
|
|
||||||
p : .--.
|
|
||||||
q : --.-
|
|
||||||
r : .-.
|
|
||||||
s : ...
|
|
||||||
t : -
|
|
||||||
u : ..-
|
|
||||||
v : ...-
|
|
||||||
w : .--
|
|
||||||
x : -..-
|
|
||||||
y : -.--
|
|
||||||
z : --..
|
|
||||||
0 : -----
|
|
||||||
1 : .----
|
|
||||||
2 : ..---
|
|
||||||
3 : ...--
|
|
||||||
4 : ....-
|
|
||||||
5 : .....
|
|
||||||
6 : -....
|
|
||||||
7 : --...
|
|
||||||
8 : ---..
|
|
||||||
9 : ----.
|
|
||||||
. : .-.-.-
|
|
||||||
, : --..--
|
|
||||||
: : ---...
|
|
||||||
? : ..--..
|
|
||||||
' : .----.
|
|
||||||
- : -....-
|
|
||||||
/ : -..-.
|
|
||||||
" : .-..-.
|
|
||||||
@ : .--.-.
|
|
||||||
= : -...-
|
|
||||||
! : -.-.--
|
|
||||||
</pre>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div class="mdl-card mdl-shadow--4dp">
|
||||||
<h1>Vail</h1>
|
<div class="mdl-card__title">
|
||||||
|
<h2 class="mdl-card__title-text">
|
||||||
|
Vail
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
<div class="mdl-card__supporting-text">
|
||||||
<p>
|
<p>
|
||||||
This is a CW repeater,
|
This is a CW repeater,
|
||||||
named after Alfred Vail,
|
named after Alfred Vail,
|
||||||
|
@ -98,10 +123,15 @@ z : --..
|
||||||
let me know and I'll come up with something for you.
|
let me know and I'll come up with something for you.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div>
|
<div class="mdl-card mdl-shadow--4dp">
|
||||||
<h2>Why does this exist?</h2>
|
<div class="mdl-card__title">
|
||||||
|
<h2 class="mdl-card__title-text">
|
||||||
|
Why Does This Exist?
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
<div class="mdl-card__supporting-text">
|
||||||
<p>
|
<p>
|
||||||
I need a place to practice CW with actual human beings,
|
I need a place to practice CW with actual human beings,
|
||||||
and I want it to be as close as possible to what I'd experience on a radio.
|
and I want it to be as close as possible to what I'd experience on a radio.
|
||||||
|
@ -109,14 +139,20 @@ z : --..
|
||||||
Nothing else like this exists on the Internet, as far as I can tell.
|
Nothing else like this exists on the Internet, as far as I can tell.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2>Who made it?</h2>
|
<h3>Who made it?</h3>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<a href="mailto:neale@woozle.org">Neale Pickett</a> kd7oqi
|
<a href="mailto:neale@woozle.org">Neale Pickett</a> kd7oqi
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2>Future plans</h2>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mdl-card mdl-shadow--4dp">
|
||||||
|
<div class="mdl-card__title">
|
||||||
|
<h3 class="mdl-card__title-text">Future plans</h3>
|
||||||
|
</div>
|
||||||
|
<div class="mdl-card__supporting_text">
|
||||||
<ul>
|
<ul>
|
||||||
<li>Move to a more permanent URL</li>
|
<li>Move to a more permanent URL</li>
|
||||||
<li>Make this page less ugly</li>
|
<li>Make this page less ugly</li>
|
||||||
|
@ -128,12 +164,16 @@ z : --..
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
<h2>How can I help?</h2>
|
<h3>How can I help?</h3>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li>Improve the <a href="https://github.com/nealey/vail/">source code</a></li>
|
<li>Improve the <a href="https://github.com/nealey/vail/">source code</a></li>
|
||||||
<li><a href="mailto:neale@woozle.org">Email me</a> and let me know you're using it</li>
|
<li><a href="mailto:neale@woozle.org">Email me</a> and let me know you're using it</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
body {
|
.flex {
|
||||||
background-color: #ccc;
|
|
||||||
font-family: sans-serif;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: space-around;
|
||||||
|
}
|
||||||
|
|
||||||
|
.key {
|
||||||
|
width: 100%;
|
||||||
|
height: 6em;
|
||||||
}
|
}
|
||||||
|
|
||||||
code {
|
code {
|
||||||
|
|
|
@ -1,46 +1,89 @@
|
||||||
var ac = new AudioContext()
|
// jshint asi:true
|
||||||
var gain = ac.createGain()
|
|
||||||
gain.connect(ac.destination)
|
|
||||||
gain.gain.value = 0.1
|
|
||||||
|
|
||||||
var short = 80
|
var short = 80
|
||||||
var long = 200
|
var long = 200
|
||||||
var audioFreq = 660
|
var audioFreq = 660
|
||||||
var audioFreqMe = audioFreq * 6 / 5 // I think this works out to a minor third
|
var audioFreqMe = audioFreq * 6 / 5 // I think this works out to a minor third
|
||||||
var myosc
|
|
||||||
|
var ac = new AudioContext()
|
||||||
|
|
||||||
|
var mygain = ac.createGain()
|
||||||
|
mygain.connect(ac.destination)
|
||||||
|
mygain.gain.value = 0
|
||||||
|
|
||||||
|
var myosc = ac.createOscillator()
|
||||||
|
myosc.connect(mygain)
|
||||||
|
myosc.frequency.value = audioFreqMe
|
||||||
|
myosc.start()
|
||||||
|
|
||||||
|
var theirgain = ac.createGain()
|
||||||
|
theirgain.connect(ac.destination)
|
||||||
|
theirgain.gain.value = 0
|
||||||
|
|
||||||
|
var theirosc = ac.createOscillator()
|
||||||
|
theirosc.connect(theirgain)
|
||||||
|
theirosc.frequency.value = audioFreq
|
||||||
|
theirosc.start()
|
||||||
|
|
||||||
|
var repeatInterval
|
||||||
|
|
||||||
|
|
||||||
function message(event) {
|
function message(event) {
|
||||||
|
let now = ac.currentTime
|
||||||
let duration = Number(event.data) || 0
|
let duration = Number(event.data) || 0
|
||||||
duration = Math.min(duration, long)
|
duration = Math.min(duration, long)
|
||||||
|
|
||||||
let osc = ac.createOscillator()
|
if (now === 0) {
|
||||||
osc.connect(gain)
|
// Audio Context hasn't started, we can't make sound yet
|
||||||
osc.frequency.value = audioFreq
|
return
|
||||||
osc.start(ac.currentTime)
|
}
|
||||||
osc.stop(ac.currentTime + (duration * 0.001))
|
|
||||||
|
theirgain.gain.linearRampToValueAtTime(0.1, now + 0.01)
|
||||||
|
mygain.gain.setValueAtTime(0.1, now + duration/1000)
|
||||||
|
theirgain.gain.linearRampToValueAtTime(0.0, now + 0.01 + duration/1000)
|
||||||
|
}
|
||||||
|
|
||||||
|
function send(duration) {
|
||||||
|
let now = ac.currentTime
|
||||||
|
window.socket.send(duration)
|
||||||
|
|
||||||
|
if (now === 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
mygain.gain.linearRampToValueAtTime(0.1, now + 0.01)
|
||||||
|
mygain.gain.setValueAtTime(0.1, now + duration/1000)
|
||||||
|
mygain.gain.linearRampToValueAtTime(0.0, now + 0.01 + duration/1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
function key(event) {
|
function key(event) {
|
||||||
let duration = 0
|
let duration = 0
|
||||||
|
|
||||||
if ((event.button === 0) || (event.key == ",") || (event.key == "w")) {
|
ac.resume()
|
||||||
duration = short
|
|
||||||
}
|
if (event.repeat) {
|
||||||
if ((event.button === 2) || (event.key == ".") || (event.key == "v")) {
|
// Ignore key repeats generated by the OS, we do this ourselves
|
||||||
duration = long
|
|
||||||
}
|
|
||||||
// You don't get to hold the key down yet, sorry
|
|
||||||
if ((event.repeat) || (duration === 0)) {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
window.socket.send(duration)
|
if ((event.button === 0) || (event.code == "Period") || (event.key == "Shift")) {
|
||||||
|
duration = short
|
||||||
|
}
|
||||||
|
if ((event.button === 2) || (event.code == "Slash") || (event.code == "KeyZ")) {
|
||||||
|
duration = long
|
||||||
|
}
|
||||||
|
if (duration === 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
myosc = ac.createOscillator()
|
if (repeatInterval) {
|
||||||
myosc.connect(gain)
|
clearInterval(repeatInterval)
|
||||||
myosc.frequency.value = audioFreqMe
|
}
|
||||||
myosc.start(ac.currentTime)
|
|
||||||
myosc.stop(ac.currentTime + duration * 0.001)
|
if (event.type.endsWith("down")) {
|
||||||
|
send(duration)
|
||||||
|
repeatInterval = setInterval(() => {send(duration)}, duration + short)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function canWeJustNot(event) {
|
function canWeJustNot(event) {
|
||||||
|
@ -58,7 +101,9 @@ function init() {
|
||||||
// disable RMB context menu
|
// disable RMB context menu
|
||||||
document.addEventListener("contextmenu", e => canWeJustNot(e))
|
document.addEventListener("contextmenu", e => canWeJustNot(e))
|
||||||
document.addEventListener("mousedown", e => key(e))
|
document.addEventListener("mousedown", e => key(e))
|
||||||
|
document.addEventListener("mouseup", e => key(e))
|
||||||
document.addEventListener("keydown", e => key(e))
|
document.addEventListener("keydown", e => key(e))
|
||||||
|
document.addEventListener("keyup", e => key(e))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue