Made the UI mobile friendly, finally...
This commit is contained in:
@@ -10,7 +10,7 @@ export default function Dashboard() {
|
||||
<>
|
||||
<TopBar>
|
||||
<div>
|
||||
<h1 className="text-lg">Dashboard</h1>
|
||||
<h1 className="text-base sm:text-lg">Dashboard</h1>
|
||||
</div>
|
||||
<div className="flex-1"></div>
|
||||
</TopBar>
|
||||
|
||||
@@ -100,25 +100,29 @@ export default function DatasetPage({ params }: { params: { datasetName: string
|
||||
<>
|
||||
{/* Fixed top bar */}
|
||||
<TopBar>
|
||||
<div>
|
||||
<Button className="text-gray-500 dark:text-gray-300 px-3 mt-1" onClick={() => history.back()}>
|
||||
<div className="flex-shrink-0">
|
||||
<Button className="text-gray-500 dark:text-gray-300 px-2 sm:px-3 mt-1" onClick={() => history.back()}>
|
||||
<FaChevronLeft />
|
||||
</Button>
|
||||
</div>
|
||||
<div>
|
||||
<h1 className="text-lg">Dataset: {datasetName}</h1>
|
||||
<div className="min-w-0 flex-shrink">
|
||||
<h1 className="text-base sm:text-lg truncate">
|
||||
<span className="hidden sm:inline">Dataset: </span>
|
||||
{datasetName}
|
||||
</h1>
|
||||
</div>
|
||||
<div className="flex-1"></div>
|
||||
<div>
|
||||
<div className="flex-shrink-0 flex items-center gap-1 sm:gap-2">
|
||||
<AutoCaptionButton
|
||||
datasetPath={`${pathJoin(settings.DATASETS_FOLDER, datasetName)}`}
|
||||
setIsAutoCaptioning={setIsAutoCaptioning}
|
||||
/>
|
||||
<Button
|
||||
className="text-white bg-slate-600 px-3 py-1 rounded-md"
|
||||
className="text-white bg-slate-600 px-2 sm:px-3 py-1 rounded-md text-sm sm:text-base whitespace-nowrap"
|
||||
onClick={() => openImagesModal(datasetName, () => refreshImageList(datasetName))}
|
||||
>
|
||||
Add Images
|
||||
<span className="sm:hidden">+ Add</span>
|
||||
<span className="hidden sm:inline">Add Images</span>
|
||||
</Button>
|
||||
</div>
|
||||
</TopBar>
|
||||
|
||||
@@ -114,15 +114,16 @@ export default function Datasets() {
|
||||
<>
|
||||
<TopBar>
|
||||
<div>
|
||||
<h1 className="text-lg">Datasets</h1>
|
||||
<h1 className="text-base sm:text-lg">Datasets</h1>
|
||||
</div>
|
||||
<div className="flex-1"></div>
|
||||
<div>
|
||||
<Button
|
||||
className="text-white bg-slate-600 px-3 py-1 rounded-md hover:bg-slate-500 transition-colors"
|
||||
className="text-white bg-slate-600 px-2 sm:px-3 py-1 rounded-md hover:bg-slate-500 transition-colors text-sm sm:text-base whitespace-nowrap"
|
||||
onClick={() => openNewDatasetModal()}
|
||||
>
|
||||
New Dataset
|
||||
<span className="sm:hidden">+ New</span>
|
||||
<span className="hidden sm:inline">New Dataset</span>
|
||||
</Button>
|
||||
</div>
|
||||
</TopBar>
|
||||
|
||||
@@ -43,6 +43,21 @@ body {
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
}
|
||||
|
||||
/* Prevent iOS Safari from auto-zooming when a form field is focused.
|
||||
iOS only zooms when the field's font-size is < 16px. */
|
||||
@media (max-width: 639px) {
|
||||
input,
|
||||
textarea,
|
||||
select,
|
||||
.aitk-react-select-container .aitk-react-select__control,
|
||||
.aitk-react-select-container .aitk-react-select__input,
|
||||
.aitk-react-select-container .aitk-react-select__single-value,
|
||||
.aitk-react-select-container .aitk-react-select__placeholder,
|
||||
.aitk-react-select-container .aitk-react-select__option {
|
||||
font-size: 16px !important;
|
||||
}
|
||||
}
|
||||
|
||||
@layer components {
|
||||
/* control */
|
||||
.aitk-react-select-container .aitk-react-select__control {
|
||||
|
||||
@@ -79,13 +79,13 @@ export default function JobPage({ params }: { params: { jobID: string } }) {
|
||||
<>
|
||||
{/* Fixed top bar */}
|
||||
<TopBar>
|
||||
<div>
|
||||
<Button className="text-gray-500 dark:text-gray-300 px-3 mt-1" onClick={() => redirect('/jobs')}>
|
||||
<div className="flex-shrink-0">
|
||||
<Button className="text-gray-500 dark:text-gray-300 pl-0 pr-1 sm:px-3 mt-1" onClick={() => redirect('/jobs')}>
|
||||
<FaChevronLeft />
|
||||
</Button>
|
||||
</div>
|
||||
<div>
|
||||
<h1 className="text-lg">{title}</h1>
|
||||
<div className="min-w-0 flex-shrink">
|
||||
<h1 className="text-base sm:text-lg truncate">{title}</h1>
|
||||
</div>
|
||||
<div className="flex-1"></div>
|
||||
{job && (
|
||||
@@ -112,7 +112,7 @@ export default function JobPage({ params }: { params: { jobID: string } }) {
|
||||
</>
|
||||
)}
|
||||
</MainContent>
|
||||
<div className="bg-gray-800 absolute top-12 left-0 w-full h-8 flex items-center px-2 text-sm">
|
||||
<div className="bg-gray-800 absolute top-12 left-0 w-full h-8 flex items-center px-0 sm:px-2 text-sm sm:overflow-x-auto whitespace-nowrap">
|
||||
{pages.map(page => {
|
||||
if (page.jobTypes && !page.jobTypes.includes(jobType)) {
|
||||
return null;
|
||||
@@ -121,16 +121,16 @@ export default function JobPage({ params }: { params: { jobID: string } }) {
|
||||
<Button
|
||||
key={page.value}
|
||||
onClick={() => setPageKey(page.value)}
|
||||
className={`px-4 py-1 h-8 flex items-center gap-1.5 ${page.value === pageKey ? 'bg-gray-300 dark:bg-gray-700 text-white' : ''}`}
|
||||
className={`flex-1 sm:flex-initial justify-center px-2 sm:px-4 py-1 h-8 flex items-center gap-1.5 sm:flex-shrink-0 ${page.value === pageKey ? 'bg-gray-300 dark:bg-gray-700 text-white' : ''}`}
|
||||
>
|
||||
<page.icon className="text-sm" />
|
||||
{page.name}
|
||||
<span className="hidden sm:inline">{page.name}</span>
|
||||
</Button>
|
||||
);
|
||||
})}
|
||||
{page?.menuItem && (
|
||||
<>
|
||||
<div className="flex-grow"></div>
|
||||
<div className="hidden sm:block flex-grow"></div>
|
||||
<page.menuItem job={job} />
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -190,36 +190,38 @@ export default function TrainingForm() {
|
||||
return (
|
||||
<>
|
||||
<TopBar>
|
||||
<div>
|
||||
<Button className="text-gray-500 dark:text-gray-300 px-3 mt-1" onClick={() => history.back()}>
|
||||
<div className="flex-shrink-0">
|
||||
<Button className="text-gray-500 dark:text-gray-300 px-2 sm:px-3 mt-1" onClick={() => history.back()}>
|
||||
<FaChevronLeft />
|
||||
</Button>
|
||||
</div>
|
||||
<div>
|
||||
<h1 className="text-lg">{runId ? 'Edit Training Job' : 'New Training Job'}</h1>
|
||||
<div className="flex-shrink-0">
|
||||
<h1 className="text-base sm:text-lg truncate max-w-[120px] sm:max-w-none">
|
||||
{runId ? 'Edit Training Job' : 'New Training Job'}
|
||||
</h1>
|
||||
</div>
|
||||
<div className="flex-1"></div>
|
||||
{showAdvancedView && (
|
||||
<>
|
||||
<div>
|
||||
<div className="hidden sm:block">
|
||||
<SelectInput
|
||||
value={`${gpuIDs}`}
|
||||
onChange={value => setGpuIDs(value)}
|
||||
options={gpuList.map((gpu: any) => ({ value: `${gpu.index}`, label: `GPU #${gpu.index}` }))}
|
||||
/>
|
||||
</div>
|
||||
<div className="mx-4 bg-gray-200 dark:bg-gray-800 w-1 h-6"></div>
|
||||
<div>
|
||||
<div className="hidden sm:block mx-4 bg-gray-200 dark:bg-gray-800 w-1 h-6"></div>
|
||||
<div className="hidden md:block">
|
||||
<Button className="text-gray-200 bg-gray-800 px-3 py-1 rounded-md" onClick={handleImportConfig}>
|
||||
Import Config
|
||||
</Button>
|
||||
</div>
|
||||
<div className="mx-4 bg-gray-200 dark:bg-gray-800 w-1 h-6"></div>
|
||||
<div className="hidden md:block mx-4 bg-gray-200 dark:bg-gray-800 w-1 h-6"></div>
|
||||
</>
|
||||
)}
|
||||
{!showAdvancedView && (
|
||||
<>
|
||||
<div>
|
||||
<div className="hidden sm:block">
|
||||
<SelectInput
|
||||
value={`${jobConfig?.config.process[0].type}`}
|
||||
onChange={value => {
|
||||
@@ -246,25 +248,33 @@ export default function TrainingForm() {
|
||||
options={jobTypeOptions}
|
||||
/>
|
||||
</div>
|
||||
<div className="mx-4 bg-gray-200 dark:bg-gray-800 w-1 h-6"></div>
|
||||
<div className="hidden sm:block mx-4 bg-gray-200 dark:bg-gray-800 w-1 h-6"></div>
|
||||
</>
|
||||
)}
|
||||
|
||||
<div className="pr-2">
|
||||
<div className="pr-1 sm:pr-2 flex-shrink-0">
|
||||
<Button
|
||||
className="text-gray-200 bg-gray-800 px-3 py-1 rounded-md"
|
||||
className="text-gray-200 bg-gray-800 px-2 sm:px-3 py-1 rounded-md text-xs sm:text-base"
|
||||
onClick={() => setShowAdvancedView(!showAdvancedView)}
|
||||
>
|
||||
{showAdvancedView ? 'Show Simple' : 'Show Advanced'}
|
||||
<span className="sm:hidden">{showAdvancedView ? 'Simple' : 'Advanced'}</span>
|
||||
<span className="hidden sm:inline">{showAdvancedView ? 'Show Simple' : 'Show Advanced'}</span>
|
||||
</Button>
|
||||
</div>
|
||||
<div>
|
||||
<div className="flex-shrink-0">
|
||||
<Button
|
||||
className="text-white bg-green-600 hover:bg-green-700 px-3 py-1 rounded-md"
|
||||
className="text-white bg-green-600 hover:bg-green-700 px-2 sm:px-3 py-1 rounded-md text-xs sm:text-base"
|
||||
onClick={() => saveJob()}
|
||||
disabled={status === 'saving'}
|
||||
>
|
||||
{status === 'saving' ? 'Saving...' : runId ? 'Update Job' : 'Create Job'}
|
||||
{status === 'saving' ? (
|
||||
'Saving...'
|
||||
) : (
|
||||
<>
|
||||
<span className="sm:hidden">{runId ? 'Update' : 'Create'}</span>
|
||||
<span className="hidden sm:inline">{runId ? 'Update Job' : 'Create Job'}</span>
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
</TopBar>
|
||||
|
||||
@@ -9,12 +9,16 @@ export default function Dashboard() {
|
||||
<>
|
||||
<TopBar>
|
||||
<div>
|
||||
<h1 className="text-lg">Queue</h1>
|
||||
<h1 className="text-base sm:text-lg">Queue</h1>
|
||||
</div>
|
||||
<div className="flex-1"></div>
|
||||
<div>
|
||||
<Link href="/jobs/new" className="text-white bg-slate-600 px-3 py-1 rounded-md">
|
||||
New Training Job
|
||||
<Link
|
||||
href="/jobs/new"
|
||||
className="text-white bg-slate-600 px-2 sm:px-3 py-1 rounded-md text-sm sm:text-base whitespace-nowrap"
|
||||
>
|
||||
<span className="sm:hidden">+ New Job</span>
|
||||
<span className="hidden sm:inline">New Training Job</span>
|
||||
</Link>
|
||||
</div>
|
||||
</TopBar>
|
||||
|
||||
@@ -20,6 +20,12 @@ export const metadata: Metadata = {
|
||||
description: 'A toolkit for building AI things.',
|
||||
};
|
||||
|
||||
export const viewport = {
|
||||
width: 'device-width',
|
||||
initialScale: 1,
|
||||
maximumScale: 5,
|
||||
};
|
||||
|
||||
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
||||
// Check if the AI_TOOLKIT_AUTH environment variable is set
|
||||
const authRequired = process.env.AI_TOOLKIT_AUTH ? true : false;
|
||||
|
||||
@@ -36,7 +36,7 @@ export default function Settings() {
|
||||
<>
|
||||
<TopBar>
|
||||
<div>
|
||||
<h1 className="text-lg">Settings</h1>
|
||||
<h1 className="text-base sm:text-lg">Settings</h1>
|
||||
</div>
|
||||
<div className="flex-1"></div>
|
||||
</TopBar>
|
||||
|
||||
Reference in New Issue
Block a user