Compare commits
2 Commits
e39bc862cc
...
8b1da56820
| Author | SHA1 | Date | |
|---|---|---|---|
| 8b1da56820 | |||
| 05d459d58f |
@ -502,6 +502,26 @@
|
|||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
filter: grayscale(0.5);
|
filter: grayscale(0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Selection Styles */
|
||||||
|
.media-item.selected {
|
||||||
|
border: 3px solid var(--primary);
|
||||||
|
box-shadow: 0 0 0 2px rgba(37, 99, 235, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-btn.active {
|
||||||
|
background-color: var(--primary);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-link {
|
||||||
|
background-color: var(--primary);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-link:hover {
|
||||||
|
background-color: var(--primary-hover);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
@ -527,10 +547,14 @@
|
|||||||
|
|
||||||
<div class="card" style="padding-bottom: 0;">
|
<div class="card" style="padding-bottom: 0;">
|
||||||
<div class="header" style="margin-bottom:8px; display:flex; justify-content:space-between; align-items:center;">
|
<div class="header" style="margin-bottom:8px; display:flex; justify-content:space-between; align-items:center;">
|
||||||
<div style="display:flex; align-items:baseline; gap:12px;">
|
<div style="display:flex; align-items:center; gap:12px;">
|
||||||
<h2 style="margin:0;">Gallery <span id="item-count"
|
<h2 style="margin:0;">Gallery <span id="item-count"
|
||||||
style="font-weight:400; color:var(--text-secondary); font-size:12px;">(0)</span></h2>
|
style="font-weight:400; color:var(--text-secondary); font-size:12px;">(0)</span></h2>
|
||||||
<div id="quick-links" style="font-size:12px; display:flex; gap:8px;"></div>
|
<div id="quick-links" style="font-size:12px; display:flex; gap:8px;"></div>
|
||||||
|
<button id="btn-link-selected" onclick="controller.linkSelectedMedia()" class="btn btn-link"
|
||||||
|
style="display:none; width:auto; padding: 4px 12px; font-size:12px; height:28px;">
|
||||||
|
Link Selected
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div style="display: flex; gap: 8px;">
|
<div style="display: flex; gap: 8px;">
|
||||||
<button id="toggle-log-btn" onclick="ui.toggleLog()"
|
<button id="toggle-log-btn" onclick="ui.toggleLog()"
|
||||||
@ -679,8 +703,8 @@
|
|||||||
<div id="matching-modal" class="modal-overlay" style="z-index: 150;">
|
<div id="matching-modal" class="modal-overlay" style="z-index: 150;">
|
||||||
<div class="card"
|
<div class="card"
|
||||||
style="width: 600px; max-width: 90%; text-align: center; padding: 24px; position: relative; background: #fff;">
|
style="width: 600px; max-width: 90%; text-align: center; padding: 24px; position: relative; background: #fff;">
|
||||||
<h3 style="margin-top:0;">Link Media?</h3>
|
<h3 id="match-modal-title" style="margin-top:0;">Link Media?</h3>
|
||||||
<p style="color:var(--text-secondary); margin-bottom: 24px;">
|
<p id="match-modal-text" style="color:var(--text-secondary); margin-bottom: 24px;">
|
||||||
We found a matching file in Shopify. Should these be linked?
|
We found a matching file in Shopify. Should these be linked?
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@ -741,6 +765,7 @@
|
|||||||
this.token = null;
|
this.token = null;
|
||||||
this.items = [];
|
this.items = [];
|
||||||
this.initialState = [];
|
this.initialState = [];
|
||||||
|
this.selectedIds = new Set();
|
||||||
}
|
}
|
||||||
|
|
||||||
MediaState.prototype.setSku = function (info) {
|
MediaState.prototype.setSku = function (info) {
|
||||||
@ -754,10 +779,51 @@
|
|||||||
MediaState.prototype.setItems = function (items) {
|
MediaState.prototype.setItems = function (items) {
|
||||||
this.items = items || [];
|
this.items = items || [];
|
||||||
this.initialState = JSON.parse(JSON.stringify(this.items));
|
this.initialState = JSON.parse(JSON.stringify(this.items));
|
||||||
|
this.selectedIds.clear();
|
||||||
ui.render(this.items);
|
ui.render(this.items);
|
||||||
this.checkDirty();
|
this.checkDirty();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
MediaState.prototype.toggleSelection = function (id) {
|
||||||
|
var item = this.items.find(function (i) { return i.id === id; });
|
||||||
|
if (!item) return;
|
||||||
|
|
||||||
|
var isSelected = this.selectedIds.has(id);
|
||||||
|
|
||||||
|
if (isSelected) {
|
||||||
|
this.selectedIds.delete(id);
|
||||||
|
} else {
|
||||||
|
// Enforce one-pair rule: Max one Drive, one Shopify
|
||||||
|
var isDrive = (item.source === 'drive_only');
|
||||||
|
var isShopify = (item.source === 'shopify_only');
|
||||||
|
|
||||||
|
if (isDrive) {
|
||||||
|
// Clear other Drive selections
|
||||||
|
var _this = this;
|
||||||
|
this.items.forEach(function (i) {
|
||||||
|
if (i.source === 'drive_only' && _this.selectedIds.has(i.id)) {
|
||||||
|
_this.selectedIds.delete(i.id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if (isShopify) {
|
||||||
|
// Clear other Shopify selections
|
||||||
|
var _this = this;
|
||||||
|
this.items.forEach(function (i) {
|
||||||
|
if (i.source === 'shopify_only' && _this.selectedIds.has(i.id)) {
|
||||||
|
_this.selectedIds.delete(i.id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.selectedIds.add(id);
|
||||||
|
}
|
||||||
|
ui.render(this.items);
|
||||||
|
};
|
||||||
|
|
||||||
|
MediaState.prototype.clearSelection = function () {
|
||||||
|
this.selectedIds.clear();
|
||||||
|
ui.render(this.items);
|
||||||
|
};
|
||||||
|
|
||||||
MediaState.prototype.addItem = function (item) {
|
MediaState.prototype.addItem = function (item) {
|
||||||
this.items.push(item);
|
this.items.push(item);
|
||||||
ui.render(this.items);
|
ui.render(this.items);
|
||||||
@ -982,6 +1048,20 @@
|
|||||||
banner.style.display = hasProcessing ? 'flex' : 'none';
|
banner.style.display = hasProcessing ? 'flex' : 'none';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Link Selected button logic
|
||||||
|
var btnLink = document.getElementById('btn-link-selected');
|
||||||
|
if (btnLink) {
|
||||||
|
var selectedItems = items.filter(function (i) { return state.selectedIds.has(i.id); });
|
||||||
|
var hasDrive = selectedItems.some(function (i) { return i.source === 'drive_only'; });
|
||||||
|
var hasShopify = selectedItems.some(function (i) { return i.source === 'shopify_only'; });
|
||||||
|
|
||||||
|
if (hasDrive && hasShopify) {
|
||||||
|
btnLink.style.display = 'block';
|
||||||
|
} else {
|
||||||
|
btnLink.style.display = 'none';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (items.length === 0) {
|
if (items.length === 0) {
|
||||||
this.grid.innerHTML = '<div class="empty-state">No media found. Upload something!</div>';
|
this.grid.innerHTML = '<div class="empty-state">No media found. Upload something!</div>';
|
||||||
return;
|
return;
|
||||||
@ -995,7 +1075,7 @@
|
|||||||
if (this.sortable) this.sortable.destroy();
|
if (this.sortable) this.sortable.destroy();
|
||||||
this.sortable = new Sortable(this.grid, {
|
this.sortable = new Sortable(this.grid, {
|
||||||
animation: 150,
|
animation: 150,
|
||||||
filter: '.deleted-item',
|
filter: '.deleted-item', // Simplified filter
|
||||||
ghostClass: 'sortable-ghost',
|
ghostClass: 'sortable-ghost',
|
||||||
dragClass: 'sortable-drag',
|
dragClass: 'sortable-drag',
|
||||||
onEnd: function () {
|
onEnd: function () {
|
||||||
@ -1084,7 +1164,8 @@
|
|||||||
|
|
||||||
UI.prototype.createCard = function (item, index) {
|
UI.prototype.createCard = function (item, index) {
|
||||||
var div = document.createElement('div');
|
var div = document.createElement('div');
|
||||||
div.className = 'media-item ' + (item._deleted ? 'deleted-item' : '');
|
var isSelected = state.selectedIds.has(item.id);
|
||||||
|
div.className = 'media-item ' + (item._deleted ? 'deleted-item' : '') + (isSelected ? ' selected' : '');
|
||||||
div.dataset.id = item.id;
|
div.dataset.id = item.id;
|
||||||
|
|
||||||
// Processing Class
|
// Processing Class
|
||||||
@ -1092,6 +1173,8 @@
|
|||||||
div.className += ' processing-card';
|
div.className += ' processing-card';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
div.onmouseenter = function () {
|
div.onmouseenter = function () {
|
||||||
var v = div.querySelector('video');
|
var v = div.querySelector('video');
|
||||||
if (v) v.play();
|
if (v) v.play();
|
||||||
@ -1103,9 +1186,9 @@
|
|||||||
|
|
||||||
var badge = '';
|
var badge = '';
|
||||||
if (!item._deleted) {
|
if (!item._deleted) {
|
||||||
if (item.status === 'synced') badge = '<span class="badge" title="Synced" style="background:#dcfce7; color:#166534;">Synced</span>';
|
if (item.source === 'synced') badge = '<span class="badge" title="Synced" style="background:#dcfce7; color:#166534;">Synced</span>';
|
||||||
else if (item.status === 'drive_only') badge = '<span class="badge" title="Drive Only" style="background:#dbeafe; color:#1e40af;">Drive</span>';
|
else if (item.source === 'drive_only') badge = '<span class="badge" title="Drive Only" style="background:#dbeafe; color:#1e40af;">Drive</span>';
|
||||||
else if (item.status === 'shopify_only') badge = '<span class="badge" title="Shopify Only" style="background:#fce7f3; color:#9d174d;">Shopify</span>';
|
else if (item.source === 'shopify_only') badge = '<span class="badge" title="Shopify Only" style="background:#fce7f3; color:#9d174d;">Shopify</span>';
|
||||||
} else {
|
} else {
|
||||||
badge = '<span class="badge" style="background:#fee2e2; color:#991b1b;">Deleted</span>';
|
badge = '<span class="badge" style="background:#fee2e2; color:#991b1b;">Deleted</span>';
|
||||||
}
|
}
|
||||||
@ -1124,16 +1207,23 @@
|
|||||||
// content URL logic (Only relevant for Shopify where we have a direct public link)
|
// content URL logic (Only relevant for Shopify where we have a direct public link)
|
||||||
var contentUrl = item.contentUrl || "";
|
var contentUrl = item.contentUrl || "";
|
||||||
|
|
||||||
|
// Link selection button
|
||||||
|
var linkSelectionBtn = '';
|
||||||
|
if (!item._deleted && (item.source === 'drive_only' || item.source === 'shopify_only')) {
|
||||||
|
linkSelectionBtn = '<button class="icon-btn' + (isSelected ? ' active' : '') + '" onclick="event.stopPropagation(); state.toggleSelection(\'' + item.id + '\')" title="Select for linking">🔗</button>';
|
||||||
|
}
|
||||||
|
|
||||||
var actionBtn = item._deleted
|
var actionBtn = item._deleted
|
||||||
? '<button class="icon-btn" onclick="state.deleteItem(' + index + ')" title="Restore">↩️</button>'
|
? '<button class="icon-btn" onclick="state.deleteItem(' + index + ')" title="Restore">↩️</button>'
|
||||||
: '<button class="icon-btn btn-delete" onclick="state.deleteItem(' + index + ')" title="Delete">🗑️</button>';
|
: '<button class="icon-btn btn-delete" onclick="state.deleteItem(' + index + ')" title="Delete">🗑️</button>';
|
||||||
|
|
||||||
div.innerHTML =
|
div.innerHTML +=
|
||||||
badge +
|
badge +
|
||||||
videoBadgeIcon +
|
videoBadgeIcon +
|
||||||
centerIcon +
|
centerIcon +
|
||||||
'<div class="media-overlay">' +
|
'<div class="media-overlay">' +
|
||||||
'<button class="icon-btn btn-view" onclick="ui.openPreview(\'' + item.id + '\')" title="View">👁️</button>' +
|
'<button class="icon-btn btn-view" onclick="ui.openPreview(\'' + item.id + '\')" title="View">👁️</button>' +
|
||||||
|
linkSelectionBtn +
|
||||||
actionBtn +
|
actionBtn +
|
||||||
'</div>';
|
'</div>';
|
||||||
|
|
||||||
@ -1385,6 +1475,29 @@
|
|||||||
.getMediaManagerInitialState(sku, title);
|
.getMediaManagerInitialState(sku, title);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
linkSelectedMedia() {
|
||||||
|
var selectedItems = state.items.filter(function (i) { return state.selectedIds.has(i.id); });
|
||||||
|
var driveItem = selectedItems.find(function (i) { return i.source === 'drive_only'; });
|
||||||
|
var shopifyItem = selectedItems.find(function (i) { return i.source === 'shopify_only'; });
|
||||||
|
|
||||||
|
if (!driveItem || !shopifyItem) {
|
||||||
|
alert("Please select exactly one Drive item and one Shopify item.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare a single match for the modal
|
||||||
|
this.matches = [{
|
||||||
|
drive: driveItem,
|
||||||
|
shopify: shopifyItem
|
||||||
|
}];
|
||||||
|
this.currentMatchIndex = 0;
|
||||||
|
|
||||||
|
// Custom text for manual link
|
||||||
|
document.getElementById('match-modal-title').innerText = "Confirm Manual Link";
|
||||||
|
document.getElementById('match-modal-text').innerText = "Are you sure you want to link these two items?";
|
||||||
|
|
||||||
|
this.startMatching();
|
||||||
|
},
|
||||||
|
|
||||||
saveChanges() {
|
saveChanges() {
|
||||||
ui.toggleSave(false);
|
ui.toggleSave(false);
|
||||||
@ -1730,6 +1843,10 @@
|
|||||||
this.currentMatchIndex = 0;
|
this.currentMatchIndex = 0;
|
||||||
ui.logStatus('info', 'Found ' + newMatches.length + ' potential matches. Starting matching wizard...', 'info');
|
ui.logStatus('info', 'Found ' + newMatches.length + ' potential matches. Starting matching wizard...', 'info');
|
||||||
|
|
||||||
|
// Default text for automatic matching
|
||||||
|
document.getElementById('match-modal-title').innerText = "Link Media?";
|
||||||
|
document.getElementById('match-modal-text').innerText = "We found a matching file in Shopify. Should these be linked?";
|
||||||
|
|
||||||
// Preload Images
|
// Preload Images
|
||||||
newMatches.forEach(function (m) {
|
newMatches.forEach(function (m) {
|
||||||
if (m.drive && m.drive.thumbnail) new Image().src = m.drive.thumbnail;
|
if (m.drive && m.drive.thumbnail) new Image().src = m.drive.thumbnail;
|
||||||
|
|||||||
Binary file not shown.
Reference in New Issue
Block a user