Improvements to interface

This commit is contained in:
Ruben van de Ven 2019-01-24 14:27:04 +01:00
parent 8cc9cea24f
commit acbd6fdd94
11 changed files with 675 additions and 415 deletions

View file

@ -3,22 +3,23 @@
This server controls all hugveys and the processing of their narratives. It exposes itself for control to the panopticon server.
"""
import asyncio
import logging
import threading
import os
import time
import yaml
import zmq
from zmq.asyncio import Context
import asyncio
from hugvey.communication import getTopic, zmqSend, zmqReceive
from hugvey.panopticon import Panopticon
from hugvey.story import Story
from hugvey.voice.google import GoogleVoiceClient
from hugvey.voice.player import Player
from hugvey.voice.streamer import AudioStreamer
import json
import logging
import queue
import os
import threading
logger = logging.getLogger("command")
@ -72,7 +73,8 @@ class CentralCommand(object):
lang_filename = os.path.join(self.config['web']['files_dir'], lang['file'])
self.languageFiles[lang['code']] = lang['file']
with open(lang_filename, 'r') as fp:
self.languages[lang['code']] = yaml.load(fp)
self.languages[lang['code']] = json.load(fp)
print(self.languages)
self.panopticon = Panopticon(self, self.config)

View file

@ -90,6 +90,11 @@ def getWebSocketHandler(central_command):
return WebSocketHandler
class NonCachingStaticFileHandler(tornado.web.StaticFileHandler):
def set_extra_headers(self, path):
# Disable cache
self.set_header('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0')
def getUploadHandler(central_command):
class UploadHandler(tornado.web.RequestHandler):
def post(self):
@ -97,9 +102,10 @@ def getUploadHandler(central_command):
langCode = self.get_argument("language")
langFile = os.path.join(central_command.config['web']['files_dir'] , central_command.languageFiles[langCode])
print(self.request.files['json'][0])
storyData = json.loads(self.request.files['json'][0]['body'])
print(storyData)
# print(json.dumps(storyData))
# self.finish()
# return
if 'audio' in self.request.files:
msgId = self.get_argument("message_id")
@ -120,9 +126,10 @@ def getUploadHandler(central_command):
# fp.write(audioFile['body'])
break
with open(langFile, 'r') as fp:
logger.info(f'Save story to {langFile}')
# json.dump(storyData, fp)
print(os.path.abspath(langFile))
with open(langFile, 'w') as json_fp:
logger.info(f'Save story to {langFile} {json_fp}')
json.dump(storyData, json_fp)
self.finish()
return UploadHandler
@ -132,7 +139,7 @@ class Panopticon(object):
self.config = config
self.application = tornado.web.Application([
(r"/ws", getWebSocketHandler(self.command)),
(r"/local/(.*)", tornado.web.StaticFileHandler,
(r"/local/(.*)", NonCachingStaticFileHandler,
{"path": config['web']['files_dir']}),
(r"/upload", getUploadHandler(self.command)),
(r"/(.*)", tornado.web.StaticFileHandler,

View file

@ -2,13 +2,22 @@ body {
font-family: "Noto Sans", sans-serif;
margin: 0; }
.btn {
.btn, input[type="submit"] {
display: inline-block;
cursor: pointer;
background: #333;
padding: 5px;
color: white;
border-radius: 5px; }
border-radius: 5px;
margin-right: 5px;
white-space: nowrap;
border: none; }
.btn:hover, input[type="submit"]:hover {
background: #666; }
@keyframes dash-animation {
to {
stroke-dashoffset: -1000; } }
#interface {
display: flex;
@ -29,6 +38,8 @@ body {
border: solid 1px;
box-sizing: border-box;
position: relative; }
#status > div#overview {
width: 66.66667%; }
#status .hugvey {
background-image: linear-gradient(to top, #587457, #35a589);
color: white;
@ -52,11 +63,13 @@ body {
text-align: center; }
#story {
position: relative; }
position: relative;
width: calc(100% - 430px); }
#story #controls {
position: absolute;
top: 5px;
left: 5px; }
left: 5px;
white-space: nowrap; }
#story svg#graph {
width: 100%;
height: 100%;
@ -77,6 +90,11 @@ body {
font-size: 11pt;
font-family: sans-serif;
fill: white; }
#story text.msg_id {
transform: translateY(-20px);
opacity: .5; }
#story text.msg_txt {
font-weight: bold; }
#story line {
marker-end: url("#arrowHead");
stroke-width: 2px;
@ -84,6 +102,10 @@ body {
#story line.link--noconditions {
stroke-dasharray: 5 4;
stroke: red; }
#story line.dir-highlight {
stroke-dasharray: 5;
animation: dash-animation 20s infinite linear;
stroke-width: 3px; }
#story label::after {
content: '';
clear: both;
@ -109,6 +131,18 @@ body {
padding: 10px;
margin-bottom: 10px;
background: lightgray; }
#story #msg .direction {
position: relative; }
#story #msg .direction h3 {
margin-top: 0; }
#story #msg .direction .btn--delete {
position: absolute;
top: 5px;
right: 0px; }
#story #msg .direction .condition--add h4 {
margin: 0; }
#story #msg .direction .condition--add h4 + div {
margin-top: 10px; }
#story #nodes g:hover circle,
#story .selectedMsg circle {
stroke: lightgreen;
@ -130,3 +164,33 @@ body {
text-shadow: 2px 2px 2px lightgray,-2px 2px 2px lightgray,2px -2px 2px lightgray,-2px -2px 2px lightgray; }
#story .condition--add {
/* text-align: center; */ }
.flag-icon {
background-size: contain;
background-position: 50%;
background-repeat: no-repeat;
position: relative;
display: inline-block;
width: 1.33333em;
line-height: 1em; }
.flag-icon:before {
content: '\00a0'; }
.flag-icon.flag-icon-squared {
width: 1em; }
.flag-icon.en-GB {
background-image: url("/images/gb.svg"); }
.flag-icon.de-DE {
background-image: url("/images/de.svg"); }
.flag-icon.fr-FR {
background-image: url("/images/fr.svg"); }
.flag-icon.nl-NL {
background-image: url("/images/nl.svg"); }
.divToggle {
cursor: pointer; }
.divToggle:hover {
text-decoration: underline; }
.divToggle.opened + div {
display: block; }
.divToggle + div {
display: none; }

7
www/images/be.svg Normal file
View file

@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icon-css-be" viewBox="0 0 640 480">
<g fill-rule="evenodd" stroke-width="1pt">
<path d="M0 0h213.3v480H0z"/>
<path fill="#ffd90c" d="M213.3 0h213.4v480H213.3z"/>
<path fill="#f31830" d="M426.7 0H640v480H426.7z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 290 B

5
www/images/de.svg Normal file
View file

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icon-css-de" viewBox="0 0 640 480">
<path fill="#ffce00" d="M0 320h640v160H0z"/>
<path d="M0 0h640v160H0z"/>
<path fill="#d00" d="M0 160h640v160H0z"/>
</svg>

After

Width:  |  Height:  |  Size: 213 B

7
www/images/fr.svg Normal file
View file

@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icon-css-fr" viewBox="0 0 640 480">
<g fill-rule="evenodd" stroke-width="1pt">
<path fill="#fff" d="M0 0h640v480H0z"/>
<path fill="#00267f" d="M0 0h213.3v480H0z"/>
<path fill="#f31830" d="M426.7 0H640v480H426.7z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 292 B

15
www/images/gb.svg Normal file
View file

@ -0,0 +1,15 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icon-css-gb" viewBox="0 0 640 480">
<defs>
<clipPath id="a">
<path fill-opacity=".7" d="M-85.3 0h682.6v512H-85.3z"/>
</clipPath>
</defs>
<g clip-path="url(#a)" transform="translate(80) scale(.94)">
<g stroke-width="1pt">
<path fill="#012169" d="M-256 0H768v512H-256z"/>
<path fill="#fff" d="M-256 0v57.2L653.5 512H768v-57.2L-141.5 0H-256zM768 0v57.2L-141.5 512H-256v-57.2L653.5 0H768z"/>
<path fill="#fff" d="M170.7 0v512h170.6V0H170.7zM-256 170.7v170.6H768V170.7H-256z"/>
<path fill="#c8102e" d="M-256 204.8v102.4H768V204.8H-256zM204.8 0v512h102.4V0H204.8zM-256 512L85.3 341.3h76.4L-179.7 512H-256zm0-512L85.3 170.7H9L-256 38.2V0zm606.4 170.7L691.7 0H768L426.7 170.7h-76.3zM768 512L426.7 341.3H503l265 132.5V512z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 837 B

7
www/images/nl.svg Normal file
View file

@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icon-css-nl" viewBox="0 0 640 480">
<g fill-rule="evenodd" stroke-width="1pt" transform="scale(1.25 .9375)">
<rect width="512" height="509.8" fill="#fff" rx="0" ry="0"/>
<rect width="512" height="169.9" y="342.1" fill="#21468b" rx="0" ry="0"/>
<path fill="#ae1c28" d="M0 0h512v170H0z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 364 B

View file

@ -11,16 +11,18 @@
</head>
<body>
<div id="interface">
<div id="interface" class='showStatus'>
<div id='status'>
<div id='overview'>
<dl>
<dt>Uptime</dt>
<dd>{{uptime}}</dd>
<dt>Languages</dt>
<dd v-for="lang in languages" :title="lang.file"
class="btn lang--btn" @click="loadNarrative(lang.code, lang.file)">{{lang.code}}</dd>
</dl>
<ul id='languages'>
<li v-for="lang in languages" :title="lang.file"
class="btn lang--btn" @click="loadNarrative(lang.code, lang.file)"><span :class="['flag-icon', lang.code]"></span> {{lang.code}}</li>
</ul>
</div>
<div class='hugvey' v-for="hv in hugveys"
:class="[{'hugvey--off': hv.status == 'off'},{'hugvey--on': hv.status != 'off'},{'hugvey--paused': hv.status == 'paused'},{'hugvey--running': hv.status == 'running'}]">
@ -43,6 +45,7 @@
</div>
<div id='story'>
<div id="controls">
<span id="current_lang"></span>
<div id="btn-save" class="btn">Save</div>
<div id="btn-addMsg" class="btn">Create message</div>
</div>

File diff suppressed because it is too large Load diff

View file

@ -1,15 +1,31 @@
$status_width: 430px;
$status_width_open: 860px;
body{
font-family: "Noto Sans", sans-serif;
margin: 0;
}
.btn{
.btn, input[type="submit"]{
display:inline-block;
cursor: pointer;
background: #333;
padding: 5px;
color: white;
border-radius: 5px;
margin-right: 5px;
white-space: nowrap;
border: none;
&:hover{
background: #666;
}
}
@keyframes dash-animation {
to {
stroke-dashoffset: -1000;
}
}
#interface{
@ -17,6 +33,9 @@ body{
flex-direction: row;
height: 100vh;
width: 100vw;
&.showStatus{
}
}
#status{
@ -33,6 +52,10 @@ body{
border: solid 1px;
box-sizing: border-box;
position: relative;
&#overview{
width: 100% / 3 * 2;
}
}
.hugvey{
@ -72,11 +95,13 @@ body{
#story{
position: relative;
width: calc(100% - #{$status_width});
#controls{
position:absolute;
top: 5px;
left: 5px;
white-space: nowrap;
}
svg#graph{
width: 100%;
@ -106,16 +131,30 @@ body{
font-size: 11pt;
font-family: sans-serif;
fill: white;
&.msg_id {
transform: translateY(-20px);
opacity: .5;
}
&.msg_txt{
font-weight: bold;
}
}
line{
marker-end: url('#arrowHead');
stroke-width: 2px;
stroke: black;
}
line.link--noconditions{
&.link--noconditions{
stroke-dasharray: 5 4;
stroke: red;
}
&.dir-highlight{
stroke-dasharray: 5;
animation: dash-animation 20s infinite linear;
stroke-width: 3px;
}
}
label::after {
content: '';
clear: both;
@ -148,6 +187,27 @@ body{
margin-bottom: 10px;
background:lightgray;
}
.direction{
position: relative;
h3{
margin-top:0;
}
.btn--delete{
position: absolute;
top: 5px;
right: 0px;
}
.condition--add{
h4{
margin: 0;
}
h4 +div {
margin-top: 10px;
}
}
}
}
#nodes g:hover circle,
@ -180,3 +240,53 @@ body{
/* text-align: center; */
}
}
.flag-icon {
background-size: contain;
background-position: 50%;
background-repeat: no-repeat;
position: relative;
display: inline-block;
width: (4 / 3) * 1em;
line-height: 1em;
&:before {
content: '\00a0';
}
&.flag-icon-squared {
width: 1em;
}
&.en-GB {
background-image: url('/images/gb.svg');
}
&.de-DE {
background-image: url('/images/de.svg');
}
&.fr-FR {
background-image: url('/images/fr.svg');
}
&.nl-NL {
background-image: url('/images/nl.svg');
}
}
.divToggle{
cursor: pointer;
&:hover{
text-decoration: underline;
}
&.opened {
+ div{
display: block;
}
}
+ div{
display: none;
}
}