wiki-plugin-shoppe 0.0.25 → 0.0.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/client/shoppe.js +70 -10
- package/package.json +1 -1
package/client/shoppe.js
CHANGED
|
@@ -22,8 +22,11 @@
|
|
|
22
22
|
.sw-shoppe-left { display: flex; flex-direction: column; gap: 2px; }
|
|
23
23
|
.sw-shoppe-name { font-weight: 600; font-size: 15px; }
|
|
24
24
|
.sw-shoppe-code { font-size: 18px; letter-spacing: 4px; }
|
|
25
|
+
.sw-shoppe-actions { display: flex; align-items: center; gap: 12px; }
|
|
25
26
|
.sw-link { font-size: 13px; color: #0066cc; text-decoration: none; white-space: nowrap; }
|
|
26
27
|
.sw-link:hover { text-decoration: underline; }
|
|
28
|
+
.sw-btn-delete { background: none; border: none; color: #cc0000; font-size: 13px; cursor: pointer; padding: 0; white-space: nowrap; }
|
|
29
|
+
.sw-btn-delete:hover { text-decoration: underline; }
|
|
27
30
|
.sw-empty { font-size: 13px; color: #999; font-style: italic; }
|
|
28
31
|
.sw-drop { border: 2px dashed #ccc; border-radius: 12px; padding: 28px 20px; text-align: center; background: #fafafa; transition: border-color 0.2s, background 0.2s; cursor: pointer; }
|
|
29
32
|
.sw-drop.dragover { border-color: #0066cc; background: #e8f0fe; }
|
|
@@ -41,6 +44,8 @@
|
|
|
41
44
|
.sw-status.success { background: #d1fae5; color: #065f46; display: block; }
|
|
42
45
|
.sw-status.error { background: #fee2e2; color: #991b1b; display: block; }
|
|
43
46
|
.sw-status code { background: rgba(0,0,0,0.08); border-radius: 4px; padding: 1px 5px; font-size: 12px; }
|
|
47
|
+
.sw-remove { display: block; width: 100%; margin-top: 24px; padding: 8px; background: none; border: 1px solid #e5e5ea; border-radius: 8px; font-size: 12px; color: #aaa; cursor: pointer; text-align: center; }
|
|
48
|
+
.sw-remove:hover { border-color: #cc0000; color: #cc0000; }
|
|
44
49
|
</style>
|
|
45
50
|
|
|
46
51
|
<!-- Directory -->
|
|
@@ -161,37 +166,70 @@
|
|
|
161
166
|
<div id="sw-register-status" class="sw-status"></div>
|
|
162
167
|
</div>
|
|
163
168
|
|
|
169
|
+
<button class="sw-remove" id="sw-remove-btn">Remove plugin from page</button>
|
|
170
|
+
|
|
164
171
|
</div>
|
|
165
172
|
`;
|
|
166
173
|
|
|
174
|
+
div.querySelector('#sw-remove-btn').addEventListener('click', () => {
|
|
175
|
+
const $page = $item.parents('.page');
|
|
176
|
+
if (window.pageHandler && $page.length) {
|
|
177
|
+
pageHandler.put($page, { type: 'remove', id: item.id });
|
|
178
|
+
$item.remove();
|
|
179
|
+
} else if (window.wiki && wiki.textEditor) {
|
|
180
|
+
wiki.textEditor($item, item);
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
|
|
167
184
|
setupListeners(div);
|
|
168
|
-
|
|
169
|
-
|
|
185
|
+
checkOwner(div).then(isOwner => {
|
|
186
|
+
if (!isOwner) loadDirectory(div, false);
|
|
187
|
+
});
|
|
170
188
|
},
|
|
171
189
|
|
|
172
|
-
bind: function($item, item) {
|
|
190
|
+
bind: function($item, item) {
|
|
191
|
+
$item.on('dblclick', () => {
|
|
192
|
+
const $page = $item.parents('.page');
|
|
193
|
+
if (window.pageHandler && $page.length) {
|
|
194
|
+
pageHandler.put($page, { type: 'remove', id: item.id });
|
|
195
|
+
$item.remove();
|
|
196
|
+
} else if (window.wiki && wiki.textEditor) {
|
|
197
|
+
wiki.textEditor($item, item);
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
}
|
|
173
201
|
};
|
|
174
202
|
|
|
175
|
-
// ── Directory
|
|
203
|
+
// ── Directory ────────────────────────────────────────────────────────────────
|
|
176
204
|
|
|
177
|
-
async function loadDirectory(container) {
|
|
205
|
+
async function loadDirectory(container, isOwner = false) {
|
|
178
206
|
const el = container.querySelector('#sw-directory');
|
|
179
207
|
try {
|
|
180
|
-
const resp = await fetch('/plugin/shoppe/directory');
|
|
208
|
+
const resp = await fetch(isOwner ? '/plugin/shoppe/tenants' : '/plugin/shoppe/directory');
|
|
181
209
|
const result = await resp.json();
|
|
182
|
-
|
|
210
|
+
const shoppes = isOwner ? result.tenants : result.shoppes;
|
|
211
|
+
if (!result.success || !shoppes || shoppes.length === 0) {
|
|
183
212
|
el.innerHTML = '<em class="sw-empty">No shoppes yet — be the first!</em>';
|
|
184
213
|
return;
|
|
185
214
|
}
|
|
186
|
-
el.innerHTML =
|
|
187
|
-
<div class="sw-shoppe">
|
|
215
|
+
el.innerHTML = shoppes.map(s => `
|
|
216
|
+
<div class="sw-shoppe" id="sw-shoppe-${s.uuid}">
|
|
188
217
|
<div class="sw-shoppe-left">
|
|
189
218
|
<span class="sw-shoppe-name">${s.name}</span>
|
|
190
219
|
<span class="sw-shoppe-code">${s.emojicode}</span>
|
|
191
220
|
</div>
|
|
192
|
-
<
|
|
221
|
+
<div class="sw-shoppe-actions">
|
|
222
|
+
<a class="sw-link" href="${s.url}" target="_blank">Visit shoppe →</a>
|
|
223
|
+
${isOwner ? `<button class="sw-btn-delete" data-uuid="${s.uuid}" data-name="${s.name}">Delete</button>` : ''}
|
|
224
|
+
</div>
|
|
193
225
|
</div>
|
|
194
226
|
`).join('');
|
|
227
|
+
|
|
228
|
+
if (isOwner) {
|
|
229
|
+
el.querySelectorAll('.sw-btn-delete').forEach(btn => {
|
|
230
|
+
btn.addEventListener('click', () => deleteShoppe(btn.dataset.uuid, btn.dataset.name, container));
|
|
231
|
+
});
|
|
232
|
+
}
|
|
195
233
|
} catch (err) {
|
|
196
234
|
el.innerHTML = '<em class="sw-empty">Could not load directory.</em>';
|
|
197
235
|
}
|
|
@@ -208,8 +246,30 @@
|
|
|
208
246
|
if (result.sanoraUrl) {
|
|
209
247
|
container.querySelector('#sw-url-input').value = result.sanoraUrl;
|
|
210
248
|
}
|
|
249
|
+
loadDirectory(container, true);
|
|
250
|
+
return true;
|
|
211
251
|
}
|
|
212
252
|
} catch (err) { /* not owner, stay hidden */ }
|
|
253
|
+
return false;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// ── Delete shoppe (owner) ────────────────────────────────────────────────────
|
|
257
|
+
|
|
258
|
+
async function deleteShoppe(uuid, name, container) {
|
|
259
|
+
if (!confirm(`Delete "${name}"? This will remove the shoppe and all its products from Sanora.`)) return;
|
|
260
|
+
|
|
261
|
+
const row = container.querySelector(`#sw-shoppe-${uuid}`);
|
|
262
|
+
if (row) row.style.opacity = '0.4';
|
|
263
|
+
|
|
264
|
+
try {
|
|
265
|
+
const resp = await fetch(`/plugin/shoppe/${uuid}`, { method: 'DELETE' });
|
|
266
|
+
const result = await resp.json();
|
|
267
|
+
if (!result.success) throw new Error(result.error || 'Delete failed');
|
|
268
|
+
loadDirectory(container, true);
|
|
269
|
+
} catch (err) {
|
|
270
|
+
if (row) row.style.opacity = '1';
|
|
271
|
+
alert(`Could not delete shoppe: ${err.message}`);
|
|
272
|
+
}
|
|
213
273
|
}
|
|
214
274
|
|
|
215
275
|
// ── Listeners ───────────────────────────────────────────────────────────────
|