toolbar.cljs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611
  1. (ns frontend.extensions.pdf.toolbar
  2. (:require [cljs-bean.core :as bean]
  3. [clojure.string :as string]
  4. [frontend.components.svg :as svg]
  5. [frontend.context.i18n :refer [t]]
  6. [frontend.extensions.pdf.assets :as pdf-assets]
  7. [frontend.extensions.pdf.utils :as pdf-utils]
  8. [frontend.extensions.pdf.windows :refer [resolve-own-container] :as pdf-windows]
  9. [frontend.handler.assets :as assets-handler]
  10. [frontend.handler.notification :as notification]
  11. [frontend.rum :refer [use-atom]]
  12. [frontend.state :as state]
  13. [frontend.storage :as storage]
  14. [frontend.ui :as ui]
  15. [frontend.util :as util]
  16. [logseq.shui.ui :as shui]
  17. [promesa.core :as p]
  18. [rum.core :as rum]))
  19. (declare make-docinfo-in-modal)
  20. (def *area-dashed? (atom ((fnil identity false) (storage/get (str "ls-pdf-area-is-dashed")))))
  21. (def *area-mode? (atom false))
  22. (def *highlight-mode? (atom false))
  23. #_:clj-kondo/ignore
  24. (rum/defcontext *highlights-ctx*)
  25. (rum/defc pdf-settings
  26. [^js viewer theme {:keys [hide-settings! select-theme! t]}]
  27. (let [*el-popup (rum/use-ref nil)
  28. [area-dashed? set-area-dashed?] (use-atom *area-dashed?)
  29. [hl-block-colored? set-hl-block-colored?] (rum/use-state (state/sub :pdf/block-highlight-colored?))
  30. [auto-open-ctx-menu? set-auto-open-ctx-menu!] (rum/use-state (state/sub :pdf/auto-open-ctx-menu?))]
  31. (rum/use-effect!
  32. (fn []
  33. (let [el-popup (rum/deref *el-popup)
  34. cb (fn [^js e]
  35. (and (= (.-which e) 27) (hide-settings!)))]
  36. (js/setTimeout #(.focus el-popup))
  37. (.addEventListener el-popup "keyup" cb)
  38. #(.removeEventListener el-popup "keyup" cb)))
  39. [])
  40. (rum/use-effect!
  41. (fn []
  42. (storage/set "ls-pdf-area-is-dashed" (boolean area-dashed?)))
  43. [area-dashed?])
  44. (rum/use-effect!
  45. (fn []
  46. (let [b (boolean hl-block-colored?)]
  47. (state/set-state! :pdf/block-highlight-colored? b)
  48. (storage/set "ls-pdf-hl-block-is-colored" b)))
  49. [hl-block-colored?])
  50. (rum/use-effect!
  51. (fn []
  52. (let [b (boolean auto-open-ctx-menu?)]
  53. (state/set-state! :pdf/auto-open-ctx-menu? b)
  54. (storage/set "ls-pdf-auto-open-ctx-menu" b)))
  55. [auto-open-ctx-menu?])
  56. (rum/use-effect!
  57. (fn []
  58. (let [cb #(let [^js target (.-target %)]
  59. (when (and (not (some-> (rum/deref *el-popup) (.contains target)))
  60. (nil? (.closest target ".ui__modal")))
  61. (hide-settings!)))
  62. doc (resolve-own-container viewer)]
  63. (js/setTimeout
  64. #(.addEventListener doc "click" cb))
  65. #(.removeEventListener doc "click" cb)))
  66. [])
  67. [:div.extensions__pdf-settings.hls-popup-overlay.visible
  68. [:div.extensions__pdf-settings-inner.hls-popup-box
  69. {:ref *el-popup
  70. :tab-index -1}
  71. [:div.extensions__pdf-settings-item.theme-picker
  72. (map (fn [it]
  73. [:button.flex.items-center.justify-center
  74. {:key it :class it :on-click #(select-theme! it)}
  75. (when (= theme it) (svg/check))])
  76. ["light", "warm", "dark"])]
  77. [:div.extensions__pdf-settings-item.toggle-input
  78. [:label (t :pdf/toggle-dashed)]
  79. (ui/toggle area-dashed? #(set-area-dashed? (not area-dashed?)) true)]
  80. [:div.extensions__pdf-settings-item.toggle-input.is-between
  81. [:label (t :pdf/hl-block-colored)]
  82. (ui/toggle hl-block-colored? #(set-hl-block-colored? (not hl-block-colored?)) true)]
  83. [:div.extensions__pdf-settings-item.toggle-input.is-between
  84. [:label (t :pdf/auto-open-context-menu)]
  85. (ui/toggle auto-open-ctx-menu? #(set-auto-open-ctx-menu! (not auto-open-ctx-menu?)) true)]
  86. [:div.extensions__pdf-settings-item.toggle-input
  87. [:a.is-info.w-full.text-gray-500
  88. {:title (t :pdf/doc-metadata)
  89. :on-click (fn []
  90. (p/let [ret (pdf-utils/get-meta-data$ viewer)]
  91. (hide-settings!)
  92. (shui/dialog-open! (make-docinfo-in-modal ret))))}
  93. [:span.flex.items-center.justify-between.w-full
  94. (t :pdf/doc-metadata)
  95. (svg/icon-info)]]]]]))
  96. (rum/defc docinfo-display
  97. [info close-fn!]
  98. [:div#pdf-docinfo.extensions__pdf-doc-info
  99. [:div.inner-text
  100. (for [[k v] info
  101. :let [k (str (string/replace-first (pr-str k) #"^\:" "") "::")]]
  102. [:p {:key k} [:strong k] " " [:i (pr-str v)]])]
  103. [:div.flex.items-center.justify-center.pt-2.pb--2
  104. (ui/button "Copy all"
  105. :on-click
  106. (fn []
  107. (let [text (.-innerText (js/document.querySelector "#pdf-docinfo > .inner-text"))
  108. text (string/replace text #"[\n\t]+" "\n")]
  109. (util/copy-to-clipboard! text)
  110. (notification/show! "Copied!" :success)
  111. (close-fn!))))]])
  112. (defn make-docinfo-in-modal
  113. [info]
  114. (fn [close-fn!]
  115. (docinfo-display info close-fn!)))
  116. (defonce find-status
  117. {0 ::found
  118. 1 ::not-found
  119. 2 ::wrapped
  120. 3 ::pending})
  121. (rum/defc ^:large-vars/data-var pdf-finder
  122. [^js viewer {:keys [hide-finder!]}]
  123. (let [*el-finder (rum/use-ref nil)
  124. *el-input (rum/use-ref nil)
  125. ^js bus (.-eventBus viewer)
  126. [case-sensitive?, set-case-sensitive?] (rum/use-state nil)
  127. [input, set-input!] (rum/use-state "")
  128. [matches, set-matches!] (rum/use-state {:current 0 :total 0})
  129. [find-state, set-find-state!] (rum/use-state {:status nil :current 0 :total 0 :query ""})
  130. [entered-active0?, set-entered-active0?] (rum/use-state false)
  131. [entered-active?, set-entered-active?] (rum/use-state false)
  132. reset-finder! (fn []
  133. (.dispatch bus "findbarclose" nil)
  134. (set-matches! nil)
  135. (set-find-state! nil)
  136. (set-entered-active? false)
  137. (set-entered-active0? false))
  138. close-finder! (fn []
  139. (reset-finder!)
  140. (hide-finder!))
  141. do-find! (fn [{:keys [type prev?] :as opts}]
  142. (when-let [type (if (keyword? opts) opts type)]
  143. (.dispatch bus "find"
  144. #js {:source nil
  145. :type (name type)
  146. :query input
  147. :phraseSearch true
  148. :caseSensitive case-sensitive?
  149. :highlightAll true
  150. :findPrevious prev?
  151. :matchDiacritics false})))]
  152. (rum/use-effect!
  153. (fn []
  154. (when-let [^js doc (resolve-own-container viewer)]
  155. (let [handler (fn [^js e]
  156. (when-let [^js target (and (string/blank? (.-value (rum/deref *el-input)))
  157. (.-target e))]
  158. (when (and (not= "Search" (.-title target))
  159. (not (some-> (rum/deref *el-finder) (.contains target))))
  160. (close-finder!))))]
  161. (.addEventListener doc "click" handler)
  162. #(.removeEventListener doc "click" handler))))
  163. [viewer])
  164. (rum/use-effect!
  165. (fn []
  166. (when-let [^js bus (.-eventBus viewer)]
  167. (.on bus "updatefindmatchescount" (fn [^js e]
  168. (let [matches (bean/->clj (.-matchesCount e))]
  169. (set-matches! matches)
  170. (set-find-state! (fn [s] (merge s matches))))))
  171. (.on bus "updatefindcontrolstate" (fn [^js e]
  172. (set-find-state!
  173. (merge
  174. {:status (get find-status (.-state e))
  175. :query (.-rawQuery e)}
  176. (bean/->clj (.-matchesCount e))))))))
  177. [viewer])
  178. (rum/use-effect!
  179. (fn []
  180. (when-not (nil? case-sensitive?)
  181. (do-find! :casesensitivitychange)))
  182. [case-sensitive?])
  183. [:div.extensions__pdf-finder-wrap.hls-popup-overlay.visible
  184. {:on-click #()}
  185. [:div.extensions__pdf-finder.hls-popup-box
  186. {:ref *el-finder
  187. :tab-index -1}
  188. [:div.input-inner.flex.items-center
  189. [:div.input-wrap.relative
  190. [:input
  191. {:placeholder "search"
  192. :type "text"
  193. :ref *el-input
  194. :auto-focus true
  195. :value input
  196. :on-change (fn [^js e]
  197. (let [val (.-value (.-target e))]
  198. (set-input! val)
  199. (set-entered-active0? (not (string/blank? (util/trim-safe val))))
  200. (set-entered-active? false)))
  201. :on-key-up (fn [^js e]
  202. (case (.-which e)
  203. 13 ;; enter
  204. (let [shift? (.-shiftKey e)]
  205. (do-find! {:type :again :prev? shift?})
  206. (set-entered-active? true))
  207. 27 ;; esc
  208. (if (string/blank? input)
  209. (close-finder!)
  210. (do
  211. (reset-finder!)
  212. (set-input! "")))
  213. :dune))}]
  214. (when entered-active0?
  215. (ui/button {:icon "arrow-back"
  216. :intent "link"
  217. :title "Enter to search"
  218. :class "icon-enter"
  219. :small? true}))]
  220. (ui/button {:icon "letter-case"
  221. :intent "link"
  222. :class (string/join " " (util/classnames [{:active case-sensitive?}]))
  223. :small? true :on-click #(set-case-sensitive? (not case-sensitive?))})
  224. (ui/button {:icon "chevron-up"
  225. :intent "link"
  226. :small? true :on-click #(do (do-find! {:type :again :prev? true}) (util/stop %))})
  227. (ui/button
  228. {:icon "chevron-down"
  229. :intent "link"
  230. :small? true :on-click #(do (do-find! {:type :again}) (util/stop %))})
  231. (ui/button
  232. {:icon "x"
  233. :intent "link"
  234. :small? true :on-click close-finder!})]
  235. [:div.result-inner
  236. (when-let [status (and entered-active?
  237. (not (string/blank? input))
  238. (:status find-state))]
  239. (if-not (= ::not-found status)
  240. [:div.flex.px-3.py-3.text-xs.opacity-90
  241. (apply max (map :current [find-state matches])) " of "
  242. (:total find-state)
  243. (str " matches (\"" (:query find-state) "\")")]
  244. [:div.px-3.py-3.text-xs.opacity-80.text-red-600 "Not found."]))]]]))
  245. (rum/defc pdf-outline-item
  246. [^js viewer
  247. {:keys [title items parent dest expanded]}
  248. {:keys [upt-outline-node!] :as ops}]
  249. (let [has-child? (seq items)
  250. expanded? (boolean expanded)]
  251. [:div.extensions__pdf-outline-item
  252. {:class (util/classnames [{:has-children has-child? :is-expand expanded?}])}
  253. [:div.inner
  254. [:a
  255. {:data-dest (js/JSON.stringify (bean/->js dest))
  256. :on-click (fn [^js/MouseEvent e]
  257. (let [target (.-target e)]
  258. (if (.closest target "i")
  259. (let [path (map #(if (re-find #"\d+" %) (int %) (keyword %))
  260. (string/split parent #"\-"))]
  261. (.preventDefault e)
  262. (upt-outline-node! path {:expanded (not expanded?)}))
  263. (when-let [^js dest (and dest (bean/->js dest))]
  264. (.goToDestination (.-linkService viewer) dest)))))}
  265. [:i.arrow svg/arrow-right-v2]
  266. [:span title]]]
  267. ;; children
  268. (when (and has-child? expanded?)
  269. [:div.children
  270. (map-indexed
  271. (fn [idx itm]
  272. (let [parent (str parent "-items-" idx)]
  273. (rum/with-key
  274. (pdf-outline-item
  275. viewer
  276. (merge itm {:parent parent})
  277. ops) parent))) items)])]))
  278. (rum/defc pdf-outline
  279. [^js viewer _visible? set-visible!]
  280. (when-let [^js pdf-doc (and viewer (.-pdfDocument viewer))]
  281. (let [*el-outline (rum/use-ref nil)
  282. [outline-data, set-outline-data!] (rum/use-state [])
  283. upt-outline-node! (rum/use-callback
  284. (fn [path attrs]
  285. (set-outline-data! (update-in outline-data path merge attrs)))
  286. [outline-data])]
  287. (rum/use-effect!
  288. (fn []
  289. (p/catch
  290. (p/let [^js data (.getOutline pdf-doc)]
  291. #_:clj-kondo/ignore
  292. (when-let [data (and data (.map data (fn [^js it]
  293. (set! (.-href it) (.. viewer -linkService (getDestinationHash (.-dest it))))
  294. (set! (.-expanded it) false)
  295. it)))])
  296. (set-outline-data! (bean/->clj data)))
  297. (fn [e]
  298. (js/console.error "[Load outline Error]" e))))
  299. [pdf-doc])
  300. (rum/use-effect!
  301. (fn []
  302. (let [el-outline (rum/deref *el-outline)
  303. cb (fn [^js e]
  304. (and (= (.-which e) 27) (set-visible! false)))]
  305. (js/setTimeout #(.focus el-outline))
  306. (.addEventListener el-outline "keyup" cb)
  307. #(.removeEventListener el-outline "keyup" cb)))
  308. [])
  309. [:div.extensions__pdf-outline-list-content
  310. {:ref *el-outline
  311. :tab-index -1}
  312. (if (seq outline-data)
  313. [:section
  314. (map-indexed (fn [idx itm]
  315. (rum/with-key
  316. (pdf-outline-item
  317. viewer
  318. (merge itm {:parent idx})
  319. {:upt-outline-node! upt-outline-node!})
  320. idx))
  321. outline-data)]
  322. [:section.is-empty "No outlines"])])))
  323. (rum/defc pdf-highlights-list
  324. [^js viewer]
  325. (let [[active, set-active!] (rum/use-state false)]
  326. (rum/with-context
  327. [hls-state *highlights-ctx*]
  328. (let [hls (sort-by :page (or (seq (:initial-hls hls-state))
  329. (:latest-hls hls-state)))]
  330. (for [{:keys [id content properties page] :as hl} hls
  331. :let [goto-ref! #(pdf-assets/goto-block-ref! hl)]]
  332. [:div.extensions__pdf-highlights-list-item
  333. {:key id
  334. :class (when (= active id) "active")
  335. :on-click (fn []
  336. (pdf-utils/scroll-to-highlight viewer hl)
  337. (set-active! id))
  338. :on-double-click goto-ref!}
  339. [:h6.flex
  340. [:span.flex.items-center
  341. [:small {:data-color (:color properties)}]
  342. [:strong "Page " page]]
  343. [:button
  344. {:title (t :pdf/linked-ref)
  345. :on-click goto-ref!}
  346. (ui/icon "external-link")]]
  347. (if-let [img-stamp (:image content)]
  348. (let [fpath (pdf-assets/resolve-area-image-file
  349. img-stamp (state/get-current-pdf) hl)
  350. fpath (assets-handler/<make-asset-url fpath)]
  351. [:p.area-wrap
  352. [:img {:src fpath}]])
  353. [:p.text-wrap (:text content)])])))))
  354. (rum/defc pdf-outline-&-highlights
  355. [^js viewer visible? set-visible!]
  356. (let [*el-container (rum/use-ref nil)
  357. [active-tab, set-active-tab!] (rum/use-state "contents")
  358. set-outline-visible! #(set-active-tab! "contents")
  359. contents? (= active-tab "contents")]
  360. (rum/use-effect!
  361. (fn []
  362. (when-let [^js doc (resolve-own-container viewer)]
  363. (let [cb (fn [^js e]
  364. (when-let [^js target (.-target e)]
  365. (when (and
  366. (not= "Outline" (.-title target))
  367. (not (some-> (rum/deref *el-container) (.contains target))))
  368. (set-visible! false)
  369. (set-outline-visible!))))]
  370. (.addEventListener doc "click" cb)
  371. #(.removeEventListener doc "click" cb))))
  372. [viewer])
  373. [:div.extensions__pdf-outline-wrap.hls-popup-overlay
  374. {:class (util/classnames [{:visible visible?}])}
  375. [:div.extensions__pdf-outline.hls-popup-box
  376. {:ref *el-container
  377. :tab-index -1}
  378. [:div.extensions__pdf-outline-tabs
  379. [:div.inner
  380. [:button {:class (when contents? "active")
  381. :on-click #(set-active-tab! "contents")} "Contents"]
  382. [:button {:class (when-not contents? "active")
  383. :on-click #(set-active-tab! "highlights")} "Highlights"]]]
  384. [:div.extensions__pdf-outline-panels
  385. (if contents?
  386. (pdf-outline viewer contents? set-outline-visible!)
  387. (pdf-highlights-list viewer))]]]))
  388. (rum/defc ^:large-vars/cleanup-todo pdf-toolbar
  389. [^js viewer {:keys [on-external-window!]}]
  390. (let [[area-mode?, set-area-mode!] (use-atom *area-mode?)
  391. [outline-visible?, set-outline-visible!] (rum/use-state false)
  392. [finder-visible?, set-finder-visible!] (rum/use-state false)
  393. [highlight-mode?, set-highlight-mode!] (use-atom *highlight-mode?)
  394. [settings-visible?, set-settings-visible!] (rum/use-state false)
  395. *page-ref (rum/use-ref nil)
  396. [current-page-num, set-current-page-num!] (rum/use-state 1)
  397. [total-page-num, set-total-page-num!] (rum/use-state 1)
  398. [viewer-theme, set-viewer-theme!] (rum/use-state (or (storage/get "ls-pdf-viewer-theme") "light"))
  399. group-id (.-$groupIdentity viewer)
  400. in-system-window? (.-$inSystemWindow viewer)
  401. doc (pdf-windows/resolve-own-document viewer)]
  402. ;; themes hooks
  403. (rum/use-effect!
  404. (fn []
  405. (when-let [^js el (some-> doc (.getElementById (str "pdf-layout-container_" group-id)))]
  406. (set! (. (. el -dataset) -theme) viewer-theme)
  407. (storage/set "ls-pdf-viewer-theme" viewer-theme)
  408. #(js-delete (. el -dataset) "theme")))
  409. [viewer-theme])
  410. ;; export page state
  411. (rum/use-effect!
  412. (fn []
  413. (when viewer
  414. (.dispatch (.-eventBus viewer) (name :ls-update-extra-state)
  415. #js {:page current-page-num})))
  416. [viewer current-page-num])
  417. ;; pager hooks
  418. (rum/use-effect!
  419. (fn []
  420. (when-let [total (and viewer (.-numPages (.-pdfDocument viewer)))]
  421. (let [^js bus (.-eventBus viewer)
  422. page-fn (fn [^js evt]
  423. (let [num (.-pageNumber evt)]
  424. (set-current-page-num! num)))]
  425. (set-total-page-num! total)
  426. (set-current-page-num! (.-currentPageNumber viewer))
  427. (.on bus "pagechanging" page-fn)
  428. #(.off bus "pagechanging" page-fn))))
  429. [viewer])
  430. (rum/use-effect!
  431. (fn []
  432. (let [^js input (rum/deref *page-ref)]
  433. (set! (. input -value) current-page-num)))
  434. [current-page-num])
  435. [:div.extensions__pdf-header
  436. [:div.extensions__pdf-toolbar
  437. [:div.inner
  438. [:div.r.flex.buttons
  439. ;; appearance
  440. [:a.button
  441. {:title "More settings"
  442. :on-click #(set-settings-visible! (not settings-visible?))}
  443. (svg/adjustments 18)]
  444. ;; selection
  445. [:a.button
  446. {:title (str "Area highlight (" (if util/mac? "⌘" "Shift") ")")
  447. :class (when area-mode? "is-active")
  448. :on-click #(set-area-mode! (not area-mode?))}
  449. (svg/icon-area 18)]
  450. [:a.button
  451. {:title "Highlight mode"
  452. :class (when highlight-mode? "is-active")
  453. :on-click #(set-highlight-mode! (not highlight-mode?))}
  454. (svg/highlighter 16)]
  455. ;; zoom
  456. [:a.button
  457. {:title "Zoom out"
  458. :on-click (partial pdf-utils/zoom-out-viewer viewer)}
  459. (svg/zoom-out 18)]
  460. [:a.button
  461. {:title "Zoom in"
  462. :on-click (partial pdf-utils/zoom-in-viewer viewer)}
  463. (svg/zoom-in 18)]
  464. [:a.button
  465. {:title "Outline"
  466. :on-click #(set-outline-visible! (not outline-visible?))}
  467. (svg/view-list 16)]
  468. ;; search
  469. [:a.button
  470. {:title "Search"
  471. :on-click #(set-finder-visible! (not finder-visible?))}
  472. (svg/search2 19)]
  473. ;; annotations
  474. [:a.button
  475. {:title "Annotations page"
  476. :on-click #(pdf-assets/goto-annotations-page! (:pdf/current @state/state))}
  477. (svg/annotations 16)]
  478. ;; system window
  479. [:a.button
  480. {:title (if in-system-window?
  481. "Open in app window"
  482. "Open in external window")
  483. :on-click #(if in-system-window?
  484. (pdf-windows/exit-pdf-in-system-window! true)
  485. (on-external-window!))}
  486. (ui/icon (if in-system-window?
  487. "window-minimize"
  488. "window-maximize"))]
  489. ;; pager
  490. [:div.pager.flex.items-center.ml-1
  491. [:span.nu.flex.items-center.opacity-70
  492. [:input {:ref *page-ref
  493. :type "number"
  494. :min 1
  495. :max total-page-num
  496. :class (util/classnames [{:is-long (> (util/safe-parse-int current-page-num) 999)}])
  497. :default-value current-page-num
  498. :on-mouse-enter #(.select ^js (.-target %))
  499. :on-key-up (fn [^js e]
  500. (let [^js input (.-target e)
  501. value (util/safe-parse-int (.-value input))]
  502. (set-current-page-num! value)
  503. (when (and (= (.-keyCode e) 13) value (> value 0))
  504. (->> (if (> value total-page-num) total-page-num value)
  505. (set! (. viewer -currentPageNumber))))))}]
  506. [:small "/ " total-page-num]]
  507. [:span.ct.flex.items-center
  508. [:a.button {:on-click #(. viewer previousPage)} (svg/up-narrow)]
  509. [:a.button {:on-click #(. viewer nextPage)} (svg/down-narrow)]]]
  510. [:a.button
  511. {:on-click #(if in-system-window?
  512. (pdf-windows/exit-pdf-in-system-window! false)
  513. (state/set-current-pdf! nil))}
  514. (t :close)]]]
  515. ;; contents outline
  516. (pdf-outline-&-highlights viewer outline-visible? set-outline-visible!)
  517. ;; finder
  518. (when finder-visible?
  519. (pdf-finder viewer {:hide-finder! #(set-finder-visible! false)}))
  520. ;; settings
  521. (when settings-visible?
  522. (pdf-settings
  523. viewer
  524. viewer-theme
  525. {:t t
  526. :hide-settings! #(set-settings-visible! false)
  527. :select-theme! #(set-viewer-theme! %)}))]]))