feat(ui): add mobile responsive layout for narrow viewports#27
Conversation
Append a @media (max-width: 600px) block that stacks key/manage rows, full-width nav buttons, drops the mnemonic grid to two columns, lets the address row and DPNS username row wrap cleanly, and allows the fee table to scroll horizontally. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
📝 WalkthroughWalkthroughA single CSS ChangesMobile Responsive Layout
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
index.html (2)
2459-2462: 💤 Low valueConsider visual consistency of network selector wrapping.
The
flex-basis: 100%on.devnet-dropdownforces it to take a full row, while.network-btn(Testnet/Mainnet) can wrap together. This creates inconsistent button widths where the devnet dropdown is always full-width but the other network buttons can share a row.If this visual inconsistency is intentional for prominence, it's fine. Otherwise, consider letting all network controls wrap naturally by removing
flex-basis: 100%.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@index.html` around lines 2459 - 2462, The CSS rule .devnet-dropdown forces the dropdown to occupy a full row via flex-basis: 100%, causing inconsistent widths vs .network-btn; remove the flex-basis: 100% (or replace it with flex: 0 1 auto / flex-basis: auto) on .devnet-dropdown so it can wrap naturally like .network-btn and match the visual behaviour of the other network controls.
2651-2653: 💤 Low valueVerify the visual order of modal buttons.
Using
flex-direction: column-reversewill display the "Save"/"Confirm" button above the "Cancel" button on mobile. While this emphasizes the primary action, it reverses the conventional left-to-right desktop order (Cancel, Confirm), which might momentarily confuse users.If the reversed order is intentional to highlight the primary action on mobile, consider adding a comment to document this choice.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@index.html` around lines 2651 - 2653, The CSS rule .devnet-modal-actions { flex-direction: column-reverse; } reverses the vertical stacking so the primary action (Save/Confirm) appears above Cancel on mobile; if this reversal is intentional, add an inline comment above the rule explaining the UX rationale (e.g., "Primary action placed first on mobile for emphasis") to document the choice, otherwise change the rule to column (or remove column-reverse) and, if you need to maintain visual emphasis while preserving conventional order, keep flex-direction: column and use the order property on the specific button elements (e.g., .primary { order: 2 } .cancel { order: 1 }) to control placement without reversing semantic order.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@index.html`:
- Around line 2428-2697: Small touch targets on mobile: increase the tappable
area for .remove-key-btn, .remove-dpns-username-btn, and
.remove-manage-new-key-btn inside the existing `@media` (max-width: 600px) block
by setting explicit width and height to at least 44px (and adjust
font-size/line-height if needed) so they meet the recommended touch target;
ensure any flex alignment or padding is updated (e.g., maintain align-self or
margin) so layout doesn’t break when these elements grow.
---
Nitpick comments:
In `@index.html`:
- Around line 2459-2462: The CSS rule .devnet-dropdown forces the dropdown to
occupy a full row via flex-basis: 100%, causing inconsistent widths vs
.network-btn; remove the flex-basis: 100% (or replace it with flex: 0 1 auto /
flex-basis: auto) on .devnet-dropdown so it can wrap naturally like .network-btn
and match the visual behaviour of the other network controls.
- Around line 2651-2653: The CSS rule .devnet-modal-actions { flex-direction:
column-reverse; } reverses the vertical stacking so the primary action
(Save/Confirm) appears above Cancel on mobile; if this reversal is intentional,
add an inline comment above the rule explaining the UX rationale (e.g., "Primary
action placed first on mobile for emphasis") to document the choice, otherwise
change the rule to column (or remove column-reverse) and, if you need to
maintain visual emphasis while preserving conventional order, keep
flex-direction: column and use the order property on the specific button
elements (e.g., .primary { order: 2 } .cancel { order: 1 }) to control placement
without reversing semantic order.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
| @media (max-width: 600px) { | ||
| body { | ||
| padding: 10px; | ||
| align-items: flex-start; | ||
| } | ||
|
|
||
| .bridge-container { | ||
| padding: 20px 16px; | ||
| border-radius: 12px; | ||
| } | ||
|
|
||
| h1 { | ||
| font-size: 1.4rem; | ||
| } | ||
|
|
||
| header { | ||
| margin-bottom: 20px; | ||
| } | ||
|
|
||
| /* Network selector: allow wrap, drop max-widths so buttons fit */ | ||
| .network-selector { | ||
| flex-wrap: wrap; | ||
| gap: 8px; | ||
| } | ||
|
|
||
| .network-btn { | ||
| max-width: none; | ||
| padding: 12px 14px; | ||
| font-size: 0.9rem; | ||
| } | ||
|
|
||
| .devnet-dropdown { | ||
| max-width: none; | ||
| flex-basis: 100%; | ||
| } | ||
|
|
||
| /* Mode buttons */ | ||
| .mode-btn { | ||
| padding: 18px; | ||
| } | ||
|
|
||
| /* Primary/secondary buttons */ | ||
| .primary-btn { | ||
| padding: 16px 24px; | ||
| font-size: 1rem; | ||
| } | ||
|
|
||
| /* Configure keys row: stack label above controls, each select on its own row */ | ||
| .key-row { | ||
| flex-wrap: wrap; | ||
| padding: 12px; | ||
| gap: 8px; | ||
| } | ||
|
|
||
| .key-name { | ||
| width: 100%; | ||
| } | ||
|
|
||
| .key-config { | ||
| flex-wrap: wrap; | ||
| width: 100%; | ||
| } | ||
|
|
||
| .key-config select { | ||
| flex: 1 1 100%; | ||
| font-size: 0.85rem; | ||
| min-width: 0; | ||
| } | ||
|
|
||
| .key-config .key-purpose-select { | ||
| min-width: 0; | ||
| } | ||
|
|
||
| .key-config .remove-key-btn { | ||
| align-self: flex-end; | ||
| } | ||
|
|
||
| /* Nav / action buttons: stack full-width */ | ||
| .nav-buttons { | ||
| flex-direction: column; | ||
| } | ||
|
|
||
| .nav-buttons .primary-btn, | ||
| .nav-buttons .secondary-btn { | ||
| width: 100%; | ||
| white-space: normal; | ||
| } | ||
|
|
||
| .error-actions .primary-btn, | ||
| .error-actions .secondary-btn { | ||
| flex: 1 1 100%; | ||
| } | ||
|
|
||
| .dpns-action-buttons .primary-btn, | ||
| .dpns-action-buttons .secondary-btn, | ||
| .manage-action-buttons .primary-btn, | ||
| .manage-action-buttons .secondary-btn { | ||
| width: 100%; | ||
| } | ||
|
|
||
| /* Deposit screen */ | ||
| .deposit-headline { | ||
| font-size: 1.1rem; | ||
| } | ||
|
|
||
| .qr-container { | ||
| padding: 12px; | ||
| max-width: 100%; | ||
| } | ||
|
|
||
| .qr-container img { | ||
| max-width: 100%; | ||
| height: auto; | ||
| } | ||
|
|
||
| .address-display { | ||
| flex-direction: column; | ||
| gap: 10px; | ||
| } | ||
|
|
||
| .address { | ||
| font-size: 0.8rem; | ||
| padding: 10px 12px; | ||
| width: 100%; | ||
| } | ||
|
|
||
| /* Mnemonic: 2 columns on small screens */ | ||
| .mnemonic-section { | ||
| padding: 18px; | ||
| } | ||
|
|
||
| .mnemonic-words { | ||
| grid-template-columns: repeat(2, 1fr); | ||
| gap: 8px; | ||
| } | ||
|
|
||
| .mnemonic-word { | ||
| font-size: 0.85rem; | ||
| padding: 8px 10px; | ||
| } | ||
|
|
||
| /* Processing details */ | ||
| .processing-headline { | ||
| font-size: 1.2rem; | ||
| } | ||
|
|
||
| .processing-details { | ||
| padding: 14px; | ||
| } | ||
|
|
||
| /* Manage keys rows */ | ||
| .manage-key-row { | ||
| padding: 12px; | ||
| font-size: 0.85rem; | ||
| } | ||
|
|
||
| .manage-key-row .key-disable-toggle { | ||
| margin-left: 0; | ||
| width: 100%; | ||
| } | ||
|
|
||
| .add-key-config { | ||
| gap: 8px; | ||
| flex-direction: column; | ||
| align-items: stretch; | ||
| } | ||
|
|
||
| .add-key-config select { | ||
| flex: 1 1 100%; | ||
| width: 100%; | ||
| min-width: 0; | ||
| } | ||
|
|
||
| .add-key-config .manage-key-purpose-select { | ||
| min-width: 0; | ||
| } | ||
|
|
||
| .add-key-config .remove-manage-new-key-btn { | ||
| align-self: flex-end; | ||
| } | ||
|
|
||
| /* DPNS username row */ | ||
| .dpns-username-row { | ||
| flex-wrap: wrap; | ||
| gap: 8px; | ||
| } | ||
|
|
||
| .dpns-username-input-wrapper { | ||
| flex: 1 1 100%; | ||
| order: 1; | ||
| } | ||
|
|
||
| .dpns-username-status { | ||
| flex: 1; | ||
| text-align: left; | ||
| order: 2; | ||
| min-width: 0; | ||
| } | ||
|
|
||
| .remove-dpns-username-btn { | ||
| order: 3; | ||
| } | ||
|
|
||
| .dpns-username-input { | ||
| padding: 12px 14px; | ||
| font-size: 1rem; | ||
| } | ||
|
|
||
| /* Input with button (fetch identity) */ | ||
| .input-with-button { | ||
| flex-direction: column; | ||
| } | ||
|
|
||
| .fetch-btn { | ||
| width: 100%; | ||
| } | ||
|
|
||
| /* Devnet modal */ | ||
| .devnet-modal { | ||
| padding: 20px; | ||
| width: 95%; | ||
| } | ||
|
|
||
| .devnet-modal-actions { | ||
| flex-direction: column-reverse; | ||
| } | ||
|
|
||
| .devnet-modal-actions .primary-btn, | ||
| .devnet-modal-actions .secondary-btn { | ||
| width: 100%; | ||
| } | ||
|
|
||
| /* Faucet hero */ | ||
| .faucet-section.faucet-hero { | ||
| padding: 18px; | ||
| } | ||
|
|
||
| .faucet-btn.faucet-btn-hero { | ||
| padding: 14px 24px; | ||
| font-size: 1rem; | ||
| width: 100%; | ||
| } | ||
|
|
||
| /* Identity / contract id rows */ | ||
| .id-row { | ||
| flex-wrap: wrap; | ||
| } | ||
|
|
||
| .id-row .identity-id { | ||
| font-size: 0.8rem; | ||
| } | ||
|
|
||
| /* Fee table — let it scroll if too wide */ | ||
| .fee-breakdown { | ||
| overflow-x: auto; | ||
| } | ||
|
|
||
| .fee-table { | ||
| font-size: 0.8rem; | ||
| } | ||
|
|
||
| /* Complete stats: shrink padding */ | ||
| .complete-stats { | ||
| gap: 8px; | ||
| } | ||
|
|
||
| .stat { | ||
| padding: 8px 10px; | ||
| } | ||
| } |
There was a problem hiding this comment.
Increase touch target sizes for small interactive buttons.
Several interactive buttons have dimensions below the minimum recommended touch target size of 44×44px (WCAG 2.1 AA, iOS HIG) or 48×48px (Android Material Design):
.remove-key-btn: 20×20px (line 649-650).remove-dpns-username-btn: 32×32px (line 1336-1337).remove-manage-new-key-btn: 32×32px (line 1805-1806)
On narrow viewports where users rely on touch input, these small targets are difficult to tap accurately and create accessibility barriers.
Consider adding mobile-specific rules to increase these to at least 44×44px, for example:
`@media` (max-width: 600px) {
.remove-key-btn {
width: 44px;
height: 44px;
font-size: 1rem;
}
.remove-dpns-username-btn,
.remove-manage-new-key-btn {
width: 44px;
height: 44px;
}
}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@index.html` around lines 2428 - 2697, Small touch targets on mobile: increase
the tappable area for .remove-key-btn, .remove-dpns-username-btn, and
.remove-manage-new-key-btn inside the existing `@media` (max-width: 600px) block
by setting explicit width and height to at least 44px (and adjust
font-size/line-height if needed) so they meet the recommended touch target;
ensure any flex alignment or padding is updated (e.g., maintain align-self or
margin) so layout doesn’t break when these elements grow.
Append a @media (max-width: 600px) block that stacks key/manage rows, full-width nav buttons, drops the mnemonic grid to two columns, lets the address row and DPNS username row wrap cleanly, and allows the fee table to scroll horizontally.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
Summary by CodeRabbit