aminskjen commited on
Commit
2c623f1
·
verified ·
1 Parent(s): ff7275e

Update static/js/script.js

Browse files
Files changed (1) hide show
  1. static/js/script.js +82 -154
static/js/script.js CHANGED
@@ -1,4 +1,4 @@
1
- // InkBoard JavaScript - Main Application Logic
2
 
3
  class InkBoard {
4
  constructor() {
@@ -10,30 +10,28 @@ class InkBoard {
10
  init() {
11
  this.setupEventListeners();
12
  this.loadGallery();
13
- this.showSection('create');
14
  }
15
 
16
  setupEventListeners() {
17
- // Scene form submission
18
- document.getElementById('scene-form').addEventListener('submit', (e) => {
19
  e.preventDefault();
20
  this.generateContent();
21
  });
22
 
23
- // Journal modal save button
24
- document.getElementById('save-journal').addEventListener('click', () => {
25
  this.saveJournal();
26
  });
27
 
28
- // Handle modal close
29
- document.getElementById('journalModal').addEventListener('hidden.bs.modal', () => {
30
  this.currentCreationId = null;
31
  document.getElementById('journal-text').value = '';
32
  });
33
  }
34
 
35
  async generateContent() {
36
- const sceneIdea = document.getElementById('scene-idea').value.trim();
 
37
 
38
  if (!sceneIdea) {
39
  this.showAlert('Please enter a scene idea', 'danger');
@@ -50,12 +48,9 @@ class InkBoard {
50
  body: JSON.stringify({ scene_idea: sceneIdea })
51
  });
52
 
53
- const contentType = response.headers.get("content-type");
54
- if (!contentType || !contentType.includes("application/json")) {
55
- const text = await response.text();
56
- console.error("Non-JSON response:", text);
57
- this.showAlert("Server error or you're not logged in", "danger");
58
- return;
59
  }
60
 
61
  const data = await response.json();
@@ -63,15 +58,15 @@ class InkBoard {
63
  if (data.success) {
64
  this.displayResult(data);
65
  this.loadGallery();
66
- document.getElementById('scene-idea').value = '';
67
- this.showAlert('Story and image generated successfully!', 'success');
68
  } else {
69
  this.showAlert(data.error || 'Failed to generate content', 'danger');
70
  }
71
 
72
  } catch (error) {
73
  console.error('Error generating content:', error);
74
- this.showAlert('Network error. Please try again.', 'danger');
75
  } finally {
76
  this.showLoading(false);
77
  this.setButtonLoading(false);
@@ -83,70 +78,53 @@ class InkBoard {
83
 
84
  const imageSection = data.image_url ? `
85
  <div class="col-lg-6 mb-4">
86
- <div class="image-container">
87
- <img src="${data.image_url}" alt="Generated Scene" class="img-fluid rounded shadow">
88
- </div>
89
  </div>` : '';
90
 
91
  const storyColClass = data.image_url ? 'col-lg-6' : 'col-12';
92
-
93
  const downloadButton = data.image_url ? `
94
  <button class="btn btn-outline-success btn-sm" onclick="inkBoard.downloadImage('${data.image_url}')">
95
- <i class="fas fa-download me-1"></i>
96
- Download Image
97
  </button>` : '';
98
 
99
- const resultHTML = `
100
- <div class="col-12 mb-5">
101
- <div class="card shadow-lg border-0">
102
- <div class="card-body p-4">
103
- <h4 class="card-title text-center mb-4">
104
- <i class="fas fa-sparkles me-2"></i>
105
- Your Creation
106
- </h4>
107
- <div class="row">
108
- ${imageSection}
109
- <div class="${storyColClass}">
110
- <div class="story-container">
111
- <h5 class="mb-3">
112
- <i class="fas fa-book-open me-2"></i>
113
- Your Story
114
- </h5>
115
- <p class="story-text">${data.story}</p>
116
- <div class="mt-3">
117
- <button class="btn btn-outline-primary btn-sm me-2" onclick="inkBoard.openJournal('${data.creation_id}')">
118
- <i class="fas fa-journal-whills me-1"></i>
119
- Add Journal Entry
120
- </button>
121
- ${downloadButton}
122
- </div>
123
- </div>
124
- </div>
125
- </div>
126
  </div>
127
  </div>
128
  </div>
129
  `;
130
-
131
- resultsSection.innerHTML = resultHTML;
132
  resultsSection.scrollIntoView({ behavior: 'smooth' });
133
  }
134
 
135
  async loadGallery() {
136
  try {
137
  const response = await fetch('/get_creations');
 
 
 
 
 
 
 
138
  const data = await response.json();
139
  const galleryGrid = document.getElementById('gallery-grid');
140
 
141
- if (data.creations && data.creations.length > 0) {
142
- const galleryHTML = data.creations.map(c => this.createGalleryItem(c)).join('');
143
- galleryGrid.innerHTML = galleryHTML;
144
  } else {
145
  galleryGrid.innerHTML = `
146
- <div class="col-12 text-center py-5">
147
- <i class="fas fa-palette fa-3x text-muted mb-3"></i>
148
- <h5 class="text-muted">No creations yet</h5>
149
- <p class="text-muted">Start by describing a scene above!</p>
150
  </div>`;
151
  }
152
  } catch (error) {
@@ -156,122 +134,72 @@ class InkBoard {
156
 
157
  createGalleryItem(creation) {
158
  const journalEntry = creation.journal_entry ? `
159
- <div class="journal-entry">
160
- <small class="text-muted">
161
- <i class="fas fa-journal-whills me-1"></i>
162
- Journal Entry:
163
- </small>
164
- <p class="mb-0 mt-1">${creation.journal_entry}</p>
165
- </div>` : '';
166
-
167
- const imageSection = creation.image_url ?
168
- `<img src="${creation.image_url}" alt="Scene: ${creation.scene_idea}" loading="lazy">` : '';
169
-
170
- const downloadButton = creation.image_url ?
171
- `<button class="btn btn-outline-success btn-sm" onclick="inkBoard.downloadImage('${creation.image_url}')">
172
- <i class="fas fa-download me-1"></i>
173
- Download
174
- </button>` : '';
175
 
176
  return `
177
- <div class="gallery-item">
178
- ${imageSection}
179
- <div class="gallery-item-content">
180
- <div class="gallery-item-scene">
181
- <i class="fas fa-quote-left me-1"></i>
182
- ${creation.scene_idea}
183
- </div>
184
- <div class="gallery-item-story">
185
- ${creation.story}
186
- </div>
187
- ${journalEntry}
188
- <div class="gallery-item-actions">
189
- <button class="btn btn-outline-primary btn-sm" onclick="inkBoard.openJournal('${creation.id}', '${creation.journal_entry || ''}')">
190
- <i class="fas fa-journal-whills me-1"></i>
191
- ${creation.journal_entry ? 'Edit' : 'Add'} Journal
192
- </button>
193
- ${downloadButton}
194
- </div>
195
- </div>
196
  </div>`;
197
  }
198
 
199
- openJournal(creationId, existingText = '') {
200
- this.currentCreationId = creationId;
201
- document.getElementById('journal-text').value = existingText;
202
-
203
  const modal = new bootstrap.Modal(document.getElementById('journalModal'));
204
  modal.show();
205
  }
206
 
207
  async saveJournal() {
208
- if (!this.currentCreationId) {
209
- this.showAlert('No creation selected', 'danger');
210
- return;
211
- }
212
 
213
- const journalText = document.getElementById('journal-text').value.trim();
214
-
215
- try {
216
- const res = await fetch('/save_journal', {
217
- method: 'POST',
218
- headers: { 'Content-Type': 'application/json' },
219
- body: JSON.stringify({
220
- creation_id: this.currentCreationId,
221
- journal_entry: journalText
222
- })
223
- });
224
-
225
- const data = await res.json();
226
-
227
- if (data.success) {
228
- this.showAlert('Journal saved successfully!', 'success');
229
- this.loadGallery();
230
- const modal = bootstrap.Modal.getInstance(document.getElementById('journalModal'));
231
- modal.hide();
232
- } else {
233
- this.showAlert('Failed to save journal.', 'danger');
234
- }
235
- } catch (error) {
236
- console.error('Error saving journal:', error);
237
- this.showAlert('Network error.', 'danger');
238
- }
239
  }
240
 
241
- downloadImage(url) {
242
- const a = document.createElement('a');
243
- a.href = url;
244
- a.download = 'inkboard-image.png';
245
- document.body.appendChild(a);
246
- a.click();
247
- document.body.removeChild(a);
248
  }
249
 
250
- showAlert(message, type = 'info') {
251
- const alertBox = document.getElementById('alert-box');
252
- alertBox.innerHTML = `
253
- <div class="alert alert-${type} alert-dismissible fade show" role="alert">
254
- ${message}
255
- <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
256
- </div>`;
257
  }
258
 
259
- showLoading(state) {
260
- const loader = document.getElementById('loading-spinner');
261
- loader.style.display = state ? 'block' : 'none';
 
 
 
 
262
  }
263
 
264
- setButtonLoading(loading) {
265
- const button = document.getElementById('generate-btn');
266
- button.disabled = loading;
267
- button.innerHTML = loading ? `<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> Generating...` : `Generate`;
268
  }
269
 
270
- showSection(section) {
271
- this.currentSection = section;
272
- // Add logic here if needed for tab switching
 
 
 
 
273
  }
274
  }
275
 
276
- // Initialize
277
  const inkBoard = new InkBoard();
 
1
+ // --- InkBoard JavaScript (Fixed) ---
2
 
3
  class InkBoard {
4
  constructor() {
 
10
  init() {
11
  this.setupEventListeners();
12
  this.loadGallery();
13
+ this.showSection('create'); // Default
14
  }
15
 
16
  setupEventListeners() {
17
+ document.getElementById('scene-form')?.addEventListener('submit', (e) => {
 
18
  e.preventDefault();
19
  this.generateContent();
20
  });
21
 
22
+ document.getElementById('save-journal')?.addEventListener('click', () => {
 
23
  this.saveJournal();
24
  });
25
 
26
+ document.getElementById('journalModal')?.addEventListener('hidden.bs.modal', () => {
 
27
  this.currentCreationId = null;
28
  document.getElementById('journal-text').value = '';
29
  });
30
  }
31
 
32
  async generateContent() {
33
+ const sceneIdeaInput = document.getElementById('scene-idea');
34
+ const sceneIdea = sceneIdeaInput?.value.trim();
35
 
36
  if (!sceneIdea) {
37
  this.showAlert('Please enter a scene idea', 'danger');
 
48
  body: JSON.stringify({ scene_idea: sceneIdea })
49
  });
50
 
51
+ const contentType = response.headers.get('content-type') || '';
52
+ if (!contentType.includes('application/json')) {
53
+ throw new Error("Server didn't return JSON – are you logged in?");
 
 
 
54
  }
55
 
56
  const data = await response.json();
 
58
  if (data.success) {
59
  this.displayResult(data);
60
  this.loadGallery();
61
+ sceneIdeaInput.value = '';
62
+ this.showAlert('Story and image generated!', 'success');
63
  } else {
64
  this.showAlert(data.error || 'Failed to generate content', 'danger');
65
  }
66
 
67
  } catch (error) {
68
  console.error('Error generating content:', error);
69
+ this.showAlert('Network or server error. Please try again.', 'danger');
70
  } finally {
71
  this.showLoading(false);
72
  this.setButtonLoading(false);
 
78
 
79
  const imageSection = data.image_url ? `
80
  <div class="col-lg-6 mb-4">
81
+ <img src="${data.image_url}" alt="Generated Scene" class="img-fluid rounded shadow">
 
 
82
  </div>` : '';
83
 
84
  const storyColClass = data.image_url ? 'col-lg-6' : 'col-12';
 
85
  const downloadButton = data.image_url ? `
86
  <button class="btn btn-outline-success btn-sm" onclick="inkBoard.downloadImage('${data.image_url}')">
87
+ <i class="fas fa-download me-1"></i> Download Image
 
88
  </button>` : '';
89
 
90
+ resultsSection.innerHTML = `
91
+ <div class="card shadow border-0 p-4">
92
+ <h4 class="mb-4">Your Creation</h4>
93
+ <div class="row">
94
+ ${imageSection}
95
+ <div class="${storyColClass}">
96
+ <p>${data.story}</p>
97
+ <button class="btn btn-outline-primary btn-sm me-2" onclick="inkBoard.openJournal('${data.creation_id}')">
98
+ <i class="fas fa-journal-whills me-1"></i> Add Journal
99
+ </button>
100
+ ${downloadButton}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
  </div>
102
  </div>
103
  </div>
104
  `;
 
 
105
  resultsSection.scrollIntoView({ behavior: 'smooth' });
106
  }
107
 
108
  async loadGallery() {
109
  try {
110
  const response = await fetch('/get_creations');
111
+
112
+ const contentType = response.headers.get('content-type') || '';
113
+ if (!contentType.includes('application/json')) {
114
+ console.warn('Gallery load skipped — likely not logged in.');
115
+ return;
116
+ }
117
+
118
  const data = await response.json();
119
  const galleryGrid = document.getElementById('gallery-grid');
120
 
121
+ if (data.creations.length > 0) {
122
+ galleryGrid.innerHTML = data.creations.map(this.createGalleryItem).join('');
 
123
  } else {
124
  galleryGrid.innerHTML = `
125
+ <div class="text-center py-5 text-muted">
126
+ <h5>No creations yet</h5>
127
+ <p>Start by describing a scene above!</p>
 
128
  </div>`;
129
  }
130
  } catch (error) {
 
134
 
135
  createGalleryItem(creation) {
136
  const journalEntry = creation.journal_entry ? `
137
+ <div class="mt-2"><strong>Journal:</strong> ${creation.journal_entry}</div>` : '';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
138
 
139
  return `
140
+ <div class="gallery-item card shadow-sm p-3 mb-3">
141
+ <h6>${creation.scene_idea}</h6>
142
+ <p>${creation.story}</p>
143
+ ${creation.image_url ? `<img src="${creation.image_url}" class="img-fluid">` : ''}
144
+ ${journalEntry}
145
+ <button class="btn btn-sm btn-outline-primary mt-2" onclick="inkBoard.openJournal('${creation.id}', '${creation.journal_entry || ''}')">
146
+ ${creation.journal_entry ? 'Edit' : 'Add'} Journal
147
+ </button>
 
 
 
 
 
 
 
 
 
 
 
148
  </div>`;
149
  }
150
 
151
+ openJournal(id, text = '') {
152
+ this.currentCreationId = id;
153
+ document.getElementById('journal-text').value = text;
 
154
  const modal = new bootstrap.Modal(document.getElementById('journalModal'));
155
  modal.show();
156
  }
157
 
158
  async saveJournal() {
159
+ if (!this.currentCreationId) return;
 
 
 
160
 
161
+ const text = document.getElementById('journal-text').value.trim();
162
+ await fetch('/save_journal', {
163
+ method: 'POST',
164
+ headers: { 'Content-Type': 'application/json' },
165
+ body: JSON.stringify({ creation_id: this.currentCreationId, journal_entry: text })
166
+ });
167
+ this.loadGallery();
168
+ const modal = bootstrap.Modal.getInstance(document.getElementById('journalModal'));
169
+ modal.hide();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
170
  }
171
 
172
+ showLoading(state) {
173
+ const spinner = document.getElementById('loading-spinner');
174
+ if (spinner) spinner.style.display = state ? 'block' : 'none';
 
 
 
 
175
  }
176
 
177
+ setButtonLoading(state) {
178
+ const btn = document.querySelector('#scene-form button[type="submit"]');
179
+ if (btn) btn.disabled = state;
 
 
 
 
180
  }
181
 
182
+ showAlert(msg, type = 'info') {
183
+ const alertBox = document.getElementById('alert-box');
184
+ if (!alertBox) return;
185
+ alertBox.className = `alert alert-${type}`;
186
+ alertBox.innerText = msg;
187
+ alertBox.style.display = 'block';
188
+ setTimeout(() => alertBox.style.display = 'none', 5000);
189
  }
190
 
191
+ showSection(name) {
192
+ this.currentSection = name;
 
 
193
  }
194
 
195
+ downloadImage(url) {
196
+ const link = document.createElement('a');
197
+ link.href = url;
198
+ link.download = 'inkboard_image.png';
199
+ document.body.appendChild(link);
200
+ link.click();
201
+ document.body.removeChild(link);
202
  }
203
  }
204
 
 
205
  const inkBoard = new InkBoard();