4 Commits
Author SHA1 Message Date
AdminandClaude Sonnet 5 b63e30d2f8 Move domain data helpers into lib/data
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-22 14:10:55 +02:00
AdminandClaude Sonnet 5 f1220a688a Remove leftover old paths from the lib/state move
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-22 14:10:15 +02:00
AdminandClaude Sonnet 5 9770580f7f Add folder structure reorganization plan
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-22 14:09:37 +02:00
AdminandClaude Sonnet 5 f98c47f5ed Move rune-based state modules into lib/state
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-22 14:09:36 +02:00
22 changed files with 150 additions and 23 deletions
+127
View File
@@ -0,0 +1,127 @@
# Plan — Organización de carpetas (web-player)
> Plan de trabajo para agentes/IA. Cubre la **estructura de directorios**, no el sistema de
> diseño (para tokens/componentización visual ver `docs/frontend-refactor-plan.md`, P0–P14,
> que sigue siendo la referencia para radios/tamaños/tipografía/colores).
> Basado en una lectura completa de `web-player/src` (2026-09-22, rama `web-player-ref`).
## Cómo usar este documento
1. Cada fase (F1…F7) es independiente y es **un commit**. No mezcles fases.
2. Al mover archivos: actualizar todos los imports que los referencian (`grep` del nombre
viejo de ruta antes de dar la fase por cerrada).
3. Cierre de cada fase: `npm run check` y `npm run lint` **limpios** (desde `web-player/`).
4. Al terminar una fase, marca su casilla en la sección Registro.
Orden recomendado: `F1 → F2 → F3 → F4 → F6` (independientes entre sí, pueden ir en
cualquier orden). `F5` es opcional y requiere confirmación explícita del usuario antes de
empezarla (cambia URLs públicas / config de Zitadel).
---
## Diagnóstico
- `src/lib/` raíz tiene 12 archivos sueltos mezclando estado reactivo (runes), helpers de
dominio y utilidades genéricas.
- `src/lib/components/` raíz tiene 4 componentes de layout/chrome sueltos (ni `ui/` ni
`player/`).
- `src/lib/components/ui/` tiene 38 componentes en un único nivel, sin categorizar.
- `src/routes/` reparte auth en cuatro sitios distintos (`/login`, `/logout`, `/auth/login`,
`/auth/callback`).
---
## F1 — Agrupar estado reactivo
Crear `src/lib/state/` y mover:
- `menus.svelte.ts`
- `navigation.svelte.ts`
- `playlists.svelte.ts`
- `toggle.svelte.ts`
`lib/player/*.svelte.ts` y `lib/theme/mode.svelte.ts` se quedan donde están (ya tienen
dominio propio, no son huérfanos).
**Cierre:** imports actualizados, `npm run check` y `npm run lint` limpios.
## F2 — Agrupar helpers de dominio
Crear `src/lib/data/` y mover:
- `albums.ts`
- `collections.ts`
- `genres.ts`
- `mixes.ts`
- `recentlyPlayed.ts`
- `search.ts`
**Cierre:** igual que F1.
## F3 — Utilidades genéricas
- `format.ts` → `src/lib/utils/format.ts`.
- `types.ts` se queda en la raíz de `lib/` (si crece mucho, pasar a `src/lib/types/index.ts`
en una fase futura — no crear la carpeta por adelantado).
- `config.ts` se queda en la raíz de `lib/` (config global, un único archivo, no amerita
carpeta).
**Cierre:** igual que F1.
## F4 — Componentes de layout/chrome
Crear `src/lib/components/layout/` y mover:
- `MobileHeader.svelte`
- `Sidebar.svelte`
- `TabsBar.svelte`
- `TopBar.svelte`
**Cierre:** igual que F1.
## F5 (opcional, requiere confirmación) — Consolidar rutas de auth
Unificar `/login`, `/logout`, `/auth/login`, `/auth/callback` bajo `/auth/`:
- `/auth` → page (login screen, hoy en `/login/+page.svelte`)
- `/auth/login` → server endpoint (ya existe)
- `/auth/logout` → server endpoint (hoy `/logout/+server.ts`)
- `/auth/callback` → server endpoint (ya existe)
**Cambia URLs públicas.** Si `AUTH_REDIRECT_URI` / `AUTH_POST_LOGOUT_URI` en la config de
Zitadel apuntan a las rutas actuales, hay que actualizarlas ahí también antes de mergear.
No empezar esta fase sin confirmación explícita.
## F6 — Categorizar `components/ui/`
38 componentes en un único nivel dificultan el escaneo visual y el autocompletado del
editor. Agrupar por categoría funcional (no por jerarquía atómica estricta — sería excesivo
para este tamaño):
| Carpeta | Componentes | Criterio |
| -------------- | --------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------ |
| `primitives/` | Alert, BackLink, Button, Checkbox, Chip, EmptyState, Field, IconButton, InfiniteScroll, Input, Logo, SegmentedControl, Slider, Surface, Textarea | Piezas genéricas, sin conocimiento del dominio música |
| `overlay/` | AccountMenu, ConfirmDialog, ContextMenu, GlassMenu, MenuItem, Modal | Todo lo que flota encima del contenido |
| `media/` | ArtistLink, Artwork, Avatar, EqBars, ExplicitBadge, ListRow, MediaCard, MediaIdentity, PlayButton, TrackList | Específicos del dominio música/track |
| `forms/` | AlbumForm, CoverForm, ImageDropzone, PlaylistForm | Formularios compuestos de entidad |
| `layout/` | Page, PageHeader, SectionHeading | Andamiaje de página (distinto de `components/layout/` de F4, que es el chrome global) |
Sin barrels/`index.ts` — actualizar cada ruta de import directamente, no hace falta esa
indirección para esto.
Hacer **un sub-commit por categoría** (mover + actualizar imports + `npm run check`) en vez
de mover las 38 de una vez, para mantener el diff revisable.
**Cierre:** las 5 subcarpetas creadas, `ui/` raíz sin `.svelte` sueltos, imports
actualizados, `npm run check` y `npm run lint` limpios.
---
## Registro
- [ ] F1 — estado reactivo → `lib/state/`
- [ ] F2 — helpers de dominio → `lib/data/`
- [ ] F3 — utilidades genéricas (`format.ts` → `lib/utils/`)
- [ ] F4 — componentes de layout/chrome → `components/layout/`
- [ ] F5 — consolidar rutas de auth bajo `/auth/` (opcional, pendiente de confirmación)
- [ ] F6 — categorizar `components/ui/` (primitives/overlay/media/forms/layout)
+2 -2
View File
@@ -1,8 +1,8 @@
<script lang="ts">
import { page } from '$app/state';
import { isSectionActive, appNavLinks } from '$lib/navigation.svelte';
import { isSectionActive, appNavLinks } from '$lib/state/navigation.svelte';
import { liked } from '$lib/player/liked.svelte';
import { createPlaylistModal } from '$lib/playlists.svelte';
import { createPlaylistModal } from '$lib/state/playlists.svelte';
import type { SessionUser } from '$lib/types';
import ListRow from './ui/ListRow.svelte';
import IconButton from './ui/IconButton.svelte';
+1 -1
View File
@@ -1,6 +1,6 @@
<script lang="ts">
import { page } from '$app/state';
import { isSectionActive, appNavLinks } from '$lib/navigation.svelte';
import { isSectionActive, appNavLinks } from '$lib/state/navigation.svelte';
import type { SessionUser } from '$lib/types';
interface Props {
+1 -1
View File
@@ -3,7 +3,7 @@
import { page } from '$app/state';
import type { SessionUser } from '$lib/types';
import { SEARCH_DEBOUNCE_MS, SEARCH_MIN_LENGTH } from '$lib/config';
import { searchHref } from '$lib/navigation.svelte';
import { searchHref } from '$lib/state/navigation.svelte';
import Search from '@lucide/svelte/icons/search';
import X from '@lucide/svelte/icons/x';
import ChevronLeft from '@lucide/svelte/icons/chevron-left';
@@ -1,6 +1,6 @@
<script lang="ts">
import ArrowLeft from '@lucide/svelte/icons/arrow-left';
import { previousPage } from '$lib/navigation.svelte';
import { previousPage } from '$lib/state/navigation.svelte';
interface Props {
href: string;
+1 -1
View File
@@ -1,7 +1,7 @@
import { browser } from '$app/environment';
import { DEFAULT_ACCENT } from '$lib/theme/color';
import { extractAccent, type Accent } from '$lib/theme/palette';
import { shuffle } from '$lib/collections';
import { shuffle } from '$lib/data/collections';
export interface PlayerTrack {
id: string | number;
@@ -1,3 +1,3 @@
import { createToggle } from '../toggle.svelte';
import { createToggle } from '../state/toggle.svelte';
export const queuePanel = createToggle();
@@ -1,5 +1,5 @@
import { contextMenuPosition, type MenuPosition } from '$lib/components/ui/ContextMenu.svelte';
import { player, toQueueItem, type ApiTrackLike } from './player/player.svelte';
import { player, toQueueItem, type ApiTrackLike } from '../player/player.svelte';
export type TrackMenuState = { track: ApiTrackLike } & MenuPosition;
@@ -7,7 +7,7 @@ import Heart from '@lucide/svelte/icons/heart';
import Disc from '@lucide/svelte/icons/disc-2';
import Folder from '@lucide/svelte/icons/folder';
import Upload from '@lucide/svelte/icons/upload';
import type { SessionUser } from './types';
import type { SessionUser } from '../types';
const HISTORY_INDEX = 'sveltekit:history';
@@ -1,7 +1,7 @@
<script lang="ts">
import Music from '@lucide/svelte/icons/music';
import { player, toQueueItem } from '$lib/player/player.svelte';
import { fetchAlbumQueueItems } from '$lib/albums';
import { fetchAlbumQueueItems } from '$lib/data/albums';
import { fmtTime, fmtPlays, plural } from '$lib/format';
import Page from '$lib/components/ui/Page.svelte';
import PageHeader from '$lib/components/ui/PageHeader.svelte';
@@ -16,13 +16,13 @@
import Chip from '$lib/components/ui/Chip.svelte';
import SectionHeading from '$lib/components/ui/SectionHeading.svelte';
import { EXPLORE_PAGE_SIZE } from '$lib/config';
import { searchHref } from '$lib/navigation.svelte';
import { createTrackMenu } from '$lib/menus.svelte';
import { searchHref } from '$lib/state/navigation.svelte';
import { createTrackMenu } from '$lib/state/menus.svelte';
import ContextMenu, { contextMenuPosition } from '$lib/components/ui/ContextMenu.svelte';
import ListPlus from '@lucide/svelte/icons/list-plus';
import ListEnd from '@lucide/svelte/icons/list-end';
import { appendUnique } from '$lib/collections';
import { genreTiles } from '$lib/genres';
import { appendUnique } from '$lib/data/collections';
import { genreTiles } from '$lib/data/genres';
import {
type SearchFilter,
showGroup,
@@ -31,7 +31,7 @@
searchCounts,
searchChips,
findTopResult
} from '$lib/search';
} from '$lib/data/search';
type AlbumMenuState = { x: number; y: number; openLeft: boolean; albumId: string };
@@ -19,8 +19,8 @@
import TrackList from '$lib/components/ui/TrackList.svelte';
import ContextMenu from '$lib/components/ui/ContextMenu.svelte';
import ListPlus from '@lucide/svelte/icons/list-plus';
import { createTrackMenu } from '$lib/menus.svelte';
import { mixItemTrack } from '$lib/mixes';
import { createTrackMenu } from '$lib/state/menus.svelte';
import { mixItemTrack } from '$lib/data/mixes';
let { data, form } = $props();
@@ -5,7 +5,7 @@
import MediaCard from '$lib/components/ui/MediaCard.svelte';
import EmptyState from '$lib/components/ui/EmptyState.svelte';
import Button from '$lib/components/ui/Button.svelte';
import { createPlaylistModal } from '$lib/playlists.svelte';
import { createPlaylistModal } from '$lib/state/playlists.svelte';
import { fmtDurationLong, plural, playlistMeta } from '$lib/format';
let { data } = $props();
+2 -2
View File
@@ -14,11 +14,11 @@
import { player } from '$lib/player/player.svelte';
import { queuePanel } from '$lib/player/queuePanel.svelte';
import { liked } from '$lib/player/liked.svelte';
import { createPlaylistModal } from '$lib/playlists.svelte';
import { createPlaylistModal } from '$lib/state/playlists.svelte';
import { ACCENT_HUE } from '$lib/theme/color';
import { buildThemeTokens, applyThemeTokens, tokensToCss } from '$lib/theme/tokens';
import { themeMode } from '$lib/theme/mode.svelte';
import { trackNavigation } from '$lib/navigation.svelte';
import { trackNavigation } from '$lib/state/navigation.svelte';
import { page } from '$app/state';
let { children, data } = $props();
+3 -3
View File
@@ -13,8 +13,8 @@
type ApiTrackLike
} from '$lib/player/player.svelte';
import { pressable } from '$lib/actions/pressable';
import { mergeRecentlyPlayed } from '$lib/recentlyPlayed';
import { mixItemTrack } from '$lib/mixes';
import { mergeRecentlyPlayed } from '$lib/data/recentlyPlayed';
import { mixItemTrack } from '$lib/data/mixes';
import { fmtTime, fmtDurationLong, fmtPlays, plural } from '$lib/format';
import Page from '$lib/components/ui/Page.svelte';
import Artwork from '$lib/components/ui/Artwork.svelte';
@@ -26,7 +26,7 @@
import Button from '$lib/components/ui/Button.svelte';
import ContextMenu from '$lib/components/ui/ContextMenu.svelte';
import ListPlus from '@lucide/svelte/icons/list-plus';
import { createTrackMenu } from '$lib/menus.svelte';
import { createTrackMenu } from '$lib/state/menus.svelte';
import { HOME_CONTINUE_LIMIT, HOME_POPULAR_MAX } from '$lib/config';
let { data } = $props();