Skip to content

Commit 0d51cd4

Browse files
authored
Merge pull request #7 from TechyCSR/ashish
Fix portfolio footer responsiveness and username unavailable feedback.
2 parents 772abc4 + 0621cee commit 0d51cd4

3 files changed

Lines changed: 34 additions & 15 deletions

File tree

backend/src/routes/auth.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,16 @@ router.get('/check-username', async (req, res) => {
3333

3434
const existingUser = await User.findOne({ username: username.toLowerCase() });
3535

36+
if (existingUser) {
37+
return res.json({
38+
available: false,
39+
username: username.toLowerCase(),
40+
error: 'Username is not available'
41+
});
42+
}
43+
3644
res.json({
37-
available: !existingUser,
45+
available: true,
3846
username: username.toLowerCase()
3947
});
4048
} catch (error) {

frontend/src/pages/UsernameSelection.jsx

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,15 +54,19 @@ function UsernameSelection() {
5454
useEffect(() => {
5555
if (!username || username.length < 3) {
5656
setIsAvailable(null)
57+
setError('')
5758
return
5859
}
5960

6061
const timer = setTimeout(async () => {
6162
setIsChecking(true)
63+
setError('')
6264
try {
6365
const { data } = await checkUsername(username)
6466
setIsAvailable(data.available)
65-
setError(data.error || '')
67+
setError(
68+
data.error || (data.available === false ? 'Username is not available' : '')
69+
)
6670
} catch (err) {
6771
setError(err.response?.data?.error || 'Failed to check username')
6872
setIsAvailable(false)
@@ -99,6 +103,8 @@ function UsernameSelection() {
99103
const value = e.target.value.toLowerCase().replace(/[^a-z0-9_]/g, '')
100104
if (value.length <= MAX_USERNAME_LENGTH) {
101105
setUsername(value)
106+
setIsAvailable(null)
107+
setError('')
102108
}
103109
}
104110

@@ -154,7 +160,7 @@ function UsernameSelection() {
154160
<Check size={18} strokeWidth={ICON_STROKE} className="text-success" />
155161
)}
156162
{!isChecking && isAvailable === false && (
157-
<X size={18} strokeWidth={ICON_STROKE} className="text-muted" />
163+
<X size={18} strokeWidth={ICON_STROKE} className="text-error" />
158164
)}
159165
</div>
160166
</div>
@@ -175,7 +181,12 @@ function UsernameSelection() {
175181
✓ Username is available!
176182
</p>
177183
)}
178-
{error && (
184+
{isAvailable === false && !isChecking && (
185+
<p className="mt-2 text-sm text-error">
186+
{error || 'Username is not available'}
187+
</p>
188+
)}
189+
{error && isAvailable !== false && (
179190
<p className="mt-2 text-sm text-error">
180191
{error}
181192
</p>

frontend/src/portfolio/components/Footer.jsx

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,15 @@ function Footer({ profile, compact = false }) {
2626
const customBranding = profile?.customBranding
2727

2828
return (
29-
<footer className={`relative flex-shrink-0 ${compact ? 'py-3 mt-3 pb-[max(0.75rem,env(safe-area-inset-bottom))]' : 'py-12 px-4 mt-8'}`}>
29+
<footer className={`relative flex-shrink-0 overflow-visible ${compact ? 'px-2 sm:px-0 py-3 mt-3 pb-[max(0.75rem,env(safe-area-inset-bottom))]' : 'py-12 px-4 mt-8'}`}>
3030
{!compact && (
3131
<div
3232
className="absolute top-0 left-1/2 -translate-x-1/2 w-1/2 max-w-md h-px"
3333
style={{ background: 'var(--pf-border-subtle)' }}
3434
/>
3535
)}
3636

37-
<div className={`${compact ? '' : 'max-w-6xl mx-auto'} flex justify-center`}>
37+
<div className={`${compact ? 'w-full' : 'max-w-6xl mx-auto'} flex justify-center`}>
3838
{customBranding?.enabled && customBranding?.text ? (
3939
<a
4040
href={safeHref(customBranding.url) || '#'}
@@ -55,20 +55,20 @@ function Footer({ profile, compact = false }) {
5555
)}
5656
</a>
5757
) : (
58-
<div className="relative">
58+
<div className="inline-flex items-center gap-2 sm:gap-3 max-w-full">
5959
<div
60-
className="absolute -top-2 -left-2 z-20 portfolio-no-print"
60+
className="relative flex-shrink-0 portfolio-no-print"
6161
onMouseEnter={handleMouseEnter}
6262
onMouseLeave={handleMouseLeave}
6363
>
6464
<button
6565
type="button"
66-
className="portfolio-btn-primary min-h-[44px] min-w-[44px] rounded-full flex items-center justify-center shadow-lg portfolio-touch-target"
66+
className="portfolio-btn-primary rounded-full flex items-center justify-center shadow-lg portfolio-touch-target w-9 h-9 sm:w-10 sm:h-10"
6767
aria-label="Premium branding information"
6868
aria-expanded={showPremiumInfo}
6969
onClick={() => setShowPremiumInfo((open) => !open)}
7070
>
71-
<Info size={14} strokeWidth={3} />
71+
<Info size={compact ? 12 : 14} strokeWidth={3} className="flex-shrink-0" />
7272
</button>
7373

7474
<AnimatePresence>
@@ -77,7 +77,7 @@ function Footer({ profile, compact = false }) {
7777
initial={{ opacity: 0, y: 8, scale: 0.96 }}
7878
animate={{ opacity: 1, y: 0, scale: 1 }}
7979
exit={{ opacity: 0, y: 8, scale: 0.96 }}
80-
className="portfolio-surface absolute bottom-full mb-3 left-1/2 -translate-x-1/2 w-56 p-4 rounded-xl text-xs text-center shadow-xl z-30"
80+
className="portfolio-surface absolute bottom-full mb-2 left-1/2 -translate-x-1/2 w-[min(14rem,calc(100vw-2rem))] p-3 sm:p-4 rounded-xl text-xs text-center shadow-xl z-30"
8181
onMouseEnter={handleMouseEnter}
8282
onMouseLeave={handleMouseLeave}
8383
>
@@ -101,17 +101,17 @@ function Footer({ profile, compact = false }) {
101101
href={getAppUrl()}
102102
target="_blank"
103103
rel="noopener noreferrer"
104-
className={`group portfolio-surface rounded-xl inline-flex items-center gap-3 transition-transform hover:-translate-y-0.5 ${compact ? 'px-4 py-2' : 'px-6 py-3'}`}
104+
className={`group portfolio-surface rounded-xl inline-flex items-center gap-2 sm:gap-3 transition-transform hover:-translate-y-0.5 min-w-0 ${compact ? 'px-3 py-2 sm:px-4' : 'px-6 py-3'}`}
105105
>
106106
<img
107107
src={BRAND_LOGO_SRC}
108108
alt={BRAND_LOGO_ALT}
109-
className={`object-contain flex-shrink-0 ${compact ? 'w-6 h-6' : 'w-8 h-8'}`}
109+
className={`object-contain flex-shrink-0 ${compact ? 'w-5 h-5 sm:w-6 sm:h-6' : 'w-8 h-8'}`}
110110
width={compact ? 24 : 32}
111111
height={compact ? 24 : 32}
112112
decoding="async"
113113
/>
114-
<div className="flex items-center gap-2">
114+
<div className="flex items-center gap-1.5 sm:gap-2 min-w-0 whitespace-nowrap">
115115
<span className={`portfolio-text-secondary ${compact ? 'text-xs' : 'text-sm'}`}>Built with</span>
116116
<span className={`font-semibold ${compact ? 'text-xs' : 'text-sm'}`}>
117117
<span className="portfolio-text">Portlify</span>
@@ -121,7 +121,7 @@ function Footer({ profile, compact = false }) {
121121
<ChevronRight
122122
size={16}
123123
strokeWidth={ICON_STROKE}
124-
className="portfolio-link opacity-0 group-hover:opacity-100 group-hover:translate-x-0.5 transition-all"
124+
className="portfolio-link opacity-0 group-hover:opacity-100 group-hover:translate-x-0.5 transition-all hidden sm:block flex-shrink-0"
125125
/>
126126
</a>
127127
</div>

0 commit comments

Comments
 (0)