239 lines
12 KiB
Plaintext
239 lines
12 KiB
Plaintext
@page "{handler?}"
|
|
@model Media.JoshHeaps.Net.Pages.GalleryModel
|
|
@{
|
|
ViewData["Title"] = "Gallery";
|
|
Layout = "_Layout";
|
|
}
|
|
|
|
@section Styles {
|
|
<link rel="stylesheet" href="~/css/Gallery/page.css" asp-append-version="true" />
|
|
<link rel="stylesheet" href="~/css/gallery.css" asp-append-version="true" />
|
|
}
|
|
|
|
<div class="dashboard-container">
|
|
<div class="welcome-section">
|
|
<div class="welcome-left">
|
|
<a href="/Landing" class="back-button" title="Back to Home">
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
<line x1="19" y1="12" x2="5" y2="12"></line>
|
|
<polyline points="12 19 5 12 12 5"></polyline>
|
|
</svg>
|
|
</a>
|
|
<h1>Welcome back, @Model.Dashboard?.Username!</h1>
|
|
</div>
|
|
|
|
<div class="quick-actions">
|
|
@if (Model.Dashboard?.EmailVerified == false)
|
|
{
|
|
<a href="/[email protected](Model.Dashboard.Email)" class="btn btn-primary">
|
|
Verify Email
|
|
</a>
|
|
}
|
|
<a href="/Profile" class="btn btn-secondary">Edit Profile</a>
|
|
<a href="/Logout" class="btn btn-danger">Logout</a>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card" id="upload-form-card" style="display:none;">
|
|
<div class="upload-form-header">
|
|
<h2>Upload Image</h2>
|
|
<button type="button" class="close-upload-form" id="close-upload-btn">×</button>
|
|
</div>
|
|
@if (!string.IsNullOrEmpty(Model.UploadMessage))
|
|
{
|
|
<div class="alert @(Model.UploadSuccess ? "alert-success" : "alert-error")">
|
|
@Model.UploadMessage
|
|
</div>
|
|
}
|
|
<form method="post" enctype="multipart/form-data" id="upload-form">
|
|
@Html.AntiForgeryToken()
|
|
<div class="form-group">
|
|
<label for="UploadedFile">Select Image(s)</label>
|
|
<input type="file" id="UploadedFile" name="UploadedFile" accept="image/*" multiple required />
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="Description">Description (optional)</label>
|
|
<textarea id="Description" name="Description" rows="3" placeholder="Add a description for all images..."></textarea>
|
|
</div>
|
|
<div id="upload-progress" style="display:none;">
|
|
<div class="progress-bar">
|
|
<div class="progress-fill" id="progress-fill"></div>
|
|
</div>
|
|
<div class="progress-text" id="progress-text">Uploading...</div>
|
|
</div>
|
|
<button type="submit" class="btn btn-primary" id="upload-btn">Upload</button>
|
|
</form>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<div class="gallery-header">
|
|
<div class="breadcrumb-nav">
|
|
<a href="/[email protected]">Home</a>
|
|
@foreach (var folder in Model.FolderPath)
|
|
{
|
|
<span class="breadcrumb-separator">/</span>
|
|
<a href="/[email protected]&[email protected]">@folder.Name</a>
|
|
}
|
|
@if (Model.IsSharedFolder && !string.IsNullOrEmpty(Model.SharedByUsername))
|
|
{
|
|
<span class="shared-indicator">(Shared by @Model.SharedByUsername)</span>
|
|
}
|
|
</div>
|
|
<div class="header-actions">
|
|
<div class="view-mode-toggle">
|
|
<a href="/Gallery?view=own" class="view-mode-btn @(Model.ViewMode == "own" ? "active" : "")">My Folders</a>
|
|
<a href="/Gallery?view=shared" class="view-mode-btn @(Model.ViewMode == "shared" ? "active" : "")">Shared with Me</a>
|
|
<a href="/Gallery?view=all" class="view-mode-btn @(Model.ViewMode == "all" ? "active" : "")">All</a>
|
|
</div>
|
|
@if (!Model.IsSharedFolder)
|
|
{
|
|
<button type="button" class="btn btn-secondary" id="new-folder-btn">New Folder</button>
|
|
}
|
|
</div>
|
|
</div>
|
|
<h2>
|
|
@if (Model.CurrentFolderId.HasValue)
|
|
{
|
|
<span>@(Model.FolderPath.LastOrDefault()?.Name ?? "Folder")</span>
|
|
}
|
|
else
|
|
{
|
|
<span>My Media</span>
|
|
}
|
|
<span class="item-count">(@(Model.Folders.Count + Model.MediaItems.Count) items)</span>
|
|
</h2>
|
|
<div id="gallery" class="gallery-grid">
|
|
@if (Model.CurrentFolderId.HasValue)
|
|
{
|
|
var backUrl = Model.FolderPath.Count > 1
|
|
? $"/Gallery?folderId={Model.FolderPath[Model.FolderPath.Count - 2].Id}&view={Model.ViewMode}"
|
|
: $"/Gallery?view={Model.ViewMode}";
|
|
<div class="gallery-item folder-item" data-folder-id="back" onclick="window.location.href='@backUrl'">
|
|
<div class="folder-icon">
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M9 6l6 6-6 6"/>
|
|
</svg>
|
|
</div>
|
|
<div class="folder-name">..</div>
|
|
</div>
|
|
}
|
|
@foreach (var sharedFolder in Model.SharedFolders)
|
|
{
|
|
<div class="gallery-item folder-item shared-folder-item" data-folder-id="@sharedFolder.FolderId" onclick="window.location.href='/[email protected]&[email protected]'">
|
|
<div class="folder-icon">
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/>
|
|
<path d="M20 12h-2m-2 0h-2" stroke-width="1.5"/>
|
|
</svg>
|
|
</div>
|
|
<div class="folder-name">
|
|
@sharedFolder.FolderName
|
|
<span class="shared-badge">Shared by @sharedFolder.OwnerUsername</span>
|
|
</div>
|
|
</div>
|
|
}
|
|
@foreach (var folder in Model.Folders)
|
|
{
|
|
<div class="gallery-item folder-item @(folder.UserId != Model.UserId ? "shared-folder-item" : "")" data-folder-id="@folder.Id" data-owner-id="@folder.UserId" onclick="window.location.href='/[email protected]&[email protected]'">
|
|
<div class="folder-icon">
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/>
|
|
</svg>
|
|
</div>
|
|
<div class="folder-name">@folder.Name</div>
|
|
@if (folder.UserId == Model.UserId && !Model.IsSharedFolder)
|
|
{
|
|
<div class="folder-actions">
|
|
<button type="button" class="btn-action" onclick="event.stopPropagation(); showShareModal(@folder.Id, '@folder.Name')">Share</button>
|
|
<button type="button" class="btn-action" onclick="event.stopPropagation(); renameFolder(@folder.Id, '@folder.Name')">Rename</button>
|
|
<button type="button" class="btn-action" onclick="event.stopPropagation(); deleteFolder(@folder.Id)">Delete</button>
|
|
</div>
|
|
}
|
|
</div>
|
|
}
|
|
@foreach (var media in Model.MediaItems)
|
|
{
|
|
<div class="gallery-item media-item" data-media-id="@media.Id" draggable="true">
|
|
<div class="selection-checkbox">
|
|
<input type="checkbox" class="media-select" data-media-id="@media.Id" />
|
|
</div>
|
|
<img src="/api/media/image/@media.Id" alt="@media.FileName" loading="lazy" />
|
|
@if (!string.IsNullOrEmpty(media.Description))
|
|
{
|
|
<div class="gallery-item-description">@media.Description</div>
|
|
}
|
|
<div class="gallery-item-info">
|
|
<span class="gallery-item-date">@media.CreatedAt.ToString("MMM d, yyyy")</span>
|
|
<form method="post" style="display:inline;">
|
|
@Html.AntiForgeryToken()
|
|
<input type="hidden" name="MediaId" value="@media.Id" />
|
|
<button type="submit" class="btn-delete" onclick="return confirm('Are you sure you want to delete this image?');" asp-page-handler="Delete">Delete</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
}
|
|
</div>
|
|
<div id="loading" style="display:none; text-align:center; padding:20px;">
|
|
Loading more images...
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Selection Action Bar -->
|
|
<div id="selection-bar" class="selection-bar" style="display: none;">
|
|
<div class="selection-info">
|
|
<span id="selection-count">0 images selected</span>
|
|
<button type="button" class="btn btn-link" id="select-all-btn">Select All</button>
|
|
<button type="button" class="btn btn-link" id="deselect-all-btn">Deselect All</button>
|
|
</div>
|
|
<div class="selection-actions">
|
|
<button type="button" class="btn btn-primary" id="move-here-btn">Move Here</button>
|
|
<button type="button" class="btn btn-secondary" id="cancel-selection-btn">Cancel</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Share Folder Modal -->
|
|
<div id="share-modal" class="modal" style="display: none;">
|
|
<div class="modal-backdrop" onclick="closeShareModal()"></div>
|
|
<div class="modal-dialog">
|
|
<div class="modal-header">
|
|
<h3>Share Folder: <span id="share-folder-name"></span></h3>
|
|
<button type="button" class="modal-close" onclick="closeShareModal()">×</button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="form-group">
|
|
<label for="user-search">Search users by email or username</label>
|
|
<input type="text" id="user-search" class="form-control" placeholder="Type to search..." />
|
|
<div id="user-search-results" class="search-results"></div>
|
|
</div>
|
|
<div class="shared-users-section">
|
|
<h4>Shared with:</h4>
|
|
<div id="shared-users-list" class="shared-users-list">
|
|
<p class="text-muted">Loading...</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Floating Add Files Button (hidden in shared folders) -->
|
|
@if (!Model.IsSharedFolder)
|
|
{
|
|
<button type="button" class="floating-add-btn" id="add-files-btn" title="Add Files">
|
|
<span class="btn-icon">+</span>
|
|
</button>
|
|
}
|
|
|
|
@section Scripts {
|
|
<script>
|
|
const currentFolderId = @(Model.CurrentFolderId?.ToString() ?? "null");
|
|
const isSharedFolder = @(Model.IsSharedFolder.ToString().ToLower());
|
|
</script>
|
|
<script src="~/js/gallery.js" asp-append-version="true"></script>
|
|
<script src="~/js/upload.js" asp-append-version="true"></script>
|
|
<script src="~/js/folders.js" asp-append-version="true"></script>
|
|
<script src="~/js/folder-sharing.js" asp-append-version="true"></script>
|
|
<script src="~/js/drag-drop.js" asp-append-version="true"></script>
|
|
<script src="~/js/context-menu.js" asp-append-version="true"></script>
|
|
}
|