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 |
24 |
}})
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 |
5 |
6 | @foreach($post->attachment('image')->get() as $image)
7 | - first) ? 'class="active"' : ''}} >
8 | @endforeach
9 |
10 |
11 | @foreach($post->attachment('image')->get() as $image)
12 |
13 |
}})
14 |
15 |
{{$image->alt}}
16 |
{{$image->description}}
17 |
18 |
19 | @endforeach
20 |
21 |
22 |
23 | Previous
24 |
25 |
26 |
27 | Next
28 |
29 |
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 |
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 |
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 |
--------------------------------------------------------------------------------