@@ -183,15 +183,12 @@ <h2 id="carousels">Carousels</h2>
183183 < div class ="tab-content " id ="nav-tabContent ">
184184 < div class ="tab-pane fade show active " id ="nav-mockup " role ="tabpanel " aria-labelledby ="nav-mockup-tab " tabindex ="0 ">
185185 < p class ="small "> Click/drag to rearrange your components.</ p >
186-
187- < button id ="download-mockup-btn " class ="btn btn-primary btn-sm mb-3 ">
188- Download Mockup (JPG)
189- </ button >
190-
186+ < button id ="download-mockup-btn " class ="btn btn-primary btn-sm mb-3 "> Download Mockup (JPG)</ button >
191187 < ul id ="selected-list " class ="list-unstyled ">
192188 </ ul >
193189 </ div >
194190 < div class ="tab-pane fade " id ="nav-code " role ="tabpanel " aria-labelledby ="nav-code-tab " tabindex ="0 ">
191+ < button class ="btn btn-primary btn-sm mb-3 " onclick ="copyDivText() "> Copy Code</ button >
195192 < ul id ="selected-code-list " class ="list-unstyled ">
196193 </ ul >
197194 </ div >
@@ -211,184 +208,7 @@ <h2 id="carousels">Carousels</h2>
211208 crossorigin ="anonymous "> </ script >
212209 < script src ="https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.min.js "> </ script >
213210 < script src ="https://cdn.jsdelivr.net/npm/sortablejs@1.15.2/Sortable.min.js "> </ script >
214- < script >
215- document . addEventListener ( 'DOMContentLoaded' , ( ) => {
216- const sourceList = document . getElementById ( 'source-list' ) ;
217- const selectedList = document . getElementById ( 'selected-list' ) ;
218- const selectedCodeList = document . getElementById ( 'selected-code-list' ) ; // Get the code list
219-
220- // --- New Download Feature Logic ---
221- const downloadBtn = document . getElementById ( 'download-mockup-btn' ) ;
222- // const selectedList = document.getElementById('selected-list');
223-
224- if ( downloadBtn ) {
225- downloadBtn . addEventListener ( 'click' , ( ) => {
226- // Check if the list has any items before attempting to download
227- if ( selectedList . children . length === 0 ) {
228- alert ( "The Mockup list is empty. Add some components first!" ) ;
229- return ;
230- }
231-
232- // Options for html2canvas
233- const options = {
234- // Ignore the remove buttons from the final image
235- ignoreElements : ( element ) => {
236- return element . classList . contains ( 'remove-item' ) ;
237- } ,
238- // Use a white background (important for JPEGs)
239- backgroundColor : '#ffffff' ,
240- // Enable image cross-origin access if needed (optional)
241- useCORS : true
242- } ;
243-
244- // Convert the list content to a canvas
245- html2canvas ( selectedList , options ) . then ( canvas => {
246- // 1. Convert the canvas to a JPEG data URL (quality 0.9)
247- const imageURL = canvas . toDataURL ( 'image/jpeg' , 0.9 ) ;
248-
249- // 2. Create a temporary link element for the download
250- const link = document . createElement ( 'a' ) ;
251-
252- // 3. Set the download filename and image source
253- link . download = `mockup-${ new Date ( ) . toISOString ( ) . split ( 'T' ) [ 0 ] } .jpg` ;
254- link . href = imageURL ;
255-
256- // 4. Trigger the download and clean up
257- document . body . appendChild ( link ) ;
258- link . click ( ) ;
259- document . body . removeChild ( link ) ;
260- } ) ;
261- } ) ;
262- }
263-
264- // Initialize SortableJS on the target list to make it draggable
265- // NOTE: SortableJS is only initialized on the Mockup list.
266- // The code list will be updated based on the Mockup list's order.
267- new Sortable ( selectedList , {
268- animation : 150 ,
269- ghostClass : 'sortable-ghost' ,
270- chosenClass : 'sortable-chosen' ,
271- dragClass : 'sortable-drag' ,
272-
273- // This 'onEnd' function is the key to keeping the code list mirrored
274- onEnd : function ( evt ) {
275- // Get all items in the reordered selectedList
276- const mockupItems = Array . from ( selectedList . children ) ;
277-
278- // Reorder the selectedCodeList to match the new order of selectedList
279- const fragment = document . createDocumentFragment ( ) ;
280- mockupItems . forEach ( mockupItem => {
281- // Get the unique ID from the mockup item (added in the 'click' listener)
282- const uniqueId = mockupItem . dataset . uniqueId ;
283-
284- // Find the corresponding code item using the unique ID
285- const codeItem = selectedCodeList . querySelector ( `[data-unique-id="${ uniqueId } "]` ) ;
286-
287- if ( codeItem ) {
288- fragment . appendChild ( codeItem ) ;
289- }
290- } ) ;
291- selectedCodeList . appendChild ( fragment ) ;
292- }
293- } ) ;
294-
295- // Variable to generate unique IDs for mirrored elements
296- let uniqueItemId = 0 ;
297-
298- // --- Add Item Logic (Mirrors to both lists) ---
299- sourceList . addEventListener ( 'click' , ( event ) => {
300- const clickedItem = event . target . closest ( '.item' ) ;
301- if ( ! clickedItem ) return ;
302-
303- // 1. Generate a unique ID for the pair of list items
304- const currentUniqueId = uniqueItemId ++ ;
305-
306- // --- Mockup List Item ---
307- const newItemMockup = clickedItem . cloneNode ( true ) ;
308- newItemMockup . classList . remove ( 'item-selected' ) ;
309- // Add the unique ID to the mockup item
310- newItemMockup . dataset . uniqueId = currentUniqueId ;
311-
312- // Add a visual indicator (like a trash icon) for easy removal
313- const removeButton = document . createElement ( 'span' ) ;
314- removeButton . classList . add ( 'remove-item' , 'btn' , 'btn-danger' , 'btn-sm' , 'ms-2' ) ;
315- removeButton . textContent = 'X' ;
316- // Append the button to a div/span within the clone that will be visible
317- const contentContainer = document . createElement ( 'div' ) ;
318- contentContainer . style . display = 'flex' ;
319- contentContainer . style . alignItems = 'center' ;
320- contentContainer . innerHTML = newItemMockup . querySelector ( 'img' ) ? newItemMockup . querySelector ( 'img' ) . outerHTML : '' ;
321- contentContainer . appendChild ( removeButton ) ;
322-
323- // Replace the content of the list item
324- newItemMockup . innerHTML = '' ;
325- newItemMockup . appendChild ( contentContainer ) ;
326-
327-
328- // --- Code List Item ---
329- const newItemCode = document . createElement ( 'li' ) ;
330- newItemCode . classList . add ( 'item' , 'col-12' ) ; // Use col-12 for full width in the code tab
331- // Add the unique ID to the code item
332- newItemCode . dataset . uniqueId = currentUniqueId ;
333-
334- // Get the HTML code from the original item's <code> tag
335- const codeElement = clickedItem . querySelector ( 'code' ) ;
336- if ( codeElement ) {
337- // Create a new <code> element for the code list
338- const newCodeBlock = document . createElement ( 'code' ) ;
339- newCodeBlock . textContent = codeElement . textContent . trim ( ) ;
340- newCodeBlock . style . display = 'block' ; // Ensure the code block takes up space
341- newCodeBlock . style . whiteSpace = 'pre' ; // Preserve formatting
342- newCodeBlock . style . backgroundColor = '#f4f4f4' ;
343- newCodeBlock . style . padding = '5px' ;
344- newCodeBlock . style . marginBottom = '10px' ;
345- newItemCode . appendChild ( newCodeBlock ) ;
346- } else {
347- // If no <code> tag, just add a placeholder text
348- newItemCode . textContent = clickedItem . textContent . trim ( ) ;
349- }
350-
351- // 3. Add to both lists
352- selectedList . appendChild ( newItemMockup ) ;
353- selectedCodeList . appendChild ( newItemCode ) ;
354- } ) ;
355-
356- // --- Remove Item Logic (Mirrors to both lists) ---
357- selectedList . addEventListener ( 'click' , ( event ) => {
358- // Check if the actual remove button or the list item itself was clicked
359- const clickedRemoveButton = event . target . closest ( '.remove-item' ) ;
360- const clickedMockupItem = event . target . closest ( '.item' ) ;
361-
362- // Only proceed if a remove button or an item in the *selected list* was clicked
363- if ( ! clickedMockupItem || ! selectedList . contains ( clickedMockupItem ) ) return ;
364-
365- // Determine if we should remove the item
366- let itemToRemove = null ;
367- if ( clickedRemoveButton ) {
368- // If the explicit remove button was clicked, use its parent item
369- itemToRemove = clickedRemoveButton . closest ( '.item' ) ;
370- } else {
371- // If the item itself was clicked (and no explicit button), remove it
372- itemToRemove = clickedMockupItem ;
373- }
374-
375- if ( itemToRemove ) {
376- const uniqueIdToRemove = itemToRemove . dataset . uniqueId ;
377-
378- // 1. Remove from the Mockup list
379- itemToRemove . remove ( ) ;
380-
381- // 2. Find and remove the corresponding item from the Code list using the unique ID
382- const codeItemToRemove = selectedCodeList . querySelector ( `[data-unique-id="${ uniqueIdToRemove } "]` ) ;
383- if ( codeItemToRemove ) {
384- codeItemToRemove . remove ( ) ;
385- }
386- // console.log(`Removed pair with ID: ${uniqueIdToRemove}`);
387- }
388- } ) ;
389-
390- } ) ;
391- </ script >
211+ < script src ="../js/scripts.js "> </ script >
392212</ body >
393213
394214</ html >
0 commit comments