Ver Fonte

native top bar

Tienson Qin há 1 mês atrás
pai
commit
7c41eaa413

+ 4 - 0
ios/App/App.xcodeproj/project.pbxproj

@@ -26,6 +26,7 @@
                 CBF2D2E22DE95970006338BE /* AppViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBF2D2E12DE95970006338BE /* AppViewController.swift */; };
                 CBF2D2E22DE95970006338BE /* AppViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBF2D2E12DE95970006338BE /* AppViewController.swift */; };
                 A1B2C3D41E2F3A4B5C6D7E90 /* NativePageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C3D41E2F3A4B5C6D7E8F /* NativePageViewController.swift */; };
                 A1B2C3D41E2F3A4B5C6D7E90 /* NativePageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C3D41E2F3A4B5C6D7E8F /* NativePageViewController.swift */; };
                 A1B2C3D41E2F3A4B5C6D7E92 /* SharedWebViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C3D41E2F3A4B5C6D7E91 /* SharedWebViewController.swift */; };
                 A1B2C3D41E2F3A4B5C6D7E92 /* SharedWebViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1B2C3D41E2F3A4B5C6D7E91 /* SharedWebViewController.swift */; };
+                ABCDEF0123456789000000AB /* NativeTopBarPlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABCDEF0123456789000000AA /* NativeTopBarPlugin.swift */; };
                 D32752BE275496C60039291C /* CloudKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D32752BD275496C60039291C /* CloudKit.framework */; };
                 D32752BE275496C60039291C /* CloudKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D32752BD275496C60039291C /* CloudKit.framework */; };
                 D3490CC62E7CE9EA00E796A6 /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D3490CC52E7CE9EA00E796A6 /* WidgetKit.framework */; };
                 D3490CC62E7CE9EA00E796A6 /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D3490CC52E7CE9EA00E796A6 /* WidgetKit.framework */; };
                 D3490CC82E7CE9EA00E796A6 /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D3490CC72E7CE9EA00E796A6 /* SwiftUI.framework */; };
                 D3490CC82E7CE9EA00E796A6 /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D3490CC72E7CE9EA00E796A6 /* SwiftUI.framework */; };
@@ -95,6 +96,7 @@
                 B2E26D73EA097D0B3B22942E /* Pods_Logseq.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Logseq.framework; sourceTree = BUILT_PRODUCTS_DIR; };
                 B2E26D73EA097D0B3B22942E /* Pods_Logseq.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Logseq.framework; sourceTree = BUILT_PRODUCTS_DIR; };
                 CBF2D2D92DE83CB0006338BE /* UILocalPlugin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UILocalPlugin.swift; sourceTree = "<group>"; };
                 CBF2D2D92DE83CB0006338BE /* UILocalPlugin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UILocalPlugin.swift; sourceTree = "<group>"; };
                 CBF2D2E12DE95970006338BE /* AppViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppViewController.swift; sourceTree = "<group>"; };
                 CBF2D2E12DE95970006338BE /* AppViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppViewController.swift; sourceTree = "<group>"; };
+                ABCDEF0123456789000000AA /* NativeTopBarPlugin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NativeTopBarPlugin.swift; sourceTree = "<group>"; };
                 A1B2C3D41E2F3A4B5C6D7E8F /* NativePageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NativePageViewController.swift; sourceTree = "<group>"; };
                 A1B2C3D41E2F3A4B5C6D7E8F /* NativePageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NativePageViewController.swift; sourceTree = "<group>"; };
                 A1B2C3D41E2F3A4B5C6D7E91 /* SharedWebViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharedWebViewController.swift; sourceTree = "<group>"; };
                 A1B2C3D41E2F3A4B5C6D7E91 /* SharedWebViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharedWebViewController.swift; sourceTree = "<group>"; };
                 D32752BC275496A60039291C /* App.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = App.entitlements; sourceTree = "<group>"; };
                 D32752BC275496A60039291C /* App.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = App.entitlements; sourceTree = "<group>"; };
@@ -187,6 +189,7 @@
                                 A1B2C3D41E2F3A4B5C6D7E91 /* SharedWebViewController.swift */,
                                 A1B2C3D41E2F3A4B5C6D7E91 /* SharedWebViewController.swift */,
                                 CBF2D2E12DE95970006338BE /* AppViewController.swift */,
                                 CBF2D2E12DE95970006338BE /* AppViewController.swift */,
                                 CBF2D2D92DE83CB0006338BE /* UILocalPlugin.swift */,
                                 CBF2D2D92DE83CB0006338BE /* UILocalPlugin.swift */,
+                                ABCDEF0123456789000000AA /* NativeTopBarPlugin.swift */,
                                 5FF86329283B5ADB0047731B /* Utils.swift */,
                                 5FF86329283B5ADB0047731B /* Utils.swift */,
                                 5FF8632B283B5BFD0047731B /* Utils.m */,
                                 5FF8632B283B5BFD0047731B /* Utils.m */,
                                 D32752BF2754C5AB0039291C /* AppDebug.entitlements */,
                                 D32752BF2754C5AB0039291C /* AppDebug.entitlements */,
@@ -432,6 +435,7 @@
                                 CBF2D2E22DE95970006338BE /* AppViewController.swift in Sources */,
                                 CBF2D2E22DE95970006338BE /* AppViewController.swift in Sources */,
                                 D3D62A0A275C92880003FBDC /* FileContainer.swift in Sources */,
                                 D3D62A0A275C92880003FBDC /* FileContainer.swift in Sources */,
                                 CBF2D2DA2DE83CB8006338BE /* UILocalPlugin.swift in Sources */,
                                 CBF2D2DA2DE83CB8006338BE /* UILocalPlugin.swift in Sources */,
+                                ABCDEF0123456789000000AB /* NativeTopBarPlugin.swift in Sources */,
                                 A1B2C3D41E2F3A4B5C6D7E90 /* NativePageViewController.swift in Sources */,
                                 A1B2C3D41E2F3A4B5C6D7E90 /* NativePageViewController.swift in Sources */,
                                 A1B2C3D41E2F3A4B5C6D7E92 /* SharedWebViewController.swift in Sources */,
                                 A1B2C3D41E2F3A4B5C6D7E92 /* SharedWebViewController.swift in Sources */,
                                 D3D62A0C275C928F0003FBDC /* FileContainer.m in Sources */,
                                 D3D62A0C275C928F0003FBDC /* FileContainer.m in Sources */,

+ 1 - 0
ios/App/App/AppViewController.swift

@@ -11,5 +11,6 @@ import Capacitor
 @objc public class AppViewController: CAPBridgeViewController {
 @objc public class AppViewController: CAPBridgeViewController {
   override public func capacitorDidLoad() {
   override public func capacitorDidLoad() {
     bridge?.registerPluginInstance(UILocalPlugin())
     bridge?.registerPluginInstance(UILocalPlugin())
+    bridge?.registerPluginInstance(NativeTopBarPlugin())
   }
   }
 }
 }

+ 147 - 0
ios/App/App/NativeTopBarPlugin.swift

@@ -0,0 +1,147 @@
+import Capacitor
+import UIKit
+
+@objc(NativeTopBarPlugin)
+public class NativeTopBarPlugin: CAPPlugin, CAPBridgedPlugin {
+    public let identifier = "NativeTopBarPlugin"
+    public let jsName = "NativeTopBarPlugin"
+    public let pluginMethods: [CAPPluginMethod] = [
+        CAPPluginMethod(name: "configure", returnType: CAPPluginReturnPromise)
+    ]
+
+    private class NativeTopBarButton: UIButton {
+        var buttonId: String = ""
+    }
+
+    private func navigationController() -> UINavigationController? {
+        // AppViewController is embedded inside NativePageViewController, which
+        // lives in the root UINavigationController created in AppDelegate.
+        if let nav = bridge?.viewController?.parent?.navigationController {
+            return nav
+        }
+        return bridge?.viewController?.navigationController
+    }
+
+    @objc func configure(_ call: CAPPluginCall) {
+        guard let nav = navigationController() else {
+            call.reject("Navigation controller not found")
+            return
+        }
+
+        let title = call.getString("title")
+        let leftButtons = call.getArray("leftButtons", JSObject.self) ?? []
+        let rightButtons = call.getArray("rightButtons", JSObject.self) ?? []
+        let backgroundColorHex = call.getString("backgroundColor")
+        let tintColorHex = call.getString("tintColor")
+        let titleClickable = call.getBool("titleClickable") ?? false
+
+        DispatchQueue.main.async { [weak self] in
+            guard let self = self else { return }
+            nav.setNavigationBarHidden(false, animated: false)
+
+            let appearance = UINavigationBarAppearance()
+            appearance.configureWithOpaqueBackground()
+            appearance.backgroundColor = backgroundColorHex?.toUIColor(defaultColor: .systemBackground)
+            appearance.shadowColor = .clear
+            appearance.titleTextAttributes = [
+                .foregroundColor: tintColorHex?.toUIColor(defaultColor: .label) ?? .label
+            ]
+
+            nav.navigationBar.standardAppearance = appearance
+            nav.navigationBar.scrollEdgeAppearance = appearance
+            nav.navigationBar.tintColor = tintColorHex?.toUIColor(defaultColor: .label) ?? .label
+
+            if let topVC = nav.topViewController {
+                topVC.navigationItem.titleView = nil
+                if titleClickable, let title {
+                    let button = NativeTopBarButton(type: .system)
+                    button.buttonId = "title"
+                    button.setTitle(title, for: .normal)
+                    button.setTitleColor(nav.navigationBar.tintColor, for: .normal)
+                    button.titleLabel?.font = UIFont.systemFont(ofSize: 17, weight: .semibold)
+                    button.addTarget(self, action: #selector(titleTapped(_:)), for: .touchUpInside)
+                    topVC.navigationItem.titleView = button
+                } else {
+                    topVC.navigationItem.title = title
+                }
+                topVC.navigationItem.leftBarButtonItems = self.buildButtons(from: leftButtons)
+                topVC.navigationItem.rightBarButtonItems = self.buildButtons(from: rightButtons)
+            }
+
+            call.resolve()
+        }
+    }
+
+    private func buildButtons(from array: [JSObject]) -> [UIBarButtonItem] {
+        return array.compactMap { obj in
+            guard let id = obj["id"] as? String else { return nil }
+            let systemIconName = (obj["systemIcon"] as? String) ?? "circle"
+
+            let button = NativeTopBarButton(type: .system)
+            button.buttonId = id
+            if let image = UIImage(systemName: systemIconName) {
+                button.setImage(image, for: .normal)
+            }
+            button.tintColor = tintColor(for: obj)
+            button.frame = CGRect(x: 0, y: 0, width: 32, height: 32)
+            button.imageView?.contentMode = .scaleAspectFit
+            button.addTarget(self, action: #selector(buttonTapped(_:)), for: .touchUpInside)
+
+            let item = UIBarButtonItem(customView: button)
+            // Ensure a minimum tap target size
+            button.widthAnchor.constraint(equalToConstant: 36).isActive = true
+            button.heightAnchor.constraint(equalToConstant: 32).isActive = true
+            return item
+        }
+    }
+
+    private func tintColor(for obj: JSObject) -> UIColor {
+        if let hex = obj["tintColor"] as? String {
+            return hex.toUIColor(defaultColor: .label)
+        }
+        return .label
+    }
+
+    @objc private func buttonTapped(_ sender: NativeTopBarButton) {
+        notifyListeners("buttonTapped", data: ["id": sender.buttonId])
+    }
+
+    @objc private func titleTapped(_ sender: NativeTopBarButton) {
+        notifyListeners("buttonTapped", data: ["id": "title"])
+    }
+}
+
+// MARK: - Color helpers
+
+private extension String {
+    func toUIColor(defaultColor: UIColor) -> UIColor {
+        var hexString = self.trimmingCharacters(in: .whitespacesAndNewlines).uppercased()
+        if hexString.hasPrefix("#") {
+            hexString.removeFirst()
+        }
+
+        var rgbValue: UInt64 = 0
+        guard Scanner(string: hexString).scanHexInt64(&rgbValue) else {
+            return defaultColor
+        }
+
+        switch hexString.count {
+        case 6: // RRGGBB
+            return UIColor(
+                red: CGFloat((rgbValue & 0xFF0000) >> 16) / 255.0,
+                green: CGFloat((rgbValue & 0x00FF00) >> 8) / 255.0,
+                blue: CGFloat(rgbValue & 0x0000FF) / 255.0,
+                alpha: 1.0
+            )
+        case 8: // RRGGBBAA
+            return UIColor(
+                red: CGFloat((rgbValue & 0xFF000000) >> 24) / 255.0,
+                green: CGFloat((rgbValue & 0x00FF0000) >> 16) / 255.0,
+                blue: CGFloat((rgbValue & 0x0000FF00) >> 8) / 255.0,
+                alpha: CGFloat(rgbValue & 0x000000FF) / 255.0
+            )
+        default:
+            return defaultColor
+        }
+    }
+}

+ 4 - 1
src/main/frontend/mobile/util.cljs

@@ -23,8 +23,11 @@
 
 
 (defonce folder-picker (registerPlugin "FolderPicker"))
 (defonce folder-picker (registerPlugin "FolderPicker"))
 (defonce ui-local (registerPlugin "UILocal"))
 (defonce ui-local (registerPlugin "UILocal"))
+(defonce native-top-bar nil)
+(defonce ios-utils nil)
 (when (native-ios?)
 (when (native-ios?)
-  (defonce ios-utils (registerPlugin "Utils")))
+  (set! native-top-bar (registerPlugin "NativeTopBarPlugin"))
+  (set! ios-utils (registerPlugin "Utils")))
 
 
 (defn hide-splash []
 (defn hide-splash []
   (.hide SplashScreen))
   (.hide SplashScreen))

+ 1 - 1
src/main/mobile/components/app.cljs

@@ -221,7 +221,7 @@
                         {:data-tab (str tab)}
                         {:data-tab (str tab)}
                         (main-content tab *home)])))
                         (main-content tab *home)])))
 
 
-      ;; (mobile-header/header tab login?)
+      (mobile-header/header tab login?)
 
 
       (mobile-left-sidebar/left-sidebar)
       (mobile-left-sidebar/left-sidebar)
 
 

+ 106 - 101
src/main/mobile/components/header.cljs

@@ -19,70 +19,21 @@
             [logseq.shui.ui :as shui]
             [logseq.shui.ui :as shui]
             [missionary.core :as m]
             [missionary.core :as m]
             [mobile.components.ui :as ui-component]
             [mobile.components.ui :as ui-component]
-            [mobile.components.ui-silk :as ui-silk]
             [mobile.state :as mobile-state]
             [mobile.state :as mobile-state]
             [promesa.core :as p]
             [promesa.core :as p]
             [rum.core :as rum]))
             [rum.core :as rum]))
 
 
-(rum/defc app-graphs-select
-  []
-  (let [current-repo (state/get-current-repo)
-        short-repo-name (if current-repo
-                          (db-conn/get-short-repo-name current-repo)
-                          "Select a Graph")]
-    [:.app-graph-select
-     (shui/button
-      {:variant :text
-       :size :sm
-       :on-click (fn [e]
-                   (shui/popup-show! (.-target e)
-                                     (fn [{:keys [id]}]
-                                       (repo/repos-dropdown-content {:contentid id}))
-                                     {:id :switch-graph
-                                      :default-height false
-                                      :content-props {:class "repos-list"}}))}
-      [:span.flex.items-center.pt-1
-       [:span.overflow-hidden.text-ellipsis.block.text-base
-        {:style {:max-width "40vw"}}
-        short-repo-name]])]))
-
-(rum/defc journal-calendar-btn
-  []
-  (shui/button
-   {:variant :text
-    :size :sm
-    :on-click (fn []
-                (let [apply-date! (fn [date]
-                                    (let [page-name (date/journal-name (gdate/Date. (js/Date. date)))]
-                                      (if-let [journal (db/get-page page-name)]
-                                        (mobile-state/open-block-modal! journal)
-                                        (-> (page-handler/<create! page-name {:redirect? false})
-                                            (p/then #(mobile-state/open-block-modal! (db/get-page page-name)))))))]
-                  (-> (.showDatePicker mobile-util/ui-local)
-                      (p/then (fn [^js e] (some-> e (.-value) (apply-date!)))))))}
-   [:span.mt-1
-    (shui/tabler-icon "calendar-month" {:size 24})]))
+(defonce native-top-bar-listener? (atom false))
 
 
-(rum/defc rtc-indicator-btn
-  []
-  (let [repo (state/get-current-repo)]
-    [:div.flex.flex-row.items-center.gap-2
-     (when (and repo
-                (ldb/get-graph-rtc-uuid (db/get-db))
-                (user-handler/logged-in?))
-       (rtc-indicator/indicator))]))
-
-(rum/defc menu-button
-  []
-  (shui/button
-   {:variant :text
-    :size :sm
-    :on-pointer-down (fn [e]
-                       (util/stop e)
-                       (mobile-state/close-block-modal!)
-                       (mobile-state/open-left-sidebar!))}
-   [:span.mt-2
-    (shui/tabler-icon "menu" {:size 24})]))
+(defn- open-journal-calendar! []
+  (let [apply-date! (fn [date]
+                      (let [page-name (date/journal-name (gdate/Date. (js/Date. date)))]
+                        (if-let [journal (db/get-page page-name)]
+                          (mobile-state/open-block-modal! journal)
+                          (-> (page-handler/<create! page-name {:redirect? false})
+                              (p/then #(mobile-state/open-block-modal! (db/get-page page-name)))))))]
+    (-> (.showDatePicker mobile-util/ui-local)
+        (p/then (fn [^js e] (some-> e (.-value) (apply-date!)))))))
 
 
 (rum/defc log
 (rum/defc log
   []
   []
@@ -142,47 +93,101 @@
         (for [record records]
         (for [record records]
           [:li (str (:level record) " " (:message record))])])]))
           [:li (str (:level record) " " (:message record))])])]))
 
 
+(defn- open-settings-actions! []
+  (ui-component/open-popup!
+   (fn []
+     [:div.-mx-2
+      (when (user-handler/logged-in?)
+        (ui/menu-link {:on-click #(user-handler/logout)}
+                      [:span.text-lg.flex.gap-2.items-center.text-red-700
+                       (shui/tabler-icon "logout" {:class "opacity-80" :size 22})
+                       "Logout"]))
+      (ui/menu-link {:on-click #(js/window.open "https://github.com/logseq/db-test/issues")}
+                    [:span.text-lg.flex.gap-2.items-center
+                     (shui/tabler-icon "bug" {:class "opacity-70" :size 22})
+                     "Report bug"])
+      (ui/menu-link {:on-click (fn []
+                                 (mobile-state/set-popup! nil)
+                                 (mobile-state/set-popup!
+                                  {:open? true
+                                   :content-fn (fn [] (log))}))}
+                    [:span.text-lg.flex.gap-2.items-center
+                     "Check log"])])
+   {:title "Actions"
+    :default-height false
+    :type :action-sheet}))
+
+(defn- open-graph-switcher! []
+  (ui-component/open-popup!
+   (fn []
+     [:div.px-1
+      (repo/repos-dropdown-content {})])
+   {:title "Select a Graph"
+    :default-height false
+    :type :action-sheet}))
+
+(defn- register-native-top-bar-events! []
+  (when (and (mobile-util/native-ios?)
+             (not @native-top-bar-listener?))
+    (.addListener mobile-util/native-top-bar "buttonTapped"
+                  (fn [^js e]
+                    (case (.-id e)
+                      "menu" (if (mobile-state/left-sidebar-open?)
+                               (mobile-state/close-left-sidebar!)
+                               (mobile-state/open-left-sidebar!))
+                      "title" (open-graph-switcher!)
+                      "calendar" (open-journal-calendar!)
+                      "settings-actions" (open-settings-actions!)
+                      nil)))
+    (reset! native-top-bar-listener? true)))
+
+(defn- configure-native-top-bar!
+  [{:keys [tab title]}]
+  (when (mobile-util/native-ios?)
+    (let [base {:title title
+                :tintColor "#1f2937"}
+          left-buttons (when (= tab "home")
+                         [{:id "menu" :systemIcon "line.3.horizontal"}])
+          right-buttons (cond
+                          (= tab "home")
+                          [{:id "calendar" :systemIcon "calendar"}]
+
+                          (= tab "settings")
+                          [{:id "settings-actions" :systemIcon "ellipsis"}]
+
+                          :else nil)
+          header (cond-> base
+                   left-buttons (assoc :leftButtons left-buttons)
+                   right-buttons (assoc :rightButtons right-buttons)
+                   (= tab "home") (assoc :titleClickable true))]
+      (.configure mobile-util/native-top-bar
+                  (clj->js header)))))
+
+(rum/defc rtc-indicator-btn
+  []
+  (let [repo (state/get-current-repo)]
+    [:div.flex.flex-row.items-center.gap-2
+     (when (and repo
+                (ldb/get-graph-rtc-uuid (db/get-db))
+                (user-handler/logged-in?))
+       (rtc-indicator/indicator))]))
+
 (rum/defc header
 (rum/defc header
   [tab login?]
   [tab login?]
-  (ui-silk/app-silk-topbar
-   (cond-> {:title [:span.capitalize (str tab)]
-            :props {:class (str tab)}}
-     (= tab "home")
-     (assoc
-      :left-render (menu-button)
-      :title (app-graphs-select)
-      :right-render [:div.flex.items-center.gap-1
-                     (journal-calendar-btn)
-                     (rtc-indicator-btn)]
-      :center-title? true)
-
-     (= tab "settings")
-     (assoc
-      :right-render
-      [:<>
-       (shui/button
-        {:variant :icon :size :sm
-         :on-click (fn []
-                     (ui-component/open-popup!
-                      (fn []
-                        [:div.-mx-2
-                         (when login?
-                           (ui/menu-link {:on-click #(user-handler/logout)}
-                                         [:span.text-lg.flex.gap-2.items-center.text-red-700
-                                          (shui/tabler-icon "logout" {:class "opacity-80" :size 22})
-                                          "Logout"]))
-                         (ui/menu-link {:on-click #(js/window.open "https://github.com/logseq/db-test/issues")}
-                                       [:span.text-lg.flex.gap-2.items-center
-                                        (shui/tabler-icon "bug" {:class "opacity-70" :size 22})
-                                        "Report bug"])
-                         (ui/menu-link {:on-click (fn []
-                                                    (mobile-state/set-popup! nil)
-                                                    (mobile-state/set-popup!
-                                                     {:open? true
-                                                      :content-fn (fn [] (log))}))}
-                                       [:span.text-lg.flex.gap-2.items-center
-                                        "Check log"])])
-                      {:title "Actions"
-                       :default-height false
-                       :type :action-sheet}))}
-        (shui/tabler-icon "dots" {:size 23}))]))))
+  (let [current-repo (state/get-current-repo)
+        short-repo-name (if current-repo
+                          (db-conn/get-short-repo-name current-repo)
+                          "Select a Graph")]
+    (hooks/use-effect!
+     (fn []
+       (when (mobile-util/native-ios?)
+         (register-native-top-bar-events!)
+         (configure-native-top-bar!
+          {:tab tab
+           :title (if (= tab "home")
+                    short-repo-name
+                    (string/capitalize tab))}))
+       nil)
+     [tab short-repo-name])
+
+    [:<>]))