Skip to content

Commit 88d0f9d

Browse files
markdown editor
Fixes after rebase
1 parent c851380 commit 88d0f9d

File tree

21 files changed

+4507
-2528
lines changed

21 files changed

+4507
-2528
lines changed

packages/components/modules/messages/web/MessageUpdate/index.tsx

+4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import { FC, useEffect, useRef } from 'react'
44

5+
import { MarkdownEditor } from '@baseapp-frontend/design-system/components/web/inputs'
56
import { setFormRelayErrors } from '@baseapp-frontend/utils'
67

78
import { zodResolver } from '@hookform/resolvers/zod'
@@ -144,6 +145,9 @@ const MessageUpdate: FC<MessageUpdateProps> = ({
144145
ariaLabel: 'save message edit',
145146
cancelAriaLabel: 'cancel message edit',
146147
}}
148+
SocialTextFieldProps={{
149+
TextField: MarkdownEditor,
150+
}}
147151
{...SocialInputProps}
148152
/>
149153
)

packages/components/modules/messages/web/MessagesList/MessagesGroup/UserMessage/MessageItem/index.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
DownloadIcon,
88
PenEditIcon,
99
} from '@baseapp-frontend/design-system/components/web/icons'
10+
import { Markdown } from '@baseapp-frontend/design-system/components/web/markdowns'
1011
import { useNotification } from '@baseapp-frontend/utils'
1112

1213
import { Typography } from '@mui/material'
@@ -80,7 +81,7 @@ const MessageItem: FC<MessageItemProps> = ({
8081
>
8182
{deletedMessage && <BlockIcon sx={{ fontSize: '20px', color: 'grey.500' }} />}
8283
{deletedMessage && ' '}
83-
{message?.content}
84+
<Markdown>{message?.content}</Markdown>
8485
</Typography>
8586
)
8687
}

packages/components/modules/messages/web/SendMessage/index.tsx

+4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import { forwardRef } from 'react'
44

55
import { useCurrentProfile } from '@baseapp-frontend/authentication'
6+
import { MarkdownEditor } from '@baseapp-frontend/design-system/components/web/inputs'
67
import { setFormRelayErrors } from '@baseapp-frontend/utils'
78

89
import { zodResolver } from '@hookform/resolvers/zod'
@@ -124,6 +125,9 @@ const SendMessage = forwardRef<HTMLInputElement, SendMessageProps>(
124125
form={form}
125126
submit={onSubmit}
126127
isLoading={isMutationInFlight}
128+
SocialTextFieldProps={{
129+
TextField: MarkdownEditor,
130+
}}
127131
{...SocialInputProps}
128132
/>
129133
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import React from 'react'
2+
3+
import { Meta, StoryFn, StoryObj } from '@storybook/react'
4+
5+
import LazyLoadImage from '..'
6+
import { LazyLoadImageProps } from '../types'
7+
8+
const meta: Meta = {
9+
title: '@baseapp-frontend-template / Design System/Displays/LazyLoadImage',
10+
component: LazyLoadImage,
11+
}
12+
13+
export default meta
14+
15+
type Story = StoryObj<LazyLoadImageProps>
16+
17+
const Template: StoryFn<LazyLoadImageProps> = (args: any) => <LazyLoadImage {...args} />
18+
19+
export const Default: Story = Template.bind({})
20+
Default.args = {
21+
src: '/png/home-banner.png',
22+
alt: 'Example lazy-loaded image',
23+
ratio: '16/9',
24+
width: 200,
25+
height: 225,
26+
overlay: 'rgba(0, 0, 0, 0.5)',
27+
disabledEffect: false,
28+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
'use client'
2+
3+
import { forwardRef } from 'react'
4+
5+
import Box from '@mui/material/Box'
6+
import { alpha, useTheme } from '@mui/material/styles'
7+
import { LazyLoadImage as ReactLazyLoadImage } from 'react-lazy-load-image-component'
8+
9+
import { LazyLoadImageProps } from './types'
10+
import { getRatio } from './utils'
11+
12+
export type * from './types'
13+
14+
const LazyLoadImage = forwardRef<HTMLSpanElement, LazyLoadImageProps>(
15+
(
16+
{
17+
ratio,
18+
overlay,
19+
disabledEffect = false,
20+
alt,
21+
src,
22+
afterLoad,
23+
delayTime,
24+
threshold,
25+
beforeLoad,
26+
delayMethod,
27+
placeholder,
28+
wrapperProps,
29+
scrollPosition,
30+
effect = 'blur',
31+
visibleByDefault,
32+
wrapperClassName,
33+
useIntersectionObserver,
34+
sx,
35+
...other
36+
},
37+
ref,
38+
) => {
39+
const theme = useTheme()
40+
41+
const overlayStyles = !!overlay && {
42+
'&:before': {
43+
content: "''",
44+
top: 0,
45+
left: 0,
46+
width: 1,
47+
height: 1,
48+
zIndex: 1,
49+
position: 'absolute',
50+
background: overlay || alpha(theme.palette.grey[900], 0.48),
51+
},
52+
}
53+
54+
const content = (
55+
<Box
56+
component={ReactLazyLoadImage}
57+
alt={alt}
58+
src={src}
59+
afterLoad={afterLoad}
60+
delayTime={delayTime}
61+
threshold={threshold}
62+
beforeLoad={beforeLoad}
63+
delayMethod={delayMethod}
64+
placeholder={placeholder}
65+
wrapperProps={wrapperProps}
66+
scrollPosition={scrollPosition}
67+
visibleByDefault={visibleByDefault}
68+
effect={disabledEffect ? undefined : effect}
69+
useIntersectionObserver={useIntersectionObserver}
70+
wrapperClassName={wrapperClassName || 'component-image-wrapper'}
71+
placeholderSrc={disabledEffect ? '/assets/transparent.png' : '/assets/placeholder.svg'}
72+
sx={{
73+
width: 1,
74+
height: 1,
75+
objectFit: 'cover',
76+
verticalAlign: 'bottom',
77+
...(!!ratio && {
78+
top: 0,
79+
left: 0,
80+
position: 'absolute',
81+
}),
82+
}}
83+
/>
84+
)
85+
86+
return (
87+
<Box
88+
ref={ref}
89+
component="span"
90+
className="component-image"
91+
sx={{
92+
overflow: 'hidden',
93+
position: 'relative',
94+
verticalAlign: 'bottom',
95+
display: 'inline-block',
96+
...(!!ratio && {
97+
width: 1,
98+
}),
99+
'& span.component-image-wrapper': {
100+
width: 1,
101+
height: 1,
102+
verticalAlign: 'bottom',
103+
backgroundSize: 'cover !important',
104+
...(!!ratio && {
105+
pt: getRatio(ratio),
106+
}),
107+
},
108+
...overlayStyles,
109+
...sx,
110+
}}
111+
{...other}
112+
>
113+
{content}
114+
</Box>
115+
)
116+
},
117+
)
118+
119+
export default LazyLoadImage
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { BoxProps } from '@mui/material/Box'
2+
import { LazyLoadImageProps as ReactLazyLoadImageProps } from 'react-lazy-load-image-component'
3+
4+
export type LazyLoadImageRatio =
5+
| '4/3'
6+
| '3/4'
7+
| '6/4'
8+
| '4/6'
9+
| '16/9'
10+
| '9/16'
11+
| '21/9'
12+
| '9/21'
13+
| '1/1'
14+
15+
export type LazyLoadImageProps = BoxProps &
16+
ReactLazyLoadImageProps & {
17+
overlay?: string
18+
ratio?: LazyLoadImageRatio
19+
disabledEffect?: boolean
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// ----------------------------------------------------------------------
2+
3+
export function getRatio(ratio = '1/1') {
4+
return {
5+
'4/3': 'calc(100% / 4 * 3)',
6+
'3/4': 'calc(100% / 3 * 4)',
7+
'6/4': 'calc(100% / 6 * 4)',
8+
'4/6': 'calc(100% / 4 * 6)',
9+
'16/9': 'calc(100% / 16 * 9)',
10+
'9/16': 'calc(100% / 9 * 16)',
11+
'21/9': 'calc(100% / 21 * 9)',
12+
'9/21': 'calc(100% / 9 * 21)',
13+
'1/1': '100%',
14+
}[ratio]
15+
}

packages/design-system/components/web/images/index.ts

+3
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,6 @@ export { default as Iconify } from './Iconify'
44
export type * from './Iconify/types'
55
export { default as ImageWithFallback } from './ImageWithFallback'
66
export type * from './ImageWithFallback/types'
7+
8+
export { default as LazyLoadImage } from './LazyLoadImage'
9+
export type * from './LazyLoadImage/types'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/* Remove borders and paddings from the editor */
2+
.container {
3+
border: 1px solid transparent;
4+
padding-bottom: 5px;
5+
width: 100%;
6+
max-width: 100%;
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
'use client'
2+
3+
import React, { FC } from 'react'
4+
5+
import { withController } from '@baseapp-frontend/utils'
6+
7+
import MDEditor from '@uiw/react-md-editor'
8+
import rehypeSanitize from 'rehype-sanitize'
9+
10+
import './index.css'
11+
// TODO check custom css is not appling with the new build method
12+
import { MarkdownEditorProps } from './types'
13+
14+
const MarkdownEditor: FC<MarkdownEditorProps> = ({
15+
value,
16+
onChange,
17+
onKeyDown,
18+
placeholder,
19+
...props
20+
}) => (
21+
<div className="container" style={{ maxWidth: '100%', width: '100%' }}>
22+
<div data-color-mode="light">
23+
<MDEditor
24+
height={150}
25+
preview="edit"
26+
value={value}
27+
onChange={onChange}
28+
previewOptions={{
29+
rehypePlugins: [[rehypeSanitize]],
30+
}}
31+
textareaProps={{
32+
placeholder,
33+
onKeyDown: (e) => {
34+
onKeyDown?.(e)
35+
},
36+
}}
37+
{...props}
38+
/>
39+
</div>
40+
</div>
41+
)
42+
43+
export default withController(MarkdownEditor)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { KeyboardEventHandler } from 'react'
2+
3+
import { FormControl } from '@baseapp-frontend/utils'
4+
5+
import { MDEditorProps } from '@uiw/react-md-editor'
6+
7+
export type MarkdownEditorProps = MDEditorProps &
8+
FormControl & {
9+
onKeyDown?: KeyboardEventHandler<HTMLTextAreaElement>
10+
placeholder?: string
11+
}

packages/design-system/components/web/inputs/SocialTextField/index.tsx

+3-1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ const SocialTextField: FC<SocialTextFieldProps> = ({
2727
isReply,
2828
replyTargetName,
2929
onCancelReply,
30+
TextField = TextareaField,
3031
...props
3132
}) => (
3233
<Container>
@@ -48,7 +49,8 @@ const SocialTextField: FC<SocialTextFieldProps> = ({
4849
</div>
4950
</OutsideReplyContainer>
5051
)}
51-
<TextareaField {...props} />
52+
{/* @ts-ignore TODO: Type this properly */}
53+
<TextField {...props} />
5254
<div className="flex justify-between px-3 pb-3">{children}</div>
5355
</Container>
5456
)
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
1-
import { PropsWithChildren } from 'react'
1+
import { FC, PropsWithChildren } from 'react'
22

33
import { FormControl } from '@baseapp-frontend/utils'
44

5+
import { MarkdownEditorProps } from '../MarkdownEditor/types'
56
import { TextFieldProps } from '../TextField/types'
7+
import { TextareaFieldProps } from '../TextareaField/types'
68

79
export type SocialTextFieldProps = FormControl &
810
TextFieldProps &
911
PropsWithChildren & {
1012
isReply?: boolean
1113
onCancelReply?: () => void
1214
replyTargetName?: string | null
15+
TextField?: FC<TextareaFieldProps> | FC<MarkdownEditorProps>
1316
}

packages/design-system/components/web/inputs/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
'use client'
22

3+
export { default as MarkdownEditor } from './MarkdownEditor'
4+
export type * from './MarkdownEditor/types'
35
export { default as PhoneNumberField } from './PhoneNumberField'
46
export type * from './PhoneNumberField/types'
57
export { default as Searchbar } from './Searchbar'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import hljs from 'highlight.js'
2+
import 'highlight.js/styles/base16/tomorrow-night.css'
3+
4+
declare global {
5+
interface Window {
6+
hljs: any
7+
}
8+
}
9+
10+
hljs.configure({
11+
languages: ['javascript', 'sh', 'bash', 'html', 'scss', 'css', 'json'],
12+
})
13+
14+
if (typeof window !== 'undefined') {
15+
window.hljs = hljs
16+
}

0 commit comments

Comments
 (0)