diff --git a/messages/en-US.json b/messages/en-US.json
index d27196be2..289399e5c 100644
--- a/messages/en-US.json
+++ b/messages/en-US.json
@@ -3573,6 +3573,11 @@
"resourceLauncherViewAsAdmin": "View as Admin",
"resourceLauncherUnlabeled": "Unlabeled",
"resourceLauncherNoResourcesInGroup": "No resources in this group",
+ "resourceLauncherEmptyStateTitle": "No Resources Available",
+ "resourceLauncherEmptyStateDescription": "You don't have access to any resources yet. Contact your administrator to request access.",
+ "resourceLauncherEmptyStateNoResultsTitle": "No Resources Found",
+ "resourceLauncherEmptyStateNoResultsDescription": "No resources match your current search or filters. Try adjusting them to find what you are looking for.",
+ "resourceLauncherEmptyStateNoResultsWithQuery": "No resources match \"{query}\". Try adjusting your search or clearing filters to see all resources.",
"resourceLauncherCopiedToClipboard": "Copied to clipboard",
"resourceLauncherCopiedAccessDescription": "Resource access has been copied to your clipboard.",
"resourceLauncherViewNamePlaceholder": "View name",
diff --git a/src/components/resource-launcher/LauncherEmptyState.tsx b/src/components/resource-launcher/LauncherEmptyState.tsx
new file mode 100644
index 000000000..193ffae78
--- /dev/null
+++ b/src/components/resource-launcher/LauncherEmptyState.tsx
@@ -0,0 +1,118 @@
+"use client";
+
+import { Button } from "@app/components/ui/button";
+import { cn } from "@app/lib/cn";
+import { LayoutGrid, SearchX } from "lucide-react";
+import { useTranslations } from "next-intl";
+
+type LauncherEmptyStateVariant = "empty" | "noResults";
+
+type LauncherEmptyStateProps = {
+ variant: LauncherEmptyStateVariant;
+ layout: "grid" | "list";
+ query?: string;
+ onClearFilters?: () => void;
+};
+
+function GhostResourceGrid() {
+ return (
+