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

UI Updates
This commit is contained in:
Eric Dubé
2024-05-30 16:48:28 -04:00
committed by GitHub
12 changed files with 186 additions and 13 deletions
+39
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -3709,6 +3709,10 @@ fieldset[name=number-code] {
height: 45px;
}
.thin-card {
padding: 0 15px;
}
.settings-card strong {
font-weight: 500;
}
+4
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;