@@ -75,6 +75,8 @@ import TabIconModal from './TabIconModal';
7575import GoogleAccountConnection from './GoogleAccountConnection' ;
7676import ClamValueModal from './ClamValueModal' ;
7777import SoundPicker from './SoundPicker' ;
78+ import useIsMobile from '../hooks/useIsMobile.js' ;
79+ import { stackableTableSx } from '../utils/responsiveTable.js' ;
7880
7981const USERS_UPDATED_EVENT = 'homeglow:users-updated' ;
8082const DEVICE_SETTINGS_UPDATED_EVENT = 'homeglow:device-settings-updated' ;
@@ -204,6 +206,7 @@ const buildTagUrl = (repository, tagName) => {
204206const toShortCommit = ( commitSha ) => ( commitSha ? commitSha . slice ( 0 , 7 ) : 'Unknown' ) ;
205207
206208const AdminPanel = ( { setWidgetSettings, onPluginsChanged, onTabsChanged } ) => {
209+ const isMobile = useIsMobile ( ) ;
207210 const [ currentDeviceName , setCurrentDeviceName ] = useState ( ( ) => getDeviceName ( ) ) ;
208211 const API_DEVICE_URL = getDeviceApiBase ( API_BASE_URL ) ;
209212 const CORE_WIDGET_DEFAULT_SIZES = {
@@ -1775,11 +1778,18 @@ const AdminPanel = ({ setWidgetSettings, onPluginsChanged, onTabsChanged }) => {
17751778
17761779 return (
17771780 < Box sx = { { width : '100%' , maxWidth : 1200 , mx : 'auto' } } >
1778- < Typography variant = "h4" gutterBottom >
1781+ < Typography variant = "h4" gutterBottom sx = { { pr : { xs : 5 , sm : 0 } } } >
17791782 ⚙️ Admin Panel
17801783 </ Typography >
17811784
1782- < Tabs value = { activeTab } onChange = { ( e , newValue ) => setActiveTab ( newValue ) } sx = { { mb : 3 } } >
1785+ < Tabs
1786+ value = { activeTab }
1787+ onChange = { ( e , newValue ) => setActiveTab ( newValue ) }
1788+ variant = "scrollable"
1789+ scrollButtons = "auto"
1790+ allowScrollButtonsMobile
1791+ sx = { { mb : 3 } }
1792+ >
17831793 { adminTabs . map ( ( tab , index ) => (
17841794 < Tab key = { tab } label = { tab } />
17851795 ) ) }
@@ -1790,7 +1800,14 @@ const AdminPanel = ({ setWidgetSettings, onPluginsChanged, onTabsChanged }) => {
17901800 < Card >
17911801 < CardContent >
17921802 < Box sx = { { borderBottom : 1 , borderColor : 'divider' , mb : 3 } } >
1793- < Tabs value = { widgetsSubTab } onChange = { ( _ , v ) => setWidgetsSubTab ( v ) } size = "small" >
1803+ < Tabs
1804+ value = { widgetsSubTab }
1805+ onChange = { ( _ , v ) => setWidgetsSubTab ( v ) }
1806+ size = "small"
1807+ variant = "scrollable"
1808+ scrollButtons = "auto"
1809+ allowScrollButtonsMobile
1810+ >
17941811 < Tab label = "Widgets" />
17951812 < Tab label = "Plugins" />
17961813 < Tab label = "Tabs" />
@@ -2224,7 +2241,7 @@ const AdminPanel = ({ setWidgetSettings, onPluginsChanged, onTabsChanged }) => {
22242241 </ Box >
22252242
22262243 < TableContainer component = { Paper } >
2227- < Table >
2244+ < Table sx = { stackableTableSx } >
22282245 < TableHead >
22292246 < TableRow >
22302247 < TableCell width = { 60 } > Order</ TableCell >
@@ -2257,22 +2274,22 @@ const AdminPanel = ({ setWidgetSettings, onPluginsChanged, onTabsChanged }) => {
22572274 opacity : draggingTabNumber === tab . number ? 0.65 : 1 ,
22582275 } }
22592276 >
2260- < TableCell >
2277+ < TableCell data-label = "Order" >
22612278 < Box sx = { { display : 'flex' , alignItems : 'center' , gap : 1 } } >
22622279 { ! isHome && < DragIndicator fontSize = "small" /> }
22632280 < Chip label = { tab . number } size = "small" />
22642281 </ Box >
22652282 </ TableCell >
2266- < TableCell >
2283+ < TableCell data-label = "Label" >
22672284 { tab . label }
22682285 { isHome && (
22692286 < Chip size = "small" label = "Home" color = "primary" sx = { { ml : 1 } } />
22702287 ) }
22712288 </ TableCell >
2272- < TableCell >
2289+ < TableCell data-label = "Icon" >
22732290 < Chip size = "small" label = { tab . icon } />
22742291 </ TableCell >
2275- < TableCell >
2292+ < TableCell data-label = "Show Label" >
22762293 < Switch
22772294 checked = { Boolean ( tab . show_label ) }
22782295 onClick = { ( e ) => e . stopPropagation ( ) }
@@ -2327,7 +2344,7 @@ const AdminPanel = ({ setWidgetSettings, onPluginsChanged, onTabsChanged }) => {
23272344 </ Box >
23282345
23292346 < TableContainer component = { Paper } >
2330- < Table >
2347+ < Table sx = { stackableTableSx } >
23312348 < TableHead >
23322349 < TableRow >
23332350 < TableCell > Name</ TableCell >
@@ -2341,18 +2358,18 @@ const AdminPanel = ({ setWidgetSettings, onPluginsChanged, onTabsChanged }) => {
23412358 const isCurrent = device . name === currentDeviceName ;
23422359 return (
23432360 < TableRow key = { device . name } >
2344- < TableCell >
2361+ < TableCell data-label = "Name" >
23452362 < Box sx = { { display : 'flex' , alignItems : 'center' , gap : 1 , flexWrap : 'wrap' } } >
23462363 { isCurrent && < Chip label = "Current" color = "primary" size = "small" /> }
23472364 < Typography variant = "body2" sx = { { fontFamily : 'monospace' } } >
23482365 { device . name }
23492366 </ Typography >
23502367 </ Box >
23512368 </ TableCell >
2352- < TableCell >
2369+ < TableCell data-label = "Last Updated" >
23532370 { device . updateTime ? new Date ( device . updateTime ) . toLocaleString ( ) : 'Unknown' }
23542371 </ TableCell >
2355- < TableCell >
2372+ < TableCell data-label = "Widgets" >
23562373 < Chip label = { Number ( device . widgets ) || 0 } size = "small" />
23572374 </ TableCell >
23582375 < TableCell >
@@ -2767,7 +2784,7 @@ const AdminPanel = ({ setWidgetSettings, onPluginsChanged, onTabsChanged }) => {
27672784 </ Box >
27682785
27692786 < TableContainer component = { Paper } >
2770- < Table >
2787+ < Table sx = { stackableTableSx } >
27712788 < TableHead >
27722789 < TableRow >
27732790 < TableCell > Avatar</ TableCell >
@@ -2799,7 +2816,7 @@ const AdminPanel = ({ setWidgetSettings, onPluginsChanged, onTabsChanged }) => {
27992816 </ Button >
28002817 </ Box >
28012818 </ TableCell >
2802- < TableCell >
2819+ < TableCell data-label = "Username" >
28032820 { editingUser ?. id === user . id ? (
28042821 < TextField
28052822 value = { editingUser . username }
@@ -2810,7 +2827,7 @@ const AdminPanel = ({ setWidgetSettings, onPluginsChanged, onTabsChanged }) => {
28102827 user . username
28112828 ) }
28122829 </ TableCell >
2813- < TableCell >
2830+ < TableCell data-label = "Email" sx = { { '@media (max-width:599.95px)' : { wordBreak : 'break-all' } } } >
28142831 { editingUser ?. id === user . id ? (
28152832 < TextField
28162833 value = { editingUser . email }
@@ -2821,7 +2838,7 @@ const AdminPanel = ({ setWidgetSettings, onPluginsChanged, onTabsChanged }) => {
28212838 user . email
28222839 ) }
28232840 </ TableCell >
2824- < TableCell >
2841+ < TableCell data-label = "Clam Total" >
28252842 < Box sx = { { display : 'flex' , alignItems : 'center' , gap : 1 } } >
28262843 < Chip
28272844 label = { `${ user . clam_total || 0 } 🥟` }
@@ -2839,7 +2856,7 @@ const AdminPanel = ({ setWidgetSettings, onPluginsChanged, onTabsChanged }) => {
28392856 </ Tooltip >
28402857 </ Box >
28412858 </ TableCell >
2842- < TableCell >
2859+ < TableCell data-label = "Chores" >
28432860 < Button
28442861 variant = "outlined"
28452862 size = "small"
@@ -2978,7 +2995,14 @@ const AdminPanel = ({ setWidgetSettings, onPluginsChanged, onTabsChanged }) => {
29782995 </ Box >
29792996
29802997 < Box sx = { { borderBottom : 1 , borderColor : 'divider' , mb : 3 } } >
2981- < Tabs value = { choresSubTab } onChange = { ( _ , v ) => setChoresSubTab ( v ) } size = "small" >
2998+ < Tabs
2999+ value = { choresSubTab }
3000+ onChange = { ( _ , v ) => setChoresSubTab ( v ) }
3001+ size = "small"
3002+ variant = "scrollable"
3003+ scrollButtons = "auto"
3004+ allowScrollButtonsMobile
3005+ >
29823006 < Tab label = "Chores" />
29833007 < Tab label = "History" />
29843008 </ Tabs >
@@ -3045,7 +3069,7 @@ const AdminPanel = ({ setWidgetSettings, onPluginsChanged, onTabsChanged }) => {
30453069 { prizes . map ( ( prize ) => (
30463070 < ListItem key = { prize . id } sx = { { border : '1px solid var(--card-border)' , borderRadius : 1 , mb : 1 } } >
30473071 { editingPrize ?. id === prize . id ? (
3048- < Box sx = { { display : 'flex' , gap : 2 , width : '100%' , alignItems : ' center' } } >
3072+ < Box sx = { { display : 'flex' , flexDirection : { xs : 'column' , sm : 'row' } , gap : 2 , width : '100%' , alignItems : { xs : 'stretch' , sm : ' center' } } } >
30493073 < TextField
30503074 label = "Prize Name"
30513075 value = { editingPrize . name }
@@ -3057,7 +3081,7 @@ const AdminPanel = ({ setWidgetSettings, onPluginsChanged, onTabsChanged }) => {
30573081 type = "number"
30583082 value = { editingPrize . clam_cost }
30593083 onChange = { ( e ) => setEditingPrize ( { ...editingPrize , clam_cost : parseInt ( e . target . value ) || 0 } ) }
3060- sx = { { width : 120 } }
3084+ sx = { { width : { xs : '100%' , sm : 120 } } }
30613085 />
30623086 < IconButton onClick = { savePrize } color = "primary" >
30633087 < Save />
@@ -3459,6 +3483,7 @@ const AdminPanel = ({ setWidgetSettings, onPluginsChanged, onTabsChanged }) => {
34593483 onClose = { ( ) => setDeleteTabDialog ( { open : false , tab : null } ) }
34603484 maxWidth = "sm"
34613485 fullWidth
3486+ fullScreen = { isMobile }
34623487 >
34633488 < DialogTitle >
34643489 < Box sx = { { display : 'flex' , alignItems : 'center' , gap : 1 } } >
@@ -3489,6 +3514,7 @@ const AdminPanel = ({ setWidgetSettings, onPluginsChanged, onTabsChanged }) => {
34893514 onClose = { ( ) => setCopyDeviceDialog ( { open : false , device : null } ) }
34903515 maxWidth = "sm"
34913516 fullWidth
3517+ fullScreen = { isMobile }
34923518 >
34933519 < DialogTitle >
34943520 < Box sx = { { display : 'flex' , alignItems : 'center' , gap : 1 } } >
@@ -3525,6 +3551,7 @@ const AdminPanel = ({ setWidgetSettings, onPluginsChanged, onTabsChanged }) => {
35253551 onClose = { ( ) => setRenameDeviceDialog ( { open : false , currentName : '' , newName : '' , error : '' } ) }
35263552 maxWidth = "sm"
35273553 fullWidth
3554+ fullScreen = { isMobile }
35283555 >
35293556 < DialogTitle >
35303557 < Box sx = { { display : 'flex' , alignItems : 'center' , gap : 1 } } >
@@ -3559,6 +3586,7 @@ const AdminPanel = ({ setWidgetSettings, onPluginsChanged, onTabsChanged }) => {
35593586 onClose = { ( ) => setDeleteDeviceDialog ( { open : false , device : null } ) }
35603587 maxWidth = "sm"
35613588 fullWidth
3589+ fullScreen = { isMobile }
35623590 >
35633591 < DialogTitle >
35643592 < Box sx = { { display : 'flex' , alignItems : 'center' , gap : 1 } } >
@@ -3590,6 +3618,7 @@ const AdminPanel = ({ setWidgetSettings, onPluginsChanged, onTabsChanged }) => {
35903618 onClose = { ( ) => setDeleteUserDialog ( { open : false , user : null } ) }
35913619 maxWidth = "sm"
35923620 fullWidth
3621+ fullScreen = { isMobile }
35933622 >
35943623 < DialogTitle >
35953624 < Box sx = { { display : 'flex' , alignItems : 'center' , gap : 1 } } >
@@ -3632,6 +3661,7 @@ const AdminPanel = ({ setWidgetSettings, onPluginsChanged, onTabsChanged }) => {
36323661 onClose = { closeChoreModal }
36333662 maxWidth = "md"
36343663 fullWidth
3664+ fullScreen = { isMobile }
36353665 >
36363666 < DialogTitle >
36373667 < Box sx = { { display : 'flex' , alignItems : 'center' , gap : 1 } } >
@@ -3652,7 +3682,7 @@ const AdminPanel = ({ setWidgetSettings, onPluginsChanged, onTabsChanged }) => {
36523682 </ Typography >
36533683 ) : (
36543684 < TableContainer component = { Paper } sx = { { mt : 1 } } >
3655- < Table >
3685+ < Table sx = { stackableTableSx } >
36563686 < TableHead >
36573687 < TableRow >
36583688 < TableCell > Title</ TableCell >
@@ -3666,29 +3696,29 @@ const AdminPanel = ({ setWidgetSettings, onPluginsChanged, onTabsChanged }) => {
36663696 < TableBody >
36673697 { choreModal . userChores . map ( ( chore ) => (
36683698 < TableRow key = { chore . id } >
3669- < TableCell >
3699+ < TableCell data-label = "Title" >
36703700 < Typography variant = "body2" sx = { { fontWeight : 'bold' } } >
36713701 { chore . title }
36723702 </ Typography >
36733703 </ TableCell >
3674- < TableCell >
3704+ < TableCell data-label = "Description" >
36753705 < Typography variant = "body2" color = "text.secondary" >
36763706 { chore . description || 'No description' }
36773707 </ Typography >
36783708 </ TableCell >
3679- < TableCell >
3709+ < TableCell data-label = "Schedule" >
36803710 < Typography variant = "body2" sx = { { fontFamily : 'monospace' } } >
36813711 { chore . crontab || 'One-time' }
36823712 </ Typography >
36833713 </ TableCell >
3684- < TableCell >
3714+ < TableCell data-label = "Visible" >
36853715 < Chip
36863716 label = { chore . visible ? 'Visible' : 'Hidden' }
36873717 color = { chore . visible ? 'success' : 'default' }
36883718 size = "small"
36893719 />
36903720 </ TableCell >
3691- < TableCell >
3721+ < TableCell data-label = "Clams" >
36923722 { chore . clam_value > 0 ? (
36933723 < Chip
36943724 label = { `${ chore . clam_value } 🥟` }
0 commit comments