Nuzwa commited on
Commit
9a1ebba
·
verified ·
1 Parent(s): b17ced4

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +41 -81
index.html CHANGED
@@ -21,12 +21,10 @@
21
  .generate-btn { background: linear-gradient(90deg,#ff93e9,#9b7cff); border:none; border-radius:12px; padding:12px 18px; font-size:14px; cursor:pointer; color:#fff; min-height:56px; display:inline-flex; align-items:center; justify-content:center; transition:opacity .15s; }
22
  .generate-btn[disabled]{ opacity:0.6; cursor:default; }
23
 
24
- /* Always-visible control panel (no width/height fields) */
25
  .controls { display:flex; flex-wrap:wrap; gap:10px; padding:10px; border:1px solid rgba(255,255,255,0.06); background:#0f0f0f; border-radius:12px; }
26
  .controls label { font-size:13px; color:#eaeaea; display:flex; align-items:center; gap:6px; }
27
  .controls select, .controls input[type="number"] { background:#0c0c0c; border:1px solid rgba(255,255,255,0.04); color:#fff; padding:6px 8px; border-radius:8px; font-size:13px; min-width:90px; }
28
 
29
- /* Styles grid */
30
  .styles-wrap { margin-top:6px; }
31
  .styles-grid { display:grid; grid-template-columns:repeat(2, minmax(140px,1fr)); gap:8px; }
32
  @media (min-width:760px){ .styles-grid { grid-template-columns:repeat(5, minmax(120px,1fr)); } }
@@ -57,7 +55,6 @@
57
  <button id="generateBtn" class="generate-btn" aria-label="Generate">Generate</button>
58
  </div>
59
 
60
- <!-- Always-visible controls (no width/height) -->
61
  <div class="controls" id="controls">
62
  <label>Model
63
  <select id="model">
@@ -70,8 +67,8 @@
70
  <select id="aspect">
71
  <option value="1:1">1:1</option>
72
  <option value="16:9">16:9</option>
73
- <option value="19:6" selected>19:6</option>
74
- <option value="3:2">3:2</option>
75
  <option value="2:3">2:3</option>
76
  <option value="4:5">4:5</option>
77
  <option value="9:16">9:16</option>
@@ -92,7 +89,6 @@
92
  <label><input id="randomSeed" type="checkbox" checked /> Random</label>
93
  </div>
94
 
95
- <!-- Styles inline -->
96
  <div class="styles-wrap">
97
  <div class="note">Choose a style (optional):</div>
98
  <div class="styles-grid" id="stylesGrid">
@@ -109,41 +105,52 @@
109
  </div>
110
 
111
  <script>
112
-
113
- function applyDefaultsFromURL() {
114
- const params = new URLSearchParams(window.location.search);
115
-
116
- const aspect = params.get('default_aspect');
117
- const framing = params.get('default_framing');
118
-
119
- if (aspect) {
120
- const aspectDropdown = document.getElementById('aspectRatio');
121
- if (aspectDropdown) {
122
- aspectDropdown.value = aspect;
123
- aspectDropdown.dispatchEvent(new Event('change'));
124
- }
125
  }
126
 
127
- if (framing) {
128
- const framingDropdown = document.getElementById('framing');
129
- if (framingDropdown) {
130
- framingDropdown.value = framing;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
131
  }
132
  }
 
 
133
 
134
- // Save these defaults to local storage so they persist
135
- saveSettingsToStorage();
136
- }
137
-
138
- // Apply defaults right after settings load
139
- loadSettingsFromStorage();
140
- applyDefaultsFromURL();
141
-
142
  const baseUrl = 'https://image.pollinations.ai';
143
  let selectedStyle = null;
144
  let isGenerating = false;
145
 
146
- // Presets (cinema without letterbox; photo wider lens)
147
  const styleTemplates = {
148
  cinema: " cinematic lighting, rich color grading",
149
  realistic: " realistic stock photo",
@@ -158,7 +165,6 @@ applyDefaultsFromURL();
158
  full: "full body, head-to-toe, wide shot, 35mm lens, subject fully in frame, feet visible"
159
  };
160
 
161
- // Persist minimal settings (no width/height in storage)
162
  function saveSettings() {
163
  const s = {
164
  model: document.getElementById('model').value,
@@ -182,15 +188,14 @@ applyDefaultsFromURL();
182
  } catch(e) {}
183
  }
184
 
185
- // Aspect helpers → always compute high-res size within 2048
186
  function parseAspect(aspectStr){ const [w,h]=aspectStr.split(':').map(Number); return (!w||!h)?1:(w/h); }
187
  function sizeForAspect(aspectStr, maxDim=2048){
188
  const r = parseAspect(aspectStr);
189
- if (r >= 1){ // landscape or square
190
  const width = maxDim;
191
  const height = Math.max(64, Math.round(width / r));
192
  return {width, height};
193
- } else { // portrait
194
  const height = maxDim;
195
  const width = Math.max(64, Math.round(height * r));
196
  return {width, height};
@@ -199,7 +204,6 @@ applyDefaultsFromURL();
199
 
200
  loadSettings();
201
 
202
- // Style selection
203
  document.querySelectorAll('.style-card').forEach(card=>{
204
  card.addEventListener('click',()=>{
205
  document.querySelectorAll('.style-card').forEach(c=>c.classList.remove('selected'));
@@ -208,13 +212,11 @@ applyDefaultsFromURL();
208
  });
209
  });
210
 
211
- // Seed toggle
212
  const randomSeedEl = document.getElementById('randomSeed');
213
  const seedEl = document.getElementById('seed');
214
  randomSeedEl.addEventListener('change', ()=>{ seedEl.disabled = randomSeedEl.checked; saveSettings(); });
215
  seedEl.disabled = randomSeedEl.checked;
216
 
217
- // Prompt textarea UX
218
  const promptEl = document.getElementById('prompt');
219
  function autoResizeTextarea(){ promptEl.style.height='auto'; promptEl.style.height=Math.min(250, promptEl.scrollHeight)+'px'; }
220
  promptEl.addEventListener('input', autoResizeTextarea); setTimeout(autoResizeTextarea,0);
@@ -245,45 +247,3 @@ applyDefaultsFromURL();
245
  async function generateImage(){
246
  if (isGenerating) return;
247
  const rawPrompt = promptEl.value.trim();
248
- if (!rawPrompt){ const temp=document.createElement('div'); temp.className='image-card'; temp.innerHTML='<div class="muted">Please enter a prompt</div>'; imagesContainer.prepend(temp); setTimeout(()=>temp.remove(),1200); return; }
249
-
250
- isGenerating=true; generateBtn.disabled=true;
251
- const card=document.createElement('div'); card.className='image-card';
252
- card.innerHTML=`<div style="display:flex;align-items:center;"><div class="loader"></div><div class="muted">Generating...</div></div>`; imagesContainer.prepend(card);
253
-
254
- // Build prompt with selected style + framing
255
- const framingChoice=document.getElementById('framing').value;
256
- const aspect=document.getElementById('aspect').value;
257
- const enhanceOn=document.getElementById('enhance').checked;
258
-
259
- let promptWithStyle=rawPrompt;
260
- if (selectedStyle && styleTemplates[selectedStyle]) promptWithStyle += ' ' + styleTemplates[selectedStyle];
261
- if (framingTemplates[framingChoice]) promptWithStyle += ' ' + framingTemplates[framingChoice];
262
-
263
- const finalPrompt = enhanceOn ? await enhancePrompt(promptWithStyle) : promptWithStyle;
264
-
265
- // Always compute high-res size from aspect (no UI fields)
266
- const {width, height} = sizeForAspect(aspect, 2048);
267
-
268
- const model = encodeURIComponent(document.getElementById('model').value || 'flux');
269
- const seed = document.getElementById('randomSeed').checked ? randomInt(0, 4294967295) : (Number(seedEl.value) || 42);
270
-
271
- try{
272
- const url = `${baseUrl}/prompt/${encodeURIComponent(finalPrompt)}?model=${model}&width=${width}&height=${height}&seed=${seed}&nologo=true&safe=false`;
273
- const res = await fetch(url); if(!res.ok) throw new Error('Network '+res.status);
274
- const blob = await res.blob(); const imgUrl = URL.createObjectURL(blob);
275
- const filename = `image_${width}x${height}_seed${seed}.png`;
276
- card.innerHTML = `<img src="${imgUrl}" alt="generated image">`;
277
- card.appendChild(makeActionsBar(imgUrl, filename, finalPrompt, seed, width, height));
278
- }catch(err){
279
- console.error(err); card.innerHTML = `<div class="muted" style="color:#ff6b6b;">Error generating image</div>`;
280
- }finally{
281
- isGenerating=false; generateBtn.disabled=false; saveSettings();
282
- }
283
- }
284
-
285
- document.getElementById('generateBtn').addEventListener('click', generateImage);
286
- promptEl.addEventListener('keydown', (e)=>{ if(e.key==='Enter'&&(e.ctrlKey||e.metaKey)) generateImage(); });
287
- </script>
288
- </body>
289
- </html>
 
21
  .generate-btn { background: linear-gradient(90deg,#ff93e9,#9b7cff); border:none; border-radius:12px; padding:12px 18px; font-size:14px; cursor:pointer; color:#fff; min-height:56px; display:inline-flex; align-items:center; justify-content:center; transition:opacity .15s; }
22
  .generate-btn[disabled]{ opacity:0.6; cursor:default; }
23
 
 
24
  .controls { display:flex; flex-wrap:wrap; gap:10px; padding:10px; border:1px solid rgba(255,255,255,0.06); background:#0f0f0f; border-radius:12px; }
25
  .controls label { font-size:13px; color:#eaeaea; display:flex; align-items:center; gap:6px; }
26
  .controls select, .controls input[type="number"] { background:#0c0c0c; border:1px solid rgba(255,255,255,0.04); color:#fff; padding:6px 8px; border-radius:8px; font-size:13px; min-width:90px; }
27
 
 
28
  .styles-wrap { margin-top:6px; }
29
  .styles-grid { display:grid; grid-template-columns:repeat(2, minmax(140px,1fr)); gap:8px; }
30
  @media (min-width:760px){ .styles-grid { grid-template-columns:repeat(5, minmax(120px,1fr)); } }
 
55
  <button id="generateBtn" class="generate-btn" aria-label="Generate">Generate</button>
56
  </div>
57
 
 
58
  <div class="controls" id="controls">
59
  <label>Model
60
  <select id="model">
 
67
  <select id="aspect">
68
  <option value="1:1">1:1</option>
69
  <option value="16:9">16:9</option>
70
+ <option value="19:6">19:6</option>
71
+ <option value="3:2" selected>3:2</option>
72
  <option value="2:3">2:3</option>
73
  <option value="4:5">4:5</option>
74
  <option value="9:16">9:16</option>
 
89
  <label><input id="randomSeed" type="checkbox" checked /> Random</label>
90
  </div>
91
 
 
92
  <div class="styles-wrap">
93
  <div class="note">Choose a style (optional):</div>
94
  <div class="styles-grid" id="stylesGrid">
 
105
  </div>
106
 
107
  <script>
108
+ (function initDefaultsFromURL() {
109
+ if (document.readyState === 'loading') {
110
+ document.addEventListener('DOMContentLoaded', applyDefaultsFromURLSafe);
111
+ } else {
112
+ applyDefaultsFromURLSafe();
 
 
 
 
 
 
 
 
113
  }
114
 
115
+ function applyDefaultsFromURLSafe() {
116
+ try {
117
+ const params = new URLSearchParams(window.location.search);
118
+ const aspectParam = params.get('default_aspect');
119
+ const framingParam = params.get('default_framing');
120
+ const framingMap = { 'full-body': 'full', 'close-up': 'close' };
121
+
122
+ const aspectEl = document.getElementById('aspect');
123
+ const framingEl = document.getElementById('framing');
124
+
125
+ if (aspectEl) {
126
+ const defaultAspect = aspectParam || '3:2';
127
+ const hasOption = Array.from(aspectEl.options).some(o => o.value === defaultAspect);
128
+ if (hasOption) {
129
+ aspectEl.value = defaultAspect;
130
+ }
131
+ }
132
+
133
+ if (framingEl && (framingParam || framingMap[framingParam])) {
134
+ const normalized = framingMap[framingParam] || framingParam;
135
+ const hasOption = Array.from(framingEl.options).some(o => o.value === normalized);
136
+ if (hasOption) framingEl.value = normalized;
137
+ }
138
+
139
+ if (typeof saveSettings === 'function') {
140
+ saveSettings();
141
+ }
142
+ } catch (e) {
143
+ console.error('applyDefaultsFromURL failed:', e);
144
  }
145
  }
146
+ })();
147
+ </script>
148
 
149
+ <script>
 
 
 
 
 
 
 
150
  const baseUrl = 'https://image.pollinations.ai';
151
  let selectedStyle = null;
152
  let isGenerating = false;
153
 
 
154
  const styleTemplates = {
155
  cinema: " cinematic lighting, rich color grading",
156
  realistic: " realistic stock photo",
 
165
  full: "full body, head-to-toe, wide shot, 35mm lens, subject fully in frame, feet visible"
166
  };
167
 
 
168
  function saveSettings() {
169
  const s = {
170
  model: document.getElementById('model').value,
 
188
  } catch(e) {}
189
  }
190
 
 
191
  function parseAspect(aspectStr){ const [w,h]=aspectStr.split(':').map(Number); return (!w||!h)?1:(w/h); }
192
  function sizeForAspect(aspectStr, maxDim=2048){
193
  const r = parseAspect(aspectStr);
194
+ if (r >= 1){
195
  const width = maxDim;
196
  const height = Math.max(64, Math.round(width / r));
197
  return {width, height};
198
+ } else {
199
  const height = maxDim;
200
  const width = Math.max(64, Math.round(height * r));
201
  return {width, height};
 
204
 
205
  loadSettings();
206
 
 
207
  document.querySelectorAll('.style-card').forEach(card=>{
208
  card.addEventListener('click',()=>{
209
  document.querySelectorAll('.style-card').forEach(c=>c.classList.remove('selected'));
 
212
  });
213
  });
214
 
 
215
  const randomSeedEl = document.getElementById('randomSeed');
216
  const seedEl = document.getElementById('seed');
217
  randomSeedEl.addEventListener('change', ()=>{ seedEl.disabled = randomSeedEl.checked; saveSettings(); });
218
  seedEl.disabled = randomSeedEl.checked;
219
 
 
220
  const promptEl = document.getElementById('prompt');
221
  function autoResizeTextarea(){ promptEl.style.height='auto'; promptEl.style.height=Math.min(250, promptEl.scrollHeight)+'px'; }
222
  promptEl.addEventListener('input', autoResizeTextarea); setTimeout(autoResizeTextarea,0);
 
247
  async function generateImage(){
248
  if (isGenerating) return;
249
  const rawPrompt = promptEl.value.trim();