From 7aff4ca10d20d9e41597f482e1e6747ca5789df1 Mon Sep 17 00:00:00 2001 From: Meriem-BenIsmail Date: Fri, 14 Feb 2025 10:05:46 +0100 Subject: [PATCH 01/11] style adjusting with JupyterHub 5 --- dev-requirements.txt | 2 +- src/common/style.css | 37 ++++++++++++++++++ src/environments/App.tsx | 44 ++++++++++++++++++++-- src/environments/EnvironmentList.tsx | 8 ++-- src/environments/NewEnvironmentDialog.tsx | 4 +- src/servers/App.tsx | 44 ++++++++++++++++++++-- src/servers/NewServerDialog.tsx | 8 +++- src/servers/ServersList.tsx | 8 ++-- tljh_repo2docker/templates/images.html | 2 +- tljh_repo2docker/templates/page.html | 46 +++++++++++------------ tljh_repo2docker/templates/servers.html | 2 +- 11 files changed, 163 insertions(+), 42 deletions(-) diff --git a/dev-requirements.txt b/dev-requirements.txt index 77d4592..fc83389 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -1,6 +1,6 @@ git+https://github.com/jupyterhub/the-littlest-jupyterhub@1.0.0 git+https://github.com/jupyterhub/binderhub.git@main -jupyterhub>=4,<5 +jupyterhub>=5 alembic>=1.13.0,<1.14 pytest pytest-aiohttp diff --git a/src/common/style.css b/src/common/style.css index 0328a57..8dadee6 100644 --- a/src/common/style.css +++ b/src/common/style.css @@ -1,3 +1,40 @@ .MuiButton-root { text-transform: capitalize !important; + font-size: 1rem !important; +} +.MuiScopedCssBaseline-root { + background-color: var(--bs-body-bg) !important; +} +/*DataGrid custom styling*/ +.tljh-container .MuiDataGrid-root, +.tljh-form-dialog .MuiDataGrid-root { + font-size: 1rem !important; +} +.tljh-container .MuiSvgIcon-root, +.tljh-form-dialog .MuiSvgIcon-root { + width: 1.5rem; + height: 1.5rem; +} +.tljh-container .MuiTablePagination-displayedRows, +.tljh-form-dialog .MuiTablePagination-displayedRows { + font-size: 1.1rem !important; +} + +/* Dialog custom styling */ +.tljh-form-dialog .MuiDialogTitle-root { + font-size: 1.5rem !important; +} +.tljh-form-dialog .MuiInputLabel-root, +.tljh-form-dialog .MuiInputBase-root { + font-size: 1rem !important; +} +.tljh-form-dialog .MuiMenuItem-root { + font-size: inherit !important; +} +.tljh-form-dialog .MuiDivider-wrapper .MuiTypography-root, +.tljh-form-dialog .MuiDialogContentText-root { + font-size: 1.1rem !important; +} +.tljh-form-dialog .MuiFormHelperText-root { + font-size: inherit !important; } diff --git a/src/environments/App.tsx b/src/environments/App.tsx index 5a301ef..83b7f56 100644 --- a/src/environments/App.tsx +++ b/src/environments/App.tsx @@ -1,15 +1,15 @@ import { Stack } from '@mui/material'; import ScopedCssBaseline from '@mui/material/ScopedCssBaseline'; -import { ThemeProvider } from '@mui/material/styles'; +import { ThemeProvider, createTheme } from '@mui/material/styles'; -import { customTheme } from '../common/theme'; import { IEnvironmentData } from './types'; import { EnvironmentList } from './EnvironmentList'; import { IMachineProfile, NewEnvironmentDialog } from './NewEnvironmentDialog'; import { AxiosContext } from '../common/AxiosContext'; -import { useMemo } from 'react'; +import { useEffect, useMemo, useState } from 'react'; import { AxiosClient } from '../common/axiosclient'; import { useJupyterhub } from '../common/JupyterhubContext'; +import '../common/style.css'; export interface IAppProps { images: IEnvironmentData[]; @@ -22,6 +22,44 @@ export interface IAppProps { export default function App(props: IAppProps) { const jhData = useJupyterhub(); + const [themeMode, setThemeMode] = useState<'light' | 'dark'>( + (document.documentElement.getAttribute('data-bs-theme') as + | 'light' + | 'dark') || 'light' + ); + + useEffect(() => { + const observer = new MutationObserver(() => { + const newTheme = document.documentElement.getAttribute( + 'data-bs-theme' + ) as 'light' | 'dark'; + if (newTheme !== themeMode) { + setThemeMode(newTheme); + } + }); + + observer.observe(document.documentElement, { + attributes: true, + attributeFilter: ['data-bs-theme'] + }); + + return () => observer.disconnect(); + }, [themeMode]); + + // Create theme dynamically based on mode + const customTheme = useMemo( + () => + createTheme({ + palette: { + mode: themeMode, + primary: { main: '#1976D2' }, + secondary: { main: '#FF4081' } + }, + typography: { fontSize: 22 } + }), + [themeMode] + ); + const serviceClient = useMemo(() => { const baseUrl = jhData.servicePrefix; const xsrfToken = jhData.xsrfToken; diff --git a/src/environments/EnvironmentList.tsx b/src/environments/EnvironmentList.tsx index 296ad7f..fcbc8e1 100644 --- a/src/environments/EnvironmentList.tsx +++ b/src/environments/EnvironmentList.tsx @@ -29,7 +29,7 @@ const columns: GridColDef[] = [ { field: 'ref', headerName: 'Reference', - maxWidth: 150, + width: 200, renderCell: params => { return ( {params.value} @@ -39,17 +39,17 @@ const columns: GridColDef[] = [ { field: 'mem_limit', headerName: 'Mem. Limit (GB)', - width: 150 + width: 200 }, { field: 'cpu_limit', headerName: 'CPU Limit', - width: 100 + width: 150 }, { field: 'status', headerName: 'Status', - width: 100, + width: 150, hideSortIcons: true, renderCell: params => { return params.value === 'built' ? ( diff --git a/src/environments/NewEnvironmentDialog.tsx b/src/environments/NewEnvironmentDialog.tsx index 335b666..a126d1c 100644 --- a/src/environments/NewEnvironmentDialog.tsx +++ b/src/environments/NewEnvironmentDialog.tsx @@ -193,11 +193,13 @@ function _NewEnvironmentDialog(props: INewEnvironmentDialogProps) { Create new environment + ) => { diff --git a/src/servers/App.tsx b/src/servers/App.tsx index d5b4f51..072b0f3 100644 --- a/src/servers/App.tsx +++ b/src/servers/App.tsx @@ -1,16 +1,16 @@ import { Stack } from '@mui/material'; import ScopedCssBaseline from '@mui/material/ScopedCssBaseline'; -import { ThemeProvider } from '@mui/material/styles'; +import { ThemeProvider, createTheme } from '@mui/material/styles'; +import { useEffect, useMemo, useState } from 'react'; -import { customTheme } from '../common/theme'; import { IServerData } from './types'; import { AxiosContext } from '../common/AxiosContext'; -import { useMemo } from 'react'; import { AxiosClient } from '../common/axiosclient'; import { ServerList } from './ServersList'; import { NewServerDialog } from './NewServerDialog'; import { IEnvironmentData } from '../environments/types'; import { useJupyterhub } from '../common/JupyterhubContext'; +import '../common/style.css'; export interface IAppProps { images: IEnvironmentData[]; @@ -22,6 +22,44 @@ export interface IAppProps { export default function App(props: IAppProps) { const jhData = useJupyterhub(); + const [themeMode, setThemeMode] = useState<'light' | 'dark'>( + (document.documentElement.getAttribute('data-bs-theme') as + | 'light' + | 'dark') || 'light' + ); + + useEffect(() => { + const observer = new MutationObserver(() => { + const newTheme = document.documentElement.getAttribute( + 'data-bs-theme' + ) as 'light' | 'dark'; + if (newTheme !== themeMode) { + setThemeMode(newTheme); + } + }); + + observer.observe(document.documentElement, { + attributes: true, + attributeFilter: ['data-bs-theme'] + }); + + return () => observer.disconnect(); + }, [themeMode]); + + // Create theme dynamically based on mode + const customTheme = useMemo( + () => + createTheme({ + palette: { + mode: themeMode, + primary: { main: '#1976D2' }, + secondary: { main: '#FF4081' } + }, + typography: { fontSize: 22 } + }), + [themeMode] + ); + const serviceClient = useMemo(() => { const baseUrl = jhData.servicePrefix; const xsrfToken = jhData.xsrfToken; diff --git a/src/servers/NewServerDialog.tsx b/src/servers/NewServerDialog.tsx index 608f4c1..047023d 100644 --- a/src/servers/NewServerDialog.tsx +++ b/src/servers/NewServerDialog.tsx @@ -105,7 +105,13 @@ function _NewServerDialog(props: INewServerDialogProps) { Create new Server - + Server Options diff --git a/src/servers/ServersList.tsx b/src/servers/ServersList.tsx index d65c290..4d46ca2 100644 --- a/src/servers/ServersList.tsx +++ b/src/servers/ServersList.tsx @@ -23,12 +23,12 @@ const columns: GridColDef[] = [ { field: 'last_activity', headerName: 'Last activity', - width: 150 + width: 250 }, { field: 'active', headerName: 'Status', - width: 100, + width: 125, hideSortIcons: true, renderCell: params => { return params.value ? ( @@ -45,7 +45,7 @@ const columns: GridColDef[] = [ { field: 'status', headerName: '', - width: 125, + width: 175, filterable: false, sortable: false, hideable: false, @@ -56,7 +56,7 @@ const columns: GridColDef[] = [ { field: 'action', headerName: '', - width: 125, + width: 175, filterable: false, sortable: false, hideable: false, diff --git a/tljh_repo2docker/templates/images.html b/tljh_repo2docker/templates/images.html index 87cc8ec..eaad85e 100644 --- a/tljh_repo2docker/templates/images.html +++ b/tljh_repo2docker/templates/images.html @@ -1,5 +1,5 @@ {% extends "page.html" %} {% block main %} -
+
diff --git a/tljh_repo2docker/templates/page.html b/tljh_repo2docker/templates/page.html index 3e2a194..50e41c1 100644 --- a/tljh_repo2docker/templates/page.html +++ b/tljh_repo2docker/templates/page.html @@ -30,6 +30,11 @@ } + + {% block meta %} {% endblock %} @@ -42,11 +47,10 @@ {% block nav_bar %} -