177d65a90e
Replace the single-column-only feed with a max-columns model: one
Columns setting (1 / 2 / 3 / ∞) where 1 is the reading list and
anything wider packs into a Google-Keep-style column grid. There is
deliberately no separate list/grid mode — the setting is a ceiling,
and widths that only fit one column fall back to the flow list.
- ColumnGrid: absolute-positioned packing that only translates cards,
so appends and reorders never remount them; sticky column assignment
keeps existing cards in place when new memos arrive; tiles are capped
at 360px with a fade; columns clamp to 420px and center.
- Column one is the action column: the composer and active filters
stack as its first tile, and a just-created memo is pinned directly
beneath them.
- Multi-column always renders compact cards (policy centralized in
PagedMemoList and threaded through renderer(memo, { compact })).
- Setting persists in ViewContext localStorage; the settings menu
derives its options from the context's canonical value list.
47 lines
1.5 KiB
TypeScript
47 lines
1.5 KiB
TypeScript
import { act, renderHook } from "@testing-library/react";
|
|
import type { ReactNode } from "react";
|
|
import { beforeEach, describe, expect, it } from "vitest";
|
|
import { useView, ViewProvider } from "@/contexts/ViewContext";
|
|
|
|
const LOCAL_STORAGE_KEY = "memos-view-setting";
|
|
|
|
const wrapper = ({ children }: { children: ReactNode }) => <ViewProvider>{children}</ViewProvider>;
|
|
|
|
const persisted = () => JSON.parse(localStorage.getItem(LOCAL_STORAGE_KEY) ?? "{}");
|
|
|
|
describe("ViewContext maxColumns setting", () => {
|
|
beforeEach(() => {
|
|
localStorage.clear();
|
|
});
|
|
|
|
it("defaults to a single column", () => {
|
|
const { result } = renderHook(() => useView(), { wrapper });
|
|
expect(result.current.maxColumns).toBe(1);
|
|
});
|
|
|
|
it("updates and persists the column ceiling", () => {
|
|
const { result } = renderHook(() => useView(), { wrapper });
|
|
|
|
act(() => result.current.setMaxColumns(0));
|
|
|
|
expect(result.current.maxColumns).toBe(0);
|
|
expect(persisted().maxColumns).toBe(0);
|
|
});
|
|
|
|
it("restores a persisted column count on init", () => {
|
|
localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify({ maxColumns: 2 }));
|
|
|
|
const { result } = renderHook(() => useView(), { wrapper });
|
|
|
|
expect(result.current.maxColumns).toBe(2);
|
|
});
|
|
|
|
it("falls back to a single column for an invalid persisted value", () => {
|
|
localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify({ maxColumns: 7 }));
|
|
|
|
const { result } = renderHook(() => useView(), { wrapper });
|
|
|
|
expect(result.current.maxColumns).toBe(1);
|
|
});
|
|
});
|