Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 36 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -524,7 +524,9 @@ or other CSS effects. Add styles with the following functions:

```
setPanelStyle(uint16_t id, String style);
setElementStyle(uint16_t id, String style)
setPanelStyle(uint16_t id, String style);
setElementStyle(uint16_t id, String style);
setPanelClass(uint16_t id, String pClass);
```

A panel style is applied to the panel on which the UI element is placed, an element style is applied to the element itself.
Expand All @@ -551,6 +553,8 @@ The [completeExample](examples/completeExample/completeExample.cpp) example incl

![More Inline Styles](docs/ui_inlinestyles2.png)

You can also add custom CSS classes to the panel of a control using `setPanelClass`. This allows you to apply arbitrary CSS classes to your controls.


### Disabling Controls

Expand Down Expand Up @@ -686,6 +690,37 @@ void setup() {

The custom JavaScript is served at `/js/custom.js` and is automatically included in the `index.htm` file.

### User-defined CSS

You can add your own custom CSS to the UI. This allows you to globaly style the UI.

To add custom CSS, call `ESPUI.setCustomCSS()` before `ESPUI.begin()`. The argument to `setCustomCSS()` is a C-string containing the CSS code. This string must remain valid for the lifetime of the ESPUIClass instance.

```cpp
const char* myCustomCSS = ".test { color: red; }";

void setup() {
// ...
ESPUI.setCustomCSS(myCustomCSS);
ESPUI.begin("ESPUI Control");
// ...
}
```

The custom CSS is served at `/css/custom.css` and is automatically included in the `index.htm` file.

This can be used in conjunction with `setPanelClass` to apply custom CSS styles to controls. For example:

```cpp
// Make the value span of the panel red on error
ESPUI.setCustomCSS(".err span { color: red; }");
// Set the panel class to 'err' to make its value red
ESPUI.setPanelClass(<id>, "err");
```

For simpler styles without using classes, you can use `setElementStyle` or `setPanelStyle` instead.



# Notes for Development

Expand Down
1 change: 1 addition & 0 deletions data/index.htm
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
/>
<link rel="stylesheet" href="/css/normalize.css" />
<link rel="stylesheet" href="/css/style.css" />
<link rel="stylesheet" href="/css/custom.css" />

<script src="/js/zepto.min.js"></script>
<script src="/js/slider.js"></script>
Expand Down
2 changes: 1 addition & 1 deletion data/index.min.htm
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<!doctype html><meta charset=utf-8><title>Control</title><meta content="width=device-width,initial-scale=1" name=viewport><link rel="shortcut icon" href=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAPFBMVEUAAACA1VWR21qQ2liR3FqR3FqS3VuR3VqR3VuR3VqO21mS21uS3FqS3FqS21uJ2GKQ21qR3FuR3FoAAAB/3Gu7AAAAEnRSTlMABoA3kPBwz8i5Kzioxg4NVcU3uEJHAAAAAWJLR0QAiAUdSAAAAAlwSFlzAAAN1wAADdcBQiibeAAAAAd0SU1FB+EFEhcEM+HpYwQAAABYSURBVBjThY/JDsAgCESt4lpX/v9jLQZJ6qF9t3khAyj1xXUKbQ4BVowDwqOYgExkkW4iY6lPaF06RqM8YItOuRbMaz6xjbsusDAW/drplBg47jP696cXE8bPA1eUDeK2AAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE3LTA1LTE4VDIzOjA0OjUxKzAyOjAwxE59ewAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNy0wNS0xOFQyMzowNDo1MSswMjowMLUTxccAAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb7jwaAAAAAElFTkSuQmCC><link href=/css/normalize.css rel=stylesheet><link href=/css/style.css rel=stylesheet><script src=/js/zepto.min.js></script><script src=/js/slider.js></script><script src=/js/graph.js></script><script src=/js/controls.js></script><script src=/js/tabbedcontent.js></script><script src=/js/custom.js></script><body onload=javascript:start();><div><h4><div id=mainHeader>Control</div> <span class=label id=conStatus>Offline</span></h4></div><hr><div class=container><div class="row u-full-width" id=row></div><ul class="navigation navigation-tabs u-full-width" id=tabsnav></ul><div class="tabscontent u-full-width" id=tabscontent></div></div>
<!DOCTYPE html><html> <head><meta charset=utf-8><title>Control</title><meta name=viewport content="width=device-width, initial-scale=1"><link rel="shortcut icon" href=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAPFBMVEUAAACA1VWR21qQ2liR3FqR3FqS3VuR3VqR3VuR3VqO21mS21uS3FqS3FqS21uJ2GKQ21qR3FuR3FoAAAB/3Gu7AAAAEnRSTlMABoA3kPBwz8i5Kzioxg4NVcU3uEJHAAAAAWJLR0QAiAUdSAAAAAlwSFlzAAAN1wAADdcBQiibeAAAAAd0SU1FB+EFEhcEM+HpYwQAAABYSURBVBjThY/JDsAgCESt4lpX/v9jLQZJ6qF9t3khAyj1xXUKbQ4BVowDwqOYgExkkW4iY6lPaF06RqM8YItOuRbMaz6xjbsusDAW/drplBg47jP696cXE8bPA1eUDeK2AAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE3LTA1LTE4VDIzOjA0OjUxKzAyOjAwxE59ewAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNy0wNS0xOFQyMzowNDo1MSswMjowMLUTxccAAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb7jwaAAAAAElFTkSuQmCC><link rel=stylesheet href=/css/normalize.css><link rel=stylesheet href=/css/style.css><link rel=stylesheet href=/css/custom.css><script src=/js/zepto.min.js></script><script src=/js/slider.js></script><script src=/js/graph.js></script><script src=/js/controls.js></script><script src=/js/tabbedcontent.js></script><script src=/js/custom.js></script></head> <body onload=javascript:start();> <div> <h4> <div id=mainHeader>Control</div> <span id=conStatus class=label>Offline</span> </h4> </div> <hr> <div class=container> <div id=row class="row u-full-width"></div> <ul id=tabsnav class="navigation navigation-tabs u-full-width"></ul> <div id=tabscontent class="tabscontent u-full-width"></div> </div> </body> </html>
16 changes: 13 additions & 3 deletions data/js/controls.js
Original file line number Diff line number Diff line change
Expand Up @@ -791,6 +791,14 @@ function start() {
$("#id" + data.id).hide();
}

if (data.hasOwnProperty('panelClass')) {
var element = $("#id" + data.id);
var baseClass = element.attr("data-base-class");
if (baseClass) {
element.attr("class", baseClass + " " + data.panelClass);
}
}

if (data.type == UPDATE_SLIDER) {
element.removeClass(
"slider-turquoise slider-emerald slider-peterriver slider-wetasphalt slider-sunflower slider-carrot slider-alizarin"
Expand Down Expand Up @@ -990,6 +998,7 @@ var rangeSlider = function (isDiscrete) {

var addToHTML = function (data) {
panelStyle = data.hasOwnProperty('panelStyle') ? " style='" + data.panelStyle + "' " : "";
panelClass = data.hasOwnProperty('panelClass') ? " " + data.panelClass + " " : "";
panelwide = data.hasOwnProperty('wide') ? "wide" : "";

if (!data.hasOwnProperty('parentControl') || $("#tab" + data.parentControl).length > 0) {
Expand All @@ -1013,14 +1022,15 @@ var addToHTML = function (data) {
case UI_GAUGE:
case UI_ACCEL:
case UI_FILEDISPLAY:
html = "<div id='id" + data.id + "' " + panelStyle + " class='two columns " + panelwide + " card tcenter " +
colorClass(data.color) + "'><h5>" + data.label + "</h5><hr/>" +
var baseClass = "two columns " + panelwide + " card tcenter " + colorClass(data.color);
html = "<div id='id" + data.id + "' " + panelStyle + " class='" + baseClass + panelClass + "' data-base-class='" + baseClass + "'><h5>" + data.label + "</h5><hr/>" +
elementHTML(data) +
"</div>";
break;

case UI_SEPARATOR:
html = "<div id='id" + data.id + "' " + panelStyle + " class='sectionbreak columns'>" +
var baseClass = "sectionbreak columns";
html = "<div id='id" + data.id + "' " + panelStyle + " class='" + baseClass + panelClass + "' data-base-class='" + baseClass + "'>" +
"<h5>" + data.label + "</h5><hr/></div>";
break;
case UI_TIME:
Expand Down
6 changes: 3 additions & 3 deletions data/js/controls.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

31 changes: 31 additions & 0 deletions src/ESPUI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,25 @@
// js: JavaScript code as a C-string. Must remain valid for the lifetime of the ESPUIClass instance.
static const char* customJS = nullptr;

// Optional user-defined CSS to be included in the UI.
// Served at /css/custom.css, which is automatically included in index.htm.
// css: CSS code as a C-string. Must remain valid for the lifetime of the ESPUIClass instance.
static const char* customCSS = nullptr;

// Set custom JavaScript to be included in the UI.
// js: JavaScript code as a C-string. Must remain valid for the lifetime of the ESPUIClass instance.
void ESPUIClass::setCustomJS(const char* js)
{
customJS = js;
}

// Set custom CSS to be included in the UI.
// css: CSS code as a C-string. Must remain valid for the lifetime of the ESPUIClass instance.
void ESPUIClass::setCustomCSS(const char* css)
{
customCSS = css;
}

static String heapInfo(const __FlashStringHelper* mode)
{
String result;
Expand Down Expand Up @@ -757,6 +769,16 @@ void ESPUIClass::setPanelStyle(uint16_t id, const String& style, int clientId)
}
}

void ESPUIClass::setPanelClass(uint16_t id, const String& pClass, int clientId)
{
Control* control = getControl(id);
if (control)
{
control->panelClass = pClass;
updateControl(control, clientId);
}
}

void ESPUIClass::setElementStyle(uint16_t id, const String& style, int clientId)
{
Control* control = getControl(id);
Expand Down Expand Up @@ -1293,6 +1315,15 @@ void ESPUIClass::begin(const char* _title, const char* username, const char* pas
request->send(200, "application/javascript", customJS ? customJS : "");
});

server->on("/css/custom.css", HTTP_GET, [](AsyncWebServerRequest* request) {
if (ESPUI.basicAuth && !request->authenticate(ESPUI.basicAuthUsername, ESPUI.basicAuthPassword))
{
return request->requestAuthentication();
}

request->send(200, "text/css", customCSS ? customCSS : "");
});

server->begin();

#if defined(DEBUG_ESPUI)
Expand Down
6 changes: 6 additions & 0 deletions src/ESPUI.h
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ class ESPUIClass
void addGraphPoint(uint16_t id, int nValue, int clientId = -1);

void setPanelStyle(uint16_t id, const String& style, int clientId = -1);
void setPanelClass(uint16_t id, const String& pClass, int clientId = -1);
void setElementStyle(uint16_t id, const String& style, int clientId = -1);
void setInputType(uint16_t id, const String& type, int clientId = -1);

Expand All @@ -206,6 +207,11 @@ class ESPUIClass
// This is intentionally not a String to avoid dynamic memory allocation.
void setCustomJS(const char* js);

// Set optional user-defined CSS to be included in the UI.
// css: CSS code as a C-string. Must remain valid for the lifetime of the ESPUIClass instance.
// This is intentionally not a String to avoid dynamic memory allocation.
void setCustomCSS(const char* css);

// Variables
const char* ui_title = "ESPUI"; // Store UI Title and Header Name
Control* controls = nullptr;
Expand Down
1 change: 1 addition & 0 deletions src/ESPUIcontrol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ bool Control::MarshalControl(JsonObject & _item,
item[F("enabled")] = enabled;

if (!panelStyle.isEmpty()) {item[F("panelStyle")] = panelStyle;}
if (!panelClass.isEmpty()) {item[F("panelClass")] = panelClass;}
if (!elementStyle.isEmpty()) {item[F("elementStyle")] = elementStyle;}
if (!inputType.isEmpty()) {item[F("inputType")] = inputType;}
if (wide == true) {item[F("wide")] = true;}
Expand Down
2 changes: 2 additions & 0 deletions src/ESPUIcontrol.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,9 @@ class Control
bool enabled;
uint16_t parentControl;
String panelStyle;
String panelClass;
String elementStyle;

String inputType;
Control* next;

Expand Down
Loading