cjm-transcript-segment-align 0.0.9__tar.gz → 0.0.11__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. {cjm_transcript_segment_align-0.0.9/cjm_transcript_segment_align.egg-info → cjm_transcript_segment_align-0.0.11}/PKG-INFO +156 -51
  2. {cjm_transcript_segment_align-0.0.9 → cjm_transcript_segment_align-0.0.11}/README.md +155 -50
  3. cjm_transcript_segment_align-0.0.11/cjm_transcript_segment_align/__init__.py +1 -0
  4. {cjm_transcript_segment_align-0.0.9 → cjm_transcript_segment_align-0.0.11}/cjm_transcript_segment_align/_modidx.py +14 -2
  5. {cjm_transcript_segment_align-0.0.9 → cjm_transcript_segment_align-0.0.11}/cjm_transcript_segment_align/components/handlers.py +45 -21
  6. {cjm_transcript_segment_align-0.0.9 → cjm_transcript_segment_align-0.0.11}/cjm_transcript_segment_align/components/keyboard_config.py +24 -2
  7. {cjm_transcript_segment_align-0.0.9 → cjm_transcript_segment_align-0.0.11}/cjm_transcript_segment_align/components/step_renderer.py +64 -37
  8. cjm_transcript_segment_align-0.0.11/cjm_transcript_segment_align/components/sync_controls.py +141 -0
  9. cjm_transcript_segment_align-0.0.11/cjm_transcript_segment_align/components/toolbar_state.py +64 -0
  10. {cjm_transcript_segment_align-0.0.9 → cjm_transcript_segment_align-0.0.11}/cjm_transcript_segment_align/html_ids.py +1 -1
  11. {cjm_transcript_segment_align-0.0.9 → cjm_transcript_segment_align-0.0.11}/cjm_transcript_segment_align/routes/chrome.py +35 -63
  12. {cjm_transcript_segment_align-0.0.9 → cjm_transcript_segment_align-0.0.11}/cjm_transcript_segment_align/routes/forced_alignment.py +3 -2
  13. {cjm_transcript_segment_align-0.0.9 → cjm_transcript_segment_align-0.0.11}/cjm_transcript_segment_align/routes/init.py +3 -1
  14. {cjm_transcript_segment_align-0.0.9 → cjm_transcript_segment_align-0.0.11/cjm_transcript_segment_align.egg-info}/PKG-INFO +156 -51
  15. {cjm_transcript_segment_align-0.0.9 → cjm_transcript_segment_align-0.0.11}/cjm_transcript_segment_align.egg-info/SOURCES.txt +2 -0
  16. {cjm_transcript_segment_align-0.0.9 → cjm_transcript_segment_align-0.0.11}/settings.ini +1 -1
  17. cjm_transcript_segment_align-0.0.9/cjm_transcript_segment_align/__init__.py +0 -1
  18. {cjm_transcript_segment_align-0.0.9 → cjm_transcript_segment_align-0.0.11}/LICENSE +0 -0
  19. {cjm_transcript_segment_align-0.0.9 → cjm_transcript_segment_align-0.0.11}/MANIFEST.in +0 -0
  20. {cjm_transcript_segment_align-0.0.9 → cjm_transcript_segment_align-0.0.11}/cjm_transcript_segment_align/components/__init__.py +0 -0
  21. {cjm_transcript_segment_align-0.0.9 → cjm_transcript_segment_align-0.0.11}/cjm_transcript_segment_align/components/helpers.py +0 -0
  22. {cjm_transcript_segment_align-0.0.9 → cjm_transcript_segment_align-0.0.11}/cjm_transcript_segment_align/models.py +0 -0
  23. {cjm_transcript_segment_align-0.0.9 → cjm_transcript_segment_align-0.0.11}/cjm_transcript_segment_align/routes/__init__.py +0 -0
  24. {cjm_transcript_segment_align-0.0.9 → cjm_transcript_segment_align-0.0.11}/cjm_transcript_segment_align/services/__init__.py +0 -0
  25. {cjm_transcript_segment_align-0.0.9 → cjm_transcript_segment_align-0.0.11}/cjm_transcript_segment_align/services/forced_alignment.py +0 -0
  26. {cjm_transcript_segment_align-0.0.9 → cjm_transcript_segment_align-0.0.11}/cjm_transcript_segment_align.egg-info/dependency_links.txt +0 -0
  27. {cjm_transcript_segment_align-0.0.9 → cjm_transcript_segment_align-0.0.11}/cjm_transcript_segment_align.egg-info/entry_points.txt +0 -0
  28. {cjm_transcript_segment_align-0.0.9 → cjm_transcript_segment_align-0.0.11}/cjm_transcript_segment_align.egg-info/not-zip-safe +0 -0
  29. {cjm_transcript_segment_align-0.0.9 → cjm_transcript_segment_align-0.0.11}/cjm_transcript_segment_align.egg-info/requires.txt +0 -0
  30. {cjm_transcript_segment_align-0.0.9 → cjm_transcript_segment_align-0.0.11}/cjm_transcript_segment_align.egg-info/top_level.txt +0 -0
  31. {cjm_transcript_segment_align-0.0.9 → cjm_transcript_segment_align-0.0.11}/pyproject.toml +0 -0
  32. {cjm_transcript_segment_align-0.0.9 → cjm_transcript_segment_align-0.0.11}/setup.cfg +0 -0
  33. {cjm_transcript_segment_align-0.0.9 → cjm_transcript_segment_align-0.0.11}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: cjm-transcript-segment-align
3
- Version: 0.0.9
3
+ Version: 0.0.11
4
4
  Summary: FastHTML dual-column text segmentation & VAD alignment UI for transcript decomposition workflows with forced alignment-based text splitting for aligning text segments with VAD chunks.
5
5
  Home-page: https://github.com/cj-mills/cjm-transcript-segment-align
6
6
  Author: Christian J. Mills
@@ -48,11 +48,13 @@ pip install cjm_transcript_segment_align
48
48
  ## Project Structure
49
49
 
50
50
  nbs/
51
- ├── components/ (4)
51
+ ├── components/ (6)
52
52
  │ ├── handlers.ipynb # Handler wrappers for cross-domain coordination (alignment status updates)
53
53
  │ ├── helpers.ipynb # State extraction helpers for cross-domain coordination in Phase 2 combined step
54
54
  │ ├── keyboard_config.ipynb # Shared keyboard navigation configuration for the combined Phase 2 step
55
- └── step_renderer.ipynb # Phase 2 combined step renderer: dual-column layout for Segment & Align
55
+ ├── step_renderer.ipynb # Phase 2 combined step renderer: dual-column layout for Segment & Align
56
+ │ ├── sync_controls.ipynb # Synced navigation toggle for the combined Phase 2 dual-column step
57
+ │ └── toolbar_state.ipynb # Centralized client-side toolbar state restoration after HTMX settles
56
58
  ├── routes/ (3)
57
59
  │ ├── chrome.ipynb # Shared chrome switching route handlers for the combined Phase 2 step
58
60
  │ ├── forced_alignment.ipynb # Routes for toggling between NLTK and force-aligned pre-splits, plus rendering helpers for FA UI controls. Trigger and progress are handled by `cjm-fasthtml-job-monitor`.
@@ -62,7 +64,7 @@ pip install cjm_transcript_segment_align
62
64
  ├── html_ids.ipynb # HTML ID constants for Phase 2 Shell: Dual-Column Layout shared chrome
63
65
  └── models.ipynb # Data types and result containers for the segment-align integration surface
64
66
 
65
- Total: 10 notebooks across 3 directories
67
+ Total: 12 notebooks across 3 directories
66
68
 
67
69
  ## Module Dependencies
68
70
 
@@ -72,6 +74,8 @@ graph LR
72
74
  components_helpers[components.helpers<br/>helpers]
73
75
  components_keyboard_config[components.keyboard_config<br/>keyboard_config]
74
76
  components_step_renderer[components.step_renderer<br/>step_combined]
77
+ components_sync_controls[components.sync_controls<br/>sync_controls]
78
+ components_toolbar_state[components.toolbar_state<br/>toolbar_state]
75
79
  html_ids[html_ids<br/>html_ids]
76
80
  models[models<br/>models]
77
81
  routes_chrome[routes.chrome<br/>chrome]
@@ -79,31 +83,39 @@ graph LR
79
83
  routes_init[routes.init<br/>routes/init]
80
84
  services_forced_alignment[services.forced_alignment<br/>forced_alignment]
81
85
 
86
+ components_handlers --> components_sync_controls
82
87
  components_handlers --> components_keyboard_config
83
- components_handlers --> services_forced_alignment
84
- components_handlers --> components_step_renderer
85
88
  components_handlers --> html_ids
89
+ components_handlers --> components_step_renderer
90
+ components_handlers --> services_forced_alignment
86
91
  components_handlers --> routes_forced_alignment
87
92
  components_keyboard_config --> html_ids
93
+ components_keyboard_config --> components_sync_controls
88
94
  components_step_renderer --> components_keyboard_config
95
+ components_step_renderer --> components_toolbar_state
89
96
  components_step_renderer --> html_ids
90
97
  components_step_renderer --> components_helpers
98
+ components_step_renderer --> components_sync_controls
99
+ components_toolbar_state --> components_sync_controls
100
+ routes_chrome --> components_sync_controls
91
101
  routes_chrome --> components_handlers
92
- routes_chrome --> components_step_renderer
93
102
  routes_chrome --> html_ids
94
- routes_forced_alignment --> components_step_renderer
103
+ routes_chrome --> components_step_renderer
104
+ routes_forced_alignment --> components_sync_controls
95
105
  routes_forced_alignment --> html_ids
96
- routes_init --> components_step_renderer
97
- routes_init --> components_handlers
98
- routes_init --> routes_chrome
106
+ routes_forced_alignment --> components_step_renderer
99
107
  routes_init --> components_keyboard_config
100
- routes_init --> html_ids
101
- routes_init --> routes_forced_alignment
102
108
  routes_init --> models
109
+ routes_init --> components_handlers
110
+ routes_init --> html_ids
103
111
  routes_init --> services_forced_alignment
112
+ routes_init --> routes_chrome
113
+ routes_init --> routes_forced_alignment
114
+ routes_init --> components_step_renderer
115
+ routes_init --> components_sync_controls
104
116
  ```
105
117
 
106
- *22 cross-module dependencies detected*
118
+ *30 cross-module dependencies detected*
107
119
 
108
120
  ## CLI Reference
109
121
 
@@ -128,17 +140,6 @@ from cjm_transcript_segment_align.routes.chrome import (
128
140
 
129
141
  #### Functions
130
142
 
131
- ``` python
132
- def _restore_align_auto_nav_js() -> str
133
- """
134
- Generate JS to sync the auto-navigate toggle checkbox and color classes with the Web Audio state.
135
-
136
- After chrome switch re-renders the toolbar, the checkbox starts unchecked with bg-error.
137
- This reads the JS state (source of truth) and restores the checkbox + color classes.
138
- Included inside the toolbar OOB so it runs after HTMX inserts the new content.
139
- """
140
- ```
141
-
142
143
  ``` python
143
144
  async def _handle_switch_chrome(
144
145
  state_store:SQLiteWorkflowStateStore, # State store instance
@@ -151,7 +152,13 @@ async def _handle_switch_chrome(
151
152
  fa_toggle_url:str="", # URL for FA toggle route
152
153
  fa_available:bool=False, # Whether FA plugin is available
153
154
  ) -> tuple: # OOB swaps for shared chrome containers
154
- "Switch shared chrome content based on active column."
155
+ """
156
+ Switch shared chrome content based on active column.
157
+
158
+ Client-side toolbar state restoration (sync button, auto-play toggle)
159
+ is handled by the centralized settle handler from toolbar_state.py.
160
+ Settings modals persist in the DOM — only the trigger buttons swap.
161
+ """
155
162
  ```
156
163
 
157
164
  ``` python
@@ -473,9 +480,6 @@ def create_seg_mutation_wrapper(
473
480
  Calls the _result handler variant, builds targeted OOB response with FA
474
481
  controls in toolbar, and appends alignment status + mini-stats OOB.
475
482
  Computes nltk_split_disabled from state for toolbar rendering.
476
-
477
- When clear_fa_presplit=True (used for NLTK Split), clears the FA pre-split
478
- snapshot so the toggle is replaced with the Force Align button.
479
483
  """
480
484
  ```
481
485
 
@@ -503,30 +507,14 @@ def create_seg_init_chrome_wrapper(
503
507
 
504
508
  Saves nltk_presplit snapshot at init time for match detection.
505
509
  FA controls are rendered in the toolbar via extra_actions.
510
+ Settings modals are rendered in a persistent container (both seg + align).
506
511
  """
507
512
  ```
508
513
 
509
514
  ``` python
510
- def create_align_init_chrome_wrapper() -> Callable: # Wrapped handler that adds alignment status
511
- """Create a wrapper for align init that adds mini-stats and alignment status.
512
-
513
- Returns a footer OOB (not a standalone alignment status badge) to avoid
514
- a race condition: both seg and align init auto-trigger on load, and the
515
- alignment status badge only exists inside the footer after seg init's
516
- footer OOB is processed. Using a footer OOB is safe because the footer
517
- container always exists in the DOM.
518
- """
519
- async def wrapped_align_init(
520
- state_store:WorkflowStateStore,
521
- workflow_id:str,
522
- source_service:SourceService,
523
- alignment_service:AlignmentService,
524
- request:Any,
525
- sess:Any,
526
- urls:AlignmentUrls,
527
- visible_count:int=5,
528
- card_width:int=40,
529
- )
515
+ def create_align_init_chrome_wrapper(
516
+ should_play_fn:str="", # Consumer-defined play guard function name
517
+ ) -> Callable: # Wrapped handler that adds alignment status
530
518
  """
531
519
  Create a wrapper for align init that adds mini-stats and alignment status.
532
520
 
@@ -851,9 +839,9 @@ def _render_shared_chrome(
851
839
  seg_state:dict=None, # Extracted segmentation state (None = show placeholders)
852
840
  align_state:dict=None, # Extracted alignment state (None = no VAD data yet)
853
841
  urls:SegmentationUrls=None, # Segmentation URL bundle (required when seg_state provided)
854
- fa_extra_actions:Any=None, # FA controls for toolbar extra_actions slot
842
+ extra_actions:tuple=(), # Extra toolbar elements (FA controls, sync toggle, etc.)
855
843
  nltk_split_disabled:bool=False, # Whether NLTK Split button is disabled
856
- ) -> tuple: # (toolbar, controls, footer)
844
+ ) -> tuple: # (toolbar, footer, settings_modals_container)
857
845
  """
858
846
  Render shared chrome containers, populated with segmentation content when initialized.
859
847
 
@@ -919,3 +907,120 @@ _FOOTER_INNER_CLS
919
907
  _SEG_COLUMN_CLS
920
908
  _ALIGNMENT_COLUMN_CLS
921
909
  ```
910
+
911
+ ### sync_controls (`sync_controls.ipynb`)
912
+
913
+ > Synced navigation toggle for the combined Phase 2 dual-column step
914
+
915
+ #### Import
916
+
917
+ ``` python
918
+ from cjm_transcript_segment_align.components.sync_controls import (
919
+ SYNC_TOGGLE_FN,
920
+ SYNC_KEY,
921
+ SYNC_BTN_ID,
922
+ SHOULD_PLAY_FN,
923
+ render_sync_toggle_button,
924
+ generate_sync_script,
925
+ generate_sync_key_toggle_js,
926
+ generate_should_play_js,
927
+ generate_sync_restore_js,
928
+ build_extra_actions
929
+ )
930
+ ```
931
+
932
+ #### Functions
933
+
934
+ ``` python
935
+ def render_sync_toggle_button() -> Any: # Sync toggle button element
936
+ "Render the synced navigation toggle button for the seg toolbar."
937
+ ```
938
+
939
+ ``` python
940
+ def generate_sync_script(
941
+ source_input_id:str, # Seg card stack's focused_index hidden input ID
942
+ target_nav_url:str, # Align card stack's nav_to_index URL
943
+ ) -> Any: # Script element with sync JS
944
+ "Generate the sync JS Script element for the combined step."
945
+ ```
946
+
947
+ ``` python
948
+ def generate_sync_key_toggle_js() -> str: # JS defining window._segAlignSyncKeyToggle
949
+ "Generate JS for the S key sync toggle wrapper function."
950
+ ```
951
+
952
+ ``` python
953
+ def generate_should_play_js() -> str: # JS defining window.shouldAlignPlay
954
+ """
955
+ Generate JS for the custom play guard function.
956
+
957
+ Returns true when audio should play:
958
+ - Zone is active (direct align navigation), OR
959
+ - Auto-navigate is on (auto-play through align stack), OR
960
+ - Sync is enabled (seg navigation driving align)
961
+ """
962
+ ```
963
+
964
+ ``` python
965
+ def generate_sync_restore_js() -> str: # JS to restore sync button styling from client state
966
+ """
967
+ Generate JS to sync the toolbar button styling with the client-side sync state.
968
+
969
+ After chrome switch re-renders the seg toolbar, the sync button starts
970
+ with btn-outline. This reads the JS state and restores btn-primary if
971
+ sync is enabled.
972
+ """
973
+ ```
974
+
975
+ ``` python
976
+ def build_extra_actions(
977
+ fa_extra:Any=None, # FA controls element (from build_fa_extra_actions, or None)
978
+ ) -> tuple: # Tuple of toolbar extra action elements
979
+ """
980
+ Build the extra_actions tuple for the seg toolbar.
981
+
982
+ Combines FA controls (if available) with the sync toggle button.
983
+ Client-side state restoration (sync button styling) is handled by
984
+ the centralized toolbar restore settle handler in toolbar_state.py.
985
+ Returns a tuple compatible with render_toolbar(extra_actions=...).
986
+ """
987
+ ```
988
+
989
+ #### Variables
990
+
991
+ ``` python
992
+ SYNC_TOGGLE_FN = 'toggleSegAlignSync'
993
+ SYNC_KEY = '_segAlignSync'
994
+ SYNC_BTN_ID = 'sd-sync-toggle-btn'
995
+ SHOULD_PLAY_FN = 'shouldAlignPlay'
996
+ ```
997
+
998
+ ### toolbar_state (`toolbar_state.ipynb`)
999
+
1000
+ > Centralized client-side toolbar state restoration after HTMX settles
1001
+
1002
+ #### Import
1003
+
1004
+ ``` python
1005
+ from cjm_transcript_segment_align.components.toolbar_state import (
1006
+ generate_toolbar_restore_js
1007
+ )
1008
+ ```
1009
+
1010
+ #### Functions
1011
+
1012
+ ``` python
1013
+ def generate_toolbar_restore_js() -> Script: # Script element with settle handler
1014
+ """
1015
+ Generate the centralized toolbar state restore settle handler.
1016
+
1017
+ Restores client-side state for all toolbar toggles/buttons after any
1018
+ HTMX settle that re-renders the toolbar. Runs once per settle event.
1019
+ """
1020
+ ```
1021
+
1022
+ #### Variables
1023
+
1024
+ ``` python
1025
+ _TOOLBAR_RESTORE_KEY = '_sdToolbarRestoreHandler'
1026
+ ```
@@ -12,11 +12,13 @@ pip install cjm_transcript_segment_align
12
12
  ## Project Structure
13
13
 
14
14
  nbs/
15
- ├── components/ (4)
15
+ ├── components/ (6)
16
16
  │ ├── handlers.ipynb # Handler wrappers for cross-domain coordination (alignment status updates)
17
17
  │ ├── helpers.ipynb # State extraction helpers for cross-domain coordination in Phase 2 combined step
18
18
  │ ├── keyboard_config.ipynb # Shared keyboard navigation configuration for the combined Phase 2 step
19
- └── step_renderer.ipynb # Phase 2 combined step renderer: dual-column layout for Segment & Align
19
+ ├── step_renderer.ipynb # Phase 2 combined step renderer: dual-column layout for Segment & Align
20
+ │ ├── sync_controls.ipynb # Synced navigation toggle for the combined Phase 2 dual-column step
21
+ │ └── toolbar_state.ipynb # Centralized client-side toolbar state restoration after HTMX settles
20
22
  ├── routes/ (3)
21
23
  │ ├── chrome.ipynb # Shared chrome switching route handlers for the combined Phase 2 step
22
24
  │ ├── forced_alignment.ipynb # Routes for toggling between NLTK and force-aligned pre-splits, plus rendering helpers for FA UI controls. Trigger and progress are handled by `cjm-fasthtml-job-monitor`.
@@ -26,7 +28,7 @@ pip install cjm_transcript_segment_align
26
28
  ├── html_ids.ipynb # HTML ID constants for Phase 2 Shell: Dual-Column Layout shared chrome
27
29
  └── models.ipynb # Data types and result containers for the segment-align integration surface
28
30
 
29
- Total: 10 notebooks across 3 directories
31
+ Total: 12 notebooks across 3 directories
30
32
 
31
33
  ## Module Dependencies
32
34
 
@@ -36,6 +38,8 @@ graph LR
36
38
  components_helpers[components.helpers<br/>helpers]
37
39
  components_keyboard_config[components.keyboard_config<br/>keyboard_config]
38
40
  components_step_renderer[components.step_renderer<br/>step_combined]
41
+ components_sync_controls[components.sync_controls<br/>sync_controls]
42
+ components_toolbar_state[components.toolbar_state<br/>toolbar_state]
39
43
  html_ids[html_ids<br/>html_ids]
40
44
  models[models<br/>models]
41
45
  routes_chrome[routes.chrome<br/>chrome]
@@ -43,31 +47,39 @@ graph LR
43
47
  routes_init[routes.init<br/>routes/init]
44
48
  services_forced_alignment[services.forced_alignment<br/>forced_alignment]
45
49
 
50
+ components_handlers --> components_sync_controls
46
51
  components_handlers --> components_keyboard_config
47
- components_handlers --> services_forced_alignment
48
- components_handlers --> components_step_renderer
49
52
  components_handlers --> html_ids
53
+ components_handlers --> components_step_renderer
54
+ components_handlers --> services_forced_alignment
50
55
  components_handlers --> routes_forced_alignment
51
56
  components_keyboard_config --> html_ids
57
+ components_keyboard_config --> components_sync_controls
52
58
  components_step_renderer --> components_keyboard_config
59
+ components_step_renderer --> components_toolbar_state
53
60
  components_step_renderer --> html_ids
54
61
  components_step_renderer --> components_helpers
62
+ components_step_renderer --> components_sync_controls
63
+ components_toolbar_state --> components_sync_controls
64
+ routes_chrome --> components_sync_controls
55
65
  routes_chrome --> components_handlers
56
- routes_chrome --> components_step_renderer
57
66
  routes_chrome --> html_ids
58
- routes_forced_alignment --> components_step_renderer
67
+ routes_chrome --> components_step_renderer
68
+ routes_forced_alignment --> components_sync_controls
59
69
  routes_forced_alignment --> html_ids
60
- routes_init --> components_step_renderer
61
- routes_init --> components_handlers
62
- routes_init --> routes_chrome
70
+ routes_forced_alignment --> components_step_renderer
63
71
  routes_init --> components_keyboard_config
64
- routes_init --> html_ids
65
- routes_init --> routes_forced_alignment
66
72
  routes_init --> models
73
+ routes_init --> components_handlers
74
+ routes_init --> html_ids
67
75
  routes_init --> services_forced_alignment
76
+ routes_init --> routes_chrome
77
+ routes_init --> routes_forced_alignment
78
+ routes_init --> components_step_renderer
79
+ routes_init --> components_sync_controls
68
80
  ```
69
81
 
70
- *22 cross-module dependencies detected*
82
+ *30 cross-module dependencies detected*
71
83
 
72
84
  ## CLI Reference
73
85
 
@@ -92,17 +104,6 @@ from cjm_transcript_segment_align.routes.chrome import (
92
104
 
93
105
  #### Functions
94
106
 
95
- ``` python
96
- def _restore_align_auto_nav_js() -> str
97
- """
98
- Generate JS to sync the auto-navigate toggle checkbox and color classes with the Web Audio state.
99
-
100
- After chrome switch re-renders the toolbar, the checkbox starts unchecked with bg-error.
101
- This reads the JS state (source of truth) and restores the checkbox + color classes.
102
- Included inside the toolbar OOB so it runs after HTMX inserts the new content.
103
- """
104
- ```
105
-
106
107
  ``` python
107
108
  async def _handle_switch_chrome(
108
109
  state_store:SQLiteWorkflowStateStore, # State store instance
@@ -115,7 +116,13 @@ async def _handle_switch_chrome(
115
116
  fa_toggle_url:str="", # URL for FA toggle route
116
117
  fa_available:bool=False, # Whether FA plugin is available
117
118
  ) -> tuple: # OOB swaps for shared chrome containers
118
- "Switch shared chrome content based on active column."
119
+ """
120
+ Switch shared chrome content based on active column.
121
+
122
+ Client-side toolbar state restoration (sync button, auto-play toggle)
123
+ is handled by the centralized settle handler from toolbar_state.py.
124
+ Settings modals persist in the DOM — only the trigger buttons swap.
125
+ """
119
126
  ```
120
127
 
121
128
  ``` python
@@ -437,9 +444,6 @@ def create_seg_mutation_wrapper(
437
444
  Calls the _result handler variant, builds targeted OOB response with FA
438
445
  controls in toolbar, and appends alignment status + mini-stats OOB.
439
446
  Computes nltk_split_disabled from state for toolbar rendering.
440
-
441
- When clear_fa_presplit=True (used for NLTK Split), clears the FA pre-split
442
- snapshot so the toggle is replaced with the Force Align button.
443
447
  """
444
448
  ```
445
449
 
@@ -467,30 +471,14 @@ def create_seg_init_chrome_wrapper(
467
471
 
468
472
  Saves nltk_presplit snapshot at init time for match detection.
469
473
  FA controls are rendered in the toolbar via extra_actions.
474
+ Settings modals are rendered in a persistent container (both seg + align).
470
475
  """
471
476
  ```
472
477
 
473
478
  ``` python
474
- def create_align_init_chrome_wrapper() -> Callable: # Wrapped handler that adds alignment status
475
- """Create a wrapper for align init that adds mini-stats and alignment status.
476
-
477
- Returns a footer OOB (not a standalone alignment status badge) to avoid
478
- a race condition: both seg and align init auto-trigger on load, and the
479
- alignment status badge only exists inside the footer after seg init's
480
- footer OOB is processed. Using a footer OOB is safe because the footer
481
- container always exists in the DOM.
482
- """
483
- async def wrapped_align_init(
484
- state_store:WorkflowStateStore,
485
- workflow_id:str,
486
- source_service:SourceService,
487
- alignment_service:AlignmentService,
488
- request:Any,
489
- sess:Any,
490
- urls:AlignmentUrls,
491
- visible_count:int=5,
492
- card_width:int=40,
493
- )
479
+ def create_align_init_chrome_wrapper(
480
+ should_play_fn:str="", # Consumer-defined play guard function name
481
+ ) -> Callable: # Wrapped handler that adds alignment status
494
482
  """
495
483
  Create a wrapper for align init that adds mini-stats and alignment status.
496
484
 
@@ -815,9 +803,9 @@ def _render_shared_chrome(
815
803
  seg_state:dict=None, # Extracted segmentation state (None = show placeholders)
816
804
  align_state:dict=None, # Extracted alignment state (None = no VAD data yet)
817
805
  urls:SegmentationUrls=None, # Segmentation URL bundle (required when seg_state provided)
818
- fa_extra_actions:Any=None, # FA controls for toolbar extra_actions slot
806
+ extra_actions:tuple=(), # Extra toolbar elements (FA controls, sync toggle, etc.)
819
807
  nltk_split_disabled:bool=False, # Whether NLTK Split button is disabled
820
- ) -> tuple: # (toolbar, controls, footer)
808
+ ) -> tuple: # (toolbar, footer, settings_modals_container)
821
809
  """
822
810
  Render shared chrome containers, populated with segmentation content when initialized.
823
811
 
@@ -883,3 +871,120 @@ _FOOTER_INNER_CLS
883
871
  _SEG_COLUMN_CLS
884
872
  _ALIGNMENT_COLUMN_CLS
885
873
  ```
874
+
875
+ ### sync_controls (`sync_controls.ipynb`)
876
+
877
+ > Synced navigation toggle for the combined Phase 2 dual-column step
878
+
879
+ #### Import
880
+
881
+ ``` python
882
+ from cjm_transcript_segment_align.components.sync_controls import (
883
+ SYNC_TOGGLE_FN,
884
+ SYNC_KEY,
885
+ SYNC_BTN_ID,
886
+ SHOULD_PLAY_FN,
887
+ render_sync_toggle_button,
888
+ generate_sync_script,
889
+ generate_sync_key_toggle_js,
890
+ generate_should_play_js,
891
+ generate_sync_restore_js,
892
+ build_extra_actions
893
+ )
894
+ ```
895
+
896
+ #### Functions
897
+
898
+ ``` python
899
+ def render_sync_toggle_button() -> Any: # Sync toggle button element
900
+ "Render the synced navigation toggle button for the seg toolbar."
901
+ ```
902
+
903
+ ``` python
904
+ def generate_sync_script(
905
+ source_input_id:str, # Seg card stack's focused_index hidden input ID
906
+ target_nav_url:str, # Align card stack's nav_to_index URL
907
+ ) -> Any: # Script element with sync JS
908
+ "Generate the sync JS Script element for the combined step."
909
+ ```
910
+
911
+ ``` python
912
+ def generate_sync_key_toggle_js() -> str: # JS defining window._segAlignSyncKeyToggle
913
+ "Generate JS for the S key sync toggle wrapper function."
914
+ ```
915
+
916
+ ``` python
917
+ def generate_should_play_js() -> str: # JS defining window.shouldAlignPlay
918
+ """
919
+ Generate JS for the custom play guard function.
920
+
921
+ Returns true when audio should play:
922
+ - Zone is active (direct align navigation), OR
923
+ - Auto-navigate is on (auto-play through align stack), OR
924
+ - Sync is enabled (seg navigation driving align)
925
+ """
926
+ ```
927
+
928
+ ``` python
929
+ def generate_sync_restore_js() -> str: # JS to restore sync button styling from client state
930
+ """
931
+ Generate JS to sync the toolbar button styling with the client-side sync state.
932
+
933
+ After chrome switch re-renders the seg toolbar, the sync button starts
934
+ with btn-outline. This reads the JS state and restores btn-primary if
935
+ sync is enabled.
936
+ """
937
+ ```
938
+
939
+ ``` python
940
+ def build_extra_actions(
941
+ fa_extra:Any=None, # FA controls element (from build_fa_extra_actions, or None)
942
+ ) -> tuple: # Tuple of toolbar extra action elements
943
+ """
944
+ Build the extra_actions tuple for the seg toolbar.
945
+
946
+ Combines FA controls (if available) with the sync toggle button.
947
+ Client-side state restoration (sync button styling) is handled by
948
+ the centralized toolbar restore settle handler in toolbar_state.py.
949
+ Returns a tuple compatible with render_toolbar(extra_actions=...).
950
+ """
951
+ ```
952
+
953
+ #### Variables
954
+
955
+ ``` python
956
+ SYNC_TOGGLE_FN = 'toggleSegAlignSync'
957
+ SYNC_KEY = '_segAlignSync'
958
+ SYNC_BTN_ID = 'sd-sync-toggle-btn'
959
+ SHOULD_PLAY_FN = 'shouldAlignPlay'
960
+ ```
961
+
962
+ ### toolbar_state (`toolbar_state.ipynb`)
963
+
964
+ > Centralized client-side toolbar state restoration after HTMX settles
965
+
966
+ #### Import
967
+
968
+ ``` python
969
+ from cjm_transcript_segment_align.components.toolbar_state import (
970
+ generate_toolbar_restore_js
971
+ )
972
+ ```
973
+
974
+ #### Functions
975
+
976
+ ``` python
977
+ def generate_toolbar_restore_js() -> Script: # Script element with settle handler
978
+ """
979
+ Generate the centralized toolbar state restore settle handler.
980
+
981
+ Restores client-side state for all toolbar toggles/buttons after any
982
+ HTMX settle that re-renders the toolbar. Runs once per settle event.
983
+ """
984
+ ```
985
+
986
+ #### Variables
987
+
988
+ ``` python
989
+ _TOOLBAR_RESTORE_KEY = '_sdToolbarRestoreHandler'
990
+ ```
@@ -0,0 +1 @@
1
+ __version__ = "0.0.11"
@@ -63,6 +63,20 @@ d = { 'settings': { 'branch': 'main',
63
63
  'cjm_transcript_segment_align/components/step_renderer.py'),
64
64
  'cjm_transcript_segment_align.components.step_renderer.render_seg_mini_stats_badge': ( 'components/step_renderer.html#render_seg_mini_stats_badge',
65
65
  'cjm_transcript_segment_align/components/step_renderer.py')},
66
+ 'cjm_transcript_segment_align.components.sync_controls': { 'cjm_transcript_segment_align.components.sync_controls.build_extra_actions': ( 'components/sync_controls.html#build_extra_actions',
67
+ 'cjm_transcript_segment_align/components/sync_controls.py'),
68
+ 'cjm_transcript_segment_align.components.sync_controls.generate_should_play_js': ( 'components/sync_controls.html#generate_should_play_js',
69
+ 'cjm_transcript_segment_align/components/sync_controls.py'),
70
+ 'cjm_transcript_segment_align.components.sync_controls.generate_sync_key_toggle_js': ( 'components/sync_controls.html#generate_sync_key_toggle_js',
71
+ 'cjm_transcript_segment_align/components/sync_controls.py'),
72
+ 'cjm_transcript_segment_align.components.sync_controls.generate_sync_restore_js': ( 'components/sync_controls.html#generate_sync_restore_js',
73
+ 'cjm_transcript_segment_align/components/sync_controls.py'),
74
+ 'cjm_transcript_segment_align.components.sync_controls.generate_sync_script': ( 'components/sync_controls.html#generate_sync_script',
75
+ 'cjm_transcript_segment_align/components/sync_controls.py'),
76
+ 'cjm_transcript_segment_align.components.sync_controls.render_sync_toggle_button': ( 'components/sync_controls.html#render_sync_toggle_button',
77
+ 'cjm_transcript_segment_align/components/sync_controls.py')},
78
+ 'cjm_transcript_segment_align.components.toolbar_state': { 'cjm_transcript_segment_align.components.toolbar_state.generate_toolbar_restore_js': ( 'components/toolbar_state.html#generate_toolbar_restore_js',
79
+ 'cjm_transcript_segment_align/components/toolbar_state.py')},
66
80
  'cjm_transcript_segment_align.html_ids': { 'cjm_transcript_segment_align.html_ids.CombinedHtmlIds': ( 'html_ids.html#combinedhtmlids',
67
81
  'cjm_transcript_segment_align/html_ids.py'),
68
82
  'cjm_transcript_segment_align.html_ids.CombinedHtmlIds.as_selector': ( 'html_ids.html#combinedhtmlids.as_selector',
@@ -73,8 +87,6 @@ d = { 'settings': { 'branch': 'main',
73
87
  'cjm_transcript_segment_align/models.py')},
74
88
  'cjm_transcript_segment_align.routes.chrome': { 'cjm_transcript_segment_align.routes.chrome._handle_switch_chrome': ( 'routes/chrome.html#_handle_switch_chrome',
75
89
  'cjm_transcript_segment_align/routes/chrome.py'),
76
- 'cjm_transcript_segment_align.routes.chrome._restore_align_auto_nav_js': ( 'routes/chrome.html#_restore_align_auto_nav_js',
77
- 'cjm_transcript_segment_align/routes/chrome.py'),
78
90
  'cjm_transcript_segment_align.routes.chrome.init_chrome_router': ( 'routes/chrome.html#init_chrome_router',
79
91
  'cjm_transcript_segment_align/routes/chrome.py')},
80
92
  'cjm_transcript_segment_align.routes.forced_alignment': { 'cjm_transcript_segment_align.routes.forced_alignment._handle_fa_toggle': ( 'routes/forced_alignment.html#_handle_fa_toggle',