sidebar.cljs 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. (ns frontend.components.sidebar
  2. (:require [rum.core :as rum]
  3. [frontend.ui :as ui]
  4. [frontend.mixins :as mixins]
  5. [frontend.db :as db]
  6. [frontend.components.repo :as repo]
  7. [frontend.components.journal :as journal]
  8. [goog.crypt.base64 :as b64]
  9. [frontend.util :as util]
  10. [frontend.state :as state]))
  11. (defonce active-button :a.group.flex.items-center.px-2.py-2.text-base.leading-6.font-medium.rounded-md.text-white.bg-gray-900.focus:outline-none.focus:bg-gray-700.transition.ease-in-out.duration-150)
  12. (defonce inactive-button :a.mt-1.group.flex.items-center.px-2.py-2.text-base.leading-6.font-medium.rounded-md.text-gray-300.hover:text-white.hover:bg-gray-700.focus:outline-none.focus:text-white.focus:bg-gray-700.transition.ease-in-out.duration-150)
  13. (defn nav-item
  14. ([title href svg-d]
  15. (nav-item title href svg-d false))
  16. ([title href svg-d active?]
  17. (let [a (if active? active-button inactive-button)]
  18. [a {:href href}
  19. [:svg.mr-4.h-6.w-6.text-gray-400.group-hover:text-gray-300.group-focus:text-gray-300.transition.ease-in-out.duration-150
  20. {:viewBox "0 0 24 24", :fill "none", :stroke "currentColor"}
  21. [:path
  22. {:d svg-d
  23. :stroke-width "2",
  24. :stroke-linejoin "round",
  25. :stroke-linecap "round"}]]
  26. title])))
  27. (rum/defc files-list
  28. [file-active?]
  29. (let [files (db/get-files)]
  30. [:div.cursor-pointer.my-1.flex.flex-col.ml-2
  31. (if (seq files)
  32. (for [file files]
  33. (let [encoded-path (b64/encodeString file)]
  34. [:a {:key file
  35. :class (util/hiccup->class "mt-1.group.flex.items-center.px-2.py-1.text-base.leading-6.font-medium.rounded-md.text-gray-500.hover:text-white.hover:bg-gray-700.focus:outline-none.focus:text-white.focus:bg-gray-700.transition.ease-in-out.duration-150")
  36. :style {:color (if (file-active? encoded-path) "#FFF")}
  37. :href (str "/file/" encoded-path)}
  38. file])))]))
  39. (rum/defc sidebar-nav < rum/reactive
  40. []
  41. (let [{:keys [:route-match]} (rum/react state/state)
  42. active? (fn [route] (= route (get-in route-match [:data :name])))
  43. file-active? (fn [path]
  44. (= path (get-in route-match [:parameters :path :path])))]
  45. [:nav.flex-1.px-2.py-4.bg-gray-800
  46. (nav-item "Daily notes" "/"
  47. "M3 12l9-9 9 9M5 10v10a1 1 0 001 1h3a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1h3a1 1 0 001-1V10M9 21h6"
  48. (active? :home))
  49. (nav-item "Agenda" "/agenda"
  50. "M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"
  51. (active? :agenda))
  52. (files-list file-active?)]))
  53. (rum/defc main-content
  54. []
  55. (let [repos (db/get-repos)]
  56. [:div.max-w-7xl.mx-auto.px-4.sm:px-6.md:px-8
  57. (if (seq repos)
  58. (journal/journals)
  59. (repo/add-repo))]))
  60. (rum/defcs sidebar < (mixins/modal)
  61. [state main-content]
  62. (let [{:keys [open? close-fn open-fn]} state]
  63. [:div.h-screen.flex.overflow-hidden.bg-gray-100
  64. [:div.md:hidden
  65. [:div.fixed.inset-0.z-30.bg-gray-600.opacity-0.pointer-events-none.transition-opacity.ease-linear.duration-300
  66. {:class (if @open?
  67. "opacity-75 pointer-events-auto"
  68. "opacity-0 pointer-events-none")
  69. :on-click close-fn}]
  70. [:div.fixed.inset-y-0.left-0.flex.flex-col.z-40.max-w-xs.w-full.bg-gray-800.transform.ease-in-out.duration-300
  71. {:class (if @open?
  72. "translate-x-0"
  73. "-translate-x-full")}
  74. (if @open?
  75. [:div.absolute.top-0.right-0.-mr-14.p-1
  76. [:button.flex.items-center.justify-center.h-12.w-12.rounded-full.focus:outline-none.focus:bg-gray-600
  77. {:on-click close-fn}
  78. [:svg.h-6.w-6.text-white
  79. {:viewBox "0 0 24 24", :fill "none", :stroke "currentColor"}
  80. [:path
  81. {:d "M6 18L18 6M6 6l12 12",
  82. :stroke-width "2",
  83. :stroke-linejoin "round",
  84. :stroke-linecap "round"}]]]])
  85. [:div.flex-shrink-0.flex.items-center.h-16.px-4.bg-gray-900
  86. [:img.h-8.w-auto
  87. {:alt "Gitnotes",
  88. :src "https://tailwindui.com/img/logos/workflow-logo-on-dark.svg"}]]
  89. [:div.flex-1.h-0.overflow-y-auto
  90. (sidebar-nav)]
  91. ]]
  92. [:div.hidden.md:flex.md:flex-shrink-0
  93. [:div.flex.flex-col.w-64
  94. [:div.flex.items-center.h-16.flex-shrink-0.px-4.bg-gray-900
  95. [:img.h-8.w-auto
  96. {:alt "Gitnotes",
  97. :src "https://tailwindui.com/img/logos/workflow-logo-on-dark.svg"}]]
  98. [:div.h-0.flex-1.flex.flex-col.overflow-y-auto
  99. (sidebar-nav)]]]
  100. [:div.flex.flex-col.w-0.flex-1.overflow-hidden
  101. [:div.relative.z-10.flex-shrink-0.flex.h-16.bg-white.shadow
  102. [:button.px-4.border-r.border-gray-200.text-gray-500.focus:outline-none.focus:bg-gray-100.focus:text-gray-600.md:hidden
  103. {:on-click open-fn}
  104. [:svg.h-6.w-6
  105. {:viewBox "0 0 24 24", :fill "none", :stroke "currentColor"}
  106. [:path
  107. {:d "M4 6h16M4 12h16M4 18h7",
  108. :stroke-width "2",
  109. :stroke-linejoin "round",
  110. :stroke-linecap "round"}]]]
  111. [:div.flex-1.px-4.flex.justify-between
  112. [:div.flex-1.flex
  113. [:div.w-full.flex.md:ml-0
  114. [:label.sr-only {:for "search_field"} "Search"]
  115. [:div.relative.w-full.text-gray-400.focus-within:text-gray-600
  116. [:div.absolute.inset-y-0.left-0.flex.items-center.pointer-events-none
  117. [:svg.h-5.w-5
  118. {:viewBox "0 0 20 20", :fill "currentColor"}
  119. [:path
  120. {:d
  121. "M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z",
  122. :clip-rule "evenodd",
  123. :fill-rule "evenodd"}]]]
  124. [:input#search_field.block.w-full.h-full.pl-8.pr-3.py-2.rounded-md.text-gray-900.placeholder-gray-500.focus:outline-none.focus:placeholder-gray-400.sm:text-sm
  125. {:placeholder "Search"}]]]]
  126. [:div.ml-4.flex.items-center.md:ml-6
  127. [:button.p-1.text-gray-400.rounded-full.hover:bg-gray-100.hover:text-gray-500.focus:outline-none.focus:shadow-outline.focus:text-gray-500
  128. [:svg.h-6.w-6
  129. {:viewBox "0 0 24 24", :fill "none", :stroke "currentColor"}
  130. [:path
  131. {:d
  132. "M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9",
  133. :stroke-width "2",
  134. :stroke-linejoin "round",
  135. :stroke-linecap "round"}]]]
  136. (ui/dropdown-with-links
  137. [{:title "Your Profile"
  138. :options {:href "#"}}
  139. {:title "Settings"
  140. :options {:href "#"}}
  141. {:title "Sign out"
  142. :options {:href "#"}}])]]]
  143. [:main.flex-1.relative.z-0.overflow-y-auto.py-6.focus:outline-none
  144. ;; {:x-init "$el.focus()", :x-data "x-data", :tabindex "0"}
  145. {:tabIndex "0"}
  146. [:div.flex.justify-center
  147. [:div.flex-1.m-6 {:style {:position "relative"
  148. :max-width 800}}
  149. main-content]]]
  150. (ui/notification)]]))