// Otherwise show the edit view if they're a guest
$this->setPageTitle(trans('entities.pages_new'));
- return view('pages/guest-create', ['parent' => $parent]);
+ return view('pages.guest-create', ['parent' => $parent]);
}
/**
$this->setPageTitle(trans('entities.pages_edit_draft'));
$draftsEnabled = $this->signedIn;
- return view('pages/edit', [
+ return view('pages.edit', [
'page' => $draft,
'book' => $draft->book,
'isDraft' => true,
Views::add($page);
$this->setPageTitle($page->getShortName());
- return view('pages/show', [
+ return view('pages.show', [
'page' => $page,'book' => $page->book,
'current' => $page,
'sidebarTree' => $sidebarTree,
}
$draftsEnabled = $this->signedIn;
- return view('pages/edit', [
+ return view('pages.edit', [
'page' => $page,
'book' => $page->book,
'current' => $page,
$page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
$this->checkOwnablePermission('page-delete', $page);
$this->setPageTitle(trans('entities.pages_delete_named', ['pageName'=>$page->getShortName()]));
- return view('pages/delete', ['book' => $page->book, 'page' => $page, 'current' => $page]);
+ return view('pages.delete', ['book' => $page->book, 'page' => $page, 'current' => $page]);
}
$page = $this->pageRepo->getById('page', $pageId, true);
$this->checkOwnablePermission('page-update', $page);
$this->setPageTitle(trans('entities.pages_delete_draft_named', ['pageName'=>$page->getShortName()]));
- return view('pages/delete', ['book' => $page->book, 'page' => $page, 'current' => $page]);
+ return view('pages.delete', ['book' => $page->book, 'page' => $page, 'current' => $page]);
}
/**
* @param string $bookSlug
* @param string $pageSlug
* @return \Illuminate\View\View
+ * @throws NotFoundException
*/
public function showRevisions($bookSlug, $pageSlug)
{
$page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
$this->setPageTitle(trans('entities.pages_revisions_named', ['pageName'=>$page->getShortName()]));
- return view('pages/revisions', ['page' => $page, 'book' => $page->book, 'current' => $page]);
+ return view('pages.revisions', ['page' => $page, 'current' => $page]);
}
/**
$page->fill($revision->toArray());
$this->setPageTitle(trans('entities.pages_revision_named', ['pageName' => $page->getShortName()]));
- return view('pages/revision', [
+ return view('pages.revision', [
'page' => $page,
'book' => $page->book,
+ 'diff' => null,
'revision' => $revision
]);
}
$page->fill($revision->toArray());
$this->setPageTitle(trans('entities.pages_revision_named', ['pageName'=>$page->getShortName()]));
- return view('pages/revision', [
+ return view('pages.revision', [
'page' => $page,
'book' => $page->book,
'diff' => $diff,
// Check if its the latest revision, cannot delete latest revision.
if (intval($currentRevision->id) === intval($revId)) {
session()->flash('error', trans('entities.revision_cannot_delete_latest'));
- return response()->view('pages/revisions', ['page' => $page, 'book' => $page->book, 'current' => $page], 400);
+ return response()->view('pages.revisions', ['page' => $page, 'book' => $page->book, 'current' => $page], 400);
}
$revision->delete();
session()->flash('success', trans('entities.revision_delete_success'));
- return view('pages/revisions', ['page' => $page, 'book' => $page->book, 'current' => $page]);
+ return view('pages.revisions', ['page' => $page, 'book' => $page->book, 'current' => $page]);
}
/**
return $this->downloadResponse($pageText, $pageSlug . '.txt');
}
- /**
- * Show a listing of recently created pages
- * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
- */
- public function showRecentlyCreated()
- {
- $pages = $this->pageRepo->getRecentlyCreatedPaginated('page', 20)->setPath(baseUrl('/pages/recently-created'));
- return view('pages/detailed-listing', [
- 'title' => trans('entities.recently_created_pages'),
- 'pages' => $pages
- ]);
- }
-
/**
* Show a listing of recently created pages
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function showRecentlyUpdated()
{
+ // TODO - Still exist?
$pages = $this->pageRepo->getRecentlyUpdatedPaginated('page', 20)->setPath(baseUrl('/pages/recently-updated'));
- return view('pages/detailed-listing', [
+ return view('pages.detailed-listing', [
'title' => trans('entities.recently_updated_pages'),
'pages' => $pages
]);
}
- /**
- * Show the Restrictions view.
- * @param string $bookSlug
- * @param string $pageSlug
- * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
- */
- public function showRestrict($bookSlug, $pageSlug)
- {
- $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
- $this->checkOwnablePermission('restrictions-manage', $page);
- $roles = $this->userRepo->getRestrictableRoles();
- return view('pages/restrictions', [
- 'page' => $page,
- 'roles' => $roles
- ]);
- }
-
/**
* Show the view to choose a new parent to move a page into.
* @param string $bookSlug
$page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
$this->checkOwnablePermission('page-update', $page);
$this->checkOwnablePermission('page-delete', $page);
- return view('pages/move', [
+ return view('pages.move', [
'book' => $page->book,
'page' => $page
]);
public function showCopy($bookSlug, $pageSlug)
{
$page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
- $this->checkOwnablePermission('page-update', $page);
+ $this->checkOwnablePermission('page-view', $page);
session()->flashInput(['name' => $page->name]);
- return view('pages/copy', [
+ return view('pages.copy', [
'book' => $page->book,
'page' => $page
]);
public function copy($bookSlug, $pageSlug, Request $request)
{
$page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
- $this->checkOwnablePermission('page-update', $page);
+ $this->checkOwnablePermission('page-view', $page);
$entitySelection = $request->get('entity_selection', null);
if ($entitySelection === null || $entitySelection === '') {
return redirect($pageCopy->getUrl());
}
+ /**
+ * Show the Permissions view.
+ * @param string $bookSlug
+ * @param string $pageSlug
+ * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
+ * @throws NotFoundException
+ */
+ public function showPermissions($bookSlug, $pageSlug)
+ {
+ $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
+ $this->checkOwnablePermission('restrictions-manage', $page);
+ $roles = $this->userRepo->getRestrictableRoles();
+ return view('pages.permissions', [
+ 'page' => $page,
+ 'roles' => $roles
+ ]);
+ }
+
/**
* Set the permissions for this page.
* @param string $bookSlug
* @param Request $request
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
* @throws NotFoundException
+ * @throws \Throwable
*/
- public function restrict($bookSlug, $pageSlug, Request $request)
+ public function permissions($bookSlug, $pageSlug, Request $request)
{
$page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
$this->checkOwnablePermission('restrictions-manage', $page);
if ($default === false) {
$default = config('setting-defaults.' . $key, false);
}
+
if (isset($this->localCache[$key])) {
return $this->localCache[$key];
}
*/
public function getUser($user, $key, $default = false)
{
+ if ($user->isDefault()) {
+ return session()->get($key, $default);
+ }
return $this->get($this->userKey($user->id, $key), $default);
}
*/
public function putUser($user, $key, $value)
{
+ if ($user->isDefault()) {
+ return session()->put($key, $value);
+ }
return $this->put($this->userKey($user->id, $key), $value);
}
<?php
+ use BookStack\Auth\Permissions\PermissionService;
+ use BookStack\Entities\Entity;
use BookStack\Ownable;
/**
* Check if current user is a signed in user.
* @return bool
*/
-function signedInUser()
+function signedInUser() : bool
{
return auth()->user() && !auth()->user()->isDefault();
}
+/**
+ * Check if the current user has general access.
+ * @return bool
+ */
+function hasAppAccess() : bool {
+ return !auth()->guest() || setting('app-public');
+}
+
/**
* Check if the current user has a permission.
* If an ownable element is passed in the jointPermissions are checked against
* that particular item.
- * @param $permission
+ * @param string $permission
* @param Ownable $ownable
* @return mixed
*/
- function userCan($permission, Ownable $ownable = null)
+ function userCan(string $permission, Ownable $ownable = null)
{
if ($ownable === null) {
return user() && user()->can($permission);
}
// Check permission on ownable item
- $permissionService = app(\BookStack\Auth\Permissions\PermissionService::class);
+ $permissionService = app(PermissionService::class);
return $permissionService->checkOwnableUserAccess($ownable, $permission);
}
+ /**
+ * Check if the current user has the given permission
+ * on any item in the system.
+ * @param string $permission
+ * @param string|null $entityClass
+ * @return bool
+ */
+ function userCanOnAny(string $permission, string $entityClass = null)
+ {
+ $permissionService = app(PermissionService::class);
+ return $permissionService->checkUserHasPermissionOnAnything($permission, $entityClass);
+ }
+
/**
* Helper to access system settings.
* @param $key
/**
* Handle pasting images from clipboard.
* @param {ClipboardEvent} event
+ * @param {WysiwygEditor} wysiwygComponent
* @param editor
*/
- function editorPaste(event, editor) {
+ function editorPaste(event, editor, wysiwygComponent) {
if (!event.clipboardData || !event.clipboardData.items) return;
- let items = event.clipboardData.items;
- for (let i = 0; i < items.length; i++) {
- if (items[i].type.indexOf("image") === -1) continue;
+ for (let clipboardItem of event.clipboardData.items) {
+ if (clipboardItem.type.indexOf("image") === -1) continue;
event.preventDefault();
- let id = "image-" + Math.random().toString(16).slice(2);
- let loadingImage = window.baseUrl('/loading.gif');
- let file = items[i].getAsFile();
+ const id = "image-" + Math.random().toString(16).slice(2);
+ const loadingImage = window.baseUrl('/loading.gif');
+ const file = clipboardItem.getAsFile();
+
setTimeout(() => {
editor.insertContent(`<p><img src="${loadingImage}" id="${id}"></p>`);
- uploadImageFile(file).then(resp => {
+
+ uploadImageFile(file, wysiwygComponent).then(resp => {
editor.dom.setAttrib(id, 'src', resp.thumbs.display);
}).catch(err => {
editor.dom.remove(id);
/**
* Upload an image file to the server
* @param {File} file
+ * @param {WysiwygEditor} wysiwygComponent
*/
- function uploadImageFile(file) {
- if (file === null || file.type.indexOf('image') !== 0) return Promise.reject(`Not an image file`);
+ async function uploadImageFile(file, wysiwygComponent) {
+ if (file === null || file.type.indexOf('image') !== 0) {
+ throw new Error(`Not an image file`);
+ }
let ext = 'png';
if (file.name) {
if (fileNameMatches.length > 1) ext = fileNameMatches[1];
}
- let remoteFilename = "image-" + Date.now() + "." + ext;
- let formData = new FormData();
+ const remoteFilename = "image-" + Date.now() + "." + ext;
+ const formData = new FormData();
formData.append('file', file, remoteFilename);
+ formData.append('uploaded_to', wysiwygComponent.pageId);
- return window.$http.post(window.baseUrl('/images/gallery/upload'), formData).then(resp => (resp.data));
+ const resp = await window.$http.post(window.baseUrl('/images/gallery/upload'), formData);
+ return resp.data;
}
function registerEditorShortcuts(editor) {
constructor(elem) {
this.elem = elem;
- this.textDirection = document.getElementById('page-editor').getAttribute('text-direction');
+
+ const pageEditor = document.getElementById('page-editor');
+ this.pageId = pageEditor.getAttribute('page-id');
+ this.textDirection = pageEditor.getAttribute('text-direction');
this.plugins = "image table textcolor paste link autolink fullscreen imagetools code customhr autosave lists codeeditor media";
this.loadPlugins();
}
getTinyMceConfig() {
+
+ const context = this;
+
return {
selector: '#html-editor',
content_css: [
plugins: this.plugins,
imagetools_toolbar: 'imageoptions',
toolbar: this.getToolBar(),
- content_style: "body {padding-left: 15px !important; padding-right: 15px !important; margin:0!important; margin-left:auto!important;margin-right:auto!important;}",
+ content_style: "html, body {background: #FFF;} body {padding-left: 15px !important; padding-right: 15px !important; margin:0!important; margin-left:auto!important;margin-right:auto!important;}",
style_formats: [
{title: "Header Large", format: "h2"},
{title: "Header Medium", format: "h3"},
});
// Paste image-uploads
- editor.on('paste', event => editorPaste(event, editor));
+ editor.on('paste', event => editorPaste(event, editor, context));
}
};
}
flex-direction: column;
align-items: stretch;
overflow: hidden;
+ background-color: #FFF;
.faded-small {
height: auto;
}
width: 100%;
max-width: 840px;
margin: 0 auto;
- margin-top: $-xxl;
overflow-wrap: break-word;
- &.flex {
- margin-top: $-m;
- }
.align-left {
text-align: left;
}
margin: $-xs $-s $-xs 0;
}
.align-right {
- float: right !important;
+ text-align: right !important;
}
img.align-right, table.align-right {
- text-align: right;
+ float: right !important;
margin: $-xs 0 $-xs $-s;
}
.align-center {
text-align: center;
}
+ img.align-center {
+ display: block;
+ }
+ img.align-center, table.align-center {
+ margin-left: auto;
+ margin-right: auto;
+ }
img {
max-width: 100%;
height:auto;
}
}
-.comments-container {
- width: 100%;
- border-top: 1px solid #DDD;
- margin-top: $-xl;
- margin-bottom: $-m;
- h5 {
- color: #888;
- font-weight: normal;
- margin-top: 0.5em;
- }
+.comments-container h5 {
+ color: #888;
+ font-weight: normal;
+ margin-top: 0.5em;
}
.comment-editor .CodeMirror, .comment-editor .CodeMirror-scroll {
.mce-open {
display: none;
}
+}
+
+.entity-list-item > span:first-child, .icon-list-item > span:first-child {
+ font-size: 0.8rem;
+ width: 1.88em;
+ height: 1.88em;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ text-align: center;
+ border-radius: 1em;
+ position: relative;
+ overflow: hidden;
+ svg {
+ margin: 0;
+ bottom: 0;
+ }
+ &:after {
+ content: '';
+ position: absolute;
+ background-color: currentColor;
+ opacity: 0.2;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ }
+}
+
+.entity-chip {
+ display: inline-block;
+ align-items: center;
+ justify-content: center;
+ text-align: center;
+ font-size: 0.9em;
+ border-radius: 3px;
+ position: relative;
+ overflow: hidden;
+ padding: $-xs $-s;
+ fill: currentColor;
+ opacity: 0.85;
+ transition: opacity ease-in-out 120ms;
+ &:after {
+ content: '';
+ position: absolute;
+ background-color: currentColor;
+ opacity: 0.15;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ }
+ &:hover {
+ text-decoration: none;
+ opacity: 1;
+ }
}
--- /dev/null
- @if(userCan('bookshelf-view-all') || userCan('bookshelf-view-own'))
+<header id="header" header-mobile-toggle>
+ <div class="grid break-l mx-l">
+
+ <div>
+ <a href="{{ baseUrl('/') }}" class="logo">
+ @if(setting('app-logo', '') !== 'none')
+ <img class="logo-image" src="{{ setting('app-logo', '') === '' ? baseUrl('/logo.png') : baseUrl(setting('app-logo', '')) }}" alt="Logo">
+ @endif
+ @if (setting('app-name-header'))
+ <span class="logo-text">{{ setting('app-name') }}</span>
+ @endif
+ </a>
+ <div class="mobile-menu-toggle hide-over-l">@icon('more')</div>
+ </div>
+
+ <div class="header-search hide-under-l">
+ @if (hasAppAccess())
+ <form action="{{ baseUrl('/search') }}" method="GET" class="search-box">
+ <button id="header-search-box-button" type="submit">@icon('search') </button>
+ <input id="header-search-box-input" type="text" name="term" tabindex="2" placeholder="{{ trans('common.search') }}" value="{{ isset($searchTerm) ? $searchTerm : '' }}">
+ </form>
+ @endif
+ </div>
+
+ <div class="text-right">
+ <div class="header-links">
+ <div class="links text-center">
+ @if (hasAppAccess())
+ <a class="hide-over-l" href="{{ baseUrl('/search') }}">@icon('search'){{ trans('common.search') }}</a>
++ @if(userCanOnAny('view', \BookStack\Entities\Bookshelf::class) || userCan('bookshelf-view-all') || userCan('bookshelf-view-own'))
+ <a href="{{ baseUrl('/shelves') }}">@icon('bookshelf'){{ trans('entities.shelves') }}</a>
+ @endif
+ <a href="{{ baseUrl('/books') }}">@icon('books'){{ trans('entities.books') }}</a>
+ @if(signedInUser() && userCan('settings-manage'))
+ <a href="{{ baseUrl('/settings') }}">@icon('settings'){{ trans('settings.settings') }}</a>
+ @endif
+ @if(signedInUser() && userCan('users-manage') && !userCan('settings-manage'))
+ <a href="{{ baseUrl('/settings/users') }}">@icon('users'){{ trans('settings.users') }}</a>
+ @endif
+ @endif
+
+ @if(!signedInUser())
+ @if(setting('registration-enabled', false))
+ <a href="{{ baseUrl("/register") }}">@icon('new-user') {{ trans('auth.sign_up') }}</a>
+ @endif
+ <a href="{{ baseUrl('/login') }}">@icon('login') {{ trans('auth.log_in') }}</a>
+ @endif
+ </div>
+ @if(signedInUser())
+ <?php $currentUser = user(); ?>
+ <div class="dropdown-container" dropdown>
+ <span class="user-name hide-under-l" dropdown-toggle>
+ <img class="avatar" src="{{$currentUser->getAvatar(30)}}" alt="{{ $currentUser->name }}">
+ <span class="name">{{ $currentUser->getShortName(9) }}</span> @icon('caret-down')
+ </span>
+ <ul>
+ <li>
+ <a href="{{ baseUrl("/user/{$currentUser->id}") }}" class="text-primary">@icon('user'){{ trans('common.view_profile') }}</a>
+ </li>
+ <li>
+ <a href="{{ baseUrl("/settings/users/{$currentUser->id}") }}" class="text-primary">@icon('edit'){{ trans('common.edit_profile') }}</a>
+ </li>
+ <li>
+ <a href="{{ baseUrl('/logout') }}" class="text-neg">@icon('logout'){{ trans('auth.logout') }}</a>
+ </li>
+ </ul>
+ </div>
+ @endif
+ </div>
+ </div>
+
+ </div>
+</header>
-@extends('sidebar-layout')
+@extends('tri-layout')
-@section('toolbar')
- <div class="col-sm-8 col-xs-5 faded">
- @include('pages._breadcrumbs', ['page' => $page])
+@section('body')
+
+ <div class="mb-m">
+ @include('partials.breadcrumbs', ['crumbs' => [
+ $page->book,
+ $page->hasChapter() ? $page->chapter : null,
+ $page,
+ ]])
</div>
- <div class="col-sm-4 col-xs-7 faded">
- <div class="action-buttons">
- <span dropdown class="dropdown-container">
- <div dropdown-toggle class="text-button text-primary">@icon('export'){{ trans('entities.export') }}</div>
- <ul class="wide">
- <li><a href="{{ $page->getUrl('/export/html') }}" target="_blank">{{ trans('entities.export_html') }} <span class="text-muted float right">.html</span></a></li>
- <li><a href="{{ $page->getUrl('/export/pdf') }}" target="_blank">{{ trans('entities.export_pdf') }} <span class="text-muted float right">.pdf</span></a></li>
- <li><a href="{{ $page->getUrl('/export/plaintext') }}" target="_blank">{{ trans('entities.export_text') }} <span class="text-muted float right">.txt</span></a></li>
- </ul>
- </span>
- @if(userCan('page-update', $page))
- <a href="{{ $page->getUrl('/edit') }}" class="text-primary text-button" >@icon('edit'){{ trans('common.edit') }}</a>
- @endif
- @if((userCan('page-view', $page) && userCanOnAny('page-create')) || userCan('page-update', $page) || userCan('restrictions-manage', $page) || userCan('page-delete', $page))
- <div dropdown class="dropdown-container">
- <a dropdown-toggle class="text-primary text-button">@icon('more') {{ trans('common.more') }}</a>
- <ul>
- @if(userCanOnAny('page-create'))
- <li><a href="{{ $page->getUrl('/copy') }}" class="text-primary" >@icon('copy'){{ trans('common.copy') }}</a></li>
- @endif
- @if(userCan('page-delete', $page) && userCan('page-update', $page))
- <li><a href="{{ $page->getUrl('/move') }}" class="text-primary" >@icon('folder'){{ trans('common.move') }}</a></li>
- @endif
- @if(userCan('page-update', $page))
- <li><a href="{{ $page->getUrl('/revisions') }}" class="text-primary">@icon('history'){{ trans('entities.revisions') }}</a></li>
- @endif
- @if(userCan('restrictions-manage', $page))
- <li><a href="{{ $page->getUrl('/permissions') }}" class="text-primary">@icon('lock'){{ trans('entities.permissions') }}</a></li>
- @endif
- @if(userCan('page-delete', $page))
- <li><a href="{{ $page->getUrl('/delete') }}" class="text-neg">@icon('delete'){{ trans('common.delete') }}</a></li>
- @endif
- </ul>
+
+ <div class="content-wrap card">
+ <div class="page-content flex" page-display="{{ $page->id }}">
+
+ <div class="pointer-container" id="pointer">
+ <div class="pointer anim {{ userCan('page-update', $page) ? 'is-page-editable' : ''}}" >
+ <span class="icon text-primary">@icon('link') @icon('include', ['style' => 'display:none;'])</span>
+ <span class="input-group">
+ <input readonly="readonly" type="text" id="pointer-url" placeholder="url">
+ <button class="button icon" data-clipboard-target="#pointer-url" type="button" title="{{ trans('entities.pages_copy_link') }}">@icon('copy')</button>
+ </span>
+ @if(userCan('page-update', $page))
+ <a href="{{ $page->getUrl('/edit') }}" id="pointer-edit" data-edit-href="{{ $page->getUrl('/edit') }}"
+ class="button icon heading-edit-icon" title="{{ trans('entities.pages_edit_content_link')}}">@icon('edit')</a>
+ @endif
</div>
- @endif
+ </div>
+ @include('pages.page-display')
</div>
</div>
+
+ @if ($commentsEnabled)
+ <div class="container small nopad comments-container mb-l">
+ @include('comments.comments', ['page' => $page])
+ <div class="clearfix"></div>
+ </div>
+ @endif
@stop
-@section('sidebar')
+@section('left')
@if($page->tags->count() > 0)
<section>
@endif
@if ($page->attachments->count() > 0)
- <div class="card">
- <h3>@icon('attach') {{ trans('entities.pages_attachments') }}</h3>
+ <div id="page-attachments" class="mb-xl">
+ <h5>{{ trans('entities.pages_attachments') }}</h5>
<div class="body">
@foreach($page->attachments as $attachment)
<div class="attachment">
@endif
@if (isset($pageNav) && count($pageNav))
- <div class="card">
- <h3>@icon('open-book') {{ trans('entities.pages_navigation') }}</h3>
+ <div id="page-navigation" class="mb-xl">
+ <h5>{{ trans('entities.pages_navigation') }}</h5>
<div class="body">
<div class="sidebar-page-nav menu">
@foreach($pageNav as $navItem)
<li class="page-nav-item h{{ $navItem['level'] }}">
<a href="{{ $navItem['link'] }}">{{ $navItem['text'] }}</a>
+ <div class="primary-background sidebar-page-nav-bullet"></div>
</li>
@endforeach
</div>
</div>
@endif
- <div class="card entity-details">
- <h3>@icon('info') {{ trans('common.details') }}</h3>
+ <div id="page-details" class="entity-details mb-xl">
+ <h5>{{ trans('common.details') }}</h5>
<div class="body text-muted text-small blended-links">
@include('partials.entity-meta', ['entity' => $page])
</div>
</div>
- @include('partials/book-tree', ['book' => $book, 'sidebarTree' => $sidebarTree])
-
+ @include('partials.book-tree', ['book' => $book, 'sidebarTree' => $sidebarTree])
@stop
-@section('body-wrap-classes', 'flex-fill columns')
+@section('right')
+ <div class="actions mb-xl">
+ <h5>Actions</h5>
-@section('body')
-
- <div class="page-content flex" page-display="{{ $page->id }}">
+ <div class="icon-list text-primary">
+ {{--Export--}}
+ <div dropdown class="dropdown-container block">
+ <div dropdown-toggle class="icon-list-item">
+ <span>@icon('export')</span>
+ <span>{{ trans('entities.export') }}</span>
+ </div>
+ <ul class="wide">
+ <li><a href="{{ $page->getUrl('/export/html') }}" target="_blank">{{ trans('entities.export_html') }} <span class="text-muted float right">.html</span></a></li>
+ <li><a href="{{ $page->getUrl('/export/pdf') }}" target="_blank">{{ trans('entities.export_pdf') }} <span class="text-muted float right">.pdf</span></a></li>
+ <li><a href="{{ $page->getUrl('/export/plaintext') }}" target="_blank">{{ trans('entities.export_text') }} <span class="text-muted float right">.txt</span></a></li>
+ </ul>
+ </div>
- <div class="pointer-container" id="pointer">
- <div class="pointer anim {{ userCan('page-update', $page) ? 'is-page-editable' : ''}}" >
- <span class="icon text-primary">@icon('link') @icon('include', ['style' => 'display:none;'])</span>
- <span class="input-group">
- <input readonly="readonly" type="text" id="pointer-url" placeholder="url">
- <button class="button icon" data-clipboard-target="#pointer-url" type="button" title="{{ trans('entities.pages_copy_link') }}">@icon('copy')</button>
- </span>
- @if(userCan('page-update', $page))
- <a href="{{ $page->getUrl('/edit') }}" id="pointer-edit" data-edit-href="{{ $page->getUrl('/edit') }}"
- class="button icon heading-edit-icon" title="{{ trans('entities.pages_edit_content_link')}}">@icon('edit')</a>
+ {{--User Actions--}}
+ @if(userCan('page-update', $page))
+ <a href="{{ $page->getUrl('/edit') }}" class="icon-list-item">
+ <span>@icon('edit')</span>
+ <span>{{ trans('common.edit') }}</span>
+ </a>
++ @endif
++ @if(userCanOnAny('page-create'))
+ <a href="{{ $page->getUrl('/copy') }}" class="icon-list-item">
+ <span>@icon('copy')</span>
+ <span>{{ trans('common.copy') }}</span>
+ </a>
++ @endif
++ @if(userCan('page-update', $page))
+ @if(userCan('page-delete', $page))
+ <a href="{{ $page->getUrl('/move') }}" class="icon-list-item">
+ <span>@icon('folder')</span>
+ <span>{{ trans('common.move') }}</span>
+ </a>
@endif
- </div>
+ <a href="{{ $page->getUrl('/revisions') }}" class="icon-list-item">
+ <span>@icon('history')</span>
+ <span>{{ trans('entities.revisions') }}</span>
+ </a>
+ @endif
+ @if(userCan('restrictions-manage', $page))
+ <a href="{{ $page->getUrl('/permissions') }}" class="icon-list-item">
+ <span>@icon('lock')</span>
+ <span>{{ trans('entities.permissions') }}</span>
+ </a>
+ @endif
+ @if(userCan('page-delete', $page))
+ <a href="{{ $page->getUrl('/delete') }}" class="icon-list-item">
+ <span>@icon('delete')</span>
+ <span>{{ trans('common.delete') }}</span>
+ </a>
+ @endif
</div>
- @include('pages/page-display')
</div>
-
- @if ($commentsEnabled)
- <div class="container small nopad comments-container">
- @include('comments/comments', ['page' => $page])
- </div>
- @endif
@stop
@extends('simple-layout')
-@section('toolbar')
- @include('settings/navbar', ['selected' => 'users'])
-@stop
-
@section('body')
-
<div class="container small">
- <p> </p>
- <div class="card">
- <h3>@icon('edit') {{ $user->id === $currentUser->id ? trans('settings.users_edit_profile') : trans('settings.users_edit') }}</h3>
- <div class="body">
- <form action="{{ baseUrl("/settings/users/{$user->id}") }}" method="post">
- <div class="row">
- <div class="col-sm-6">
- {!! csrf_field() !!}
- <input type="hidden" name="_method" value="put">
- @include('users.forms.' . $authMethod, ['model' => $user])
- </div>
- <div class="col-sm-6">
- <div class="form-group" id="logo-control">
- <label for="user-avatar">{{ trans('settings.users_avatar') }}</label>
- <p class="small">{{ trans('settings.users_avatar_desc') }}</p>
+ <div class="py-m">
+ @include('settings.navbar', ['selected' => 'users'])
+ </div>
- @include('components.image-picker', [
- 'resizeHeight' => '512',
- 'resizeWidth' => '512',
- 'showRemove' => false,
- 'defaultImage' => baseUrl('/user_avatar.png'),
- 'currentImage' => $user->getAvatar(80),
- 'currentId' => $user->image_id,
- 'name' => 'image_id',
- 'imageClass' => 'avatar large'
- ])
- </div>
- <div class="form-group">
- <label for="user-language">{{ trans('settings.users_preferred_language') }}</label>
- <select name="setting[language]" id="user-language">
+ <div class="card content-wrap">
+ <h1 class="list-heading">{{ $user->id === $currentUser->id ? trans('settings.users_edit_profile') : trans('settings.users_edit') }}</h1>
+ <form action="{{ baseUrl("/settings/users/{$user->id}") }}" method="post">
+ {!! csrf_field() !!}
+ <input type="hidden" name="_method" value="PUT">
- @foreach(trans('settings.language_select') as $lang => $label)
- <option @if(setting()->getUser($user, 'language', config('app.default_locale')) === $lang) selected @endif value="{{ $lang }}">{{ $label }}</option>
- @endforeach
- </select>
- </div>
+ <div class="setting-list">
+ @include('users.form', ['model' => $user, 'authMethod' => $authMethod])
+
+ <div class="grid half large-gap">
+ <div>
+ <label for="user-avatar" class="setting-list-label">{{ trans('settings.users_avatar') }}</label>
+ <p class="small">{{ trans('settings.users_avatar_desc') }}</p>
+ </div>
+ <div>
+ @include('components.image-picker', [
+ 'resizeHeight' => '512',
+ 'resizeWidth' => '512',
+ 'showRemove' => false,
+ 'defaultImage' => baseUrl('/user_avatar.png'),
+ 'currentImage' => $user->getAvatar(80),
+ 'currentId' => $user->image_id,
+ 'name' => 'image_id',
+ 'imageClass' => 'avatar large'
+ ])
</div>
</div>
- <div class="form-group text-right">
- <a href="{{ baseUrl($currentUser->can('users-manage') ? "/settings/users" : "/") }}" class="button outline">{{ trans('common.cancel') }}</a>
- @if($authMethod !== 'system')
- <a href="{{ baseUrl("/settings/users/{$user->id}/delete") }}" class="neg button">{{ trans('settings.users_delete') }}</a>
- @endif
- <button class="button pos" type="submit">{{ trans('common.save') }}</button>
+
+ <div class="grid half large-gap v-center">
+ <div>
+ <label for="user-language" class="setting-list-label">{{ trans('settings.users_preferred_language') }}</label>
+ <p class="small">
+ {{ trans('settings.users_preferred_language_desc') }}
+ </p>
+ </div>
+ <div>
+ <select name="setting[language]" id="user-language">
+ @foreach(trans('settings.language_select') as $lang => $label)
- <option @if(setting()->getUser($user, 'language') === $lang) selected @endif value="{{ $lang }}">{{ $label }}</option>
++ <option @if(setting()->getUser($user, 'language', config('app.default_locale')) === $lang) selected @endif value="{{ $lang }}">{{ $label }}</option>
+ @endforeach
+ </select>
+ </div>
</div>
- </form>
- </div>
+
+ </div>
+
+ <div class="text-right">
+ <a href="{{ baseUrl($currentUser->can('users-manage') ? "/settings/users" : "/") }}" class="button outline">{{ trans('common.cancel') }}</a>
+ @if($authMethod !== 'system')
+ <a href="{{ baseUrl("/settings/users/{$user->id}/delete") }}" class="button outline">{{ trans('settings.users_delete') }}</a>
+ @endif
+ <button class="button primary" type="submit">{{ trans('common.save') }}</button>
+ </div>
+ </form>
</div>
@if($currentUser->id === $user->id && count($activeSocialDrivers) > 0)
- <div class="card">
- <h3>@icon('login') {{ trans('settings.users_social_accounts') }}</h3>
- <div class="body">
- <p class="text-muted">{{ trans('settings.users_social_accounts_info') }}</p>
- <div class="container">
- <div class="row">
- @foreach($activeSocialDrivers as $driver => $enabled)
- <div class="col-sm-4 col-xs-6 text-center">
- <div>@icon('auth/'. $driver, ['style' => 'width: 56px;height: 56px;'])</div>
- <div>
- @if($user->hasSocialAccount($driver))
- <a href="{{ baseUrl("/login/service/{$driver}/detach") }}" class="button neg">{{ trans('settings.users_social_disconnect') }}</a>
- @else
- <a href="{{ baseUrl("/login/service/{$driver}") }}" class="button pos">{{ trans('settings.users_social_connect') }}</a>
- @endif
- </div>
- <div> </div>
+ <div class="card content-wrap auto-height">
+ <h2 class="list-heading">{{ trans('settings.users_social_accounts') }}</h2>
+ <p class="text-muted">{{ trans('settings.users_social_accounts_info') }}</p>
+ <div class="container">
+ <div class="grid third">
+ @foreach($activeSocialDrivers as $driver => $enabled)
+ <div class="text-center mb-m">
+ <div>@icon('auth/'. $driver, ['style' => 'width: 56px;height: 56px;'])</div>
+ <div>
+ @if($user->hasSocialAccount($driver))
+ <a href="{{ baseUrl("/login/service/{$driver}/detach") }}" class="button small outline">{{ trans('settings.users_social_disconnect') }}</a>
+ @else
+ <a href="{{ baseUrl("/login/service/{$driver}") }}" class="button small outline">{{ trans('settings.users_social_connect') }}</a>
+ @endif
</div>
- @endforeach
- </div>
+ </div>
+ @endforeach
</div>
</div>
</div>
@endif
-
-
</div>
- <p class="margin-top large"><br></p>
@include('components.image-manager', ['imageType' => 'user'])
--@stop
++@stop