Newer
Older
Sakayaki / Pages / Gallery.cshtml
@fabre fabre on 23 Jan 6 KB 他说他超进化了
@page
@model GalleryModel
@{
    ViewData["Title"] = string.IsNullOrWhiteSpace(Model.Author) ? "Gallery" : $"{Model.Author} Gallery";
}

<div class="d-flex flex-wrap gap-2 align-items-end mt-3">
    <a class="btn btn-outline-secondary" href="@Url.Page("Index")">Authors</a>

    <form method="get" class="row g-2 align-items-end flex-grow-1 mb-0">
        <input type="hidden" name="author" value="@Model.Author" />
        <div class="col-12 col-sm-6 col-md-4">
            <input id="keywordInput"
                   name="keyword"
                   class="form-control"
                   value="@Model.Keyword"
                   placeholder="Search by keyword"
                   aria-label="Keyword" />
        </div>
        <div class="col-auto">
            <button type="submit" class="btn btn-primary">Search</button>
            <a class="btn btn-outline-secondary" href="@Url.Page("Gallery", null, new { author = Model.Author })">Clear</a>
        </div>
    </form>
</div>

@if (string.IsNullOrWhiteSpace(Model.Author))
{
    <div class="alert alert-secondary mt-3">Select an author to view folders.</div>
}
else
{
    <div class="row row-cols-1 row-cols-sm-2 row-cols-lg-4 g-3 mt-3">
        @if (Model.Folders.Count == 0)
        {
            <div class="col">
                <div class="alert alert-secondary mb-0">No records yet.</div>
            </div>
        }
        else
        {
            foreach (var card in Model.Folders)
            {
                var item = card.Folder;
                <div class="col">
                    <a class="card h-100 text-start shadow-sm text-decoration-none"
                       data-folder-link="true"
                       data-folder-id="@item.Id"
                       href="@Url.Page("Folder", null, new { id = item.Id, author = Model.Author, keyword = Model.Keyword, p = Model.PageNumber > 1 ? Model.PageNumber : (int?)null })">
                        @if (!string.IsNullOrWhiteSpace(card.CoverUrl))
                        {
                            <img src="@card.CoverUrl" alt="@card.CoverFileName" class="card-img-top" />
                        }
                        <div class="card-body d-flex flex-column">
                            <h5 class="card-title mb-1">@item.Title</h5>
                            <div class="text-muted small">@item.Date.ToString("yyyy-MM-dd") · @item.Author</div>
                            <div class="mt-auto pt-2">
                                <span class="badge text-bg-light">@((item.FileCount ?? 0).ToString()) files</span>
                            </div>
                        </div>
                    </a>
                </div>
            }
        }
    </div>
}

@if (Model.TotalPages > 1 && !string.IsNullOrWhiteSpace(Model.Author))
{
    <nav class="mt-3" aria-label="Pagination">
        <ul class="pagination mb-0">
            <li class="page-item @(Model.PageNumber <= 1 ? "disabled" : "")">
                <a class="page-link"
                   href="@Url.Page("Gallery", null, new { author = Model.Author, p = 1, keyword = Model.Keyword })"
                   aria-label="First">
                    <span aria-hidden="true">««</span>
                </a>
            </li>
            <li class="page-item @(Model.PageNumber <= 1 ? "disabled" : "")">
                <a class="page-link"
                   href="@Url.Page("Gallery", null, new { author = Model.Author, p = Model.PageNumber - 1, keyword = Model.Keyword })"
                   aria-label="Previous">
                    <span aria-hidden="true">«</span>
                </a>
            </li>
            @{
                var startPage = Math.Max(1, Model.PageNumber - 1);
                var endPage = Math.Min(Model.TotalPages, Model.PageNumber + 1);
            }
            @for (var i = startPage; i <= endPage; i++)
            {
                <li class="page-item @(i == Model.PageNumber ? "active" : "")">
                    <a class="page-link" href="@Url.Page("Gallery", null, new { author = Model.Author, p = i, keyword = Model.Keyword })">@i</a>
                </li>
            }
            <li class="page-item @(Model.PageNumber >= Model.TotalPages ? "disabled" : "")">
                <a class="page-link"
                   href="@Url.Page("Gallery", null, new { author = Model.Author, p = Model.PageNumber + 1, keyword = Model.Keyword })"
                   aria-label="Next">
                    <span aria-hidden="true">»</span>
                </a>
            </li>
            <li class="page-item @(Model.PageNumber >= Model.TotalPages ? "disabled" : "")">
                <a class="page-link"
                   href="@Url.Page("Gallery", null, new { author = Model.Author, p = Model.TotalPages, keyword = Model.Keyword })"
                   aria-label="Last">
                    <span aria-hidden="true">»»</span>
                </a>
            </li>
        </ul>
        <div class="small text-muted mt-2">Page @Model.PageNumber / @Model.TotalPages</div>
    </nav>
}

<div id="thumbWait" class="position-fixed top-0 start-0 w-100 h-100 d-none" style="z-index: 1080;">
    <div class="d-flex align-items-center justify-content-center w-100 h-100 bg-dark bg-opacity-50">
        <div class="text-center text-white">
            <div class="spinner-border text-light" role="status" aria-hidden="true"></div>
            <div class="mt-2">Please wait, generating thumbnails...</div>
        </div>
    </div>
</div>

@section Scripts {
    <script>
        const waitOverlay = document.getElementById("thumbWait");
        function isBackForwardNavigation() {
            const navEntry = performance.getEntriesByType("navigation")[0];
            return navEntry?.type === "back_forward";
        }

        window.addEventListener("pageshow", event => {
            if (event.persisted || isBackForwardNavigation()) {
                waitOverlay?.classList.add("d-none");
            }
        });

        document.querySelectorAll("[data-folder-link='true']").forEach(link => {
            link.addEventListener("click", async event => {
                if (event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) {
                    return;
                }

                if (isBackForwardNavigation()) {
                    return;
                }

                const folderId = link.dataset.folderId;
                if (!folderId) {
                    return;
                }

                event.preventDefault();
                waitOverlay?.classList.remove("d-none");

                try {
                    await fetch(`?handler=EnsureThumbnails&id=${encodeURIComponent(folderId)}`);
                } catch (error) {
                    console.warn("Thumbnail generation failed", error);
                }

                window.location.href = link.href;
            });
        });
    </script>
}