浏览代码

Merge pull request #444 from HeyPuter/eric/ui-updates

UI Updates
Eric Dubé 11 月之前
父节点
当前提交
dd1d129693

+ 39 - 0
src/UI/Components/ActionCard.js

@@ -0,0 +1,39 @@
+const Component = use('util.Component');
+
+export default def(class ActionCard extends Component {
+    static ID = 'ui.component.ActionCard';
+    static RENDER_MODE = Component.NO_SHADOW;
+
+    static PROPERTIES = {
+        title: {
+            value: 'Title'
+        },
+        info: {},
+        button_text: {},
+        button_style: {},
+        on_click: {},
+        style: {},
+    }
+
+    create_template ({ template }) {
+        $(template).html(/*html*/`
+            <div class="settings-card ${ this.get('style') ? this.get('style') : '' }">
+                <div>
+                    <strong style="display: block">${ this.get('title') }</strong>
+                    <span style="display: block margin-top: 5px">${
+                        this.get('info')
+                    }</span>
+                </div>
+                <div style="flex-grow: 1">
+                    <button class="button ${ this.get('button_style') }" style="float: right;">${
+                        this.get('button_text')
+                    }</button>
+                </div>
+            </div>
+        `);
+    }
+
+    on_ready ({ listen }) {
+        $(this.dom_).find('button').on('click', this.get('on_click') || (() => {}));
+    }
+});

+ 20 - 0
src/UI/Components/Frame.js

@@ -0,0 +1,20 @@
+const Component = use('util.Component');
+
+export default def(class Frame extends Component {
+    static ID = 'ui.component.Frame';
+    static RENDER_MODE = Component.NO_SHADOW;
+
+    static PROPERTIES = {
+        component: {},
+    }
+
+    on_ready ({ listen }) {
+        listen('component', component => {
+            this.dom_.innerHTML = '';
+            if ( ! component ) {
+                return;
+            }
+            component.attach(this.dom_);
+        });
+    }
+});

+ 28 - 0
src/UI/Components/Glyph.js

@@ -0,0 +1,28 @@
+import { Component } from "../../util/Component.js";
+
+export default def(class Glyph extends Component {
+    static ID = 'ui.component.Glyph';
+
+    static PROPERTIES = {
+        size: {
+            value: 24,
+        },
+        codepoint: {
+            value: '✅',
+        },
+    }
+
+    static CSS = `
+        div {
+            text-align: center;
+        }
+    `;
+
+    create_template ({ template }) {
+        template.innerHTML = /*html*/`
+            <div style="font-size: ${this.get('size')}px;">
+                ${this.get('codepoint')}
+            </div>
+        `;
+    }
+});

+ 9 - 0
src/UI/Components/JustHTML.js

@@ -15,4 +15,13 @@ export default def(class JustHTML extends Component {
             $(this.dom_).find('span').html(html);
         });
     }
+
+    _set_dom_based_on_render_mode({ property_values }) {
+        if ( property_values.no_shadow ) {
+            this.dom_ = this;
+            return;
+        }
+
+        return super._set_dom_based_on_render_mode();
+    }
 });

+ 25 - 0
src/UI/Components/NotifCard.js

@@ -0,0 +1,25 @@
+const Component = use('util.Component');
+
+export default def(class NotifCard extends Component {
+    static ID = 'ui.component.NotifCard';
+    static RENDER_MODE = Component.NO_SHADOW;
+
+    static PROPERTIES = {
+        text: { value: 'no text' },
+        style: {},
+    }
+
+    create_template ({ template }) {
+        $(template).html(/*html*/`
+            <div class="settings-card thin-card ${ this.get('style') ? this.get('style') : '' }">
+                <div>
+                    ${ this.get('text') }
+                </div>
+            </div>
+        `);
+    }
+
+    on_ready ({ listen }) {
+        $(this.dom_).find('button').on('click', this.get('on_click') || (() => {}));
+    }
+});

+ 7 - 3
src/UI/Components/Spinner.js

@@ -3,15 +3,19 @@ const Component = use('util.Component');
 export default def(class Spinner extends Component {
     static ID = 'ui.component.Spinner';
 
-    static PROPERTIES = {}
+    static PROPERTIES = {
+        size: {
+            value: 24,
+        },
+    }
     // static RENDER_MODE = Component.NO_SHADOW;
 
     create_template ({ template }) {
-        console.log('template?', template);
+        const size = '' + Number(this.get('size'));
 
         template.innerHTML = /*html*/`
             <div>
-                <svg style="display:block; margin: 0 auto; " xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 24 24">
+                <svg style="display:block; margin: 0 auto; " xmlns="http://www.w3.org/2000/svg" height="${size}" width="${size}" viewBox="0 0 24 24">
                     <title>circle anim</title>
                     <g fill="#212121" class="nc-icon-wrapper">
                         <g class="nc-loop-circle-24-icon-f">

+ 17 - 4
src/UI/Settings/UIWindowSettings.js

@@ -17,6 +17,7 @@
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
+import Placeholder from '../../util/Placeholder.js';
 import UIWindow from '../UIWindow.js'
 
 async function UIWindowSettings(options){
@@ -26,6 +27,7 @@ async function UIWindowSettings(options){
         const svc_settings = globalThis.services.get('settings');
 
         const tabs = svc_settings.get_tabs();
+        const tab_placeholders = [];
 
         let h = '';
 
@@ -42,9 +44,14 @@ async function UIWindowSettings(options){
             h += `<div class="settings-content-container">`;
 
             tabs.forEach((tab, i) => {
-                h += `<div class="settings-content ${i === 0 ? 'active' : ''}" data-settings="${tab.id}">
-                        ${tab.html()}
-                    </div>`;
+                h += `<div class="settings-content ${i === 0 ? 'active' : ''}" data-settings="${tab.id}">`;
+                if ( tab.factory ) {
+                    tab_placeholders[i] = Placeholder();
+                    h += tab_placeholders[i].html;
+                } else {
+                    h += tab.html();
+                }
+                h += `</div>`;
             });
 
             h += `</div>`;
@@ -85,7 +92,13 @@ async function UIWindowSettings(options){
             }
         });
         const $el_window = $(el_window);
-        tabs.forEach(tab => tab.init($el_window));
+        tabs.forEach((tab, i) => {
+            tab.init && tab.init($el_window);
+            if ( tab.factory ) {
+                const component = tab.factory();
+                component.attach(tab_placeholders[i]);
+            }
+        });
 
         $(el_window).on('click', '.settings-sidebar-item', function(){
             const $this = $(this);

+ 4 - 0
src/css/style.css

@@ -3709,6 +3709,10 @@ fieldset[name=number-code] {
     height: 45px;
 }
 
+.thin-card {
+    padding: 0 15px;
+}
+
 .settings-card strong {
     font-weight: 500;
 }

+ 4 - 0
src/init_async.js

@@ -3,6 +3,10 @@ logger.info('start -> async initialization');
 
 import './util/TeePromise.js';
 import './util/Component.js';
+import './UI/Components/Frame.js';
+import './UI/Components/Glyph.js';
+import './UI/Components/ActionCard.js';
+import './UI/Components/NotifCard.js';
 
 logger.info('end -> async initialization');
 globalThis.init_promise.resolve();

+ 2 - 1
src/init_sync.js

@@ -84,7 +84,8 @@ logger.info('start -> blocking initialization');
         }
 
         if ( registry_.classes_m[id] ) {
-            throw new Error(`Class with ID ${id} already registered`);
+            // throw new Error(`Class with ID ${id} already registered`);
+            return;
         }
 
         registry_.classes_m[id] = cls;

+ 29 - 3
src/util/Component.js

@@ -34,14 +34,23 @@ export const Component = def(class Component extends HTMLElement {
         });
     }
 
-    constructor (property_values) {
-        super();
-
+    _set_dom_based_on_render_mode () {
         if ( this.constructor.RENDER_MODE === Component.NO_SHADOW ) {
             this.dom_ = this;
         } else {
             this.dom_ = this.attachShadow({ mode: 'open' });
         }
+    }
+
+    constructor (property_values) {
+        super();
+
+        property_values = property_values || {};
+
+        // We allow a subclass of component to define custom behavior
+        // for the `RENDER_MODE` static property. This is so JustHTML
+        // can have ths `no_shadow: true` option.
+        this._set_dom_based_on_render_mode({ property_values });
 
         this.values_ = {};
 
@@ -104,6 +113,10 @@ export const Component = def(class Component extends HTMLElement {
     }
 
     get (key) {
+        if ( ! this.values_.hasOwnProperty(key) ) {
+            throw new Error(`Unknown property \`${key}\` in ${
+                this.constructor.ID || this.constructor.name}`);
+        }
         return this.values_[key].get();
     }
 
@@ -130,6 +143,11 @@ export const Component = def(class Component extends HTMLElement {
             return;
         }
 
+        if ( destination instanceof ShadowRoot ) {
+            destination.appendChild(this);
+            return;
+        }
+
         if ( destination.$ === 'placeholder' ) {
             destination.replaceWith(this);
             return;
@@ -162,6 +180,14 @@ export const Component = def(class Component extends HTMLElement {
     get_api_ () {
         return {
             listen: (name, callback) => {
+                if ( Array.isArray(name) ) {
+                    const names = name;
+                    for ( const name of names ) {
+                        this.values_[name].sub((_, more) => {
+                            callback(this, { ...more, name });
+                        });
+                    }
+                }
                 this.values_[name].sub(callback);
                 callback(this.values_[name].get(), {});
             }

+ 2 - 2
src/util/Placeholder.js

@@ -18,7 +18,7 @@
  * 
  * @returns {PlaceholderReturn}
  */
-const Placeholder = () => {
+const Placeholder = def(() => {
     const id = Placeholder.get_next_id_();
     return {
         $: 'placeholder',
@@ -29,7 +29,7 @@ const Placeholder = () => {
             place.replaceWith(el);
         }
     };
-};
+}, 'util.Placeholder');
 
 const anti_collision = `94d2cb6b85a1`; // Arbitrary random string
 Placeholder.next_id_ = 0;