Skip to content

Commit ff8b25b

Browse files
committed
compare view: Metadata sidebar
Agentic assisted, have caution. Reviewed and patched up with care, seems to be good.
1 parent d5c612d commit ff8b25b

4 files changed

Lines changed: 134 additions & 2 deletions

File tree

src/Pages/_Generate/GenerateTab.cshtml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@
218218
<button class="basic-button translate" data-compare-mode="transparency" type="button">Transparency Overlay</button>
219219
<button class="basic-button translate" data-compare-mode="single" type="button">Single View</button>
220220
<button class="basic-button translate" id="image_compare_swap_button" type="button">Switch Image</button>
221+
<button class="basic-button translate" id="image_compare_metadata_toggle_button" type="button">Toggle Metadata</button>
221222
</div>
222223
</div>
223224
</div>

src/wwwroot/css/genpage.css

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -820,6 +820,8 @@ body {
820820
.image_compare_modal .imageview_modal_imagewrap {
821821
flex: 1 1 auto;
822822
min-height: 0;
823+
display: flex;
824+
align-items: stretch;
823825
}
824826
.image_compare_modal .imageview_popup_modal_undertext {
825827
flex: 0 0 auto;
@@ -856,13 +858,67 @@ body {
856858
background-color: var(--button-background-hover);
857859
border-color: var(--emphasis);
858860
}
861+
.image_compare_metadata {
862+
width: min(42rem, 40vw);
863+
max-width: min(42rem, 40vw);
864+
height: 100%;
865+
overflow: auto;
866+
text-align: left;
867+
flex: 0 0 auto;
868+
padding: 0.25rem;
869+
background-color: var(--background);
870+
border-left: 1px solid var(--light-border);
871+
box-sizing: border-box;
872+
}
873+
.image_compare_metadata_table {
874+
width: 100%;
875+
border-collapse: separate;
876+
border-spacing: 0 0.15rem;
877+
}
878+
.image_compare_metadata_table th, .image_compare_metadata_table td {
879+
padding: 0.15rem 0.35rem;
880+
vertical-align: top;
881+
overflow-wrap: anywhere;
882+
}
883+
.image_compare_metadata_table th {
884+
color: var(--text);
885+
background-color: var(--background-soft);
886+
}
887+
.image_compare_metadata_table .param_view_block {
888+
display: table-row;
889+
width: auto;
890+
}
891+
.image_compare_metadata_table td {
892+
border-top: 1px solid var(--light-border);
893+
border-bottom: 1px solid var(--light-border);
894+
color: inherit;
895+
}
896+
.image_compare_metadata_table td:first-child {
897+
border-left: 1px solid var(--light-border);
898+
border-top-left-radius: 0.3rem;
899+
border-bottom-left-radius: 0.3rem;
900+
min-width: 8rem;
901+
}
902+
.image_compare_metadata_table td:last-child {
903+
border-right: 1px solid var(--light-border);
904+
border-top-right-radius: 0.3rem;
905+
border-bottom-right-radius: 0.3rem;
906+
}
907+
.image_compare_metadata_table .param_view_block_model td {
908+
background-color: color-mix(in srgb, transparent 99%, var(--tag-color));
909+
}
910+
.image_compare_metadata_same {
911+
opacity: 0.45;
912+
}
859913
.image_compare_stage {
860914
width: 100%;
861915
height: 100%;
916+
min-width: 0;
862917
min-height: 0;
863918
overflow: hidden;
864919
padding: 0;
865920
background-color: transparent;
921+
flex: 1 1 auto;
866922
}
867923
.image_compare_stage.image_compare_stage_side {
868924
display: grid;
@@ -987,10 +1043,19 @@ body {
9871043
pointer-events: none;
9881044
}
9891045
@media (max-width: 900px) {
1046+
.image_compare_modal .imageview_modal_imagewrap {
1047+
flex-direction: column;
1048+
}
9901049
.image_compare_stage.image_compare_stage_side {
9911050
grid-template-columns: 1fr;
9921051
grid-template-rows: 1fr 1fr;
9931052
}
1053+
.image_compare_metadata {
1054+
width: 100%;
1055+
max-width: 100%;
1056+
height: 35vh;
1057+
padding-left: 0;
1058+
}
9941059
}
9951060
.browser-folder-tree-container {
9961061
width: 15rem;

src/wwwroot/js/genpage/gentab/currentimagehandler.js

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1408,7 +1408,7 @@ class ImageCompareHelper {
14081408
if (e.target.tagName == 'BODY') {
14091409
return;
14101410
}
1411-
if (!this.noClose && this.isOpen() && !findParentOfClass(e.target, 'imageview_popup_modal_undertext')) {
1411+
if (!this.noClose && this.isOpen() && !findParentOfClass(e.target, 'imageview_popup_modal_undertext') && !findParentOfClass(e.target, 'image_compare_metadata')) {
14121412
this.close();
14131413
e.preventDefault();
14141414
e.stopPropagation();
@@ -1432,6 +1432,7 @@ class ImageCompareHelper {
14321432
this.mode = 'side';
14331433
this.left = null;
14341434
this.right = null;
1435+
this.showMetadata = false;
14351436
this.resetViewportState();
14361437
this.modeButtonMap = {};
14371438
for (let button of this.modal.querySelectorAll('[data-compare-mode]')) {
@@ -1441,6 +1442,8 @@ class ImageCompareHelper {
14411442
}
14421443
this.swapButton = getRequiredElementById('image_compare_swap_button');
14431444
this.swapButton.addEventListener('click', () => this.swapImages());
1445+
this.metadataToggleButton = getRequiredElementById('image_compare_metadata_toggle_button');
1446+
this.metadataToggleButton.addEventListener('click', () => this.toggleMetadataVisibility(!this.showMetadata));
14441447
this.transparencyRow = getRequiredElementById('image_compare_transparency_row');
14451448
this.transparencySlider = getRequiredElementById('image_compare_transparency_slider');
14461449
this.transparencyValue = getRequiredElementById('image_compare_transparency_value');
@@ -1449,6 +1452,9 @@ class ImageCompareHelper {
14491452
this.transparencyValue.innerText = `${Math.round(this.transparencyPercent)}%`;
14501453
this.getOverlay()?.style.setProperty('--image-compare-transparency', `${this.transparencyPercent / 100}`);
14511454
});
1455+
this.metadataDiv = createDiv(null, 'image_compare_metadata current-image-data extras-wrapper-sideblock');
1456+
this.modal.querySelector('.imageview_modal_imagewrap').appendChild(this.metadataDiv);
1457+
this.updateMetadataVisibility();
14521458
this.updateModeControls();
14531459
this.supportedTypes = ['image', 'video'];
14541460
}
@@ -1657,6 +1663,58 @@ class ImageCompareHelper {
16571663
return `<img class="${mediaClass}" src="${encodedSrc}" ${imageAttrs}>`;
16581664
}
16591665

1666+
getMetadataEntryMap(metadata) {
1667+
let formatted = getFormattedMetadataEntries(metadata);
1668+
let result = {};
1669+
for (let entry of formatted.entries) {
1670+
result[entry.id] = entry;
1671+
}
1672+
return result;
1673+
}
1674+
1675+
renderMetadataCell(entry) {
1676+
if (!entry) {
1677+
return '';
1678+
}
1679+
return entry.valueHtml + entry.extras;
1680+
}
1681+
1682+
renderMetadataTable() {
1683+
let leftEntries = this.getMetadataEntryMap(this.left?.metadata);
1684+
let rightEntries = this.getMetadataEntryMap(this.right?.metadata);
1685+
let ids = Object.keys(leftEntries);
1686+
for (let id of Object.keys(rightEntries)) {
1687+
if (!ids.includes(id)) {
1688+
ids.push(id);
1689+
}
1690+
}
1691+
if (ids.length == 0) {
1692+
return '';
1693+
}
1694+
let result = '<table class="image_compare_metadata_table"><thead><tr><th class="translate">Parameter</th><th class="translate">Image 1</th><th class="translate">Image 2</th></tr></thead><tbody>';
1695+
for (let id of ids) {
1696+
let entry = leftEntries[id] || rightEntries[id];
1697+
let leftEntry = leftEntries[id];
1698+
let rightEntry = rightEntries[id];
1699+
let sameClass = leftEntry && rightEntry && leftEntry.compareValue == rightEntry.compareValue ? ' image_compare_metadata_same' : '';
1700+
result += `<tr class="param_view_block tag-text tag-type-${entry.hash}${entry.added}${sameClass}"><td><span class="param_view_name" title="${escapeHtmlNoBr(entry.keyTitle)}">${escapeHtml(entry.key)}</span></td><td>${this.renderMetadataCell(leftEntry)}</td><td>${this.renderMetadataCell(rightEntry)}</td></tr>`;
1701+
}
1702+
return `${result}</tbody></table>`;
1703+
}
1704+
1705+
updateMetadataVisibility() {
1706+
this.metadataDiv.style.display = this.showMetadata && this.metadataDiv.innerHTML ? '' : 'none';
1707+
this.metadataToggleButton.setAttribute('aria-pressed', this.showMetadata ? 'true' : 'false');
1708+
}
1709+
1710+
toggleMetadataVisibility(showMetadata) {
1711+
this.showMetadata = showMetadata;
1712+
this.updateMetadataVisibility();
1713+
if (this.hasSelection()) {
1714+
this.applyView();
1715+
}
1716+
}
1717+
16601718
showComparison(left, right) {
16611719
this.left = left;
16621720
this.right = right;
@@ -1796,8 +1854,11 @@ class ImageCompareHelper {
17961854
this.left = null;
17971855
this.right = null;
17981856
this.mode = 'side';
1857+
this.showMetadata = false;
17991858
this.resetViewportState();
18001859
this.setStageContent('side', '');
1860+
this.metadataDiv.innerHTML = '';
1861+
this.updateMetadataVisibility();
18011862
this.updateModeControls();
18021863
}
18031864

@@ -1860,6 +1921,8 @@ class ImageCompareHelper {
18601921
this.updateModeControls();
18611922
if (!this.hasSelection()) {
18621923
this.setStageContent('side', '');
1924+
this.metadataDiv.innerHTML = '';
1925+
this.updateMetadataVisibility();
18631926
this.updateModeControls();
18641927
return;
18651928
}
@@ -1875,6 +1938,9 @@ class ImageCompareHelper {
18751938
<div class="image_compare_slot">${this.renderMedia(this.right)}</div>`
18761939
);
18771940
}
1941+
let metadataHtml = this.renderMetadataTable();
1942+
this.metadataDiv.innerHTML = metadataHtml;
1943+
this.updateMetadataVisibility();
18781944
this.applyView();
18791945
}
18801946

src/wwwroot/js/genpage/gentab/outputhistory.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ function buttonsForImage(fullsrc, src, metadata, isCurrentImage = false) {
188188
title: 'Compare 2 images or 2 videos',
189189
onclick: (e) => {
190190
// TODO: Give browsers.js a real "run once with the full selection" bulk handler
191-
let items = imageHistoryBrowser.getMultiSelectedFiles().map(f => ({ src: f.data.src, mediaType: getMediaType(f.data.src) }));
191+
let items = imageHistoryBrowser.getMultiSelectedFiles().map(f => ({ src: f.data.src, mediaType: getMediaType(f.data.src), metadata: f.data.metadata }));
192192
let valid = imageCompareHelper.evaluateSelection(items);
193193
if (valid.state != 'ready') {
194194
showError(valid.reason || 'Cannot compare current selection.');

0 commit comments

Comments
 (0)