Skip to content

Commit fc3f7e5

Browse files
authored
feat(toolbar): collapsible and per-tool customizable structure toolbar (#568)
* feat(toolbar): add collapsible customizable structure tools * fix(bonds): make JS fallback PBC-aware
1 parent 52da719 commit fc3f7e5

16 files changed

Lines changed: 1035 additions & 61 deletions

src/lib/i18n/en/structure.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1833,6 +1833,40 @@ const structure: Record<string, string> = {
18331833
phase_reset_camera_r_key: `Reset camera view (R key)`,
18341834
phase_drop_json_load_data: `Drop JSON file to load phase diagram data`,
18351835

1836+
// Customizable structure toolbar
1837+
toolbar_customize: `Customize toolbar`,
1838+
toolbar_collapse: `Collapse toolbar`,
1839+
toolbar_expand: `Expand toolbar`,
1840+
toolbar_preferences: `Toolbar preferences`,
1841+
toolbar_reset: `Restore defaults`,
1842+
toolbar_group_view: `View`,
1843+
toolbar_group_editing: `Editing`,
1844+
toolbar_group_analysis: `Analysis`,
1845+
toolbar_group_compute: `Compute & Files`,
1846+
toolbar_group_assistant: `Assistant & Plugins`,
1847+
toolbar_tool_reset_camera: `Reset camera`,
1848+
toolbar_tool_view_angles: `View angles`,
1849+
toolbar_tool_fullscreen: `Fullscreen`,
1850+
toolbar_tool_info: `Structure info`,
1851+
toolbar_tool_controls: `Display controls`,
1852+
toolbar_tool_performance: `Large-system performance`,
1853+
toolbar_tool_molstar: `Open in Mol*`,
1854+
toolbar_tool_gesture: `Gesture controls`,
1855+
toolbar_tool_touch: `Touch controls`,
1856+
toolbar_tool_draw: `Draw mode`,
1857+
toolbar_tool_build: `Build tools`,
1858+
toolbar_tool_optimize: `Structure optimizer`,
1859+
toolbar_tool_analysis: `Analysis tools`,
1860+
toolbar_tool_measure: `Measurements`,
1861+
toolbar_tool_workflow: `Workflow`,
1862+
toolbar_tool_server: `Server / HPC`,
1863+
toolbar_tool_upload_hpc: `Upload to HPC`,
1864+
toolbar_tool_terminal: `Terminal`,
1865+
toolbar_tool_io: `Import / Export`,
1866+
toolbar_tool_remote_save: `Save back to remote`,
1867+
toolbar_tool_chat: `AI assistant`,
1868+
toolbar_tool_plugin_hub: `Plugin hub`,
1869+
18361870
// Pathway controls
18371871
pathway_surface_label: `Surface`,
18381872
pathway_surface_n: `Surface {n}`,

src/lib/i18n/zh/structure.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1787,6 +1787,40 @@ const structure: Record<string, string> = {
17871787
phase_reset_camera_r_key: `重置相机视图(R 键)`,
17881788
phase_drop_json_load_data: `拖放 JSON 文件以加载相图数据`,
17891789

1790+
// 可自定义结构工具栏
1791+
toolbar_customize: `自定义工具栏`,
1792+
toolbar_collapse: `折叠工具栏`,
1793+
toolbar_expand: `展开工具栏`,
1794+
toolbar_preferences: `工具栏设置`,
1795+
toolbar_reset: `恢复默认`,
1796+
toolbar_group_view: `视图`,
1797+
toolbar_group_editing: `编辑`,
1798+
toolbar_group_analysis: `分析`,
1799+
toolbar_group_compute: `计算与文件`,
1800+
toolbar_group_assistant: `助手与插件`,
1801+
toolbar_tool_reset_camera: `重置相机`,
1802+
toolbar_tool_view_angles: `视角`,
1803+
toolbar_tool_fullscreen: `全屏`,
1804+
toolbar_tool_info: `结构信息`,
1805+
toolbar_tool_controls: `显示设置`,
1806+
toolbar_tool_performance: `大体系性能模式`,
1807+
toolbar_tool_molstar: `在 Mol* 中打开`,
1808+
toolbar_tool_gesture: `手势控制`,
1809+
toolbar_tool_touch: `触控操作`,
1810+
toolbar_tool_draw: `绘制模式`,
1811+
toolbar_tool_build: `构建工具`,
1812+
toolbar_tool_optimize: `结构优化`,
1813+
toolbar_tool_analysis: `分析工具`,
1814+
toolbar_tool_measure: `测量`,
1815+
toolbar_tool_workflow: `工作流`,
1816+
toolbar_tool_server: `服务器 / HPC`,
1817+
toolbar_tool_upload_hpc: `上传到 HPC`,
1818+
toolbar_tool_terminal: `终端`,
1819+
toolbar_tool_io: `导入 / 导出`,
1820+
toolbar_tool_remote_save: `保存回远程`,
1821+
toolbar_tool_chat: `AI 助手`,
1822+
toolbar_tool_plugin_hub: `插件中心`,
1823+
17901824
// 路径控制
17911825
pathway_surface_label: `表面`,
17921826
pathway_surface_n: `表面 {n}`,

src/lib/structure/OptimizationPane.svelte

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
pane_open = $bindable(false),
3232
toggle_props = {},
3333
pane_props = {},
34+
show_toggle = true,
3435
on_push_undo,
3536
on_structure_change,
3637
selected_indices = [],
@@ -40,6 +41,7 @@
4041
pane_open?: boolean
4142
toggle_props?: ComponentProps<typeof DraggablePane>['toggle_props']
4243
pane_props?: ComponentProps<typeof DraggablePane>['pane_props']
44+
show_toggle?: boolean
4345
on_push_undo?: () => void
4446
on_structure_change?: (structure: AnyStructure) => void
4547
/** Indices of selected atoms to optimize (if empty, all atoms are optimized) */
@@ -546,6 +548,7 @@
546548

547549
<DraggablePane
548550
bind:show={pane_open}
551+
{show_toggle}
549552
max_width="20em"
550553
close_on_click_outside={false}
551554
toggle_props={{

src/lib/structure/Structure.svelte

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,11 @@
165165
} from './controllers/viewer-controller'
166166
// tool-controller.svelte.ts exists but is not yet wired (template bind: compatibility)
167167
import StructureToolbar from './StructureToolbar.svelte'
168+
import {
169+
pane_toolbar,
170+
register_toolbar_pane,
171+
type ToolbarToolId,
172+
} from './toolbar-state.svelte'
168173
import { MdAnalysisPane, MdPlot } from '$lib/md'
169174
import SlowGrowthPane from '$lib/structure/SlowGrowthPane.svelte'
170175
import ScaleBar from '$lib/structure/ScaleBar.svelte'
@@ -1211,6 +1216,18 @@
12111216
& Omit<ComponentProps<typeof StructureControls>, `children` | `onclose`>
12121217
& Omit<HTMLAttributes<HTMLDivElement>, `children`> = $props()
12131218
1219+
const toolbar_fallback_key = $props.id()
1220+
let toolbar_pane_key = $derived(viewer_id ?? tab_id ?? toolbar_fallback_key)
1221+
let structure_toolbar_prefs = $derived(pane_toolbar(toolbar_pane_key))
1222+
$effect(() => register_toolbar_pane(toolbar_pane_key))
1223+
1224+
function structure_toolbar_tool_visible(tool_id: ToolbarToolId): boolean {
1225+
const forced_hidden = hidden_toolbar_items.includes(tool_id) ||
1226+
(tool_id === `upload_hpc` && hidden_toolbar_items.includes(`server`))
1227+
return !structure_toolbar_prefs.collapsed && !forced_hidden &&
1228+
!structure_toolbar_prefs.hidden.includes(tool_id)
1229+
}
1230+
12141231
// ── Initialize Controllers (must be after $props() so closures can capture structure, wrapper, etc.) ──
12151232
settings = create_settings_controller({
12161233
get_structure: () => structure,
@@ -3781,6 +3798,8 @@
37813798
</div>
37823799
{:else if (structure?.sites?.length ?? 0) > 0}
37833800
<StructureToolbar
3801+
pane_key={toolbar_pane_key}
3802+
show_info_tool={enable_info_pane && !!structure}
37843803
{camera_has_moved}
37853804
{visible_buttons}
37863805
{hide_extra_tools}
@@ -4039,6 +4058,7 @@
40394058

40404059
{#if structure}
40414060
<OptimizationPane
4061+
show_toggle={structure_toolbar_tool_visible(`optimize`)}
40424062
bind:structure
40434063
bind:pane_open={optimization_pane_open}
40444064
on_push_undo={push_to_undo}
@@ -4629,6 +4649,7 @@
46294649
<!-- === Info / Export / Settings === -->
46304650
{#if enable_info_pane && structure}
46314651
<StructureInfoPane
4652+
show_toggle={structure_toolbar_tool_visible(`info`)}
46324653
{structure}
46334654
bind:pane_open={info_pane_open}
46344655
{selected_sites}
@@ -4640,6 +4661,7 @@
46404661
<!-- ExportPane is now embedded inside IOPane -->
46414662

46424663
<StructureControls
4664+
show_toggle={structure_toolbar_tool_visible(`controls`)}
46434665
bind:controls_open
46444666
bind:scene_props
46454667
bind:lattice_props

src/lib/structure/StructureInfoPane.svelte

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
atom_count_thresholds = [50, 500],
2121
toggle_props = {},
2222
pane_props = {},
23+
show_toggle = true,
2324
highlighted_sites = $bindable([]),
2425
selected_sites = $bindable([]),
2526
symmetry_data = null,
@@ -30,6 +31,7 @@
3031
atom_count_thresholds?: [number, number] // if atom count is less than min_threshold, show sites, if atom count is greater than max_threshold, hide sites. in between, show sites behind a toggle button.
3132
toggle_props?: ComponentProps<typeof DraggablePane>[`toggle_props`]
3233
pane_props?: ComponentProps<typeof DraggablePane>[`pane_props`]
34+
show_toggle?: boolean
3335
highlighted_sites?: number[] // Sites highlighted from Wyckoff table hover
3436
selected_sites?: number[] // Sites selected from Wyckoff table click
3537
symmetry_data?: MoyoDataset | null // Symmetry analysis data (bindable for external access)
@@ -325,6 +327,7 @@
325327

326328
<DraggablePane
327329
bind:show={pane_open}
330+
{show_toggle}
328331
max_width="24em"
329332
toggle_props={{
330333
class: `structure-info-toggle`,

src/lib/structure/StructureScene.svelte

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3433,9 +3433,9 @@
34333433

34343434
// The first bond computation can run before the ferrox WASM finishes loading
34353435
// (a popout window loads its structure at mount; mobile cold-starts are slow).
3436-
// compute_bonds_sync then falls back to the pure-JS path, which emits NO
3437-
// cross-cell PBC bonds. When WASM finishes, recompute ONCE with the real
3438-
// (PBC-aware) detector. Done imperatively + untracked so it can't entangle
3436+
// atom_radii now has an exact PBC-aware JS fallback; the heuristic strategies
3437+
// still need Rust for their periodic graphs. When WASM finishes, recompute
3438+
// ONCE with the preferred detector. Done imperatively + untracked so it can't entangle
34393439
// with the reactive bond effect above (that would loop on bond_state writes).
34403440
$effect(() => on_ferrox_wasm_ready(() => untrack(() => {
34413441
invalidate_bonds_for_recompute(bond_state, bond_input)

0 commit comments

Comments
 (0)