Skip to content

Commit 1610980

Browse files
committed
chore(dashboard): new default app logo, less padding on Connect header, support for up to 5 featured apps
1 parent 5050a01 commit 1610980

File tree

4 files changed

+145
-75
lines changed

4 files changed

+145
-75
lines changed
Lines changed: 16 additions & 0 deletions
Loading

packages/apps/app-dashboard/src/components/explorer/ui/FeaturedApps.tsx

Lines changed: 118 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,79 @@ import { Logo } from '@/components/shared/ui/Logo';
44
import { theme, fonts } from '@/components/user-dashboard/connect/ui/theme';
55
import { useCallback } from 'react';
66

7+
interface FeaturedAppCardProps {
8+
app: App;
9+
handleAppClick: (appId: number) => void;
10+
}
11+
712
interface FeaturedAppsProps {
813
apps: App[];
914
onNavigate?: (path: string) => void;
1015
}
1116

17+
function FeaturedAppCard({ app, handleAppClick }: FeaturedAppCardProps) {
18+
return (
19+
<div
20+
onClick={() => handleAppClick(app.appId)}
21+
className="group relative overflow-hidden rounded-xl md:rounded-2xl border border-gray-200 dark:border-white/10 hover:border-gray-300 dark:hover:border-white/20 transition-all duration-300 cursor-pointer h-[300px] md:h-[400px]"
22+
>
23+
{/* Image at the top with fade effect */}
24+
<div className="absolute inset-0 z-0">
25+
{/* Gradient overlay that fades from solid color to transparent */}
26+
<div
27+
className="absolute inset-0 z-10"
28+
style={{
29+
background: `linear-gradient(to top, ${'rgba(255, 66, 5, 0.85)'} 0%, ${'rgba(255, 66, 5, 0.7)'} 15%, ${'rgba(255, 66, 5, 0.4)'} 30%, transparent 50%, transparent 100%)`,
30+
}}
31+
/>
32+
33+
{/* App logo/image */}
34+
<div className="absolute inset-0 flex items-start justify-center pt-12 opacity-60 group-hover:opacity-80 transition-opacity duration-300">
35+
<div className="w-48 h-48 rounded-2xl overflow-hidden">
36+
<Logo logo={app.logo} alt={`${app.name} logo`} className="w-full h-full object-cover" />
37+
</div>
38+
</div>
39+
</div>
40+
41+
{/* Content at the bottom */}
42+
<div className="absolute bottom-0 left-0 right-0 p-8 z-20">
43+
<div className="flex items-start justify-between mb-3">
44+
<div className="flex-1">
45+
<h3 className={`text-2xl font-semibold ${theme.text} mb-2`} style={fonts.heading}>
46+
{app.name}
47+
</h3>
48+
<p className={`${theme.text} text-sm line-clamp-2 opacity-80`} style={fonts.body}>
49+
{app.description || 'No description available'}
50+
</p>
51+
</div>
52+
</div>
53+
54+
<div className="flex items-center gap-3">
55+
<span
56+
className={`px-3 py-1 rounded-full text-xs font-medium ${theme.bg} ${theme.text} backdrop-blur-sm ${theme.cardBorder} border`}
57+
style={fonts.heading}
58+
>
59+
v{app.activeVersion}
60+
</span>
61+
<span
62+
className={`px-3 py-1 rounded-full text-xs font-medium ${theme.bg} ${theme.text} backdrop-blur-sm ${theme.cardBorder} border`}
63+
style={fonts.heading}
64+
>
65+
{app.deploymentStatus === 'prod'
66+
? 'LIVE'
67+
: app.deploymentStatus === 'test'
68+
? 'BETA'
69+
: app.deploymentStatus?.toUpperCase()}
70+
</span>
71+
</div>
72+
</div>
73+
74+
{/* Hover effect overlay */}
75+
<div className="absolute inset-0 bg-black/0 group-hover:bg-black/5 transition-colors duration-300 z-10" />
76+
</div>
77+
);
78+
}
79+
1280
export function FeaturedApps({ apps, onNavigate }: FeaturedAppsProps) {
1381
const navigate = useNavigate();
1482

@@ -35,13 +103,59 @@ export function FeaturedApps({ apps, onNavigate }: FeaturedAppsProps) {
35103
const found = apps.find((app: App) => String(app.appId) === String(appId));
36104
return found;
37105
})
38-
.filter((app: App | undefined): app is App => app !== undefined)
39-
.slice(0, 2); // Limit to 2 featured apps
106+
.filter((app: App | undefined): app is App => app !== undefined);
40107

41108
if (featuredApps.length === 0) {
42109
return null;
43110
}
44111

112+
// Determine grid layout based on number of apps
113+
const getGridClasses = (count: number) => {
114+
switch (count) {
115+
case 1:
116+
return 'grid-cols-1';
117+
case 2:
118+
return 'grid-cols-1 md:grid-cols-2';
119+
case 3:
120+
return 'grid-cols-1 md:grid-cols-3';
121+
case 4:
122+
return 'grid-cols-1 md:grid-cols-2';
123+
default:
124+
return 'grid-cols-1 md:grid-cols-2';
125+
}
126+
};
127+
128+
// For 5 apps, split into two rows (2 apps in first row, 3 in second)
129+
if (featuredApps.length === 5) {
130+
const firstRowApps = featuredApps.slice(0, 2);
131+
const secondRowApps = featuredApps.slice(2, 5);
132+
133+
return (
134+
<div className="mb-8 md:mb-12">
135+
<h2
136+
className={`text-2xl md:text-3xl font-semibold ${theme.text} mb-4 md:mb-6`}
137+
style={fonts.heading}
138+
>
139+
Featured Apps
140+
</h2>
141+
<div className="space-y-6">
142+
{/* First row: 2 apps */}
143+
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
144+
{firstRowApps.map((app: App) => (
145+
<FeaturedAppCard key={app.appId} app={app} handleAppClick={handleAppClick} />
146+
))}
147+
</div>
148+
{/* Second row: 3 apps */}
149+
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
150+
{secondRowApps.map((app: App) => (
151+
<FeaturedAppCard key={app.appId} app={app} handleAppClick={handleAppClick} />
152+
))}
153+
</div>
154+
</div>
155+
</div>
156+
);
157+
}
158+
45159
return (
46160
<div className="mb-8 md:mb-12">
47161
<h2
@@ -50,73 +164,9 @@ export function FeaturedApps({ apps, onNavigate }: FeaturedAppsProps) {
50164
>
51165
Featured Apps
52166
</h2>
53-
<div
54-
className={`grid ${featuredApps.length === 2 ? 'grid-cols-1 md:grid-cols-2' : 'grid-cols-1'} gap-6`}
55-
>
167+
<div className={`grid ${getGridClasses(featuredApps.length)} gap-6`}>
56168
{featuredApps.map((app: App) => (
57-
<div
58-
key={app.appId}
59-
onClick={() => handleAppClick(app.appId)}
60-
className="group relative overflow-hidden rounded-xl md:rounded-2xl border border-gray-200 dark:border-white/10 hover:border-gray-300 dark:hover:border-white/20 transition-all duration-300 cursor-pointer h-[300px] md:h-[400px]"
61-
>
62-
{/* Image at the top with fade effect */}
63-
<div className="absolute inset-0 z-0">
64-
{/* Gradient overlay that fades from solid color to transparent */}
65-
<div
66-
className="absolute inset-0 z-10"
67-
style={{
68-
background: `linear-gradient(to top, ${'rgba(255, 66, 5, 0.85)'} 0%, ${'rgba(255, 66, 5, 0.7)'} 15%, ${'rgba(255, 66, 5, 0.4)'} 30%, transparent 50%, transparent 100%)`,
69-
}}
70-
/>
71-
72-
{/* App logo/image */}
73-
<div className="absolute inset-0 flex items-start justify-center pt-12 opacity-60 group-hover:opacity-80 transition-opacity duration-300">
74-
<div className="w-48 h-48 rounded-2xl overflow-hidden">
75-
<Logo
76-
logo={app.logo}
77-
alt={`${app.name} logo`}
78-
className="w-full h-full object-cover"
79-
/>
80-
</div>
81-
</div>
82-
</div>
83-
84-
{/* Content at the bottom */}
85-
<div className="absolute bottom-0 left-0 right-0 p-8 z-20">
86-
<div className="flex items-start justify-between mb-3">
87-
<div className="flex-1">
88-
<h3 className={`text-2xl font-semibold ${theme.text} mb-2`} style={fonts.heading}>
89-
{app.name}
90-
</h3>
91-
<p className={`${theme.text} text-sm line-clamp-2 opacity-80`} style={fonts.body}>
92-
{app.description || 'No description available'}
93-
</p>
94-
</div>
95-
</div>
96-
97-
<div className="flex items-center gap-3">
98-
<span
99-
className={`px-3 py-1 rounded-full text-xs font-medium ${theme.bg} ${theme.text} backdrop-blur-sm ${theme.cardBorder} border`}
100-
style={fonts.heading}
101-
>
102-
v{app.activeVersion}
103-
</span>
104-
<span
105-
className={`px-3 py-1 rounded-full text-xs font-medium ${theme.bg} ${theme.text} backdrop-blur-sm ${theme.cardBorder} border`}
106-
style={fonts.heading}
107-
>
108-
{app.deploymentStatus === 'prod'
109-
? 'LIVE'
110-
: app.deploymentStatus === 'test'
111-
? 'BETA'
112-
: app.deploymentStatus?.toUpperCase()}
113-
</span>
114-
</div>
115-
</div>
116-
117-
{/* Hover effect overlay */}
118-
<div className="absolute inset-0 bg-black/0 group-hover:bg-black/5 transition-colors duration-300 z-5" />
119-
</div>
169+
<FeaturedAppCard key={app.appId} app={app} handleAppClick={handleAppClick} />
120170
))}
121171
</div>
122172
</div>

packages/apps/app-dashboard/src/components/shared/ui/Logo.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ interface LogoProps {
66

77
/**
88
* A reusable Logo component that handles fallback logic consistently.
9-
* Validates logo URL length and provides onError fallback to '/logo.svg'
9+
* Validates logo URL length and provides onError fallback to '/internal-logos/default-app-logo.svg'
1010
*/
1111
export function Logo({ logo, alt, className = '' }: LogoProps) {
1212
const hasValidLogo = logo && logo.length >= 10;
@@ -18,11 +18,13 @@ export function Logo({ logo, alt, className = '' }: LogoProps) {
1818
alt={alt}
1919
className={className}
2020
onError={(e) => {
21-
e.currentTarget.src = '/logo.svg';
21+
e.currentTarget.src = '/internal-logos/default-app-logo.svg';
2222
}}
2323
/>
2424
);
2525
}
2626

27-
return <img src="/logo.svg" alt="Vincent logo" className={className} />;
27+
return (
28+
<img src="/internal-logos/default-app-logo.svg" alt="Default app logo" className={className} />
29+
);
2830
}

packages/apps/app-dashboard/src/components/user-dashboard/connect/ui/ConnectAppHeader.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,12 @@ export function ConnectAppHeader({ app }: ConnectAppHeaderProps) {
1616
transition={{ duration: 0.5 }}
1717
>
1818
<div className="flex flex-col sm:flex-row items-center gap-4">
19-
<div
20-
className={`p-3 sm:p-4 rounded-2xl ${theme.iconBg} border ${theme.iconBorder} flex-shrink-0`}
21-
>
22-
<Logo logo={app.logo} alt={app.name} className="w-8 h-8 sm:w-10 sm:h-10" />
19+
<div className={`p-2 rounded-2xl ${theme.iconBg} border ${theme.iconBorder} flex-shrink-0`}>
20+
<Logo
21+
logo={app.logo}
22+
alt={app.name}
23+
className="w-12 h-12 sm:w-16 sm:h-16 object-contain"
24+
/>
2325
</div>
2426
<div className="flex-1 min-w-0 text-center sm:text-left">
2527
<h2 className={`text-lg sm:text-xl font-bold ${theme.text} break-words`}>{app.name}</h2>

0 commit comments

Comments
 (0)