Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
0d822e2
add google login
sajjadmrx Dec 7, 2025
9303e92
feat: enhance referral modal design and functionality in sign-in form
sajjadmrx Dec 7, 2025
09f5f14
feat: implement password and OTP authentication steps with Google log…
sajjadmrx Dec 7, 2025
dead134
feat: implement OTP authentication flow with request and verification…
sajjadmrx Dec 7, 2025
ee8ba28
feat: enhance Google login functionality and improve authentication e…
sajjadmrx Dec 7, 2025
6085930
feat: enhance OTP authentication flow with loading state and improved…
sajjadmrx Dec 7, 2025
96aaea4
feat: add translations for invalid OTP code and email usage instructions
sajjadmrx Dec 7, 2025
b669273
feat: expand ignored endpoints for token refreshing in API client
sajjadmrx Dec 9, 2025
183f18d
add tw-merge package
shakurt Dec 10, 2025
5d7035d
modify modal
shakurt Dec 10, 2025
7967cb0
implement auth components
shakurt Dec 10, 2025
ebaf2bf
responsive and optimize the auth components
shakurt Dec 10, 2025
874d48e
feat: bump version to 1.0.60 in wxt.config.ts
sajjadmrx Dec 20, 2025
7f87bc8
jackpot sajjad
shakurt Dec 22, 2025
be6bccb
enhance authentication forms with autocomplete and error handling imp…
sajjadmrx Dec 22, 2025
d1cbc47
feat: implement Google login and OTP authentication components
sajjadmrx Dec 23, 2025
827de3a
refactor: update import paths for consistency in auth components
sajjadmrx Dec 23, 2025
594bccc
style: update button text styles for Google, OTP, and password login …
sajjadmrx Dec 23, 2025
5a6f94f
Merge branch 'main' into google-login
sajjadmrx Dec 23, 2025
3009c47
feat: add tailwind-merge package to enhance styling capabilities
sajjadmrx Dec 23, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@
"react-hot-toast": "2.6.0",
"react-icons": "5.5.0",
"react-joyride": "2.9.3",
"swiper": "12.0.3",
"swiper": "12.0.2",
"tailwind-merge": "^3.4.0",
"uuid": "13.0.0",
"workbox-background-sync": "7.4.0",
"workbox-cacheable-response": "7.4.0",
Expand Down
97 changes: 70 additions & 27 deletions src/components/modal.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { type ReactNode, useEffect } from 'react'
import React, { type ReactNode, useEffect, useRef } from 'react'
import { createPortal } from 'react-dom'
import { LuX } from 'react-icons/lu'

Expand All @@ -16,20 +16,24 @@ type ModalProps = {

const sizeClasses = {
sm: {
w: 'max-w-sm',
h: 'max-h-[70vh]',
w: 'w-[calc(100vw-2rem)] max-w-sm',
h: 'max-h-[calc(100vh-4rem)] md:max-h-[560px]',
minH: 'min-h-[180px]',
},
md: {
w: 'max-w-md',
h: 'max-h-[80vh]',
w: 'w-[calc(100vw-2rem)] max-w-md',
h: 'max-h-[calc(100vh-4rem)] md:max-h-[640px]',
minH: 'min-h-[200px]',
},
lg: {
w: 'max-w-lg',
h: 'max-h-[85vh]',
w: 'w-[calc(100vw-2rem)] max-w-lg',
h: 'max-h-[calc(100vh-4rem)] md:max-h-[720px]',
minH: 'min-h-[240px]',
},
xl: {
w: 'max-w-4xl',
h: 'max-h-[90vh]',
w: 'w-[calc(100vw-2rem)] max-w-4xl',
h: 'max-h-[calc(100vh-4rem)] md:max-h-[800px]',
minH: 'min-h-[280px]',
},
} as const

Expand All @@ -44,24 +48,53 @@ export default function Modal({
showCloseButton = true,
className = '',
}: ModalProps) {
const modalRef = useRef<HTMLDivElement>(null)
const sizeValue = sizeClasses[size] || sizeClasses.md

// Lock body scroll when modal is open
useEffect(() => {
document.documentElement.classList.toggle('modal-isActive', isOpen)
return () => document.documentElement.classList.remove('modal-isActive')
if (isOpen) {
document.documentElement.classList.add('modal-isActive')
document.body.style.overflow = 'hidden'
} else {
document.documentElement.classList.remove('modal-isActive')
document.body.style.overflow = ''
}
return () => {
document.documentElement.classList.remove('modal-isActive')
document.body.style.overflow = ''
}
}, [isOpen])

// Handle keyboard events
useEffect(() => {
if (!isOpen) return

const handleKeyDown = (e: KeyboardEvent) => {
if (e.key === 'Escape' && isOpen) onClose()
if (e.key === 'Escape') {
e.preventDefault()
onClose()
}
}

document.addEventListener('keydown', handleKeyDown)
return () => document.removeEventListener('keydown', handleKeyDown)
}, [isOpen, onClose])

// Focus management
useEffect(() => {
if (isOpen && modalRef.current) {
const focusableElements = modalRef.current.querySelectorAll(
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
)
const firstElement = focusableElements[0] as HTMLElement
firstElement?.focus()
}
}, [isOpen])

const modalBoxClasses = `
modal-box overflow-hidden rounded-2xl p-4 shadow-xl transition-all duration-200
${sizeValue.w} ${className}
modal-box overflow-hidden rounded-xl md:rounded-2xl p-3 md:p-4 shadow-xl transition-all duration-200
${sizeValue.w} ${sizeValue.minH} ${className}
`

if (!isOpen) return null
Expand All @@ -70,34 +103,44 @@ export default function Modal({
<dialog
open={isOpen}
dir={direction}
aria-labelledby={typeof title === 'string' ? title : undefined}
aria-labelledby={typeof title === 'string' ? title : 'modal-title'}
aria-modal="true"
onClick={() => closeOnBackdropClick && onClose()}
className={`modal modal-middle flex items-center justify-center transition-opacity duration-200 ${
isOpen ? 'opacity-100' : 'opacity-0 pointer-events-none'
}`}
className="modal modal-middle flex items-center justify-center transition-opacity duration-200 opacity-100 p-2 md:p-4"
>
<div
ref={modalRef}
onClick={(e) => e.stopPropagation()}
className={`${modalBoxClasses} transform ${
isOpen ? 'scale-100 opacity-100' : 'scale-95 opacity-0'
}`}
className={`${modalBoxClasses} animate-modal-in`}
>
{(title || showCloseButton) && (
<div className="flex items-center justify-between mb-2">
{title && <h3 className="text-lg font-medium">{title}</h3>}
<div className="flex items-center justify-between mb-2 md:mb-3 gap-2 md:gap-4">
{title && (
<h3
id="modal-title"
className="text-base md:text-lg font-semibold"
>
{title}
</h3>
)}
{showCloseButton && (
<button
type="button"
onClick={onClose}
className="flex items-center justify-center transition-transform rounded-full cursor-pointer w-7 h-7 bg-base-300 text-muted hover:scale-105 active:scale-95"
aria-label="Close"
className="flex items-center justify-center transition-all rounded-full cursor-pointer w-7 h-7 md:w-8 md:h-8 bg-base-300 text-muted hover:bg-base-content/10 hover:scale-105 active:scale-95 shrink-0"
aria-label="Close modal"
>
<LuX size={16} />
<LuX size={16} className="md:hidden" />
<LuX size={18} className="hidden md:block" />
</button>
)}
</div>
)}
<div className={`overflow-y-auto ${sizeValue.h}`}>{children}</div>
<div
className={`overflow-y-auto overflow-x-hidden ${sizeValue.h} pr-0.5 md:pr-1`}
>
{children}
</div>
</div>
</dialog>,
document.body
Expand Down
4 changes: 3 additions & 1 deletion src/components/text-input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ interface TextInputProps {
size?: TextInputSize
min?: number
max?: number
autoComplete?: 'on' | 'off'
}

const sizes: Record<TextInputSize, string> = {
Expand Down Expand Up @@ -56,6 +57,7 @@ export const TextInput = memo(function TextInput({
size = TextInputSize.MD,
min,
max,
autoComplete = 'off',
}: TextInputProps) {
const [localValue, setLocalValue] = useState(value)
const debounceTimerRef = useRef<NodeJS.Timeout | null>(null)
Expand Down Expand Up @@ -119,7 +121,7 @@ export const TextInput = memo(function TextInput({
font-light ${className}`}
onChange={handleChange}
maxLength={maxLength}
autoComplete="off"
autoComplete={autoComplete}
min={min}
max={max}
/>
Expand Down
Loading