mirror of
https://github.com/RetroShare/RSNewWebUI.git
synced 2026-09-14 11:05:47 +05:00
Merge pull request #14 from jolavillette/feature/responsive-webui
Phone adaptations inside the pages
This commit is contained in:
commit
a2352e2963
@ -218,7 +218,9 @@ const CommentsTable = () => {
|
||||
oninit: (v) => {},
|
||||
view: (v) =>
|
||||
m('table.comments', [
|
||||
m('tr', [
|
||||
// See table.mails: the header row is tagged so the small screen
|
||||
// stylesheet can card-ify the data rows only.
|
||||
m('tr.comments-head', [
|
||||
m('th', ''),
|
||||
m('th', 'Comment'),
|
||||
m('th', 'Author'),
|
||||
|
||||
@ -114,7 +114,7 @@ const navbar = () => {
|
||||
? 'Connected to RetroShare Core'
|
||||
: 'Connection Lost',
|
||||
}),
|
||||
m('span.webui-version', { style: { fontSize: '0.7em' } }, 'v139'),
|
||||
m('span.webui-version', { style: { fontSize: '0.7em' } }, 'v140'),
|
||||
m('i.fas.fa-sync-alt.refresh-icon', {
|
||||
style: { cursor: 'pointer', fontSize: '0.8em' },
|
||||
onclick: () => window.location.reload(true),
|
||||
@ -236,7 +236,7 @@ const MobileStatus = () => {
|
||||
m('small', statusbar.formatBytes(state.totalOut)),
|
||||
]),
|
||||
]),
|
||||
m('.mobile-status-sheet__version', 'WebUI v139'),
|
||||
m('.mobile-status-sheet__version', 'WebUI v140'),
|
||||
])),
|
||||
];
|
||||
},
|
||||
|
||||
304
webui-src/app/scss/_responsive.scss
Normal file
304
webui-src/app/scss/_responsive.scss
Normal file
@ -0,0 +1,304 @@
|
||||
// -----------------------------------------------------------------------------
|
||||
// Phone adaptations, inside the pages.
|
||||
//
|
||||
// Loaded LAST from main.scss so these rules win over the page stylesheets
|
||||
// without needing !important. Everything here is scoped inside the `mobile`
|
||||
// (phone, portrait or landscape) or `touch` (no hover) mixins from
|
||||
// abstracts/_mixins.scss, so the desktop rendering is untouched.
|
||||
//
|
||||
// Neither the navigation, nor the two-pane pages, nor the mail list are this
|
||||
// file's business: main.js renders a bottom tab bar and a status sheet of its
|
||||
// own on a phone, components/_navbar.scss hides the desktop rail below 700px,
|
||||
// the network, people and chat pages switch to master-detail on their own
|
||||
// through a .mobile-detail-open class driven from their own state, and
|
||||
// pages/_mail.scss turns table.mails into a card list. This file starts where
|
||||
// all of that stops -- inside the pages, still laid out for a wide screen:
|
||||
// * multi column grids and wide tables collapse to a single column,
|
||||
// * anything only reachable on :hover gets a touch fallback.
|
||||
//
|
||||
// The page stylesheets carry a small screen layout of their own, with their own
|
||||
// breakpoints (768px for network and people, 899px for the chat, 700px for
|
||||
// files and config). This file neither repeats nor edits them: it takes over
|
||||
// below the phone breakpoint, and the few places where a tablet compromise does
|
||||
// not survive on a phone are overridden with !important and carry a comment
|
||||
// saying which rule they beat; there should be no other !important here.
|
||||
// -----------------------------------------------------------------------------
|
||||
@use 'abstracts' as *;
|
||||
|
||||
/* =========================================================================
|
||||
1. Multi column grids collapse
|
||||
========================================================================= */
|
||||
|
||||
@include mobile {
|
||||
/* Network friend details, identity details, location cards */
|
||||
.network-detail-view {
|
||||
gap: 1rem;
|
||||
|
||||
.detail-header {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
/* gap comes from pages/_network.scss, which sets it !important */
|
||||
padding-bottom: 1rem;
|
||||
|
||||
.detail-title h2 {
|
||||
font-size: 1.35rem;
|
||||
}
|
||||
|
||||
.detail-actions {
|
||||
flex-wrap: wrap;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.detail-section {
|
||||
padding: 0.875rem;
|
||||
|
||||
.info-grid {
|
||||
grid-template-columns: 1fr;
|
||||
row-gap: 0.25rem;
|
||||
|
||||
.info-label {
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.locations-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.location-card .loc-body {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
/* Config: proxy rows are 160+220+220px wide, i.e. 620px minimum */
|
||||
.proxy-row {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 0.35rem;
|
||||
padding-bottom: 0.75rem;
|
||||
border-bottom: 1px solid #e2e8f0;
|
||||
}
|
||||
|
||||
/* Generic two column form grid used across the config pages */
|
||||
.grid-2col {
|
||||
grid-template-columns: 1fr;
|
||||
|
||||
& input[type='checkbox'] {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* People: identity detail card */
|
||||
.identity {
|
||||
margin: 0.5rem;
|
||||
padding: 0.75rem;
|
||||
|
||||
& .details {
|
||||
grid-template-columns: 1fr;
|
||||
grid-row-gap: 0.125rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Mail composer popup: pages/_mail.scss already grows it to 95% of the
|
||||
viewport on a small screen, which on a phone leaves a useless 5% frame
|
||||
around a form that needs every pixel. Its rule is !important, hence these. */
|
||||
.composePopupOverlay .composePopup {
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
inset: 0;
|
||||
|
||||
& > .widget {
|
||||
padding: 0.75rem;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
& .close-btn {
|
||||
top: 0.5rem;
|
||||
right: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.widget {
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
.widget-half {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
/* =========================================================================
|
||||
2. Tables
|
||||
========================================================================= */
|
||||
|
||||
@include mobile {
|
||||
/* The global `table-layout: fixed` plus percentage column widths squeeze
|
||||
every column below readability. Let the content drive the width instead. */
|
||||
table {
|
||||
table-layout: auto;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
table td,
|
||||
table th {
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
/* Files tables: drop the hardcoded 50% name column */
|
||||
table.myfiles th:nth-child(2),
|
||||
table.friendsfiles th:nth-child(2) {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
/* --- Channel comments: 8 columns, unusable as a table -----------------
|
||||
The header row carries .comments-head (set in channels_util.js) because
|
||||
mithril builds the DOM through the DOM API and therefore does not get the
|
||||
implicit <tbody> the HTML parser would insert: neither tr:first-child nor a
|
||||
`> tbody >` path is reliable here. */
|
||||
table.comments {
|
||||
/* The table box has to go: a <tr> switched to block/flex inside a table box
|
||||
is wrapped back into an anonymous table cell and re-sized by the column
|
||||
algorithm, which shreds the row. */
|
||||
display: block;
|
||||
|
||||
& tbody {
|
||||
display: block;
|
||||
}
|
||||
|
||||
& tr.comments-head {
|
||||
display: none;
|
||||
}
|
||||
|
||||
& tr:not(.comments-head) {
|
||||
display: block;
|
||||
padding: 0.5rem 0;
|
||||
|
||||
& > td {
|
||||
display: block;
|
||||
text-align: start;
|
||||
padding: 0.125rem 0;
|
||||
}
|
||||
|
||||
/* author / date / score / votes fold into one small meta line */
|
||||
& > td:nth-child(n + 3) {
|
||||
display: inline-block;
|
||||
margin-right: 0.75rem;
|
||||
font-size: 0.8rem;
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
& > td:nth-child(5)::before {
|
||||
content: 'Score: ';
|
||||
}
|
||||
|
||||
& > td:nth-child(6)::before {
|
||||
content: '\002B06 ';
|
||||
}
|
||||
|
||||
& > td:nth-child(7)::before {
|
||||
content: '\002B07 ';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* =========================================================================
|
||||
3. Statusbar
|
||||
========================================================================= */
|
||||
|
||||
@include mobile {
|
||||
.statusbar {
|
||||
/* padding and font-size are already shrunk by components/_statusbar.scss */
|
||||
gap: 0.5rem;
|
||||
/* Keep every counter reachable rather than dropping data */
|
||||
overflow-x: auto;
|
||||
white-space: nowrap;
|
||||
scrollbar-width: none;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&-left,
|
||||
&-right {
|
||||
flex-shrink: 0;
|
||||
gap: 0.5rem !important;
|
||||
}
|
||||
|
||||
&-divider {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* =========================================================================
|
||||
4. Forms and inputs
|
||||
========================================================================= */
|
||||
|
||||
@include mobile {
|
||||
/* iOS zooms the whole page in when a focused field is under 16px */
|
||||
input[type='text'],
|
||||
input[type='password'],
|
||||
input[type='number'],
|
||||
input[type='search'],
|
||||
input[type='email'],
|
||||
select,
|
||||
textarea {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
input {
|
||||
&.stretched,
|
||||
&.searchbar {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&.small {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
/* Page level sidebars turned into a horizontal tab strip by _navbar.scss:
|
||||
make the targets tall enough for a finger. */
|
||||
.sidebar a {
|
||||
min-height: $touch-target;
|
||||
display: inline-flex !important;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* Tooltips are anchored with a fixed -120px offset, which pushes them off
|
||||
screen on a narrow viewport */
|
||||
.tooltiptext {
|
||||
left: 0;
|
||||
margin-left: 0;
|
||||
min-width: 0;
|
||||
width: max-content;
|
||||
max-width: 80vw;
|
||||
}
|
||||
}
|
||||
|
||||
/* =========================================================================
|
||||
5. Touch fallbacks (independent of the viewport width)
|
||||
========================================================================= */
|
||||
|
||||
@include touch {
|
||||
/* Hover-revealed helpers are unreachable without a pointer */
|
||||
.tooltip .tooltiptext {
|
||||
/* still hidden by default, but reachable by tapping the element */
|
||||
&:focus,
|
||||
&:focus-within {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
|
||||
.tooltip:focus-within .tooltiptext {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
/* Recipient autocomplete stays open while the field has focus; the list is
|
||||
only kept alive by :hover on desktop. */
|
||||
.compose-mail__recipients .recipients__input:focus-within .recipients__input-list {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
@ -3,6 +3,29 @@
|
||||
// -----------------------------------------------------------------------------
|
||||
@use 'sass:color';
|
||||
@use './colors' as *;
|
||||
@use './variables' as *;
|
||||
|
||||
/// Responsive helpers
|
||||
/// Always go through these instead of hardcoding a pixel value, so the
|
||||
/// breakpoints stay defined in a single place (abstracts/_variables.scss).
|
||||
|
||||
/// The phone layer: portrait, plus landscape, which is wide enough to escape a
|
||||
/// width-only breakpoint but far too short for a two-pane layout. Between the
|
||||
/// two lies the small screen layout of the page stylesheets, which this file
|
||||
/// deliberately leaves alone.
|
||||
@mixin mobile {
|
||||
@media (max-width: $bp-mobile), (max-width: $bp-narrow) and (max-height: $bp-short) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
/// Devices without a real pointer: :hover never fires reliably, so anything
|
||||
/// that is only reachable on hover has to be made permanently visible here.
|
||||
@mixin touch {
|
||||
@media (hover: none), (pointer: coarse) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
/// Button Mixin
|
||||
@mixin button($bg-color) {
|
||||
|
||||
@ -4,3 +4,20 @@
|
||||
$FontPath: './webfonts' !default;
|
||||
$FontName: 'Roboto' !default;
|
||||
$FontVersion: '3.008' !default;
|
||||
|
||||
// Responsive breakpoints.
|
||||
//
|
||||
// The page stylesheets already carry a small screen layout of their own: they
|
||||
// stack the two panes of network and people below 768px, the chat below 899px,
|
||||
// and turn the mail sidebar into a drawer. _responsive.scss does not redo that
|
||||
// work and does not edit those files; it adds the phone layer underneath, and
|
||||
// overrides them only where a tablet compromise does not survive a phone.
|
||||
//
|
||||
// $bp-mobile therefore means "a phone", not "a small window".
|
||||
$bp-mobile: 700px !default; // phone, portrait
|
||||
$bp-narrow: 899px !default; // widest small screen rule of the page stylesheets
|
||||
$bp-short: 500px !default; // a phone held sideways is wide, but never tall
|
||||
|
||||
// Minimum comfortable size for a touch target (Material/HIG recommend ~44px)
|
||||
$touch-target: 2.75rem !default;
|
||||
|
||||
|
||||
@ -5,6 +5,10 @@ General site-wide rules
|
||||
|
||||
#main {
|
||||
height: 100vh;
|
||||
/* Mobile browsers count the collapsible URL bar in 100vh, which pushes the
|
||||
statusbar and the bottom navigation off screen. dvh follows the visible
|
||||
viewport; the vh above stays as the fallback. */
|
||||
height: 100dvh;
|
||||
}
|
||||
|
||||
/* Main base div for tabs used by m.route */
|
||||
|
||||
@ -20,3 +20,7 @@
|
||||
|
||||
// 6. Page-specific styles
|
||||
@use 'pages';
|
||||
|
||||
// 7. Small screen / touch adaptations. Must stay last: it overrides the
|
||||
// layouts defined above without relying on !important.
|
||||
@use 'responsive';
|
||||
|
||||
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user