- 100%
+
diff --git a/app/components/media_asset_component/media_asset_component.scss b/app/components/media_asset_component/media_asset_component.scss
index 067066dc4..dcaa5ad90 100644
--- a/app/components/media_asset_component/media_asset_component.scss
+++ b/app/components/media_asset_component/media_asset_component.scss
@@ -1,11 +1,41 @@
-.media-asset-component.fit-screen img, .media-asset-component.fit-screen video {
- max-width: 100%;
- max-height: 90vh;
- width: auto;
- height: auto;
+.media-asset-component:not(:hover) .media-asset-zoom-level {
+ opacity: 0;
}
.media-asset-zoom-level {
color: var(--preview-icon-color);
background: var(--preview-icon-background);
}
+
+.media-asset-container {
+ &:not(.media-asset-container-fit-height) .paginator {
+ position: sticky;
+ }
+
+ &:hover {
+ .paginator-prev, .paginator-next {
+ opacity: 0.8;
+ }
+ }
+
+ .paginator-prev, .paginator-next {
+ opacity: 0;
+ width: 48px;
+ height: 96px;
+ top: calc((100vh - var(--header-visible-height) - 96px) / 2);
+ transition: opacity 0.125s, background-color 0.125s;
+
+ color: var(--asset-paginator-link-color);
+ background-color: var(--asset-paginator-background-color);
+
+ &:hover {
+ color: var(--asset-paginator-link-hover-color);
+ background-color: var(--asset-paginator-background-hover-color);
+ }
+ }
+
+ &.media-asset-container-fit-height {
+ max-height: calc(100vh - var(--header-visible-height));
+ justify-content: center;
+ }
+}
diff --git a/app/javascript/src/javascripts/media_asset_component.js b/app/javascript/src/javascripts/media_asset_component.js
index 3abec25e7..97ff2a6f0 100644
--- a/app/javascript/src/javascripts/media_asset_component.js
+++ b/app/javascript/src/javascripts/media_asset_component.js
@@ -1,47 +1,72 @@
export default class MediaAssetComponent {
static initialize() {
- $(".media-asset-component").toArray().forEach(element => {
+ $(".media-asset-container").toArray().forEach(element => {
new MediaAssetComponent(element);
});
}
constructor(element) {
- this.$component = $(element);
+ this.$container = $(element);
+ this.$component = this.$container.find(".media-asset-component");
+
+ if (this.$container.attr("data-dynamic-height") === "true") {
+ this.updateHeight();
+ $(window).on("scroll.danbooru", element => {
+ this.updateHeight();
+ });
+ }
if (this.$image.length) {
this.$image.on("click.danbooru", e => this.toggleFit());
+ this.$image.on("load.danbooru", e => this.updateZoom());
+ this.$image.on("load.danbooru", e => this.updateHeight());
new ResizeObserver(() => this.updateZoom()).observe(this.$image.get(0));
this.updateZoom();
}
}
toggleFit() {
- this.$component.toggleClass("fit-screen");
+ if (this.canZoom) {
+ this.$container.toggleClass("media-asset-container-fit-height");
+ }
+
this.updateZoom();
}
updateZoom() {
this.$image.removeClass("cursor-zoom-in cursor-zoom-out");
- this.$zoomLevel.addClass("hidden").text(`${Math.round(100 * this.zoomLevel)}%`);
+ this.$zoomLevel.removeClass("hidden").text(`${Math.round(100 * this.zoomLevel)}%`);
- if (this.isDownscaled) {
- this.$image.addClass("cursor-zoom-out");
- this.$zoomLevel.removeClass("hidden");
- } else if (this.isTooBig) {
+ if (this.canZoomIn) {
this.$image.addClass("cursor-zoom-in");
+ } else if (this.canZoomOut) {
+ this.$image.addClass("cursor-zoom-out");
}
}
+ updateHeight() {
+ // XXX 115 = header height (hardcoded to prevent height glitches as page loads)
+ this.$container.css("--header-visible-height", Math.min(115, Math.max(0, this.$container.offset().top - $(window).scrollTop())) + "px");
+ }
+
get zoomLevel() {
return this.$image.width() / Number(this.$image.attr("width"));
}
- get isDownscaled() {
- return this.$image.width() < Number(this.$image.attr("width"));
+ get canZoom() {
+ return this.canZoomIn || this.canZoomOut;
}
- get isTooBig() {
- return this.$image.width() > this.$component.width();
+ get canZoomIn() {
+ return !this.isZoomed && this.$image.height() < this.$image.get(0).naturalHeight && Math.round(this.$image.width()) < Math.round(this.$container.width());
+ }
+
+ get canZoomOut() {
+ return this.isZoomed;
+ }
+
+ get isZoomed() {
+ return !this.$container.is(".media-asset-container-fit-height");
}
get $image() {
diff --git a/app/javascript/src/styles/base/040_colors.scss b/app/javascript/src/styles/base/040_colors.scss
index 5e474c343..e6b649e98 100644
--- a/app/javascript/src/styles/base/040_colors.scss
+++ b/app/javascript/src/styles/base/040_colors.scss
@@ -116,6 +116,9 @@ html, body[data-current-user-theme="light"] {
--default-border-color: var(--grey-1);
+ --success-color: var(--green-5);
+ --error-color: var(--red-5);
+
--error-background-color: var(--red-1);
--success-background-color: var(--green-0);
--target-background: var(--yellow-0);
@@ -287,6 +290,11 @@ html, body[data-current-user-theme="light"] {
--paginator-arrow-background-color: var(--inverse-text-color);
--paginator-arrow-color: var(--link-color);
+ --asset-paginator-link-color: var(--link-color);
+ --asset-paginator-link-hover-color: var(--link-color);
+ --asset-paginator-background-color: var(--white);
+ --asset-paginator-background-hover-color: var(--blue-0);
+
--artist-tag-color: var(--red-6);
--artist-tag-hover-color: var(--red-5);
--copyright-tag-color: var(--magenta-6);
@@ -334,6 +342,9 @@ html, body[data-current-user-theme="light"] {
--link-color: var(--azure-4);
--link-hover-color: var(--azure-3);
+ --success-color: var(--green-3);
+ --error-color: var(--red-3);
+
--default-border-color: var(--grey-7);
--error-background-color: var(--red-9);
@@ -494,6 +505,11 @@ html, body[data-current-user-theme="light"] {
--paginator-arrow-background-color: var(--grey-0);
--paginator-arrow-color: var(--link-color);
+ --asset-paginator-link-color: var(--white);
+ --asset-paginator-link-hover-color: var(--white);
+ --asset-paginator-background-color: var(--grey-9);
+ --asset-paginator-background-hover-color: var(--grey-8);
+
--artist-tag-color: var(--red-3);
--artist-tag-hover-color: var(--red-2);
--copyright-tag-color: var(--purple-3);
diff --git a/app/javascript/src/styles/common/utilities.scss b/app/javascript/src/styles/common/utilities.scss
index 8e236eed1..47ccd3079 100644
--- a/app/javascript/src/styles/common/utilities.scss
+++ b/app/javascript/src/styles/common/utilities.scss
@@ -46,6 +46,7 @@ $spacer: 0.25rem; /* 4px */
}
.overflow-auto { overflow: auto; }
+.overflow-hidden { overflow: hidden; }
.break-all { word-break: break-all; }
.whitespace-nowrap { white-space: nowrap; }
@@ -62,11 +63,21 @@ $spacer: 0.25rem; /* 4px */
.relative { position: relative; }
.sticky { position: sticky; }
+.top-0 { top: 0; }
+.bottom-0 { bottom: 0; }
+.left-0 { left: 0; }
+.right-0 { right: 0; }
+
.top-0\.5 { top: 0.5 * $spacer; }
.bottom-0\.5 { bottom: 0.5 * $spacer; }
.left-0\.5 { left: 0.5 * $spacer; }
.right-0\.5 { right: 0.5 * $spacer; }
+.top-4 { top: 4 * $spacer; }
+.bottom-4 { bottom: 4 * $spacer; }
+.left-4 { left: 4 * $spacer; }
+.right-4 { right: 4 * $spacer; }
+
.inset-0 { top: 0; right: 0; bottom: 0; left: 0 }
.border, %border { border-width: 1px; }
@@ -138,6 +149,7 @@ $spacer: 0.25rem; /* 4px */
.w-auto { width: auto; }
.w-min { width: min-content; }
.w-max { width: max-content; }
+.w-fit { width: fit-content; }
.w-sm { width: 24rem; }
.w-md { width: 28rem; }
.w-1\/4 { width: 25%; }
@@ -149,15 +161,20 @@ $spacer: 0.25rem; /* 4px */
.w-225px { width: 225px; }
.w-270px { width: 270px; }
.w-360px { width: 360px; }
+.w-600px { width: 600px; }
+
+.min-w-0 { min-width: 0; }
.max-w-full { max-width: 100%; }
.max-h-full { max-height: 100%; }
.h-auto { height: auto; }
.h-inherit { height: inherit; }
+.h-fit { height: fit-content; }
.h-1 { height: 1 * $spacer; }
.h-3 { height: 3 * $spacer; }
.h-4 { height: 4 * $spacer; }
+.h-6 { height: 6 * $spacer; }
.h-8 { height: 8 * $spacer; }
.h-10 { height: 10 * $spacer; }
.h-12 { height: 12 * $spacer; }
@@ -176,6 +193,7 @@ $spacer: 0.25rem; /* 4px */
.max-h-360px { max-height: 360px; }
.max-h-720px { max-height: 720px; }
.max-h-screen { max-height: 100vh; }
+.max-h-inherit { max-height: inherit; }
.space-x-1 > * + * { margin-left: 1 * $spacer; }
.space-x-2 > * + * { margin-left: 2 * $spacer; }
@@ -195,6 +213,7 @@ $spacer: 0.25rem; /* 4px */
.flex-1 { flex: 1 1 0%; }
.flex-auto { flex: 1 1 auto; }
.flex-initial { flex: 0 1 auto; }
+.flex-none { flex: none; }
.flex-grow-1 { flex-grow: 1; }
.flex-col { flex-direction: column; }
.flex-wrap { flex-wrap: wrap; }
@@ -212,6 +231,7 @@ $spacer: 0.25rem; /* 4px */
.self-start { align-self: flex-start; }
.self-center { align-self: center; }
.self-stretch { align-self: stretch; }
+.self-end { align-self: flex-end; }
.float-right { float: right; }
@@ -223,8 +243,19 @@ $spacer: 0.25rem; /* 4px */
.grid-cols-8 { grid-template-columns: repeat(8, minmax(0, 1fr)); }
.grid-cols-12 { grid-template-columns: repeat(12, minmax(0, 1fr)); }
+.z-0 { z-index: 0; }
+.z-10 { z-index: 10; }
+.z-20 { z-index: 20; }
+
.link-color { color: var(--link-color); }
+.text-success { color: var(--success-color); }
+.text-error { color: var(--error-color); }
+
+.transition-opacity {
+ transition: opacity 0.15s ease;
+}
+
.card {
@extend %border;
@extend %rounded-lg;
@@ -232,10 +263,9 @@ $spacer: 0.25rem; /* 4px */
}
.thin-scrollbar {
- overflow-x: hidden;
- overflow-y: auto;
+ overflow: auto;
padding-right: 2 * $spacer;
- overscroll-behavior: contain; // https://caniuse.com/css-overscroll-behavior
+ overscroll-behavior-x: contain; // https://caniuse.com/css-overscroll-behavior
// Firefox only
// https://caniuse.com/?search=scrollbar-width
@@ -304,8 +334,11 @@ $spacer: 0.25rem; /* 4px */
.md\:block { display: block; }
.md\:flex { display: flex; }
.md\:grid { display: grid; }
+ .md\:sticky { position: sticky; }
.md\:space-x-4 > * + * { margin-left: 4 * $spacer; }
.md\:space-x-8 > * + * { margin-left: 8 * $spacer; }
.md\:space-y-0 > * + * { margin-top: 0; }
+
+ .md\:w-360px { width: 360px; }
}
diff --git a/app/views/media_assets/show.html.erb b/app/views/media_assets/show.html.erb
index 98a7a6516..12bbb39fa 100644
--- a/app/views/media_assets/show.html.erb
+++ b/app/views/media_assets/show.html.erb
@@ -1,33 +1,112 @@