@soul-refiner/design-system 0.1.25 → 0.1.27
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/package.json +7 -6
- package/src/components/actions/dropdown/dropdown.tsx +14 -11
- package/src/components/atoms/typography/typography.tsx +1 -1
- package/src/components/editor/constants.ts +181 -0
- package/src/components/editor/editor.tsx +95 -0
- package/src/components/editor/index.ts +2 -0
- package/src/components/editor/navbar/alignment_dropdown.tsx +142 -0
- package/src/components/editor/navbar/button_modal.tsx +146 -0
- package/src/components/editor/navbar/index.ts +2 -0
- package/src/components/editor/navbar/navbar.tsx +350 -0
- package/src/components/editor/navbar/style_dropdown.tsx +107 -0
- package/src/components/editor/plate.ts +37 -0
- package/src/components/editor/plugins/blockquote.tsx +25 -0
- package/src/components/editor/plugins/buttons.tsx +140 -0
- package/src/components/editor/plugins/exitBreak.ts +39 -0
- package/src/components/editor/plugins/image.tsx +80 -0
- package/src/components/editor/plugins/index.ts +165 -0
- package/src/components/editor/plugins/link.tsx +144 -0
- package/src/components/editor/plugins/list.tsx +34 -0
- package/src/components/editor/plugins/resetBlockType.ts +29 -0
- package/src/components/editor/plugins/selectOnBackspace.ts +7 -0
- package/src/components/editor/plugins/softBreak.ts +19 -0
- package/src/components/editor/plugins/text.tsx +142 -0
- package/src/components/index.ts +1 -0
- package/src/components/input/radio/radio.tsx +2 -2
- package/src/components/surfaces/modal/modal.tsx +6 -2
- package/src/icons/text/align_justified.tsx +1 -1
- package/tsconfig.json +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@soul-refiner/design-system",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.27",
|
|
4
4
|
"main": "src/index.ts",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"publishConfig": {
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
49
|
"@emoji-mart/react": "^1.1.1",
|
|
50
|
-
"@udecode/plate": "^
|
|
50
|
+
"@udecode/plate": "^22.0.1",
|
|
51
51
|
"emoji-mart": "^5.5.2",
|
|
52
52
|
"react": "^18.2.0",
|
|
53
53
|
"react-dnd": "^16.0.1",
|
|
@@ -59,23 +59,24 @@
|
|
|
59
59
|
"slate": "^0.94.1",
|
|
60
60
|
"slate-history": "^0.93.0",
|
|
61
61
|
"slate-hyperscript": "^0.77.0",
|
|
62
|
-
"slate-react": "^0.
|
|
62
|
+
"slate-react": "^0.97.1",
|
|
63
63
|
"styled-components": "^6.0.0-rc.3"
|
|
64
64
|
},
|
|
65
65
|
"peerDependencies": {
|
|
66
66
|
"@emoji-mart/react": "^1.1.1",
|
|
67
|
-
"@udecode/plate": "^
|
|
67
|
+
"@udecode/plate": "^22.0.1",
|
|
68
68
|
"emoji-mart": "^5.5.2",
|
|
69
69
|
"react": "^18.2.0",
|
|
70
70
|
"react-dnd": "^16.0.1",
|
|
71
71
|
"react-dnd-html5-backend": "^16.0.1",
|
|
72
72
|
"react-dom": "^18.2.0",
|
|
73
73
|
"react-is": "^18.2.0",
|
|
74
|
+
"react-tooltip": "^5.18.0",
|
|
74
75
|
"scheduler": "^0.23.0",
|
|
75
76
|
"slate": "^0.94.1",
|
|
76
77
|
"slate-history": "^0.93.0",
|
|
77
78
|
"slate-hyperscript": "^0.77.0",
|
|
78
|
-
"slate-react": "^0.
|
|
79
|
-
"styled-components": "^6.0.0-rc.
|
|
79
|
+
"slate-react": "^0.97.1",
|
|
80
|
+
"styled-components": "^6.0.0-rc.3"
|
|
80
81
|
}
|
|
81
82
|
}
|
|
@@ -180,7 +180,8 @@ const Dropdown = ({
|
|
|
180
180
|
>
|
|
181
181
|
{React.cloneElement(
|
|
182
182
|
trigger,
|
|
183
|
-
typeof trigger.type === 'string'
|
|
183
|
+
typeof trigger.type === 'string' ||
|
|
184
|
+
(trigger.type as any)?.displayName !== 'Button'
|
|
184
185
|
? { onClick: handleOpen }
|
|
185
186
|
: { isDropdownOpen: open, onClick: handleOpen }
|
|
186
187
|
)}
|
|
@@ -254,7 +255,7 @@ export interface DropdownOptionProps {
|
|
|
254
255
|
color?: string;
|
|
255
256
|
disabled?: boolean;
|
|
256
257
|
icon?: React.ReactElement;
|
|
257
|
-
label
|
|
258
|
+
label?: React.ReactNode;
|
|
258
259
|
onClick?: (event: React.MouseEvent<HTMLDivElement>) => void | undefined;
|
|
259
260
|
selected: boolean;
|
|
260
261
|
sublabel?: string;
|
|
@@ -285,15 +286,17 @@ const Option = ({
|
|
|
285
286
|
>
|
|
286
287
|
{checkbox ? <Checkbox selected={selected} /> : icon}
|
|
287
288
|
<Box $dir="column" $display="flex">
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
289
|
+
{label && (
|
|
290
|
+
<P
|
|
291
|
+
$color="grey-4"
|
|
292
|
+
$fontSize={14}
|
|
293
|
+
$lineHeight={20}
|
|
294
|
+
$mediumBold
|
|
295
|
+
$textClampLines={1}
|
|
296
|
+
>
|
|
297
|
+
{label}
|
|
298
|
+
</P>
|
|
299
|
+
)}
|
|
297
300
|
{sublabel && (
|
|
298
301
|
<P
|
|
299
302
|
$color="grey-4"
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
export {
|
|
2
|
+
ELEMENT_BLOCKQUOTE,
|
|
3
|
+
ELEMENT_CODE_LINE,
|
|
4
|
+
ELEMENT_CODE_SYNTAX,
|
|
5
|
+
ELEMENT_DEFAULT,
|
|
6
|
+
ELEMENT_H1,
|
|
7
|
+
ELEMENT_H2,
|
|
8
|
+
ELEMENT_H3,
|
|
9
|
+
ELEMENT_H4,
|
|
10
|
+
ELEMENT_H5,
|
|
11
|
+
ELEMENT_H6,
|
|
12
|
+
ELEMENT_HR,
|
|
13
|
+
ELEMENT_IMAGE,
|
|
14
|
+
ELEMENT_LI,
|
|
15
|
+
ELEMENT_LIC,
|
|
16
|
+
ELEMENT_LINK,
|
|
17
|
+
ELEMENT_MEDIA,
|
|
18
|
+
ELEMENT_MEDIA_EMBED,
|
|
19
|
+
ELEMENT_MENTION,
|
|
20
|
+
ELEMENT_MENTION_INPUT,
|
|
21
|
+
ELEMENT_OL,
|
|
22
|
+
ELEMENT_PARAGRAPH,
|
|
23
|
+
ELEMENT_TABLE,
|
|
24
|
+
ELEMENT_TD,
|
|
25
|
+
ELEMENT_TH,
|
|
26
|
+
ELEMENT_TODO_LI,
|
|
27
|
+
ELEMENT_TR,
|
|
28
|
+
ELEMENT_UL,
|
|
29
|
+
MARK_BG_COLOR,
|
|
30
|
+
MARK_BOLD,
|
|
31
|
+
MARK_CODE,
|
|
32
|
+
MARK_COLOR,
|
|
33
|
+
MARK_FONT_FAMILY,
|
|
34
|
+
MARK_FONT_SIZE,
|
|
35
|
+
MARK_FONT_WEIGHT,
|
|
36
|
+
MARK_HIGHLIGHT,
|
|
37
|
+
MARK_ITALIC,
|
|
38
|
+
MARK_KBD,
|
|
39
|
+
MARK_SEARCH_HIGHLIGHT,
|
|
40
|
+
MARK_STRIKETHROUGH,
|
|
41
|
+
MARK_SUBSCRIPT,
|
|
42
|
+
MARK_SUPERSCRIPT,
|
|
43
|
+
MARK_UNDERLINE,
|
|
44
|
+
} from '@udecode/plate';
|
|
45
|
+
|
|
46
|
+
export const ELEMENT_AUDIO = 'audio';
|
|
47
|
+
export const ELEMENT_BIBLE_QUOTE = 'bible-quote';
|
|
48
|
+
export const ELEMENT_BUTTON = 'button';
|
|
49
|
+
export const ELEMENT_EXAMPLE = 'example';
|
|
50
|
+
export const ELEMENT_FOOTNOTE = 'footnote';
|
|
51
|
+
export const ELEMENT_PAYWALL = 'paywall';
|
|
52
|
+
export const ELEMENT_POLL = 'poll';
|
|
53
|
+
export const ELEMENT_QA = 'q-n-a';
|
|
54
|
+
export const ELEMENT_RECIPE = 'recipe';
|
|
55
|
+
export const ELEMENT_VIDEO = 'video';
|
|
56
|
+
|
|
57
|
+
// export const BUTTON_COMMENT = 'button-comment';
|
|
58
|
+
// export const BUTTON_GIFT_SUBSCRIPTION = 'button-gift-subscription';
|
|
59
|
+
// export const BUTTON_SHARE = 'button-share';
|
|
60
|
+
// export const BUTTON_SHARE_PAGE = 'button-share-page';
|
|
61
|
+
// export const BUTTON_SIGNUP = 'signup';
|
|
62
|
+
// export const BUTTON_SPECIAL_OFFER = 'button-special-offer';
|
|
63
|
+
export const BUTTON_LINK = 'button-link';
|
|
64
|
+
export const BUTTON_SUBSCRIBE = 'button-subscribe';
|
|
65
|
+
|
|
66
|
+
export const COLORS = [
|
|
67
|
+
'var(--color-turquoise-5)',
|
|
68
|
+
'var(--color-green-5)',
|
|
69
|
+
'var(--color-blue-5)',
|
|
70
|
+
'var(--color-purple-5)',
|
|
71
|
+
'var(--color-yellow-5)',
|
|
72
|
+
'var(--color-orange-5)',
|
|
73
|
+
'var(--color-red-5)',
|
|
74
|
+
];
|
|
75
|
+
|
|
76
|
+
export const PLACEHOLDER = 'This is a placeholder';
|
|
77
|
+
|
|
78
|
+
export const DEFAULT_CONTENT = [
|
|
79
|
+
{
|
|
80
|
+
type: 'h1',
|
|
81
|
+
children: [
|
|
82
|
+
{
|
|
83
|
+
text: 'Module 1: The Warrior Identity',
|
|
84
|
+
bold: true,
|
|
85
|
+
},
|
|
86
|
+
],
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
type: 'p',
|
|
90
|
+
children: [
|
|
91
|
+
{
|
|
92
|
+
text: 'Welcome to Warpath. You’re about to embark on a journey towards lifelong healing, freedom and victory. This is a season of training. It’s sanctification on steroids, not for the faint-hearted, but for those who truly desire to live the rest of their lives for Jesus. No reserves, no retreats, no regrets.',
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
text: ' What was once your deepest, darkest secret will now become the word of your testimony that heals and liberates others.',
|
|
96
|
+
},
|
|
97
|
+
],
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
type: 'p',
|
|
101
|
+
children: [
|
|
102
|
+
{
|
|
103
|
+
text: 'In this new season, God is calling you up. He’s calling you to a higher level, a place where you’re no longer part of the problem but are becoming a part of the solution.',
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
text: '',
|
|
107
|
+
},
|
|
108
|
+
],
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
type: 'blockquote',
|
|
112
|
+
children: [
|
|
113
|
+
{
|
|
114
|
+
text: '"Warpath isn’t about just winning for you; that’s the beginning. Warpath is about you taking the battle and winning for others so they can have their families, and their marriages, and their destinies." \n— ',
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
text: 'Dr. Doug Weiss',
|
|
118
|
+
italic: true,
|
|
119
|
+
},
|
|
120
|
+
],
|
|
121
|
+
},
|
|
122
|
+
// {
|
|
123
|
+
// type: 'hr',
|
|
124
|
+
// children: [
|
|
125
|
+
// {
|
|
126
|
+
// text: '',
|
|
127
|
+
// },
|
|
128
|
+
// ],
|
|
129
|
+
// },
|
|
130
|
+
{
|
|
131
|
+
type: 'h3',
|
|
132
|
+
align: 'center',
|
|
133
|
+
children: [
|
|
134
|
+
{
|
|
135
|
+
text: 'THE WARRIOR IDENTITY',
|
|
136
|
+
bold: true,
|
|
137
|
+
},
|
|
138
|
+
],
|
|
139
|
+
},
|
|
140
|
+
// {
|
|
141
|
+
// type: 'hr',
|
|
142
|
+
// children: [
|
|
143
|
+
// {
|
|
144
|
+
// text: '',
|
|
145
|
+
// },
|
|
146
|
+
// ],
|
|
147
|
+
// },
|
|
148
|
+
{
|
|
149
|
+
type: 'img',
|
|
150
|
+
url: 'https://source.unsplash.com/1600x900/?christian',
|
|
151
|
+
children: [
|
|
152
|
+
{
|
|
153
|
+
text: '',
|
|
154
|
+
},
|
|
155
|
+
],
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
type: 'p',
|
|
159
|
+
children: [
|
|
160
|
+
{
|
|
161
|
+
text: 'Identity: You will have to grasp your true identity in Christ. You cannot look at this as a “what”, but instead about a “who”. We must become more like Christ, because He is a warrior.',
|
|
162
|
+
},
|
|
163
|
+
],
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
type: 'p',
|
|
167
|
+
children: [
|
|
168
|
+
{
|
|
169
|
+
text: 'A different DNA: As a warrior, your spiritual genetic code will be different from those who haven’t tasted the victory and grace you’ve experienced from this battle. You’ve experienced truth as a person: Jesus; and it has forever changed you. You’ve been set apart as a “fighting man”, no longer a civilian idly consumed by the cares of this world, but a warrior who’s passionate about the Kingdom and craving some sweet revenge.',
|
|
170
|
+
},
|
|
171
|
+
],
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
type: 'p',
|
|
175
|
+
children: [
|
|
176
|
+
{
|
|
177
|
+
text: '',
|
|
178
|
+
},
|
|
179
|
+
],
|
|
180
|
+
},
|
|
181
|
+
];
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import styled from 'styled-components';
|
|
3
|
+
import { createPlugins, Plate, PlateProvider, TElement } from '@udecode/plate';
|
|
4
|
+
import { DEFAULT_CONTENT, PLACEHOLDER } from './constants';
|
|
5
|
+
import { EditorBar } from './navbar';
|
|
6
|
+
import { plateUI } from './plate';
|
|
7
|
+
import { blocks, inline, marks, utils } from './plugins';
|
|
8
|
+
|
|
9
|
+
const plugins = createPlugins([...blocks, ...inline, ...marks, ...utils], {
|
|
10
|
+
components: plateUI,
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
export interface EditorProps {
|
|
14
|
+
communityName: string;
|
|
15
|
+
editable: boolean;
|
|
16
|
+
handleUploadImage: (dataURL: File) => Promise<string>;
|
|
17
|
+
onChange: (newNodes: TElement[]) => void;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const Editor = ({
|
|
21
|
+
editable,
|
|
22
|
+
handleUploadImage,
|
|
23
|
+
onChange,
|
|
24
|
+
}: EditorProps) => {
|
|
25
|
+
return (
|
|
26
|
+
<PlateProvider
|
|
27
|
+
id="main"
|
|
28
|
+
initialValue={DEFAULT_CONTENT}
|
|
29
|
+
onChange={onChange}
|
|
30
|
+
plugins={plugins}
|
|
31
|
+
>
|
|
32
|
+
<Wrapper>
|
|
33
|
+
<EditorBar handleUploadImage={handleUploadImage} />
|
|
34
|
+
<Plate
|
|
35
|
+
id="main"
|
|
36
|
+
editableProps={{
|
|
37
|
+
readOnly: !editable,
|
|
38
|
+
spellCheck: true,
|
|
39
|
+
autoFocus: true,
|
|
40
|
+
placeholder: PLACEHOLDER,
|
|
41
|
+
}}
|
|
42
|
+
/>
|
|
43
|
+
</Wrapper>
|
|
44
|
+
</PlateProvider>
|
|
45
|
+
);
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const Wrapper = styled.div`
|
|
49
|
+
* {
|
|
50
|
+
font-family: Inter;
|
|
51
|
+
outline: none;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.slate-bold {
|
|
55
|
+
font-weight: 700;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.slate-italic {
|
|
59
|
+
font-style: italic;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.slate-strikethrough {
|
|
63
|
+
text-decoration: line-through;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.slate-underline {
|
|
67
|
+
text-decoration: underline;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.slate-code {
|
|
71
|
+
& > * {
|
|
72
|
+
font-family: 'Roboto Mono';
|
|
73
|
+
& > * {
|
|
74
|
+
font-family: 'Roboto Mono';
|
|
75
|
+
& > * {
|
|
76
|
+
font-family: 'Roboto Mono';
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
background-color: var(--color-grey-9);
|
|
82
|
+
padding: 0.4em 0.4em;
|
|
83
|
+
font-size: 0.8em;
|
|
84
|
+
line-height: 0.8em;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
& > [data-slate-editor='true'] > * {
|
|
88
|
+
margin: 24px 0px;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
position: relative;
|
|
92
|
+
padding: 24px;
|
|
93
|
+
max-width: 1200px;
|
|
94
|
+
margin: 98px auto 0px;
|
|
95
|
+
`;
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import {
|
|
3
|
+
Alignment,
|
|
4
|
+
// isCollapsed,
|
|
5
|
+
PlateEditor,
|
|
6
|
+
setAlign,
|
|
7
|
+
} from '@udecode/plate';
|
|
8
|
+
import {
|
|
9
|
+
useAlignDropdownMenu,
|
|
10
|
+
useAlignDropdownMenuState,
|
|
11
|
+
} from '@udecode/plate-alignment';
|
|
12
|
+
import { Dropdown } from 'components';
|
|
13
|
+
import {
|
|
14
|
+
PlayerListPlay,
|
|
15
|
+
AlignCenter,
|
|
16
|
+
AlignJustified,
|
|
17
|
+
AlignLeft,
|
|
18
|
+
AlignRight,
|
|
19
|
+
} from 'icons';
|
|
20
|
+
import { MenuButton } from './navbar';
|
|
21
|
+
|
|
22
|
+
export interface AlignmentDropdownProps {
|
|
23
|
+
editorRef: PlateEditor;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const items = [
|
|
27
|
+
{
|
|
28
|
+
value: 'left',
|
|
29
|
+
icon: AlignLeft,
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
value: 'center',
|
|
33
|
+
icon: AlignCenter,
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
value: 'right',
|
|
37
|
+
icon: AlignRight,
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
value: 'justify',
|
|
41
|
+
icon: AlignJustified,
|
|
42
|
+
},
|
|
43
|
+
];
|
|
44
|
+
|
|
45
|
+
export const AlignmentDropdown = ({ editorRef }: AlignmentDropdownProps) => {
|
|
46
|
+
const alignState = useAlignDropdownMenuState();
|
|
47
|
+
const { radioGroupProps } = useAlignDropdownMenu(alignState);
|
|
48
|
+
|
|
49
|
+
const current = radioGroupProps.value;
|
|
50
|
+
|
|
51
|
+
const IconValue =
|
|
52
|
+
items.find((item) => item.value === radioGroupProps.value)?.icon ??
|
|
53
|
+
PlayerListPlay;
|
|
54
|
+
|
|
55
|
+
const handleAlign = (event: React.FormEvent) => {
|
|
56
|
+
const value = (event.target as HTMLElement)?.getAttribute(
|
|
57
|
+
'data-value'
|
|
58
|
+
) as Alignment | null;
|
|
59
|
+
|
|
60
|
+
if (!value) return;
|
|
61
|
+
|
|
62
|
+
setAlign(editorRef, {
|
|
63
|
+
value: value,
|
|
64
|
+
});
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
return (
|
|
68
|
+
<Dropdown
|
|
69
|
+
onChange={handleAlign}
|
|
70
|
+
offset={[0, 0]}
|
|
71
|
+
options={[
|
|
72
|
+
{
|
|
73
|
+
icon: (
|
|
74
|
+
<MenuButton $active={current === 'left'}>
|
|
75
|
+
<AlignLeft size={24} color="grey-5" />
|
|
76
|
+
</MenuButton>
|
|
77
|
+
),
|
|
78
|
+
sx: 'gap: 0px; padding: 4px;',
|
|
79
|
+
value: 'left',
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
icon: (
|
|
83
|
+
<MenuButton $active={current === 'center'}>
|
|
84
|
+
<AlignCenter size={24} color="grey-5" />
|
|
85
|
+
</MenuButton>
|
|
86
|
+
),
|
|
87
|
+
sx: 'gap: 0px; padding: 4px;',
|
|
88
|
+
value: 'center',
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
icon: (
|
|
92
|
+
<MenuButton $active={current === 'right'}>
|
|
93
|
+
<AlignRight size={24} color="grey-5" />
|
|
94
|
+
</MenuButton>
|
|
95
|
+
),
|
|
96
|
+
sx: 'gap: 0px; padding: 4px;',
|
|
97
|
+
value: 'right',
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
icon: (
|
|
101
|
+
<MenuButton $active={current === 'justify'}>
|
|
102
|
+
<AlignJustified size={24} color="grey-5" />
|
|
103
|
+
</MenuButton>
|
|
104
|
+
),
|
|
105
|
+
sx: 'gap: 0px; padding: 4px;',
|
|
106
|
+
value: 'justify',
|
|
107
|
+
},
|
|
108
|
+
]}
|
|
109
|
+
maintainState={false}
|
|
110
|
+
trigger={<IconValue size={24} color="grey-5" />}
|
|
111
|
+
/>
|
|
112
|
+
);
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
// <AlignToolbarButton
|
|
116
|
+
// as="div"
|
|
117
|
+
// active={alignment === 'left' ? true : undefined}
|
|
118
|
+
// data-value="left"
|
|
119
|
+
// value="left"
|
|
120
|
+
// icon={<AlignLeft size={24} color="grey-5" />}
|
|
121
|
+
// />
|
|
122
|
+
// <AlignToolbarButton
|
|
123
|
+
// as="div"
|
|
124
|
+
// active={alignment === 'center' ? true : undefined}
|
|
125
|
+
// data-value="center"
|
|
126
|
+
// value="center"
|
|
127
|
+
// icon={<AlignCenter size={24} color="grey-5" />}
|
|
128
|
+
// />
|
|
129
|
+
// <AlignToolbarButton
|
|
130
|
+
// as="div"
|
|
131
|
+
// active={alignment === 'right' ? true : undefined}
|
|
132
|
+
// data-value="right"
|
|
133
|
+
// value="right"
|
|
134
|
+
// icon={<AlignRight size={24} color="grey-5" />}
|
|
135
|
+
// />
|
|
136
|
+
// <AlignToolbarButton
|
|
137
|
+
// as="div"
|
|
138
|
+
// active={alignment === 'justify' ? true : undefined}
|
|
139
|
+
// data-value="justify"
|
|
140
|
+
// value="justify"
|
|
141
|
+
// icon={<AlignJustified size={24} color="grey-5" />}
|
|
142
|
+
// />
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import styled from 'styled-components';
|
|
3
|
+
import { Box, Button, H, Modal, P, Radio } from 'components';
|
|
4
|
+
import { Close, InsertButton } from 'icons';
|
|
5
|
+
import { MenuButton } from './navbar';
|
|
6
|
+
import { BUTTON_LINK, BUTTON_SUBSCRIBE } from '../constants';
|
|
7
|
+
|
|
8
|
+
interface ButtonModalProps {
|
|
9
|
+
onButtonInsert: (type: string) => void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const ButtonModal = ({ onButtonInsert }: ButtonModalProps) => {
|
|
13
|
+
const [buttonType, setButtonType] = React.useState<string | undefined>();
|
|
14
|
+
|
|
15
|
+
const handleButtonInsert = () => {
|
|
16
|
+
buttonType && onButtonInsert(buttonType);
|
|
17
|
+
setButtonType(undefined);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<Modal>
|
|
22
|
+
<Modal.Trigger>
|
|
23
|
+
<MenuButton>
|
|
24
|
+
<InsertButton size={24} color="grey-5" />
|
|
25
|
+
</MenuButton>
|
|
26
|
+
</Modal.Trigger>
|
|
27
|
+
<Modal.Content sx="border-radius: 16px; max-width: 782px; width: 100%; margin: 24px; padding: 0px;">
|
|
28
|
+
<Box $dir="column">
|
|
29
|
+
<Box
|
|
30
|
+
$align="center"
|
|
31
|
+
$justify="space-between"
|
|
32
|
+
sx="padding: 24px; box-shadow: var(--elevation-2);"
|
|
33
|
+
>
|
|
34
|
+
<Box $align="center" $gap={32}>
|
|
35
|
+
<IconWrapper>
|
|
36
|
+
<InsertButton size={24} color="hue-blue-1" />
|
|
37
|
+
</IconWrapper>
|
|
38
|
+
<H $bold $color="hue-blue-1" $fontSize={20} $lineHeight={28}>
|
|
39
|
+
Insert Button
|
|
40
|
+
</H>
|
|
41
|
+
</Box>
|
|
42
|
+
<Close
|
|
43
|
+
size={24}
|
|
44
|
+
sx="&:hover { cursor: pointer; border-radius: 50%; background-color: var(--color-grey-9); }"
|
|
45
|
+
/>
|
|
46
|
+
</Box>
|
|
47
|
+
<Box $dir="column" $gap={24} sx="padding: 24px 48px 24px 24px;">
|
|
48
|
+
<ButtonItem
|
|
49
|
+
active={buttonType === BUTTON_SUBSCRIBE}
|
|
50
|
+
description="A button encouraging the reader to purchase a paid subscription to your community"
|
|
51
|
+
onClick={() => setButtonType(BUTTON_SUBSCRIBE)}
|
|
52
|
+
title="Subscribe Now"
|
|
53
|
+
>
|
|
54
|
+
<Button size="small" sx="width: 130px;">
|
|
55
|
+
Subscribe
|
|
56
|
+
</Button>
|
|
57
|
+
</ButtonItem>
|
|
58
|
+
<ButtonItem
|
|
59
|
+
active={buttonType === BUTTON_LINK}
|
|
60
|
+
description="A button that links to a URL"
|
|
61
|
+
onClick={() => setButtonType(BUTTON_LINK)}
|
|
62
|
+
title="Link Button"
|
|
63
|
+
>
|
|
64
|
+
<Button size="small" sx="width: 130px;">
|
|
65
|
+
Link
|
|
66
|
+
</Button>
|
|
67
|
+
</ButtonItem>
|
|
68
|
+
</Box>
|
|
69
|
+
<Box
|
|
70
|
+
$padding={24}
|
|
71
|
+
$gap={16}
|
|
72
|
+
sx="padding: 24px; background-color: var(--color-white); border-top: 1px solid var(--color-grey-8);"
|
|
73
|
+
>
|
|
74
|
+
<Modal.Dismiss>
|
|
75
|
+
<Button
|
|
76
|
+
size="small"
|
|
77
|
+
sx="flex: 1;"
|
|
78
|
+
type="outlined"
|
|
79
|
+
onClick={() => setButtonType(undefined)}
|
|
80
|
+
>
|
|
81
|
+
Cancel
|
|
82
|
+
</Button>
|
|
83
|
+
</Modal.Dismiss>
|
|
84
|
+
<Modal.Dismiss>
|
|
85
|
+
<Button size="small" sx="flex: 1;" onClick={handleButtonInsert}>
|
|
86
|
+
Confirm
|
|
87
|
+
</Button>
|
|
88
|
+
</Modal.Dismiss>
|
|
89
|
+
</Box>
|
|
90
|
+
</Box>
|
|
91
|
+
</Modal.Content>
|
|
92
|
+
</Modal>
|
|
93
|
+
);
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const IconWrapper = styled.div`
|
|
97
|
+
height: 48px;
|
|
98
|
+
width: 48px;
|
|
99
|
+
box-sizing: border-box;
|
|
100
|
+
padding: 12px;
|
|
101
|
+
border-radius: 8px;
|
|
102
|
+
background-color: var(--color-hue-blue-2);
|
|
103
|
+
`;
|
|
104
|
+
|
|
105
|
+
interface ButtonItemProps extends React.PropsWithChildren {
|
|
106
|
+
active?: boolean;
|
|
107
|
+
description: string;
|
|
108
|
+
onClick: () => void;
|
|
109
|
+
title: string;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const ButtonItem = ({
|
|
113
|
+
active,
|
|
114
|
+
children,
|
|
115
|
+
description,
|
|
116
|
+
onClick,
|
|
117
|
+
title,
|
|
118
|
+
}: ButtonItemProps) => (
|
|
119
|
+
<Box
|
|
120
|
+
$dir="column"
|
|
121
|
+
onClick={onClick}
|
|
122
|
+
sx="border-radius: 16px; box-shadow: var(--elevation-2); cursor: pointer;"
|
|
123
|
+
>
|
|
124
|
+
<Box
|
|
125
|
+
sx={`
|
|
126
|
+
padding: 24px;
|
|
127
|
+
background-color: var(--color-blue-10);
|
|
128
|
+
border-radius: 8px 8px 0px 0px;
|
|
129
|
+
border-bottom: 1px solid var(--color-grey-9);
|
|
130
|
+
`}
|
|
131
|
+
>
|
|
132
|
+
<Radio checked={!!active} sx="align-items: flex-start;" value={title} />
|
|
133
|
+
<Box $dir="column">
|
|
134
|
+
<P $semiBold>{title}</P>
|
|
135
|
+
<P>{description}</P>
|
|
136
|
+
</Box>
|
|
137
|
+
</Box>
|
|
138
|
+
<Box
|
|
139
|
+
$align="center"
|
|
140
|
+
$justify="center"
|
|
141
|
+
sx="border-radius: 0px 0px 8px 8px; padding: 24px;"
|
|
142
|
+
>
|
|
143
|
+
{children}
|
|
144
|
+
</Box>
|
|
145
|
+
</Box>
|
|
146
|
+
);
|