├── .github └── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── composer.json ├── database ├── factories │ ├── ArticleFactory.php │ └── CategoryFactory.php └── migrations │ ├── 2018_10_31_025550_create_blogged_categories_table.php │ └── 2018_10_31_025555_create_blogged_articles_table.php ├── mix-manifest.json ├── package-lock.json ├── package.json ├── publishable ├── assets │ ├── 403.svg │ ├── css │ │ └── app.css │ ├── empty.svg │ ├── fonts │ │ ├── fontawesome-webfont.eot │ │ ├── fontawesome-webfont.svg │ │ ├── fontawesome-webfont.ttf │ │ ├── fontawesome-webfont.woff │ │ ├── fontawesome-webfont.woff2 │ │ ├── nucleo-icons.eot │ │ ├── nucleo-icons.svg │ │ ├── nucleo-icons.ttf │ │ ├── nucleo-icons.woff │ │ └── nucleo-icons.woff2 │ ├── js │ │ └── app.js │ └── new.svg ├── config │ └── blogged.php └── policies │ ├── BloggedArticlePolicy.php │ └── BloggedCategoryPolicy.php ├── resources ├── js │ ├── Article.js │ ├── Components │ │ ├── Articles.vue │ │ ├── BackToTop.vue │ │ ├── ImageUploader.vue │ │ ├── SEOTips.vue │ │ └── Statistics.vue │ ├── app.js │ ├── argon.js │ ├── bootsrap.js │ ├── router │ │ ├── index.js │ │ └── routes.js │ ├── vendor │ │ └── prism.js │ └── views │ │ ├── 403.vue │ │ ├── 404.vue │ │ ├── Categories.vue │ │ ├── Dashboard.vue │ │ ├── EditArticle.vue │ │ ├── NewArticle.vue │ │ └── ViewArticle.vue ├── sass │ ├── app.scss │ ├── argon.scss │ ├── blog.scss │ ├── bootstrap │ │ ├── _alert.scss │ │ ├── _badge.scss │ │ ├── _breadcrumb.scss │ │ ├── _button-group.scss │ │ ├── _buttons.scss │ │ ├── _card.scss │ │ ├── _carousel.scss │ │ ├── _close.scss │ │ ├── _code.scss │ │ ├── _custom-forms.scss │ │ ├── _dropdown.scss │ │ ├── _forms.scss │ │ ├── _functions.scss │ │ ├── _grid.scss │ │ ├── _images.scss │ │ ├── _input-group.scss │ │ ├── _jumbotron.scss │ │ ├── _list-group.scss │ │ ├── _media.scss │ │ ├── _mixins.scss │ │ ├── _modal.scss │ │ ├── _nav.scss │ │ ├── _navbar.scss │ │ ├── _pagination.scss │ │ ├── _popover.scss │ │ ├── _print.scss │ │ ├── _progress.scss │ │ ├── _reboot.scss │ │ ├── _root.scss │ │ ├── _tables.scss │ │ ├── _tooltip.scss │ │ ├── _transitions.scss │ │ ├── _type.scss │ │ ├── _utilities.scss │ │ ├── _variables.scss │ │ ├── mixins │ │ │ ├── _alert.scss │ │ │ ├── _background-variant.scss │ │ │ ├── _badge.scss │ │ │ ├── _border-radius.scss │ │ │ ├── _box-shadow.scss │ │ │ ├── _breakpoints.scss │ │ │ ├── _buttons.scss │ │ │ ├── _caret.scss │ │ │ ├── _clearfix.scss │ │ │ ├── _float.scss │ │ │ ├── _forms.scss │ │ │ ├── _gradients.scss │ │ │ ├── _grid-framework.scss │ │ │ ├── _grid.scss │ │ │ ├── _hover.scss │ │ │ ├── _image.scss │ │ │ ├── _list-group.scss │ │ │ ├── _lists.scss │ │ │ ├── _nav-divider.scss │ │ │ ├── _pagination.scss │ │ │ ├── _reset-text.scss │ │ │ ├── _resize.scss │ │ │ ├── _screen-reader.scss │ │ │ ├── _size.scss │ │ │ ├── _table-row.scss │ │ │ ├── _text-emphasis.scss │ │ │ ├── _text-hide.scss │ │ │ ├── _text-truncate.scss │ │ │ ├── _transition.scss │ │ │ └── _visibility.scss │ │ └── utilities │ │ │ ├── _align.scss │ │ │ ├── _background.scss │ │ │ ├── _borders.scss │ │ │ ├── _clearfix.scss │ │ │ ├── _display.scss │ │ │ ├── _embed.scss │ │ │ ├── _flex.scss │ │ │ ├── _float.scss │ │ │ ├── _position.scss │ │ │ ├── _screenreaders.scss │ │ │ ├── _shadows.scss │ │ │ ├── _sizing.scss │ │ │ ├── _spacing.scss │ │ │ ├── _text.scss │ │ │ └── _visibility.scss │ ├── core │ │ ├── alerts │ │ │ ├── _alert-dismissible.scss │ │ │ └── _alert.scss │ │ ├── avatars │ │ │ ├── _avatar-group.scss │ │ │ └── _avatar.scss │ │ ├── badges │ │ │ ├── _badge-circle.scss │ │ │ ├── _badge-dot.scss │ │ │ └── _badge.scss │ │ ├── buttons │ │ │ ├── _button-brand.scss │ │ │ ├── _button-icon.scss │ │ │ └── _button.scss │ │ ├── cards │ │ │ ├── _card-animations.scss │ │ │ ├── _card-blockquote.scss │ │ │ ├── _card-profile.scss │ │ │ ├── _card-stats.scss │ │ │ └── _card.scss │ │ ├── charts │ │ │ └── _chart.scss │ │ ├── close │ │ │ └── _close.scss │ │ ├── custom-forms │ │ │ ├── _custom-checkbox.scss │ │ │ ├── _custom-control.scss │ │ │ ├── _custom-form.scss │ │ │ ├── _custom-radio.scss │ │ │ └── _custom-toggle.scss │ │ ├── dropdowns │ │ │ └── _dropdown.scss │ │ ├── footers │ │ │ └── _footer.scss │ │ ├── forms │ │ │ ├── _form-validation.scss │ │ │ ├── _form.scss │ │ │ └── _input-group.scss │ │ ├── headers │ │ │ └── _header.scss │ │ ├── icons │ │ │ ├── _icon-shape.scss │ │ │ └── _icon.scss │ │ ├── list-groups │ │ │ └── _list-group.scss │ │ ├── maps │ │ │ └── _map.scss │ │ ├── masks │ │ │ └── _mask.scss │ │ ├── mixins │ │ │ ├── _alert.scss │ │ │ ├── _background-variant.scss │ │ │ ├── _badge.scss │ │ │ ├── _buttons.scss │ │ │ ├── _forms.scss │ │ │ ├── _icon.scss │ │ │ ├── _modals.scss │ │ │ └── _popover.scss │ │ ├── modals │ │ │ └── _modal.scss │ │ ├── navbars │ │ │ ├── _navbar-collapse.scss │ │ │ ├── _navbar-dropdown.scss │ │ │ ├── _navbar-search.scss │ │ │ ├── _navbar-vertical.scss │ │ │ └── _navbar.scss │ │ ├── navs │ │ │ ├── _nav-pills.scss │ │ │ └── _nav.scss │ │ ├── paginations │ │ │ └── _pagination.scss │ │ ├── popovers │ │ │ └── _popover.scss │ │ ├── progresses │ │ │ └── _progress.scss │ │ ├── separators │ │ │ └── _separator.scss │ │ ├── tables │ │ │ └── _table.scss │ │ ├── type │ │ │ ├── _article.scss │ │ │ ├── _display.scss │ │ │ ├── _heading.scss │ │ │ └── _type.scss │ │ ├── utilities │ │ │ ├── _backgrounds.scss │ │ │ ├── _blurable.scss │ │ │ ├── _floating.scss │ │ │ ├── _helper.scss │ │ │ ├── _image.scss │ │ │ ├── _opacity.scss │ │ │ ├── _overflow.scss │ │ │ ├── _position.scss │ │ │ ├── _shadows.scss │ │ │ ├── _sizing.scss │ │ │ ├── _spacing.scss │ │ │ ├── _text.scss │ │ │ └── _transform.scss │ │ └── vendors │ │ │ ├── _bootstrap-datepicker.scss │ │ │ ├── _headroom.scss │ │ │ ├── _nouislider.scss │ │ │ └── _scrollbar.scss │ ├── custom │ │ ├── _alert.scss │ │ ├── _avatar.scss │ │ ├── _badge.scss │ │ ├── _buttons.scss │ │ ├── _card.scss │ │ ├── _chart.scss │ │ ├── _close.scss │ │ ├── _components.scss │ │ ├── _content.scss │ │ ├── _custom-forms.scss │ │ ├── _dropdown.scss │ │ ├── _footer.scss │ │ ├── _forms.scss │ │ ├── _functions.scss │ │ ├── _header.scss │ │ ├── _icons.scss │ │ ├── _input-group.scss │ │ ├── _list-group.scss │ │ ├── _map.scss │ │ ├── _mask.scss │ │ ├── _mixins.scss │ │ ├── _modal.scss │ │ ├── _nav.scss │ │ ├── _navbar.scss │ │ ├── _pagination.scss │ │ ├── _popover.scss │ │ ├── _progress.scss │ │ ├── _reboot.scss │ │ ├── _section.scss │ │ ├── _separator.scss │ │ ├── _tables.scss │ │ ├── _type.scss │ │ ├── _utilities.scss │ │ ├── _variables.scss │ │ └── _vendors.scss │ ├── global.scss │ └── vendor │ │ ├── _prism-dark.scss │ │ ├── _prism-light.scss │ │ ├── font-awesome │ │ ├── css │ │ │ ├── font-awesome.css │ │ │ └── font-awesome.min.css │ │ └── fonts │ │ │ ├── FontAwesome.otf │ │ │ ├── fontawesome-webfont.eot │ │ │ ├── fontawesome-webfont.svg │ │ │ ├── fontawesome-webfont.ttf │ │ │ ├── fontawesome-webfont.woff │ │ │ └── fontawesome-webfont.woff2 │ │ └── nucleo │ │ ├── css │ │ ├── nucleo-svg.css │ │ └── nucleo.css │ │ └── fonts │ │ ├── nucleo-icons.eot │ │ ├── nucleo-icons.svg │ │ ├── nucleo-icons.ttf │ │ ├── nucleo-icons.woff │ │ └── nucleo-icons.woff2 └── views │ ├── blog │ ├── index.blade.php │ └── show.blade.php │ ├── dashboard │ ├── index.blade.php │ └── sidebar.blade.php │ ├── layout.blade.php │ ├── partials │ ├── author.blade.php │ ├── card.blade.php │ ├── dashboard-links.blade.php │ ├── footer.blade.php │ ├── navbar.blade.php │ ├── seo.blade.php │ ├── share.blade.php │ ├── sidebar.blade.php │ └── style.blade.php │ └── plugins │ └── forum.blade.php ├── routes ├── api.php └── web.php ├── src ├── BloggedServiceProvider.php ├── Commands │ ├── InstallCommand.php │ └── PoliciesCommand.php ├── Contracts │ └── BloggedUser.php ├── Exceptions │ └── AuthenticationException.php ├── Filters │ ├── ArticleFilters.php │ ├── Filterable.php │ └── Filters.php ├── Helpers │ └── helpers.php ├── Http │ ├── Controllers │ │ ├── ArticleController.php │ │ ├── BlogController.php │ │ ├── CategoryController.php │ │ ├── Controller.php │ │ └── ImageController.php │ ├── Middleware │ │ ├── Authenticate.php │ │ └── Authorize.php │ ├── Requests │ │ ├── CreateArticleFormRequest.php │ │ └── UpdateArticleFormRequest.php │ └── Resources │ │ ├── ArticleMinimalResource.php │ │ └── ArticleResource.php ├── Jobs │ ├── CreateNewArticle.php │ └── UpdateArticle.php ├── Models │ ├── Article.php │ └── Category.php └── Traits │ ├── Authorizable.php │ ├── CanWriteArticles.php │ └── HasMarkdownParser.php └── webpack.mix.js /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | 5 | --- 6 | 7 | **Describe the bug** 8 | A clear and concise description of what the bug is. 9 | 10 | **To Reproduce** 11 | Steps to reproduce the behavior: 12 | 1. Go to '...' 13 | 2. Click on '....' 14 | 3. Scroll down to '....' 15 | 4. See error 16 | 17 | **Expected behavior** 18 | A clear and concise description of what you expected to happen. 19 | 20 | **Screenshots** 21 | If applicable, add screenshots to help explain your problem. 22 | 23 | **Desktop (please complete the following information):** 24 | - OS: [e.g. iOS] 25 | - Browser [e.g. chrome, safari] 26 | - Version [e.g. 22] 27 | 28 | **Smartphone (please complete the following information):** 29 | - Device: [e.g. iPhone6] 30 | - OS: [e.g. iOS8.1] 31 | - Browser [e.g. stock browser, safari] 32 | - Version [e.g. 22] 33 | 34 | **Additional context** 35 | Add any other context about the problem here. 36 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | 5 | --- 6 | 7 | **Is your feature request related to a problem? Please describe.** 8 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 9 | 10 | **Describe the solution you'd like** 11 | A clear and concise description of what you want to happen. 12 | 13 | **Describe alternatives you've considered** 14 | A clear and concise description of any alternative solutions or features you've considered. 15 | 16 | **Additional context** 17 | Add any other context or screenshots about the feature request here. 18 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Contributions are **welcome** and will be fully **credited**. 4 | 5 | Please read and understand the contribution guide before creating an issue or pull request. 6 | 7 | ## Procedure 8 | 9 | Before filing an issue: 10 | 11 | - Attempt to replicate the problem, to ensure that it wasn't a coincidental incident. 12 | - Check to make sure your feature suggestion isn't already present within the project. 13 | - Check the pull requests tab to ensure that the bug doesn't have a fix in progress. 14 | - Check the pull requests tab to ensure that the feature isn't already in progress. 15 | 16 | Before submitting a pull request: 17 | 18 | - Check the codebase to ensure that your feature doesn't already exist. 19 | - Check the pull requests to ensure that another person hasn't already submitted the feature or fix. 20 | 21 | ## Requirements 22 | 23 | If the project maintainer has any additional requirements, you will find them listed here. 24 | 25 | - **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** - The easiest way to apply the conventions is to install [PHP Code Sniffer](https://pear.php.net/package/PHP_CodeSniffer). 26 | 27 | - **Add tests!** - Your patch won't be accepted if it doesn't have tests. 28 | 29 | - **Document any change in behaviour** - Make sure the `README.md` and any other relevant documentation are kept up-to-date. 30 | 31 | - **Consider our release cycle** - We try to follow [SemVer v2.0.0](https://semver.org/). Randomly breaking public APIs is not an option. 32 | 33 | - **One pull request per feature** - If you want to do more than one thing, send multiple pull requests. 34 | 35 | - **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please [squash them](https://www.git-scm.com/book/en/v2/Git-Tools-Rewriting-History#Changing-Multiple-Commit-Messages) before submitting. 36 | 37 | **Happy coding**! 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Saleem Hadad 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, 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, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 |

6 | Blogged 7 |

8 | 9 | 10 |
11 | Write beautiful blog articles using Markdown inside your Laravel app. 12 |
13 | 14 | 15 |

16 | Build Status 17 | StyleCI 18 | License 19 |

20 |

21 | 22 | # Blogged 🖍 23 | 24 | **Blogged** is a carefully designed Laravel package provides an easy way to create a beautiful blog like [this](https://blogged.binarytorch.com.my/blog) inside your normal Laravel projects. It lives besides your code project's code base without interacting with it. It comes with a beautiful looking user interface which is highly configurable to fit your need. 25 | 26 | ![blogged](https://blogged.binarytorch.com.my/blogged-showcase.png) 27 | 28 | ## Get Started 29 | 30 | ☝️ Install the package via composer. 31 | 32 | composer require binarytorch/blogged 33 | 34 | ✌️ Run the install command. 35 | 36 | php artisan blogged:install 37 | 38 | Visit your app domain with `/blog` endpoint. That's it. 39 | 40 | #### See [full documentation and demo](https://blogged.binarytorch.com.my/docs) 41 | 42 | ## License 43 | 44 | This library is licensed under the MIT License - see the [LICENSE.md](LICENSE) file for details. 45 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "binarytorch/blogged", 3 | "description": "Write gorgeous articles for your Laravel applications using MarkDown", 4 | "keywords": ["laravel", "markdown", "blog", "articles"], 5 | "license": "MIT", 6 | "type": "library", 7 | "support": { 8 | "issues": "https://github.com/saleem-hadad/blogged/issues", 9 | "source": "https://github.com/saleem-hadad/blogged" 10 | }, 11 | "authors": [ 12 | { 13 | "name": "Saleem Hadad", 14 | "email": "saleem@binary-torch.com" 15 | } 16 | ], 17 | "require": { 18 | "illuminate/support": "~5.4.0|~5.5.0|~5.6.0|~5.7.0|~5.8.0|^6.0|^7.0", 19 | "erusev/parsedown-extra": "^0.7.1", 20 | "symfony/dom-crawler": "^4.1", 21 | "mockery/mockery": "^1.2", 22 | "mews/purifier": "^3.1" 23 | }, 24 | "require-dev": { 25 | "phpunit/phpunit": "^8.0", 26 | "laravel/framework": "~5.4.0|~5.5.0|~5.6.0|~5.7.0|~5.8.0|^6.0|^7.0", 27 | "orchestra/database": "~3.4.0|~3.5.0|~3.6.0|~3.7.0|~3.8.0|^4.0", 28 | "orchestra/testbench": "~3.4.0|~3.5.0|~3.6.0|~3.7.0|~3.8.0|^4.0" 29 | }, 30 | "autoload": { 31 | "psr-4": { 32 | "BinaryTorch\\Blogged\\": "src/" 33 | } 34 | }, 35 | "autoload-dev": { 36 | "psr-4": { 37 | "BinaryTorch\\Blogged\\Tests\\": "tests/" 38 | } 39 | }, 40 | "minimum-stability": "stable", 41 | "extra": { 42 | "laravel": { 43 | "providers": [ 44 | "BinaryTorch\\Blogged\\BloggedServiceProvider" 45 | ] 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /database/factories/ArticleFactory.php: -------------------------------------------------------------------------------- 1 | define(Article::class, function (Faker\Generator $faker) { 7 | return [ 8 | 'title' => $faker->sentence, 9 | 'slug' => $faker->unique()->slug(), 10 | 'image' => $faker->randomElement([ 11 | 'https://s3-ap-southeast-1.amazonaws.com/myseniorio/larecipe.png', 12 | 'https://s3-ap-southeast-1.amazonaws.com/myseniorio/zino.png', 13 | 'https://s3-ap-southeast-1.amazonaws.com/myseniorio/blogged.png', 14 | ]), 15 | 'excerpt' => $faker->sentence, 16 | 'body' => $faker->sentence, 17 | 'publish_date' => $faker->dateTime, 18 | 'published' => false, 19 | 'featured' => false, 20 | 'author_id' => 1, 21 | 'category_id' => function() { 22 | return factory(Category::class)->create()->id; 23 | }, 24 | ]; 25 | }); -------------------------------------------------------------------------------- /database/factories/CategoryFactory.php: -------------------------------------------------------------------------------- 1 | define(Category::class, function (Faker\Generator $faker) { 6 | return [ 7 | 'title' => $faker->sentence, 8 | 'slug' => $faker->unique()->slug(), 9 | ]; 10 | }); -------------------------------------------------------------------------------- /database/migrations/2018_10_31_025550_create_blogged_categories_table.php: -------------------------------------------------------------------------------- 1 | increments('id'); 18 | $table->string('title', 100); 19 | $table->string('slug', 120)->unique()->index(); 20 | 21 | $table->timestamps(); 22 | }); 23 | } 24 | 25 | /** 26 | * Reverse the migrations. 27 | * 28 | * @return void 29 | */ 30 | public function down() 31 | { 32 | Schema::dropIfExists('blogged_categories'); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /database/migrations/2018_10_31_025555_create_blogged_articles_table.php: -------------------------------------------------------------------------------- 1 | increments('id'); 18 | $table->string('title', 100); 19 | $table->string('slug', 120)->unique()->index(); 20 | $table->string('image', 254); 21 | $table->text('excerpt'); 22 | $table->longtext('body'); 23 | 24 | $table->datetime('publish_date')->nullable(); 25 | $table->boolean('published')->default(false); 26 | $table->boolean('featured')->default(false); 27 | 28 | $table->unsignedInteger('author_id')->index()->references('id')->on('users')->onDelete('cascade'); 29 | $table->unsignedInteger('category_id')->index()->references('id')->on('blogged_categories')->onDelete('cascade'); 30 | $table->timestamps(); 31 | }); 32 | } 33 | 34 | /** 35 | * Reverse the migrations. 36 | * 37 | * @return void 38 | */ 39 | public function down() 40 | { 41 | Schema::dropIfExists('blogged_articles'); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /mix-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "/publishable/assets/js/app.js": "/publishable/assets/js/app.js", 3 | "/publishable/assets/css/app.css": "/publishable/assets/css/app.css" 4 | } 5 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "dev": "npm run development", 5 | "development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js", 6 | "watch": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js", 7 | "watch-poll": "npm run watch -- --watch-poll", 8 | "hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js", 9 | "prod": "npm run production", 10 | "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js" 11 | }, 12 | "devDependencies": { 13 | "cross-env": "^5.1", 14 | "laravel-mix": "^2.0" 15 | }, 16 | "dependencies": { 17 | "axios": "^0.18.1", 18 | "bootstrap": "^4.3.1", 19 | "cropperjs": "^1.4.3", 20 | "jquery": "^3.5", 21 | "markdown-it": "^8.4.2", 22 | "marked": "^0.6.1", 23 | "popper.js": "^1.12", 24 | "reading-time": "^1.1.3", 25 | "vue": "^2.5.16", 26 | "vue-loaders": "^2.0.0", 27 | "vue-router": "^3.0.1", 28 | "vue-toasted": "^1.1.25" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /publishable/assets/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saleem-hadad/blogged/4c7d12b62d429862dfdd7fe6fdd21ddac2b2b1a6/publishable/assets/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /publishable/assets/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saleem-hadad/blogged/4c7d12b62d429862dfdd7fe6fdd21ddac2b2b1a6/publishable/assets/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /publishable/assets/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saleem-hadad/blogged/4c7d12b62d429862dfdd7fe6fdd21ddac2b2b1a6/publishable/assets/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /publishable/assets/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saleem-hadad/blogged/4c7d12b62d429862dfdd7fe6fdd21ddac2b2b1a6/publishable/assets/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /publishable/assets/fonts/nucleo-icons.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saleem-hadad/blogged/4c7d12b62d429862dfdd7fe6fdd21ddac2b2b1a6/publishable/assets/fonts/nucleo-icons.eot -------------------------------------------------------------------------------- /publishable/assets/fonts/nucleo-icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saleem-hadad/blogged/4c7d12b62d429862dfdd7fe6fdd21ddac2b2b1a6/publishable/assets/fonts/nucleo-icons.ttf -------------------------------------------------------------------------------- /publishable/assets/fonts/nucleo-icons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saleem-hadad/blogged/4c7d12b62d429862dfdd7fe6fdd21ddac2b2b1a6/publishable/assets/fonts/nucleo-icons.woff -------------------------------------------------------------------------------- /publishable/assets/fonts/nucleo-icons.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saleem-hadad/blogged/4c7d12b62d429862dfdd7fe6fdd21ddac2b2b1a6/publishable/assets/fonts/nucleo-icons.woff2 -------------------------------------------------------------------------------- /publishable/policies/BloggedArticlePolicy.php: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 20 | 21 | 25 | 29 | 30 | 31 |
ImageTitleStatusActions
16 |
17 | article image 18 |
19 |
22 | Draft 23 | Published 24 | 26 | 27 | 28 |
32 |
33 | 34 | 35 | -------------------------------------------------------------------------------- /resources/js/Components/BackToTop.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 25 | 26 | -------------------------------------------------------------------------------- /resources/js/Components/SEOTips.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 29 | -------------------------------------------------------------------------------- /resources/js/app.js: -------------------------------------------------------------------------------- 1 | require('./bootsrap'); 2 | require('./argon'); 3 | 4 | import Vue from "vue"; 5 | import router from "./router"; 6 | import Article from './Article'; 7 | import Toasted from 'vue-toasted'; 8 | import 'vue-loaders/dist/vue-loaders.css'; 9 | import { BallBeatLoader } from 'vue-loaders'; 10 | import BackToTop from "./components/BackToTop"; 11 | 12 | Vue.config.productionTip = false; 13 | Vue.use(Toasted, { 14 | router, 15 | theme: 'blogged', 16 | position: 'bottom-right', 17 | duration: 5000, 18 | }) 19 | 20 | Vue.component(BackToTop.name, BackToTop); 21 | Vue.component('loader', BallBeatLoader); 22 | 23 | const noDelimiter = {replace: () => '(?!x)x'}; 24 | 25 | new Vue({ 26 | el: '#app', 27 | delimiters: [noDelimiter, noDelimiter], 28 | router, 29 | mounted() { 30 | Article.parse(); 31 | } 32 | }); 33 | 34 | ga('set', 'page', router.currentRoute.path); 35 | ga('send', 'pageview'); 36 | 37 | router.afterEach(( to, from ) => { 38 | ga('set', 'page', to.path); 39 | ga('send', 'pageview'); 40 | }); -------------------------------------------------------------------------------- /resources/js/bootsrap.js: -------------------------------------------------------------------------------- 1 | import router from "./router"; 2 | 3 | try { 4 | window.Popper = require('popper.js').default; 5 | window.$ = window.jQuery = require('jquery'); 6 | 7 | require('bootstrap'); 8 | } catch (e) {} 9 | 10 | // axios 11 | const axios = require('axios'); 12 | 13 | axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; 14 | axios.defaults.headers.common['X-CSRF-TOKEN'] = document.head.querySelector('meta[name="csrf-token"]').content; 15 | 16 | // apply interceptor on response 17 | axios.interceptors.response.use( 18 | response => response, 19 | error => { 20 | const { status } = error.response 21 | 22 | if (status === 401) { 23 | window.location.href = window.base 24 | } 25 | 26 | if (status === 403) { 27 | router.push({ name: '403' }) 28 | } 29 | 30 | if (status === 404) { 31 | router.push({ name: '404' }) 32 | } 33 | 34 | return Promise.reject(error) 35 | } 36 | ); 37 | 38 | window.axios = axios 39 | 40 | // This enables all language support via CDN 41 | require('./vendor/prism.js'); 42 | Prism.plugins.autoloader.use_minified = true; 43 | Prism.plugins.autoloader.languages_path = 'https://cdnjs.cloudflare.com/ajax/libs/prism/1.15.0/components/'; 44 | -------------------------------------------------------------------------------- /resources/js/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue" 2 | import routes from './routes' 3 | import Router from "vue-router" 4 | 5 | Vue.use(Router); 6 | 7 | const router = new Router({ 8 | base: window.base, 9 | routes: routes, 10 | mode: "history", 11 | linkActiveClass: 'active', 12 | scrollBehavior (to, from, savedPosition) { 13 | return { x: 0, y: 0 } 14 | } 15 | }); 16 | 17 | export default router; -------------------------------------------------------------------------------- /resources/js/router/routes.js: -------------------------------------------------------------------------------- 1 | import Dashboard from '../views/Dashboard'; 2 | import Categories from '../views/Categories'; 3 | import NewArticle from '../views/NewArticle'; 4 | import ViewArticle from '../views/ViewArticle'; 5 | import EditArticle from '../views/EditArticle'; 6 | import Error403 from '../views/403'; 7 | import Error404 from '../views/404'; 8 | 9 | export default [ 10 | { 11 | name: 'dashboard', 12 | path: '/', 13 | component: Dashboard, 14 | props: true, 15 | }, 16 | { 17 | name: 'categories', 18 | path: '/categories', 19 | component: Categories, 20 | props: true, 21 | }, 22 | { 23 | name: 'new', 24 | path: '/articles/new', 25 | component: NewArticle, 26 | props: true, 27 | }, 28 | { 29 | name: 'view', 30 | path: '/articles/:slug*', 31 | component: ViewArticle, 32 | props: true, 33 | }, 34 | { 35 | name: 'edit', 36 | path: '/articles/:slug*/edit', 37 | component: EditArticle, 38 | props: true, 39 | }, 40 | { 41 | name: '403', 42 | path: '/unauthorized', 43 | component: Error403, 44 | props: true, 45 | }, 46 | { 47 | name: '404', 48 | path: '/404', 49 | component: Error404, 50 | }, 51 | { 52 | name: 'not-found', 53 | path: '*', 54 | component: Error404, 55 | }, 56 | ] 57 | -------------------------------------------------------------------------------- /resources/js/views/403.vue: -------------------------------------------------------------------------------- 1 | 24 | -------------------------------------------------------------------------------- /resources/js/views/404.vue: -------------------------------------------------------------------------------- 1 | 24 | -------------------------------------------------------------------------------- /resources/js/views/ViewArticle.vue: -------------------------------------------------------------------------------- 1 | 40 | 41 | -------------------------------------------------------------------------------- /resources/sass/app.scss: -------------------------------------------------------------------------------- 1 | @import "argon"; 2 | @import "./vendor/prism-light"; 3 | @import "./vendor/prism-dark"; 4 | @import "blog"; 5 | @import "global"; -------------------------------------------------------------------------------- /resources/sass/argon.scss: -------------------------------------------------------------------------------- 1 | 2 | /*! 3 | ========================================================= 4 | * Argon Dashboard - v1.0.0 5 | ========================================================= 6 | 7 | * Product Page: https://www.creative-tim.com/product/argon-dashboard 8 | * Copyright 2018 Creative Tim (https://www.creative-tim.com) 9 | * Licensed under MIT (https://github.com/creativetimofficial/argon-dashboard/blob/master/LICENSE.md) 10 | 11 | * Coded by Creative Tim 12 | 13 | ========================================================= 14 | 15 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 16 | 17 | */ 18 | 19 | // Core 20 | 21 | @import "custom/functions"; 22 | @import "custom/variables"; 23 | @import "custom/mixins"; 24 | 25 | // Bootstrap (4.1.3) components 26 | 27 | @import "bootstrap/root"; 28 | @import "bootstrap/reboot"; 29 | @import "bootstrap/type"; 30 | @import "bootstrap/images"; 31 | @import "bootstrap/code"; 32 | @import "bootstrap/grid"; 33 | @import "bootstrap/tables"; 34 | @import "bootstrap/forms"; 35 | @import "bootstrap/buttons"; 36 | @import "bootstrap/transitions"; 37 | @import "bootstrap/dropdown"; 38 | @import "bootstrap/button-group"; 39 | @import "bootstrap/input-group"; 40 | @import "bootstrap/custom-forms"; 41 | @import "bootstrap/nav"; 42 | @import "bootstrap/navbar"; 43 | @import "bootstrap/card"; 44 | @import "bootstrap/breadcrumb"; 45 | @import "bootstrap/pagination"; 46 | @import "bootstrap/badge"; 47 | @import "bootstrap/jumbotron"; 48 | @import "bootstrap/alert"; 49 | @import "bootstrap/progress"; 50 | @import "bootstrap/media"; 51 | @import "bootstrap/list-group"; 52 | @import "bootstrap/close"; 53 | @import "bootstrap/modal"; 54 | @import "bootstrap/tooltip"; 55 | @import "bootstrap/popover"; 56 | @import "bootstrap/carousel"; 57 | @import "bootstrap/utilities"; 58 | @import "bootstrap/print"; 59 | 60 | // Argon utilities and components 61 | 62 | @import "custom/reboot"; 63 | @import "custom/utilities"; 64 | @import "custom/components"; 65 | 66 | // Vendor (Plugins) 67 | 68 | @import "custom/vendors"; 69 | 70 | 71 | -------------------------------------------------------------------------------- /resources/sass/blog.scss: -------------------------------------------------------------------------------- 1 | article { 2 | img { 3 | max-width: 100%; 4 | } 5 | 6 | h1:first-of-type { 7 | border-left: 2px solid $primary; 8 | padding-left: 1rem; 9 | margin-bottom: 1.5rem; 10 | font-weight: $font-weight-bold; 11 | } 12 | 13 | p { 14 | font-size: 1.2rem; 15 | word-break: break-word; 16 | } 17 | 18 | hr { 19 | border-top: 2px dashed $gray-200; 20 | } 21 | 22 | :not(pre) > code { 23 | background-color: $gray-100; 24 | padding: 5px; 25 | border-radius: 5px; 26 | color: $primary; 27 | } 28 | 29 | blockquote { 30 | margin: 2rem 0; 31 | font-size: 1rem !important; 32 | 33 | &:hover { 34 | box-shadow: $input-focus-alternative-box-shadow !important; 35 | } 36 | 37 | p { 38 | padding-left: 30px; 39 | margin-bottom: 0px; 40 | color: $white 41 | } 42 | 43 | .flag { 44 | position: absolute; 45 | width: 30px; 46 | left: 15px; 47 | top: 10px; 48 | font-weight: $font-weight-bold; 49 | svg { 50 | fill: $white; 51 | width: 24px; 52 | height: 24px; 53 | } 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /resources/sass/bootstrap/_alert.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Base styles 3 | // 4 | 5 | .alert { 6 | position: relative; 7 | padding: $alert-padding-y $alert-padding-x; 8 | margin-bottom: $alert-margin-bottom; 9 | border: $alert-border-width solid transparent; 10 | @include border-radius($alert-border-radius); 11 | } 12 | 13 | // Headings for larger alerts 14 | .alert-heading { 15 | // Specified to prevent conflicts of changing $headings-color 16 | color: inherit; 17 | } 18 | 19 | // Provide class for links that match alerts 20 | .alert-link { 21 | font-weight: $alert-link-font-weight; 22 | } 23 | 24 | 25 | // Dismissible alerts 26 | // 27 | // Expand the right padding and account for the close button's positioning. 28 | 29 | .alert-dismissible { 30 | padding-right: ($close-font-size + $alert-padding-x * 2); 31 | 32 | // Adjust close link position 33 | .close { 34 | position: absolute; 35 | top: 0; 36 | right: 0; 37 | padding: $alert-padding-y $alert-padding-x; 38 | color: inherit; 39 | } 40 | } 41 | 42 | 43 | // Alternate styles 44 | // 45 | // Generate contextual modifier classes for colorizing the alert. 46 | 47 | @each $color, $value in $theme-colors { 48 | .alert-#{$color} { 49 | @include alert-variant(theme-color-level($color, $alert-bg-level), theme-color-level($color, $alert-border-level), theme-color-level($color, $alert-color-level)); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /resources/sass/bootstrap/_badge.scss: -------------------------------------------------------------------------------- 1 | // Base class 2 | // 3 | // Requires one of the contextual, color modifier classes for `color` and 4 | // `background-color`. 5 | 6 | .badge { 7 | display: inline-block; 8 | padding: $badge-padding-y $badge-padding-x; 9 | font-size: $badge-font-size; 10 | font-weight: $badge-font-weight; 11 | line-height: 1; 12 | text-align: center; 13 | white-space: nowrap; 14 | vertical-align: baseline; 15 | @include border-radius($badge-border-radius); 16 | 17 | // Empty badges collapse automatically 18 | &:empty { 19 | display: none; 20 | } 21 | } 22 | 23 | // Quick fix for badges in buttons 24 | .btn .badge { 25 | position: relative; 26 | top: -1px; 27 | } 28 | 29 | // Pill badges 30 | // 31 | // Make them extra rounded with a modifier to replace v3's badges. 32 | 33 | .badge-pill { 34 | padding-right: $badge-pill-padding-x; 35 | padding-left: $badge-pill-padding-x; 36 | @include border-radius($badge-pill-border-radius); 37 | } 38 | 39 | // Colors 40 | // 41 | // Contextual variations (linked badges get darker on :hover). 42 | 43 | @each $color, $value in $theme-colors { 44 | .badge-#{$color} { 45 | @include badge-variant($value); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /resources/sass/bootstrap/_breadcrumb.scss: -------------------------------------------------------------------------------- 1 | .breadcrumb { 2 | display: flex; 3 | flex-wrap: wrap; 4 | padding: $breadcrumb-padding-y $breadcrumb-padding-x; 5 | margin-bottom: $breadcrumb-margin-bottom; 6 | list-style: none; 7 | background-color: $breadcrumb-bg; 8 | @include border-radius($breadcrumb-border-radius); 9 | } 10 | 11 | .breadcrumb-item { 12 | // The separator between breadcrumbs (by default, a forward-slash: "/") 13 | + .breadcrumb-item { 14 | padding-left: $breadcrumb-item-padding; 15 | 16 | &::before { 17 | display: inline-block; // Suppress underlining of the separator in modern browsers 18 | padding-right: $breadcrumb-item-padding; 19 | color: $breadcrumb-divider-color; 20 | content: $breadcrumb-divider; 21 | } 22 | } 23 | 24 | // IE9-11 hack to properly handle hyperlink underlines for breadcrumbs built 25 | // without `