diff options
Diffstat (limited to 'Pages')
| -rw-r--r-- | Pages/Component/Dialog.razor.css | 2 | ||||
| -rw-r--r-- | Pages/Component/MediaTagTable.razor.css | 8 | ||||
| -rw-r--r-- | Pages/Component/MobileMenu.razor | 32 | ||||
| -rw-r--r-- | Pages/Component/MobileMenu.razor.css | 46 | ||||
| -rw-r--r-- | Pages/Component/TabContainer.razor.css | 14 | ||||
| -rw-r--r-- | Pages/Component/TagSelectDialog.razor.css | 6 | ||||
| -rw-r--r-- | Pages/Component/Titlebar.razor | 29 | ||||
| -rw-r--r-- | Pages/Component/Titlebar.razor.css | 28 | ||||
| -rw-r--r-- | Pages/Gallery.razor.css | 7 | ||||
| -rw-r--r-- | Pages/TagDefinitions.razor.css | 5 | ||||
| -rw-r--r-- | Pages/Upload.razor | 2 | ||||
| -rw-r--r-- | Pages/Upload.razor.css | 25 | ||||
| -rw-r--r-- | Pages/ViewMedia.razor | 204 | ||||
| -rw-r--r-- | Pages/ViewMedia.razor.css | 134 | ||||
| -rw-r--r-- | Pages/_Host.cshtml | 4 |
15 files changed, 403 insertions, 143 deletions
diff --git a/Pages/Component/Dialog.razor.css b/Pages/Component/Dialog.razor.css index 1447407..93680c5 100644 --- a/Pages/Component/Dialog.razor.css +++ b/Pages/Component/Dialog.razor.css @@ -10,7 +10,7 @@ top: 50%; transform: translate(-50%, -50%); transition: visibility 0.1s, opacity 0.1s linear; - width: 450px; + width: min(450px, 100%); z-index: 1000; } diff --git a/Pages/Component/MediaTagTable.razor.css b/Pages/Component/MediaTagTable.razor.css index dcf5e09..4dedb3f 100644 --- a/Pages/Component/MediaTagTable.razor.css +++ b/Pages/Component/MediaTagTable.razor.css @@ -1,3 +1,9 @@ -td { +th, td { font-size: 8pt; } + +@media (hover: none) and (pointer: coarse) { + th, td { + font-size: 7pt; + } +} diff --git a/Pages/Component/MobileMenu.razor b/Pages/Component/MobileMenu.razor new file mode 100644 index 0000000..6cb3281 --- /dev/null +++ b/Pages/Component/MobileMenu.razor @@ -0,0 +1,32 @@ +@inject NavigationManager navigationManager +@inject IJSRuntime jsRuntime +@implements IDisposable + +<div id="mobile-menu" class="hidden"> + <a href="/">Home</a> + <a href="/TagDefinitions">Tags</a> + <a href="/Gallery?ingest=true">Ingest</a> + <a href="/Upload">Upload</a> + <div id="nsfw-switch"> + <p id="nsfw-label">NSFW</p> + <NsfwSwitch/> + </div> + <a href="javascript:logout();">Logout</a> +</div> + +<script suppress-error="BL9992"> + function hideMobileMenu() { + document.getElementById('mobile-menu').classList.add('hidden'); + } +</script> + +@code { + protected override void OnInitialized() => + navigationManager.LocationChanged += LocationChanged; + + public async void LocationChanged(object? sender, LocationChangedEventArgs e) => + await jsRuntime.InvokeVoidAsync("hideMobileMenu"); + + public void Dispose() => + navigationManager.LocationChanged -= LocationChanged; +} diff --git a/Pages/Component/MobileMenu.razor.css b/Pages/Component/MobileMenu.razor.css new file mode 100644 index 0000000..b60e07b --- /dev/null +++ b/Pages/Component/MobileMenu.razor.css @@ -0,0 +1,46 @@ +div#mobile-menu { + background: var(--col-bg); + display: flex; + flex-direction: column; + flex: 1 1 calc(100vh - 59px); + height: 100%; + overflow-y: auto; + position: relative; + width: 100%; +} + +div#mobile-menu.hidden { + display: none; +} + +div#mobile-menu > a { + color: #fff; + padding: 20px; +} + +div#mobile-menu > a:not(:last-of-type) { + border-bottom: 1px solid var(--col-hr); +} + +div#mobile-menu > a:hover { + background: var(--col-dialog-bg); + filter: none; +} + +div#mobile-menu > a:active { + background: #fff; + color: var(--col-bg); + filter: none; +} + +div#nsfw-switch { + align-items: center; + border-bottom: 1px solid var(--col-hr); + display: flex; + flex-direction: row; + padding: 5px 20px 5px 20px; +} + +div#nsfw-switch > p#nsfw-label { + margin-right: auto; +} diff --git a/Pages/Component/TabContainer.razor.css b/Pages/Component/TabContainer.razor.css index 6a56021..bfb5694 100644 --- a/Pages/Component/TabContainer.razor.css +++ b/Pages/Component/TabContainer.razor.css @@ -13,7 +13,15 @@ div.tabs > a.selected { padding-bottom: 5px; } -div.tabs > a:hover { - background: rgba(255, 255, 255, 0.4); - filter: none; +@media (hover: hover) { + div.tabs > a:hover { + background: rgba(255, 255, 255, 0.4); + filter: none; + } +} + +@media (hover: none) and (pointer: coarse) { + div.tabs > a { + font-size: 8pt; + } } diff --git a/Pages/Component/TagSelectDialog.razor.css b/Pages/Component/TagSelectDialog.razor.css index 7b50077..dadd0c4 100644 --- a/Pages/Component/TagSelectDialog.razor.css +++ b/Pages/Component/TagSelectDialog.razor.css @@ -14,8 +14,10 @@ div.tag-definitions label { transition: background 0.1s linear; } -div.tag-definitions label:hover { - background: #777; +@media(hover: hover) { + div.tag-definitions label:hover { + background: #777; + } } div.tag-definitions input:checked + label { diff --git a/Pages/Component/Titlebar.razor b/Pages/Component/Titlebar.razor index 8033413..a0b9eec 100644 --- a/Pages/Component/Titlebar.razor +++ b/Pages/Component/Titlebar.razor @@ -43,20 +43,23 @@ <AuthorizeView> <Authorized> <div id="navbar"> - <a href="/">Home</a> - <a href="/TagDefinitions">Tags</a> - <a href="/Gallery?ingest=true">Ingest</a> - <a href="/Upload">Upload</a> - <a href="javascript:;" @onclick=@(() => aboutDialog.Show())>About</a> + <p class="mobile">HyperBooru</p> + <a class="mobile menu-button" href="javascript:toggleMobileMenu();">☰</a> - <p id="nsfw-label">NSFW</p> - <div id="nsfw-switch"> - <NsfwSwitch/> - </div> - <form action="/Gallery" method="get"> - <input type="text" name="q" placeholder="Search"/> - </form> - <a href="javascript:logout();">Logout</a> + <a class="desktop" href="/">Home</a> + <a class="desktop" href="/TagDefinitions">Tags</a> + <a class="desktop" href="/Gallery?ingest=true">Ingest</a> + <a class="desktop" href="/Upload">Upload</a> + <a class="desktop" href="javascript:;" @onclick=@(() => aboutDialog.Show())>About</a> + + <p class="desktop" id="nsfw-label">NSFW</p> + <div id="nsfw-switch" class="desktop"> + <NsfwSwitch/> + </div> + <form action="/Gallery" method="get" class="desktop"> + <input type="text" name="q" placeholder="Search"/> + </form> + <a class="desktop" href="javascript:logout();">Logout</a> </div> <AboutDialog @ref=aboutDialog/> </Authorized> diff --git a/Pages/Component/Titlebar.razor.css b/Pages/Component/Titlebar.razor.css index ea10740..58a1c0c 100644 --- a/Pages/Component/Titlebar.razor.css +++ b/Pages/Component/Titlebar.razor.css @@ -11,17 +11,20 @@ div#navbar > h2 { margin-left: 20px; } -div#navbar > a { +div#navbar > a, div#navbar > p { align-items: center; color: white; display: flex; height: 100%; padding: 0 20px 0 20px; + user-select: none; } -div#navbar > a:hover { - background: rgba(255, 255, 255, 0.4); - filter: none; +@media (hover: hover) and (pointer: fine) { + div#navbar > a:hover { + background: rgba(255, 255, 255, 0.4); + filter: none; + } } div#navbar > a:active { @@ -29,6 +32,11 @@ div#navbar > a:active { color: var(--col-navbar-bg); } +div#navbar > a.menu-button { + font-size: 18pt; + margin-left: auto; +} + p#nsfw-label { align-self: center; font-size: 9pt; @@ -77,3 +85,15 @@ input[type="text"], input[type="password"] { input[type="password"] { margin-left: 20px; } + +@media (hover: none) and (pointer: coarse) { + .desktop { + display: none !important; + } +} + +@media (hover: hover) and (pointer: fine) { + .mobile { + display: none !important; + } +} diff --git a/Pages/Gallery.razor.css b/Pages/Gallery.razor.css index 989e252..1b5ed86 100644 --- a/Pages/Gallery.razor.css +++ b/Pages/Gallery.razor.css @@ -4,8 +4,9 @@ } div#feed-error { - position: relative; - top: 50%; - left: 50%; + left: 50%; + padding: 10px; + position: relative; + top: 50%; transform: translate(-50%, -50%); }
\ No newline at end of file diff --git a/Pages/TagDefinitions.razor.css b/Pages/TagDefinitions.razor.css new file mode 100644 index 0000000..409eacc --- /dev/null +++ b/Pages/TagDefinitions.razor.css @@ -0,0 +1,5 @@ +@media (hover: none) and (pointer: coarse) { + td, th { + font-size: 6pt; + } +}
\ No newline at end of file diff --git a/Pages/Upload.razor b/Pages/Upload.razor index 614cec0..6d6e8bc 100644 --- a/Pages/Upload.razor +++ b/Pages/Upload.razor @@ -2,7 +2,7 @@ @attribute [Authorize] <div id="dropzone"> - <p>Drag a file to upload it<br/>or click to select one or more file(s)</p> + <p></p> <form id="uploadForm" action="/media" method="post" enctype="multipart/form-data"> <input type="file" id="fileUpload" name="fileUpload" accept="image/*,video/*" multiple/> </form> diff --git a/Pages/Upload.razor.css b/Pages/Upload.razor.css index 6ff40a2..d510bc6 100644 --- a/Pages/Upload.razor.css +++ b/Pages/Upload.razor.css @@ -8,7 +8,7 @@ top: 50%; transform: translate(-50%, -50%); transition: border-color 0.1s linear; - width: 700px; + width: min(700px, 85%); } div#dropzone p { @@ -22,14 +22,27 @@ div#dropzone p { transform: translate(-50%, -50%); } +div#dropzone p::before { + content: "Drag a file to upload it\Aor click to select one or more file(s)"; + white-space: pre; +} + +@media (hover: none) and (pointer: coarse) { + div#dropzone p::before { + content: "Tap to select a file to upload"; + } +} + div#dropzone input { display: none; } -div#dropzone.hover, div#dropzone:hover { - border: 3px dashed white; -} +@media (hover: hover) { + div#dropzone.hover, div#dropzone:hover { + border: 3px dashed white; + } -div#dropzone.hover p, div#dropzone:hover p { - color: white; + div#dropzone.hover p, div#dropzone:hover p { + color: white; + } }
\ No newline at end of file diff --git a/Pages/ViewMedia.razor b/Pages/ViewMedia.razor index b5a33a2..c6ff2ce 100644 --- a/Pages/ViewMedia.razor +++ b/Pages/ViewMedia.razor @@ -11,105 +11,117 @@ <script suppress-warning="BL9992"> function toggleSidebar() { - document.getElementById("metadata").classList.toggle("hidden"); + document.getElementById("hcontainer").classList.toggle("hide-metadata"); } + + function showSidebar(visible) { + document.getElementById("hcontainer").classList.toggle("hide-metadata", !visible) + } </script> -<div id="content"> - <div id="image-container"> - <img - src="/media/@(media.Guid)" - width=@media.CurrentUploadedFile.Width - height=@media.CurrentUploadedFile.Height - onclick="toggleSidebar()"/> - </div> - <div id="metadata"> - <div id="metadata-container"> - <div id="metadata-fileinfo"> - @if(infoEditMode) { - <form action="javascript:;" @onsubmit=@(() => ApplyInfoEdit(true))> - <table id="edit-metadata"> - <tr> - <td>Title:</td> - <td><input type="text" @bind=shortDescription @ref=shortDescriptionInput/></td> - </tr> - <tr> - <td>Description:</td> - <td><textarea rows="4" @bind=longDescription/></td> - </tr> - </table> - </form> - } else { - <p>Title: <i>@(media.ShortDescription ?? "None")</i></p> - <p class="newlines">Description:<br/><i>@(media.LongDescription ?? "None")</i></p> - } - <p>Resolution: @(media.CurrentUploadedFile.Width)x@(media.CurrentUploadedFile.Height)</p> - <p class="heading">Upload history</p> - <hr/> - <table id="uploaded-files" class="data-table"> - <tr> - <th>Created On</th> - <th>Last Write</th> - <th>Uploaded On</th> - <th>Filename</th> - <th>Size</th> - <th>Original Checksum</th> - </tr> - @foreach(var file in media.UploadedFiles.OrderByDescending(uf => uf.UploadTime)) { - string? sourceUrl = null; - if(file.Filename is not null) - sourceUrl = sourceService.GetUrlFromFilename(file.Filename); - <tr> - <td title=@file.CreateTime?.ToString()> - @(file.CreateTime?.ToString("d") ?? "N/A") - </td> - <td title=@file.LastWriteTime?.ToString()> - @(file.LastWriteTime?.ToString("d") ?? "N/A") - </td> - <td title=@file.UploadTime>@(file.UploadTime.ToString("d"))</td> - <td title=@(file.Path is not null ? $"{file.Path.Replace('\\', '/')}/{file.Filename}" : file.Filename)> - @if(sourceUrl is not null) { - <a class="nondecorated" target="_blank" href=@sourceUrl>@file.Filename</a> - } else { - @file.Filename - } - </td> - <td title=@file.Length>@file.Length.ToBytesSI()</td> - <td - title=@(file.Checksum + (file.ChecksumVerified ? " (verified)" : "")) - class=@(file.ChecksumVerified ? "verified" : null)> - - @file.Checksum.Substring(0, 8) - </td> - </tr> - } - </table> - </div> - <div id="metadata-tags"> - <p class="heading">Tags</p> - <hr/> - <MediaTagTable Media=media @ref=mediaTagTable/> - </div> - </div> - <div id="button-container"> - <ButtonContainer> - <button @onclick=@(() => deleteDialog.Show()) class="warning" data-keyboard-shortcut="d"><u>D</u>elete</button> - <button @onclick=@(() => tagDialog.Show()) class="secondary" data-keyboard-shortcut="t">Add <u>T</u>ag</button> - <button @onclick=@(() => ocrDialog.Show()) class="secondary" data-keyboard-shortcut="o">View <u>O</u>CR</button> - @if(infoEditMode) { - <button @onclick=@(() => ApplyInfoEdit(false)) class="secondary">Cancel</button> - <button @onclick=@(() => ApplyInfoEdit(true))>Apply</button> - } else { - <button @onclick=@(() => InfoEditMode = true) class="secondary" data-keyboard-shortcut="e"><u>E</u>dit Info</button> - } - @if(media.IsIngest) { - <button @onclick=@(() => SetIngest(false)) data-keyboard-shortcut="c">Mark Tagging <u>C</u>omplete</button> - } else { - <button class="secondary" @onclick=@(() => SetIngest(true)) data-keyboard-shortcut="c">Mark Tagging In<u>c</u>omplete</button> - } - </ButtonContainer> - </div> - </div> +<div id="vcontainer"> + <div id="hcontainer" class="hide-metadata"> + <div id="image-container"> + <img + src="/media/@(media.Guid)" + width=@media.CurrentUploadedFile.Width + height=@media.CurrentUploadedFile.Height/> + </div> + <div id="metadata-show-button"> + <a href="javascript:toggleSidebar();"></a> + </div> + <div id="metadata"> + <div id="metadata-container"> + <div id="metadata-fileinfo"> + @if(infoEditMode) { + <form action="javascript:;" @onsubmit=@(() => ApplyInfoEdit(true))> + <table id="edit-metadata"> + <tr> + <td>Title:</td> + <td><input type="text" @bind=shortDescription @ref=shortDescriptionInput/></td> + </tr> + <tr> + <td>Description:</td> + <td><textarea rows="4" @bind=longDescription/></td> + </tr> + </table> + </form> + } else { + <p>Title: <i>@(media.ShortDescription ?? "None")</i></p> + <p class="newlines">Description:<br/><i>@(media.LongDescription ?? "None")</i></p> + } + <p>Resolution: @(media.CurrentUploadedFile.Width)x@(media.CurrentUploadedFile.Height)</p> + <p class="heading">Upload history</p> + <hr/> + <table id="uploaded-files" class="data-table"> + <tr> + <th>Created On</th> + <th>Last Write</th> + <th>Uploaded On</th> + <th>Filename</th> + <th>Size</th> + <th>Original Checksum</th> + </tr> + @foreach(var file in media.UploadedFiles.OrderByDescending(uf => uf.UploadTime)) { + string? sourceUrl = null; + if(file.Filename is not null) + sourceUrl = sourceService.GetUrlFromFilename(file.Filename); + <tr> + <td title=@file.CreateTime?.ToString()> + @(file.CreateTime?.ToString("d") ?? "N/A") + </td> + <td title=@file.LastWriteTime?.ToString()> + @(file.LastWriteTime?.ToString("d") ?? "N/A") + </td> + <td title=@file.UploadTime>@(file.UploadTime.ToString("d"))</td> + <td title=@(file.Path is not null ? $"{file.Path.Replace('\\', '/')}/{file.Filename}" : file.Filename)> + @if(sourceUrl is not null) { + <a class="nondecorated" target="_blank" href=@sourceUrl>@file.Filename</a> + } else { + @file.Filename + } + </td> + <td title=@file.Length>@file.Length.ToBytesSI()</td> + <td + title=@(file.Checksum + (file.ChecksumVerified ? " (verified)" : "")) + class=@(file.ChecksumVerified ? "verified" : null)> + + @file.Checksum.Substring(0, 8) + </td> + </tr> + } + </table> + </div> + <div id="metadata-tags"> + <p class="heading">Tags</p> + <hr/> + <MediaTagTable Media=media @ref=mediaTagTable/> + </div> + </div> + <div id="button-container"> + <ButtonContainer> + <button @onclick=@(() => deleteDialog.Show()) class="warning" data-keyboard-shortcut="d"><u>D</u>elete</button> + <button @onclick=@(() => tagDialog.Show()) class="secondary" data-keyboard-shortcut="t">Add <u>T</u>ag</button> + <button @onclick=@(() => ocrDialog.Show()) class="secondary" data-keyboard-shortcut="o">View <u>O</u>CR</button> + @if(infoEditMode) { + <button @onclick=@(() => ApplyInfoEdit(false)) class="secondary">Cancel</button> + <button @onclick=@(() => ApplyInfoEdit(true))>Apply</button> + } else { + <button @onclick=@(() => InfoEditMode = true) class="secondary" data-keyboard-shortcut="e"><u>E</u>dit Info</button> + } + @if(media.IsIngest) { + <button @onclick=@(() => SetIngest(false)) data-keyboard-shortcut="c">Mark Tagging <u>C</u>omplete</button> + } else { + <button class="secondary" @onclick=@(() => SetIngest(true)) data-keyboard-shortcut="c">Mark Tagging In<u>c</u>omplete</button> + } + </ButtonContainer> + </div> + </div> + </div> + <div id="bottom-bar"> + <a href="javascript:showSidebar(false);">🖼</a> + <a href="javascript:showSidebar(true);">🛈</a> + </div> </div> <Dialog Title="Delete this media?" @ref=deleteDialog> diff --git a/Pages/ViewMedia.razor.css b/Pages/ViewMedia.razor.css index 53d5eca..d5bac3e 100644 --- a/Pages/ViewMedia.razor.css +++ b/Pages/ViewMedia.razor.css @@ -1,7 +1,19 @@ -div#content { - display: flex; - align-items: start; - height: 100%; +div#vcontainer { + align-items: start; + display: flex; + flex-direction: column; + height: 100%; + overflow: hidden; + width: 100%; +} + +div#hcontainer { + align-items: start; + display: flex; + flex-direction: row; + height: 100%; + overflow: hidden; + width: 100%; } div#image-container { @@ -23,9 +35,50 @@ div#image-container > img { transform: translate(-50%, -50%); } +div#metadata-show-button { + display: flex; + flex-direction: column; + height: 100%; + justify-content: center; + user-select: none; + width: 20px; +} + +div#metadata-show-button > a::before { + content: "\25B6"; +} + +div#hcontainer.hide-metadata > div#metadata-show-button > a::before { + content: "\25C0" !important; +} + +@media (hover: none) and (pointer: coarse) { + div#metadata-show-button { + display: none !important; + } +} + +div#metadata-show-button > a { + /* TODO: Use colours from global.css */ + background: #333; + border-radius: 10px 0 0 10px; + color: #fff; + display: block; + padding: 15px 0 15px 0; + text-align: center; +} + +div#metadata-show-button > a:hover { + filter: brightness(1.5); +} + +div#metadata-show-button > a:active { + background: #fff; +} + div#metadata { background: #333; - box-shadow: rgba(0, 0, 0, 0.5) -10px 0px 10px; + box-shadow: rgba(0, 0, 0, 0.25) -10px 0px 10px; box-sizing: border-box; display: flex; flex-direction: column; @@ -38,15 +91,28 @@ div#metadata { z-index: 90; } -div#metadata.hidden { - box-shadow: none; - margin-right: -700px; +@media (hover: hover) and (pointer: fine) { + div#hcontainer.hide-metadata > div#metadata { + box-shadow: none; + margin-right: -700px; + } } -@media (max-aspect-ratio: 4/3) { +@media (hover: none) and (pointer: coarse) { + div#image-container { + display: none; + } + div#metadata { - box-shadow: none; - margin-right: -700px; + width: 100%; + } + + div#hcontainer.hide-metadata > div#image-container { + display: initial; + } + + div#hcontainer.hide-metadata > div#metadata { + display: none; } } @@ -54,6 +120,12 @@ div#button-container { margin-top: auto; } +@media (hover: none) and (pointer: coarse) { + div#button-container button { + font-size: 8pt; + } +} + div#metadata-container { overflow-x: hidden; overflow-y: auto; @@ -93,12 +165,19 @@ table#uploaded-files th { table#uploaded-files td { font-family: 'Lucida Console'; - font-size: 8pt; + font-size: 7pt; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +@media (hover: none) and (pointer: coarse) { + table#uploaded-files th, + table#uploaded-files td { + font-size: 6pt; + } +} + table#uploaded-files td:nth-child(4) { max-width: 170px; } @@ -114,3 +193,34 @@ p.heading { p.newlines { white-space: pre-line; } + +div#bottom-bar { + /* TODO: Use colours from global.css */ + align-items: center; + background: #141414; + box-shadow: rgba(0, 0, 0, 0.25) 0px -5px 5px; + display: none; + flex-direction: row; + width: 100%; +} + +@media (hover: none) and (pointer: coarse) { + div#bottom-bar { + display: flex; + } +} + +div#bottom-bar > a { + color: white; + display: block; + font-size: 18pt; + margin: auto; + padding: 7px; + user-select: none; +} + +div#bottom-bar > a:active { + /* TODO: Use colours from global.css */ + background: white; + color: #141414; +} diff --git a/Pages/_Host.cshtml b/Pages/_Host.cshtml index 69bced8..abee742 100644 --- a/Pages/_Host.cshtml +++ b/Pages/_Host.cshtml @@ -7,13 +7,15 @@ <html lang="en"> <head> <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1" /> <base href="~/" /> <link href="css/site.css" rel="stylesheet" /> <link href="/styles/global.css" rel="stylesheet" /> <link href="/favicon.ico" rel="icon" /> <link href="/manifest.webmanifest" rel="manifest" /> - <script type="text/javascript" src="/js/keyboard.js"></script> <script type="text/javascript" src="/js/dialog.js"></script> + <script type="text/javascript" src="/js/keyboard.js"></script> + <script type="text/javascript" src="/js/mobile.js"></script> <component type="typeof(HeadOutlet)" render-mode="ServerPrerendered" /> </head> <body> |
