'name' => 'required|string|max:255',
'description' => 'string|max:1000'
]);
+ $book->fill($request->all());
$slug = Str::slug($book->name);
while($this->bookRepo->countBySlug($slug) > 0 && $book->slug != $slug) {
$slug += '1';
}
$book->slug = $slug;
$book->save();
- return redirect('/books');
+ return redirect($book->getUrl());
}
/**
*/
public function show($bookSlug, $pageSlug)
{
- $page = $this->pageRepo->getBySlug($pageSlug);
+ $book = $this->bookRepo->getBySlug($bookSlug);
+ $page = $this->pageRepo->getBySlug($pageSlug, $book->id);
return view('pages/show', ['page' => $page]);
}
*/
public function edit($bookSlug, $pageSlug)
{
- $page = $this->pageRepo->getBySlug($pageSlug);
+ $book = $this->bookRepo->getBySlug($bookSlug);
+ $page = $this->pageRepo->getBySlug($pageSlug, $book->id);
return view('pages/edit', ['page' => $page]);
}
*/
public function update(Request $request, $bookSlug, $pageSlug)
{
- $page = $this->pageRepo->getBySlug($pageSlug);
$book = $this->bookRepo->getBySlug($bookSlug);
+ $page = $this->pageRepo->getBySlug($pageSlug, $book->id);
$page->fill($request->all());
$slug = Str::slug($page->name);
while($this->pageRepo->countBySlug($slug, $book->id) > 0 && $slug != $pageSlug) {
return $this->page->all();
}
- public function getBySlug($slug)
+ public function getBySlug($slug, $bookId)
{
- return $this->page->where('slug', '=', $slug)->first();
+ return $this->page->where('slug', '=', $slug)->where('book_id', '=', $bookId)->first();
}
public function newFromInput($input)
],
"dependencies": {
"dropzone": "~4.0.1",
- "tinymce-dist": "~4.2.1"
+ "tinymce-dist": "~4.2.1",
+ "bootstrap": "~3.3.5",
+ "jquery-sortable": "~0.9.13"
}
}
var elixir = require('laravel-elixir');
+require('laravel-elixir-livereload');
/*
|--------------------------------------------------------------------------
*/
elixir(function(mix) {
- mix.sass('styles.scss');
+ mix.sass('styles.scss').livereload();
});
{
"private": true,
"devDependencies": {
- "gulp": "^3.8.8"
+ "gulp": "^3.8.8",
+ "laravel-elixir-livereload": "0.0.3"
},
"dependencies": {
"laravel-elixir": "^2.0.0",
@include generate-button-colors(#EEE, $primary);
}
-.button, button[type="button"], input[type="button"], input[type="submit"] {
+.button, input[type="button"], input[type="submit"] {
@extend .button-base;
&.pos {
@include generate-button-colors(#EEE, $positive);
.form-group {
margin-bottom: $-s;
}
+
+.inline-input-style {
+ border: 2px dotted #BBB;
+ display: block;
+ width: 100%;
+ padding: $-xs $-s;
+}
+
+.title-input label, .description-input label{
+ margin-top: $-m;
+ color: #666;
+}
+
+.title-input input[type="text"] {
+ @extend h1;
+ @extend .inline-input-style;
+ margin-top: 0;
+ color: #444;
+}
+
+.title-input.page-title {
+ padding: $-s;
+}
+.title-input.page-title input[type="text"]{
+ //border: 2px dotted #BBB;
+ margin-bottom: 0;
+}
+.edit-area {
+ padding: 0 $-s $-s $-s;
+}
+
+.description-input textarea {
+ @extend .inline-input-style;
+ font-size: $fs-m;
+ color: #666;
+ width: 100%;
+}
\ No newline at end of file
box-sizing: border-box;
}
html {
- background-color: #FFF;
+ background-color: #f8f8f8;
}
body {
font-family: $text;
/*
-* Header Styles
-*/
+ * Header Styles
+ */
h1 {
font-size: 3.625em;
h4 {
font-size: 1em;
line-height: 1.375em;
- margin-top: 1.375em;
- margin-bottom: 1.375em;
+ margin-top: 0.78571429em;
+ margin-bottom: 0.43137255em;
}
h1, h2, h3, h4 {
+ font-weight: 500;
.subheader {
display: block;
font-size: 0.5em;
}
/*
-* Link styling
-*/
+ * Link styling
+ */
a {
color: $primary;
cursor: pointer;
text-decoration: underline;
color: darken($primary, 20%);
}
+ i {
+ padding-right: $-s;
+ }
}
/*
-* Other HTML Text Elements
-*/
+ * Other HTML Text Elements
+ */
p, ul, ol, pre, table, blockquote {
margin-top: 0.3em;
margin-bottom: 1.375em;
padding: 1px $-xs;
}
/*
-* Text colors
-*/
+ * Text colors
+ */
p.pos, p .pos, span.pos, .text-pos {
color: $positive;
}
}
/*
-* Generic text styling classes
-*/
+ * Generic text styling classes
+ */
.underlined {
text-decoration: underline;
}
.text-right {
text-align: right;
}
+
+/**
+ * Grouping
+ */
+.header-group {
+ margin: $-m 0;
+ h1, h2, h3, h4, h5, h6 {
+ margin: 0;
+ }
+}
\ No newline at end of file
--- /dev/null
+
+//.mce-container {
+// .mce-menubar, .mce-toolbar-grp {
+// position: fixed;
+// width: 100%;
+// }
+// .mce-container-body {
+// position: relative;
+// overflow: hidden;
+// display: block;
+// }
+//}
+
+.mce-tinymce.mce-container.fullscreen {
+ position: fixed;
+ top: 0;
+ height: 100%;
+}
\ No newline at end of file
@import "blocks";
@import "buttons";
@import "forms";
+@import "tinymce";
+
+header {
+ background-color: #f8f8f8;
+ position: fixed;
+ display: block;
+ width: 100%;
+ z-index: -1;
+ top: 0;
+}
+
+body {
+ margin-top: 64px;
+}
header hr {
margin-top: 0;
font-size: 1.4em;
}
+.affix {
+ position: fixed;
+}
+
+.page-style {
+ background-color: #FFF;
+ padding: $-s $-xxl $-xxl $-xxl;
+ border-radius: 4px;
+ box-shadow: 0 0 9px 0 rgba(0, 0, 0, 0.15);
+ margin-bottom: $-xxl;
+ max-width: 100%;
+}
+
+.page-style.editor {
+ padding: 0 !important;
+}
+
+.page-content {
+ @extend .page-style;
+ min-height: 70vh;
+ &.right {
+ float: right;
+ }
+ &.left {
+ float: left;
+ }
+}
+
+.page-list {
+ a {
+ display: block;
+ padding: $-s 0;
+ border-bottom: 2px dotted #CCC;
+ &:first-child {
+ border-top: 2px dotted #CCC;
+ }
+ }
+}
+
+.page-menu {
+ opacity: 0.6;
+ transition: opacity ease-in-out 120ms;
+ &:hover {
+ opacity: 1;
+ }
+}
+
+.page-nav-list {
+ $nav-indent: $-s;
+ li {
+ //border-left: 1px solid rgba(0, 0, 0, 0.1);
+ padding-left: $-xs;
+ }
+ .nav-H2 {
+ margin-left: $nav-indent;
+ font-size: 0.95em;
+ }
+ .nav-H3 {
+ margin-left: $nav-indent*2;
+ font-size: 0.90em
+ }
+ .nav-H4 {
+ margin-left: $nav-indent*3;
+ font-size: 0.85em
+ }
+ .nav-H5 {
+ margin-left: $nav-indent*4;
+ font-size: 0.80em
+ }
+ .nav-H6 {
+ margin-left: $nav-indent*5;
+ font-size: 0.75em
+ }
+}
+
.overlay {
background-color: rgba(0, 0, 0, 0.2);
position: fixed;
<link href='http://fonts.googleapis.com/css?family=Roboto:400,400italic,500,500italic,700,700italic,300italic,100,300' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
+ <script src="/bower/bootstrap/dist/js/bootstrap.js"></script>
+ <script>
+ $.fn.smoothScrollTo = function() {
+ $('body').animate({
+ scrollTop: this.offset().top - 60 // Adjust to change final scroll position top margin
+ }, 800); // Adjust to change animations speed (ms)
+ return this;
+ };
+ </script>
@yield('head')
</head>
<body>
- <header class="container">
- <div class="padded-vertical clearfix">
- <div class="logo float left">Oxbow</div>
- <ul class="menu float right">
- <li><a href="/books">Books</a></li>
- </ul>
+ <header>
+ <div class="container">
+ <div class="padded-vertical clearfix">
+ <div class="logo float left">Oxbow</div>
+ <ul class="menu float right">
+ <li><a href="/books"><i class="fa fa-book"></i>Books</a></li>
+ </ul>
+ </div>
</div>
- <hr>
</header>
<section class="container">
@extends('base')
@section('content')
- <h2>New Book</h2>
- <form action="/books" method="POST">
- {{ csrf_field() }}
- @include('books/form')
- </form>
+ <div class="row">
+
+ <div class="col-md-3 page-menu">
+ <h4>You are creating a new book.</h4>
+ </div>
+
+ <div class="col-md-9 page-content">
+ <form action="/books" method="POST">
+ @include('books/form')
+ </form>
+ </div>
+
+ </div>
+
@stop
\ No newline at end of file
@extends('base')
@section('content')
- <h2>Edit Book</h2>
- <form action="/books/{{$book->slug}}" method="POST">
- {{ csrf_field() }}
- <input type="hidden" name="_method" value="PUT">
- @include('books/form', ['model' => $book])
- </form>
+
+ <div class="row">
+
+ <div class="col-md-3 page-menu">
+ <h4>You are editing the details for the book '{{$book->name}}'.</h4>
+ <hr>
+ @include('form/delete-button', ['url' => '/books/' . $book->id . '/destroy', 'text' => 'Delete this book'])
+ </div>
+
+ <div class="col-md-9 page-content">
+ <form action="/books/{{$book->slug}}" method="POST">
+ <input type="hidden" name="_method" value="PUT">
+ @include('books/form', ['model' => $book])
+ </form>
+ </div>
+
+ </div>
+
+
+
+
@stop
\ No newline at end of file
-<div class="form-group">
- <label for="name">Name</label>
+
+{{ csrf_field() }}
+<div class="form-group title-input">
+ <label for="name">Book Name</label>
@include('form/text', ['name' => 'name'])
</div>
-<div class="form-group">
+<div class="form-group description-input">
<label for="description">Description</label>
@include('form/textarea', ['name' => 'description'])
</div>
@section('content')
+
<div class="row">
- <div class="col-md-6">
+
+ <div class="col-md-3 page-menu">
+ <h4>Books</h4>
<a href="/books/create">+ Add new book</a>
</div>
- </div>
- <div class="row">
- @foreach($books as $book)
- <div class="col-md-4 shaded book">
- <h3><a href="{{$book->getUrl()}}">{{$book->name}}</a></h3>
- <p>{{$book->description}}</p>
- <div class="buttons">
- <a href="{{$book->getEditUrl()}}" class="button secondary">Edit</a>
- @include('form/delete-button', ['url' => '/books/' . $book->id . '/destroy', 'text' => 'Delete'])
- </div>
+ <div class="col-md-9">
+
+ <div class="row">
+ @foreach($books as $book)
+ <div class="col-md-6">
+ <div class="book page-style">
+ <h3><a href="{{$book->getUrl()}}">{{$book->name}}</a></h3>
+ <p class="text-muted">{{$book->description}}</p>
+ </div>
+ </div>
+ @endforeach
</div>
- @endforeach
+
+ </div>
</div>
+
+
@stop
\ No newline at end of file
@section('content')
- <h2>{{$book->name}}</h2>
- <p class="text-muted">{{$book->description}}</p>
- <a href="{{$book->getUrl() . '/page/create'}}">+ New Page</a>
-
- <h4>Pages:</h4>
- @if(count($book->pages) > 0)
- @foreach($book->pages as $page)
- <a href="{{$page->getUrl()}}">{{$page->name}}</a><br>
- @endforeach
- @else
- <p class="text-muted">This book has no pages</p>
- @endif
+
+ <div class="row">
+
+ <div class="col-md-3 page-menu">
+ <h4>Book Actions</h4>
+ <div class="buttons">
+ <a href="{{$book->getEditUrl()}}"><i class="fa fa-pencil"></i>Edit Book</a>
+ </div>
+ </div>
+
+ <div class="page-content col-md-9 float left">
+ <h1>{{$book->name}}</h1>
+ <p class="text-muted">{{$book->description}}</p>
+
+ <div class="clearfix header-group">
+ <h4 class="float">Pages</h4>
+ <a href="{{$book->getUrl() . '/page/create'}}" class="text-pos float right">+ New Page</a>
+ </div>
+ <div class="page-list">
+ @if(count($book->pages) > 0)
+ @foreach($book->pages as $page)
+ <a href="{{$page->getUrl()}}">{{$page->name}}</a>
+ @endforeach
+ @else
+ <p class="text-muted">This book has no pages</p>
+ @endif
+ </div>
+
+ <p>
+
+ </p>
+
+
+ </div>
+
+
+ </div>
+
@stop
\ No newline at end of file
-<form action="{{$url}}" method="POST">
+<form action="{{$url}}" method="POST" class="inline">
{{ csrf_field() }}
<input type="hidden" name="_method" value="DELETE">
<button type="submit" class="button neg">{{ isset($text) ? $text : 'Delete' }}</button>
-<textarea id="{{ $name }}" name="{{ $name }}"
+<textarea id="{{ $name }}" name="{{ $name }}" rows="5"
@if($errors->has($name)) class="neg" @endif>@if(isset($model) || old($name)){{ old($name) ? old($name) : $model->$name}}@endif</textarea>
@if($errors->has($name))
<div class="text-neg text-small">{{ $errors->first($name) }}</div>
@extends('base')
@section('head')
- <link rel="stylesheet" href="/plugins/css/froala_editor.min.css">
- <link rel="stylesheet" href="/plugins/css/froala_style.min.css">
- <script src="/plugins/js/froala_editor.min.js"></script>
+ <script src="/bower/tinymce-dist/tinymce.jquery.min.js"></script>
+ <script src="/bower/dropzone/dist/min/dropzone.min.js"></script>
+ <script src="/js/image-manager.js"></script>
@stop
@section('content')
@stop
@section('content')
- <form action="{{$page->getUrl()}}" method="POST">
- <input type="hidden" name="_method" value="PUT">
- @include('pages/form', ['model' => $page])
- </form>
- <section class="overlay" style="display:none;">
- <div id="image-manager">
- <div class="image-manager-left">
- <div class="image-manager-header">
- <button type="button" class="button neg float right" data-action="close">Close</button>
- <div class="image-manager-title">Image Library</div>
- </div>
- <div class="image-manager-display">
- </div>
- <form action="/upload/image" class="image-manager-dropzone">
- {{ csrf_field() }}
- Drag images or click here to upload
- </form>
- </div>
- {{--<div class="sidebar">--}}
+ <div class="row">
+ <form action="{{$page->getUrl()}}" method="POST">
+ <input type="hidden" name="_method" value="PUT">
+ @include('pages/form', ['model' => $page])
+ </form>
+ </div>
- {{--</div>--}}
- </div>
- </section>
-
- <script>
- $(function() {
- //ImageManager.show('#image-manager');
-
- tinymce.init({
- selector: '.edit-area textarea',
- content_css: '/css/app.css',
- body_class: 'container',
- plugins: "autoresize image table textcolor paste link imagetools",
- content_style: "body {padding-left: 15px !important; padding-right: 15px !important;}",
- file_browser_callback: function(field_name, url, type, win) {
- ImageManager.show('#image-manager', function(image) {
- win.document.getElementById(field_name).value = image.url;
- if ("createEvent" in document) {
- var evt = document.createEvent("HTMLEvents");
- evt.initEvent("change", false, true);
- win.document.getElementById(field_name).dispatchEvent(evt);
- } else {
- win.document.getElementById(field_name).fireEvent("onchange");
- }
- });
- }
- });
-
-
-
- });
- </script>
@stop
\ No newline at end of file
-{{ csrf_field() }}
-<div class="page-title row">
- <div class="col-md-10">
- @include('form/text', ['name' => 'name', 'placeholder' => 'Enter Page Title'])
+
+<div class="col-md-3 page-menu">
+ <h4>You are editing a page</h4>
+ <button type="submit" class="button pos">Save Page</button>
+</div>
+
+<div class="col-md-9 page-style editor">
+
+ {{ csrf_field() }}
+ <div class="title-input page-title">
+ @include('form/text', ['name' => 'name', 'placeholder' => 'Enter Page Title'])
</div>
- <div class="col-md-2">
- <button type="submit" class="button pos">Save</button>
+ <div class="edit-area">
+ @include('form/textarea', ['name' => 'html'])
</div>
+
</div>
-<div class="edit-area">
- @include('form/textarea', ['name' => 'html'])
-</div>
+
+
+<section class="overlay" style="display:none;">
+ <div id="image-manager">
+ <div class="image-manager-left">
+ <div class="image-manager-header">
+ <button type="button" class="button neg float right" data-action="close">Close</button>
+ <div class="image-manager-title">Image Library</div>
+ </div>
+ <div class="image-manager-display">
+ </div>
+ <form action="/upload/image" class="image-manager-dropzone">
+ {{ csrf_field() }}
+ Drag images or click here to upload
+ </form>
+ </div>
+ {{--<div class="sidebar">--}}
+
+ {{--</div>--}}
+ </div>
+</section>
+
+<script>
+ $(function() {
+ //ImageManager.show('#image-manager');
+
+ tinymce.init({
+ selector: '.edit-area textarea',
+ content_css: '/css/app.css',
+ body_class: 'container',
+ relative_urls: false,
+ height: 600,
+ plugins: "image table textcolor paste link imagetools",
+ toolbar: "undo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | table | fontsizeselect full",
+ content_style: "body {padding-left: 15px !important; padding-right: 15px !important; margin:0!important}",
+ file_browser_callback: function(field_name, url, type, win) {
+ ImageManager.show('#image-manager', function(image) {
+ win.document.getElementById(field_name).value = image.url;
+ if ("createEvent" in document) {
+ var evt = document.createEvent("HTMLEvents");
+ evt.initEvent("change", false, true);
+ win.document.getElementById(field_name).dispatchEvent(evt);
+ } else {
+ win.document.getElementById(field_name).fireEvent("onchange");
+ }
+ });
+ },
+ setup: function(editor) {
+ editor.addButton('full', {
+ text: 'Expand',
+ icon: false,
+ onclick: function() {
+ var container = $(editor.getContainer()).toggleClass('fullscreen');
+ }
+ });
+ }
+ });
+
+
+
+ });
+</script>
\ No newline at end of file
@section('content')
- <a href="{{$page->getUrl() . '/edit'}}" class="button primary float right">Edit Page</a>
+ <div class="row">
+ <div class="page-menu col-md-3">
+ <div class="page-nav">
+ <h4>Navigation</h4>
+ <ul class="page-nav-list"></ul>
+ </div>
+ <div class="page-actions">
+ <h4>Actions</h4>
+ <a href="{{$page->getUrl() . '/edit'}}" class="muted"><i class="fa fa-pencil"></i>Edit this page</a>
+ </div>
+ </div>
- <h1>{{$page->name}}</h1>
-
- <div class="page-content">
- {!! $page->html !!}
+ <div class="page-content right col-md-9">
+ <h1>{{$page->name}}</h1>
+ {!! $page->html !!}
+ </div>
</div>
+
+ <script>
+ $(document).ready(function() {
+
+ // Set up fixed side menu
+ $('.page-menu').affix({
+ offset: {
+ top: 10,
+ bottom: function () {
+ return (this.bottom = $('.footer').outerHeight(true))
+ }
+ }
+ });
+
+ // Set up document navigation
+ var pageNav = $('.page-nav-list');
+ var pageContent = $('.page-content');
+ var headers = pageContent.find('h1, h2, h3, h4, h5, h6');
+ var sortedHeaders = [];
+ headers.each(function() {
+ var header = $(this);
+ var tag = header.prop('tagName');
+ var listElem = $('<li></li>').addClass('nav-'+tag);
+ var link = $('<a></a>').text(header.text().trim()).attr('href', '#');
+ listElem.append(link);
+ pageNav.append(listElem);
+ link.click(function(e) {
+ e.preventDefault();
+ header.smoothScrollTo();
+ })
+ });
+ });
+ </script>
@stop