diff --git a/src/components/official-library-panel.test.ts b/src/components/official-library-panel.test.ts
index 4f6a4e7..8131eb0 100644
--- a/src/components/official-library-panel.test.ts
+++ b/src/components/official-library-panel.test.ts
@@ -45,6 +45,38 @@ describe("OfficialLibraryPanel", () => {
expect(screen.getByText("spacex-s1.pdf")).toBeTruthy();
});
+ it("keeps file add actions visible on mobile", () => {
+ render(
+ React.createElement(OfficialLibraryPanel, {
+ officialLibrarySources: [
+ {
+ librarySourceId: "financial-spacex-s1",
+ categoryId: "financial-reports",
+ categoryLabel: "Financial Reports",
+ title: "spacex-s1.pdf",
+ sourceUrl: "https://example.com/spacex-s1.pdf",
+ mimeType: "application/pdf",
+ status: "ready",
+ demoSourceId: "demo-spacex-s1",
+ chunkCount: 922,
+ },
+ ],
+ onOfficialLibrarySourceAdd: vi.fn(),
+ }),
+ );
+
+ fireEvent.click(
+ screen.getByRole("button", { name: "Open Financial Reports" }),
+ );
+
+ const addButton = screen.getByRole("button", {
+ name: "Add spacex-s1.pdf to sources",
+ });
+
+ expect(addButton.className).toContain("opacity-100");
+ expect(addButton.className).toContain("min-[1116px]:opacity-0");
+ });
+
it("opens to the all-categories view", () => {
render(
React.createElement(OfficialLibraryPanel, {
diff --git a/src/components/official-library-panel.tsx b/src/components/official-library-panel.tsx
index 2483204..8ab70f8 100644
--- a/src/components/official-library-panel.tsx
+++ b/src/components/official-library-panel.tsx
@@ -199,7 +199,7 @@ function OfficialLibraryCard({
type="button"
disabled={!canAdd || isAdding}
onClick={onAdd}
- className="absolute right-3 top-1 inline-flex size-6 items-center justify-center rounded-md text-muted-foreground opacity-0 transition-opacity hover:bg-background hover:text-foreground group-hover:opacity-100 focus:opacity-100 disabled:cursor-not-allowed disabled:opacity-40"
+ className="absolute right-3 top-1 inline-flex size-6 items-center justify-center rounded-md bg-background/95 text-muted-foreground opacity-100 shadow-xs transition-opacity hover:bg-background hover:text-foreground focus:opacity-100 disabled:cursor-not-allowed disabled:opacity-40 min-[1116px]:bg-transparent min-[1116px]:opacity-0 min-[1116px]:shadow-none min-[1116px]:group-hover:opacity-100"
aria-label={`Add ${item.title} to sources`}
>
{isAdding ? : }
diff --git a/src/domains/workspace/initial-state.test.ts b/src/domains/workspace/initial-state.test.ts
index 02d3914..ba73f91 100644
--- a/src/domains/workspace/initial-state.test.ts
+++ b/src/domains/workspace/initial-state.test.ts
@@ -74,15 +74,6 @@ describe("loadWorkspaceShellInitialState", () => {
demoSourceId: "demo-tsla-q4-2025",
chunkCount: 70,
},
- {
- librarySourceId: "stem-transformers",
- categoryId: "stem-books",
- categoryLabel: "STEM books",
- title: "Transformers.pdf",
- sourceUrl: "https://example.com/transformers.pdf",
- mimeType: "application/pdf",
- status: "planned",
- },
])
expect(state.chatMessages).toEqual([
{
diff --git a/src/domains/workspace/initial-state.ts b/src/domains/workspace/initial-state.ts
index 02836aa..a407b71 100644
--- a/src/domains/workspace/initial-state.ts
+++ b/src/domains/workspace/initial-state.ts
@@ -29,7 +29,11 @@ import type {
Source,
Workspace,
} from "@/infrastructure/db/schema"
-import { knowhereDemoApi, type DemoCatalog } from "@/integrations/knowhere-demo"
+import {
+ knowhereDemoApi,
+ type DemoCatalog,
+ type OfficialLibrarySource,
+} from "@/integrations/knowhere-demo"
import { effectOperation } from "@/lib/effect-operation"
import { notebookRequestContext } from "./request-context"
@@ -369,15 +373,29 @@ function toOfficialLibrarySourceViews(
category.label,
]),
)
- return catalog.officialLibrary.sources.map((source) => ({
- librarySourceId: source.librarySourceId,
- categoryId: source.categoryId,
- categoryLabel: categoryLabelById.get(source.categoryId) ?? source.categoryId,
- title: source.title,
- sourceUrl: source.sourceUrl,
- mimeType: source.mimeType,
- status: source.status,
- ...(source.demoSourceId ? { demoSourceId: source.demoSourceId } : {}),
- ...(source.chunkCount !== undefined ? { chunkCount: source.chunkCount } : {}),
- }))
+ return catalog.officialLibrary.sources
+ .filter(isReadyOfficialLibrarySource)
+ .map((source) => ({
+ librarySourceId: source.librarySourceId,
+ categoryId: source.categoryId,
+ categoryLabel:
+ categoryLabelById.get(source.categoryId) ?? source.categoryId,
+ title: source.title,
+ sourceUrl: source.sourceUrl,
+ mimeType: source.mimeType,
+ status: source.status,
+ demoSourceId: source.demoSourceId,
+ ...(source.chunkCount !== undefined
+ ? { chunkCount: source.chunkCount }
+ : {}),
+ }))
+}
+
+function isReadyOfficialLibrarySource(
+ source: OfficialLibrarySource,
+): source is OfficialLibrarySource & {
+ readonly status: "ready"
+ readonly demoSourceId: string
+} {
+ return source.status === "ready" && source.demoSourceId !== undefined
}