浏览代码

Better org display

Tienson Qin 5 年之前
父节点
当前提交
61829ecd88

+ 1 - 1
.gitignore

@@ -1,5 +1,5 @@
 node_modules/
 node_modules/
-public/js
+public/static/js
 
 
 /.cpcache
 /.cpcache
 /target
 /target

+ 4 - 3
now.json

@@ -12,8 +12,9 @@
     { "src": "/public/**", "use": "@now/static"}
     { "src": "/public/**", "use": "@now/static"}
   ],
   ],
   "routes": [
   "routes": [
-    { "src": "/api(.*)", "dest": "api/index.js" },
-    { "src": "/(.+js|.+css|.+png|.+svg|.+jpg|.+ico|robots.txt|.+map)", "dest": "/public/$1" },
-    { "src": "/(.*)", "dest": "/public/index.html" }
+      { "src": "/api(.*)", "dest": "api/index.js" },
+      { "src": "/static/(.*)", "dest": "/public/static/$1" },
+      { "src": "/(.+js|.+css|.+png|.+svg|.+jpg|.+ico|robots.txt|.+map)", "dest": "/public/$1" },
+      { "src": "/(.*)", "dest": "/public/index.html" }
   ]
   ]
 }
 }

+ 3 - 3
web/.gitignore

@@ -1,7 +1,7 @@
 node_modules/
 node_modules/
-public/js/cljs-runtime
-public/js/main.js
-public/js/manifest.edn
+public/static/js/cljs-runtime
+public/static/js/main.js
+public/static/js/manifest.edn
 
 
 /.cpcache
 /.cpcache
 /target
 /target

+ 2 - 4
web/package.json

@@ -9,15 +9,13 @@
     "watch": "npx shadow-cljs watch app",
     "watch": "npx shadow-cljs watch app",
     "release": "npx shadow-cljs release app",
     "release": "npx shadow-cljs release app",
     "server": "npx shadow-cljs server;",
     "server": "npx shadow-cljs server;",
-    "clean": "rm -rf target; rm -rf public/js/compiled; rm -rf public/js/cljs-runtime"
+    "clean": "rm -rf target; rm -rf public/static/js/compiled; rm -rf public/static/js/cljs-runtime"
   },
   },
   "dependencies": {
   "dependencies": {
-    "@material-ui/core": "^4.7.2",
-    "@material-ui/icons": "^4.5.1",
     "browserfs": "^1.4.3",
     "browserfs": "^1.4.3",
     "dev": "^0.1.3",
     "dev": "^0.1.3",
     "isomorphic-git": "^1.1.2",
     "isomorphic-git": "^1.1.2",
-    "mldoc_org": "^0.1.8",
+    "mldoc_org": "^0.2.0",
     "purgecss": "^2.1.0",
     "purgecss": "^2.1.0",
     "react": "^16.12.0",
     "react": "^16.12.0",
     "react-dom": "^16.12.0",
     "react-dom": "^16.12.0",

+ 6 - 6
web/public/index.html

@@ -3,11 +3,11 @@
   <head>
   <head>
     <meta charset="utf-8">
     <meta charset="utf-8">
     <meta content="minimum-scale=1, initial-scale=1, width=device-width, shrink-to-fit=no" name="viewport">
     <meta content="minimum-scale=1, initial-scale=1, width=device-width, shrink-to-fit=no" name="viewport">
-    <link href="/css/tailwind.min.css" rel="stylesheet" type="text/css">
-    <link href="/css/org.css" rel="stylesheet">
-    <link href="/css/style.css" rel="stylesheet" type="text/css">
+    <link href="/static/css/tailwind.min.css" rel="stylesheet" type="text/css">
+    <link href="/static/css/org.css" rel="stylesheet">
+    <link href="/static/css/style.css" rel="stylesheet" type="text/css">
     <link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&amp;display=swap" rel="stylesheet">
     <link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&amp;display=swap" rel="stylesheet">
-    <link href="/css/highlight.css" rel="stylesheet">
+    <link href="/static/css/highlight.css" rel="stylesheet">
     <title>Gitnotes</title>
     <title>Gitnotes</title>
   </head>
   </head>
   <body>
   <body>
@@ -20,7 +20,7 @@
       git.plugins.set('fs', window.fs);
       git.plugins.set('fs', window.fs);
       window.pfs = window.fs.promises;
       window.pfs = window.fs.promises;
     </script>
     </script>
-    <script src="/js/main.js"></script>
-    <script src="/js/highlight.pack.js"></script>
+    <script src="/static/js/main.js"></script>
+    <script src="/static/js/highlight.pack.js"></script>
   </body>
   </body>
 </html>
 </html>

+ 0 - 0
web/public/css/highlight.css → web/public/static/css/highlight.css


+ 0 - 0
web/public/css/org.css → web/public/static/css/org.css


+ 2 - 5
web/public/css/style.css → web/public/static/css/style.css

@@ -30,13 +30,10 @@
             font-size: medium;
             font-size: medium;
             font-weight: bold;
             font-weight: bold;
             margin-top:0; }
             margin-top:0; }
-.todo   { font-family: monospace; color: red; }
-.done   { font-family: monospace; color: green; }
-.priority { font-family: monospace; color: orange; }
 .tag    { background-color: #eee; font-family: monospace;
 .tag    { background-color: #eee; font-family: monospace;
           padding: 2px; font-size: 80%; font-weight: normal; }
           padding: 2px; font-size: 80%; font-weight: normal; }
-.timestamp { color: #bebebe; }
-.timestamp-kwd { color: #5f9ea0; }
+.timestamp { color: #bebebe; margin-left: 6px; }
+.timestamp-kwd { color: #5f9ea0; margin-left: 6px; }
 .org-right  { margin-left: auto; margin-right: 0px;  text-align: right; }
 .org-right  { margin-left: auto; margin-right: 0px;  text-align: right; }
 .org-left   { margin-left: 0px;  margin-right: auto; text-align: left; }
 .org-left   { margin-left: 0px;  margin-right: auto; text-align: left; }
 .org-center { margin-left: auto; margin-right: auto; text-align: center; }
 .org-center { margin-left: auto; margin-right: auto; text-align: center; }

+ 0 - 0
web/public/css/tailwind.min.css → web/public/static/css/tailwind.min.css


+ 0 - 0
web/public/img/angled-background.svg → web/public/static/img/angled-background.svg


+ 0 - 0
web/public/img/hero-pattern-lg.png → web/public/static/img/hero-pattern-lg.png


+ 0 - 0
web/public/js/highlight.pack.js → web/public/static/js/highlight.pack.js


文件差异内容过多而无法显示
+ 0 - 0
web/public/static/js/manifest.edn


+ 5 - 2
web/shadow-cljs.edn

@@ -20,13 +20,16 @@
   {:target :browser
   {:target :browser
    :modules {:main {:init-fn frontend.core/init}}
    :modules {:main {:init-fn frontend.core/init}}
 
 
+   :output-dir "public/static/js"
+   :asset-path "/static/js"
+
    :compiler-options {:infer-externs :auto
    :compiler-options {:infer-externs :auto
                       :externs ["datascript/externs.js"]}
                       :externs ["datascript/externs.js"]}
    ;; TODO: purge-css not working properly
    ;; TODO: purge-css not working properly
    ;; :build-hooks [(shadow.hooks/purge-css
    ;; :build-hooks [(shadow.hooks/purge-css
    ;;                {:css-source "node_modules/tailwindcss/dist/tailwind.min.css"
    ;;                {:css-source "node_modules/tailwindcss/dist/tailwind.min.css"
-   ;;                 :js-globs   ["public/js/*.js"]
-   ;;                 :public-dir    "public/css"})]
+   ;;                 :js-globs   ["public/static/js/*.js"]
+   ;;                 :public-dir    "public/static/css"})]
    :devtools
    :devtools
    ;; before live-reloading any code call this function
    ;; before live-reloading any code call this function
    {:before-load frontend.core/stop
    {:before-load frontend.core/stop

+ 3 - 4
web/src/frontend/components/file.cljs

@@ -31,9 +31,9 @@
     (sidebar/sidebar
     (sidebar/sidebar
      (if (and suffix (contains? #{"md" "markdown" "org"} suffix))
      (if (and suffix (contains? #{"md" "markdown" "org"} suffix))
        [:div#content.flex.justify-center
        [:div#content.flex.justify-center
-        [:div.m-6.flex-1 {:style {:max-width 900}}
-         [:a {:style {:float "right"}
-              :href (str "/file/" encoded-path "/edit")}
+        [:div.m-6.flex-1 {:style {:position "relative"
+                                  :max-width 800}}
+         [:a {:href (str "/file/" encoded-path "/edit")}
           "edit"]
           "edit"]
          (if content
          (if content
            (util/raw-html (format/to-html content suffix))
            (util/raw-html (format/to-html content suffix))
@@ -75,5 +75,4 @@
                              (let [commit-message (if (string/blank? @commit-message)
                              (let [commit-message (if (string/blank? @commit-message)
                                                     (str "Update " path)
                                                     (str "Update " path)
                                                     @commit-message)]
                                                     @commit-message)]
-                               (prn "commit!")
                                (handler/alter-file path commit-message @content)))))]])))
                                (handler/alter-file path commit-message @content)))))]])))

+ 2 - 3
web/src/frontend/components/repo.cljs

@@ -14,7 +14,6 @@
         (for [url repos]
         (for [url repos]
           [:li {:key url}
           [:li {:key url}
            [:button {:on-click (fn []
            [:button {:on-click (fn []
-                                 (prn "set current repo: " url)
                                  ;; (handler/set-current-repo url)
                                  ;; (handler/set-current-repo url)
                                  )}
                                  )}
             (string/replace url "https://github.com/" "")]])]])))
             (string/replace url "https://github.com/" "")]])]])))
@@ -27,8 +26,8 @@
       [:div
       [:div
        [:label.block.text-sm.font-medium.leading-5.text-gray-700
        [:label.block.text-sm.font-medium.leading-5.text-gray-700
         {:for "Repo"}
         {:for "Repo"}
-        "Repo"]
-       [:div.mt-1.relative.rounded-md.shadow-sm
+        "Specify your repo: "]
+       [:div.mt-2.mb-2.relative.rounded-md.shadow-sm
         [:input.form-input.block.w-full.sm:text-sm.sm:leading-5
         [:input.form-input.block.w-full.sm:text-sm.sm:leading-5
          {:auto-focus true
          {:auto-focus true
           :placeholder "https://github.com/yourname/repo"
           :placeholder "https://github.com/yourname/repo"

+ 4 - 10
web/src/frontend/components/sidebar.cljs

@@ -46,13 +46,7 @@
              true)
              true)
    (nav-item "Agenda" "#"
    (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")
              "M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z")
-   (nav-item "Budgets" "#"
-             "M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z")
-   (nav-item "Files" "#"
-             "M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z")
-
-   (files-list)
-   ])
+   (files-list)])
 
 
 (rum/defq main-content <
 (rum/defq main-content <
   {:q (fn [_state] (db/sub-repos))}
   {:q (fn [_state] (db/sub-repos))}
@@ -152,6 +146,6 @@
        main-content
        main-content
        [:div.max-w-7xl.mx-auto.px-4.sm:px-6.md:px-8
        [:div.max-w-7xl.mx-auto.px-4.sm:px-6.md:px-8
         [:div.py-4
         [: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]]]]
+
+      (ui/notification)]]))

+ 35 - 17
web/src/frontend/db.cljs

@@ -7,6 +7,7 @@
 
 
 ;; TODO: don't persistent :github/token
 ;; TODO: don't persistent :github/token
 
 
+(def datascript-db "gitnotes/DB")
 (def schema
 (def schema
   {:db/ident        {:db/unique :db.unique/identity}
   {:db/ident        {:db/unique :db.unique/identity}
    :github/token    {}
    :github/token    {}
@@ -27,7 +28,7 @@
    ;; heading
    ;; heading
    :heading/uuid   {:db/unique      :db.unique/identity}
    :heading/uuid   {:db/unique      :db.unique/identity}
    :heading/repo   {:db/valueType   :db.type/ref}
    :heading/repo   {:db/valueType   :db.type/ref}
-   :heading/file   {}
+   :heading/file   {:db/valueType   :db.type/ref}
    :heading/anchor {}
    :heading/anchor {}
    :heading/marker {}
    :heading/marker {}
    :heading/priority {}
    :heading/priority {}
@@ -59,8 +60,7 @@
 
 
 ;; persisting DB between page reloads
 ;; persisting DB between page reloads
 (defn persist [db]
 (defn persist [db]
-  (prn "DB size: " (count (db->string db)))
-  (js/localStorage.setItem "gitnotes/DB" (db->string db)))
+  (js/localStorage.setItem datascript-db (db->string db)))
 
 
 (defn reset-conn! [db]
 (defn reset-conn! [db]
   (reset! conn db)
   (reset! conn db)
@@ -73,8 +73,15 @@
              (when-let [db (:db-after tx-report)]
              (when-let [db (:db-after tx-report)]
                (js/setTimeout #(persist db) 0))))
                (js/setTimeout #(persist db) 0))))
 
 
+;; (new TextEncoder().encode('foo')).length
+(defn db-size
+  []
+  (when-let [store (js/localStorage.getItem datascript-db)]
+    (let [bytes (.-length (.encode (js/TextEncoder.) store))]
+      (/ bytes 1000))))
+
 (defn restore! []
 (defn restore! []
-  (when-let [stored (js/localStorage.getItem "gitnotes/DB")]
+  (when-let [stored (js/localStorage.getItem datascript-db)]
    (let [stored-db (string->db stored)]
    (let [stored-db (string->db stored)]
      (when (= (:schema stored-db) schema) ;; check for code update
      (when (= (:schema stored-db) schema) ;; check for code update
        (reset-conn! stored-db)))))
        (reset-conn! stored-db)))))
@@ -132,16 +139,6 @@
              heading)))
              heading)))
         headings))
         headings))
 
 
-(defn delete-headings!
-  []
-  )
-
-;; transactions
-(defn reset-headings!
-  [headings]
-  (let [headings (safe-headings headings)]
-    (d/transact! conn headings)))
-
 ;; queries
 ;; queries
 
 
 (defn- distinct-result
 (defn- distinct-result
@@ -161,6 +158,29 @@
           [?h :heading/tags ?tags]]
           [?h :heading/tags ?tags]]
      @conn)))
      @conn)))
 
 
+(defn get-repo-headings
+  [repo-url]
+  (-> (d/q '[:find ?heading
+          :in $ ?repo-url
+          :where
+          [?repo :repo/url ?repo-url]
+          [?heading :heading/repo ?repo]]
+        @conn repo-url)
+      seq-flatten))
+
+(defn delete-headings!
+  [repo-url]
+  (let [headings (get-repo-headings repo-url)
+        headings (mapv (fn [eid] [:db.fn/retractEntity eid]) headings)]
+    (d/transact! conn headings)))
+
+;; transactions
+(defn reset-headings!
+  [repo-url headings]
+  (delete-headings! repo-url)
+  (let [headings (safe-headings headings)]
+    (d/transact! conn headings)))
+
 (defn get-all-headings
 (defn get-all-headings
   []
   []
   (seq-flatten
   (seq-flatten
@@ -365,6 +385,4 @@
                      :heading/marker "TODO"
                      :heading/marker "TODO"
                      :heading/priority "A"
                      :heading/priority "A"
                      :heading/level "10"
                      :heading/level "10"
-                     :heading/title "hello world"}
-                    ]))
-  )
+                     :heading/title "hello world"}])))

+ 5 - 14
web/src/frontend/format/org_mode.cljs

@@ -5,25 +5,16 @@
 (defrecord OrgMode [content]
 (defrecord OrgMode [content]
   protocol/Format
   protocol/Format
   (toHtml [this]
   (toHtml [this]
-    (.parseHtml (.-MldocOrg org) content)))
+    (.parseHtml (.-MldocOrg org)
+                content
+                (js/JSON.stringify
+                 #js {:toc false
+                      :heading_number false}))))
 
 
 (defn parse-json
 (defn parse-json
   [content]
   [content]
   (.parseJson (.-MldocOrg org) content))
   (.parseJson (.-MldocOrg org) content))
 
 
-(defn json->ast
-  [json]
-  (.jsonToAst (.-MldocOrg org) json))
-
-(defn json->html
-  [json]
-  (.jsonToHtmlStr (.-MldocOrg org) json))
-
 (defn inline-list->html
 (defn inline-list->html
   [json]
   [json]
   (.inlineListToHtmlStr (.-MldocOrg org) json))
   (.inlineListToHtmlStr (.-MldocOrg org) json))
-
-(comment
-  (let [text "*** TODO /*great*/ [[https://personal.utdallas.edu/~gupta/courses/acl/papers/datalog-paper.pdf][What You Always Wanted to Know About Datalog]] :datalog:"
-        blocks-json (parse-json text)]
-    (json->html blocks-json)))

+ 15 - 14
web/src/frontend/handler.cljs

@@ -66,7 +66,7 @@
   (when-let [token (db/get-github-token)]
   (when-let [token (db/get-github-token)]
     (pull repo-url token)
     (pull repo-url token)
     (js/setInterval #(pull repo-url token)
     (js/setInterval #(pull repo-url token)
-                    (* 10 1000))))
+                    (* 60 1000))))
 
 
 (defn add-transaction
 (defn add-transaction
   [tx]
   [tx]
@@ -107,7 +107,6 @@
   (let [token (db/get-github-token)]
   (let [token (db/get-github-token)]
     (util/p-handle
     (util/p-handle
      (do
      (do
-       (prn "Debug: cloning " repo)
        (db/set-repo-cloning repo true)
        (db/set-repo-cloning repo true)
        (git/clone repo token))
        (git/clone repo token))
      (fn []
      (fn []
@@ -162,15 +161,20 @@
       (notify-fn)
       (notify-fn)
       (js/setInterval notify-fn (* 1000 60)))))
       (js/setInterval notify-fn (* 1000 60)))))
 
 
+(defn show-notification!
+  [text]
+  (swap! state/state assoc
+         :notification/show? true
+         :notification/text text)
+  (js/setTimeout #(swap! state/state assoc
+                         :notification/show? false
+                         :notification/text nil)
+                 3000))
+
 (defn alter-file
 (defn alter-file
   [path commit-message content]
   [path commit-message content]
   (let [token (db/get-github-token)
   (let [token (db/get-github-token)
         repo-url (db/get-current-repo)]
         repo-url (db/get-current-repo)]
-    (prn {:repo-url repo-url
-          :token token
-          :path path
-          :content content
-          :commit-message commit-message})
     (util/p-handle
     (util/p-handle
      (fs/write-file (git/get-repo-dir repo-url) path content)
      (fs/write-file (git/get-repo-dir repo-url) path content)
      (fn [_]
      (fn [_]
@@ -180,8 +184,7 @@
                             token
                             token
                             (fn []
                             (fn []
                               (db/set-file-content! repo-url path content)
                               (db/set-file-content! repo-url path content)
-                              ;; (show-snackbar "File updated!")
-                              )
+                              (show-notification! "File updated!"))
                             (fn [error]
                             (fn [error]
                               (prn "Failed to update file, error: " error)))))))
                               (prn "Failed to update file, error: " error)))))))
 
 
@@ -228,8 +231,8 @@
         headings (block/extract-headings headings)]
         headings (block/extract-headings headings)]
     (map (fn [heading]
     (map (fn [heading]
            (assoc heading
            (assoc heading
-                  :repo [:repo/url repo-url]
-                  :file file))
+                  :heading/repo [:repo/url repo-url]
+                  :heading/file [:file/path file]))
       headings)))
       headings)))
 
 
 (defn load-all-contents!
 (defn load-all-contents!
@@ -241,7 +244,6 @@
                               (db/set-file-content! repo-url file content)))))
                               (db/set-file-content! repo-url file content)))))
         (p/then
         (p/then
          (fn [_]
          (fn [_]
-           (prn "Files are loaded!")
            (ok-handler))))))
            (ok-handler))))))
 
 
 (defn extract-all-headings
 (defn extract-all-headings
@@ -261,7 +263,7 @@
                       (fn []
                       (fn []
                         (let [headings (extract-all-headings repo-url)]
                         (let [headings (extract-all-headings repo-url)]
                           (reset! headings-atom headings)
                           (reset! headings-atom headings)
-                          (db/reset-headings! headings)))))
+                          (db/reset-headings! repo-url headings)))))
 
 
 
 
 ;; (defn sync
 ;; (defn sync
@@ -313,7 +315,6 @@
   []
   []
   (db/restore!)
   (db/restore!)
   (when-let [first-repo (first (db/get-repos))]
   (when-let [first-repo (first (db/get-repos))]
-    (prn "first-repo: " first-repo)
     (db/set-current-repo! first-repo))
     (db/set-current-repo! first-repo))
   (let [repos (db/get-repos)]
   (let [repos (db/get-repos)]
     (doseq [repo repos]
     (doseq [repo repos]

+ 0 - 3
web/src/frontend/mixins.cljs

@@ -101,13 +101,10 @@
          (assoc state
          (assoc state
                 k open?
                 k open?
                 :close-fn (fn []
                 :close-fn (fn []
-                            (prn "close-fn on " @open?)
                             (reset! open? false))
                             (reset! open? false))
                 :open-fn (fn []
                 :open-fn (fn []
-                           (prn "open-fn on " @open?)
                            (reset! open? true))
                            (reset! open? true))
                 :toggle-fn (fn []
                 :toggle-fn (fn []
-                             (prn "toggle-fn on " @open?)
                              (swap! open? not))))))))
                              (swap! open? not))))))))
 
 
 (defn will-mount-effect
 (defn will-mount-effect

+ 2 - 0
web/src/frontend/state.cljs

@@ -4,4 +4,6 @@
 (def state (atom
 (def state (atom
             {:route-match nil
             {:route-match nil
              :tasks {}
              :tasks {}
+             :notification/show? false
+             :notification/text nil
              }))
              }))

+ 45 - 1
web/src/frontend/ui.cljs

@@ -3,7 +3,8 @@
             [frontend.rum :as r]
             [frontend.rum :as r]
             ["react-transition-group" :refer [TransitionGroup CSSTransition]]
             ["react-transition-group" :refer [TransitionGroup CSSTransition]]
             [frontend.util :as util]
             [frontend.util :as util]
-            [frontend.mixins :as mixins]))
+            [frontend.mixins :as mixins]
+            [frontend.state :as state]))
 
 
 (defonce transition-group (r/adapt-class TransitionGroup))
 (defonce transition-group (r/adapt-class TransitionGroup))
 (defonce css-transition (r/adapt-class CSSTransition))
 (defonce css-transition (r/adapt-class CSSTransition))
@@ -49,3 +50,46 @@
    {:type "button"
    {:type "button"
     :on-click on-click}
     :on-click on-click}
    text])
    text])
+
+(rum/defc notification-content
+  [state text]
+  [:div.fixed.inset-0.flex.items-end.justify-center.px-4.py-6.pointer-events-none.sm:p-6.sm:items-start.sm:justify-end
+   [:div.max-w-sm.w-full.bg-white.shadow-lg.rounded-lg.pointer-events-auto
+    {:class (case state
+              "entering" "transition ease-out duration-300 transform opacity-0 translate-y-2 sm:translate-x-0"
+              "entered" "transition ease-out duration-300 transform translate-y-0 opacity-100 sm:translate-x-0"
+              "exiting" "transition ease-in duration-100 opacity-100"
+              "exited" "transition ease-in duration-100 opacity-0")}
+    [:div.rounded-lg.shadow-xs.overflow-hidden
+     [:div.p-4
+      [:div.flex.items-start
+       [:div.flex-shrink-0
+        [:svg.h-6.w-6.text-green-400
+         {:stroke "currentColor", :viewbox "0 0 24 24", :fill "none"}
+         [:path
+          {:d "M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z",
+           :stroke-width "2",
+           :stroke-linejoin "round",
+           :stroke-linecap "round"}]]]
+       [:div.ml-3.w-0.flex-1.pt-0.5
+        [:p.text-sm.leading-5.font-medium.text-gray-900
+         text]]
+       [:div.ml-4.flex-shrink-0.flex
+        [:button.inline-flex.text-gray-400.focus:outline-none.focus:text-gray-500.transition.ease-in-out.duration-150
+         {:on-click (fn []
+                      (swap! state/state assoc :notification/show? false))}
+         [:svg.h-5.w-5
+          {:fill "currentColor", :viewbox "0 0 20 20"}
+          [:path
+           {:clip-rule "evenodd",
+            :d
+            "M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z",
+            :fill-rule "evenodd"}]]]]]]]]])
+
+(rum/defc notification < rum/reactive
+  []
+  (let [{:keys [:notification/show? :notification/text]} (rum/react state/state)]
+    (css-transition
+     {:in show? :timeout 100}
+     (fn [state]
+       (notification-content state text)))))

+ 4 - 4
web/yarn.lock

@@ -1126,10 +1126,10 @@ mkdirp@^0.5.1:
   dependencies:
   dependencies:
     minimist "0.0.8"
     minimist "0.0.8"
 
 
-mldoc_org@^0.1.8:
-  version "0.1.8"
-  resolved "https://registry.yarnpkg.com/mldoc_org/-/mldoc_org-0.1.8.tgz#f3241a308a11319d948a20ae5e6401c375301b6c"
-  integrity sha512-xaV4pbCV6eumQ4tS/TD40EnsGKN8tZhfKk0llxO+TcNaVEdLAIoilUyJJMiCRwq8esJlMjq53v+ULlC3cQeU6w==
+mldoc_org@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/mldoc_org/-/mldoc_org-0.2.0.tgz#b9643333939dbddf6b38e76ec130c4b2cc72d6ab"
+  integrity sha512-s5QuzNWRX8XuAV6ymrBB43qwqvxjsCfUZX6/3AuCJ/dka3+jPxcQVjjOfueTFdzbQdPOBMxAhutV+AX9oQnv1A==
   dependencies:
   dependencies:
     yargs "^12.0.2"
     yargs "^12.0.2"
 
 

部分文件因为文件数量过多而无法显示