mirror of
https://github.com/Dvorinka/Dash.git
synced 2026-06-03 15:02:56 +00:00
17a579880f
Relocate frontend source code from `next-app/` to `frontend/` to align with the new project structure. This includes removing the old Next.js boilerplate files and establishing a cleaner workspace. Additionally, updates the OpenAPI specification to include support for the `immich` widget type and its corresponding configuration schema. - Move frontend files to `frontend/` - Delete obsolete `next-app/` directory and its configuration - Add `immich` widget type to `openapi.yaml` - Update `FrontendPlan.md` with dashboard refactor and UX direction
1264 lines
21 KiB
Markdown
1264 lines
21 KiB
Markdown
# FrontendPlan.md
|
|
|
|
## Mission
|
|
|
|
Build the complete frontend for the self-hosted homelab dashboard. The frontend owns the Next.js app, shadcn UI composition, dashboard interactions, drag/drop UX, theme system, generated API client usage, frontend tests, and production-grade responsive design.
|
|
|
|
This agent may edit:
|
|
|
|
- `/frontend`
|
|
|
|
This agent must not edit `/backend`, `/db`, or `/openapi`. Read `openapi/openapi.yaml` only to generate client/types. If the API contract is missing or wrong, document the needed backend change instead of creating duplicate schemas.
|
|
|
|
## Product Context
|
|
|
|
The app is a fast, clean dashboard for home lab services. It should feel closer to Vercel, Linear, and a Nothing-style instrument panel than older dashboard tools. The first screen is the actual dashboard, not a landing page.
|
|
|
|
Core frontend responsibilities:
|
|
|
|
- Show date/time/timezones.
|
|
- Show dashboard widgets.
|
|
- Show grouped and ungrouped services.
|
|
- Add/edit/delete services with multiple URLs.
|
|
- Let user choose local/external/custom URL before opening when service has multiple URLs.
|
|
- Create/edit/collapse/delete groups.
|
|
- Drag/drop reorder groups, services, and widgets.
|
|
- Support dark and light mode.
|
|
- Use generated API types/client only.
|
|
|
|
## Stack
|
|
|
|
- Next.js App Router.
|
|
- React with TypeScript strict mode.
|
|
- Tailwind CSS.
|
|
- shadcn/ui.
|
|
- `@dnd-kit` for drag/drop.
|
|
- `@tanstack/react-query` for server state.
|
|
- `openapi-typescript` for generated types.
|
|
- `openapi-fetch` or a thin generated client wrapper for requests.
|
|
- Playwright for end-to-end tests.
|
|
- MSW or local fixtures while backend is incomplete.
|
|
|
|
## Repository Layout
|
|
|
|
Use this frontend layout:
|
|
|
|
```text
|
|
frontend/
|
|
app/
|
|
layout.tsx
|
|
page.tsx
|
|
globals.css
|
|
components/
|
|
dashboard/
|
|
groups/
|
|
services/
|
|
widgets/
|
|
shell/
|
|
ui/
|
|
lib/
|
|
api/
|
|
mocks/
|
|
theme/
|
|
utils/
|
|
hooks/
|
|
tests/
|
|
e2e/
|
|
```
|
|
|
|
Intent:
|
|
|
|
- `app`: Next.js routes and global shell.
|
|
- `components/ui`: shadcn components only.
|
|
- `components/dashboard`: dashboard composition and layout.
|
|
- `components/groups`: group panels, group controls, group reorder.
|
|
- `components/services`: service cards, service form, URL picker.
|
|
- `components/widgets`: clock, image, Pi-hole widget cards, widget form.
|
|
- `lib/api`: generated client and React Query hooks.
|
|
- `lib/mocks`: fixtures/MSW handlers matching OpenAPI.
|
|
- `lib/theme`: theme constants and helpers.
|
|
|
|
## API Contract
|
|
|
|
Frontend consumes `../openapi/openapi.yaml`.
|
|
|
|
Generate types/client through scripts:
|
|
|
|
```json
|
|
{
|
|
"scripts": {
|
|
"api:generate": "openapi-typescript ../openapi/openapi.yaml -o lib/api/schema.ts",
|
|
"typecheck": "tsc --noEmit",
|
|
"test:e2e": "playwright test"
|
|
}
|
|
}
|
|
```
|
|
|
|
Rules:
|
|
|
|
- Do not hand-write API response types.
|
|
- All API DTOs come from generated OpenAPI types.
|
|
- UI view models may exist, but must be derived from generated types.
|
|
- If backend is unavailable, use MSW fixtures shaped exactly like generated types.
|
|
- API base URL comes from `NEXT_PUBLIC_API_BASE_URL`, default `http://localhost:8080`.
|
|
|
|
Expected resources:
|
|
|
|
```text
|
|
Dashboard
|
|
Group
|
|
Service
|
|
ServiceUrl
|
|
WidgetInstance
|
|
WidgetData
|
|
AssetFile
|
|
ErrorResponse
|
|
```
|
|
|
|
Required frontend API hooks:
|
|
|
|
```text
|
|
useDashboard()
|
|
useCreateGroup()
|
|
useUpdateGroup()
|
|
useDeleteGroup()
|
|
useCreateService()
|
|
useUpdateService()
|
|
useDeleteService()
|
|
useUpdateLayout()
|
|
useUploadIcon()
|
|
useCreateWidget()
|
|
useUpdateWidget()
|
|
useDeleteWidget()
|
|
useWidgetData(widgetId)
|
|
useRefreshWidget(widgetId)
|
|
```
|
|
|
|
Mutation behavior:
|
|
|
|
- Optimistically update layout reorder where safe.
|
|
- Roll back reorder on API failure.
|
|
- For CRUD forms, close dialog only after success.
|
|
- Render inline errors as `[ERROR: message]`.
|
|
- Avoid toast dependency for core flows; inline status preferred.
|
|
|
|
## Design Direction
|
|
|
|
Primary design direction:
|
|
|
|
- Dark-first dashboard.
|
|
- Light mode complete and polished.
|
|
- Vercel-inspired structure: restrained cards, shadow-as-border, tight typography.
|
|
- Nothing-inspired accents: OLED black, mono uppercase labels, red signal accent only when meaningful.
|
|
|
|
Fonts:
|
|
|
|
- Load `Geist` and `Geist_Mono` with `next/font/google`.
|
|
- Optional `Doto` only for large clock/hero metric. Do not use Doto for body text.
|
|
|
|
Visual tokens:
|
|
|
|
- Background dark: near/OLED black.
|
|
- Background light: off-white/white.
|
|
- Text dark mode: white/soft gray hierarchy.
|
|
- Text light mode: `#171717` and neutral grays.
|
|
- Radius: 6px for controls, 8px for cards, no large rounded card stacks.
|
|
- Borders: use shadow-as-border or tokenized border, not heavy outlines.
|
|
- Accent: red only for alert/active signal/destructive state.
|
|
- Icons: monoline Lucide via shadcn project icon library.
|
|
|
|
Nothing/Vercel constraints:
|
|
|
|
- No gradients in app chrome.
|
|
- No decorative blobs/orbs.
|
|
- No emojis.
|
|
- No nested cards.
|
|
- No large marketing hero.
|
|
- No skeleton-only loading screens; prefer `[LOADING...]` or compact shadcn loading state.
|
|
- No visible instructional paragraphs explaining obvious UI.
|
|
- Use strong spacing and hierarchy instead of decorative containers.
|
|
|
|
## shadcn Rules
|
|
|
|
Use shadcn components before custom markup:
|
|
|
|
- Button
|
|
- Card
|
|
- Dialog
|
|
- Sheet
|
|
- Input
|
|
- Select
|
|
- Switch
|
|
- Tabs
|
|
- Badge
|
|
- DropdownMenu
|
|
- Tooltip
|
|
- Collapsible
|
|
- Alert
|
|
- Empty
|
|
- Separator
|
|
- ScrollArea
|
|
- Field / FieldGroup where available
|
|
|
|
Rules:
|
|
|
|
- Forms use `FieldGroup` and `Field` patterns.
|
|
- Dialogs, Sheets, and Drawers always have titles.
|
|
- Buttons with icons use `data-icon`.
|
|
- Use `gap-*`, never `space-x-*` or `space-y-*`.
|
|
- Use semantic Tailwind tokens, not random raw colors in component classes.
|
|
- Use `cn()` for conditional class names.
|
|
- Use shadcn `Empty` for no services/no groups.
|
|
- Use shadcn `Alert` for blocking errors.
|
|
|
|
## Screens and Components
|
|
|
|
### Dashboard Page
|
|
|
|
The first viewport is the dashboard.
|
|
|
|
Layout:
|
|
|
|
- Top shell with app name, current date/time, theme toggle, add button.
|
|
- Widget strip below header.
|
|
- Service area below widgets.
|
|
- Groups render as collapsible sections.
|
|
- Ungrouped services render in their own section when present.
|
|
- Empty dashboard renders a minimal empty state with primary add action.
|
|
|
|
Desktop:
|
|
|
|
- Max width around 1200-1400px.
|
|
- Dense but calm grid.
|
|
- Service cards use responsive columns.
|
|
|
|
Mobile:
|
|
|
|
- Single-column service grid.
|
|
- Add/edit forms use full-screen or near-full-height Sheet/Dialog.
|
|
- Drag handles must remain tappable.
|
|
|
|
### Service Cards
|
|
|
|
Show:
|
|
|
|
- Icon or generated initials fallback.
|
|
- Service name.
|
|
- URL kind badges or compact count.
|
|
- Optional primary URL label.
|
|
- Menu for edit/delete/move.
|
|
|
|
Click behavior:
|
|
|
|
- If service has one URL, open it directly in same tab or new tab based on app setting/default.
|
|
- If service has multiple URLs, open URL picker dialog.
|
|
- URL picker lists label, kind, and hostname.
|
|
|
|
Drag behavior:
|
|
|
|
- Drag service within group.
|
|
- Drag service across groups.
|
|
- Drag service to ungrouped.
|
|
- Show clear drop target state.
|
|
- Persist through `PUT /api/v1/layout`.
|
|
|
|
### Service Form
|
|
|
|
Fields:
|
|
|
|
- Name.
|
|
- Icon mode: icon URL or upload file.
|
|
- URLs dynamic list:
|
|
- label
|
|
- kind: local, external, custom
|
|
- URL
|
|
- primary toggle
|
|
- Group select.
|
|
|
|
Validation:
|
|
|
|
- Name required.
|
|
- At least one URL required.
|
|
- URL must be absolute `http` or `https`.
|
|
- Exactly one primary URL in UI; if user never chooses, first is primary.
|
|
- Show field-level errors, not generic banners only.
|
|
|
|
### Groups
|
|
|
|
Group section includes:
|
|
|
|
- Name.
|
|
- Service count.
|
|
- Collapse/expand control.
|
|
- Drag handle.
|
|
- Menu for rename/delete.
|
|
|
|
Behavior:
|
|
|
|
- Collapsed state persists via group PATCH.
|
|
- Empty group can be deleted.
|
|
- Non-empty group delete should ask user to move services to ungrouped, matching backend option.
|
|
- Group reorder persists through layout endpoint.
|
|
|
|
### Widgets
|
|
|
|
Widget strip supports:
|
|
|
|
- Clock widget.
|
|
- Image widget.
|
|
- Pi-hole widget.
|
|
|
|
Clock:
|
|
|
|
- Shows large time and date.
|
|
- Supports configured timezones when backend exposes config.
|
|
- Uses Geist Mono or optional Doto for display moment.
|
|
|
|
Image:
|
|
|
|
- Shows configured image in restrained card.
|
|
- Optional link click.
|
|
- No decorative cropping that hides important content.
|
|
|
|
Pi-hole:
|
|
|
|
- Shows status, blocked count, query count, percent blocked.
|
|
- Loading: `[LOADING...]`.
|
|
- Error: `[ERROR: ...]`.
|
|
- Stale data: show data with compact stale label.
|
|
- Manual refresh button.
|
|
|
|
Widget management:
|
|
|
|
- Add/edit widget Sheet.
|
|
- Widget type select.
|
|
- Type-specific config fields.
|
|
- Widget drag reorder persisted through layout endpoint.
|
|
|
|
## State Management
|
|
|
|
Use React Query for server state:
|
|
|
|
- Dashboard query is primary source for layout.
|
|
- Widget data can be separate query per widget.
|
|
- Invalidate dashboard after CRUD mutations.
|
|
- Use optimistic mutation for layout reorder.
|
|
|
|
Local UI state:
|
|
|
|
- Dialog open/closed.
|
|
- Drag active item.
|
|
- Theme.
|
|
- Form draft state.
|
|
|
|
Do not mirror entire dashboard into global client state unless needed for drag preview. If local reorder state is needed, keep it scoped to dashboard components and reconcile from query data.
|
|
|
|
## Accessibility
|
|
|
|
Required:
|
|
|
|
- Keyboard focus visible on all controls.
|
|
- Dialog title for every Dialog/Sheet.
|
|
- Service cards keyboard-accessible.
|
|
- Drag/drop has keyboard fallback or at least accessible controls for move up/down.
|
|
- Form fields have labels and error messages.
|
|
- Theme toggle has accessible label.
|
|
- Icon-only buttons have labels/tooltips.
|
|
- Color is not only signal for URL kind or errors.
|
|
|
|
## Testing Plan
|
|
|
|
Unit/component tests:
|
|
|
|
- Service form validates required name and URL.
|
|
- Dynamic URL rows add/remove correctly.
|
|
- URL picker opens for multi-URL service.
|
|
- Group collapse button updates state.
|
|
- Widget cards render loading/error/stale/data states.
|
|
|
|
Playwright tests:
|
|
|
|
- Dashboard loads fixture data.
|
|
- Add service with two URLs.
|
|
- Click multi-URL service and choose local/external URL.
|
|
- Create group and move service into group.
|
|
- Collapse group and confirm persisted state after reload.
|
|
- Drag reorder services and verify layout mutation.
|
|
- Toggle dark/light mode.
|
|
- Pi-hole widget shows data and refresh button.
|
|
|
|
Build checks:
|
|
|
|
```bash
|
|
npm run api:generate
|
|
npm run typecheck
|
|
npm run lint
|
|
npm run build
|
|
npm run test:e2e
|
|
```
|
|
|
|
Use the package manager chosen during app scaffold. If using pnpm, scripts remain same but commands run as `pnpm ...`.
|
|
|
|
## Implementation Steps
|
|
|
|
1. Scaffold Next.js App Router project in `/frontend` with TypeScript and Tailwind.
|
|
2. Initialize shadcn/ui and install required base components.
|
|
3. Add API generation script from `../openapi/openapi.yaml`.
|
|
4. Create generated client wrapper and React Query provider.
|
|
5. Build MSW/fixture data matching OpenAPI.
|
|
6. Implement theme tokens, fonts, dark/light modes, and shell.
|
|
7. Build dashboard page with fixture data.
|
|
8. Build service cards and URL picker.
|
|
9. Build add/edit service form with dynamic URLs and icon upload field.
|
|
10. Build group sections, collapse, menus, and group forms.
|
|
11. Add drag/drop for services, groups, and widgets.
|
|
12. Build widgets: clock, image, Pi-hole.
|
|
13. Wire all CRUD and layout mutations to API client.
|
|
14. Add tests and responsive polish.
|
|
15. Run build/typecheck/e2e.
|
|
|
|
## Acceptance Criteria
|
|
|
|
- `/frontend` builds successfully.
|
|
- Frontend generates types from `../openapi/openapi.yaml`.
|
|
- No hand-written API DTO duplication.
|
|
- Dashboard works with MSW fixtures before backend is ready.
|
|
- Dashboard works against backend API once available by changing `NEXT_PUBLIC_API_BASE_URL`.
|
|
- Add/edit/delete service flows work.
|
|
- Multiple URL picker works.
|
|
- Groups can be created, collapsed, reordered, and deleted safely.
|
|
- Drag/drop persists through layout API.
|
|
- Clock, image, and Pi-hole widgets render expected states.
|
|
- Dark and light modes are polished.
|
|
- Mobile and desktop layouts do not overlap or clip text.
|
|
|
|
## Parallel Coordination
|
|
|
|
- Frontend can start with fixtures while backend builds API.
|
|
- Do not invent contract fields outside OpenAPI.
|
|
- If UI needs a new field, request OpenAPI change from backend agent.
|
|
- Regenerate API client after any OpenAPI update.
|
|
- Keep all frontend work isolated inside `/frontend`.
|
|
|
|
|
|
|
|
|
|
# Dashboard Refactor & UX Plan
|
|
|
|
## Core Product Direction
|
|
|
|
The dashboard should feel empty, intentional, and flexible on first launch.
|
|
|
|
Current issue:
|
|
|
|
* The app starts with too much structure and too many assumptions.
|
|
* Users feel boxed into layouts before they build their own workspace.
|
|
|
|
New direction:
|
|
|
|
* Start with a clean canvas.
|
|
* Let users create widgets and apps only when needed.
|
|
* Prioritize drag-and-drop, layout freedom, responsiveness, and visual clarity.
|
|
* Make the dashboard feel closer to CasaOS in usability and visual hierarchy.
|
|
|
|
---
|
|
|
|
# 1. First Launch Experience
|
|
|
|
## Current Problem
|
|
|
|
Dashboard launches with widgets/groups already visible.
|
|
|
|
## New Behavior
|
|
|
|
On first launch:
|
|
|
|
* No widgets
|
|
* No pre-created services
|
|
* No placeholder cards
|
|
* No fake demo groups
|
|
|
|
Only show:
|
|
|
|
### Section 1 — Widgets
|
|
|
|
Top-right:
|
|
|
|
* Small `+ Add Widget` button
|
|
|
|
### Section 2 — Apps / Services
|
|
|
|
Top-right:
|
|
|
|
* Small `+ Add App` button
|
|
|
|
Layout example:
|
|
|
|
```text
|
|
Widgets ------------------------------------- [+]
|
|
(empty state)
|
|
|
|
Apps ---------------------------------------- [+]
|
|
(empty state)
|
|
```
|
|
|
|
## Empty State Design
|
|
|
|
Empty states should feel premium.
|
|
|
|
Example:
|
|
|
|
```text
|
|
No widgets yet
|
|
Create your first widget to customize your dashboard.
|
|
```
|
|
|
|
and:
|
|
|
|
```text
|
|
No apps added
|
|
Start by adding your first app or service.
|
|
```
|
|
|
|
Avoid giant centered buttons.
|
|
|
|
---
|
|
|
|
# 2. Layout Architecture
|
|
|
|
## Dashboard Sections
|
|
|
|
The dashboard should always contain:
|
|
|
|
1. Widgets Section
|
|
2. Apps Section
|
|
|
|
These are not groups.
|
|
|
|
These are permanent layout containers.
|
|
|
|
Groups belong inside Apps.
|
|
|
|
---
|
|
|
|
# 3. Widget System Improvements
|
|
|
|
## Current Problems
|
|
|
|
* Hard to resize
|
|
* Limited placement
|
|
* Dragging feels disconnected
|
|
* Drag icon placement is awkward
|
|
* Widgets feel static
|
|
|
|
## Required Improvements
|
|
|
|
### Fully Resizable Widgets
|
|
|
|
Users should be able to:
|
|
|
|
* Resize width
|
|
* Resize height
|
|
* Stretch across columns
|
|
* Fill entire section width
|
|
* Create masonry/grid layouts
|
|
|
|
Examples:
|
|
|
|
* Clock widget = small
|
|
* Pi-hole widget = large
|
|
* Analytics widget = full width
|
|
|
|
Recommended implementation:
|
|
|
|
### Use Grid-Based Resizing
|
|
|
|
Strong recommendation:
|
|
|
|
```text
|
|
react-grid-layout
|
|
```
|
|
|
|
Benefits:
|
|
|
|
* Resize handles
|
|
* Dragging support
|
|
* Collision detection
|
|
* Snap-to-grid
|
|
* Persistent positions
|
|
* Responsive layouts
|
|
|
|
---
|
|
|
|
## Widget Drag Handle
|
|
|
|
Current problem:
|
|
|
|
* Drag handle outside widget feels detached.
|
|
|
|
Fix:
|
|
|
|
* Drag handle should exist inside widget card.
|
|
* Top-right or top-left.
|
|
|
|
Example:
|
|
|
|
```text
|
|
[ Widget Title ⋮⋮ ]
|
|
```
|
|
|
|
Users should instantly understand:
|
|
|
|
* drag
|
|
* settings
|
|
* resize
|
|
|
|
---
|
|
|
|
## Widget Responsiveness
|
|
|
|
Widgets must:
|
|
|
|
* Reflow on smaller screens
|
|
* Collapse naturally on mobile
|
|
* Maintain resize ratios
|
|
* Support multiple breakpoints
|
|
|
|
Recommended breakpoints:
|
|
|
|
```text
|
|
Desktop: 12-column grid
|
|
Tablet: 6-column grid
|
|
Mobile: 1-column stack
|
|
```
|
|
|
|
---
|
|
|
|
# 4. Clock Widget Improvements
|
|
|
|
## Current Problem
|
|
|
|
Timezone entry requires manual input.
|
|
|
|
## Better UX
|
|
|
|
Replace manual timezone input with:
|
|
|
|
### Searchable Dropdown
|
|
|
|
Recommended:
|
|
|
|
```text
|
|
Europe/Prague
|
|
Europe/London
|
|
America/New_York
|
|
Asia/Tokyo
|
|
```
|
|
|
|
### Better Option
|
|
|
|
Checkbox multi-select dropdown:
|
|
|
|
User can:
|
|
|
|
* Add multiple clocks
|
|
* Select timezone quickly
|
|
* Remove timezone instantly
|
|
|
|
Recommended libraries:
|
|
|
|
```text
|
|
react-select
|
|
shadcn Command + Popover
|
|
```
|
|
|
|
---
|
|
|
|
# 5. Widget Reliability
|
|
|
|
## Pi-hole Widget
|
|
|
|
### Must Validate:
|
|
|
|
* API reachable
|
|
* Token valid
|
|
* IP correct
|
|
* Live refresh updates
|
|
* Error states visible
|
|
|
|
Show:
|
|
|
|
```text
|
|
Cannot reach Pi-hole instance
|
|
Check URL or API key
|
|
```
|
|
|
|
---
|
|
|
|
## Memos Widget
|
|
|
|
### Must Validate:
|
|
|
|
Correct fields:
|
|
|
|
* API endpoint
|
|
* token/auth
|
|
* user scope
|
|
* response parsing
|
|
|
|
Must not silently fail.
|
|
|
|
---
|
|
|
|
## Refresh Button Issue
|
|
|
|
### Problem
|
|
|
|
Refresh button exists but cannot be clicked.
|
|
|
|
Likely causes:
|
|
|
|
* z-index overlap
|
|
* pointer-events disabled
|
|
* absolute layer blocking
|
|
* drag overlay intercepting clicks
|
|
|
|
Fix:
|
|
|
|
```css
|
|
pointer-events: auto;
|
|
z-index: 10;
|
|
```
|
|
|
|
Drag handles should not block interaction.
|
|
|
|
---
|
|
|
|
# 6. Drag & Drop — Highest Priority
|
|
|
|
## Core Principle
|
|
|
|
Drag-and-drop is the main feature.
|
|
|
|
It must feel effortless.
|
|
|
|
---
|
|
|
|
## Current Problems
|
|
|
|
* Dragging unreliable
|
|
* No placement preview
|
|
* Group movement broken
|
|
* Cross-group movement inconsistent
|
|
|
|
---
|
|
|
|
## Required Behavior
|
|
|
|
### Apps Should Be:
|
|
|
|
* Fully draggable
|
|
* Reorderable
|
|
* Group movable
|
|
* Cross-group movable
|
|
* Smooth animations
|
|
|
|
---
|
|
|
|
## Placement Preview
|
|
|
|
When dragging:
|
|
|
|
Show:
|
|
|
|
* Highlight insertion slot
|
|
* Ghost preview
|
|
* Position indicator
|
|
|
|
Users must know exactly where the app will land.
|
|
|
|
---
|
|
|
|
## Recommended Library
|
|
|
|
### Strong Recommendation
|
|
|
|
```text
|
|
@dnd-kit
|
|
```
|
|
|
|
Why:
|
|
|
|
* Best React drag library currently
|
|
* Excellent collision detection
|
|
* Smooth performance
|
|
* Group nesting support
|
|
* Sortable containers
|
|
* Keyboard accessible
|
|
|
|
---
|
|
|
|
## App Dragging Behavior
|
|
|
|
Allow:
|
|
|
|
```text
|
|
Ungrouped → Group
|
|
Group → Group
|
|
Group → Ungrouped
|
|
Reorder inside same group
|
|
Move group itself
|
|
```
|
|
|
|
Must be instant.
|
|
|
|
No modal.
|
|
|
|
No confirmation.
|
|
|
|
---
|
|
|
|
# 7. Apps Section Improvements
|
|
|
|
## Card View Problems
|
|
|
|
Current card view:
|
|
|
|
* Too rectangular
|
|
* Icon too small
|
|
* Doesn't feel visual enough
|
|
|
|
---
|
|
|
|
## New Card View
|
|
|
|
Make app cards square.
|
|
|
|
Inspired by CasaOS.
|
|
|
|
### New Card Structure
|
|
|
|
```text
|
|
┌───────────────┐
|
|
│ │
|
|
│ ICON │
|
|
│ │
|
|
│ App Name │
|
|
└───────────────┘
|
|
```
|
|
|
|
### Improvements
|
|
|
|
* Larger icons
|
|
* Centered content
|
|
* Better spacing
|
|
* More visual identity
|
|
* Hover interaction
|
|
* Rounded corners
|
|
|
|
Recommended:
|
|
|
|
```css
|
|
aspect-ratio: 1 / 1;
|
|
```
|
|
|
|
---
|
|
|
|
## List View
|
|
|
|
Keep mostly unchanged.
|
|
|
|
List view already works.
|
|
|
|
---
|
|
|
|
# 8. Groups System
|
|
|
|
## Problems
|
|
|
|
* Poor naming
|
|
* Not visually distinct
|
|
* Dragging unreliable
|
|
* Cannot collapse
|
|
|
|
---
|
|
|
|
## New Group Requirements
|
|
|
|
### Groups Should Support
|
|
|
|
* Expand/collapse
|
|
* Rename
|
|
* Drag reorder
|
|
* Nested app sorting
|
|
* Instant moving between groups
|
|
|
|
---
|
|
|
|
## Group Header Layout
|
|
|
|
```text
|
|
Infrastructure ▼ [⋮]
|
|
```
|
|
|
|
Avoid:
|
|
|
|
```text
|
|
GRP2
|
|
```
|
|
|
|
Groups must feel human.
|
|
|
|
---
|
|
|
|
## Group Dragging
|
|
|
|
Group itself should be draggable.
|
|
|
|
Move entire group section vertically.
|
|
|
|
---
|
|
|
|
# 9. Modal Improvements
|
|
|
|
## Problem
|
|
|
|
Modals have transparent backgrounds.
|
|
|
|
This reduces readability.
|
|
|
|
---
|
|
|
|
## Fix
|
|
|
|
Use proper modal surface.
|
|
|
|
Recommended:
|
|
|
|
```css
|
|
background: var(--surface);
|
|
backdrop-filter: blur(16px);
|
|
border: 1px solid rgba(255,255,255,.08);
|
|
```
|
|
|
|
No transparent forms.
|
|
|
|
---
|
|
|
|
# 10. Add App Flow
|
|
|
|
## Current Problem
|
|
|
|
Feels generic.
|
|
|
|
---
|
|
|
|
## Rename
|
|
|
|
Replace:
|
|
|
|
```text
|
|
Add Service
|
|
```
|
|
|
|
with:
|
|
|
|
```text
|
|
Add App
|
|
```
|
|
|
|
---
|
|
|
|
## Better Flow
|
|
|
|
### Modal Structure
|
|
|
|
Step 1:
|
|
|
|
* Choose app type
|
|
|
|
Step 2:
|
|
|
|
* Configure details
|
|
|
|
Step 3:
|
|
|
|
* Add icon/logo
|
|
|
|
Step 4:
|
|
|
|
* Select group
|
|
|
|
---
|
|
|
|
## Add App Card
|
|
|
|
When adding in-grid:
|
|
|
|
Small add tile.
|
|
|
|
Not giant button.
|
|
|
|
Example:
|
|
|
|
```text
|
|
+ Add App
|
|
```
|
|
|
|
Should visually match app cards.
|
|
|
|
---
|
|
|
|
# 11. URL Improvements
|
|
|
|
## Current Problem
|
|
|
|
URLs are visually weak.
|
|
|
|
---
|
|
|
|
## Better URL Display
|
|
|
|
Show:
|
|
|
|
```text
|
|
https://app.domain.com
|
|
```
|
|
|
|
With:
|
|
|
|
* favicon
|
|
* hostname extraction
|
|
* quick open
|
|
* copy button
|
|
|
|
Example:
|
|
|
|
```text
|
|
🌐 jellyfin.local
|
|
```
|
|
|
|
---
|
|
|
|
# 12. CasaOS-Inspired Theme
|
|
|
|
## Goal
|
|
|
|
Add an optional theme.
|
|
|
|
Not replacing current dark/light.
|
|
|
|
Add third style:
|
|
|
|
```text
|
|
CasaOS Inspired
|
|
```
|
|
|
|
---
|
|
|
|
## CasaOS Characteristics
|
|
|
|
### Visual Style
|
|
|
|
* Large spacing
|
|
* Rounded containers
|
|
* Soft shadows
|
|
* Glassmorphism feel
|
|
* Bigger cards
|
|
* Centered icons
|
|
* Calm background
|
|
* Floating panels
|
|
|
|
---
|
|
|
|
## CasaOS Dashboard Characteristics
|
|
|
|
### Keep
|
|
|
|
* App grid focus
|
|
* Icon-first navigation
|
|
* Background image
|
|
* Floating sections
|
|
* Minimal chrome
|
|
|
|
---
|
|
|
|
## Remove from CasaOS Reference
|
|
|
|
Do NOT include:
|
|
|
|
* Search bar
|
|
* Storage sync banner
|
|
* Drive discovery cards
|
|
|
|
Only use:
|
|
|
|
* Layout feel
|
|
* Card structure
|
|
* App sizing
|
|
* Background styling
|
|
|
|
---
|
|
|
|
## CasaOS Theme Structure
|
|
|
|
### Background
|
|
|
|
Use:
|
|
|
|
* gradient
|
|
* blurred wallpaper
|
|
* ambient overlay
|
|
|
|
---
|
|
|
|
### Panels
|
|
|
|
```css
|
|
background: rgba(18, 24, 40, 0.65);
|
|
backdrop-filter: blur(18px);
|
|
border-radius: 24px;
|
|
```
|
|
|
|
---
|
|
|
|
### App Cards
|
|
|
|
```css
|
|
aspect-ratio: 1;
|
|
border-radius: 28px;
|
|
transition: transform .2s ease;
|
|
```
|
|
|
|
Hover:
|
|
|
|
```css
|
|
transform: translateY(-3px);
|
|
```
|
|
|
|
---
|
|
|
|
## Theme Switcher
|
|
|
|
Add:
|
|
|
|
```text
|
|
Light
|
|
Dark
|
|
CasaOS Inspired
|
|
```
|
|
|
|
Store in:
|
|
|
|
```text
|
|
localStorage
|
|
```
|
|
|
|
---
|
|
|
|
# 13. Recommended Tech Stack Improvements
|
|
|
|
## Layout
|
|
|
|
```text
|
|
react-grid-layout
|
|
```
|
|
|
|
---
|
|
|
|
## Drag & Drop
|
|
|
|
```text
|
|
@dnd-kit
|
|
```
|
|
|
|
---
|
|
|
|
## Animations
|
|
|
|
```text
|
|
framer-motion
|
|
```
|
|
|
|
---
|
|
|
|
## UI Components
|
|
|
|
```text
|
|
shadcn/ui
|
|
```
|
|
|
|
---
|
|
|
|
## State
|
|
|
|
```text
|
|
zustand
|
|
```
|
|
|
|
---
|
|
|
|
# 14. Priority Order
|
|
|
|
## Phase 1 — Critical UX
|
|
|
|
1. Empty dashboard state
|
|
2. Widgets section + apps section
|
|
3. Smaller add buttons
|
|
4. Drag-and-drop fixes
|
|
5. Placement preview
|
|
6. Group movement
|
|
7. App movement between groups
|
|
|
|
---
|
|
|
|
## Phase 2 — Widget System
|
|
|
|
1. Resizable widgets
|
|
2. Widget drag handles
|
|
3. Better timezone picker
|
|
4. Fix refresh buttons
|
|
5. Widget validation
|
|
|
|
---
|
|
|
|
## Phase 3 — Visual Improvements
|
|
|
|
1. Square app cards
|
|
2. Better icon sizing
|
|
3. Modal redesign
|
|
4. Better group styling
|
|
5. URL redesign
|
|
|
|
---
|
|
|
|
## Phase 4 — CasaOS Theme
|
|
|
|
1. Theme architecture
|
|
2. Background system
|
|
3. Glass panels
|
|
4. CasaOS grid cards
|
|
5. Theme switcher
|
|
|
|
---
|
|
|
|
# 15. Biggest Product Rule
|
|
|
|
The dashboard should feel like:
|
|
|
|
* A workspace
|
|
* A customizable OS
|
|
* A clean home-lab control center
|
|
* A visual launcher
|
|
* Not a traditional admin panel
|
|
|
|
Users should instantly understand:
|
|
|
|
* Add
|
|
* Move
|
|
* Resize
|
|
* Organize
|
|
* Customize
|
|
|
|
without reading instructions.
|