Merge branch 'master' of git://github.com/BookStackApp/BookStack into BookStackApp-master

Conflicts:
	app/Http/Controllers/BookController.php
	resources/lang/en/common.php
	resources/views/books/create.blade.php
	resources/views/books/form.blade.php
	resources/views/books/index.blade.php
	resources/views/users/edit.blade.php
	tests/Entity/EntityTest.php
This commit is contained in:
Bharadwaja G 2017-08-29 12:19:00 +05:30
commit 6200948eec
99 changed files with 2562 additions and 1986 deletions

View File

@ -231,7 +231,6 @@ class RegisterController extends Controller
return redirect('/register/confirm'); return redirect('/register/confirm');
} }
$this->emailConfirmationService->sendConfirmation($user);
session()->flash('success', trans('auth.email_confirm_resent')); session()->flash('success', trans('auth.email_confirm_resent'));
return redirect('/register/confirm'); return redirect('/register/confirm');
} }

View File

@ -36,12 +36,17 @@ class BookController extends Controller
*/ */
public function index() public function index()
{ {
$books = $this->entityRepo->getAllPaginated('book', 16); $books = $this->entityRepo->getAllPaginated('book', 20);
$recents = $this->signedIn ? $this->entityRepo->getRecentlyViewed('book', 4, 0) : false; $recents = $this->signedIn ? $this->entityRepo->getRecentlyViewed('book', 4, 0) : false;
$popular = $this->entityRepo->getPopular('book', 3, 0); $popular = $this->entityRepo->getPopular('book', 4, 0);
$books_display = $this->currentUser->books_display; $new = $this->entityRepo->getRecentlyCreated('book', 4, 0);
$this->setPageTitle('Books'); $this->setPageTitle('Books');
return view('books/index', ['books' => $books, 'recents' => $recents, 'popular' => $popular, 'books_display' => $books_display] ); return view('books/index', [
'books' => $books,
'recents' => $recents,
'popular' => $popular,
'new' => $new
]);
} }
/** /**
@ -85,7 +90,12 @@ class BookController extends Controller
$bookChildren = $this->entityRepo->getBookChildren($book); $bookChildren = $this->entityRepo->getBookChildren($book);
Views::add($book); Views::add($book);
$this->setPageTitle($book->getShortName()); $this->setPageTitle($book->getShortName());
return view('books/show', ['book' => $book, 'current' => $book, 'bookChildren' => $bookChildren]); return view('books/show', [
'book' => $book,
'current' => $book,
'bookChildren' => $bookChildren,
'activity' => Activity::entityActivity($book, 20, 0)
]);
} }
/** /**

View File

@ -29,15 +29,25 @@ class HomeController extends Controller
$activity = Activity::latest(10); $activity = Activity::latest(10);
$draftPages = $this->signedIn ? $this->entityRepo->getUserDraftPages(6) : []; $draftPages = $this->signedIn ? $this->entityRepo->getUserDraftPages(6) : [];
$recentFactor = count($draftPages) > 0 ? 0.5 : 1; $recentFactor = count($draftPages) > 0 ? 0.5 : 1;
$recents = $this->signedIn ? Views::getUserRecentlyViewed(12*$recentFactor, 0) : $this->entityRepo->getRecentlyCreated('book', 10*$recentFactor); $recents = $this->signedIn ? Views::getUserRecentlyViewed(12*$recentFactor, 0) : $this->entityRepo->getRecentlyCreated('book', 12*$recentFactor);
$recentlyCreatedPages = $this->entityRepo->getRecentlyCreated('page', 5); $recentlyUpdatedPages = $this->entityRepo->getRecentlyUpdated('page', 12);
$recentlyUpdatedPages = $this->entityRepo->getRecentlyUpdated('page', 5);
return view('home', [ // Custom homepage
$customHomepage = false;
$homepageSetting = setting('app-homepage');
if ($homepageSetting) {
$id = intval(explode(':', $homepageSetting)[0]);
$customHomepage = $this->entityRepo->getById('page', $id, false, true);
$this->entityRepo->renderPage($customHomepage, true);
}
$view = $customHomepage ? 'home-custom' : 'home';
return view($view, [
'activity' => $activity, 'activity' => $activity,
'recents' => $recents, 'recents' => $recents,
'recentlyCreatedPages' => $recentlyCreatedPages,
'recentlyUpdatedPages' => $recentlyUpdatedPages, 'recentlyUpdatedPages' => $recentlyUpdatedPages,
'draftPages' => $draftPages 'draftPages' => $draftPages,
'customHomepage' => $customHomepage
]); ]);
} }

View File

@ -167,7 +167,7 @@ class PageController extends Controller
return view('pages/show', [ return view('pages/show', [
'page' => $page,'book' => $page->book, 'page' => $page,'book' => $page->book,
'current' => $page, 'sidebarTree' => $sidebarTree, 'current' => $page, 'sidebarTree' => $sidebarTree,
'pageNav' => $pageNav, 'pageContent' => $pageContent]); 'pageNav' => $pageNav]);
} }
/** /**
@ -380,6 +380,7 @@ class PageController extends Controller
return view('pages/revision', [ return view('pages/revision', [
'page' => $page, 'page' => $page,
'book' => $page->book, 'book' => $page->book,
'revision' => $revision
]); ]);
} }
@ -409,6 +410,7 @@ class PageController extends Controller
'page' => $page, 'page' => $page,
'book' => $page->book, 'book' => $page->book,
'diff' => $diff, 'diff' => $diff,
'revision' => $revision
]); ]);
} }

View File

@ -47,4 +47,16 @@ class PageRevision extends Model
return null; return null;
} }
/**
* Allows checking of the exact class, Used to check entity type.
* Included here to align with entities in similar use cases.
* (Yup, Bit of an awkward hack)
* @param $type
* @return bool
*/
public static function isA($type)
{
return $type === 'revision';
}
} }

View File

@ -137,10 +137,15 @@ class EntityRepo
* @param string $type * @param string $type
* @param integer $id * @param integer $id
* @param bool $allowDrafts * @param bool $allowDrafts
* @param bool $ignorePermissions
* @return Entity * @return Entity
*/ */
public function getById($type, $id, $allowDrafts = false) public function getById($type, $id, $allowDrafts = false, $ignorePermissions = false)
{ {
if ($ignorePermissions) {
$entity = $this->getEntity($type);
return $entity->newQuery()->find($id);
}
return $this->entityQuery($type, $allowDrafts)->find($id); return $this->entityQuery($type, $allowDrafts)->find($id);
} }
@ -671,9 +676,10 @@ class EntityRepo
/** /**
* Render the page for viewing, Parsing and performing features such as page transclusion. * Render the page for viewing, Parsing and performing features such as page transclusion.
* @param Page $page * @param Page $page
* @param bool $ignorePermissions
* @return mixed|string * @return mixed|string
*/ */
public function renderPage(Page $page) public function renderPage(Page $page, $ignorePermissions = false)
{ {
$content = $page->html; $content = $page->html;
$matches = []; $matches = [];
@ -685,7 +691,7 @@ class EntityRepo
$pageId = intval($splitInclude[0]); $pageId = intval($splitInclude[0]);
if (is_nan($pageId)) continue; if (is_nan($pageId)) continue;
$page = $this->getById('page', $pageId); $page = $this->getById('page', $pageId, false, $ignorePermissions);
if ($page === null) { if ($page === null) {
$content = str_replace($matches[0][$index], '', $content); $content = str_replace($matches[0][$index], '', $content);
continue; continue;
@ -710,6 +716,7 @@ class EntityRepo
$content = str_replace($matches[0][$index], trim($innerContent), $content); $content = str_replace($matches[0][$index], trim($innerContent), $content);
} }
$page->renderedHTML = $content;
return $content; return $content;
} }

View File

@ -27,9 +27,9 @@ class ExportService
*/ */
public function pageToContainedHtml(Page $page) public function pageToContainedHtml(Page $page)
{ {
$this->entityRepo->renderPage($page);
$pageHtml = view('pages/export', [ $pageHtml = view('pages/export', [
'page' => $page, 'page' => $page
'pageContent' => $this->entityRepo->renderPage($page)
])->render(); ])->render();
return $this->containHtml($pageHtml); return $this->containHtml($pageHtml);
} }
@ -74,9 +74,9 @@ class ExportService
*/ */
public function pageToPdf(Page $page) public function pageToPdf(Page $page)
{ {
$this->entityRepo->renderPage($page);
$html = view('pages/pdf', [ $html = view('pages/pdf', [
'page' => $page, 'page' => $page
'pageContent' => $this->entityRepo->renderPage($page)
])->render(); ])->render();
return $this->htmlToPdf($html); return $this->htmlToPdf($html);
} }

View File

@ -92,7 +92,7 @@ class SearchService
return [ return [
'total' => $total, 'total' => $total,
'count' => count($results), 'count' => count($results),
'results' => $results->sortByDesc('score') 'results' => $results->sortByDesc('score')->values()
]; ];
} }

View File

@ -62,7 +62,7 @@ class ViewService
$query->whereIn('viewable_type', $filterModel); $query->whereIn('viewable_type', $filterModel);
} else if ($filterModel) { } else if ($filterModel) {
$query->where('viewable_type', '=', get_class($filterModel)); $query->where('viewable_type', '=', get_class($filterModel));
}; }
return $query->with('viewable')->skip($skipCount)->take($count)->get()->pluck('viewable'); return $query->with('viewable')->skip($skipCount)->take($count)->get()->pluck('viewable');
} }

View File

@ -3,16 +3,20 @@
const argv = require('yargs').argv; const argv = require('yargs').argv;
const gulp = require('gulp'), const gulp = require('gulp'),
plumber = require('gulp-plumber'); plumber = require('gulp-plumber');
const autoprefixer = require('gulp-autoprefixer'); const autoprefixer = require('gulp-autoprefixer');
const uglify = require('gulp-uglify');
const minifycss = require('gulp-clean-css'); const minifycss = require('gulp-clean-css');
const sass = require('gulp-sass'); const sass = require('gulp-sass');
const sourcemaps = require('gulp-sourcemaps');
const browserify = require("browserify"); const browserify = require("browserify");
const source = require('vinyl-source-stream'); const source = require('vinyl-source-stream');
const buffer = require('vinyl-buffer'); const buffer = require('vinyl-buffer');
const babelify = require("babelify"); const babelify = require("babelify");
const watchify = require("watchify"); const watchify = require("watchify");
const envify = require("envify"); const envify = require("envify");
const uglify = require('gulp-uglify');
const gutil = require("gulp-util"); const gutil = require("gulp-util");
const liveReload = require('gulp-livereload'); const liveReload = require('gulp-livereload');
@ -21,6 +25,7 @@ let isProduction = argv.production || process.env.NODE_ENV === 'production';
gulp.task('styles', () => { gulp.task('styles', () => {
let chain = gulp.src(['resources/assets/sass/**/*.scss']) let chain = gulp.src(['resources/assets/sass/**/*.scss'])
.pipe(sourcemaps.init())
.pipe(plumber({ .pipe(plumber({
errorHandler: function (error) { errorHandler: function (error) {
console.log(error.message); console.log(error.message);
@ -29,6 +34,7 @@ gulp.task('styles', () => {
.pipe(sass()) .pipe(sass())
.pipe(autoprefixer('last 2 versions')); .pipe(autoprefixer('last 2 versions'));
if (isProduction) chain = chain.pipe(minifycss()); if (isProduction) chain = chain.pipe(minifycss());
chain = chain.pipe(sourcemaps.write());
return chain.pipe(gulp.dest('public/css/')).pipe(liveReload()); return chain.pipe(gulp.dest('public/css/')).pipe(liveReload());
}); });

View File

@ -36,6 +36,7 @@
"clipboard": "^1.7.1", "clipboard": "^1.7.1",
"codemirror": "^5.26.0", "codemirror": "^5.26.0",
"dropzone": "^4.0.1", "dropzone": "^4.0.1",
"gulp-sourcemaps": "^2.6.1",
"gulp-util": "^3.0.8", "gulp-util": "^3.0.8",
"markdown-it": "^8.3.1", "markdown-it": "^8.3.1",
"markdown-it-task-lists": "^2.0.0", "markdown-it-task-lists": "^2.0.0",

View File

@ -1,7 +1,7 @@
# BookStack # BookStack
[![GitHub release](https://img.shields.io/github/release/BookStackApp/BookStack.svg?maxAge=2592000)](https://github.com/BookStackApp/BookStack/releases/latest) [![GitHub release](https://img.shields.io/github/release/BookStackApp/BookStack.svg)](https://github.com/BookStackApp/BookStack/releases/latest)
[![license](https://img.shields.io/github/license/BookStackApp/BookStack.svg?maxAge=2592000)](https://github.com/BookStackApp/BookStack/blob/master/LICENSE) [![license](https://img.shields.io/github/license/BookStackApp/BookStack.svg)](https://github.com/BookStackApp/BookStack/blob/master/LICENSE)
[![Build Status](https://travis-ci.org/BookStackApp/BookStack.svg)](https://travis-ci.org/BookStackApp/BookStack) [![Build Status](https://travis-ci.org/BookStackApp/BookStack.svg)](https://travis-ci.org/BookStackApp/BookStack)
A platform for storing and organising information and documentation. General information and documentation for BookStack can be found at https://www.bookstackapp.com/. A platform for storing and organising information and documentation. General information and documentation for BookStack can be found at https://www.bookstackapp.com/.
@ -13,6 +13,12 @@ A platform for storing and organising information and documentation. General inf
* *Password: `password`* * *Password: `password`*
* [BookStack Blog](https://www.bookstackapp.com/blog) * [BookStack Blog](https://www.bookstackapp.com/blog)
## Project Definition
BookStack is an opinionated wiki system that provides a pleasant and simple out of the box experience. New users to an instance should find the experience intuitive and only basic word-processing skills should be required to get involved in creating content on BookStack. The platform should provide advanced power features to those that desire it but they should not interfere with the core simple user experience.
BookStack is not designed as an extensible platform to be used for purposes that differ to the statement above.
## Development & Testing ## Development & Testing
All development on BookStack is currently done on the master branch. When it's time for a release the master branch is merged into release with built & minified CSS & JS then tagged at it's version. Here are the current development requirements: All development on BookStack is currently done on the master branch. When it's time for a release the master branch is merged into release with built & minified CSS & JS then tagged at it's version. Here are the current development requirements:

View File

@ -0,0 +1,47 @@
class EntitySelectorPopup {
constructor(elem) {
this.elem = elem;
window.EntitySelectorPopup = this;
this.callback = null;
this.selection = null;
this.selectButton = elem.querySelector('.entity-link-selector-confirm');
this.selectButton.addEventListener('click', this.onSelectButtonClick.bind(this));
window.$events.listen('entity-select-change', this.onSelectionChange.bind(this));
window.$events.listen('entity-select-confirm', this.onSelectionConfirm.bind(this));
}
show(callback) {
this.callback = callback;
this.elem.components.overlay.show();
}
hide() {
this.elem.components.overlay.hide();
}
onSelectButtonClick() {
this.hide();
if (this.selection !== null && this.callback) this.callback(this.selection);
}
onSelectionConfirm(entity) {
this.hide();
if (this.callback && entity) this.callback(entity);
}
onSelectionChange(entity) {
this.selection = entity;
if (entity === null) {
this.selectButton.setAttribute('disabled', 'true');
} else {
this.selectButton.removeAttribute('disabled');
}
}
}
module.exports = EntitySelectorPopup;

View File

@ -0,0 +1,118 @@
class EntitySelector {
constructor(elem) {
this.elem = elem;
this.search = '';
this.lastClick = 0;
let entityTypes = elem.hasAttribute('entity-types') ? elem.getAttribute('entity-types') : 'page,book,chapter';
this.searchUrl = window.baseUrl(`/ajax/search/entities?types=${encodeURIComponent(entityTypes)}`);
this.input = elem.querySelector('[entity-selector-input]');
this.searchInput = elem.querySelector('[entity-selector-search]');
this.loading = elem.querySelector('[entity-selector-loading]');
this.resultsContainer = elem.querySelector('[entity-selector-results]');
this.elem.addEventListener('click', this.onClick.bind(this));
let lastSearch = 0;
this.searchInput.addEventListener('input', event => {
lastSearch = Date.now();
this.showLoading();
setTimeout(() => {
if (Date.now() - lastSearch < 199) return;
this.searchEntities(this.searchInput.value);
}, 200);
});
this.searchInput.addEventListener('keydown', event => {
if (event.keyCode === 13) event.preventDefault();
});
this.showLoading();
this.initialLoad();
}
showLoading() {
this.loading.style.display = 'block';
this.resultsContainer.style.display = 'none';
}
hideLoading() {
this.loading.style.display = 'none';
this.resultsContainer.style.display = 'block';
}
initialLoad() {
window.$http.get(this.searchUrl).then(resp => {
this.resultsContainer.innerHTML = resp.data;
this.hideLoading();
})
}
searchEntities(searchTerm) {
this.input.value = '';
let url = this.searchUrl + `&term=${encodeURIComponent(searchTerm)}`;
window.$http.get(url).then(resp => {
this.resultsContainer.innerHTML = resp.data;
this.hideLoading();
});
}
isDoubleClick() {
let now = Date.now();
let answer = now - this.lastClick < 300;
this.lastClick = now;
return answer;
}
onClick(event) {
let t = event.target;
console.log('click', t);
if (t.matches('.entity-list-item *')) {
event.preventDefault();
event.stopPropagation();
let item = t.closest('[data-entity-type]');
this.selectItem(item);
} else if (t.matches('[data-entity-type]')) {
this.selectItem(t)
}
}
selectItem(item) {
let isDblClick = this.isDoubleClick();
let type = item.getAttribute('data-entity-type');
let id = item.getAttribute('data-entity-id');
let isSelected = !item.classList.contains('selected') || isDblClick;
this.unselectAll();
this.input.value = isSelected ? `${type}:${id}` : '';
if (!isSelected) window.$events.emit('entity-select-change', null);
if (isSelected) {
item.classList.add('selected');
item.classList.add('primary-background');
}
if (!isDblClick && !isSelected) return;
let link = item.querySelector('.entity-list-item-link').getAttribute('href');
let name = item.querySelector('.entity-list-item-name').textContent;
let data = {id: Number(id), name: name, link: link};
if (isDblClick) window.$events.emit('entity-select-confirm', data);
if (isSelected) window.$events.emit('entity-select-change', data);
}
unselectAll() {
let selected = this.elem.querySelectorAll('.selected');
for (let i = 0, len = selected.length; i < len; i++) {
selected[i].classList.remove('selected');
selected[i].classList.remove('primary-background');
}
}
}
module.exports = EntitySelector;

View File

@ -6,6 +6,10 @@ let componentMapping = {
'notification': require('./notification'), 'notification': require('./notification'),
'chapter-toggle': require('./chapter-toggle'), 'chapter-toggle': require('./chapter-toggle'),
'expand-toggle': require('./expand-toggle'), 'expand-toggle': require('./expand-toggle'),
'entity-selector-popup': require('./entity-selector-popup'),
'entity-selector': require('./entity-selector'),
'sidebar': require('./sidebar'),
'page-picker': require('./page-picker'),
}; };
window.components = {}; window.components = {};

View File

@ -6,7 +6,7 @@ class Notification {
this.type = elem.getAttribute('notification'); this.type = elem.getAttribute('notification');
this.textElem = elem.querySelector('span'); this.textElem = elem.querySelector('span');
this.autohide = this.elem.hasAttribute('data-autohide'); this.autohide = this.elem.hasAttribute('data-autohide');
window.Events.listen(this.type, text => { window.$events.listen(this.type, text => {
this.show(text); this.show(text);
}); });
elem.addEventListener('click', this.hide.bind(this)); elem.addEventListener('click', this.hide.bind(this));

View File

@ -0,0 +1,60 @@
class PagePicker {
constructor(elem) {
this.elem = elem;
this.input = elem.querySelector('input');
this.resetButton = elem.querySelector('[page-picker-reset]');
this.selectButton = elem.querySelector('[page-picker-select]');
this.display = elem.querySelector('[page-picker-display]');
this.defaultDisplay = elem.querySelector('[page-picker-default]');
this.buttonSep = elem.querySelector('span.sep');
this.value = this.input.value;
this.setupListeners();
}
setupListeners() {
// Select click
this.selectButton.addEventListener('click', event => {
window.EntitySelectorPopup.show(entity => {
this.setValue(entity.id, entity.name);
});
});
this.resetButton.addEventListener('click', event => {
this.setValue('', '');
});
}
setValue(value, name) {
this.value = value;
this.input.value = value;
this.controlView(name);
}
controlView(name) {
let hasValue = this.value && this.value !== 0;
toggleElem(this.resetButton, hasValue);
toggleElem(this.buttonSep, hasValue);
toggleElem(this.defaultDisplay, !hasValue);
toggleElem(this.display, hasValue);
if (hasValue) {
let id = this.getAssetIdFromVal();
this.display.textContent = `#${id}, ${name}`;
this.display.href = window.baseUrl(`/link/${id}`);
}
}
getAssetIdFromVal() {
return Number(this.value);
}
}
function toggleElem(elem, show) {
let display = (elem.tagName === 'BUTTON' || elem.tagName === 'SPAN') ? 'inline-block' : 'block';
elem.style.display = show ? display : 'none';
}
module.exports = PagePicker;

View File

@ -0,0 +1,16 @@
class Sidebar {
constructor(elem) {
this.elem = elem;
this.toggleElem = elem.querySelector('.sidebar-toggle');
this.toggleElem.addEventListener('click', this.toggle.bind(this));
}
toggle(show = true) {
this.elem.classList.toggle('open');
}
}
module.exports = Sidebar;

View File

@ -252,7 +252,7 @@ module.exports = function (ngApp, events) {
// Show the popup link selector and insert a link when finished // Show the popup link selector and insert a link when finished
function showLinkSelector() { function showLinkSelector() {
let cursorPos = cm.getCursor('from'); let cursorPos = cm.getCursor('from');
window.showEntityLinkSelector(entity => { window.EntitySelectorPopup.show(entity => {
let selectedText = cm.getSelection() || entity.name; let selectedText = cm.getSelection() || entity.name;
let newText = `[${selectedText}](${entity.link})`; let newText = `[${selectedText}](${entity.link})`;
cm.focus(); cm.focus();
@ -387,154 +387,6 @@ module.exports = function (ngApp, events) {
} }
}]); }]);
ngApp.directive('entityLinkSelector', [function($http) {
return {
restrict: 'A',
link: function(scope, element, attrs) {
const selectButton = element.find('.entity-link-selector-confirm');
let callback = false;
let entitySelection = null;
// Handle entity selection change, Stores the selected entity locally
function entitySelectionChange(entity) {
entitySelection = entity;
if (entity === null) {
selectButton.attr('disabled', 'true');
} else {
selectButton.removeAttr('disabled');
}
}
events.listen('entity-select-change', entitySelectionChange);
// Handle selection confirm button click
selectButton.click(event => {
hide();
if (entitySelection !== null) callback(entitySelection);
});
// Show selector interface
function show() {
element.fadeIn(240);
}
// Hide selector interface
function hide() {
element.fadeOut(240);
}
scope.hide = hide;
// Listen to confirmation of entity selections (doubleclick)
events.listen('entity-select-confirm', entity => {
hide();
callback(entity);
});
// Show entity selector, Accessible globally, and store the callback
window.showEntityLinkSelector = function(passedCallback) {
show();
callback = passedCallback;
};
}
};
}]);
ngApp.directive('entitySelector', ['$http', '$sce', function ($http, $sce) {
return {
restrict: 'A',
scope: true,
link: function (scope, element, attrs) {
scope.loading = true;
scope.entityResults = false;
scope.search = '';
// Add input for forms
const input = element.find('[entity-selector-input]').first();
// Detect double click events
let lastClick = 0;
function isDoubleClick() {
let now = Date.now();
let answer = now - lastClick < 300;
lastClick = now;
return answer;
}
// Listen to entity item clicks
element.on('click', '.entity-list a', function(event) {
event.preventDefault();
event.stopPropagation();
let item = $(this).closest('[data-entity-type]');
itemSelect(item, isDoubleClick());
});
element.on('click', '[data-entity-type]', function(event) {
itemSelect($(this), isDoubleClick());
});
// Select entity action
function itemSelect(item, doubleClick) {
let entityType = item.attr('data-entity-type');
let entityId = item.attr('data-entity-id');
let isSelected = !item.hasClass('selected') || doubleClick;
element.find('.selected').removeClass('selected').removeClass('primary-background');
if (isSelected) item.addClass('selected').addClass('primary-background');
let newVal = isSelected ? `${entityType}:${entityId}` : '';
input.val(newVal);
if (!isSelected) {
events.emit('entity-select-change', null);
}
if (!doubleClick && !isSelected) return;
let link = item.find('.entity-list-item-link').attr('href');
let name = item.find('.entity-list-item-name').text();
if (doubleClick) {
events.emit('entity-select-confirm', {
id: Number(entityId),
name: name,
link: link
});
}
if (isSelected) {
events.emit('entity-select-change', {
id: Number(entityId),
name: name,
link: link
});
}
}
// Get search url with correct types
function getSearchUrl() {
let types = (attrs.entityTypes) ? encodeURIComponent(attrs.entityTypes) : encodeURIComponent('page,book,chapter');
return window.baseUrl(`/ajax/search/entities?types=${types}`);
}
// Get initial contents
$http.get(getSearchUrl()).then(resp => {
scope.entityResults = $sce.trustAsHtml(resp.data);
scope.loading = false;
});
// Search when typing
scope.searchEntities = function() {
scope.loading = true;
input.val('');
let url = getSearchUrl() + '&term=' + encodeURIComponent(scope.search);
$http.get(url).then(resp => {
scope.entityResults = $sce.trustAsHtml(resp.data);
scope.loading = false;
});
};
}
};
}]);
ngApp.directive('commentReply', [function () { ngApp.directive('commentReply', [function () {
return { return {
restrict: 'E', restrict: 'E',

View File

@ -0,0 +1,20 @@
/**
* Polyfills for DOM API's
*/
if (!Element.prototype.matches) {
Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector;
}
if (!Element.prototype.closest) {
Element.prototype.closest = function (s) {
var el = this;
var ancestor = this;
if (!document.documentElement.contains(el)) return null;
do {
if (ancestor.matches(s)) return ancestor;
ancestor = ancestor.parentElement;
} while (ancestor !== null);
return null;
};
}

View File

@ -1,5 +1,6 @@
"use strict"; "use strict";
require("babel-polyfill"); require("babel-polyfill");
require('./dom-polyfills');
// Url retrieval function // Url retrieval function
window.baseUrl = function(path) { window.baseUrl = function(path) {
@ -13,9 +14,11 @@ window.baseUrl = function(path) {
class EventManager { class EventManager {
constructor() { constructor() {
this.listeners = {}; this.listeners = {};
this.stack = [];
} }
emit(eventName, eventData) { emit(eventName, eventData) {
this.stack.push({name: eventName, data: eventData});
if (typeof this.listeners[eventName] === 'undefined') return this; if (typeof this.listeners[eventName] === 'undefined') return this;
let eventsToStart = this.listeners[eventName]; let eventsToStart = this.listeners[eventName];
for (let i = 0; i < eventsToStart.length; i++) { for (let i = 0; i < eventsToStart.length; i++) {
@ -32,7 +35,7 @@ class EventManager {
} }
} }
window.Events = new EventManager(); window.$events = new EventManager();
const Vue = require("vue"); const Vue = require("vue");
const axios = require("axios"); const axios = require("axios");
@ -47,13 +50,13 @@ axiosInstance.interceptors.request.use(resp => {
return resp; return resp;
}, err => { }, err => {
if (typeof err.response === "undefined" || typeof err.response.data === "undefined") return Promise.reject(err); if (typeof err.response === "undefined" || typeof err.response.data === "undefined") return Promise.reject(err);
if (typeof err.response.data.error !== "undefined") window.Events.emit('error', err.response.data.error); if (typeof err.response.data.error !== "undefined") window.$events.emit('error', err.response.data.error);
if (typeof err.response.data.message !== "undefined") window.Events.emit('error', err.response.data.message); if (typeof err.response.data.message !== "undefined") window.$events.emit('error', err.response.data.message);
}); });
window.$http = axiosInstance; window.$http = axiosInstance;
Vue.prototype.$http = axiosInstance; Vue.prototype.$http = axiosInstance;
Vue.prototype.$events = window.Events; Vue.prototype.$events = window.$events;
// AngularJS - Create application and load components // AngularJS - Create application and load components
@ -78,8 +81,8 @@ require("./components");
// Load in angular specific items // Load in angular specific items
const Directives = require('./directives'); const Directives = require('./directives');
const Controllers = require('./controllers'); const Controllers = require('./controllers');
Directives(ngApp, window.Events); Directives(ngApp, window.$events);
Controllers(ngApp, window.Events); Controllers(ngApp, window.$events);
//Global jQuery Config & Extensions //Global jQuery Config & Extensions

View File

@ -274,7 +274,7 @@ module.exports = function() {
file_browser_callback: function (field_name, url, type, win) { file_browser_callback: function (field_name, url, type, win) {
if (type === 'file') { if (type === 'file') {
window.showEntityLinkSelector(function(entity) { window.EntitySelectorPopup.show(function(entity) {
let originalField = win.document.getElementById(field_name); let originalField = win.document.getElementById(field_name);
originalField.value = entity.link; originalField.value = entity.link;
$(originalField).closest('.mce-form').find('input').eq(2).val(entity.name); $(originalField).closest('.mce-form').find('input').eq(2).val(entity.name);

View File

@ -106,25 +106,25 @@ let setupPageShow = window.setupPageShow = function (pageId) {
goToText(event.target.getAttribute('href').substr(1)); goToText(event.target.getAttribute('href').substr(1));
}); });
// Make the book-tree sidebar stick in view on scroll // Make the sidebar stick in view on scroll
let $window = $(window); let $window = $(window);
let $bookTree = $(".book-tree"); let $sidebar = $("#sidebar .scroll-body");
let $bookTreeParent = $bookTree.parent(); let $bookTreeParent = $sidebar.parent();
// Check the page is scrollable and the content is taller than the tree // Check the page is scrollable and the content is taller than the tree
let pageScrollable = ($(document).height() > $window.height()) && ($bookTree.height() < $('.page-content').height()); let pageScrollable = ($(document).height() > $window.height()) && ($sidebar.height() < $('.page-content').height());
// Get current tree's width and header height // Get current tree's width and header height
let headerHeight = $("#header").height() + $(".toolbar").height(); let headerHeight = $("#header").height() + $(".toolbar").height();
let isFixed = $window.scrollTop() > headerHeight; let isFixed = $window.scrollTop() > headerHeight;
// Function to fix the tree as a sidebar // Function to fix the tree as a sidebar
function stickTree() { function stickTree() {
$bookTree.width($bookTreeParent.width() + 15); $sidebar.width($bookTreeParent.width() + 15);
$bookTree.addClass("fixed"); $sidebar.addClass("fixed");
isFixed = true; isFixed = true;
} }
// Function to un-fix the tree back into position // Function to un-fix the tree back into position
function unstickTree() { function unstickTree() {
$bookTree.css('width', 'auto'); $sidebar.css('width', 'auto');
$bookTree.removeClass("fixed"); $sidebar.removeClass("fixed");
isFixed = false; isFixed = false;
} }
// Checks if the tree stickiness state should change // Checks if the tree stickiness state should change

View File

@ -181,3 +181,27 @@
content: '\f1f1'; content: '\f1f1';
} }
} }
.card {
margin: $-m;
background-color: #FFF;
box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.2);
h3 {
padding: $-m;
border-bottom: 1px solid #E8E8E8;
margin: 0;
font-size: $fs-s;
color: #888;
font-weight: 400;
text-transform: uppercase;
}
.body, p.empty-text {
padding: $-m;
}
}
.well {
background-color: #F8F8F8;
padding: $-m;
border: 1px solid #DDD;
}

View File

@ -2,9 +2,12 @@
@mixin generate-button-colors($textColor, $backgroundColor) { @mixin generate-button-colors($textColor, $backgroundColor) {
background-color: $backgroundColor; background-color: $backgroundColor;
color: $textColor; color: $textColor;
text-transform: uppercase;
border: 1px solid $backgroundColor;
vertical-align: top;
&:hover { &:hover {
background-color: lighten($backgroundColor, 8%); background-color: lighten($backgroundColor, 8%);
box-shadow: $bs-med; //box-shadow: $bs-med;
text-decoration: none; text-decoration: none;
color: $textColor; color: $textColor;
} }
@ -26,16 +29,16 @@ $button-border-radius: 2px;
text-decoration: none; text-decoration: none;
font-size: $fs-m; font-size: $fs-m;
line-height: 1.4em; line-height: 1.4em;
padding: $-xs $-m; padding: $-xs*1.3 $-m;
margin: $-xs $-xs $-xs 0; margin: $-xs $-xs $-xs 0;
display: inline-block; display: inline-block;
border: none; border: none;
font-weight: 500; font-weight: 400;
outline: 0; outline: 0;
border-radius: $button-border-radius; border-radius: $button-border-radius;
cursor: pointer; cursor: pointer;
transition: all ease-in-out 120ms; transition: all ease-in-out 120ms;
box-shadow: 0 0.5px 1.5px 0 rgba(0, 0, 0, 0.21); box-shadow: 0;
@include generate-button-colors(#EEE, $primary); @include generate-button-colors(#EEE, $primary);
} }
@ -51,13 +54,47 @@ $button-border-radius: 2px;
@include generate-button-colors(#EEE, $secondary); @include generate-button-colors(#EEE, $secondary);
} }
&.muted { &.muted {
@include generate-button-colors(#EEE, #888); @include generate-button-colors(#EEE, #AAA);
} }
&.muted-light { &.muted-light {
@include generate-button-colors(#666, #e4e4e4); @include generate-button-colors(#666, #e4e4e4);
} }
} }
.button.outline {
background-color: transparent;
color: #888;
border: 1px solid #DDD;
&:hover, &:focus, &:active {
box-shadow: none;
background-color: #EEE;
}
&.page {
border-color: $color-page;
color: $color-page;
&:hover, &:focus, &:active {
background-color: $color-page;
color: #FFF;
}
}
&.chapter {
border-color: $color-chapter;
color: $color-chapter;
&:hover, &:focus, &:active {
background-color: $color-chapter;
color: #FFF;
}
}
&.book {
border-color: $color-book;
color: $color-book;
&:hover, &:focus, &:active {
background-color: $color-book;
color: #FFF;
}
}
}
.text-button { .text-button {
@extend .link; @extend .link;
background-color: transparent; background-color: transparent;

View File

@ -366,9 +366,9 @@ span.CodeMirror-selectedtext { background: none; }
.cm-s-base16-light span.cm-atom { color: #aa759f; } .cm-s-base16-light span.cm-atom { color: #aa759f; }
.cm-s-base16-light span.cm-number { color: #aa759f; } .cm-s-base16-light span.cm-number { color: #aa759f; }
.cm-s-base16-light span.cm-property, .cm-s-base16-light span.cm-attribute { color: #90a959; } .cm-s-base16-light span.cm-property, .cm-s-base16-light span.cm-attribute { color: #678c30; }
.cm-s-base16-light span.cm-keyword { color: #ac4142; } .cm-s-base16-light span.cm-keyword { color: #ac4142; }
.cm-s-base16-light span.cm-string { color: #f4bf75; } .cm-s-base16-light span.cm-string { color: #e09c3c; }
.cm-s-base16-light span.cm-variable { color: #90a959; } .cm-s-base16-light span.cm-variable { color: #90a959; }
.cm-s-base16-light span.cm-variable-2 { color: #6a9fb5; } .cm-s-base16-light span.cm-variable-2 { color: #6a9fb5; }
@ -392,7 +392,7 @@ span.CodeMirror-selectedtext { background: none; }
} }
.cm-s-base16-light .CodeMirror-gutters { background: #f5f5f5; border-right: 1px solid #DDD; } .cm-s-base16-light .CodeMirror-gutters { background: #f5f5f5; border-right: 1px solid #DDD; }
.flex-fill .CodeMirror { .code-fill .CodeMirror {
position: absolute; position: absolute;
top: 0; top: 0;
bottom: 0; bottom: 0;

View File

@ -2,14 +2,13 @@
.input-base { .input-base {
background-color: #FFF; background-color: #FFF;
border-radius: 3px; border-radius: 3px;
border: 1px solid #CCC; border: 1px solid #D4D4D4;
display: inline-block; display: inline-block;
font-size: $fs-s; font-size: $fs-s;
padding: $-xs; padding: $-xs*1.5;
color: #222; color: #666;
width: 250px; width: 250px;
max-width: 100%; max-width: 100%;
//-webkit-appearance:none;
&.neg, &.invalid { &.neg, &.invalid {
border: 1px solid $negative; border: 1px solid $negative;
} }
@ -24,6 +23,11 @@
} }
} }
.fake-input {
@extend .input-base;
overflow: auto;
}
#html-editor { #html-editor {
display: none; display: none;
} }
@ -84,8 +88,9 @@ label {
display: block; display: block;
line-height: 1.4em; line-height: 1.4em;
font-size: 0.94em; font-size: 0.94em;
font-weight: 500; font-weight: 400;
color: #666; color: #999;
text-transform: uppercase;
padding-bottom: 2px; padding-bottom: 2px;
margin-bottom: 0.2em; margin-bottom: 0.2em;
&.inline { &.inline {
@ -186,28 +191,15 @@ input:checked + .toggle-switch {
} }
.inline-input-style { .inline-input-style {
border: 2px dotted #BBB;
display: block; display: block;
width: 100%; width: 100%;
padding: $-xs $-s; padding: $-s;
}
.title-input .input {
width: 100%;
}
.title-input label, .description-input label{
margin-top: $-m;
color: #666;
} }
.title-input input[type="text"] { .title-input input[type="text"] {
@extend h1;
@extend .inline-input-style; @extend .inline-input-style;
margin-top: 0; margin-top: 0;
padding-right: 0; font-size: 2em;
width: 100%;
color: #444;
} }
.title-input.page-title { .title-input.page-title {
@ -250,8 +242,8 @@ div[editor-type="markdown"] .title-input.page-title input[type="text"] {
padding: 0; padding: 0;
cursor: pointer; cursor: pointer;
position: absolute; position: absolute;
left: 7px; left: 8px;
top: 7px; top: 9.5px;
} }
input { input {
display: block; display: block;

View File

@ -20,19 +20,122 @@ body.flexbox {
align-items: stretch; align-items: stretch;
min-height: 0; min-height: 0;
position: relative; position: relative;
.flex, &.flex { &.rows {
flex-direction: row;
}
&.columns {
flex-direction: column;
}
}
.flex {
min-height: 0; min-height: 0;
flex: 1; flex: 1;
}
.flex.scroll {
//overflow-y: auto;
display: flex;
&.sidebar {
margin-right: -14px;
} }
} }
.flex.scroll .scroll-body {
overflow-y: scroll;
flex: 1;
}
.flex-child > div { .flex-child > div {
flex: 1; flex: 1;
} }
//body.ie .flex-child > div { .flex.sidebar {
// flex: 1 0 0px; flex: 1;
//} background-color: #F2F2F2;
max-width: 360px;
min-height: 90vh;
}
.flex.sidebar + .flex.content {
flex: 3;
background-color: #FFFFFF;
padding: 0 $-l;
border-left: 1px solid #DDD;
max-width: 100%;
}
.flex.sidebar .sidebar-toggle {
display: none;
}
@include smaller-than($xl) {
body.sidebar-layout {
padding-left: 30px;
}
.flex.sidebar {
position: fixed;
top: 0;
left: 0;
bottom: 0;
z-index: 100;
padding-right: 30px;
width: 360px;
box-shadow: none;
transform: translate3d(-330px, 0, 0);
transition: transform ease-in-out 120ms;
}
.flex.sidebar.open {
box-shadow: 1px 2px 2px 1px rgba(0,0,0,.10);
transform: translate3d(0, 0, 0);
.sidebar-toggle i {
transform: rotate(180deg);
}
}
.flex.sidebar .sidebar-toggle {
display: block;
position: absolute;
opacity: 0.9;
right: 0;
top: 0;
bottom: 0;
width: 30px;
color: #666;
font-size: 20px;
vertical-align: middle;
text-align: center;
border: 1px solid #DDD;
border-top: 1px solid #BBB;
padding-top: $-m;
cursor: pointer;
i {
opacity: 0.5;
transition: all ease-in-out 120ms;
padding: 0;
}
&:hover i {
opacity: 1;
}
}
#sidebar .scroll-body.fixed {
width: auto !important;
}
}
@include larger-than($xl) {
#sidebar .scroll-body.fixed {
z-index: 5;
position: fixed;
top: 0;
padding-right: $-m;
width: 30%;
left: 0;
height: 100%;
overflow-y: scroll;
-ms-overflow-style: none;
//background-color: $primary-faded;
border-left: 1px solid #DDD;
&::-webkit-scrollbar { width: 0 !important }
}
}
/** Rules for all columns */ /** Rules for all columns */
div[class^="col-"] img { div[class^="col-"] img {

View File

@ -85,7 +85,7 @@ header {
} }
header .search-box { header .search-box {
display: inline-block; display: inline-block;
margin-top: $-s; margin-top: 10px;
input { input {
background-color: rgba(0, 0, 0, 0.2); background-color: rgba(0, 0, 0, 0.2);
border: 1px solid rgba(255, 255, 255, 0.3); border: 1px solid rgba(255, 255, 255, 0.3);
@ -171,6 +171,10 @@ header .search-box {
background-color: $primary-faded; background-color: $primary-faded;
} }
.toolbar-container {
background-color: #FFF;
}
.breadcrumbs .text-button, .action-buttons .text-button { .breadcrumbs .text-button, .action-buttons .text-button {
display: inline-block; display: inline-block;
padding: $-s; padding: $-s;

View File

@ -9,6 +9,9 @@ html {
&.flexbox { &.flexbox {
overflow-y: hidden; overflow-y: hidden;
} }
&.shaded {
background-color: #F2F2F2;
}
} }
body { body {
@ -16,6 +19,9 @@ body {
line-height: 1.6; line-height: 1.6;
color: #616161; color: #616161;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
&.shaded {
background-color: #F2F2F2;
}
} }
button { button {

View File

@ -86,31 +86,8 @@
// Sidebar list // Sidebar list
.book-tree { .book-tree {
padding: $-xs 0 0 0;
position: relative;
right: 0;
top: 0;
transition: ease-in-out 240ms; transition: ease-in-out 240ms;
transition-property: right, border; transition-property: right, border;
border-left: 0px solid #FFF;
background-color: #FFF;
max-width: 320px;
&.fixed {
background-color: #FFF;
z-index: 5;
position: fixed;
top: 0;
padding-left: $-l;
padding-right: $-l + 15;
width: 30%;
right: -15px;
height: 100%;
overflow-y: scroll;
-ms-overflow-style: none;
//background-color: $primary-faded;
border-left: 1px solid #DDD;
&::-webkit-scrollbar { width: 0 !important }
}
} }
.book-tree h4 { .book-tree h4 {
padding: $-m $-s 0 $-s; padding: $-m $-s 0 $-s;
@ -245,6 +222,9 @@
.left + .right { .left + .right {
margin-left: 30px + $-s; margin-left: 30px + $-s;
} }
&:last-of-type {
border-bottom: 0;
}
} }
ul.pagination { ul.pagination {
@ -297,9 +277,6 @@ ul.pagination {
h4 { h4 {
margin: 0; margin: 0;
} }
p {
margin: $-xs 0 0 0;
}
hr { hr {
margin: 0; margin: 0;
} }
@ -316,6 +293,11 @@ ul.pagination {
} }
} }
.card .entity-list-item, .card .activity-list-item {
padding-left: $-m;
padding-right: $-m;
}
.entity-list.compact { .entity-list.compact {
font-size: 0.6em; font-size: 0.6em;
h4, a { h4, a {
@ -324,9 +306,11 @@ ul.pagination {
.entity-item-snippet { .entity-item-snippet {
display: none; display: none;
} }
p { .entity-list-item p {
font-size: $fs-m * 0.8; font-size: $fs-m * 0.8;
padding-top: $-xs; padding-top: $-xs;
}
p {
margin: 0; margin: 0;
} }
> p.empty-text { > p.empty-text {

View File

@ -1,12 +1,3 @@
#page-show {
>.row .col-md-9 {
z-index: 2;
}
>.row .col-md-3 {
z-index: 1;
}
}
.page-editor { .page-editor {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -36,6 +27,8 @@
.page-content { .page-content {
max-width: 840px; max-width: 840px;
margin: 0 auto;
margin-top: $-xxl;
overflow-wrap: break-word; overflow-wrap: break-word;
.align-left { .align-left {
text-align: left; text-align: left;
@ -252,8 +245,6 @@
} }
.tag-display { .tag-display {
width: 100%;
//opacity: 0.7;
position: relative; position: relative;
table { table {
width: 100%; width: 100%;

View File

@ -2,7 +2,7 @@
* Fonts * Fonts
*/ */
body, button, input, select, label { body, button, input, select, label, textarea {
font-family: $text; font-family: $text;
} }
.Codemirror, pre, #markdown-editor-input, .editor-toolbar, .code-base { .Codemirror, pre, #markdown-editor-input, .editor-toolbar, .code-base {
@ -378,12 +378,6 @@ span.sep {
display: block; display: block;
} }
.action-header {
h1 {
margin-top: $-m;
}
}
/** /**
* Icons * Icons
*/ */

View File

@ -217,22 +217,15 @@ $btt-size: 40px;
} }
.center-box { .center-box {
margin: $-xl auto 0 auto; margin: $-xxl auto 0 auto;
padding: $-m $-xxl $-xl $-xxl;
width: 420px; width: 420px;
max-width: 100%; max-width: 100%;
display: inline-block; display: inline-block;
text-align: left; text-align: left;
vertical-align: top; vertical-align: top;
//border: 1px solid #DDD;
input { input {
width: 100%; width: 100%;
} }
&.login {
background-color: #EEE;
box-shadow: 0 0 2px 0 rgba(0, 0, 0, 0.1);
border: 1px solid #DDD;
}
} }

View File

@ -10,6 +10,7 @@ return [
'save' => 'Save', 'save' => 'Save',
'continue' => 'Continue', 'continue' => 'Continue',
'select' => 'Select', 'select' => 'Select',
'more' => 'More',
/** /**
* Form Labels * Form Labels
@ -36,7 +37,6 @@ return [
'remove' => 'Remove', 'remove' => 'Remove',
'add' => 'Add', 'add' => 'Add',
/** /**
* Misc * Misc
*/ */
@ -46,7 +46,7 @@ return [
'back_to_top' => 'Back to top', 'back_to_top' => 'Back to top',
'toggle_details' => 'Toggle Details', 'toggle_details' => 'Toggle Details',
'toggle_thumbnails' => 'Toggle Thumbnails', 'toggle_thumbnails' => 'Toggle Thumbnails',
'details' => 'Details',
/** /**
* Header * Header
*/ */

View File

@ -73,11 +73,13 @@ return [
'books_empty' => 'No books have been created', 'books_empty' => 'No books have been created',
'books_popular' => 'Popular Books', 'books_popular' => 'Popular Books',
'books_recent' => 'Recent Books', 'books_recent' => 'Recent Books',
'books_new' => 'New Books',
'books_popular_empty' => 'The most popular books will appear here.', 'books_popular_empty' => 'The most popular books will appear here.',
'books_new_empty' => 'The most recently created books will appear here.',
'books_create' => 'Create New Book', 'books_create' => 'Create New Book',
'books_delete' => 'Delete Book', 'books_delete' => 'Delete Book',
'books_delete_named' => 'Delete Book :bookName', 'books_delete_named' => 'Delete Book :bookName',
'books_delete_explain' => 'This will delete the book with the name \':bookName\', All pages and chapters will be removed.', 'books_delete_explain' => 'This will delete the book with the name \':bookName\'. All pages and chapters will be removed.',
'books_delete_confirmation' => 'Are you sure you want to delete this book?', 'books_delete_confirmation' => 'Are you sure you want to delete this book?',
'books_edit' => 'Edit Book', 'books_edit' => 'Edit Book',
'books_edit_named' => 'Edit Book :bookName', 'books_edit_named' => 'Edit Book :bookName',
@ -108,8 +110,7 @@ return [
'chapters_create' => 'Create New Chapter', 'chapters_create' => 'Create New Chapter',
'chapters_delete' => 'Delete Chapter', 'chapters_delete' => 'Delete Chapter',
'chapters_delete_named' => 'Delete Chapter :chapterName', 'chapters_delete_named' => 'Delete Chapter :chapterName',
'chapters_delete_explain' => 'This will delete the chapter with the name \':chapterName\', All pages will be removed 'chapters_delete_explain' => 'This will delete the chapter with the name \':chapterName\'. All pages will be removed and added directly to the parent book.',
and added directly to the parent book.',
'chapters_delete_confirm' => 'Are you sure you want to delete this chapter?', 'chapters_delete_confirm' => 'Are you sure you want to delete this chapter?',
'chapters_edit' => 'Edit Chapter', 'chapters_edit' => 'Edit Chapter',
'chapters_edit_named' => 'Edit Chapter :chapterName', 'chapters_edit_named' => 'Edit Chapter :chapterName',
@ -164,6 +165,7 @@ return [
'pages_move_success' => 'Page moved to ":parentName"', 'pages_move_success' => 'Page moved to ":parentName"',
'pages_permissions' => 'Page Permissions', 'pages_permissions' => 'Page Permissions',
'pages_permissions_success' => 'Page permissions updated', 'pages_permissions_success' => 'Page permissions updated',
'pages_revision' => 'Revision',
'pages_revisions' => 'Page Revisions', 'pages_revisions' => 'Page Revisions',
'pages_revisions_named' => 'Page Revisions for :pageName', 'pages_revisions_named' => 'Page Revisions for :pageName',
'pages_revision_named' => 'Page Revision for :pageName', 'pages_revision_named' => 'Page Revision for :pageName',

View File

@ -31,6 +31,9 @@ return [
'app_logo_desc' => 'This image should be 43px in height. <br>Large images will be scaled down.', 'app_logo_desc' => 'This image should be 43px in height. <br>Large images will be scaled down.',
'app_primary_color' => 'Application primary color', 'app_primary_color' => 'Application primary color',
'app_primary_color_desc' => 'This should be a hex value. <br>Leave empty to reset to the default color.', 'app_primary_color_desc' => 'This should be a hex value. <br>Leave empty to reset to the default color.',
'app_homepage' => 'Application Homepage',
'app_homepage_desc' => 'Select a page to show on the homepage instead of the default view. Page permissions are ignored for selected pages.',
'app_homepage_default' => 'Default homepage view chosen',
/** /**
* Registration settings * Registration settings

View File

@ -9,9 +9,10 @@
@section('content') @section('content')
<div class="text-center"> <div class="text-center">
<div class="center-box"> <div class="card center-box">
<h1>{{ title_case(trans('auth.log_in')) }}</h1> <h3><i class="zmdi zmdi-sign-in"></i> {{ title_case(trans('auth.log_in')) }}</h3>
<div class="body">
<form action="{{ baseUrl("/login") }}" method="POST" id="login-form"> <form action="{{ baseUrl("/login") }}" method="POST" id="login-form">
{!! csrf_field() !!} {!! csrf_field() !!}
@ -41,5 +42,6 @@
@endif @endif
</div> </div>
</div> </div>
</div>
@stop @stop

View File

@ -9,10 +9,12 @@
@section('content') @section('content')
<div class="text-center"> <div class="text-center">
<div class="center-box"> <div class="card center-box">
<h2>{{ trans('auth.register_thanks') }}</h2> <h3><i class="zmdi zmdi-accounts"></i> {{ trans('auth.register_thanks') }}</h3>
<div class="body">
<p>{{ trans('auth.register_confirm', ['appName' => setting('app-name')]) }}</p> <p>{{ trans('auth.register_confirm', ['appName' => setting('app-name')]) }}</p>
</div> </div>
</div> </div>
</div>
@stop @stop

View File

@ -7,9 +7,9 @@
@section('content') @section('content')
<div class="text-center"> <div class="text-center">
<div class="center-box"> <div class="card center-box">
<h1>{{ title_case(trans('auth.sign_up')) }}</h1> <h3><i class="zmdi zmdi-account-add"></i> {{ title_case(trans('auth.sign_up')) }}</h3>
<div class="body">
<form action="{{ baseUrl("/register") }}" method="POST"> <form action="{{ baseUrl("/register") }}" method="POST">
{!! csrf_field() !!} {!! csrf_field() !!}
@ -44,6 +44,7 @@
@endif @endif
</div> </div>
</div> </div>
</div>
@stop @stop

View File

@ -2,9 +2,11 @@
@section('content') @section('content')
<div class="row"> <div class="container small">
<div class="col-md-6 col-md-offset-3"> <p>&nbsp;</p>
<h2>{{ trans('auth.email_not_confirmed') }}</h2> <div class="card">
<h3><i class="zmdi zmdi-accounts"></i> {{ trans('auth.email_not_confirmed') }}</h3>
<div class="body">
<p class="text-muted">{{ trans('auth.email_not_confirmed_text') }}<br> <p class="text-muted">{{ trans('auth.email_not_confirmed_text') }}<br>
{{ trans('auth.email_not_confirmed_click_link') }} <br> {{ trans('auth.email_not_confirmed_click_link') }} <br>
{{ trans('auth.email_not_confirmed_resend') }} {{ trans('auth.email_not_confirmed_resend') }}
@ -27,4 +29,6 @@
</div> </div>
</div> </div>
</div>
@stop @stop

View File

@ -34,7 +34,7 @@
@include('partials/notifications') @include('partials/notifications')
<header id="header"> <header id="header">
<div class="container"> <div class="container fluid">
<div class="row"> <div class="row">
<div class="col-sm-4" ng-non-bindable> <div class="col-sm-4" ng-non-bindable>
<a href="{{ baseUrl('/') }}" class="logo"> <a href="{{ baseUrl('/') }}" class="logo">

View File

@ -1,12 +1,27 @@
@extends('base') @extends('simple-layout')
@section('content') @section('toolbar')
<div class="col-sm-8 faded">
<div class="breadcrumbs">
<a href="{{ baseUrl('/books') }}" class="text-button"><i class="zmdi zmdi-book"></i>{{ trans('entities.books') }}</a>
<span class="sep">&raquo;</span>
<a href="{{ baseUrl('/books/create') }}" class="text-button"><i class="zmdi zmdi-plus"></i>{{ trans('entities.books_create') }}</a>
</div>
</div>
@stop
<div class="container small" ng-non-bindable> @section('body')
<h1>{{ trans('entities.books_create') }}</h1>
<div ng-non-bindable class="container small">
<p>&nbsp;</p>
<div class="card">
<h3><i class="zmdi zmdi-plus"></i> {{ trans('entities.books_create') }}</h3>
<div class="body">
<form action="{{ baseUrl("/books") }}" method="POST" enctype="multipart/form-data"> <form action="{{ baseUrl("/books") }}" method="POST" enctype="multipart/form-data">
@include('books/form') @include('books/form')
</form> </form>
</div>
</div>
</div> </div>
<p class="margin-top large"><br></p> <p class="margin-top large"><br></p>
@include('components.image-manager', ['imageType' => 'cover']) @include('components.image-manager', ['imageType' => 'cover'])

View File

@ -1,28 +1,30 @@
@extends('base') @extends('simple-layout')
@section('content') @section('toolbar')
<div class="faded-small toolbar">
<div class="container">
<div class="row">
<div class="col-sm-12 faded"> <div class="col-sm-12 faded">
@include('books._breadcrumbs', ['book' => $book]) @include('books._breadcrumbs', ['book' => $book])
</div> </div>
</div> @stop
</div>
</div> @section('body')
<div class="container small" ng-non-bindable> <div class="container small" ng-non-bindable>
<h1>{{ trans('entities.books_delete') }}</h1> <p>&nbsp;</p>
<div class="card">
<h3><i class="zmdi zmdi-delete"></i> {{ trans('entities.books_delete') }}</h3>
<div class="body">
<p>{{ trans('entities.books_delete_explain', ['bookName' => $book->name]) }}</p> <p>{{ trans('entities.books_delete_explain', ['bookName' => $book->name]) }}</p>
<p class="text-neg">{{ trans('entities.books_delete_confirmation') }}</p> <p class="text-neg">{{ trans('entities.books_delete_confirmation') }}</p>
<form action="{{$book->getUrl()}}" method="POST"> <form action="{{$book->getUrl()}}" method="POST">
{!! csrf_field() !!} {!! csrf_field() !!}
<input type="hidden" name="_method" value="DELETE"> <input type="hidden" name="_method" value="DELETE">
<a href="{{$book->getUrl()}}" class="button">{{ trans('common.cancel') }}</a> <a href="{{$book->getUrl()}}" class="button outline">{{ trans('common.cancel') }}</a>
<button type="submit" class="button neg">{{ trans('common.confirm') }}</button> <button type="submit" class="button neg">{{ trans('common.confirm') }}</button>
</form> </form>
</div> </div>
</div>
</div>
@stop @stop

View File

@ -1,23 +1,24 @@
@extends('base') @extends('simple-layout')
@section('content') @section('toolbar')
<div class="faded-small toolbar">
<div class="container">
<div class="row">
<div class="col-sm-12 faded"> <div class="col-sm-12 faded">
@include('books._breadcrumbs', ['book' => $book]) @include('books._breadcrumbs', ['book' => $book])
</div> </div>
</div> @stop
</div>
</div> @section('body')
<div class="container small" ng-non-bindable> <div class="container small" ng-non-bindable>
<h1>{{ trans('entities.books_edit') }}</h1> <p>&nbsp;</p>
<div class="card">
<h3><i class="zmdi zmdi-edit"></i> {{ trans('entities.books_edit') }}</h3>
<div class="body">
<form action="{{ $book->getUrl() }}" method="POST"> <form action="{{ $book->getUrl() }}" method="POST">
<input type="hidden" name="_method" value="PUT"> <input type="hidden" name="_method" value="PUT">
@include('books/form', ['model' => $book]) @include('books/form', ['model' => $book])
</form> </form>
</div> </div>
</div>
</div>
@include('components.image-manager', ['imageType' => 'cover']) @include('components.image-manager', ['imageType' => 'cover'])
@stop @stop

View File

@ -24,7 +24,8 @@
'imageClass' => 'cover' 'imageClass' => 'cover'
]) ])
</div> </div>
<div class="form-group">
<a href="{{ isset($book) ? $book->getUrl() : baseUrl('/books') }}" class="button muted">{{ trans('common.cancel') }}</a> <div class="form-group text-right">
<a href="{{ isset($book) ? $book->getUrl() : baseUrl('/books') }}" class="button outline">{{ trans('common.cancel') }}</a>
<button type="submit" class="button pos">{{ trans('entities.books_save') }}</button> <button type="submit" class="button pos">{{ trans('entities.books_save') }}</button>
</div> </div>

View File

@ -1,43 +1,53 @@
@extends('base') @extends('sidebar-layout')
@section('content') @section('toolbar')
<div class="col-xs-1"></div>
<div class="faded-small toolbar"> <div class="col-xs-11 faded">
<div class="container"> <div class="action-buttons">
<div class="row">
<div class="col-xs-12 faded">
<div class="action-buttons text-left">
<a data-action="expand-thumbnail" class="text-primary text-button"><i class="zmdi zmdi-wrap-text"></i>{{ trans('common.toggle_thumbnails') }}</a>
@if($currentUser->can('book-create-all')) @if($currentUser->can('book-create-all'))
<a href="{{ baseUrl("/books/create") }}" class="text-pos text-button"><i class="zmdi zmdi-plus"></i>{{ trans('entities.books_create') }}</a> <a href="{{ baseUrl("/books/create") }}" class="text-pos text-button"><i class="zmdi zmdi-plus"></i>{{ trans('entities.books_create') }}</a>
@endif @endif
</div> </div>
</div> </div>
@stop
@section('sidebar')
@if($recents)
<div id="recents" class="card">
<h3><i class="zmdi zmdi-eye"></i> {{ trans('entities.recently_viewed') }}</h3>
@include('partials/entity-list', ['entities' => $recents, 'style' => 'compact'])
</div> </div>
</div> @endif
<div id="popular" class="card">
<h3><i class="zmdi zmdi-fire"></i> {{ trans('entities.books_popular') }}</h3>
@if(count($popular) > 0)
@include('partials/entity-list', ['entities' => $popular, 'style' => 'compact'])
@else
<div class="body text-muted">{{ trans('entities.books_popular_empty') }}</div>
@endif
</div> </div>
<div id="new" class="card">
<h3><i class="zmdi zmdi-star-circle"></i> {{ trans('entities.books_new') }}</h3>
@if(count($popular) > 0)
@include('partials/entity-list', ['entities' => $new, 'style' => 'compact'])
@else
<div class="body text-muted">{{ trans('entities.books_new_empty') }}</div>
@endif
</div>
@stop
<div class="container" ng-non-bindable> @section('body')
<div class="row">
<div class="col-xs-12 col-sm-12 col-md-9"> <div class="container small" ng-non-bindable>
<h1>{{ trans('entities.books') }}</h1> <h1>{{ trans('entities.books') }}</h1>
@if(count($books) > 0) @if(count($books) > 0)
@if($books_display=='grid')
<div class="row">
@foreach($books as $book)
@include('books/grid-item', ['book' => $book])
@endforeach
<div class="col-xs-12">
{!! $books->render() !!}
</div>
</div>
@else
@foreach($books as $book) @foreach($books as $book)
@include('books/list-item', ['book' => $book]) @include('books/list-item', ['book' => $book])
<hr>
@endforeach @endforeach
{!! $books->render() !!} {!! $books->render() !!}
@endif
@else @else
<p class="text-muted">{{ trans('entities.books_empty') }}</p> <p class="text-muted">{{ trans('entities.books_empty') }}</p>
@if(userCan('books-create-all')) @if(userCan('books-create-all'))
@ -45,25 +55,5 @@
@endif @endif
@endif @endif
</div> </div>
<div class="col-xs-12 col-sm-12 col-md-3">
<div id="recents">
@if($recents)
<div class="margin-top">&nbsp;</div>
<h3>{{ trans('entities.recently_viewed') }}</h3>
@include('partials/entity-list', ['entities' => $recents])
@endif
</div>
<div class="margin-top large">&nbsp;</div>
<div id="popular">
<h3>{{ trans('entities.books_popular') }}</h3>
@if(count($popular) > 0)
@include('partials/entity-list', ['entities' => $popular])
@else
<p class="text-muted">{{ trans('entities.books_popular_empty') }}</p>
@endif
</div>
</div>
</div>
</div>
@stop @stop

View File

@ -1,21 +1,21 @@
@extends('base') @extends('simple-layout')
@section('content') @section('toolbar')
<div class="faded-small toolbar">
<div class="container">
<div class="row">
<div class="col-sm-12 faded"> <div class="col-sm-12 faded">
@include('books._breadcrumbs', ['book' => $book]) @include('books._breadcrumbs', ['book' => $book])
</div> </div>
</div> @stop
</div>
</div>
@section('body')
<div class="container" ng-non-bindable> <div class="container" ng-non-bindable>
<h1>{{ trans('entities.books_permissions') }}</h1> <p>&nbsp;</p>
<div class="card">
<h3><i class="zmdi zmdi-lock-outline"></i> {{ trans('entities.books_permissions') }}</h3>
<div class="body">
@include('form/restriction-form', ['model' => $book]) @include('form/restriction-form', ['model' => $book])
</div> </div>
</div>
</div>
@stop @stop

View File

@ -1,10 +1,6 @@
@extends('base') @extends('sidebar-layout')
@section('content') @section('toolbar')
<div class="faded-small toolbar">
<div class="container">
<div class="row">
<div class="col-sm-6 col-xs-1 faded"> <div class="col-sm-6 col-xs-1 faded">
@include('books._breadcrumbs', ['book' => $book]) @include('books._breadcrumbs', ['book' => $book])
</div> </div>
@ -24,14 +20,12 @@
@if(userCan('chapter-create', $book)) @if(userCan('chapter-create', $book))
<a href="{{ $book->getUrl('/chapter/create') }}" class="text-pos text-button"><i class="zmdi zmdi-plus"></i>{{ trans('entities.chapters_new') }}</a> <a href="{{ $book->getUrl('/chapter/create') }}" class="text-pos text-button"><i class="zmdi zmdi-plus"></i>{{ trans('entities.chapters_new') }}</a>
@endif @endif
@if(userCan('book-update', $book))
<a href="{{$book->getEditUrl()}}" class="text-primary text-button"><i class="zmdi zmdi-edit"></i>{{ trans('common.edit') }}</a>
@endif
@if(userCan('book-update', $book) || userCan('restrictions-manage', $book) || userCan('book-delete', $book)) @if(userCan('book-update', $book) || userCan('restrictions-manage', $book) || userCan('book-delete', $book))
<div dropdown class="dropdown-container"> <div dropdown class="dropdown-container">
<a dropdown-toggle class="text-primary text-button"><i class="zmdi zmdi-more-vert"></i></a> <a dropdown-toggle class="text-primary text-button"><i class="zmdi zmdi-more-vert"></i>{{ trans('common.more') }}</a>
<ul> <ul>
@if(userCan('book-update', $book)) @if(userCan('book-update', $book))
<li><a href="{{$book->getEditUrl()}}" class="text-primary"><i class="zmdi zmdi-edit"></i>{{ trans('common.edit') }}</a></li>
<li><a href="{{ $book->getUrl('/sort') }}" class="text-primary"><i class="zmdi zmdi-sort"></i>{{ trans('common.sort') }}</a></li> <li><a href="{{ $book->getUrl('/sort') }}" class="text-primary"><i class="zmdi zmdi-sort"></i>{{ trans('common.sort') }}</a></li>
@endif @endif
@if(userCan('restrictions-manage', $book)) @if(userCan('restrictions-manage', $book))
@ -45,22 +39,65 @@
@endif @endif
</div> </div>
</div> </div>
</div> @stop
@section('sidebar')
<div class="card">
<div class="body">
<form v-on:submit.prevent="searchBook" class="search-box">
<input v-model="searchTerm" v-on:change="checkSearchForm()" type="text" name="term" placeholder="{{ trans('entities.books_search_this') }}">
<button type="submit"><i class="zmdi zmdi-search"></i></button>
<button v-if="searching" v-cloak class="text-neg" v-on:click="clearSearch()" type="button"><i class="zmdi zmdi-close"></i></button>
</form>
</div> </div>
</div> </div>
@if($book->restricted)
<div class="card">
<h3><i class="zmdi zmdi-key"></i> {{ trans('entities.permissions') }}</h3>
<div class="body">
<p class="text-muted">
@if(userCan('restrictions-manage', $book))
<a href="{{ $book->getUrl('/permissions') }}"><i class="zmdi zmdi-lock-outline"></i>{{ trans('entities.books_permissions_active') }}</a>
@else
<i class="zmdi zmdi-lock-outline"></i>{{ trans('entities.books_permissions_active') }}
@endif
</p>
</div>
</div>
@endif
<div ng-non-bindable class="container" id="entity-dashboard" entity-id="{{ $book->id }}" entity-type="book"> @if(count($activity) > 0)
<div class="row"> <div class="activity card">
<div class="col-md-7"> <h3><i class="zmdi zmdi-time"></i> {{ trans('entities.recent_activity') }}</h3>
@include('partials/activity-list', ['activity' => $activity])
</div>
@endif
<div class="card">
<h3><i class="zmdi zmdi-info-outline"></i> {{ trans('common.details') }}</h3>
<div class="body">
@include('partials.entity-meta', ['entity' => $book])
</div>
</div>
@stop
@section('container-attrs')
id="entity-dashboard"
entity-id="{{ $book->id }}"
entity-type="book"
@stop
@section('body')
<div ng-non-bindable class="container small">
<h1>{{$book->name}}</h1> <h1>{{$book->name}}</h1>
<div class="book-content" v-show="!searching"> <div class="book-content" v-show="!searching">
<p class="text-muted" v-pre>{!! nl2br(e($book->description)) !!}</p> <p class="text-muted" v-pre>{!! nl2br(e($book->description)) !!}</p>
@if(count($bookChildren) > 0)
<div class="page-list" v-pre> <div class="page-list" v-pre>
<hr> <hr>
@if(count($bookChildren) > 0)
@foreach($bookChildren as $childElement) @foreach($bookChildren as $childElement)
@if($childElement->isA('chapter')) @if($childElement->isA('chapter'))
@include('chapters/list-item', ['chapter' => $childElement]) @include('chapters/list-item', ['chapter' => $childElement])
@ -69,23 +106,22 @@
@endif @endif
<hr> <hr>
@endforeach @endforeach
</div>
@else @else
<p class="text-muted">{{ trans('entities.books_empty_contents') }}</p> <div class="well">
<p> <p class="text-muted italic">{{ trans('entities.books_empty_contents') }}</p>
@if(userCan('page-create', $book)) @if(userCan('page-create', $book))
<a href="{{ $book->getUrl('/page/create') }}" class="text-page"><i class="zmdi zmdi-file-text"></i>{{ trans('entities.books_empty_create_page') }}</a> <a href="{{ $book->getUrl('/page/create') }}" class="button outline page"><i class="zmdi zmdi-file-text"></i>{{ trans('entities.books_empty_create_page') }}</a>
@endif @endif
@if(userCan('page-create', $book) && userCan('chapter-create', $book)) @if(userCan('page-create', $book) && userCan('chapter-create', $book))
&nbsp;&nbsp;<em class="text-muted">-{{ trans('entities.books_empty_or') }}-</em>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;<em class="text-muted">-{{ trans('entities.books_empty_or') }}-</em>&nbsp;&nbsp;&nbsp;
@endif @endif
@if(userCan('chapter-create', $book)) @if(userCan('chapter-create', $book))
<a href="{{ $book->getUrl('/chapter/create') }}" class="text-chapter"><i class="zmdi zmdi-collection-bookmark"></i>{{ trans('entities.books_empty_add_chapter') }}</a> <a href="{{ $book->getUrl('/chapter/create') }}" class="button outline chapter"><i class="zmdi zmdi-collection-bookmark"></i>{{ trans('entities.books_empty_add_chapter') }}</a>
@endif @endif
</p>
<hr>
@endif
@include('partials.entity-meta', ['entity' => $book])
</div> </div>
@endif
</div> </div>
<div class="search-results" v-cloak v-show="searching"> <div class="search-results" v-cloak v-show="searching">
<h3 class="text-muted">{{ trans('entities.search_results') }} <a v-if="searching" v-on:click="clearSearch()" class="text-small"><i class="zmdi zmdi-close"></i>{{ trans('entities.search_clear') }}</a></h3> <h3 class="text-muted">{{ trans('entities.search_results') }} <a v-if="searching" v-on:click="clearSearch()" class="text-small"><i class="zmdi zmdi-close"></i>{{ trans('entities.search_clear') }}</a></h3>
@ -94,35 +130,6 @@
</div> </div>
<div v-html="searchResults"></div> <div v-html="searchResults"></div>
</div> </div>
</div>
<div class="col-md-4 col-md-offset-1">
<div class="margin-top large"></div>
@if($book->restricted)
<p class="text-muted">
@if(userCan('restrictions-manage', $book))
<a href="{{ $book->getUrl('/permissions') }}"><i class="zmdi zmdi-lock-outline"></i>{{ trans('entities.books_permissions_active') }}</a>
@else
<i class="zmdi zmdi-lock-outline"></i>{{ trans('entities.books_permissions_active') }}
@endif
</p>
@endif
<form v-on:submit.prevent="searchBook" class="search-box">
<input v-model="searchTerm" v-on:change="checkSearchForm()" type="text" name="term" placeholder="{{ trans('entities.books_search_this') }}">
<button type="submit"><i class="zmdi zmdi-search"></i></button>
<button v-if="searching" v-cloak class="text-neg" v-on:click="clearSearch()" type="button"><i class="zmdi zmdi-close"></i></button>
</form>
<div class="activity">
<h3>{{ trans('entities.recent_activity') }}</h3>
@include('partials/activity-list', ['activity' => Activity::entityActivity($book, 20, 0)])
</div>
</div>
</div>
</div> </div>
@stop @stop

View File

@ -1,34 +1,45 @@
@extends('base') @extends('simple-layout')
@section('head') @section('head')
<script src="{{ baseUrl("/libs/jquery-sortable/jquery-sortable.min.js") }}"></script> <script src="{{ baseUrl("/libs/jquery-sortable/jquery-sortable.min.js") }}"></script>
@stop @stop
@section('content') @section('toolbar')
<div class="faded-small toolbar">
<div class="container">
<div class="row">
<div class="col-sm-12 faded"> <div class="col-sm-12 faded">
@include('books._breadcrumbs', ['book' => $book]) @include('books._breadcrumbs', ['book' => $book])
</div> </div>
</div> @stop
</div>
</div> @section('body')
<div class="container" ng-non-bindable> <div class="container" ng-non-bindable>
<h1>{{ trans('entities.books_sort') }}</h1>
<div class="row"> <div class="row">
<div class="col-md-8" id="sort-boxes"> <div class="col-md-8">
<div class="card">
<h3><i class="zmdi zmdi-sort"></i> {{ trans('entities.books_sort') }}</h3>
<div class="body">
<div id="sort-boxes">
@include('books/sort-box', ['book' => $book, 'bookChildren' => $bookChildren]) @include('books/sort-box', ['book' => $book, 'bookChildren' => $bookChildren])
</div> </div>
<form action="{{ $book->getUrl('/sort') }}" method="POST">
{!! csrf_field() !!}
<input type="hidden" name="_method" value="PUT">
<input type="hidden" id="sort-tree-input" name="sort-tree">
<div class="list">
<a href="{{ $book->getUrl() }}" class="button outline">{{ trans('common.cancel') }}</a>
<button class="button pos" type="submit">{{ trans('entities.books_sort_save') }}</button>
</div>
</form>
</div>
</div>
</div>
@if(count($books) > 1) @if(count($books) > 1)
<div class="col-md-4"> <div class="col-md-4">
<h3>{{ trans('entities.books_sort_show_other') }}</h3> <div class="card">
<div id="additional-books"> <h3><i class="zmdi zmdi-book"></i> {{ trans('entities.books_sort_show_other') }}</h3>
<div class="body" id="additional-books">
@foreach($books as $otherBook) @foreach($books as $otherBook)
@if($otherBook->id !== $book->id) @if($otherBook->id !== $book->id)
<div> <div>
@ -38,19 +49,11 @@
@endforeach @endforeach
</div> </div>
</div> </div>
</div>
@endif @endif
</div> </div>
<form action="{{ $book->getUrl('/sort') }}" method="POST">
{!! csrf_field() !!}
<input type="hidden" name="_method" value="PUT">
<input type="hidden" id="sort-tree-input" name="sort-tree">
<div class="list">
<a href="{{ $book->getUrl() }}" class="button muted">{{ trans('common.cancel') }}</a>
<button class="button pos" type="submit">{{ trans('entities.books_sort_save') }}</button>
</div>
</form>
</div> </div>

View File

@ -1,12 +1,26 @@
@extends('base') @extends('simple-layout')
@section('content') @section('toolbar')
<div class="col-sm-12 faded">
<div class="breadcrumbs">
<a href="{{$book->getUrl()}}" class="text-book text-button"><i class="zmdi zmdi-book"></i>{{ $book->getShortName() }}</a>
<span class="sep">&raquo;</span>
<a href="{{ baseUrl('/books/chapter/create') }}" class="text-button"><i class="zmdi zmdi-plus"></i>{{ trans('entities.chapters_create') }}</a>
</div>
</div>
@stop
@section('body')
<div class="container small" ng-non-bindable> <div class="container small" ng-non-bindable>
<h1>{{ trans('entities.chapters_create') }}</h1> <div class="card">
<h3><i class="zmdi zmdi-plus"></i> {{ trans('entities.chapters_create') }}</h3>
<div class="body">
<form action="{{ $book->getUrl('/chapter/create') }}" method="POST"> <form action="{{ $book->getUrl('/chapter/create') }}" method="POST">
@include('chapters/form') @include('chapters/form')
</form> </form>
</div> </div>
</div>
</div>
@stop @stop

View File

@ -1,28 +1,30 @@
@extends('base') @extends('simple-layout')
@section('content') @section('toolbar')
<div class="faded-small toolbar">
<div class="container">
<div class="row">
<div class="col-sm-12 faded"> <div class="col-sm-12 faded">
@include('chapters._breadcrumbs', ['chapter' => $chapter]) @include('chapters._breadcrumbs', ['chapter' => $chapter])
</div> </div>
</div> @stop
</div>
</div> @section('body')
<div class="container small" ng-non-bindable> <div class="container small" ng-non-bindable>
<h1>{{ trans('entities.chapters_delete') }}</h1> <p>&nbsp;</p>
<div class="card">
<h3><i class="zmdi zmdi-delete"></i> {{ trans('entities.chapters_delete') }}</h3>
<div class="body">
<p>{{ trans('entities.chapters_delete_explain', ['chapterName' => $chapter->name]) }}</p> <p>{{ trans('entities.chapters_delete_explain', ['chapterName' => $chapter->name]) }}</p>
<p class="text-neg">{{ trans('entities.chapters_delete_confirm') }}</p> <p class="text-neg">{{ trans('entities.chapters_delete_confirm') }}</p>
<form action="{{ $chapter->getUrl() }}" method="POST"> <form action="{{ $chapter->getUrl() }}" method="POST">
{!! csrf_field() !!} {!! csrf_field() !!}
<input type="hidden" name="_method" value="DELETE"> <input type="hidden" name="_method" value="DELETE">
<a href="{{ $chapter->getUrl() }}" class="button primary">{{ trans('common.cancel') }}</a> <a href="{{ $chapter->getUrl() }}" class="button outline">{{ trans('common.cancel') }}</a>
<button type="submit" class="button neg">{{ trans('common.confirm') }}</button> <button type="submit" class="button neg">{{ trans('common.confirm') }}</button>
</form> </form>
</div> </div>
</div>
</div>
@stop @stop

View File

@ -1,13 +1,24 @@
@extends('base') @extends('simple-layout')
@section('content') @section('toolbar')
<div class="col-sm-12 faded">
@include('chapters._breadcrumbs', ['chapter' => $chapter])
</div>
@stop
@section('body')
<div class="container small" ng-non-bindable> <div class="container small" ng-non-bindable>
<h1>{{ trans('entities.chapters_edit') }}</h1> <p>&nbsp;</p>
<div class="card">
<h3><i class="zmdi zmdi-edit"></i> {{ trans('entities.chapters_edit') }}</h3>
<div class="body">
<form action="{{ $chapter->getUrl() }}" method="POST"> <form action="{{ $chapter->getUrl() }}" method="POST">
<input type="hidden" name="_method" value="PUT"> <input type="hidden" name="_method" value="PUT">
@include('chapters/form', ['model' => $chapter]) @include('chapters/form', ['model' => $chapter])
</form> </form>
</div> </div>
</div>
</div>
@stop @stop

View File

@ -11,7 +11,7 @@
@include('form/textarea', ['name' => 'description']) @include('form/textarea', ['name' => 'description'])
</div> </div>
<div class="form-group"> <div class="form-group text-right">
<a href="{{ back()->getTargetUrl() }}" class="button muted">{{ trans('common.cancel') }}</a> <a href="{{ back()->getTargetUrl() }}" class="button outline">{{ trans('common.cancel') }}</a>
<button type="submit" class="button pos">{{ trans('entities.chapters_save') }}</button> <button type="submit" class="button pos">{{ trans('entities.chapters_save') }}</button>
</div> </div>

View File

@ -1,29 +1,34 @@
@extends('base') @extends('simple-layout')
@section('content') @section('toolbar')
<div class="faded-small toolbar">
<div class="container">
<div class="row">
<div class="col-sm-12 faded"> <div class="col-sm-12 faded">
@include('chapters._breadcrumbs', ['chapter' => $chapter]) @include('chapters._breadcrumbs', ['chapter' => $chapter])
</div> </div>
</div> @stop
</div>
</div> @section('body')
<div class="container"> <div class="container">
<h1>{{ trans('entities.chapters_move') }}</h1>
<div class="card">
<h3><i class="zmdi zmdi-folder"></i> {{ trans('entities.chapters_move') }}</h3>
<div class="body">
<form action="{{ $chapter->getUrl('/move') }}" method="POST"> <form action="{{ $chapter->getUrl('/move') }}" method="POST">
{!! csrf_field() !!} {!! csrf_field() !!}
<input type="hidden" name="_method" value="PUT"> <input type="hidden" name="_method" value="PUT">
@include('components.entity-selector', ['name' => 'entity_selection', 'selectorSize' => 'large', 'entityTypes' => 'book']) @include('components.entity-selector', ['name' => 'entity_selection', 'selectorSize' => 'large', 'entityTypes' => 'book'])
<a href="{{ $chapter->getUrl() }}" class="button muted">{{ trans('common.cancel') }}</a> <div class="form-group text-right">
<a href="{{ $chapter->getUrl() }}" class="button outline">{{ trans('common.cancel') }}</a>
<button type="submit" class="button pos">{{ trans('entities.chapters_move') }}</button> <button type="submit" class="button pos">{{ trans('entities.chapters_move') }}</button>
</div>
</form> </form>
</div>
</div>
</div> </div>
@stop @stop

View File

@ -1,20 +1,21 @@
@extends('base') @extends('simple-layout')
@section('content') @section('toolbar')
<div class="faded-small toolbar">
<div class="container">
<div class="row">
<div class="col-sm-12 faded"> <div class="col-sm-12 faded">
@include('chapters._breadcrumbs', ['chapter' => $chapter]) @include('chapters._breadcrumbs', ['chapter' => $chapter])
</div> </div>
</div> @stop
</div>
</div> @section('body')
<div class="container" ng-non-bindable> <div class="container" ng-non-bindable>
<h1>{{ trans('entities.chapters_permissions') }}</h1> <p>&nbsp;</p>
<div class="card">
<h3><i class="zmdi zmdi-lock-outline"></i> {{ trans('entities.chapters_permissions') }}</h3>
<div class="body">
@include('form/restriction-form', ['model' => $chapter]) @include('form/restriction-form', ['model' => $chapter])
</div> </div>
</div>
</div>
@stop @stop

View File

@ -1,10 +1,6 @@
@extends('base') @extends('sidebar-layout')
@section('content') @section('toolbar')
<div class="faded-small toolbar">
<div class="container">
<div class="row">
<div class="col-sm-6 col-xs-3 faded" ng-non-bindable> <div class="col-sm-6 col-xs-3 faded" ng-non-bindable>
@include('chapters._breadcrumbs', ['chapter' => $chapter]) @include('chapters._breadcrumbs', ['chapter' => $chapter])
</div> </div>
@ -26,7 +22,7 @@
@endif @endif
@if(userCan('chapter-update', $chapter) || userCan('restrictions-manage', $chapter) || userCan('chapter-delete', $chapter)) @if(userCan('chapter-update', $chapter) || userCan('restrictions-manage', $chapter) || userCan('chapter-delete', $chapter))
<div dropdown class="dropdown-container"> <div dropdown class="dropdown-container">
<a dropdown-toggle class="text-primary text-button"><i class="zmdi zmdi-more-vert"></i></a> <a dropdown-toggle class="text-primary text-button"><i class="zmdi zmdi-more-vert"></i> {{ trans('common.more') }}</a>
<ul> <ul>
@if(userCan('chapter-update', $chapter)) @if(userCan('chapter-update', $chapter))
<li><a href="{{ $chapter->getUrl('/move') }}" class="text-primary"><i class="zmdi zmdi-folder"></i>{{ trans('common.move') }}</a></li> <li><a href="{{ $chapter->getUrl('/move') }}" class="text-primary"><i class="zmdi zmdi-folder"></i>{{ trans('common.move') }}</a></li>
@ -42,14 +38,65 @@
@endif @endif
</div> </div>
</div> </div>
</div> @stop
@section('container-attrs')
id="entity-dashboard"
entity-id="{{ $chapter->id }}"
entity-type="chapter"
@stop
@section('sidebar')
<div class="card">
<div class="body">
<form @submit.prevent="searchBook" class="search-box">
<input v-model="searchTerm" @change="checkSearchForm()" type="text" name="term" placeholder="{{ trans('entities.chapters_search_this') }}">
<button type="submit"><i class="zmdi zmdi-search"></i></button>
<button v-if="searching" v-cloak class="text-neg" @click="clearSearch()" type="button"><i class="zmdi zmdi-close"></i></button>
</form>
</div> </div>
</div> </div>
@if($book->restricted || $chapter->restricted)
<div class="card">
<h3><i class="zmdi zmdi-key"></i> {{ trans('entities.permissions') }}</h3>
<div class="body">
@if($book->restricted)
<p class="text-muted">
@if(userCan('restrictions-manage', $book))
<a href="{{ $book->getUrl('/permissions') }}"><i class="zmdi zmdi-lock-outline"></i>{{ trans('entities.books_permissions_active') }}</a>
@else
<i class="zmdi zmdi-lock-outline"></i>{{ trans('entities.books_permissions_active') }}
@endif
</p>
@endif
<div class="container" id="entity-dashboard" ng-non-bindable entity-id="{{ $chapter->id }}" entity-type="chapter"> @if($chapter->restricted)
<div class="row"> <p class="text-muted">
<div class="col-md-7"> @if(userCan('restrictions-manage', $chapter))
<a href="{{ $chapter->getUrl('/permissions') }}"><i class="zmdi zmdi-lock-outline"></i>{{ trans('entities.chapters_permissions_active') }}</a>
@else
<i class="zmdi zmdi-lock-outline"></i>{{ trans('entities.chapters_permissions_active') }}
@endif
</p>
@endif
</div>
</div>
@endif
<div class="card">
<h3><i class="zmdi zmdi-info-outline"></i> {{ trans('common.details') }}</h3>
<div class="body">
@include('partials.entity-meta', ['entity' => $chapter])
</div>
</div>
@include('partials/book-tree', ['book' => $book, 'sidebarTree' => $sidebarTree])
@stop
@section('body')
<div class="container small" ng-non-bindable >
<h1>{{ $chapter->name }}</h1> <h1>{{ $chapter->name }}</h1>
<div class="chapter-content" v-show="!searching"> <div class="chapter-content" v-show="!searching">
<p class="text-muted">{!! nl2br(e($chapter->description)) !!}</p> <p class="text-muted">{!! nl2br(e($chapter->description)) !!}</p>
@ -63,71 +110,30 @@
@endforeach @endforeach
</div> </div>
@else @else
<hr> <div class="well">
<p class="text-muted">{{ trans('entities.chapters_empty') }}</p> <p class="text-muted italic">{{ trans('entities.chapters_empty') }}</p>
<p> <p>
@if(userCan('page-create', $chapter)) @if(userCan('page-create', $chapter))
<a href="{{ $chapter->getUrl('/create-page') }}" class="text-page"><i class="zmdi zmdi-file-text"></i>{{ trans('entities.books_empty_create_page') }}</a> <a href="{{ $chapter->getUrl('/create-page') }}" class="button outline page"><i class="zmdi zmdi-file-text"></i>{{ trans('entities.books_empty_create_page') }}</a>
@endif @endif
@if(userCan('page-create', $chapter) && userCan('book-update', $book)) @if(userCan('page-create', $chapter) && userCan('book-update', $book))
&nbsp;&nbsp;<em class="text-muted">-{{ trans('entities.books_empty_or') }}-</em>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;<em class="text-muted">-{{ trans('entities.books_empty_or') }}-</em>&nbsp;&nbsp; &nbsp;
@endif @endif
@if(userCan('book-update', $book)) @if(userCan('book-update', $book))
<a href="{{ $book->getUrl('/sort') }}" class="text-book"><i class="zmdi zmdi-book"></i>{{ trans('entities.books_empty_sort_current_book') }}</a> <a href="{{ $book->getUrl('/sort') }}" class="button outline book"><i class="zmdi zmdi-book"></i>{{ trans('entities.books_empty_sort_current_book') }}</a>
@endif @endif
</p> </p>
<hr> </div>
@endif @endif
@include('partials.entity-meta', ['entity' => $chapter])
</div> </div>
<div class="search-results" v-cloak v-show="searching"> <div class="search-results" v-cloak v-show="searching">
<h3 class="text-muted">{{ trans('entities.search_results') }} <a v-if="searching" v-on:click="clearSearch()" class="text-small"><i class="zmdi zmdi-close"></i>{{ trans('entities.search_clear') }}</a></h3> <h3 class="text-muted">{{ trans('entities.search_results') }} <a v-if="searching" @click="clearSearch()" class="text-small"><i class="zmdi zmdi-close"></i>{{ trans('entities.search_clear') }}</a></h3>
<div v-if="!searchResults"> <div v-if="!searchResults">
@include('partials/loading-icon') @include('partials/loading-icon')
</div> </div>
<div v-html="searchResults"></div> <div v-html="searchResults"></div>
</div> </div>
</div> </div>
<div class="col-md-4 col-md-offset-1">
<div class="margin-top large"></div>
@if($book->restricted || $chapter->restricted)
<div class="text-muted">
@if($book->restricted)
<p class="text-muted">
@if(userCan('restrictions-manage', $book))
<a href="{{ $book->getUrl('/permissions') }}"><i class="zmdi zmdi-lock-outline"></i>{{ trans('entities.books_permissions_active') }}</a>
@else
<i class="zmdi zmdi-lock-outline"></i>{{ trans('entities.books_permissions_active') }}
@endif
</p>
@endif
@if($chapter->restricted)
@if(userCan('restrictions-manage', $chapter))
<a href="{{ $chapter->getUrl('/permissions') }}"><i class="zmdi zmdi-lock-outline"></i>{{ trans('entities.chapters_permissions_active') }}</a>
@else
<i class="zmdi zmdi-lock-outline"></i>{{ trans('entities.chapters_permissions_active') }}
@endif
@endif
</div>
@endif
<form v-on:submit.prevent="searchBook" class="search-box">
<input v-model="searchTerm" v-on:change="checkSearchForm()" type="text" name="term" placeholder="{{ trans('entities.chapters_search_this') }}">
<button type="submit"><i class="zmdi zmdi-search"></i></button>
<button v-if="searching" v-cloak class="text-neg" v-on:click="clearSearch()" type="button"><i class="zmdi zmdi-close"></i></button>
</form>
@include('pages/sidebar-tree-list', ['book' => $book, 'sidebarTree' => $sidebarTree])
</div>
</div>
</div>
@stop @stop

View File

@ -1,5 +1,5 @@
<div id="entity-selector-wrap"> <div id="entity-selector-wrap">
<div overlay entity-link-selector> <div overlay entity-selector-popup>
<div class="popup-body small flex-child"> <div class="popup-body small flex-child">
<div class="popup-header primary-background"> <div class="popup-header primary-background">
<div class="popup-title">{{ trans('entities.entity_select') }}</div> <div class="popup-title">{{ trans('entities.entity_select') }}</div>

View File

@ -1,8 +1,8 @@
<div class="form-group"> <div class="form-group">
<div entity-selector class="entity-selector {{$selectorSize or ''}}" entity-types="{{ $entityTypes or 'book,chapter,page' }}"> <div entity-selector class="entity-selector {{$selectorSize or ''}}" entity-types="{{ $entityTypes or 'book,chapter,page' }}">
<input type="hidden" entity-selector-input name="{{$name}}" value=""> <input type="hidden" entity-selector-input name="{{$name}}" value="">
<input type="text" placeholder="{{ trans('common.search') }}" ng-model="search" ng-model-options="{debounce: 200}" ng-change="searchEntities()"> <input type="text" placeholder="{{ trans('common.search') }}" entity-selector-search>
<div class="text-center loading" ng-show="loading">@include('partials.loading-icon')</div> <div class="text-center loading" entity-selector-loading>@include('partials.loading-icon')</div>
<div ng-show="!loading" ng-bind-html="entityResults"></div> <div entity-selector-results></div>
</div> </div>
</div> </div>

View File

@ -0,0 +1,13 @@
{{--Depends on entity selector popup--}}
<div page-picker>
<div class="input-base">
<span @if($value) style="display: none" @endif page-picker-default class="text-muted italic">{{ $placeholder }}</span>
<a @if(!$value) style="display: none" @endif href="{{ baseUrl('/link/' . $value) }}" target="_blank" class="text-page" page-picker-display>#{{$value}}, {{$value ? \BookStack\Page::find($value)->name : '' }}</a>
</div>
<br>
<input type="hidden" value="{{$value}}" name="{{$name}}" id="{{$name}}">
<button @if(!$value) style="display: none" @endif type="button" page-picker-reset class="text-button">{{ trans('common.reset') }}</button>
<span @if(!$value) style="display: none" @endif class="sep">|</span>
<button type="button" page-picker-select class="text-button">{{ trans('common.select') }}</button>
</div>

View File

@ -1,32 +1,42 @@
@extends('base') @extends('simple-layout')
@section('content') @section('content')
<div class="container"> <div class="container">
<p>&nbsp;</p>
<h1>{{ $message or trans('errors.404_page_not_found') }}</h1> <div class="card">
<p>{{ trans('errors.sorry_page_not_found') }}</p> <h3><i class="zmdi zmdi-alert-octagon"></i> {{ $message or trans('errors.404_page_not_found') }}</h3>
<p><a href="{{ baseUrl('/') }}" class="button">{{ trans('errors.return_home') }}</a></p> <div class="body">
<h5>{{ trans('errors.sorry_page_not_found') }}</h5>
<p><a href="{{ baseUrl('/') }}" class="button outline">{{ trans('errors.return_home') }}</a></p>
</div>
</div>
@if (setting('app-public') || !user()->isDefault()) @if (setting('app-public') || !user()->isDefault())
<hr>
<div class="row"> <div class="row">
<div class="col-md-4"> <div class="col-md-4">
<h3 class="text-muted">{{ trans('entities.pages_popular') }}</h3> <div class="card">
<h3 class="text-muted"><i class="zmdi zmdi-file-text"></i> {{ trans('entities.pages_popular') }}</h3>
@include('partials.entity-list', ['entities' => Views::getPopular(10, 0, [\BookStack\Page::class]), 'style' => 'compact']) @include('partials.entity-list', ['entities' => Views::getPopular(10, 0, [\BookStack\Page::class]), 'style' => 'compact'])
</div> </div>
<div class="col-md-4">
<h3 class="text-muted">{{ trans('entities.books_popular') }}</h3>
@include('partials.entity-list', ['entities' => Views::getPopular(10, 0, [\BookStack\Book::class]), 'style' => 'compact'])
</div> </div>
<div class="col-md-4"> <div class="col-md-4">
<h3 class="text-muted">{{ trans('entities.chapters_popular') }}</h3> <div class="card">
<h3 class="text-muted"><i class="zmdi zmdi-book"></i> {{ trans('entities.books_popular') }}</h3>
@include('partials.entity-list', ['entities' => Views::getPopular(10, 0, [\BookStack\Book::class]), 'style' => 'compact'])
</div>
</div>
<div class="col-md-4">
<div class="card">
<h3 class="text-muted"><i class="zmdi zmdi-collection-bookmark"></i> {{ trans('entities.chapters_popular') }}</h3>
@include('partials.entity-list', ['entities' => Views::getPopular(10, 0, [\BookStack\Chapter::class]), 'style' => 'compact']) @include('partials.entity-list', ['entities' => Views::getPopular(10, 0, [\BookStack\Chapter::class]), 'style' => 'compact'])
</div> </div>
</div> </div>
</div>
@endif @endif
</div> </div>

View File

@ -3,8 +3,13 @@
@section('content') @section('content')
<div class="container"> <div class="container">
<h1 class="text-muted">{{ trans('errors.error_occurred') }}</h1> <div class="card">
<p>{{ $message }}</p> <h3 class="text-muted">{{ trans('errors.error_occurred') }}</h3>
<div class="body">
<h5>{{ $message }}</h5>
<p><a href="{{ baseUrl('/') }}" class="button outline">{{ trans('errors.return_home') }}</a></p>
</div>
</div>
</div> </div>
@stop @stop

View File

@ -2,9 +2,13 @@
@section('content') @section('content')
<div class="container"> <div class="container small">
<h1 class="text-muted">{{ trans('errors.app_down', ['appName' => setting('app-name')]) }}</h1> <div class="card">
<div class="body">
<h4 class="text-muted"><i class="zmdi zmdi-alert-octagon"></i> {{ trans('errors.app_down', ['appName' => setting('app-name')]) }}</h4>
<p>{{ trans('errors.back_soon') }}</p> <p>{{ trans('errors.back_soon') }}</p>
</div> </div>
</div>
</div>
@stop @stop

View File

@ -27,6 +27,8 @@
@endforeach @endforeach
</table> </table>
<a href="{{ $model->getUrl() }}" class="button muted">{{ trans('common.cancel') }}</a> <div class="text-right">
<a href="{{ $model->getUrl() }}" class="button outline">{{ trans('common.cancel') }}</a>
<button type="submit" class="button pos">{{ trans('entities.permissions_save') }}</button> <button type="submit" class="button pos">{{ trans('entities.permissions_save') }}</button>
</div>
</form> </form>

View File

@ -0,0 +1,56 @@
@extends('sidebar-layout')
@section('toolbar')
<div class="col-sm-6 faded">
<div class="action-buttons text-left">
<a expand-toggle=".entity-list.compact .entity-item-snippet" class="text-primary text-button"><i class="zmdi zmdi-wrap-text"></i>{{ trans('common.toggle_details') }}</a>
</div>
</div>
@stop
@section('sidebar')
@if(count($draftPages) > 0)
<div id="recent-drafts" class="card">
<h3><i class="zmdi zmdi-edit"></i> {{ trans('entities.my_recent_drafts') }}</h3>
@include('partials/entity-list', ['entities' => $draftPages, 'style' => 'compact'])
</div>
@endif
<div class="card">
<h3><i class="zmdi zmdi-{{ $signedIn ? 'eye' : 'star-circle' }}"></i> {{ trans('entities.' . ($signedIn ? 'my_recently_viewed' : 'books_recent')) }}</h3>
@include('partials/entity-list', [
'entities' => $recents,
'style' => 'compact',
'emptyText' => $signedIn ? trans('entities.no_pages_viewed') : trans('entities.books_empty')
])
</div>
<div class="card">
<h3><i class="zmdi zmdi-file"></i> <a class="no-color" href="{{ baseUrl("/pages/recently-updated") }}">{{ trans('entities.recently_updated_pages') }}</a></h3>
<div id="recently-updated-pages">
@include('partials/entity-list', [
'entities' => $recentlyUpdatedPages,
'style' => 'compact',
'emptyText' => trans('entities.no_pages_recently_updated')
])
</div>
</div>
<div id="recent-activity" class="card">
<h3><i class="zmdi zmdi-time"></i> {{ trans('entities.recent_activity') }}</h3>
@include('partials/activity-list', ['activity' => $activity])
</div>
@stop
@section('body')
<div class="page-content" ng-non-bindable>
@include('pages/page-display', ['page' => $customHomepage])
</div>
@stop
@section('scripts')
<script>
setupPageShow({{$customHomepage->id}});
</script>
@stop

View File

@ -1,52 +1,39 @@
@extends('base') @extends('simple-layout')
@section('content') @section('toolbar')
<div class="faded-small toolbar">
<div class="container">
<div class="row">
<div class="col-sm-6 faded"> <div class="col-sm-6 faded">
<div class="action-buttons text-left"> <div class="action-buttons text-left">
<a expand-toggle=".entity-list.compact .entity-item-snippet" class="text-primary text-button"><i class="zmdi zmdi-wrap-text"></i>{{ trans('common.toggle_details') }}</a> <a expand-toggle=".entity-list.compact .entity-item-snippet" class="text-primary text-button"><i class="zmdi zmdi-wrap-text"></i>{{ trans('common.toggle_details') }}</a>
</div> </div>
</div> </div>
</div> @stop
</div>
</div> @section('body')
<div class="container" ng-non-bindable> <div class="container" ng-non-bindable>
<div class="row"> <div class="row">
<div class="col-sm-4"> <div class="col-sm-4">
<div id="recent-drafts">
@if(count($draftPages) > 0) @if(count($draftPages) > 0)
<h4>{{ trans('entities.my_recent_drafts') }}</h4> <div id="recent-drafts" class="card">
<h3><i class="zmdi zmdi-edit"></i> {{ trans('entities.my_recent_drafts') }}</h3>
@include('partials/entity-list', ['entities' => $draftPages, 'style' => 'compact']) @include('partials/entity-list', ['entities' => $draftPages, 'style' => 'compact'])
@endif
</div> </div>
@if($signedIn)
<h4>{{ trans('entities.my_recently_viewed') }}</h4>
@else
<h4>{{ trans('entities.books_recent') }}</h4>
@endif @endif
<div class="card">
<h3><i class="zmdi zmdi-{{ $signedIn ? 'eye' : 'star-circle' }}"></i> {{ trans('entities.' . ($signedIn ? 'my_recently_viewed' : 'books_recent')) }}</h3>
@include('partials/entity-list', [ @include('partials/entity-list', [
'entities' => $recents, 'entities' => $recents,
'style' => 'compact', 'style' => 'compact',
'emptyText' => $signedIn ? trans('entities.no_pages_viewed') : trans('entities.books_empty') 'emptyText' => $signedIn ? trans('entities.no_pages_viewed') : trans('entities.books_empty')
]) ])
</div> </div>
<div class="col-sm-4">
<h4><a class="no-color" href="{{ baseUrl("/pages/recently-created") }}">{{ trans('entities.recently_created_pages') }}</a></h4>
<div id="recently-created-pages">
@include('partials/entity-list', [
'entities' => $recentlyCreatedPages,
'style' => 'compact',
'emptyText' => trans('entities.no_pages_recently_created')
])
</div> </div>
<h4><a class="no-color" href="{{ baseUrl("/pages/recently-updated") }}">{{ trans('entities.recently_updated_pages') }}</a></h4> <div class="col-sm-4">
<div class="card">
<h3><i class="zmdi zmdi-file"></i> <a class="no-color" href="{{ baseUrl("/pages/recently-updated") }}">{{ trans('entities.recently_updated_pages') }}</a></h3>
<div id="recently-updated-pages"> <div id="recently-updated-pages">
@include('partials/entity-list', [ @include('partials/entity-list', [
'entities' => $recentlyUpdatedPages, 'entities' => $recentlyUpdatedPages,
@ -55,11 +42,14 @@
]) ])
</div> </div>
</div> </div>
</div>
<div class="col-sm-4" id="recent-activity"> <div class="col-sm-4" id="recent-activity">
<h4>{{ trans('entities.recent_activity') }}</h4> <div class="card">
<h3><i class="zmdi zmdi-time"></i> {{ trans('entities.recent_activity') }}</h3>
@include('partials/activity-list', ['activity' => $activity]) @include('partials/activity-list', ['activity' => $activity])
</div> </div>
</div>
</div> </div>
</div> </div>

View File

@ -1,27 +1,30 @@
@extends('base') @extends('simple-layout')
@section('content') @section('toolbar')
<div class="faded-small toolbar">
<div class="container">
<div class="row">
<div class="col-sm-12 faded"> <div class="col-sm-12 faded">
@include('pages._breadcrumbs', ['page' => $page]) @include('pages._breadcrumbs', ['page' => $page])
</div> </div>
</div> @stop
</div>
</div> @section('body')
<div class="container small" ng-non-bindable> <div class="container small" ng-non-bindable>
<h1>{{ $page->draft ? trans('entities.pages_delete_draft') : trans('entities.pages_delete') }}</h1> <p>&nbsp;</p>
<div class="card">
<h3><i class="zmdi zmdi-delete"></i> {{ $page->draft ? trans('entities.pages_delete_draft') : trans('entities.pages_delete') }}</h3>
<div class="body">
<p class="text-neg">{{ $page->draft ? trans('entities.pages_delete_draft_confirm'): trans('entities.pages_delete_confirm') }}</p> <p class="text-neg">{{ $page->draft ? trans('entities.pages_delete_draft_confirm'): trans('entities.pages_delete_confirm') }}</p>
<form action="{{ $page->getUrl() }}" method="POST"> <form action="{{ $page->getUrl() }}" method="POST">
{!! csrf_field() !!} {!! csrf_field() !!}
<input type="hidden" name="_method" value="DELETE"> <input type="hidden" name="_method" value="DELETE">
<a href="{{ $page->getUrl() }}" class="button primary">{{ trans('common.cancel') }}</a> <div class="form-group">
<a href="{{ $page->getUrl() }}" class="button outline">{{ trans('common.cancel') }}</a>
<button type="submit" class="button neg">{{ trans('common.confirm') }}</button> <button type="submit" class="button neg">{{ trans('common.confirm') }}</button>
</div>
</form> </form>
</div> </div>
</div>
</div>
@stop @stop

View File

@ -1,18 +1,15 @@
@extends('base') @extends('simple-layout')
@section('content') @section('body')
<div class="container small">
<div class="container"> <p>&nbsp;</p>
<div class="row"> <div class="card">
<h3>{{ $title }}</h3>
<div class="col-sm-7">
<h1>{{ $title }}</h1>
@include('partials/entity-list', ['entities' => $pages, 'style' => 'detailed']) @include('partials/entity-list', ['entities' => $pages, 'style' => 'detailed'])
<div class="body text-center">
{!! $pages->links() !!} {!! $pages->links() !!}
</div> </div>
<div class="col-sm-4 col-sm-offset-1"></div>
</div> </div>
</div> </div>
@stop @stop

View File

@ -16,8 +16,6 @@
@include('pages/form', ['model' => $page]) @include('pages/form', ['model' => $page])
@include('pages/form-toolbox') @include('pages/form-toolbox')
</form> </form>
</div> </div>
@include('components.image-manager', ['imageType' => 'gallery', 'uploaded_to' => $page->id]) @include('components.image-manager', ['imageType' => 'gallery', 'uploaded_to' => $page->id])

View File

@ -5,7 +5,7 @@
{{--Header Bar--}} {{--Header Bar--}}
<div class="faded-small toolbar"> <div class="faded-small toolbar">
<div class="container"> <div class="container fluid">
<div class="row"> <div class="row">
<div class="col-sm-4 faded"> <div class="col-sm-4 faded">
<div class="action-buttons text-left"> <div class="action-buttons text-left">
@ -74,7 +74,7 @@
{{--Markdown Editor--}} {{--Markdown Editor--}}
@if(setting('app-editor') === 'markdown') @if(setting('app-editor') === 'markdown')
<div id="markdown-editor" markdown-editor class="flex-fill flex"> <div id="markdown-editor" markdown-editor class="flex-fill flex code-fill">
<div class="markdown-editor-wrap"> <div class="markdown-editor-wrap">
<div class="editor-toolbar"> <div class="editor-toolbar">

View File

@ -1,29 +1,31 @@
@extends('base') @extends('simple-layout')
@section('content') @section('toolbar')
<div class="faded-small toolbar">
<div class="container">
<div class="row">
<div class="col-sm-12 faded"> <div class="col-sm-12 faded">
@include('pages._breadcrumbs', ['page' => $page]) @include('pages._breadcrumbs', ['page' => $page])
</div> </div>
</div> @stop
</div>
</div> @section('body')
<div class="container"> <div class="container">
<h1>{{ trans('entities.pages_move') }}</h1> <p>&nbsp;</p>
<div class="card">
<h3><i class="zmdi zmdi-folder"></i> {{ trans('entities.pages_move') }}</h3>
<div class="body">
<form action="{{ $page->getUrl('/move') }}" method="POST"> <form action="{{ $page->getUrl('/move') }}" method="POST">
{!! csrf_field() !!} {!! csrf_field() !!}
<input type="hidden" name="_method" value="PUT"> <input type="hidden" name="_method" value="PUT">
@include('components.entity-selector', ['name' => 'entity_selection', 'selectorSize' => 'large', 'entityTypes' => 'book,chapter']) @include('components.entity-selector', ['name' => 'entity_selection', 'selectorSize' => 'large', 'entityTypes' => 'book,chapter'])
<a href="{{ $page->getUrl() }}" class="button muted">{{ trans('common.cancel') }}</a> <div class="form-group text-right">
<a href="{{ $page->getUrl() }}" class="button outline">{{ trans('common.cancel') }}</a>
<button type="submit" class="button pos">{{ trans('entities.pages_move') }}</button> <button type="submit" class="button pos">{{ trans('entities.pages_move') }}</button>
</div>
</form> </form>
</div> </div>
</div>
</div>
@stop @stop

View File

@ -7,6 +7,6 @@
@if (isset($diff) && $diff) @if (isset($diff) && $diff)
{!! $diff !!} {!! $diff !!}
@else @else
{!! isset($pageContent) ? $pageContent : $page->html !!} {!! isset($page->renderedHTML) ? $page->renderedHTML : $page->html !!}
@endif @endif
</div> </div>

View File

@ -1,20 +1,19 @@
@extends('base') @extends('simple-layout')
@section('content') @section('toolbar')
<div class="faded-small toolbar">
<div class="container">
<div class="row">
<div class="col-sm-12 faded"> <div class="col-sm-12 faded">
@include('pages._breadcrumbs', ['page' => $page]) @include('pages._breadcrumbs', ['page' => $page])
</div> </div>
</div> @stop
</div>
</div>
@section('body')
<div class="container" ng-non-bindable> <div class="container" ng-non-bindable>
<h1>{{ trans('entities.pages_permissions') }}</h1> <p>&nbsp;</p>
<div class="card">
<h3><i class="zmdi zmdi-lock-outline"></i> {{ trans('entities.pages_permissions') }}</h3>
<div class="body">
@include('form.restriction-form', ['model' => $page]) @include('form.restriction-form', ['model' => $page])
</div> </div>
</div>
</div>
@stop @stop

View File

@ -1,12 +1,20 @@
@extends('base') @extends('sidebar-layout')
@section('content') @section('sidebar')
<div class="card">
<h3><i class="zmdi zmdi-info-outline"></i> {{ trans('common.details') }}</h3>
<div class="body">
@include('partials.entity-meta', ['entity' => $revision])
</div>
</div>
@stop
@section('body')
<div class="container" ng-non-bindable> <div class="container" ng-non-bindable>
<div class="row"> <div class="row">
<div class="col-md-9"> <div class="col-md-9">
<div class="page-content anim fadeIn"> <div class="page-content">
@include('pages.page-display') @include('pages.page-display')
</div> </div>
</div> </div>

View File

@ -1,20 +1,18 @@
@extends('base') @extends('simple-layout')
@section('content') @section('toolbar')
<div class="faded-small toolbar">
<div class="container">
<div class="row">
<div class="col-sm-12 faded"> <div class="col-sm-12 faded">
@include('pages._breadcrumbs', ['page' => $page]) @include('pages._breadcrumbs', ['page' => $page])
</div> </div>
</div> @stop
</div>
</div>
@section('body')
<div class="container" ng-non-bindable> <div class="container" ng-non-bindable>
<h1>{{ trans('entities.pages_revisions') }}</h1> <p>&nbsp;</p>
<div class="card">
<h3><i class="zmdi zmdi-replay"></i> {{ trans('entities.pages_revisions') }}</h3>
<div class="body">
@if(count($page->revisions) > 0) @if(count($page->revisions) > 0)
<table class="table"> <table class="table">
@ -57,6 +55,8 @@
@else @else
<p>{{ trans('entities.pages_revisions_none') }}</p> <p>{{ trans('entities.pages_revisions_none') }}</p>
@endif @endif
</div>
</div>
</div> </div>

View File

@ -1,10 +1,6 @@
@extends('base') @extends('sidebar-layout')
@section('content') @section('toolbar')
<div class="faded-small toolbar">
<div class="container">
<div class="row">
<div class="col-sm-8 col-xs-5 faded"> <div class="col-sm-8 col-xs-5 faded">
@include('pages._breadcrumbs', ['page' => $page]) @include('pages._breadcrumbs', ['page' => $page])
</div> </div>
@ -23,7 +19,7 @@
@endif @endif
@if(userCan('page-update', $page) || userCan('restrictions-manage', $page) || userCan('page-delete', $page)) @if(userCan('page-update', $page) || userCan('restrictions-manage', $page) || userCan('page-delete', $page))
<div dropdown class="dropdown-container"> <div dropdown class="dropdown-container">
<a dropdown-toggle class="text-primary text-button"><i class="zmdi zmdi-more-vert"></i></a> <a dropdown-toggle class="text-primary text-button"><i class="zmdi zmdi-more-vert"></i> {{ trans('common.more') }}</a>
<ul> <ul>
@if(userCan('page-update', $page)) @if(userCan('page-update', $page))
<li><a href="{{ $page->getUrl('/move') }}" class="text-primary" ><i class="zmdi zmdi-folder"></i>{{ trans('common.move') }}</a></li> <li><a href="{{ $page->getUrl('/move') }}" class="text-primary" ><i class="zmdi zmdi-folder"></i>{{ trans('common.move') }}</a></li>
@ -41,37 +37,13 @@
</div> </div>
</div> </div>
</div> @stop
</div>
</div>
@section('sidebar')
<div class="container" id="page-show">
<div class="row">
<div class="col-md-9 print-full-width">
<div class="page-content" ng-non-bindable>
<div class="pointer-container" id="pointer">
<div class="pointer anim" >
<span class="icon text-primary"><i class="zmdi zmdi-link"></i></span>
<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') }}"><i class="zmdi zmdi-copy"></i></button>
</div>
</div>
@include('pages/page-display')
<hr>
@include('partials.entity-meta', ['entity' => $page])
</div>
@include('comments/comments', ['pageId' => $page->id])
</div>
<div class="col-md-3 print-hidden">
<div class="margin-top large"></div>
@if($book->restricted || ($page->chapter && $page->chapter->restricted) || $page->restricted) @if($book->restricted || ($page->chapter && $page->chapter->restricted) || $page->restricted)
<div class="card">
<h3><i class="zmdi zmdi-key"></i> {{ trans('entities.permissions') }}</h3>
<div class="body">
<div class="text-muted"> <div class="text-muted">
@if($book->restricted) @if($book->restricted)
@ -101,14 +73,82 @@
<br> <br>
@endif @endif
</div> </div>
</div>
</div>
@endif @endif
@if($page->tags->count() > 0)
<div class="card tag-display">
<h3><i class="zmdi zmdi-tag"></i> {{ trans('entities.page_tags') }}</h3>
<div class="body">
<table>
<tbody>
@foreach($page->tags as $tag)
<tr class="tag">
<td @if(!$tag->value) colspan="2" @endif><a href="{{ baseUrl('/search?term=%5B' . urlencode($tag->name) .'%5D') }}">{{ $tag->name }}</a></td>
@if($tag->value) <td class="tag-value"><a href="{{ baseUrl('/search?term=%5B' . urlencode($tag->name) .'%3D' . urlencode($tag->value) . '%5D') }}">{{$tag->value}}</a></td> @endif
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
@endif
@if ($page->attachments->count() > 0)
<div class="card">
<h3><i class="zmdi zmdi-attachment-alt"></i> {{ trans('entities.pages_attachments') }}</h3>
<div class="body">
@foreach($page->attachments as $attachment)
<div class="attachment">
<a href="{{ $attachment->getUrl() }}" @if($attachment->external) target="_blank" @endif><i class="zmdi zmdi-{{ $attachment->external ? 'open-in-new' : 'file' }}"></i>{{ $attachment->name }}</a>
</div>
@endforeach
</div>
</div>
@endif
@include('pages/sidebar-tree-list', ['book' => $book, 'sidebarTree' => $sidebarTree, 'pageNav' => $pageNav]) @if (isset($pageNav) && count($pageNav))
<div class="card">
<h3><i class="zmdi zmdi-compass"></i> {{ trans('entities.pages_navigation') }}</h3>
<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>
</li>
@endforeach
</div>
</div>
</div>
@endif
@include('partials/book-tree', ['book' => $book, 'sidebarTree' => $sidebarTree])
<div class="card">
<h3><i class="zmdi zmdi-info-outline"></i> {{ trans('common.details') }}</h3>
<div class="body">
@include('partials.entity-meta', ['entity' => $page])
</div>
</div>
@stop
@section('body')
<div class="page-content" ng-non-bindable>
<div class="pointer-container" id="pointer">
<div class="pointer anim" >
<span class="icon text-primary"><i class="zmdi zmdi-link"></i></span>
<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') }}"><i class="zmdi zmdi-copy"></i></button>
</div>
</div> </div>
@include('pages/page-display')
</div> </div>
<div class="container small">
@include('comments/comments', ['pageId' => $page->id])
</div> </div>
@stop @stop

View File

@ -1,74 +0,0 @@
<div class="book-tree" ng-non-bindable>
@if(isset($page) && $page->tags->count() > 0)
<div class="tag-display">
<h6 class="text-muted">{{ trans('entities.page_tags') }}</h6>
<table>
<tbody>
@foreach($page->tags as $tag)
<tr class="tag">
<td @if(!$tag->value) colspan="2" @endif><a href="{{ baseUrl('/search?term=%5B' . urlencode($tag->name) .'%5D') }}">{{ $tag->name }}</a></td>
@if($tag->value) <td class="tag-value"><a href="{{ baseUrl('/search?term=%5B' . urlencode($tag->name) .'%3D' . urlencode($tag->value) . '%5D') }}">{{$tag->value}}</a></td> @endif
</tr>
@endforeach
</tbody>
</table>
</div>
@endif
@if (isset($page) && $page->attachments->count() > 0)
<h6 class="text-muted">{{ trans('entities.pages_attachments') }}</h6>
@foreach($page->attachments as $attachment)
<div class="attachment">
<a href="{{ $attachment->getUrl() }}" @if($attachment->external) target="_blank" @endif><i class="zmdi zmdi-{{ $attachment->external ? 'open-in-new' : 'file' }}"></i>{{ $attachment->name }}</a>
</div>
@endforeach
@endif
@if (isset($pageNav) && count($pageNav))
<h6 class="text-muted">{{ trans('entities.pages_navigation') }}</h6>
<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>
</li>
@endforeach
</div>
@endif
<h6 class="text-muted">{{ trans('entities.books_navigation') }}</h6>
<ul class="sidebar-page-list menu">
@if (userCan('view', $book))
<li class="book-header"><a href="{{ $book->getUrl() }}" class="book {{ $current->matches($book)? 'selected' : '' }}"><i class="zmdi zmdi-book"></i>{{$book->name}}</a></li>
@endif
@foreach($sidebarTree as $bookChild)
<li class="list-item-{{ $bookChild->getClassName() }} {{ $bookChild->getClassName() }} {{ $bookChild->isA('page') && $bookChild->draft ? 'draft' : '' }}">
<a href="{{ $bookChild->getUrl() }}" class="{{ $bookChild->getClassName() }} {{ $current->matches($bookChild)? 'selected' : '' }}">
@if($bookChild->isA('chapter'))<i class="zmdi zmdi-collection-bookmark"></i>@else <i class="zmdi zmdi-file-text"></i>@endif{{ $bookChild->name }}
</a>
@if($bookChild->isA('chapter') && count($bookChild->pages) > 0)
<p chapter-toggle class="text-muted @if($bookChild->matchesOrContains($current)) open @endif">
<i class="zmdi zmdi-caret-right"></i> <i class="zmdi zmdi-file-text"></i> <span>{{ trans('entities.x_pages', ['count' => $bookChild->pages->count()]) }}</span>
</p>
<ul class="menu sub-menu inset-list @if($bookChild->matchesOrContains($current)) open @endif">
@foreach($bookChild->pages as $childPage)
<li class="list-item-page {{ $childPage->isA('page') && $childPage->draft ? 'draft' : '' }}">
<a href="{{ $childPage->getUrl() }}" class="page {{ $current->matches($childPage)? 'selected' : '' }}">
<i class="zmdi zmdi-file-text"></i> {{ $childPage->name }}
</a>
</li>
@endforeach
</ul>
@endif
</li>
@endforeach
</ul>
</div>

View File

@ -8,5 +8,5 @@
@endforeach @endforeach
</div> </div>
@else @else
<p class="text-muted">{{ trans('common.no_activity') }}</p> <p class="text-muted empty-text">{{ trans('common.no_activity') }}</p>
@endif @endif

View File

@ -0,0 +1,36 @@
<div class="card book-tree" ng-non-bindable>
<h3><i class="zmdi zmdi-book"></i> {{ trans('entities.books_navigation') }}</h3>
<div class="body">
<ul class="sidebar-page-list menu">
@if (userCan('view', $book))
<li class="book-header"><a href="{{ $book->getUrl() }}" class="book {{ $current->matches($book)? 'selected' : '' }}"><i class="zmdi zmdi-book"></i>{{$book->name}}</a></li>
@endif
@foreach($sidebarTree as $bookChild)
<li class="list-item-{{ $bookChild->getClassName() }} {{ $bookChild->getClassName() }} {{ $bookChild->isA('page') && $bookChild->draft ? 'draft' : '' }}">
<a href="{{ $bookChild->getUrl() }}" class="{{ $bookChild->getClassName() }} {{ $current->matches($bookChild)? 'selected' : '' }}">
@if($bookChild->isA('chapter'))<i class="zmdi zmdi-collection-bookmark"></i>@else <i class="zmdi zmdi-file-text"></i>@endif{{ $bookChild->name }}
</a>
@if($bookChild->isA('chapter') && count($bookChild->pages) > 0)
<p chapter-toggle class="text-muted @if($bookChild->matchesOrContains($current)) open @endif">
<i class="zmdi zmdi-caret-right"></i> <i class="zmdi zmdi-file-text"></i> <span>{{ trans('entities.x_pages', ['count' => $bookChild->pages->count()]) }}</span>
</p>
<ul class="menu sub-menu inset-list @if($bookChild->matchesOrContains($current)) open @endif">
@foreach($bookChild->pages as $childPage)
<li class="list-item-page {{ $childPage->isA('page') && $childPage->draft ? 'draft' : '' }}">
<a href="{{ $childPage->getUrl() }}" class="page {{ $current->matches($childPage)? 'selected' : '' }}">
<i class="zmdi zmdi-file-text"></i> {{ $childPage->name }}
</a>
</li>
@endforeach
</ul>
@endif
</li>
@endforeach
</ul>
</div>
</div>

View File

@ -1,5 +1,4 @@
<style id="custom-styles" data-color="{{ setting('app-color') }}" data-color-light="{{ setting('app-color-light') }}"> <style id="custom-styles" data-color="{{ setting('app-color') }}" data-color-light="{{ setting('app-color-light') }}">
@if(setting('app-color'))
header, [back-to-top], .primary-background { header, [back-to-top], .primary-background {
background-color: {{ setting('app-color') }} !important; background-color: {{ setting('app-color') }} !important;
} }
@ -18,5 +17,4 @@
.text-primary, p.primary, p .primary, span.primary:hover, .text-primary:hover, a, a:hover, a:focus, .text-button, .text-button:hover, .text-button:focus { .text-primary, p.primary, p .primary, span.primary:hover, .text-primary:hover, a, a:hover, a:focus, .text-button, .text-button:hover, .text-button:focus {
color: {{ setting('app-color') }}; color: {{ setting('app-color') }};
} }
@endif
</style> </style>

View File

@ -1,4 +1,9 @@
<p class="text-muted small"> <p class="text-muted small">
@if($entity->isA('revision'))
{{ trans('entities.pages_revision') }}
{{ trans('entities.pages_revisions_number') }}{{ $entity->revision_number == 0 ? '' : $entity->revision_number }}
<br>
@endif
@if ($entity->isA('page')) {{ trans('entities.meta_revision', ['revisionCount' => $entity->revision_count]) }} <br> @endif @if ($entity->isA('page')) {{ trans('entities.meta_revision', ['revisionCount' => $entity->revision_count]) }} <br> @endif
@if ($entity->createdBy) @if ($entity->createdBy)
{!! trans('entities.meta_created_name', [ {!! trans('entities.meta_created_name', [
@ -14,7 +19,7 @@
'timeLength' => '<span title="' . $entity->updated_at->toDayDateTimeString() .'">' . $entity->updated_at->diffForHumans() .'</span>', 'timeLength' => '<span title="' . $entity->updated_at->toDayDateTimeString() .'">' . $entity->updated_at->diffForHumans() .'</span>',
'user' => "<a href='{$entity->updatedBy->getProfileUrl()}'>".htmlentities($entity->updatedBy->name). "</a>" 'user' => "<a href='{$entity->updatedBy->getProfileUrl()}'>".htmlentities($entity->updatedBy->name). "</a>"
]) !!} ]) !!}
@else @elseif (!$entity->isA('revision'))
<span title="{{ $entity->updated_at->toDayDateTimeString() }}">{{ trans('entities.meta_updated', ['timeLength' => $entity->updated_at->diffForHumans()]) }}</span> <span title="{{ $entity->updated_at->toDayDateTimeString() }}">{{ trans('entities.meta_updated', ['timeLength' => $entity->updated_at->diffForHumans()]) }}</span>
@endif @endif
</p> </p>

View File

@ -1,5 +1,5 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html class="shaded">
<head> <head>
<title>{{ setting('app-name') }}</title> <title>{{ setting('app-name') }}</title>
@ -23,12 +23,12 @@
{!! setting('app-custom-head') !!} {!! setting('app-custom-head') !!}
@endif @endif
</head> </head>
<body class="@yield('body-class')" ng-app="bookStack"> <body class="@yield('body-class')">
@include('partials.notifications') @include('partials.notifications')
<header id="header"> <header id="header">
<div class="container"> <div class="container fluid">
<div class="row"> <div class="row">
<div class="col-sm-6"> <div class="col-sm-6">

View File

@ -1,39 +1,23 @@
@extends('base') @extends('sidebar-layout')
@section('content') @section('toolbar')
<input type="hidden" name="searchTerm" value="{{$searchTerm}}">
<div id="search-system">
<div class="faded-small toolbar">
<div class="container">
<div class="row">
<div class="col-sm-12 faded"> <div class="col-sm-12 faded">
<div class="breadcrumbs"> <div class="breadcrumbs">
<a href="{{ baseUrl("/search?term=" . urlencode($searchTerm)) }}" class="text-button"><i class="zmdi zmdi-search"></i>{{ trans('entities.search_for_term', ['term' => $searchTerm]) }}</a> <a href="{{ baseUrl("/search?term=" . urlencode($searchTerm)) }}" class="text-button"><i class="zmdi zmdi-search"></i>{{ trans('entities.search_for_term', ['term' => $searchTerm]) }}</a>
</div> </div>
</div> </div>
</div> @stop
</div>
</div>
<div class="container" ng-non-bindable id="searchSystem"> @section('container-attrs')
id="search-system"
ng-non-bindable=""
@stop
<div class="row"> @section('sidebar')
<div class="card">
<div class="col-md-6">
<h1>{{ trans('entities.search_results') }}</h1>
<h6 class="text-muted">{{ trans_choice('entities.search_total_results_found', $totalResults, ['count' => $totalResults]) }}</h6>
@include('partials/entity-list', ['entities' => $entities])
@if ($hasNextPage)
<a href="{{ $nextPageLink }}" class="button">{{ trans('entities.search_more') }}</a>
@endif
</div>
<div class="col-md-5 col-md-offset-1">
<h3>{{ trans('entities.search_filters') }}</h3> <h3>{{ trans('entities.search_filters') }}</h3>
<div class="body">
<form v-on:submit="updateSearch" v-cloak class="v-cloak anim fadeIn"> <form v-on:submit="updateSearch" v-cloak class="v-cloak anim fadeIn">
<h6 class="text-muted">{{ trans('entities.search_content_type') }}</h6> <h6 class="text-muted">{{ trans('entities.search_content_type') }}</h6>
<div class="form-group"> <div class="form-group">
@ -200,14 +184,21 @@
<button type="submit" class="button primary">{{ trans('entities.search_update') }}</button> <button type="submit" class="button primary">{{ trans('entities.search_update') }}</button>
</form> </form>
</div> </div>
</div> </div>
@stop
</div> @section('body')
</div>
<div class="container small">
<input type="hidden" name="searchTerm" value="{{$searchTerm}}">
<h1>{{ trans('entities.search_results') }}</h1>
<h6 class="text-muted">{{ trans_choice('entities.search_total_results_found', $totalResults, ['count' => $totalResults]) }}</h6>
@include('partials/entity-list', ['entities' => $entities])
@if ($hasNextPage)
<a href="{{ $nextPageLink }}" class="button">{{ trans('entities.search_more') }}</a>
@endif
</div>
@stop @stop

View File

@ -1,18 +1,22 @@
@extends('base') @extends('simple-layout')
@section('content')
@section('toolbar')
@include('settings/navbar', ['selected' => 'settings']) @include('settings/navbar', ['selected' => 'settings'])
@stop
<div class="container small settings-container"> @section('body')
<div class="container small">
<h1>{{ trans('settings.settings') }}</h1> <div class="text-right text-muted container">
<br>
BookStack @if(strpos($version, 'v') !== 0) version @endif {{ $version }}
</div>
<div class="card">
<h3><i class="zmdi zmdi-settings-square"></i> {{ trans('settings.app_settings') }}</h3>
<div class="body">
<form action="{{ baseUrl("/settings") }}" method="POST"> <form action="{{ baseUrl("/settings") }}" method="POST">
{!! csrf_field() !!} {!! csrf_field() !!}
<h3>{{ trans('settings.app_settings') }}</h3>
<div class="row"> <div class="row">
<div class="col-md-6"> <div class="col-md-6">
@ -64,8 +68,13 @@
<div class="form-group" id="color-control"> <div class="form-group" id="color-control">
<label for="setting-app-color">{{ trans('settings.app_primary_color') }}</label> <label for="setting-app-color">{{ trans('settings.app_primary_color') }}</label>
<p class="small">{!! trans('settings.app_primary_color_desc') !!}</p> <p class="small">{!! trans('settings.app_primary_color_desc') !!}</p>
<input type="text" value="{{ setting('app-color', '') }}" name="setting-app-color" id="setting-app-color" placeholder="#0288D1"> <input type="text" value="{{ setting('app-color') }}" name="setting-app-color" id="setting-app-color" placeholder="#0288D1">
<input type="hidden" value="{{ setting('app-color-light', '') }}" name="setting-app-color-light" id="setting-app-color-light" placeholder="rgba(21, 101, 192, 0.15)"> <input type="hidden" value="{{ setting('app-color-light') }}" name="setting-app-color-light" id="setting-app-color-light">
</div>
<div class="form-group" id="homepage-control">
<label for="setting-app-homepage">{{ trans('settings.app_homepage') }}</label>
<p class="small">{{ trans('settings.app_homepage_desc') }}</p>
@include('components.page-picker', ['name' => 'setting-app-homepage', 'placeholder' => trans('settings.app_homepage_default'), 'value' => setting('app-homepage')])
</div> </div>
</div> </div>
@ -77,9 +86,20 @@
<textarea name="setting-app-custom-head" id="setting-app-custom-head">{{ setting('app-custom-head', '') }}</textarea> <textarea name="setting-app-custom-head" id="setting-app-custom-head">{{ setting('app-custom-head', '') }}</textarea>
</div> </div>
<hr class="margin-top"> <div class="form-group text-right">
<button type="submit" class="button pos">{{ trans('settings.settings_save') }}</button>
</div>
</form>
</div>
</div>
<h3>{{ trans('settings.reg_settings') }}</h3> <p>&nbsp;</p>
<div class="card">
<h3><i class="zmdi zmdi-accounts-add"></i> {{ trans('settings.reg_settings') }}</h3>
<div class="body">
<form action="{{ baseUrl("/settings") }}" method="POST">
{!! csrf_field() !!}
<div class="row"> <div class="row">
<div class="col-md-6"> <div class="col-md-6">
@ -114,19 +134,18 @@
</div> </div>
</div> </div>
<hr class="margin-top"> <div class="form-group text-right">
<div class="form-group">
<span class="float right muted">
BookStack @if(strpos($version, 'v') !== 0) version @endif {{ $version }}
</span>
<button type="submit" class="button pos">{{ trans('settings.settings_save') }}</button> <button type="submit" class="button pos">{{ trans('settings.settings_save') }}</button>
</div> </div>
</form> </form>
</div>
</div>
</div> </div>
@include('components.image-manager', ['imageType' => 'system']) @include('components.image-manager', ['imageType' => 'system'])
@include('components.entity-selector-popup', ['entityTypes' => 'page'])
@stop @stop
@ -139,6 +158,7 @@
var hexVal = '#' + this.color.colors.HEX; var hexVal = '#' + this.color.colors.HEX;
var rgb = this.color.colors.RND.rgb; var rgb = this.color.colors.RND.rgb;
var rgbLightVal = 'rgba('+ [rgb.r, rgb.g, rgb.b, '0.15'].join(',') +')'; var rgbLightVal = 'rgba('+ [rgb.r, rgb.g, rgb.b, '0.15'].join(',') +')';
// Set textbox color to hex color code. // Set textbox color to hex color code.
var isEmpty = $.trim($elm.val()).length === 0; var isEmpty = $.trim($elm.val()).length === 0;
if (!isEmpty) $elm.val(hexVal); if (!isEmpty) $elm.val(hexVal);

View File

@ -1,8 +1,5 @@
<div class="faded-small toolbar"> <div class="col-md-12 setting-nav nav-tabs">
<div class="container">
<div class="row">
<div class="col-md-12 setting-nav nav-tabs">
@if($currentUser->can('settings-manage')) @if($currentUser->can('settings-manage'))
<a href="{{ baseUrl('/settings') }}" @if($selected == 'settings') class="selected text-button" @endif><i class="zmdi zmdi-settings"></i>{{ trans('settings.settings') }}</a> <a href="{{ baseUrl('/settings') }}" @if($selected == 'settings') class="selected text-button" @endif><i class="zmdi zmdi-settings"></i>{{ trans('settings.settings') }}</a>
@endif @endif
@ -12,7 +9,4 @@
@if($currentUser->can('user-roles-manage')) @if($currentUser->can('user-roles-manage'))
<a href="{{ baseUrl('/settings/roles') }}" @if($selected == 'roles') class="selected text-button" @endif><i class="zmdi zmdi-lock-open"></i>{{ trans('settings.roles') }}</a> <a href="{{ baseUrl('/settings/roles') }}" @if($selected == 'roles') class="selected text-button" @endif><i class="zmdi zmdi-lock-open"></i>{{ trans('settings.roles') }}</a>
@endif @endif
</div>
</div>
</div>
</div> </div>

View File

@ -1,15 +1,17 @@
@extends('base') @extends('simple-layout')
@section('content')
@section('toolbar')
@include('settings/navbar', ['selected' => 'roles']) @include('settings/navbar', ['selected' => 'roles'])
@stop
<div class="container"> @section('body')
<h1>{{ trans('settings.role_create') }}</h1>
<form action="{{ baseUrl("/settings/roles/new") }}" method="POST"> <form action="{{ baseUrl("/settings/roles/new") }}" method="POST">
@include('settings/roles/form') <div class="container">
</form> <div class="row">
@include('settings/roles/form', ['title' => trans('settings.role_create'), 'icon' => 'plus'])
</div> </div>
</div>
</form>
@stop @stop

View File

@ -1,11 +1,15 @@
@extends('base') @extends('simple-layout')
@section('content')
@section('toolbar')
@include('settings/navbar', ['selected' => 'roles']) @include('settings/navbar', ['selected' => 'roles'])
@stop
@section('body')
<div class="container small" ng-non-bindable> <div class="container small" ng-non-bindable>
<h1>{{ trans('settings.role_delete') }}</h1> <p>&nbsp;</p>
<div class="card">
<h3><i class="zmdi zmdi-delete"></i> {{ trans('settings.role_delete') }}</h3>
<div class="body">
<p>{{ trans('settings.role_delete_confirm', ['roleName' => $role->display_name]) }}</p> <p>{{ trans('settings.role_delete_confirm', ['roleName' => $role->display_name]) }}</p>
<form action="{{ baseUrl("/settings/roles/delete/{$role->id}") }}" method="POST"> <form action="{{ baseUrl("/settings/roles/delete/{$role->id}") }}" method="POST">
@ -20,9 +24,13 @@
@endif @endif
<p class="text-neg">{{ trans('settings.role_delete_sure') }}</p> <p class="text-neg">{{ trans('settings.role_delete_sure') }}</p>
<a href="{{ baseUrl("/settings/roles/{$role->id}") }}" class="button muted">{{ trans('common.cancel') }}</a> <div class="form-group">
<a href="{{ baseUrl("/settings/roles/{$role->id}") }}" class="button outline">{{ trans('common.cancel') }}</a>
<button type="submit" class="button neg">{{ trans('common.confirm') }}</button> <button type="submit" class="button neg">{{ trans('common.confirm') }}</button>
</div>
</form> </form>
</div> </div>
</div>
</div>
@stop @stop

View File

@ -1,24 +1,17 @@
@extends('base') @extends('simple-layout')
@section('content')
@section('toolbar')
@include('settings/navbar', ['selected' => 'roles']) @include('settings/navbar', ['selected' => 'roles'])
@stop
<div class="container"> @section('body')
<div class="row">
<div class="col-sm-6">
<h1>{{ trans('settings.role_edit') }}</h1>
</div>
<div class="col-sm-6">
<p></p>
<a href="{{ baseUrl("/settings/roles/delete/{$role->id}") }}" class="button neg float right">{{ trans('settings.role_delete') }}</a>
</div>
</div>
<form action="{{ baseUrl("/settings/roles/{$role->id}") }}" method="POST"> <form action="{{ baseUrl("/settings/roles/{$role->id}") }}" method="POST">
<input type="hidden" name="_method" value="PUT"> <input type="hidden" name="_method" value="PUT">
@include('settings/roles/form', ['model' => $role]) <div class="container">
</form> <div class="row">
@include('settings/roles/form', ['model' => $role, 'title' => trans('settings.role_edit'), 'icon' => 'edit'])
</div> </div>
</div>
</form>
@stop @stop

View File

@ -1,11 +1,12 @@
{!! csrf_field() !!} {!! csrf_field() !!}
<div class="row"> <div class="col-md-9">
<div class="card">
<div class="col-md-9"> <h3><i class="zmdi zmdi-{{$icon}}"></i> {{$title}}</h3>
<div class="body">
<div class="row"> <div class="row">
<div class="col-md-5"> <div class="col-md-5">
<h3>{{ trans('settings.role_details') }}</h3> <h5>{{ trans('settings.role_details') }}</h5>
<div class="form-group"> <div class="form-group">
<label for="name">{{ trans('settings.role_name') }}</label> <label for="name">{{ trans('settings.role_name') }}</label>
@include('form/text', ['name' => 'display_name']) @include('form/text', ['name' => 'display_name'])
@ -14,7 +15,7 @@
<label for="name">{{ trans('settings.role_desc') }}</label> <label for="name">{{ trans('settings.role_desc') }}</label>
@include('form/text', ['name' => 'description']) @include('form/text', ['name' => 'description'])
</div> </div>
<h3>{{ trans('settings.role_system') }}</h3> <h5>{{ trans('settings.role_system') }}</h5>
<label>@include('settings/roles/checkbox', ['permission' => 'users-manage']) {{ trans('settings.role_manage_users') }}</label> <label>@include('settings/roles/checkbox', ['permission' => 'users-manage']) {{ trans('settings.role_manage_users') }}</label>
<label>@include('settings/roles/checkbox', ['permission' => 'user-roles-manage']) {{ trans('settings.role_manage_roles') }}</label> <label>@include('settings/roles/checkbox', ['permission' => 'user-roles-manage']) {{ trans('settings.role_manage_roles') }}</label>
<label>@include('settings/roles/checkbox', ['permission' => 'restrictions-manage-all']) {{ trans('settings.role_manage_entity_permissions') }}</label> <label>@include('settings/roles/checkbox', ['permission' => 'restrictions-manage-all']) {{ trans('settings.role_manage_entity_permissions') }}</label>
@ -24,7 +25,7 @@
<div class="col-md-6"> <div class="col-md-6">
<h3>{{ trans('settings.role_asset') }}</h3> <h5>{{ trans('settings.role_asset') }}</h5>
<p>{{ trans('settings.role_asset_desc') }}</p> <p>{{ trans('settings.role_asset_desc') }}</p>
<table class="table"> <table class="table">
@ -133,12 +134,20 @@
</table> </table>
</div> </div>
</div> </div>
<a href="{{ baseUrl("/settings/roles") }}" class="button muted">{{ trans('common.cancel') }}</a> <div class="form-group text-right">
<a href="{{ baseUrl("/settings/roles") }}" class="button outline">{{ trans('common.cancel') }}</a>
@if (isset($role) && $role->id)
<a href="{{ baseUrl("/settings/roles/delete/{$role->id}") }}" class="button neg">{{ trans('settings.role_delete') }}</a>
@endif
<button type="submit" class="button pos">{{ trans('settings.role_save') }}</button> <button type="submit" class="button pos">{{ trans('settings.role_save') }}</button>
</div> </div>
<div class="col-md-3"> </div>
<h3>{{ trans('settings.role_users') }}</h3> </div>
</div>
<div class="col-md-3">
<div class="card">
<h3><i class="zmdi zmdi-accounts"></i> {{ trans('settings.role_users') }}</h3>
<div class="body">
@if(isset($role) && count($role->users) > 0) @if(isset($role) && count($role->users) > 0)
<table class="list-table"> <table class="list-table">
@foreach($role->users as $user) @foreach($role->users as $user)
@ -161,9 +170,6 @@
{{ trans('settings.role_users_none') }} {{ trans('settings.role_users_none') }}
</p> </p>
@endif @endif
</div> </div>
</div>
</div> </div>

View File

@ -1,21 +1,16 @@
@extends('base') @extends('simple-layout')
@section('content')
@section('toolbar')
@include('settings/navbar', ['selected' => 'roles']) @include('settings/navbar', ['selected' => 'roles'])
@stop
@section('body')
<div class="container small"> <div class="container small">
<p>&nbsp;</p>
<div class="row action-header"> <div class="card">
<div class="col-sm-8"> <h3><i class="zmdi zmdi-lock-open"></i> {{ trans('settings.role_user_roles') }}</h3>
<h1>{{ trans('settings.role_user_roles') }}</h1> <div class="body">
</div>
<div class="col-sm-4">
<p></p>
<a href="{{ baseUrl("/settings/roles/new") }}" class="button float right pos"><i class="zmdi zmdi-lock-open"></i>{{ trans('settings.role_create') }}</a>
</div>
</div>
<table class="table"> <table class="table">
<tr> <tr>
<th>{{ trans('settings.role_name') }}</th> <th>{{ trans('settings.role_name') }}</th>
@ -30,6 +25,12 @@
</tr> </tr>
@endforeach @endforeach
</table> </table>
<div class="form-group">
<a href="{{ baseUrl("/settings/roles/new") }}" class="button pos">{{ trans('settings.role_create') }}</a>
</div>
</div>
</div>
</div> </div>
@stop @stop

View File

@ -0,0 +1,34 @@
@extends('base')
@section('body-class', 'sidebar-layout')
@section('content')
<div class="toolbar-container">
<div class="faded-small toolbar">
<div class="container fluid">
<div class="row">
@yield('toolbar')
</div>
</div>
</div>
</div>
<div class="flex-fill flex" @yield('container-attrs') >
<div sidebar class="sidebar flex print-hidden" id="sidebar">
<div class="sidebar-toggle primary-background-light"><i class="zmdi zmdi-caret-right-circle"></i>
</div>
<div class="scroll-body">
@yield('sidebar')
</div>
</div>
<div class="content flex">
@yield('body')
</div>
</div>
@stop

View File

@ -0,0 +1,27 @@
@extends('base')
@section('body-class', 'shaded')
@section('content')
<div class="toolbar-container">
<div class="faded-small toolbar">
<div class="container fluid">
<div class="row">
@yield('toolbar')
</div>
</div>
</div>
</div>
<div class="flex-fill flex">
<div class="content flex">
<div class="scroll-body">
@yield('body')
</div>
</div>
</div>
@stop

View File

@ -1,31 +1,26 @@
@extends('base') @extends('simple-layout')
@section('toolbar')
@include('settings/navbar', ['selected' => 'users'])
@stop
@section('content') @section('body')
<div class="faded-small toolbar">
<div class="container">
<div class="row">
<div class="col-sm-12 faded">
<div class="breadcrumbs">
<a href="{{ baseUrl('/settings/users') }}" class="text-button"><i class="zmdi zmdi-accounts"></i>{{ trans('settings.users') }}</a>
</div>
</div>
</div>
</div>
</div>
<div class="container small" ng-non-bindable> <div class="container small" ng-non-bindable>
<h1>{{ trans('settings.users_add_new') }}</h1> <p>&nbsp;</p>
<div class="card">
<h3><i class="zmdi zmdi-accounts-add"></i> {{ trans('settings.users_add_new') }}</h3>
<div class="body">
<form action="{{ baseUrl("/settings/users/create") }}" method="post"> <form action="{{ baseUrl("/settings/users/create") }}" method="post">
{!! csrf_field() !!} {!! csrf_field() !!}
@include('users/forms/' . $authMethod) @include('users/forms/' . $authMethod)
<div class="form-group"> <div class="form-group text-right">
<a href="{{ baseUrl($currentUser->can('users-manage') ? "/settings/users" : "/") }}" class="button muted">{{ trans('common.cancel') }}</a> <a href="{{ baseUrl($currentUser->can('users-manage') ? "/settings/users" : "/") }}" class="button outline">{{ trans('common.cancel') }}</a>
<button class="button pos" type="submit">{{ trans('common.save') }}</button> <button class="button pos" type="submit">{{ trans('common.save') }}</button>
</div> </div>
</form> </form>
</div> </div>
</div>
</div>
@stop @stop

View File

@ -1,32 +1,27 @@
@extends('base') @extends('simple-layout')
@section('content') @section('toolbar')
@include('settings/navbar', ['selected' => 'users'])
@stop
<div class="faded-small toolbar"> @section('body')
<div class="container">
<div class="row">
<div class="col-sm-12 faded">
<div class="breadcrumbs">
<a href="{{ baseUrl("/settings/users") }}" class="text-button"><i class="zmdi zmdi-accounts"></i>Users</a>
<span class="sep">&raquo;</span>
<a href="{{ baseUrl("/settings/users/{$user->id}") }}" class="text-button"><i class="zmdi zmdi-account"></i>{{ $user->name }}</a>
</div>
</div>
</div>
</div>
</div>
<div class="container small" ng-non-bindable> <div class="container small" ng-non-bindable>
<h1>{{ trans('settings.users_delete') }}</h1> <p>&nbsp;</p>
<div class="card">
<h3><i class="zmdi zmdi-delete"></i> {{ trans('settings.users_delete') }}</h3>
<div class="body">
<p>{{ trans('settings.users_delete_warning', ['userName' => $user->name]) }}</p> <p>{{ trans('settings.users_delete_warning', ['userName' => $user->name]) }}</p>
<p class="text-neg">{{ trans('settings.users_delete_confirm') }}</p> <p class="text-neg">{{ trans('settings.users_delete_confirm') }}</p>
<form action="{{ baseUrl("/settings/users/{$user->id}") }}" method="POST"> <form action="{{ baseUrl("/settings/users/{$user->id}") }}" method="POST">
{!! csrf_field() !!} {!! csrf_field() !!}
<input type="hidden" name="_method" value="DELETE"> <input type="hidden" name="_method" value="DELETE">
<a href="{{ baseUrl("/settings/users/{$user->id}") }}" class="button muted">{{ trans('common.cancel') }}</a> <a href="{{ baseUrl("/settings/users/{$user->id}") }}" class="button outline">{{ trans('common.cancel') }}</a>
<button type="submit" class="button neg">{{ trans('common.confirm') }}</button> <button type="submit" class="button neg">{{ trans('common.confirm') }}</button>
</form> </form>
</div> </div>
</div>
</div>
@stop @stop

View File

@ -1,23 +1,17 @@
@extends('base') @extends('simple-layout')
@section('content')
@section('toolbar')
@include('settings/navbar', ['selected' => 'users']) @include('settings/navbar', ['selected' => 'users'])
@stop
@section('body')
<div class="container small"> <div class="container small">
<p>&nbsp;</p>
<div class="card">
<h3><i class="zmdi-edit zmdi"></i> {{ $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"> <form action="{{ baseUrl("/settings/users/{$user->id}") }}" method="post">
<div class="row">
<div class="col-sm-8">
<h1>{{ $user->id === $currentUser->id ? trans('settings.users_edit_profile') : trans('settings.users_edit') }}</h1>
</div>
<div class="col-sm-4">
<p></p>
@if($authMethod !== 'system')
<a href="{{ baseUrl("/settings/users/{$user->id}/delete") }}" class="neg button float right">{{ trans('settings.users_delete') }}</a>
@endif
</div>
</div>
<div class="row"> <div class="row">
<div class="col-sm-6" ng-non-bindable> <div class="col-sm-6" ng-non-bindable>
{!! csrf_field() !!} {!! csrf_field() !!}
@ -49,29 +43,28 @@
@endforeach @endforeach
</select> </select>
</div> </div>
<div class="form-group">
<label for="books_display">{{ trans('settings.users_books_display_type') }}</label>
<select name="books_display" id="books_display">
<option @if($user->books_display === 'grid') selected @endif value="grid">Grid</option>
<option @if($user->books_display === 'list') selected @endif value="list">List</option>
</select>
</div> </div>
</div> </div>
</div> <div class="form-group text-right">
<div class="form-group"> <a href="{{ baseUrl($currentUser->can('users-manage') ? "/settings/users" : "/") }}" class="button outline">{{ trans('common.cancel') }}</a>
<a href="{{ baseUrl($currentUser->can('users-manage') ? "/settings/users" : "/") }}" class="button muted">{{ 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> <button class="button pos" type="submit">{{ trans('common.save') }}</button>
</div> </div>
</form> </form>
</div>
<hr class="margin-top large"> </div>
@if($currentUser->id === $user->id && count($activeSocialDrivers) > 0) @if($currentUser->id === $user->id && count($activeSocialDrivers) > 0)
<h3>{{ trans('settings.users_social_accounts') }}</h3> <div class="card">
<h3><i class="zmdi zmdi-sign-in"></i> {{ trans('settings.users_social_accounts') }}</h3>
<div class="body">
<p class="text-muted">{{ trans('settings.users_social_accounts_info') }}</p> <p class="text-muted">{{ trans('settings.users_social_accounts_info') }}</p>
<div class="container">
<div class="row"> <div class="row">
@foreach($activeSocialDrivers as $driver => $enabled) @foreach($activeSocialDrivers as $driver => $enabled)
<div class="col-sm-3 col-xs-6 text-center"> <div class="col-sm-4 col-xs-6 text-center">
<div>@icon($driver, ['width' => 56])</div> <div>@icon($driver, ['width' => 56])</div>
<div> <div>
@if($user->hasSocialAccount($driver)) @if($user->hasSocialAccount($driver))
@ -80,9 +73,13 @@
<a href="{{ baseUrl("/login/service/{$driver}") }}" class="button pos">{{ trans('settings.users_social_connect') }}</a> <a href="{{ baseUrl("/login/service/{$driver}") }}" class="button pos">{{ trans('settings.users_social_connect') }}</a>
@endif @endif
</div> </div>
<div>&nbsp;</div>
</div> </div>
@endforeach @endforeach
</div> </div>
</div>
</div>
</div>
@endif @endif

View File

@ -1,38 +1,31 @@
@extends('base') @extends('simple-layout')
@section('content')
@section('toolbar')
@include('settings/navbar', ['selected' => 'users']) @include('settings/navbar', ['selected' => 'users'])
@stop
@section('body')
<div class="container small" ng-non-bindable> <div class="container small" ng-non-bindable>
<div class="row action-header"> <p>&nbsp;</p>
<div class="col-sm-8"> <div class="card">
<h1>{{ trans('settings.users') }}</h1> <h3><i class="zmdi zmdi-accounts"></i> {{ trans('settings.users') }}</h3>
</div> <div class="body">
<div class="col-sm-4"> <div class="container">
<p></p>
@if(userCan('users-manage'))
<a href="{{ baseUrl("/settings/users/create") }}" class="pos button float right"><i class="zmdi zmdi-account-add"></i>{{ trans('settings.users_add_new') }}</a>
@endif
</div>
</div>
<div class="row"> <div class="row">
<div class="col-sm-8">
<div class="compact">
{{ $users->links() }}
</div>
</div>
<div class="col-sm-4"> <div class="col-sm-4">
<form method="get" class="float right" action="{{ baseUrl("/settings/users") }}"> <form method="get" action="{{ baseUrl("/settings/users") }}">
@foreach(collect($listDetails)->except('search') as $name => $val) @foreach(collect($listDetails)->except('search') as $name => $val)
<input type="hidden" name="{{ $name }}" value="{{ $val }}"> <input type="hidden" name="{{ $name }}" value="{{ $val }}">
@endforeach @endforeach
<input type="text" name="search" placeholder="{{ trans('settings.users_search') }}" @if($listDetails['search']) value="{{$listDetails['search']}}" @endif> <input type="text" name="search" placeholder="{{ trans('settings.users_search') }}" @if($listDetails['search']) value="{{$listDetails['search']}}" @endif>
</form> </form>
</div> </div>
<div class="col-sm-8 text-right">
@if(userCan('users-manage'))
<a href="{{ baseUrl("/settings/users/create") }}" style="margin-top: 0;" class="pos button">{{ trans('settings.users_add_new') }}</a>
@endif
</div>
</div>
</div> </div>
<table class="table"> <table class="table">
@ -75,6 +68,10 @@
<div> <div>
{{ $users->links() }} {{ $users->links() }}
</div> </div>
</div>
</div>
</div> </div>
@stop @stop

View File

@ -1,10 +1,23 @@
@extends('base') @extends('sidebar-layout')
@section('content') @section('toolbar')
<div class="col-sm-6 col-xs-1 faded">
<div class="breadcrumbs">
<a href="{{ $user->getProfileUrl() }}" class="text-button"><i class="zmdi zmdi-account"></i>{{ $user->name }}</a>
</div>
</div>
@stop
<div class="container" ng-non-bindable> @section('sidebar')
<div class="row"> <div class="card" id="recent-activity">
<div class="col-sm-7"> <h3><i class="zmdi zmdi-time"></i> {{ trans('entities.recent_activity') }}</h3>
@include('partials/activity-list', ['activity' => $activity])
</div>
@stop
@section('body')
<div class="container small" ng-non-bindable>
<div class="padded-top large"></div> <div class="padded-top large"></div>
@ -65,13 +78,5 @@
@endif @endif
</div> </div>
<div class="col-sm-4 col-sm-offset-1" id="recent-activity">
<h3>{{ trans('entities.recent_activity') }}</h3>
@include('partials/activity-list', ['activity' => $activity])
</div>
</div>
</div>
@stop @stop

33
tests/HomepageTest.php Normal file
View File

@ -0,0 +1,33 @@
<?php namespace Tests;
use BookStack\JointPermission;
use BookStack\Page;
use BookStack\Repos\EntityRepo;
class HomepageTest extends TestCase
{
public function test_default_homepage_visible()
{
$this->asEditor();
$homeVisit = $this->get('/');
$homeVisit->assertSee('My Recently Viewed');
$homeVisit->assertSee('Recently Updated Pages');
$homeVisit->assertSee('Recent Activity');
}
public function test_custom_homepage() {
$this->asEditor();
$name = 'My custom homepage';
$content = 'This is the body content of my custom homepage.';
$customPage = $this->newPage(['name' => $name, 'html' => $content]);
$this->setSettings(['app-homepage' => $customPage->id]);
$homeVisit = $this->get('/');
$homeVisit->assertSee($name);
$homeVisit->assertSee($content);
$homeVisit->assertSee('My Recently Viewed');
$homeVisit->assertSee('Recently Updated Pages');
$homeVisit->assertSee('Recent Activity');
}
}

View File

@ -4,6 +4,7 @@ use BookStack\Book;
use BookStack\Chapter; use BookStack\Chapter;
use BookStack\Repos\EntityRepo; use BookStack\Repos\EntityRepo;
use BookStack\Role; use BookStack\Role;
use BookStack\Services\SettingService;
use Illuminate\Foundation\Testing\DatabaseTransactions; use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase; use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
@ -88,4 +89,16 @@ abstract class TestCase extends BaseTestCase
$draftPage = $entityRepo->getDraftPage($book); $draftPage = $entityRepo->getDraftPage($book);
return $entityRepo->publishPageDraft($draftPage, $input); return $entityRepo->publishPageDraft($draftPage, $input);
} }
/**
* Quickly sets an array of settings.
* @param $settingsArray
*/
protected function setSettings($settingsArray)
{
$settings = app(SettingService::class);
foreach ($settingsArray as $key => $value) {
$settings->put($key, $value);
}
}
} }