Skip to content

Commit 777acde

Browse files
committed
Add icon background and border options
Expose background and border styling for icon widgets and update build asset paths. plugin.js: add bg_color prop, apply backgroundColor and optional border (width, color, radius) to the rendered icon and emit rectangle calls for exported drawings. properties.js: add UI controls for Background, Border Width, Border Color and Corner Radius in the properties panel (with sensible defaults). dist/index.html: switch asset and image references to relative ./ paths and update main asset filenames from the new build.
1 parent a896e9b commit 777acde

File tree

3 files changed

+46
-5
lines changed

3 files changed

+46
-5
lines changed

custom_components/esphome_designer/frontend/dist/index.html

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,15 @@
2424
rel="stylesheet">
2525

2626
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@mdi/font@7.4.47/css/materialdesignicons.min.css">
27-
<link rel="icon" href="/assets/favicon-BFR8sXii.png" type="image/x-icon">
28-
<script type="module" crossorigin src="/assets/index-CwC0zESX.js"></script>
29-
<link rel="stylesheet" crossorigin href="/assets/index-gxormkqd.css">
27+
<link rel="icon" href="./assets/favicon-BFR8sXii.png" type="image/x-icon">
28+
<script type="module" crossorigin src="./assets/main-403oi-Ur.js"></script>
29+
<link rel="stylesheet" crossorigin href="./assets/main-1OkGAQ6K.css">
3030
</head>
3131

3232
<body>
3333
<header class="main-header" role="banner">
3434
<div class="main-header-title">
35-
<img src="/assets/logo_header-CUGdaeC6.png" alt="ESPHome Designer" class="logo-image">
35+
<img src="./assets/logo_header-CUGdaeC6.png" alt="ESPHome Designer" class="logo-image">
3636
<span><small style="opacity: 0.5; margin-left: 8px;">v1.0.0 RC5</small> <span id="currentLayoutDevice"
3737
style="margin-left:8px; color:var(--accent);"></span></span>
3838
</div>

custom_components/esphome_designer/frontend/features/icon/plugin.js

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const render = (el, widget, { getColorStyle }) => {
77
let iconCode = "F0595"; // Default
88
let size = props.size || 24;
99
const color = props.color || "theme_auto";
10+
const bgColor = props.bg_color || "transparent";
1011

1112
// Handle template colors in preview: use a fallback if it looks like a template
1213
let effectiveColor = color;
@@ -16,6 +17,7 @@ const render = (el, widget, { getColorStyle }) => {
1617
}
1718

1819
const colorStyle = getColorStyle(effectiveColor);
20+
const bgColorStyle = getColorStyle(bgColor);
1921

2022
const codeRaw = props.code || "";
2123
// Handle template in icon code
@@ -46,11 +48,20 @@ const render = (el, widget, { getColorStyle }) => {
4648
el.innerText = ch;
4749
el.style.fontSize = `${size}px`;
4850
el.style.color = colorStyle;
51+
el.style.backgroundColor = bgColorStyle;
4952
el.style.fontFamily = "MDI, system-ui, -apple-system, BlinkMacSystemFont, -sans-serif";
5053
el.style.lineHeight = "1";
5154
el.style.display = "flex";
5255
el.style.alignItems = "center";
5356
el.style.justifyContent = "center";
57+
58+
// Border
59+
if (props.border_width) {
60+
const borderColor = getColorStyle(props.border_color || "black");
61+
el.style.border = `${props.border_width}px solid ${borderColor}`;
62+
el.style.borderRadius = `${props.border_radius || 0}px`;
63+
el.style.boxSizing = "border-box";
64+
}
5465
};
5566

5667
export default {
@@ -64,8 +75,12 @@ export default {
6475
height: 60,
6576
size: 48,
6677
color: "theme_auto",
78+
bg_color: "transparent",
6779
font_ref: "font_mdi_medium",
68-
fit_icon_to_frame: true
80+
fit_icon_to_frame: true,
81+
border_width: 0,
82+
border_color: "theme_auto",
83+
border_radius: 0
6984
},
7085
collectRequirements: (w, context) => {
7186
const p = w.props || {};
@@ -153,6 +168,15 @@ export default {
153168
lines.push(` it.filled_rectangle(${w.x}, ${w.y}, ${w.width}, ${w.height}, ${bgColorConst});`);
154169
}
155170

171+
// Draw Border if defined
172+
const borderWidth = p.border_width || 0;
173+
if (borderWidth > 0) {
174+
const borderColor = getColorConst(p.border_color || "theme_auto");
175+
for (let i = 0; i < borderWidth; i++) {
176+
lines.push(` it.rectangle(${w.x} + ${i}, ${w.y} + ${i}, ${w.width} - 2 * ${i}, ${w.height} - 2 * ${i}, ${borderColor});`);
177+
}
178+
}
179+
156180
const cond = getConditionCheck(w);
157181
if (cond) lines.push(` ${cond}`);
158182

custom_components/esphome_designer/frontend/js/core/properties.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -703,6 +703,15 @@ export class PropertiesPanel {
703703
this.addLabeledInputWithIconPicker("Icon Code", "text", props.code || "F0595", (v) => updateProp("code", v), widget);
704704
this.addLabeledInput("Size", "number", props.size || 48, (v) => updateProp("size", parseInt(v, 10)));
705705
this.addColorSelector("Color", props.color || "black", colors, (v) => updateProp("color", v));
706+
this.addColorSelector("Background", props.bg_color || "transparent", colors, (v) => updateProp("bg_color", v));
707+
708+
this.createSection("Border Style", false);
709+
this.addLabeledInput("Border Width", "number", props.border_width || 0, (v) => updateProp("border_width", parseInt(v, 10)));
710+
this.addColorSelector("Border Color", props.border_color || "theme_auto", colors, (v) => updateProp("border_color", v));
711+
this.addLabeledInput("Corner Radius", "number", props.border_radius || 0, (v) => updateProp("border_radius", parseInt(v, 10)));
712+
this.addDropShadowButton(this.getContainer(), widget.id);
713+
this.endSection();
714+
706715
this.endSection();
707716
}
708717
else if (type === "sensor_text") {
@@ -910,6 +919,7 @@ export class PropertiesPanel {
910919
this.addSelect("Font", props.font_family || "Roboto", ["Roboto", "Inter", "Roboto Mono"], (v) => updateProp("font_family", v));
911920
this.endSection();
912921
}
922+
913923
else {
914924
// Smart Generic Fallback: Include Entity & Title if they likely exist
915925
const hasEntity = widget.entity_id !== undefined || props.weather_entity !== undefined || type.includes("sensor") || type.includes("icon");
@@ -1377,8 +1387,15 @@ export class PropertiesPanel {
13771387
this.addSelect("Font Reference", props.font_ref || "font_mdi_medium", ["font_mdi_medium", "font_mdi_large"], (v) => updateProp("font_ref", v));
13781388
this.addColorSelector("Color", props.color || "black", colors, (v) => updateProp("color", v));
13791389
this.addColorSelector("Background", props.bg_color || "transparent", colors, (v) => updateProp("bg_color", v));
1390+
1391+
this.createSection("Border Style", false);
1392+
this.addLabeledInput("Border Width", "number", props.border_width || 0, (v) => updateProp("border_width", parseInt(v, 10)));
1393+
this.addColorSelector("Border Color", props.border_color || "theme_auto", colors, (v) => updateProp("border_color", v));
1394+
this.addLabeledInput("Corner Radius", "number", props.border_radius || 0, (v) => updateProp("border_radius", parseInt(v, 10)));
13801395
this.addDropShadowButton(this.getContainer(), widget.id);
13811396
this.endSection();
1397+
1398+
this.endSection();
13821399
}
13831400
else if (type === "battery_icon") {
13841401
this.createSection("Data Source", true);

0 commit comments

Comments
 (0)