mirror of
https://github.com/utopia-os/utopia-ui.git
synced 2026-03-01 12:44:17 +00:00
refactorng layout
This commit is contained in:
parent
391530aba1
commit
047c640a4e
@ -13,7 +13,7 @@ const ComboBoxInput = ({ id, options, value, onValueChange }: ComboBoxProps) =>
|
||||
return (
|
||||
<select
|
||||
id={id}
|
||||
className='tw:form-select tw:block tw:w-full tw:py-2 tw:px-4 tw:border tw:border-gray-300 rounded-md tw:shadow-sm tw:text-sm tw:focus:outline-hidden tw:focus:ring-indigo-500 tw:focus:border-indigo-500 tw:sm:text-sm'
|
||||
className='tw:select'
|
||||
onChange={handleChange}
|
||||
value={value} // ← hier controlled statt defaultValue
|
||||
>
|
||||
|
||||
@ -5,7 +5,7 @@ import TextStyle from '@tiptap/extension-text-style'
|
||||
import Youtube from '@tiptap/extension-youtube'
|
||||
import { EditorProvider } from '@tiptap/react'
|
||||
import StarterKit from '@tiptap/starter-kit'
|
||||
import { useState } from 'react'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { Markdown } from 'tiptap-markdown'
|
||||
|
||||
import { TextEditorMenu } from './TextEditorMenu'
|
||||
@ -30,6 +30,7 @@ const extensions = [
|
||||
Youtube.configure({
|
||||
controls: false,
|
||||
nocookie: true,
|
||||
width: 100,
|
||||
}),
|
||||
]
|
||||
|
||||
@ -63,9 +64,9 @@ export function RichTextEditor({
|
||||
// const ref = useRef<HTMLTextAreaElement>(null)
|
||||
const [inputValue, setInputValue] = useState<string>(defaultValue)
|
||||
|
||||
/* useEffect(() => {
|
||||
useEffect(() => {
|
||||
setInputValue(defaultValue)
|
||||
}, [defaultValue]) */
|
||||
}, [defaultValue])
|
||||
|
||||
console.log(
|
||||
labelTitle,
|
||||
@ -88,7 +89,9 @@ export function RichTextEditor({
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={`tw:form-control tw:w-full ${containerStyle ?? ''}`}>
|
||||
<div
|
||||
className={`tw:form-control tw:w-full tw:flex tw:flex-col tw:min-h-0 ${containerStyle ?? ''}`}
|
||||
>
|
||||
{labelTitle ? (
|
||||
<label className='tw:label'>
|
||||
<span className={`tw:label-text tw:text-base-content ${labelStyle ?? ''}`}>
|
||||
@ -96,22 +99,21 @@ export function RichTextEditor({
|
||||
</span>
|
||||
</label>
|
||||
) : null}
|
||||
<EditorProvider
|
||||
slotBefore={
|
||||
<>
|
||||
<br />
|
||||
<TextEditorMenu />
|
||||
</>
|
||||
}
|
||||
extensions={extensions}
|
||||
content={inputValue}
|
||||
onUpdate={handleChange}
|
||||
editorProps={{
|
||||
attributes: {
|
||||
class: 'prose prose-sm sm:prose-base lg:prose-lg xl:prose-2xl m-5 focus:outline-none',
|
||||
},
|
||||
}}
|
||||
></EditorProvider>
|
||||
<div
|
||||
className={`editor-wrapper tw:border-base-content/20 tw:rounded-box tw:border tw:flex tw:flex-col tw:flex-1 tw:min-h-0`}
|
||||
>
|
||||
<EditorProvider
|
||||
slotBefore={<TextEditorMenu />}
|
||||
extensions={extensions}
|
||||
content={inputValue}
|
||||
onUpdate={handleChange}
|
||||
editorProps={{
|
||||
attributes: {
|
||||
class: `tw:h-full tw:max-h-full tw:p-2 tw:overflow-y-auto`,
|
||||
},
|
||||
}}
|
||||
></EditorProvider>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@ import H3Icon from '@heroicons/react/24/solid/H3Icon'
|
||||
import ItalicIcon from '@heroicons/react/24/solid/ItalicIcon'
|
||||
import ListBulletIcon from '@heroicons/react/24/solid/ListBulletIcon'
|
||||
import NumberedListIcon from '@heroicons/react/24/solid/NumberedListIcon'
|
||||
import { useCurrentEditor } from '@tiptap/react'
|
||||
import { useCurrentEditor, useEditorState } from '@tiptap/react'
|
||||
import { FaQuoteLeft } from 'react-icons/fa6'
|
||||
import { MdUndo, MdRedo, MdHorizontalRule } from 'react-icons/md'
|
||||
|
||||
@ -17,6 +17,36 @@ export const TextEditorMenu = () => {
|
||||
return null
|
||||
}
|
||||
|
||||
const editorState = useEditorState({
|
||||
editor,
|
||||
selector: (ctx) => {
|
||||
return {
|
||||
isBold: ctx.editor.isActive('bold'),
|
||||
canBold: ctx.editor.can().chain().focus().toggleBold().run(),
|
||||
isItalic: ctx.editor.isActive('italic'),
|
||||
canItalic: ctx.editor.can().chain().focus().toggleItalic().run(),
|
||||
isStrike: ctx.editor.isActive('strike'),
|
||||
canStrike: ctx.editor.can().chain().focus().toggleStrike().run(),
|
||||
isCode: ctx.editor.isActive('code'),
|
||||
canCode: ctx.editor.can().chain().focus().toggleCode().run(),
|
||||
canClearMarks: ctx.editor.can().chain().focus().unsetAllMarks().run(),
|
||||
isParagraph: ctx.editor.isActive('paragraph'),
|
||||
isHeading1: ctx.editor.isActive('heading', { level: 1 }),
|
||||
isHeading2: ctx.editor.isActive('heading', { level: 2 }),
|
||||
isHeading3: ctx.editor.isActive('heading', { level: 3 }),
|
||||
isHeading4: ctx.editor.isActive('heading', { level: 4 }),
|
||||
isHeading5: ctx.editor.isActive('heading', { level: 5 }),
|
||||
isHeading6: ctx.editor.isActive('heading', { level: 6 }),
|
||||
isBulletList: ctx.editor.isActive('bulletList'),
|
||||
isOrderedList: ctx.editor.isActive('orderedList'),
|
||||
isCodeBlock: ctx.editor.isActive('codeBlock'),
|
||||
isBlockquote: ctx.editor.isActive('blockquote'),
|
||||
canUndo: ctx.editor.can().chain().focus().undo().run(),
|
||||
canRedo: ctx.editor.can().chain().focus().redo().run(),
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
const addYoutubeVideo = () => {
|
||||
const url = prompt('Enter YouTube URL')
|
||||
|
||||
@ -31,10 +61,28 @@ export const TextEditorMenu = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<ul className='tw:menu tw:menu-horizontal tw:bg-base-200 tw:rounded-box tw:mt-6'>
|
||||
<ul className='tw:menu tw:menu-horizontal tw:flex-none tw:bg-base-200 tw:rounded-box tw:w-full tw:rounded-b-none'>
|
||||
<li>
|
||||
<a
|
||||
className='tw:tooltip'
|
||||
className={`tw:tooltip ${editorState.canUndo ? '' : 'tw:opacity-50'}`}
|
||||
data-tip='Undo'
|
||||
onClick={() => editor.chain().focus().undo().run()}
|
||||
>
|
||||
<MdUndo className='tw:w-5 tw:h-5' />
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
className={`tw:tooltip ${editorState.canRedo ? '' : 'tw:opacity-50'}`}
|
||||
data-tip='Redo'
|
||||
onClick={() => editor.chain().focus().redo().run()}
|
||||
>
|
||||
<MdRedo className='tw:w-5 tw:h-5' />
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
className={`tw:tooltip ${editorState.isBold ? 'tw:bg-base-100' : ''}`}
|
||||
data-tip='Bold'
|
||||
onClick={() => editor.chain().focus().toggleBold().run()}
|
||||
>
|
||||
@ -43,7 +91,7 @@ export const TextEditorMenu = () => {
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
className='tw:tooltip'
|
||||
className={`tw:tooltip ${editorState.isItalic ? 'tw:bg-base-100' : ''}`}
|
||||
data-tip='Italic'
|
||||
onClick={() => editor.chain().focus().toggleItalic().run()}
|
||||
>
|
||||
@ -52,8 +100,8 @@ export const TextEditorMenu = () => {
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
className='tw:tooltip'
|
||||
data-tip='Details'
|
||||
className={`tw:tooltip ${editorState.isHeading1 ? 'tw:bg-base-100' : ''}`}
|
||||
data-tip='Heading 1'
|
||||
onClick={() => editor.chain().focus().toggleHeading({ level: 1 }).run()}
|
||||
>
|
||||
<H1Icon className='tw:w-5 tw:h-5' />
|
||||
@ -61,8 +109,8 @@ export const TextEditorMenu = () => {
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
className='tw:tooltip'
|
||||
data-tip='Details'
|
||||
className={`tw:tooltip ${editorState.isHeading2 ? 'tw:bg-base-100' : ''}`}
|
||||
data-tip='Heading 2'
|
||||
onClick={() => editor.chain().focus().toggleHeading({ level: 2 }).run()}
|
||||
>
|
||||
<H2Icon className='tw:w-5 tw:h-5' />
|
||||
@ -70,8 +118,8 @@ export const TextEditorMenu = () => {
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
className='tw:tooltip'
|
||||
data-tip='Details'
|
||||
className={`tw:tooltip ${editorState.isHeading3 ? 'tw:bg-base-100' : ''}`}
|
||||
data-tip='Heading 3'
|
||||
onClick={() => editor.chain().focus().toggleHeading({ level: 3 }).run()}
|
||||
>
|
||||
<H3Icon className='tw:w-5 tw:h-5' />
|
||||
@ -79,8 +127,8 @@ export const TextEditorMenu = () => {
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
className='tw:tooltip'
|
||||
data-tip='Details'
|
||||
className={`tw:tooltip ${editorState.isBulletList ? 'tw:bg-base-100' : ''}`}
|
||||
data-tip='List'
|
||||
onClick={() => editor.chain().focus().toggleBulletList().run()}
|
||||
>
|
||||
<ListBulletIcon className='tw:w-5 tw:h-5' />
|
||||
@ -88,8 +136,8 @@ export const TextEditorMenu = () => {
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
className='tw:tooltip'
|
||||
data-tip='Details'
|
||||
className={`tw:tooltip ${editorState.isOrderedList ? 'tw:bg-base-100' : ''}`}
|
||||
data-tip='List'
|
||||
onClick={() => editor.chain().focus().toggleOrderedList().run()}
|
||||
>
|
||||
<NumberedListIcon className='tw:w-5 tw:h-5' />
|
||||
@ -97,8 +145,8 @@ export const TextEditorMenu = () => {
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
className='tw:tooltip'
|
||||
data-tip='Details'
|
||||
className={`tw:tooltip ${editorState.isCodeBlock ? 'tw:bg-base-100' : ''}`}
|
||||
data-tip='Code'
|
||||
onClick={() => editor.chain().focus().toggleCodeBlock().run()}
|
||||
>
|
||||
<CodeBracketIcon className='tw:w-5 tw:h-5' />
|
||||
@ -106,8 +154,8 @@ export const TextEditorMenu = () => {
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
className='tw:tooltip'
|
||||
data-tip='Details'
|
||||
className={`tw:tooltip ${editorState.isBlockquote ? 'tw:bg-base-100' : ''}`}
|
||||
data-tip='Quote'
|
||||
onClick={() => editor.chain().focus().toggleBlockquote().run()}
|
||||
>
|
||||
<FaQuoteLeft className='tw:w-5 tw:h-5' />
|
||||
@ -116,25 +164,7 @@ export const TextEditorMenu = () => {
|
||||
<li>
|
||||
<a
|
||||
className='tw:tooltip'
|
||||
data-tip='Details'
|
||||
onClick={() => editor.chain().focus().redo().run()}
|
||||
>
|
||||
<MdRedo className='tw:w-5 tw:h-5' />
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
className='tw:tooltip'
|
||||
data-tip='Details'
|
||||
onClick={() => editor.chain().focus().undo().run()}
|
||||
>
|
||||
<MdUndo className='tw:w-5 tw:h-5' />
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
className='tw:tooltip'
|
||||
data-tip='Details'
|
||||
data-tip='Horizontal Line'
|
||||
onClick={() => editor.chain().focus().setHorizontalRule().run()}
|
||||
>
|
||||
<MdHorizontalRule className='tw:w-5 tw:h-5' />
|
||||
|
||||
@ -158,10 +158,10 @@ export function ProfileForm() {
|
||||
<>
|
||||
<MapOverlayPage
|
||||
backdrop
|
||||
className='tw:mx-4 tw:mt-4 tw:mb-4 tw:overflow-x-hidden tw:w-[calc(100%-32px)] tw:md:w-[calc(50%-32px)] tw:max-w-3xl tw:left-auto! tw:top-0 tw:bottom-0'
|
||||
className='tw:mx-4 tw:mt-4 tw:mb-4 tw:overflow-x-hidden tw:w-[calc(100%-32px)] tw:md:w-[calc(50%-32px)] tw:max-w-3xl tw:left-auto! tw:top-0 tw:bottom-0 tw:flex tw:flex-col'
|
||||
>
|
||||
<form
|
||||
className='tw:h-full'
|
||||
className='tw:flex tw:flex-col tw:flex-1 tw:min-h-0'
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault()
|
||||
void onUpdateItem(
|
||||
@ -178,7 +178,7 @@ export function ProfileForm() {
|
||||
)
|
||||
}}
|
||||
>
|
||||
<div className='tw:flex tw:flex-col tw:h-full'>
|
||||
<div className='tw:flex tw:flex-col tw:flex-1 tw:min-h-0'>
|
||||
<FormHeader item={item} state={state} setState={setState} />
|
||||
|
||||
{template === 'onepager' && (
|
||||
|
||||
@ -58,8 +58,8 @@ export const ProfileTextForm = ({
|
||||
}))
|
||||
}
|
||||
labelStyle={hideInputLabel ? 'tw:hidden' : ''}
|
||||
containerStyle={size === 'full' ? 'tw:grow tw:h-full' : ''}
|
||||
inputStyle={size === 'full' ? 'tw:h-full' : 'tw:h-24'}
|
||||
containerStyle={size === 'full' ? 'tw:grow' : 'tw:h-28 tw:flex-none'}
|
||||
inputStyle={size === 'full' ? 'tw:grow' : 'tw:h-28 tw:max-h-28 tw:flex-none'}
|
||||
required={required}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@ -29,7 +29,7 @@ export const FlexForm = ({
|
||||
item: Item
|
||||
}) => {
|
||||
return (
|
||||
<div className='tw:mt-6 tw:flex tw:flex-col tw:h-full'>
|
||||
<div className='tw:mt-6 tw:flex tw:flex-col tw:flex-1 tw:min-h-0'>
|
||||
{item.layer?.itemType.profileTemplate.map((templateItem) => {
|
||||
const TemplateComponent = componentMap[templateItem.collection]
|
||||
return TemplateComponent ? (
|
||||
|
||||
@ -53,23 +53,23 @@ export const TabsForm = ({
|
||||
}, [location.search])
|
||||
|
||||
return (
|
||||
<div className='tw:grow'>
|
||||
<div role='tablist' className='tw:tabs tw:h-full tw:tabs-lift tw:mt-3'>
|
||||
<div className='tw:grow tw:flex tw:flex-col tw:min-h-0'>
|
||||
<div role='tablist' className='tw:tabs tw:flex tw:flex-1 tw:min-h-0 tw:tabs-lift tw:mt-3'>
|
||||
<input
|
||||
type='radio'
|
||||
name='my_tabs_2'
|
||||
role='tab'
|
||||
className={'tw:tab '}
|
||||
className={'tw:tab'}
|
||||
aria-label='Info'
|
||||
checked={activeTab === 1 && true}
|
||||
onChange={() => updateActiveTab(1)}
|
||||
/>
|
||||
<div
|
||||
role='tabpanel'
|
||||
className='tw:tab-content tw:bg-base-100 tw:border-(--fallback-bc,oklch(var(--bc)/0.2)) tw:rounded-box tw:!h-[calc(100%-48px)] tw:min-h-56 tw:border-none'
|
||||
className='tw:!flex tw:!flex-col tw:tab-content tw:bg-base-100 tw:border-(--fallback-bc,oklch(var(--bc)/0.2)) tw:rounded-box tw:!h-[calc(100%-48px)] tw:min-h-56 tw:border-none'
|
||||
>
|
||||
<div
|
||||
className={`tw:flex tw:flex-col tw:h-full ${item.layer.itemType.show_start_end_input && 'tw:pt-4'}`}
|
||||
className={`tw:flex tw:flex-col tw:flex-1 tw:min-h-0 ${item.layer.itemType.show_start_end_input && 'tw:pt-4'}`}
|
||||
>
|
||||
{item.layer.itemType.show_start_end_input && (
|
||||
<PopupStartEndInput
|
||||
@ -114,7 +114,7 @@ export const TabsForm = ({
|
||||
}))
|
||||
}
|
||||
inputStyle=''
|
||||
containerStyle='tw:pt-4 tw:h-24 tw:flex-none'
|
||||
containerStyle='tw:pt-4 tw:h-32'
|
||||
required={false}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@ -11,4 +11,11 @@
|
||||
.tiptap blockquote,
|
||||
.tiptap code {
|
||||
all: revert;
|
||||
}
|
||||
|
||||
.editor-wrapper div {
|
||||
min-height: 0;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user