From 1e3b9bf63e83ce7af11d00ea4a4d6c8b85a52a1d Mon Sep 17 00:00:00 2001 From: "James N. V. Cash" Date: Tue, 23 Feb 2016 15:13:16 -0500 Subject: [PATCH 1/9] start working on braid tutorial tour --- resources/less/chat.less | 51 +++++++++++++ src/chat/client/routes.cljs | 3 + src/chat/client/views.cljs | 6 +- src/chat/client/views/pages/tour.cljs | 102 ++++++++++++++++++++++++++ 4 files changed, 160 insertions(+), 2 deletions(-) create mode 100644 src/chat/client/views/pages/tour.cljs diff --git a/resources/less/chat.less b/resources/less/chat.less index d1fbcd339..fd7d82558 100644 --- a/resources/less/chat.less +++ b/resources/less/chat.less @@ -746,3 +746,54 @@ body { } } } + +.page.tour { + background-color: rgba(0,0,0,0.2); + .tour-msg { + background-color: white; + border-radius: 1rem; + font-size: 1em; + padding: 0.5em; + position: absolute; + &.center { + transform: translate(-50%, -50%); + -webkit-transform: translate(-50%, -50%); + left: 50%; + top: 50%; + } + &.left { + left: @pad; + } + &.top { + top: @pad; + } + &.arrow { + &:before { + content: ""; + display: block; + position: absolute; + width: 0; + height: 0; + border-color: transparent; + border-width: 15px; + border-style: solid; + } + } + &.arrow-left { + &:before { + right: 100%; + top: 50%; + margin-top: -15px; + border-right-color: white; + } + } + &.arrow-bottom { + &:before { + top: 100%; + border-right-color: white; + left: 50%; + margin-top: -15px; + } + } + } +} diff --git a/src/chat/client/routes.cljs b/src/chat/client/routes.cljs index 095766440..e9aaf666b 100644 --- a/src/chat/client/routes.cljs +++ b/src/chat/client/routes.cljs @@ -34,6 +34,9 @@ (defroute help-page-path "/:group-id/help" [group-id] (store/set-group-and-page! (UUID. group-id nil) {:type :help})) +(defroute help-page-path "/:group-id/tour" [group-id] + (store/set-group-and-page! (UUID. group-id nil) {:type :tour})) + (defroute search-page-path "/:group-id/search/:query" [group-id query] (store/set-group-and-page! (UUID. group-id nil) {:type :search :search-query query})) diff --git a/src/chat/client/views.cljs b/src/chat/client/views.cljs index c532c84b8..e0625412d 100644 --- a/src/chat/client/views.cljs +++ b/src/chat/client/views.cljs @@ -14,7 +14,8 @@ [chat.client.views.pages.user :refer [user-page-view]] [chat.client.views.pages.help :refer [help-page-view]] [chat.client.views.pages.group-explore :refer [group-explore-view]] - [chat.client.views.pages.me :refer [me-page-view]])) + [chat.client.views.pages.me :refer [me-page-view]] + [chat.client.views.pages.tour :refer [tour-view]])) (defn login-view [data owner] (reify @@ -76,7 +77,8 @@ :user (om/build user-page-view data) :channels (om/build channels-page-view data) :me (om/build me-page-view data) - :group-explore (om/build group-explore-view data)))))) + :group-explore (om/build group-explore-view data) + :tour (om/build tour-view data)))))) (defn app-view [data owner] (reify diff --git a/src/chat/client/views/pages/tour.cljs b/src/chat/client/views/pages/tour.cljs new file mode 100644 index 000000000..ffe932314 --- /dev/null +++ b/src/chat/client/views/pages/tour.cljs @@ -0,0 +1,102 @@ +(ns chat.client.views.pages.tour + (:require [om.core :as om] + [om.dom :as dom] + [chat.client.store :as store] + [chat.client.routes :as routes] + [chat.client.views.threads :refer [thread-view new-thread-view]])) + +; tutorial view. show: +; - groups on the side: +; - show how clicking on group selects which one you're in +; - new message box: +; - explain how tagging works +; - tag +; - user mention +; - explain other special things: +; - links, emphasis, images, file upload +; - existing threads: +; - types of threads: +; - threads with no tags +; - "private" threads +; - threads with tags +; - explain how threads can be closed & get re-opened? +; - top bar: +; - inbox +; - recent +; - users +; - tags +; - help +; - search +; - me/settings +; - other pages +; - user page +; - tag/channel page + +(declare state->next state->prev) + +(defn advance-state! + [owner] + (when-let [next-state (state->next (om/get-state owner :tour-state))] + (om/set-state! owner :tour-state next-state))) + +(defn retreat-state! + [owner] + (when-let [prev-state (state->prev (om/get-state owner :tour-state))] + (om/set-state! owner :tour-state prev-state))) + +(defn next-button + [owner] + (dom/button #js {:onClick (fn [_] (advance-state! owner)) + :className "forward"} + "Next")) + +(defn prev-button + [owner] + (dom/button #js {:onClick (fn [_] (retreat-state! owner)) + :className "back"} + "Back")) + +(def tour-states + [ + [:initial + (fn [owner] + (dom/div #js {:className "tour-msg center"} + (dom/h1 nil "Welcome to Braid!") + (dom/p nil "Braid is a little different from other chat programs " + "you might be used to") + (dom/p nil "Let's have a quick tour of how this works") + (next-button owner)))] + [:sidebar + (fn [owner] + (dom/div #js {:className "tour-msg left top arrow arrow-left"} + (dom/p nil "This sidebar shows the groups you are in") + (prev-button owner) + (next-button owner)))] + [:end + (fn [owner] + (dom/div #js {:className "tour-msg center"} + (dom/h1 nil "Ready to Go!") + (dom/p nil "Now you are ready to start using Braid in earnest") + (dom/p nil "Click" + (dom/a #js {:href (routes/inbox-page-path {:group-id (routes/current-group)})} + "here") + " to go to your inbox and start chatting in earnest!") + (prev-button owner) + ))] + ]) + +(def state->next (->> tour-states (map first) (partition 2 1) + (into {} (map vec)))) +(def state->prev (into {} (map (fn [[a b]] [b a])) state->next)) +(def state->view (into {} tour-states)) + +(defn tour-view [data owner] + (reify + om/IInitState + (init-state [_] + {:tour-state :initial}) + om/IRenderState + (render-state [_ {:keys [tour-state] :as state}] + (dom/div #js {:className "page tour"} + (dom/div #js {:className "title"} "Braid Tour") + ((state->view tour-state) owner))))) From f81942d78919c09ca10786beb5cb381d92c6f2fb Mon Sep 17 00:00:00 2001 From: "James N. V. Cash" Date: Tue, 23 Feb 2016 15:13:31 -0500 Subject: [PATCH 2/9] formatting --- src/chat/client/views/pages/inbox.cljs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/chat/client/views/pages/inbox.cljs b/src/chat/client/views/pages/inbox.cljs index 1b1cb0dae..72291e408 100644 --- a/src/chat/client/views/pages/inbox.cljs +++ b/src/chat/client/views/pages/inbox.cljs @@ -19,7 +19,8 @@ (when (and (or (.contains target-classes "thread") (.contains target-classes "threads")) (= 0 (.-deltaX e) (.-deltaZ e))) - (set! (.-scrollLeft this-elt) (- (.-scrollLeft this-elt) (.-deltaY e))))))} + (set! (.-scrollLeft this-elt) + (- (.-scrollLeft this-elt) (.-deltaY e))))))} (concat [(new-thread-view {})] (map (fn [t] (om/build thread-view t {:key :id})) From c4d9eeb5adac7a0bc4c77d08c1d8a9b6d63f982b Mon Sep 17 00:00:00 2001 From: "James N. V. Cash" Date: Tue, 23 Feb 2016 17:34:16 -0500 Subject: [PATCH 3/9] remove debugging fn --- src/chat/client/views/new_message.cljs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/chat/client/views/new_message.cljs b/src/chat/client/views/new_message.cljs index 2efa1bd6f..3676458f4 100644 --- a/src/chat/client/views/new_message.cljs +++ b/src/chat/client/views/new_message.cljs @@ -10,10 +10,6 @@ [chat.client.views.helpers :refer [id->color debounce]]) (:import [goog.events KeyCodes])) - -(defn tee [x] - (println x) x) - (defn fuzzy-matches? [s m] ; TODO: make this fuzzier? something like interleave with .* & re-match? From 63f3ca36c81c50edc3c242ebad2e9c032edfb297 Mon Sep 17 00:00:00 2001 From: "James N. V. Cash" Date: Tue, 23 Feb 2016 20:35:17 -0500 Subject: [PATCH 4/9] formatting --- src/chat/client/views/pages/tour.cljs | 69 ++++++++++++++++----------- 1 file changed, 40 insertions(+), 29 deletions(-) diff --git a/src/chat/client/views/pages/tour.cljs b/src/chat/client/views/pages/tour.cljs index ffe932314..087969092 100644 --- a/src/chat/client/views/pages/tour.cljs +++ b/src/chat/client/views/pages/tour.cljs @@ -5,6 +5,30 @@ [chat.client.routes :as routes] [chat.client.views.threads :refer [thread-view new-thread-view]])) +(declare state->next state->prev) + +(defn advance-state! + [owner] + (when-let [next-state (state->next (om/get-state owner :tour-state))] + (om/set-state! owner :tour-state next-state))) + +(defn retreat-state! + [owner] + (when-let [prev-state (state->prev (om/get-state owner :tour-state))] + (om/set-state! owner :tour-state prev-state))) + +(defn next-button + [owner] + (dom/button #js {:onClick (fn [_] (advance-state! owner)) + :className "forward"} + "Next")) + +(defn prev-button + [owner] + (dom/button #js {:onClick (fn [_] (retreat-state! owner)) + :className "back"} + "Back")) + ; tutorial view. show: ; - groups on the side: ; - show how clicking on group selects which one you're in @@ -32,31 +56,8 @@ ; - user page ; - tag/channel page -(declare state->next state->prev) - -(defn advance-state! - [owner] - (when-let [next-state (state->next (om/get-state owner :tour-state))] - (om/set-state! owner :tour-state next-state))) - -(defn retreat-state! - [owner] - (when-let [prev-state (state->prev (om/get-state owner :tour-state))] - (om/set-state! owner :tour-state prev-state))) - -(defn next-button - [owner] - (dom/button #js {:onClick (fn [_] (advance-state! owner)) - :className "forward"} - "Next")) - -(defn prev-button - [owner] - (dom/button #js {:onClick (fn [_] (retreat-state! owner)) - :className "back"} - "Back")) - (def tour-states + "The states and corresponding view functions for each step in the tour" [ [:initial (fn [owner] @@ -66,18 +67,22 @@ "you might be used to") (dom/p nil "Let's have a quick tour of how this works") (next-button owner)))] + [:sidebar (fn [owner] (dom/div #js {:className "tour-msg left top arrow arrow-left"} (dom/p nil "This sidebar shows the groups you are in") + (dom/p nil "When you're in more than one group, you can click on " + "the tiles here to switch between which one you're looking at") (prev-button owner) (next-button owner)))] + [:end (fn [owner] (dom/div #js {:className "tour-msg center"} (dom/h1 nil "Ready to Go!") (dom/p nil "Now you are ready to start using Braid in earnest") - (dom/p nil "Click" + (dom/p nil "Click " (dom/a #js {:href (routes/inbox-page-path {:group-id (routes/current-group)})} "here") " to go to your inbox and start chatting in earnest!") @@ -85,10 +90,16 @@ ))] ]) -(def state->next (->> tour-states (map first) (partition 2 1) - (into {} (map vec)))) -(def state->prev (into {} (map (fn [[a b]] [b a])) state->next)) -(def state->view (into {} tour-states)) +(def state->next + "Map of current-state to next-state. (e.g. {:initial :sidebar, :sidebar :end})" + (->> tour-states (map first) (partition 2 1) (into {} (map vec)))) +(def state->prev + "Inverse of state->next, to go from current state to previous state" + (into {} (map (fn [[a b]] [b a])) state->next)) + +(def state->view + "Map of state to view function" + (into {} tour-states)) (defn tour-view [data owner] (reify From 0b64f5f99cd95eb8c976be1c14a906d4e37ff11a Mon Sep 17 00:00:00 2001 From: "James N. V. Cash" Date: Tue, 23 Feb 2016 20:35:35 -0500 Subject: [PATCH 5/9] set max width of tutorial msg box --- resources/less/chat.less | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/less/chat.less b/resources/less/chat.less index fd7d82558..fb57105ea 100644 --- a/resources/less/chat.less +++ b/resources/less/chat.less @@ -751,6 +751,7 @@ body { background-color: rgba(0,0,0,0.2); .tour-msg { background-color: white; + max-width: 20%; border-radius: 1rem; font-size: 1em; padding: 0.5em; From ab345d6b1b218c48c5baca6e80ed32c95fa2c371 Mon Sep 17 00:00:00 2001 From: "James N. V. Cash" Date: Thu, 25 Feb 2016 11:23:28 -0500 Subject: [PATCH 6/9] add helper fn for predicate functions --- src/chat/shared/util.cljc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/chat/shared/util.cljc b/src/chat/shared/util.cljc index 49623c420..2520c2ac8 100644 --- a/src/chat/shared/util.cljc +++ b/src/chat/shared/util.cljc @@ -34,3 +34,9 @@ [f] (fn [& args] (apply f (reverse args)))) + +(defn if? + "Given a predicate function, then function and else function, return a fn + that returns (then x) if (pred x) returns true and (else x) otherwise" + [pred t e] + (fn [x] (if (pred x) (t x) (e x)))) From 6dc3a47c599e19ac7404e007250d6721037b485a Mon Sep 17 00:00:00 2001 From: "James N. V. Cash" Date: Thu, 25 Feb 2016 11:23:53 -0500 Subject: [PATCH 7/9] WIP: adding new message stage to tour --- resources/less/chat.less | 13 ++++++++++++- src/chat/client/views/pages/tour.cljs | 20 +++++++++++++++++--- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/resources/less/chat.less b/resources/less/chat.less index fb57105ea..ed660a1fe 100644 --- a/resources/less/chat.less +++ b/resources/less/chat.less @@ -751,7 +751,7 @@ body { background-color: rgba(0,0,0,0.2); .tour-msg { background-color: white; - max-width: 20%; + max-width: 25em; border-radius: 1rem; font-size: 1em; padding: 0.5em; @@ -768,6 +768,17 @@ body { &.top { top: @pad; } + &.bottom { + bottom: @pad; + } + &.middle { + top: 50%; + } + /* lol, hacks */ + &.new-adjacent { + left: @card-width + 2*@pad; + bottom: 2*@pad; + } &.arrow { &:before { content: ""; diff --git a/src/chat/client/views/pages/tour.cljs b/src/chat/client/views/pages/tour.cljs index 087969092..2152a5497 100644 --- a/src/chat/client/views/pages/tour.cljs +++ b/src/chat/client/views/pages/tour.cljs @@ -3,7 +3,10 @@ [om.dom :as dom] [chat.client.store :as store] [chat.client.routes :as routes] - [chat.client.views.threads :refer [thread-view new-thread-view]])) + [chat.client.views.threads :refer [thread-view new-thread-view]] + [chat.shared.util :refer [if?]])) + +(def ->seq (if? sequential? identity vector)) (declare state->next state->prev) @@ -77,6 +80,17 @@ (prev-button owner) (next-button owner)))] + [:new-message + (fn [owner] + [(dom/div #js {:className "threads"} + (new-thread-view {})) + + (dom/div #js {:className "tour-msg new-adjacent"} + (dom/p nil "Let's start a new thread") + (dom/p nil "Type some text (e.g. \"Hello Braid!\") in the adjacent box" + " and hit return") + (prev-button owner))])] + [:end (fn [owner] (dom/div #js {:className "tour-msg center"} @@ -108,6 +122,6 @@ {:tour-state :initial}) om/IRenderState (render-state [_ {:keys [tour-state] :as state}] - (dom/div #js {:className "page tour"} + (apply dom/div #js {:className "page tour"} (dom/div #js {:className "title"} "Braid Tour") - ((state->view tour-state) owner))))) + (->seq ((state->view tour-state) owner)))))) From 537c3eaa4dd87c6e4d3ee1b281ea8fc296985961 Mon Sep 17 00:00:00 2001 From: "James N. V. Cash" Date: Thu, 25 Feb 2016 20:05:47 -0500 Subject: [PATCH 8/9] basic message-creating tour --- src/chat/client/views/pages/tour.cljs | 102 +++++++++++++++++++++----- 1 file changed, 83 insertions(+), 19 deletions(-) diff --git a/src/chat/client/views/pages/tour.cljs b/src/chat/client/views/pages/tour.cljs index 2152a5497..080b56ddf 100644 --- a/src/chat/client/views/pages/tour.cljs +++ b/src/chat/client/views/pages/tour.cljs @@ -1,6 +1,7 @@ (ns chat.client.views.pages.tour (:require [om.core :as om] [om.dom :as dom] + [cljs-uuid-utils.core :as uuid] [chat.client.store :as store] [chat.client.routes :as routes] [chat.client.views.threads :refer [thread-view new-thread-view]] @@ -20,6 +21,11 @@ (when-let [prev-state (state->prev (om/get-state owner :tour-state))] (om/set-state! owner :tour-state prev-state))) +(defn reset-tour! + [owner] + (om/set-state! owner :tour-state :initial) + (om/set-state! owner :new-thread-id (uuid/make-random-squuid))) + (defn next-button [owner] (dom/button #js {:onClick (fn [_] (advance-state! owner)) @@ -60,7 +66,13 @@ ; - tag/channel page (def tour-states - "The states and corresponding view functions for each step in the tour" + "The states and corresponding view functions for each step in the tour. The + states are specificied as a vector where the first value is a keyword + indicating the name of the state, the second is a function which takes one + argument (the container owner), and optionally a third argument which is a + state transition function, which is called in will-update (useful if you want + the state to change based on something happening, instead of just a button + press)" [ [:initial (fn [owner] @@ -82,26 +94,67 @@ [:new-message (fn [owner] - [(dom/div #js {:className "threads"} - (new-thread-view {})) + (let [thread-id (om/get-state owner :new-thread-id)] + [(dom/div #js {:className "threads"} + (new-thread-view {:id thread-id})) - (dom/div #js {:className "tour-msg new-adjacent"} - (dom/p nil "Let's start a new thread") - (dom/p nil "Type some text (e.g. \"Hello Braid!\") in the adjacent box" - " and hit return") - (prev-button owner))])] + (dom/div #js {:className "tour-msg new-adjacent"} + (dom/p nil "Let's start a new thread that other people here will be able to see") + (dom/p nil "Type some text (e.g. \"Hello Braid!\") in the adjacent box" + " and hit return") + (prev-button owner))])) + (fn [owner next-props next-state] + (when (contains? (next-props :threads) (next-state :new-thread-id)) + (advance-state! owner)))] + + [:mention-user + (fn [owner] + (let [thread-id (om/get-state owner :new-thread-id) + thread (get-in (om/get-props owner) [:threads thread-id])] + [(dom/div #js {:className "threads"} + (om/build thread-view thread)) + (dom/div #js {:className "tour-msg new-adjacent"} + (dom/p nil "Now let's mention a user") + (dom/p nil "Start typing \"@\" and select a user you want to mention, then hit enter") + (dom/p nil "(maybe the person who invited you!)"))])) + (fn [owner next-props next-state] + (let [thread (get-in next-props [:threads (next-state :new-thread-id)])] + (when-not (empty? (thread :mentioned-ids)) + (advance-state! owner))))] + + [:tag-thread + (fn [owner] + (let [thread-id (om/get-state owner :new-thread-id) + thread (get-in (om/get-props owner) [:threads thread-id])] + [(dom/div #js {:className "threads"} + (om/build thread-view thread)) + (dom/div #js {:className "tour-msg new-adjacent"} + (dom/p nil "Let's make this thread we've started publicly viewable to the group") + (dom/p nil "We do this by adding a tag:") + (dom/p nil "Starting type \"#\", find a tag in the autocomplete, and hit enter") + (dom/p nil "(something like \"general\" or \"watercooler\" is " + " probably a good place for this)") + )])) + (fn [owner next-props next-state] + (let [thread (get-in next-props [:threads (next-state :new-thread-id)])] + (when-not (empty? (thread :tag-ids)) + (advance-state! owner))))] [:end (fn [owner] - (dom/div #js {:className "tour-msg center"} - (dom/h1 nil "Ready to Go!") - (dom/p nil "Now you are ready to start using Braid in earnest") - (dom/p nil "Click " - (dom/a #js {:href (routes/inbox-page-path {:group-id (routes/current-group)})} - "here") - " to go to your inbox and start chatting in earnest!") - (prev-button owner) - ))] + (let [thread-id (om/get-state owner :new-thread-id) + thread (get-in (om/get-props owner) [:threads thread-id])] + [(dom/div #js {:className "threads"} + (om/build thread-view thread)) + (dom/div #js {:className "tour-msg center"} + (dom/h1 nil "Ready to Go!") + (dom/p nil "Now you are ready to start using Braid in earnest") + (dom/p nil "Click " + (dom/a #js {:href (routes/inbox-page-path {:group-id (routes/current-group)})} + "here") + " to go to your inbox and start chatting in earnest!") + (dom/button #js {:onClick (fn [_] (reset-tour! owner))} + "Restart the tour"))]))] ]) (def state->next @@ -113,13 +166,24 @@ (def state->view "Map of state to view function" - (into {} tour-states)) + (into {} (map (fn [[st v]] [st v])) tour-states)) + +(def state->update-fn + "Map of state name to update-fn (to be called in will-update)" + (into {} (comp (remove (fn [[_ up]] (nil? up))) + (map (fn [[st _ up]] [st up]))) + tour-states)) (defn tour-view [data owner] (reify om/IInitState (init-state [_] - {:tour-state :initial}) + {:tour-state :initial + :new-thread-id (uuid/make-random-squuid)}) + om/IWillUpdate + (will-update [_ next-props next-state] + (when-let [f (state->update-fn (next-state :tour-state))] + (f owner next-props next-state))) om/IRenderState (render-state [_ {:keys [tour-state] :as state}] (apply dom/div #js {:className "page tour"} From 9d2cb7c6d54361fa71e363a6c8188bdfdfa94856 Mon Sep 17 00:00:00 2001 From: "James N. V. Cash" Date: Fri, 26 Feb 2016 11:44:00 -0500 Subject: [PATCH 9/9] add tour stages for top bar buttons --- resources/less/chat.less | 45 +++++++---- src/chat/client/views/pages/tour.cljs | 112 ++++++++++++++++++++++---- 2 files changed, 125 insertions(+), 32 deletions(-) diff --git a/resources/less/chat.less b/resources/less/chat.less index ed660a1fe..96116bc9e 100644 --- a/resources/less/chat.less +++ b/resources/less/chat.less @@ -747,6 +747,19 @@ body { } } +.arrow() { + &:before { + content: ""; + display: block; + position: absolute; + width: 0; + height: 0; + border-color: transparent; + border-width: 15px; + border-style: solid; + } +} + .page.tour { background-color: rgba(0,0,0,0.2); .tour-msg { @@ -768,30 +781,27 @@ body { &.top { top: @pad; } + &.topbar { + top: 4*@pad; + right: @pad*3; + } &.bottom { bottom: @pad; } &.middle { top: 50%; } + &.right { + right: 2*@pad; + } /* lol, hacks */ &.new-adjacent { left: @card-width + 2*@pad; bottom: 2*@pad; } - &.arrow { - &:before { - content: ""; - display: block; - position: absolute; - width: 0; - height: 0; - border-color: transparent; - border-width: 15px; - border-style: solid; - } - } + &.arrow-left { + .arrow(); &:before { right: 100%; top: 50%; @@ -799,12 +809,13 @@ body { border-right-color: white; } } - &.arrow-bottom { + &.arrow-up { + margin-top: 15px; + .arrow(); &:before { - top: 100%; - border-right-color: white; - left: 50%; - margin-top: -15px; + bottom: 100%; + left: 15px; + border-bottom-color: white; } } } diff --git a/src/chat/client/views/pages/tour.cljs b/src/chat/client/views/pages/tour.cljs index 080b56ddf..c0ca991b5 100644 --- a/src/chat/client/views/pages/tour.cljs +++ b/src/chat/client/views/pages/tour.cljs @@ -9,6 +9,21 @@ (def ->seq (if? sequential? identity vector)) +(defn element-offset + [el] + (loop [el el + x 0 y 0] + (if (and (some? el) (not (js/isNaN (.-offsetLeft el))) + (not (js/isNaN (.-offsetTop el)))) + (recur (.-offsetParent el) + (+ x (.-offsetLeft el) + (- (.-scrollLeft el)) + (.-clientLeft el)) + (+ y (.-offsetTop el) + (- (.-scrollTop el)) + (.-clientTop el))) + {:top y :left x}))) + (declare state->next state->prev) (defn advance-state! @@ -41,6 +56,17 @@ ; tutorial view. show: ; - groups on the side: ; - show how clicking on group selects which one you're in +; - top bar: +; - inbox +; - recent +; - users +; - tags +; - help +; - search +; - me/settings +; - other pages +; - user page +; - tag/channel page ; - new message box: ; - explain how tagging works ; - tag @@ -53,17 +79,6 @@ ; - "private" threads ; - threads with tags ; - explain how threads can be closed & get re-opened? -; - top bar: -; - inbox -; - recent -; - users -; - tags -; - help -; - search -; - me/settings -; - other pages -; - user page -; - tag/channel page (def tour-states "The states and corresponding view functions for each step in the tour. The @@ -85,20 +100,86 @@ [:sidebar (fn [owner] - (dom/div #js {:className "tour-msg left top arrow arrow-left"} + (dom/div #js {:className "tour-msg left top arrow-left"} (dom/p nil "This sidebar shows the groups you are in") (dom/p nil "When you're in more than one group, you can click on " "the tiles here to switch between which one you're looking at") (prev-button owner) (next-button owner)))] + [:inbox-button + (fn [owner] + (let [inbox-btn (.querySelector js/document ".inbox.shortcut") + {:keys [top left]} (element-offset inbox-btn)] + (dom/div #js {:className "tour-msg arrow-up" + :style #js {:top (str (+ top 30) "px") + :left (str (- left 90) "px")}} + (dom/p nil "This is the inbox button") + (prev-button owner) + (next-button owner))))] + + [:recent-button + (fn [owner] + (let [inbox-btn (.querySelector js/document ".recent.shortcut") + {:keys [top left]} (element-offset inbox-btn)] + (dom/div #js {:className "tour-msg arrow-up" + :style #js {:top (str (+ top 30) "px") + :left (str (- left 90) "px")}} + (dom/p nil "This is the recent button") + (prev-button owner) + (next-button owner))))] + + [:people-button + (fn [owner] + (let [inbox-btn (.querySelector js/document ".users.shortcut") + {:keys [top left]} (element-offset inbox-btn)] + (dom/div #js {:className "tour-msg arrow-up" + :style #js {:top (str (+ top 30) "px") + :left (str (- left 90) "px")}} + (dom/p nil "This is the users button") + (prev-button owner) + (next-button owner))))] + + [:tags-button + (fn [owner] + (let [inbox-btn (.querySelector js/document ".tags.shortcut") + {:keys [top left]} (element-offset inbox-btn)] + (dom/div #js {:className "tour-msg arrow-up" + :style #js {:top (str (+ top 30) "px") + :left (str (- left 90) "px")}} + (dom/p nil "This is the tags button") + (prev-button owner) + (next-button owner))))] + + [:history-search + (fn [owner] + (let [inbox-btn (.querySelector js/document ".search-bar") + {:keys [top left]} (element-offset inbox-btn)] + (dom/div #js {:className "tour-msg arrow-up" + :style #js {:top (str (+ top 30) "px") + :left (str (- left 90) "px")}} + (dom/p nil "This is the history search field") + (prev-button owner) + (next-button owner))))] + + [:me-button + (fn [owner] + (let [inbox-btn (.querySelector js/document ".header .avatar") + {:keys [top left]} (element-offset inbox-btn)] + (dom/div #js {:className "tour-msg arrow-up" + :style #js {:top (str (+ top 30) "px") + :left (str (- left 90) "px")}} + (dom/p nil "This is will take you to your user profile page") + (prev-button owner) + (next-button owner))))] + [:new-message (fn [owner] (let [thread-id (om/get-state owner :new-thread-id)] [(dom/div #js {:className "threads"} (new-thread-view {:id thread-id})) - (dom/div #js {:className "tour-msg new-adjacent"} + (dom/div #js {:className "tour-msg new-adjacent arrow-left"} (dom/p nil "Let's start a new thread that other people here will be able to see") (dom/p nil "Type some text (e.g. \"Hello Braid!\") in the adjacent box" " and hit return") @@ -113,9 +194,10 @@ thread (get-in (om/get-props owner) [:threads thread-id])] [(dom/div #js {:className "threads"} (om/build thread-view thread)) - (dom/div #js {:className "tour-msg new-adjacent"} + (dom/div #js {:className "tour-msg new-adjacent arrow-left"} (dom/p nil "Now let's mention a user") - (dom/p nil "Start typing \"@\" and select a user you want to mention, then hit enter") + (dom/p nil "Start typing \"@\" and select a user you want to mention," + " then hit enter") (dom/p nil "(maybe the person who invited you!)"))])) (fn [owner next-props next-state] (let [thread (get-in next-props [:threads (next-state :new-thread-id)])]