mirror of https://github.com/logseq/logseq
Add home page
parent
c3419afbd4
commit
877f36d63f
|
@ -1,24 +1,24 @@
|
|||
{:deps
|
||||
{org.clojure/clojure {:mvn/version "RELEASE"}
|
||||
org.clojure/clojurescript {:mvn/version "RELEASE"}
|
||||
|
||||
cljs-bean {:mvn/version "1.5.0"}
|
||||
|
||||
uix.core {:git/url "https://github.com/roman01la/uix.git"
|
||||
:deps/root "core"
|
||||
:sha "46011c8a2f1a05025971af8e26b8b6704520383c"}
|
||||
uix.dom {:git/url "https://github.com/roman01la/uix.git"
|
||||
:deps/root "dom"
|
||||
:sha "46011c8a2f1a05025971af8e26b8b6704520383c"}
|
||||
|
||||
{;; dev
|
||||
thheller/shadow-cljs {:mvn/version "RELEASE"}
|
||||
cider/cider-nrepl {:mvn/version "0.23.0-SNAPSHOT"}
|
||||
binaryage/devtools {:mvn/version "0.9.10"}
|
||||
rum {:mvn/version "0.11.4"}
|
||||
|
||||
org.clojure/clojure {:mvn/version "RELEASE"}
|
||||
org.clojure/clojurescript {:mvn/version "RELEASE"}
|
||||
cljs-bean {:mvn/version "1.5.0"}
|
||||
uix.core {:git/url "https://github.com/tiensonqin/uix.git"
|
||||
:deps/root "core"
|
||||
:sha "f6d82d12d62c13ff1894ac9dc2dd894a3521cd3d"}
|
||||
uix.dom {:git/url "https://github.com/roman01la/uix.git"
|
||||
:deps/root "dom"
|
||||
:sha "46011c8a2f1a05025971af8e26b8b6704520383c"}
|
||||
datascript {:mvn/version "0.18.9"}
|
||||
funcool/promesa {:mvn/version "4.0.2"}
|
||||
medley {:mvn/version "1.2.0"}
|
||||
}
|
||||
metosin/reitit {:mvn/version "0.3.10"}
|
||||
metosin/reitit-spec {:mvn/version "0.3.10"}
|
||||
metosin/reitit-frontend {:mvn/version "0.3.10"}}
|
||||
|
||||
:paths
|
||||
["src"
|
||||
|
|
|
@ -1,98 +1,99 @@
|
|||
(ns frontend.components.agenda
|
||||
(:require [rum.core :as rum]
|
||||
[frontend.mui :as mui]
|
||||
[frontend.util :as util]
|
||||
[frontend.handler :as handler]
|
||||
[frontend.format.org.block :as block]
|
||||
[frontend.state :as state]
|
||||
[clojure.string :as string]
|
||||
[frontend.format.org-mode :as org]))
|
||||
|
||||
(rum/defc timestamps-cp
|
||||
[timestamps]
|
||||
[:ul
|
||||
(for [[type {:keys [date time]}] timestamps]
|
||||
(let [{:keys [year month day]} date
|
||||
{:keys [hour min]} time]
|
||||
[:li {:key type}
|
||||
[:span {:style {:margin-right 6}} type]
|
||||
[:span (if time
|
||||
(str year "-" month "-" day " " hour ":" min)
|
||||
(str year "-" month "-" day))]]))])
|
||||
|
||||
(rum/defc title-cp
|
||||
[title]
|
||||
(let [title-json (js/JSON.stringify (clj->js title))
|
||||
html (org/inline-list->html title-json)]
|
||||
(util/raw-html html)))
|
||||
|
||||
(rum/defc marker-cp
|
||||
[marker]
|
||||
[:span {:class (str "marker-" (string/lower-case marker))
|
||||
:style {:margin-left 8}}
|
||||
(if (contains? #{"DOING" "IN-PROGRESS"} marker)
|
||||
(str " (" marker ")"))])
|
||||
|
||||
(rum/defc tags-cp
|
||||
[tags]
|
||||
[:span
|
||||
(for [tag tags]
|
||||
[:span.tag {:key tag}
|
||||
[:span
|
||||
tag]])])
|
||||
|
||||
(rum/defc agenda
|
||||
[tasks]
|
||||
[:span "TBD"]
|
||||
;; [:div#agenda
|
||||
;; (if (seq tasks)
|
||||
;; (for [[section-name tasks] tasks]
|
||||
;; [:div.section {:key (str "section-" section-name)}
|
||||
;; [:h3 section-name]
|
||||
;; (mui/list
|
||||
;; (for [[idx {:keys [marker title priority level tags children timestamps meta]}] (util/indexed (block/sort-tasks tasks))]
|
||||
;; (mui/list-item
|
||||
;; {:key (str "task-" section-name "-" idx)
|
||||
;; :style {:padding-left 8
|
||||
;; :padding-right 8}}
|
||||
;; [:div.column
|
||||
;; [:div.row {:style {:align-items "center"}}
|
||||
;; (let [marker (case marker
|
||||
;; (list "DOING" "IN-PROGRESS" "TODO")
|
||||
;; (mui/checkbox {:checked false
|
||||
;; :on-change (fn [_]
|
||||
;; ;; FIXME: Log timestamp
|
||||
;; (handler/check marker (:pos meta)))
|
||||
;; :color "primary"
|
||||
;; :style {:padding 0}})
|
||||
|
||||
;; "WAIT"
|
||||
;; [:span {:style {:font-weight "bold"}}
|
||||
;; "WAIT"]
|
||||
|
||||
;; "DONE"
|
||||
;; (mui/checkbox {:checked true
|
||||
;; :on-change (fn [_]
|
||||
;; ;; FIXME: rollback to the last state if exists.
|
||||
;; ;; it must not be `TODO`
|
||||
;; (handler/uncheck (:pos meta)))
|
||||
;; :color "primary"
|
||||
;; :style {:padding 0}})
|
||||
|
||||
;; nil)]
|
||||
;; (if priority
|
||||
;; (mui/badge {:badge-content (string/lower-case priority)
|
||||
;; :overlay "circle"}
|
||||
;; marker)
|
||||
;; marker))
|
||||
|
||||
;; [:div.row {:style {:margin-left 8}}
|
||||
;; (title-cp title)
|
||||
;; (marker-cp marker)
|
||||
;; (when (seq tags)
|
||||
;; (tags-cp tags))]]
|
||||
;; (when (seq timestamps)
|
||||
;; (timestamps-cp timestamps))
|
||||
;; ])))])
|
||||
;; "Empty")]
|
||||
;; (:require [rum.core :as rum]
|
||||
;; [frontend.mui :as mui]
|
||||
;; [frontend.util :as util]
|
||||
;; [frontend.handler :as handler]
|
||||
;; [frontend.format.org.block :as block]
|
||||
;; [frontend.state :as state]
|
||||
;; [clojure.string :as string]
|
||||
;; [frontend.format.org-mode :as org])
|
||||
)
|
||||
|
||||
;; (rum/defc timestamps-cp
|
||||
;; [timestamps]
|
||||
;; [:ul
|
||||
;; (for [[type {:keys [date time]}] timestamps]
|
||||
;; (let [{:keys [year month day]} date
|
||||
;; {:keys [hour min]} time]
|
||||
;; [:li {:key type}
|
||||
;; [:span {:style {:margin-right 6}} type]
|
||||
;; [:span (if time
|
||||
;; (str year "-" month "-" day " " hour ":" min)
|
||||
;; (str year "-" month "-" day))]]))])
|
||||
|
||||
;; (rum/defc title-cp
|
||||
;; [title]
|
||||
;; (let [title-json (js/JSON.stringify (clj->js title))
|
||||
;; html (org/inline-list->html title-json)]
|
||||
;; (util/raw-html html)))
|
||||
|
||||
;; (rum/defc marker-cp
|
||||
;; [marker]
|
||||
;; [:span {:class (str "marker-" (string/lower-case marker))
|
||||
;; :style {:margin-left 8}}
|
||||
;; (if (contains? #{"DOING" "IN-PROGRESS"} marker)
|
||||
;; (str " (" marker ")"))])
|
||||
|
||||
;; (rum/defc tags-cp
|
||||
;; [tags]
|
||||
;; [:span
|
||||
;; (for [tag tags]
|
||||
;; [:span.tag {:key tag}
|
||||
;; [:span
|
||||
;; tag]])])
|
||||
|
||||
;; (rum/defc agenda
|
||||
;; [tasks]
|
||||
;; [:span "TBD"]
|
||||
;; ;; [:div#agenda
|
||||
;; ;; (if (seq tasks)
|
||||
;; ;; (for [[section-name tasks] tasks]
|
||||
;; ;; [:div.section {:key (str "section-" section-name)}
|
||||
;; ;; [:h3 section-name]
|
||||
;; ;; (mui/list
|
||||
;; ;; (for [[idx {:keys [marker title priority level tags children timestamps meta]}] (util/indexed (block/sort-tasks tasks))]
|
||||
;; ;; (mui/list-item
|
||||
;; ;; {:key (str "task-" section-name "-" idx)
|
||||
;; ;; :style {:padding-left 8
|
||||
;; ;; :padding-right 8}}
|
||||
;; ;; [:div.column
|
||||
;; ;; [:div.row {:style {:align-items "center"}}
|
||||
;; ;; (let [marker (case marker
|
||||
;; ;; (list "DOING" "IN-PROGRESS" "TODO")
|
||||
;; ;; (mui/checkbox {:checked false
|
||||
;; ;; :on-change (fn [_]
|
||||
;; ;; ;; FIXME: Log timestamp
|
||||
;; ;; (handler/check marker (:pos meta)))
|
||||
;; ;; :color "primary"
|
||||
;; ;; :style {:padding 0}})
|
||||
|
||||
;; ;; "WAIT"
|
||||
;; ;; [:span {:style {:font-weight "bold"}}
|
||||
;; ;; "WAIT"]
|
||||
|
||||
;; ;; "DONE"
|
||||
;; ;; (mui/checkbox {:checked true
|
||||
;; ;; :on-change (fn [_]
|
||||
;; ;; ;; FIXME: rollback to the last state if exists.
|
||||
;; ;; ;; it must not be `TODO`
|
||||
;; ;; (handler/uncheck (:pos meta)))
|
||||
;; ;; :color "primary"
|
||||
;; ;; :style {:padding 0}})
|
||||
|
||||
;; ;; nil)]
|
||||
;; ;; (if priority
|
||||
;; ;; (mui/badge {:badge-content (string/lower-case priority)
|
||||
;; ;; :overlay "circle"}
|
||||
;; ;; marker)
|
||||
;; ;; marker))
|
||||
|
||||
;; ;; [:div.row {:style {:margin-left 8}}
|
||||
;; ;; (title-cp title)
|
||||
;; ;; (marker-cp marker)
|
||||
;; ;; (when (seq tags)
|
||||
;; ;; (tags-cp tags))]]
|
||||
;; ;; (when (seq timestamps)
|
||||
;; ;; (timestamps-cp timestamps))
|
||||
;; ;; ])))])
|
||||
;; ;; "Empty")]
|
||||
;; )
|
||||
|
|
|
@ -1,66 +1,67 @@
|
|||
(ns frontend.components.file
|
||||
(:require [rum.core :as rum]
|
||||
[frontend.mui :as mui]
|
||||
["@material-ui/core/colors" :as colors]
|
||||
[frontend.state :as state]
|
||||
[frontend.util :as util]
|
||||
[frontend.handler :as handler]
|
||||
[clojure.string :as string]))
|
||||
;; (:require [rum.core :as rum]
|
||||
;; [frontend.mui :as mui]
|
||||
;; ["@material-ui/core/colors" :as colors]
|
||||
;; [frontend.state :as state]
|
||||
;; [frontend.util :as util]
|
||||
;; [frontend.handler :as handler]
|
||||
;; [clojure.string :as string])
|
||||
)
|
||||
|
||||
(rum/defc files-list
|
||||
[current-repo files]
|
||||
[:div
|
||||
(if (seq files)
|
||||
(let [files-set (set files)
|
||||
prefix [(files-set "tasks.org")]
|
||||
files (->> (remove (set prefix) files)
|
||||
(concat prefix)
|
||||
(remove nil?))]
|
||||
(mui/list
|
||||
(for [file files]
|
||||
(mui/list-item
|
||||
{:button true
|
||||
:key file
|
||||
:style {:overflow "hidden"}
|
||||
:on-click (fn []
|
||||
(handler/load-file current-repo file)
|
||||
(handler/toggle-drawer? false))}
|
||||
(mui/list-item-text file)))))
|
||||
"Loading...")])
|
||||
;; (rum/defc files-list
|
||||
;; [current-repo files]
|
||||
;; [:div
|
||||
;; (if (seq files)
|
||||
;; (let [files-set (set files)
|
||||
;; prefix [(files-set "tasks.org")]
|
||||
;; files (->> (remove (set prefix) files)
|
||||
;; (concat prefix)
|
||||
;; (remove nil?))]
|
||||
;; (mui/list
|
||||
;; (for [file files]
|
||||
;; (mui/list-item
|
||||
;; {:button true
|
||||
;; :key file
|
||||
;; :style {:overflow "hidden"}
|
||||
;; :on-click (fn []
|
||||
;; (handler/load-file current-repo file)
|
||||
;; (handler/toggle-drawer? false))}
|
||||
;; (mui/list-item-text file)))))
|
||||
;; "Loading...")])
|
||||
|
||||
(rum/defc edit < rum/reactive
|
||||
[]
|
||||
(let [state (rum/react state/state)
|
||||
{:keys [current-repo current-file contents]} state]
|
||||
(mui/container
|
||||
{:id "root-container"
|
||||
:style {:display "flex"
|
||||
:justify-content "center"
|
||||
:margin-top 64}}
|
||||
[:div.column
|
||||
(let [paths [:editing-files current-file]]
|
||||
(mui/textarea {:style {:margin-bottom 12
|
||||
:padding 8
|
||||
:min-height 300}
|
||||
:auto-focus true
|
||||
:on-change (fn [event]
|
||||
(let [v (util/evalue event)]
|
||||
(swap! state/state assoc-in paths v)))
|
||||
:default-value (get contents current-file)
|
||||
:value (get-in state/state paths)}))
|
||||
(let [path [:commit-message current-file]]
|
||||
(mui/text-field {:id "standard-basic"
|
||||
:style {:margin-bottom 12}
|
||||
:label "Commit message"
|
||||
:auto-focus true
|
||||
:on-change (fn [event]
|
||||
(let [v (util/evalue event)]
|
||||
(when-not (string/blank? v)
|
||||
(swap! state/state assoc-in path v))))
|
||||
:default-value (str "Update " current-file)
|
||||
:value (get-in state/state path)}))
|
||||
(mui/button {:variant "contained"
|
||||
:color "primary"
|
||||
:on-click (fn []
|
||||
(handler/alter-file current-repo current-file))}
|
||||
"Submit")])))
|
||||
;; (rum/defc edit < rum/reactive
|
||||
;; []
|
||||
;; (let [state (rum/react state/state)
|
||||
;; {:keys [current-repo current-file contents]} state]
|
||||
;; (mui/container
|
||||
;; {:id "root-container"
|
||||
;; :style {:display "flex"
|
||||
;; :justify-content "center"
|
||||
;; :margin-top 64}}
|
||||
;; [:div.column
|
||||
;; (let [paths [:editing-files current-file]]
|
||||
;; (mui/textarea {:style {:margin-bottom 12
|
||||
;; :padding 8
|
||||
;; :min-height 300}
|
||||
;; :auto-focus true
|
||||
;; :on-change (fn [event]
|
||||
;; (let [v (util/evalue event)]
|
||||
;; (swap! state/state assoc-in paths v)))
|
||||
;; :default-value (get contents current-file)
|
||||
;; :value (get-in state/state paths)}))
|
||||
;; (let [path [:commit-message current-file]]
|
||||
;; (mui/text-field {:id "standard-basic"
|
||||
;; :style {:margin-bottom 12}
|
||||
;; :label "Commit message"
|
||||
;; :auto-focus true
|
||||
;; :on-change (fn [event]
|
||||
;; (let [v (util/evalue event)]
|
||||
;; (when-not (string/blank? v)
|
||||
;; (swap! state/state assoc-in path v))))
|
||||
;; :default-value (str "Update " current-file)
|
||||
;; :value (get-in state/state path)}))
|
||||
;; (mui/button {:variant "contained"
|
||||
;; :color "primary"
|
||||
;; :on-click (fn []
|
||||
;; (handler/alter-file current-repo current-file))}
|
||||
;; "Submit")])))
|
||||
|
|
|
@ -1,94 +1,220 @@
|
|||
(ns frontend.components.home
|
||||
(:require [rum.core :as rum]
|
||||
[frontend.mui :as mui]
|
||||
["@material-ui/core/colors" :as colors]
|
||||
[frontend.state :as state]
|
||||
(:require [frontend.state :as state]
|
||||
[frontend.util :as util]
|
||||
[frontend.handler :as handler]
|
||||
[frontend.components.agenda :as agenda]
|
||||
[frontend.components.file :as file]
|
||||
[frontend.components.settings :as settings]
|
||||
[frontend.components.repo :as repo]
|
||||
[frontend.ui :as ui]
|
||||
[frontend.hooks :as hooks]
|
||||
[uix.core.alpha :as uix]
|
||||
;; [frontend.components.agenda :as agenda]
|
||||
;; [frontend.components.file :as file]
|
||||
;; [frontend.components.settings :as settings]
|
||||
;; [frontend.components.repo :as repo]
|
||||
[frontend.format :as format]
|
||||
[clojure.string :as string]))
|
||||
[clojure.string :as string])
|
||||
)
|
||||
|
||||
(rum/defc content-html
|
||||
< {:did-mount (fn [state]
|
||||
(doseq [block (-> (js/document.querySelectorAll "pre code")
|
||||
(array-seq))]
|
||||
(js/hljs.highlightBlock block))
|
||||
state)}
|
||||
[current-file html-content]
|
||||
[:div
|
||||
(mui/link {:style {:float "right"}
|
||||
:on-click (fn []
|
||||
(handler/change-page :edit-file))}
|
||||
"edit")
|
||||
(util/raw-html html-content)])
|
||||
|
||||
(rum/defc home < rum/reactive
|
||||
(defn home
|
||||
[]
|
||||
(let [state (rum/react state/state)
|
||||
{:keys [user tokens repos repo-url github-token github-repo contents loadings current-repo current-file width drawer? tasks cloning?]} state
|
||||
current-repo (or current-repo
|
||||
(when-let [first-repo (first (keys repos))]
|
||||
(handler/set-current-repo first-repo)
|
||||
first-repo))
|
||||
files (get-in state [:repos current-repo :files])
|
||||
cloned? (get-in state [:repos current-repo :cloned?])
|
||||
loading? (get loadings current-file)
|
||||
width (or width (util/get-width))
|
||||
mobile? (and width (<= width 600))]
|
||||
(prn {:current-repo current-repo
|
||||
:cloned? cloned?})
|
||||
(mui/container
|
||||
{:id "root-container"
|
||||
:style {:display "flex"
|
||||
:justify-content "center"
|
||||
;; TODO: fewer spacing for mobile, 24px
|
||||
:margin-top 64}}
|
||||
(cond
|
||||
(nil? user)
|
||||
(mui/button {:variant "contained"
|
||||
:color "primary"
|
||||
:start-icon (mui/github-icon)
|
||||
:href "/login/github"}
|
||||
"Login with Github")
|
||||
(let [ref (uix/ref nil)
|
||||
open? (uix/state false)
|
||||
close-fn (fn [] (reset! open? false))
|
||||
open-fn (fn [] (reset! open? true))]
|
||||
(prn "open: " open?)
|
||||
;; effects
|
||||
(hooks/setup-close-listener! ref open?)
|
||||
[:div.relative.bg-white.overflow-hidden {:ref ref}
|
||||
[:div.max-w-screen-xl.mx-auto
|
||||
[:div.relative.z-10.pb-8.bg-white.sm:pb-16.md:pb-20.lg:max-w-2xl.lg:w-full.lg:pb-28.xl:pb-32
|
||||
[:div.pt-6.px-4.sm:px-6.lg:px-8
|
||||
[:nav.relative.flex.items-center.justify-between.sm:h-10.lg:justify-start
|
||||
[:div.flex.items-center.flex-grow.flex-shrink-0.lg:flex-grow-0
|
||||
[:div.flex.items-center.justify-between.w-full.md:w-auto
|
||||
[:a
|
||||
{:href "#"}
|
||||
[:img.h-8.w-auto.sm:h-10
|
||||
{:alt "", :src "https://tailwindui.com/img/logos/workflow-mark-on-white.svg"}]]
|
||||
[:div.-mr-2.flex.items-center.md:hidden
|
||||
[:button.inline-flex.items-center.justify-center.p-2.rounded-md.text-gray-400.hover:text-gray-500.hover:bg-gray-100.focus:outline-none.focus:bg-gray-100.focus:text-gray-500.transition.duration-150.ease-in-out
|
||||
{:type "button",
|
||||
:on-click open-fn}
|
||||
[:svg.h-6.w-6
|
||||
{:viewbox "0 0 24 24",
|
||||
:fill "none",
|
||||
:stroke "currentColor"}
|
||||
[:path
|
||||
{:d "M4 6h16M4 12h16M4 18h16",
|
||||
:stroke-width "2",
|
||||
:stroke-linejoin "round",
|
||||
:stroke-linecap "round"}]]]]]]
|
||||
[:div.hidden.md:block.md:ml-10.md:pr-4
|
||||
[:a.font-medium.text-gray-500.hover:text-gray-900.focus:outline-none.focus:text-gray-900.transition.duration-150.ease-in-out
|
||||
{:href "#"}
|
||||
"Product"]
|
||||
[:a.ml-8.font-medium.text-gray-500.hover:text-gray-900.focus:outline-none.focus:text-gray-900.transition.duration-150.ease-in-out
|
||||
{:href "#"}
|
||||
"Features"]
|
||||
[:a.ml-8.font-medium.text-gray-500.hover:text-gray-900.focus:outline-none.focus:text-gray-900.transition.duration-150.ease-in-out
|
||||
{:href "#"}
|
||||
"Marketplace"]
|
||||
[:a.ml-8.font-medium.text-gray-500.hover:text-gray-900.focus:outline-none.focus:text-gray-900.transition.duration-150.ease-in-out
|
||||
{:href "#"}
|
||||
"Company"]
|
||||
[:a.ml-8.font-medium.text-indigo-600.hover:text-indigo-900.focus:outline-none.focus:text-indigo-700.transition.duration-150.ease-in-out
|
||||
{:href "#"}
|
||||
"Log in"]]]]
|
||||
(ui/css-transition @open? 0
|
||||
(fn [state]
|
||||
[:div.absolute.top-0.inset-x-0.p-2.transition.transform.origin-top-right.md:hidden
|
||||
{:class (case state
|
||||
"entering" "duration-150 ease-out opacity-0 scale-95"
|
||||
"entered" "duration-150 ease-out opacity-100 scale-100"
|
||||
"exiting" "duration-100 ease-in opacity-100 scale-100"
|
||||
"exited" "duration-100 ease-in opacity-0 scale-95")}
|
||||
[:div.rounded-lg.shadow-md
|
||||
[:div.rounded-lg.bg-white.shadow-xs.overflow-hidden
|
||||
[:div.px-5.pt-4.flex.items-center.justify-between
|
||||
[:div
|
||||
[:img.h-8.w-auto
|
||||
{:alt "", :src "https://tailwindui.com/img/logos/workflow-mark-on-white.svg"}]]
|
||||
[:div.-mr-2
|
||||
[:button.inline-flex.items-center.justify-center.p-2.rounded-md.text-gray-400.hover:text-gray-500.hover:bg-gray-100.focus:outline-none.focus:bg-gray-100.focus:text-gray-500.transition.duration-150.ease-in-out
|
||||
{:type "button",
|
||||
:on-click close-fn}
|
||||
[:svg.h-6.w-6
|
||||
{:viewbox "0 0 24 24",
|
||||
:fill "none",
|
||||
:stroke "currentColor"}
|
||||
[:path
|
||||
{:d "M6 18L18 6M6 6l12 12",
|
||||
:stroke-width "2",
|
||||
:stroke-linejoin "round",
|
||||
:stroke-linecap "round"}]]]]]
|
||||
[:div.px-2.pt-2.pb-3
|
||||
[:a.block.px-3.py-2.rounded-md.text-base.font-medium.text-gray-700.hover:text-gray-900.hover:bg-gray-50.focus:outline-none.focus:text-gray-900.focus:bg-gray-50.transition.duration-150.ease-in-out
|
||||
{:href "#"}
|
||||
"Product"]
|
||||
[:a.mt-1.block.px-3.py-2.rounded-md.text-base.font-medium.text-gray-700.hover:text-gray-900.hover:bg-gray-50.focus:outline-none.focus:text-gray-900.focus:bg-gray-50.transition.duration-150.ease-in-out
|
||||
{:href "#"}
|
||||
"Features"]
|
||||
[:a.mt-1.block.px-3.py-2.rounded-md.text-base.font-medium.text-gray-700.hover:text-gray-900.hover:bg-gray-50.focus:outline-none.focus:text-gray-900.focus:bg-gray-50.transition.duration-150.ease-in-out
|
||||
{:href "#"}
|
||||
"Marketplace"]
|
||||
[:a.mt-1.block.px-3.py-2.rounded-md.text-base.font-medium.text-gray-700.hover:text-gray-900.hover:bg-gray-50.focus:outline-none.focus:text-gray-900.focus:bg-gray-50.transition.duration-150.ease-in-out
|
||||
{:href "#"}
|
||||
"Company"]]
|
||||
[:div
|
||||
[:a.block.w-full.px-5.py-3.text-center.font-medium.text-indigo-600.bg-gray-50.hover:bg-gray-100.hover:text-indigo-700.focus:outline-none.focus:bg-gray-100.focus:text-indigo-700.transition.duration-150.ease-in-out
|
||||
{:href "#"}
|
||||
"\n Log in\n "]]]]]))
|
||||
|
||||
(empty? repos)
|
||||
(repo/add-repo repo-url)
|
||||
[:div.mt-10.mx-auto.max-w-screen-xl.px-4.sm:mt-12.sm:px-6.md:mt-16.lg:mt-20.lg:px-8.xl:mt-28
|
||||
[:div.sm:text-center.lg:text-left
|
||||
[:h2.text-4xl.tracking-tight.leading-10.font-extrabold.text-gray-900.sm:text-5xl.sm:leading-none.md:text-6xl
|
||||
"\n Data to enrich your\n "
|
||||
[:br.xl:hidden]
|
||||
[:span.text-indigo-600 "online business"]]
|
||||
[:p.mt-3.text-base.text-gray-500.sm:mt-5.sm:text-lg.sm:max-w-xl.sm:mx-auto.md:mt-5.md:text-xl.lg:mx-0
|
||||
"\n Anim aute id magna aliqua ad ad non deserunt sunt. Qui irure qui lorem cupidatat commodo. Elit sunt amet fugiat veniam occaecat fugiat aliqua.\n "]
|
||||
[:div.mt-5.sm:mt-8.sm:flex.sm:justify-center.lg:justify-start
|
||||
[:div.rounded-md.shadow
|
||||
[:a.w-full.flex.items-center.justify-center.px-8.py-3.border.border-transparent.text-base.leading-6.font-medium.rounded-md.text-white.bg-indigo-600.hover:bg-indigo-500.focus:outline-none.focus:shadow-outline.transition.duration-150.ease-in-out.md:py-4.md:text-lg.md:px-10
|
||||
{:href "#"}
|
||||
"Login with Github"]]
|
||||
[:div.mt-3.sm:mt-0.sm:ml-3
|
||||
[:a.w-full.flex.items-center.justify-center.px-8.py-3.border.border-transparent.text-base.leading-6.font-medium.rounded-md.text-indigo-700.bg-indigo-100.hover:text-indigo-600.hover:bg-indigo-50.focus:outline-none.focus:shadow-outline.focus:border-indigo-300.transition.duration-150.ease-in-out.md:py-4.md:text-lg.md:px-10
|
||||
{:href "#"}
|
||||
"Live demo"]]]]]
|
||||
[:svg
|
||||
{:class (util/hiccup->class ".hidden.lg:block.absolute.right-0.inset-y-0.h-full.w-48.text-white.transform.translate-x-1/2")
|
||||
:preserveaspectratio "none",
|
||||
:viewbox "0 0 100 100",
|
||||
:fill "currentColor"}
|
||||
[:polygon {:points "50,0 100,0 50,100 0,100"}]]]]
|
||||
[:div
|
||||
{:class (util/hiccup->class ".lg:absolute.lg:inset-y-0.lg:right-0.lg:w-1/2")}
|
||||
[:img.h-56.w-full.object-cover.sm:h-72.md:h-96.lg:w-full.lg:h-full
|
||||
{:alt "",
|
||||
:src
|
||||
"https://images.unsplash.com/photo-1551434678-e076c223a692?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=2850&q=80"}]]])
|
||||
)
|
||||
|
||||
cloned?
|
||||
(mui/grid
|
||||
{:container true
|
||||
:spacing 3}
|
||||
(when-not mobile?
|
||||
(mui/grid {:xs 2}
|
||||
(file/files-list current-repo files)))
|
||||
;; (rum/defc content-html
|
||||
;; < {:did-mount (fn [state]
|
||||
;; (doseq [block (-> (js/document.querySelectorAll "pre code")
|
||||
;; (array-seq))]
|
||||
;; (js/hljs.highlightBlock block))
|
||||
;; state)}
|
||||
;; [current-file html-content]
|
||||
;; [:div
|
||||
;; (mui/link {:style {:float "right"}
|
||||
;; :on-click (fn []
|
||||
;; (handler/change-page :edit-file))}
|
||||
;; "edit")
|
||||
;; (util/raw-html html-content)])
|
||||
|
||||
(if (and (not mobile?)
|
||||
(not drawer?))
|
||||
(mui/divider {:orientation "vertical"
|
||||
:style {:margin "0 24px"}}))
|
||||
(mui/grid {:xs 9
|
||||
:style {:margin-left (if (or mobile? drawer?) 24 0)}}
|
||||
(cond
|
||||
(nil? current-file)
|
||||
(agenda/agenda tasks)
|
||||
;; (rum/defc home < rum/reactive
|
||||
;; []
|
||||
;; (let [state (rum/react state/state)
|
||||
;; {:keys [user tokens repos repo-url github-token github-repo contents loadings current-repo current-file width drawer? tasks cloning?]} state
|
||||
;; current-repo (or current-repo
|
||||
;; (when-let [first-repo (first (keys repos))]
|
||||
;; (handler/set-current-repo first-repo)
|
||||
;; first-repo))
|
||||
;; files (get-in state [:repos current-repo :files])
|
||||
;; cloned? (get-in state [:repos current-repo :cloned?])
|
||||
;; loading? (get loadings current-file)
|
||||
;; width (or width (util/get-width))
|
||||
;; mobile? (and width (<= width 600))]
|
||||
;; (prn {:current-repo current-repo
|
||||
;; :cloned? cloned?})
|
||||
;; (mui/container
|
||||
;; {:id "root-container"
|
||||
;; :style {:display "flex"
|
||||
;; :justify-content "center"
|
||||
;; ;; TODO: fewer spacing for mobile, 24px
|
||||
;; :margin-top 64}}
|
||||
;; (cond
|
||||
;; (nil? user)
|
||||
;; (mui/button {:variant "contained"
|
||||
;; :color "primary"
|
||||
;; :start-icon (mui/github-icon)
|
||||
;; :href "/login/github"}
|
||||
;; "Login with Github")
|
||||
|
||||
loading?
|
||||
[:div "Loading ..."]
|
||||
;; (empty? repos)
|
||||
;; (repo/add-repo repo-url)
|
||||
|
||||
:else
|
||||
(let [content (get contents current-file)
|
||||
suffix (last (string/split current-file #"\."))]
|
||||
(if (and suffix (contains? #{"md" "markdown" "org"} suffix))
|
||||
(content-html current-file (format/to-html content suffix))
|
||||
[:div "File " suffix " is not supported."])))))
|
||||
cloning?
|
||||
[:div "Cloning..."]
|
||||
;; cloned?
|
||||
;; (mui/grid
|
||||
;; {:container true
|
||||
;; :spacing 3}
|
||||
;; (when-not mobile?
|
||||
;; (mui/grid {:xs 2}
|
||||
;; (file/files-list current-repo files)))
|
||||
|
||||
:else
|
||||
[:div "TBC"]
|
||||
;; (settings/settings-form github-token github-repo)
|
||||
))))
|
||||
;; (if (and (not mobile?)
|
||||
;; (not drawer?))
|
||||
;; (mui/divider {:orientation "vertical"
|
||||
;; :style {:margin "0 24px"}}))
|
||||
;; (mui/grid {:xs 9
|
||||
;; :style {:margin-left (if (or mobile? drawer?) 24 0)}}
|
||||
;; (cond
|
||||
;; (nil? current-file)
|
||||
;; (agenda/agenda tasks)
|
||||
|
||||
;; loading?
|
||||
;; [:div "Loading ..."]
|
||||
|
||||
;; :else
|
||||
;; (let [content (get contents current-file)
|
||||
;; suffix (last (string/split current-file #"\."))]
|
||||
;; (if (and suffix (contains? #{"md" "markdown" "org"} suffix))
|
||||
;; (content-html current-file (format/to-html content suffix))
|
||||
;; [:div "File " suffix " is not supported."])))))
|
||||
;; cloning?
|
||||
;; [:div "Cloning..."]
|
||||
|
||||
;; :else
|
||||
;; [:div "TBC"]
|
||||
;; ;; (settings/settings-form github-token github-repo)
|
||||
;; ))))
|
||||
|
|
|
@ -1,38 +1,39 @@
|
|||
(ns frontend.components.repo
|
||||
(:require [rum.core :as rum]
|
||||
[frontend.mui :as mui]
|
||||
[frontend.util :as util]
|
||||
[frontend.state :as state]
|
||||
[frontend.handler :as handler]
|
||||
[clojure.string :as string]))
|
||||
;; (:require [rum.core :as rum]
|
||||
;; [frontend.mui :as mui]
|
||||
;; [frontend.util :as util]
|
||||
;; [frontend.state :as state]
|
||||
;; [frontend.handler :as handler]
|
||||
;; [clojure.string :as string])
|
||||
)
|
||||
|
||||
(defn repos
|
||||
[repos]
|
||||
(when (seq repos)
|
||||
[:div#repos
|
||||
[:ul
|
||||
(for [{:keys [url id]} (vals repos)]
|
||||
[:li {:key id}
|
||||
[:button {:on-click (fn []
|
||||
(handler/set-current-repo url))}
|
||||
(string/replace url "https://github.com/" "")]])]]))
|
||||
;; (defn repos
|
||||
;; [repos]
|
||||
;; (when (seq repos)
|
||||
;; [:div#repos
|
||||
;; [:ul
|
||||
;; (for [{:keys [url id]} (vals repos)]
|
||||
;; [:li {:key id}
|
||||
;; [:button {:on-click (fn []
|
||||
;; (handler/set-current-repo url))}
|
||||
;; (string/replace url "https://github.com/" "")]])]]))
|
||||
|
||||
(defn add-repo
|
||||
[repo-url]
|
||||
[:form {:style {:min-width 300}}
|
||||
(mui/grid
|
||||
{:container true
|
||||
:direction "column"}
|
||||
(mui/text-field {:id "standard-basic"
|
||||
:style {:margin-bottom 12}
|
||||
:label "Repo url"
|
||||
:on-change (fn [event]
|
||||
(let [v (util/evalue event)]
|
||||
(swap! state/state assoc :repo-url v)))
|
||||
:value repo-url
|
||||
})
|
||||
(mui/button {:variant "contained"
|
||||
:color "primary"
|
||||
:on-click (fn []
|
||||
(handler/add-repo-and-clone repo-url))}
|
||||
"Sync"))])
|
||||
;; (defn add-repo
|
||||
;; [repo-url]
|
||||
;; [:form {:style {:min-width 300}}
|
||||
;; (mui/grid
|
||||
;; {:container true
|
||||
;; :direction "column"}
|
||||
;; (mui/text-field {:id "standard-basic"
|
||||
;; :style {:margin-bottom 12}
|
||||
;; :label "Repo url"
|
||||
;; :on-change (fn [event]
|
||||
;; (let [v (util/evalue event)]
|
||||
;; (swap! state/state assoc :repo-url v)))
|
||||
;; :value repo-url
|
||||
;; })
|
||||
;; (mui/button {:variant "contained"
|
||||
;; :color "primary"
|
||||
;; :on-click (fn []
|
||||
;; (handler/add-repo-and-clone repo-url))}
|
||||
;; "Sync"))])
|
||||
|
|
|
@ -1,50 +1,51 @@
|
|||
(ns frontend.components.settings
|
||||
(:require [rum.core :as rum]
|
||||
[frontend.mui :as mui]
|
||||
[frontend.util :as util]
|
||||
[frontend.state :as state]
|
||||
[frontend.handler :as handler]
|
||||
[clojure.string :as string]))
|
||||
;; (:require [rum.core :as rum]
|
||||
;; [frontend.mui :as mui]
|
||||
;; [frontend.util :as util]
|
||||
;; [frontend.state :as state]
|
||||
;; [frontend.handler :as handler]
|
||||
;; [clojure.string :as string])
|
||||
)
|
||||
|
||||
(defn settings-form
|
||||
[github-token github-repo]
|
||||
[:form {:style {:min-width 300}}
|
||||
(mui/grid
|
||||
{:container true
|
||||
:direction "column"}
|
||||
(mui/text-field {:id "standard-basic"
|
||||
:style {:margin-bottom 12}
|
||||
:label "Github repo"
|
||||
:on-change (fn [event]
|
||||
(let [v (util/evalue event)]
|
||||
(swap! state/state assoc :github-repo v)))
|
||||
:value github-repo
|
||||
})
|
||||
(mui/button {:variant "contained"
|
||||
:color "primary"
|
||||
:on-click (fn []
|
||||
(when (and github-token github-repo)
|
||||
(handler/clone github-token github-repo)))}
|
||||
"Sync"))])
|
||||
;; (defn settings-form
|
||||
;; [github-token github-repo]
|
||||
;; [:form {:style {:min-width 300}}
|
||||
;; (mui/grid
|
||||
;; {:container true
|
||||
;; :direction "column"}
|
||||
;; (mui/text-field {:id "standard-basic"
|
||||
;; :style {:margin-bottom 12}
|
||||
;; :label "Github repo"
|
||||
;; :on-change (fn [event]
|
||||
;; (let [v (util/evalue event)]
|
||||
;; (swap! state/state assoc :github-repo v)))
|
||||
;; :value github-repo
|
||||
;; })
|
||||
;; (mui/button {:variant "contained"
|
||||
;; :color "primary"
|
||||
;; :on-click (fn []
|
||||
;; (when (and github-token github-repo)
|
||||
;; (handler/clone github-token github-repo)))}
|
||||
;; "Sync"))])
|
||||
|
||||
(rum/defc settings < rum/reactive
|
||||
[]
|
||||
;; Change repo and basic token
|
||||
(let [state (rum/react state/state)
|
||||
{:keys [github-token github-repo]} state]
|
||||
(mui/container
|
||||
{:id "root-container"
|
||||
:style {:display "flex"
|
||||
:justify-content "center"
|
||||
:margin-top 64}}
|
||||
;; (rum/defc settings < rum/reactive
|
||||
;; []
|
||||
;; ;; Change repo and basic token
|
||||
;; (let [state (rum/react state/state)
|
||||
;; {:keys [github-token github-repo]} state]
|
||||
;; (mui/container
|
||||
;; {:id "root-container"
|
||||
;; :style {:display "flex"
|
||||
;; :justify-content "center"
|
||||
;; :margin-top 64}}
|
||||
|
||||
[:div
|
||||
;; [:div
|
||||
|
||||
(settings-form github-token github-repo)
|
||||
;; (settings-form github-token github-repo)
|
||||
|
||||
(mui/divider {:style {:margin "24px 0"}})
|
||||
;; (mui/divider {:style {:margin "24px 0"}})
|
||||
|
||||
;; clear storage
|
||||
(mui/button {:on-click handler/clear-storage
|
||||
:color "primary"}
|
||||
"Clear storage and clone")])))
|
||||
;; ;; clear storage
|
||||
;; (mui/button {:on-click handler/clear-storage
|
||||
;; :color "primary"}
|
||||
;; "Clear storage and clone")])))
|
||||
|
|
|
@ -1,18 +1,47 @@
|
|||
(ns frontend.components.sidebar
|
||||
(:require [rum.core :as rum]
|
||||
(:require [uix.core.alpha :as uix :refer [defui]]
|
||||
[xframe.core.alpha :as xf :refer [<sub]]
|
||||
[frontend.ui :as ui]
|
||||
[frontend.mixins :as mixins]))
|
||||
[frontend.hooks :as hooks]))
|
||||
|
||||
(rum/defcs sidebar
|
||||
<
|
||||
(rum/local false ::open?)
|
||||
(mixins/event-mixin #(mixins/simple-close-listener % ::open?))
|
||||
[state]
|
||||
(let [open? (get state ::open?)
|
||||
(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)
|
||||
(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)
|
||||
|
||||
(defn nav-item
|
||||
([title href svg-d]
|
||||
(nav-item title href svg-d false))
|
||||
([title href svg-d active?]
|
||||
(let [a (if active? active-button inactive-button)]
|
||||
[a {:href href}
|
||||
[: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
|
||||
{:viewBox "0 0 24 24", :fill "none", :stroke "currentColor"}
|
||||
[:path
|
||||
{:d svg-d
|
||||
:stroke-width "2",
|
||||
:stroke-linejoin "round",
|
||||
:stroke-linecap "round"}]]
|
||||
title])))
|
||||
|
||||
(defn sidebar-nav
|
||||
[]
|
||||
[:nav.flex-1.px-2.py-4.bg-gray-800
|
||||
(nav-item "Journal" "#"
|
||||
"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"
|
||||
true)
|
||||
(nav-item "Repos" "#"
|
||||
"M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z")
|
||||
(nav-item "Agenda" "#"
|
||||
"M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z")])
|
||||
|
||||
(defn sidebar
|
||||
[]
|
||||
(let [ref (uix/ref nil)
|
||||
open? (uix/state false)
|
||||
close-fn (fn [] (reset! open? false))
|
||||
open-fn (fn [] (reset! open? true))]
|
||||
(prn "open: " @open?)
|
||||
[:div.h-screen.flex.overflow-hidden.bg-gray-100
|
||||
;; effects
|
||||
(hooks/setup-close-listener! ref open?)
|
||||
[:div.h-screen.flex.overflow-hidden.bg-gray-100 {:ref ref}
|
||||
[:div.md:hidden
|
||||
[:div.fixed.inset-0.z-30.bg-gray-600.opacity-0.pointer-events-none.transition-opacity.ease-linear.duration-300
|
||||
{:class (if @open?
|
||||
|
@ -25,167 +54,35 @@
|
|||
"-translate-x-full")}
|
||||
(if @open?
|
||||
[:div.absolute.top-0.right-0.-mr-14.p-1
|
||||
[:button.flex.items-center.justify-center.h-12.w-12.rounded-full.focus:outline-none.focus:bg-gray-600
|
||||
{:on-click close-fn}
|
||||
[:svg.h-6.w-6.text-white
|
||||
{:viewBox "0 0 24 24", :fill "none", :stroke "currentColor"}
|
||||
[:path
|
||||
{:d "M6 18L18 6M6 6l12 12",
|
||||
:stroke-width "2",
|
||||
:stroke-linejoin "round",
|
||||
:stroke-linecap "round"}]]]])
|
||||
[:button.flex.items-center.justify-center.h-12.w-12.rounded-full.focus:outline-none.focus:bg-gray-600
|
||||
{:on-click close-fn}
|
||||
[:svg.h-6.w-6.text-white
|
||||
{:viewBox "0 0 24 24", :fill "none", :stroke "currentColor"}
|
||||
[:path
|
||||
{:d "M6 18L18 6M6 6l12 12",
|
||||
:stroke-width "2",
|
||||
:stroke-linejoin "round",
|
||||
:stroke-linecap "round"}]]]])
|
||||
[:div.flex-shrink-0.flex.items-center.h-16.px-4.bg-gray-900
|
||||
[:img.h-8.w-auto
|
||||
{:alt "Workflow",
|
||||
:src "/img/logos/workflow-logo-on-dark.svg"}]]
|
||||
{:alt "Gitnotes",
|
||||
:src "https://tailwindui.com/img/logos/workflow-logo-on-dark.svg"}]]
|
||||
[:div.flex-1.h-0.overflow-y-auto
|
||||
[:nav.px-2.py-4
|
||||
[: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
|
||||
{:href "#"}
|
||||
[:svg.mr-4.h-6.w-6.text-gray-300.group-hover:text-gray-300.group-focus:text-gray-300.transition.ease-in-out.duration-150
|
||||
{:viewBox "0 0 24 24", :fill "none", :stroke "currentColor"}
|
||||
[:path
|
||||
{:d
|
||||
"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",
|
||||
:stroke-width "2",
|
||||
:stroke-linejoin "round",
|
||||
:stroke-linecap "round"}]]
|
||||
"\n Dashboard\n "]
|
||||
[: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
|
||||
{:href "#"}
|
||||
[: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
|
||||
{:viewBox "0 0 24 24", :fill "none", :stroke "currentColor"}
|
||||
[:path
|
||||
{:d
|
||||
"M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z",
|
||||
:stroke-width "2",
|
||||
:stroke-linejoin "round",
|
||||
:stroke-linecap "round"}]]
|
||||
"\n Team\n "]
|
||||
[: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
|
||||
{:href "#"}
|
||||
[: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
|
||||
{:viewBox "0 0 24 24", :fill "none", :stroke "currentColor"}
|
||||
[:path
|
||||
{:d
|
||||
"M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z",
|
||||
:stroke-width "2",
|
||||
:stroke-linejoin "round",
|
||||
:stroke-linecap "round"}]]
|
||||
"\n Projects\n "]
|
||||
[: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
|
||||
{:href "#"}
|
||||
[: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
|
||||
{:viewBox "0 0 24 24", :fill "none", :stroke "currentColor"}
|
||||
[:path
|
||||
{:d
|
||||
"M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z",
|
||||
:stroke-width "2",
|
||||
:stroke-linejoin "round",
|
||||
:stroke-linecap "round"}]]
|
||||
"\n Calendar\n "]
|
||||
[: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
|
||||
{:href "#"}
|
||||
[: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
|
||||
{:viewBox "0 0 24 24", :fill "none", :stroke "currentColor"}
|
||||
[:path
|
||||
{:d
|
||||
"M20 13V6a2 2 0 00-2-2H6a2 2 0 00-2 2v7m16 0v5a2 2 0 01-2 2H6a2 2 0 01-2-2v-5m16 0h-2.586a1 1 0 00-.707.293l-2.414 2.414a1 1 0 01-.707.293h-3.172a1 1 0 01-.707-.293l-2.414-2.414A1 1 0 006.586 13H4",
|
||||
:stroke-width "2",
|
||||
:stroke-linejoin "round",
|
||||
:stroke-linecap "round"}]]
|
||||
"\n Documents\n "]
|
||||
[: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
|
||||
{:href "#"}
|
||||
[: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
|
||||
{:viewBox "0 0 24 24", :fill "none", :stroke "currentColor"}
|
||||
[:path
|
||||
{:d
|
||||
"M16 8v8m-4-5v5m-4-2v2m-2 4h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z",
|
||||
:stroke-width "2",
|
||||
:stroke-linejoin "round",
|
||||
:stroke-linecap "round"}]]
|
||||
"\n Reports\n "]]]]]
|
||||
[sidebar-nav]]]]
|
||||
[:div.hidden.md:flex.md:flex-shrink-0
|
||||
[:div.flex.flex-col.w-64
|
||||
[:div.flex.items-center.h-16.flex-shrink-0.px-4.bg-gray-900
|
||||
[:img.h-8.w-auto
|
||||
{:alt "Workflow",
|
||||
:src "/img/logos/workflow-logo-on-dark.svg"}]]
|
||||
{:alt "Gitnotes",
|
||||
:src "https://tailwindui.com/img/logos/workflow-logo-on-dark.svg"}]]
|
||||
[:div.h-0.flex-1.flex.flex-col.overflow-y-auto
|
||||
[:nav.flex-1.px-2.py-4.bg-gray-800
|
||||
[:a.group.flex.items-center.px-2.py-2.text-sm.leading-5.font-medium.text-white.rounded-md.bg-gray-900.focus:outline-none.focus:bg-gray-700.transition.ease-in-out.duration-150
|
||||
{:href "#"}
|
||||
[:svg.mr-3.h-6.w-6.text-gray-300.group-hover:text-gray-300.group-focus:text-gray-300.transition.ease-in-out.duration-150
|
||||
{:viewBox "0 0 24 24", :fill "none", :stroke "currentColor"}
|
||||
[:path
|
||||
{:d
|
||||
"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",
|
||||
:stroke-width "2",
|
||||
:stroke-linejoin "round",
|
||||
:stroke-linecap "round"}]]
|
||||
"\n Dashboard\n "]
|
||||
[:a.mt-1.group.flex.items-center.px-2.py-2.text-sm.leading-5.font-medium.text-gray-300.rounded-md.hover:text-white.hover:bg-gray-700.focus:outline-none.focus:text-white.focus:bg-gray-700.transition.ease-in-out.duration-150
|
||||
{:href "#"}
|
||||
[:svg.mr-3.h-6.w-6.text-gray-400.group-hover:text-gray-300.group-focus:text-gray-300.transition.ease-in-out.duration-150
|
||||
{:viewBox "0 0 24 24", :fill "none", :stroke "currentColor"}
|
||||
[:path
|
||||
{:d
|
||||
"M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z",
|
||||
:stroke-width "2",
|
||||
:stroke-linejoin "round",
|
||||
:stroke-linecap "round"}]]
|
||||
"\n Team\n "]
|
||||
[:a.mt-1.group.flex.items-center.px-2.py-2.text-sm.leading-5.font-medium.text-gray-300.rounded-md.hover:text-white.hover:bg-gray-700.focus:outline-none.focus:text-white.focus:bg-gray-700.transition.ease-in-out.duration-150
|
||||
{:href "#"}
|
||||
[:svg.mr-3.h-6.w-6.text-gray-400.group-hover:text-gray-300.group-focus:text-gray-300.transition.ease-in-out.duration-150
|
||||
{:viewBox "0 0 24 24", :fill "none", :stroke "currentColor"}
|
||||
[:path
|
||||
{:d
|
||||
"M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z",
|
||||
:stroke-width "2",
|
||||
:stroke-linejoin "round",
|
||||
:stroke-linecap "round"}]]
|
||||
"\n Projects\n "]
|
||||
[:a.mt-1.group.flex.items-center.px-2.py-2.text-sm.leading-5.font-medium.text-gray-300.rounded-md.hover:text-white.hover:bg-gray-700.focus:outline-none.focus:text-white.focus:bg-gray-700.transition.ease-in-out.duration-150
|
||||
{:href "#"}
|
||||
[:svg.mr-3.h-6.w-6.text-gray-400.group-hover:text-gray-300.group-focus:text-gray-300.transition.ease-in-out.duration-150
|
||||
{:viewBox "0 0 24 24", :fill "none", :stroke "currentColor"}
|
||||
[:path
|
||||
{:d
|
||||
"M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z",
|
||||
:stroke-width "2",
|
||||
:stroke-linejoin "round",
|
||||
:stroke-linecap "round"}]]
|
||||
"\n Calendar\n "]
|
||||
[:a.mt-1.group.flex.items-center.px-2.py-2.text-sm.leading-5.font-medium.text-gray-300.rounded-md.hover:text-white.hover:bg-gray-700.focus:outline-none.focus:text-white.focus:bg-gray-700.transition.ease-in-out.duration-150
|
||||
{:href "#"}
|
||||
[:svg.mr-3.h-6.w-6.text-gray-400.group-hover:text-gray-300.group-focus:text-gray-300.transition.ease-in-out.duration-150
|
||||
{:viewBox "0 0 24 24", :fill "none", :stroke "currentColor"}
|
||||
[:path
|
||||
{:d
|
||||
"M20 13V6a2 2 0 00-2-2H6a2 2 0 00-2 2v7m16 0v5a2 2 0 01-2 2H6a2 2 0 01-2-2v-5m16 0h-2.586a1 1 0 00-.707.293l-2.414 2.414a1 1 0 01-.707.293h-3.172a1 1 0 01-.707-.293l-2.414-2.414A1 1 0 006.586 13H4",
|
||||
:stroke-width "2",
|
||||
:stroke-linejoin "round",
|
||||
:stroke-linecap "round"}]]
|
||||
"\n Documents\n "]
|
||||
[:a.mt-1.group.flex.items-center.px-2.py-2.text-sm.leading-5.font-medium.text-gray-300.rounded-md.hover:text-white.hover:bg-gray-700.focus:outline-none.focus:text-white.focus:bg-gray-700.transition.ease-in-out.duration-150
|
||||
{:href "#"}
|
||||
[:svg.mr-3.h-6.w-6.text-gray-400.group-hover:text-gray-300.group-focus:text-gray-300.transition.ease-in-out.duration-150
|
||||
{:viewBox "0 0 24 24", :fill "none", :stroke "currentColor"}
|
||||
[:path
|
||||
{:d
|
||||
"M16 8v8m-4-5v5m-4-2v2m-2 4h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z",
|
||||
:stroke-width "2",
|
||||
:stroke-linejoin "round",
|
||||
:stroke-linecap "round"}]]
|
||||
"\n Reports\n "]]]]]
|
||||
[sidebar-nav]]]]
|
||||
[:div.flex.flex-col.w-0.flex-1.overflow-hidden
|
||||
[:div.relative.z-10.flex-shrink-0.flex.h-16.bg-white.shadow
|
||||
[:button.px-4.border-r.border-gray-200.text-gray-500.focus:outline-none.focus:bg-gray-100.focus:text-gray-600.md:hidden
|
||||
{:on-click open-fn}
|
||||
[:svg.h-6.w-6
|
||||
{:viewbox "0 0 24 24", :fill "none", :stroke "currentColor"}
|
||||
{:viewBox "0 0 24 24", :fill "none", :stroke "currentColor"}
|
||||
[:path
|
||||
{:d "M4 6h16M4 12h16M4 18h7",
|
||||
:stroke-width "2",
|
||||
|
@ -230,5 +127,4 @@
|
|||
[:h1.text-2xl.font-semibold.text-gray-900 "Dashboard"]]
|
||||
[:div.max-w-7xl.mx-auto.px-4.sm:px-6.md:px-8
|
||||
[:div.py-4
|
||||
[:div.border-4.border-dashed.border-gray-200.rounded-lg.h-96]]
|
||||
]]]]))
|
||||
[:div.border-4.border-dashed.border-gray-200.rounded-lg.h-96]]]]]]))
|
||||
|
|
|
@ -1,25 +1,31 @@
|
|||
(ns frontend.core
|
||||
(:require [rum.core :as rum]
|
||||
[frontend.git :as git]
|
||||
[frontend.util :as util]
|
||||
[frontend.state :as state]
|
||||
(:require [uix.dom.alpha :as dom]
|
||||
[frontend.handler :as handler]
|
||||
[frontend.routes :as routes]
|
||||
[frontend.page :as page]
|
||||
[frontend.api :as api]))
|
||||
[frontend.routes :as routes]
|
||||
[reitit.frontend :as rf]
|
||||
[reitit.frontend.easy :as rfe]
|
||||
[reitit.coercion :as rc]
|
||||
[reitit.coercion.spec :as rss]))
|
||||
|
||||
(defn start []
|
||||
(rum/mount (page/current-page)
|
||||
(.getElementById js/document "root")))
|
||||
(dom/render [page/current-page] js/root))
|
||||
|
||||
(defn ^:export init []
|
||||
;; init is called ONCE when the page loads
|
||||
;; this is called in the index.html and must be exported
|
||||
;; so it is available even in :advanced release builds
|
||||
(rfe/start!
|
||||
(rf/router routes/routes {:data {:coercion rss/coercion}})
|
||||
handler/set-route-match!
|
||||
;; set to false to enable HistoryAPI
|
||||
{:use-fragment false})
|
||||
|
||||
(handler/get-me)
|
||||
|
||||
(handler/listen-to-resize)
|
||||
|
||||
;; popup to notify user, could be toggled in settings
|
||||
;; (handler/request-notifications-if-not-asked)
|
||||
|
||||
;; (handler/run-notify-worker!)
|
||||
|
|
|
@ -406,3 +406,7 @@
|
|||
(defn set-current-repo
|
||||
[repo-url]
|
||||
(swap! state/state assoc :current-repo repo-url))
|
||||
|
||||
(defn set-route-match!
|
||||
[route]
|
||||
(swap! state/state assoc :route-match route))
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
(ns frontend.hooks
|
||||
(:require [goog.dom :as dom]
|
||||
[uix.core.alpha :as uix]
|
||||
[uix.dom.alpha :as uix-dom])
|
||||
(:import [goog.events EventHandler]))
|
||||
|
||||
(defn detach-listeners
|
||||
"Detach all event listeners."
|
||||
[state]
|
||||
(some-> state ::event-handler .removeAll))
|
||||
|
||||
(defn listen
|
||||
"Register an event `handler` for events of `type` on `target`."
|
||||
[^EventHandler event-handler target type handler & [opts]]
|
||||
(.listen event-handler target (name type) handler (clj->js opts)))
|
||||
|
||||
;; (defn timeout-mixin
|
||||
;; "The setTimeout mixin."
|
||||
;; [name t f]
|
||||
;; {:will-mount
|
||||
;; (fn [state]
|
||||
;; (assoc state name (util/set-timeout t f)))
|
||||
;; :will-unmount
|
||||
;; (fn [state]
|
||||
;; (let [timeout (get state name)]
|
||||
;; (util/clear-timeout timeout)
|
||||
;; (dissoc state name)))})
|
||||
|
||||
;; (defn interval-mixin
|
||||
;; "The setInterval mixin."
|
||||
;; [name t f]
|
||||
;; {:will-mount
|
||||
;; (fn [state]
|
||||
;; (assoc state name (util/set-interval t f)))
|
||||
;; :will-unmount
|
||||
;; (fn [state]
|
||||
;; (when-let [interval (get state name)]
|
||||
;; (util/clear-interval interval))
|
||||
;; (dissoc state name))})
|
||||
|
||||
(defn event-hook
|
||||
[attach-listeners]
|
||||
(let [event-handler (uix/state (EventHandler.))]
|
||||
(uix/effect!
|
||||
(fn []
|
||||
;; did mount
|
||||
(attach-listeners @event-handler)
|
||||
(fn []
|
||||
;; will-unmount
|
||||
(detach-listeners @event-handler)))
|
||||
[])))
|
||||
|
||||
(defn close-when-esc-or-outside
|
||||
[ref event-handler open? & {:keys [on-close]}]
|
||||
(let [node (uix-dom/find-dom-node @ref)]
|
||||
(when open?
|
||||
(when node
|
||||
(listen event-handler js/window "click"
|
||||
(fn [e]
|
||||
;; If the click target is outside of current node
|
||||
(when-not (dom/contains node (.. e -target))
|
||||
(on-close e)))))
|
||||
|
||||
(listen event-handler js/window "keydown"
|
||||
(fn [e]
|
||||
(case (.-keyCode e)
|
||||
;; Esc
|
||||
27 (on-close e)
|
||||
nil))))))
|
||||
|
||||
(defn setup-close-listener!
|
||||
[ref open?]
|
||||
(event-hook (fn [event-handler]
|
||||
(close-when-esc-or-outside
|
||||
ref
|
||||
event-handler
|
||||
open?
|
||||
:on-close (fn []
|
||||
(reset! open? false))))))
|
|
@ -1,66 +1,66 @@
|
|||
(ns frontend.layout
|
||||
(:require [frontend.mui :as mui]
|
||||
[frontend.handler :as handler]
|
||||
[frontend.state :as state]
|
||||
[frontend.components.file :as file]
|
||||
[frontend.components.repo :as repo]
|
||||
[rum.core :as rum]
|
||||
[clojure.string :as string]))
|
||||
;; (:require [frontend.handler :as handler]
|
||||
;; [frontend.state :as state]
|
||||
;; [frontend.components.file :as file]
|
||||
;; [frontend.components.repo :as repo]
|
||||
;; [rum.core :as rum]
|
||||
;; [clojure.string :as string])
|
||||
)
|
||||
|
||||
(rum/defc frame < rum/reactive
|
||||
[content width]
|
||||
(let [state (rum/react state/state)
|
||||
{:keys [files drawer? snackbar? snackbar-message current-repo]} state
|
||||
mobile? (and width (<= width 600))]
|
||||
(mui/theme-provider
|
||||
{:theme (mui/custom-theme)}
|
||||
[:div {:class "root"
|
||||
:style {:padding-bottom 100}}
|
||||
(mui/css-baseline)
|
||||
(mui/app-bar
|
||||
{:position "static"}
|
||||
(mui/tool-bar
|
||||
{}
|
||||
(if mobile?
|
||||
(mui/icon-button {:edge "start"
|
||||
:class "menuButton"
|
||||
:color "inherit"
|
||||
:on-click (fn []
|
||||
(handler/toggle-drawer? true))}
|
||||
(mui/menu-icon)))
|
||||
(mui/typography {:class "grow"
|
||||
:variant "h6"
|
||||
:color "inherit"
|
||||
:no-wrap true
|
||||
:on-click (fn []
|
||||
(handler/change-page :home)
|
||||
(handler/reset-current-file))}
|
||||
"Gitnotes")
|
||||
;; (rum/defc frame < rum/reactive
|
||||
;; [content width]
|
||||
;; (let [state (rum/react state/state)
|
||||
;; {:keys [files drawer? snackbar? snackbar-message current-repo]} state
|
||||
;; mobile? (and width (<= width 600))]
|
||||
;; (mui/theme-provider
|
||||
;; {:theme (mui/custom-theme)}
|
||||
;; [:div {:class "root"
|
||||
;; :style {:padding-bottom 100}}
|
||||
;; (mui/css-baseline)
|
||||
;; (mui/app-bar
|
||||
;; {:position "static"}
|
||||
;; (mui/tool-bar
|
||||
;; {}
|
||||
;; (if mobile?
|
||||
;; (mui/icon-button {:edge "start"
|
||||
;; :class "menuButton"
|
||||
;; :color "inherit"
|
||||
;; :on-click (fn []
|
||||
;; (handler/toggle-drawer? true))}
|
||||
;; (mui/menu-icon)))
|
||||
;; (mui/typography {:class "grow"
|
||||
;; :variant "h6"
|
||||
;; :color "inherit"
|
||||
;; :no-wrap true
|
||||
;; :on-click (fn []
|
||||
;; (handler/change-page :home)
|
||||
;; (handler/reset-current-file))}
|
||||
;; "Gitnotes")
|
||||
|
||||
(mui/button {:color "inherit"
|
||||
:on-click (fn []
|
||||
(handler/sync))}
|
||||
"Sync")
|
||||
;; (mui/button {:color "inherit"
|
||||
;; :on-click (fn []
|
||||
;; (handler/sync))}
|
||||
;; "Sync")
|
||||
|
||||
(mui/button {:color "inherit"
|
||||
:on-click (fn []
|
||||
(handler/change-page :settings))}
|
||||
"Settings")))
|
||||
;; (mui/button {:color "inherit"
|
||||
;; :on-click (fn []
|
||||
;; (handler/change-page :settings))}
|
||||
;; "Settings")))
|
||||
|
||||
(repo/repos (:repos state))
|
||||
;; (repo/repos (:repos state))
|
||||
|
||||
content
|
||||
;; content
|
||||
|
||||
(if mobile?
|
||||
(mui/drawer {:open drawer?
|
||||
:disableBackdropTransition true
|
||||
:on-open (fn []
|
||||
(handler/toggle-drawer? true))
|
||||
:on-close (fn []
|
||||
(handler/toggle-drawer? false))}
|
||||
[:div {:style {:width 240}}
|
||||
(file/files-list current-repo files)]))
|
||||
;; (if mobile?
|
||||
;; (mui/drawer {:open drawer?
|
||||
;; :disableBackdropTransition true
|
||||
;; :on-open (fn []
|
||||
;; (handler/toggle-drawer? true))
|
||||
;; :on-close (fn []
|
||||
;; (handler/toggle-drawer? false))}
|
||||
;; [:div {:style {:width 240}}
|
||||
;; (file/files-list current-repo files)]))
|
||||
|
||||
(mui/snackbar {:open snackbar?
|
||||
:auto-hide-duration 3000
|
||||
:message snackbar-message})])))
|
||||
;; (mui/snackbar {:open snackbar?
|
||||
;; :auto-hide-duration 3000
|
||||
;; :message snackbar-message})])))
|
||||
|
|
|
@ -1,86 +0,0 @@
|
|||
(ns frontend.mixins
|
||||
(:require [rum.core :as rum]
|
||||
[goog.dom :as dom])
|
||||
(:import [goog.events EventHandler]))
|
||||
|
||||
(defn detach
|
||||
"Detach all event listeners."
|
||||
[state]
|
||||
(some-> state ::event-handler .removeAll))
|
||||
|
||||
(defn listen
|
||||
"Register an event `handler` for events of `type` on `target`."
|
||||
[state target type handler & [opts]]
|
||||
(when-let [event-handler (::event-handler state)]
|
||||
(.listen event-handler target (name type) handler (clj->js opts))))
|
||||
|
||||
(def event-handler-mixin
|
||||
"The event handler mixin."
|
||||
{:will-mount
|
||||
(fn [state]
|
||||
(assoc state ::event-handler (EventHandler.)))
|
||||
:will-unmount
|
||||
(fn [state]
|
||||
(detach state)
|
||||
(dissoc state ::event-handler))})
|
||||
|
||||
;; (defn timeout-mixin
|
||||
;; "The setTimeout mixin."
|
||||
;; [name t f]
|
||||
;; {:will-mount
|
||||
;; (fn [state]
|
||||
;; (assoc state name (util/set-timeout t f)))
|
||||
;; :will-unmount
|
||||
;; (fn [state]
|
||||
;; (let [timeout (get state name)]
|
||||
;; (util/clear-timeout timeout)
|
||||
;; (dissoc state name)))})
|
||||
|
||||
;; (defn interval-mixin
|
||||
;; "The setInterval mixin."
|
||||
;; [name t f]
|
||||
;; {:will-mount
|
||||
;; (fn [state]
|
||||
;; (assoc state name (util/set-interval t f)))
|
||||
;; :will-unmount
|
||||
;; (fn [state]
|
||||
;; (when-let [interval (get state name)]
|
||||
;; (util/clear-interval interval))
|
||||
;; (dissoc state name))})
|
||||
|
||||
(defn close-when-esc-or-outside
|
||||
[state open? & {:keys [on-close]}]
|
||||
(let [node (rum/dom-node state)]
|
||||
(when open?
|
||||
(listen state js/window "click"
|
||||
(fn [e]
|
||||
;; If the click target is outside of current node
|
||||
(when-not (dom/contains node (.. e -target))
|
||||
(on-close e))))
|
||||
|
||||
(listen state js/window "keydown"
|
||||
(fn [e]
|
||||
(case (.-keyCode e)
|
||||
;; Esc
|
||||
27 (on-close e)
|
||||
nil))))))
|
||||
|
||||
(defn simple-close-listener
|
||||
[state key]
|
||||
(let [open? (get state key)]
|
||||
(close-when-esc-or-outside state
|
||||
open?
|
||||
:on-close (fn []
|
||||
(reset! open? false)))))
|
||||
|
||||
(defn event-mixin
|
||||
[attach-listeners]
|
||||
(merge
|
||||
event-handler-mixin
|
||||
{:did-mount (fn [state]
|
||||
(attach-listeners state)
|
||||
state)
|
||||
:did-remount (fn [old-state new-state]
|
||||
(detach old-state)
|
||||
(attach-listeners new-state)
|
||||
new-state)}))
|
|
@ -1,114 +0,0 @@
|
|||
(ns frontend.mui
|
||||
(:refer-clojure :exclude [list stepper])
|
||||
(:require [rum.core]
|
||||
[frontend.rum :as r]
|
||||
["@material-ui/core" :refer [MuiThemeProvider]]
|
||||
["@material-ui/core/styles" :refer [createMuiTheme withStyles makeStyles]]
|
||||
["@material-ui/core/colors" :as colors]
|
||||
["@material-ui/core/CssBaseline" :default CssBaseline]
|
||||
["@material-ui/core/Typography" :default Typography]
|
||||
["@material-ui/core/Avatar" :default mui-avatar]
|
||||
["@material-ui/icons/Android" :default AndroidIcon]
|
||||
["@material-ui/core/AppBar" :default AppBar]
|
||||
["@material-ui/core/Divider" :default Divider]
|
||||
["@material-ui/core/Paper" :default Paper]
|
||||
["@material-ui/core/Toolbar" :default ToolBar]
|
||||
["@material-ui/core/IconButton" :default IconButton]
|
||||
["@material-ui/icons/Menu" :default MenuIcon]
|
||||
["@material-ui/core/Button" :default Button]
|
||||
["@material-ui/core/SwipeableDrawer" :default SwipeableDrawer]
|
||||
["@material-ui/core/Chip" :default Chip]
|
||||
["@material-ui/core/Fab" :default Fab]
|
||||
["@material-ui/core/List" :default List]
|
||||
["@material-ui/core/ListItem" :default ListItem]
|
||||
["@material-ui/core/ListItemText" :default ListItemText]
|
||||
["@material-ui/core/Container" :default Container]
|
||||
["@material-ui/core/Box" :default Box]
|
||||
["@material-ui/core/Snackbar" :default Snackbar]
|
||||
["@material-ui/core/Link" :default Link]
|
||||
["@material-ui/core/Checkbox" :default Checkbox]
|
||||
["@material-ui/core/Grid" :default Grid]
|
||||
["@material-ui/core/GridList" :default GridList]
|
||||
["@material-ui/core/Hidden" :default Hidden]
|
||||
;; ["@material-ui/core/Form" :default Form]
|
||||
["@material-ui/core/TextField" :default TextField]
|
||||
["@material-ui/core/TextareaAutosize" :default TextareaAutosize]
|
||||
["@material-ui/core/Card" :default Card]
|
||||
["@material-ui/core/CardActions" :default CardActions]
|
||||
["@material-ui/core/CardContent" :default CardContent]
|
||||
["@material-ui/core/CardHeader" :default CardHeader]
|
||||
["@material-ui/core/CardMedia" :default CardMedia]
|
||||
["@material-ui/core/Collapse" :default Collapse]
|
||||
["@material-ui/core/Avatar" :default Avatar]
|
||||
["@material-ui/core/CircularProgress" :default CircularProgress]
|
||||
["@material-ui/core/Badge" :default Badge]
|
||||
["@material-ui/core/Tooltip" :default Tooltip]
|
||||
["@material-ui/core/Dialog" :default Dialog]
|
||||
["@material-ui/core/DialogTitle" :default DialogTitle]
|
||||
["@material-ui/core/DialogContent" :default DialogContent]
|
||||
["@material-ui/core/DialogActions" :default DialogActions]
|
||||
["@material-ui/icons/Favorite" :default FavoriteIcon]
|
||||
["@material-ui/icons/Add" :default AddIcon]
|
||||
["@material-ui/icons/GitHub" :default GithubIcon]
|
||||
["@material-ui/icons/Share" :default ShareIcon]
|
||||
["@material-ui/icons/MoreVert" :default MoreVertIcon]
|
||||
))
|
||||
|
||||
(defn custom-theme []
|
||||
(createMuiTheme
|
||||
(clj->js
|
||||
{:palette
|
||||
{:type "light"
|
||||
;; :primary (.-purple colors)
|
||||
;; :secondary (.-green colors)
|
||||
}
|
||||
:typography
|
||||
{:useNextVariants true}})))
|
||||
|
||||
(defonce theme-provider (r/adapt-class MuiThemeProvider))
|
||||
(defonce css-baseline (r/adapt-class CssBaseline))
|
||||
(defonce app-bar (r/adapt-class AppBar))
|
||||
(defonce divider (r/adapt-class Divider))
|
||||
(defonce tool-bar (r/adapt-class ToolBar))
|
||||
(defonce button (r/adapt-class Button))
|
||||
(defonce icon-button (r/adapt-class IconButton))
|
||||
(defonce typography (r/adapt-class Typography))
|
||||
(defonce container (r/adapt-class Container))
|
||||
(defonce box (r/adapt-class Box))
|
||||
(defonce snackbar (r/adapt-class Snackbar))
|
||||
(defonce link (r/adapt-class Link))
|
||||
(defonce checkbox (r/adapt-class Checkbox))
|
||||
(defonce grid (r/adapt-class Grid))
|
||||
(defonce grid-list (r/adapt-class GridList))
|
||||
(defonce paper (r/adapt-class Paper))
|
||||
(defonce collapse (r/adapt-class Collapse))
|
||||
(defonce avatar (r/adapt-class Avatar))
|
||||
(defonce favorite-icon (r/adapt-class FavoriteIcon))
|
||||
(defonce github-icon (r/adapt-class GithubIcon))
|
||||
(defonce add-icon (r/adapt-class AddIcon))
|
||||
(defonce fab (r/adapt-class Fab))
|
||||
(defonce share-icon (r/adapt-class ShareIcon))
|
||||
(defonce more-vert-icon (r/adapt-class MoreVertIcon))
|
||||
(defonce circular-progress (r/adapt-class CircularProgress))
|
||||
(defonce badge (r/adapt-class Badge))
|
||||
(defonce text-field (r/adapt-class TextField))
|
||||
(defonce textarea (r/adapt-class TextareaAutosize))
|
||||
(defonce tooltip (r/adapt-class Tooltip))
|
||||
(defonce dialog (r/adapt-class Dialog))
|
||||
(defonce dialog-title (r/adapt-class DialogTitle))
|
||||
(defonce dialog-content (r/adapt-class DialogContent))
|
||||
(defonce dialog-actions (r/adapt-class DialogActions))
|
||||
(defonce menu-icon (r/adapt-class MenuIcon))
|
||||
(defonce drawer (r/adapt-class SwipeableDrawer))
|
||||
(defonce chip (r/adapt-class Chip))
|
||||
(defonce list (r/adapt-class List))
|
||||
(defonce list-item (r/adapt-class ListItem))
|
||||
(defonce list-item-text (r/adapt-class ListItemText))
|
||||
|
||||
;; card
|
||||
(defonce card (r/adapt-class Card))
|
||||
(defonce card-actions (r/adapt-class CardActions))
|
||||
(defonce card-content (r/adapt-class CardContent))
|
||||
(defonce card-actions (r/adapt-class CardActions))
|
||||
(defonce card-header (r/adapt-class CardHeader))
|
||||
(defonce card-media (r/adapt-class CardMedia))
|
|
@ -1,15 +1,11 @@
|
|||
(ns frontend.page
|
||||
(:require [rum.core :as rum]
|
||||
[frontend.layout :as layout]
|
||||
[frontend.routes :as routes]
|
||||
[frontend.state :as state]
|
||||
[frontend.components.sidebar :as sidebar]))
|
||||
(:require [uix.core.alpha :as uix]
|
||||
[frontend.state :as state]))
|
||||
|
||||
(rum/defc current-page < rum/reactive
|
||||
(defn current-page
|
||||
[]
|
||||
(let [state (rum/react state/state)
|
||||
current-page (get state :current-page :home)]
|
||||
(sidebar/sidebar)
|
||||
;; (when-let [view (get routes/routes current-page)]
|
||||
;; (layout/frame (view) (:width state)))
|
||||
))
|
||||
(let [route-match @(uix/state (:route-match @state/state))]
|
||||
(prn "route-match: " route-match)
|
||||
(if route-match
|
||||
(when-let [view (:view (:data route-match))]
|
||||
(view route-match)))))
|
||||
|
|
|
@ -1,10 +1,19 @@
|
|||
(ns frontend.routes
|
||||
(:require [frontend.components.home :as home]
|
||||
[frontend.components.settings :as settings]
|
||||
[frontend.components.file :as file]
|
||||
))
|
||||
[frontend.components.sidebar :as sidebar]))
|
||||
|
||||
(def routes
|
||||
{:home home/home
|
||||
:settings settings/settings
|
||||
:edit-file file/edit})
|
||||
[["/"
|
||||
{:name :home
|
||||
:view home/home
|
||||
;; :view sidebar/sidebar
|
||||
}]
|
||||
|
||||
;; TODO: edit file
|
||||
;; Settings
|
||||
;; ["/item/:id"
|
||||
;; {:name ::item
|
||||
;; :view item-page
|
||||
;; :parameters {:path {:id int?}
|
||||
;; :query {(ds/opt :foo) keyword?}}}]
|
||||
])
|
||||
|
|
|
@ -1,59 +0,0 @@
|
|||
(ns frontend.rum
|
||||
(:require [clojure.string :as s]
|
||||
[clojure.set :as set]
|
||||
[clojure.walk :as w]))
|
||||
|
||||
;; copy from https://github.com/priornix/antizer/blob/35ba264cf48b84e6597743e28b3570d8aa473e74/src/antizer/core.cljs
|
||||
|
||||
(defn kebab-case->camel-case
|
||||
"Converts from kebab case to camel case, eg: on-click to onClick"
|
||||
[input]
|
||||
(let [words (s/split input #"-")
|
||||
capitalize (->> (rest words)
|
||||
(map #(apply str (s/upper-case (first %)) (rest %))))]
|
||||
(apply str (first words) capitalize)))
|
||||
|
||||
(defn map-keys->camel-case
|
||||
"Stringifys all the keys of a cljs hashmap and converts them
|
||||
from kebab case to camel case. If :html-props option is specified,
|
||||
then rename the html properties values to their dom equivalent
|
||||
before conversion"
|
||||
[data & {:keys [html-props]}]
|
||||
(let [convert-to-camel (fn [[key value]]
|
||||
[(kebab-case->camel-case (name key)) value])]
|
||||
(w/postwalk (fn [x]
|
||||
(if (map? x)
|
||||
(let [new-map (if html-props
|
||||
(set/rename-keys x {:class :className :for :htmlFor})
|
||||
x)]
|
||||
(into {} (map convert-to-camel new-map)))
|
||||
x))
|
||||
data)))
|
||||
|
||||
;; adapted from https://github.com/tonsky/rum/issues/20
|
||||
(defn adapt-class [react-class]
|
||||
(fn [& args]
|
||||
(let [[opts children] (if (map? (first args))
|
||||
[(first args) (rest args)]
|
||||
[{} args])
|
||||
type# (first children)
|
||||
;; we have to make sure to check if the children is sequential
|
||||
;; as a list can be returned, eg: from a (for)
|
||||
new-children (if (sequential? type#)
|
||||
(let [result (sablono.interpreter/interpret children)]
|
||||
(if (sequential? result)
|
||||
result
|
||||
[result]))
|
||||
children)
|
||||
;; convert any options key value to a react element, if
|
||||
;; a valid html element tag is used, using sablono
|
||||
vector->react-elems (fn [[key val]]
|
||||
(if (sequential? val)
|
||||
[key (sablono.interpreter/interpret val)]
|
||||
[key val]))
|
||||
new-options (into {} (map vector->react-elems opts))]
|
||||
;; (.dir js/console new-children)
|
||||
(apply js/React.createElement react-class
|
||||
;; sablono html-to-dom-attrs does not work for nested hashmaps
|
||||
(clj->js (map-keys->camel-case new-options :html-props true))
|
||||
new-children))))
|
|
@ -22,4 +22,5 @@
|
|||
:width nil
|
||||
:drawer? false
|
||||
:tasks {}
|
||||
:route-match nil
|
||||
}))
|
||||
|
|
|
@ -1,23 +1,17 @@
|
|||
(ns frontend.ui
|
||||
(:require [rum.core :as rum]
|
||||
[frontend.rum :as r]
|
||||
["react-transition-group" :refer [TransitionGroup CSSTransition]]
|
||||
(:require ["react-transition-group" :refer [CSSTransition]]
|
||||
[frontend.util :as util]
|
||||
[frontend.mixins :as mixins]))
|
||||
[frontend.hooks :as hooks]
|
||||
[uix.core.alpha :as uix]))
|
||||
|
||||
(defonce transition-group (r/adapt-class TransitionGroup))
|
||||
(defonce css-transition (r/adapt-class CSSTransition))
|
||||
(defn css-transition
|
||||
[open? timeout state-fn]
|
||||
[:> CSSTransition
|
||||
{:in open? :timeout timeout}
|
||||
(fn [state]
|
||||
(uix/as-element (state-fn state)))])
|
||||
|
||||
(defn css-transition-group
|
||||
[css-options items]
|
||||
(when (seq items)
|
||||
(transition-group
|
||||
(for [item items]
|
||||
(css-transition
|
||||
(merge {:key (cljs.core/random-uuid)} css-options)
|
||||
item)))))
|
||||
|
||||
(rum/defc dropdown-content-wrapper [state content]
|
||||
(defn dropdown-content-wrapper [state content]
|
||||
[:div.origin-top-right.absolute.right-0.mt-2.w-48.rounded-md.shadow-lg
|
||||
{:class (case state
|
||||
"entering" "transition ease-out duration-100 transform opacity-0 scale-95"
|
||||
|
@ -27,23 +21,22 @@
|
|||
content])
|
||||
|
||||
;; public exports
|
||||
(rum/defcs dropdown <
|
||||
(rum/local false ::show-dropdown?)
|
||||
(mixins/event-mixin #(mixins/simple-close-listener % ::show-dropdown?))
|
||||
[state content]
|
||||
(let [show-dropdown? (get state ::show-dropdown?)]
|
||||
[:div.ml-3.relative
|
||||
(defn dropdown
|
||||
[content]
|
||||
(let [ref (uix/ref nil)
|
||||
open? (uix/state false)]
|
||||
(hooks/setup-close-listener! ref open?)
|
||||
[:div.ml-3.relative {:ref ref}
|
||||
[:div
|
||||
[:button.max-w-xs.flex.items-center.text-sm.rounded-full.focus:outline-none.focus:shadow-outline
|
||||
{:on-click (fn []
|
||||
(swap! show-dropdown? not))}
|
||||
(swap! open? not))}
|
||||
[:img.h-8.w-8.rounded-full
|
||||
{:src
|
||||
"https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80"}]]]
|
||||
(css-transition
|
||||
{:in @show-dropdown? :timeout 0}
|
||||
(fn [state]
|
||||
(dropdown-content-wrapper state content)))]))
|
||||
(css-transition @open? 0
|
||||
(fn [state]
|
||||
(dropdown-content-wrapper state content)))]))
|
||||
|
||||
(defn dropdown-with-links
|
||||
[links]
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
(ns frontend.util
|
||||
(:require [goog.object :as gobj]
|
||||
[promesa.core :as p]
|
||||
[clojure.walk :as walk]))
|
||||
[clojure.walk :as walk]
|
||||
[clojure.string :as string]))
|
||||
|
||||
(defn evalue
|
||||
[event]
|
||||
|
@ -92,3 +93,10 @@
|
|||
(->> (map (fn [entry] [(get entry k) entry])
|
||||
col)
|
||||
(into {})))
|
||||
|
||||
;; ".lg:absolute.lg:inset-y-0.lg:right-0.lg:w-1/2"
|
||||
(defn hiccup->class
|
||||
[class]
|
||||
(some->> (string/split class #"\.")
|
||||
(string/join " ")
|
||||
(string/trim)))
|
||||
|
|
Loading…
Reference in New Issue