Design Prot Merge #1
@@ -784,7 +784,7 @@ Tareas:
|
||||
| P9 | ✅ | (pendiente) | MediaCard gana hover-zoom del arte y scrim+PlayButton condicionados a `onPlay` (antes exclusivos de MixTile); ahora se aplicarían a cualquier card futura con onPlay, consistencia intencional. Sin QA visual autenticada (Docker no disponible) |
|
||||
| P10 | ✅ | (pendiente) | Decisión tomada (recomendada, sin bloquear): iconos en los botones de cabecera de playlist (antes solo álbum tenía). PlaylistHeader pierde su prop `id` sin usar tras inlinearlo. Explorar: la cabecera de "Resultados para…" ahora usa el `mb-7/8` de PageHeader en vez de un `mt-5` ajustado a mano antes de los chips de filtro — gap ligeramente mayor entre el resumen y los chips (Δ menor, documentado). Sin QA visual autenticada (Docker no disponible) |
|
||||
| P11 | ✅ | (pendiente) | CoverForm añade snippet `extra` (no está en la spec literal, solo `fields`) para el contenido a ancho completo bajo la fila portada+campos (descripción de álbum, selector de visibilidad de playlist) que no cabía en una única columna. Upload usa ImageDropzone con `onselect` (prop nueva) y se envuelve en `{#key}` para poder resetear tras publicar — Δ: el contenedor de portada pasa de 144/176px (móvil/desktop) a 144px fijo (size-cover-hero, sin variante desktop mayor), y el icono de posición vacía de 64px a 36px (icon-xl), tal como recomienda el plan. Sin QA visual autenticada (Docker no disponible) |
|
||||
| P12 | ⬜ | | |
|
||||
| P12 | ✅ | (pendiente) | PlayerExtras se fusiona en PlayerBar (volumen/cola inline); Slider sustituye a SeekBar+VolumeControl (confirmado por grep que el modo `compact` de SeekBar era código muerto). Sidebar y TabsBar migran a `appNavLinks()` (P5). Decisión tomada (sin bloquear): Sidebar gana la marca-gradiente `Logo` que no tenía antes, para consistencia con MobileHeader/login. z-index de PlayerDock/MobileHeader corregido a `z-(--z-sticky)` (son barras fijas, no menús) y SegmentedControl a `z-(--z-raised)`, tal como indica B.1.5. `glass-bar`/`theme-transition` aplicados en PlayerBar (ambas variantes), TabsBar, Queue e Inicio (hero/spotlight), sustituyendo estilos duplicados. Sin QA visual autenticada (Docker no disponible); smoke test de `/login` sin errores de consola |
|
||||
| P13 | ⬜ | | |
|
||||
| P14 | ⬜ | | |
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
import AccountMenu from './ui/AccountMenu.svelte';
|
||||
import Avatar from './ui/Avatar.svelte';
|
||||
import IconButton from './ui/IconButton.svelte';
|
||||
import Logo from './ui/Logo.svelte';
|
||||
|
||||
interface Props {
|
||||
user: SessionUser | null;
|
||||
@@ -17,14 +18,10 @@
|
||||
</script>
|
||||
|
||||
<header
|
||||
class="sticky top-0 z-40 flex h-14 items-center justify-between border-b border-hairline bg-bg/85 page-x backdrop-blur-md sm:hidden"
|
||||
class="sticky top-0 z-(--z-sticky) flex h-14 items-center justify-between border-b border-hairline bg-bg/85 page-x backdrop-blur-md sm:hidden"
|
||||
>
|
||||
<a
|
||||
href="/"
|
||||
class="flex items-center gap-2 font-display text-lg font-semibold tracking-[-0.02em] text-fg"
|
||||
>
|
||||
<span class="h-5.5 w-5.5 rounded-lg bg-[image:var(--mf-logo-grad)]"></span>
|
||||
Musify
|
||||
<a href="/">
|
||||
<Logo size="sm" />
|
||||
</a>
|
||||
|
||||
{#if user}
|
||||
|
||||
@@ -1,18 +1,12 @@
|
||||
<script lang="ts">
|
||||
import { page } from '$app/state';
|
||||
import { isSectionActive } from '$lib/navigation.svelte';
|
||||
import { isSectionActive, appNavLinks } from '$lib/navigation.svelte';
|
||||
import { liked } from '$lib/player/liked.svelte';
|
||||
import { createPlaylistModal } from '$lib/playlists.svelte';
|
||||
import type { SessionUser } from '$lib/types';
|
||||
import ListRow from './ui/ListRow.svelte';
|
||||
import IconButton from './ui/IconButton.svelte';
|
||||
import Home from '@lucide/svelte/icons/house';
|
||||
import Compass from '@lucide/svelte/icons/compass';
|
||||
import ListMusic from '@lucide/svelte/icons/list-music';
|
||||
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 Logo from './ui/Logo.svelte';
|
||||
import Plus from '@lucide/svelte/icons/plus';
|
||||
|
||||
interface SidebarPlaylist {
|
||||
@@ -29,19 +23,7 @@
|
||||
|
||||
let { user, playlists }: Props = $props();
|
||||
|
||||
const navLinks = $derived(
|
||||
user
|
||||
? [
|
||||
{ href: '/', label: 'Inicio', icon: Home },
|
||||
{ href: '/explore', label: 'Descubrir', icon: Compass },
|
||||
{ href: '/playlists', label: 'Playlists', icon: ListMusic, count: playlists.length },
|
||||
{ href: '/liked', label: 'Me gusta', icon: Heart, count: liked.count },
|
||||
{ href: '/albums', label: 'Mis álbumes', icon: Disc },
|
||||
{ href: '/library', label: 'Canciones subidas', icon: Folder },
|
||||
{ href: '/upload', label: 'Subir música', icon: Upload }
|
||||
]
|
||||
: [{ href: '/explore', label: 'Descubrir', icon: Compass }]
|
||||
);
|
||||
const navLinks = $derived(appNavLinks(user, { playlists: playlists.length, liked: liked.count }));
|
||||
|
||||
function isActive(href: string) {
|
||||
return isSectionActive(href, page.url.pathname, page.data.section);
|
||||
@@ -49,10 +31,12 @@
|
||||
</script>
|
||||
|
||||
<aside
|
||||
class="hidden shrink-0 flex-col border-r border-hairline bg-bg p-5 transition-[background] duration-500 ease-out lg:flex"
|
||||
class="theme-transition hidden shrink-0 flex-col border-r border-hairline bg-bg p-5 lg:flex"
|
||||
style="width:var(--mf-sidebar-w)"
|
||||
>
|
||||
<a href="/" class="px-3 pb-3 font-display text-lg font-semibold tracking-tight text-fg">Musify</a>
|
||||
<a href="/" class="px-3 pb-3">
|
||||
<Logo size="sm" />
|
||||
</a>
|
||||
|
||||
<nav class="flex flex-col gap-1">
|
||||
{#each navLinks as link (link.href)}
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { page } from '$app/state';
|
||||
import { isSectionActive } from '$lib/navigation.svelte';
|
||||
import { isSectionActive, appNavLinks } from '$lib/navigation.svelte';
|
||||
import type { SessionUser } from '$lib/types';
|
||||
import Home from '@lucide/svelte/icons/house';
|
||||
import Compass from '@lucide/svelte/icons/compass';
|
||||
import ListMusic from '@lucide/svelte/icons/list-music';
|
||||
import Heart from '@lucide/svelte/icons/heart';
|
||||
|
||||
interface Props {
|
||||
user: SessionUser | null;
|
||||
@@ -14,16 +10,7 @@
|
||||
|
||||
let { user, class: klass = '' }: Props = $props();
|
||||
|
||||
const links = $derived(
|
||||
user
|
||||
? [
|
||||
{ href: '/', label: 'Inicio', icon: Home },
|
||||
{ href: '/explore', label: 'Descubrir', icon: Compass },
|
||||
{ href: '/playlists', label: 'Playlists', icon: ListMusic },
|
||||
{ href: '/liked', label: 'Me gusta', icon: Heart }
|
||||
]
|
||||
: [{ href: '/explore', label: 'Descubrir', icon: Compass }]
|
||||
);
|
||||
const links = $derived(appNavLinks(user).filter((link) => link.primary));
|
||||
|
||||
function isActive(href: string) {
|
||||
return isSectionActive(href, page.url.pathname, page.data.section);
|
||||
@@ -31,7 +18,7 @@
|
||||
</script>
|
||||
|
||||
<nav
|
||||
class="pointer-events-auto flex items-center justify-around border-t border-hairline bg-[image:var(--mf-bar-bg)] px-4 py-1.75 backdrop-blur-xl transition-[background] duration-500 lg:hidden {klass}"
|
||||
class="pointer-events-auto flex items-center justify-around glass-bar px-4 py-1.75 lg:hidden {klass}"
|
||||
style="padding-bottom:calc(0.4375rem + var(--mf-safe-b))"
|
||||
>
|
||||
{#each links as link (link.href)}
|
||||
|
||||
@@ -1,12 +1,21 @@
|
||||
<script lang="ts">
|
||||
import TrackInfo from './TrackInfo.svelte';
|
||||
import TransportControls from './TransportControls.svelte';
|
||||
import SeekBar from './SeekBar.svelte';
|
||||
import PlayerExtras from './PlayerExtras.svelte';
|
||||
import Slider from '$lib/components/ui/Slider.svelte';
|
||||
import IconButton from '$lib/components/ui/IconButton.svelte';
|
||||
import { player } from '$lib/player/player.svelte';
|
||||
import { queuePanel } from '$lib/player/queuePanel.svelte';
|
||||
import { fmtTime } from '$lib/format';
|
||||
import Volume2 from '@lucide/svelte/icons/volume-2';
|
||||
import ListMusic from '@lucide/svelte/icons/list-music';
|
||||
|
||||
function seek(value: number) {
|
||||
if (player.current.duration > 0) player.seekFraction(value / player.current.duration);
|
||||
}
|
||||
</script>
|
||||
|
||||
<div
|
||||
class="animate-enter pointer-events-auto flex items-center gap-4.5 border-t border-hairline bg-[image:var(--mf-bar-bg)] px-4 py-2.75 backdrop-blur-xl transition-[background] duration-500 sm:hidden"
|
||||
class="animate-enter pointer-events-auto flex items-center gap-4.5 glass-bar px-4 py-2.75 sm:hidden"
|
||||
>
|
||||
<div class="min-w-0 flex-1">
|
||||
<TrackInfo compact />
|
||||
@@ -15,14 +24,46 @@
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="animate-enter pointer-events-auto hidden items-center gap-5 border-t border-hairline bg-[image:var(--mf-bar-bg)] px-4 py-2.75 backdrop-blur-xl transition-[background] duration-500 sm:flex"
|
||||
class="animate-enter pointer-events-auto hidden items-center gap-5 glass-bar px-4 py-2.75 sm:flex"
|
||||
>
|
||||
<div class="w-64 min-w-0 shrink-0">
|
||||
<div class="w-(--mf-player-side-w) min-w-0 shrink-0">
|
||||
<TrackInfo />
|
||||
</div>
|
||||
<div class="flex min-w-0 flex-1 flex-col items-center gap-2">
|
||||
<TransportControls />
|
||||
<SeekBar />
|
||||
<div class="flex w-full max-w-hero items-center gap-2.75">
|
||||
<span class="min-w-8 text-right text-xs text-fg-3 tabular-nums">
|
||||
{fmtTime(player.progress)}
|
||||
</span>
|
||||
<Slider
|
||||
value={player.progress}
|
||||
max={player.current.duration}
|
||||
label="Barra de progreso"
|
||||
oninput={seek}
|
||||
variant="seek"
|
||||
/>
|
||||
<span class="min-w-8 text-xs text-fg-3 tabular-nums">
|
||||
{fmtTime(player.current.duration)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hidden w-(--mf-player-side-w) shrink-0 items-center justify-end gap-3.5 sm:flex">
|
||||
<Volume2 class="size-icon-sm shrink-0 text-fg-3" strokeWidth={1.8} />
|
||||
<Slider
|
||||
value={player.volume}
|
||||
max={100}
|
||||
label="Volumen"
|
||||
oninput={(value) => player.setVolume(value)}
|
||||
variant="volume"
|
||||
/>
|
||||
<IconButton
|
||||
label="Cola de reproducción"
|
||||
tone="plain"
|
||||
size="xs"
|
||||
pressed={queuePanel.open}
|
||||
onclick={() => queuePanel.toggle()}
|
||||
>
|
||||
<ListMusic class="size-icon-sm" strokeWidth={1.8} />
|
||||
</IconButton>
|
||||
</div>
|
||||
<PlayerExtras />
|
||||
</div>
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
</script>
|
||||
|
||||
<div
|
||||
class="pointer-events-none fixed inset-x-0 bottom-0 z-40 flex flex-col lg:left-[var(--mf-sidebar-w)]"
|
||||
class="pointer-events-none fixed inset-x-0 bottom-0 z-(--z-sticky) flex flex-col lg:left-(--mf-sidebar-w)"
|
||||
>
|
||||
{#if player.error}
|
||||
<div class="pointer-events-auto px-4 pb-2.5">
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
<script lang="ts">
|
||||
import VolumeControl from './VolumeControl.svelte';
|
||||
import IconButton from '$lib/components/ui/IconButton.svelte';
|
||||
import { queuePanel } from '$lib/player/queuePanel.svelte';
|
||||
import ListMusic from '@lucide/svelte/icons/list-music';
|
||||
</script>
|
||||
|
||||
<div class="hidden w-(--mf-player-side-w) shrink-0 items-center justify-end gap-3.5 sm:flex">
|
||||
<VolumeControl />
|
||||
<IconButton
|
||||
label="Cola de reproducción"
|
||||
tone="plain"
|
||||
size="xs"
|
||||
pressed={queuePanel.open}
|
||||
onclick={() => queuePanel.toggle()}
|
||||
>
|
||||
<ListMusic class="size-icon-sm" strokeWidth={1.8} />
|
||||
</IconButton>
|
||||
</div>
|
||||
@@ -18,7 +18,7 @@
|
||||
{#if queuePanel.open}
|
||||
<aside
|
||||
transition:fly={{ x: 24, duration: 220, easing: cubicOut }}
|
||||
class="hidden shrink-0 flex-col border-l border-hairline bg-bg px-4 pt-5 transition-[background] duration-500 sm:flex"
|
||||
class="hidden shrink-0 flex-col border-l border-hairline bg-bg px-4 pt-5 theme-transition sm:flex"
|
||||
style="width:var(--mf-queue-w); padding-bottom:calc(var(--mf-player-h) + 2rem)"
|
||||
>
|
||||
<div class="mb-5 flex items-center justify-between">
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { player } from '$lib/player/player.svelte';
|
||||
import { fmtTime } from '$lib/format';
|
||||
|
||||
interface Props {
|
||||
compact?: boolean;
|
||||
}
|
||||
|
||||
let { compact = false }: Props = $props();
|
||||
|
||||
function seek(event: MouseEvent) {
|
||||
const rect = (event.currentTarget as HTMLElement).getBoundingClientRect();
|
||||
player.seekFraction((event.clientX - rect.left) / rect.width);
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if compact}
|
||||
<button
|
||||
type="button"
|
||||
onclick={seek}
|
||||
aria-label="Barra de progreso"
|
||||
class="relative block h-1 w-full cursor-pointer bg-track"
|
||||
>
|
||||
<div
|
||||
class="absolute inset-y-0 left-0 bg-accent/70"
|
||||
style="width:{player.progressPercent}%"
|
||||
></div>
|
||||
</button>
|
||||
{:else}
|
||||
<div class="flex w-full max-w-hero items-center gap-2.75">
|
||||
<span class="min-w-8 text-right text-xs text-fg-3 tabular-nums">
|
||||
{fmtTime(player.progress)}
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
onclick={seek}
|
||||
aria-label="Barra de progreso"
|
||||
class="group relative h-3.5 flex-1 cursor-pointer"
|
||||
>
|
||||
<div class="h-[3.5px] w-full overflow-hidden rounded-full bg-track">
|
||||
<div class="h-full rounded-full bg-accent" style="width:{player.progressPercent}%"></div>
|
||||
</div>
|
||||
</button>
|
||||
<span class="min-w-8 text-xs text-fg-3 tabular-nums">
|
||||
{fmtTime(player.current.duration)}
|
||||
</span>
|
||||
</div>
|
||||
{/if}
|
||||
@@ -1,52 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { player } from '$lib/player/player.svelte';
|
||||
import Volume2 from '@lucide/svelte/icons/volume-2';
|
||||
|
||||
function handleVolumeChange(event: Event) {
|
||||
const target = event.currentTarget as HTMLInputElement;
|
||||
player.setVolume(Number(target.value));
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="flex items-center gap-2.25">
|
||||
<Volume2 class="h-3.75 w-3.75 shrink-0 text-fg-3" strokeWidth={1.8} />
|
||||
<input
|
||||
type="range"
|
||||
min="0"
|
||||
max="100"
|
||||
value={player.volume}
|
||||
oninput={handleVolumeChange}
|
||||
aria-label="Volumen"
|
||||
class="mf-volume"
|
||||
style="background:linear-gradient(to right, var(--mf-text-2) {player.volume}%, var(--mf-track) {player.volume}%)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.mf-volume {
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
width: 84px;
|
||||
height: 3.5px;
|
||||
border-radius: 100px;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
.mf-volume::-webkit-slider-thumb {
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
width: 11px;
|
||||
height: 11px;
|
||||
border-radius: 50%;
|
||||
background: var(--mf-text);
|
||||
cursor: pointer;
|
||||
}
|
||||
.mf-volume::-moz-range-thumb {
|
||||
width: 11px;
|
||||
height: 11px;
|
||||
border-radius: 50%;
|
||||
background: var(--mf-text);
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,22 @@
|
||||
<script lang="ts">
|
||||
interface Props {
|
||||
size?: 'sm' | 'lg';
|
||||
}
|
||||
|
||||
let { size = 'sm' }: Props = $props();
|
||||
|
||||
const MARK: Record<'sm' | 'lg', string> = {
|
||||
sm: 'size-5.5 rounded-lg',
|
||||
lg: 'size-8 rounded-control'
|
||||
};
|
||||
|
||||
const TEXT: Record<'sm' | 'lg', string> = {
|
||||
sm: 'font-display text-lg font-semibold tracking-tight text-fg',
|
||||
lg: 'font-display text-[clamp(1.5rem,3vw,2.5rem)] font-semibold tracking-tight'
|
||||
};
|
||||
</script>
|
||||
|
||||
<span class="flex items-center gap-3">
|
||||
<span class="{MARK[size]} bg-[image:var(--mf-logo-grad)]"></span>
|
||||
<span class={TEXT[size]}>Musify</span>
|
||||
</span>
|
||||
@@ -23,7 +23,7 @@
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => (value = option.value)}
|
||||
class="relative z-10 flex-1 px-4 py-1.5 text-center text-xs font-medium transition-colors {value ===
|
||||
class="relative z-(--z-raised) flex-1 px-4 py-1.5 text-center text-xs font-medium transition-colors {value ===
|
||||
option.value
|
||||
? 'text-ink'
|
||||
: 'text-muted hover:text-fg-2'}"
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
<script lang="ts">
|
||||
interface Props {
|
||||
value: number;
|
||||
max: number;
|
||||
label: string;
|
||||
oninput: (value: number) => void;
|
||||
variant: 'seek' | 'volume';
|
||||
}
|
||||
|
||||
let { value, max, label, oninput, variant }: Props = $props();
|
||||
|
||||
const percent = $derived(max > 0 ? (value / max) * 100 : 0);
|
||||
|
||||
function handleInput(event: Event) {
|
||||
oninput(Number((event.currentTarget as HTMLInputElement).value));
|
||||
}
|
||||
</script>
|
||||
|
||||
<input
|
||||
type="range"
|
||||
min="0"
|
||||
{max}
|
||||
{value}
|
||||
oninput={handleInput}
|
||||
aria-label={label}
|
||||
class="mf-slider mf-slider-{variant}"
|
||||
style="background:linear-gradient(to right, var(--mf-text-2) {percent}%, var(--mf-track) {percent}%)"
|
||||
/>
|
||||
|
||||
<style>
|
||||
.mf-slider {
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
height: var(--mf-range-h);
|
||||
border-radius: 100px;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
.mf-slider-seek {
|
||||
width: 100%;
|
||||
}
|
||||
.mf-slider-volume {
|
||||
width: var(--mf-volume-w);
|
||||
}
|
||||
.mf-slider::-webkit-slider-thumb {
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
width: var(--mf-range-thumb);
|
||||
height: var(--mf-range-thumb);
|
||||
border-radius: 50%;
|
||||
background: var(--mf-text);
|
||||
cursor: pointer;
|
||||
}
|
||||
.mf-slider::-moz-range-thumb {
|
||||
width: var(--mf-range-thumb);
|
||||
height: var(--mf-range-thumb);
|
||||
border-radius: 50%;
|
||||
background: var(--mf-text);
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
@@ -137,7 +137,7 @@
|
||||
|
||||
<section class="page-x pt-3 sm:pt-4">
|
||||
<div
|
||||
class="relative overflow-hidden rounded-3xl bg-[image:var(--mf-hero-bg)] px-6 py-8 transition-[background] duration-500 sm:px-9 sm:py-8.5"
|
||||
class="relative overflow-hidden rounded-3xl bg-[image:var(--mf-hero-bg)] px-6 py-8 theme-transition sm:px-9 sm:py-8.5"
|
||||
>
|
||||
<div
|
||||
class="relative flex flex-col items-start gap-7 lg:flex-row lg:flex-wrap lg:items-end lg:justify-between"
|
||||
@@ -220,7 +220,7 @@
|
||||
{#if spotlight}
|
||||
<section>
|
||||
<div
|
||||
class="grid grid-cols-1 overflow-hidden rounded-panel-lg transition-[background] duration-500 lg:grid-cols-2"
|
||||
class="grid grid-cols-1 overflow-hidden rounded-panel-lg theme-transition lg:grid-cols-2"
|
||||
style="background-image:var(--mf-spotlight-bg), linear-gradient(to right, transparent 50%, color-mix(in oklch, var(--mf-scrim) 22%, transparent) 61%, transparent 92.5%)"
|
||||
>
|
||||
<div class="flex flex-col justify-center p-8 sm:p-9">
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script lang="ts">
|
||||
import Button from '$lib/components/ui/Button.svelte';
|
||||
import Logo from '$lib/components/ui/Logo.svelte';
|
||||
|
||||
let { data } = $props();
|
||||
|
||||
@@ -15,12 +16,7 @@
|
||||
<div class="pointer-events-none absolute inset-0" style="background:var(--mf-ambient)"></div>
|
||||
|
||||
<div class="relative flex w-full max-w-4xl flex-col items-center gap-12 text-center">
|
||||
<div class="flex items-center gap-3">
|
||||
<span class="h-8 w-8 rounded-xl bg-[image:var(--mf-logo-grad)]"></span>
|
||||
<span class="font-display text-[clamp(1.5rem,3vw,2.5rem)] font-semibold tracking-tight">
|
||||
Musify
|
||||
</span>
|
||||
</div>
|
||||
<Logo size="lg" />
|
||||
|
||||
<div class="animate-enter flex flex-col items-center gap-5">
|
||||
<h1
|
||||
@@ -32,7 +28,7 @@
|
||||
<p class="text-lg text-fg-2">Inicia sesión para continuar.</p>
|
||||
</div>
|
||||
|
||||
<div class="flex w-full max-w-80 flex-col gap-3">
|
||||
<div class="flex w-full max-w-cta flex-col gap-3">
|
||||
<Button href={`/auth/login?${returnParam}`} reload size="lg" class="w-full">
|
||||
Iniciar sesión
|
||||
</Button>
|
||||
|
||||
Reference in New Issue
Block a user