fix(ui): wrap plugin tabs to new lines instead of scrolling (#201)

* fix(ui): wrap plugin tabs to new lines instead of scrolling

Change plugin tabs row from overflow-x-auto to flex-wrap so that
when many plugins are installed, tabs break to new lines instead
of becoming smaller or requiring horizontal scrolling.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(ui): use gap-x instead of space-x for proper wrapped row alignment

Switch from space-x-* to gap-x-* utilities so wrapped rows align
correctly without indentation on subsequent lines.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(ui): add missing flex-wrap and gap utilities to CSS

The project uses hand-written Tailwind-like CSS, not actual Tailwind.
Added missing utility classes needed for plugin tabs wrapping:
- flex-wrap
- gap-x-4, gap-x-6, gap-x-8, gap-y-2
- lg:gap-x-6, xl:gap-x-8 responsive variants

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(ui): apply flex-wrap to system tabs row

Apply the same wrapping behavior to the system tabs row (Overview,
General, WiFi, etc.) so they also wrap to new lines on smaller
viewports instead of scrolling.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(ui): constrain tab container width to enable flex-wrap

Add max-w-full and overflow-hidden to tab row containers to properly
constrain their width, allowing flex-wrap to work correctly.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(ui): remove overflow-hidden that was hiding tabs

Revert the max-w-full overflow-hidden approach as it was hiding
content. Keep both rows using flex-wrap with gap utilities.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat: Add custom-leagues widget support for soccer plugin

- Add server-side template rendering for x-widget="custom-leagues"
- Renders table with Name, League Code, Priority, Enabled columns
- Includes inline JavaScript for add/remove row functionality
- Uses indexed field naming for proper array serialization
- Shows common ESPN league codes as hint

This enables the soccer scoreboard plugin's custom leagues feature
to work properly in the web UI.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(ui): reduce tab gap spacing for tighter layout

Reduce horizontal gap between tabs from gap-x-4/6/8 to gap-x-2/3/4
for a more compact appearance.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor(widget): Replace custom-leagues with generic array-table widget

- Add generic array-table widget that reads columns from schema
- Support x-columns to specify which columns to display
- Auto-detect columns from items.properties if x-columns not specified
- Remove hardcoded custom-leagues implementation
- Any plugin can now use x-widget: "array-table" for array-of-objects

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(ui): use data attributes for array table button to avoid JSON escaping issues

Move JSON blobs (item_properties and display_columns) from inline onclick
to data-* attributes with proper HTML entity escaping via Jinja's |e filter.
Update addArrayTableRow() to read and parse these data attributes.

This fixes HTML attribute breakage caused by tojson emitting double quotes
inside the onclick attribute value.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(ui): update Add button state when array table rows change

Add updateAddButtonState() helper that toggles the Add button's disabled
attribute and opacity based on current row count vs maxItems.

Called after addArrayTableRow() and removeArrayTableRow(), and also on
page load to ensure correct initial state.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(ui): add try/catch for JSON parsing in addArrayTableRow

Wrap JSON.parse calls for data-item-properties and data-display-columns
in try/catch blocks with fallback to {} and [] respectively. Logs error
with raw attribute values to help debug malformed JSON.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(array-table): Fix getValue input name validation and setValue Add button state sync

- Fix getValue to use early-continue guard preventing errors on inputs without names
- Add updateAddButtonState call in setValue to refresh Add button state after repopulating rows

* fix(ui): make Configure button larger than Uninstall in plugin manager

Swapped button sizes in installed plugins section - Configure button is now
the largest (flex-2), Update is medium (flex-1), and Uninstall is smallest
(no flex class). This prioritizes the Configure action over Uninstall.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix(ui): correct forEach continue and plugin button flex sizing

- Replace invalid continue with return in array-table forEach callback
- Remove redundant hidden input type check in array-table getValue
- Fix plugin button sizing using inline flex styles instead of invalid flex-2 class
- Configure button now properly sized at flex: 2, Update and Uninstall at flex: 1

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* refactor(ui): reorganize plugin buttons into two-row layout

Configure button now takes full width on first row, while Update and
Uninstall buttons share the second row evenly. This makes Configure
more prominent and separates destructive actions to a second row.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix(ui): override inline-flex on Configure button to enable full width

The .btn class uses display: inline-flex which prevents w-full from working.
Added inline style to override with display: flex and width: 100% so the
Configure button properly takes the full width of its row.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix(ui): use inline styles for plugin action buttons layout

Replace Tailwind classes with explicit inline styles to ensure proper
two-row layout for plugin action buttons. Configure button on first row
at full width, Update and Uninstall sharing second row evenly.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Chuck <chuck@example.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Chuck
2026-01-22 10:40:13 -05:00
committed by GitHub
parent 1833e30c1d
commit d0ad2031c8
5 changed files with 443 additions and 16 deletions

View File

@@ -113,6 +113,7 @@ body {
.flex { display: flex; }
.inline-flex { display: inline-flex; }
.flex-wrap { flex-wrap: wrap; }
.flex-shrink-0 { flex-shrink: 0; }
.flex-1 { flex: 1; }
.items-center { align-items: center; }
@@ -137,6 +138,12 @@ body {
.gap-3 { gap: 0.75rem; }
.gap-4 { gap: 1rem; }
.gap-6 { gap: 1.5rem; }
.gap-x-2 { column-gap: 0.5rem; }
.gap-x-3 { column-gap: 0.75rem; }
.gap-x-4 { column-gap: 1rem; }
.gap-x-6 { column-gap: 1.5rem; }
.gap-x-8 { column-gap: 2rem; }
.gap-y-2 { row-gap: 0.5rem; }
/* Enhanced Typography */
.text-xs { font-size: 0.75rem; line-height: 1.4; }
@@ -175,6 +182,7 @@ h4 { font-size: 1.125rem; }
.right-4 { right: 1rem; }
.max-w-7xl { max-width: 56rem; }
.max-w-full { max-width: 100%; }
.mx-auto { margin-left: auto; margin-right: auto; }
.overflow-x-auto { overflow-x: auto; }
.overflow-hidden { overflow: hidden; }
@@ -339,6 +347,8 @@ a, button, input, select, textarea {
.lg\:grid-cols-5 { grid-template-columns: repeat(5, minmax(0, 1fr)); }
.lg\:grid-cols-6 { grid-template-columns: repeat(6, minmax(0, 1fr)); }
.lg\:px-8 { padding-left: 2rem; padding-right: 2rem; }
.lg\:gap-x-3 { column-gap: 0.75rem; }
.lg\:gap-x-6 { column-gap: 1.5rem; }
}
@media (min-width: 1280px) {
@@ -349,6 +359,8 @@ a, button, input, select, textarea {
.xl\:grid-cols-8 { grid-template-columns: repeat(8, minmax(0, 1fr)); }
.xl\:px-12 { padding-left: 3rem; padding-right: 3rem; }
.xl\:space-x-6 > * + * { margin-left: 1.5rem; }
.xl\:gap-x-4 { column-gap: 1rem; }
.xl\:gap-x-8 { column-gap: 2rem; }
}
@media (min-width: 1536px) {