1
0
mirror of https://github.com/BookStackApp/BookStack.git synced 2024-10-30 07:32:39 +01:00

Merge pull request #4604 from BookStackApp/editor_trim_enhancement

Editor design update
This commit is contained in:
Dan Brown 2023-10-14 17:30:04 +01:00 committed by GitHub
commit 3274181e14
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 295 additions and 218 deletions

View File

@ -295,6 +295,7 @@ return [
'pages_is_template' => 'Page Template',
// Editor Sidebar
'toggle_sidebar' => 'Toggle Sidebar',
'page_tags' => 'Page Tags',
'chapter_tags' => 'Chapter Tags',
'book_tags' => 'Book Tags',

View File

@ -8,6 +8,7 @@ export class EditorToolbox extends Component {
this.buttons = this.$manyRefs.tabButton;
this.contentElements = this.$manyRefs.tabContent;
this.toggleButton = this.$refs.toggle;
this.editorWrapEl = this.container.closest('.page-editor');
this.setupListeners();
@ -30,8 +31,9 @@ export class EditorToolbox extends Component {
toggle() {
this.container.classList.toggle('open');
const expanded = this.container.classList.contains('open') ? 'true' : 'false';
this.toggleButton.setAttribute('aria-expanded', expanded);
const isOpen = this.container.classList.contains('open');
this.toggleButton.setAttribute('aria-expanded', isOpen ? 'true' : 'false');
this.editorWrapEl.classList.toggle('toolbox-open', isOpen);
}
setActiveTab(tabName, openToolbox = false) {

View File

@ -155,6 +155,7 @@
margin-bottom: $-l;
overflow: initial;
min-height: 60vh;
border-radius: 8px;
&.auto-height {
min-height: 0;
}

View File

@ -148,10 +148,9 @@ html.markdown-editor-display.dark-mode {
width: 100%;
font-size: 11px;
line-height: 1.6;
border-bottom: 1px solid #DDD;
background-color: #EEE;
@include lightDark(background-color, #eee, #111);
@include lightDark(border-color, #ddd, #000);
border-bottom: 1px solid #CCC;
//background-color: var(--color-primary-light);
@include lightDark(border-color, #CCC, #000);
flex: none;
@include whenDark {
button {
@ -398,27 +397,6 @@ input[type=color] {
height: auto;
}
.title-input.page-title {
font-size: 0.8em;
@include lightDark(background-color, #fff, #333);
.input {
border: 0;
margin-bottom: -1px;
}
input[type="text"] {
max-width: 840px;
margin: 0 auto;
border: none;
height: auto;
}
}
.page-title input {
display: block;
width: 100%;
font-size: 1.4em;
}
.description-input textarea {
display: block;
width: 100%;
@ -428,11 +406,6 @@ input[type=color] {
height: auto;
}
div[editor-type="markdown"] .title-input.page-title input[type="text"] {
max-width: 100%;
border-radius: 0;
}
.search-box {
max-width: 100%;
position: relative;

View File

@ -364,43 +364,4 @@ header .search-box.search-active:focus-within {
.faded span.faded-text {
display: inline-block;
padding: $-s;
}
.action-buttons .text-button {
display: inline-block;
padding: $-xs $-s;
&:last-child {
padding-inline-end: 0;
}
&:first-child {
padding-inline-start: 0;
}
}
.action-buttons .dropdown-container:last-child a {
padding-inline-end: 0;
padding-inline-start: $-s;
}
.action-buttons {
text-align: end;
&.text-left {
text-align: start;
.text-button {
padding-inline-end: $-m;
padding-inline-start: 0;
}
}
&.text-center {
text-align: center;
}
}
@include smaller-than($m) {
.action-buttons .text-button {
padding: $-xs $-xs;
}
.action-buttons .dropdown-container:last-child a {
padding-inline-start: $-xs;
}
}

View File

@ -8,6 +8,8 @@
flex: 1;
flex-direction: column;
z-index: 10;
overflow: hidden;
border-radius: 0 0 8px 8px;
}
.mce-tinymce {
@ -19,6 +21,69 @@
}
}
.page-editor-page-area {
width: 100%;
border-radius: 8px;
box-shadow: $bs-card;
@include lightDark(background-color, #FFF, #333)
}
.page-edit-toolbar {
width: 100%;
margin: 0 auto;
display: grid;
grid-template-columns: minmax(max-content, 2fr) 1.5fr minmax(max-content, 2fr);
align-items: center;
}
@include larger-than($xxl) {
.page-editor-wysiwyg .page-edit-toolbar,
.page-editor-wysiwyg .page-editor-page-area {
max-width: 1140px;
}
.page-editor-wysiwyg .floating-toolbox {
position: absolute;
}
}
@include smaller-than($m) {
.page-edit-toolbar {
display: flex;
flex-direction: row;
justify-content: space-between;
}
}
.title-input.page-title {
font-size: 0.8em;
.input {
border: 0;
margin-bottom: -1px;
}
input[type="text"] {
max-width: 840px;
margin: 0 auto;
border: none;
height: auto;
display: block;
width: 100%;
font-size: 20px;
border-radius: 8px;
}
input[type="text"]:focus {
position: relative;
outline-offset: -1px;
outline: 1px dashed var(--color-primary);
box-shadow: $bs-card;
z-index: 50;
}
}
.page-editor-markdown .title-input.page-title input[type="text"] {
max-width: 100%;
}
body.tox-fullscreen .page-editor .edit-area,
body.markdown-fullscreen .page-editor .edit-area {
z-index: 12;
@ -35,8 +100,7 @@ body.tox-fullscreen, body.markdown-fullscreen {
overflow-x: scroll;
overflow-y: visible;
}
.page-edit-toolbar .grid.third {
display: block;
.page-edit-toolbar {
white-space: nowrap;
> div {
display: inline-block;
@ -48,10 +112,10 @@ body.tox-fullscreen, body.markdown-fullscreen {
position: fixed;
z-index: 30;
border-radius: 50%;
width: 56px;
height: 56px;
font-size: 24px;
right: $-m;
width: 52px;
height: 52px;
font-size: 26px;
right: $-xs;
bottom: $-s;
box-shadow: $bs-hover;
background-color: currentColor;
@ -149,22 +213,27 @@ body.tox-fullscreen, body.markdown-fullscreen {
}
}
// Attribute form
// Page editor sidebar toolbox
.floating-toolbox {
border: 1px solid #DDD;
@include lightDark(background-color, #fff, #222);
@include lightDark(border-color, #DDD, #000);
right: $-xl*2;
width: 48px;
@include lightDark(background-color, #FFF, #222);
overflow: hidden;
align-items: stretch;
flex-direction: row;
display: flex;
transition: width ease-in-out 180ms;
margin-top: -1px;
min-height: 0;
max-height: 100%;
border-radius: 8px;
box-shadow: $bs-card;
margin-bottom: auto;
margin-left: $-l;
position: relative;
&.open {
width: 480px;
position: relative;
right: 0;
max-width: 480px;
margin-bottom: 0;
}
&:not(.open) .toolbox-tab-content {
display: none !important;
}
.toolbox-toggle svg {
transition: transform ease-in-out 180ms;
@ -173,7 +242,7 @@ body.tox-fullscreen, body.markdown-fullscreen {
transition: background-color ease-in-out 180ms;
}
&.open .toolbox-toggle {
background-color: rgba(255, 0, 0, 0.29);
background-color: rgba(255, 0, 0, 0.20);
}
&.open .toolbox-toggle svg {
transform: rotate(180deg);
@ -183,28 +252,34 @@ body.tox-fullscreen, body.markdown-fullscreen {
position: relative;
}
.tabs {
display: block;
border-inline-end: 1px solid #DDD;
@include lightDark(border-color, #ddd, #000);
width: 48px;
border-right: 1px solid #DDD;
@include lightDark(border-right-color, #DDD, #000);
width: 40px;
flex: 0 1 auto;
margin-right: -1px;
}
.tabs-inner {
@include lightDark(background-color, #FFFFFF, #222);
}
.tabs svg {
padding: 0;
margin: 0;
}
.tabs > button {
@include lightDark(color, rgba(0, 0, 0, 0.5), rgba(255, 255, 255, 0.5));
.tabs-inner > button {
@include lightDark(color, rgba(0, 0, 0, 0.7), rgba(255, 255, 255, 0.5));
display: block;
cursor: pointer;
padding: $-s $-m;
font-size: 16px;
padding: 10px $-xs;
font-size: 18px;
line-height: 1.6;
border-bottom: 1px solid rgba(255, 255, 255, 0.3);
}
&.open .tabs > button.active {
@include lightDark(color, #444, #EEE);
background-color: rgba(0, 0, 0, 0.1);
.tabs-inner > button:hover, &.open .tabs-inner > button.active {
background-color: var(--color-primary-light);
color: var(--color-primary);
}
&.open .tabs-inner > button.active {
border-inline-end: 1px solid var(--color-primary);
margin-inline-end: -1px;
}
h4 {
font-size: 24px;
@ -237,6 +312,33 @@ body.tox-fullscreen, body.markdown-fullscreen {
}
}
@include smaller-than($xxl) {
.floating-toolbox {
margin-left: $-s;
}
}
@include smaller-than($s) {
.page-editor-page-area-wrap {
margin: 4px !important;
}
.floating-toolbox {
margin-left: 4px;
}
.floating-toolbox .tabs {
width: 32px;
}
.floating-toolbox .tabs-inner > button {
font-size: 12px;
}
.page-edit-toolbar {
padding-block: 0 !important;
}
.page-editor.toolbox-open .page-editor-page-area {
display: none;
}
}
.toolbox-tab-content {
display: none;
overflow-y: auto;

View File

@ -9,6 +9,12 @@
z-index: 100;
}
// Editor wrapper edits
.tox.tox-tinymce {
border-inline: 0;
border-bottom: 0;
}
// In editor body overrides
.page-content.mce-content-body {
padding-block-start: 1rem;

View File

@ -10,7 +10,6 @@
@if(!$isDraft) {{ method_field('PUT') }} @endif
@include('pages.parts.form', ['model' => $page])
@include('pages.parts.editor-toolbox')
</form>
</div>

View File

@ -1,97 +1,116 @@
<div class="primary-background-light toolbar page-edit-toolbar">
<div class="grid third no-break v-center">
<div class="toolbar page-edit-toolbar py-xs">
<div class="action-buttons text-left px-m py-xs">
<div>
<div class="inline block">
<a href="{{ $isDraft ? $page->getParent()->getUrl() : $page->getUrl() }}"
class="text-button text-link">@icon('back')<span class="hide-under-l">{{ trans('common.back') }}</span></a>
class="icon-list-item text-link"><span>@icon('back')</span><span class="hide-under-l">{{ trans('common.back') }}</span></a>
</div>
</div>
<div class="text-center px-m">
<div component="dropdown"
option:dropdown:move-menu="true"
class="dropdown-container draft-display text {{ $draftsEnabled ? '' : 'hidden' }}">
<button type="button" refs="dropdown@toggle" aria-haspopup="true" aria-expanded="false" title="{{ trans('entities.pages_edit_draft_options') }}" class="text-link text-button py-s px-m"><span refs="page-editor@draftDisplay" class="faded-text"></span>&nbsp; @icon('more')</button>
<div class="text-center">
<div component="dropdown"
option:dropdown:move-menu="true"
class="dropdown-container draft-display text {{ $draftsEnabled ? '' : 'hidden' }}">
<div class="flex-container-row items-center justify-center">
<button type="button"
refs="dropdown@toggle"
aria-haspopup="true"
aria-expanded="false"
title="{{ trans('entities.pages_edit_draft_options') }}"
class="text-link icon-list-item">
<span>@icon('time')</span>
<span><span refs="page-editor@draftDisplay" class="faded-text"></span>&nbsp; @icon('more')</span>
</button>
@icon('check-circle', ['class' => 'text-pos draft-notification svg-icon', 'refs' => 'page-editor@draftDisplayIcon'])
<ul refs="dropdown@menu" class="dropdown-menu" role="menu">
<li>
<button refs="page-editor@saveDraft" type="button" class="text-pos icon-item">
@icon('save')
<div>{{ trans('entities.pages_edit_save_draft') }}</div>
</button>
</li>
@if($isDraft)
<li>
<a href="{{ $model->getUrl('/delete') }}" class="text-neg icon-item">
@icon('delete')
{{ trans('entities.pages_edit_delete_draft') }}
</a>
</li>
@endif
<li refs="page-editor@discard-draft-wrap" {{ $isDraftRevision ? '' : 'hidden' }}>
<button refs="page-editor@discard-draft" type="button" class="text-warn icon-item">
@icon('cancel')
<div>{{ trans('entities.pages_edit_discard_draft') }}</div>
</button>
</li>
<li refs="page-editor@delete-draft-wrap" {{ $isDraftRevision ? '' : 'hidden' }}>
<button refs="page-editor@delete-draft" type="button" class="text-neg icon-item">
@icon('delete')
<div>{{ trans('entities.pages_edit_delete_draft') }}</div>
</button>
</li>
@if(userCan('editor-change'))
<li>
<hr>
</li>
<li>
@if($editor === 'wysiwyg')
<a href="{{ $model->getUrl($isDraft ? '' : '/edit') }}?editor=markdown-clean" refs="page-editor@changeEditor" class="icon-item">
@icon('swap-horizontal')
<div>
{{ trans('entities.pages_edit_switch_to_markdown') }}
<br>
<small>{{ trans('entities.pages_edit_switch_to_markdown_clean') }}</small>
</div>
</a>
<a href="{{ $model->getUrl($isDraft ? '' : '/edit') }}?editor=markdown-stable" refs="page-editor@changeEditor" class="icon-item">
@icon('swap-horizontal')
<div>
{{ trans('entities.pages_edit_switch_to_markdown') }}
<br>
<small>{{ trans('entities.pages_edit_switch_to_markdown_stable') }}</small>
</div>
</a>
@else
<a href="{{ $model->getUrl($isDraft ? '' : '/edit') }}?editor=wysiwyg" refs="page-editor@changeEditor" class="icon-item">
@icon('swap-horizontal')
<div>{{ trans('entities.pages_edit_switch_to_wysiwyg') }}</div>
</a>
@endif
</li>
@endif
</ul>
</div>
<ul refs="dropdown@menu" class="dropdown-menu" role="menu">
<li>
<button refs="page-editor@saveDraft" type="button" class="text-pos icon-item">
@icon('save')
<div>{{ trans('entities.pages_edit_save_draft') }}</div>
</button>
</li>
@if($isDraft)
<li>
<a href="{{ $model->getUrl('/delete') }}" class="text-neg icon-item">
@icon('delete')
{{ trans('entities.pages_edit_delete_draft') }}
</a>
</li>
@endif
<li refs="page-editor@discard-draft-wrap" {{ $isDraftRevision ? '' : 'hidden' }}>
<button refs="page-editor@discard-draft" type="button" class="text-warn icon-item">
@icon('cancel')
<div>{{ trans('entities.pages_edit_discard_draft') }}</div>
</button>
</li>
<li refs="page-editor@delete-draft-wrap" {{ $isDraftRevision ? '' : 'hidden' }}>
<button refs="page-editor@delete-draft" type="button" class="text-neg icon-item">
@icon('delete')
<div>{{ trans('entities.pages_edit_delete_draft') }}</div>
</button>
</li>
@if(userCan('editor-change'))
<li>
<hr>
</li>
<li>
@if($editor === 'wysiwyg')
<a href="{{ $model->getUrl($isDraft ? '' : '/edit') }}?editor=markdown-clean" refs="page-editor@changeEditor" class="icon-item">
@icon('swap-horizontal')
<div>
{{ trans('entities.pages_edit_switch_to_markdown') }}
<br>
<small>{{ trans('entities.pages_edit_switch_to_markdown_clean') }}</small>
</div>
</a>
<a href="{{ $model->getUrl($isDraft ? '' : '/edit') }}?editor=markdown-stable" refs="page-editor@changeEditor" class="icon-item">
@icon('swap-horizontal')
<div>
{{ trans('entities.pages_edit_switch_to_markdown') }}
<br>
<small>{{ trans('entities.pages_edit_switch_to_markdown_stable') }}</small>
</div>
</a>
@else
<a href="{{ $model->getUrl($isDraft ? '' : '/edit') }}?editor=wysiwyg" refs="page-editor@changeEditor" class="icon-item">
@icon('swap-horizontal')
<div>{{ trans('entities.pages_edit_switch_to_wysiwyg') }}</div>
</a>
@endif
</li>
@endif
</ul>
</div>
</div>
<div class="flex-container-row justify-flex-end gap-x-m items-center">
<div component="dropdown"
option:dropdown:move-menu="true"
class="dropdown-container">
<button refs="dropdown@toggle" type="button" aria-haspopup="true" aria-expanded="false" class="icon-list-item text-link">
<span>@icon('edit')</span>
<span refs="page-editor@changelogDisplay">{{ trans('entities.pages_edit_set_changelog') }}</span>
</button>
<ul refs="dropdown@menu" class="wide dropdown-menu">
<li class="px-l py-m">
<p class="text-muted pb-s">{{ trans('entities.pages_edit_enter_changelog_desc') }}</p>
<input refs="page-editor@changelogInput"
name="summary"
id="summary-input"
type="text"
placeholder="{{ trans('entities.pages_edit_enter_changelog') }}" />
</li>
</ul>
<span>{{-- Prevents button jumping on menu show --}}</span>
</div>
<div class="action-buttons px-m py-xs">
<div component="dropdown"
option:dropdown:move-menu="true"
class="dropdown-container">
<button refs="dropdown@toggle" type="button" aria-haspopup="true" aria-expanded="false" class="text-link text-button">@icon('edit') <span refs="page-editor@changelogDisplay">{{ trans('entities.pages_edit_set_changelog') }}</span></button>
<ul refs="dropdown@menu" class="wide dropdown-menu">
<li class="px-l py-m">
<p class="text-muted pb-s">{{ trans('entities.pages_edit_enter_changelog_desc') }}</p>
<input refs="page-editor@changelogInput"
name="summary"
id="summary-input"
type="text"
placeholder="{{ trans('entities.pages_edit_enter_changelog') }}" />
</li>
</ul>
<span>{{-- Prevents button jumping on menu show --}}</span>
</div>
<button type="submit" id="save-button" class="float-left text-link text-button text-pos-hover hide-under-m">@icon('save')<span>{{ trans('entities.pages_save') }}</span></button>
<div class="inline block">
<button type="submit" id="save-button"
class="icon-list-item hide-under-m text-pos fill-width">
<span>@icon('save')</span>
<span>{{ trans('entities.pages_save') }}</span>
</button>
</div>
</div>
</div>

View File

@ -1,15 +1,17 @@
<div component="editor-toolbox" class="floating-toolbox">
<div class="tabs primary-background-light">
<button type="button" refs="editor-toolbox@toggle" aria-expanded="false" class="toolbox-toggle">@icon('caret-left-circle')</button>
<button type="button" refs="editor-toolbox@tab-button" data-tab="tags" title="{{ trans('entities.page_tags') }}" class="active">@icon('tag')</button>
@if(userCan('attachment-create-all'))
<button type="button" refs="editor-toolbox@tab-button" data-tab="files" title="{{ trans('entities.attachments') }}">@icon('attach')</button>
@endif
<button type="button" refs="editor-toolbox@tab-button" data-tab="templates" title="{{ trans('entities.templates') }}">@icon('template')</button>
@if($comments->enabled())
<button type="button" refs="editor-toolbox@tab-button" data-tab="comments" title="{{ trans('entities.comments') }}">@icon('comment')</button>
@endif
<div class="tabs flex-container-column justify-flex-start">
<div class="tabs-inner flex-container-column justify-center">
<button type="button" refs="editor-toolbox@toggle" title="{{ trans('entities.toggle_sidebar') }}" aria-expanded="false" class="toolbox-toggle">@icon('caret-left-circle')</button>
<button type="button" refs="editor-toolbox@tab-button" data-tab="tags" title="{{ trans('entities.page_tags') }}" class="active">@icon('tag')</button>
@if(userCan('attachment-create-all'))
<button type="button" refs="editor-toolbox@tab-button" data-tab="files" title="{{ trans('entities.attachments') }}">@icon('attach')</button>
@endif
<button type="button" refs="editor-toolbox@tab-button" data-tab="templates" title="{{ trans('entities.templates') }}">@icon('template')</button>
@if($comments->enabled())
<button type="button" refs="editor-toolbox@tab-button" data-tab="comments" title="{{ trans('entities.comments') }}">@icon('comment')</button>
@endif
</div>
</div>
<div refs="editor-toolbox@tab-content" data-tab-content="tags" class="toolbox-tab-content">

View File

@ -1,4 +1,4 @@
<div component="page-editor" class="page-editor flex-fill flex"
<div component="page-editor" class="page-editor page-editor-{{ $editor }} flex-fill flex"
option:page-editor:drafts-enabled="{{ $draftsEnabled ? 'true' : 'false' }}"
@if(config('services.drawio'))
drawio-url="{{ is_string(config('services.drawio')) ? config('services.drawio') : 'https://embed.diagrams.net/?embed=1&proto=json&spin=1&configure=1' }}"
@ -20,26 +20,37 @@
{{--Header Toolbar--}}
@include('pages.parts.editor-toolbar', ['model' => $model, 'editor' => $editor, 'isDraft' => $isDraft, 'draftsEnabled' => $draftsEnabled])
{{--Title input--}}
<div class="title-input page-title clearfix">
<div refs="page-editor@titleContainer" class="input">
@include('form.text', ['name' => 'name', 'model' => $model, 'placeholder' => trans('entities.pages_title')])
<div class="flex flex-fill mx-s mb-s justify-center page-editor-page-area-wrap">
<div class="page-editor-page-area flex-container-column flex flex-fill">
{{--Title input--}}
<div class="title-input page-title clearfix">
<div refs="page-editor@titleContainer" class="input">
@include('form.text', ['name' => 'name', 'model' => $model, 'placeholder' => trans('entities.pages_title')])
</div>
</div>
<div class="flex-fill flex">
{{--Editors--}}
<div class="edit-area flex-fill flex">
{{--WYSIWYG Editor--}}
@if($editor === 'wysiwyg')
@include('pages.parts.wysiwyg-editor', ['model' => $model])
@endif
{{--Markdown Editor--}}
@if($editor === 'markdown')
@include('pages.parts.markdown-editor', ['model' => $model])
@endif
</div>
</div>
</div>
</div>
{{--Editors--}}
<div class="edit-area flex-fill flex">
{{--WYSIWYG Editor--}}
@if($editor === 'wysiwyg')
@include('pages.parts.wysiwyg-editor', ['model' => $model])
@endif
{{--Markdown Editor--}}
@if($editor === 'markdown')
@include('pages.parts.markdown-editor', ['model' => $model])
@endif
<div class="relative flex-fill">
@include('pages.parts.editor-toolbox')
</div>
</div>
{{--Mobile Save Button--}}

View File

@ -7,7 +7,7 @@
<div class="markdown-editor-wrap active flex-container-column">
<div class="editor-toolbar flex-container-row items-stretch justify-space-between">
<div class="editor-toolbar-label text-mono px-m py-xs flex-container-row items-center flex">
<div class="editor-toolbar-label text-mono bold px-m py-xs flex-container-row items-center flex">
<span>{{ trans('entities.pages_md_editor') }}</span>
</div>
<div component="dropdown" class="buttons flex-container-row items-stretch">
@ -44,7 +44,7 @@
<div refs="markdown-editor@divider" class="markdown-panel-divider flex-fill"></div>
<div class="flex-container-column flex flex-fill">
<div class="editor-toolbar">
<div class="editor-toolbar-label text-mono px-m py-xs">{{ trans('entities.pages_md_preview') }}</div>
<div class="editor-toolbar-label text-mono bold px-m py-xs">{{ trans('entities.pages_md_preview') }}</div>
</div>
<iframe src="about:blank"
refs="markdown-editor@display"