Skip to content

Commit 7d29ef3

Browse files
committed
0.8.4
1 parent 3e6eabf commit 7d29ef3

File tree

18 files changed

+892
-148
lines changed

18 files changed

+892
-148
lines changed

custom_components/reterminal_dashboard/frontend/editor.css

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,17 @@ textarea:focus {
313313
font-size: 10px;
314314
}
315315

316+
.btn-ai-sparkle {
317+
background: var(--accent-soft) !important;
318+
color: var(--accent) !important;
319+
border: 1px solid var(--accent-soft) !important;
320+
}
321+
322+
.btn-ai-sparkle:hover {
323+
background: var(--accent) !important;
324+
color: white !important;
325+
}
326+
316327
.page-list,
317328
.widget-list {
318329
display: flex;
@@ -860,6 +871,52 @@ textarea:focus {
860871
padding-top: 12px;
861872
}
862873

874+
/* Shortcuts UI */
875+
.shortcuts-grid {
876+
display: grid;
877+
grid-template-columns: 1fr 1fr 1fr;
878+
gap: 6px 16px;
879+
margin-top: 10px;
880+
}
881+
882+
.shortcut-item {
883+
display: flex;
884+
align-items: center;
885+
justify-content: space-between;
886+
padding: 4px 0;
887+
border-bottom: 1px solid rgba(255, 255, 255, 0.03);
888+
}
889+
890+
.shortcut-item:last-child {
891+
border-bottom: none;
892+
}
893+
894+
.shortcut-label {
895+
font-size: 11px;
896+
color: var(--muted);
897+
font-weight: 500;
898+
}
899+
900+
.shortcut-key {
901+
display: inline-flex;
902+
gap: 2px;
903+
}
904+
905+
kbd {
906+
background: var(--bg);
907+
color: var(--accent);
908+
border: 1px solid var(--border-subtle);
909+
border-radius: 4px;
910+
padding: 2px 6px;
911+
font-size: 10px;
912+
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
913+
font-weight: 700;
914+
box-shadow: 0 2px 0 0 rgba(0, 0, 0, 0.3);
915+
text-transform: uppercase;
916+
min-width: 24px;
917+
text-align: center;
918+
}
919+
863920
@font-face {
864921
font-family: "MDI";
865922
src:

custom_components/reterminal_dashboard/frontend/editor.html

Lines changed: 67 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
<header class="main-header">
2222
<div class="main-header-title">
2323
<h2><span class="logo-dot"></span> ESPHome Designer</h2>
24-
<span>Visual YAML Editor <small style="opacity: 0.5; margin-left: 8px;">v0.8.3</small> <span
24+
<span>Visual YAML Editor <small style="opacity: 0.5; margin-left: 8px;">v0.8.4</small> <span
2525
id="currentLayoutDevice" style="margin-left:8px; color:var(--accent);"></span></span>
2626
</div>
2727
<div class="main-header-actions desktop-only">
@@ -37,8 +37,6 @@ <h2><span class="logo-dot"></span> ESPHome Designer</h2>
3737
</a>
3838
<button id="deviceSettingsBtn" class="btn btn-secondary">📱 Device Settings</button>
3939
<button id="editorSettingsBtn" class="btn btn-secondary">⚙ Editor Settings</button>
40-
<button id="aiPromptBtn" class="btn btn-primary" style="background: var(--accent); color: white; border: none;">
41-
AI Prompt</button>
4240
</div>
4341
<div class="main-header-actions mobile-only">
4442
<button id="mobileWidgetsBtn" class="btn btn-secondary"><svg viewBox="0 0 24 24" width="18" height="18"
@@ -85,6 +83,7 @@ <h2><span class="logo-dot"></span> ESPHome Designer</h2>
8583
Widgets
8684
</div>
8785
<div id="widgetPalette" class="widget-list">
86+
8887
<!-- CORE CATEGORY -->
8988
<div class="widget-category expanded" data-category="core">
9089
<div class="widget-category-header" onclick="toggleWidgetCategory('core')">
@@ -306,6 +305,15 @@ <h2><span class="logo-dot"></span> ESPHome Designer</h2>
306305
<span class="label">Reload Page</span>
307306
<span class="tag">Nav</span>
308307
</div>
308+
<div class="item" draggable="true" data-widget-type="template_nav_bar">
309+
<svg class="widget-icon" viewBox="0 0 24 24" width="18" height="18">
310+
<rect x="2" y="6" width="20" height="12" rx="2" fill="none" stroke="currentColor" stroke-width="2" />
311+
<path d="M7 12l-3-3 3-3M17 12l3-3-3-3M12 9v6" stroke="currentColor" stroke-width="2"
312+
stroke-linecap="round" stroke-linejoin="round" />
313+
</svg>
314+
<span class="label">Navigation Bar</span>
315+
<span class="tag">Template</span>
316+
</div>
309317
</div>
310318
</div>
311319

@@ -353,6 +361,14 @@ <h2><span class="logo-dot"></span> ESPHome Designer</h2>
353361
<span class="label">Humidity</span>
354362
<span class="tag">SHT4x</span>
355363
</div>
364+
<div class="item" draggable="true" data-widget-type="template_sensor_bar">
365+
<svg class="widget-icon" viewBox="0 0 24 24" width="18" height="18">
366+
<rect x="2" y="6" width="20" height="12" rx="2" fill="none" stroke="currentColor" stroke-width="2" />
367+
<path d="M5 12h2M10 12h2M15 12h4" stroke="currentColor" stroke-width="2" stroke-linecap="round" />
368+
</svg>
369+
<span class="label">On-Board Sensor Bar</span>
370+
<span class="tag">New</span>
371+
</div>
356372
</div>
357373
</div>
358374

@@ -591,6 +607,7 @@ <h2><span class="logo-dot"></span> ESPHome Designer</h2>
591607
<div class="code-panel-header">
592608
<div class="code-panel-title">ESPHome YAML</div>
593609
<div class="code-panel-actions">
610+
<button id="aiPromptBtn" class="btn btn-secondary btn-xs btn-ai-sparkle">✨ AI Assistant</button>
594611
<button id="copySnippetBtn" class="btn btn-secondary btn-xs">Copy</button>
595612
<button id="fullscreenSnippetBtn" class="btn btn-secondary btn-xs">Full</button>
596613
<button id="updateLayoutBtn" class="btn btn-secondary btn-xs"
@@ -1125,31 +1142,43 @@ <h2><span class="logo-dot"></span> ESPHome Designer</h2>
11251142
</div>
11261143
<div class="field" style="border-top:1px solid var(--border-subtle); padding-top:12px; margin-top:12px;">
11271144
<div class="prop-label">Keyboard Shortcuts</div>
1128-
<div style="font-size: var(--fs-xs); color: var(--muted); line-height: 2;">
1129-
<div><kbd
1130-
style="background:var(--bg-input); padding:2px 6px; border-radius:3px; border:1px solid var(--border-subtle);">Ctrl+Z</kbd>
1131-
Undo</div>
1132-
<div><kbd
1133-
style="background:var(--bg-input); padding:2px 6px; border-radius:3px; border:1px solid var(--border-subtle);">Ctrl+Y</kbd>
1134-
Redo</div>
1135-
<div><kbd
1136-
style="background:var(--bg-input); padding:2px 6px; border-radius:3px; border:1px solid var(--border-subtle);">Ctrl+C</kbd>
1137-
Copy widget</div>
1138-
<div><kbd
1139-
style="background:var(--bg-input); padding:2px 6px; border-radius:3px; border:1px solid var(--border-subtle);">Ctrl+V</kbd>
1140-
Paste widget</div>
1141-
<div><kbd
1142-
style="background:var(--bg-input); padding:2px 6px; border-radius:3px; border:1px solid var(--border-subtle);">Delete</kbd>
1143-
Remove selected widget</div>
1144-
<div><kbd
1145-
style="background:var(--bg-input); padding:2px 6px; border-radius:3px; border:1px solid var(--border-subtle);">Alt
1146-
+ Drag</kbd> Disable snap guides</div>
1147-
<div><kbd
1148-
style="background:var(--bg-input); padding:2px 6px; border-radius:3px; border:1px solid var(--border-subtle);">Shift+Space</kbd>
1149-
Quick widget search</div>
1150-
<div><kbd
1151-
style="background:var(--bg-input); padding:2px 6px; border-radius:3px; border:1px solid var(--border-subtle);">Ctrl+R</kbd>
1152-
Reset canvas zoom</div>
1145+
<div class="shortcuts-grid">
1146+
<div class="shortcut-item">
1147+
<span class="shortcut-label">Undo</span>
1148+
<span class="shortcut-key"><kbd>Ctrl+Z</kbd></span>
1149+
</div>
1150+
<div class="shortcut-item">
1151+
<span class="shortcut-label">Redo</span>
1152+
<span class="shortcut-key"><kbd>Ctrl+Y</kbd></span>
1153+
</div>
1154+
<div class="shortcut-item">
1155+
<span class="shortcut-label">Copy</span>
1156+
<span class="shortcut-key"><kbd>Ctrl+C</kbd></span>
1157+
</div>
1158+
<div class="shortcut-item">
1159+
<span class="shortcut-label">Paste</span>
1160+
<span class="shortcut-key"><kbd>Ctrl+V</kbd></span>
1161+
</div>
1162+
<div class="shortcut-item">
1163+
<span class="shortcut-label">Delete</span>
1164+
<span class="shortcut-key"><kbd>DEL</kbd></span>
1165+
</div>
1166+
<div class="shortcut-item">
1167+
<span class="shortcut-label">Lock/Unlock</span>
1168+
<span class="shortcut-key"><kbd>Ctrl+L</kbd></span>
1169+
</div>
1170+
<div class="shortcut-item">
1171+
<span class="shortcut-label">Search</span>
1172+
<span class="shortcut-key"><kbd>Shift+Space</kbd></span>
1173+
</div>
1174+
<div class="shortcut-item">
1175+
<span class="shortcut-label">Zoom Reset</span>
1176+
<span class="shortcut-key"><kbd>Ctrl+R</kbd></span>
1177+
</div>
1178+
<div class="shortcut-item">
1179+
<span class="shortcut-label">Snap Off</span>
1180+
<span class="shortcut-key"><kbd>ALT</kbd></span>
1181+
</div>
11531182
</div>
11541183
</div>
11551184
</div>
@@ -1166,6 +1195,14 @@ <h2><span class="logo-dot"></span> ESPHome Designer</h2>
11661195
<button id="aiPromptClose" class="btn btn-secondary">Close</button>
11671196
</div>
11681197
<div class="modal-body">
1198+
<div id="aiConfigWarning"
1199+
style="background: rgba(82, 199, 234, 0.1); border-left: 3px solid var(--accent); padding: 10px; border-radius: 4px; font-size: 11px; margin-bottom: 12px; line-height: 1.4;">
1200+
<strong>💡 Configuration Required:</strong><br>
1201+
An API provider and key must be configured in <strong>Editor Settings</strong> before using the AI Assistant.
1202+
<button
1203+
onclick="window.openEditorSettingsModal(); document.getElementById('aiPromptModal').classList.add('hidden');"
1204+
class="btn btn-secondary btn-xs" style="margin-top:8px; display:block;">⚙ Open Editor Settings</button>
1205+
</div>
11691206
<div style="font-size: 11px; color: var(--muted); margin-bottom: 12px;">
11701207
Describe what you want to change. Example: "Move the selected widget 50px right" or "Make a nice weather
11711208
layout with 4 days forecast".
@@ -1309,6 +1346,8 @@ <h2><span class="logo-dot"></span> ESPHome Designer</h2>
13091346
<script src="features/touch_area/render.js"></script>
13101347
<script src="features/weather_forecast/render.js"></script>
13111348
<script src="features/weather_icon/render.js"></script>
1349+
<script src="features/template_sensor_bar/render.js"></script>
1350+
<script src="features/template_nav_bar/render.js"></script>
13121351
<script src="js/main.js"></script>
13131352
</body>
13141353

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
(() => {
2+
const render = (el, widget, { getColorStyle }) => {
3+
const props = widget.props || {};
4+
const color = props.color || "black";
5+
const iconSize = props.icon_size || 24;
6+
7+
el.style.display = "flex";
8+
el.style.alignItems = "center";
9+
el.style.justifyContent = "space-around";
10+
el.style.padding = "0 10px";
11+
el.style.boxSizing = "border-box";
12+
el.style.color = getColorStyle(color);
13+
el.style.overflow = "hidden";
14+
15+
if (props.show_background) {
16+
el.style.backgroundColor = getColorStyle(props.background_color || "gray");
17+
el.style.borderRadius = (props.border_radius || 8) + "px";
18+
} else {
19+
el.style.backgroundColor = "transparent";
20+
el.style.borderRadius = "0";
21+
}
22+
23+
const buttons = [];
24+
25+
if (props.show_prev !== false) {
26+
buttons.push({ type: 'prev', icon: 'F0141' });
27+
}
28+
if (props.show_home !== false) {
29+
buttons.push({ type: 'home', icon: 'F02DC' });
30+
}
31+
if (props.show_next !== false) {
32+
buttons.push({ type: 'next', icon: 'F0142' });
33+
}
34+
35+
el.innerHTML = "";
36+
37+
buttons.forEach(btn => {
38+
const icon = document.createElement("span");
39+
const cp = parseInt(btn.icon, 16);
40+
icon.innerText = String.fromCodePoint(cp);
41+
icon.style.fontFamily = "'Material Design Icons', system-ui, -sans-serif";
42+
icon.style.fontSize = iconSize + "px";
43+
icon.style.lineHeight = "1";
44+
icon.style.cursor = "pointer";
45+
icon.style.padding = "5px";
46+
icon.style.transition = "transform 0.1s";
47+
48+
icon.onmousedown = () => icon.style.transform = "scale(0.9)";
49+
icon.onmouseup = () => icon.style.transform = "scale(1)";
50+
icon.onmouseleave = () => icon.style.transform = "scale(1)";
51+
52+
el.appendChild(icon);
53+
});
54+
};
55+
56+
if (window.FeatureRegistry) {
57+
window.FeatureRegistry.register("template_nav_bar", { render });
58+
}
59+
})();
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
(() => {
2+
const render = (el, widget, { getColorStyle }) => {
3+
const props = widget.props || {};
4+
const color = props.color || "black";
5+
const iconSize = props.icon_size || 20;
6+
const fontSize = props.font_size || 14;
7+
8+
el.style.display = "flex";
9+
el.style.alignItems = "center";
10+
el.style.justifyContent = "space-around";
11+
el.style.padding = "0 10px";
12+
el.style.boxSizing = "border-box";
13+
el.style.color = getColorStyle(color);
14+
el.style.overflow = "hidden";
15+
16+
if (props.show_background) {
17+
el.style.backgroundColor = getColorStyle(props.background_color || "gray");
18+
el.style.borderRadius = (props.border_radius || 8) + "px";
19+
} else {
20+
el.style.backgroundColor = "transparent";
21+
el.style.borderRadius = "0";
22+
}
23+
24+
const getEntityState = (possibleIds) => {
25+
if (!window.AppState || !window.AppState.entityStates) return null;
26+
for (const id of possibleIds) {
27+
if (window.AppState.entityStates[id]) return window.AppState.entityStates[id].state;
28+
}
29+
return null;
30+
};
31+
32+
const sensors = [];
33+
34+
if (props.show_wifi) {
35+
const state = getEntityState(['wifi_signal_dbm', 'sensor.wifi_signal']);
36+
sensors.push({
37+
type: 'wifi',
38+
icon: 'F0928',
39+
val: state !== null ? Math.round(state) + 'dB' : '-65dB'
40+
});
41+
}
42+
43+
if (props.show_temperature) {
44+
const state = getEntityState(['sht4x_temperature', 'sht3x_temperature', 'shtc3_temperature', 'sensor.temperature']);
45+
sensors.push({
46+
type: 'temp',
47+
icon: 'F050F',
48+
val: state !== null ? parseFloat(state).toFixed(1) + '°C' : '23.5°C'
49+
});
50+
}
51+
52+
if (props.show_humidity) {
53+
const state = getEntityState(['sht4x_humidity', 'sht3x_humidity', 'shtc3_humidity', 'sensor.humidity']);
54+
sensors.push({
55+
type: 'hum',
56+
icon: 'F058E',
57+
val: state !== null ? Math.round(state) + '%' : '45%'
58+
});
59+
}
60+
61+
if (props.show_battery) {
62+
const state = getEntityState(['battery_level', 'sensor.battery_level']);
63+
sensors.push({
64+
type: 'bat',
65+
icon: 'F0079',
66+
val: state !== null ? Math.round(state) + '%' : '85%'
67+
});
68+
}
69+
70+
el.innerHTML = "";
71+
72+
sensors.forEach(s => {
73+
const group = document.createElement("div");
74+
group.style.display = "flex";
75+
group.style.alignItems = "center";
76+
group.style.gap = "6px";
77+
78+
const icon = document.createElement("span");
79+
const cp = parseInt(s.icon, 16);
80+
icon.innerText = String.fromCodePoint(cp);
81+
icon.style.fontFamily = "'Material Design Icons', system-ui, -sans-serif";
82+
icon.style.fontSize = iconSize + "px";
83+
icon.style.lineHeight = "1";
84+
85+
const text = document.createElement("span");
86+
text.innerText = s.val;
87+
text.style.fontSize = fontSize + "px";
88+
text.style.fontFamily = "Roboto, system-ui, -sans-serif";
89+
text.style.fontWeight = "500";
90+
text.style.whiteSpace = "nowrap";
91+
92+
group.appendChild(icon);
93+
group.appendChild(text);
94+
el.appendChild(group);
95+
});
96+
};
97+
98+
if (window.FeatureRegistry) {
99+
window.FeatureRegistry.register("template_sensor_bar", { render });
100+
}
101+
})();

0 commit comments

Comments
 (0)