diff --git a/CHANGELOG.md b/CHANGELOG.md
index 25defefbc..a8026f41a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,10 @@
## 0.4.6
* System
* Automatically persist logs during (and for a short time after) updates
+* Webapp
+ * Move home screen, player page controls to bottom of screen on mobile
+ * Update CSS breakpoints to scale the player page better on the smallest of screens
+ * Reformat Player page volume controls to be more modern
## 0.4.5
* Web App
diff --git a/web/src/components/CustomMarquee/CustomMarquee.jsx b/web/src/components/CustomMarquee/CustomMarquee.jsx
index 72c4befe7..9bcaa22a8 100644
--- a/web/src/components/CustomMarquee/CustomMarquee.jsx
+++ b/web/src/components/CustomMarquee/CustomMarquee.jsx
@@ -42,14 +42,13 @@ export default function CustomMarquee(props) {
}
}
- let resizeTimout;
+ let resizeTimeout; // Your IDE will say this is unused, it's actually used to make sure the timeout below is limited to one instance at a time by taking up a specific variable
function handleResize(){
if(!resizeCooldown.current){
resizeCooldown.current = true;
assessMarquee()
-
- resizeTimout = setTimeout(()=>{resizeCooldown.current = false;}, 1000) // set a cooldown for resize checks to avoid excessive renders
+ resizeTimeout = setTimeout(()=>{resizeCooldown.current = false;}, 1000)
}
}
window.addEventListener("resize", handleResize()); // Doesn't call assessMarquee directly to avoid calling thousands of times per second when resizing window
diff --git a/web/src/components/GroupVolumeSlider/GroupVolumeSlider.jsx b/web/src/components/GroupVolumeSlider/GroupVolumeSlider.jsx
index f1edf40cb..6196f99cb 100644
--- a/web/src/components/GroupVolumeSlider/GroupVolumeSlider.jsx
+++ b/web/src/components/GroupVolumeSlider/GroupVolumeSlider.jsx
@@ -89,12 +89,12 @@ const GroupVolumeSlider = ({ groupId, sourceId, groupsLeft }) => {
onClick={() => setSlidersOpen(!slidersOpen)}
>
{slidersOpen ? (
-
) : (
-
diff --git a/web/src/components/GroupVolumeSlider/GroupVolumeSlider.scss b/web/src/components/GroupVolumeSlider/GroupVolumeSlider.scss
index f6975cc3d..0ce4199b8 100644
--- a/web/src/components/GroupVolumeSlider/GroupVolumeSlider.scss
+++ b/web/src/components/GroupVolumeSlider/GroupVolumeSlider.scss
@@ -6,6 +6,10 @@
}
.group-volume-children-container {
+ // Equates to the height of a single volume bar (with title) * 3 on desktop
+ // Previously also had a mobile version (204px) but mobile doesn't always show a scrollbar when needed (unlike desktop) so it was hard to tell when there was > 3
+ max-height: 168px;
+ overflow: auto;
padding-left: 1rem;
}
@@ -23,5 +27,4 @@
.group-volume-slider {
width: 100%;
- margin: 0 1rem;
}
diff --git a/web/src/components/MediaControl/MediaControl.scss b/web/src/components/MediaControl/MediaControl.scss
index 01e8cbc65..d116fc2c7 100644
--- a/web/src/components/MediaControl/MediaControl.scss
+++ b/web/src/components/MediaControl/MediaControl.scss
@@ -8,7 +8,6 @@
justify-content: center;
margin-top: 1rem;
margin-bottom: 1rem;
- width: 90vw;
}
.media-inner {
@@ -19,6 +18,7 @@
}
.media-control {
+ font-size: 3.5rem;
color: general.$controls-color;
padding-left: 1.5rem;
padding-right: 1.5rem;
@@ -30,11 +30,11 @@
padding-right: 1.25rem;
}
- @media (min-width: 365px) and (max-width: 425px) {
+ @media (min-width: 365px) and (max-width: 435px) {
font-size: 2.5rem;
}
- @media (min-width: 425px) {
+ @media (min-width: 435px) {
font-size: 3.5rem;
}
}
diff --git a/web/src/components/SongInfo/SongInfo.scss b/web/src/components/SongInfo/SongInfo.scss
index ed3b965bf..973f47688 100644
--- a/web/src/components/SongInfo/SongInfo.scss
+++ b/web/src/components/SongInfo/SongInfo.scss
@@ -10,6 +10,11 @@
white-space: nowrap;
overflow: hidden;
+
+ @media (max-width: 435px){
+ max-height: 50vh;
+ max-width: 50vh;
+ }
}
.artist-name {
diff --git a/web/src/components/StreamBar/StreamBar.scss b/web/src/components/StreamBar/StreamBar.scss
index 01c847eaf..655b18905 100644
--- a/web/src/components/StreamBar/StreamBar.scss
+++ b/web/src/components/StreamBar/StreamBar.scss
@@ -21,15 +21,26 @@
color: general.$text-color;
width: 100%;
max-width: 80%; // Leave space for icon
- font-size: 2.5rem;
font-weight: medium;
white-space: nowrap;
overflow: hidden;
@include general.header-font;
padding: 0.5rem;
+ @media (max-height: 500px){
+ font-size: 1.5rem;
+ }
+ @media (min-height: 500px){
+ font-size: 2.5rem;
+ }
}
.stream-bar-icon {
- width: 4rem;
- height: 4rem;
+ @media (max-height: 500px){
+ width: 2rem;
+ height: 2rem;
+ }
+ @media (min-height: 500px){
+ width: 4rem;
+ height: 4rem;
+ }
}
diff --git a/web/src/components/ZoneVolumeSlider/ZoneVolumeSlider.scss b/web/src/components/ZoneVolumeSlider/ZoneVolumeSlider.scss
index 73669bc62..3402b9a45 100644
--- a/web/src/components/ZoneVolumeSlider/ZoneVolumeSlider.scss
+++ b/web/src/components/ZoneVolumeSlider/ZoneVolumeSlider.scss
@@ -3,4 +3,5 @@
.zone-volume-container {
@include general.header-font;
font-size: 1rem;
+ max-width: calc(100% - 47px)
}
diff --git a/web/src/pages/Home/Home.jsx b/web/src/pages/Home/Home.jsx
index 215a53bf4..d12882577 100644
--- a/web/src/pages/Home/Home.jsx
+++ b/web/src/pages/Home/Home.jsx
@@ -55,11 +55,13 @@ const PresetAndAdd = ({
);
} else {
return (
-
setPresetsModalOpen(true)}
- >
- Presets
+
+
setPresetsModalOpen(true)}
+ >
+ Presets
+
);
}
diff --git a/web/src/pages/Home/Home.scss b/web/src/pages/Home/Home.scss
index 121fa8212..9c6b5aa0f 100644
--- a/web/src/pages/Home/Home.scss
+++ b/web/src/pages/Home/Home.scss
@@ -2,7 +2,12 @@
.home-outer {
padding-top: 10px;
- padding-bottom: 10px;
+ @media (max-width: 435px) {
+ padding-bottom: 85px;
+ }
+ @media (min-width: 435px) {
+ padding-bottom: 10px;
+ }
display: flex;
flex-direction: column;
align-items: center;
@@ -69,6 +74,12 @@
}
.home-presets-container {
+ @media (max-width: 435px) {
+ position: fixed;
+ bottom: 65px;
+ }
+
+ z-index: 1; // Needed to ensure that scrolling marquees do not appear on top of the presets button
display: flex;
flex-direction: row;
diff --git a/web/src/pages/Player/Player.jsx b/web/src/pages/Player/Player.jsx
index 872ee214f..887239c8b 100644
--- a/web/src/pages/Player/Player.jsx
+++ b/web/src/pages/Player/Player.jsx
@@ -87,6 +87,7 @@ const Player = () => {
{
-
-
-
- {/* There are many sub-divs classed player-inner here because formatting was strange otherwise */}
-
-
-
-
-
-
+
+
+
{!alone && !is_streamer && zones.length > 0 && (
-
-
- setExpanded(!expanded)}>
- {expanded ? (
-
- ) : (
-
- )}
-
+
+
+
+ setExpanded(!expanded)}>
+ {expanded ? (
+
+ ) : (
+
+ )}
+
+
+
+ {/* When expanded, take up max height to prevent constant resizes as more dropdowns expand */}
+
+
+
)}
-
);
};
diff --git a/web/src/pages/Player/Player.scss b/web/src/pages/Player/Player.scss
index 0da4b71a0..1e894f1bf 100644
--- a/web/src/pages/Player/Player.scss
+++ b/web/src/pages/Player/Player.scss
@@ -33,7 +33,19 @@
border-radius: 2.5%;
}
-.player-volume-slider {
+.media-controls {
+ position: fixed;
+ z-index: 0;
+ bottom: 129px
+}
+
+.player-volume-container {
+ position: fixed;
+ bottom: 65px;
+ z-index: 1;
+}
+
+.player-volume-header {
display: flex;
flex-direction: row;
align-items: center;
@@ -41,6 +53,14 @@
width: 90vw;
}
+.player-volume-body {
+ display: flex;
+ align-items: center;
+ flex-direction: column;
+ max-height: calc(85vh - 120px);
+ overflow-y: auto;
+}
+
.player-volume-expand-button {
color: general.$controls-color;
}
@@ -52,3 +72,16 @@
@include general.header-font;
padding: 0.5rem;
}
+
+.control-gap {
+ // Dynamically size the gap so that the controls are always at the bottom of the screen when screen is scrolled to the top of the page
+ @media(min-height: 800px) {
+ height: 7.5vh
+ }
+ @media(min-height: 850px) {
+ height: 10vh
+ }
+ @media(min-height: 875px) {
+ height: 12.5vh
+ }
+}