├── resources ├── sass │ ├── app.scss │ └── plugins │ │ └── nestable.scss ├── templates │ └── clean-blog │ │ ├── views │ │ ├── widgets │ │ │ ├── menu │ │ │ │ ├── dropdown.blade.php │ │ │ │ ├── menu-header.blade.php │ │ │ │ ├── menu-footer.blade.php │ │ │ │ └── menuitem.blade.php │ │ │ └── category │ │ │ │ ├── menu.blade.php │ │ │ │ └── main.blade.php │ │ ├── partials │ │ │ ├── comment │ │ │ │ ├── childcomments.blade.php │ │ │ │ └── comments.blade.php │ │ │ ├── carousel.blade.php │ │ │ └── pagination.blade.php │ │ ├── pages │ │ │ ├── blog.blade.php │ │ │ ├── category.blade.php │ │ │ └── post.blade.php │ │ └── layouts │ │ │ └── app.blade.php │ │ ├── js │ │ ├── components │ │ │ └── ExampleComponent.vue │ │ ├── app.js │ │ └── bootstrap.js │ │ └── sass │ │ ├── app.scss │ │ ├── _variables.scss │ │ └── theme │ │ └── theme.scss ├── js │ ├── app.js │ └── controllers │ │ ├── fields │ │ └── tag_controller.js │ │ └── components │ │ └── menu_controller.js ├── views │ ├── fields │ │ └── tags.blade.php │ ├── container │ │ └── posts │ │ │ ├── restore.blade.php │ │ │ └── edit.blade.php │ └── partials │ │ └── menu │ │ └── item.blade.php ├── stubs │ ├── single.stub │ └── many.stub └── lang │ ├── ru.json │ └── uk.json ├── public ├── clean-blog │ └── img │ │ ├── home-bg.jpg │ │ ├── post-bg.jpg │ │ ├── about-bg.jpg │ │ ├── bg-masthead.jpg │ │ ├── contact-bg.jpg │ │ ├── post-sample-image.jpg │ │ └── portfolio │ │ ├── fullsize │ │ ├── 1.jpg │ │ ├── 2.jpg │ │ ├── 3.jpg │ │ ├── 4.jpg │ │ ├── 5.jpg │ │ └── 6.jpg │ │ └── thumbnails │ │ ├── 1.jpg │ │ ├── 2.jpg │ │ ├── 3.jpg │ │ ├── 4.jpg │ │ ├── 5.jpg │ │ └── 6.jpg ├── mix-manifest.json └── css │ └── press.css ├── src ├── Models │ ├── Page.php │ ├── Tagged.php │ ├── TermRelationship.php │ ├── Term.php │ ├── Menu.php │ ├── Category.php │ ├── Tag.php │ ├── Taxonomy.php │ └── Comment.php ├── Screen │ ├── Actions │ │ └── Link.php │ └── Fields │ │ └── Tags.php ├── Http │ ├── Layouts │ │ ├── EntitiesSelection.php │ │ ├── Comment │ │ │ ├── CommentEditLayout.php │ │ │ └── CommentListLayout.php │ │ └── Category │ │ │ ├── CategoryListLayout.php │ │ │ └── CategoryEditLayout.php │ ├── Widgets │ │ ├── CategoryWidget.php │ │ └── MenuWidget.php │ ├── Controllers │ │ ├── Systems │ │ │ └── TagsController.php │ │ └── MenuController.php │ ├── Filters │ │ ├── StatusFilter.php │ │ ├── CreatedFilter.php │ │ └── SearchFilter.php │ ├── Screens │ │ ├── Comment │ │ │ ├── CommentListScreen.php │ │ │ └── CommentEditScreen.php │ │ ├── Category │ │ │ ├── CategoryListScreen.php │ │ │ └── CategoryEditScreen.php │ │ ├── EntityListScreen.php │ │ └── EntityEditScreen.php │ └── Composers │ │ ├── PressMenuComposer.php │ │ └── SystemMenuComposer.php ├── Exceptions │ └── EntityTypeException.php ├── Entities │ ├── Single.php │ ├── EntityContract.php │ ├── Actions.php │ ├── Many.php │ └── Structure.php ├── Support │ ├── macros.php │ └── helpers.php ├── Commands │ ├── MakeEntityMany.php │ ├── MakeEntitySingle.php │ └── TemplateCommand.php ├── Builders │ └── TaxonomyBuilder.php └── Providers │ ├── RouteServiceProvider.php │ ├── WebServiceProvider.php │ └── PressServiceProvider.php ├── .github └── ISSUE_TEMPLATE ├── .babelrc ├── database ├── seeds │ ├── TermsTableSeeder.php │ ├── PagesTableSeeder.php │ ├── PressDatabaseSeeder.php │ ├── MenusTableSeeder.php │ └── PostsTableSeeder.php ├── factories │ ├── CommentFactory.php │ ├── TaxonomyFactory.php │ ├── TermFactory.php │ ├── MenuFactory.php │ ├── PageFactory.php │ └── PostFactory.php └── migrations │ └── press │ ├── 2016_12_06_070031_create_orchid_terms_table.php │ ├── 2015_04_15_105754_create_orchid_menu_table.php │ ├── 2016_12_06_070036_create_orchid_taxonomy_table.php │ ├── 2016_12_06_070037_create_orchid_relationships_table.php │ ├── 2015_04_15_102754_create_orchid_tags_table.php │ ├── 2016_02_09_194940_create_orchid_post_table.php │ └── 2016_12_06_070037_create_orchid_comments_table.php ├── install-stubs ├── routes │ └── press.php ├── Orchid │ └── Entities │ │ └── Page.php └── Controllers │ └── PressController.php ├── routes ├── bindings.php ├── press.php └── breadcrumbs.php ├── webpack.mix.js ├── composer.json ├── package.json ├── phpunit.xml └── config └── press.php /resources/sass/app.scss: -------------------------------------------------------------------------------- 1 | @import "plugins/nestable"; 2 | -------------------------------------------------------------------------------- /public/clean-blog/img/home-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orchidcommunity/press/HEAD/public/clean-blog/img/home-bg.jpg -------------------------------------------------------------------------------- /public/clean-blog/img/post-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orchidcommunity/press/HEAD/public/clean-blog/img/post-bg.jpg -------------------------------------------------------------------------------- /public/clean-blog/img/about-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orchidcommunity/press/HEAD/public/clean-blog/img/about-bg.jpg -------------------------------------------------------------------------------- /public/clean-blog/img/bg-masthead.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orchidcommunity/press/HEAD/public/clean-blog/img/bg-masthead.jpg -------------------------------------------------------------------------------- /public/clean-blog/img/contact-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orchidcommunity/press/HEAD/public/clean-blog/img/contact-bg.jpg -------------------------------------------------------------------------------- /public/clean-blog/img/post-sample-image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orchidcommunity/press/HEAD/public/clean-blog/img/post-sample-image.jpg -------------------------------------------------------------------------------- /public/clean-blog/img/portfolio/fullsize/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orchidcommunity/press/HEAD/public/clean-blog/img/portfolio/fullsize/1.jpg -------------------------------------------------------------------------------- /public/clean-blog/img/portfolio/fullsize/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orchidcommunity/press/HEAD/public/clean-blog/img/portfolio/fullsize/2.jpg -------------------------------------------------------------------------------- /public/clean-blog/img/portfolio/fullsize/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orchidcommunity/press/HEAD/public/clean-blog/img/portfolio/fullsize/3.jpg -------------------------------------------------------------------------------- /public/clean-blog/img/portfolio/fullsize/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orchidcommunity/press/HEAD/public/clean-blog/img/portfolio/fullsize/4.jpg -------------------------------------------------------------------------------- /public/clean-blog/img/portfolio/fullsize/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orchidcommunity/press/HEAD/public/clean-blog/img/portfolio/fullsize/5.jpg -------------------------------------------------------------------------------- /public/clean-blog/img/portfolio/fullsize/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orchidcommunity/press/HEAD/public/clean-blog/img/portfolio/fullsize/6.jpg -------------------------------------------------------------------------------- /public/clean-blog/img/portfolio/thumbnails/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orchidcommunity/press/HEAD/public/clean-blog/img/portfolio/thumbnails/1.jpg -------------------------------------------------------------------------------- /public/clean-blog/img/portfolio/thumbnails/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orchidcommunity/press/HEAD/public/clean-blog/img/portfolio/thumbnails/2.jpg -------------------------------------------------------------------------------- /public/clean-blog/img/portfolio/thumbnails/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orchidcommunity/press/HEAD/public/clean-blog/img/portfolio/thumbnails/3.jpg -------------------------------------------------------------------------------- /public/clean-blog/img/portfolio/thumbnails/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orchidcommunity/press/HEAD/public/clean-blog/img/portfolio/thumbnails/4.jpg -------------------------------------------------------------------------------- /public/clean-blog/img/portfolio/thumbnails/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orchidcommunity/press/HEAD/public/clean-blog/img/portfolio/thumbnails/5.jpg -------------------------------------------------------------------------------- /public/clean-blog/img/portfolio/thumbnails/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orchidcommunity/press/HEAD/public/clean-blog/img/portfolio/thumbnails/6.jpg -------------------------------------------------------------------------------- /public/mix-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "/clean-blog/js/app.js": "/clean-blog/js/app.js", 3 | "/js/press.js": "/js/press.js", 4 | "/css/press.css": "/css/press.css", 5 | "/clean-blog/css/app.css": "/clean-blog/css/app.css" 6 | } 7 | -------------------------------------------------------------------------------- /src/Models/Page.php: -------------------------------------------------------------------------------- 1 | style}}" 3 | href="{{$item->slug}}" 4 | title="{{$item->title}}" 5 | target="{{$item->target}}" 6 | rel="{{$item->robot}}" 7 | > 8 | {{$item->label}} 9 | 10 | @endforeach 11 | -------------------------------------------------------------------------------- /resources/templates/clean-blog/views/widgets/menu/menu-header.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 9 | -------------------------------------------------------------------------------- /src/Models/Tagged.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | -------------------------------------------------------------------------------- /resources/js/app.js: -------------------------------------------------------------------------------- 1 | import ComponentsMenu from "./controllers/components/menu_controller"; 2 | import FieldsTag from "./controllers/fields/tag_controller"; 3 | 4 | require('nestable2'); 5 | 6 | //We can work with this only when we already have an application 7 | if (typeof window.application !== 'undefined') { 8 | window.application.register('components--menu', ComponentsMenu); 9 | window.application.register('fields--tag', FieldsTag); 10 | } -------------------------------------------------------------------------------- /resources/views/fields/tags.blade.php: -------------------------------------------------------------------------------- 1 | @component($typeForm, get_defined_vars()) 2 |
3 | 10 |
11 | @endcomponent 12 | -------------------------------------------------------------------------------- /resources/templates/clean-blog/views/widgets/category/menu.blade.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/Screen/Actions/Link.php: -------------------------------------------------------------------------------- 1 | name('Locale'); 20 | $link->view = $view; 21 | 22 | return $link; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /resources/templates/clean-blog/views/widgets/category/main.blade.php: -------------------------------------------------------------------------------- 1 | 2 |
3 |
{{ __('Categories') }}
4 |
5 |
6 |
7 | 14 |
15 |
16 |
17 |
-------------------------------------------------------------------------------- /database/seeds/TermsTableSeeder.php: -------------------------------------------------------------------------------- 1 | create()->each(function ($u) { 19 | $u->taxonomy()->saveMany(factory(Taxonomy::class, 1)->make()); 20 | }); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /database/seeds/PagesTableSeeder.php: -------------------------------------------------------------------------------- 1 | where('slug', '=', $page)->count() === 0) { 20 | factory(Post::class)->create(['type' => 'page', 'slug' => $page]); 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /resources/templates/clean-blog/views/partials/comment/childcomments.blade.php: -------------------------------------------------------------------------------- 1 | {{-- Child comments --}} 2 | 3 | @foreach($comments as $comment) 4 |
5 | 6 |
7 |
{{$comment->author->name}} от {{$comment->updated_at->diffForHumans()}}
8 | {{$comment->content}} 9 | @if($comment->replies->where('approved', 1)->count() > 0) 10 | @include('partials.comment.childcomments',['comments' => $comment->replies->where('approved', 1)]) 11 | @endif 12 |
13 |
14 | @endforeach -------------------------------------------------------------------------------- /src/Http/Layouts/EntitiesSelection.php: -------------------------------------------------------------------------------- 1 | filters = $filters; 24 | } 25 | 26 | /** 27 | * @return array 28 | */ 29 | public function filters(): array 30 | { 31 | return $this->filters; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Exceptions/EntityTypeException.php: -------------------------------------------------------------------------------- 1 | message = 'Field '.$type.' does not exist or inheritance FieldContract'; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /resources/templates/clean-blog/js/components/ExampleComponent.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 24 | -------------------------------------------------------------------------------- /resources/views/container/posts/restore.blade.php: -------------------------------------------------------------------------------- 1 | @section('flash_notification.sub_message') 2 | @if(session('restore')) 3 | 8 | {{__('Restore the record.')}} 9 | 10 | 11 | 20 | @endif 21 | @stop -------------------------------------------------------------------------------- /resources/views/partials/menu/item.blade.php: -------------------------------------------------------------------------------- 1 | @foreach($menu as $item) 2 |
  • getAttributes() as $name => $value) 4 | data-{{$name}}="{{is_bool($value) ? intval($value) : $value}}" 5 | @endforeach 6 | > 7 |
    {{ __('Drag') }}
    8 |
    {{$item->label}}
    9 | 10 | @if($item->children->count() > 0) 11 |
      12 | @include('press::partials.menu.item',[ 13 | 'menu' => $item->children 14 | ]) 15 |
    16 | @endif 17 |
  • 18 | @endforeach 19 | -------------------------------------------------------------------------------- /resources/templates/clean-blog/js/app.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * First we will load all of this project's JavaScript dependencies which 4 | * includes Vue and other libraries. It is a great starting point when 5 | * building robust, powerful web applications using Vue and Laravel. 6 | */ 7 | 8 | require('./bootstrap'); 9 | 10 | window.Vue = require('vue'); 11 | 12 | /** 13 | * Next, we will create a fresh Vue application instance and attach it to 14 | * the page. Then, you may begin adding components to this application 15 | * or customize the JavaScript scaffolding to fit your unique needs. 16 | */ 17 | 18 | Vue.component('example-component', require('./components/ExampleComponent.vue')); 19 | 20 | const app = new Vue({ 21 | el: '#app' 22 | }); 23 | 24 | -------------------------------------------------------------------------------- /database/factories/CommentFactory.php: -------------------------------------------------------------------------------- 1 | define(Comment::class, function (Faker $faker) { 18 | return [ 19 | 'content' => $faker->paragraph(2, true), 20 | 'approved' => $faker->randomElement([0, 1]), 21 | ]; 22 | }); 23 | -------------------------------------------------------------------------------- /src/Http/Widgets/CategoryWidget.php: -------------------------------------------------------------------------------- 1 | handler($arg); 17 | } 18 | 19 | /** 20 | * @return mixed 21 | */ 22 | public function handler($type = 'main') 23 | { 24 | $category = Category::with('allChildrenTerm') 25 | ->with('term') 26 | ->get(); 27 | 28 | //dd($category); 29 | 30 | return view(config('press.view').'widgets.category.'.$type, [ 31 | 'category' => $category, 32 | ]); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Entities/Single.php: -------------------------------------------------------------------------------- 1 | title(__('Time of Publication')), 27 | 28 | Select::make('status') 29 | ->options($this->status()) 30 | ->title(__('Status')), 31 | ]; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /database/seeds/PressDatabaseSeeder.php: -------------------------------------------------------------------------------- 1 | call([ 22 | //TermsTableSeeder::class, 23 | //MenusTableSeeder::class, 24 | //PagesTableSeeder::class, 25 | //PostsTableSeeder::class, 26 | //\Orchid\Database\Seeds\SettingsTableSeeder::class, 27 | ]); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /database/migrations/press/2016_12_06_070031_create_orchid_terms_table.php: -------------------------------------------------------------------------------- 1 | increments('id'); 16 | $table->string('slug')->unique(); 17 | $table->jsonb('content'); 18 | $table->integer('term_group')->default(0); 19 | $table->timestamps(); 20 | }); 21 | } 22 | 23 | /** 24 | * Reverse the migrations. 25 | */ 26 | public function down() 27 | { 28 | Schema::drop('terms'); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /resources/templates/clean-blog/sass/app.scss: -------------------------------------------------------------------------------- 1 | 2 | // Fonts 3 | @import url("https://fonts.googleapis.com/css?family=Raleway:300,400,600"); 4 | @import url(https://fonts.googleapis.com/css?family=Lora:400,400i,700,700i&subset=cyrillic); 5 | @import url(https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800); 6 | 7 | // Variables 8 | @import "variables"; 9 | 10 | // Bootstrap 11 | 12 | @import "~bootstrap/scss/bootstrap"; 13 | @import "~@fortawesome/fontawesome-free/scss/fontawesome"; 14 | @import "~@fortawesome/fontawesome-free/scss/brands"; 15 | @import "~@fortawesome/fontawesome-free/scss/solid"; 16 | @import "~@fortawesome/fontawesome-free/scss/regular"; 17 | @import "~startbootstrap-clean-blog/scss/clean-blog"; 18 | @import "~startbootstrap-creative/scss/creative"; 19 | @import "theme/theme"; 20 | -------------------------------------------------------------------------------- /install-stubs/routes/press.php: -------------------------------------------------------------------------------- 1 | router->get('/', [PressController::class, 'index'])->name('home'); 6 | 7 | $this->router->get('tag/{tag}', [PressController::class, 'tagsPosts']) 8 | ->name('tag.posts'); 9 | 10 | $this->router->get('/{term}', [PressController::class, 'category']) 11 | //->where('cat','^(?!dashboard).*$') 12 | ->name('posts'); 13 | 14 | $this->router->get('/{term}/{post}', [PressController::class, 'post']) 15 | //->where('cat','^(?!dashboard).*$') 16 | ->name('post'); 17 | 18 | /* 19 | $this->router->get('/category/{term}/{post}',[PressController::class, 'post']) 20 | //->where('cat','^(?!dashboard).*$') 21 | ->name('category.post'); 22 | 23 | $this->router->get('/category/{term}',[PressController::class, 'category']) 24 | ->name('category'); 25 | */ 26 | -------------------------------------------------------------------------------- /database/seeds/MenusTableSeeder.php: -------------------------------------------------------------------------------- 1 | $MenuType]; 21 | 22 | factory(Menu::class, 5)->create($Type)->each(function ($u) use ($Type) { 23 | $u->children()->saveMany(factory(Menu::class, 2)->create($Type) 24 | ->each(function ($p) use ($Type) { 25 | $p->children()->saveMany(factory(Menu::class, 2)->make($Type)); 26 | })); 27 | }); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Http/Widgets/MenuWidget.php: -------------------------------------------------------------------------------- 1 | handler($arg); 19 | } 20 | 21 | /** 22 | * @return mixed 23 | */ 24 | public function handler($type = 'header') 25 | { 26 | $menu = Menu::where('lang', config('app.locale')) 27 | ->where('parent', 0) 28 | ->where('type', $type) 29 | ->orderBy('sort', 'Asc') 30 | ->with('children') 31 | ->get(); 32 | //dd($menu); 33 | 34 | return view(config('press.view').'widgets.menu.menu-'.$type, [ 35 | 'menu' => $menu, 36 | ]); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /database/seeds/PostsTableSeeder.php: -------------------------------------------------------------------------------- 1 | create()->each(function ($p) { 20 | $p->comments()->saveMany(factory(Comment::class, 2)->create(['post_id' => $p->id]) 21 | ->each(function ($c) { 22 | $c->replies()->saveMany(factory(Comment::class, 1)->make(['post_id' => $c->post_id, 'parent_id' => $c->id])); 23 | })); 24 | factory(Attachmentable::class, 4)->create(['attachmentable_id' => $p->id]); 25 | }); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /resources/templates/clean-blog/views/widgets/menu/menuitem.blade.php: -------------------------------------------------------------------------------- 1 | @category('menu') 2 | 3 | @foreach($menu as $item) 4 | @if($item->children->count() > 0) 5 | 17 | @else 18 | 28 | @endif 29 | @endforeach 30 | -------------------------------------------------------------------------------- /src/Http/Layouts/Comment/CommentEditLayout.php: -------------------------------------------------------------------------------- 1 | max(255) 25 | ->rows(10) 26 | ->required() 27 | ->title(__('Content')) 28 | ->help(__('User comment')), 29 | 30 | CheckBox::make('comment.approved') 31 | ->title(__('Checking')) 32 | ->help(__('Show comment')) 33 | ->sendTrueOrFalse(), 34 | ]; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Http/Controllers/Systems/TagsController.php: -------------------------------------------------------------------------------- 1 | where('name', 'like', '%'.$tag.'%') 24 | ->limit(10) 25 | ->get() 26 | ->map(function ($item) { 27 | return [ 28 | 'id' => $item['name'], 29 | 'text' => $item['name'], 30 | 'count' => $item['count'], 31 | ]; 32 | }) 33 | ->toArray(); 34 | 35 | return response()->json($tags); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /database/factories/TaxonomyFactory.php: -------------------------------------------------------------------------------- 1 | define(Taxonomy::class, function (Faker $faker) { 18 | $taxonomy = $faker->randomElement($array = ['category', 'goods']); 19 | $parent = Taxonomy::where('taxonomy', $taxonomy)->get()->count(); 20 | $parent_id = ($parent > 0) ? Taxonomy::where('taxonomy', $taxonomy)->inRandomOrder()->first()->id : null; 21 | 22 | return [ 23 | 'taxonomy' => $taxonomy, 24 | 'parent_id' => $faker->randomElement($array = [null, $parent_id]), 25 | ]; 26 | }); 27 | -------------------------------------------------------------------------------- /resources/stubs/single.stub: -------------------------------------------------------------------------------- 1 | define(Term::class, function (Faker $faker) { 19 | $lang = app()->getLocale(); 20 | 21 | return [ 22 | 'slug' => Str::slug($faker->unique()->sentence($nbWords = 2, $variableNbWords = true)), 23 | 'content' => [ 24 | $lang => [ 25 | 'name' => $faker->sentence($nbWords = 2, $variableNbWords = true), 26 | 'body' => $faker->text, 27 | ], 28 | ], 29 | 'term_group' => $faker->randomElement($array = [0, 1, 2]), 30 | ]; 31 | }); 32 | -------------------------------------------------------------------------------- /routes/bindings.php: -------------------------------------------------------------------------------- 1 | where('id', $value)->firstOrFail(); 13 | }); 14 | 15 | Route::bind('type', function ($value) { 16 | $post = Dashboard::modelClass(Post::class); 17 | 18 | return $post->getEntity($value)->getEntityObject(); 19 | }); 20 | 21 | Route::bind('page', function ($value) { 22 | $model = Dashboard::modelClass(Page::class); 23 | 24 | $page = $model->where('id', $value) 25 | ->orWhere('slug', $value) 26 | ->first(); 27 | 28 | if ($page === null) { 29 | $model->slug = $value; 30 | $page = $model; 31 | } 32 | 33 | return $page; 34 | }); 35 | 36 | Route::bind('post', function ($value) { 37 | $post = Dashboard::modelClass(Post::class); 38 | 39 | return $post->where('id', $value) 40 | ->orWhere('slug', $value) 41 | ->firstOrFail(); 42 | }); 43 | -------------------------------------------------------------------------------- /src/Models/TermRelationship.php: -------------------------------------------------------------------------------- 1 | belongsTo(Dashboard::model(Post::class), 'post_id'); 38 | } 39 | 40 | /** 41 | * @return \Illuminate\Database\Eloquent\Relations\BelongsTo 42 | */ 43 | public function taxonomy(): BelongsTo 44 | { 45 | return $this->belongsTo(Dashboard::model(Taxonomy::class), 'term_taxonomy_id'); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /webpack.mix.js: -------------------------------------------------------------------------------- 1 | let mix = require('laravel-mix'); 2 | 3 | /* 4 | |-------------------------------------------------------------------------- 5 | | Mix Asset Management 6 | |-------------------------------------------------------------------------- 7 | | 8 | | Mix provides a clean, fluent API for defining some Webpack build steps 9 | | for your Laravel application. By default, we are compiling the Sass 10 | | file for the application as well as bundling up all the JS files. 11 | | 12 | */ 13 | 14 | let theme = process.env.PRESS_THEME || 'clean-blog'; 15 | //mix.setPublicPath(path.normalize('public/' + theme)); 16 | mix.setPublicPath(path.normalize('public')); 17 | 18 | mix 19 | .sass('resources/sass/app.scss', 'css/press.css') 20 | .js('resources/js/app.js', 'js/press.js') 21 | .copyDirectory('./node_modules/startbootstrap-clean-blog/img', 'public/' + theme + '/img') 22 | .copyDirectory('./node_modules/startbootstrap-creative/img', 'public/' + theme + '/img') 23 | .js('resources/templates/'+ theme + '/js/app.js', theme + '/js') 24 | .sass('resources/templates/'+ theme + '/sass/app.scss', theme + '/css') 25 | .copyDirectory('public/fonts', 'public/' + theme + '/fonts'); 26 | -------------------------------------------------------------------------------- /resources/templates/clean-blog/views/partials/comment/comments.blade.php: -------------------------------------------------------------------------------- 1 | {{-- Comments --}} 2 | {{-- dd(Auth::user()) --}} 3 | 4 | @if (Auth::user()) 5 |
    6 |
    Leave a Comment:
    7 |
    8 |
    9 |
    10 | 11 |
    12 | 13 |
    14 |
    15 |
    16 | @endif 17 | 18 | @foreach($comments as $comment) 19 |
    20 | 21 |
    22 |
    {{$comment->author->name}} от {{$comment->updated_at->diffForHumans()}}
    23 | {{$comment->content}} 24 | @if($comment->replies->where('approved', 1)->count() > 0) 25 | @include('partials.comment.childcomments',['comments' => $comment->replies->where('approved', 1)]) 26 | @endif 27 |
    28 |
    29 | @endforeach -------------------------------------------------------------------------------- /src/Models/Term.php: -------------------------------------------------------------------------------- 1 | 'array', 36 | 'slug' => 'string', 37 | ]; 38 | 39 | /** 40 | * Get the route key for the model. 41 | * 42 | * @return string 43 | */ 44 | public function getRouteKeyName(): string 45 | { 46 | return 'slug'; 47 | } 48 | 49 | /** 50 | * @return \Illuminate\Database\Eloquent\Relations\HasOne 51 | */ 52 | public function taxonomy(): HasOne 53 | { 54 | return $this->hasOne(Dashboard::model(Taxonomy::class), 'term_id'); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /database/migrations/press/2015_04_15_105754_create_orchid_menu_table.php: -------------------------------------------------------------------------------- 1 | increments('id'); 16 | $table->string('label'); 17 | $table->string('title')->nullable(); 18 | $table->string('slug'); 19 | $table->string('robot')->nullable(); 20 | $table->string('style')->nullable(); 21 | $table->string('target')->nullable(); 22 | $table->boolean('auth')->default(false); 23 | $table->string('lang'); 24 | $table->integer('parent')->default(0); 25 | $table->integer('sort')->default(0); 26 | $table->string('type'); 27 | $table->timestamps(); 28 | }); 29 | } 30 | 31 | /** 32 | * Reverse the migrations. 33 | */ 34 | public function down() 35 | { 36 | Schema::drop('menu'); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Support/macros.php: -------------------------------------------------------------------------------- 1 | render(static function (Post $post) use ($text) { 10 | return (string) Link::make($post->getContent($text)) 11 | ->route('platform.entities.type.edit', [ 12 | 'type' => $post->type, 13 | 'post' => $post, 14 | ]); 15 | }); 16 | 17 | return $this; 18 | }); 19 | 20 | /** FIXME: Uses deprecated in Orchid 6 and removed in Orchid 7 TD attribute 'locale' */ 21 | TD::macro('column', function (string $column = null) { 22 | if ($column !== null) { 23 | $this->column = $column; 24 | } 25 | if ($this->locale && $column !== null) { 26 | $locale = '.'.app()->getLocale().'.'; 27 | $this->column = preg_replace('/'.preg_quote('.', '/').'/', $locale, $column); 28 | } 29 | 30 | return $this; 31 | }); 32 | 33 | Dashboard::macro('getEntities', function () { 34 | return collect($this->getResource('entities'))->transform(function ($value) { 35 | return is_object($value) ? $value : new $value(); 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /src/Commands/MakeEntityMany.php: -------------------------------------------------------------------------------- 1 | 5 |
    6 |
    7 | 8 |
    9 | @foreach($posts as $post) 10 | 11 |
    12 | 13 |

    14 | {{$post->getContent('input')}} 15 |

    16 |

    17 | {{$post->getContent('description')}} 18 |

    19 |
    20 | 23 |
    24 |
    25 | @endforeach 26 | 27 | 28 | {{ $posts->links(config('press.view').'partials.pagination') }} 29 | 30 |
    31 |
    32 |
    33 | 34 | @endsection -------------------------------------------------------------------------------- /resources/stubs/many.stub: -------------------------------------------------------------------------------- 1 | increments('id'); 16 | $table->unsignedInteger('term_id'); 17 | $table->string('taxonomy'); 18 | $table->unsignedInteger('parent_id')->nullable(); 19 | $table->index(['id', 'taxonomy']); 20 | 21 | $table->foreign('parent_id') 22 | ->references('id') 23 | ->on('term_taxonomy') 24 | ->onUpdate('cascade') 25 | ->onDelete('cascade'); 26 | $table->foreign('term_id') 27 | ->references('id') 28 | ->on('terms') 29 | ->onUpdate('cascade') 30 | ->onDelete('cascade'); 31 | }); 32 | } 33 | 34 | /** 35 | * Reverse the migrations. 36 | */ 37 | public function down() 38 | { 39 | Schema::drop('term_taxonomy'); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /database/migrations/press/2016_12_06_070037_create_orchid_relationships_table.php: -------------------------------------------------------------------------------- 1 | unsignedInteger('post_id'); 16 | $table->unsignedInteger('term_taxonomy_id'); 17 | $table->integer('term_order')->default(0); 18 | $table->index(['post_id', 'term_taxonomy_id']); 19 | $table->foreign('post_id') 20 | ->references('id') 21 | ->on('posts') 22 | ->onUpdate('cascade') 23 | ->onDelete('cascade'); 24 | $table->foreign('term_taxonomy_id') 25 | ->references('id') 26 | ->on('term_taxonomy') 27 | ->onUpdate('cascade') 28 | ->onDelete('cascade'); 29 | }); 30 | } 31 | 32 | /** 33 | * Reverse the migrations. 34 | */ 35 | public function down() 36 | { 37 | Schema::drop('term_relationships'); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Entities/EntityContract.php: -------------------------------------------------------------------------------- 1 | status($this->request->get('status')); 37 | } 38 | 39 | /** 40 | * @return Field[] 41 | */ 42 | public function display(): array 43 | { 44 | return [ 45 | Select::make('status') 46 | ->value($this->request->get('status')) 47 | ->options([ 48 | 'publish' => __('Published'), 49 | 'draft' => __('Draft'), 50 | ]) 51 | ->empty() 52 | ->title($this->name()) 53 | ->autocomplete('off'), 54 | ]; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Http/Layouts/Category/CategoryListLayout.php: -------------------------------------------------------------------------------- 1 | render(function ($category) { 35 | return ''.$category->delimiter.' '.$category->term->GetContent('name').''; 37 | }), 38 | TD::set('slug', __('Slug')) 39 | ->render(function ($category) { 40 | return $category->term->slug; 41 | }), 42 | TD::set('created_at', __('Created')) 43 | ->render(function ($category) { 44 | return $category->term->created_at; 45 | }), 46 | ]; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /database/migrations/press/2015_04_15_102754_create_orchid_tags_table.php: -------------------------------------------------------------------------------- 1 | increments('id'); 16 | $table->string('taggable_type'); 17 | $table->unsignedInteger('taggable_id'); 18 | $table->unsignedInteger('tag_id'); 19 | $table->engine = 'InnoDB'; 20 | $table->index(['taggable_type', 'taggable_id']); 21 | }); 22 | Schema::create('tags', function (Blueprint $table) { 23 | $table->increments('id'); 24 | $table->string('namespace'); 25 | $table->string('slug'); 26 | $table->string('name'); 27 | $table->unsignedInteger('count')->default(0); 28 | $table->engine = 'InnoDB'; 29 | }); 30 | } 31 | 32 | /** 33 | * Reverse the migrations. 34 | */ 35 | public function down() 36 | { 37 | $tables = ['tagged', 'tags']; 38 | foreach ($tables as $table) { 39 | Schema::dropIfExists($table); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /database/migrations/press/2016_02_09_194940_create_orchid_post_table.php: -------------------------------------------------------------------------------- 1 | increments('id'); 16 | $table->unsignedBigInteger('user_id')->nullable(); 17 | $table->string('type'); 18 | $table->string('status')->nullable(); 19 | $table->jsonb('content')->nullable(); 20 | $table->jsonb('options')->nullable(); 21 | $table->string('slug')->unique(); 22 | $table->timestamp('publish_at')->nullable()->useCurrent(); 23 | $table->timestamps(); 24 | $table->softDeletes(); 25 | $table->index(['status', 'type']); 26 | 27 | $table->foreign('user_id') 28 | ->references('id') 29 | ->on('users') 30 | ->onUpdate('cascade') 31 | ->onDelete('cascade'); 32 | }); 33 | } 34 | 35 | /** 36 | * Reverse the migrations. 37 | */ 38 | public function down() 39 | { 40 | Schema::drop('posts'); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /resources/templates/clean-blog/views/pages/category.blade.php: -------------------------------------------------------------------------------- 1 | @extends(config('press.view').'layouts.app') 2 | 3 | @section('content') 4 | 5 | 6 | 7 | 8 |
    9 | 10 |
    11 | 12 | 13 |
    14 |

    {{ $category->term->getContent('name') }} 15 | {!! $category->term->getContent('body') !!} 16 |

    17 | 18 | 19 | 20 | @foreach($category->posts as $post) 21 | 22 |
    23 |

    {{$post->getContent('name')}}

    24 | Card image cap 25 |
    26 |

    {{ \Str::limit(strip_tags($post->getContent('body')),150) }}

    27 | Read More → 28 |
    29 | 32 |
    33 | @endforeach 34 | 35 | 36 | {{-- $category->posts->links('partials.pagination') --}} 37 | 38 |
    39 | 40 | 41 | 42 | @endsection -------------------------------------------------------------------------------- /src/Http/Screens/Comment/CommentListScreen.php: -------------------------------------------------------------------------------- 1 | function ($query) { 35 | $query->select('id', 'type', 'slug'); 36 | }, 37 | ])->latest() 38 | ->paginate(); 39 | 40 | return [ 41 | 'comments' => $comments, 42 | ]; 43 | } 44 | 45 | /** 46 | * Button commands. 47 | * 48 | * @return Link[] 49 | */ 50 | public function commandBar(): array 51 | { 52 | return []; 53 | } 54 | 55 | /** 56 | * Views. 57 | * 58 | * @return Layout[] 59 | */ 60 | public function layout(): array 61 | { 62 | return [ 63 | CommentListLayout::class, 64 | ]; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /resources/templates/clean-blog/views/partials/carousel.blade.php: -------------------------------------------------------------------------------- 1 | 2 | @if ($post->attachment('image')->get()->count()>0) 3 |
    4 | 30 |
    31 | @endif -------------------------------------------------------------------------------- /resources/templates/clean-blog/views/partials/pagination.blade.php: -------------------------------------------------------------------------------- 1 | @if ($paginator->hasPages()) 2 | 36 | 37 | @endif -------------------------------------------------------------------------------- /src/Builders/TaxonomyBuilder.php: -------------------------------------------------------------------------------- 1 | with('posts'); 24 | } 25 | 26 | /** 27 | * Set taxonomy type to category. 28 | * 29 | * @return \Orchid\Press\Builders\TaxonomyBuilder 30 | */ 31 | public function category(): self 32 | { 33 | return $this->where('taxonomy', 'category'); 34 | } 35 | 36 | /** 37 | * Get a term taxonomy by specific slug. 38 | * 39 | * @param string 40 | * 41 | * @return \Orchid\Press\Builders\TaxonomyBuilder 42 | */ 43 | public function slug($slug = null): self 44 | { 45 | if (!empty($slug)) { 46 | // set this slug to be used in with callback 47 | $this->slug = $slug; 48 | 49 | // exception to filter on specific slug 50 | $exception = function ($query) { 51 | $query->where('slug', '=', $this->slug); 52 | }; 53 | 54 | // load term to filter 55 | return $this->whereHas('term', $exception); 56 | } 57 | 58 | return $this; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /resources/js/controllers/fields/tag_controller.js: -------------------------------------------------------------------------------- 1 | import { Controller } from 'stimulus'; 2 | 3 | export default class extends Controller { 4 | connect() { 5 | const select = this.element.querySelector('select'); 6 | 7 | setTimeout(() => { 8 | $(select).select2({ 9 | theme: 'bootstrap', 10 | templateResult: (state) => { 11 | if (!state.id || !state.count) { 12 | return state.text; 13 | } 14 | return $(`${state.text}${state.count}`); 15 | }, 16 | createTag(tag) { 17 | return { 18 | id: tag.term, 19 | text: tag.term, 20 | }; 21 | }, 22 | escapeMarkup(m) { 23 | return m; 24 | }, 25 | width: '100%', 26 | tags: true, 27 | cache: true, 28 | ajax: { 29 | url(params) { 30 | return platform.prefix(`/press/tags/${params.term}`); 31 | }, 32 | delay: 340, 33 | processResults(data) { 34 | return { 35 | results: data, 36 | }; 37 | }, 38 | }, 39 | }); 40 | }, 100); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /resources/templates/clean-blog/views/pages/post.blade.php: -------------------------------------------------------------------------------- 1 | @extends(config('press.view').'layouts.app') 2 | 3 | @section('title',$post->getContent('title')) 4 | @section('keywords',$post->getContent('keywords')) 5 | @section('description',$post->getContent('description')) 6 | 7 | @if (!is_null($post->getContent('picture'))) 8 | @section('head_image',$post->getContent('picture')) 9 | @endif 10 | 11 | @section('author') 12 | {{__('Posted by')}} 13 | {{ $post->getUser()->name }} 14 | on {{$post->publish_at->diffForHumans()}} 15 | 16 | @endsection 17 | 18 | @section('content') 19 | 20 | 21 |
    22 |
    23 |
    24 |
    25 | {!! $post->getContent('body') !!} 26 |
    27 | 28 |
    29 | @foreach($post->tags as $tag) 30 | {{ $tag->name }} 31 | @endforeach 32 |
    33 | 34 | {{-- Comments --}} 35 | {{-- @include(config('press.view').'partials.comment.comments',['comments' => $comments]) --}} 36 |
    37 |
    38 |
    39 |
    40 | 41 | @endsection -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "dev": "NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js", 5 | "watch": "NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js", 6 | "hot": "NODE_ENV=development webpack-dev-server --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js", 7 | "production": "NODE_ENV=production node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js", 8 | "eslint": "./node_modules/.bin/eslint resources/js/ --fix" 9 | }, 10 | "dependencies": { 11 | "@babel/plugin-proposal-class-properties": "^7.5.5", 12 | "@babel/plugin-transform-block-scoping": "^7.6.0", 13 | "@babel/preset-env": "^7.6.0", 14 | "axios": "^0.18.1", 15 | "babel-preset-env": "^1.7.0", 16 | "bootstrap": "^4.3.1", 17 | "cross-env": "^5.2.1", 18 | "jquery": "^3.4.1", 19 | "laravel-mix": "4.0.14", 20 | "nestable2": "^1.6.0", 21 | "popper.js": "^1.15.0", 22 | "startbootstrap-clean-blog": "^5.0.7", 23 | "startbootstrap-creative": "^5.1.7", 24 | "stimulus": "^1.1.1", 25 | "turbolinks": "^5.2.0", 26 | "vue": "^2.5.7" 27 | }, 28 | "devDependencies": { 29 | "resolve-url-loader": "2.3.1", 30 | "sass": "^1.22.10", 31 | "sass-loader": "^7.3.1", 32 | "vue-template-compiler": "^2.6.10" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /database/migrations/press/2016_12_06_070037_create_orchid_comments_table.php: -------------------------------------------------------------------------------- 1 | increments('id'); 16 | $table->unsignedInteger('post_id')->nullable(); 17 | $table->unsignedBigInteger('user_id')->nullable(); 18 | $table->integer('parent_id')->nullable(); 19 | $table->text('content'); 20 | $table->boolean('approved')->nullable(); 21 | $table->timestamps(); 22 | 23 | $table->index(['approved', 'post_id']); 24 | $table->index('post_id'); 25 | $table->index('parent_id'); 26 | $table->foreign('post_id') 27 | ->references('id') 28 | ->on('posts') 29 | ->onUpdate('cascade') 30 | ->onDelete('cascade'); 31 | $table->foreign('user_id') 32 | ->references('id') 33 | ->on('users') 34 | ->onUpdate('cascade') 35 | ->onDelete('cascade'); 36 | }); 37 | } 38 | 39 | /** 40 | * Reverse the migrations. 41 | */ 42 | public function down() 43 | { 44 | Schema::drop('comments'); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /database/factories/MenuFactory.php: -------------------------------------------------------------------------------- 1 | define(Menu::class, function (Faker $faker) { 19 | $lang = app()->getLocale(); 20 | $MenuTitle = $faker->unique()->word; 21 | 22 | $RobotArr = ['answer', 'chapter', 'co-worker', 'colleague', 'contact', 23 | 'details', 'edit', 'friend', 'question', 'archives', 'author', 24 | 'bookmark', 'first', 'help', 'index', 'last', 'license', 'me', 25 | 'next', 'nofollow', 'noreferrer', 'prefetch', 'prev', 'search', 26 | 'sidebar', 'tag', 'up', ]; 27 | 28 | return [ 29 | 'label' => Str::slug($MenuTitle), 30 | 'title' => $MenuTitle.' '.Str::slug($faker->word), 31 | 'slug' => '/'.Str::slug($MenuTitle), 32 | 'robot' => $faker->randomElement($RobotArr), 33 | 'style' => $faker->safeColorName, 34 | 'target' => $faker->randomElement(['_self', '_blank']), 35 | 'auth' => $faker->randomElement([0, 1]), 36 | 'lang' => $lang, 37 | 'sort' => 0, 38 | ]; 39 | }); 40 | -------------------------------------------------------------------------------- /src/Http/Filters/CreatedFilter.php: -------------------------------------------------------------------------------- 1 | where('created_at', '>', $this->request->input('created_at.start')) 44 | ->where('created_at', '<', $this->request->input('created_at.end')); 45 | } 46 | 47 | /** 48 | * @return Field[] 49 | */ 50 | public function display(): array 51 | { 52 | return [ 53 | DateRange::make('created_at') 54 | ->title($this->name()) 55 | ->value([ 56 | 'start' => $this->request->input('created_at.start'), 57 | 'end' => $this->request->input('created_at.end'), 58 | ]), 59 | ]; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/Http/Filters/SearchFilter.php: -------------------------------------------------------------------------------- 1 | getQuery()->getConnection() instanceof PostgresConnection) { 38 | return $builder->whereRaw('content::TEXT ILIKE ?', '%'.$this->request->get('search').'%'); 39 | } 40 | 41 | return $builder->where('content', 'LIKE', '%'.$this->request->get('search').'%'); 42 | } 43 | 44 | /** 45 | * @return Field[] 46 | */ 47 | public function display(): array 48 | { 49 | return [ 50 | Input::make('search') 51 | ->type('text') 52 | ->value($this->request->get('search')) 53 | ->placeholder(__('Search...')) 54 | ->title($this->name()) 55 | ->maxlength(200) 56 | ->autocomplete('off'), 57 | ]; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Http/Layouts/Category/CategoryEditLayout.php: -------------------------------------------------------------------------------- 1 | getLocale(); 24 | 25 | return [ 26 | Input::make($categoryContent.'.name') 27 | ->type('text') 28 | ->max(255) 29 | ->required() 30 | ->title(__('Category name')) 31 | ->placeholder(__('Category name')) 32 | ->help(__('Category title')), 33 | 34 | Input::make('category.term.slug') 35 | ->type('text') 36 | ->max(255) 37 | ->required() 38 | ->title(__('Slug')), 39 | 40 | Select::make('category.parent_id') 41 | ->options(function () { 42 | $options = $this->query->getContent('catselect'); 43 | 44 | return array_replace([0=> __('Without parent')], $options); 45 | }) 46 | ->title(__('Parent Category')), 47 | 48 | TinyMCE::make($categoryContent.'.body') 49 | ->title(__('Description')), 50 | 51 | ]; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /database/factories/PageFactory.php: -------------------------------------------------------------------------------- 1 | define(Page::class, function (Faker $faker) { 18 | return [ 19 | 'type' => 'example-page', 20 | 'status' => 'publish', 21 | 'content' => [ 22 | 'en' => [ 23 | 'name' => $faker->sentence(6), 24 | 'title' => $faker->sentence(6), 25 | 'description' => $faker->paragraph(2), 26 | 'body' => $faker->text, 27 | 'body2' => $faker->text, 28 | 'picture' => $faker->imageUrl(640, 480), 29 | 'open' => $faker->dateTimeBetween('-30 years', 'now')->format('Y-m-d H:i:s'), 30 | 'robot' => $faker->randomElement(['noindex']), 31 | 'block' => $faker->text, 32 | 'keywords' => implode(',', $faker->words(5)), 33 | 'list' => $faker->words(5), 34 | ], 35 | ], 36 | 'publish_at' => $faker->date('Y-m-d H:i:s'), 37 | 'options' => [ 38 | 'locale' => [ 39 | 'en' => 'true', 40 | ], 41 | ], 42 | 'slug' => 'example-page', 43 | ]; 44 | }); 45 | -------------------------------------------------------------------------------- /src/Http/Composers/PressMenuComposer.php: -------------------------------------------------------------------------------- 1 | dashboard = $dashboard; 22 | } 23 | 24 | /** 25 | * Registering the main menu items. 26 | */ 27 | public function compose(): void 28 | { 29 | $this->registerMenuPost(); 30 | } 31 | 32 | 33 | protected function registerMenuPost(): self 34 | { 35 | $this->dashboard->getEntities() 36 | ->where('display', true) 37 | ->sortBy('sort') 38 | ->each(function ($page) { 39 | $route = is_a($page, Single::class) ? 'platform.entities.type.page' : 'platform.entities.type'; 40 | $params = is_a($page, Single::class) ? [$page->slug, $page->slug] : [$page->slug]; 41 | $active = [route($route, $params), route($route, $params) . '/*']; 42 | 43 | $this->dashboard->menu->add(Menu::MAIN, 44 | ItemMenu::label($page->name) 45 | ->slug($page->slug) 46 | ->icon($page->icon) 47 | ->title($page->title) 48 | ->route($route, $params) 49 | ->permission('platform.entities.type.'.$page->slug) 50 | ->sort($page->sort) 51 | ->canSee($page->display) 52 | ->active($active) 53 | ); 54 | }); 55 | 56 | return $this; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /database/factories/PostFactory.php: -------------------------------------------------------------------------------- 1 | define(Post::class, function (Faker $faker) { 19 | $name = $faker->sentence(6); 20 | 21 | return [ 22 | 'type' => 'example-post', 23 | 'status' => 'publish', 24 | 'content' => [ 25 | 'en' => [ 26 | 'name' => $name, 27 | 'title' => $faker->sentence(6), 28 | 'description' => $faker->paragraph(2), 29 | 'body' => $faker->text, 30 | 'body2' => $faker->text, 31 | 'picture' => $faker->imageUrl(640, 480), 32 | 'open' => $faker->dateTimeBetween('-30 years', 'now')->format('Y-m-d H:i:s'), 33 | 'robot' => $faker->randomElement(['noindex']), 34 | 'block' => $faker->text, 35 | 'keywords' => implode(',', $faker->words(5)), 36 | 'list' => $faker->words(5), 37 | ], 38 | ], 39 | 'publish_at' => $faker->date('Y-m-d H:i:s'), 40 | 'options' => [ 41 | 'locale' => [ 42 | 'en' => 'true', 43 | ], 44 | ], 45 | 'slug' => SlugService::createSlug(Post::class, 'slug', $name), 46 | ]; 47 | }); 48 | -------------------------------------------------------------------------------- /resources/templates/clean-blog/sass/theme/theme.scss: -------------------------------------------------------------------------------- 1 | 2 | $fa-font-path: '/dashboard/resources/press/clean-blog/fonts/vendor/@fortawesome/fontawesome-free'; 3 | @font-face { 4 | font-family: 'Font Awesome 5 Free'; 5 | font-style: normal; 6 | font-weight: 400; 7 | font-display: $fa-font-display; 8 | src: url('#{$fa-font-path}/webfa-regular-400.eot'); 9 | src: url('#{$fa-font-path}/webfa-regular-400.eot?#iefix') format('embedded-opentype'), 10 | url('#{$fa-font-path}/webfa-regular-400.woff2') format('woff2'), 11 | url('#{$fa-font-path}/webfa-regular-400.woff') format('woff'), 12 | url('#{$fa-font-path}/webfa-regular-400.ttf') format('truetype'), 13 | url('#{$fa-font-path}/webfa-regular-400.svg#fontawesome') format('svg'); 14 | } 15 | 16 | @font-face { 17 | font-family: 'Font Awesome 5 Brands'; 18 | font-style: normal; 19 | font-weight: normal; 20 | font-display: $fa-font-display; 21 | src: url('#{$fa-font-path}/webfa-brands-400.eot'); 22 | src: url('#{$fa-font-path}/webfa-brands-400.eot?#iefix') format('embedded-opentype'), 23 | url('#{$fa-font-path}/webfa-brands-400.woff2') format('woff2'), 24 | url('#{$fa-font-path}/webfa-brands-400.woff') format('woff'), 25 | url('#{$fa-font-path}/webfa-brands-400.ttf') format('truetype'), 26 | url('#{$fa-font-path}/webfa-brands-400.svg#fontawesome') format('svg'); 27 | } 28 | 29 | @font-face { 30 | font-family: 'Font Awesome 5 Free'; 31 | font-style: normal; 32 | font-weight: 900; 33 | font-display: $fa-font-display; 34 | src: url('#{$fa-font-path}/webfa-solid-900.eot'); 35 | src: url('#{$fa-font-path}/webfa-solid-900.eot?#iefix') format('embedded-opentype'), 36 | url('#{$fa-font-path}/webfa-solid-900.woff2') format('woff2'), 37 | url('#{$fa-font-path}/webfa-solid-900.woff') format('woff'), 38 | url('#{$fa-font-path}/webfa-solid-900.ttf') format('truetype'), 39 | url('#{$fa-font-path}/webfa-solid-900.svg#fontawesome') format('svg'); 40 | } 41 | -------------------------------------------------------------------------------- /src/Models/Menu.php: -------------------------------------------------------------------------------- 1 | 'string', 40 | 'parent' => 'integer', 41 | 'sort' => 'integer', 42 | ]; 43 | 44 | /** 45 | * @return \Illuminate\Database\Eloquent\Relations\HasMany 46 | */ 47 | public function children(): HasMany 48 | { 49 | return $this->hasMany(static::class, 'parent')->orderBy('sort'); 50 | } 51 | 52 | /** 53 | * @return \Illuminate\Database\Eloquent\Relations\HasOne 54 | */ 55 | public function parent(): HasOne 56 | { 57 | return $this->hasOne(static::class, 'id', 'parent'); 58 | } 59 | 60 | /** 61 | * @return string 62 | */ 63 | public function getRoute(): string 64 | { 65 | if ((strpos($this->slug, ',') > 0) && (is_array($routearray = explode(',', $this->slug)))) { 66 | $routearray = array_filter($routearray, function ($element) { 67 | return !empty($element); 68 | }); 69 | $path = route(array_shift($routearray), $routearray ?? []); 70 | } else { 71 | $path = url($this->slug); 72 | } 73 | 74 | return $path; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/Commands/TemplateCommand.php: -------------------------------------------------------------------------------- 1 | setValueEnv('PRESS_TEMPLATE', 'clean-blog'); 37 | 38 | $this->call('vendor:publish', [ 39 | '--provider' => PressServiceProvider::class, 40 | '--force' => true, 41 | ]); 42 | } 43 | 44 | /** 45 | * @param string $constant 46 | * @param string $value 47 | * 48 | * @return \Orchid\Platform\Commands\TemplateCommand 49 | */ 50 | private function setValueEnv($constant, $value = 'null'): self 51 | { 52 | $str = $this->fileGetContent(app_path('../.env')); 53 | 54 | if ($str !== false && strpos($str, $constant) === false) { 55 | file_put_contents(app_path('../.env'), $str.PHP_EOL.$constant.'='.$value.PHP_EOL); 56 | } 57 | 58 | return $this; 59 | } 60 | 61 | /** 62 | * @param string $file 63 | * 64 | * @return false|string 65 | */ 66 | private function fileGetContent(string $file) 67 | { 68 | if (!is_file($file)) { 69 | return ''; 70 | } 71 | 72 | return file_get_contents($file); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/Models/Category.php: -------------------------------------------------------------------------------- 1 | taxonomy; 30 | 31 | return $this; 32 | } 33 | 34 | /** 35 | * Select all categories, except current. 36 | * 37 | * @return array 38 | */ 39 | public function getAllCategories() 40 | { 41 | $categories = $this->exists ? self::whereNotIn('id', [$this->id])->get() : self::get(); 42 | 43 | return $categories->mapWithKeys(function ($item) { 44 | return [$item->id => $item->term->GetContent('name')]; 45 | })->toArray(); 46 | } 47 | 48 | /** 49 | * Create category term. 50 | * 51 | * @param array $term 52 | * 53 | * @return self 54 | */ 55 | public function newWithCreateTerm($term): self 56 | { 57 | $newTerm = Term::firstOrCreate($term); 58 | $this->term_id = $newTerm->id; 59 | $this->term()->associate($newTerm); 60 | $this->setTaxonomy(); 61 | 62 | return $this; 63 | } 64 | 65 | /** 66 | * Set parent category. 67 | * 68 | * @param int|null $parent_id 69 | * 70 | * @return self 71 | */ 72 | public function setParent($parent_id = null): self 73 | { 74 | $parent_id = ((int) $parent_id > 0) ? (int) $parent_id : null; 75 | 76 | $this->setAttribute('parent_id', $parent_id); 77 | 78 | return $this; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 | 16 | ./tests/Console 17 | 18 | 19 | ./tests/Feature 20 | 21 | 22 | ./tests/Unit 23 | 24 | 25 | 26 | 27 | ./src 28 | 29 | ./src/ 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /src/Providers/RouteServiceProvider.php: -------------------------------------------------------------------------------- 1 | binding(); 20 | //$this->filters(); 21 | 22 | parent::boot(); 23 | } 24 | 25 | 26 | public function binding() 27 | { 28 | Route::bind('post', function ($value) { 29 | return Post::where('slug', $value) 30 | ->type('blog') 31 | ->with(['attachment']) 32 | ->firstOrFail(); 33 | }); 34 | /* 35 | Route::bind('term', function ($value) { 36 | return Category::where('slug', $value) 37 | ->firstOrFail(); 38 | }); 39 | */ 40 | } 41 | 42 | public function filters() 43 | { 44 | $category = Category::with('allChildrenTerm') 45 | ->with('term') 46 | ->get() 47 | ->map(function ($item, $key) { 48 | return $item->term->slug; 49 | }) 50 | ->toArray(); 51 | 52 | Route::pattern('category', implode('|', $category)); 53 | } 54 | 55 | /** 56 | * Define the routes for the application. 57 | * 58 | * @return void 59 | */ 60 | public function map() 61 | { 62 | /* 63 | if ($this->app->routesAreCached()) { 64 | return; 65 | } 66 | */ 67 | if (file_exists(base_path('routes/press.php'))) { 68 | Route::domain((string) config('press.domain')) 69 | ->prefix(config('press.prefix')) 70 | ->as('press.') 71 | ->middleware(config('press.middleware.public')) 72 | ->group(base_path('routes/press.php')); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/Entities/Actions.php: -------------------------------------------------------------------------------- 1 | save(); 37 | } 38 | 39 | /** 40 | * @param \Illuminate\Database\Eloquent\Model $model 41 | * 42 | * @throws Exception 43 | */ 44 | public function delete(Model $model) 45 | { 46 | $model->delete(); 47 | } 48 | 49 | /** 50 | * Get the value of the model's route key. 51 | * 52 | * @return mixed 53 | */ 54 | public function getRouteKey() 55 | { 56 | return $this->slug; 57 | } 58 | 59 | /** 60 | * Get the route key for the model. 61 | * 62 | * @return string 63 | */ 64 | public function getRouteKeyName() 65 | { 66 | return $this->slug; 67 | } 68 | 69 | /** 70 | * Retrieve the model for a bound value. 71 | * 72 | * @param mixed $value 73 | * @param string|null $field 74 | * @return \Illuminate\Database\Eloquent\Model|null 75 | */ 76 | public function resolveRouteBinding($value, $field = null) 77 | { 78 | return $value; 79 | } 80 | 81 | /** 82 | * Retrieve the child model for a bound value. 83 | * 84 | * @param string $childType 85 | * @param mixed $value 86 | * @param string|null $field 87 | * @return \Illuminate\Database\Eloquent\Model|null 88 | */ 89 | public function resolveChildRouteBinding($childType, $value, $field) { 90 | return null; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/Providers/WebServiceProvider.php: -------------------------------------------------------------------------------- 1 | dashboard = $dashboard; 29 | 30 | $this->registerViews() 31 | ->registerRoute(); 32 | $this->registerDirectives(); 33 | 34 | $this->app->register(RouteServiceProvider::class); 35 | } 36 | 37 | /** 38 | * Register views & Publish views. 39 | * 40 | * @return $this 41 | */ 42 | public function registerViews(): self 43 | { 44 | $this->loadViewsFrom(PRESS_PATH.'/resources/templates/'.config('press.theme').'/views', 'template'); 45 | 46 | $this->publishes([ 47 | PRESS_PATH.'/resources/templates/' => resource_path('views/vendor/press'), 48 | ], 'views'); 49 | 50 | return $this; 51 | } 52 | 53 | /** 54 | * Register directives. 55 | */ 56 | public function registerDirectives(): void 57 | { 58 | Blade::directive('category', function ($expression) { 59 | return "get($expression); ?>"; 60 | }); 61 | 62 | Blade::directive('menu', function ($expression) { 63 | return "get($expression); ?>"; 64 | }); 65 | } 66 | 67 | /** 68 | * Register route. 69 | * 70 | * @return $this 71 | */ 72 | protected function registerRoute(): self 73 | { 74 | $this->publishes([ 75 | realpath(PRESS_PATH.'/install-stubs/routes/') => base_path('routes'), 76 | ], 'press-routes'); 77 | 78 | return $this; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/Http/Layouts/Comment/CommentListLayout.php: -------------------------------------------------------------------------------- 1 | render(function ($comment) { 25 | if ($comment->approved) { 26 | return ''; 27 | } 28 | 29 | return ''; 30 | }), 31 | 32 | TD::set('content', __('Content')) 33 | ->render(function ($comment) { 34 | return ''.\Str::limit($comment->content, 70).''; 36 | }), 37 | 38 | TD::set('post_id', __('Recording')) 39 | ->render(function ($comment) { 40 | if (!is_null($comment->post)) { 41 | return ''; 45 | } 46 | 47 | return ''; 48 | }) 49 | ->align(TD::ALIGN_CENTER), 50 | 51 | TD::set('user_id', __('User')) 52 | ->render(function ($comment) { 53 | return ''; 55 | }) 56 | ->align(TD::ALIGN_CENTER), 57 | 58 | TD::set('updated_at', __('Last edit')) 59 | ->render(function ($comment) { 60 | return $comment->updated_at; 61 | }), 62 | ]; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /routes/press.php: -------------------------------------------------------------------------------- 1 | router->screen('comments/{comments}/edit', CommentEditScreen::class)->name('systems.comments.edit'); 25 | $this->router->screen('comments/create', CommentEditScreen::class)->name('systems.comments.create'); 26 | $this->router->screen('comments', CommentListScreen::class)->name('systems.comments'); 27 | 28 | // Categories... 29 | $this->router->screen('category/{category}/edit', CategoryEditScreen::class)->name('systems.category.edit'); 30 | $this->router->screen('category/create', CategoryEditScreen::class)->name('systems.category.create'); 31 | $this->router->screen('category', CategoryListScreen::class)->name('systems.category'); 32 | 33 | // Entities... 34 | $this->router->screen('entities/{type}/{post?}/edit', EntityEditScreen::class)->name('entities.type.edit'); 35 | $this->router->screen('entities/{type}/create', EntityEditScreen::class)->name('entities.type.create'); 36 | $this->router->screen('entities/{type}/{page?}/page', EntityEditScreen::class)->name('entities.type.page'); 37 | $this->router->screen('entities/{type}', EntityListScreen::class)->name('entities.type'); 38 | 39 | // Menu... 40 | $this->router->resource('menu', MenuController::class, [ 41 | 'only' => [ 42 | 'index', 'show', 'update', 'store', 'destroy', 43 | ], 44 | 'names' => [ 45 | 'index' => 'systems.menu.index', 46 | 'show' => 'systems.menu.show', 47 | 'update' => 'systems.menu.update', 48 | 'store' => 'systems.menu.store', 49 | 'destroy' => 'systems.menu.destroy', 50 | ], 51 | ]); 52 | 53 | $this->router->get('tags/{tags?}', [TagsController::class, 'show']) 54 | ->name('systems.tag.search'); 55 | -------------------------------------------------------------------------------- /src/Http/Composers/SystemMenuComposer.php: -------------------------------------------------------------------------------- 1 | dashboard = $dashboard; 22 | } 23 | 24 | /** 25 | * Registering the main menu items. 26 | */ 27 | public function compose(): void 28 | { 29 | $this->dashboard->menu 30 | ->add(Menu::SYSTEMS, 31 | ItemMenu::label('Content management') 32 | ->slug('CMS') 33 | ->icon('icon-layers') 34 | ->permission('platform.systems.index') 35 | ->sort(1000) 36 | ) 37 | ->add('CMS', 38 | ItemMenu::label('Menu') 39 | ->icon('icon-menu') 40 | ->route('platform.systems.menu.index') 41 | ->permission('platform.systems.menu') 42 | ->canSee(count(config('press.menu', [])) > 0) 43 | ->title(__('Editing of a custom menu (navigation) using drag & drop and localization support.')) 44 | ) 45 | ->add('CMS', 46 | ItemMenu::label('Categories') 47 | ->icon('icon-briefcase') 48 | ->route('platform.systems.category') 49 | ->permission('platform.systems.category') 50 | ->sort(1000) 51 | ->title(__('Sort entries into groups of posts on a given topic. This helps the user to find the necessary information on the site.')) 52 | ) 53 | ->add('CMS', 54 | ItemMenu::label('Comments') 55 | ->icon('icon-bubbles') 56 | ->route('platform.systems.comments') 57 | ->permission('platform.systems.comments') 58 | ->sort(1000) 59 | ->title(__("Comments allow your website's visitors to have a discussion with you and each other.")) 60 | ->badge(function () { 61 | return Comment::where('approved', 0)->count() ?: null; 62 | }) 63 | ); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /config/press.php: -------------------------------------------------------------------------------- 1 | env('PRESS_TEMPLATE', 'clean-blog'), 13 | 14 | /* 15 | |-------------------------------------------------------------------------- 16 | | view 17 | |-------------------------------------------------------------------------- 18 | | 19 | | Path to blade of template 20 | | 21 | */ 22 | 23 | 'view' => '', 24 | 25 | /* 26 | |-------------------------------------------------------------------------- 27 | | prefix 28 | |-------------------------------------------------------------------------- 29 | | 30 | | Prefix site - http://sitename.com/prefix/ 31 | | 32 | */ 33 | 34 | 'prefix' => '', 35 | 36 | /* 37 | |-------------------------------------------------------------------------- 38 | | Post prefix 39 | |-------------------------------------------------------------------------- 40 | | 41 | | Post site prefix - http://sitename.com/prefix/postpefix/post 42 | | 43 | */ 44 | 45 | 46 | 'post' => [ 47 | 'prefix' => 'press', 48 | ], 49 | 50 | 51 | 'middleware' => [ 52 | 'public' => ['web'], 53 | 'private' => ['web', 'dashboard'], 54 | ], 55 | /* 56 | |-------------------------------------------------------------------------- 57 | | Locales 58 | |-------------------------------------------------------------------------- 59 | | 60 | | Localization of records 61 | | 62 | */ 63 | 64 | 'locales' => [ 65 | 'ru' => [ 66 | 'name' => 'Russian', 67 | 'script' => 'Cyrl', 68 | 'dir' => 'ltr', 69 | 'native' => 'Русский', 70 | 'regional' => 'ru_RU', 71 | 'required' => true, 72 | ], 73 | ], 74 | 75 | /* 76 | |-------------------------------------------------------------------------- 77 | | Available menu 78 | |-------------------------------------------------------------------------- 79 | | 80 | | Marked menu areas 81 | | 82 | */ 83 | 84 | 'menu' => [ 85 | 'header' => 'Header menu', 86 | 'sidebar' => 'Sidebar menu', 87 | 'footer' => 'Footer menu', 88 | ], 89 | 90 | 91 | ]; 92 | -------------------------------------------------------------------------------- /src/Http/Screens/Category/CategoryListScreen.php: -------------------------------------------------------------------------------- 1 | with('allChildrenTerm')->get(); 35 | $allCategories = collect(); 36 | 37 | foreach ($categories as $category) { 38 | $allCategories = $allCategories->merge($this->getCategory($category)); 39 | } 40 | 41 | return [ 42 | 'category' => $allCategories, 43 | ]; 44 | } 45 | 46 | /** 47 | * @param \Orchid\Press\Models\Category $category 48 | * @param string $delimiter 49 | * 50 | * @return \Illuminate\Support\Collection 51 | */ 52 | private function getCategory(Category $category, $delimiter = '') 53 | { 54 | $result = collect(); 55 | $category->delimiter = $delimiter; 56 | $result->push($category); 57 | 58 | if (!$category->allChildrenTerm()->count()) { 59 | return $result; 60 | } 61 | 62 | foreach ($category->allChildrenTerm()->get() as $item) { 63 | $result = $result->merge($this->getCategory($item, $delimiter.'-')); 64 | } 65 | 66 | return $result; 67 | } 68 | 69 | /** 70 | * Button commands. 71 | * 72 | * @return Link[] 73 | */ 74 | public function commandBar(): array 75 | { 76 | return [ 77 | Link::make(__('Add')) 78 | ->icon('icon-plus') 79 | ->href(route('platform.systems.category.create')), 80 | ]; 81 | } 82 | 83 | /** 84 | * Views. 85 | * 86 | * @return Layout[] 87 | */ 88 | public function layout(): array 89 | { 90 | return [ 91 | CategoryListLayout::class, 92 | ]; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /resources/templates/clean-blog/js/bootstrap.js: -------------------------------------------------------------------------------- 1 | 2 | //window._ = require('lodash'); 3 | 4 | /** 5 | * We'll load jQuery and the Bootstrap jQuery plugin which provides support 6 | * for JavaScript based Bootstrap features such as modals and tabs. This 7 | * code may be modified to fit the specific needs of your application. 8 | */ 9 | 10 | try { 11 | window.$ = window.jQuery = require('jquery'); 12 | } catch (e) {} 13 | 14 | 15 | window.Vue = require('vue'); 16 | 17 | window.Popper = require('popper.js'); 18 | 19 | require('bootstrap'); 20 | 21 | document.addEventListener('turbolinks:load', function() { 22 | $("input[data-role='tagsinput']").tagsinput('refresh'); 23 | }); 24 | 25 | 26 | 27 | 28 | 29 | 30 | /** 31 | * We'll load the axios HTTP library which allows us to easily issue requests 32 | * to our Laravel back-end. This library automatically handles sending the 33 | * CSRF token as a header based on the value of the "XSRF" token cookie. 34 | */ 35 | 36 | window.axios = require('axios'); 37 | 38 | window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; 39 | 40 | /** 41 | * Next we will register the CSRF Token as a common header with Axios so that 42 | * all outgoing HTTP requests automatically have it attached. This is just 43 | * a simple convenience so we don't have to attach every token manually. 44 | */ 45 | 46 | document.addEventListener('turbolinks:load', function() { 47 | let token = document.head.querySelector('meta[name="csrf_token"]'); 48 | 49 | if (token) { 50 | window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content; 51 | } else { 52 | console.error( 53 | 'CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token', 54 | ); 55 | } 56 | 57 | $.ajaxSetup({ 58 | headers: { 59 | 'X-CSRF-TOKEN': $('meta[name="csrf_token"]').attr('content'), 60 | }, 61 | }); 62 | }); 63 | 64 | 65 | /** 66 | * Echo exposes an expressive API for subscribing to channels and listening 67 | * for events that are broadcast by Laravel. Echo and event broadcasting 68 | * allows your team to easily build robust real-time web applications. 69 | */ 70 | 71 | // import Echo from 'laravel-echo' 72 | 73 | // window.Pusher = require('pusher-js'); 74 | 75 | // window.Echo = new Echo({ 76 | // broadcaster: 'pusher', 77 | // key: 'your-pusher-key', 78 | // cluster: 'mt1', 79 | // encrypted: true 80 | // }); 81 | 82 | 83 | require('startbootstrap-clean-blog/js/clean-blog.js'); 84 | require('startbootstrap-creative/js/creative.js'); 85 | require('startbootstrap-clean-blog/js/contact_me.js'); 86 | require('startbootstrap-clean-blog/js/jqBootstrapValidation.js'); -------------------------------------------------------------------------------- /src/Entities/Many.php: -------------------------------------------------------------------------------- 1 | slug) 59 | ->filtersApplyDashboard($this->slug) 60 | ->filters() 61 | ->with($this->with) 62 | ->defaultSort('id', 'desc') 63 | ->paginate(); 64 | } 65 | 66 | /** 67 | * Get all the filters. 68 | * 69 | * @return Collection 70 | */ 71 | public function getFilters(): Collection 72 | { 73 | $filters = collect(); 74 | foreach ($this->filters() as $filter) { 75 | $filter = new $filter($this); 76 | $filters->push($filter); 77 | } 78 | 79 | return $filters; 80 | } 81 | 82 | /** 83 | * Registered fields for main. 84 | * 85 | * @throws \Throwable|\Orchid\Press\Exceptions\EntityTypeException 86 | * 87 | * @return array 88 | */ 89 | public function main(): array 90 | { 91 | return [ 92 | Input::make('slug') 93 | ->type('text') 94 | ->name('slug') 95 | ->max(255) 96 | ->title(__('Semantic URL')) 97 | ->placeholder(__('Unique name')), 98 | 99 | DateTimer::make('publish_at') 100 | ->title(__('Time of publication')), 101 | 102 | Select::make('status') 103 | ->options($this->status()) 104 | ->title(__('Status')), 105 | ]; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/Http/Screens/Comment/CommentEditScreen.php: -------------------------------------------------------------------------------- 1 | $comment, 41 | ]; 42 | } 43 | 44 | /** 45 | * Button commands. 46 | * 47 | * @return Link[] 48 | */ 49 | public function commandBar(): array 50 | { 51 | return [ 52 | Link::make(__('Save')) 53 | ->icon('icon-check') 54 | ->method('save'), 55 | 56 | Link::make(__('Remove')) 57 | ->icon('icon-trash') 58 | ->method('remove'), 59 | ]; 60 | } 61 | 62 | /** 63 | * Views. 64 | * 65 | * @return Layout[] 66 | */ 67 | public function layout(): array 68 | { 69 | return [ 70 | Layout::columns([ 71 | 'CommentEdit' => [ 72 | CommentEditLayout::class, 73 | ], 74 | ]), 75 | ]; 76 | } 77 | 78 | /** 79 | * @param Comment $comment 80 | * @param Request $request 81 | * 82 | * @return \Illuminate\Http\RedirectResponse 83 | */ 84 | public function save(Comment $comment, Request $request) 85 | { 86 | $comment 87 | ->fill($request->get('comment')) 88 | ->save(); 89 | 90 | Alert::info(__('Comment was saved')); 91 | 92 | return redirect()->route('platform.systems.comments'); 93 | } 94 | 95 | /** 96 | * @param Comment $comment 97 | * 98 | * @throws \Exception 99 | * 100 | * @return \Illuminate\Http\RedirectResponse 101 | */ 102 | public function remove(Comment $comment) 103 | { 104 | $comment->delete(); 105 | 106 | Alert::info(__('Comment was removed')); 107 | 108 | return redirect()->route('platform.systems.comments'); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/Entities/Structure.php: -------------------------------------------------------------------------------- 1 | __('Published'), 76 | 'draft' => __('Draft'), 77 | ]; 78 | } 79 | 80 | /** 81 | * Request Validation. 82 | * 83 | * @return array 84 | */ 85 | public function isValid(): array 86 | { 87 | return $this->validate(request(), $this->rules()); 88 | } 89 | 90 | /** 91 | * Validation Request Rules. 92 | * 93 | * @return array 94 | */ 95 | public function rules(): array 96 | { 97 | return []; 98 | } 99 | 100 | /** 101 | * Registered fields for main. 102 | * 103 | * @return array 104 | */ 105 | abstract public function main(): array; 106 | 107 | /** 108 | * Registered fields for filling. 109 | * 110 | * @return array 111 | */ 112 | abstract public function fields(): array; 113 | 114 | /** 115 | * Registered fields for options. 116 | * 117 | * @return array 118 | */ 119 | abstract public function options(): array; 120 | 121 | /** 122 | * Language support for recording. 123 | * 124 | * @return array 125 | */ 126 | public function locale(): array 127 | { 128 | return config('press.locales', []); 129 | } 130 | 131 | /** 132 | * @return string 133 | */ 134 | public function __toString() 135 | { 136 | return $this->slug; 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /src/Models/Tag.php: -------------------------------------------------------------------------------- 1 | exists) { 47 | $this->tagged()->delete(); 48 | } 49 | 50 | return parent::delete(); 51 | } 52 | 53 | /** 54 | * Returns the polymorphic relationship. 55 | * 56 | * @return \Illuminate\Database\Eloquent\Relations\MorphTo 57 | */ 58 | public function taggable() 59 | { 60 | return $this->morphTo(); 61 | } 62 | 63 | /** 64 | * Returns this tag tagged entities. 65 | * 66 | * @return \Illuminate\Database\Eloquent\Relations\HasMany 67 | */ 68 | public function tagged() 69 | { 70 | return $this->hasMany(static::$taggedModel, 'tag_id'); 71 | } 72 | 73 | /** 74 | * Finds a tag by its name. 75 | * 76 | * @param \Illuminate\Database\Eloquent\Builder $query 77 | * @param string $name 78 | * 79 | * @return \Illuminate\Database\Eloquent\Builder 80 | */ 81 | public function scopeName(Builder $query, $name) 82 | { 83 | return $query->whereName($name); 84 | } 85 | 86 | /** 87 | * Finds a tag by its slug. 88 | * 89 | * @param \Illuminate\Database\Eloquent\Builder $query 90 | * @param string $slug 91 | * 92 | * @return \Illuminate\Database\Eloquent\Builder 93 | */ 94 | public function scopeSlug(Builder $query, $slug) 95 | { 96 | return $query->whereSlug($slug); 97 | } 98 | 99 | /** 100 | * Returns the tagged entities model. 101 | * 102 | * @return string 103 | */ 104 | public static function getTaggedModel() 105 | { 106 | return static::$taggedModel; 107 | } 108 | 109 | /** 110 | * Sets the tagged entities model. 111 | * 112 | * @param string $taggedModel 113 | * 114 | * @return void 115 | */ 116 | public static function setTaggedModel($taggedModel) 117 | { 118 | static::$taggedModel = $taggedModel; 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /resources/lang/ru.json: -------------------------------------------------------------------------------- 1 | { 2 | "Add link to browser favorites": "Добавить ссылку в избранное браузера", 3 | "Answer to the question": "Ответ на вопрос", 4 | "Categories": "Категории", 5 | "Category": "Категории", 6 | "Category name": "Название категории", 7 | "Category title": "Название категории", 8 | "Category was removed": "Категория была удалена", 9 | "Category was saved": "Категория была сохранена", 10 | "Comment": "Комментарий", 11 | "Comment was removed": "Комментарий был удален", 12 | "Comment was saved": "Комментарий был сохранен", 13 | "Comments": "Комментарии", 14 | "Comments allow your website's visitors to have a discussion with you and each other.": "Комментарии позволяют посетителям вашего сайта общаться с вами и друг с другом.", 15 | "Do not pass HTTP headers over the link": "Не передавать по ссылке HTTP-заголовки", 16 | "Do not pass on the link TIC and PR.": "Не передавать по ссылке ТИЦ и PR.", 17 | "Editable version of the current document": "Редактируемая версия текущего документа", 18 | "Indicates that the tag (tag) is relevant to the current document": "Указывает, что метка (тег) имеет отношение к текущему документу", 19 | "Indicates that you must cache the specified resource in advance": "Указывает, что надо заранее кэшировать указанный ресурс", 20 | "Link to a colleague's page": "Ссылка на страницу коллеги по работе", 21 | "Link to a colleague's page (not at work)": "Ссылка на страницу коллеги (не по работе)", 22 | "Link to a document with help": "Ссылка на документ со справкой", 23 | "Link to a page with a license agreement or copyrights": "Ссылка на страницу с лицензионным соглашением или авторскими правами", 24 | "Link to author page on another domain": "Ссылка на страницу автора на другом домене", 25 | "Link to content": "Ссылка на содержание", 26 | "Link to friend page": "Ссылка на страницу друга", 27 | "Link to next page or section": "Ссылка на следующую страницу или раздел", 28 | "Link to page with details": "Ссылка на страницу с подробностями", 29 | "Link to search": "Ссылка на поиск", 30 | "Link to the first page": "Ссылка на первую страницу", 31 | "Link to the last page": "Ссылка на последнюю страницу", 32 | "Link to the page about the author on the same domain": "Ссылка на страницу об авторе на том же домене", 33 | "Link to the page with contact information": "Ссылка на страницу с контактной информацией", 34 | "Link to the parent page": "Ссылка на родительскую страницу", 35 | "Link to the previous page or section": "Ссылка на предыдущую страницу или раздел", 36 | "Link to the site archive": "Ссылка на архив сайта", 37 | "Menu": "Меню", 38 | "Permanent link to a section or entry": "Постоянная ссылка на раздел или запись", 39 | "Posted by": "Опубликовано", 40 | "Page": "Страница", 41 | "Post": "Запись", 42 | "Posts": "Записи", 43 | "Question": "Вопрос", 44 | "Section or chapter of the current document": "Раздел или глава текущего документа", 45 | "Header menu": "Верхнее меню", 46 | "Sidebar menu": "Боковое меню", 47 | "Footer menu": "Нижнее меню" 48 | } -------------------------------------------------------------------------------- /src/Http/Screens/EntityListScreen.php: -------------------------------------------------------------------------------- 1 | name = $type->name; 64 | $this->description = $type->description; 65 | $this->entity = $type; 66 | 67 | $this->checkPermission(Post::POST_PERMISSION_PREFIX.$type->slug); 68 | 69 | $this->grid = $type->grid(); 70 | $this->filters = $type->filters(); 71 | 72 | return [ 73 | 'data' => $type->get(), 74 | ]; 75 | } 76 | 77 | /** 78 | * @return array 79 | */ 80 | public function commandBar(): array 81 | { 82 | return [ 83 | Link::make(__('Create')) 84 | ->icon('icon-check') 85 | ->href(route('platform.entities.type.create', $this->entity->slug)), 86 | ]; 87 | } 88 | 89 | /** 90 | * Views. 91 | * 92 | * @return array 93 | */ 94 | public function layout(): array 95 | { 96 | return [ 97 | LayoutFactory::view('press::container.posts.restore'), 98 | new EntitiesSelection($this->filters), 99 | LayoutFactory::table('data', $this->grid), 100 | ]; 101 | } 102 | 103 | /** 104 | * @param EntityContract $type 105 | * @param int $id 106 | * 107 | * @return RedirectResponse 108 | */ 109 | public function restore(EntityContract $type, int $id): RedirectResponse 110 | { 111 | Post::onlyTrashed()->findOrFail($id)->restore(); 112 | 113 | Alert::success(__('Operation completed successfully.')); 114 | 115 | return redirect()->route('platform.entities.type', [ 116 | 'type' => $type->slug, 117 | ]); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /resources/lang/uk.json: -------------------------------------------------------------------------------- 1 | { 2 | "Add link to browser favorites": "Додати посилання до закладки у браузері", 3 | "Answer to the question": "Відповідь на питання", 4 | "Categories": "Категорії", 5 | "Category": "Категорія", 6 | "Category name": "Назва категорії", 7 | "Category title": "Заголовок категорії", 8 | "Category was removed": "Категорія видалена", 9 | "Category was saved": "Зміни до категорії збережені", 10 | "Comment": "Коментар", 11 | "Comment was removed": "Коментар успішно видален", 12 | "Comment was saved": "Коментар збереженно", 13 | "Comments": "Коментарі", 14 | "Comments allow your website's visitors to have a discussion with you and each other.": "Коментарі дозволяють відвідувачам вашого веб-сайту провести обговорення один з одним та з вами.", 15 | "Do not pass HTTP headers over the link": "Не передавати в HTTP-заголовку адрес сайту.", 16 | "Do not pass on the link TIC and PR.": "Заборонии пошуковим системам індексувати посилання.", 17 | "Editable version of the current document": "Поточна версія документу з можливістю редагування", 18 | "Indicates that the tag (tag) is relevant to the current document": "Вказує, що тег відповідає поточному документу", 19 | "Indicates that you must cache the specified resource in advance": "Вказує, що потрібно заздалегідь кешувати вказаний ресурс", 20 | "Link to a colleague's page": "Посилання на сторінку колеги по роботі", 21 | "Link to a colleague's page (not at work)": "Посилання на сторінку колеги по спеціальності", 22 | "Link to a document with help": "Посилання на документ із довідковою інформацією", 23 | "Link to a page with a license agreement or copyrights": "Посилання на сторінку з ліцензійною угодою або авторськими правами", 24 | "Link to author page on another domain": "Посилання на сторінку автора на іншому сайті", 25 | "Link to content": "Посилання на сторінку", 26 | "Link to friend page": "Посилання на сторінку друга", 27 | "Link to next page or section": "Посилання на наступну сторінку або розділ", 28 | "Link to page with details": "Посилання на сторінку з детальною інформацією", 29 | "Link to search": "Посилання на пошук", 30 | "Link to the first page": "Посилання на першу сторінку", 31 | "Link to the last page": "Посилання на останню сторінку", 32 | "Link to the page about the author on the same domain": "Посилання на сторінку про автора на цьому ж сайті", 33 | "Link to the page with contact information": "Посилання на сторінку з контактною інформацією", 34 | "Link to the parent page": "Посилання на материнську сторінку", 35 | "Link to the previous page or section": "Посилання на попередню сторінку або розділ", 36 | "Link to the site archive": "Посилання на архів сайту", 37 | "Menu": "Меню", 38 | "Permanent link to a section or entry": "Постійне посилання на розділ або запис", 39 | "Page": "Сторінка", 40 | "Post": "Запис", 41 | "Posted by": "Опубліковано", 42 | "Posts": "Записи", 43 | "Question": "Питання", 44 | "Section or chapter of the current document": "Розділ або глава поточного документа", 45 | "Header menu": "Верхнє меню", 46 | "Sidebar menu": "Бокове меню", 47 | "Footer menu": "Нижнє меню" 48 | } -------------------------------------------------------------------------------- /src/Http/Screens/Category/CategoryEditScreen.php: -------------------------------------------------------------------------------- 1 | exists) { 41 | $category->setRelation('term', [new Term()]); 42 | } 43 | 44 | return [ 45 | 'category' => $category, 46 | 'catselect'=> $category->getAllCategories(), 47 | ]; 48 | } 49 | 50 | /** 51 | * Button commands. 52 | * 53 | * @return Link[] 54 | */ 55 | public function commandBar(): array 56 | { 57 | return [ 58 | Button::make(__('Save')) 59 | ->icon('icon-check') 60 | ->method('save'), 61 | 62 | Button::make(__('Remove')) 63 | ->icon('icon-trash') 64 | ->method('remove'), 65 | ]; 66 | } 67 | 68 | /** 69 | * Views. 70 | * 71 | * @return Layout[] 72 | */ 73 | public function layout(): array 74 | { 75 | return [ 76 | CategoryEditLayout::class, 77 | ]; 78 | } 79 | 80 | /** 81 | * @param Category $category 82 | * @param Request $request 83 | * 84 | * @return \Illuminate\Http\RedirectResponse 85 | */ 86 | public function save(Category $category, Request $request) 87 | { 88 | $attributes = $request->get('category'); 89 | 90 | if (!$category->exists) { 91 | $category->newWithCreateTerm($attributes['term']); 92 | } 93 | 94 | $category->setParent($attributes['parent_id']); 95 | 96 | $category->term->fill($attributes['term'])->save(); 97 | $category->save(); 98 | 99 | Alert::info(__('Category was saved')); 100 | 101 | return redirect()->route('platform.systems.category'); 102 | } 103 | 104 | /** 105 | * @param Category $category 106 | * 107 | * @throws \Exception 108 | * 109 | * @return \Illuminate\Http\RedirectResponse 110 | */ 111 | public function remove(Category $category) 112 | { 113 | $category->term->delete(); 114 | $category->delete(); 115 | 116 | Alert::info(__('Category was removed')); 117 | 118 | return redirect()->route('platform.systems.category'); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src/Models/Taxonomy.php: -------------------------------------------------------------------------------- 1 | $key) && isset($this->term->$key)) { 53 | return $this->term->$key; 54 | } 55 | 56 | return parent::__get($key); 57 | } 58 | 59 | /** 60 | * Relationship with Term model. 61 | * 62 | * @return \Illuminate\Database\Eloquent\Relations\BelongsTo 63 | */ 64 | public function term(): BelongsTo 65 | { 66 | return $this->belongsTo(Dashboard::model(Term::class), 'term_id'); 67 | } 68 | 69 | /** 70 | * Relationship with parent Term model. 71 | * 72 | * @return \Illuminate\Database\Eloquent\Relations\BelongsTo 73 | */ 74 | public function parentTerm(): BelongsTo 75 | { 76 | return $this->belongsTo(static::class, 'parent_id'); 77 | } 78 | 79 | /** 80 | * @return mixed 81 | */ 82 | public function allChildrenTerm() 83 | { 84 | return $this->childrenTerm()->with('childrenTerm'); 85 | } 86 | 87 | /** 88 | * Relationship with children Term model. 89 | * 90 | * @return \Illuminate\Database\Eloquent\Relations\HasMany 91 | */ 92 | public function childrenTerm(): HasMany 93 | { 94 | return $this->hasMany(static::class, 'parent_id'); 95 | } 96 | 97 | /** 98 | * Relationship with Posts model. 99 | * 100 | * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany 101 | */ 102 | public function posts(): BelongsToMany 103 | { 104 | return $this->belongsToMany(Dashboard::model(Post::class), 'term_relationships', 'term_taxonomy_id', 'post_id'); 105 | } 106 | 107 | /** 108 | * @param \Illuminate\Database\Query\Builder $query 109 | * 110 | * @return TaxonomyBuilder 111 | */ 112 | public function newEloquentBuilder($query) 113 | { 114 | $builder = new TaxonomyBuilder($query); 115 | 116 | return isset($this->taxonomy) && $this->taxonomy ? $builder->where('taxonomy', $this->taxonomy) : $builder; 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/Models/Comment.php: -------------------------------------------------------------------------------- 1 | 'integer', 40 | 'user_id' => 'integer', 41 | 'parent_id' => 'integer', 42 | 'approved' => 'boolean', 43 | ]; 44 | 45 | /** 46 | * Find a comment by post ID. 47 | * 48 | * @param int $postId 49 | * 50 | * @return mixed 51 | */ 52 | public static function findByPostId(int $postId) 53 | { 54 | $instance = new static(); 55 | 56 | return $instance->where('post_id', $postId)->get(); 57 | } 58 | 59 | /** 60 | * Post relationship. 61 | * 62 | * @return \Illuminate\Database\Eloquent\Relations\BelongsTo 63 | */ 64 | public function post(): BelongsTo 65 | { 66 | return $this->belongsTo(Dashboard::model(Post::class), 'post_id'); 67 | } 68 | 69 | /** 70 | * Original relationship. 71 | * 72 | * @return \Illuminate\Database\Eloquent\Relations\BelongsTo 73 | */ 74 | public function original(): BelongsTo 75 | { 76 | return $this->belongsTo(static::class, 'parent_id'); 77 | } 78 | 79 | /** 80 | * Replies relationship. 81 | * 82 | * @return \Illuminate\Database\Eloquent\Relations\HasMany 83 | */ 84 | public function replies(): HasMany 85 | { 86 | return $this->hasMany(static::class, 'parent_id'); 87 | } 88 | 89 | /** 90 | * Verify if the current comment is approved. 91 | * 92 | * @return bool 93 | */ 94 | public function isApproved(): bool 95 | { 96 | return $this->attributes['approved'] === 1 || $this->attributes['approved'] === true; 97 | } 98 | 99 | /** 100 | * Verify if the current comment is a reply from another comment. 101 | * 102 | * @return bool 103 | */ 104 | public function isReply(): bool 105 | { 106 | return $this->attributes['parent_id'] > 0; 107 | } 108 | 109 | /** 110 | * Verify if the current comment has replies. 111 | * 112 | * @return bool 113 | */ 114 | public function hasReplies(): bool 115 | { 116 | return count($this->replies) > 0; 117 | } 118 | 119 | /** 120 | * Author relationship. 121 | * 122 | * @return \Illuminate\Database\Eloquent\Relations\BelongsTo 123 | */ 124 | public function author(): BelongsTo 125 | { 126 | return $this->belongsTo(Dashboard::model(User::class), 'user_id'); 127 | } 128 | 129 | /** 130 | * Where clause for only approved comments. 131 | * 132 | * @param Builder $query 133 | * 134 | * @return Builder 135 | */ 136 | public function scopeApproved(Builder $query): Builder 137 | { 138 | return $query->where('approved', 1); 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /routes/breadcrumbs.php: -------------------------------------------------------------------------------- 1 | System > Menu 4 | Breadcrumbs::for('platform.systems.menu.index', function ($trail) { 5 | $trail->parent('platform.systems.index'); 6 | $trail->push(__('Menu'), route('platform.systems.menu.index')); 7 | }); 8 | 9 | // Platform > System > Menu > Editing 10 | Breadcrumbs::for('platform.systems.menu.show', function ($trail, $menu) { 11 | $trail->parent('platform.systems.menu.index'); 12 | $trail->push(__('Editing'), route('platform.systems.menu.show', $menu)); 13 | }); 14 | 15 | // Platform > System > Category 16 | Breadcrumbs::for('platform.systems.category', function ($trail) { 17 | $trail->parent('platform.systems.index'); 18 | $trail->push(__('Categories'), route('platform.systems.category')); 19 | }); 20 | 21 | // Platform > System > Categories > Create 22 | Breadcrumbs::for('platform.systems.category.create', function ($trail) { 23 | $trail->parent('platform.systems.category'); 24 | $trail->push(__('Create'), route('platform.systems.category.create')); 25 | }); 26 | 27 | // Platform > Categories > Category 28 | Breadcrumbs::for('platform.systems.category.edit', function ($trail, $category) { 29 | $trail->parent('platform.systems.category'); 30 | $trail->push(__('Category'), route('platform.systems.category.edit', $category)); 31 | }); 32 | 33 | // Platform > System > Comments 34 | Breadcrumbs::for('platform.systems.comments', function ($trail) { 35 | $trail->parent('platform.systems.index'); 36 | $trail->push(__('Comments'), route('platform.systems.comments')); 37 | }); 38 | 39 | // Platform > System > Comments > Comment 40 | Breadcrumbs::for('platform.systems.comments.edit', function ($trail, $comment) { 41 | $trail->parent('platform.systems.comments'); 42 | $trail->push(__('Comment'), route('platform.systems.comments.edit', $comment)); 43 | }); 44 | 45 | //Posts 46 | 47 | // Platform > Posts 48 | Breadcrumbs::for('platform.entities.type', function ($trail, $type) { 49 | $trail->parent('platform.index'); 50 | $trail->push(__('Posts'), route('platform.entities.type', $type->slug)); 51 | }); 52 | 53 | // Platform > Posts > Create 54 | Breadcrumbs::for('platform.entities.type.create', function ($trail, $type) { 55 | $trail->parent('platform.entities.type', $type); 56 | $trail->push(__('Create'), route('platform.entities.type', $type->slug)); 57 | }); 58 | 59 | // Platform > Posts > Edit 60 | Breadcrumbs::for('platform.entities.type.edit', function ($trail, $type, $post) { 61 | $trail->parent('platform.entities.type', $type); 62 | $trail->push($post->getContent($type->slugFields) ?? '—', route('platform.entities.type.edit', [$type->slug, $post->slug])); 63 | }); 64 | 65 | // Platform > Pages 66 | Breadcrumbs::for('platform.entities.type.page', function ($trail, $page) { 67 | $trail->parent('platform.index'); 68 | $trail->push(__('Pages'), route('platform.entities.type.page', $page)); 69 | }); 70 | 71 | // Home 72 | Breadcrumbs::for('home', function ($trail) { 73 | $trail->push('Home', route('home')); 74 | }); 75 | 76 | // Home > About 77 | Breadcrumbs::for('about', function ($trail) { 78 | $trail->parent('home'); 79 | $trail->push('About', route('about')); 80 | }); 81 | 82 | // Home > Blog 83 | Breadcrumbs::for('blog', function ($trail) { 84 | $trail->parent('home'); 85 | $trail->push('Blog', route('blog')); 86 | }); 87 | 88 | // Home > Blog > [Category] 89 | Breadcrumbs::for('category', function ($trail, $category) { 90 | $trail->parent('blog'); 91 | $trail->push($category->title, route('category', $category->id)); 92 | }); 93 | 94 | // Home > Blog > [Category] > [Post] 95 | Breadcrumbs::for('post', function ($trail, $post) { 96 | $trail->parent('category', $post->category); 97 | $trail->push($post->title, route('post', $post->id)); 98 | }); 99 | -------------------------------------------------------------------------------- /resources/templates/clean-blog/views/layouts/app.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | @yield('title','Последние записи') - {{setting('site_title')}} 9 | 10 | 11 | @php $theme_path = '/dashboard/resources/press/'.config('press.theme'); @endphp 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 32 | 33 | 34 |
    35 |
    36 |
    37 |
    38 |
    39 |
    40 |

    {{setting('site_title') ?? 'Clean Blog'}}

    41 | {{setting('site_description') ?? 'A Blog Theme by Start Bootstrap'}} 42 | @yield('author') 43 |
    44 |
    45 |
    46 |
    47 |
    48 | 49 | 50 | @yield('content') 51 | 52 |
    53 | 54 | 55 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /src/Support/helpers.php: -------------------------------------------------------------------------------- 1 | setLanguage($language) 30 | ->setPrefix($prefix) 31 | ->generateForm(); 32 | } 33 | } 34 | 35 | if (!function_exists('theme_path')) { 36 | /** 37 | * Helper function to send an alert. 38 | * 39 | * @param $img 40 | * @param string $level 41 | * 42 | * @return Alert 43 | */ 44 | function theme_path($path = '') 45 | { 46 | return '/dashboard/resources/press/'.config('press.theme').'/'.$path; 47 | } 48 | } 49 | 50 | 51 | if (!function_exists('phone_number')) { 52 | /** 53 | * Helper function to send an alert. 54 | * 55 | * @param $img 56 | * @param string $level 57 | * 58 | * @return Alert 59 | */ 60 | 61 | function phone_number($phone, $variant = 1) 62 | { 63 | $phone = trim($phone); 64 | 65 | if ($variant==2) { 66 | return preg_replace( 67 | array( 68 | '/[\+]?([7|8])[-|\s]?\([-|\s]?(\d{3})[-|\s]?\)[-|\s]?(\d{3})[-|\s]?(\d{2})[-|\s]?(\d{2})/', 69 | '/[\+]?([7|8])[-|\s]?(\d{3})[-|\s]?(\d{3})[-|\s]?(\d{2})[-|\s]?(\d{2})/', 70 | '/[\+]?([7|8])[-|\s]?\([-|\s]?(\d{4})[-|\s]?\)[-|\s]?(\d{2})[-|\s]?(\d{2})[-|\s]?(\d{2})/', 71 | '/[\+]?([7|8])[-|\s]?(\d{4})[-|\s]?(\d{2})[-|\s]?(\d{2})[-|\s]?(\d{2})/', 72 | '/[\+]?([7|8])[-|\s]?\([-|\s]?(\d{4})[-|\s]?\)[-|\s]?(\d{3})[-|\s]?(\d{3})/', 73 | '/[\+]?([7|8])[-|\s]?(\d{4})[-|\s]?(\d{3})[-|\s]?(\d{3})/', 74 | ), 75 | array( 76 | '+7 $2 $3-$4-$5', 77 | '+7 $2 $3-$4-$5', 78 | '+7 $2 $3-$4-$5', 79 | '+7 $2 $3-$4-$5', 80 | '+7 $2 $3-$4', 81 | '+7 $2 $3-$4', 82 | ), 83 | $phone 84 | ); 85 | } 86 | 87 | return preg_replace( 88 | array( 89 | '/[\+]?([7|8])[-|\s]?\([-|\s]?(\d{4})[-|\s]?\)[-|\s]?(\d{2})[-|\s]?(\d{2})[-|\s]?(\d{2})/', 90 | '/[\+]?([7|8])[-|\s]?(\d{4})[-|\s]?(\d{2})[-|\s]?(\d{2})[-|\s]?(\d{2})/', 91 | '/[\+]?([7|8])[-|\s]?\([-|\s]?(\d{4})[-|\s]?\)[-|\s]?(\d{2})[-|\s]?(\d{2})[-|\s]?(\d{2})/', 92 | '/[\+]?([7|8])[-|\s]?(\d{4})[-|\s]?(\d{2})[-|\s]?(\d{2})[-|\s]?(\d{2})/', 93 | '/[\+]?([7|8])[-|\s]?\([-|\s]?(\d{4})[-|\s]?\)[-|\s]?(\d{3})[-|\s]?(\d{3})/', 94 | '/[\+]?([7|8])[-|\s]?(\d{4})[-|\s]?(\d{3})[-|\s]?(\d{3})/', 95 | ), 96 | array( 97 | '+7 ($2) $3-$4-$5', 98 | '+7 ($2) $3-$4-$5', 99 | '+7 ($2) $3-$4-$5', 100 | '+7 ($2) $3-$4-$5', 101 | '+7 ($2) $3-$4', 102 | '+7 ($2) $3-$4', 103 | ), 104 | $phone 105 | ); 106 | 107 | } 108 | 109 | } -------------------------------------------------------------------------------- /src/Screen/Fields/Tags.php: -------------------------------------------------------------------------------- 1 | 'form-control', 57 | 'multiple' => 'multiple', 58 | ]; 59 | 60 | /** 61 | * Attributes available for a particular tag. 62 | * 63 | * @var array 64 | */ 65 | public $inlineAttributes = [ 66 | 'accept', 67 | 'accesskey', 68 | 'autocomplete', 69 | 'autofocus', 70 | 'checked', 71 | 'disabled', 72 | 'form', 73 | 'formaction', 74 | 'formenctype', 75 | 'formmethod', 76 | 'formnovalidate', 77 | 'formtarget', 78 | 'list', 79 | 'max', 80 | 'maxlength', 81 | 'min', 82 | 'multiple', 83 | 'name', 84 | 'pattern', 85 | 'placeholder', 86 | 'readonly', 87 | 'required', 88 | 'size', 89 | 'src', 90 | 'step', 91 | 'tabindex', 92 | 'type', 93 | 'value', 94 | ]; 95 | 96 | /** 97 | * @param string|null $name 98 | * 99 | * @return self 100 | */ 101 | public static function make(string $name = null): self 102 | { 103 | return (new static())->name($name); 104 | } 105 | 106 | /** 107 | * @param string|\Closure $name 108 | * 109 | * @return \Orchid\Screen\Field|void 110 | */ 111 | public function modifyName() 112 | { 113 | $name = $this->get('name'); 114 | if (substr($name, -1) !== '.') { 115 | $this->attributes['name'] = $name.'[]'; 116 | } 117 | 118 | parent::modifyName(); 119 | 120 | return $this; 121 | } 122 | 123 | /** 124 | * @param mixed $value 125 | * 126 | * @return self 127 | */ 128 | public function modifyValue() 129 | { 130 | $value = $this->getOldValue() ?: $this->get('value'); 131 | if (is_string($value)) { 132 | $this->attributes['value'] = explode(',', $value); 133 | } 134 | 135 | if ($value instanceof \Closure) { 136 | $this->attributes['value'] = $value($this->attributes); 137 | } 138 | 139 | if (is_null($value)) { 140 | $this->attributes['value'] = []; 141 | } 142 | 143 | return $this; 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /src/Http/Controllers/MenuController.php: -------------------------------------------------------------------------------- 1 | checkPermission('platform.systems.menu'); 31 | } 32 | 33 | /** 34 | * @return \Illuminate\Http\RedirectResponse|null 35 | */ 36 | public function index() 37 | { 38 | $availableMenus = collect(config('press.menu')); 39 | 40 | if ($availableMenus->count() > 0) { 41 | return redirect()->route('platform.systems.menu.show', $availableMenus->keys()->first()); 42 | } 43 | 44 | abort(404); 45 | } 46 | 47 | /** 48 | * @param string $name 49 | * @param Request $request 50 | * 51 | * @return View 52 | */ 53 | public function show(string $name, Request $request) 54 | { 55 | $availableMenus = config('press.menu'); 56 | $currentLocale = $request->get('lang', app()->getLocale()); 57 | 58 | $menu = Dashboard::modelClass(Menu::class) 59 | ->where('lang', $currentLocale) 60 | ->where('parent', 0) 61 | ->where('type', $name) 62 | ->orderBy('sort', 'asc') 63 | ->with('children') 64 | ->get(); 65 | 66 | return view('press::container.systems.menu', [ 67 | 'name' => $name, 68 | 'locales' => config('press.locales'), 69 | 'currentLocale' => $currentLocale, 70 | 'menu' => $menu, 71 | 'availableMenus' => $availableMenus, 72 | ]); 73 | } 74 | 75 | /** 76 | * @param Request $request 77 | * 78 | * @return \Illuminate\Http\JsonResponse 79 | */ 80 | public function store(Request $request) 81 | { 82 | $menu = Dashboard::model(Menu::class)::create(array_merge($request->input('params.data'), [ 83 | 'lang' => $request->input('params.lang'), 84 | 'type' => $request->input('params.menu'), 85 | 'parent' => 0, 86 | ])); 87 | 88 | return response()->json([ 89 | 'type' => 'success', 90 | 'id' => $menu->id, 91 | ]); 92 | } 93 | 94 | /** 95 | * @param string $menu 96 | * @param Request $request 97 | * 98 | * @return \Illuminate\Http\JsonResponse 99 | */ 100 | public function update(string $menu, Request $request) 101 | { 102 | $this->lang = $request->get('lang'); 103 | $this->menu = $menu; 104 | 105 | $this->createMenuElement($request->get('data')); 106 | 107 | return response()->json([ 108 | 'type' => 'success', 109 | ]); 110 | } 111 | 112 | /** 113 | * @param array $items 114 | * @param int $parent 115 | */ 116 | private function createMenuElement(array $items, $parent = 0) 117 | { 118 | foreach ($items as $item) { 119 | Dashboard::model(Menu::class)::firstOrNew([ 120 | 'id' => $item['id'], 121 | ])->fill(array_merge($item, [ 122 | 'lang' => $this->lang, 123 | 'type' => $this->menu, 124 | 'parent' => $parent, 125 | ]))->save(); 126 | 127 | if (array_key_exists('children', $item)) { 128 | $this->createMenuElement($item['children'], $item['id']); 129 | } 130 | } 131 | } 132 | 133 | /** 134 | * @param Menu $menu 135 | * 136 | * @throws \Exception 137 | * 138 | * @return \Illuminate\Http\JsonResponse 139 | */ 140 | public function destroy(Menu $menu) 141 | { 142 | Dashboard::model(Menu::class)::where('parent', $menu->id)->delete(); 143 | $menu->delete(); 144 | 145 | return response()->json([ 146 | 'type' => 'success', 147 | ]); 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /src/Http/Screens/EntityEditScreen.php: -------------------------------------------------------------------------------- 1 | name = $type->name; 61 | $this->description = $type->description; 62 | $this->entity = $type; 63 | $this->exist = $post->exists; 64 | $this->locales = collect($type->locale()); 65 | 66 | $this->checkPermission(Post::POST_PERMISSION_PREFIX.$type->slug); 67 | 68 | return [ 69 | 'locales' => collect($type->locale()), 70 | 'type' => $type, 71 | 'post' => $type->create($post), 72 | ]; 73 | } 74 | 75 | /** 76 | * @return array 77 | */ 78 | public function commandBar(): array 79 | { 80 | return [ 81 | Button::make(__('Create')) 82 | ->icon('icon-check') 83 | ->method('save') 84 | ->canSee(!$this->exist), 85 | 86 | Button::make(__('Remove')) 87 | ->icon('icon-trash') 88 | ->method('destroy') 89 | ->canSee($this->exist && is_a($this->entity, Many::class)), 90 | 91 | Button::make(__('Save')) 92 | ->icon('icon-check') 93 | ->method('save') 94 | ->canSee($this->exist), 95 | ]; 96 | } 97 | 98 | /** 99 | * Views. 100 | * 101 | * @return array 102 | */ 103 | public function layout(): array 104 | { 105 | return [ 106 | LayoutFactory::view('press::container.posts.edit'), 107 | ]; 108 | } 109 | 110 | /** 111 | * @param EntityContract $type 112 | * @param Post $post 113 | * @param Request $request 114 | * 115 | * @throws \Illuminate\Validation\ValidationException 116 | * 117 | * @return RedirectResponse 118 | */ 119 | public function save(EntityContract $type, Post $post, Request $request): RedirectResponse 120 | { 121 | $this->checkPermission(Post::POST_PERMISSION_PREFIX.$type->slug); 122 | $type->isValid(); 123 | 124 | $post->fill($request->all())->fill([ 125 | 'type' => $type->slug, 126 | 'user_id' => $request->user()->id, 127 | 'options' => $post->getOptions(), 128 | ]); 129 | 130 | $type->save($post); 131 | 132 | Alert::success(__('Operation completed successfully.')); 133 | 134 | $route = is_a($type, Many::class) 135 | ? 'platform.entities.type.edit' 136 | : 'platform.entities.type.page'; 137 | 138 | return redirect()->route($route, [$post->type, $post->slug]); 139 | } 140 | 141 | /** 142 | * @param EntityContract $type 143 | * @param Post $post 144 | * 145 | * @throws \Exception 146 | * 147 | * @return RedirectResponse 148 | * 149 | * @internal param Request $request 150 | * @internal param Post $type 151 | */ 152 | public function destroy(EntityContract $type, Post $post): RedirectResponse 153 | { 154 | $this->checkPermission(Post::POST_PERMISSION_PREFIX.$type->slug); 155 | 156 | $type->delete($post); 157 | 158 | Alert::success(__('Operation completed successfully.')); 159 | 160 | return redirect()->route('platform.entities.type', [ 161 | 'type' => $type->slug, 162 | ])->with([ 163 | 'restore' => route('platform.entities.type', [ 164 | 'type' => $type->slug, 165 | $post->id, 166 | 'restore', 167 | ]), 168 | ]); 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /install-stubs/Orchid/Entities/Page.php: -------------------------------------------------------------------------------- 1 | 'sometimes|integer|unique:posts', 63 | 'content.*.name' => 'required|string', 64 | 'content.*.body' => 'required|string', 65 | ]; 66 | } 67 | 68 | /** 69 | * @throws \Throwable|\Orchid\Screen\Exceptions\TypeException 70 | * 71 | * @return array 72 | */ 73 | public function fields(): array 74 | { 75 | return [ 76 | 77 | Field::group([ 78 | 79 | Input::make('name') 80 | ->type('text') 81 | ->max(255) 82 | ->required() 83 | ->title('Name Articles') 84 | ->help('Article title'), 85 | 86 | Input::make('title') 87 | ->type('text') 88 | ->max(255) 89 | ->required() 90 | ->title('Article Title') 91 | ->help('SEO title'), 92 | 93 | ]), 94 | 95 | Field::group([ 96 | 97 | DateTimer::make('open') 98 | ->title('Opening date') 99 | ->help('The opening event will take place'), 100 | 101 | Input::make('phone') 102 | ->type('text') 103 | ->mask('(999) 999-9999') 104 | ->title('Phone') 105 | ->help('Number Phone'), 106 | 107 | CheckBox::make('free') 108 | ->sendTrueOrFalse() 109 | ->title('Free') 110 | ->placeholder('Event for free') 111 | ->help('Event for free'), 112 | ]), 113 | 114 | TextArea::make('description') 115 | ->max(255) 116 | ->rows(5) 117 | ->required() 118 | ->title('Short description'), 119 | 120 | TinyMCE::make('body') 121 | ->required() 122 | ->title('Name Articles') 123 | ->help('Article title'), 124 | 125 | Map::make('place') 126 | ->required() 127 | ->title('Object on the map') 128 | ->help('Enter the coordinates, or use the search'), 129 | 130 | Cropper::make('picture') 131 | ->width(500) 132 | ->height(300), 133 | 134 | UTM::make('link') 135 | ->title('UTM link') 136 | ->help('Generated link'), 137 | 138 | Select::make('robot.') 139 | ->options([ 140 | 'index' => 'Index', 141 | 'noindex' => 'No index', 142 | ]) 143 | ->multiple() 144 | ->title('Indexing') 145 | ->help('Allow search bots to index'), 146 | 147 | Tags::make('keywords') 148 | ->title('Keywords') 149 | ->help('SEO keywords'), 150 | 151 | SimpleMDE::make('body2') 152 | ->title('Name Articles') 153 | ->help('Article title'), 154 | 155 | Quill::make('body3') 156 | ->title('Name Articles') 157 | ->help('Article title'), 158 | 159 | Code::make('code') 160 | ->title('Name Articles') 161 | ->help('Article title'), 162 | ]; 163 | } 164 | 165 | /** 166 | * @throws \Throwable 167 | * 168 | * @return array 169 | */ 170 | public function options(): array 171 | { 172 | return []; 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /resources/views/container/posts/edit.blade.php: -------------------------------------------------------------------------------- 1 |
    2 | 3 |
    4 | @if(count($type->fields()) > 0) 5 | 6 |
    7 |
    8 |
    9 | @if($hasLocales = ($locales->count() > 1)) 10 | 26 | @endif 27 |
    28 | @foreach($locales as $code => $lang) 29 |
    31 | {!! generate_form($type->fields(), $post->toArray(), $code, 'content') !!} 32 |
    33 | @endforeach 34 |
    35 |
    36 |
    37 |
    38 | 39 | @endif 40 | 41 |
    42 |
    43 |
    44 |
    47 | @if($hasOptions = ($type->options() !== [])) 48 | 72 | @endif 73 |
    74 |
    75 |
    76 | {!! generate_form($type->main(), $post->toArray()) !!} 77 |
    78 |
    79 | @if($hasOptions) 80 |
    81 |
    82 | {!! generate_form($type->options(), $post->toArray(), null, 'options') !!} 83 |
    84 |
    85 | @endif 86 |
    87 |
    88 |
    89 |
    90 |
    91 | 92 |
    93 |
    94 | -------------------------------------------------------------------------------- /public/css/press.css: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /** 4 | * Nestable 5 | */ 6 | 7 | .dd { 8 | position: relative; 9 | display: block; 10 | margin: 0; 11 | padding: 0; 12 | max-width: 100%; 13 | list-style: none; 14 | font-size: 13px; 15 | line-height: 20px; 16 | /** 17 | * Nestable Extras 18 | */ 19 | /** 20 | * Nestable Draggable Handles 21 | */ 22 | } 23 | 24 | .dd .edit { 25 | position: absolute; 26 | margin: 0; 27 | right: 0; 28 | top: 0; 29 | cursor: pointer; 30 | width: 40px; 31 | text-indent: 100%; 32 | white-space: nowrap; 33 | overflow: hidden; 34 | border: 1px solid #ebebeb; 35 | background: #ffffff; 36 | border-top-right-radius: 0; 37 | padding: 10px 10px; 38 | height: 42px; 39 | } 40 | 41 | .dd .edit:before { 42 | display: block; 43 | position: absolute; 44 | left: 0; 45 | top: 10px; 46 | width: 100%; 47 | text-align: center; 48 | text-indent: 0; 49 | color: #495057; 50 | font-size: 15px; 51 | font-weight: normal; 52 | } 53 | 54 | .dd .dd-list { 55 | display: block; 56 | position: relative; 57 | margin: 0; 58 | padding: 0; 59 | list-style: none; 60 | } 61 | 62 | .dd .dd-list .dd-list { 63 | padding-left: 30px; 64 | } 65 | 66 | .dd .dd-dragel .edit { 67 | display: none; 68 | } 69 | 70 | .dd .dd-item, 71 | .dd .dd-empty, 72 | .dd .dd-placeholder { 73 | display: block; 74 | position: relative; 75 | margin: 0; 76 | padding: 0; 77 | min-height: 20px; 78 | font-size: 13px; 79 | line-height: 20px; 80 | } 81 | 82 | .dd .dd-item.dd-collapsed .dd-list, 83 | .dd .dd-item.dd-collapsed .dd-collapse { 84 | display: none; 85 | } 86 | 87 | .dd .dd-item.dd-collapsed .dd-expand { 88 | display: block; 89 | } 90 | 91 | .dd .dd-handle, 92 | .dd .dd3-content { 93 | display: block; 94 | margin: 5px 0; 95 | padding: 10px 10px; 96 | text-decoration: none; 97 | border: 1px solid #ebebeb; 98 | background: #ffffff; 99 | border-radius: 3px; 100 | } 101 | 102 | .dd .dd-handle:hover, 103 | .dd .dd3-content:hover { 104 | background: #ffffff; 105 | } 106 | 107 | .dd .dd3-content { 108 | padding: 10px 10px 10px 50px; 109 | } 110 | 111 | .dd .dd-item > button { 112 | display: block; 113 | position: relative; 114 | cursor: pointer; 115 | float: left; 116 | width: 25px; 117 | height: 30px; 118 | margin: 5px 0; 119 | padding: 0; 120 | text-indent: 100%; 121 | white-space: nowrap; 122 | overflow: hidden; 123 | border: 0; 124 | background: transparent; 125 | font-size: 12px; 126 | line-height: 1; 127 | text-align: center; 128 | font-weight: bold; 129 | } 130 | 131 | .dd .dd-item > button.dd-expand { 132 | display: none; 133 | } 134 | 135 | .dd .dd-item > button:before { 136 | content: "+"; 137 | display: block; 138 | position: absolute; 139 | width: 100%; 140 | text-align: center; 141 | text-indent: 0; 142 | } 143 | 144 | .dd .dd-item > button[data-action=collapse]:before { 145 | content: "-"; 146 | } 147 | 148 | .dd .dd-placeholder { 149 | margin: 5px 0; 150 | padding: 0; 151 | min-height: 30px; 152 | background: #f2fbff; 153 | border: 1px dashed #b6bcbf; 154 | box-sizing: border-box; 155 | -moz-box-sizing: border-box; 156 | } 157 | 158 | .dd .dd-empty { 159 | margin: 5px 0; 160 | padding: 0; 161 | box-sizing: border-box; 162 | -moz-box-sizing: border-box; 163 | border: 1px dashed #bbbbbb; 164 | min-height: 100px; 165 | background-size: 60px 60px; 166 | background: #e5e5e5 0 0, 30px 30px; 167 | } 168 | 169 | .dd .dd-dragel { 170 | position: absolute; 171 | pointer-events: none; 172 | z-index: 9999; 173 | } 174 | 175 | .dd .dd-dragel > .dd-item .dd-handle { 176 | margin-top: 0; 177 | } 178 | 179 | .dd .dd-dragel .dd-handle { 180 | box-shadow: 2px 4px 6px 0 rgba(0, 0, 0, 0.1); 181 | } 182 | 183 | .dd .nestable-lists { 184 | display: block; 185 | clear: both; 186 | padding: 30px 0; 187 | width: 100%; 188 | border: 0; 189 | border-top: 2px solid #dddddd; 190 | border-bottom: 2px solid #dddddd; 191 | } 192 | 193 | @media only screen and (min-width: 700px) { 194 | .dd .dd + .dd { 195 | margin-left: 2%; 196 | } 197 | } 198 | 199 | .dd .dd-hover > .dd-handle { 200 | background: #2ea8e5 !important; 201 | } 202 | 203 | .dd .dd-dragel > .dd3-item > .dd3-content { 204 | margin: 0; 205 | } 206 | 207 | .dd .dd3-item > button { 208 | margin-left: 40px; 209 | } 210 | 211 | .dd .dd3-handle { 212 | position: absolute; 213 | margin: 0; 214 | left: 0; 215 | top: 0; 216 | cursor: pointer; 217 | width: 40px; 218 | text-indent: 100%; 219 | white-space: nowrap; 220 | overflow: hidden; 221 | border: 1px solid #ebebeb; 222 | background: #ffffff; 223 | color: #ffffff; 224 | border-top-right-radius: 0; 225 | border-bottom-right-radius: 0; 226 | } 227 | 228 | .dd .dd3-handle:before { 229 | content: "\2261"; 230 | display: block; 231 | position: absolute; 232 | left: 0; 233 | top: 10px; 234 | width: 100%; 235 | text-align: center; 236 | text-indent: 0; 237 | color: #495057; 238 | font-size: 20px; 239 | font-weight: normal; 240 | } 241 | 242 | .dd .dd3-handle:hover { 243 | background: #f7f7f7; 244 | } 245 | 246 | -------------------------------------------------------------------------------- /resources/sass/plugins/nestable.scss: -------------------------------------------------------------------------------- 1 | $gray-700 : #495057; 2 | 3 | /** 4 | * Nestable 5 | */ 6 | 7 | .dd { 8 | position: relative; 9 | display: block; 10 | margin: 0; 11 | padding: 0; 12 | max-width : 100%; 13 | list-style: none; 14 | font-size: 13px; 15 | line-height: 20px; 16 | 17 | .edit { 18 | position : absolute; 19 | margin : 0; 20 | right : 0; 21 | top : 0; 22 | cursor : pointer; 23 | width : 40px; 24 | text-indent : 100%; 25 | white-space : nowrap; 26 | overflow : hidden; 27 | border : 1px solid #ebebeb; 28 | background : #ffffff; 29 | border-top-right-radius : 0; 30 | padding : 10px 10px; 31 | height: 42px; 32 | 33 | &:before { 34 | display : block; 35 | position : absolute; 36 | left : 0; 37 | top: 10px; 38 | width : 100%; 39 | text-align : center; 40 | text-indent : 0; 41 | color : $gray-700; 42 | font-size : 15px; 43 | font-weight : normal; 44 | } 45 | } 46 | 47 | 48 | .dd-list { 49 | display: block; 50 | position: relative; 51 | margin: 0; 52 | padding: 0; 53 | list-style: none; 54 | .dd-list { 55 | padding-left: 30px; 56 | } 57 | } 58 | 59 | .dd-dragel{ 60 | .edit{ 61 | display: none; 62 | } 63 | } 64 | 65 | .dd-item, .dd-empty, .dd-placeholder { 66 | display: block; 67 | position: relative; 68 | margin: 0; 69 | padding: 0; 70 | min-height: 20px; 71 | font-size: 13px; 72 | line-height: 20px; 73 | } 74 | 75 | .dd-item.dd-collapsed { 76 | .dd-list, .dd-collapse { 77 | display: none; 78 | } 79 | .dd-expand { 80 | display: block; 81 | } 82 | } 83 | 84 | .dd-handle, .dd3-content { 85 | display: block; 86 | margin: 5px 0; 87 | padding: 10px 10px; 88 | text-decoration: none; 89 | border: 1px solid #ebebeb; 90 | background: #ffffff; 91 | -webkit-border-radius: 3px; 92 | border-radius: 3px; 93 | &:hover { 94 | background: #ffffff; 95 | } 96 | } 97 | 98 | .dd3-content{ 99 | padding: 10px 10px 10px 50px; 100 | } 101 | 102 | 103 | .dd-item > button { 104 | display: block; 105 | position: relative; 106 | cursor: pointer; 107 | float: left; 108 | width: 25px; 109 | height: 30px; 110 | margin: 5px 0; 111 | padding: 0; 112 | text-indent: 100%; 113 | white-space: nowrap; 114 | overflow: hidden; 115 | border: 0; 116 | background: transparent; 117 | font-size: 12px; 118 | line-height: 1; 119 | text-align: center; 120 | font-weight: bold; 121 | &.dd-expand { 122 | display: none; 123 | } 124 | &:before { 125 | content: '+'; 126 | display: block; 127 | position: absolute; 128 | width: 100%; 129 | text-align: center; 130 | text-indent: 0; 131 | } 132 | &[data-action='collapse']:before { 133 | content: '-'; 134 | } 135 | } 136 | 137 | .dd-placeholder { 138 | margin: 5px 0; 139 | padding: 0; 140 | min-height: 30px; 141 | background: #f2fbff; 142 | border: 1px dashed #b6bcbf; 143 | box-sizing: border-box; 144 | -moz-box-sizing: border-box; 145 | } 146 | 147 | .dd-empty { 148 | margin: 5px 0; 149 | padding: 0; 150 | box-sizing: border-box; 151 | -moz-box-sizing: border-box; 152 | border: 1px dashed #bbbbbb; 153 | min-height: 100px; 154 | background-size: 60px 60px; 155 | background: #e5e5e5 0 0, 30px 30px; 156 | } 157 | 158 | .dd-dragel { 159 | position: absolute; 160 | pointer-events: none; 161 | z-index: 9999; 162 | > .dd-item .dd-handle { 163 | margin-top: 0; 164 | } 165 | .dd-handle { 166 | -webkit-box-shadow: 2px 4px 6px 0 rgba(0, 0, 0, 0.1); 167 | box-shadow: 2px 4px 6px 0 rgba(0, 0, 0, 0.1); 168 | } 169 | } 170 | 171 | /** 172 | * Nestable Extras 173 | */ 174 | 175 | .nestable-lists { 176 | display: block; 177 | clear: both; 178 | padding: 30px 0; 179 | width: 100%; 180 | border: 0; 181 | border-top: 2px solid #dddddd; 182 | border-bottom: 2px solid #dddddd; 183 | } 184 | 185 | @media only screen and (min-width: 700px) { 186 | .dd + .dd { 187 | margin-left: 2%; 188 | } 189 | } 190 | 191 | .dd-hover > .dd-handle { 192 | background: #2ea8e5 !important; 193 | } 194 | 195 | /** 196 | * Nestable Draggable Handles 197 | */ 198 | 199 | .dd-dragel > .dd3-item > .dd3-content { 200 | margin: 0; 201 | } 202 | 203 | .dd3-item > button { 204 | margin-left: 40px; 205 | } 206 | 207 | .dd3-handle { 208 | position: absolute; 209 | margin: 0; 210 | left: 0; 211 | top: 0; 212 | cursor: pointer; 213 | width: 40px; 214 | text-indent: 100%; 215 | white-space: nowrap; 216 | overflow: hidden; 217 | border: 1px solid #ebebeb; 218 | background: #ffffff; 219 | color: #ffffff; 220 | border-top-right-radius: 0; 221 | border-bottom-right-radius: 0; 222 | &:before { 223 | content: '≡'; 224 | display: block; 225 | position: absolute; 226 | left: 0; 227 | top: 10px; 228 | width: 100%; 229 | text-align: center; 230 | text-indent: 0; 231 | color: $gray-700; 232 | font-size: 20px; 233 | font-weight: normal; 234 | } 235 | &:hover { 236 | background: #f7f7f7; 237 | } 238 | } 239 | } -------------------------------------------------------------------------------- /install-stubs/Controllers/PressController.php: -------------------------------------------------------------------------------- 1 | type) 24 | ->status('publish') 25 | ->with('attachment') 26 | ->orderBy('publish_at', 'Desc') 27 | ->with('taxonomies') 28 | ->paginate(10); 29 | 30 | return view(config('press.view').'pages.main', [ 31 | 'posts' => $posts, 32 | ]); 33 | } 34 | 35 | /** 36 | * @param Post $post 37 | * 38 | * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View 39 | */ 40 | public function post($categorySlug, Post $post) 41 | { 42 | $category = Category::slug($categorySlug) 43 | ->first(); 44 | $categorypage = Post::type('cathead') 45 | ->whereSlug($categorySlug) 46 | ->with('attachment') 47 | ->first(); 48 | 49 | $comments = Comment::findByPostId($post->id)->where('parent_id', 0)->where('approved', 1); 50 | 51 | $post->setRelation('category', $category); 52 | $post->setRelation('categorypage', $categorypage); 53 | 54 | $subposts = Post::type('subblog') 55 | ->whereRaw("JSON_EXTRACT(`content`, '$.ru.parentpost') = '".$post->slug."'") 56 | ->with('attachment') 57 | ->get(); 58 | $post->setRelation('subposts', $subposts); 59 | 60 | $list = (empty($post->getContent('list')) || is_null($post->getContent('list')[0])) 61 | ? ['name', 'picture', 'body', 'map', 'tags'] 62 | : $post->getContent('list'); 63 | 64 | return view(config('press.view').'pages.post', [ 65 | 'post' => $post, 66 | 'comments' => $comments, 67 | 'list' => $list, 68 | ]); 69 | } 70 | 71 | /** 72 | * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View 73 | */ 74 | public function category($categorySlug) 75 | { 76 | $category = Category::slug($categorySlug) 77 | ->with(['posts' => function ($query) { 78 | $query->type($this->type) 79 | ->status('publish') 80 | ->with('attachment') 81 | ->orderBy('publish_at', 'Desc') 82 | ->get(); 83 | }]) 84 | ->first(); 85 | 86 | $childcats = $category 87 | ->allChildrenTerm() 88 | ->with(['posts' => function ($query) { 89 | $query->type($this->type) 90 | ->status('publish') 91 | ->with('attachment') 92 | ->orderBy('publish_at', 'Desc') 93 | ->get(); 94 | }]) 95 | ->get(); 96 | 97 | $page = Post::type('cathead') 98 | ->whereSlug($categorySlug) 99 | ->with('attachment') 100 | ->first(); 101 | 102 | return view(config('press.view').'pages.category', [ 103 | 'category' => $category, 104 | 'childcats' => $childcats, 105 | 'page' => $page, 106 | ]); 107 | } 108 | 109 | /** 110 | * @param Post $post 111 | * 112 | * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View 113 | */ 114 | public function subpost($category_slug, $prefpost, $subpost) 115 | { 116 | $category = Category::slug($category_slug)->first(); 117 | 118 | $parentpost = Post::type($this->type) 119 | ->whereSlug($prefpost) 120 | ->first(); 121 | 122 | if (!is_null($category)) { 123 | $parentpost->setRelation('category', $category); 124 | } 125 | 126 | $subblog_slug = $prefpost.'-'.$subpost; 127 | 128 | $post = Post::type('subblog') 129 | ->whereSlug($subblog_slug) 130 | ->with('attachment') 131 | ->first(); 132 | 133 | if (!is_null($category)) { 134 | $post->setRelation('category', $category); 135 | } 136 | if (!is_null($parentpost)) { 137 | $post->setRelation('parentpost', $parentpost); 138 | } 139 | 140 | if (!is_null($post)) { 141 | $comments = Comment::findByPostId($post->id)->where('parent_id', 0)->where('approved', 1); 142 | } 143 | 144 | $list = (empty($post->getContent('list')) || is_null($post->getContent('list')[0])) 145 | ? ['name', 'body', 'carousel', 'tags'] 146 | : $post->getContent('list'); 147 | 148 | return view(config('press.view').'pages.subpost', [ 149 | 'post' => $post, 150 | 'comments' => $comments, 151 | 'list' => $list, 152 | ]); 153 | } 154 | 155 | /** 156 | * @param Post $post 157 | * 158 | * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View 159 | */ 160 | public function tagsPosts($tag_slug) 161 | { 162 | $posts = Post::type($this->type) 163 | ->whereTag($tag_slug) 164 | ->status('publish') 165 | ->with('attachment') 166 | ->with('scopeTaxonomies') 167 | ->orderBy('publish_at', 'Desc') 168 | ->get(); 169 | 170 | $images = $posts->map(function ($item, $key) { 171 | if (!is_null($item->attachment('image')->where('sort', 0)->first())) { 172 | return $item->attachment('image')->where('sort', 0)->first(); 173 | } 174 | })->filter()->sortBy('size'); 175 | 176 | $tag = Tag::whereSlug($tag_slug)->first(); 177 | 178 | return view(config('press.view').'pages.tags', [ 179 | 'posts' => $posts, 180 | 'tag' => $tag, 181 | 'images' => $images, 182 | ]); 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /resources/js/controllers/components/menu_controller.js: -------------------------------------------------------------------------------- 1 | import {Controller} from "stimulus" 2 | 3 | export default class extends Controller { 4 | 5 | /** 6 | * 7 | * @type {string[]} 8 | */ 9 | static targets = [ 10 | "id", 11 | "label", 12 | "slug", 13 | "auth", 14 | "robot", 15 | "style", 16 | "target", 17 | "title", 18 | ]; 19 | 20 | /** 21 | * 22 | */ 23 | connect() { 24 | 25 | let menu = this; 26 | 27 | $('.dd').nestable({}) 28 | .on('change', () => { 29 | menu.sort(); 30 | 31 | menu.send(); 32 | }).on('click', '.edit', (event) => { 33 | menu.edit(event.target); 34 | }); 35 | 36 | menu.sort(); 37 | 38 | this.checkExist(); 39 | } 40 | 41 | /** 42 | * 43 | * @param object 44 | */ 45 | load(object) { 46 | this.id = object.id; 47 | this.labelTarget.value = object.label; 48 | this.slugTarget.value = object.slug; 49 | this.authTarget.value = object.auth; 50 | this.robotTarget.value = object.robot; 51 | this.styleTarget.value = object.style; 52 | this.targetTarget.value = object.target; 53 | this.titleTarget.value = object.title; 54 | 55 | this.checkExist(); 56 | } 57 | 58 | /** 59 | * 60 | */ 61 | sort() { 62 | $('.dd-item').each((i, item) => { 63 | $(item).data({ 64 | sort: i, 65 | }); 66 | }); 67 | } 68 | 69 | /** 70 | * 71 | * @param element 72 | */ 73 | edit(element) { 74 | let data = $(element) 75 | .parent() 76 | .data(); 77 | 78 | data.label = $(element) 79 | .prev() 80 | .text(); 81 | this.load(data); 82 | 83 | $('#menuModal').modal('toggle'); 84 | } 85 | 86 | /** 87 | * 88 | * @returns {{label: *, title: *, auth: *, slug: *, robot: *, style: *, target: *}} 89 | */ 90 | getFormData() { 91 | return { 92 | label: this.labelTarget.value, 93 | title: this.titleTarget.value, 94 | auth: this.authTarget.value, 95 | slug: this.slugTarget.value, 96 | robot: this.robotTarget.value, 97 | style: this.styleTarget.value, 98 | target: this.targetTarget.value, 99 | } 100 | } 101 | 102 | /** 103 | * 104 | */ 105 | add() { 106 | if (!this.checkForm()) { 107 | return; 108 | } 109 | 110 | let $menu = this, $dd = $('.dd'), 111 | data = { 112 | menu: $dd.attr('data-name'), 113 | lang: $dd.attr('data-lang'), 114 | data: this.getFormData() 115 | }; 116 | 117 | axios 118 | .post(this.getUri(''), {params: data}) 119 | .then((response) => { 120 | $menu.add2Dom(response.data.id) 121 | }); 122 | } 123 | 124 | /** 125 | * 126 | * @param id 127 | */ 128 | add2Dom(id) { 129 | $('.dd > .dd-list').append( 130 | `
  • Drag
    ${this.labelTarget.value}
  • `, 131 | ); 132 | 133 | $(`li[data-id=${id}]`).data(this.getFormData()); 134 | 135 | this.sort(); 136 | this.clear(); 137 | this.send(); 138 | } 139 | 140 | /** 141 | * 142 | */ 143 | save() { 144 | if (!this.checkForm()) { 145 | return; 146 | } 147 | 148 | $(`li[data-id=${this.id}]`).data(this.getFormData()); 149 | $(`li[data-id=${this.id}] > .dd3-content`).html(this.labelTarget.value); 150 | 151 | this.clear(); 152 | this.send(); 153 | } 154 | 155 | /** 156 | * 157 | * @param id 158 | */ 159 | destroy(id) { 160 | axios 161 | .delete(this.getUri(id)) 162 | .then(response => { 163 | }); 164 | } 165 | 166 | /** 167 | * 168 | */ 169 | remove() { 170 | $(`li[data-id=${this.id}]`).remove(); 171 | this.destroy(this.id); 172 | this.clear(); 173 | } 174 | 175 | /** 176 | * 177 | */ 178 | clear() { 179 | this.labelTarget.value = ''; 180 | this.titleTarget.value = ''; 181 | this.authTarget.value = 0; 182 | this.slugTarget.value = ''; 183 | this.robotTarget.value = 'follow'; 184 | this.styleTarget.value = ''; 185 | this.targetTarget.value = '_self'; 186 | this.id = ''; 187 | 188 | this.checkExist(); 189 | 190 | $('#menuModal').modal('toggle'); 191 | } 192 | 193 | /** 194 | * 195 | */ 196 | send() { 197 | let $dd = $('.dd'), 198 | name = $dd.attr('data-name'), 199 | data = { 200 | lang: $dd.attr('data-lang'), 201 | data: $dd.nestable('serialize'), 202 | }; 203 | 204 | axios 205 | .put(this.getUri(name), data) 206 | .then(response => { 207 | }); 208 | } 209 | 210 | /** 211 | * 212 | * @returns {boolean} 213 | */ 214 | checkForm() { 215 | if (!this.labelTarget.value) { 216 | this.showBlocks('errors.label'); 217 | return false; 218 | } 219 | 220 | if (!this.titleTarget.value) { 221 | this.showBlocks('errors.title'); 222 | return false; 223 | } 224 | 225 | if (!this.slugTarget.value) { 226 | this.showBlocks('errors.slug'); 227 | return false; 228 | } 229 | 230 | this.hiddenBlocks([ 231 | 'errors.slug', 232 | 'errors.label', 233 | 'errors.title', 234 | ]); 235 | 236 | return true; 237 | } 238 | 239 | /** 240 | * 241 | */ 242 | checkExist() { 243 | if (this.exist()) { 244 | 245 | this.showBlocks([ 246 | 'menu.remove', 247 | 'menu.reset', 248 | 'menu.save' 249 | ]); 250 | 251 | this.hiddenBlocks('menu.create'); 252 | return; 253 | } 254 | 255 | this.showBlocks([ 256 | 'menu.create', 257 | ]); 258 | 259 | this.hiddenBlocks([ 260 | 'menu.remove', 261 | 'menu.reset', 262 | 'menu.save' 263 | ]); 264 | } 265 | 266 | /** 267 | * 268 | * @returns {boolean} 269 | */ 270 | exist() { 271 | return Number.isInteger(this.id) && 272 | $(`li[data-id=${this.id}]`).length > 0; 273 | } 274 | 275 | /** 276 | * 277 | * @param path 278 | * @returns {*} 279 | */ 280 | getUri(path = '') { 281 | path = path === '' ? `/press/menu` : `/press/menu/${path}`; 282 | return platform.prefix(path); 283 | } 284 | 285 | /** 286 | * 287 | * @param blocks 288 | */ 289 | hiddenBlocks(blocks) { 290 | if (!Array.isArray((blocks))) { 291 | blocks = [blocks]; 292 | } 293 | blocks.forEach(function (element) { 294 | document.getElementById(element).classList.add("none"); 295 | }); 296 | } 297 | 298 | /** 299 | * 300 | * @param blocks 301 | */ 302 | showBlocks(blocks) { 303 | if (!Array.isArray((blocks))) { 304 | blocks = [blocks]; 305 | } 306 | blocks.forEach(function (element) { 307 | document.getElementById(element).classList.remove("none"); 308 | }); 309 | } 310 | } 311 | -------------------------------------------------------------------------------- /src/Providers/PressServiceProvider.php: -------------------------------------------------------------------------------- 1 | dashboard = $dashboard; 47 | 48 | $this->app->booted(function () { 49 | $this->registerDashboardRoutes(); 50 | $this->registerBindings(); 51 | $this->dashboard 52 | //->registerEntities($this->findEntities()) 53 | //->macro($this->findEntities()) 54 | ->registerResource('entities', $this->findEntities()) 55 | ->registerPermissions($this->registerPermissionsEntities()) 56 | ->registerPermissions($this->registerPermissions()); 57 | }); 58 | 59 | $this->dashboard->addPublicDirectory('press', PRESS_PATH.'/public/'); 60 | 61 | View::composer('platform::app', function () use ($dashboard) { 62 | $dashboard 63 | ->registerResource('scripts', orchid_mix('/js/press.js', 'press')) 64 | ->registerResource('stylesheets', orchid_mix('/css/press.css', 'press')); 65 | }); 66 | 67 | $this->registerMigrations() 68 | ->registerStubs() 69 | ->registerConfig() 70 | ->registerViews() 71 | ->registerCommands() 72 | ->registerMacros() 73 | ->registerTranslations() 74 | ->registerProviders(); 75 | 76 | View::composer('platform::dashboard', PressMenuComposer::class); 77 | View::composer('platform::systems', SystemMenuComposer::class); 78 | } 79 | 80 | /** 81 | * Register any application services. 82 | */ 83 | public function register(): void 84 | { 85 | /** 86 | * Define package path 87 | */ 88 | if (!defined('PRESS_PATH')) { 89 | define('PRESS_PATH', dirname(__DIR__, 2)); 90 | } 91 | } 92 | 93 | /** 94 | * Register views & Publish views. 95 | */ 96 | public function registerViews(): self 97 | { 98 | $this->loadViewsFrom(PRESS_PATH.'/resources/views', 'press'); 99 | 100 | $this->publishes([ 101 | PRESS_PATH.'/resources/views' => resource_path('views/vendor/press'), 102 | ], 'press-views'); 103 | 104 | return $this; 105 | } 106 | 107 | /** 108 | * Register dashboard routes. 109 | */ 110 | public function registerDashboardRoutes(): void 111 | { 112 | if ($this->app->routesAreCached()) { 113 | return; 114 | } 115 | 116 | Route::domain((string) config('platform.domain')) 117 | ->prefix(Dashboard::prefix('/press')) 118 | ->as('platform.') 119 | ->middleware(config('platform.middleware.private')) 120 | ->group(realpath(PRESS_PATH.'/routes/press.php')); 121 | } 122 | 123 | protected function registerConfig(): self 124 | { 125 | $this->publishes([ 126 | realpath(PRESS_PATH.'/config/press.php') => config_path('press.php'), 127 | ], 'config'); 128 | 129 | $this->mergeConfigFrom( 130 | realpath(PRESS_PATH.'/config/press.php'), 'press' 131 | ); 132 | 133 | return $this; 134 | } 135 | 136 | protected function registerMigrations(): self 137 | { 138 | $this->loadMigrationsFrom(PRESS_PATH.'/database/migrations/press'); 139 | 140 | return $this; 141 | } 142 | 143 | public function findEntities(): array 144 | { 145 | $namespace = app()->getNamespace(); 146 | $directory = app_path('Orchid/Entities'); 147 | $resources = []; 148 | 149 | if (!is_dir($directory)) { 150 | return []; 151 | } 152 | 153 | foreach ((new Finder())->in($directory)->files() as $resource) { 154 | $resource = $namespace.str_replace( 155 | ['/', '.php'], 156 | ['\\', ''], 157 | Str::after($resource->getPathname(), app_path().DIRECTORY_SEPARATOR) 158 | ); 159 | 160 | if (is_subclass_of($resource, Many::class) || 161 | is_subclass_of($resource, Single::class)) { 162 | $resources[] = $resource; 163 | } 164 | } 165 | 166 | return collect($resources)->sort()->all(); 167 | } 168 | 169 | protected function registerPermissionsEntities(): ItemPermission 170 | { 171 | $permissions = new ItemPermission(); 172 | /* 173 | $posts = collect($this->dashboard->getResource('entities')) 174 | ->transform(function ($value) { 175 | return is_object($value) ? $value : new $value(); 176 | }) 177 | */ 178 | $posts = $this->dashboard->getEntities() 179 | ->each(function ($post) use ($permissions) { 180 | $permissions->addPermission('platform.entities.type.'.$post->slug, $post->name); 181 | }); 182 | 183 | if ($posts->count() > 0) { 184 | $permissions->group = __('Posts'); 185 | } 186 | 187 | return $permissions; 188 | } 189 | 190 | protected function registerPermissions(): ItemPermission 191 | { 192 | return ItemPermission::group(__('Systems')) 193 | ->addPermission('platform.systems.menu', __('Menu')) 194 | ->addPermission('platform.systems.comments', __('Comments')) 195 | ->addPermission('platform.systems.category', __('Category')); 196 | } 197 | 198 | 199 | public function registerBindings(): self 200 | { 201 | require PRESS_PATH.'/routes/bindings.php'; 202 | 203 | return $this; 204 | } 205 | 206 | public function registerCommands(): self 207 | { 208 | if (!$this->app->runningInConsole()) { 209 | return $this; 210 | } 211 | 212 | foreach ($this->commands as $command) { 213 | $this->commands($command); 214 | } 215 | 216 | return $this; 217 | } 218 | 219 | public function registerTranslations(): self 220 | { 221 | $this->loadJsonTranslationsFrom(realpath(PRESS_PATH.'/resources/lang/')); 222 | 223 | return $this; 224 | } 225 | 226 | protected function registerStubs(): self 227 | { 228 | $this->publishes([ 229 | PRESS_PATH.'/install-stubs/Orchid/Entities' => app_path('Orchid/Entities'), 230 | PRESS_PATH.'/install-stubs/Controllers' => app_path('Http/Controllers') 231 | ], 'press-stubs'); 232 | 233 | return $this; 234 | } 235 | 236 | public function registerMacros(): self 237 | { 238 | require PRESS_PATH.'/src/Support/macros.php'; 239 | 240 | return $this; 241 | } 242 | 243 | 244 | /** 245 | * Register provider. 246 | */ 247 | public function registerProviders(): self 248 | { 249 | if (env('PRESS_WEB')) { 250 | $this->app->register(WebServiceProvider::class); 251 | } 252 | 253 | return $this; 254 | } 255 | 256 | 257 | } 258 | --------------------------------------------------------------------------------