Przeglądaj źródła

Improved styling of sand-converter. Added api-key to cookie save.

Thokoop 11 miesięcy temu
rodzic
commit
e2de8b5b38
5 zmienionych plików z 186 dodań i 185 usunięć
  1. 48 59
      static/css/image2sand.css
  2. 3 3
      static/css/style.css
  3. 12 7
      static/js/image2sand-init.js
  4. 9 1
      static/js/main.js
  5. 114 115
      templates/index.html

+ 48 - 59
static/css/image2sand.css

@@ -1,36 +1,20 @@
-/* Image Converter Dialog Styles */
-.image-converter-overlay {
-    position: fixed;
-    top: 0;
-    left: 0;
-    width: 100%;
-    height: 100%;
-    background-color: rgba(0, 0, 0, 0.7);
-    z-index: 1000;
+/* Image Converter Section Styles */
+.image-converter-content {
+    overflow-y: auto;
     display: flex;
-    justify-content: center;
-    align-items: center;
-    opacity: 0;
-    visibility: hidden;
-    transition: opacity 0.3s, visibility 0.3s;
+    flex-direction: column;
+    gap: 20px;
+    flex-grow: 1;
 }
 
-.image-converter-overlay.visible {
-    opacity: 1;
-    visibility: visible;
+.image-converter-steps {
+    flex-wrap: wrap;
+    gap: 10px;
+    display: flex;
 }
 
-.image-converter-dialog {
-    background-color: var(--background-secondary);
-    border-radius: 8px;
-    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
-    width: 90%;
-    max-width: 1000px;
-    max-height: 90vh;
-    overflow-y: auto;
-    padding: 20px;
-    position: relative;
-    color: var(--text-primary);
+.image-converter-steps > .image-converter-preview {
+    width: 33%;
 }
 
 .image-converter-header {
@@ -47,21 +31,6 @@
     color: var(--theme-secondary-hover);
 }
 
-.image-converter-close {
-    background: none;
-    border: none;
-    font-size: 1.5rem;
-    cursor: pointer;
-    color: var(--text-primary);
-}
-
-.image-converter-grid {
-    display: grid;
-    grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
-    gap: 20px;
-    margin-bottom: 20px;
-}
-
 .preview-controls-container {
     display: grid;
     grid-template-columns: minmax(300px, 1fr) minmax(300px, 1fr);
@@ -69,29 +38,20 @@
     margin-bottom: 20px;
 }
 
-@media (max-width: 768px) {
-    .image-converter-grid,
-    .preview-controls-container {
-        grid-template-columns: 1fr;
-    }
-}
-
 .image-converter-settings {
     display: flex;
     flex-direction: column;
     gap: 15px;
     padding: 15px;
-    background-color: var(--background-tertiary);
-    border-radius: 6px;
-    border: 1px solid var(--border-primary);
 }
 
-.image-converter-preview, 
+.image-converter-preview,
 .sand-garden-preview {
     display: flex;
     flex-direction: column;
     align-items: center;
     margin-bottom: 15px;
+    flex-grow: 1;
 }
 
 .image-converter-preview canvas,
@@ -115,6 +75,12 @@
     min-height: 250px;
 }
 
+#connect-image {
+    /*border: 1px solid var(--border-primary);*/
+    /*background: var(--theme-secondary);*/
+    padding: 15px;
+}
+
 .sand-garden-preview canvas {
     min-height: 250px;
 }
@@ -272,8 +238,12 @@
 }
 
 @keyframes spin {
-    0% { transform: rotate(0deg); }
-    100% { transform: rotate(360deg); }
+    0% {
+        transform: rotate(0deg);
+    }
+    100% {
+        transform: rotate(360deg);
+    }
 }
 
 #total-points {
@@ -295,9 +265,9 @@ input[type="range"] {
 /* Ensure the dialog transitions smoothly with theme changes */
 .image-converter-dialog * {
     transition: background-color var(--transition-fast),
-                color var(--transition-fast),
-                border-color var(--transition-fast);
-} 
+    color var(--transition-fast),
+    border-color var(--transition-fast);
+}
 
 .gen-button {
     margin-left: 10px;
@@ -305,4 +275,23 @@ input[type="range"] {
 
 canvas#connect-image {
     clip-path: ellipse();
+}
+
+
+@media (min-width: 769px) {
+    .image-converter-content {
+        flex-direction: row;
+    }
+
+    .image-converter-content > div {
+        width: calc(100% / 3);
+    }
+
+    .image-converter-steps {
+        overflow-y: auto;
+    }
+
+    .image-converter-steps > .image-converter-preview:last-of-type {
+        max-width: none;
+    }
 }

+ 3 - 3
static/css/style.css

@@ -15,7 +15,7 @@
     --background-secondary-dark: #1e1e1e;
     --background-tertiary-dark: #2d2d2d;
     --background-accent-dark: #4e453fef;
-    --background-translucent-dark: rgba(18, 18, 18, 0.5);
+    --background-translucent-dark: rgba(18, 18, 18, 0.75);
     --text-primary-dark: #eeeeee;
     --text-secondary-dark: #fff;
     --border-primary-dark: #404040;
@@ -161,7 +161,7 @@ header {
     position: sticky;
     height: 50px;
     top: 0;
-    z-index: 10;
+    z-index: 20;
     background: var(--background-primary);
     display: flex;
     justify-content: center;
@@ -484,7 +484,7 @@ section.sticky {
 
 section.sticky.fullscreen {
     position: fixed;
-    top: 0;
+    top: 50px;
     left: 0;
     width: 100vw;
     max-height: none;

+ 12 - 7
static/js/image2sand-init.js

@@ -37,9 +37,10 @@ function openImageConverter(file) {
         drawAndPrepImage(img);
         
         // Show the converter dialog
-        const overlay = document.getElementById('image-converter-overlay');
+        const overlay = document.getElementById('image-converter');
+        overlay.classList.remove('hidden');
         overlay.classList.add('visible');
-        
+
         // Initialize the UI elements
         initializeUI();
         
@@ -160,9 +161,10 @@ function clearCanvas(canvasId) {
  * Close the image converter dialog
  */
 function closeImageConverter() {
-    const overlay = document.getElementById('image-converter-overlay');
+    const overlay = document.getElementById('image-converter');
     overlay.classList.remove('visible');
-    
+    overlay.classList.add('hidden');
+
     // Clear the canvases
     clearCanvas('original-image');
     clearCanvas('edge-image');
@@ -184,6 +186,10 @@ async function generateOpenAIImage(apiKey, prompt) {
         logMessage("Image is still generating - please don't press the button.", LOG_TYPE.INFO);
     } else {
         isGeneratingImage = true;
+        clearCanvas('original-image');
+        clearCanvas('edge-image');
+        clearCanvas('dot-image');
+        clearCanvas('connect-image');
         document.getElementById('gen-image-button').disabled = true;
         // Show processing indicator
         const processingIndicator = document.getElementById('processing-status');
@@ -245,7 +251,6 @@ async function generateOpenAIImage(apiKey, prompt) {
 
 }
 
-
 // Override the uploadThetaRho function to handle image files
 const originalUploadThetaRho = window.uploadThetaRho;
 
@@ -274,8 +279,8 @@ document.getElementById('gen-image-button').addEventListener('click', function()
     let apiKey = document.getElementById('api-key').value;
     const prompt = document.getElementById('prompt').value + (document.getElementById('googly-eyes').checked ? ' with disproportionately large googly eyes' : '');
     // Show the converter dialog
-    const overlay = document.getElementById('image-converter-overlay');
-    overlay.classList.add('visible');
+    const overlay = document.getElementById('image-converter');
+    overlay.classList.remove('hidden');
     // Initialize the UI elements
     initializeUI();
     generateOpenAIImage(apiKey, prompt);

+ 9 - 1
static/js/main.js

@@ -1492,7 +1492,7 @@ function attachFullScreenListeners() {
             const stickySection = this.closest('.sticky'); // Find the closest sticky section
             if (stickySection) {
                 // Close all other sections
-                document.querySelectorAll('.sticky:not(#currently-playing-container)').forEach(section => {
+                document.querySelectorAll('.sticky:not(#currently-playing-container):not(#image-converter)').forEach(section => {
                     if (section !== stickySection) {
                         section.classList.remove('fullscreen');
                         section.classList.remove('visible');
@@ -1565,11 +1565,13 @@ function saveSettingsToCookies() {
     const clearPattern = document.getElementById('clear_pattern').value;
     const runMode = document.querySelector('input[name="run_mode"]:checked').value;
     const shuffle = document.getElementById('shuffle_playlist').checked;
+    const apiKey = document.getElementById('api-key').value;
 
     setCookie('pause_time', pauseTime, 365);
     setCookie('clear_pattern', clearPattern, 365);
     setCookie('run_mode', runMode, 365);
     setCookie('shuffle', shuffle, 365);
+    setCookie('api_key', apiKey, 365);
 }
 
 // Load settings from cookies
@@ -1594,6 +1596,11 @@ function loadSettingsFromCookies() {
         document.getElementById('shuffle_playlist').checked = shuffle === 'true';
     }
 
+    const apiKey = getCookie('api_key');
+    if (apiKey !== '') {
+        document.getElementById('api-key').value = apiKey;
+    }
+
     logMessage('Settings loaded from cookies.');
 }
 
@@ -1606,6 +1613,7 @@ function attachSettingsSaveListeners() {
         input.addEventListener('change', saveSettingsToCookies);
     });
     document.getElementById('shuffle_playlist').addEventListener('change', saveSettingsToCookies);
+    document.getElementById('api-key').addEventListener('change', saveSettingsToCookies);
 }
 
 

+ 114 - 115
templates/index.html

@@ -47,7 +47,7 @@
             <div id="generate" class="add-to-container hidden">
                 <div class="action-buttons">
                     <div id="api-key-group"></div>
-                    <input type="text" id="api-key" placeholder="Enter a valid OpenAI API key">
+                    <input type="password" id="api-key" placeholder="Enter a valid OpenAI API key">
                     <input type="text" id="prompt" placeholder="What do you want to draw?" maxlength="500">
                     <div class="checkbox-container">
                         <input type="checkbox" id="googly-eyes" name="googly-eyes">
@@ -130,6 +130,119 @@
                 </div>
             </div>
         </section>
+
+        <section id="image-converter" class="sticky hidden fullscreen">
+            <div class="header">
+                <h2>Convert Image to Pattern</h2>
+                <button class="close-button no-bg" onclick="closeImageConverter()">
+                    <i class="fa-solid fa-xmark"></i>
+                </button>
+            </div>
+            <div class="image-converter-content">
+                <div id="processing-status" class="processing-indicator">
+                    <div class="spinner"></div>
+                    <span id="processing-message">Processing image...</span>
+                </div>
+                <div class="image-converter-steps">
+                    <div class="image-converter-preview">
+                        <h3>Original Image</h3>
+                        <canvas id="original-image"></canvas>
+                    </div>
+                    <div class="image-converter-preview">
+                        <h3>Detected Edges</h3>
+                        <canvas id="edge-image"></canvas>
+                    </div>
+                    <div class="image-converter-preview">
+                        <h3>Identified Points</h3>
+                        <canvas id="dot-image"></canvas>
+                    </div>
+                </div>
+
+                <div class="image-converter-settings">
+                    <div class="setting-item">
+                        <label for="epsilon-slider">Detail Level</label>
+                        <div class="slider-container">
+                            <input type="range" id="epsilon-slider" min="0.1" max="20" step="0.1" value="0.5">
+                            <div class="slider-labels">
+                                <small>Fine</small>
+                                <small id="epsilon-value-display">0.5</small>
+                                <small>Coarse</small>
+                            </div>
+                        </div>
+                    </div>
+                    <div class="setting-item">
+                        <label for="dot-number">Point Limit</label>
+                        <select id="dot-number">
+                            <option value="100">100 points</option>
+                            <option value="200">200 points</option>
+                            <option value="300">300 points</option>
+                            <option value="400">400 points</option>
+                            <option value="500" selected>500 points</option>
+                            <option value="1000">1000 points</option>
+                        </select>
+                    </div>
+                    <div class="setting-item">
+                        <label for="contour-mode">Contour Mode</label>
+                        <select id="contour-mode">
+                            <option value="External">External Only</option>
+                            <option value="Tree" selected>External + Internal</option>
+                        </select>
+                    </div>
+                    <div class="checkbox-group">
+                        <div class="checkbox-container">
+                            <input type="checkbox" id="is-loop" checked>
+                            <label for="is-loop">Loop Drawing</label>
+                        </div>
+                        <div class="checkbox-container">
+                            <input type="checkbox" id="no-shortcuts" checked>
+                            <label for="no-shortcuts">No Shortcuts</label>
+                        </div>
+                    </div>
+                    <input type="hidden" id="output-type" value="2">
+                    <div class="generate-button-container">
+                        <button id="generate-button" class="cta" onclick="convertImage()">
+                            <i class="fa-solid fa-wand-magic-sparkles"></i>
+                            <span>Regenerate Pattern</span>
+                        </button>
+                    </div>
+                </div>
+
+                <div class="sand-garden-preview">
+                    <h3>Sand Garden Preview</h3>
+                    <canvas id="connect-image"></canvas>
+                    <div id="total-points"></div>
+                    <div style="display: none;">
+                        <h4>contours</h4>
+                        <canvas id="plotcontours" width="400" height="400" style="border:1px solid #000000;"></canvas>
+                        <button id="plotButton">Plot Next Contour</button>
+                    </div>
+                </div>
+
+                <div style="display: none;">
+                    <!-- hidden inputs for image2sand compatibility. -->
+                    <label id="generation-status" style="display: none;">Image is generating - please wait...</label>
+                    <textarea id="polar-coordinates-textarea"></textarea>
+                    <div id="simple-coords"></div>
+                    <div id="simple-coords-title"></div>
+                    <input type="checkbox" id="gaussian-blur-toggle">
+                    <div>
+                        <input type="file" id="file-input">
+                        <button id="file-button"></button>
+                        <span id="file-name"></span>
+                    </div>
+                </div>
+            </div>
+            <div class="image-converter-actions">
+                <button class="cancel" onclick="closeImageConverter()">
+                    <i class="fa-solid fa-xmark"></i>
+                    <span>Cancel</span>
+                </button>
+                <button class="cta" id="save-pattern-button" onclick="saveConvertedPattern()">
+                    <i class="fa-solid fa-floppy-disk"></i>
+                    <span>Save Pattern</span>
+                </button>
+            </div>
+        </section>
     </main>
 
     <!-- Playlists Tab -->
@@ -445,120 +558,6 @@
     <!-- Messages will be appended here -->
 </div>
 
-<div id="image-converter-overlay" class="image-converter-overlay">
-    <div class="image-converter-dialog">
-        <div class="image-converter-header">
-            <h2>Convert Image to Pattern</h2>
-            <button class="image-converter-close" onclick="closeImageConverter()">
-                <i class="fa-solid fa-xmark"></i>
-            </button>
-        </div>
-        <div class="image-converter-grid grid">
-            <div class="image-converter-preview">
-                <h3>Original Image</h3>
-                <canvas id="original-image"></canvas>
-            </div>
-            <div class="image-converter-preview">
-                <h3>Detected Edges</h3>
-                <canvas id="edge-image"></canvas>
-            </div>
-            <div class="image-converter-preview">
-                <h3>Identified Points</h3>
-                <canvas id="dot-image"></canvas>
-            </div>
-        </div>
-        
-        <div class="preview-controls-container">
-            <div class="sand-garden-preview">
-                <h3>Sand Garden Preview</h3>
-                <canvas id="connect-image"></canvas>
-                <div id="total-points"></div>
-                <div style="display: none;">
-                    <h4>contours</h4>
-                    <canvas id="plotcontours" width="400" height="400" style="border:1px solid #000000;"></canvas>
-                    <button id="plotButton">Plot Next Contour</button>
-                </div>
-            </div>
-            
-            <div class="image-converter-settings">
-                <div class="setting-item">
-                    <label for="epsilon-slider">Detail Level</label>
-                    <div class="slider-container">
-                        <input type="range" id="epsilon-slider" min="0.1" max="20" step="0.1" value="0.5">
-                        <div class="slider-labels">
-                            <small>Fine</small>
-                            <small id="epsilon-value-display">0.5</small>
-                            <small>Coarse</small>
-                        </div>
-                    </div>
-                </div>
-                <div class="setting-item">
-                    <label for="dot-number">Point Limit</label>
-                    <select id="dot-number">
-                        <option value="100">100 points</option>
-                        <option value="200">200 points</option>
-                        <option value="300">300 points</option>
-                        <option value="400">400 points</option>
-                        <option value="500" selected>500 points</option>
-                        <option value="1000">1000 points</option>
-                    </select>
-                </div>
-                <div class="setting-item">
-                    <label for="contour-mode">Contour Mode</label>
-                    <select id="contour-mode">
-                        <option value="External">External Only</option>
-                        <option value="Tree" selected>External + Internal</option>
-                    </select>
-                </div>
-                <div class="checkbox-group">
-                    <div class="checkbox-container">
-                        <input type="checkbox" id="is-loop" checked>
-                        <label for="is-loop">Loop Drawing</label>
-                    </div>
-                    <div class="checkbox-container">
-                        <input type="checkbox" id="no-shortcuts" checked>
-                        <label for="no-shortcuts">No Shortcuts</label>
-                    </div>
-                </div>
-                <input type="hidden" id="output-type" value="2">
-                <div class="generate-button-container">
-                    <button id="generate-button" class="cta" onclick="convertImage()">
-                        <i class="fa-solid fa-wand-magic-sparkles"></i>
-                        <span>Regenerate Pattern</span>
-                    </button>
-                </div>
-            </div>
-        </div>
-        <div class="image-converter-actions">
-            <button class="cancel" onclick="closeImageConverter()">
-                <i class="fa-solid fa-xmark"></i>
-                <span>Cancel</span>
-            </button>
-            <button class="cta" id="save-pattern-button" onclick="saveConvertedPattern()">
-                <i class="fa-solid fa-floppy-disk"></i>
-                <span>Save Pattern</span>
-            </button>
-        </div>
-        <div id="processing-status" class="processing-indicator">
-            <div class="spinner"></div>
-            <span id="processing-message">Processing image...</span>
-        </div>
-        <div style="display: none;">
-            <!-- hidden inputs for image2sand compatibility. -->
-            <label id="generation-status" style="display: none;">Image is generating - please wait...</label>
-            <textarea id="polar-coordinates-textarea"></textarea>
-            <div id="simple-coords"></div>
-            <div id="simple-coords-title"></div>
-            <input type="checkbox" id="gaussian-blur-toggle">
-            <div>
-                <input type="file" id="file-input">
-                <button id="file-button"></button>
-                <span id="file-name"></span>
-            </div>
-        </div>        
-    </div>
-</div>
-
 <script src="../static/js/main.js"></script>
 <script src="../static/js/image2sand.js"></script>
 <script src="../static/js/image2sand-init.js"></script>