@soul-refiner/design-system 0.0.3 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (271) hide show
  1. package/.eslintrc.js +4 -0
  2. package/.turbo/turbo-build.log +12 -0
  3. package/.turbo/turbo-test.log +4417 -0
  4. package/CHANGELOG.md +7 -0
  5. package/babel.config.js +6 -0
  6. package/custom.d.ts +4 -0
  7. package/package.json +1 -10
  8. package/src/actions/Button/Button.module.scss +205 -0
  9. package/src/actions/Button/Button.spec.js +56 -0
  10. package/src/actions/Button/Button.tsx +143 -0
  11. package/src/actions/Button/index.ts +1 -0
  12. package/src/actions/Dropdown/Dropdown.module.scss +77 -0
  13. package/src/actions/Dropdown/Dropdown.spec.js +149 -0
  14. package/src/actions/Dropdown/Dropdown.tsx +224 -0
  15. package/src/actions/Dropdown/index.ts +6 -0
  16. package/src/actions/Dropzone/Dropzone.module.scss +48 -0
  17. package/src/actions/Dropzone/Dropzone.spec.js +60 -0
  18. package/src/actions/Dropzone/Dropzone.tsx +191 -0
  19. package/src/actions/Dropzone/index.ts +1 -0
  20. package/src/actions/Rate/Rate.module.scss +17 -0
  21. package/src/actions/Rate/Rate.tsx +53 -0
  22. package/src/actions/Rate/index.ts +1 -0
  23. package/src/actions/Switch/Switch.module.scss +35 -0
  24. package/src/actions/Switch/Switch.spec.js +31 -0
  25. package/src/actions/Switch/Switch.tsx +34 -0
  26. package/src/actions/Switch/index.ts +1 -0
  27. package/src/actions/index.ts +5 -0
  28. package/src/cards/CourseCard/CourseCard.module.scss +219 -0
  29. package/src/cards/CourseCard/CourseCard.spec.js +60 -0
  30. package/src/cards/CourseCard/CourseCard.tsx +145 -0
  31. package/src/cards/CourseCard/index.ts +1 -0
  32. package/src/cards/EpisodeCard/EpisodeCard.module.scss +69 -0
  33. package/src/cards/EpisodeCard/EpisodeCard.tsx +53 -0
  34. package/src/cards/EpisodeCard/index.ts +1 -0
  35. package/src/cards/FeatureCard/FeatureCard.module.scss +116 -0
  36. package/src/cards/FeatureCard/FeatureCard.spec.js +70 -0
  37. package/src/cards/FeatureCard/FeatureCard.tsx +123 -0
  38. package/src/cards/FeatureCard/index.ts +1 -0
  39. package/src/cards/index.ts +3 -0
  40. package/src/data/Bar/Bar.module.scss +105 -0
  41. package/src/data/Bar/Bar.tsx +161 -0
  42. package/src/data/Bar/index.ts +1 -0
  43. package/src/data/Line/Line.module.scss +102 -0
  44. package/src/data/Line/Line.tsx +162 -0
  45. package/src/data/Line/index.ts +1 -0
  46. package/src/data/Pie/Pie.module.scss +56 -0
  47. package/src/data/Pie/Pie.spec.js +72 -0
  48. package/src/data/Pie/Pie.tsx +111 -0
  49. package/src/data/Pie/index.ts +1 -0
  50. package/src/data/index.ts +3 -0
  51. package/src/editor/Editor.module.scss +125 -0
  52. package/src/editor/Editor.tsx +327 -0
  53. package/src/editor/common/elements.ts +50 -0
  54. package/src/editor/common/index.ts +2 -0
  55. package/src/editor/common/marks.ts +27 -0
  56. package/src/editor/components/MediaDrawer/MediaDrawer.module.scss +316 -0
  57. package/src/editor/components/MediaDrawer/MediaDrawer.tsx +457 -0
  58. package/src/editor/components/MediaDrawer/index.ts +1 -0
  59. package/src/editor/components/index.ts +1 -0
  60. package/src/editor/config/default.ts +213 -0
  61. package/src/editor/config/index.ts +2 -0
  62. package/src/editor/config/props.ts +9 -0
  63. package/src/editor/index.ts +2 -0
  64. package/src/editor/plateUI.ts +82 -0
  65. package/src/editor/plugins/blocks.tsx +71 -0
  66. package/src/editor/plugins/custom/assets/DefaultThumbnail.tsx +57 -0
  67. package/src/editor/plugins/custom/assets/index.ts +1 -0
  68. package/src/editor/plugins/custom/buttons.tsx +289 -0
  69. package/src/editor/plugins/custom/example.tsx +64 -0
  70. package/src/editor/plugins/custom/exitBreak.ts +41 -0
  71. package/src/editor/plugins/custom/footnote.tsx +185 -0
  72. package/src/editor/plugins/custom/index.ts +14 -0
  73. package/src/editor/plugins/custom/paywall.tsx +156 -0
  74. package/src/editor/plugins/custom/qa.tsx +390 -0
  75. package/src/editor/plugins/custom/resetBlockType.ts +29 -0
  76. package/src/editor/plugins/custom/selectOnBackspace.ts +7 -0
  77. package/src/editor/plugins/custom/softBreak.ts +20 -0
  78. package/src/editor/plugins/custom/styles/Button.module.scss +51 -0
  79. package/src/editor/plugins/custom/styles/Footnote.module.scss +58 -0
  80. package/src/editor/plugins/custom/styles/Paywall.module.scss +67 -0
  81. package/src/editor/plugins/custom/styles/QA.module.scss +140 -0
  82. package/src/editor/plugins/custom/styles/Video.module.scss +79 -0
  83. package/src/editor/plugins/custom/video.tsx +163 -0
  84. package/src/editor/plugins/index.ts +18 -0
  85. package/src/editor/plugins/inline.ts +46 -0
  86. package/src/editor/plugins/marks.ts +25 -0
  87. package/src/editor/plugins/utils.ts +22 -0
  88. package/src/feedback/Chip/Chip.module.scss +23 -0
  89. package/src/feedback/Chip/Chip.tsx +58 -0
  90. package/src/feedback/Chip/index.ts +1 -0
  91. package/src/feedback/Loader/Loader.module.scss +18 -0
  92. package/src/feedback/Loader/Loader.spec.js +18 -0
  93. package/src/feedback/Loader/Loader.tsx +53 -0
  94. package/src/feedback/Loader/index.ts +1 -0
  95. package/src/feedback/ProgressBar/ProgressBar.module.scss +13 -0
  96. package/src/feedback/ProgressBar/ProgressBar.tsx +32 -0
  97. package/src/feedback/ProgressBar/index.ts +1 -0
  98. package/src/feedback/Toast/Toast.module.scss +44 -0
  99. package/src/feedback/Toast/Toast.tsx +76 -0
  100. package/src/feedback/Toast/index.ts +1 -0
  101. package/src/feedback/Tooltip/Tooltip.module.scss +47 -0
  102. package/src/feedback/Tooltip/Tooltip.tsx +10 -0
  103. package/src/feedback/Tooltip/index.ts +1 -0
  104. package/src/feedback/index.ts +5 -0
  105. package/src/global.d.ts +6 -0
  106. package/src/iconography/Avatar/Avatar.module.scss +90 -0
  107. package/src/iconography/Avatar/Avatar.spec.js +75 -0
  108. package/src/iconography/Avatar/Avatar.tsx +96 -0
  109. package/src/iconography/Avatar/DefaultIcon.svg +4 -0
  110. package/src/iconography/Avatar/DefaultIcon.tsx +12 -0
  111. package/src/iconography/Avatar/iconHelpers.tsx +186 -0
  112. package/src/iconography/Avatar/index.ts +1 -0
  113. package/src/iconography/ColoredIcon/ColoredIcon.module.scss +40 -0
  114. package/src/iconography/ColoredIcon/ColoredIcon.tsx +30 -0
  115. package/src/iconography/ColoredIcon/index.ts +5 -0
  116. package/src/iconography/DevicePreview/DevicePreview.module.scss +143 -0
  117. package/src/iconography/DevicePreview/DevicePreview.tsx +592 -0
  118. package/src/iconography/DevicePreview/index.ts +1 -0
  119. package/src/iconography/IconHeader/IconHeader.module.scss +42 -0
  120. package/src/iconography/IconHeader/IconHeader.tsx +42 -0
  121. package/src/iconography/IconHeader/index.ts +1 -0
  122. package/src/iconography/StarRating/StarRating.tsx +99 -0
  123. package/src/iconography/StarRating/index.ts +1 -0
  124. package/src/iconography/index.ts +5 -0
  125. package/src/implementations/BodyContent/BodyContent.module.scss +38 -0
  126. package/src/implementations/BodyContent/BodyContent.tsx +78 -0
  127. package/src/implementations/BodyContent/index.ts +2 -0
  128. package/src/implementations/JoinGroupModal/JoinGroupModal.module.scss +83 -0
  129. package/src/implementations/JoinGroupModal/JoinGroupModal.tsx +176 -0
  130. package/src/implementations/JoinGroupModal/index.ts +1 -0
  131. package/src/implementations/index.ts +2 -0
  132. package/src/index.ts +149 -0
  133. package/src/inputs/CalendarInput/CalendarInput.module.scss +38 -0
  134. package/src/inputs/CalendarInput/CalendarInput.spec.js +19 -0
  135. package/src/inputs/CalendarInput/CalendarInput.tsx +29 -0
  136. package/src/inputs/CalendarInput/index.ts +1 -0
  137. package/src/inputs/CheckboxInput/CheckboxInput.module.scss +23 -0
  138. package/src/inputs/CheckboxInput/CheckboxInput.tsx +39 -0
  139. package/src/inputs/CheckboxInput/index.ts +1 -0
  140. package/src/inputs/FeedInput/FeedInput.module.scss +48 -0
  141. package/src/inputs/FeedInput/FeedInput.spec.js +16 -0
  142. package/src/inputs/FeedInput/FeedInput.tsx +197 -0
  143. package/src/inputs/FeedInput/index.ts +1 -0
  144. package/src/inputs/InboxInput/InboxInput.module.scss +48 -0
  145. package/src/inputs/InboxInput/InboxInput.spec.js +19 -0
  146. package/src/inputs/InboxInput/InboxInput.tsx +97 -0
  147. package/src/inputs/InboxInput/index.ts +1 -0
  148. package/src/inputs/PostInput/PostInput.module.scss +49 -0
  149. package/src/inputs/PostInput/PostInput.spec.js +19 -0
  150. package/src/inputs/PostInput/PostInput.tsx +54 -0
  151. package/src/inputs/PostInput/index.ts +1 -0
  152. package/src/inputs/RadioInput/RadioInput.module.scss +68 -0
  153. package/src/inputs/RadioInput/RadioInput.tsx +55 -0
  154. package/src/inputs/RadioInput/index.ts +1 -0
  155. package/src/inputs/SearchInput/SearchInput.module.scss +40 -0
  156. package/src/inputs/SearchInput/SearchInput.tsx +61 -0
  157. package/src/inputs/SearchInput/index.ts +1 -0
  158. package/src/inputs/SelectInput/SelectInput.module.scss +66 -0
  159. package/src/inputs/SelectInput/SelectInput.tsx +145 -0
  160. package/src/inputs/SelectInput/index.ts +1 -0
  161. package/src/inputs/TagInput/TagInput.module.scss +75 -0
  162. package/src/inputs/TagInput/TagInput.tsx +115 -0
  163. package/src/inputs/TagInput/index.ts +1 -0
  164. package/src/inputs/TextInput/TextInput.module.scss +35 -0
  165. package/src/inputs/TextInput/TextInput.tsx +46 -0
  166. package/src/inputs/TextInput/index.ts +1 -0
  167. package/src/inputs/index.ts +10 -0
  168. package/src/lists/ContactDetails/ContactDetails.module.scss +70 -0
  169. package/src/lists/ContactDetails/ContactDetails.spec.js +69 -0
  170. package/src/lists/ContactDetails/ContactDetails.tsx +185 -0
  171. package/src/lists/ContactDetails/index.ts +1 -0
  172. package/src/lists/index.ts +1 -0
  173. package/src/navigation/Breadcrumbs/Breadcrumbs.module.scss +18 -0
  174. package/src/navigation/Breadcrumbs/Breadcrumbs.spec.js +38 -0
  175. package/src/navigation/Breadcrumbs/Breadcrumbs.tsx +43 -0
  176. package/src/navigation/Breadcrumbs/index.ts +1 -0
  177. package/src/navigation/Drawer/Drawer.module.scss +104 -0
  178. package/src/navigation/Drawer/Drawer.tsx +177 -0
  179. package/src/navigation/Drawer/index.ts +1 -0
  180. package/src/navigation/EditorBar/EditorBar.module.scss +118 -0
  181. package/src/navigation/EditorBar/EditorBar.tsx +416 -0
  182. package/src/navigation/EditorBar/components/AlignmentDropdown/AlignmentDropdown.tsx +106 -0
  183. package/src/navigation/EditorBar/components/AlignmentDropdown/index.ts +1 -0
  184. package/src/navigation/EditorBar/components/ButtonModal/ButtonModal.module.scss +85 -0
  185. package/src/navigation/EditorBar/components/ButtonModal/ButtonModal.tsx +314 -0
  186. package/src/navigation/EditorBar/components/ButtonModal/assets/Comment.tsx +28 -0
  187. package/src/navigation/EditorBar/components/ButtonModal/assets/GiftSubscription.tsx +28 -0
  188. package/src/navigation/EditorBar/components/ButtonModal/assets/Link.tsx +28 -0
  189. package/src/navigation/EditorBar/components/ButtonModal/assets/Share.tsx +28 -0
  190. package/src/navigation/EditorBar/components/ButtonModal/assets/ShareCommunity.tsx +42 -0
  191. package/src/navigation/EditorBar/components/ButtonModal/assets/Signup.tsx +68 -0
  192. package/src/navigation/EditorBar/components/ButtonModal/assets/Special.tsx +24 -0
  193. package/src/navigation/EditorBar/components/ButtonModal/assets/Subscribe.tsx +28 -0
  194. package/src/navigation/EditorBar/components/ButtonModal/assets/index.ts +8 -0
  195. package/src/navigation/EditorBar/components/ButtonModal/index.ts +1 -0
  196. package/src/navigation/EditorBar/components/FontDropdown/FontDropdown.module.scss +16 -0
  197. package/src/navigation/EditorBar/components/FontDropdown/FontDropdown.tsx +137 -0
  198. package/src/navigation/EditorBar/components/FontDropdown/index.ts +1 -0
  199. package/src/navigation/EditorBar/components/MoreDropdown/MoreDropdown.module.scss +43 -0
  200. package/src/navigation/EditorBar/components/MoreDropdown/MoreDropdown.tsx +124 -0
  201. package/src/navigation/EditorBar/components/MoreDropdown/index.ts +1 -0
  202. package/src/navigation/EditorBar/components/OutlineDropdown/OutlineDropdown.module.scss +21 -0
  203. package/src/navigation/EditorBar/components/OutlineDropdown/OutlineDropdown.tsx +37 -0
  204. package/src/navigation/EditorBar/components/OutlineDropdown/index.ts +1 -0
  205. package/src/navigation/EditorBar/components/TextTypeDropdown/TextTypeDropdown.module.scss +51 -0
  206. package/src/navigation/EditorBar/components/TextTypeDropdown/TextTypeDropdown.tsx +80 -0
  207. package/src/navigation/EditorBar/components/TextTypeDropdown/index.ts +1 -0
  208. package/src/navigation/EditorBar/components/VideoModal/VideoModal.module.scss +150 -0
  209. package/src/navigation/EditorBar/components/VideoModal/VideoModal.tsx +163 -0
  210. package/src/navigation/EditorBar/components/VideoModal/index.ts +1 -0
  211. package/src/navigation/EditorBar/components/index.ts +7 -0
  212. package/src/navigation/EditorBar/index.ts +1 -0
  213. package/src/navigation/MenuTabs/MenuTabs.module.scss +34 -0
  214. package/src/navigation/MenuTabs/MenuTabs.spec.js +36 -0
  215. package/src/navigation/MenuTabs/MenuTabs.tsx +52 -0
  216. package/src/navigation/MenuTabs/index.ts +1 -0
  217. package/src/navigation/Navigation/Navigation.module.scss +92 -0
  218. package/src/navigation/Navigation/Navigation.spec.js +144 -0
  219. package/src/navigation/Navigation/Navigation.tsx +111 -0
  220. package/src/navigation/Navigation/SubNavigation.module.scss +255 -0
  221. package/src/navigation/Navigation/SubNavigation.spec.js +112 -0
  222. package/src/navigation/Navigation/SubNavigation.tsx +443 -0
  223. package/src/navigation/Navigation/index.ts +15 -0
  224. package/src/navigation/Pagination/Pagination.module.scss +49 -0
  225. package/src/navigation/Pagination/Pagination.tsx +115 -0
  226. package/src/navigation/Pagination/index.ts +1 -0
  227. package/src/navigation/index.ts +21 -0
  228. package/src/surfaces/Comment/Comment.module.scss +106 -0
  229. package/src/surfaces/Comment/Comment.spec.js +105 -0
  230. package/src/surfaces/Comment/Comment.tsx +157 -0
  231. package/src/surfaces/Comment/index.ts +1 -0
  232. package/src/surfaces/Faq/Faq.module.scss +91 -0
  233. package/src/surfaces/Faq/Faq.spec.js +38 -0
  234. package/src/surfaces/Faq/Faq.tsx +156 -0
  235. package/src/surfaces/Faq/index.ts +1 -0
  236. package/src/surfaces/Message/Message.module.scss +37 -0
  237. package/src/surfaces/Message/Message.spec.js +47 -0
  238. package/src/surfaces/Message/Message.tsx +54 -0
  239. package/src/surfaces/Message/index.ts +1 -0
  240. package/src/surfaces/Modal/Modal.module.scss +52 -0
  241. package/src/surfaces/Modal/Modal.spec.js +38 -0
  242. package/src/surfaces/Modal/Modal.tsx +131 -0
  243. package/src/surfaces/Modal/index.ts +5 -0
  244. package/src/surfaces/Plan/Plan.module.scss +79 -0
  245. package/src/surfaces/Plan/Plan.tsx +75 -0
  246. package/src/surfaces/Plan/index.ts +1 -0
  247. package/src/surfaces/Post/Post.module.scss +46 -0
  248. package/src/surfaces/Post/Post.spec.js +103 -0
  249. package/src/surfaces/Post/Post.tsx +185 -0
  250. package/src/surfaces/Post/index.ts +1 -0
  251. package/src/surfaces/Post/postHelpers.ts +20 -0
  252. package/src/surfaces/ProfileHeader/ProfileHeader.module.scss +202 -0
  253. package/src/surfaces/ProfileHeader/ProfileHeader.tsx +103 -0
  254. package/src/surfaces/ProfileHeader/index.ts +1 -0
  255. package/src/surfaces/RatingsOverview/RatingsOverview.module.scss +54 -0
  256. package/src/surfaces/RatingsOverview/RatingsOverview.tsx +69 -0
  257. package/src/surfaces/RatingsOverview/index.ts +1 -0
  258. package/src/surfaces/Review/Review.module.scss +73 -0
  259. package/src/surfaces/Review/Review.tsx +88 -0
  260. package/src/surfaces/Review/index.ts +1 -0
  261. package/src/surfaces/index.ts +9 -0
  262. package/src/tables/Filter/Filter.module.scss +34 -0
  263. package/src/tables/Filter/Filter.tsx +30 -0
  264. package/src/tables/Filter/index.ts +1 -0
  265. package/src/tables/Table/Table.module.scss +126 -0
  266. package/src/tables/Table/Table.spec.js +113 -0
  267. package/src/tables/Table/Table.tsx +251 -0
  268. package/src/tables/Table/index.ts +7 -0
  269. package/src/tables/index.ts +7 -0
  270. package/tsconfig.json +14 -0
  271. package/vite.config.ts +29 -0
@@ -0,0 +1,106 @@
1
+ @use "@soul-refiner/styles/_mixins";
2
+
3
+ .comment {
4
+ @include mixins.flex($justify: space-between, $gap: 12px);
5
+ position: relative;
6
+ padding-bottom: 12px;
7
+
8
+ [class~="content-wrapper"] {
9
+ flex: 1;
10
+
11
+ [class~="comment"] {
12
+ padding: 16px;
13
+ border-radius: 18px;
14
+ background-color: #ffffff;
15
+
16
+ [class~="name"] {
17
+ margin-bottom: 8px;
18
+ display: block;
19
+ }
20
+ }
21
+
22
+ [class~="actions-wrapper"] {
23
+ @include mixins.flex($gap: 16px, $align: center);
24
+ margin: 8px 0px;
25
+ padding-left: 17px;
26
+
27
+ p {
28
+ color: var(--color-grey-4);
29
+ font-size: 12px;
30
+ line-height: 18px;
31
+ user-select: none;
32
+ }
33
+
34
+ [class~="interactive"] {
35
+ cursor: pointer;
36
+ }
37
+
38
+ [class~="likes-wrapper"] {
39
+ @include mixins.flex($gap: 5px);
40
+ margin-left: auto;
41
+ div {
42
+ border-radius: 50%;
43
+ background: linear-gradient(0deg, #1d62f0 0%, #1ad5fd 100%);
44
+ }
45
+ }
46
+ }
47
+
48
+ textarea {
49
+ width: 100%;
50
+ margin: 16px 0px;
51
+ }
52
+
53
+ [class~="has-replies"] {
54
+ position: relative;
55
+
56
+ &::before {
57
+ content: "";
58
+ position: absolute;
59
+ top: 32px;
60
+ left: -28px;
61
+ height: calc(100% - 12px);
62
+ border-left: 2px solid var(--color-grey-9);
63
+ }
64
+ }
65
+
66
+ [class~="is-reply"] {
67
+ position: relative;
68
+
69
+ &::before {
70
+ content: "";
71
+ position: absolute;
72
+ left: -28px;
73
+ height: 100%;
74
+ border-left: 2px solid var(--color-grey-9);
75
+ }
76
+ }
77
+ }
78
+ }
79
+
80
+ .replies {
81
+ padding-top: 12px;
82
+
83
+ [class~="reply-line-bottom"] {
84
+ position: absolute;
85
+ top: 0;
86
+ left: -28px;
87
+ width: 28px;
88
+ height: 16px;
89
+ border-bottom-left-radius: 16px;
90
+ border: 2px solid var(--color-grey-9);
91
+ border-top: none;
92
+ border-right: none;
93
+ }
94
+
95
+ [class~="show-replies"] {
96
+ padding: 5px 0px 8px 5px;
97
+ font-weight: 600;
98
+ color: var(--color-grey-4);
99
+ cursor: pointer;
100
+ user-select: none;
101
+
102
+ &:hover {
103
+ color: var(--colorify-blue-3);
104
+ }
105
+ }
106
+ }
@@ -0,0 +1,105 @@
1
+ import React from "react";
2
+ import "@testing-library/jest-dom";
3
+ import { render, screen, fireEvent } from "@testing-library/react";
4
+
5
+ import { Comment } from "./Comment";
6
+
7
+ const props = {
8
+ commenter: {
9
+ id: 1,
10
+ avatar: "https://i.pravatar.cc/32",
11
+ firstName: "Dietrich",
12
+ lastName: "von Hildebrand",
13
+ url: "",
14
+ },
15
+ content: "What a great point!",
16
+ created: new Date(),
17
+ hasLiked: false,
18
+ reactions: 0,
19
+ onReact: jest.fn(),
20
+ onReply: jest.fn(),
21
+ };
22
+
23
+ describe("Comment renders", () => {
24
+ it("the comment, name, and avatar", () => {
25
+ render(<Comment {...props} />);
26
+ expect(screen.getByText("What a great point!"));
27
+ expect(screen.getByText("Dietrich von Hildebrand"));
28
+ expect(screen.getByRole("img"));
29
+ });
30
+
31
+ it("with reactions", () => {
32
+ props.reactions = 10;
33
+ render(<Comment {...props} />);
34
+ expect(screen.getByTestId("likes-wrapper").lastChild.textContent).toEqual(
35
+ "10"
36
+ );
37
+ });
38
+
39
+ it("without reactions", () => {
40
+ render(<Comment {...props} />);
41
+ expect(!screen.queryByTestId("likes-wrapper"));
42
+ });
43
+
44
+ it("a yet-to-be reacted to comment", () => {
45
+ render(<Comment {...props} />);
46
+ const notLikedIcon = screen.getByTestId("not-liked-icon");
47
+ fireEvent.click(notLikedIcon);
48
+ expect(props.onReact).toHaveBeenCalled();
49
+ });
50
+
51
+ it("a liked comment", () => {
52
+ props.hasReacted = true;
53
+ render(<Comment {...props} />);
54
+ const likedIcon = screen.getByTestId("liked-icon");
55
+ fireEvent.click(likedIcon);
56
+ expect(props.onReact).toHaveBeenCalled();
57
+ });
58
+
59
+ it("the abbreviated time the commented was posted", () => {
60
+ render(<Comment {...props} />);
61
+ expect(screen.getByText("Just now"));
62
+ });
63
+
64
+ it("nested comments", () => {
65
+ props.replies = [
66
+ {
67
+ commentId: "zlk2jlkjsalkfjaslkdfj",
68
+ commenter: {
69
+ id: 3,
70
+ avatar: "",
71
+ firstName: "Laura",
72
+ lastName: "Smith",
73
+ url: "",
74
+ },
75
+ content:
76
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc tempus, leo, id mi proin aenean gravida. Suspendisse auctor rutrum porttitor viverra convallis neque. Ipsum, aliquet sed laoreet tincidunt. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc tempus, leo, id mi proin aenean gravida. Suspendisse auctor rutrum porttitor viverra convallis neque. Ipsum, aliquet sed laoreet tincidunt. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc tempus, leo, id mi proin aenean gravida. Suspendisse auctor rutrum porttitor viverra convallis neque. Ipsum, aliquet sed laoreet tincidunt.",
77
+ created: new Date(new Date().getTime() - 60000 * 1),
78
+ hasReacted: false,
79
+ onReact: jest.fn(),
80
+ onReply: jest.fn(),
81
+ reactions: 1,
82
+ },
83
+ {
84
+ commentId: "blkjsdlkjlkjwlfkajsdf",
85
+ commenter: {
86
+ id: 3,
87
+ avatar: "https://i.pravatar.cc/36",
88
+ firstName: "Dave",
89
+ lastName: "Johannisburger",
90
+ url: "",
91
+ },
92
+ content:
93
+ "Onec euismod, nisl eget consectetur tempor, nisl nunc egestas nisi, euismod aliquam.",
94
+ created: new Date(),
95
+ hasReacted: false,
96
+ onReact: jest.fn(),
97
+ onReply: jest.fn(),
98
+ reactions: 1,
99
+ },
100
+ ];
101
+ render(<Comment {...props}></Comment>);
102
+ expect(screen.getByText("Show Replies"));
103
+ expect(screen.getByTestId("reply-line-bottom"));
104
+ });
105
+ });
@@ -0,0 +1,157 @@
1
+ import React from "react";
2
+ import commentStyles from "./Comment.module.scss";
3
+ import { abbrRelativeTimeString } from "@soul-refiner/utils/src";
4
+ import { Comment as IComment } from "@soul-refiner/models";
5
+
6
+ import { Avatar } from "../../iconography";
7
+ import { PostInput } from "../../inputs";
8
+ import {
9
+ Circle,
10
+ CommentOutline,
11
+ Like,
12
+ LikeOutline,
13
+ } from "@soul-refiner/icons/src";
14
+
15
+ export interface CommentProps extends IComment {
16
+ onReact: () => void;
17
+ onReply: (reply: string) => void;
18
+ onShowReplies?: () => void;
19
+ replies?: IComment[];
20
+ showReplies: boolean;
21
+ }
22
+
23
+ export const Comment = ({
24
+ id,
25
+ parentId,
26
+ user,
27
+ text,
28
+ created,
29
+ onReact,
30
+ onReply,
31
+ onShowReplies,
32
+ replies,
33
+ reactions,
34
+ showReplies,
35
+ }: CommentProps) => {
36
+ const [showReplyInput, setshowReplyInput] = React.useState(false);
37
+ const [reply, setReply] = React.useState("");
38
+
39
+ const handleshowReplyInput = () => setshowReplyInput(true);
40
+
41
+ const handleReplyChange = (
42
+ event: React.KeyboardEvent<HTMLTextAreaElement>
43
+ ) => {
44
+ setReply((event.target as HTMLTextAreaElement).value);
45
+ };
46
+
47
+ const handleReplySubmit = (
48
+ event: React.KeyboardEvent<HTMLTextAreaElement>
49
+ ) => {
50
+ if (event.key === "Enter") {
51
+ onReply(reply);
52
+ setshowReplyInput(false);
53
+ setReply("");
54
+ }
55
+ };
56
+
57
+ const numReplies = replies ? replies.length : 0;
58
+
59
+ return (
60
+ <div className={`${commentStyles.comment}`} data-commentid={id}>
61
+ <Avatar
62
+ as="a"
63
+ href={user?.url ? user.url : ""}
64
+ size={32}
65
+ url={user?.avatar ? user.avatar : ""}
66
+ />
67
+ <div className="content-wrapper">
68
+ <div className={`${numReplies > 0 ? "has-replies" : ""}`}>
69
+ <p className="comment body">
70
+ <span className="lead name">
71
+ {user.firstName} {user.lastName}
72
+ </span>
73
+ <span className="body-large">{text}</span>
74
+ </p>
75
+ <div className="actions-wrapper">
76
+ {reactions.some((reaction) => reaction.userId !== user.id) ? (
77
+ <Like
78
+ className="interactive"
79
+ data-testid="liked-icon"
80
+ fill="var(--colorify-blue-3)"
81
+ iconSize={18}
82
+ onClick={onReact}
83
+ size={18}
84
+ />
85
+ ) : (
86
+ <LikeOutline
87
+ className="interactive"
88
+ data-testid="not-liked-icon"
89
+ fill="var(--colorify-blue-3)"
90
+ iconSize={18}
91
+ onClick={onReact}
92
+ size={18}
93
+ />
94
+ )}
95
+ <CommentOutline
96
+ className="interactive"
97
+ fill="var(--colorify-blue-3)"
98
+ iconSize={16}
99
+ onClick={handleshowReplyInput}
100
+ size={18}
101
+ />
102
+ <Circle fill="var(--color-grey-7" iconSize={3} size={3} />
103
+ <p>{abbrRelativeTimeString(new Date(created))}</p>
104
+ {!!reactions && (
105
+ <div className="likes-wrapper" data-testid="likes-wrapper">
106
+ <Like fill="white" iconSize={10} inline size={18} />
107
+ <p>{reactions.length}</p>
108
+ </div>
109
+ )}
110
+ </div>
111
+ {showReplyInput && (
112
+ <PostInput
113
+ onChange={handleReplyChange}
114
+ onKeyDown={handleReplySubmit}
115
+ placeholder="Write a reply"
116
+ value={reply}
117
+ />
118
+ )}
119
+ </div>
120
+ {numReplies > 0 && (
121
+ <div className={`${commentStyles.replies}`}>
122
+ {showReplies ? (
123
+ replies &&
124
+ replies.map(({ ...reply }, index) => (
125
+ <div
126
+ className={index !== numReplies - 1 ? "is-reply" : ""}
127
+ key={reply.id + text.length + index}
128
+ style={{ position: "relative" }}
129
+ >
130
+ <Comment
131
+ onReact={onReact}
132
+ onReply={onReply}
133
+ onShowReplies={onShowReplies}
134
+ showReplies={true}
135
+ {...reply}
136
+ />
137
+ <div className="reply-line-bottom"></div>
138
+ </div>
139
+ ))
140
+ ) : (
141
+ <div
142
+ onClick={onShowReplies}
143
+ style={{ position: "relative", width: "fit-content" }}
144
+ >
145
+ <p className="show-replies">Show Replies</p>
146
+ <div
147
+ className="reply-line-bottom"
148
+ data-testid="reply-line-bottom"
149
+ ></div>
150
+ </div>
151
+ )}
152
+ </div>
153
+ )}
154
+ </div>
155
+ </div>
156
+ );
157
+ };
@@ -0,0 +1 @@
1
+ export { Comment, type CommentProps } from "./Comment";
@@ -0,0 +1,91 @@
1
+ @use "@soul-refiner/styles/mixins";
2
+ .faq,
3
+ .create {
4
+ display: flex;
5
+ flex-grow: 1;
6
+ align-self: stretch;
7
+ padding: 14px 16px;
8
+ background-color: var(--color-grey-9);
9
+ flex-direction: column;
10
+ border-radius: var(--border-radius-small);
11
+ gap: 16px;
12
+
13
+ .header {
14
+ display: flex;
15
+ flex-direction: row;
16
+ justify-content: space-between;
17
+ flex: 1;
18
+ place-items: center;
19
+ gap: 16px;
20
+ }
21
+
22
+ input,
23
+ textarea {
24
+ padding: 16px;
25
+ background-color: var(--color-grey-10);
26
+ border: none;
27
+ border-radius: var(--border-radius-small);
28
+ width: 100%;
29
+ resize: vertical;
30
+ outline: none;
31
+ color: var(--color-grey-3);
32
+ box-shadow: inset 0px 4px 4px rgb(0 0 0 / 3%);
33
+ }
34
+
35
+ input {
36
+ width: 50%;
37
+ }
38
+
39
+ .contentArea {
40
+ white-space: pre-line;
41
+ color: var(--color-grey-0);
42
+ padding-bottom: 16px;
43
+ }
44
+
45
+ .entry {
46
+ font-size: var(--size-20);
47
+ font-weight: var(--weight-inter-semibold);
48
+ }
49
+
50
+ .arrowUp {
51
+ transform: rotate(180deg);
52
+ }
53
+
54
+ [class~="row"] {
55
+ display: flex;
56
+ flex-direction: row;
57
+ gap: 16px;
58
+ place-items: center;
59
+ }
60
+
61
+ [class~="actions"] {
62
+ @include mixins.flex($justify: flex-end, $gap: 4px);
63
+ width: 100%;
64
+ button {
65
+ background-color: var(--color-grey-10);
66
+ box-shadow: 0px 3px 5px rgba(9, 30, 66, 0.2),
67
+ 0px 0px 1px rgba(9, 30, 66, 0.31);
68
+ border-radius: 3px;
69
+
70
+ &:hover {
71
+ background-color: var(--color-blue-9);
72
+ }
73
+
74
+ &:active {
75
+ background-color: var(--color-grey-4);
76
+ color: var(--color-grey-10);
77
+ svg {
78
+ fill: var(--color-grey-10);
79
+ }
80
+ }
81
+ }
82
+ }
83
+ }
84
+
85
+ .create {
86
+ border: 1px dashed #97a0a3;
87
+ font-size: var(--size-20);
88
+ font-weight: var(--weight-inter-semibold);
89
+ color: var(--color-grey-0);
90
+ background-color: transparent;
91
+ }
@@ -0,0 +1,38 @@
1
+ import React from "react";
2
+ import "@testing-library/jest-dom";
3
+ import { render, screen, fireEvent } from "@testing-library/react";
4
+
5
+
6
+ import { Faq } from "./Faq";
7
+
8
+ const generateProps = props => ({
9
+ editable: true,
10
+ title: "What is Soul Refiner?",
11
+ content: "Soul Refiner is the streaming platform that makes it possible for anyone to watch or listen to hundreds of video lessons taught by 150+ of the world’s best.",
12
+ creationMode: false,
13
+ onSubmit: jest.fn(e => e.preventDefault()),
14
+ ...props
15
+ });
16
+
17
+ describe("FAQ", () => {
18
+ it("adds another", () => {
19
+ const props = generateProps();
20
+ render(<Faq {...props} />);
21
+ fireEvent.click(screen.getByText("Add a FAQ"));
22
+ let title = screen.getByPlaceholderText("Title");
23
+ let content = screen.getByPlaceholderText("Your FAQ content...");
24
+ expect(title).toHaveAttribute(
25
+ "value",
26
+ "What is Soul Refiner?"
27
+ );
28
+ expect(content.value).toEqual(
29
+ "Soul Refiner is the streaming platform that makes it possible for anyone to watch or listen to hundreds of video lessons taught by 150+ of the world’s best."
30
+ );
31
+ const submit = screen.getByTestId("faq-submit");
32
+ fireEvent.click(submit);
33
+ title = screen.getByText("What is Soul Refiner?");
34
+ content = screen.getByText("Soul Refiner is the streaming platform that makes it possible for anyone to watch or listen to hundreds of video lessons taught by 150+ of the world’s best.");
35
+ expect(title.tagName).toEqual("H3");
36
+ expect(content.tagName).toEqual("P");
37
+ });
38
+ })
@@ -0,0 +1,156 @@
1
+ import React, { useEffect, useState } from "react";
2
+ import { Component } from "@soul-refiner/utils/src";
3
+ import { Check, Close, ChevronDown, Pencil } from "@soul-refiner/icons/src";
4
+ import faqStyles from "./Faq.module.scss";
5
+
6
+ export interface FaqProps {
7
+ title: string;
8
+ content: string;
9
+ editable: boolean;
10
+ creationMode: boolean;
11
+ onSubmit: (
12
+ event: React.FormEvent,
13
+ props: { title: string; content: string }
14
+ ) => void;
15
+ }
16
+
17
+ export const Faq = ({
18
+ title = "",
19
+ content = "",
20
+ editable,
21
+ creationMode,
22
+ onSubmit,
23
+ }: FaqProps) => {
24
+ const [createFaq, setCreateFaq] = useState(creationMode);
25
+ const [editing, setEditing] = useState(false);
26
+ const [collapsed, setCollapsed] = useState(true);
27
+ const [details, setDetails] = useState(() => ({
28
+ title: title,
29
+ content: content,
30
+ }));
31
+
32
+ React.useEffect(() => {
33
+ setCreateFaq(creationMode);
34
+ }, [creationMode]);
35
+
36
+ const handleReset = () => {
37
+ if (details.title === "" && details.content === "") {
38
+ setCreateFaq(false);
39
+ } else {
40
+ setDetails({
41
+ title: title,
42
+ content: content,
43
+ });
44
+ }
45
+ setEditing(false);
46
+ };
47
+
48
+ const handleCreateFaq = () => {
49
+ setCreateFaq(true);
50
+ setEditing(true);
51
+ setCollapsed(false);
52
+ };
53
+
54
+ const handleSubmit = (event: React.FormEvent) => {
55
+ setEditing(false);
56
+ onSubmit(event, details);
57
+ };
58
+
59
+ const handleChange = (e: React.FormEvent) => {
60
+ const element: HTMLInputElement = e.target as HTMLInputElement;
61
+
62
+ setDetails((prev) => ({
63
+ ...prev,
64
+ [element.name]: element.value,
65
+ }));
66
+ };
67
+
68
+ if (!createFaq) {
69
+ return (
70
+ <>
71
+ <button className={faqStyles.create} onClick={handleCreateFaq}>
72
+ Add a FAQ
73
+ </button>
74
+ </>
75
+ );
76
+ }
77
+
78
+ return (
79
+ <>
80
+ <Component as={editing ? "form" : "div"} className={faqStyles.faq}>
81
+ <div className={faqStyles.header}>
82
+ <Component
83
+ as={editing ? "input" : "h3"}
84
+ className={faqStyles.entry}
85
+ children={editing ? undefined : details.title}
86
+ name="title"
87
+ onChange={handleChange}
88
+ value={details.title}
89
+ data-form-type="other"
90
+ placeholder="Title"
91
+ />
92
+
93
+ <div className="row">
94
+ {!editing && editable && (
95
+ <Pencil
96
+ as="button"
97
+ fill="var(--color-grey-4)"
98
+ iconSize={14}
99
+ size={24}
100
+ onClick={() => {
101
+ setEditing(true);
102
+ setCollapsed(false);
103
+ }}
104
+ />
105
+ )}
106
+
107
+ <ChevronDown
108
+ as="button"
109
+ fill="var(--color-grey-0)"
110
+ iconSize={16}
111
+ size={32}
112
+ className={!collapsed ? faqStyles.arrowUp : ""}
113
+ onClick={() => setCollapsed(!collapsed)}
114
+ />
115
+ </div>
116
+ </div>
117
+
118
+ {!collapsed && (
119
+ <div className={faqStyles.contentArea}>
120
+ <Component
121
+ as={editing ? "textarea" : "p"}
122
+ rows={3}
123
+ className={faqStyles.content}
124
+ children={editing ? undefined : details.content}
125
+ name="content"
126
+ onChange={handleChange}
127
+ value={details.content}
128
+ placeholder="Your FAQ content..."
129
+ />
130
+ </div>
131
+ )}
132
+
133
+ {editing && (
134
+ <div className="actions">
135
+ <Check
136
+ as="button"
137
+ data-testid="faq-submit"
138
+ fill="var(--color-grey-4)"
139
+ iconSize={10}
140
+ onClick={handleSubmit}
141
+ size={32}
142
+ />
143
+ <Close
144
+ as="button"
145
+ data-testid="faq-reset"
146
+ fill="var(--color-grey-4)"
147
+ iconSize={10}
148
+ onClick={handleReset}
149
+ size={32}
150
+ />
151
+ </div>
152
+ )}
153
+ </Component>
154
+ </>
155
+ );
156
+ };
@@ -0,0 +1 @@
1
+ export { Faq, type FaqProps } from "./Faq";
@@ -0,0 +1,37 @@
1
+ @use "@soul-refiner/styles/_mixins";
2
+
3
+ .message {
4
+ margin-bottom: 64px;
5
+
6
+ & > div:first-of-type {
7
+ justify-content: flex-start;
8
+ }
9
+
10
+ &[class~="fromSelf"] {
11
+ & > div:first-of-type {
12
+ justify-content: flex-end;
13
+ }
14
+ }
15
+ }
16
+
17
+ .individual {
18
+ max-width: 480px;
19
+ margin: 10px 70px;
20
+ border-radius: 18px;
21
+ border-top-left-radius: 0px;
22
+ padding: 20px 16px;
23
+ background-color: var(--color-grey-9);
24
+ & > * {
25
+ color: var(--color-grey-1);
26
+ }
27
+
28
+ &[class~="fromSelf"] {
29
+ border-top-left-radius: 18px;
30
+ border-top-right-radius: 0px;
31
+ background-color: var(--color-blue-3);
32
+ margin-left: auto;
33
+ & > * {
34
+ color: #ffffff;
35
+ }
36
+ }
37
+ }