diff --git a/packages/web/src/components/files/FileList.test.tsx b/packages/web/src/components/files/FileList.test.tsx index b682a4c..b86ca79 100644 --- a/packages/web/src/components/files/FileList.test.tsx +++ b/packages/web/src/components/files/FileList.test.tsx @@ -20,17 +20,39 @@ describe.each(["list", "grid"] as const)("%s file view", (view) => { onOpen={onOpen} />, ) - fireEvent.click(screen.getByRole("checkbox", { name: "Select Documents" })) - expect(onSelect).toHaveBeenCalledWith("folder", true) - fireEvent.click(screen.getByRole("button", { name: /Documents/ })) + fireEvent.click(screen.getByText("Documents")) + expect(onSelect).toHaveBeenCalledWith("folder", true, false) + fireEvent.dblClick(screen.getByText("Documents")) expect(onOpen).toHaveBeenCalledWith(folder) }) - it("shows the complete filename and honors externally changed selection", () => { + it("preserves the original filename presentation and selection styling", () => { const entry = file({ name: "report.final.pdf" }) const props = { files: [entry], view, pending: false, onSelect: vi.fn(), onOpen: vi.fn() } const { rerender } = render() - expect(screen.getByText("report.final.pdf")).toBeTruthy() + expect(screen.getByText(view === "grid" ? "report" : "report.final.pdf")).toBeTruthy() rerender() - expect(screen.getByRole("checkbox", { checked: true })).toBeTruthy() + expect( + screen + .getByText(view === "grid" ? "report" : "report.final.pdf") + .closest(view === "grid" ? "span" : "tr")?.className, + ).toContain("bg-orange-500") + }) + it("opens the record on double-click without changing the selected record", () => { + const entry = file() + const onSelect = vi.fn() + const onOpen = vi.fn() + render( + , + ) + fireEvent.dblClick(screen.getByText(view === "grid" ? entry.name.split(".")[0] : entry.name)) + expect(onOpen).toHaveBeenCalledWith(entry) + expect(onSelect).not.toHaveBeenCalled() }) }) diff --git a/packages/web/src/styles/file-views.css b/packages/web/src/styles/file-views.css new file mode 100644 index 0000000..7b9e920 --- /dev/null +++ b/packages/web/src/styles/file-views.css @@ -0,0 +1,124 @@ +.file-table, +.file-grid { + margin: 32px 0 0; + width: 100%; + background: var(--panel); + border: 1px solid var(--line); + border-radius: 6px; + box-shadow: 0 1px 2px #0001; +} +.file-name { + display: block; + background: none; + border: 0; + border-radius: 0; + padding: 0; + color: inherit; + text-align: inherit; + font: inherit; +} +.file-table { + border-spacing: 0; + overflow: hidden; + text-align: left; +} +.file-table th { + padding: 8px; + font-weight: 600; +} +.file-table th, +.file-table tbody tr:not(:last-child) td { + border-bottom: 1px solid var(--line); +} +.file-table td { + padding: 4px 8px; +} +.file-table td:first-child { + padding: 0; +} +.file-table .file-name { + width: 100%; + padding: 4px 8px; + overflow-wrap: anywhere; +} +.file-table tbody tr:hover { + background: #e5e5e5; +} +.file-table tbody tr.selected { + background: var(--accent); + color: white; +} +.file-table td:not(:first-child) { + white-space: nowrap; +} +.file-grid { + list-style: none; + display: grid; + grid-template-columns: repeat(auto-fill, minmax(144px, 1fr)); + padding: 8px; +} +.file-grid li { + min-width: 0; +} +.file-grid .file-name { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + width: 144px; + height: 144px; + max-width: 100%; + margin: auto; +} +.file-icon-pad { + display: flex; + align-items: center; + justify-content: center; + width: 96px; + height: 96px; + margin: 4px; + border-radius: 6px; +} +.file-icon-pad .icon { + width: 64px; + height: 64px; + margin: 8px; + color: var(--accent); +} +.file-grid .file-label { + max-width: 100%; + padding: 0 4px; + border-radius: 6px; + font-size: 14px; + line-height: 20px; + font-weight: 500; + overflow-wrap: anywhere; +} +.file-grid .file-name:hover .file-icon-pad { + background: #7373731a; +} +.file-grid [aria-checked="true"] .file-icon-pad { + background: #73737366; +} +.file-grid [aria-checked="true"] .file-label { + background: var(--accent); + color: white; +} +@media (min-width: 640px) { + .file-grid { + padding: 16px; + } +} +@media (min-width: 768px) { + .file-grid { + padding: 32px; + } +} +@media (prefers-color-scheme: dark) { + .file-table tbody tr:hover { + background: #404040; + } + .file-table tbody tr.selected { + background: var(--accent); + } +}