Skip to content

Commit

Permalink
feat: responsive mobile support (#8)
Browse files Browse the repository at this point in the history
  • Loading branch information
drochetti authored May 5, 2023
1 parent 654007d commit e6abec1
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 67 deletions.
6 changes: 3 additions & 3 deletions src/components/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ export interface CardProps {
export default function Card(props: PropsWithChildren<CardProps>) {
return (
<div
className={`prose card rounded-md bg-base-200 shadow max-w-full ${
className={`prose card rounded-none md:rounded-md bg-base-200 shadow-sm md:shadow max-w-full ${
props.classNames ?? ""
}`}
>
<div className="card-body">
<div className="card-body p-4 md:p-8">
{props.title && (
<h3 className="card-title font-light uppercase opacity-60 mt-0">
<h3 className="card-title text-sm md:text-lg font-light uppercase opacity-60 mt-0">
{props.title}
</h3>
)}
Expand Down
2 changes: 1 addition & 1 deletion src/components/EmptyMessage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export interface EmptyMessageProps {

export default function EmptyMessage(props: EmptyMessageProps) {
return (
<div className="text-center font-light prose prose-slate max-w-full my-8">
<div className="text-center font-light prose prose-slate max-w-full my-4 md:my-8">
<InformationCircleIcon className="h-6 w-6 opacity-40 inline-block me-2" />
{props.message}
</div>
Expand Down
18 changes: 13 additions & 5 deletions src/components/ErrorNotification.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { XCircleIcon } from "@heroicons/react/24/outline";
import { useCallback } from "react";

export interface ErrorNotificationProps {
message: string;
Expand All @@ -7,16 +8,23 @@ export interface ErrorNotificationProps {
}

export default function ErrorNotification(props: ErrorNotificationProps) {
const { details, message, onDismiss } = props;
const handleDismiss = useCallback(() => {
onDismiss?.call(null);
}, [onDismiss]);
return (
<div className="toast toast-top toast-center md:toast-end">
<div className="alert alert-error rounded-md space-y-4">
<div className="toast toast-top toast-center w-full md:w-auto md:toast-end">
<div
className="alert alert-error rounded-md space-y-2 md:space-y-4"
onClick={handleDismiss}
>
<div>
<XCircleIcon className="flex-shrink-0 h-6 w-6" />
<span>{props.message}</span>
<span>{message}</span>
</div>
{props.details && (
{details && (
<div>
<span>{props.details}</span>
<span>{details}</span>
</div>
)}
</div>
Expand Down
96 changes: 61 additions & 35 deletions src/components/ImageSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,35 +11,50 @@ export interface ImageFile {
};
}

type OnImageSelect = (image: ImageFile) => void;

export interface ImageSelectorProps {
disabled: boolean;
onImageSelect: (image: ImageFile) => void;
onImageSelect: OnImageSelect;
}

const MAX_FILE_SIZE = 4 * 1024 * 1024; // 4MB

export default function ImageSelector(props: ImageSelectorProps) {
const { onImageSelect } = props;

const readImage = (file: File, callback: OnImageSelect) => {
let data = "";
const image = new Image();
const reader = new FileReader();
image.onload = () => {
callback({
data,
filename: file.name,
size: { width: image.width, height: image.height },
});
};
reader.onloadend = () => {
data = reader.result?.toString() ?? data;
image.src = data;
};
reader.readAsDataURL(file);
};

const onFileSelected = useCallback(
(event: React.ChangeEvent<HTMLInputElement>) => {
const file = event.target.files?.[0];
if (file) {
readImage(file, onImageSelect);
}
},
[onImageSelect]
);
const onDrop = useCallback(
(files: File[]) => {
if (files && files.length) {
const file = files[0];

let data = "";
const image = new Image();
const reader = new FileReader();
image.onload = () => {
onImageSelect({
data,
filename: file.name,
size: { width: image.width, height: image.height },
});
};
reader.onloadend = () => {
data = reader.result?.toString() ?? data;
image.src = data;
};
reader.readAsDataURL(file);
readImage(file, onImageSelect);
}
},
[onImageSelect]
Expand All @@ -55,29 +70,40 @@ export default function ImageSelector(props: ImageSelectorProps) {
});

return (
<label
{...getRootProps()}
className="flex justify-center w-full h-fill px-4 py-16 transition bg-base-100 bg-opacity-30 border-2 dark:border-base-100 border-dashed rounded-md appearance-none cursor-pointer focus:outline-none"
>
<div className="flex flex-col items-center prose">
<PhotoIcon className="m-auto w-64 h-64 opacity-5" />
<p className="font-medium text-lg mx-0 mt-6 mb-2">
Drop image file to begin, or{" "}
<span className="text-secondary">click</span> to browse
</p>
<p id="file_input_help" className="opacity-80 mx-0 mt-0">
Accepted formats: .jpg, .png (max size: 4MB)
</p>
</div>
<>
<label
{...getRootProps()}
className="hidden md:display md:flex justify-center w-full h-fill px-4 py-16 transition bg-base-100 bg-opacity-30 border-2 dark:border-base-100 border-dashed rounded-md appearance-none cursor-pointer focus:outline-none"
>
<div className="flex flex-col items-center prose">
<PhotoIcon className="m-auto w-64 h-64 opacity-5" />
<p className="font-medium text-lg mx-0 mt-6 mb-2">
Drop image file to begin, or{" "}
<span className="text-secondary">click</span> to browse
</p>
<p id="file_input_help" className="opacity-80 mx-0 mt-0">
Accepted formats: .jpg, .png (max size: 4MB)
</p>
</div>
<input
id="file_input"
type="file"
name="image"
{...getInputProps()}
aria-describedby="file_input_help"
className="hidden"
disabled={props.disabled}
/>
</label>
<input
id="file_input"
type="file"
name="image"
{...getInputProps()}
aria-describedby="file_input_help"
className="hidden"
accept="image/jpeg,image/jpg,image/png"
className="md:hidden file-input w-full placeholder-gray-500"
disabled={props.disabled}
onChange={onFileSelected}
/>
</label>
</>
);
}
8 changes: 1 addition & 7 deletions src/pages/_navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,7 @@ export default function NavBar() {
</a>
</span>
</div>
<div className="flex-none">
<ul className="text-sm menu menu-horizontal px-1">
<li>
<a>About</a>
</li>
</ul>
</div>
<div className="flex-none"></div>
</div>
</div>
);
Expand Down
35 changes: 19 additions & 16 deletions src/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ const Home = () => {
setError(null);
}, [step, selectedImage, position, selectedMask]);

const dismissError = () => {
setError(null);
};

const handleImageSelected = (image: ImageFile) => {
setSelectedImage(image);
setStep(StepName.SetMaskPoint);
Expand Down Expand Up @@ -141,12 +145,12 @@ const Home = () => {
const hasPrompt = prompt && prompt.trim().length > 0;

return (
<main className="min-h-screen py-16">
<main className="min-h-screen md:py-12">
<Head>
<title>Edit Anything | fal-serverless</title>
</Head>
<div className="container mx-auto grid grid-cols-1 md:grid-cols-3 gap-8 w-full">
<div className="md:col-span-3">
<div className="hidden md:display md:col-span-3">
<Card>
<Steps currentStep={step} />
</Card>
Expand Down Expand Up @@ -187,11 +191,13 @@ const Home = () => {
<div className="md:col-span-1">
<Card title="Masks" classNames="min-h-full">
{masks.length === 0 && (
<div className="mt-12">
<EmptyMessage message="No masks generated yet" />
<div className="items-center mt-0 md:mt-12">
<div className="hidden md:display">
<EmptyMessage message="No masks generated yet" />
</div>
<div className="flex flex-col items-center">
<button
className="btn btn-primary"
className="btn btn-primary max-sm:btn-wide mb-4 md:mb-0"
disabled={isLoading || !selectedImage || !position}
onClick={generateMasks}
>
Expand Down Expand Up @@ -222,13 +228,10 @@ const Home = () => {
</div>
</div>
<div className="container mx-auto pt-8 w-full">
<Card>
<div className="flex space-x-6">
<div className="form-control w-3/5 max-w-full">
<label className="input-group">
<span>
<code className="opacity-40">/imagine</code>
</span>
<Card title="Imagine...">
<div className="flex flex-col md:flex-row md:space-x-6">
<div className="form-control w-full md:w-3/5 max-w-full">
<label>
<input
id="prompt_input"
type="text"
Expand All @@ -242,7 +245,7 @@ const Home = () => {
</label>
</div>
<button
className="btn btn-primary"
className="btn btn-primary max-sm:btn-wide mt-4 mx-auto md:mx-0 md:mt-0"
disabled={isLoading || !selectedMask || !hasPrompt}
onClick={handleGenerate}
>
Expand All @@ -254,7 +257,7 @@ const Home = () => {
<EmptyMessage message="Nothing to see just yet" />
</div>
)}
<div className="grid grid-cols-2 gap-4 mt-6">
<div className="grid grid-cols-1 gap-4 mt-4 md:mt-6 lg:p-12 mx-auto">
{imageUrls.map((url, index) => (
<NextImage
key={index}
Expand All @@ -272,15 +275,15 @@ const Home = () => {
</div>
{isLoading && (
<div className="fixed top-0 left-0 w-full h-full bg-black bg-opacity-50 flex items-center justify-center z-50">
<div className="alert max-w-md shadow-lg p-12">
<div className="alert max-w-md shadow-lg p-6 md:p-12 mx-4 md:mx-0">
<div className="flex-col items-center pt-6 w-full">
<progress className="progress progress-primary w-max-[60%]"></progress>
<p className="my-4">Hold on tight, we&apos;re working on it!</p>
</div>
</div>
</div>
)}
{error && <ErrorNotification {...error} />}
{error && <ErrorNotification {...error} onDismiss={dismissError} />}
</main>
);
};
Expand Down

0 comments on commit e6abec1

Please sign in to comment.