Move Lexical styles to tailwind

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
marcin mikołajczak 2023-03-28 17:42:16 +02:00
parent 6b2109735d
commit 4ccfab3e5e
4 changed files with 91 additions and 419 deletions

View file

@ -157,11 +157,15 @@ const FloatingLinkEditor = ({
}, [isEditMode]);
return (
<div ref={editorRef} className='link-editor'>
<div className='link-input'>
<div
ref={editorRef}
className='absolute top-0 left-0 z-10 w-full max-w-sm rounded-lg bg-white opacity-0 shadow-md transition-opacity will-change-transform'
>
<div className='relative my-2 mx-3 box-border block rounded-2xl border-0 bg-gray-100 py-2 px-3 text-sm text-gray-800 outline-0 dark:bg-gray-800 dark:text-gray-100'>
{isEditMode ? (
<>
<input
className='-my-2 -mx-3 w-full border-0 bg-transparent py-2 px-3 text-sm text-gray-900 outline-0'
ref={inputRef}
value={linkUrl}
onChange={(event) => {
@ -188,7 +192,7 @@ const FloatingLinkEditor = ({
}}
/>
<div
className='link-edit'
className='absolute inset-y-0 right-0 flex w-9 cursor-pointer items-center justify-center'
role='button'
tabIndex={0}
onMouseDown={(event) => event.preventDefault()}
@ -201,11 +205,11 @@ const FloatingLinkEditor = ({
</>
) : (
<>
<a href={linkUrl} target='_blank' rel='noopener noreferrer'>
<a className='mr-8 block overflow-hidden text-ellipsis whitespace-nowrap text-primary-600 no-underline hover:underline dark:text-accent-blue' href={linkUrl} target='_blank' rel='noopener noreferrer'>
{linkUrl}
</a>
<div
className='link-edit'
className='absolute inset-y-0 right-0 flex w-9 cursor-pointer items-center justify-center'
role='button'
tabIndex={0}
onMouseDown={(event) => event.preventDefault()}

View file

@ -80,6 +80,24 @@ const blockTypeToBlockName = {
quote: 'Quote',
};
interface IToolbarButton extends React.HTMLAttributes<HTMLButtonElement> {
active?: boolean
icon: string
}
const ToolbarButton: React.FC<IToolbarButton> = ({ active, icon, ...props }) => (
<button
className={clsx(
'flex cursor-pointer rounded-lg border-0 bg-none p-1 align-middle hover:bg-gray-100 disabled:cursor-not-allowed disabled:hover:bg-none hover:dark:bg-primary-700',
{ 'bg-gray-100/30 dark:bg-gray-800/30': active },
)}
type='button'
{...props}
>
<Icon className='h-5 w-5' src={icon} />
</button>
);
const BlockTypeDropdown = ({ editor, anchorElem, blockType, icon }: {
editor: LexicalEditor
anchorElem: HTMLElement
@ -172,70 +190,56 @@ const BlockTypeDropdown = ({ editor, anchorElem, blockType, icon }: {
<>
<button
onClick={() => setShowDropDown(!showDropDown)}
className='popup-item spaced relative'
className='relative flex cursor-pointer rounded-lg border-0 bg-none p-1 align-middle hover:bg-gray-100 disabled:cursor-not-allowed disabled:hover:bg-none hover:dark:bg-primary-700'
aria-label=''
type='button'
>
<Icon src={icon} />
<Icon src={require('@tabler/icons/chevron-down.svg')} className='-bottom-2 h-4 w-4' />
{showDropDown && (
<div className='floating-text-format-popup' style={{ opacity: 1, top: 36 }}>
<button
<div
className='absolute top-9 left-0 z-10 flex h-[38px] gap-0.5 rounded-lg bg-white p-1 shadow-lg transition-[opacity] dark:bg-gray-900'
>
<ToolbarButton
onClick={formatParagraph}
className={clsx('popup-item spaced', blockType === 'paragraph' && 'active')}
type='button'
>
<Icon src={blockTypeToIcon.paragraph} />
</button>
<button
active={blockType === 'paragraph'}
icon={blockTypeToIcon.paragraph}
/>
<ToolbarButton
onClick={() => formatHeading('h1')}
className={clsx('popup-item spaced', blockType === 'h1' && 'active')}
type='button'
>
<Icon src={blockTypeToIcon.h1} />
</button>
<button
active={blockType === 'h1'}
icon={blockTypeToIcon.h1}
/>
<ToolbarButton
onClick={() => formatHeading('h2')}
className={clsx('popup-item spaced', blockType === 'h2' && 'active')}
type='button'
>
<Icon src={blockTypeToIcon.h2} />
</button>
<button
active={blockType === 'h2'}
icon={blockTypeToIcon.h2}
/>
<ToolbarButton
onClick={() => formatHeading('h3')}
className={clsx('popup-item spaced', blockType === 'h3' && 'active')}
type='button'
>
<Icon src={blockTypeToIcon.h3} />
</button>
<button
active={blockType === 'h3'}
icon={blockTypeToIcon.h3}
/>
<ToolbarButton
onClick={formatBulletList}
className={clsx('popup-item spaced', blockType === 'bullet' && 'active')}
type='button'
>
<Icon src={blockTypeToIcon.bullet} />
</button>
<button
active={blockType === 'bullet'}
icon={blockTypeToIcon.bullet}
/>
<ToolbarButton
onClick={formatNumberedList}
className={clsx('popup-item spaced', blockType === 'number' && 'active')}
type='button'
>
<Icon src={blockTypeToIcon.number} />
</button>
<button
active={blockType === 'number'}
icon={blockTypeToIcon.number}
/>
<ToolbarButton
onClick={formatQuote}
className={clsx('popup-item spaced', blockType === 'quote' && 'active')}
type='button'
>
<Icon src={blockTypeToIcon.quote} />
</button>
<button
active={blockType === 'quote'}
icon={blockTypeToIcon.quote}
/>
<ToolbarButton
onClick={formatCode}
className={clsx('popup-item spaced', blockType === 'code' && 'active')}
type='button'
>
<Icon src={blockTypeToIcon.code} />
</button>
active={blockType === 'code'}
icon={blockTypeToIcon.code}
/>
</div>
)}
</button>
@ -344,7 +348,10 @@ const TextFormatFloatingToolbar = ({
}, [editor, updateTextFormatFloatingToolbar]);
return (
<div ref={popupCharStylesEditorRef} className='floating-text-format-popup'>
<div
ref={popupCharStylesEditorRef}
className='absolute top-0 left-0 z-10 flex h-[38px] gap-0.5 rounded-lg bg-white p-1 opacity-0 shadow-lg transition-[opacity] dark:bg-gray-900'
>
{editor.isEditable() && (
<>
<BlockTypeDropdown
@ -353,64 +360,52 @@ const TextFormatFloatingToolbar = ({
blockType={blockType}
icon={blockTypeToIcon[blockType]}
/>
<button
<ToolbarButton
onClick={() => {
editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'bold');
}}
className={'popup-item spaced ' + (isBold ? 'active' : '')}
active={isBold}
aria-label='Format text as bold'
type='button'
>
<Icon src={require('@tabler/icons/bold.svg')} />
</button>
<button
icon={require('@tabler/icons/bold.svg')}
/>
<ToolbarButton
onClick={() => {
editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'italic');
}}
className={'popup-item spaced ' + (isItalic ? 'active' : '')}
active={isItalic}
aria-label='Format text as italics'
type='button'
>
<Icon src={require('@tabler/icons/italic.svg')} />
</button>
<button
icon={require('@tabler/icons/italic.svg')}
/>
<ToolbarButton
onClick={() => {
editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'underline');
}}
className={'popup-item spaced ' + (isUnderline ? 'active' : '')}
active={isUnderline}
aria-label='Format text to underlined'
type='button'
>
<Icon src={require('@tabler/icons/underline.svg')} />
</button>
<button
icon={require('@tabler/icons/underline.svg')}
/>
<ToolbarButton
onClick={() => {
editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'strikethrough');
}}
className={'popup-item spaced ' + (isStrikethrough ? 'active' : '')}
active={isStrikethrough}
aria-label='Format text with a strikethrough'
type='button'
>
<Icon src={require('@tabler/icons/strikethrough.svg')} />
</button>
<button
icon={require('@tabler/icons/strikethrough.svg')}
/>
<ToolbarButton
onClick={() => {
editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'code');
}}
className={'popup-item spaced ' + (isCode ? 'active' : '')}
active={isCode}
aria-label='Insert code block'
type='button'
>
<Icon src={require('@tabler/icons/code.svg')} />
</button>
<button
icon={require('@tabler/icons/code.svg')}
/>
<ToolbarButton
onClick={insertLink}
className={'popup-item spaced ' + (isLink ? 'active' : '')}
active={isLink}
aria-label='Insert link'
type='button'
>
<Icon src={require('@tabler/icons/link.svg')} />
</button>
icon={require('@tabler/icons/link.svg')}
/>
</>
)}
</div>

View file

@ -27,7 +27,6 @@
@import 'components/crypto-donate';
@import 'components/aliases';
@import 'components/icon';
@import 'components/lexical';
@import 'forms';
@import 'utilities';
@import 'components/datepicker';

View file

@ -1,326 +0,0 @@
.lexical {
.floating-text-format-popup {
@apply flex h-[38px] p-1 absolute top-0 left-0 bg-white dark:bg-gray-900 z-10 rounded-lg shadow-lg opacity-0 transition-[opacity];
}
.floating-text-format-popup button.popup-item {
border: 0;
display: flex;
background: none;
border-radius: 10px;
padding: 5px;
cursor: pointer;
vertical-align: middle;
}
.floating-text-format-popup button.popup-item:disabled {
cursor: not-allowed;
}
.floating-text-format-popup button.popup-item.spaced {
margin-right: 2px;
}
.floating-text-format-popup button.popup-item i.format {
background-size: contain;
height: 18px;
width: 18px;
margin-top: 2px;
vertical-align: -0.25em;
display: flex;
opacity: 0.6;
}
.floating-text-format-popup button.popup-item:disabled i.format {
opacity: 0.2;
}
.floating-text-format-popup button.popup-item.active {
background-color: rgba(223, 232, 250, 0.3);
}
.floating-text-format-popup button.popup-item.active i {
opacity: 1;
}
.floating-text-format-popup button.popup-item svg {
@apply h-5 w-5;
}
.floating-text-format-popup .popup-item:not([disabled]) {
@apply hover:bg-gray-100 hover:dark:bg-primary-700;
}
.floating-text-format-popup select.popup-item {
border: 0;
display: flex;
background: none;
border-radius: 10px;
padding: 8px;
vertical-align: middle;
width: 70px;
font-size: 14px;
color: #777;
text-overflow: ellipsis;
}
.floating-text-format-popup select.code-language {
text-transform: capitalize;
width: 130px;
}
.floating-text-format-popup .popup-item .text {
display: flex;
line-height: 20px;
vertical-align: middle;
font-size: 14px;
color: #777;
text-overflow: ellipsis;
width: 70px;
overflow: hidden;
height: 20px;
text-align: left;
}
.floating-text-format-popup .popup-item .icon {
display: flex;
width: 20px;
height: 20px;
user-select: none;
margin-right: 8px;
line-height: 16px;
background-size: contain;
}
.floating-text-format-popup i.chevron-down {
margin-top: 3px;
width: 16px;
height: 16px;
display: flex;
user-select: none;
}
.floating-text-format-popup i.chevron-down.inside {
width: 16px;
height: 16px;
display: flex;
margin-left: -25px;
margin-top: 11px;
margin-right: 10px;
pointer-events: none;
}
.floating-text-format-popup .divider {
width: 1px;
background-color: #eee;
margin: 0 4px;
}
.link-editor {
position: absolute;
top: 0;
left: 0;
z-index: 10;
max-width: 400px;
width: 100%;
opacity: 0;
background-color: #fff;
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.3);
border-radius: 8px;
transition: opacity 0.5s;
will-change: transform;
}
.link-editor .button {
width: 20px;
height: 20px;
display: inline-block;
padding: 6px;
border-radius: 8px;
cursor: pointer;
margin: 0 2px;
}
.link-editor .button.hovered {
width: 20px;
height: 20px;
display: inline-block;
background-color: #eee;
}
.link-editor .button i,
.actions i {
background-size: contain;
display: inline-block;
height: 20px;
width: 20px;
vertical-align: -0.25em;
}
.link-editor .button.active,
.toolbar .button.active {
background-color: rgb(223, 232, 250);
}
.link-editor .link-input {
display: block;
width: calc(100% - 24px);
box-sizing: border-box;
margin: 8px 12px;
padding: 8px 12px;
border-radius: 15px;
background-color: #eee;
font-size: 15px;
color: rgb(5, 5, 5);
border: 0;
outline: 0;
position: relative;
font-family: inherit;
}
.link-editor .link-input input {
width: 100%;
margin: -8px -12px;
padding: 8px 12px;
background: transparent;
font-size: 15px;
color: rgb(5, 5, 5);
border: 0;
outline: 0;
}
.link-editor div.link-edit {
display: flex;
align-items: center;
justify-content: center;
width: 36px;
position: absolute;
right: 0;
top: 0;
bottom: 0;
cursor: pointer;
}
.link-editor .link-input a {
color: rgb(33, 111, 219);
text-decoration: none;
display: block;
white-space: nowrap;
overflow: hidden;
margin-right: 30px;
text-overflow: ellipsis;
}
.link-editor .link-input a:hover {
text-decoration: underline;
}
.link-editor .font-size-wrapper,
.link-editor .font-family-wrapper {
display: flex;
margin: 0 4px;
}
.link-editor select {
padding: 6px;
border: none;
background-color: rgba(0, 0, 0, 0.075);
border-radius: 4px;
}
}
.typeahead-popover {
background: #fff;
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.3);
border-radius: 8px;
margin-top: 25px;
}
.typeahead-popover ul {
padding: 0;
list-style: none;
margin: 0;
border-radius: 8px;
max-height: 200px;
overflow-y: scroll;
}
.typeahead-popover ul::-webkit-scrollbar {
display: none;
}
.typeahead-popover ul {
-ms-overflow-style: none;
scrollbar-width: none;
}
.typeahead-popover ul li {
margin: 0;
min-width: 180px;
font-size: 14px;
outline: none;
cursor: pointer;
border-radius: 8px;
}
.typeahead-popover ul li.selected {
background: #eee;
}
.typeahead-popover li {
margin: 0 8px;
padding: 8px;
color: #050505;
cursor: pointer;
line-height: 16px;
font-size: 15px;
display: flex;
align-content: center;
flex-direction: row;
flex-shrink: 0;
background-color: #fff;
border-radius: 8px;
border: 0;
}
.typeahead-popover li.active {
display: flex;
width: 20px;
height: 20px;
background-size: contain;
}
.typeahead-popover li:first-child {
border-radius: 8px 8px 0 0;
}
.typeahead-popover li:last-child {
border-radius: 0 0 8px 8px;
}
.typeahead-popover li:hover {
background-color: #eee;
}
.typeahead-popover li .text {
display: flex;
line-height: 20px;
flex-grow: 1;
min-width: 150px;
}
.typeahead-popover li .icon {
display: flex;
width: 20px;
height: 20px;
user-select: none;
margin-right: 8px;
line-height: 16px;
background-size: contain;
background-repeat: no-repeat;
background-position: center;
}
.mentions-menu {
width: 250px;
}