Mobile: fix modal and form control overflow

Inline width:NNNpx beats the .modal { width: 95vw } mobile rule due to
specificity. Convert to max-width:NNNpx;width:95vw on the three affected
modals so they cap at their desktop size but still shrink on mobile:
  - playlists.js add-item modal (560px)
  - device-detail.js assign-playlist modal (650px)
  - content-library.js edit-content modal (500px)

Same fix pattern for fixed-width form controls flagged in QA — selects
and inputs change to max-width:NNNpx;width:100% so they keep their
desktop size but shrink to container on mobile:
  - admin.js role/plan selects (120/130px)
  - teams.js member role + add-device selects (100/200px)
  - content-library.js search input + folder filter (250/180px)
  - onboarding.js pairing code + display name inputs (240px)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
ScreenTinker 2026-04-21 18:48:51 -05:00
parent 0bd34544e5
commit 481ae0209a
6 changed files with 11 additions and 11 deletions

View file

@ -65,14 +65,14 @@ async function loadUsers() {
<td style="padding:8px"><span style="background:var(--bg-primary);padding:2px 8px;border-radius:10px;font-size:11px">${u.auth_provider}</span></td>
<td style="padding:8px;font-size:11px;color:var(--text-muted)">${u.last_login ? new Date(u.last_login * 1000).toLocaleString() : 'Never'}</td>
<td style="padding:8px">
<select class="input" style="width:120px;background:var(--bg-input);font-size:12px;padding:4px" data-role-user="${u.id}">
<select class="input" style="max-width:120px;width:100%;background:var(--bg-input);font-size:12px;padding:4px" data-role-user="${u.id}">
<option value="user" ${u.role === 'user' ? 'selected' : ''}>User</option>
<option value="admin" ${u.role === 'admin' ? 'selected' : ''}>Admin</option>
<option value="superadmin" ${u.role === 'superadmin' ? 'selected' : ''}>Superadmin</option>
</select>
</td>
<td style="padding:8px">
<select class="input" style="width:130px;background:var(--bg-input);font-size:12px;padding:4px" data-plan-user="${u.id}">
<select class="input" style="max-width:130px;width:100%;background:var(--bg-input);font-size:12px;padding:4px" data-plan-user="${u.id}">
${plans.map(p => `<option value="${p.id}" ${u.plan_id === p.id ? 'selected' : ''}>${p.display_name}</option>`).join('')}
</select>
</td>

View file

@ -72,8 +72,8 @@ export function render(container) {
</div>
<div style="display:flex;gap:12px;margin-bottom:16px;align-items:center;flex-wrap:wrap">
<input type="text" id="contentSearch" class="input" placeholder="Search content..." style="width:250px">
<select id="folderFilter" class="input" style="width:180px;background:var(--bg-input)">
<input type="text" id="contentSearch" class="input" placeholder="Search content..." style="max-width:250px;width:100%">
<select id="folderFilter" class="input" style="max-width:180px;width:100%;background:var(--bg-input)">
<option value="">All Folders</option>
</select>
<button class="btn btn-secondary btn-sm" id="newFolderBtn">+ New Folder</button>
@ -368,7 +368,7 @@ function showEditModal(contentItem, onSave) {
const isRemote = !!contentItem.remote_url;
overlay.innerHTML = `
<div class="modal" style="width:500px">
<div class="modal" style="max-width:500px;width:95vw">
<div class="modal-header">
<h3>Edit Content</h3>
<button class="btn-icon" id="closeEditModal">

View file

@ -891,7 +891,7 @@ async function setupPlaylistActions(device) {
const modal = document.createElement('div');
modal.className = 'modal-overlay';
modal.innerHTML = `
<div class="modal" style="width:650px">
<div class="modal" style="max-width:650px;width:95vw">
<div class="modal-header">
<h3>Add to Playlist</h3>
<button class="btn-icon" id="closeAssignModal">

View file

@ -39,12 +39,12 @@ const STEPS = [
content: `<p style="color:var(--text-secondary);margin-bottom:16px">Enter the 6-digit code shown on your display.</p>
<div style="text-align:center;margin:20px 0">
<input type="text" id="onboardPairingCode" maxlength="6" pattern="[0-9]{6}" placeholder="000000"
style="width:240px;padding:16px;background:var(--bg-input);border:1px solid var(--border);border-radius:8px;
style="max-width:240px;width:100%;padding:16px;background:var(--bg-input);border:1px solid var(--border);border-radius:8px;
color:var(--text-primary);font-size:32px;font-weight:700;text-align:center;letter-spacing:8px;font-family:monospace">
</div>
<div style="text-align:center">
<input type="text" id="onboardDeviceName" placeholder="Display name (e.g., Lobby TV)"
style="width:240px;padding:10px;background:var(--bg-input);border:1px solid var(--border);border-radius:8px;color:var(--text-primary);font-size:14px;text-align:center">
style="max-width:240px;width:100%;padding:10px;background:var(--bg-input);border:1px solid var(--border);border-radius:8px;color:var(--text-primary);font-size:14px;text-align:center">
</div>
<p id="onboardPairStatus" style="color:var(--text-muted);font-size:13px;text-align:center;margin-top:12px"></p>`,
action: 'pair'

View file

@ -513,7 +513,7 @@ async function showAddItemModal(playlistId) {
const modal = document.createElement('div');
modal.style.cssText = 'position:fixed;inset:0;background:rgba(0,0,0,0.6);display:flex;align-items:center;justify-content:center;z-index:1000';
modal.innerHTML = `
<div style="background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius-lg);padding:24px;width:560px;max-width:90vw;max-height:80vh;display:flex;flex-direction:column">
<div style="background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius-lg);padding:24px;max-width:560px;width:95vw;max-height:80vh;display:flex;flex-direction:column">
<h3 style="margin-bottom:16px;color:var(--text-primary)">Add Content to Playlist</h3>
<div style="display:flex;gap:8px;margin-bottom:12px">
<button class="btn btn-primary btn-sm tab-btn active" data-tab="content">Content</button>

View file

@ -97,7 +97,7 @@ async function renderTeamDetail(container, teamId) {
<div style="font-size:13px;font-weight:500">${m.user_name || m.email}</div>
<div style="font-size:11px;color:var(--text-muted)">${m.email}</div>
</div>
<select class="input" style="width:100px;background:var(--bg-input);font-size:12px;padding:4px 8px" data-member-id="${m.user_id}" ${m.role === 'owner' ? 'disabled' : ''}>
<select class="input" style="max-width:100px;width:100%;background:var(--bg-input);font-size:12px;padding:4px 8px" data-member-id="${m.user_id}" ${m.role === 'owner' ? 'disabled' : ''}>
<option value="viewer" ${m.role === 'viewer' ? 'selected' : ''}>Viewer</option>
<option value="editor" ${m.role === 'editor' ? 'selected' : ''}>Editor</option>
<option value="owner" ${m.role === 'owner' ? 'selected' : ''}>Owner</option>
@ -112,7 +112,7 @@ async function renderTeamDetail(container, teamId) {
<div class="settings-section" style="margin:0">
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:12px">
<h3 style="font-size:15px">Shared Devices (${devices.length})</h3>
<select id="addDeviceToTeam" class="input" style="width:200px;background:var(--bg-input);font-size:12px">
<select id="addDeviceToTeam" class="input" style="max-width:200px;width:100%;background:var(--bg-input);font-size:12px">
<option value="">+ Add device...</option>
${unassignedDevices.map(d => `<option value="${d.id}">${d.name}</option>`).join('')}
</select>