[beast: 45/70] EBEAST: move version information into a modal About dialog



commit 8e24101a98c6df7632b04cee167eb3be7e864bd5
Author: Tim Janik <timj gnu org>
Date:   Mon Mar 6 19:06:13 2017 +0100

    EBEAST: move version information into a modal About dialog
    
    Signed-off-by: Tim Janik <timj gnu org>

 ebeast/.eslintrc.js        |    1 +
 ebeast/app.less            |    1 +
 ebeast/assets/dialogs.js   |  106 ++++++++++++++++++++++++++++++++++++++++++++
 ebeast/assets/dialogs.less |   38 ++++++++++++++++
 ebeast/index.html          |   73 ++++++++++++++++--------------
 5 files changed, 184 insertions(+), 35 deletions(-)
---
diff --git a/ebeast/.eslintrc.js b/ebeast/.eslintrc.js
index a79325e..510c9b8 100644
--- a/ebeast/.eslintrc.js
+++ b/ebeast/.eslintrc.js
@@ -9,6 +9,7 @@ module.exports = {
     "Electron": false,
     "Mithril": false,
     "Bse": false,
+    "App": false,
     "module": true /* allow mods */
   },
   "rules": {
diff --git a/ebeast/app.less b/ebeast/app.less
index d4fda52..5b13baa 100644
--- a/ebeast/app.less
+++ b/ebeast/app.less
@@ -1,4 +1,5 @@
 @import "assets/widgets.less";
+@import "assets/dialogs.less";
 
 /* == Settings == */
 @theme-foreground:             #ffffff;
diff --git a/ebeast/assets/dialogs.js b/ebeast/assets/dialogs.js
new file mode 100644
index 0000000..4cbf8e9
--- /dev/null
+++ b/ebeast/assets/dialogs.js
@@ -0,0 +1,106 @@
+'use strict';
+const m = Mithril;
+
+// == ModalDialog ==
+/**
+ * Show a popup dialog.
+ * Attributes:
+ * - title: dialog title vnode
+ * - buttons: list of vnodes
+ * - onclose: callback for dialog closing
+ */
+const ModalDialog = {
+  view: function (vnode) {
+    const child_attrs = {
+      title: undefined,
+      buttons: undefined,
+      onclose: undefined,
+      __proto__: vnode.attrs
+    };
+    let divs = [
+      m ('.ModalDialogArea.vbox', [
+       m ('.maxbox'), /* eat space for vertical centering */
+       m ('.minbox', [
+         m ('.DialogSpacer.hbox', [
+           m ('.maxbox.w100'), /* eat space for horizontal centering */
+           m ('.minbox.shrinkbox', [
+             m ('.DialogRack', [
+               m ('.Dialog.vbox', child_attrs, [
+                 m ('.DialogInside.vbox', [
+                   m ('.Header.minbox', [
+                     m ('.hbox.w100', [
+                       m ('.Title.maxbox', vnode.attrs.title),
+                       m ('div.minbox.Closer[autofocus]', {
+                         style: 'cursor: default',
+                         onclick: (event) => {
+                           if (vnode.attrs.onclose)
+                             vnode.attrs.onclose (event);
+                         }
+                       }, 'X'),
+                     ]),
+                   ]),
+                   m ('.Contents.maxbox', [
+                     m ('.DialogHS', vnode.children),
+                   ]),
+                   m ('.DialogControls.minbox', [
+                     m ('.DialogButtons', [
+                       vnode.attrs.buttons,
+                     ])
+                   ]),
+                 ]),
+               ]),
+             ]),
+           ]),
+           m ('.maxbox.w100'), /* eat space for horizontal centering */
+         ]),
+       ]),
+       m ('.maxbox'), /* eat space for vertical centering */
+      ]),
+    ];
+    return m.fragment ({}, divs);
+  }
+};
+module.exports.ModalDialog = ModalDialog;
+
+// == About ==
+function version_rows () {
+  const App = Electron.app;
+  const os = require ('os');
+  return [
+    m ('tr', [ m ('th', 'Application:'),       m ('td', App.getName() + ' ' + App.getVersion()) ]),
+    m ('tr', [ m ('th', 'OS:'),                        m ('td', process.platform + ' ' + process.arch + ' (' 
+ os.release() + ')') ]),
+    m ('tr', [ m ('th', 'Electron:'),          m ('td', process.versions.electron) ]),
+    m ('tr', [ m ('th', 'Chrome:'),            m ('td', process.versions.chrome) ]),
+    m ('tr', [ m ('th', 'User Agent:'),                m ('td', navigator.userAgent) ]),
+    m ('tr', [ m ('th', 'V8:'),                        m ('td', process.versions.v8) ]),
+    m ('tr', [ m ('th', 'Node.js:'),           m ('td', process.versions.node) ]),
+    m ('tr', [ m ('th', 'Bse:'),               m ('td', Bse.server.get_version()) ]),
+    m ('tr', [ m ('th', 'Vorbis:'),            m ('td', Bse.server.get_vorbis_version()) ]),
+    m ('tr', [ m ('th', 'Libuv:'),             m ('td', process.versions.uv) ]),
+    m ('tr', [ m ('th', 'Executable:'),                m ('td', m('p',App.getPath ('exe'))) ]),
+    m ('tr', [ m ('th', 'Mithril'),            m ('td', Mithril.version) ]),
+    m ('tr', [ m ('th', 'jQuery'),             m ('td', jQuery.fn.jquery) ]),
+    m ('tr', [ m ('th', 'Working Dir:'),       m ('td', App.getAppPath()) ]),
+    m ('tr', [ m ('th', 'Desktop Dir:'),       m ('td', App.getPath ('desktop')) ]),
+    m ('tr', [ m ('th', 'Config Path:'),       m ('td', App.getPath ('userData')) ]),
+    m ('tr', [ m ('th', 'Music Path:'),                m ('td', App.getPath ('music')) ]),
+  ];
+}
+module.exports.about_dialog = function () {
+  if (!App.show_about)
+    return null;
+  function doclose (ev) {
+    App.show_about = false;
+  }
+  return (
+    m (ModalDialog, { class: 'About',
+                     title: 'About BEAST',
+                     onclose: doclose,
+                     buttons: [
+                       m ('button', [ 'Toggle', ]),
+                       m ('button[autofocus]', { onclick: doclose }, [ 'Close', ]),
+                       m ('button', [ 'Help', ]),
+                     ] },
+       m ('table', version_rows())
+      ));
+};
diff --git a/ebeast/assets/dialogs.less b/ebeast/assets/dialogs.less
new file mode 100644
index 0000000..140a498
--- /dev/null
+++ b/ebeast/assets/dialogs.less
@@ -0,0 +1,38 @@
+/* == Dialog == */
+.ModalDialogArea               { z-index: 999999; position: fixed; top: 0; left: 0; right: 0; bottom: 0; }
+.DialogRack                    { height: initial; /* assign concrete height to allow scrolling inside */
+                                 /* Note, centering with translate(-50%, -50%); messes up chrome's pixel 
alignment */
+                                 max-width: 100%; }
+.DialogSpacer                  { max-width: 100% }
+.Dialog                                { max-height: 100%; } /* constrain dialog on overflow */
+.Dialog .Header                        { width: 100%; }
+.Dialog .Header .Title         { display: block; font-size: 1.3em; }
+.Dialog .Contents              { flex-shrink: 1; max-width: 100%; } /* shrink on overflow */
+.Dialog .DialogHS              { overflow-x: auto; max-width: 100%; }
+.DialogInside                  { max-width: 100%; }
+.Dialog .DialogControls                { width: 100%; }
+.Dialog .DialogButtons         { width: 100%; }
+.Dialog .DialogButtons > *     { margin: 0.1em 0.7em; }
+/* looks */
+.ModalDialogArea               { background-color: fadeout(darken(@theme-background, 15%), 15%); } /* 
backdrop */
+.DialogRack                    { box-shadow: 0px 0px 7px 3px rgba(0, 0, 0, 0.25);
+                                 /*border: 1px solid @panel-background-border;*/
+                               }
+.Dialog                                { border-top: 3px solid @panel-background-light; border-left: 3px 
solid @panel-background-light;
+                                 border-bottom: 3px solid @panel-background-dark; border-right: 3px solid 
@panel-background-dark; }
+.DialogInside                  { padding: 0; .gradient-01-bg; }
+.DialogRack, .Dialog,
+.DialogInside                  { border-radius: @theme-border-radius; }
+.Dialog .Header                        { background-color: darken(@theme-background, 8%); padding: .5em .7em;
+                                 font-weight: bold; text-align: center; }
+.Dialog .Header .hbox          { align-items: center; }
+.Dialog .Header .Closer                { background-color: darken(@theme-background, 25%); padding: 5px; }
+.Dialog .Contents              { padding: 1em .7em; }
+.Dialog .DialogControls                { background-color: darken(@theme-background, 8%); padding: 1em .7em;
+                                 text-align: center; }
+
+/* == About Dialog == */
+.About.Dialog .content { max-height: 100%; overflow: auto; }
+.About.Dialog table    { table-layout: fixed; max-width: 100%; }
+.About.Dialog th       { text-align: right; padding-right: .5em; min-width: 15em; }
+.About.Dialog td       { font-family: monospace; width: 70%; overflow-wrap: break-word; }
diff --git a/ebeast/index.html b/ebeast/index.html
index b86c6b0..481df07 100644
--- a/ebeast/index.html
+++ b/ebeast/index.html
@@ -1,51 +1,54 @@
 <!DOCTYPE html> <!-- GNU LGPL v2.1+: http://www.gnu.org/licenses/lgpl.html -->
-<html>
-<head>
+<html><head>
+
   <title>BEAST</title>
 
   <link rel="stylesheet" href="objects/app.css">
 
-</head>
-<body>
-
   <script>
     'use strict';
     const Electron = require ('electron').remote;
     const Bse = require ('./v8bse/v8bse.node');
     const Mithril = require ('mithril');
     window.$ = window.jQuery = require ('jquery');
+    const Dialogs = require ('./assets/dialogs.js');
+    "" + Bse; // FIXME 'unused' warnings
+    const App = {
+      show_about: true,
+      __proto__ : Electron.app
+    };
+    Object.preventExtensions (App);
   </script>
 
-  <div style="margin: 1em auto; overflow: auto; max-height: 100%; max-width: 100%;">
-    <h1 style="float:right; margin-top: 0">BEAST/BSE</h1>
-    <style>
-     table.version-table th { text-align: right; padding-right: .5em; }
-     table.version-table td { font-family: monospace; }
-    </style>
-    <script>
-      const app = Electron.app;
-      const os = require ('os');
-    </script>
-    <table class="version-table">
-      <tr> <th> Application: </th> <td><script> document.write (app.getName() + ' ' + app.getVersion()); 
</script></td> </tr>
-      <tr> <th> OS: </th>          <td><script> document.write (process.platform + ' ' + process.arch + ' (' 
+ os.release() + ')'); </script></td> </tr>
-      <tr> <th> Electron: </th>    <td><script> document.write (process.versions.electron); </script></td> 
</tr>
-      <tr> <th> Chrome: </th>      <td><script> document.write (process.versions.chrome); </script></td> 
</tr>
-      <tr> <th> V8: </th>          <td><script> document.write (process.versions.v8); </script></td> </tr>
-      <tr> <th> Node.js: </th>     <td><script> document.write (process.versions.node); </script></td> </tr>
-      <tr> <th> Bse: </th>         <td><script> document.write (Bse.server.get_version()); </script></td> 
</tr>
-      <tr> <th> Vorbis: </th>      <td><script> document.write (Bse.server.get_vorbis_version()); 
</script></td> </tr>
-      <tr> <th> Libuv: </th>       <td><script> document.write (process.versions.uv); </script></td> </tr>
-      <tr> <th> Executable: </th>  <td><script> document.write (app.getPath ('exe')); </script></td> </tr>
-      <tr> <th> Working Dir: </th> <td><script> document.write (app.getAppPath()); </script></td> </tr>
-      <tr> <th> Desktop Dir: </th> <td><script> document.write (app.getPath ('desktop')); </script></td> 
</tr>
-      <tr> <th> Config Path: </th> <td><script> document.write (app.getPath ('userData')); </script></td> 
</tr>
-      <tr> <th> Music Path: </th>  <td><script> document.write (app.getPath ('music')); </script></td> </tr>
-    </table>
+</head><body>
 
-    <button> Close </button>
-  </div>
+  <script>
+    Dialogs.toggle_about = function() {
+      const m = Mithril;
+      return (
+       m ('button',
+          { onclick: function () { App.show_about = !App.show_about; } },
+          'Toggle About')
+      );
+    };
+  </script>
 
-</body>
-</html>
+  <script>
+    const MithrilApp = {
+      view: function () {
+       const m = Mithril;
+       const app_body = [
+         Dialogs.toggle_about(),
+         Dialogs.about_dialog(),
+       ];
+       return (
+         m ('div#mithril.Mithril', {
+           style: 'position: absolute; top: 0; left: 0; right: 0; bottom: 0;',
+         }, app_body)
+       );
+      }
+    };
+    Mithril.mount (document.body, MithrilApp);
+  </script>
 
+</body></html>


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]