Skip to content

Commit

Permalink
UI/UX Improvements (#167)
Browse files Browse the repository at this point in the history
* Monospace font for OS commands.

* Going with FontAwesome terminal icon.

* No 'OS' since we have icon, labeling 'ON' and 'OFF' for commands.

* Labeling OFF for confirmation setting.

* Prefexing GPIO input with BCM helper.

* Moving and scaling icon previews.

* Captions for previews.

* Minor: shorter label.

* Better preview caption appearance.

* Adding help icon opening pins enumeration docs.

* Reducing the help block on inverted relays.

* Introducing CSS asset (not complete).

* Easier CSS references and better markup.

* CSS extracting complete.

* Better info icons.

* Ref: extracting css class bindings into 'let' ones.

* Slightly smaller ON/OFF labels on the left side.

* Updating tests.

* UX: fading the tabs switching.

* Updating snapshot.

* Neat: icon preview border radius.

* Changelog: the future 3.5.0.
  • Loading branch information
RobinTail authored Aug 11, 2023
1 parent 106dbfa commit e7149e2
Show file tree
Hide file tree
Showing 6 changed files with 1,802 additions and 987 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

## Version 3

### 3.5.0

- A couple more improvements for the UI/UX.
- This version introduces a new asset — CSS file.

![UI](https://user-images.githubusercontent.com/13189514/260043096-38e10e10-1285-401f-bf1f-18aa9e397c25.png)

### 3.4.0

- New feature: event-based automation.
Expand Down
5 changes: 4 additions & 1 deletion octoprint_octorelay/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,10 @@ def get_ui_vars():
}

# Plugin's asset files to automatically include in the core UI
ASSETS = { "js": [ "js/octorelay.js" ] }
ASSETS = {
"js": [ "js/octorelay.js" ],
"css": [ "css/octorelay.css" ]
}

# Public interface commands:
UPDATE_COMMAND = "update"
Expand Down
63 changes: 63 additions & 0 deletions octoprint_octorelay/static/css/octorelay.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#settings_plugin_octorelay .tab-content {
position: relative
}

#settings_plugin_octorelay .btn > input[type='radio'] {
display: none
}

#settings_plugin_octorelay input.code {
font-family: monospace;
}

#settings_plugin_octorelay .input-prepend > .add-on.tiny {
font-size: 0.45rem;
font-weight: 600;
}

#settings_plugin_octorelay .help-inline a.same-color {
color: inherit;
}

#settings_plugin_octorelay .control-label span.label {
zoom: 0.85; /* not scale */
}

#settings_plugin_octorelay .fa-info {
border: 2px solid currentColor;
padding: 3px 8px;
border-radius: 50%;
scale: 0.6;
transform-origin: left;
}

#settings_plugin_octorelay .preview {
display: flex;
width: 24px;
height: 24px;
overflow: hidden;
line-height: unset;
font-size: 1.25rem;
align-items: center;
justify-content: center;
position: absolute;
top: 0;
scale: 3;
transform-origin: top left;
border: 0.3px dashed #00000066;
box-sizing: content-box;
border-radius: 2px;
}

#settings_plugin_octorelay .preview-caption {
position: absolute;
top: 75px;
width: 75px;
display: flex;
justify-content: center;
align-items: baseline;
gap: 0.5ch;
white-space: nowrap;
scale: 0.75;
transform-origin: top;
}
144 changes: 95 additions & 49 deletions octoprint_octorelay/templates/octorelay_settings.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -17,26 +17,26 @@
{% for n in range(1,9) %}
<div
id="relay_settings_{{n}}"
class="tab-pane"
data-bind="css: { active: 1 === {{n}} }, using: settings.plugins.octorelay.r{{n}}"
class="tab-pane fade"
data-bind="css: { 'active in': 1 === {{n}} }, using: settings.plugins.octorelay.r{{n}}"
>

<div class="control-group">
<label class="control-label">{{ _('Active') }}</label>
<div class="controls">
<div class="btn-group">
{% for value, option in plugin_octorelay_boolean.items() %}
<label
class="btn"
data-bind="css: { 'active btn-{{option.color}}': active() === {{value}}, 'btn-default': active() !== {{value}} }"
>
<!--ko let: { classBinding: {
'active btn-{{option.color}}': active() === {{value}},
'btn-default': active() !== {{value}}
} } -->
<label class="btn" data-bind="css: classBinding">
<input
type="radio"
style="display: none"
data-bind="checkedValue: {{value}}, checked: active"
/>
{{ _(option.caption) }}
</label>
<!--/ko-->
{% endfor %}
</div>
<span class="help-block" data-bind="hidden: active">
Expand All @@ -46,24 +46,59 @@
</div>

<div data-bind="visible: active">
{% for state, offset in {"on": 315, "off": 415}.items() %}
<div class="preview" style="left: {{offset}}px;" data-bind="html: icon_{{state}}"></div>
<div class="preview-caption" style="left: {{offset}}px">
<span class="label">{{ _(state.upper()) }}</span>
{{ _('preview') }}
</div>
{% endfor %}

<div class="control-group">
<label class="control-label">{{ _('Label') }}</label>
<div class="controls">
<input type="text" class="input-small" data-bind="value: label_text">
</div>
</div>

{% for state in ["on", "off"] %}
<div class="control-group">
<label class="control-label">
{{ _('Icon') }}
<span class="label">{{ _(state.upper()) }}</span>
</label>
<div class="controls">
<div class="input-prepend">
<span class="add-on"><i class="fa fa-code fa-sm"></i></span>
<input
type="text"
class="input-xlarge code"
data-bind="value: icon_{{state}}"
>
</div>
</div>
</div>
{% endfor %}

<div class="control-group">
<label class="control-label">{{ _('GPIO Number') }}</label>
<div class="controls">
<input
id="relay_pin-input{{n}}"
type="number"
min="1"
max="27"
class="input-small"
data-bind="value: relay_pin"
>
<div class="input-prepend">
<span class="add-on tiny">BCM</span>
<input
id="relay_pin-input{{n}}"
type="number"
min="1"
max="27"
class="input-mini"
data-bind="value: relay_pin"
>
</div>
<span class="help-inline">
<a href="https://pinout.xyz/" target="_blank" class="same-color">
<i class="fa fa-info"></i>
</a>
</span>
</div>
</div>

Expand All @@ -72,54 +107,53 @@
<div class="controls">
<div class="btn-group">
{% for value, option in plugin_octorelay_boolean.items() %}
<label
class="btn"
data-bind="css: { 'active btn-{{option.color}}': inverted_output() === {{value}}, 'btn-default': inverted_output() !== {{value}} }"
>
<!--ko let: { classBinding: {
'active btn-{{option.color}}': inverted_output() === {{value}},
'btn-default': inverted_output() !== {{value}}
} } -->
<label class="btn" data-bind="css: classBinding">
<input
type="radio"
style="display: none"
data-bind="checkedValue: {{value}}, checked: inverted_output"
/>
{{ _(option.caption) }}
</label>
<!--/ko-->
{% endfor %}
</div>
<span class="help-block">
{{ _('For normally closed relays: the electrical circuit is closed without applying current and the relay connects the power to the load.') }}
<span class="help-inline">
{{ _('For normally closed relays') }}
<a
href="https://www.google.com/search?q=what+normally+closed+relay+is"
target="_blank"
class="same-color"
>
<i class="fa fa-info"></i>
</a>
</span>
</div>
</div>

{% for state in ["on", "off"] %}
<div class="control-group">
<label class="control-label">{{ _('Icon') }} {{ _(state.upper()) }}</label>
<div class="controls">
<input type="text" class="input-large" data-bind="value: icon_{{state}}">
<div
style="display: inline-flex; width: 24px; height: 24px; margin-left: 8px; overflow: hidden; line-height: unset; vertical-align: middle; font-size: 1.25rem; align-items: center; justify-content: center;"
data-bind="html: icon_{{state}}"
></div>
</div>
</div>
{% endfor %}

<div class="control-group">
<label class="control-label">{{ _('Warn when turning OFF') }}</label>
<label class="control-label">
{{ _('Warn if turning') }}
<span class="label">{{ _('OFF') }}</span>
</label>
<div class="controls">
<div class="btn-group">
{% for value, option in plugin_octorelay_boolean.items() %}
<label
class="btn"
data-bind="css: { 'active btn-{{option.color}}': confirm_off() === {{value}}, 'btn-default': confirm_off() !== {{value}} }"
>
<!--ko let: { classBinding: {
'active btn-{{option.color}}': confirm_off() === {{value}},
'btn-default': confirm_off() !== {{value}}
} } -->
<label class="btn" data-bind="css: classBinding">
<input
type="radio"
style="display: none"
data-bind="checkedValue: {{value}}, checked: confirm_off"
/>
{{ _(option.caption) }}
</label>
<!--/ko-->
{% endfor %}
</div>
</div>
Expand All @@ -131,16 +165,18 @@
<div class="controls">
<div class="btn-group">
{% for value, state in plugin_octorelay_tristate.items() %}
<label
class="btn"
data-bind="css: { 'active btn-{{state.color}}': state() === {{value}}, 'btn-default': state() !== {{value}} }"
>
<!--ko let: { classBinding: {
'active btn-{{state.color}}': state() === {{value}},
'btn-default': state() !== {{value}}
} } -->
<label class="btn" data-bind="css: classBinding">
<input
type="radio"
style="display: none" data-bind="checkedValue: {{value}}, checked: state"
data-bind="checkedValue: {{value}}, checked: state"
/>
{{ _(state.caption) }}
</label>
<!--/ko-->
{% endfor %}
</div>
<div class="input-prepend input-append" data-bind="hidden: state() === null">
Expand All @@ -154,9 +190,19 @@

{% for state in ["on", "off"] %}
<div class="control-group">
<label class="control-label">{{ _('OS Command') }} {{ _(state.upper()) }}</label>
<label class="control-label">
{{ _('Command') }}
<span class="label">{{ _(state.upper()) }}</span>
</label>
<div class="controls">
<input type="text" class="input-large" data-bind="value: cmd_{{state}}">
<div class="input-prepend">
<span class="add-on"><i class="fa fa-terminal fa-sm"></i></span>
<input
type="text"
class="input-xlarge code"
data-bind="value: cmd_{{state}}"
>
</div>
</div>
</div>
{% endfor %}
Expand Down
Loading

0 comments on commit e7149e2

Please sign in to comment.