prithivMLmods commited on
Commit
4515d6d
Β·
verified Β·
1 Parent(s): 7c62c84

update UI./

Browse files
Files changed (1) hide show
  1. index.html +237 -5
index.html CHANGED
@@ -152,6 +152,16 @@ body{
152
  repeating-conic-gradient(#0c0c0c 0% 25%, #050505 0% 50%) 0 0/24px 24px;
153
  padding: 24px;
154
  }
 
 
 
 
 
 
 
 
 
 
155
  #draw-canvas {
156
  background: #ffffff;
157
  border: 1px solid var(--border2);
@@ -181,6 +191,60 @@ body{
181
  display: none;
182
  }
183
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
184
  /* Loader */
185
  .modern-loader{
186
  display:none;position:absolute;inset:0;background:rgba(0,0,0,.92);
@@ -429,6 +493,13 @@ body{
429
  <svg viewBox="0 0 24 24"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg>
430
  </button>
431
 
 
 
 
 
 
 
 
432
  <div class="rail-sep"></div>
433
  <div class="rail-label">Result</div>
434
  <button class="rail-btn" id="btn-download" title="Download Result" disabled>
@@ -454,7 +525,11 @@ body{
454
  <div class="loader-bar-track"><div class="loader-bar-fill" id="loader-bar-fill"></div></div>
455
  </div>
456
 
457
- <canvas id="draw-canvas" width="1024" height="576" class="cursor-brush" style="aspect-ratio: 16 / 9;"></canvas>
 
 
 
 
458
  <img id="result-img" alt="Result Image" style="display:none; aspect-ratio: 16 / 9;">
459
  </div>
460
  </div>
@@ -544,6 +619,8 @@ const canvas = document.getElementById('draw-canvas');
544
  const ctx = canvas.getContext('2d');
545
  const resultImg = document.getElementById('result-img');
546
  const btnDownload = document.getElementById('btn-download');
 
 
547
 
548
  const btnBrush = document.getElementById('btn-brush');
549
  const btnEraser = document.getElementById('btn-eraser');
@@ -632,6 +709,7 @@ function updateCanvasRatio(ratio) {
632
  setupCanvas(); // Clear and reset canvas on ratio change
633
  undoStack = []; // Clear history on ratio change
634
  redoStack = [];
 
635
  saveState(); // Save initial blank state
636
  }
637
 
@@ -659,6 +737,8 @@ function getPos(e) {
659
  }
660
 
661
  function startDrawing(e) {
 
 
662
  e.preventDefault();
663
  isDrawing = true;
664
  const pos = getPos(e);
@@ -739,6 +819,7 @@ sizeSlider.addEventListener('input', (e) => {
739
  btnClear.addEventListener('click', () => {
740
  setupCanvas();
741
  saveState();
 
742
  showToast('Canvas cleared', 'info');
743
  });
744
 
@@ -767,16 +848,141 @@ btnDownload.addEventListener('click', () => {
767
  }
768
  });
769
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
770
  /* ── UI Toggles ── */
771
  function setViewMode(mode) {
772
  if (mode === 'result') {
773
- canvas.style.display = 'none';
774
  resultImg.style.display = 'block';
775
  segResult.classList.add('active');
776
  segInput.classList.remove('active');
777
  canvasMeta.textContent = 'Generated Result';
778
  } else {
779
- canvas.style.display = 'block';
780
  resultImg.style.display = 'none';
781
  segResult.classList.remove('active');
782
  segInput.classList.add('active');
@@ -891,7 +1097,33 @@ try {
891
  showToast('Could not connect to the backend API', 'error');
892
  }
893
 
894
- /* ── Run Generation ── */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
895
  let running = false;
896
  let currentJob = null;
897
 
@@ -913,7 +1145,7 @@ async function runEdit() {
913
  showLoader('Submitting to queue…');
914
  btnDownload.disabled = true;
915
 
916
- const sketch_b64 = canvas.toDataURL('image/png');
917
  const selectedRatio = ratioSelect.value;
918
  const [targetW, targetH] = dims[selectedRatio];
919
 
 
152
  repeating-conic-gradient(#0c0c0c 0% 25%, #050505 0% 50%) 0 0/24px 24px;
153
  padding: 24px;
154
  }
155
+
156
+ .canvas-container {
157
+ position: relative;
158
+ max-width: 100%;
159
+ max-height: 100%;
160
+ display: flex;
161
+ align-items: center;
162
+ justify-content: center;
163
+ }
164
+
165
  #draw-canvas {
166
  background: #ffffff;
167
  border: 1px solid var(--border2);
 
191
  display: none;
192
  }
193
 
194
+ /* Sticker Layer */
195
+ #sticker-layer {
196
+ position: absolute;
197
+ top: 0; left: 0; width: 100%; height: 100%;
198
+ pointer-events: none; /* Container itself doesn't block canvas clicks */
199
+ }
200
+ .sticker-wrapper {
201
+ position: absolute;
202
+ pointer-events: auto;
203
+ cursor: move;
204
+ border: 1px dashed transparent;
205
+ user-select: none;
206
+ }
207
+ .sticker-wrapper:hover, .sticker-wrapper.selected {
208
+ border-color: var(--accent);
209
+ }
210
+ .sticker-wrapper img {
211
+ width: 100%;
212
+ height: 100%;
213
+ display: block;
214
+ pointer-events: none;
215
+ }
216
+ .sticker-del-btn {
217
+ position: absolute;
218
+ top: -10px; right: -10px;
219
+ width: 20px; height: 20px;
220
+ background: #ef4444;
221
+ color: #fff;
222
+ border: none;
223
+ border-radius: 50%;
224
+ cursor: pointer;
225
+ display: none;
226
+ align-items: center;
227
+ justify-content: center;
228
+ font-size: 12px;
229
+ z-index: 10;
230
+ }
231
+ .sticker-wrapper:hover .sticker-del-btn, .sticker-wrapper.selected .sticker-del-btn {
232
+ display: flex;
233
+ }
234
+ .resize-handle {
235
+ position: absolute;
236
+ width: 12px; height: 12px;
237
+ background: #fff;
238
+ border: 1px solid #000;
239
+ bottom: -6px; right: -6px;
240
+ cursor: nwse-resize;
241
+ pointer-events: auto;
242
+ display: none;
243
+ }
244
+ .sticker-wrapper:hover .resize-handle, .sticker-wrapper.selected .resize-handle {
245
+ display: block;
246
+ }
247
+
248
  /* Loader */
249
  .modern-loader{
250
  display:none;position:absolute;inset:0;background:rgba(0,0,0,.92);
 
493
  <svg viewBox="0 0 24 24"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg>
494
  </button>
495
 
496
+ <div class="rail-sep"></div>
497
+ <div class="rail-label">Assets</div>
498
+ <button class="rail-btn" id="btn-sticker" title="Add Sticker / Image">
499
+ <svg viewBox="0 0 24 24"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>
500
+ </button>
501
+ <input type="file" id="sticker-input" accept="image/*" style="display:none;">
502
+
503
  <div class="rail-sep"></div>
504
  <div class="rail-label">Result</div>
505
  <button class="rail-btn" id="btn-download" title="Download Result" disabled>
 
525
  <div class="loader-bar-track"><div class="loader-bar-fill" id="loader-bar-fill"></div></div>
526
  </div>
527
 
528
+ <div class="canvas-container" id="canvas-container">
529
+ <canvas id="draw-canvas" width="1024" height="576" class="cursor-brush" style="aspect-ratio: 16 / 9;"></canvas>
530
+ <div id="sticker-layer"></div>
531
+ </div>
532
+
533
  <img id="result-img" alt="Result Image" style="display:none; aspect-ratio: 16 / 9;">
534
  </div>
535
  </div>
 
619
  const ctx = canvas.getContext('2d');
620
  const resultImg = document.getElementById('result-img');
621
  const btnDownload = document.getElementById('btn-download');
622
+ const stickerLayer = document.getElementById('sticker-layer');
623
+ const canvasContainer = document.getElementById('canvas-container');
624
 
625
  const btnBrush = document.getElementById('btn-brush');
626
  const btnEraser = document.getElementById('btn-eraser');
 
709
  setupCanvas(); // Clear and reset canvas on ratio change
710
  undoStack = []; // Clear history on ratio change
711
  redoStack = [];
712
+ stickerLayer.innerHTML = ''; // Clear stickers on ratio change
713
  saveState(); // Save initial blank state
714
  }
715
 
 
737
  }
738
 
739
  function startDrawing(e) {
740
+ // Only draw if clicking directly on canvas, not a sticker
741
+ if (e.target !== canvas) return;
742
  e.preventDefault();
743
  isDrawing = true;
744
  const pos = getPos(e);
 
819
  btnClear.addEventListener('click', () => {
820
  setupCanvas();
821
  saveState();
822
+ stickerLayer.innerHTML = ''; // Clear stickers too
823
  showToast('Canvas cleared', 'info');
824
  });
825
 
 
848
  }
849
  });
850
 
851
+ /* ── Sticker / Asset Logic ── */
852
+ const btnSticker = document.getElementById('btn-sticker');
853
+ const stickerInput = document.getElementById('sticker-input');
854
+ let stickers = [];
855
+
856
+ btnSticker.addEventListener('click', () => stickerInput.click());
857
+
858
+ stickerInput.addEventListener('change', (e) => {
859
+ const file = e.target.files[0];
860
+ if (!file) return;
861
+ const reader = new FileReader();
862
+ reader.onload = (ev) => addSticker(ev.target.result);
863
+ reader.readAsDataURL(file);
864
+ e.target.value = ''; // reset input
865
+ });
866
+
867
+ function addSticker(src) {
868
+ const wrapper = document.createElement('div');
869
+ wrapper.className = 'sticker-wrapper';
870
+
871
+ const img = document.createElement('img');
872
+ img.src = src;
873
+ img.draggable = false; // prevent native drag
874
+ wrapper.appendChild(img);
875
+
876
+ const delBtn = document.createElement('button');
877
+ delBtn.className = 'sticker-del-btn';
878
+ delBtn.innerHTML = 'βœ•';
879
+ delBtn.addEventListener('click', (e) => {
880
+ e.stopPropagation();
881
+ wrapper.remove();
882
+ stickers = stickers.filter(s => s.element !== wrapper);
883
+ });
884
+ wrapper.appendChild(delBtn);
885
+
886
+ const resizeHandle = document.createElement('div');
887
+ resizeHandle.className = 'resize-handle';
888
+ wrapper.appendChild(resizeHandle);
889
+
890
+ // Initial size and position (center)
891
+ wrapper.style.width = '150px';
892
+ wrapper.style.height = '150px'; // Will be overwritten by aspect ratio on load
893
+ wrapper.style.left = '40%';
894
+ wrapper.style.top = '40%';
895
+
896
+ stickerLayer.appendChild(wrapper);
897
+
898
+ const stickerObj = { element: wrapper, img: img };
899
+ stickers.push(stickerObj);
900
+
901
+ // Adjust initial height based on image aspect ratio
902
+ img.onload = () => {
903
+ const aspect = img.naturalWidth / img.naturalHeight;
904
+ const w = wrapper.offsetWidth;
905
+ wrapper.style.height = `${w / aspect}px`;
906
+ };
907
+
908
+ // Make draggable
909
+ wrapper.addEventListener('pointerdown', (e) => startDrag(e, stickerObj));
910
+ // Make resizable
911
+ resizeHandle.addEventListener('pointerdown', (e) => startResize(e, stickerObj));
912
+ }
913
+
914
+ function startDrag(e, sticker) {
915
+ e.stopPropagation();
916
+ e.preventDefault();
917
+ sticker.element.classList.add('selected');
918
+
919
+ const rect = sticker.element.getBoundingClientRect();
920
+ const offsetX = e.clientX - rect.left;
921
+ const offsetY = e.clientY - rect.top;
922
+
923
+ function onMove(ev) {
924
+ const layerRect = stickerLayer.getBoundingClientRect();
925
+ let x = ev.clientX - layerRect.left - offsetX;
926
+ let y = ev.clientY - layerRect.top - offsetY;
927
+
928
+ // Keep within bounds roughly
929
+ x = Math.max(-rect.width/2, Math.min(x, layerRect.width - rect.width/2));
930
+ y = Math.max(-rect.height/2, Math.min(y, layerRect.height - rect.height/2));
931
+
932
+ sticker.element.style.left = `${x}px`;
933
+ sticker.element.style.top = `${y}px`;
934
+ }
935
+ function onUp() {
936
+ document.removeEventListener('pointermove', onMove);
937
+ document.removeEventListener('pointerup', onUp);
938
+ sticker.element.classList.remove('selected');
939
+ }
940
+ document.addEventListener('pointermove', onMove);
941
+ document.addEventListener('pointerup', onUp);
942
+ }
943
+
944
+ function startResize(e, sticker) {
945
+ e.stopPropagation();
946
+ e.preventDefault();
947
+ sticker.element.classList.add('selected');
948
+
949
+ const rect = sticker.element.getBoundingClientRect();
950
+ const startW = rect.width;
951
+ const startH = rect.height;
952
+ const startX = e.clientX;
953
+ const startY = e.clientY;
954
+ const aspect = startW / startH;
955
+
956
+ function onMove(ev) {
957
+ let newW = startW + (ev.clientX - startX);
958
+ // Maintain aspect ratio
959
+ let newH = newW / aspect;
960
+
961
+ if (newW < 30) newW = 30;
962
+ if (newH < 30) newH = 30;
963
+
964
+ sticker.element.style.width = `${newW}px`;
965
+ sticker.element.style.height = `${newH}px`;
966
+ }
967
+ function onUp() {
968
+ document.removeEventListener('pointermove', onMove);
969
+ document.removeEventListener('pointerup', onUp);
970
+ sticker.element.classList.remove('selected');
971
+ }
972
+ document.addEventListener('pointermove', onMove);
973
+ document.addEventListener('pointerup', onUp);
974
+ }
975
+
976
  /* ── UI Toggles ── */
977
  function setViewMode(mode) {
978
  if (mode === 'result') {
979
+ canvasContainer.style.display = 'none';
980
  resultImg.style.display = 'block';
981
  segResult.classList.add('active');
982
  segInput.classList.remove('active');
983
  canvasMeta.textContent = 'Generated Result';
984
  } else {
985
+ canvasContainer.style.display = 'flex';
986
  resultImg.style.display = 'none';
987
  segResult.classList.remove('active');
988
  segInput.classList.add('active');
 
1097
  showToast('Could not connect to the backend API', 'error');
1098
  }
1099
 
1100
+ /* ── Composition & Generation ── */
1101
+ function getCompositedImage() {
1102
+ const tempCanvas = document.createElement('canvas');
1103
+ tempCanvas.width = canvas.width;
1104
+ tempCanvas.height = canvas.height;
1105
+ const tempCtx = tempCanvas.getContext('2d');
1106
+
1107
+ // Draw the sketch
1108
+ tempCtx.drawImage(canvas, 0, 0);
1109
+
1110
+ // Draw stickers
1111
+ const scaleX = canvas.width / canvas.clientWidth;
1112
+ const scaleY = canvas.height / canvas.clientHeight;
1113
+
1114
+ stickers.forEach(s => {
1115
+ const wrapperRect = s.element.getBoundingClientRect();
1116
+ const layerRect = stickerLayer.getBoundingClientRect();
1117
+ const x = (wrapperRect.left - layerRect.left) * scaleX;
1118
+ const y = (wrapperRect.top - layerRect.top) * scaleY;
1119
+ const w = wrapperRect.width * scaleX;
1120
+ const h = wrapperRect.height * scaleY;
1121
+ tempCtx.drawImage(s.img, x, y, w, h);
1122
+ });
1123
+
1124
+ return tempCanvas.toDataURL('image/png');
1125
+ }
1126
+
1127
  let running = false;
1128
  let currentJob = null;
1129
 
 
1145
  showLoader('Submitting to queue…');
1146
  btnDownload.disabled = true;
1147
 
1148
+ const sketch_b64 = getCompositedImage(); // Use composited image
1149
  const selectedRatio = ratioSelect.value;
1150
  const [targetW, targetH] = dims[selectedRatio];
1151