Magnus Persson commited on
Commit
bb7c12d
·
1 Parent(s): 3819e07

Show a busy state on the text box while Help me and Give me an idea work

Browse files
src/ui/busy.py CHANGED
@@ -17,7 +17,9 @@ import gradio as gr
17
 
18
  from src.ui.components import Localizer
19
 
20
- Kind = Literal["create", "edit"]
 
 
21
  NEVER_DISABLED_MS = 3_000
22
  FAILSAFE_MS = 75_000
23
 
@@ -25,7 +27,7 @@ FAILSAFE_MS = 75_000
25
  def start_js(kind: Kind) -> str:
26
  """Browser hook for `click(js=...)`: runs before the server call and passes its inputs on."""
27
  return f"""(...args) => {{
28
- const wrap = document.getElementById('result-wrap');
29
  const button = document.querySelector('.primary-action');
30
  if (!wrap || !button) return args;
31
  window.__busyObserver?.disconnect();
@@ -35,10 +37,10 @@ def start_js(kind: Kind) -> str:
35
  window.__busyObserver?.disconnect();
36
  clearTimeout(window.__busyTimer);
37
  clearTimeout(window.__busyGrace);
38
- wrap.classList.remove('busy', 'busy-create', 'busy-edit');
39
  }};
40
  let seenDisabled = button.disabled;
41
- wrap.classList.remove('busy-create', 'busy-edit');
42
  wrap.classList.add('busy', 'busy-{kind}');
43
  window.__busyObserver = new MutationObserver(() => {{
44
  if (button.disabled) seenDisabled = true;
 
17
 
18
  from src.ui.components import Localizer
19
 
20
+ Kind = Literal["create", "edit", "helper"]
21
+ # Create and edit cover the result image; the helper buttons cover the text box they fill.
22
+ TARGET_IDS: dict[str, str] = {"create": "result-wrap", "edit": "result-wrap", "helper": "idea-box"}
23
  NEVER_DISABLED_MS = 3_000
24
  FAILSAFE_MS = 75_000
25
 
 
27
  def start_js(kind: Kind) -> str:
28
  """Browser hook for `click(js=...)`: runs before the server call and passes its inputs on."""
29
  return f"""(...args) => {{
30
+ const wrap = document.getElementById('{TARGET_IDS[kind]}');
31
  const button = document.querySelector('.primary-action');
32
  if (!wrap || !button) return args;
33
  window.__busyObserver?.disconnect();
 
37
  window.__busyObserver?.disconnect();
38
  clearTimeout(window.__busyTimer);
39
  clearTimeout(window.__busyGrace);
40
+ wrap.classList.remove('busy', 'busy-create', 'busy-edit', 'busy-helper');
41
  }};
42
  let seenDisabled = button.disabled;
43
+ wrap.classList.remove('busy-create', 'busy-edit', 'busy-helper');
44
  wrap.classList.add('busy', 'busy-{kind}');
45
  window.__busyObserver = new MutationObserver(() => {{
46
  if (button.disabled) seenDisabled = true;
src/ui/create_tab.py CHANGED
@@ -177,6 +177,7 @@ def build_create_tab(
177
  text=text,
178
  status=status,
179
  rewrite_card=rewrite_card,
 
180
  api_visibility=api_visibility,
181
  max_chars=settings.config.safety.max_input_chars,
182
  help_me=features.help_me,
 
177
  text=text,
178
  status=status,
179
  rewrite_card=rewrite_card,
180
+ create_button=create_button,
181
  api_visibility=api_visibility,
182
  max_chars=settings.config.safety.max_input_chars,
183
  help_me=features.help_me,
src/ui/helper_row.py CHANGED
@@ -21,6 +21,7 @@ from src.services.helpers import HelperService
21
  from src.services.library import PromptLibrary
22
  from src.services.limits import device_identity
23
  from src.services.session import VisitorSession
 
24
  from src.ui.components import ApiVisibility, Block, Localizer, Updates, build_heading
25
  from src.ui.ideas import IdeasPanel, build_ideas
26
 
@@ -94,6 +95,7 @@ def wire_helpers(
94
  text: gr.Textbox,
95
  status: gr.Markdown,
96
  rewrite_card: gr.Button,
 
97
  api_visibility: ApiVisibility,
98
  max_chars: int,
99
  help_me: bool,
@@ -101,7 +103,7 @@ def wire_helpers(
101
  ) -> None:
102
  t = loc.t
103
  quiet = {"queue": False, "show_progress": "hidden", "api_visibility": api_visibility}
104
- outputs = [session, device, *row.buttons, text, row.undo, status, rewrite_card]
105
  buttons = iter(row.buttons)
106
 
107
  def handler(name: str, run: Run):
@@ -109,8 +111,8 @@ def wire_helpers(
109
  current.touch()
110
  lang = current.lang
111
  device_id, device_hash = device_identity(device_value)
112
- busy = [gr.update(interactive=False)] * len(row.buttons)
113
- ready = [gr.update(interactive=True)] * len(row.buttons)
114
  yield (
115
  current,
116
  device_id,
@@ -161,6 +163,7 @@ def wire_helpers(
161
  handler("on_help", lambda idea, lang, dev: helpers.improve(idea, lang, dev)),
162
  [text, device, session],
163
  outputs,
 
164
  api_visibility=api_visibility,
165
  )
166
  if surprise_me:
@@ -168,6 +171,7 @@ def wire_helpers(
168
  handler("on_surprise", lambda idea, lang, dev: helpers.surprise(lang, dev)),
169
  [text, device, session],
170
  outputs,
 
171
  api_visibility=api_visibility,
172
  )
173
 
 
21
  from src.services.library import PromptLibrary
22
  from src.services.limits import device_identity
23
  from src.services.session import VisitorSession
24
+ from src.ui.busy import start_js
25
  from src.ui.components import ApiVisibility, Block, Localizer, Updates, build_heading
26
  from src.ui.ideas import IdeasPanel, build_ideas
27
 
 
95
  text: gr.Textbox,
96
  status: gr.Markdown,
97
  rewrite_card: gr.Button,
98
+ create_button: gr.Button,
99
  api_visibility: ApiVisibility,
100
  max_chars: int,
101
  help_me: bool,
 
103
  ) -> None:
104
  t = loc.t
105
  quiet = {"queue": False, "show_progress": "hidden", "api_visibility": api_visibility}
106
+ outputs = [session, device, *row.buttons, create_button, text, row.undo, status, rewrite_card]
107
  buttons = iter(row.buttons)
108
 
109
  def handler(name: str, run: Run):
 
111
  current.touch()
112
  lang = current.lang
113
  device_id, device_hash = device_identity(device_value)
114
+ busy = [gr.update(interactive=False)] * (len(row.buttons) + 1) # and Create
115
+ ready = [gr.update(interactive=True)] * (len(row.buttons) + 1)
116
  yield (
117
  current,
118
  device_id,
 
163
  handler("on_help", lambda idea, lang, dev: helpers.improve(idea, lang, dev)),
164
  [text, device, session],
165
  outputs,
166
+ js=start_js("helper"),
167
  api_visibility=api_visibility,
168
  )
169
  if surprise_me:
 
171
  handler("on_surprise", lambda idea, lang, dev: helpers.surprise(lang, dev)),
172
  [text, device, session],
173
  outputs,
174
+ js=start_js("helper"),
175
  api_visibility=api_visibility,
176
  )
177
 
src/ui/style.css CHANGED
@@ -295,6 +295,31 @@ textarea {
295
  }
296
  }
297
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
298
  #result-wrap.busy-create .busy-edit-text,
299
  #result-wrap.busy-edit .busy-create-text {
300
  display: none;
 
295
  }
296
  }
297
 
298
+ /* Help me / Give me an idea: the text box dims and shows a small spinner while the AI writes. */
299
+ #idea-box {
300
+ position: relative;
301
+ }
302
+
303
+ #idea-box.busy-helper textarea {
304
+ opacity: 0.4;
305
+ pointer-events: none;
306
+ }
307
+
308
+ #idea-box.busy-helper::after {
309
+ content: "";
310
+ position: absolute;
311
+ top: 62%;
312
+ right: 24px;
313
+ z-index: 5;
314
+ width: 32px;
315
+ height: 32px;
316
+ margin-top: -16px;
317
+ border: 4px solid rgba(99, 102, 241, 0.25);
318
+ border-top-color: #6366f1;
319
+ border-radius: 50%;
320
+ animation: busy-spin 0.9s linear infinite;
321
+ }
322
+
323
  #result-wrap.busy-create .busy-edit-text,
324
  #result-wrap.busy-edit .busy-create-text {
325
  display: none;