Skip to content

Commit 7633353

Browse files
Merge pull request #46 from clj-codes/feat/adds-social-info-on-author-details-page
Adds Authors Social Interactions Page
2 parents 8d89480 + 446aba4 commit 7633353

File tree

12 files changed

+419
-26
lines changed

12 files changed

+419
-26
lines changed

resources/index.src.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
<head>
66
<meta charset="utf-8" />
77
<meta name="viewport" content="width=device-width, initial-scale=1">
8-
<link rel=”mask-icon” href=”favicon.svg” color=”#000000">
9-
<link rel="icon" href="favicon.svg">
8+
<link rel=”mask-icon” href=/favicon.svg” color=”#000000">
9+
<link rel="icon" href="/favicon.svg">
1010
<link rel="stylesheet" href="/css/app.css">
1111
<title>docs.clj.codes</title>
1212
</head>
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
(ns codes.clj.docs.frontend.panels.author.adapters)
2+
3+
(defn ^:private author-socials->summary [socials]
4+
(reduce (fn [{notes-a :notes examples-a :examples see-alsos-a :see-alsos
5+
:as accum}
6+
{notes-c :notes examples-c :examples see-alsos-c :see-alsos}]
7+
(assoc accum
8+
:notes (+ notes-a (count notes-c))
9+
:examples (+ examples-a (count examples-c))
10+
:see-alsos (+ see-alsos-a (count see-alsos-c))))
11+
{:notes 0 :examples 0 :see-alsos 0}
12+
socials))
13+
14+
(defn ^:private filter-socials [socials]
15+
(reduce-kv
16+
(fn [a k v]
17+
(if (not (zero? v))
18+
(assoc a k v)
19+
a))
20+
{}
21+
socials))
22+
23+
(defn ->string-summary [author]
24+
(let [socials (-> author :socials author-socials->summary filter-socials sort)]
25+
(case (count socials)
26+
0 "This user hasn't authored any content."
27+
1 (let [[k1 v1] (first socials)]
28+
(str "This has user has authored " v1 " " (name k1) "."))
29+
2 (let [[k1 v1] (first socials)
30+
[k2 v2] (last socials)]
31+
(str "This has user has authored "
32+
v1 " " (name k1) " and " v2 " " (name k2) "."))
33+
3 (let [[k1 v1] (first socials)
34+
[k2 v2] (second socials)
35+
[k3 v3] (last socials)]
36+
(str "This has user has authored "
37+
v1 " " (name k1) ", "
38+
v2 " " (name k2) " and "
39+
v3 " " (name k3) ".")))))
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
(ns codes.clj.docs.frontend.panels.author.state
2+
(:require [codes.clj.docs.frontend.infra.http :as http]
3+
[town.lilac.flex :as flex]
4+
[town.lilac.flex.promise :as flex.promise]))
5+
6+
(def author-fetch
7+
(flex.promise/resource
8+
(fn [login source]
9+
(-> (http/request! {:path (str "social/author/" login "/" source)
10+
:method :get})
11+
(.then (fn [response]
12+
(-> response
13+
:body)))
14+
(.catch (fn [error]
15+
(js/console.error error)
16+
(throw error)))))))
17+
18+
(def author-response
19+
(flex/signal {:state @(:state author-fetch)
20+
:value @(:value author-fetch)
21+
:error @(:error author-fetch)
22+
:loading? @(:loading? author-fetch)}))
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
(ns codes.clj.docs.frontend.panels.author.view
2+
(:require ["@mantine/core" :refer [Alert Avatar Box Center Container Grid
3+
Group List LoadingOverlay Space Text
4+
Title]]
5+
["@tabler/icons-react" :refer [IconInfoCircle]]
6+
[clojure.string :as str]
7+
[codes.clj.docs.frontend.components.navigation :refer [back-to-top
8+
safe-anchor]]
9+
[codes.clj.docs.frontend.infra.flex.hook :refer [use-flex]]
10+
[codes.clj.docs.frontend.infra.helix :refer [defnc]]
11+
[codes.clj.docs.frontend.panels.author.adapters :as author.adapters]
12+
[codes.clj.docs.frontend.panels.author.state :refer [author-response]]
13+
[helix.core :refer [$]]
14+
[helix.dom :as dom]))
15+
16+
(defnc social-preview-list [{:keys [title items id-key data-key]}]
17+
(dom/div
18+
($ Title {:style #js {:paddingTop 10} :order 4}
19+
title)
20+
($ List {:listStyleType "square"}
21+
(map (fn [item]
22+
($ (-> List .-Item) {:key (id-key item)}
23+
($ Box {:w #js {:base 350 :xs 400 :sm 600 :md 800 :lg 900 :xl 1000}}
24+
($ Text {:id (id-key item) :className "social-preview-item"
25+
:truncate "end"}
26+
(data-key item)))))
27+
items))))
28+
29+
(defnc author-socials-preview-list [{:keys [socials]}]
30+
(dom/div
31+
($ Title {:order 2} "Interactions")
32+
($ Space {:h "md"})
33+
($ Group
34+
($ Grid {:data-testid "author-grid"}
35+
(map (fn [{:keys [definition-id examples notes see-alsos]}]
36+
($ (-> Grid .-Col) {:key definition-id}
37+
(dom/div
38+
($ safe-anchor {:fz "xl" :fw 500
39+
:href (str "/" definition-id)}
40+
(str/replace definition-id #"/0$" ""))
41+
42+
(when (seq examples)
43+
($ social-preview-list {:title "Examples"
44+
:items examples
45+
:id-key :example-id
46+
:data-key :body}))
47+
48+
(when (seq see-alsos)
49+
($ social-preview-list {:title "See Alsos"
50+
:items see-alsos
51+
:id-key :see-also-id
52+
:data-key :definition-id-to}))
53+
54+
(when (seq notes)
55+
($ social-preview-list {:title "Notes"
56+
:items notes
57+
:id-key :note-id
58+
:data-key :body})))))
59+
60+
socials)))))
61+
62+
(defnc author-detail-page []
63+
(let [{:keys [loading? error value]} (use-flex author-response)
64+
{:keys [login account-source avatar-url socials]} value]
65+
66+
($ Container {:p "md"}
67+
(if loading?
68+
69+
($ LoadingOverlay {:visible loading? :zIndex 1000
70+
:overlayProps #js {:radius "sm" :blur 2}})
71+
72+
(if error
73+
($ Alert {:variant "light" :color "red"
74+
:radius "md" :title "Error"
75+
:icon ($ IconInfoCircle)}
76+
(str error))
77+
78+
(dom/div
79+
80+
($ Center
81+
($ Group {:wrap "nowrap"}
82+
($ Avatar {:src avatar-url
83+
:size 200
84+
:radius 200})
85+
(dom/div
86+
($ Title {:order 3}
87+
login)
88+
89+
($ Text {:fz "xs" :tt "uppercase" :fw 700 :c "dimmed"}
90+
(name account-source))
91+
92+
($ Space {:h "sm"})
93+
94+
($ Text {:data-testid "author-social-summary"
95+
:fz "lg" :fw 500}
96+
(author.adapters/->string-summary value)))))
97+
98+
($ Space {:h "lg"})
99+
100+
(when socials
101+
($ author-socials-preview-list {:socials socials}))
102+
103+
($ back-to-top)))))))
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
(ns codes.clj.docs.frontend.panels.definition.view.author
2+
(:require ["@mantine/core" :refer [Anchor Avatar]]
3+
["react" :as react]
4+
[codes.clj.docs.frontend.infra.helix :refer [defnc]]
5+
[helix.core :refer [$]]
6+
[helix.dom :as dom]))
7+
8+
#_{:clj-kondo/ignore [:clojure-lsp/unused-public-var]}
9+
(def forward-ref react/forwardRef)
10+
11+
(defnc avatar
12+
"Custom components that are rendered inside Tooltip are required to support ref prop
13+
https://mantine.dev/core/tooltip/#required-ref-prop"
14+
{:wrap [(forward-ref)]}
15+
[{:keys [author id children]} ref]
16+
(let [{:keys [login account-source avatar-url]} author]
17+
(dom/div {:ref ref}
18+
($ Anchor {:key (str "avatar" id)
19+
:href (str "/author/" login "/" account-source)}
20+
($ Avatar {:size "sm" :src avatar-url}))
21+
children)))

src/codes/clj/docs/frontend/panels/definition/view/examples.cljs

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
previewer-code]]
77
[codes.clj.docs.frontend.infra.helix :refer [defnc]]
88
[codes.clj.docs.frontend.panels.definition.state.examples :as state.examples]
9+
[codes.clj.docs.frontend.panels.definition.view.author :as author]
910
[codes.clj.docs.frontend.panels.definition.view.editor :refer [editor-base]]
1011
[helix.core :refer [$]]
1112
[helix.hooks :as hooks]))
@@ -25,29 +26,20 @@
2526

2627
(defnc avatar-editors [{:keys [editors]}]
2728
(let [shown-editors 3]
28-
(if (>= shown-editors (count editors))
29-
($ (-> Avatar .-Group)
30-
(map
31-
#($ Tooltip {:key (str (:login %) (:edited-at %))
32-
:label (str (:login %)
33-
" reviewed at "
34-
(.toGMTString (:edited-at %)))
35-
:withArrow true}
36-
($ Avatar {:size "sm" :src (:avatar-url %)}))
37-
editors))
38-
($ (-> Avatar .-Group)
29+
($ (-> Avatar .-Group)
30+
(when (> (count editors) shown-editors)
3931
($ Tooltip {:key "older-edits"
4032
:label "Older revisions"
4133
:withArrow true}
42-
($ Avatar {:size "sm"} "+"))
43-
(map
44-
#($ Tooltip {:key (str (:login %) (:edited-at %))
45-
:label (str (:login %)
46-
" reviewed at "
47-
(.toGMTString (:edited-at %)))
48-
:withArrow true}
49-
($ Avatar {:size "sm" :src (:avatar-url %)}))
50-
(take-last shown-editors editors))))))
34+
($ Avatar {:size "sm"} "+")))
35+
(map
36+
#($ Tooltip {:key (str (:login %) (:edited-at %))
37+
:label (str (:login %)
38+
" reviewed at "
39+
(.toGMTString (:edited-at %)))
40+
:withArrow true}
41+
($ author/avatar {:author % :id (str "avatar" (:login %) (:edited-at %))}))
42+
(take-last shown-editors editors)))))
5143

5244
(defnc card-example [{:keys [example user set-delete-modal-fn]}]
5345
(let [{:keys [example-id body author created-at definition-id editors]} example

src/codes/clj/docs/frontend/panels/definition/view/notes.cljs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
(ns codes.clj.docs.frontend.panels.definition.view.notes
2-
(:require ["@mantine/core" :refer [Anchor Avatar Card Center Grid Group Text
3-
Title Tooltip]]
2+
(:require ["@mantine/core" :refer [Anchor Card Center Grid Group Text Title
3+
Tooltip]]
44
["@tabler/icons-react" :refer [IconInfoCircle]]
55
[codes.clj.docs.frontend.components.markdown :refer [markdown-viewer
66
previewer-markdown]]
77
[codes.clj.docs.frontend.infra.helix :refer [defnc]]
88
[codes.clj.docs.frontend.panels.definition.state.notes :as state.notes]
9+
[codes.clj.docs.frontend.panels.definition.view.author :as author]
910
[codes.clj.docs.frontend.panels.definition.view.editor :refer [editor-base]]
1011
[helix.core :refer [$]]
1112
[helix.hooks :as hooks]))
@@ -38,7 +39,7 @@
3839
($ (-> Card .-Section) {:withBorder true :inheritPadding true :py "sm"}
3940
($ Group {:gap "xs"}
4041
($ Tooltip {:label (:login author) :withArrow true}
41-
($ Avatar {:size "sm" :src (:avatar-url author)}))
42+
($ author/avatar {:author author :id (str "avatar" (:login author) note-id)}))
4243
($ Text {:size "xs"} (.toGMTString created-at))
4344

4445
(when is-note-author?

src/codes/clj/docs/frontend/panels/definition/view/see_alsos.cljs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,9 @@
123123
($ Group {:gap "xs"}
124124
($ Tooltip {:label (str "at " (.toGMTString created-at)) :withArrow true}
125125
($ Text {:c "dimmed"}
126-
(str "By " (:login author))))
126+
"By " ($ Anchor {:href (str "/author/" (:login author)
127+
"/" (:account-source author))}
128+
(:login author))))
127129
(when is-see-also-author?
128130
($ Group {:className "author-edit-delete-see-also"
129131
:gap "xs"}

src/codes/clj/docs/frontend/routes.cljs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
(ns codes.clj.docs.frontend.routes
22
(:require [codes.clj.docs.frontend.infra.auth.github.view :as auth.github.view]
3+
[codes.clj.docs.frontend.panels.author.state :as author.state]
4+
[codes.clj.docs.frontend.panels.author.view :as author.view]
35
[codes.clj.docs.frontend.panels.definition.state :as definition.state]
46
[codes.clj.docs.frontend.panels.definition.view :as definition.view]
57
[codes.clj.docs.frontend.panels.definitions.state :as definitions.state]
@@ -66,6 +68,19 @@
6668
(set-title! "Search - docs.clj.codes")
6769
(search.state/search-fetch page-results (or q "") 100)))}]}]
6870

71+
["author/:login/:source"
72+
{:name :author
73+
:view author.view/author-detail-page
74+
:link-text "Author Details"
75+
:conflicting true
76+
:parameters {:path {:login string?
77+
:source string?}}
78+
:controllers [{:parameters {:path [:login :source]}
79+
:start (fn [& params]
80+
(let [{:keys [login source]} (-> params first :path)]
81+
(set-title! "Author Details - docs.clj.codes")
82+
(author.state/author-fetch login source)))}]}]
83+
6984
[":organization/:project"
7085
{:name :namespaces
7186
:view namespaces.view/org-projects
@@ -82,6 +97,7 @@
8297
{:name :definitions
8398
:view definitions.view/namespace-definitions
8499
:link-text "Definitions"
100+
:conflicting true
85101
:parameters {:path {:organization string?
86102
:project string?
87103
:namespace string?}}

0 commit comments

Comments
 (0)