/ src / routes / components / AdvancedFilters.svelte
AdvancedFilters.svelte
  1  <script lang="ts">
  2    import { createEventDispatcher } from 'svelte';
  3    const dispatch = createEventDispatcher();
  4  
  5    let resultadosPorPagina = '10';
  6    // Los valores posibles son 'local' o 'peer' ('peer' se mapea a 'global' en el servidor)
  7    let recurso = 'local';
  8    let preferMask = '';
  9    // Desactivamos constraints por defecto para evitar problemas de paginación
 10    let constraints = 'false';
 11    let mediaSearch = 'extended_strict';
 12  
 13    function aplicarFiltros() {
 14      dispatch('aplicar', {
 15        resultadosPorPagina,
 16        recurso,
 17        preferMask,
 18        constraints,
 19        mediaSearch
 20      });
 21    }
 22  </script>
 23  
 24  <details class="advanced-filters-container">
 25    <summary class="advanced-filters-toggle">
 26      <span class="toggle-text">Filtros avanzados</span>
 27      <svg class="toggle-icon" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
 28        <polyline points="6 9 12 15 18 9"></polyline>
 29      </svg>
 30    </summary>
 31    
 32    <div class="advanced-filters">
 33      <div class="filters-row">
 34        <div class="filter-control">
 35          <label for="results-per-page">Resultados por página:</label>
 36          <select id="results-per-page" bind:value={resultadosPorPagina}>
 37            <option value="10">10</option>
 38            <option value="20">20</option>
 39            <option value="50">50</option>
 40            <option value="100">100</option>
 41          </select>
 42        </div>
 43        
 44        <div class="filter-control">
 45          <label for="resource-type">Recursos:</label>
 46          <select id="resource-type" bind:value={recurso}>
 47            <option value="local">Índice local</option>
 48            <option value="peer">Peer-to-Peer</option>
 49          </select>
 50        </div>
 51      </div>
 52      
 53      <div class="filters-row">
 54        <div class="filter-control">
 55          <label for="prefer-mask">Prefer mask:</label>
 56          <input type="text" id="prefer-mask" bind:value={preferMask} placeholder="Palabra clave" />
 57        </div>
 58        
 59        <div class="filter-control">
 60          <label for="constraints">Constraints:</label>
 61          <select id="constraints" bind:value={constraints}>
 62            <option value="false">Sin restricciones (recomendado)</option>
 63            <option value="all">Todas</option>
 64            <option value="only_index">Solo indexadas (primera página)</option>
 65          </select>
 66        </div>
 67        
 68        <div class="filter-control">
 69          <label for="media-search">Media search:</label>
 70          <select id="media-search" bind:value={mediaSearch}>
 71            <option value="extended_strict">Extended Strict</option>
 72            <option value="normal">Normal</option>
 73          </select>
 74        </div>
 75      </div>
 76      
 77      <div class="filters-actions">
 78        <button class="reset-button" on:click={() => {
 79          resultadosPorPagina = '10';
 80          recurso = 'local';
 81          preferMask = '';
 82          constraints = 'false';
 83          mediaSearch = 'extended_strict';
 84        }}>Restablecer</button>
 85        <button class="apply-button" on:click={aplicarFiltros}>Aplicar filtros</button>
 86      </div>
 87    </div>
 88  </details>
 89  
 90  <style>
 91    .advanced-filters-container {
 92      width: 100%;
 93    }
 94    
 95    .advanced-filters-toggle {
 96      display: flex;
 97      align-items: center;
 98      justify-content: center;
 99      gap: var(--space-xs);
100      color: var(--text-secondary);
101      padding: var(--space-sm) var(--space-md);
102      font-size: 0.9rem;
103      cursor: pointer;
104      font-weight: var(--font-weight-medium);
105      position: relative;
106      user-select: none;
107      border-radius: var(--border-radius);
108      transition: all var(--transition-speed);
109      background: var(--bg-primary);
110      border: 1px solid var(--border-color);
111    }
112    
113    .advanced-filters-toggle:hover {
114      background: var(--bg-secondary);
115      color: var(--primary);
116    }
117    
118    .advanced-filters-toggle:focus {
119      outline: none;
120      box-shadow: var(--focus-shadow);
121    }
122    
123    /* Eliminar el marcador nativo del elemento details */
124    .advanced-filters-toggle::-webkit-details-marker {
125      display: none;
126    }
127    
128    .toggle-icon {
129      transition: transform var(--transition-speed);
130    }
131    
132    details[open] .toggle-icon {
133      transform: rotate(180deg);
134    }
135    
136    .advanced-filters {
137      display: flex;
138      flex-direction: column;
139      gap: var(--space-md);
140      background: var(--bg-primary);
141      padding: var(--space-lg);
142      width: 100%;
143      border-radius: var(--border-radius);
144      border: 1px solid var(--border-color);
145      margin-top: var(--space-xs);
146      box-shadow: var(--card-shadow);
147    }
148    
149    .filters-row {
150      display: flex;
151      flex-wrap: wrap;
152      gap: var(--space-lg);
153      width: 100%;
154    }
155    
156    .filter-control {
157      display: flex;
158      flex-direction: column;
159      gap: var(--space-xs);
160      flex: 1;
161      min-width: 150px;
162    }
163    
164    .filter-control label {
165      font-size: 0.85rem;
166      font-weight: var(--font-weight-medium);
167      color: var(--text-secondary);
168    }
169    
170    .filter-control select,
171    .filter-control input {
172      padding: var(--space-sm) var(--space-md);
173      font-size: 0.85rem;
174      border: 1px solid var(--border-color);
175      border-radius: var(--border-radius-sm);
176      background: var(--bg-primary);
177      color: var(--text-color);
178      transition: all var(--transition-speed);
179    }
180    
181    .filter-control select:hover,
182    .filter-control input:hover {
183      border-color: var(--primary);
184    }
185    
186    .filter-control select:focus,
187    .filter-control input:focus {
188      border-color: var(--primary);
189      box-shadow: var(--focus-shadow);
190      outline: none;
191    }
192    
193    .filters-actions {
194      display: flex;
195      justify-content: flex-end;
196      gap: var(--space-md);
197      margin-top: var(--space-sm);
198    }
199    
200    .reset-button {
201      background: transparent;
202      color: var(--text-secondary);
203      border: 1px solid var(--border-color);
204      padding: var(--space-sm) var(--space-md);
205      border-radius: var(--border-radius-sm);
206      cursor: pointer;
207      font-size: 0.85rem;
208      font-weight: var(--font-weight-medium);
209      transition: all var(--transition-speed);
210    }
211    
212    .reset-button:hover {
213      background: var(--bg-secondary);
214      color: var(--text-color);
215    }
216    
217    .apply-button {
218      background: var(--primary);
219      color: white;
220      border: none;
221      padding: var(--space-sm) var(--space-md);
222      border-radius: var(--border-radius-sm);
223      cursor: pointer;
224      font-size: 0.85rem;
225      font-weight: var(--font-weight-medium);
226      transition: all var(--transition-speed);
227    }
228    
229    .apply-button:hover {
230      background: var(--primary-dark);
231    }
232    
233    .reset-button:active,
234    .apply-button:active {
235      transform: translateY(1px);
236    }
237    
238    @media (max-width: 768px) {
239      .filters-row {
240        flex-direction: column;
241        gap: var(--space-sm);
242      }
243      
244      .filters-actions {
245        justify-content: center;
246      }
247    }
248    @media (max-width: 768px) {
249      .advanced-filters {
250        flex-direction: column;
251        gap: 0.3rem;
252      }
253    }
254  </style>