Skip to content

Commit f28bb35

Browse files
feat(ui): migrate config UI to homebridge-ui-kit with redesigned layout
- Migrate to @mp-consulting/homebridge-ui-kit (Bootstrap 5.3, Bootstrap Icons) - Redesign from 4 tabs to 3 tabs: Devices, Settings, Tools - Merge Connection tab into Settings; move Discover Devices to top of Devices tab - Replace inline edit forms with compact device list + 2-column edit form (Settings/Advanced tabs) - Auto-expand accordion sections with devices; count badge turns blue when non-zero - Add dark/light mode theme detection - Harmonize package.json (author, funding, engines, scripts)
1 parent ab8b2b9 commit f28bb35

9 files changed

Lines changed: 811 additions & 339 deletions

File tree

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,19 @@
22

33
All notable changes to this project will be documented in this file.
44

5+
## [1.0.8] - 2026-03-05
6+
7+
### Changed
8+
9+
- **Config UI**: Migrated to `@mp-consulting/homebridge-ui-kit` design system (Bootstrap 5.3, Bootstrap Icons)
10+
- **Config UI**: Replaced emoji icons with Bootstrap Icons throughout device accordion
11+
- **Config UI**: Redesigned layout — 3 tabs (Devices, Settings, Tools) instead of 4; Settings and Connection tabs merged; Discover Devices moved to the top of the Devices tab
12+
- **Config UI**: Device list now shows compact rows with Edit/Remove buttons; clicking Edit opens a 2-column form with Settings and Advanced tabs
13+
- **Config UI**: Device accordion sections auto-expand when they have devices configured; count badge turns blue when non-zero
14+
- **Config UI**: Connection settings (AWS IoT, LAN, BLE) displayed in a 3-column side-by-side layout
15+
- **Config UI**: Added dark/light mode theme detection from system preference and Homebridge user settings
16+
- **package.json**: Harmonized author, funding, engines, and scripts with other repos
17+
518
## [1.0.7] - 2026-03-04
619

720
### Fixed

eslint.config.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import tseslint from 'typescript-eslint';
44
export default tseslint.config(
55
// Ignores
66
{
7-
ignores: ['dist/**', 'node_modules/**', 'homebridge-ui/public/models.js'],
7+
ignores: ['dist/**', 'node_modules/**', 'homebridge-ui/public/models.js', 'homebridge-ui/public/lib/**'],
88
},
99
// Base recommended configs
1010
eslint.configs.recommended,
@@ -71,6 +71,7 @@ export default tseslint.config(
7171
confirm: 'readonly',
7272
modelCategories: 'readonly',
7373
getDeviceTypeFromModel: 'readonly',
74+
MpKit: 'readonly',
7475
},
7576
},
7677
rules: {

homebridge-ui/public/index.html

Lines changed: 211 additions & 208 deletions
Large diffs are not rendered by default.

homebridge-ui/public/lib/kit.css

Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
/* @mp-consulting/homebridge-ui-kit v1.0.0 */
2+
3+
/* ── Design tokens ──────────────────────────────────────────────────────────
4+
CSS custom properties used throughout the design system.
5+
Override these in your plugin's styles.css to customize per-plugin.
6+
────────────────────────────────────────────────────────────────────────── */
7+
8+
:root {
9+
/* Brand */
10+
--mp-primary: #4f46e5;
11+
--mp-primary-rgb: 79, 70, 229;
12+
--mp-primary-hover: #4338ca;
13+
--mp-primary-subtle: rgba(79, 70, 229, 0.12);
14+
15+
/* Status */
16+
--mp-status-online: #10b981;
17+
--mp-status-online-glow: rgba(16, 185, 129, 0.35);
18+
--mp-status-offline: #ef4444;
19+
--mp-status-checking: #94a3b8;
20+
21+
/* Surfaces */
22+
--mp-surface: rgba(255, 255, 255, 0.03);
23+
--mp-border: rgba(255, 255, 255, 0.08);
24+
25+
/* Shape */
26+
--mp-radius: 0.5rem;
27+
--mp-shadow-hover: 0 0.5rem 1rem rgba(0, 0, 0, 0.3);
28+
}
29+
30+
/* ── Bootstrap 5 overrides ──────────────────────────────────────────────────
31+
Remap Bootstrap components to use brand tokens.
32+
────────────────────────────────────────────────────────────────────────── */
33+
34+
/* Primary button */
35+
.btn-primary {
36+
--bs-btn-bg: var(--mp-primary);
37+
--bs-btn-border-color: var(--mp-primary);
38+
--bs-btn-hover-bg: var(--mp-primary-hover);
39+
--bs-btn-hover-border-color: var(--mp-primary-hover);
40+
--bs-btn-active-bg: var(--mp-primary-hover);
41+
--bs-btn-active-border-color: var(--mp-primary-hover);
42+
--bs-btn-focus-shadow-rgb: var(--mp-primary-rgb);
43+
}
44+
45+
/* Primary spinner */
46+
.spinner-border.text-primary,
47+
.spinner-grow.text-primary {
48+
color: var(--mp-primary) !important;
49+
}
50+
51+
/* ── Components ─────────────────────────────────────────────────────────────
52+
Reusable UI components used across all Homebridge plugins.
53+
────────────────────────────────────────────────────────────────────────── */
54+
55+
/* ── Plugin header ──────────────────────────────────────── */
56+
57+
.mp-header {
58+
display: flex;
59+
align-items: center;
60+
gap: 0.875rem;
61+
margin-bottom: 0.5rem;
62+
}
63+
64+
.mp-header-icon {
65+
font-size: 2rem;
66+
flex-shrink: 0;
67+
line-height: 1;
68+
}
69+
70+
.mp-header-title {
71+
font-size: 1.375rem;
72+
font-weight: 600;
73+
margin: 0;
74+
line-height: 1.3;
75+
}
76+
77+
.mp-header-subtitle {
78+
font-size: 0.875rem;
79+
color: var(--bs-secondary-color);
80+
margin: 0;
81+
}
82+
83+
/* ── Status indicator dot ───────────────────────────────── */
84+
85+
.mp-status {
86+
width: 8px;
87+
height: 8px;
88+
border-radius: 50%;
89+
display: inline-block;
90+
flex-shrink: 0;
91+
vertical-align: middle;
92+
}
93+
94+
.mp-status-online {
95+
background-color: var(--mp-status-online);
96+
box-shadow: 0 0 5px var(--mp-status-online-glow);
97+
}
98+
99+
.mp-status-offline {
100+
background-color: var(--mp-status-offline);
101+
}
102+
103+
.mp-status-checking {
104+
background-color: var(--mp-status-checking);
105+
animation: mp-pulse 1.5s ease-in-out infinite;
106+
}
107+
108+
@keyframes mp-pulse {
109+
0%, 100% { opacity: 1; }
110+
50% { opacity: 0.35; }
111+
}
112+
113+
/* ── Device card ────────────────────────────────────────── */
114+
115+
.mp-device-card {
116+
transition: transform 0.15s ease, box-shadow 0.15s ease;
117+
cursor: pointer;
118+
}
119+
120+
.mp-device-card:hover {
121+
transform: translateY(-1px);
122+
box-shadow: var(--mp-shadow-hover) !important;
123+
}
124+
125+
/* ── Settings surface card ──────────────────────────────── */
126+
127+
.mp-settings-card {
128+
background: var(--mp-surface);
129+
border: 1px solid var(--mp-border) !important;
130+
border-radius: var(--mp-radius);
131+
}
132+
133+
/* ── Empty state ────────────────────────────────────────── */
134+
135+
.mp-empty-state {
136+
display: flex;
137+
flex-direction: column;
138+
align-items: center;
139+
justify-content: center;
140+
padding: 3rem 1.5rem;
141+
text-align: center;
142+
}
143+
144+
.mp-empty-state-icon {
145+
font-size: 2.5rem;
146+
color: var(--bs-secondary-color);
147+
margin-bottom: 0.75rem;
148+
line-height: 1;
149+
}
150+
151+
.mp-empty-state-title {
152+
font-size: 0.9375rem;
153+
font-weight: 500;
154+
color: var(--bs-secondary-color);
155+
margin: 0 0 0.25rem;
156+
}
157+
158+
.mp-empty-state-hint {
159+
font-size: 0.8125rem;
160+
color: var(--bs-secondary-color);
161+
margin: 0;
162+
opacity: 0.7;
163+
}
164+
165+
/* ── Loading state ──────────────────────────────────────── */
166+
167+
.mp-loading {
168+
display: flex;
169+
flex-direction: column;
170+
align-items: center;
171+
justify-content: center;
172+
padding: 2.5rem 1.5rem;
173+
gap: 0.75rem;
174+
color: var(--bs-secondary-color);
175+
font-size: 0.875rem;
176+
}
177+
178+
/* ── Nav tabs ───────────────────────────────────────────── */
179+
180+
.mp-tabs {
181+
border-bottom: 1px solid var(--mp-border);
182+
}
183+
184+
.mp-tabs .nav-link {
185+
color: var(--bs-secondary-color);
186+
border: none;
187+
padding: 0.75rem 1.25rem;
188+
font-weight: 500;
189+
}
190+
191+
.mp-tabs .nav-link:hover {
192+
color: var(--bs-body-color);
193+
border: none;
194+
}
195+
196+
.mp-tabs .nav-link.active {
197+
color: var(--mp-primary);
198+
background: transparent;
199+
border: none;
200+
border-bottom: 2px solid var(--mp-primary);
201+
}
202+
203+
/* ── Metadata label ─────────────────────────────────────── */
204+
205+
.mp-label {
206+
font-size: 0.75rem;
207+
text-transform: uppercase;
208+
letter-spacing: 0.5px;
209+
color: var(--bs-secondary-color);
210+
}
211+
212+
/* ── View toggling ──────────────────────────────────────── */
213+
214+
.mp-view {
215+
display: none;
216+
}
217+
218+
.mp-view.active {
219+
display: block;
220+
}
221+
222+
/* ── Support footer ─────────────────────────────────────── */
223+
224+
.mp-footer {
225+
display: flex;
226+
align-items: center;
227+
justify-content: center;
228+
flex-wrap: wrap;
229+
gap: 0.75rem 1rem;
230+
padding-top: 1.5rem;
231+
margin-top: 2rem;
232+
border-top: 1px solid var(--mp-border);
233+
font-size: 0.8125rem;
234+
color: var(--bs-secondary-color);
235+
}
236+
237+
.mp-footer a {
238+
color: var(--bs-secondary-color);
239+
text-decoration: none;
240+
display: inline-flex;
241+
align-items: center;
242+
gap: 0.3rem;
243+
transition: color 0.15s ease;
244+
}
245+
246+
.mp-footer a:hover {
247+
color: var(--mp-primary);
248+
}
249+
250+
.mp-footer-sep {
251+
color: var(--mp-border);
252+
user-select: none;
253+
}

0 commit comments

Comments
 (0)