├── img
└── laravel-pagebuilder.png
├── src
├── resources
│ ├── views
│ │ ├── livewire
│ │ │ ├── settings.blade.php
│ │ │ └── date-picker.blade.php
│ │ ├── main.blade.php
│ │ ├── notifications.blade.php
│ │ ├── languages
│ │ │ ├── create.blade.php
│ │ │ ├── edit.blade.php
│ │ │ └── index.blade.php
│ │ └── element-types
│ │ │ ├── create.blade.php
│ │ │ ├── edit.blade.php
│ │ │ └── index.blade.php
│ ├── stubs
│ │ ├── models
│ │ │ └── page.stub
│ │ ├── views
│ │ │ └── pages
│ │ │ │ ├── edit.stub
│ │ │ │ ├── create.stub
│ │ │ │ └── index.stub
│ │ └── controllers
│ │ │ └── page_controller.stub
│ └── lang
│ │ ├── ar
│ │ └── crud.php
│ │ ├── en
│ │ └── crud.php
│ │ └── de
│ │ └── crud.php
├── config
│ └── pagebuilder.php
├── img
│ └── pagebuilder
│ │ └── icons
│ │ ├── grid-12.png
│ │ ├── grid12.png
│ │ └── grid6-6.png
├── Pagebuilder
│ ├── Exceptions
│ │ └── MissingTranslationsException.php
│ ├── Contracts
│ │ ├── RowColumnContract.php
│ │ ├── ElementContract.php
│ │ ├── LanguageContract.php
│ │ └── PagebuilderContract.php
│ ├── Models
│ │ ├── Language.php
│ │ ├── ElementType.php
│ │ ├── ColumnTranslation.php
│ │ ├── Row.php
│ │ ├── Translation.php
│ │ ├── Column.php
│ │ └── BasePage.php
│ ├── Livewire
│ │ ├── Settings.php
│ │ └── DatePicker.php
│ ├── Database
│ │ └── Seeds
│ │ │ ├── LanguageTableSeeder.php
│ │ │ └── ElementTableSeeder.php
│ ├── RowColumn.php
│ ├── Languages.php
│ ├── Elements.php
│ ├── Uploads
│ │ └── Uploadable.php
│ ├── Commands
│ │ ├── InstallCommand.php
│ │ ├── ModelCommand.php
│ │ ├── ControllerCommand.php
│ │ └── ViewCommand.php
│ ├── Controllers
│ │ ├── PagebuilderController.php
│ │ ├── UploadController.php
│ │ ├── ElementTypeController.php
│ │ └── LanguageController.php
│ ├── PagebuilderServiceProvider.php
│ ├── Translations
│ │ └── Translatable.php
│ └── Pagebuilder.php
├── database
│ └── migrations
│ │ ├── 2018_05_11_125042_create_languages_table.php
│ │ ├── 2018_09_20_065609_create_pages_table.php
│ │ ├── 2018_05_11_133201_create_element_types_table.php
│ │ ├── 2018_09_20_082538_create_column_translations_table.php
│ │ ├── 2018_09_20_084930_create_translations_table.php
│ │ ├── 2018_09_20_070220_create_columns_table.php
│ │ ├── 2018_09_26_132707_create_media_table.php
│ │ └── 2018_09_20_065917_create_rows_table.php
└── routes
│ └── web.php
├── changelog.md
├── .gitignore
├── composer.json
├── LICENSE
└── README.md
/img/laravel-pagebuilder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flobbos/laravel-pagebuilder/HEAD/img/laravel-pagebuilder.png
--------------------------------------------------------------------------------
/src/resources/views/livewire/settings.blade.php:
--------------------------------------------------------------------------------
1 |
22 |
23 | {{ session('message') }}
24 |
25 |
26 |
29 |
30 |
31 | @endif
32 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "flobbos/laravel-pagebuilder",
3 | "description": "Build content in your database with translations.",
4 | "keywords": [
5 | "laravel",
6 | "pages",
7 | "database"
8 | ],
9 | "license": "MIT",
10 | "authors": [
11 | {
12 | "name": "Alexej Krzewitzki",
13 | "email": "alexej@helloo.it",
14 | "homepage": "http://helloo.it"
15 | }
16 | ],
17 | "require": {
18 | "php": "^8.0|^8.1|^8.2",
19 | "illuminate/support": "9.*|10.*|11.*|12.*",
20 | "flobbos/laravel-translatable-db": "^1.4",
21 | "cocur/slugify": "^4.0",
22 | "livewire/livewire": "^2.4"
23 | },
24 | "extra": {
25 | "laravel": {
26 | "providers": [
27 | "Flobbos\\Pagebuilder\\PagebuilderServiceProvider"
28 | ]
29 | }
30 | },
31 | "autoload": {
32 | "psr-4": {
33 | "Flobbos\\Pagebuilder\\": [
34 | "src/Pagebuilder"
35 | ]
36 | },
37 | "classmap": []
38 | },
39 | "minimum-stability": "stable"
40 | }
--------------------------------------------------------------------------------
/src/database/migrations/2018_09_20_070220_create_columns_table.php:
--------------------------------------------------------------------------------
1 | id('id');
18 | $table->foreignId('row_id')->onDelete('cascade');
19 | $table->foreignId('element_type_id')->onDelete('cascade');
20 | $table->string('column_size')->nullable();
21 | $table->string('custom_class')->nullable();
22 | $table->tinyInteger('sorting')->default(0);
23 | $table->boolean('active')->default(true);
24 | $table->timestamps();
25 | });
26 | }
27 |
28 | /**
29 | * Reverse the migrations.
30 | *
31 | * @return void
32 | */
33 | public function down()
34 | {
35 | Schema::dropIfExists('columns');
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/database/migrations/2018_09_26_132707_create_media_table.php:
--------------------------------------------------------------------------------
1 | id('id');
18 | $table->morphs('model');
19 | $table->string('collection_name')->nullable();
20 | $table->string('filetype')->nullable();
21 | $table->string('filename')->nullable();
22 | $table->string('disk')->default('public');
23 | $table->unsignedInteger('size');
24 | $table->unsignedInteger('order_column')->nullable();
25 | $table->timestamps();
26 | });
27 | }
28 |
29 | /**
30 | * Reverse the migrations.
31 | *
32 | * @return void
33 | */
34 | public function down()
35 | {
36 | Schema::dropIfExists('media');
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/database/migrations/2018_09_20_065917_create_rows_table.php:
--------------------------------------------------------------------------------
1 | id('id');
18 | $table->morphs('rowable');
19 | $table->string('custom_class')->nullable();
20 | $table->integer('sorting')->unsigned()->index();
21 | $table->boolean('expanded')->default(false);
22 | $table->string('alignment')->nullable();
23 | $table->string('padding_top')->nullable();
24 | $table->string('padding_bottom')->nullable();
25 | $table->timestamps();
26 | });
27 | }
28 |
29 | /**
30 | * Reverse the migrations.
31 | *
32 | * @return void
33 | */
34 | public function down()
35 | {
36 | Schema::dropIfExists('rows');
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2017 Alexej Krzewitzki alexej@helloo.it
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/src/routes/web.php:
--------------------------------------------------------------------------------
1 | ['web', 'auth'], 'prefix' => 'pagebuilder', 'as' => 'pagebuilder::'], function () {
9 | Route::get('/', [PagebuilderController::class, 'index'])->name('home');
10 | //Resource route for languages
11 | Route::resource('languages', LanguageController::class);
12 | //Resource route for elements
13 | Route::resource('element-types', ElementTypeController::class);
14 | //Upload photos
15 | Route::post('upload-photo', [UploadController::class, 'store'])->name('upload');
16 | //Delete Photos
17 | Route::delete('delete-photo', [UploadController::class, 'destroy'])->name('delete-photo');
18 | //Delete entire row
19 | Route::delete('delete-row', [PagebuilderController::class, 'deleteRow'])->name('delete-row');
20 | //Delete Column
21 | Route::delete('delete-column', [PagebuilderController::class, 'deleteColumn'])->name('delete-column');
22 | });
23 |
--------------------------------------------------------------------------------
/src/Pagebuilder/Languages.php:
--------------------------------------------------------------------------------
1 | model = $language;
14 | }
15 |
16 | public function get()
17 | {
18 | return $this->model->get();
19 | }
20 |
21 | public function find($id)
22 | {
23 | return $this->model->find($id);
24 | }
25 |
26 | public function create(array $language_data)
27 | {
28 | return $this->model->create($language_data);
29 | }
30 |
31 | public function update($id, array $language_data)
32 | {
33 | $lang = $this->find($id);
34 | if (is_null($lang)) {
35 | throw new Exception('Model not found');
36 | }
37 | if ($lang->update($language_data)) {
38 | return $lang;
39 | }
40 | return false;
41 | }
42 |
43 | public function destroy($id)
44 | {
45 | $lang = $this->find($id);
46 | return $lang->delete();
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/resources/lang/en/crud.php:
--------------------------------------------------------------------------------
1 | 'New entry',
9 | 'save' => 'Save',
10 | 'cancel' => 'Cancel',
11 | 'delete' => 'Delete',
12 | 'edit' => 'Edit',
13 | //Headlines
14 | 'th_action' => 'Action',
15 | 'create_headline' => 'Create new entry',
16 | 'edit_headline' => 'Edit entry',
17 | //List
18 | 'no_entries' => 'No entries found.',
19 | //Messages
20 | 'record_created' => 'A new entry has been successfully created.',
21 | 'record_updated' => 'The entry has been successfully updated.',
22 | 'record_deleted' => 'The entry was removed successfully',
23 | 'record_restored' => 'The entry has been restored successfully',
24 | //File error
25 | 'invalid_file_upload' => 'A problem was encountered during the file upload',
26 |
27 | 'element_types' => 'Elements',
28 | 'languages' => 'Languages',
29 |
30 | // Labels
31 | 'labels' => [
32 | 'name' => 'Name',
33 | 'iso' => 'ISO',
34 | 'sorting' => 'Sorting',
35 | 'icon' => 'Icon',
36 | 'component' => 'Component'
37 | ]
38 | ];
39 |
--------------------------------------------------------------------------------
/src/Pagebuilder/Database/Seeds/ElementTableSeeder.php:
--------------------------------------------------------------------------------
1 | insert([
19 | 'name' => 'Headline + Text',
20 | 'component' => 'v-headline-text',
21 | 'icon' => 'headline-text-element-icon',
22 | 'sorting' => 1
23 | ]);
24 | //Text component
25 | DB::table('element_types')->insert([
26 | 'name' => 'Text',
27 | 'component' => 'v-text',
28 | 'icon' => 'text-element-icon',
29 | 'sorting' => 2
30 | ]);
31 | //Photo + Description
32 | DB::table('element_types')->insert([
33 | 'name' => 'Photo + Description',
34 | 'component' => 'v-photo-description',
35 | 'icon' => 'image-element-icon',
36 | 'sorting' => 3
37 | ]);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/resources/lang/de/crud.php:
--------------------------------------------------------------------------------
1 | 'Neuer Eintrag',
9 | 'save' => 'Speichern',
10 | 'cancel' => 'Abbrechen',
11 | 'delete' => 'Löschen',
12 | 'edit' => 'Editieren',
13 | //Headlines
14 | 'th_action' => 'Aktion',
15 | 'create_headline' => 'Neuen Eintrag erstellen',
16 | 'edit_headline' => 'Eintrag editieren',
17 | //List
18 | 'no_entries' => 'Keine Einträge gefunden.',
19 | //Messages
20 | 'record_created' => 'Ein neuer Eintrag wurde erfolgreich erstellt.',
21 | 'record_updated' => 'Der Eintrag wurde erfolgreich aktualisiert.',
22 | 'record_deleted' => 'Der Eintrag wurde erfolgreich gelöscht.',
23 | 'record_restored' => 'Der Eintrag wurde erfolgreich wiederhergestellt.',
24 | //File error
25 | 'invalid_file_upload' => 'Es gab ein Problem beim Upload der Datei.',
26 |
27 | 'element_types' => 'Elemente',
28 | 'languages' => 'Sprachen',
29 |
30 | // Labels
31 | 'labels' => [
32 | 'name' => 'Name',
33 | 'iso' => 'ISO',
34 | 'sorting' => 'Sortierung',
35 | 'icon' => 'Icon',
36 | 'component' => 'Komponente'
37 | ]
38 | ];
39 |
--------------------------------------------------------------------------------
/src/Pagebuilder/Elements.php:
--------------------------------------------------------------------------------
1 | model = $element_type;
17 | }
18 |
19 | public function get()
20 | {
21 | return $this->model->get();
22 | }
23 |
24 | public function find($id)
25 | {
26 | return $this->model->find($id);
27 | }
28 |
29 | public function create(array $element_data)
30 | {
31 | return $this->model->create($element_data);
32 | }
33 |
34 | public function update($id, array $element_data)
35 | {
36 | $element = $this->find($id);
37 | if (is_null($element)) {
38 | throw new Exception('Model not found');
39 | }
40 | if ($element->update($element_data)) {
41 | return $element;
42 | }
43 | return false;
44 | }
45 |
46 | public function delete($id)
47 | {
48 | $element = $this->find($id);
49 | return $element->delete();
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/Pagebuilder/Models/BasePage.php:
--------------------------------------------------------------------------------
1 | morphMany(Row::class, 'rowable')->orderBy('sorting');
26 | }
27 |
28 | public function translations()
29 | {
30 | return $this->morphMany(Translation::class, 'translatable');
31 | }
32 |
33 | //Overrides for polymorphic delete
34 | public function forceDelete()
35 | {
36 | $deleted = parent::forceDelete();
37 | if ($deleted) {
38 | $this->translations()->delete();
39 | $this->rows()->delete();
40 | }
41 | }
42 |
43 | public function getSlugField()
44 | {
45 | return $this->slug_field ?? null;
46 | }
47 |
48 | public function getSlugName()
49 | {
50 | return $this->slug_name;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/Pagebuilder/Uploads/Uploadable.php:
--------------------------------------------------------------------------------
1 | file($fieldname)) || !$request->file($fieldname)->isValid()) {
26 | throw new \Exception(trans('crud.invalid_file_upload'));
27 | }
28 | //Get filename
29 | $basename = basename($request->file($fieldname)->getClientOriginalName(), '.' . $request->file($fieldname)->getClientOriginalExtension());
30 | if ($randomize) {
31 | $filename = Str::slug($basename) . '-' . uniqid() . '.' . $request->file($fieldname)->getClientOriginalExtension();
32 | } else {
33 | $filename = Str::slug($basename) . '.' . $request->file($fieldname)->getClientOriginalExtension();
34 | }
35 | //Move file to location
36 | $request->file($fieldname)->storeAs($folder, $filename, $storage_disk);
37 | return $filename;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/Pagebuilder/Commands/InstallCommand.php:
--------------------------------------------------------------------------------
1 | comment('Running migrations.');
38 |
39 | Artisan::call('migrate');
40 |
41 | $this->comment('Running seeds.');
42 | Artisan::call('db:seed', ['--class' => 'Flobbos\\Pagebuilder\\ElementTableSeeder']);
43 | Artisan::call('db:seed', ['--class' => 'Flobbos\\Pagebuilder\\LanguageTableSeeder']);
44 |
45 | $this->comment('Publishing package files');
46 |
47 | Artisan::call('vendor:publish', ['--provider' => 'Flobbos\\Pagebuilder\\PagebuilderServiceProvider']);
48 |
49 | $this->info('Installation completed.');
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/Pagebuilder/Controllers/PagebuilderController.php:
--------------------------------------------------------------------------------
1 | with([
18 | 'elements' => $elements->get(),
19 | 'languages' => $lang->get()
20 | ]);
21 | }
22 |
23 | /**
24 | *
25 | * @param Request $request
26 | * @return type
27 | */
28 | public function deleteRow(Request $request, RowColumnContract $rows)
29 | {
30 | try {
31 | $rows->deleteRow($request->get('id'));
32 | return response()->json(['success' => true], 200);
33 | } catch (Exception $ex) {
34 | return response()->json(['success' => false, 'message' => $ex->getMessage()], 422);
35 | }
36 | }
37 |
38 | /**
39 | *
40 | * @param Request $request
41 | * @return type
42 | */
43 | public function deleteColumn(Request $request, RowColumnContract $rows)
44 | {
45 | try {
46 | $rows->deleteColumn($request->get('id'));
47 | return response()->json(['success' => true], 200);
48 | } catch (Exception $ex) {
49 | return response()->json(['success' => false, 'message' => $ex->getMessage()], 422);
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/Pagebuilder/PagebuilderServiceProvider.php:
--------------------------------------------------------------------------------
1 | publishes([
14 | __DIR__ . '/../config/pagebuilder.php' => config_path('pagebuilder.php'),
15 | ], 'config');
16 | //load routes
17 | $this->loadRoutesFrom(__DIR__ . '/../routes/web.php');
18 | //migrations
19 | $this->loadMigrationsFrom(__DIR__ . '/../database/migrations');
20 | //views
21 | $this->loadViewsFrom(__DIR__ . '/../resources/views', 'pagebuilder');
22 | //language
23 | $this->loadTranslationsFrom(__DIR__ . '/../resources/lang', 'pagebuilder');
24 | }
25 |
26 | /**
27 | * Register the service provider.
28 | */
29 | public function register()
30 | {
31 | //register commands
32 | $this->commands([
33 | Commands\ControllerCommand::class,
34 | Commands\ViewCommand::class,
35 | Commands\ModelCommand::class,
36 | Commands\InstallCommand::class,
37 | ]);
38 | //Merge config
39 | $this->mergeConfigFrom(
40 | __DIR__ . '/../config/pagebuilder.php',
41 | 'pagebuilder'
42 | );
43 | //Run fixed bindings
44 | $this->app->bind(Contracts\ElementContract::class, Elements::class);
45 | $this->app->bind(Contracts\PagebuilderContract::class, Pagebuilder::class);
46 | $this->app->bind(Contracts\RowColumnContract::class, RowColumn::class);
47 | $this->app->bind(Contracts\LanguageContract::class, Languages::class);
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/Pagebuilder/Controllers/UploadController.php:
--------------------------------------------------------------------------------
1 | hasFile('photo')) {
24 | return response()->json([
25 | 'filename' => $this->handleUpload($request, 'photo'),
26 | 'column_id' => $request->get('column_id'),
27 | 'lang_id' => $request->get('lang_id')
28 | ], 200);
29 | }
30 | if ($request->hasFile('file')) {
31 | return response()->json([
32 | 'filename' => $this->handleUpload($request, 'file', 'files'),
33 | 'column_id' => $request->get('column_id'),
34 | 'lang_id' => $request->get('lang_id')
35 | ], 200);
36 | }
37 | throw new Exception('No file uploaded');
38 | } catch (Exception $ex) {
39 | return response()->json(['success' => false, 'message' => $ex->getMessage()], 422);
40 | }
41 | }
42 |
43 | /**
44 | * Remove the specified resource from storage.
45 | *
46 | * @param int $id
47 | * @return \Illuminate\Http\Response
48 | */
49 | public function destroy(Request $request)
50 | {
51 | try {
52 | if ($request->has('delete_photo')) {
53 | Storage::disk($request->get('storage'))->delete($request->get('delete_photo'));
54 | }
55 | return response()->json(['success' => true], 200);
56 | } catch (Exception $ex) {
57 | return response()->json(['success' => false, 'message' => $ex->getMessage()], 422);
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/resources/views/languages/create.blade.php:
--------------------------------------------------------------------------------
1 |