🕐 adds recent opened files screen

This commit is contained in:
alonso.torres 2020-03-12 13:26:58 +01:00 committed by Andrey Antukh
parent 1ffca33be9
commit 561560ae04
20 changed files with 437 additions and 250 deletions

View file

@ -74,6 +74,7 @@
(def ungroup (icon-xref :ungroup))
(def unlock (icon-xref :unlock))
(def user (icon-xref :user))
(def recent (icon-xref :recent))
(def loader-pencil
(html

View file

@ -57,9 +57,10 @@
(declare fetch-files)
(declare fetch-projects)
(declare fetch-recent-files)
(def initialize-drafts
(ptk/reify ::initialize
(ptk/reify ::initialize-drafts
ptk/UpdateEvent
(update [_ state]
(let [profile (:profile state)]
@ -77,7 +78,7 @@
(defn initialize-team
[team-id]
(us/verify ::us/uuid team-id)
(ptk/reify ::initialize
(ptk/reify ::initialize-team
ptk/UpdateEvent
(update [_ state]
(update state :dashboard-local assoc
@ -87,14 +88,15 @@
ptk/WatchEvent
(watch [_ state stream]
(let [local (:dashboard-local state)]
(rx/of (fetch-projects (:team-id local)))))))
(rx/of (fetch-projects (:team-id local))
(fetch-recent-files (:team-id local)))))))
(defn initialize-project
[team-id project-id]
(us/verify ::us/uuid team-id)
(us/verify ::us/uuid project-id)
(ptk/reify ::initialize
(ptk/reify ::initialize-project
ptk/UpdateEvent
(update [_ state]
(update state :dashboard-local assoc
@ -156,6 +158,26 @@
files (d/index-by :id files)]
(assoc state :files files)))))
;; --- Fetch recent files
(declare recent-files-fetched)
(defn fetch-recent-files
[team-id]
(ptk/reify ::fetch-recent-files
ptk/WatchEvent
(watch [_ state stream]
(let [params {:team-id team-id}]
(->> (rp/query :recent-files params)
(rx/map recent-files-fetched))))))
(defn recent-files-fetched
[recent-files]
(ptk/reify ::recent-files-fetched
ptk/UpdateEvent
(update [_ state]
(assoc state :recent-files recent-files))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Data Modification
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -239,12 +261,12 @@
(declare file-created)
(def create-file
(defn create-file
[project-id]
(ptk/reify ::create-draft-file
ptk/WatchEvent
(watch [_ state stream]
(let [name (str "New File " (gensym "p"))
project-id (get-in state [:dashboard-local :project-id])
params {:name name :project-id project-id}]
(->> (rp/mutation! :create-file params)
(rx/map file-created))))))
@ -255,7 +277,9 @@
(ptk/reify ::create-draft-file
ptk/UpdateEvent
(update [this state]
(update state :files assoc (:id data) data))))
(-> state
(update :files assoc (:id data) data)
(update :recent-files update (:project-id data) conj data)))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

View file

@ -25,7 +25,7 @@
{:x 0 :y 0
:width "100%"
:height "100%"
:fill "#b1b2b5"}])
:fill "#AFB2BF"}])
(defn- calculate-dimensions
[data]

View file

@ -19,11 +19,11 @@
[uxbox.main.ui.dashboard.header :refer [header]]
[uxbox.main.ui.dashboard.sidebar :refer [sidebar]]
[uxbox.main.ui.dashboard.project :refer [project-page]]
[uxbox.main.ui.dashboard.team :refer [team-page]]
[uxbox.main.ui.dashboard.recent-files :refer [recent-files-page]]
[uxbox.main.ui.dashboard.profile :refer [profile-section]]
[uxbox.main.ui.messages :refer [messages-widget]]))
(defn- ^boolean uuid-str?
(defn ^boolean uuid-str?
[s]
(and (string? s)
(boolean (re-seq us/uuid-rx s))))
@ -64,7 +64,7 @@
[:& header]
(case section
:dashboard-team
(mf/element team-page #js {:team-id team-id})
(mf/element recent-files-page #js {:team-id team-id})
:dashboard-project
(mf/element project-page #js {:team-id team-id

View file

@ -0,0 +1,127 @@
(ns uxbox.main.ui.dashboard.grid
(:refer-clojure :exclude [sort-by])
(:require
[cuerdas.core :as str]
[rumext.alpha :as mf]
[uxbox.builtins.icons :as i]
[uxbox.main.data.projects :as udp]
[uxbox.main.data.dashboard :as dsh]
[uxbox.main.store :as st]
[uxbox.main.exports :as exports]
[uxbox.main.ui.modal :as modal]
[uxbox.main.ui.keyboard :as kbd]
[uxbox.main.ui.confirm :refer [confirm-dialog]]
[uxbox.util.dom :as dom]
[uxbox.util.i18n :as i18n :refer [t tr]]
[uxbox.util.time :as dt]))
;; --- Helpers
(defn sort-by
[ordering files]
(case ordering
:name (cljs.core/sort-by :name files)
:created (reverse (cljs.core/sort-by :created-at files))
:modified (reverse (cljs.core/sort-by :modified-at files))
files))
(defn contains-term?
[phrase term]
(let [term (name term)]
(str/includes? (str/lower phrase) (str/trim (str/lower term)))))
(defn filter-by
[term files]
(if (str/blank? term)
files
(filter #(contains-term? (:name %) term) files)))
;; --- Grid Item Thumbnail
(mf/defc grid-item-thumbnail
[{:keys [file] :as props}]
[:div.grid-item-th
[:& exports/page-svg {:data (:data file)
:width "290"
:height "150"}]])
;; --- Grid Item
(mf/defc grid-item-metadata
[{:keys [modified-at]}]
(let [locale (i18n/use-locale)
time (dt/timeago modified-at {:locale locale})]
(str (t locale "ds.updated-at" time))))
(mf/defc grid-item
{:wrap [mf/wrap-memo]}
[{:keys [file] :as props}]
(let [local (mf/use-state {})
on-navigate #(st/emit! (udp/go-to (:id file)))
delete-fn #(st/emit! nil (udp/delete-file (:id file)))
on-delete #(do
(dom/stop-propagation %)
(modal/show! confirm-dialog {:on-accept delete-fn}))
on-blur #(let [name (-> % dom/get-target dom/get-value)]
(st/emit! (udp/rename-file (:id file) name))
(swap! local assoc :edition false))
on-key-down #(when (kbd/enter? %) (on-blur %))
on-edit #(do
(dom/stop-propagation %)
(dom/prevent-default %)
(swap! local assoc :edition true))]
[:div.grid-item.project-th {:on-click on-navigate}
[:div.overlay]
[:& grid-item-thumbnail {:file file}]
[:div.item-info
(if (:edition @local)
[:input.element-name {:type "text"
:auto-focus true
:on-key-down on-key-down
:on-blur on-blur
;; :on-click on-edit
:default-value (:name file)}]
[:h3 (:name file)])
[:& grid-item-metadata {:modified-at (:modified-at file)}]]
[:div.project-th-actions
;; [:div.project-th-icon.pages
;; i/page
;; #_[:span (:total-pages project)]]
;; [:div.project-th-icon.comments
;; i/chat
;; [:span "0"]]
[:div.project-th-icon.edit
{:on-click on-edit}
i/pencil]
[:div.project-th-icon.delete
{:on-click on-delete}
i/trash]]]))
;; --- Grid
(mf/defc grid
[{:keys [id opts files hide-new?] :as props}]
(let [locale (i18n/use-locale)
order (:order opts :modified)
filter (:filter opts "")
files (->> files
(filter-by filter)
(sort-by order))
on-click #(do
(dom/prevent-default %)
(st/emit! (dsh/create-file id)))]
[:section.dashboard-grid
[:div.dashboard-grid-content
(if (> (count files) 0)
[:div.dashboard-grid-row
(when (not hide-new?)
[:div.grid-item.add-file {:on-click on-click}
[:span (tr "ds.new-file")]])
(for [item files]
[:& grid-item {:file item :key (:id item)}])]
[:div.grid-files-empty
[:div.grid-files-desc (t locale "dashboard.grid.empty-files")]
[:div.grid-files-link
[:a.grid-files-link-text {:on-click on-click} (t locale "ds.new-file")]]])]]))

View file

@ -11,154 +11,24 @@
(ns uxbox.main.ui.dashboard.project
(:refer-clojure :exclude [sort-by])
(:require
[cuerdas.core :as str]
[lentes.core :as l]
[rumext.alpha :as mf]
[uxbox.builtins.icons :as i]
[uxbox.main.constants :as c]
[uxbox.main.data.projects :as udp]
[uxbox.main.data.dashboard :as dsh]
[uxbox.main.store :as st]
[uxbox.main.exports :as exports]
[uxbox.main.refs :as refs]
[uxbox.main.ui.modal :as modal]
[uxbox.main.ui.keyboard :as kbd]
[uxbox.main.ui.confirm :refer [confirm-dialog]]
[uxbox.main.ui.dashboard.header :refer [header]]
[uxbox.main.ui.dashboard.sidebar :refer [sidebar]]
[uxbox.main.ui.messages :refer [messages-widget]]
[uxbox.util.dom :as dom]
[uxbox.util.i18n :as i18n :refer [t tr]]
[uxbox.util.router :as rt]
[uxbox.util.time :as dt]))
;; --- Helpers
(defn sort-by
[ordering files]
(case ordering
:name (cljs.core/sort-by :name files)
:created (reverse (cljs.core/sort-by :created-at files))
:modified (reverse (cljs.core/sort-by :modified-at files))
files))
(defn contains-term?
[phrase term]
(let [term (name term)]
(str/includes? (str/lower phrase) (str/trim (str/lower term)))))
(defn filter-by
[term files]
(if (str/blank? term)
files
(filter #(contains-term? (:name %) term) files)))
;; --- Grid Item Thumbnail
(mf/defc grid-item-thumbnail
[{:keys [file] :as props}]
[:div.grid-item-th
[:& exports/page-svg {:data (:data file)
:width "290"
:height "150"}]])
;; --- Grid Item
(mf/defc grid-item-metadata
[{:keys [modified-at]}]
(let [locale (i18n/use-locale)
time (dt/timeago modified-at {:locale locale})]
(str (t locale "ds.updated-at" time))))
(mf/defc grid-item
{:wrap [mf/wrap-memo]}
[{:keys [file] :as props}]
(let [local (mf/use-state {})
on-navigate #(st/emit! (udp/go-to (:id file)))
delete-fn #(st/emit! nil (udp/delete-file (:id file)))
on-delete #(do
(dom/stop-propagation %)
(modal/show! confirm-dialog {:on-accept delete-fn}))
on-blur #(let [name (-> % dom/get-target dom/get-value)]
(st/emit! (udp/rename-file (:id file) name))
(swap! local assoc :edition false))
on-key-down #(when (kbd/enter? %) (on-blur %))
on-edit #(do
(dom/stop-propagation %)
(dom/prevent-default %)
(swap! local assoc :edition true))]
[:div.grid-item.project-th {:on-click on-navigate}
[:& grid-item-thumbnail {:file file}]
[:div.item-info
(if (:edition @local)
[:input.element-name {:type "text"
:auto-focus true
:on-key-down on-key-down
:on-blur on-blur
;; :on-click on-edit
:default-value (:name file)}]
[:h3 (:name file)])
[:& grid-item-metadata {:modified-at (:modified-at file)}]]
[:div.project-th-actions
;; [:div.project-th-icon.pages
;; i/page
;; #_[:span (:total-pages project)]]
;; [:div.project-th-icon.comments
;; i/chat
;; [:span "0"]]
[:div.project-th-icon.edit
{:on-click on-edit}
i/pencil]
[:div.project-th-icon.delete
{:on-click on-delete}
i/trash]]]))
;; --- Grid
(mf/defc grid
[{:keys [id opts files] :as props}]
(let [order (:order opts :modified)
filter (:filter opts "")
files (->> files
(filter-by filter)
(sort-by order))
on-click #(do
(dom/prevent-default %)
(st/emit! dsh/create-file))]
[:section.dashboard-grid
[:div.dashboard-grid-content
[:div.dashboard-grid-row
[:div.grid-item.add-project {:on-click on-click}
[:span (tr "ds.new-file")]]
(for [item files]
[:& grid-item {:file item :key (:id item)}])]]]))
;; --- Component: Project
[uxbox.main.ui.dashboard.grid :refer [grid]]))
(def files-ref
(-> (comp (l/key :files)
(l/lens vals))
(l/derive st/state)))
(def opts-iref
(-> (l/key :dashboard-projects)
(l/derive st/state)))
(mf/defc project-page
[{:keys [section team-id project-id] :as props}]
(let [opts (mf/deref opts-iref)
files (mf/deref files-ref)]
(let [files (mf/deref files-ref)]
(mf/use-effect
{:fn #(st/emit! (dsh/initialize-project team-id project-id))
:deps (mf/deps team-id project-id)})
[:section.dashboard-grid.library
[:& grid {:id project-id :opts opts :files files}]]))
[:section.projects-page
[:& grid { :id project-id :files files }]]))

View file

@ -0,0 +1,77 @@
;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; This Source Code Form is "Incompatible With Secondary Licenses", as
;; defined by the Mozilla Public License, v. 2.0.
;;
;; Copyright (c) 2015-2020 Andrey Antukh <niwi@niwi.nz>
;; Copyright (c) 2015-2020 Juan de la Cruz <delacruzgarciajuan@gmail.com>
(ns uxbox.main.ui.dashboard.recent-files
(:require
[lentes.core :as l]
[rumext.alpha :as mf]
[uxbox.builtins.icons :as i]
[uxbox.common.exceptions :as ex]
[uxbox.main.constants :as c]
[uxbox.main.data.projects :as udp]
[uxbox.main.data.dashboard :as dsh]
[uxbox.main.store :as st]
[uxbox.main.exports :as exports]
[uxbox.main.refs :as refs]
[uxbox.main.ui.modal :as modal]
[uxbox.main.ui.keyboard :as kbd]
[uxbox.main.ui.confirm :refer [confirm-dialog]]
[uxbox.util.dom :as dom]
[uxbox.util.i18n :as i18n :refer [t tr]]
[uxbox.util.router :as rt]
[uxbox.util.time :as dt]
[uxbox.main.ui.dashboard.grid :refer [grid]])
)
;; --- Component: Content
(def projects-ref
(-> (l/key :projects)
(l/derive st/state)))
(def recent-files-ref
(-> (l/key :recent-files)
(l/derive st/state)))
;; --- Component: Drafts Page
(mf/defc recent-files-page
[{:keys [section team-id] :as props}]
(mf/use-effect
{:fn #(st/emit! (dsh/initialize-team team-id))
:deps (mf/deps team-id)})
(let [projects (mf/deref projects-ref)
recent-files (mf/deref recent-files-ref)
locale (i18n/use-locale)]
(if projects
[:section.recent-files-page
(for [project (vals projects)]
[:div.recent-files-row
{:key (:id project)
:class-name (when (= project (first (vals projects))) "first")}
[:div.recent-files-row-title
[:h2.recent-files-row-title-name (:name project)]
[:span.recent-files-row-title-info (str (:file-count project) " files")]
(when (and recent-files (recent-files (:id project)))
(let [time (-> (project :id)
(recent-files)
(first)
:modified-at
(dt/timeago {:locale locale}))]
[:span.recent-files-row-title-info (str ", " time)]))]
[:& grid {:id (:id project)
:files (or
(and recent-files (recent-files (:id project)))
[])
:hide-new? true}]])]
[:section
[:p "empty"]])
))

View file

@ -57,12 +57,14 @@
:on-double-click on-dbl-click
:class-name (when selected? "current")}
(if (:edit @local)
[:div
[:div.edit-wrapper
[:input.element-title {:value (:name @local)
:on-change on-input
:on-key-down on-keyup}]
[:span.close {:on-click on-cancel} i/close]]
[:span.element-title name])]))
[:*
i/folder
[:span.element-title name]])]))
(def projects-iref
(-> (l/key :projects)
@ -99,8 +101,8 @@
[:li.recent-projects
{:on-click #(st/emit! (rt/nav :dashboard-team {:team-id team-id}))
:class-name (when home? "current")}
i/user
[:span.element-title (t locale "dashboard.sidebar.personal")]]
i/recent
[:span.element-title (t locale "dashboard.sidebar.recent")]]
[:li
{:on-click #(st/emit! (rt/nav :dashboard-project {:team-id team-id

View file

@ -1,51 +0,0 @@
;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; This Source Code Form is "Incompatible With Secondary Licenses", as
;; defined by the Mozilla Public License, v. 2.0.
;;
;; Copyright (c) 2015-2020 Andrey Antukh <niwi@niwi.nz>
;; Copyright (c) 2015-2020 Juan de la Cruz <delacruzgarciajuan@gmail.com>
(ns uxbox.main.ui.dashboard.team
(:require
[lentes.core :as l]
[rumext.alpha :as mf]
[uxbox.builtins.icons :as i]
[uxbox.common.exceptions :as ex]
[uxbox.main.constants :as c]
[uxbox.main.data.projects :as udp]
[uxbox.main.data.dashboard :as dsh]
[uxbox.main.store :as st]
[uxbox.main.exports :as exports]
[uxbox.main.refs :as refs]
[uxbox.main.ui.modal :as modal]
[uxbox.main.ui.keyboard :as kbd]
[uxbox.main.ui.confirm :refer [confirm-dialog]]
[uxbox.util.dom :as dom]
[uxbox.util.i18n :as i18n :refer [t tr]]
[uxbox.util.router :as rt]
[uxbox.util.time :as dt]))
;; --- Component: Content
;; (def files-ref
;; (-> (comp (l/key :files)
;; (l/lens vals))
;; (l/derive st/state)))
;; (def opts-iref
;; (-> (l/key :dashboard-projects)
;; (l/derive st/state)))
;; --- Component: Drafts Page
(mf/defc team-page
[{:keys [section team-id] :as props}]
(mf/use-effect
{:fn #(st/emit! (dsh/initialize-team team-id))
:deps (mf/deps team-id)})
[:section
[:p "TEAM PAGE"]])