refactorng layout

This commit is contained in:
Anton Tranelis 2025-06-06 08:09:38 +02:00
parent 391530aba1
commit 047c640a4e
8 changed files with 109 additions and 70 deletions

View File

@ -13,7 +13,7 @@ const ComboBoxInput = ({ id, options, value, onValueChange }: ComboBoxProps) =>
return ( return (
<select <select
id={id} 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} onChange={handleChange}
value={value} // ← hier controlled statt defaultValue value={value} // ← hier controlled statt defaultValue
> >

View File

@ -5,7 +5,7 @@ import TextStyle from '@tiptap/extension-text-style'
import Youtube from '@tiptap/extension-youtube' import Youtube from '@tiptap/extension-youtube'
import { EditorProvider } from '@tiptap/react' import { EditorProvider } from '@tiptap/react'
import StarterKit from '@tiptap/starter-kit' import StarterKit from '@tiptap/starter-kit'
import { useState } from 'react' import { useEffect, useState } from 'react'
import { Markdown } from 'tiptap-markdown' import { Markdown } from 'tiptap-markdown'
import { TextEditorMenu } from './TextEditorMenu' import { TextEditorMenu } from './TextEditorMenu'
@ -30,6 +30,7 @@ const extensions = [
Youtube.configure({ Youtube.configure({
controls: false, controls: false,
nocookie: true, nocookie: true,
width: 100,
}), }),
] ]
@ -63,9 +64,9 @@ export function RichTextEditor({
// const ref = useRef<HTMLTextAreaElement>(null) // const ref = useRef<HTMLTextAreaElement>(null)
const [inputValue, setInputValue] = useState<string>(defaultValue) const [inputValue, setInputValue] = useState<string>(defaultValue)
/* useEffect(() => { useEffect(() => {
setInputValue(defaultValue) setInputValue(defaultValue)
}, [defaultValue]) */ }, [defaultValue])
console.log( console.log(
labelTitle, labelTitle,
@ -88,7 +89,9 @@ export function RichTextEditor({
} }
return ( 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 ? ( {labelTitle ? (
<label className='tw:label'> <label className='tw:label'>
<span className={`tw:label-text tw:text-base-content ${labelStyle ?? ''}`}> <span className={`tw:label-text tw:text-base-content ${labelStyle ?? ''}`}>
@ -96,22 +99,21 @@ export function RichTextEditor({
</span> </span>
</label> </label>
) : null} ) : null}
<EditorProvider <div
slotBefore={ 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`}
<> >
<br /> <EditorProvider
<TextEditorMenu /> slotBefore={<TextEditorMenu />}
</> extensions={extensions}
} content={inputValue}
extensions={extensions} onUpdate={handleChange}
content={inputValue} editorProps={{
onUpdate={handleChange} attributes: {
editorProps={{ class: `tw:h-full tw:max-h-full tw:p-2 tw:overflow-y-auto`,
attributes: { },
class: 'prose prose-sm sm:prose-base lg:prose-lg xl:prose-2xl m-5 focus:outline-none', }}
}, ></EditorProvider>
}} </div>
></EditorProvider>
</div> </div>
) )
} }

View File

@ -6,7 +6,7 @@ import H3Icon from '@heroicons/react/24/solid/H3Icon'
import ItalicIcon from '@heroicons/react/24/solid/ItalicIcon' import ItalicIcon from '@heroicons/react/24/solid/ItalicIcon'
import ListBulletIcon from '@heroicons/react/24/solid/ListBulletIcon' import ListBulletIcon from '@heroicons/react/24/solid/ListBulletIcon'
import NumberedListIcon from '@heroicons/react/24/solid/NumberedListIcon' 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 { FaQuoteLeft } from 'react-icons/fa6'
import { MdUndo, MdRedo, MdHorizontalRule } from 'react-icons/md' import { MdUndo, MdRedo, MdHorizontalRule } from 'react-icons/md'
@ -17,6 +17,36 @@ export const TextEditorMenu = () => {
return null 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 addYoutubeVideo = () => {
const url = prompt('Enter YouTube URL') const url = prompt('Enter YouTube URL')
@ -31,10 +61,28 @@ export const TextEditorMenu = () => {
return ( 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> <li>
<a <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' data-tip='Bold'
onClick={() => editor.chain().focus().toggleBold().run()} onClick={() => editor.chain().focus().toggleBold().run()}
> >
@ -43,7 +91,7 @@ export const TextEditorMenu = () => {
</li> </li>
<li> <li>
<a <a
className='tw:tooltip' className={`tw:tooltip ${editorState.isItalic ? 'tw:bg-base-100' : ''}`}
data-tip='Italic' data-tip='Italic'
onClick={() => editor.chain().focus().toggleItalic().run()} onClick={() => editor.chain().focus().toggleItalic().run()}
> >
@ -52,8 +100,8 @@ export const TextEditorMenu = () => {
</li> </li>
<li> <li>
<a <a
className='tw:tooltip' className={`tw:tooltip ${editorState.isHeading1 ? 'tw:bg-base-100' : ''}`}
data-tip='Details' data-tip='Heading 1'
onClick={() => editor.chain().focus().toggleHeading({ level: 1 }).run()} onClick={() => editor.chain().focus().toggleHeading({ level: 1 }).run()}
> >
<H1Icon className='tw:w-5 tw:h-5' /> <H1Icon className='tw:w-5 tw:h-5' />
@ -61,8 +109,8 @@ export const TextEditorMenu = () => {
</li> </li>
<li> <li>
<a <a
className='tw:tooltip' className={`tw:tooltip ${editorState.isHeading2 ? 'tw:bg-base-100' : ''}`}
data-tip='Details' data-tip='Heading 2'
onClick={() => editor.chain().focus().toggleHeading({ level: 2 }).run()} onClick={() => editor.chain().focus().toggleHeading({ level: 2 }).run()}
> >
<H2Icon className='tw:w-5 tw:h-5' /> <H2Icon className='tw:w-5 tw:h-5' />
@ -70,8 +118,8 @@ export const TextEditorMenu = () => {
</li> </li>
<li> <li>
<a <a
className='tw:tooltip' className={`tw:tooltip ${editorState.isHeading3 ? 'tw:bg-base-100' : ''}`}
data-tip='Details' data-tip='Heading 3'
onClick={() => editor.chain().focus().toggleHeading({ level: 3 }).run()} onClick={() => editor.chain().focus().toggleHeading({ level: 3 }).run()}
> >
<H3Icon className='tw:w-5 tw:h-5' /> <H3Icon className='tw:w-5 tw:h-5' />
@ -79,8 +127,8 @@ export const TextEditorMenu = () => {
</li> </li>
<li> <li>
<a <a
className='tw:tooltip' className={`tw:tooltip ${editorState.isBulletList ? 'tw:bg-base-100' : ''}`}
data-tip='Details' data-tip='List'
onClick={() => editor.chain().focus().toggleBulletList().run()} onClick={() => editor.chain().focus().toggleBulletList().run()}
> >
<ListBulletIcon className='tw:w-5 tw:h-5' /> <ListBulletIcon className='tw:w-5 tw:h-5' />
@ -88,8 +136,8 @@ export const TextEditorMenu = () => {
</li> </li>
<li> <li>
<a <a
className='tw:tooltip' className={`tw:tooltip ${editorState.isOrderedList ? 'tw:bg-base-100' : ''}`}
data-tip='Details' data-tip='List'
onClick={() => editor.chain().focus().toggleOrderedList().run()} onClick={() => editor.chain().focus().toggleOrderedList().run()}
> >
<NumberedListIcon className='tw:w-5 tw:h-5' /> <NumberedListIcon className='tw:w-5 tw:h-5' />
@ -97,8 +145,8 @@ export const TextEditorMenu = () => {
</li> </li>
<li> <li>
<a <a
className='tw:tooltip' className={`tw:tooltip ${editorState.isCodeBlock ? 'tw:bg-base-100' : ''}`}
data-tip='Details' data-tip='Code'
onClick={() => editor.chain().focus().toggleCodeBlock().run()} onClick={() => editor.chain().focus().toggleCodeBlock().run()}
> >
<CodeBracketIcon className='tw:w-5 tw:h-5' /> <CodeBracketIcon className='tw:w-5 tw:h-5' />
@ -106,8 +154,8 @@ export const TextEditorMenu = () => {
</li> </li>
<li> <li>
<a <a
className='tw:tooltip' className={`tw:tooltip ${editorState.isBlockquote ? 'tw:bg-base-100' : ''}`}
data-tip='Details' data-tip='Quote'
onClick={() => editor.chain().focus().toggleBlockquote().run()} onClick={() => editor.chain().focus().toggleBlockquote().run()}
> >
<FaQuoteLeft className='tw:w-5 tw:h-5' /> <FaQuoteLeft className='tw:w-5 tw:h-5' />
@ -116,25 +164,7 @@ export const TextEditorMenu = () => {
<li> <li>
<a <a
className='tw:tooltip' className='tw:tooltip'
data-tip='Details' data-tip='Horizontal Line'
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'
onClick={() => editor.chain().focus().setHorizontalRule().run()} onClick={() => editor.chain().focus().setHorizontalRule().run()}
> >
<MdHorizontalRule className='tw:w-5 tw:h-5' /> <MdHorizontalRule className='tw:w-5 tw:h-5' />

View File

@ -158,10 +158,10 @@ export function ProfileForm() {
<> <>
<MapOverlayPage <MapOverlayPage
backdrop 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 <form
className='tw:h-full' className='tw:flex tw:flex-col tw:flex-1 tw:min-h-0'
onSubmit={(e) => { onSubmit={(e) => {
e.preventDefault() e.preventDefault()
void onUpdateItem( 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} /> <FormHeader item={item} state={state} setState={setState} />
{template === 'onepager' && ( {template === 'onepager' && (

View File

@ -58,8 +58,8 @@ export const ProfileTextForm = ({
})) }))
} }
labelStyle={hideInputLabel ? 'tw:hidden' : ''} labelStyle={hideInputLabel ? 'tw:hidden' : ''}
containerStyle={size === 'full' ? 'tw:grow tw:h-full' : ''} containerStyle={size === 'full' ? 'tw:grow' : 'tw:h-28 tw:flex-none'}
inputStyle={size === 'full' ? 'tw:h-full' : 'tw:h-24'} inputStyle={size === 'full' ? 'tw:grow' : 'tw:h-28 tw:max-h-28 tw:flex-none'}
required={required} required={required}
/> />
</div> </div>

View File

@ -29,7 +29,7 @@ export const FlexForm = ({
item: Item item: Item
}) => { }) => {
return ( 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) => { {item.layer?.itemType.profileTemplate.map((templateItem) => {
const TemplateComponent = componentMap[templateItem.collection] const TemplateComponent = componentMap[templateItem.collection]
return TemplateComponent ? ( return TemplateComponent ? (

View File

@ -53,23 +53,23 @@ export const TabsForm = ({
}, [location.search]) }, [location.search])
return ( return (
<div className='tw:grow'> <div className='tw:grow tw:flex tw:flex-col tw:min-h-0'>
<div role='tablist' className='tw:tabs tw:h-full tw:tabs-lift tw:mt-3'> <div role='tablist' className='tw:tabs tw:flex tw:flex-1 tw:min-h-0 tw:tabs-lift tw:mt-3'>
<input <input
type='radio' type='radio'
name='my_tabs_2' name='my_tabs_2'
role='tab' role='tab'
className={'tw:tab '} className={'tw:tab'}
aria-label='Info' aria-label='Info'
checked={activeTab === 1 && true} checked={activeTab === 1 && true}
onChange={() => updateActiveTab(1)} onChange={() => updateActiveTab(1)}
/> />
<div <div
role='tabpanel' 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 <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 && ( {item.layer.itemType.show_start_end_input && (
<PopupStartEndInput <PopupStartEndInput
@ -114,7 +114,7 @@ export const TabsForm = ({
})) }))
} }
inputStyle='' inputStyle=''
containerStyle='tw:pt-4 tw:h-24 tw:flex-none' containerStyle='tw:pt-4 tw:h-32'
required={false} required={false}
/> />
</div> </div>

View File

@ -11,4 +11,11 @@
.tiptap blockquote, .tiptap blockquote,
.tiptap code { .tiptap code {
all: revert; all: revert;
}
.editor-wrapper div {
min-height: 0;
flex: 1;
display: flex;
flex-direction: column;
} }