icon.cljs 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. (ns frontend.components.icon
  2. (:require ["@emoji-mart/data" :as emoji-data]
  3. ["emoji-mart" :refer [SearchIndex]]
  4. [promesa.core :as p]
  5. [cljs-bean.core :as bean]
  6. [camel-snake-kebab.core :as csk]
  7. [clojure.string :as string]
  8. [frontend.search :as search]
  9. [rum.core :as rum]
  10. [frontend.ui :as ui]
  11. [frontend.util :as util]
  12. [goog.object :as gobj]
  13. [goog.functions :refer [debounce]]))
  14. (defn icon
  15. [icon]
  16. (cond
  17. (and (= :emoji (:type icon)) (:id icon))
  18. [:em-emoji {:id (:id icon)}]
  19. (and (= :tabler-icon (:type icon)) (:id icon))
  20. (ui/icon (:id icon))))
  21. (defn- search-emojis
  22. [q]
  23. (p/let [result (.search SearchIndex q)]
  24. (bean/->clj result)))
  25. (defonce *tabler-icons (atom nil))
  26. (defn- get-tabler-icons
  27. []
  28. (if @*tabler-icons
  29. @*tabler-icons
  30. (let [result (->> (keys (bean/->clj js/tablerIcons))
  31. (map (fn [k]
  32. (-> (string/replace (csk/->Camel_Snake_Case (name k)) "_" " ")
  33. (string/replace-first "Icon " ""))))
  34. ;; FIXME: somehow those icons don't work
  35. (remove #{"Ab" "Ab 2" "Ab Off"}))]
  36. (reset! *tabler-icons result)
  37. result)))
  38. (def emojis
  39. (vals (bean/->clj (gobj/get emoji-data "emojis"))))
  40. (defn- search-tabler-icons
  41. [q]
  42. (search/fuzzy-search (get-tabler-icons) q :limit 100))
  43. (defn- search
  44. [q]
  45. (p/let [icons (search-tabler-icons q)
  46. emojis (search-emojis q)]
  47. {:icons icons
  48. :emojis emojis}))
  49. (rum/defc emoji-cp < rum/static
  50. [{:keys [id name] :as emoji} {:keys [on-chosen hover]}]
  51. [:button.text-2xl.w-9.h-9.transition-opacity
  52. {:tabIndex "0"
  53. :title name
  54. :on-click (fn [e]
  55. (on-chosen e {:type :emoji
  56. :id id
  57. :name name}))
  58. :on-mouse-over #(reset! hover emoji)
  59. :on-mouse-out #(reset! hover nil)}
  60. [:em-emoji {:id id}]])
  61. (rum/defc emojis-cp < rum/static
  62. [emojis opts]
  63. [:div.emojis.flex.flex-1.flex-row.gap-1.flex-wrap
  64. (for [emoji emojis]
  65. (rum/with-key (emoji-cp emoji opts) (:id emoji)))])
  66. (rum/defc icon-cp < rum/static
  67. [icon {:keys [on-chosen hover]}]
  68. [:button.w-9.h-9.transition-opacity
  69. {:key icon
  70. :tabIndex "0"
  71. :title icon
  72. :on-click (fn [e]
  73. (on-chosen e {:type :tabler-icon
  74. :id icon
  75. :name icon}))
  76. :on-mouse-over #(reset! hover {:type :tabler-icon
  77. :id icon
  78. :name icon
  79. :icon icon})
  80. :on-mouse-out #(reset! hover nil)}
  81. (ui/icon icon {:size 24})])
  82. (rum/defc icons-cp < rum/static
  83. [icons opts]
  84. [:div.icons.flex.flex-1.flex-row.gap-1.flex-wrap
  85. (for [icon icons]
  86. (icon-cp icon opts))])
  87. (rum/defcs icon-search <
  88. (rum/local "" ::q)
  89. (rum/local nil ::result)
  90. (rum/local :emoji ::tab)
  91. (rum/local nil ::hover)
  92. [state opts]
  93. (let [*q (::q state)
  94. *result (::result state)
  95. *tab (::tab state)
  96. *hover (::hover state)
  97. result @*result
  98. emoji-tab? (= @*tab :emoji)
  99. opts (assoc opts :hover *hover)]
  100. [:div.icon-search.flex.flex-1.flex-col.gap-2
  101. [:input.form-input.block.w-full.sm:text-sm.sm:leading-5
  102. {:auto-focus true
  103. :placeholder "Select icon"
  104. :default-value ""
  105. :on-change (debounce
  106. (fn [e]
  107. (reset! *q (util/evalue e))
  108. (if (string/blank? @*q)
  109. (reset! *result {})
  110. (p/let [result (search @*q)]
  111. (reset! *result result))))
  112. 200)}]
  113. [:div.search-result
  114. (if (seq result)
  115. [:div.flex.flex-1.flex-col.gap-1
  116. (when (seq (:emojis result))
  117. (emojis-cp (:emojis result) opts))
  118. (when (seq (:icons result))
  119. (icons-cp (:icons result) opts))]
  120. [:div.flex.flex-1.flex-col.gap-1
  121. [:div.flex.flex-1.flex-row.items-center.gap-2
  122. (ui/button
  123. "Emojis"
  124. {:intent "logseq"
  125. :small? true
  126. :on-click #(reset! *tab :emoji)})
  127. (ui/button
  128. "Icons"
  129. {:intent "logseq"
  130. :small? true
  131. :on-click #(reset! *tab :icon)})]
  132. (if emoji-tab?
  133. (emojis-cp emojis opts)
  134. (icons-cp (get-tabler-icons) opts))])]
  135. (if @*hover
  136. [:div.flex.flex-1.flex-row.items-center.gap-2
  137. [:button.transition-opacity
  138. {:style {:font-size 32}
  139. :key (:id @*hover)
  140. :title (:name @*hover)}
  141. (if (= :tabler-icon (:type @*hover))
  142. (ui/icon (:icon @*hover) {:size 32})
  143. (:native (first (:skins @*hover))))]
  144. (:name @*hover)]
  145. [:div {:style {:padding-bottom 32}}])]))