-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* fix theme-toggler arrow functions * fix form-auth card paddings * add photo_profile and mingcute_camera icons * add base profile login page and its file-input component * bug do not work drag and drop * add new cross icon * add new profile name length constant * add file input component * add form profile component * add profile page * fix code style and add progress bar * add progress shadcn component * fix svgs colors display in file input component * move progress timeout delay to constant * swap bg colors in progress bar * fix img tag to next image * fix specially for shitheads that cant read through blank lines * remove unnecessary styles from imagecard in auth page * remove unnecessary styles from imagecard in profile page and move imagecard to profile page
- Loading branch information
Showing
12 changed files
with
374 additions
and
2 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,4 +8,6 @@ Roboto | |
subheadline | ||
linecap | ||
linejoin | ||
mingcute | ||
shadcn | ||
clsx |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import ImageCard from '@/components/pages/auth/image-card' | ||
import FileInput from '@/components/pages/profile/file-input' | ||
import FormProfile from '@/components/pages/profile/form-profile' | ||
import Content from '@/components/ui/content' | ||
import { ThemeToggler } from '@/components/ui/theme-toggler' | ||
|
||
export default function Profile() { | ||
return ( | ||
<section className="h-screen w-screen bg-gradient-blue-white"> | ||
<Content className="flex items-center justify-center dark:bg-none dark:bg-base-gray-8"> | ||
<div className="p-7 sm:p-10 flex gap-7 md:gap-[3.75rem] rounded-3xl bg-base-white dark:bg-base-black"> | ||
<ImageCard className="-my-[4.375rem] flex-shrink-0 hidden sm:flex py-32 px-[3.25rem]"> | ||
<FileInput /> | ||
</ImageCard> | ||
<div> | ||
<div className="flex justify-between pb-2 mt-8"> | ||
<h1 className="title-lg">Profile</h1> | ||
<ThemeToggler /> | ||
</div> | ||
<FormProfile className="mt-5" /> | ||
</div> | ||
</div> | ||
</Content> | ||
</section> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
'use client' | ||
|
||
import { Icons } from '@/components/ui/icons' | ||
import { Progress } from '@/components/ui/progress' | ||
import { PROGRESS_TIMEOUT_DELAY } from '@/constants' | ||
import { cn } from '@/lib/utils' | ||
import Image from 'next/image' | ||
import { FC, FormEvent, useRef, useState } from 'react' | ||
|
||
type FileInputProps = { | ||
className?: string | ||
} | ||
|
||
const FileInput: FC<FileInputProps> = ({ className }) => { | ||
const fileInputRef = useRef<HTMLInputElement>(null) | ||
|
||
const [_, setImage] = useState<File | undefined>() | ||
|
||
const [preview, setPreview] = useState<string | undefined>() | ||
|
||
const [progress, setProgress] = useState<number>(0) | ||
|
||
const clearSelectFile = () => { | ||
setPreview(undefined) | ||
} | ||
|
||
const handleSelectFile = () => { | ||
fileInputRef.current?.click() | ||
} | ||
|
||
const handleImageLoad = (file: File) => { | ||
setImage(file) | ||
|
||
const fileReader = new FileReader() | ||
|
||
fileReader.readAsDataURL(file) | ||
|
||
fileReader.onloadstart = () => { | ||
setProgress(0) | ||
} | ||
fileReader.onprogress = (progress) => { | ||
setProgress((progress.loaded / progress.total) * 100) | ||
} | ||
fileReader.onload = () => { | ||
setPreview(fileReader.result as string) | ||
setTimeout(() => setProgress(0), PROGRESS_TIMEOUT_DELAY) | ||
} | ||
} | ||
|
||
const handleImageChange = (event: FormEvent<HTMLInputElement>) => { | ||
const target = event.target as HTMLElement & { | ||
files: FileList | ||
} | ||
|
||
if (target.files.length > 0) { | ||
handleImageLoad(target.files[0]) | ||
} | ||
} | ||
|
||
return ( | ||
<div className={cn('relative', className)}> | ||
{preview ? ( | ||
<div> | ||
<div className="relative w-[144px] h-[144px] overflow-hidden rounded-3xl"> | ||
<Image alt="avatar" fill src={preview} /> | ||
</div> | ||
<Icons.cross | ||
className="absolute z-10 top-4 right-4 text-base-white dark:text-base-black" | ||
onClick={clearSelectFile} | ||
/> | ||
</div> | ||
) : ( | ||
<div> | ||
<Icons.photo_profile className="text-base-gray-2 dark:text-base-black" /> | ||
</div> | ||
)} | ||
<div | ||
className="absolute -bottom-4 right-1/2 translate-x-1/2" | ||
onClick={handleSelectFile} | ||
> | ||
<Icons.mingcute_camera className="text-white dark:text-bright-indigo" /> | ||
</div> | ||
|
||
<div | ||
className={cn( | ||
'absolute z-[11] top-1/2 left-1/2 w-full', | ||
!progress && 'w-0' | ||
)} | ||
> | ||
<Progress | ||
className="w-5/6 relative mx-auto transition-[width] duration-500 ease-in-out -left-1/2" | ||
value={progress} | ||
/> | ||
</div> | ||
|
||
<input | ||
className="absolute block h-full w-full top-0 opacity-0 rounded-3xl" | ||
name="image" | ||
onChange={handleImageChange} | ||
ref={fileInputRef} | ||
type="file" | ||
/> | ||
<span className="sr-only">File input</span> | ||
</div> | ||
) | ||
} | ||
|
||
export default FileInput |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
'use client' | ||
|
||
import { Button } from '@/components/ui/button' | ||
import { | ||
Form, | ||
FormControl, | ||
FormField, | ||
FormItem, | ||
FormMessage, | ||
} from '@/components/ui/form' | ||
import { Input } from '@/components/ui/input' | ||
import { PROFILE_NAME_LENGTH } from '@/constants' | ||
import { classnames } from '@/utils' | ||
import { zodResolver } from '@hookform/resolvers/zod' | ||
import { FC } from 'react' | ||
import { useForm } from 'react-hook-form' | ||
import * as z from 'zod' | ||
|
||
type FormProfileProps = { className?: string } | ||
|
||
const formSchema = z.object({ | ||
profileName: z | ||
.string() | ||
.min(PROFILE_NAME_LENGTH, 'The field must not be empty'), | ||
}) | ||
|
||
const ProfileForm: FC<FormProfileProps> = ({ className }) => { | ||
const form = useForm<z.infer<typeof formSchema>>({ | ||
defaultValues: { | ||
profileName: '', | ||
}, | ||
resolver: zodResolver(formSchema), | ||
}) | ||
|
||
function onSubmit(values: z.infer<typeof formSchema>) { | ||
alert(JSON.stringify(values)) | ||
console.log(values) | ||
} | ||
|
||
return ( | ||
<Form {...form}> | ||
<form | ||
className={classnames('space-y-8 pr-[9.75rem]', className)} | ||
onSubmit={form.handleSubmit(onSubmit)} | ||
> | ||
<FormField | ||
control={form.control} | ||
name="profileName" | ||
render={({ field }) => ( | ||
<FormItem> | ||
<FormControl> | ||
<Input | ||
className="sm:min-w-[343px]" | ||
id="profile_name" | ||
placeholder="Profile Name" | ||
type="text" | ||
{...field} | ||
/> | ||
</FormControl> | ||
<FormMessage /> | ||
</FormItem> | ||
)} | ||
/> | ||
<Button className="!mt-8 w-full" type="submit"> | ||
Submit | ||
</Button> | ||
</form> | ||
</Form> | ||
) | ||
} | ||
|
||
export default ProfileForm |
Oops, something went wrong.