From 0bb52ce6af8683e3899727c1e955041e3fa45d24 Mon Sep 17 00:00:00 2001 From: zy C Date: Sun, 27 Sep 2026 03:00:07 -0700 Subject: [PATCH 1/4] Migrate timeline chrome to Lui_element_combine.buttons --- app/journal_header.ml | 78 ++++++++------- app/journal_view.ml | 179 ++++++++++++++++++++++------------- app/journal_view.mli | 35 +++++-- logseq_journal.opam | 2 +- logseq_journal.opam.locked | 2 +- test/source_boundary_test.ml | 6 +- 6 files changed, 192 insertions(+), 110 deletions(-) diff --git a/app/journal_header.ml b/app/journal_header.ml index 222d653..e2c7fd2 100644 --- a/app/journal_header.ml +++ b/app/journal_header.ml @@ -69,21 +69,9 @@ let view ~capture_expanded ~body = - let selected = - match context with - | Context.Favorites -> true - | Journals -> false - in let heading value = V.text ~style:(Ui.Style.Text_style.create ~font_weight:Semi_bold ()) value in - let navigation label symbol selected on_press = - V.button - ~on_press - ~child:(V.label ~title:(V.text label) ~icon:(Journal_symbols.create symbol) ()) - () - |> V.semantics ~properties:(Ui.Semantics.create ~label ~selected ()) - in let account = match on_account_action with | None -> V.empty () @@ -117,21 +105,28 @@ let view , V.Button_role.Normal ) ] in - V.Menu.create - ~on_select: - (Ui.Event.Handler.create (function - | Ui.Event.Payload.Int64 id -> - List.find_opt (fun (candidate, _, _, _, _) -> candidate = id) actions - |> Option.iter (fun (_, _, _, action, _) -> - Ui.Event.Handler.Private.invoke dispatch (Ui.Event.Payload.Text action)) - | _ -> ())) - ~title:"" - ~icon:(Journal_symbols.name Journal_symbols.Account) - ~label:"Account menu" - (List.map - (fun (id, title, symbol, _, role) -> - V.Menu.action ~id ~role ~title ~icon:symbol ()) - actions) + (* The capsule composite's menu action — the top-right chrome slot now + shares the same glass capsule the sibling [V.buttons] get. *) + V.buttons + ~actions: + [ V.buttons_menu_action + ~label:"Account menu" + ~icon:(Journal_symbols.name Journal_symbols.Account) + ~on_select: + (Ui.Event.Handler.create (function + | Ui.Event.Payload.Int64 id -> + List.find_opt (fun (candidate, _, _, _, _) -> candidate = id) actions + |> Option.iter (fun (_, _, _, action, _) -> + Ui.Event.Handler.Private.invoke + dispatch + (Ui.Event.Payload.Text action)) + | _ -> ())) + (List.map + (fun (id, title, symbol, _, role) -> + V.Menu.action ~id ~role ~title ~icon:symbol ()) + actions) + ] + () |> V.semantics ~properties: (Ui.Semantics.create @@ -234,14 +229,27 @@ let view application.ml) — every toolbar item yields while it is up. *) [] | _ -> - controls - "destinations" - navigation_placement - [ ( "journals" - , navigation "Journals" Journal_symbols.Journals (not selected) on_journals ) - ; ( "favorites" - , navigation "Favorites" Journal_symbols.Favorites selected on_favorites ) - ] + (* The destination pair fuses into one capsule — [buttons] has no + per-action selected state, so the active destination is conveyed by + the page content and its principal title instead. *) + [ V.Toolbar.item + ~key:(Ui.Key.string "destinations") + ~placement:navigation_placement + (V.buttons + ~actions: + [ V.buttons_action + ~label:"Journals" + ~icon:(Journal_symbols.name Journal_symbols.Journals) + ~on_press:on_journals + () + ; V.buttons_action + ~label:"Favorites" + ~icon:(Journal_symbols.name Journal_symbols.Favorites) + ~on_press:on_favorites + () + ] + ()) + ] @ (if platform = "ios" then [ V.Toolbar.spacer diff --git a/app/journal_view.ml b/app/journal_view.ml index aa34ce6..fb0f432 100644 --- a/app/journal_view.ml +++ b/app/journal_view.ml @@ -962,18 +962,27 @@ module View = struct ;; type buttons_action = - { buttons_action_label : string - ; buttons_action_icon : string - ; buttons_action_text : string option - ; buttons_action_on_press : Event.handler - } + | Press of + { buttons_action_label : string + ; buttons_action_icon : string + ; buttons_action_text : string option + ; buttons_action_on_press : Event.handler + } + | Menu of + { buttons_action_label : string + ; buttons_action_icon : string + ; buttons_action_text : string option + ; buttons_action_menu : Lui_elements.t list + ; buttons_action_on_dismiss : Event.handler option + } let buttons_action ~label ~icon ?text ~on_press () = - { buttons_action_label = label - ; buttons_action_icon = icon - ; buttons_action_text = text - ; buttons_action_on_press = on_press - } + Press + { buttons_action_label = label + ; buttons_action_icon = icon + ; buttons_action_text = text + ; buttons_action_on_press = on_press + } ;; (* The shared [Lui_element_combine.buttons] capsule: a single action gets @@ -987,12 +996,34 @@ module View = struct ~actions: (List.map (fun action -> - { Lui_element_combine.label = action.buttons_action_label - ; icon = journal_icon action.buttons_action_icon - ; text = action.buttons_action_text - ; on_press = - (fun _ -> invoke action.buttons_action_on_press Event.Payload.Unit) - }) + match action with + | Press + { buttons_action_label = label + ; buttons_action_icon = icon + ; buttons_action_text = text + ; buttons_action_on_press = on_press + } -> + Lui_element_combine.Press + { label + ; icon = journal_icon icon + ; text + ; on_press = (fun _ -> invoke on_press Event.Payload.Unit) + } + | Menu + { buttons_action_label = label + ; buttons_action_icon = icon + ; buttons_action_text = text + ; buttons_action_menu = menu + ; buttons_action_on_dismiss = on_dismiss + } -> + Lui_element_combine.Menu + { label + ; icon = journal_icon icon + ; text + ; menu + ; on_dismiss = + Option.map (fun h _ -> invoke h Event.Payload.Unit) on_dismiss + }) actions)) ;; @@ -2353,54 +2384,61 @@ module View = struct [] ;; + let rec entry_elements ~on_select (entry : entry) : Lui_elements.t list = + match entry with + | Divider id -> + [ Lui_elements.separator ~key:(Int64.to_string id) ~orientation:`horizontal [] ] + | Action { id; label; enabled; role } -> + [ menu_item + ~key:(Int64.to_string id) + ~title:label.title + ~icon:label.icon + ~enabled + ~role + ~selected:None + ~on_press:(fun () -> invoke on_select (Event.Payload.Int64 id)) + () + ] + | Choice { id; label; selected; enabled } -> + [ Lui_element_combine.check_menu_item + ~key:(Int64.to_string id) + ~label:(if String.length label.title = 0 then " " else label.title) + ?icon:(Option.map journal_icon label.icon) + ~checked:selected + ~disabled:(not enabled) + ~on_press:(fun _ -> invoke on_select (Event.Payload.Int64 id)) + () + ] + | Section { label; entries; _ } -> + (match label with + | Some label -> + [ menu_item + ~title:label.title + ~icon:label.icon + ~enabled:false + ~role:Button_role.Normal + ~selected:None + () + ] + | None -> []) + @ List.concat_map (entry_elements ~on_select) entries + | Submenu { id; label; enabled; entries } -> + [ Lui_elements.submenu + ~key:(Int64.to_string id) + ~text:(if String.length label.title = 0 then " " else label.title) + ?icon:(Option.map journal_icon label.icon) + ~disabled:(not enabled) + (List.concat_map (entry_elements ~on_select) entries) + ] + ;; + + (* Menu entries rendered as [dropdown_menu] children — for [buttons] + menu actions, where the capsule composite mounts the trigger. *) + let to_elements ~on_select entries = + List.concat_map (entry_elements ~on_select) entries + ;; + let create ?key ?(enabled = true) ~on_select ~title ?icon ?label entries = - let rec entry_elements (entry : entry) : Lui_elements.t list = - match entry with - | Divider id -> - [ Lui_elements.separator ~key:(Int64.to_string id) ~orientation:`horizontal [] ] - | Action { id; label; enabled; role } -> - [ menu_item - ~key:(Int64.to_string id) - ~title:label.title - ~icon:label.icon - ~enabled - ~role - ~selected:None - ~on_press:(fun () -> invoke on_select (Event.Payload.Int64 id)) - () - ] - | Choice { id; label; selected; enabled } -> - [ Lui_element_combine.check_menu_item - ~key:(Int64.to_string id) - ~label:(if String.length label.title = 0 then " " else label.title) - ?icon:(Option.map journal_icon label.icon) - ~checked:selected - ~disabled:(not enabled) - ~on_press:(fun _ -> invoke on_select (Event.Payload.Int64 id)) - () - ] - | Section { label; entries; _ } -> - (match label with - | Some label -> - [ menu_item - ~title:label.title - ~icon:label.icon - ~enabled:false - ~role:Button_role.Normal - ~selected:None - () - ] - | None -> []) - @ List.concat_map entry_elements entries - | Submenu { id; label; enabled; entries } -> - [ Lui_elements.submenu - ~key:(Int64.to_string id) - ~text:(if String.length label.title = 0 then " " else label.title) - ?icon:(Option.map journal_icon label.icon) - ~disabled:(not enabled) - (List.concat_map entry_elements entries) - ] - in element ?key (Lui_elements.menu @@ -2408,9 +2446,22 @@ module View = struct ?icon:(Option.map journal_icon icon) ?label ~disabled:(not enabled) - (List.concat_map entry_elements entries)) + (to_elements ~on_select entries)) ;; end + + (* A [buttons] action that opens a native dropdown menu — the [Menu.entry] + vocabulary (actions, choices, sections, submenus) carries over, with the + same [Int64] id dispatch as [Menu.create]. *) + let buttons_menu_action ~label ~icon ?text ~on_select ?on_dismiss entries = + Menu + { buttons_action_label = label + ; buttons_action_icon = icon + ; buttons_action_text = text + ; buttons_action_menu = Menu.to_elements ~on_select entries + ; buttons_action_on_dismiss = on_dismiss + } + ;; end module Native_widget = struct diff --git a/app/journal_view.mli b/app/journal_view.mli index eb707e1..0f165bf 100644 --- a/app/journal_view.mli +++ b/app/journal_view.mli @@ -457,13 +457,23 @@ module View : sig -> t (** One capsule action for {!buttons}: [label] is the accessibility name, - [icon] an SF Symbol name, [text] optional visible text. *) + [icon] an SF Symbol name, [text] optional visible text. A [Press] + action fires its handler; a [Menu] action opens a native dropdown menu + of pre-built entries. *) type buttons_action = - { buttons_action_label : string - ; buttons_action_icon : string - ; buttons_action_text : string option - ; buttons_action_on_press : Event.handler - } + | Press of + { buttons_action_label : string + ; buttons_action_icon : string + ; buttons_action_text : string option + ; buttons_action_on_press : Event.handler + } + | Menu of + { buttons_action_label : string + ; buttons_action_icon : string + ; buttons_action_text : string option + ; buttons_action_menu : Lui_elements.t list + ; buttons_action_on_dismiss : Event.handler option + } val buttons_action : label:string @@ -919,6 +929,19 @@ module View : sig -> entry list -> t end + + (** A menu capsule action for {!buttons} built from {!Menu.entry} values: + pressing it opens the native dropdown and selecting an entry invokes + [on_select] with the entry's [Int64] id, same dispatch as + {!Menu.create}. *) + val buttons_menu_action + : label:string + -> icon:string + -> ?text:string + -> on_select:Event.handler + -> ?on_dismiss:Event.handler + -> Menu.entry list + -> buttons_action end module Native_widget : sig diff --git a/logseq_journal.opam b/logseq_journal.opam index 2818bfd..2c6eaaa 100644 --- a/logseq_journal.opam +++ b/logseq_journal.opam @@ -46,7 +46,7 @@ depends: [ ] pin-depends: [ ["rrbvec.dev" "git+https://github.com/logseq/rrbvec.git#main"] - ["lui.0.1.0" "git+https://github.com/logseq/lui.git#3ea3e5273b31bcce5d575b26ec03c47b728c58f0"] + ["lui.0.1.0" "git+https://github.com/logseq/lui.git#0c93a0000b11942c36992b1b257c3e3d5b63ede4"] ["ocaml-signal.0.1.0" "git+https://github.com/logseq/ocaml-signal.git#976b40f1770a65b3464df1ef38d1550f1d8a43dd"] ["datascript_ocaml.dev" "git+https://github.com/logseq/datascript-ocaml.git#40345cc2f59214daa88b33b8aec711337d20afa7"] ["datascript-ocaml-native.dev" "git+https://github.com/logseq/datascript-ocaml.git#40345cc2f59214daa88b33b8aec711337d20afa7"] diff --git a/logseq_journal.opam.locked b/logseq_journal.opam.locked index 622327e..ca17b46 100644 --- a/logseq_journal.opam.locked +++ b/logseq_journal.opam.locked @@ -23,7 +23,7 @@ pin-depends: [ ] [ "lui.0.1.0" - "git+https://github.com/logseq/lui.git#3ea3e5273b31bcce5d575b26ec03c47b728c58f0" + "git+https://github.com/logseq/lui.git#0c93a0000b11942c36992b1b257c3e3d5b63ede4" ] [ "melange-edn-core.0.5.0" diff --git a/test/source_boundary_test.ml b/test/source_boundary_test.ml index fe23af7..af92ba9 100644 --- a/test/source_boundary_test.ml +++ b/test/source_boundary_test.ml @@ -1170,7 +1170,7 @@ let () = require_occurrences root "logseq_journal.opam" - "git+https://github.com/logseq/lui.git#3ea3e5273b31bcce5d575b26ec03c47b728c58f0" + "git+https://github.com/logseq/lui.git#0c93a0000b11942c36992b1b257c3e3d5b63ede4" 1; require_occurrences root @@ -1324,9 +1324,9 @@ let () = root "app/journal_header.ml" [ "Journal_symbols.Account" - ; "V.button" + ; "V.buttons" ; "V.semantics" - ; "V.Menu.create" + ; "V.buttons_menu_action" ; "journal-root-navigation" ; "switch-graph" ; "sign-out" From 053fea9eea07ccc0477fc59c0922e38d694ce6ae Mon Sep 17 00:00:00 2001 From: zy C Date: Sun, 27 Sep 2026 03:50:11 -0700 Subject: [PATCH 2/4] Fuse top-right error + account chrome into one buttons capsule --- app/journal_header.ml | 191 ++++++++++++++++++++++++------------------ 1 file changed, 108 insertions(+), 83 deletions(-) diff --git a/app/journal_header.ml b/app/journal_header.ml index e2c7fd2..5167c80 100644 --- a/app/journal_header.ml +++ b/app/journal_header.ml @@ -72,85 +72,110 @@ let view let heading value = V.text ~style:(Ui.Style.Text_style.create ~font_weight:Semi_bold ()) value in - let account = - match on_account_action with - | None -> V.empty () - | Some dispatch -> - let actions = - [ ( 5L - , "Attachment settings" - , "slider.horizontal.3" - , "open-asset-settings" - , V.Button_role.Normal ) - ; 1L, "Diagnostics", "stethoscope", "open-diagnostics", V.Button_role.Normal - ; ( 2L - , "Switch graph" - , "arrow.triangle.2.circlepath" - , "switch-graph" - , V.Button_role.Normal ) - ] - @ (if local_deletion_available - then - [ ( 3L - , "Delete local graph copy" - , "trash" - , "request-local-cache-reset" - , V.Button_role.Destructive ) + let account_action = + Option.map + (fun dispatch -> + let actions = + [ ( 5L + , "Attachment settings" + , "slider.horizontal.3" + , "open-asset-settings" + , V.Button_role.Normal ) + ; 1L, "Diagnostics", "stethoscope", "open-diagnostics", V.Button_role.Normal + ; ( 2L + , "Switch graph" + , "arrow.triangle.2.circlepath" + , "switch-graph" + , V.Button_role.Normal ) + ] + @ (if local_deletion_available + then + [ ( 3L + , "Delete local graph copy" + , "trash" + , "request-local-cache-reset" + , V.Button_role.Destructive ) + ] + else []) + @ [ ( 4L + , "Sign out" + , "rectangle.portrait.and.arrow.right" + , "sign-out" + , V.Button_role.Normal ) ] - else []) - @ [ ( 4L - , "Sign out" - , "rectangle.portrait.and.arrow.right" - , "sign-out" - , V.Button_role.Normal ) - ] + in + V.buttons_menu_action + ~label:"Account menu" + ~icon:(Journal_symbols.name Journal_symbols.Account) + ~on_select: + (Ui.Event.Handler.create (function + | Ui.Event.Payload.Int64 id -> + List.find_opt (fun (candidate, _, _, _, _) -> candidate = id) actions + |> Option.iter (fun (_, _, _, action, _) -> + Ui.Event.Handler.Private.invoke + dispatch + (Ui.Event.Payload.Text action)) + | _ -> ())) + (List.map + (fun (id, title, symbol, _, role) -> + V.Menu.action ~id ~role ~title ~icon:symbol ()) + actions)) + on_account_action + in + let error_action = + Option.map + (fun on_press -> + V.buttons_action + ~label:"Error info" + ~icon:(Journal_symbols.name Journal_symbols.Error) + ~on_press + ()) + on_error_info + in + (* The error and account chrome controls fuse into one capsule: error leads + so the account menu stays the trailing glyph. *) + let cluster = + match Option.to_list error_action @ Option.to_list account_action with + | [] -> None + | actions -> + let view = V.buttons ~actions () in + let view = + if Option.is_some error_action + then + view + |> V.help ~message:"Inspect application errors" + |> test_id "journal-error-info-button" + else view in - (* The capsule composite's menu action — the top-right chrome slot now - shares the same glass capsule the sibling [V.buttons] get. *) - V.buttons - ~actions: - [ V.buttons_menu_action - ~label:"Account menu" - ~icon:(Journal_symbols.name Journal_symbols.Account) - ~on_select: - (Ui.Event.Handler.create (function - | Ui.Event.Payload.Int64 id -> - List.find_opt (fun (candidate, _, _, _, _) -> candidate = id) actions - |> Option.iter (fun (_, _, _, action, _) -> - Ui.Event.Handler.Private.invoke - dispatch - (Ui.Event.Payload.Text action)) - | _ -> ())) - (List.map - (fun (id, title, symbol, _, role) -> - V.Menu.action ~id ~role ~title ~icon:symbol ()) - actions) - ] - () - |> V.semantics - ~properties: - (Ui.Semantics.create - ~label:"Account menu" - ~hint:"Switch graphs, delete the local copy, or sign out" - ~role:Button - ()) - |> test_id "journal-account-menu-button" + let view = + if Option.is_some account_action + then + view + |> V.semantics + ~properties: + (Ui.Semantics.create + ~label:"Account menu" + ~hint:"Switch graphs, delete the local copy, or sign out" + ~role:Button + ()) + |> test_id "journal-account-menu-button" + else view + in + Some view in - let error = - match on_error_info with - | None -> V.empty () - | Some on_press -> - V.buttons - ~actions: - [ V.buttons_action - ~label:"Error info" - ~icon:(Journal_symbols.name Journal_symbols.Error) - ~on_press - () - ] - () - |> V.help ~message:"Inspect application errors" - |> test_id "journal-error-info-button" + (* The chrome's error slot is only used when there is no account action to + fuse with; otherwise the error button rides inside the account capsule. *) + let account_slot_used = Option.is_some on_account_action in + let error_slot_used = + Option.is_none on_account_action && Option.is_some on_error_info + in + let slot_column ~used = + if platform <> "ios" + then V.column [] + else ( + match cluster with + | Some view when used -> V.column [ view ] + | _ -> V.column []) in let capture = (* buttons has no disabled state — guard the handler instead. *) @@ -219,9 +244,9 @@ let view controls "account" V.Toolbar.Primary_action - (Option.to_list (Option.map (fun _ -> "error", error) on_error_info) - @ Option.to_list (Option.map (fun _ -> "account", account) on_account_action) - )) + (match cluster with + | Some view -> [ "account", view ] + | None -> [])) @ match capture_expanded with | Some _ when platform = "ios" -> @@ -292,16 +317,16 @@ let view (`Assoc [ "mode", `String "journal" ; "connecting", `Bool (sync_phase = Some Graph_service.Connecting) - ; "account", `Bool (Option.is_some on_account_action) - ; "error", `Bool (Option.is_some on_error_info) + ; "account", `Bool account_slot_used + ; "error", `Bool error_slot_used ]) ~on_event:(fun _ -> ()) (* Chrome slots are positional on the native side — absent slots must still mount a (zero-size) node or the host's index lookup shifts. *) ~children: [ V.Body.Private.to_widget body - ; (if platform = "ios" then V.column [ account ] else V.column []) - ; (if platform = "ios" then V.column [ error ] else V.column []) + ; slot_column ~used:account_slot_used + ; slot_column ~used:error_slot_used ; V.column [ (if sync_phase = Some Graph_service.Connecting then From e325255c63031c1395c6b59e6adff500a8d0fcdf Mon Sep 17 00:00:00 2001 From: zy C Date: Sun, 27 Sep 2026 05:41:20 -0700 Subject: [PATCH 3/4] chrome: float the bottom toolbar over scrolling content The .bottomBar toolbar reserves container safe-area space, so the FloatingChrome GeometryReader (and the list inside it) was inset above the bar region and the band showed the opaque window background. Hide the bottomBar toolbar background and let the content extend under it so the bottom capsules float over scrollable content, matching the floating top-right controls. --- swift/JournalChrome.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/swift/JournalChrome.swift b/swift/JournalChrome.swift index 72f99f5..0ceffc5 100644 --- a/swift/JournalChrome.swift +++ b/swift/JournalChrome.swift @@ -31,6 +31,7 @@ import SwiftUI GeometryReader { bounds in content.frame(width: bounds.size.width, height: bounds.size.height) .scrollContentBackground(.hidden) + .toolbarBackground(.hidden, for: .bottomBar) #if os(iOS) .environment(\.journalControlsSize, controlsSize) .toolbar(.hidden, for: .navigationBar) @@ -54,6 +55,9 @@ import SwiftUI } #endif } + #if os(iOS) + .ignoresSafeArea(.container, edges: .bottom) + #endif } } From b4288f8933eb4986375d5631e1a4c1689fb9f6ec Mon Sep 17 00:00:00 2001 From: zy C Date: Sun, 27 Sep 2026 06:25:19 -0700 Subject: [PATCH 4/4] pin lui to merged main (df9fddb, PR #64) --- logseq_journal.opam | 2 +- logseq_journal.opam.locked | 2 +- test/source_boundary_test.ml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/logseq_journal.opam b/logseq_journal.opam index 2c6eaaa..86b0f87 100644 --- a/logseq_journal.opam +++ b/logseq_journal.opam @@ -46,7 +46,7 @@ depends: [ ] pin-depends: [ ["rrbvec.dev" "git+https://github.com/logseq/rrbvec.git#main"] - ["lui.0.1.0" "git+https://github.com/logseq/lui.git#0c93a0000b11942c36992b1b257c3e3d5b63ede4"] + ["lui.0.1.0" "git+https://github.com/logseq/lui.git#df9fddb8ad616131d710f69d152abead837e2fd6"] ["ocaml-signal.0.1.0" "git+https://github.com/logseq/ocaml-signal.git#976b40f1770a65b3464df1ef38d1550f1d8a43dd"] ["datascript_ocaml.dev" "git+https://github.com/logseq/datascript-ocaml.git#40345cc2f59214daa88b33b8aec711337d20afa7"] ["datascript-ocaml-native.dev" "git+https://github.com/logseq/datascript-ocaml.git#40345cc2f59214daa88b33b8aec711337d20afa7"] diff --git a/logseq_journal.opam.locked b/logseq_journal.opam.locked index ca17b46..83fee00 100644 --- a/logseq_journal.opam.locked +++ b/logseq_journal.opam.locked @@ -23,7 +23,7 @@ pin-depends: [ ] [ "lui.0.1.0" - "git+https://github.com/logseq/lui.git#0c93a0000b11942c36992b1b257c3e3d5b63ede4" + "git+https://github.com/logseq/lui.git#df9fddb8ad616131d710f69d152abead837e2fd6" ] [ "melange-edn-core.0.5.0" diff --git a/test/source_boundary_test.ml b/test/source_boundary_test.ml index af92ba9..2c382d1 100644 --- a/test/source_boundary_test.ml +++ b/test/source_boundary_test.ml @@ -1170,7 +1170,7 @@ let () = require_occurrences root "logseq_journal.opam" - "git+https://github.com/logseq/lui.git#0c93a0000b11942c36992b1b257c3e3d5b63ede4" + "git+https://github.com/logseq/lui.git#df9fddb8ad616131d710f69d152abead837e2fd6" 1; require_occurrences root