Design Prot Merge #1

Merged
NotS1mp merged 217 commits from design-prot into master 2026-09-21 15:48:16 +00:00
4 changed files with 10 additions and 13 deletions
Showing only changes of commit f101ce69a0 - Show all commits
@@ -16,10 +16,10 @@ public sealed class CreateUserRequestValidator : AbstractValidator<CreateUserReq
RuleFor(x => x.FirstName) RuleFor(x => x.FirstName)
.MaximumLength(48) .MaximumLength(48)
.When(x => x.FirstName is not null); .When(x => !string.IsNullOrWhiteSpace(x.FirstName));
RuleFor(x => x.SecondName) RuleFor(x => x.SecondName)
.MaximumLength(48) .MaximumLength(48)
.When(x => x.SecondName is not null); .When(x => !string.IsNullOrWhiteSpace(x.SecondName));
} }
} }
@@ -16,9 +16,6 @@ namespace Musify.Application.Tracks
{ {
public async ValueTask<ErrorOr<PaginatedResponse<TrackApplicationResponse> >> Handle(GetTracksQuery request, CancellationToken cancellationToken) public async ValueTask<ErrorOr<PaginatedResponse<TrackApplicationResponse> >> Handle(GetTracksQuery request, CancellationToken cancellationToken)
{ {
var pageNumber = request.PageNumber < 1 ? 1 : request.PageNumber;
var pageSize = request.PageSize < 1 ? 10 : request.PageSize;
var tracksQuery = database.UserHasTracks var tracksQuery = database.UserHasTracks
.AsNoTracking() .AsNoTracking()
.Include(ut => ut.Track) .Include(ut => ut.Track)
@@ -35,7 +32,7 @@ namespace Musify.Application.Tracks
var pagedTracks = await tracksQuery var pagedTracks = await tracksQuery
.OrderBy(t => t.Id) .OrderBy(t => t.Id)
.Select(t => TrackApplicationResponse.FromEntity(t.Track)) .Select(t => TrackApplicationResponse.FromEntity(t.Track))
.ToPagedListAsync(pageNumber, pageSize, totalCount, cancellationToken); .ToPagedListAsync(request.PageNumber, request.PageSize, totalCount, cancellationToken);
return PaginatedResponse<TrackApplicationResponse>.FromPagedList(pagedTracks); return PaginatedResponse<TrackApplicationResponse>.FromPagedList(pagedTracks);
} }
@@ -65,9 +65,9 @@
type="search" type="search"
value={data.query} value={data.query}
oninput={onSearchInput} oninput={onSearchInput}
placeholder="Buscar por nombre…" placeholder="Buscar por nombre..."
autocomplete="off" autocomplete="off"
class="w-full rounded-lg border border-white/15 bg-neutral-950 py-3 pl-11 pr-4 text-sm text-neutral-100 placeholder:text-neutral-500 focus:border-emerald-500/60 focus:outline-none" class="w-full rounded-lg border border-white/15 bg-neutral-950 py-3 pl-11 pr-4 text-sm text-neutral-100 placeholder:text-neutral-500 focus:border-[var(--mf-accent)]/50 focus:outline-none"
/> />
</div> </div>
@@ -55,10 +55,10 @@
<section class="px-8 py-8"> <section class="px-8 py-8">
<a <a
href="/playlists" href="/playlists"
class="group inline-flex items-center gap-2 text-sm font-medium text-neutral-400 transition-colors hover:text-white" class="group inline-flex items-center font-medium text-neutral-400 transition-colors hover:text-[var(--mf-accent)]"
> >
<span <span
class="grid h-8 w-8 place-items-center rounded-lg border border-white/15 text-neutral-400 transition-colors duration-150 group-hover:border-[var(--mf-accent)]/50 group-hover:bg-[var(--mf-accent)]/10 group-hover:text-[var(--mf-accent)]" class="grid h-8 w-8 place-items-center rounded-lg border-white/15 text-neutral-400 transition-colors duration-150 group-hover:text-[var(--mf-accent)]"
> >
<ArrowLeft class="h-4 w-4" /> <ArrowLeft class="h-4 w-4" />
</span> </span>
@@ -73,7 +73,7 @@
/> />
<div class="min-w-0 flex-1"> <div class="min-w-0 flex-1">
<p class="text-xs font-semibold uppercase tracking-[0.14em] text-neutral-400">Lista</p> <p class="text-xs font-semibold uppercase tracking-[0.14em] text-neutral-400">Lista</p>
<h1 class="mt-1.5 font-display text-5xl font-bold tracking-tight sm:text-6xl">{playlist.name}</h1> <h1 class="mt-1.5 font-display text-5xl font-bold tracking-tight sm:text-7xl">{playlist.name}</h1>
{#if playlist.description} {#if playlist.description}
<p class="mt-3 max-w-2xl text-neutral-300">{playlist.description}</p> <p class="mt-3 max-w-2xl text-neutral-300">{playlist.description}</p>
{/if} {/if}
@@ -111,7 +111,7 @@
type="button" type="button"
onclick={() => (confirmingDelete = true)} onclick={() => (confirmingDelete = true)}
aria-label="Eliminar playlist" aria-label="Eliminar playlist"
class="grid h-12 w-12 place-items-center rounded-lg border border-white/15 text-neutral-300 transition hover:border-red-500/40 hover:bg-red-500/10 hover:text-red-200" class="grid h-12 w-12 place-items-center rounded-lg border border-white/15 text-neutral-300 transition hover:border-red-500/40 hover:bg-red-500/10 hover:text-red-400"
> >
<Trash2 class="h-4 w-4" /> <Trash2 class="h-4 w-4" />
</button> </button>
@@ -310,7 +310,7 @@
<div class="animate-pop w-full max-w-sm rounded-2xl border border-white/10 bg-neutral-900 p-6 shadow-2xl"> <div class="animate-pop w-full max-w-sm rounded-2xl border border-white/10 bg-neutral-900 p-6 shadow-2xl">
<h2 class="font-display text-lg font-bold tracking-tight">¿Eliminar «{playlist.name}»?</h2> <h2 class="font-display text-lg font-bold tracking-tight">¿Eliminar «{playlist.name}»?</h2>
<p class="mt-2 text-sm text-neutral-400"> <p class="mt-2 text-sm text-neutral-400">
Esta acción no se puede deshacer. Las canciones seguirán en tu biblioteca. Esta acción no se puede deshacer, la playlist se eliminará de tu biblioteca y de todos los dispositivos donde la tengas guardada.
</p> </p>
<div class="mt-6 flex items-center justify-end gap-3"> <div class="mt-6 flex items-center justify-end gap-3">
<button <button