Skip to content
8 changes: 8 additions & 0 deletions frontend/src/components/connections/SuggestedAppData.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ export type AppStoreApp = {
hideConnectionQr?: boolean;
internal?: boolean;
superuser?: boolean;
addedDate?: string;
};

export const appStoreCategories = {
Expand Down Expand Up @@ -217,6 +218,7 @@ export const appStoreApps: AppStoreApp[] = (
</>
),
categories: ["audio"],
addedDate: "2026-03-12",
},
{
id: "goose",
Expand Down Expand Up @@ -1778,6 +1780,7 @@ export const appStoreApps: AppStoreApp[] = (
</>
),
categories: ["misc"],
addedDate: "2026-04-10",
},
{
id: "nakapay",
Expand Down Expand Up @@ -2531,10 +2534,15 @@ export const appStoreApps: AppStoreApp[] = (
</>
),
categories: ["payment-tools"],
addedDate: "2026-04-10",
},
] satisfies AppStoreApp[]
).sort((a, b) => (a.title.toUpperCase() > b.title.toUpperCase() ? 1 : -1));

export function getAppStoreUrl(app: AppStoreApp) {
return app.internal ? `/internal-apps/${app.id}` : `/appstore/${app.id}`;
}

export const getAppStoreApp = (app: App) => {
return appStoreApps.find(
(suggestedApp) =>
Expand Down
43 changes: 13 additions & 30 deletions frontend/src/components/connections/SuggestedApps.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,37 +11,24 @@ import { cn } from "src/lib/utils";
import {
AppStoreApp,
appStoreApps,
getAppStoreUrl,
sortedAppStoreCategories,
} from "./SuggestedAppData";

function SuggestedAppCard({ id, title, description, logo }: AppStoreApp) {
function AppCard(app: AppStoreApp) {
return (
<Link to={`/appstore/${id}`}>
<Link to={getAppStoreUrl(app)}>
<Card className="h-full">
<CardContent>
<div className="flex gap-3 items-center">
<img src={logo} alt="logo" className="inline rounded-lg size-12" />
<img
src={app.logo}
alt={`${app.title} logo`}
className="inline rounded-lg size-12"
/>
Comment thread
coderabbitai[bot] marked this conversation as resolved.
<div className="grow">
<CardTitle>{title}</CardTitle>
<CardDescription>{description}</CardDescription>
</div>
</div>
</CardContent>
</Card>
</Link>
);
}

function InternalAppCard({ id, title, description, logo }: AppStoreApp) {
return (
<Link to={`/internal-apps/${id}`}>
<Card className="h-full">
<CardContent>
<div className="flex gap-3 items-center">
<img src={logo} alt="logo" className="inline rounded-lg size-12" />
<div className="grow">
<CardTitle>{title}</CardTitle>
<CardDescription>{description}</CardDescription>
<CardTitle>{app.title}</CardTitle>
<CardDescription>{app.description}</CardDescription>
</div>
</div>
</CardContent>
Expand Down Expand Up @@ -97,13 +84,9 @@ export default function SuggestedApps() {
.filter((app) =>
(app.categories as string[]).includes(categoryId)
)
.map((app) =>
app.internal ? (
<InternalAppCard key={app.id} {...app} />
) : (
<SuggestedAppCard key={app.id} {...app} />
)
)}
.map((app) => (
<AppCard key={app.id} {...app} />
))}
</div>
</div>
);
Expand Down
7 changes: 5 additions & 2 deletions frontend/src/components/home/widgets/AppOfTheDayWidget.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { ChevronRightIcon } from "lucide-react";
import { Link } from "react-router";
import { appStoreApps } from "src/components/connections/SuggestedAppData";
import {
appStoreApps,
getAppStoreUrl,
} from "src/components/connections/SuggestedAppData";
import {
Card,
CardContent,
Expand Down Expand Up @@ -33,7 +36,7 @@ export function AppOfTheDayWidget() {
</CardHeader>
<CardContent className="px-6 pt-0">
<Link
to={app.internal ? `/internal-apps/${app.id}` : `/appstore/${app.id}`}
to={getAppStoreUrl(app)}
className="group flex items-center gap-4 rounded-md"
>
<img
Expand Down
51 changes: 51 additions & 0 deletions frontend/src/components/home/widgets/NewArrivalsWidget.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { ChevronRightIcon } from "lucide-react";
import { Link } from "react-router";
import {
appStoreApps,
getAppStoreUrl,
} from "src/components/connections/SuggestedAppData";
import {
Card,
CardContent,
CardHeader,
CardTitle,
} from "src/components/ui/card";

export function NewArrivalsWidget() {
const latestApps = appStoreApps
.filter((app) => !!app.addedDate)
.sort((a, b) => b.addedDate!.localeCompare(a.addedDate!))
.slice(0, 3);

if (!latestApps.length) {
return null;
}

return (
<Card>
<CardHeader>
<CardTitle>New Arrivals</CardTitle>
</CardHeader>
<CardContent className="grid gap-4">
{latestApps.map((app) => (
<Link key={app.id} to={getAppStoreUrl(app)} className="group">
<div className="flex items-center gap-3">
<img
src={app.logo}
alt={`${app.title} logo`}
className="w-12 h-12 rounded-lg object-cover"
/>
Comment thread
reneaaron marked this conversation as resolved.
<div className="min-w-0 flex-1">
<CardTitle>{app.title}</CardTitle>
<p className="text-sm text-muted-foreground line-clamp-1">
{app.description}
</p>
</div>
<ChevronRightIcon className="size-4 shrink-0 text-muted-foreground transition-transform group-hover:translate-x-0.5" />
</div>
</Link>
))}
</CardContent>
</Card>
);
}
2 changes: 2 additions & 0 deletions frontend/src/screens/Home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { BlockHeightWidget } from "src/components/home/widgets/BlockHeightWidget
import { ForwardsWidget } from "src/components/home/widgets/ForwardsWidget";
import { LatestUsedAppsWidget } from "src/components/home/widgets/LatestUsedAppsWidget";
import { LightningMessageboardWidget } from "src/components/home/widgets/LightningMessageboardWidget";
import { NewArrivalsWidget } from "src/components/home/widgets/NewArrivalsWidget";
import { NodeStatusWidget } from "src/components/home/widgets/NodeStatusWidget";
import { OnchainFeesWidget } from "src/components/home/widgets/OnchainFeesWidget";
import { SupportAlbyWidget } from "src/components/home/widgets/SupportAlbyWidget";
Expand Down Expand Up @@ -71,6 +72,7 @@ function Home() {
<div className="grid gap-3">
<OnboardingChecklist />
<WhatsNewWidget />
<NewArrivalsWidget />
<AppOfTheDayWidget />
{info.albyAccountConnected && (
<ExternalLink to="https://www.getalby.com/dashboard">
Expand Down
Loading