Files
bookorbit/client
neon 9e1eb6119a feat(client): add configurable multi-row dashboard shelves
A shelf rendered a single horizontal row, which wastes space on wide screens and shows very
few books on narrow ones. Each shelf now carries a row count of 1 to 3, set per shelf in the
dashboard settings drawer.

Books fill bands left to right rather than filling each column top to bottom. The cheaper
grid-auto-flow approach would put the second most recent book directly under the first, which
reads wrong on ordered shelves like Continue Reading and Up Next in Series.

Below the sm breakpoint the row count is capped at two, since only two covers fit across and a
third row costs a screen height to gain two books. A shelf fetches limit * rows books, clamped
to the limit the server already accepts, so no server behaviour changes. DASHBOARD_SCROLLER_MAX_LIMIT
moves into the shared types package so both sides read one value instead of drifting apart.

The row count is part of the shelf key because a shelf snapshots its fetch limit during setup;
without it, switching to three rows would re-flow the books fetched for one.

Also widen the settings drawer, which was pinned at 384px because SheetContent's own sm:max-w-sm
outranked the plain max-w override in tailwind-merge, put Shelves ahead of Widgets, and move the
customize control out of the floating layer into the greeting row where it is not missed.

Closes #928
2026-08-10 19:44:32 +00:00
..

BookOrbit - Client

Vue 3 SPA built with Vite and Tailwind CSS v4.

Running

From the repo root: pnpm dev (starts both server and client).

Client only: pnpm dev (from this directory). Runs at http://localhost:5173.

The Vite dev server proxies /api and /socket.io requests to the backend at localhost:3000.

IDE setup

  • VS Code: Install the Vue (Official) extension. Disable Vetur if installed.
  • WebStorm / IntelliJ: Vue support is built in. Enable TypeScript service for .vue files.
  • Browser: Install Vue.js devtools and enable Custom Object Formatters in DevTools settings.

Project layout

src/
├── features/           Feature modules (one folder per domain)
│   ├── auth/           Login, registration, password reset
│   ├── book/           Book detail, covers, metadata
│   ├── library/        Library management
│   ├── collection/     Book collections
│   ├── smart-scope/           Saved search views
│   ├── scanner/        Scan progress UI
│   ├── reader/         Book reader (epub, pdf, cbz)
│   ├── settings/       User settings
│   └── admin/          Admin panel (users, roles, settings)
├── components/         Shared components (header, sidebar, icons)
│   └── ui/             Reusable UI primitives (button, dialog, etc.)
├── composables/        Global composables
├── views/              Route-level page components
├── router/             Vue Router config and guards
├── lib/                Utilities (api client, helpers)
├── stores/             Pinia stores (theme only - prefer composables)
└── assets/             CSS, fonts, static assets

Testing

pnpm test:unit          # run unit tests
pnpm test:cov           # run unit tests with coverage

Key conventions

  • All components use <script setup lang="ts"> (Composition API only).
  • Feature state lives in composables (features/<name>/composables/use*.ts), not global stores.
  • HTTP calls use the native fetch API via src/lib/api.ts.
  • Styling with Tailwind CSS v4 utility classes. Theme tokens are CSS variables in src/assets/main.css.
  • Icons from @lucide/vue only.
  • Shared types imported from @bookorbit/types.