Feature/wrapper for table of contents (#199)
* update editor layout for TableOfContents
This commit is contained in:
parent
1a233d074d
commit
39e27cc307
|
@ -249,11 +249,7 @@ export const Editor = (props: Props) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-5">
|
<div class="col-md-5" />
|
||||||
<Show when={isDesktop() && html()}>
|
|
||||||
<TableOfContents variant="editor" parentSelector="#editorBody" body={html()} />
|
|
||||||
</Show>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
<div ref={(el) => (editorElRef.current = el)} id="editorBody" />
|
<div ref={(el) => (editorElRef.current = el)} id="editorBody" />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -215,3 +215,12 @@
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.wrapperTableOfContents {
|
||||||
|
position: sticky;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
margin-bottom: -157px;
|
||||||
|
width: 240px;
|
||||||
|
padding-top: 100px;
|
||||||
|
}
|
||||||
|
|
|
@ -22,6 +22,8 @@ import { AutoSaveNotice } from '../Editor/AutoSaveNotice'
|
||||||
import { PublishSettings } from './PublishSettings'
|
import { PublishSettings } from './PublishSettings'
|
||||||
import { createStore } from 'solid-js/store'
|
import { createStore } from 'solid-js/store'
|
||||||
import SimplifiedEditor from '../Editor/SimplifiedEditor'
|
import SimplifiedEditor from '../Editor/SimplifiedEditor'
|
||||||
|
import { isDesktop } from '../../utils/media-query'
|
||||||
|
import { TableOfContents } from '../TableOfContents'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
shout: Shout
|
shout: Shout
|
||||||
|
@ -247,158 +249,166 @@ export const EditView = (props: Props) => {
|
||||||
|
|
||||||
<AutoSaveNotice active={saving()} />
|
<AutoSaveNotice active={saving()} />
|
||||||
|
|
||||||
<div class="row">
|
<div class="position-relative">
|
||||||
<div class="col-md-19 col-lg-18 col-xl-16 offset-md-5">
|
<div class={styles.wrapperTableOfContents}>
|
||||||
<Show when={page().route === 'edit'}>
|
<Show when={isDesktop() && form.body}>
|
||||||
<div class={styles.headingActions}>
|
<TableOfContents variant="editor" parentSelector="#editorBody" body={form.body} />
|
||||||
<Show when={!isSubtitleVisible()}>
|
|
||||||
<div class={styles.action} onClick={showSubtitleInput}>
|
|
||||||
{t('Add subtitle')}
|
|
||||||
</div>
|
|
||||||
</Show>
|
|
||||||
<Show when={!isLeadVisible()}>
|
|
||||||
<div class={styles.action} onClick={showLeadInput}>
|
|
||||||
{t('Add intro')}
|
|
||||||
</div>
|
|
||||||
</Show>
|
|
||||||
</div>
|
|
||||||
<>
|
|
||||||
<div class={clsx({ [styles.audioHeader]: props.shout.layout === 'audio' })}>
|
|
||||||
<div class={styles.inputContainer}>
|
|
||||||
<GrowingTextarea
|
|
||||||
allowEnterKey={true}
|
|
||||||
value={(value) => handleTitleInputChange(value)}
|
|
||||||
class={styles.titleInput}
|
|
||||||
placeholder={articleTitle()}
|
|
||||||
initialValue={form.title}
|
|
||||||
maxLength={MAX_HEADER_LIMIT}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Show when={formErrors.title}>
|
|
||||||
<div class={styles.validationError}>{formErrors.title}</div>
|
|
||||||
</Show>
|
|
||||||
|
|
||||||
<Show when={props.shout.layout === 'audio'}>
|
|
||||||
<div class={styles.additional}>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
placeholder={t('Artist...')}
|
|
||||||
class={styles.additionalInput}
|
|
||||||
value={mediaItems()[0]?.artist || ''}
|
|
||||||
onChange={(event) => handleBaseFieldsChange('artist', event.target.value)}
|
|
||||||
/>
|
|
||||||
<input
|
|
||||||
type="number"
|
|
||||||
min="1900"
|
|
||||||
max={new Date().getFullYear()}
|
|
||||||
step="1"
|
|
||||||
class={styles.additionalInput}
|
|
||||||
placeholder={t('Release date...')}
|
|
||||||
value={mediaItems()[0]?.date || ''}
|
|
||||||
onChange={(event) => handleBaseFieldsChange('date', event.target.value)}
|
|
||||||
/>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
placeholder={t('Genre...')}
|
|
||||||
class={styles.additionalInput}
|
|
||||||
value={mediaItems()[0]?.genre || ''}
|
|
||||||
onChange={(event) => handleBaseFieldsChange('genre', event.target.value)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Show>
|
|
||||||
<Show when={props.shout.layout !== 'audio'}>
|
|
||||||
<Show when={isSubtitleVisible()}>
|
|
||||||
<GrowingTextarea
|
|
||||||
textAreaRef={(el) => {
|
|
||||||
subtitleInput.current = el
|
|
||||||
}}
|
|
||||||
allowEnterKey={false}
|
|
||||||
value={(value) => setForm('subtitle', value)}
|
|
||||||
class={styles.subtitleInput}
|
|
||||||
placeholder={t('Subheader')}
|
|
||||||
initialValue={form.subtitle}
|
|
||||||
maxLength={MAX_HEADER_LIMIT}
|
|
||||||
/>
|
|
||||||
</Show>
|
|
||||||
<Show when={isLeadVisible()}>
|
|
||||||
<SimplifiedEditor
|
|
||||||
variant="minimal"
|
|
||||||
onlyBubbleControls={true}
|
|
||||||
smallHeight={true}
|
|
||||||
placeholder={t('A short introduction to keep the reader interested')}
|
|
||||||
initialContent={form.lead}
|
|
||||||
onChange={(value) => setForm('lead', value)}
|
|
||||||
/>
|
|
||||||
</Show>
|
|
||||||
</Show>
|
|
||||||
</div>
|
|
||||||
<Show when={props.shout.layout === 'audio'}>
|
|
||||||
<Show
|
|
||||||
when={form.coverImageUrl}
|
|
||||||
fallback={
|
|
||||||
<DropArea
|
|
||||||
isSquare={true}
|
|
||||||
placeholder={t('Add cover')}
|
|
||||||
description={
|
|
||||||
<>
|
|
||||||
{t('min. 1400×1400 pix')}
|
|
||||||
<br />
|
|
||||||
{t('jpg, .png, max. 10 mb.')}
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
isMultiply={false}
|
|
||||||
fileType={'image'}
|
|
||||||
onUpload={(val) => setForm('coverImageUrl', val[0].url)}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class={styles.cover}
|
|
||||||
style={{ 'background-image': `url(${imageProxy(form.coverImageUrl)})` }}
|
|
||||||
/>
|
|
||||||
</Show>
|
|
||||||
</Show>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Show when={props.shout.layout === 'image'}>
|
|
||||||
<SolidSwiper
|
|
||||||
editorMode={true}
|
|
||||||
images={mediaItems()}
|
|
||||||
onImageChange={handleMediaChange}
|
|
||||||
onImageDelete={(index) => handleMediaDelete(index)}
|
|
||||||
onImagesAdd={(value) => handleAddMedia(value)}
|
|
||||||
onImagesSorted={(value) => handleSortedMedia(value)}
|
|
||||||
/>
|
|
||||||
</Show>
|
|
||||||
|
|
||||||
<Show when={props.shout.layout === 'video'}>
|
|
||||||
<VideoUploader
|
|
||||||
video={mediaItems()}
|
|
||||||
onVideoAdd={(data) => handleAddMedia(data)}
|
|
||||||
onVideoDelete={(index) => handleMediaDelete(index)}
|
|
||||||
/>
|
|
||||||
</Show>
|
|
||||||
|
|
||||||
<Show when={props.shout.layout === 'audio'}>
|
|
||||||
<AudioUploader
|
|
||||||
audio={mediaItems()}
|
|
||||||
baseFields={baseAudioFields()}
|
|
||||||
onAudioAdd={(value) => handleAddMedia(value)}
|
|
||||||
onAudioChange={handleMediaChange}
|
|
||||||
onAudioSorted={(value) => handleSortedMedia(value)}
|
|
||||||
/>
|
|
||||||
</Show>
|
|
||||||
</>
|
|
||||||
</Show>
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-19 col-lg-18 col-xl-16 offset-md-5">
|
||||||
|
<Show when={page().route === 'edit'}>
|
||||||
|
<div class={styles.headingActions}>
|
||||||
|
<Show when={!isSubtitleVisible()}>
|
||||||
|
<div class={styles.action} onClick={showSubtitleInput}>
|
||||||
|
{t('Add subtitle')}
|
||||||
|
</div>
|
||||||
|
</Show>
|
||||||
|
<Show when={!isLeadVisible()}>
|
||||||
|
<div class={styles.action} onClick={showLeadInput}>
|
||||||
|
{t('Add intro')}
|
||||||
|
</div>
|
||||||
|
</Show>
|
||||||
|
</div>
|
||||||
|
<>
|
||||||
|
<div class={clsx({ [styles.audioHeader]: props.shout.layout === 'audio' })}>
|
||||||
|
<div class={styles.inputContainer}>
|
||||||
|
<GrowingTextarea
|
||||||
|
allowEnterKey={true}
|
||||||
|
value={(value) => handleTitleInputChange(value)}
|
||||||
|
class={styles.titleInput}
|
||||||
|
placeholder={articleTitle()}
|
||||||
|
initialValue={form.title}
|
||||||
|
maxLength={MAX_HEADER_LIMIT}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Show when={formErrors.title}>
|
||||||
|
<div class={styles.validationError}>{formErrors.title}</div>
|
||||||
|
</Show>
|
||||||
|
|
||||||
|
<Show when={props.shout.layout === 'audio'}>
|
||||||
|
<div class={styles.additional}>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
placeholder={t('Artist...')}
|
||||||
|
class={styles.additionalInput}
|
||||||
|
value={mediaItems()[0]?.artist || ''}
|
||||||
|
onChange={(event) => handleBaseFieldsChange('artist', event.target.value)}
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
min="1900"
|
||||||
|
max={new Date().getFullYear()}
|
||||||
|
step="1"
|
||||||
|
class={styles.additionalInput}
|
||||||
|
placeholder={t('Release date...')}
|
||||||
|
value={mediaItems()[0]?.date || ''}
|
||||||
|
onChange={(event) => handleBaseFieldsChange('date', event.target.value)}
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
placeholder={t('Genre...')}
|
||||||
|
class={styles.additionalInput}
|
||||||
|
value={mediaItems()[0]?.genre || ''}
|
||||||
|
onChange={(event) => handleBaseFieldsChange('genre', event.target.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Show>
|
||||||
|
<Show when={props.shout.layout !== 'audio'}>
|
||||||
|
<Show when={isSubtitleVisible()}>
|
||||||
|
<GrowingTextarea
|
||||||
|
textAreaRef={(el) => {
|
||||||
|
subtitleInput.current = el
|
||||||
|
}}
|
||||||
|
allowEnterKey={false}
|
||||||
|
value={(value) => setForm('subtitle', value)}
|
||||||
|
class={styles.subtitleInput}
|
||||||
|
placeholder={t('Subheader')}
|
||||||
|
initialValue={form.subtitle}
|
||||||
|
maxLength={MAX_HEADER_LIMIT}
|
||||||
|
/>
|
||||||
|
</Show>
|
||||||
|
<Show when={isLeadVisible()}>
|
||||||
|
<SimplifiedEditor
|
||||||
|
variant="minimal"
|
||||||
|
onlyBubbleControls={true}
|
||||||
|
smallHeight={true}
|
||||||
|
placeholder={t('A short introduction to keep the reader interested')}
|
||||||
|
initialContent={form.lead}
|
||||||
|
onChange={(value) => setForm('lead', value)}
|
||||||
|
/>
|
||||||
|
</Show>
|
||||||
|
</Show>
|
||||||
|
</div>
|
||||||
|
<Show when={props.shout.layout === 'audio'}>
|
||||||
|
<Show
|
||||||
|
when={form.coverImageUrl}
|
||||||
|
fallback={
|
||||||
|
<DropArea
|
||||||
|
isSquare={true}
|
||||||
|
placeholder={t('Add cover')}
|
||||||
|
description={
|
||||||
|
<>
|
||||||
|
{t('min. 1400×1400 pix')}
|
||||||
|
<br />
|
||||||
|
{t('jpg, .png, max. 10 mb.')}
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
isMultiply={false}
|
||||||
|
fileType={'image'}
|
||||||
|
onUpload={(val) => setForm('coverImageUrl', val[0].url)}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class={styles.cover}
|
||||||
|
style={{ 'background-image': `url(${imageProxy(form.coverImageUrl)})` }}
|
||||||
|
/>
|
||||||
|
</Show>
|
||||||
|
</Show>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Show when={props.shout.layout === 'image'}>
|
||||||
|
<SolidSwiper
|
||||||
|
editorMode={true}
|
||||||
|
images={mediaItems()}
|
||||||
|
onImageChange={handleMediaChange}
|
||||||
|
onImageDelete={(index) => handleMediaDelete(index)}
|
||||||
|
onImagesAdd={(value) => handleAddMedia(value)}
|
||||||
|
onImagesSorted={(value) => handleSortedMedia(value)}
|
||||||
|
/>
|
||||||
|
</Show>
|
||||||
|
|
||||||
|
<Show when={props.shout.layout === 'video'}>
|
||||||
|
<VideoUploader
|
||||||
|
video={mediaItems()}
|
||||||
|
onVideoAdd={(data) => handleAddMedia(data)}
|
||||||
|
onVideoDelete={(index) => handleMediaDelete(index)}
|
||||||
|
/>
|
||||||
|
</Show>
|
||||||
|
|
||||||
|
<Show when={props.shout.layout === 'audio'}>
|
||||||
|
<AudioUploader
|
||||||
|
audio={mediaItems()}
|
||||||
|
baseFields={baseAudioFields()}
|
||||||
|
onAudioAdd={(value) => handleAddMedia(value)}
|
||||||
|
onAudioChange={handleMediaChange}
|
||||||
|
onAudioSorted={(value) => handleSortedMedia(value)}
|
||||||
|
/>
|
||||||
|
</Show>
|
||||||
|
</>
|
||||||
|
</Show>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Show when={page().route === 'edit'}>
|
||||||
|
<Editor
|
||||||
|
shoutId={form.shoutId}
|
||||||
|
initialContent={form.body}
|
||||||
|
onChange={(body) => setForm('body', body)}
|
||||||
|
/>
|
||||||
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
<Show when={page().route === 'edit'}>
|
|
||||||
<Editor
|
|
||||||
shoutId={form.shoutId}
|
|
||||||
initialContent={form.body}
|
|
||||||
onChange={(body) => setForm('body', body)}
|
|
||||||
/>
|
|
||||||
</Show>
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user