@@ -180,8 +180,7 @@ function renderHomeConfig(?array $lastTextInfo, string $base, int $textCount, in
180180 </div>
181181
182182 <!-- Text cards (single row, horizontal scroll) -->
183- <div style="display: flex; gap: 0.75rem; overflow-x: auto; padding-bottom: 0.5rem;"
184- x-data="librarySearch()">
183+ <div style="display: flex; gap: 0.75rem; overflow-x: auto; padding-bottom: 0.5rem;">
185184 <!-- Current text card -->
186185 <div style="flex-shrink: 0;">
187186 <template x-if="lastText">
@@ -275,10 +274,10 @@ class="box has-background-primary-light has-text-centered"
275274 </a>
276275 </div>
277276
278- <!-- Search library card -->
277+ <!-- Search library card (plain HTML, opens modal via DOM event) -->
279278 <div style="flex-shrink: 0;">
280279 <div
281- @click ="open = true "
280+ data-action ="open-library-search "
282281 class="box has-background-warning-light has-text-centered"
283282 style="width: 180px; min-height: 180px; display: flex;
284283 flex-direction: column; justify-content: center; align-items: center;
@@ -290,108 +289,6 @@ class="box has-background-warning-light has-text-centered"
290289 <p class="mt-3 has-text-weight-semibold">Search Library</p>
291290 </div>
292291 </div>
293-
294- <!-- Library search modal -->
295- <div class="modal" :class="{ 'is-active': open }">
296- <div class="modal-background" @click="close()"></div>
297- <div class="modal-card" style="max-width: 600px; width: 90vw;">
298- <header class="modal-card-head">
299- <p class="modal-card-title">Search Project Gutenberg</p>
300- <button class="delete" aria-label="close" @click="close()"></button>
301- </header>
302- <section class="modal-card-body">
303- <form @submit.prevent="search()" class="mb-4">
304- <div class="field has-addons">
305- <div class="control is-expanded">
306- <input
307- x-model="query"
308- class="input"
309- type="text"
310- placeholder="Search by title or author..."
311- />
312- </div>
313- <div class="control">
314- <button
315- type="submit"
316- class="button is-warning"
317- :class="{ 'is-loading': loading && !searched }"
318- :disabled="loading"
319- >
320- <span class="icon"><i data-lucide="search"></i></span>
321- <span>Search</span>
322- </button>
323- </div>
324- </div>
325- </form>
326-
327- <!-- Error message -->
328- <div x-show="error" class="notification is-danger is-light" x-text="error"></div>
329-
330- <!-- Results count -->
331- <p
332- x-show="searched && !error && !loading"
333- class="has-text-grey is-size-7 mb-2"
334- >
335- <span x-text="totalCount"></span> books found
336- </p>
337-
338- <!-- Results list -->
339- <div
340- x-show="results.length > 0"
341- style="max-height: 400px; overflow-y: auto;"
342- >
343- <template x-for="book in results" :key="book.id">
344- <div class="box p-3 mb-2" style="cursor: default;">
345- <div class="is-flex is-justify-content-space-between is-align-items-start">
346- <div style="flex: 1; min-width: 0;">
347- <p
348- class="has-text-weight-semibold is-size-6"
349- x-text="book.title"
350- style="overflow: hidden; text-overflow: ellipsis;"
351- ></p>
352- <p
353- class="has-text-grey is-size-7"
354- x-text="formatAuthors(book.authors)"
355- ></p>
356- <p class="has-text-grey-light is-size-7">
357- <span x-text="formatDownloads(book.downloadCount)"></span> downloads
358- </p>
359- </div>
360- <button
361- @click="importBook(book)"
362- class="button is-primary is-small ml-3"
363- :class="{ 'is-loading': importing === book.id }"
364- :disabled="importing !== null"
365- >
366- <span class="icon"><i data-lucide="download"></i></span>
367- <span>Import</span>
368- </button>
369- </div>
370- </div>
371- </template>
372- </div>
373-
374- <!-- Load more -->
375- <button
376- x-show="hasMore && results.length > 0"
377- @click="loadMore()"
378- class="button is-small is-fullwidth mt-2"
379- :class="{ 'is-loading': loading }"
380- :disabled="loading"
381- >
382- Load more
383- </button>
384-
385- <!-- No results -->
386- <p
387- x-show="searched && results.length === 0 && !loading && !error"
388- class="has-text-grey is-italic"
389- >
390- No books found. Try a different search term.
391- </p>
392- </section>
393- </div>
394- </div>
395292 </div>
396293 </div>
397294</section>
@@ -607,4 +504,108 @@ class="button is-fullwidth is-light"
607504
608505</div><!-- End Alpine.js container -->
609506
507+ <!-- Library search modal (separate Alpine scope, outside homeApp) -->
508+ <div x-data="librarySearch" @open-library-search.document="open = true" x-cloak>
509+ <div class="modal" :class="{ 'is-active': open }">
510+ <div class="modal-background" @click="close()"></div>
511+ <div class="modal-card" style="max-width: 600px; width: 90vw;">
512+ <header class="modal-card-head">
513+ <p class="modal-card-title">Search Project Gutenberg</p>
514+ <button class="delete" aria-label="close" @click="close()"></button>
515+ </header>
516+ <section class="modal-card-body">
517+ <form @submit.prevent="search()" class="mb-4">
518+ <div class="field has-addons">
519+ <div class="control is-expanded">
520+ <input
521+ x-model="query"
522+ class="input"
523+ type="text"
524+ placeholder="Search by title or author..."
525+ />
526+ </div>
527+ <div class="control">
528+ <button
529+ type="submit"
530+ class="button is-warning"
531+ :class="{ 'is-loading': loading && !searched }"
532+ :disabled="loading"
533+ >
534+ <span class="icon"><i data-lucide="search"></i></span>
535+ <span>Search</span>
536+ </button>
537+ </div>
538+ </div>
539+ </form>
540+
541+ <!-- Error message -->
542+ <div x-show="error" class="notification is-danger is-light" x-text="error"></div>
543+
544+ <!-- Results count -->
545+ <p
546+ x-show="searched && !error && !loading"
547+ class="has-text-grey is-size-7 mb-2"
548+ >
549+ <span x-text="totalCount"></span> books found
550+ </p>
551+
552+ <!-- Results list -->
553+ <div
554+ x-show="results.length > 0"
555+ style="max-height: 400px; overflow-y: auto;"
556+ >
557+ <template x-for="book in results" :key="book.id">
558+ <div class="box p-3 mb-2" style="cursor: default;">
559+ <div class="is-flex is-justify-content-space-between is-align-items-start">
560+ <div style="flex: 1; min-width: 0;">
561+ <p
562+ class="has-text-weight-semibold is-size-6"
563+ x-text="book.title"
564+ style="overflow: hidden; text-overflow: ellipsis;"
565+ ></p>
566+ <p
567+ class="has-text-grey is-size-7"
568+ x-text="formatAuthors(book.authors)"
569+ ></p>
570+ <p class="has-text-grey-light is-size-7">
571+ <span x-text="formatDownloads(book.downloadCount)"></span> downloads
572+ </p>
573+ </div>
574+ <button
575+ @click="importBook(book)"
576+ class="button is-primary is-small ml-3"
577+ :class="{ 'is-loading': importing === book.id }"
578+ :disabled="importing !== null"
579+ >
580+ <span class="icon"><i data-lucide="download"></i></span>
581+ <span>Import</span>
582+ </button>
583+ </div>
584+ </div>
585+ </template>
586+ </div>
587+
588+ <!-- Load more -->
589+ <button
590+ x-show="hasMore && results.length > 0"
591+ @click="loadMore()"
592+ class="button is-small is-fullwidth mt-2"
593+ :class="{ 'is-loading': loading }"
594+ :disabled="loading"
595+ >
596+ Load more
597+ </button>
598+
599+ <!-- No results -->
600+ <p
601+ x-show="searched && results.length === 0 && !loading && !error"
602+ class="has-text-grey is-italic"
603+ >
604+ No books found. Try a different search term.
605+ </p>
606+ </section>
607+ </div>
608+ </div>
609+ </div>
610+
610611<?php renderHomeConfig ($ lastTextInfo , $ base , $ textCount , $ currentlang ); ?>
0 commit comments