Improvements to interface
This commit is contained in:
parent
8cc9cea24f
commit
acbd6fdd94
11 changed files with 675 additions and 415 deletions
|
@ -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)
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,13 +90,22 @@ 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;
|
||||
stroke: black; }
|
||||
#story line.link--noconditions {
|
||||
stroke-dasharray: 5 4;
|
||||
stroke: red; }
|
||||
#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
7
www/images/be.svg
Normal 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
5
www/images/de.svg
Normal 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
7
www/images/fr.svg
Normal 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
15
www/images/gb.svg
Normal 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
7
www/images/nl.svg
Normal 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 |
|
@ -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
|
@ -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,15 +131,29 @@ 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{
|
||||
stroke-dasharray: 5 4;
|
||||
stroke: red;
|
||||
|
||||
&.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: '';
|
||||
|
@ -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,
|
||||
|
@ -179,4 +239,54 @@ body{
|
|||
.condition--add{
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue