@weavy/uikit-react 11.2.0 → 12.1.0
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.
- package/.github/workflows/publish.yml +1 -1
- package/changelog.md +15 -0
- package/dist/cjs/index.js +6 -6
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/types/components/Image.d.ts +2 -0
- package/dist/cjs/types/components/PdfViewer.d.ts +6 -0
- package/dist/cjs/types/components/Preview.d.ts +58 -0
- package/dist/cjs/types/types/types.d.ts +1 -0
- package/dist/cjs/types/utils/fileUtilities.d.ts +16 -1
- package/dist/css/weavy-chat.css +2684 -0
- package/dist/css/weavy-messenger.css +3039 -0
- package/dist/css/weavy.css +3039 -0
- package/dist/esm/index.js +6 -6
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/types/components/Image.d.ts +2 -0
- package/dist/esm/types/components/PdfViewer.d.ts +6 -0
- package/dist/esm/types/components/Preview.d.ts +58 -0
- package/dist/esm/types/types/types.d.ts +1 -0
- package/dist/esm/types/utils/fileUtilities.d.ts +16 -1
- package/package.json +14 -4
- package/rollup.config.js +0 -2
- package/src/components/Attachment.tsx +5 -6
- package/src/components/Avatar.tsx +2 -3
- package/src/components/Chat.tsx +3 -4
- package/src/components/Conversation.tsx +20 -29
- package/src/components/ConversationBadge.tsx +1 -2
- package/src/components/ConversationForm.tsx +11 -18
- package/src/components/ConversationList.tsx +4 -5
- package/src/components/ConversationListItem.tsx +11 -13
- package/src/components/FileBrowser.tsx +1 -2
- package/src/components/Image.tsx +39 -7
- package/src/components/MeetingCard.tsx +7 -8
- package/src/components/Message.tsx +12 -13
- package/src/components/Messages.tsx +6 -7
- package/src/components/Messenger.tsx +3 -4
- package/src/components/NewConversation.tsx +5 -7
- package/src/components/PdfViewer.tsx +271 -0
- package/src/components/Presence.tsx +2 -2
- package/src/components/Preview.tsx +294 -0
- package/src/components/Reactions.tsx +6 -7
- package/src/components/SearchUsers.tsx +17 -16
- package/src/components/SeenBy.tsx +1 -2
- package/src/contexts/PreviewContext.tsx +4 -6
- package/src/hooks/useConversation.ts +0 -1
- package/src/hooks/usePresence.ts +4 -5
- package/src/hooks/useReactions.ts +0 -1
- package/src/scss/theme/_alert.scss +73 -0
- package/src/scss/theme/_appbar.scss +112 -0
- package/src/scss/theme/_attachments.scss +74 -0
- package/src/scss/theme/_avatar.scss +54 -0
- package/src/scss/theme/_badge.scss +47 -0
- package/src/scss/theme/_buttons.scss +96 -0
- package/src/scss/theme/_card.scss +7 -0
- package/src/scss/theme/_checkbox.scss +56 -0
- package/src/scss/theme/_cm-editor.scss +42 -0
- package/src/scss/theme/_code.scss +115 -0
- package/src/scss/theme/_colors.scss +520 -0
- package/src/scss/theme/_config.scss +6 -0
- package/src/scss/theme/_content.scss +15 -0
- package/src/scss/theme/_conversations.scss +91 -0
- package/src/scss/theme/_dropdown.scss +86 -0
- package/src/scss/theme/_emoji.scss +5 -0
- package/src/scss/theme/_filebrowser.scss +26 -0
- package/src/scss/theme/_files.scss +140 -0
- package/src/scss/theme/_icons.scss +62 -0
- package/src/scss/theme/_image-grid.scss +63 -0
- package/src/scss/theme/_inputs.scss +28 -0
- package/src/scss/theme/_message-editor.scss +90 -0
- package/src/scss/theme/_messages.scss +238 -0
- package/src/scss/theme/_nav.scss +52 -0
- package/src/scss/theme/_overlays.scss +157 -0
- package/src/scss/theme/_pager.scss +19 -0
- package/src/scss/theme/_palette.scss +165 -0
- package/src/scss/theme/_pane.scss +16 -0
- package/src/scss/theme/_panels.scss +137 -0
- package/src/scss/theme/_picker-list.scss +37 -0
- package/src/scss/theme/_preview-embed.scss +38 -0
- package/src/scss/theme/_preview-html.scss +7 -0
- package/src/scss/theme/_preview-icon.scss +41 -0
- package/src/scss/theme/_preview-image.scss +86 -0
- package/src/scss/theme/_preview-media.scss +28 -0
- package/src/scss/theme/_preview-pdf.scss +838 -0
- package/src/scss/theme/_preview-text.scss +5 -0
- package/src/scss/theme/_preview.scss +105 -0
- package/src/scss/theme/_reactions.scss +58 -0
- package/src/scss/theme/_reboot.scss +41 -0
- package/src/scss/theme/_root.scss +2 -0
- package/src/scss/theme/_scroll.scss +55 -0
- package/src/scss/theme/_search.scss +68 -0
- package/src/scss/theme/_spinner.scss +63 -0
- package/src/scss/theme/_tables.scss +53 -0
- package/src/scss/theme/_toasts.scss +47 -0
- package/src/scss/theme/_turbo.scss +17 -0
- package/src/scss/theme/_typing.scss +26 -0
- package/src/scss/theme/_variables.scss +139 -0
- package/src/scss/theme/bootstrap/_accordion.scss +146 -0
- package/src/scss/theme/bootstrap/_alert.scss +71 -0
- package/src/scss/theme/bootstrap/_badge.scss +38 -0
- package/src/scss/theme/bootstrap/_breadcrumb.scss +40 -0
- package/src/scss/theme/bootstrap/_button-group.scss +142 -0
- package/src/scss/theme/bootstrap/_buttons.scss +186 -0
- package/src/scss/theme/bootstrap/_card.scss +234 -0
- package/src/scss/theme/bootstrap/_carousel.scss +229 -0
- package/src/scss/theme/bootstrap/_close.scss +40 -0
- package/src/scss/theme/bootstrap/_containers.scss +41 -0
- package/src/scss/theme/bootstrap/_dropdown.scss +248 -0
- package/src/scss/theme/bootstrap/_forms.scss +9 -0
- package/src/scss/theme/bootstrap/_functions.scss +302 -0
- package/src/scss/theme/bootstrap/_grid.scss +33 -0
- package/src/scss/theme/bootstrap/_helpers.scss +10 -0
- package/src/scss/theme/bootstrap/_images.scss +42 -0
- package/src/scss/theme/bootstrap/_list-group.scss +191 -0
- package/src/scss/theme/bootstrap/_maps.scss +54 -0
- package/src/scss/theme/bootstrap/_mixins.scss +43 -0
- package/src/scss/theme/bootstrap/_modal.scss +237 -0
- package/src/scss/theme/bootstrap/_nav.scss +172 -0
- package/src/scss/theme/bootstrap/_navbar.scss +276 -0
- package/src/scss/theme/bootstrap/_offcanvas.scss +143 -0
- package/src/scss/theme/bootstrap/_pagination.scss +109 -0
- package/src/scss/theme/bootstrap/_placeholders.scss +51 -0
- package/src/scss/theme/bootstrap/_popover.scss +196 -0
- package/src/scss/theme/bootstrap/_progress.scss +59 -0
- package/src/scss/theme/bootstrap/_reboot.scss +610 -0
- package/src/scss/theme/bootstrap/_root.scss +73 -0
- package/src/scss/theme/bootstrap/_spinners.scss +85 -0
- package/src/scss/theme/bootstrap/_tables.scss +164 -0
- package/src/scss/theme/bootstrap/_toasts.scss +70 -0
- package/src/scss/theme/bootstrap/_tooltip.scss +120 -0
- package/src/scss/theme/bootstrap/_transitions.scss +27 -0
- package/src/scss/theme/bootstrap/_type.scss +106 -0
- package/src/scss/theme/bootstrap/_utilities.scss +647 -0
- package/src/scss/theme/bootstrap/_variables.scss +1633 -0
- package/src/scss/theme/bootstrap/forms/_floating-labels.scss +74 -0
- package/src/scss/theme/bootstrap/forms/_form-check.scss +175 -0
- package/src/scss/theme/bootstrap/forms/_form-control.scss +194 -0
- package/src/scss/theme/bootstrap/forms/_form-range.scss +91 -0
- package/src/scss/theme/bootstrap/forms/_form-select.scss +71 -0
- package/src/scss/theme/bootstrap/forms/_form-text.scss +11 -0
- package/src/scss/theme/bootstrap/forms/_input-group.scss +129 -0
- package/src/scss/theme/bootstrap/forms/_labels.scss +36 -0
- package/src/scss/theme/bootstrap/forms/_validation.scss +12 -0
- package/src/scss/theme/bootstrap/helpers/_clearfix.scss +3 -0
- package/src/scss/theme/bootstrap/helpers/_color-bg.scss +10 -0
- package/src/scss/theme/bootstrap/helpers/_colored-links.scss +12 -0
- package/src/scss/theme/bootstrap/helpers/_position.scss +36 -0
- package/src/scss/theme/bootstrap/helpers/_ratio.scss +26 -0
- package/src/scss/theme/bootstrap/helpers/_stacks.scss +15 -0
- package/src/scss/theme/bootstrap/helpers/_stretched-link.scss +15 -0
- package/src/scss/theme/bootstrap/helpers/_text-truncation.scss +7 -0
- package/src/scss/theme/bootstrap/helpers/_visually-hidden.scss +8 -0
- package/src/scss/theme/bootstrap/helpers/_vr.scss +8 -0
- package/src/scss/theme/bootstrap/mixins/_alert.scss +15 -0
- package/src/scss/theme/bootstrap/mixins/_backdrop.scss +14 -0
- package/src/scss/theme/bootstrap/mixins/_banner.scss +9 -0
- package/src/scss/theme/bootstrap/mixins/_border-radius.scss +78 -0
- package/src/scss/theme/bootstrap/mixins/_box-shadow.scss +18 -0
- package/src/scss/theme/bootstrap/mixins/_breakpoints.scss +127 -0
- package/src/scss/theme/bootstrap/mixins/_buttons.scss +70 -0
- package/src/scss/theme/bootstrap/mixins/_caret.scss +64 -0
- package/src/scss/theme/bootstrap/mixins/_clearfix.scss +9 -0
- package/src/scss/theme/bootstrap/mixins/_color-scheme.scss +7 -0
- package/src/scss/theme/bootstrap/mixins/_container.scss +11 -0
- package/src/scss/theme/bootstrap/mixins/_deprecate.scss +10 -0
- package/src/scss/theme/bootstrap/mixins/_forms.scss +152 -0
- package/src/scss/theme/bootstrap/mixins/_gradients.scss +47 -0
- package/src/scss/theme/bootstrap/mixins/_grid.scss +151 -0
- package/src/scss/theme/bootstrap/mixins/_image.scss +16 -0
- package/src/scss/theme/bootstrap/mixins/_list-group.scss +24 -0
- package/src/scss/theme/bootstrap/mixins/_lists.scss +7 -0
- package/src/scss/theme/bootstrap/mixins/_pagination.scss +10 -0
- package/src/scss/theme/bootstrap/mixins/_reset-text.scss +17 -0
- package/src/scss/theme/bootstrap/mixins/_resize.scss +6 -0
- package/src/scss/theme/bootstrap/mixins/_table-variants.scss +24 -0
- package/src/scss/theme/bootstrap/mixins/_text-truncate.scss +8 -0
- package/src/scss/theme/bootstrap/mixins/_transition.scss +26 -0
- package/src/scss/theme/bootstrap/mixins/_utilities.scss +97 -0
- package/src/scss/theme/bootstrap/mixins/_visually-hidden.scss +29 -0
- package/src/scss/theme/bootstrap/utilities/_api.scss +47 -0
- package/src/scss/theme/bootstrap/vendor/_rfs.scss +354 -0
- package/src/scss/theme/bs/_badge.scss +20 -0
- package/src/scss/theme/bs/_buttons.scss +185 -0
- package/src/scss/theme/bs/_dropdown.scss +86 -0
- package/src/scss/theme/bs/_forms.scss +161 -0
- package/src/scss/theme/bs/_list-group.scss +73 -0
- package/src/scss/theme/bs/_tables.scss +46 -0
- package/src/scss/theme/fonts/_fontmapping-roboto.scss +129 -0
- package/src/scss/theme/fonts/_fontmapping-segoe-ui.scss +127 -0
- package/src/scss/theme/fonts/_index.scss +2 -0
- package/src/scss/theme/mixins/_backdrop.scss +13 -0
- package/src/scss/theme/mixins/_palette.scss +165 -0
- package/src/scss/theme/mixins/_position.scss +33 -0
- package/src/scss/theme/mixins/_scrollbar.scss +110 -0
- package/src/scss/weavy-chat.scss +31 -0
- package/src/scss/weavy-messenger.scss +60 -0
- package/src/scss/weavy.scss +2 -0
- package/src/types/types.ts +2 -0
- package/src/ui/Button.tsx +3 -4
- package/src/ui/Dropdown.tsx +4 -5
- package/src/ui/Icon.tsx +75 -39
- package/src/ui/Overlay.tsx +2 -3
- package/src/utils/fileUtilities.ts +280 -72
- package/src/utils/scrollbarDetection.js +5 -7
- package/dist/cjs/types/utils/styles.d.ts +0 -17
- package/dist/esm/types/utils/styles.d.ts +0 -17
- package/src/utils/styles.ts +0 -57
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
import React, { useEffect, useState, useCallback } from "react";
|
|
2
|
+
import Icon from "../ui/Icon";
|
|
3
|
+
import classNames from "classnames";
|
|
4
|
+
import PdfViewer from "./PdfViewer";
|
|
5
|
+
import { checkImageLoad, imageLoaded } from "./Image";
|
|
6
|
+
|
|
7
|
+
const getStream = (response: Response) => {
|
|
8
|
+
if (response && response.ok && response.body) {
|
|
9
|
+
const reader = response.body.getReader();
|
|
10
|
+
return new ReadableStream({
|
|
11
|
+
start(controller) {
|
|
12
|
+
let pump: any = () => {
|
|
13
|
+
return reader.read().then(({ done, value }) => {
|
|
14
|
+
// When no more data needs to be consumed, close the stream
|
|
15
|
+
if (done) {
|
|
16
|
+
controller.close();
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
// Enqueue the next data chunk into our target stream
|
|
20
|
+
controller.enqueue(value);
|
|
21
|
+
return pump();
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return pump();
|
|
26
|
+
}
|
|
27
|
+
})
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
type ImageProps = {
|
|
32
|
+
src: string,
|
|
33
|
+
width?: number,
|
|
34
|
+
height?: number
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export const PreviewImage = ({ src, width, height }: ImageProps) => {
|
|
38
|
+
const imageRef = useCallback((element: HTMLImageElement) => {
|
|
39
|
+
if (element) {
|
|
40
|
+
checkImageLoad(element);
|
|
41
|
+
}
|
|
42
|
+
}, [])
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<>
|
|
46
|
+
{width && height ?
|
|
47
|
+
<div className="wy-content-image wy-responsive-image" style={{ ["--width" as any]: width, ["--height" as any]: height }}>
|
|
48
|
+
<img ref={imageRef} src={src} onLoad={imageLoaded} width={width} height={height} decoding="async" />
|
|
49
|
+
{/* TODO: spinner here */}
|
|
50
|
+
</div>
|
|
51
|
+
:
|
|
52
|
+
<div className="wy-content-image wy-responsive-image wy-intrinsic-image">
|
|
53
|
+
<img ref={imageRef} src={src} onLoad={imageLoaded} decoding="async" />
|
|
54
|
+
</div>
|
|
55
|
+
}
|
|
56
|
+
</>
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
type DocumentProps = {
|
|
61
|
+
src: string
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export const PreviewDocument = ({ src }: DocumentProps) => {
|
|
65
|
+
return (
|
|
66
|
+
<PdfViewer src={src} />
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function mediaFallback(media: HTMLVideoElement | HTMLAudioElement) {
|
|
71
|
+
if (media.classList.contains("wy-loading")) {
|
|
72
|
+
media.classList.add("wy-loaded");
|
|
73
|
+
}
|
|
74
|
+
media.classList.add("wy-error");
|
|
75
|
+
// TODO: replace with react way
|
|
76
|
+
media.outerHTML = media.outerHTML.replace(/<(video|audio)/, "<div").replace(/(video|audio)>/, "div>");
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function mediaLoaded(event: any) {
|
|
80
|
+
var src = event.target;
|
|
81
|
+
if (src.tagName === 'VIDEO' || src.tagName === 'AUDIO') {
|
|
82
|
+
if (src.classList.contains("wy-loading")) {
|
|
83
|
+
console.log("loaded")
|
|
84
|
+
src.classList.add("wy-loaded");
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function mediaError(event: any) {
|
|
90
|
+
var src = event.target;
|
|
91
|
+
var media;
|
|
92
|
+
if (src.tagName === 'SOURCE') {
|
|
93
|
+
media = src.parentNode;
|
|
94
|
+
media.dataset.errors = (media.dataset.errors || 0) + 1;
|
|
95
|
+
|
|
96
|
+
if (media.querySelectorAll("source").length >= media.dataset.errors) {
|
|
97
|
+
console.warn(media.tagName.toLowerCase() + " source error, switching to fallback");
|
|
98
|
+
mediaFallback(media);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function codecError(event: any) {
|
|
104
|
+
var src = event.target;
|
|
105
|
+
if (src.tagName === 'VIDEO' || src.tagName === 'AUDIO') {
|
|
106
|
+
// Capture codec-error for video in firefox
|
|
107
|
+
if (src.tagName === 'VIDEO' && !src.videoWidth || src.tagName === 'AUDIO' && !src.duration) {
|
|
108
|
+
console.warn(src.tagName.toLowerCase() + " track not available, switching to fallback");
|
|
109
|
+
mediaFallback(src);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
type VideoProps = {
|
|
115
|
+
src: string,
|
|
116
|
+
name: string,
|
|
117
|
+
mediaType?: string
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export const PreviewVideo = ({ src, name, mediaType }: VideoProps) => {
|
|
121
|
+
/* TODO: loading, error handling and stopping */
|
|
122
|
+
|
|
123
|
+
return (
|
|
124
|
+
<>
|
|
125
|
+
<video className="wy-content-video" controls crossOrigin="use-credentials" autoPlay>
|
|
126
|
+
<source src={src} type={mediaType} />
|
|
127
|
+
<PreviewIcon src={src} name={name} icon="file-video" download />
|
|
128
|
+
</video>
|
|
129
|
+
{/* TODO: spinner here */}
|
|
130
|
+
</>
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
type AudioProps = {
|
|
135
|
+
src: string,
|
|
136
|
+
name: string,
|
|
137
|
+
mediaType?: string
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export const PreviewAudio = ({ src, name, mediaType }: AudioProps) => {
|
|
141
|
+
/* TODO: loading, error handling and stopping */
|
|
142
|
+
return (
|
|
143
|
+
<>
|
|
144
|
+
<PreviewIcon src={src} name={name} icon="file-music" download>
|
|
145
|
+
<audio className="wy-content-audio" controls crossOrigin="use-credentials" autoPlay>
|
|
146
|
+
<source src={src} type={mediaType} />
|
|
147
|
+
</audio>
|
|
148
|
+
</PreviewIcon>
|
|
149
|
+
</>
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
type TextProps = {
|
|
154
|
+
src: string,
|
|
155
|
+
html?: boolean,
|
|
156
|
+
code?: boolean
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export const PreviewText = ({ src, html = false, code = false }: TextProps) => {
|
|
160
|
+
const [textContent, setTextContent] = useState("");
|
|
161
|
+
|
|
162
|
+
useEffect(() => {
|
|
163
|
+
fetch(src)
|
|
164
|
+
.then(getStream)
|
|
165
|
+
// Create a new response out of the stream
|
|
166
|
+
.then(stream => new Response(stream))
|
|
167
|
+
// Create an object URL for the response
|
|
168
|
+
.then(response => response.text())
|
|
169
|
+
.then(text => {
|
|
170
|
+
setTextContent(text)
|
|
171
|
+
})
|
|
172
|
+
}, [src]);
|
|
173
|
+
|
|
174
|
+
return (
|
|
175
|
+
<>
|
|
176
|
+
{html ?
|
|
177
|
+
code ?
|
|
178
|
+
<div className="wy-content-code" dangerouslySetInnerHTML={{ __html: textContent }}></div>
|
|
179
|
+
:
|
|
180
|
+
<div className="wy-content-text">
|
|
181
|
+
<pre className="wy-document" dangerouslySetInnerHTML={{ __html: textContent }}></pre>
|
|
182
|
+
</div>
|
|
183
|
+
:
|
|
184
|
+
code ?
|
|
185
|
+
<div className="wy-content-code">{textContent}</div>
|
|
186
|
+
:
|
|
187
|
+
<div className="wy-content-text">
|
|
188
|
+
<pre className="wy-document">{textContent}</pre>
|
|
189
|
+
</div>
|
|
190
|
+
}
|
|
191
|
+
</>
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
type EmbedProps = {
|
|
196
|
+
src: string,
|
|
197
|
+
name: string,
|
|
198
|
+
icon: string,
|
|
199
|
+
provider?: string
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export const PreviewEmbed = ({ src, name, icon, provider }: EmbedProps) => {
|
|
203
|
+
/* TODO: add loading and error handling */
|
|
204
|
+
return (
|
|
205
|
+
<>
|
|
206
|
+
{/* iframe needs to be object to not render error pages when content is blocked */}
|
|
207
|
+
<object className="wy-content-iframe" data={src}></object>
|
|
208
|
+
|
|
209
|
+
{/* TODO: add spinner here */}
|
|
210
|
+
|
|
211
|
+
<PreviewIcon src={src} name={name} icon={icon} provider={provider} className="wy-content-iframe-fallback" />
|
|
212
|
+
</>
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
type IconProps = {
|
|
217
|
+
children?: React.ReactNode,
|
|
218
|
+
src: string,
|
|
219
|
+
icon: string,
|
|
220
|
+
name: string,
|
|
221
|
+
provider?: string,
|
|
222
|
+
download?: boolean,
|
|
223
|
+
className?: string
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
export const PreviewIcon = ({ children, src, icon, name, provider, download = false, className }: IconProps) => {
|
|
227
|
+
return (
|
|
228
|
+
<div className={classNames("wy-content-media", className)}>
|
|
229
|
+
<div className="wy-content-icon">
|
|
230
|
+
<Icon.UI name={icon} />
|
|
231
|
+
</div>
|
|
232
|
+
<div className="wy-content-name">
|
|
233
|
+
{provider ?
|
|
234
|
+
<a href={src} target="_blank" title={`Open in ${provider}`}>{name} <Icon.UI name="open-in-new" size={1} /></a>
|
|
235
|
+
: download ?
|
|
236
|
+
<a href={src} target="_top" download>{name}</a>
|
|
237
|
+
:
|
|
238
|
+
<a href={src} target="_blank">{name} <Icon.UI name="open-in-new" size={1} /></a>
|
|
239
|
+
}
|
|
240
|
+
</div>
|
|
241
|
+
{children}
|
|
242
|
+
</div>
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
type PreviewProps = {
|
|
247
|
+
src: string,
|
|
248
|
+
format: PreviewFormatType,
|
|
249
|
+
name: string,
|
|
250
|
+
icon: string,
|
|
251
|
+
width?: number,
|
|
252
|
+
height?: number,
|
|
253
|
+
mediaType?: string,
|
|
254
|
+
provider?: string
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
export const Preview = ({ src, format, name, icon, width, height, mediaType, provider }: PreviewProps) => {
|
|
258
|
+
return (
|
|
259
|
+
<>
|
|
260
|
+
{format === "image" &&
|
|
261
|
+
<PreviewImage src={src} width={width} height={height} />
|
|
262
|
+
}
|
|
263
|
+
{format === "document" &&
|
|
264
|
+
<PreviewDocument src={src} />
|
|
265
|
+
}
|
|
266
|
+
{format === "video" &&
|
|
267
|
+
<PreviewVideo src={src} name={name} mediaType={mediaType} />
|
|
268
|
+
}
|
|
269
|
+
{format === "audio" &&
|
|
270
|
+
<PreviewAudio src={src} name={name} mediaType={mediaType} />
|
|
271
|
+
}
|
|
272
|
+
{format === "text" &&
|
|
273
|
+
<PreviewText src={src} />
|
|
274
|
+
}
|
|
275
|
+
{format === "code" &&
|
|
276
|
+
<PreviewText src={src} html code />
|
|
277
|
+
}
|
|
278
|
+
{format === "markup" &&
|
|
279
|
+
<PreviewText src={src} html />
|
|
280
|
+
}
|
|
281
|
+
{format === "embed" &&
|
|
282
|
+
<PreviewEmbed src={src} name={name} icon={icon} provider={provider} />
|
|
283
|
+
}
|
|
284
|
+
{format === "link" &&
|
|
285
|
+
<PreviewIcon src={src} name={name} icon={icon} provider={provider} />
|
|
286
|
+
}
|
|
287
|
+
{format === "download" &&
|
|
288
|
+
<PreviewIcon src={src} name={name} icon={icon} download />
|
|
289
|
+
}
|
|
290
|
+
</>
|
|
291
|
+
)
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
export default Preview;
|
|
@@ -5,7 +5,6 @@ import Button from "../ui/Button";
|
|
|
5
5
|
import { MessengerContext } from "../contexts/MessengerContext";
|
|
6
6
|
import classNames from "classnames";
|
|
7
7
|
|
|
8
|
-
import { prefix as wy } from "../utils/styles";
|
|
9
8
|
import useReactions from "../hooks/useReactions";
|
|
10
9
|
import useMutateDeleteReaction from "../hooks/useMutateDeleteReaction";
|
|
11
10
|
import { WeavyContext } from "../contexts/WeavyContext";
|
|
@@ -69,12 +68,12 @@ export const ReactionsMenu = ({ id, reactions }: ReactionMenuProps) => {
|
|
|
69
68
|
}
|
|
70
69
|
|
|
71
70
|
return (
|
|
72
|
-
<div className={
|
|
73
|
-
<Button.UI onClick={toggleReactionMenu}><Icon.UI name="emoticon-
|
|
74
|
-
<div className=
|
|
75
|
-
<div className=
|
|
71
|
+
<div className={classNames({ "wy-active": visible })} style={{ position: 'relative' }}>
|
|
72
|
+
<Button.UI onClick={toggleReactionMenu}><Icon.UI name="emoticon-plus" size={1} /></Button.UI>
|
|
73
|
+
<div className="wy-reaction-menu wy-dropdown-menu" style={{ display: visible ? 'block' : 'none', position: 'absolute', top: '-3.25rem' }}>
|
|
74
|
+
<div className="wy-reaction-picker">
|
|
76
75
|
{emojis?.map((r: string, i: number) => {
|
|
77
|
-
return <Button.UI key={i} onClick={handleReaction} className={
|
|
76
|
+
return <Button.UI key={i} onClick={handleReaction} className={classNames("wy-button-icon wy-reaction-button", { "wy-active": reactedEmoji === r })} data-emoji={r}>{r}</Button.UI> //reactedEmoji
|
|
78
77
|
})}
|
|
79
78
|
</div>
|
|
80
79
|
</div>
|
|
@@ -89,7 +88,7 @@ export const ReactionsList = ({ id, reactions }: ReactionsProps) => {
|
|
|
89
88
|
return (
|
|
90
89
|
<>
|
|
91
90
|
{reactionsList && reactionsList.map((r: ReactionGroup, i: number) => {
|
|
92
|
-
return <span key={i} className=
|
|
91
|
+
return <span key={i} className="wy-reaction" title={r.count.toString()}>{r.content}</span> //r.has_reacted
|
|
93
92
|
})}
|
|
94
93
|
</>
|
|
95
94
|
)
|
|
@@ -4,7 +4,6 @@ import useSearchUsers from "../hooks/useSearchUsers";
|
|
|
4
4
|
import Avatar from './Avatar';
|
|
5
5
|
import Button from '../ui/Button';
|
|
6
6
|
import Icon from '../ui/Icon';
|
|
7
|
-
import { prefix as wy } from "../utils/styles";
|
|
8
7
|
|
|
9
8
|
type SearchUsersProps = {
|
|
10
9
|
handleSubmit: any,
|
|
@@ -42,33 +41,33 @@ const SearchUsers = ({handleSubmit, buttonTitle}: SearchUsersProps) => {
|
|
|
42
41
|
}
|
|
43
42
|
|
|
44
43
|
return (
|
|
45
|
-
<div className=
|
|
46
|
-
<div className=
|
|
44
|
+
<div className="wy-search wy-scroll-y">
|
|
45
|
+
<div className="wy-search-form wy-pane-group">
|
|
47
46
|
<Button.UI><Icon.UI name="magnify" /></Button.UI>
|
|
48
|
-
<input className=
|
|
47
|
+
<input className="wy-search-input" value={text} onChange={(e) => setText(e.target.value)} name="text" placeholder='Search...' />
|
|
49
48
|
</div>
|
|
50
49
|
|
|
51
|
-
<div className=
|
|
50
|
+
<div className="wy-pane-group">
|
|
52
51
|
{data && data.data.length === 0 &&
|
|
53
|
-
<div className=
|
|
52
|
+
<div className="wy-search-no-result">Your search did not match any people.</div>
|
|
54
53
|
}
|
|
55
|
-
<table className=
|
|
54
|
+
<table className="wy-search-result-table">
|
|
56
55
|
<tbody>
|
|
57
56
|
{data && data.data.length > 0 && data.data.map((user: MemberType) => {
|
|
58
57
|
return (
|
|
59
|
-
<tr key={user.id} className=
|
|
60
|
-
<td className=
|
|
58
|
+
<tr key={user.id} className="wy-search-result-table-checkbox">
|
|
59
|
+
<td className="wy-search-result-table-icon">
|
|
61
60
|
<Avatar src={user.avatar_url} size={24} id={user.id} presence={user.presence} name={user.display_name} />
|
|
62
61
|
</td>
|
|
63
62
|
<td><label htmlFor={'chk' + user.id}>{user.display_name}</label></td>
|
|
64
|
-
<td className=
|
|
63
|
+
<td className="wy-search-result-table-icon"><input type="checkbox" id={'chk' + user.id} checked={isChecked(user.id)} onChange={(e) => handleSelected(e, user)} /></td>
|
|
65
64
|
</tr>
|
|
66
65
|
)
|
|
67
66
|
})}
|
|
68
|
-
</tbody>
|
|
67
|
+
</tbody>
|
|
69
68
|
</table>
|
|
70
69
|
</div>
|
|
71
|
-
{/*<div className=
|
|
70
|
+
{/*<div className="wy-search-group">
|
|
72
71
|
<h2>Selected people</h2>
|
|
73
72
|
<ul>
|
|
74
73
|
{selected && selected.length > 0 && selected.map((user: UserType) => {
|
|
@@ -76,10 +75,12 @@ const SearchUsers = ({handleSubmit, buttonTitle}: SearchUsersProps) => {
|
|
|
76
75
|
})}
|
|
77
76
|
</ul>
|
|
78
77
|
</div>*/}
|
|
79
|
-
<div className=
|
|
80
|
-
<div className=
|
|
81
|
-
<div className=
|
|
82
|
-
<
|
|
78
|
+
<div className="wy-footerbars">
|
|
79
|
+
<div className="wy-footerbar">
|
|
80
|
+
<div className="wy-pane-group">
|
|
81
|
+
<div className="wy-buttons">
|
|
82
|
+
<button className="wy-button wy-button-primary" type="button" onClick={() => {handleSubmit(selected); clear();}} disabled={selected.length === 0}>{buttonTitle}</button>
|
|
83
|
+
</div>
|
|
83
84
|
</div>
|
|
84
85
|
</div>
|
|
85
86
|
</div>
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import Avatar from "./Avatar";
|
|
3
3
|
import dayjs from 'dayjs';
|
|
4
|
-
import { prefix as wy } from "../utils/styles";
|
|
5
4
|
|
|
6
5
|
type Props = {
|
|
7
6
|
id: number,
|
|
@@ -13,7 +12,7 @@ type Props = {
|
|
|
13
12
|
const SeenBy = ({ seenBy }: Props) => {
|
|
14
13
|
|
|
15
14
|
return (
|
|
16
|
-
<div className=
|
|
15
|
+
<div className="wy-readby-status">
|
|
17
16
|
{seenBy && seenBy.length > 0 && seenBy.map((member: MemberType) => {
|
|
18
17
|
const date = dayjs.utc(member.read_at).tz(dayjs.tz.guess());
|
|
19
18
|
return (<Avatar name={`Seen by ${member.name} at ${date.format('LLLL')}`} src={member.avatar_url} size={16} key={member.id}/>)})
|
|
@@ -2,7 +2,6 @@ import React, { createContext, useEffect, useState } from "react";
|
|
|
2
2
|
import Overlay from '../ui/Overlay';
|
|
3
3
|
import Button from '../ui/Button';
|
|
4
4
|
import Icon from '../ui/Icon';
|
|
5
|
-
import { prefix as wy } from "../utils/styles";
|
|
6
5
|
|
|
7
6
|
export const PreviewContext = createContext<PreviewContextProps>({
|
|
8
7
|
openPreview: Function,
|
|
@@ -64,11 +63,11 @@ const PreviewProvider = ({ children }: Props) => {
|
|
|
64
63
|
{children}
|
|
65
64
|
</PreviewContext.Provider>
|
|
66
65
|
|
|
67
|
-
<Overlay.UI isOpen={modalPreviewOpen} className={wy
|
|
68
|
-
<header className={wy
|
|
69
|
-
<nav className={wy
|
|
66
|
+
<Overlay.UI isOpen={modalPreviewOpen} className={'wy-dark'}>
|
|
67
|
+
<header className={'wy-appbars'}>
|
|
68
|
+
<nav className={'wy-appbar'}>
|
|
70
69
|
<Button.UI onClick={closePreview}><Icon.UI name='close' /></Button.UI>
|
|
71
|
-
<div className={wy
|
|
70
|
+
<div className={'wy-appbar-text'}>
|
|
72
71
|
{activeAttachment &&
|
|
73
72
|
<span>{activeAttachment.name}</span>
|
|
74
73
|
}
|
|
@@ -102,4 +101,3 @@ const PreviewProvider = ({ children }: Props) => {
|
|
|
102
101
|
};
|
|
103
102
|
|
|
104
103
|
export default PreviewProvider;
|
|
105
|
-
|
package/src/hooks/usePresence.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { useContext, useEffect } from "react";
|
|
2
2
|
import { WeavyContext } from "../contexts/WeavyContext";
|
|
3
|
-
import { prefix as wy } from "../utils/styles";
|
|
4
3
|
|
|
5
4
|
export default function usePresence() {
|
|
6
5
|
|
|
@@ -17,18 +16,18 @@ export default function usePresence() {
|
|
|
17
16
|
const handlePresenceChange = (data: any) => {
|
|
18
17
|
|
|
19
18
|
if (Array.isArray(data)) {
|
|
20
|
-
document.querySelectorAll(
|
|
21
|
-
item.classList.remove(wy
|
|
19
|
+
document.querySelectorAll(".wy-presence").forEach(function (item) {
|
|
20
|
+
item.classList.remove("wy-presence-active");
|
|
22
21
|
});
|
|
23
22
|
|
|
24
23
|
data.forEach(function (id) {
|
|
25
24
|
document.querySelectorAll("[data-presence-id='" + id + "']").forEach(function (item) {
|
|
26
|
-
item.classList.add(wy
|
|
25
|
+
item.classList.add("wy-presence-active");
|
|
27
26
|
});
|
|
28
27
|
});
|
|
29
28
|
} else {
|
|
30
29
|
document.querySelectorAll("[data-presence-id='" + data + "']").forEach(function (item) {
|
|
31
|
-
item.classList.add(wy
|
|
30
|
+
item.classList.add("wy-presence-active");
|
|
32
31
|
});
|
|
33
32
|
}
|
|
34
33
|
}
|
|
@@ -2,7 +2,6 @@ import { useCallback, useContext, useEffect, useLayoutEffect, useState } from "r
|
|
|
2
2
|
import { UserContext } from "../contexts/UserContext";
|
|
3
3
|
import useEvents from "./useEvents";
|
|
4
4
|
|
|
5
|
-
|
|
6
5
|
export default function useReactions(id: number, reactions: ReactableType[]) {
|
|
7
6
|
const { on, off } = useEvents();
|
|
8
7
|
const { user } = useContext(UserContext);
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
@use "config" as *;
|
|
2
|
+
|
|
3
|
+
// Global alerts
|
|
4
|
+
|
|
5
|
+
.wy-alert-message {
|
|
6
|
+
padding: .25rem .5rem;
|
|
7
|
+
background-color: $client-alert-background;
|
|
8
|
+
text-align: center;
|
|
9
|
+
width: $client-panel-width;
|
|
10
|
+
color: $client-alert-color;
|
|
11
|
+
border-radius: .1875rem;
|
|
12
|
+
margin: 0 auto;
|
|
13
|
+
margin-top: 1rem;
|
|
14
|
+
font-family: $font-family-base;
|
|
15
|
+
position: relative;
|
|
16
|
+
z-index: 10;
|
|
17
|
+
box-shadow: $md-shadow-8dp;
|
|
18
|
+
max-width: calc(100% - 3rem);
|
|
19
|
+
pointer-events: none;
|
|
20
|
+
user-select: none;
|
|
21
|
+
|
|
22
|
+
a {
|
|
23
|
+
color: darken($client-alert-color, 10%);
|
|
24
|
+
text-decoration: $link-decoration;
|
|
25
|
+
font-weight: $alert-link-font-weight;
|
|
26
|
+
pointer-events: auto;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
&.wy-fade {
|
|
30
|
+
transition: all $md-animation-duration $md-animation-curve-default;
|
|
31
|
+
opacity: 0;
|
|
32
|
+
height: 0;
|
|
33
|
+
padding-top: 0;
|
|
34
|
+
padding-bottom: 0;
|
|
35
|
+
margin-top: 0;
|
|
36
|
+
|
|
37
|
+
&.wy-in {
|
|
38
|
+
transition: opacity $md-animation-duration $md-animation-curve-default;
|
|
39
|
+
opacity: 1;
|
|
40
|
+
height: auto;
|
|
41
|
+
padding-top: .5rem;
|
|
42
|
+
padding-bottom: .5rem;
|
|
43
|
+
margin-top: 1rem;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.wy-button {
|
|
48
|
+
cursor: pointer;
|
|
49
|
+
display: inline-flex;
|
|
50
|
+
flex-shrink: 0;
|
|
51
|
+
flex-grow: 0;
|
|
52
|
+
|
|
53
|
+
> * {
|
|
54
|
+
display: inline-flex;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
font-weight: 400;
|
|
58
|
+
text-align: center;
|
|
59
|
+
white-space: nowrap;
|
|
60
|
+
vertical-align: middle;
|
|
61
|
+
user-select: none;
|
|
62
|
+
border: 1px solid transparent;
|
|
63
|
+
padding: .3125rem .75rem;
|
|
64
|
+
font-size: 1rem;
|
|
65
|
+
line-height: 1.5;
|
|
66
|
+
border-radius: .1875rem;
|
|
67
|
+
color: $white;
|
|
68
|
+
background-color: $primary;
|
|
69
|
+
border-color: $primary;
|
|
70
|
+
box-shadow: $btn-box-shadow;
|
|
71
|
+
margin-top: .5rem;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
@use "config" as *;
|
|
2
|
+
@use "mixins/backdrop";
|
|
3
|
+
@use "mixins/position";
|
|
4
|
+
|
|
5
|
+
.wy-appbars {
|
|
6
|
+
@include position.sticky-top;
|
|
7
|
+
|
|
8
|
+
@include backdrop.filter {
|
|
9
|
+
> .wy-appbar {
|
|
10
|
+
backdrop-filter: none;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.wy-appbar {
|
|
16
|
+
display: grid;
|
|
17
|
+
align-items: center;
|
|
18
|
+
justify-content: space-between;
|
|
19
|
+
height: $appbar-height;
|
|
20
|
+
padding: $navbar-padding-y $navbar-padding-x;
|
|
21
|
+
flex: 0 0 $appbar-height;
|
|
22
|
+
grid-template-columns: minmax(2rem, max-content) minmax(0, max-content) minmax(2rem, max-content);
|
|
23
|
+
column-gap: .5rem;
|
|
24
|
+
|
|
25
|
+
@include backdrop.filter;
|
|
26
|
+
|
|
27
|
+
.wy-badge {
|
|
28
|
+
align-self: center;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.wy-button {
|
|
32
|
+
max-height: 2rem;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.wy-appbar-buttons {
|
|
37
|
+
display: flex;
|
|
38
|
+
flex: 0 0 1rem;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.wy-appbar-text {
|
|
42
|
+
@include text-truncate();
|
|
43
|
+
color: inherit !important;
|
|
44
|
+
user-select: none;
|
|
45
|
+
|
|
46
|
+
a {
|
|
47
|
+
color: inherit;
|
|
48
|
+
|
|
49
|
+
&:hover {
|
|
50
|
+
color: inherit;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.wy-appbar {
|
|
56
|
+
// light theme (default)
|
|
57
|
+
&, .wy-light &, &.wy-light {
|
|
58
|
+
background-color: rgba($gray-50, $opacity-backdrop);
|
|
59
|
+
color: $navbar-light-color;
|
|
60
|
+
border-bottom: $border-width solid rgba($gray-200, $opacity-backdrop);
|
|
61
|
+
}
|
|
62
|
+
// dark theme
|
|
63
|
+
.wy-dark &, &.wy-dark {
|
|
64
|
+
background-color: rgba($dark, $opacity-backdrop);
|
|
65
|
+
color: $navbar-dark-color;
|
|
66
|
+
border-bottom: $border-width solid rgba($gray-800, $opacity-backdrop);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.wy-footerbars {
|
|
71
|
+
padding-bottom: $footerbar-height;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.wy-footerbar {
|
|
75
|
+
position: absolute;
|
|
76
|
+
bottom: 0;
|
|
77
|
+
left: 0;
|
|
78
|
+
right: 0;
|
|
79
|
+
z-index: $zindex-sticky;
|
|
80
|
+
|
|
81
|
+
&::after {
|
|
82
|
+
content: "";
|
|
83
|
+
position: absolute;
|
|
84
|
+
width: 100vw;
|
|
85
|
+
left: 0;
|
|
86
|
+
bottom: 0;
|
|
87
|
+
height: $footerbar-height;
|
|
88
|
+
border-top: $border-width solid rgba($gray-200, $opacity-backdrop);
|
|
89
|
+
background: rgba($gray-50, $opacity-backdrop);
|
|
90
|
+
z-index: -1;
|
|
91
|
+
|
|
92
|
+
@include backdrop.filter;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.wy-buttons {
|
|
96
|
+
flex-direction: row-reverse;
|
|
97
|
+
|
|
98
|
+
> :not(:last-child) {
|
|
99
|
+
margin: 0 0 0 .5rem;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.wy-footerbars-fixed {
|
|
105
|
+
.wy-footerbar {
|
|
106
|
+
position: fixed;
|
|
107
|
+
|
|
108
|
+
&::after {
|
|
109
|
+
position: fixed;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|