├── .php_cs ├── composer.json ├── composer.lock ├── config ├── blog.php └── theme.php ├── database ├── factories │ └── PostFactory.php ├── migrations │ └── 2019_10_17_164316_create_posts_table.php └── seeds │ └── UsersTableSeeder.php ├── license.md ├── package-lock.json ├── package.json ├── public ├── app.js ├── fonts │ ├── FontAwesome.otf │ ├── fontawesome-webfont.eot │ ├── fontawesome-webfont.svg │ ├── fontawesome-webfont.ttf │ ├── fontawesome-webfont.woff │ └── fontawesome-webfont.woff2 ├── main.css ├── manifest.js ├── mix-manifest.json └── vendor.js ├── readme.md ├── resources ├── css │ ├── base │ │ ├── editor-preview.css │ │ ├── labels.css │ │ ├── links.css │ │ └── svg.css │ ├── components │ │ ├── button.css │ │ ├── editor.css │ │ └── text-input.css │ ├── config │ │ └── fonts.css │ ├── main.css │ ├── utilities │ │ └── helpers.css │ └── vendor │ │ ├── easymde.css │ │ └── fontawesome.css ├── fonts │ ├── FontAwesome.otf │ ├── fontawesome-webfont.eot │ ├── fontawesome-webfont.svg │ ├── fontawesome-webfont.ttf │ ├── fontawesome-webfont.woff │ └── fontawesome-webfont.woff2 ├── js │ ├── app.js │ ├── includes │ │ ├── toggle.js │ │ └── toggleHandlers │ │ │ └── toggleAdminNav.js │ └── vendor │ │ └── easymde │ │ ├── codemirror │ │ └── tablist.js │ │ └── easymde.js └── views │ ├── account │ ├── edit.blade.php │ └── partials │ │ └── form.blade.php │ ├── auth │ └── login.blade.php │ ├── dashboard.blade.php │ ├── layouts │ ├── master.blade.php │ ├── nav │ │ ├── account.blade.php │ │ ├── blog.blade.php │ │ ├── dashboard.blade.php │ │ └── items │ │ │ ├── account.blade.php │ │ │ ├── logout.blade.php │ │ │ └── site.blade.php │ └── partials │ │ ├── flash.blade.php │ │ ├── header.blade.php │ │ └── pagination.blade.php │ └── posts │ ├── create.blade.php │ ├── edit.blade.php │ ├── index.blade.php │ └── partials │ ├── deleteButton.blade.php │ ├── form.blade.php │ ├── header.blade.php │ ├── item.blade.php │ ├── legend.blade.php │ └── list-header.blade.php ├── routes └── web.php ├── src ├── BlogServiceProvider.php ├── Console │ ├── InstallCommand.php │ ├── PublishCommand.php │ └── ThemePublishCommand.php ├── Facades │ └── Blog.php ├── Http │ ├── Controllers │ │ ├── AccountController.php │ │ ├── DashboardController.php │ │ ├── Front │ │ │ ├── HomeController.php │ │ │ ├── PostsController.php │ │ │ └── TaggedPostsController.php │ │ ├── LoginController.php │ │ └── PostsController.php │ ├── Middleware │ │ ├── Authenticate.php │ │ └── NoHttpCache.php │ └── Requests │ │ ├── AccountEditRequest.php │ │ ├── ImageUploadRequest.php │ │ └── PostRequest.php ├── Markdown │ └── Markdown.php └── Posts │ ├── Post.php │ ├── PostObserver.php │ └── PostPresenter.php ├── tailwind.config.js └── webpack.mix.js /.php_cs: -------------------------------------------------------------------------------- 1 | 6 | Dariusz Rumiński 7 | This source file is subject to the MIT license that is bundled 8 | with this source code in the file LICENSE. 9 | EOF; 10 | $config = PhpCsFixer\Config::create() 11 | ->setRiskyAllowed(true) 12 | ->setRules([ 13 | '@PSR2' => true, 14 | '@PHP56Migration' => true, 15 | '@PHPUnit60Migration:risky' => true, 16 | '@Symfony' => true, 17 | '@Symfony:risky' => true, 18 | 'align_multiline_comment' => true, 19 | 'array_syntax' => ['syntax' => 'short'], 20 | 'blank_line_before_statement' => true, 21 | 'combine_consecutive_issets' => true, 22 | 'combine_consecutive_unsets' => true, 23 | 'compact_nullable_typehint' => true, 24 | 'escape_implicit_backslashes' => true, 25 | 'explicit_indirect_variable' => true, 26 | 'explicit_string_variable' => true, 27 | 'final_internal_class' => true, 28 | 'list_syntax' => ['syntax' => 'long'], 29 | 'method_chaining_indentation' => true, 30 | 'method_argument_space' => ['ensure_fully_multiline' => true], 31 | 'multiline_comment_opening_closing' => true, 32 | 'no_extra_blank_lines' => ['tokens' => ['break', 'continue', 'extra', 'return', 'throw', 'use', 'parenthesis_brace_block', 'square_brace_block', 'curly_brace_block']], 33 | 'method_separation' => true, 34 | 'no_multiline_whitespace_before_semicolons' => true, 35 | 'no_short_echo_tag' => true, 36 | 'no_superfluous_elseif' => true, 37 | 'no_unneeded_curly_braces' => true, 38 | 'no_unneeded_final_method' => true, 39 | 'no_unreachable_default_argument_value' => true, 40 | 'no_useless_else' => true, 41 | 'no_useless_return' => true, 42 | 'single_quote' => true, 43 | 'binary_operator_spaces' => [ 44 | 'align_double_arrow' => false, 45 | 'align_equals' => false, 46 | ], 47 | 'blank_line_after_opening_tag' => true, 48 | 'blank_line_before_return' => true, 49 | 'braces' => [ 50 | 'allow_single_line_closure' => true, 51 | ], 52 | 'concat_space' => ['spacing' => 'one'], 53 | 'declare_equal_normalize' => true, 54 | 'function_typehint_space' => true, 55 | 'hash_to_slash_comment' => true, 56 | 'include' => true, 57 | 'lowercase_cast' => true, 58 | 'no_empty_comment' => true, 59 | 'no_extra_consecutive_blank_lines' => [ 60 | 'curly_brace_block', 61 | 'extra', 62 | 'parenthesis_brace_block', 63 | 'square_brace_block', 64 | 'throw', 65 | 'use', 66 | ], 67 | 'no_leading_import_slash' => true, 68 | 'no_multiline_whitespace_around_double_arrow' => true, 69 | 'no_spaces_around_offset' => true, 70 | 'no_unused_imports' => true, 71 | 'no_whitespace_before_comma_in_array' => true, 72 | 'no_whitespace_in_blank_line' => true, 73 | 'object_operator_without_whitespace' => true, 74 | 'phpdoc_align' => true, 75 | 'phpdoc_indent' => true, 76 | 'phpdoc_no_useless_inheritdoc' => true, 77 | 'phpdoc_separation' => true, 78 | 'single_blank_line_before_namespace' => true, 79 | 'ternary_operator_spaces' => true, 80 | 'trim_array_spaces' => true, 81 | 'unary_operator_spaces' => true, 82 | 'whitespace_after_comma_in_array' => true, 83 | 'ordered_imports' => ['sortAlgorithm' => 'alpha'], 84 | 'ordered_class_elements' => [ 85 | 'order' => [ 86 | 'use_trait', 87 | 'constant_public', 88 | 'constant_protected', 89 | 'constant_private', 90 | 'property_public', 91 | 'property_protected', 92 | 'property_private', 93 | 'construct', 94 | 'destruct', 95 | 'magic', 96 | 'phpunit', 97 | 'method_public', 98 | 'method_protected', 99 | 'method_private', 100 | ], 101 | 'sortAlgorithm' => 'alpha', 102 | ], 103 | 'php_unit_strict' => true, 104 | 'php_unit_test_annotation' => true, 105 | 'php_unit_test_class_requires_covers' => false, 106 | 'phpdoc_add_missing_param_annotation' => true, 107 | 'phpdoc_order' => true, 108 | 'phpdoc_types_order' => true, 109 | ]) 110 | ->setFinder( 111 | PhpCsFixer\Finder::create() 112 | ->exclude(['vendor', 'build', 'public']) 113 | ->in(__DIR__) 114 | ); 115 | 116 | return $config; 117 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wingsline/blog", 3 | "description": "A blog package for Laravel", 4 | "license": "MIT", 5 | "authors": [ 6 | { 7 | "name": "Arpad Olasz", 8 | "email": "wingsline@gmail.com", 9 | "homepage": "https://wingsline.com" 10 | } 11 | ], 12 | "homepage": "https://github.com/wingsline/blog", 13 | "keywords": ["Laravel", "Blog"], 14 | "require": { 15 | "php": "^7.4", 16 | "illuminate/support": "~7", 17 | "spatie/laravel-backup": "^6.0", 18 | "spatie/laravel-csp": "^2.6", 19 | "spatie/laravel-feed": "^2.7", 20 | "spatie/laravel-flash": "^1.6.0", 21 | "spatie/laravel-medialibrary": "^8.0.0", 22 | "spatie/laravel-menu": "^3.4", 23 | "spatie/laravel-missing-page-redirector": "^2.6", 24 | "spatie/laravel-responsecache": "^6.5", 25 | "spatie/laravel-sluggable": "^2.3", 26 | "spatie/laravel-tags": "^2.7", 27 | "michelf/php-markdown": "^1.9", 28 | "intervention/image": "^2.5", 29 | "laravel/ui": "^2.0" 30 | }, 31 | "require-dev": { 32 | "phpunit/phpunit": "^8.4|^9.0", 33 | "mockery/mockery": "^1.3.1", 34 | "orchestra/testbench": "^5.0" 35 | }, 36 | "autoload": { 37 | "psr-4": { 38 | "Wingsline\\Blog\\": "src/", 39 | "Wingsline\\Blog\\Database\\Seeds\\": "database/seeds/" 40 | } 41 | }, 42 | "autoload-dev": { 43 | "psr-4": { 44 | "Wingsline\\Blog\\Tests\\": "tests/" 45 | } 46 | }, 47 | "scripts": { 48 | "test": "vendor/bin/phpunit" 49 | }, 50 | "extra": { 51 | "laravel": { 52 | "providers": [ 53 | "Wingsline\\Blog\\BlogServiceProvider" 54 | ] 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /config/blog.php: -------------------------------------------------------------------------------- 1 | env('ADMIN_PREFIX', 'admin'), 15 | 16 | /* 17 | |-------------------------------------------------------------------------- 18 | | Blog prefix 19 | |-------------------------------------------------------------------------- 20 | | 21 | | 22 | */ 23 | 'blogprefix' => env('BLOG_PREFIX', ''), 24 | 25 | /* 26 | |-------------------------------------------------------------------------- 27 | | Maximum allowed failed login attempts 28 | |-------------------------------------------------------------------------- 29 | | 30 | */ 31 | 'maxAttempts' => env('ADMIN_MAX_LOGIN_ATTEMPTS', 5), 32 | 33 | /* 34 | |-------------------------------------------------------------------------- 35 | | Pagination 36 | |-------------------------------------------------------------------------- 37 | | 38 | */ 39 | 'per_page' => env('ADMIN_PER_PAGE', 15), 40 | 41 | /* 42 | |-------------------------------------------------------------------------- 43 | | Header navigation 44 | |-------------------------------------------------------------------------- 45 | | 46 | | This is the header navigation. It uses views as menu items. 47 | | 48 | */ 49 | 'navHeader' => [ 50 | 'blog::layouts.nav.items.site', 51 | 'blog::layouts.nav.items.account', 52 | 'blog::layouts.nav.items.logout', 53 | ], 54 | 55 | /* 56 | |-------------------------------------------------------------------------- 57 | | Admin navigation 58 | |-------------------------------------------------------------------------- 59 | | 60 | | Main admin navigation 61 | | 62 | */ 63 | 'navAdmin' => [ 64 | 'blog::layouts.nav.dashboard', 65 | 'blog::layouts.nav.blog', 66 | 'blog::layouts.nav.account', 67 | ], 68 | 69 | /* 70 | |-------------------------------------------------------------------------- 71 | | Feed configuration 72 | |-------------------------------------------------------------------------- 73 | | 74 | */ 75 | 'feed' => [ 76 | 'items' => Post::class.'@getFeedItems', 77 | 'url' => '/feed/blog', 78 | 'title' => config('app.name'), 79 | 'description' => config('theme.meta.description', ''), 80 | 'language' => 'en-US', 81 | 'view' => 'feed::atom', 82 | 'type' => 'application/atom+xml', 83 | ], 84 | 85 | /* 86 | |-------------------------------------------------------------------------- 87 | | Markdown Parser class and method name 88 | |-------------------------------------------------------------------------- 89 | | 90 | | Set the markdown parser class and method name here 91 | | 92 | */ 93 | 'markdown_parser' => [ 94 | 'class' => Markdown::class, 95 | 'method' => 'convertToHtml', 96 | ], 97 | ]; 98 | -------------------------------------------------------------------------------- /config/theme.php: -------------------------------------------------------------------------------- 1 | define(Post::class, function (Faker $faker) { 8 | return [ 9 | 'title' => $faker->sentence, 10 | 'text' => $faker->paragraph, 11 | 'author' => $faker->name, 12 | 'publish_date' => $faker->dateTimeBetween('-5 years'), 13 | 'published' => $faker->boolean(90), 14 | 'original_content' => $faker->boolean(10), 15 | ]; 16 | }); 17 | -------------------------------------------------------------------------------- /database/migrations/2019_10_17_164316_create_posts_table.php: -------------------------------------------------------------------------------- 1 | bigIncrements('id'); 24 | $table->string('title', 255); 25 | $table->string('slug', 255); 26 | $table->text('text'); 27 | $table->datetime('publish_date')->nullable(); 28 | $table->tinyInteger('published'); 29 | $table->tinyInteger('tweet_sent')->default(0); 30 | $table->tinyInteger('posted_on_medium')->default(0); 31 | $table->string('author', 255); 32 | $table->timestamp('created_at')->nullable(); 33 | $table->timestamp('updated_at')->nullable(); 34 | $table->tinyInteger('original_content')->default(0); 35 | $table->string('external_url', 255)->nullable(); 36 | $table->string('tweet_url', 255)->nullable(); 37 | }); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /database/seeds/UsersTableSeeder.php: -------------------------------------------------------------------------------- 1 | getTable())->where('email', 'admin@example.com')->exists()) { 19 | $user::create([ 20 | 'name' => 'Administrator', 21 | 'email' => 'admin@example.com', 22 | 'password' => bcrypt('admin123'), 23 | ]); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /license.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Arpad Olasz 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /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": "npm run development -- --watch", 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 --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js" 11 | }, 12 | "devDependencies": { 13 | "axios": "^0.21.1", 14 | "cross-env": "^7.0.3", 15 | "laravel-mix": "^5.0.9", 16 | "laravel-mix-purgecss": "^5.0.0", 17 | "lodash": "^4.17.21", 18 | "postcss-discard-comments": "^4.0.2", 19 | "postcss-import": "^12.0.1", 20 | "postcss-inline-svg": "^4.1.0", 21 | "resolve-url-loader": "^3.1.2", 22 | "sass": "^1.30.0", 23 | "sass-loader": "^8.0.2", 24 | "vue-template-compiler": "^2.6.12" 25 | }, 26 | "dependencies": { 27 | "easymde": "^2.13.0", 28 | "highlight.js": "^10.5.0", 29 | "tailwindcss": "^1.9.6" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /public/app.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[0],{"/1ZR":function(e,t){},0:function(e,t,i){i("bUC5"),e.exports=i("/1ZR")},1:function(e,t){},"3Gcj":function(e,t,i){var o={"./toggleAdminNav.js":"waJ0"};function n(e){var t=a(e);return i(t)}function a(e){if(!i.o(o,e)){var t=new Error("Cannot find module '"+e+"'");throw t.code="MODULE_NOT_FOUND",t}return o[e]}n.keys=function(){return Object.keys(o)},n.resolve=a,e.exports=n,n.id="3Gcj"},U3XV:function(e,t,i){var o=i("VrN/");o.commands.tabAndIndentMarkdownList=function(e){var t=e.listSelections()[0].head;if(!1!==e.getStateAfter(t.line).list)e.execCommand("indentMore");else if(e.options.indentWithTabs)e.execCommand("insertTab");else{var i=Array(e.options.tabSize+1).join(" ");e.replaceSelection(i)}},o.commands.shiftTabAndUnindentMarkdownList=function(e){var t=e.listSelections()[0].head;if(!1!==e.getStateAfter(t.line).list)e.execCommand("indentLess");else if(e.options.indentWithTabs)e.execCommand("insertTab");else{var i=Array(e.options.tabSize+1).join(" ");e.replaceSelection(i)}}},YAwj:function(e,t,i){"use strict";function o(e){return(o="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}var n=i("VrN/");i("HvfG"),i("U3XV"),i("bXjK"),i("lZu9"),i("nrkQ"),i("19Vz"),i("mUiM"),i("uTOq"),i("RKCW"),i("1eCo");var a=i("6mXC"),r=i("DlQD"),s=/Mac/.test(navigator.platform),l=new RegExp(/()+?/g),c={toggleBold:y,toggleItalic:w,drawLink:B,toggleHeadingSmaller:x,toggleHeadingBigger:N,drawImage:_,toggleBlockquote:C,toggleOrderedList:E,toggleUnorderedList:H,toggleCodeBlock:k,togglePreview:R,toggleStrikethrough:S,toggleHeading1:T,toggleHeading2:I,toggleHeading3:L,cleanBlock:A,drawTable:F,drawHorizontalRule:O,undo:z,redo:U,toggleSideBySide:q,toggleFullScreen:b},d={toggleBold:"Cmd-B",toggleItalic:"Cmd-I",drawLink:"Cmd-K",toggleHeadingSmaller:"Cmd-H",toggleHeadingBigger:"Shift-Cmd-H",cleanBlock:"Cmd-E",drawImage:"Cmd-Alt-I",toggleBlockquote:"Cmd-'",toggleOrderedList:"Cmd-Alt-L",toggleUnorderedList:"Cmd-L",toggleCodeBlock:"Cmd-Alt-C",togglePreview:"Cmd-P",toggleSideBySide:"F9",toggleFullScreen:"F11"},u=function(){var e,t=!1;return e=navigator.userAgent||navigator.vendor||window.opera,(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i.test(e)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw-(n|u)|c55\/|capi|ccwa|cdm-|cell|chtm|cldc|cmd-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc-s|devi|dica|dmob|do(c|p)o|ds(12|-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(-|_)|g1 u|g560|gene|gf-5|g-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd-(m|p|t)|hei-|hi(pt|ta)|hp( i|ip)|hs-c|ht(c(-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i-(20|go|ma)|i230|iac( |-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|-[a-w])|libw|lynx|m1-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|-([1-8]|c))|phil|pire|pl(ay|uc)|pn-2|po(ck|rt|se)|prox|psio|pt-g|qa-a|qc(07|12|21|32|60|-[2-7]|i-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h-|oo|p-)|sdk\/|se(c(-|0|1)|47|mc|nd|ri)|sgh-|shar|sie(-|m)|sk-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h-|v-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl-|tdg-|tel(i|m)|tim-|t-mo|to(pl|sh)|ts(70|m-|m3|m5)|tx-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas-|your|zeto|zte-/i.test(e.substr(0,4)))&&(t=!0),t};function p(e){return e=s?e.replace("Ctrl","Cmd"):e.replace("Cmd","Ctrl")}function g(e,t,i,o){var n=m(e,!1,t,i,"button",o);n.className+=" easymde-dropdown";var a=document.createElement("div");a.className="easymde-dropdown-content";for(var r=0;r=0&&!i(g=c.getLineHandle(r));r--);var v,b,y,w,S=n(c.getTokenAt({line:r,ch:1})).fencedChars;i(c.getLineHandle(d.line))?(v="",b=d.line):i(c.getLineHandle(d.line-1))?(v="",b=d.line-1):(v=S+"\n",b=d.line),i(c.getLineHandle(u.line))?(y="",w=u.line,0===u.ch&&(w+=1)):0!==u.ch&&i(c.getLineHandle(u.line+1))?(y="",w=u.line+1):(y=S+"\n",w=u.line+1),0===u.ch&&(w-=1),c.operation((function(){c.replaceRange(y,{line:w,ch:0},{line:w+(y?0:1),ch:0}),c.replaceRange(v,{line:b,ch:0},{line:b+(v?0:1),ch:0})})),c.setSelection({line:b+(v?1:0),ch:0},{line:w+(v?1:-1),ch:0}),c.focus()}else{var k=d.line;if(i(c.getLineHandle(d.line))&&("fenced"===a(c,d.line+1)?(r=d.line,k=d.line+1):(s=d.line,k=d.line-1)),void 0===r)for(r=k;r>=0&&!i(g=c.getLineHandle(r));r--);if(void 0===s)for(l=c.lineCount(),s=k;s=0;r--)if(!(g=c.getLineHandle(r)).text.match(/^\s*$/)&&"indented"!==a(c,r,g)){r+=1;break}for(l=c.lineCount(),s=d.line;s ]+|[0-9]+(.|\)))[ ]*/,""),e.replaceRange(t,{line:n,ch:0},{line:n,ch:99999999999999})}(e.codemirror)}function B(e){var t=e.codemirror,i=h(t),o=e.options,n="https://";if(o.promptURLs&&!(n=prompt(o.promptTexts.link,"https://")))return!1;D(t,i.link,o.insertTexts.link,n)}function _(e){var t=e.codemirror,i=h(t),o=e.options,n="https://";if(o.promptURLs&&!(n=prompt(o.promptTexts.image,"https://")))return!1;D(t,i.image,o.insertTexts.image,n)}function M(e,t){var i=e.codemirror,o=h(i),n=e.options,a=t.substr(t.lastIndexOf("/")+1);D(i,o.image,n.insertTexts.uploadedImage,t),e.updateStatusBar("upload-image",e.options.imageTexts.sbOnUploaded.replace("#image_name#",a)),setTimeout((function(){e.updateStatusBar("upload-image",e.options.imageTexts.sbInit)}),1e3)}function F(e){var t=e.codemirror,i=h(t),o=e.options;D(t,i.table,o.insertTexts.table)}function O(e){var t=e.codemirror,i=h(t),o=e.options;D(t,i.image,o.insertTexts.horizontalRule)}function z(e){var t=e.codemirror;t.undo(),t.focus()}function U(e){var t=e.codemirror;t.redo(),t.focus()}function q(e){var t=e.codemirror,i=t.getWrapperElement(),o=i.nextSibling,n=e.toolbarElements&&e.toolbarElements["side-by-side"],a=!1,r=[i.parentNode,e.gui.toolbar,i,o,e.gui.statusbar];/editor-preview-active-side/.test(o.className)?(t.getOption("sideBySideNoFullscreen")&&(t.setOption("sideBySideNoFullscreen",!1),r.forEach((function(e){!function(e){e.className=e.className.replace(/\s*sided--no-fullscreen\s*/g,"")}(e)}))),o.className=o.className.replace(/\s*editor-preview-active-side\s*/g,""),n&&(n.className=n.className.replace(/\s*active\s*/g,"")),i.className=i.className.replace(/\s*CodeMirror-sided\s*/g," ")):(setTimeout((function(){t.getOption("fullScreen")||(!1===e.options.sideBySideFullscreen?(t.setOption("sideBySideNoFullscreen",!0),r.forEach((function(e){!function(e){e.className+=" sided--no-fullscreen"}(e)}))):b(e)),o.className+=" editor-preview-active-side"}),1),n&&(n.className+=" active"),i.className+=" CodeMirror-sided",a=!0);var s=i.lastChild;if(/editor-preview-active/.test(s.className)){s.className=s.className.replace(/\s*editor-preview-active\s*/g,"");var l=e.toolbarElements.preview,c=e.toolbar_div;l.className=l.className.replace(/\s*active\s*/g,""),c.className=c.className.replace(/\s*disabled-for-preview*/g,"")}if(t.sideBySideRenderingFunction||(t.sideBySideRenderingFunction=function(){var t=e.options.previewRender(e.value(),o);null!=t&&(o.innerHTML=t)}),a){var d=e.options.previewRender(e.value(),o);null!=d&&(o.innerHTML=d),t.on("update",t.sideBySideRenderingFunction)}else t.off("update",t.sideBySideRenderingFunction);t.refresh()}function R(e){var t=e.codemirror,i=t.getWrapperElement(),o=e.toolbar_div,n=!!e.options.toolbar&&e.toolbarElements.preview,a=i.lastChild,r=t.getWrapperElement().nextSibling;if(/editor-preview-active-side/.test(r.className)&&q(e),!a||!/editor-preview-full/.test(a.className)){if((a=document.createElement("div")).className="editor-preview-full",e.options.previewClass)if(Array.isArray(e.options.previewClass))for(var s=0;s\s+/,"unordered-list":i,"ordered-list":i},l=function(e,t,n){var a=i.exec(t),r=function(e,t){return{quote:">","unordered-list":"*","ordered-list":"%%i."}[e].replace("%%i",t)}(e,c);return null!==a?(function(e,t){var i=new RegExp({quote:">","unordered-list":"*","ordered-list":"\\d+."}[e]);return t&&i.test(t)}(e,a[2])&&(r=""),t=a[1]+r+a[3]+t.replace(o,"").replace(s[e],"$1")):0==n&&(t=r+" "+t),t},c=1,d=a.line;d<=r.line;d++)!function(i){var o=e.getLine(i);n[t]?o=o.replace(s[t],"$1"):("unordered-list"==t&&(o=l("ordered-list",o,!0)),o=l(t,o,!1),c+=1),e.replaceRange(o,{line:i,ch:0},{line:i,ch:99999999999999})}(d);e.focus()}}function W(e,t,i,o){if(!/editor-preview-active/.test(e.codemirror.getWrapperElement().lastChild.className)){o=void 0===o?i:o;var n,a=e.codemirror,r=h(a),s=i,l=o,c=a.getCursor("start"),d=a.getCursor("end");r[t]?(s=(n=a.getLine(c.line)).slice(0,c.ch),l=n.slice(c.ch),"bold"==t?(s=s.replace(/(\*\*|__)(?![\s\S]*(\*\*|__))/,""),l=l.replace(/(\*\*|__)/,"")):"italic"==t?(s=s.replace(/(\*|_)(?![\s\S]*(\*|_))/,""),l=l.replace(/(\*|_)/,"")):"strikethrough"==t&&(s=s.replace(/(\*\*|~~)(?![\s\S]*(\*\*|~~))/,""),l=l.replace(/(\*\*|~~)/,"")),a.replaceRange(s+l,{line:c.line,ch:0},{line:c.line,ch:99999999999999}),"bold"==t||"strikethrough"==t?(c.ch-=2,c!==d&&(d.ch-=2)):"italic"==t&&(c.ch-=1,c!==d&&(d.ch-=1))):(n=a.getSelection(),"bold"==t?n=(n=n.split("**").join("")).split("__").join(""):"italic"==t?n=(n=n.split("*").join("")).split("_").join(""):"strikethrough"==t&&(n=n.split("~~").join("")),a.replaceSelection(s+n+l),c.ch+=i.length,d.ch=c.ch+n.length),a.setSelection(c,d),a.focus()}}function V(e,t){if(Math.abs(e)<1024)return""+e+t[0];var i=0;do{e/=1024,++i}while(Math.abs(e)>=1024&&i=19968?i+=t[o].length:i+=1;return i}var K={bold:{name:"bold",action:y,className:"fa fa-bold",title:"Bold",default:!0},italic:{name:"italic",action:w,className:"fa fa-italic",title:"Italic",default:!0},strikethrough:{name:"strikethrough",action:S,className:"fa fa-strikethrough",title:"Strikethrough"},heading:{name:"heading",action:x,className:"fa fa-header fa-heading",title:"Heading",default:!0},"heading-smaller":{name:"heading-smaller",action:x,className:"fa fa-header fa-heading header-smaller",title:"Smaller Heading"},"heading-bigger":{name:"heading-bigger",action:N,className:"fa fa-header fa-heading header-bigger",title:"Bigger Heading"},"heading-1":{name:"heading-1",action:T,className:"fa fa-header fa-heading header-1",title:"Big Heading"},"heading-2":{name:"heading-2",action:I,className:"fa fa-header fa-heading header-2",title:"Medium Heading"},"heading-3":{name:"heading-3",action:L,className:"fa fa-header fa-heading header-3",title:"Small Heading"},"separator-1":{name:"separator-1"},code:{name:"code",action:k,className:"fa fa-code",title:"Code"},quote:{name:"quote",action:C,className:"fa fa-quote-left",title:"Quote",default:!0},"unordered-list":{name:"unordered-list",action:H,className:"fa fa-list-ul",title:"Generic List",default:!0},"ordered-list":{name:"ordered-list",action:E,className:"fa fa-list-ol",title:"Numbered List",default:!0},"clean-block":{name:"clean-block",action:A,className:"fa fa-eraser",title:"Clean block"},"separator-2":{name:"separator-2"},link:{name:"link",action:B,className:"fa fa-link",title:"Create Link",default:!0},image:{name:"image",action:_,className:"fa fa-image",title:"Insert Image",default:!0},"upload-image":{name:"upload-image",action:function(e){e.openBrowseFileWindow()},className:"fa fa-image",title:"Import an image"},table:{name:"table",action:F,className:"fa fa-table",title:"Insert Table"},"horizontal-rule":{name:"horizontal-rule",action:O,className:"fa fa-minus",title:"Insert Horizontal Line"},"separator-3":{name:"separator-3"},preview:{name:"preview",action:R,className:"fa fa-eye",noDisable:!0,title:"Toggle Preview",default:!0},"side-by-side":{name:"side-by-side",action:q,className:"fa fa-columns",noDisable:!0,noMobile:!0,title:"Toggle Side by Side",default:!0},fullscreen:{name:"fullscreen",action:b,className:"fa fa-arrows-alt",noDisable:!0,noMobile:!0,title:"Toggle Fullscreen",default:!0},"separator-4":{name:"separator-4"},guide:{name:"guide",action:"https://www.markdownguide.org/basic-syntax/",className:"fa fa-question-circle",noDisable:!0,title:"Markdown Guide",default:!0},"separator-5":{name:"separator-5"},undo:{name:"undo",action:z,className:"fa fa-undo",noDisable:!0,title:"Undo"},redo:{name:"redo",action:U,className:"fa fa-repeat fa-redo",noDisable:!0,title:"Redo"}},J={link:["[","](#url#)"],image:["![](","#url#)"],uploadedImage:["![](#url#)",""],table:["","\n\n| Column 1 | Column 2 | Column 3 |\n| -------- | -------- | -------- |\n| Text | Text | Text |\n\n"],horizontalRule:["","\n\n-----\n\n"]},Z={link:"URL for the link:",image:"URL of the image:"},Q={locale:"en-US",format:{hour:"2-digit",minute:"2-digit"}},Y={bold:"**",code:"```",italic:"*"},ee={sbInit:"Attach files by drag and dropping or pasting from clipboard.",sbOnDragEnter:"Drop image to upload it.",sbOnDrop:"Uploading image #images_names#...",sbProgress:"Uploading #file_name#: #progress#%",sbOnUploaded:"Uploaded #image_name#",sizeUnits:"b,Kb,Mb"},te={noFileGiven:"You must select a file.",typeNotAllowed:"This image type is not allowed.",fileTooLarge:"Image #image_name# is too big (#image_size#).\nMaximum file size is #image_max_size#.",importError:"Something went wrong when uploading the image #image_name#."};function ie(e){(e=e||{}).parent=this;var t=!0;if(!1===e.autoDownloadFontAwesome&&(t=!1),!0!==e.autoDownloadFontAwesome)for(var i=document.styleSheets,o=0;o-1&&(t=!1);if(t){var n=document.createElement("link");n.rel="stylesheet",n.href="https://maxcdn.bootstrapcdn.com/font-awesome/latest/css/font-awesome.min.css",document.getElementsByTagName("head")[0].appendChild(n)}if(e.element)this.element=e.element;else if(null===e.element)return;if(void 0===e.toolbar)for(var a in e.toolbar=[],K)Object.prototype.hasOwnProperty.call(K,a)&&(-1!=a.indexOf("separator-")&&e.toolbar.push("|"),(!0===K[a].default||e.showIcons&&e.showIcons.constructor===Array&&-1!=e.showIcons.indexOf(a))&&e.toolbar.push(a));if(Object.prototype.hasOwnProperty.call(e,"previewClass")||(e.previewClass="editor-preview"),Object.prototype.hasOwnProperty.call(e,"status")||(e.status=["autosave","lines","words","cursor"],e.uploadImage&&e.status.unshift("upload-image")),e.previewRender||(e.previewRender=function(e){return this.parent.markdown(e)}),e.parsingConfig=X({highlightFormatting:!0},e.parsingConfig||{}),e.insertTexts=X({},J,e.insertTexts||{}),e.promptTexts=X({},Z,e.promptTexts||{}),e.blockStyles=X({},Y,e.blockStyles||{}),null!=e.autosave&&(e.autosave.timeFormat=X({},Q,e.autosave.timeFormat||{})),e.shortcuts=X({},d,e.shortcuts||{}),e.minHeight=e.minHeight||"300px",e.maxHeight=e.maxHeight||void 0,e.errorCallback=e.errorCallback||function(e){alert(e)},e.uploadImage=e.uploadImage||!1,e.imageMaxSize=e.imageMaxSize||2097152,e.imageAccept=e.imageAccept||"image/png, image/jpeg",e.imageTexts=X({},ee,e.imageTexts||{}),e.errorMessages=X({},te,e.errorMessages||{}),null!=e.autosave&&null!=e.autosave.unique_id&&""!=e.autosave.unique_id&&(e.autosave.uniqueId=e.autosave.unique_id),this.options=e,this.render(),!e.initialValue||this.options.autosave&&!0===this.options.autosave.foundSavedValue||this.value(e.initialValue),e.uploadImage){var r=this;this.codemirror.on("dragenter",(function(e,t){r.updateStatusBar("upload-image",r.options.imageTexts.sbOnDragEnter),t.stopPropagation(),t.preventDefault()})),this.codemirror.on("dragend",(function(e,t){r.updateStatusBar("upload-image",r.options.imageTexts.sbInit),t.stopPropagation(),t.preventDefault()})),this.codemirror.on("dragleave",(function(e,t){r.updateStatusBar("upload-image",r.options.imageTexts.sbInit),t.stopPropagation(),t.preventDefault()})),this.codemirror.on("dragover",(function(e,t){r.updateStatusBar("upload-image",r.options.imageTexts.sbOnDragEnter),t.stopPropagation(),t.preventDefault()})),this.codemirror.on("drop",(function(t,i){i.stopPropagation(),i.preventDefault(),e.imageUploadFunction?r.uploadImagesUsingCustomFunction(e.imageUploadFunction,i.dataTransfer.files):r.uploadImages(i.dataTransfer.files)})),this.codemirror.on("paste",(function(t,i){e.imageUploadFunction?r.uploadImagesUsingCustomFunction(e.imageUploadFunction,i.clipboardData.files):r.uploadImages(i.clipboardData.files)}))}}function oe(){if("object"!==("undefined"==typeof localStorage?"undefined":o(localStorage)))return!1;try{localStorage.setItem("smde_localStorage",1),localStorage.removeItem("smde_localStorage")}catch(e){return!1}return!0}ie.prototype.uploadImages=function(e,t,i){if(0!==e.length){for(var o=[],n=0;n$/,' target="_blank">');e=e.replace(i,o)}}return e}(o))}},ie.prototype.render=function(e){if(e||(e=this.element||document.getElementsByTagName("textarea")[0]),!this._rendered||this._rendered!==e){this.element=e;var t,i,o=this.options,r=this,s={};for(var l in o.shortcuts)null!==o.shortcuts[l]&&null!==c[l]&&function(e){s[p(o.shortcuts[e])]=function(){var t=c[e];"function"==typeof t?t(r):"string"==typeof t&&window.open(t,"_blank")}}(l);if(s.Enter="newlineAndIndentContinueMarkdownList",s.Tab="tabAndIndentMarkdownList",s["Shift-Tab"]="shiftTabAndUnindentMarkdownList",s.Esc=function(e){e.getOption("fullScreen")&&b(r)},document.addEventListener("keydown",(function(e){27==(e=e||window.event).keyCode&&r.codemirror.getOption("fullScreen")&&b(r)}),!1),!1!==o.spellChecker?(t="spell-checker",(i=o.parsingConfig).name="gfm",i.gitHubSpice=!1,a({codeMirrorInstance:n})):((t=o.parsingConfig).name="gfm",t.gitHubSpice=!1),this.codemirror=n.fromTextArea(e,{mode:t,backdrop:i,theme:null!=o.theme?o.theme:"easymde",tabSize:null!=o.tabSize?o.tabSize:2,indentUnit:null!=o.tabSize?o.tabSize:2,indentWithTabs:!1!==o.indentWithTabs,lineNumbers:!1,autofocus:!0===o.autofocus,extraKeys:s,lineWrapping:!1!==o.lineWrapping,allowDropFileTypes:["text/plain"],placeholder:o.placeholder||e.getAttribute("placeholder")||"",styleSelectedText:null!=o.styleSelectedText?o.styleSelectedText:!u(),configureMouse:function(e,t,i){return{addNew:!1}},inputStyle:null!=o.inputStyle?o.inputStyle:u()?"contenteditable":"textarea",spellcheck:null==o.nativeSpellcheck||o.nativeSpellcheck}),this.codemirror.getScrollerElement().style.minHeight=o.minHeight,void 0!==o.maxHeight&&(this.codemirror.getScrollerElement().style.height=o.maxHeight),!0===o.forceSync){var d=this.codemirror;d.on("change",(function(){d.save()}))}this.gui={};var g=document.createElement("div");g.classList.add("EasyMDEContainer");var m=this.codemirror.getWrapperElement();m.parentNode.insertBefore(g,m),g.appendChild(m),!1!==o.toolbar&&(this.gui.toolbar=this.createToolbar()),!1!==o.status&&(this.gui.statusbar=this.createStatusbar()),null!=o.autosave&&!0===o.autosave.enabled&&(this.autosave(),this.codemirror.on("change",(function(){clearTimeout(r._autosave_timeout),r._autosave_timeout=setTimeout((function(){r.autosave()}),r.options.autosave.submit_delay||r.options.autosave.delay||1e3)}))),this.gui.sideBySide=this.createSideBySide(),this._rendered=this.element;var f=this.codemirror;setTimeout(function(){f.refresh()}.bind(f),0)}},ie.prototype.autosave=function(){if(oe()){var e=this;if(null==this.options.autosave.uniqueId||""==this.options.autosave.uniqueId)return;!0!==this.options.autosave.binded&&(null!=e.element.form&&null!=e.element.form&&e.element.form.addEventListener("submit",(function(){clearTimeout(e.autosaveTimeoutId),e.autosaveTimeoutId=void 0,localStorage.removeItem("smde_"+e.options.autosave.uniqueId)})),this.options.autosave.binded=!0),!0!==this.options.autosave.loaded&&("string"==typeof localStorage.getItem("smde_"+this.options.autosave.uniqueId)&&""!=localStorage.getItem("smde_"+this.options.autosave.uniqueId)&&(this.codemirror.setValue(localStorage.getItem("smde_"+this.options.autosave.uniqueId)),this.options.autosave.foundSavedValue=!0),this.options.autosave.loaded=!0);var t=e.value();""!==t?localStorage.setItem("smde_"+this.options.autosave.uniqueId,t):localStorage.removeItem("smde_"+this.options.autosave.uniqueId);var i=document.getElementById("autosaved");if(null!=i&&null!=i&&""!=i){var o=new Date,n=new Intl.DateTimeFormat([this.options.autosave.timeFormat.locale,"en-US"],this.options.autosave.timeFormat.format).format(o),a=null==this.options.autosave.text?"Autosaved: ":this.options.autosave.text;i.innerHTML=a+n}}},ie.prototype.clearAutosavedValue=function(){if(oe()){if(null==this.options.autosave||null==this.options.autosave.uniqueId||""==this.options.autosave.uniqueId)return;localStorage.removeItem("smde_"+this.options.autosave.uniqueId)}},ie.prototype.openBrowseFileWindow=function(e,t){var i=this,o=this.gui.toolbar.getElementsByClassName("imageInput")[0];o.click(),o.addEventListener("change",(function n(a){i.options.imageUploadFunction?i.uploadImagesUsingCustomFunction(i.options.imageUploadFunction,a.target.files):i.uploadImages(a.target.files,e,t),o.removeEventListener("change",n)}))},ie.prototype.uploadImage=function(e,t,i){var o=this;function n(e){o.updateStatusBar("upload-image",e),setTimeout((function(){o.updateStatusBar("upload-image",o.options.imageTexts.sbInit)}),1e4),i&&"function"==typeof i&&i(e),o.options.errorCallback(e)}function a(t){var i=o.options.imageTexts.sizeUnits.split(",");return t.replace("#image_name#",e.name).replace("#image_size#",V(e.size,i)).replace("#image_max_size#",V(o.options.imageMaxSize,i))}if(t=t||function(e){M(o,e)},e.size>this.options.imageMaxSize)n(a(this.options.errorMessages.fileTooLarge));else{var r=new FormData;r.append("image",e),o.options.imageCSRFToken&&r.append("_token",o.options.imageCSRFToken);var s=new XMLHttpRequest;s.upload.onprogress=function(t){if(t.lengthComputable){var i=""+Math.round(100*t.loaded/t.total);o.updateStatusBar("upload-image",o.options.imageTexts.sbProgress.replace("#file_name#",e.name).replace("#progress#",i))}},s.open("POST",this.options.imageUploadEndpoint),s.onload=function(){try{var e=JSON.parse(this.responseText)}catch(e){return void n(a(o.options.errorMessages.importError))}200===this.status&&e&&!e.error&&e.data&&e.data.filePath?t(window.location.origin+"/"+e.data.filePath):e.error&&e.error in o.options.errorMessages?n(a(o.options.errorMessages[e.error])):e.error?n(a(e.error)):n(a(o.options.errorMessages.importError))},s.onerror=function(e){n(o.options.errorMessages.importError)},s.send(r)}},ie.prototype.uploadImageUsingCustomFunction=function(e,t){var i=this;e(t,(function(e){M(i,e)}),(function(e){var o=function(e){var o=i.options.imageTexts.sizeUnits.split(",");return e.replace("#image_name#",t.name).replace("#image_size#",V(t.size,o)).replace("#image_max_size#",V(i.options.imageMaxSize,o))}(e);i.updateStatusBar("upload-image",o),setTimeout((function(){i.updateStatusBar("upload-image",i.options.imageTexts.sbInit)}),1e4),i.options.errorCallback(o)}))},ie.prototype.setPreviewMaxHeight=function(){var e=this.codemirror.getWrapperElement(),t=e.nextSibling,i=parseInt(window.getComputedStyle(e).paddingTop),o=parseInt(window.getComputedStyle(e).borderTopWidth),n=(parseInt(this.options.maxHeight)+2*i+2*o).toString()+"px";t.style.height=n},ie.prototype.createSideBySide=function(){var e=this.codemirror,t=e.getWrapperElement(),i=t.nextSibling;if(!i||!/editor-preview-side/.test(i.className)){if((i=document.createElement("div")).className="editor-preview-side",this.options.previewClass)if(Array.isArray(this.options.previewClass))for(var o=0;o span::selection, 474 | .CodeMirror-line > span > span::selection { 475 | background: #d7d4f0; 476 | } 477 | 478 | .CodeMirror-line::-moz-selection, 479 | .CodeMirror-line > span::-moz-selection, 480 | .CodeMirror-line > span > span::-moz-selection { 481 | background: #d7d4f0; 482 | } 483 | 484 | .cm-searching { 485 | background-color: #ffa; 486 | background-color: rgba(255, 255, 0, 0.4); 487 | } 488 | 489 | .cm-force-border { 490 | padding-right: 0.1px; 491 | } 492 | 493 | @media print { 494 | .CodeMirror div.CodeMirror-cursors { 495 | visibility: hidden; 496 | } 497 | } 498 | 499 | .cm-tab-wrap-hack::after { 500 | content: ""; 501 | } 502 | 503 | span.CodeMirror-selectedtext { 504 | background: 0 0; 505 | } 506 | 507 | .CodeMirror { 508 | @apply px-2; 509 | 510 | box-sizing: border-box; 511 | height: auto; 512 | border: 1px solid theme("colors.gray.400"); 513 | border-bottom-left-radius: 4px; 514 | border-bottom-right-radius: 4px; 515 | 516 | /* padding: 10px; */ 517 | 518 | /* font: inherit; */ 519 | z-index: 1; 520 | word-wrap: break-word; 521 | } 522 | 523 | .CodeMirror-scroll { 524 | cursor: text; 525 | } 526 | 527 | .CodeMirror-fullscreen { 528 | background: #fff; 529 | position: fixed !important; 530 | top: 50px; 531 | left: 0; 532 | right: 0; 533 | bottom: 0; 534 | height: auto; 535 | z-index: 9; 536 | border-right: none !important; 537 | border-bottom-right-radius: 0 !important; 538 | } 539 | 540 | .CodeMirror-sided { 541 | width: 50% !important; 542 | } 543 | 544 | .CodeMirror-placeholder { 545 | opacity: 0.5; 546 | } 547 | 548 | .CodeMirror-focused .CodeMirror-selected { 549 | background: #d9d9d9; 550 | } 551 | 552 | .editor-toolbar { 553 | position: relative; 554 | -webkit-user-select: none; 555 | -moz-user-select: none; 556 | -ms-user-select: none; 557 | -o-user-select: none; 558 | user-select: none; 559 | padding: 0 10px; 560 | border-top: 1px solid theme("colors.gray.400"); 561 | border-left: 1px solid theme("colors.gray.400"); 562 | border-right: 1px solid theme("colors.gray.400"); 563 | border-top-left-radius: 4px; 564 | border-top-right-radius: 4px; 565 | } 566 | 567 | .editor-toolbar::after, 568 | .editor-toolbar::before { 569 | display: block; 570 | content: " "; 571 | height: 1px; 572 | } 573 | 574 | .editor-toolbar::before { 575 | margin-bottom: 8px; 576 | } 577 | 578 | .editor-toolbar::after { 579 | margin-top: 8px; 580 | } 581 | 582 | .editor-toolbar.fullscreen { 583 | width: 100%; 584 | height: 50px; 585 | overflow-x: auto; 586 | overflow-y: hidden; 587 | white-space: nowrap; 588 | padding-top: 10px; 589 | padding-bottom: 10px; 590 | box-sizing: border-box; 591 | border: 0; 592 | position: fixed; 593 | top: 0; 594 | left: 0; 595 | opacity: 1; 596 | z-index: 9; 597 | } 598 | 599 | .editor-toolbar.fullscreen::before { 600 | width: 20px; 601 | height: 50px; 602 | background: 603 | -moz-linear-gradient( 604 | left, 605 | rgba(255, 255, 255, 1) 0, 606 | rgba(255, 255, 255, 0) 100% 607 | ); 608 | background: 609 | -webkit-gradient( 610 | linear, 611 | left top, 612 | right top, 613 | color-stop(0, rgba(255, 255, 255, 1)), 614 | color-stop(100%, rgba(255, 255, 255, 0)) 615 | ); 616 | background: 617 | -webkit-linear-gradient( 618 | left, 619 | rgba(255, 255, 255, 1) 0, 620 | rgba(255, 255, 255, 0) 100% 621 | ); 622 | background: 623 | -o-linear-gradient( 624 | left, 625 | rgba(255, 255, 255, 1) 0, 626 | rgba(255, 255, 255, 0) 100% 627 | ); 628 | background: 629 | -ms-linear-gradient( 630 | left, 631 | rgba(255, 255, 255, 1) 0, 632 | rgba(255, 255, 255, 0) 100% 633 | ); 634 | background: 635 | linear-gradient( 636 | to right, 637 | rgba(255, 255, 255, 1) 0, 638 | rgba(255, 255, 255, 0) 100% 639 | ); 640 | position: fixed; 641 | top: 0; 642 | left: 0; 643 | margin: 0; 644 | padding: 0; 645 | } 646 | 647 | .editor-toolbar.fullscreen::after { 648 | width: 20px; 649 | height: 50px; 650 | background: 651 | -moz-linear-gradient( 652 | left, 653 | rgba(255, 255, 255, 0) 0, 654 | rgba(255, 255, 255, 1) 100% 655 | ); 656 | background: 657 | -webkit-gradient( 658 | linear, 659 | left top, 660 | right top, 661 | color-stop(0, rgba(255, 255, 255, 0)), 662 | color-stop(100%, rgba(255, 255, 255, 1)) 663 | ); 664 | background: 665 | -webkit-linear-gradient( 666 | left, 667 | rgba(255, 255, 255, 0) 0, 668 | rgba(255, 255, 255, 1) 100% 669 | ); 670 | background: 671 | -o-linear-gradient( 672 | left, 673 | rgba(255, 255, 255, 0) 0, 674 | rgba(255, 255, 255, 1) 100% 675 | ); 676 | background: 677 | -ms-linear-gradient( 678 | left, 679 | rgba(255, 255, 255, 0) 0, 680 | rgba(255, 255, 255, 1) 100% 681 | ); 682 | background: 683 | linear-gradient( 684 | to right, 685 | rgba(255, 255, 255, 0) 0, 686 | rgba(255, 255, 255, 1) 100% 687 | ); 688 | position: fixed; 689 | top: 0; 690 | right: 0; 691 | margin: 0; 692 | padding: 0; 693 | } 694 | 695 | .editor-toolbar button { 696 | background: 0 0; 697 | display: inline-block; 698 | text-align: center; 699 | text-decoration: none !important; 700 | width: 30px; 701 | height: 30px; 702 | margin: 0; 703 | padding: 0; 704 | border: 1px solid transparent; 705 | border-radius: 3px; 706 | cursor: pointer; 707 | } 708 | 709 | .editor-toolbar button.active, 710 | .editor-toolbar button:hover { 711 | background: #fcfcfc; 712 | border-color: #95a5a6; 713 | } 714 | 715 | .editor-toolbar i.separator { 716 | display: inline-block; 717 | width: 0; 718 | border-left: 1px solid #d9d9d9; 719 | border-right: 1px solid #fff; 720 | color: transparent; 721 | text-indent: -10px; 722 | margin: 0 6px; 723 | } 724 | 725 | .editor-toolbar button::after { 726 | font-family: Arial, "Helvetica Neue", Helvetica, sans-serif; 727 | font-size: 65%; 728 | vertical-align: text-bottom; 729 | position: relative; 730 | top: 2px; 731 | } 732 | 733 | .editor-toolbar button.heading-1::after { 734 | content: "1"; 735 | } 736 | 737 | .editor-toolbar button.heading-2::after { 738 | content: "2"; 739 | } 740 | 741 | .editor-toolbar button.heading-3::after { 742 | content: "3"; 743 | } 744 | 745 | .editor-toolbar button.heading-bigger::after { 746 | content: "▲"; 747 | } 748 | 749 | .editor-toolbar button.heading-smaller::after { 750 | content: "▼"; 751 | } 752 | 753 | .editor-toolbar.disabled-for-preview button:not(.no-disable) { 754 | opacity: 0.6; 755 | pointer-events: none; 756 | } 757 | 758 | @media only screen and (max-width: 700px) { 759 | .editor-toolbar i.no-mobile { 760 | display: none; 761 | } 762 | } 763 | 764 | .editor-statusbar { 765 | padding: 8px 10px; 766 | font-size: 12px; 767 | color: #959694; 768 | text-align: right; 769 | } 770 | 771 | .editor-statusbar span { 772 | display: inline-block; 773 | min-width: 4em; 774 | margin-left: 1em; 775 | } 776 | 777 | .editor-statusbar .lines::before { 778 | content: "lines: "; 779 | } 780 | 781 | .editor-statusbar .words::before { 782 | content: "words: "; 783 | } 784 | 785 | .editor-statusbar .characters::before { 786 | content: "characters: "; 787 | } 788 | 789 | .editor-preview-full { 790 | position: absolute; 791 | width: 100%; 792 | height: 100%; 793 | top: 0; 794 | left: 0; 795 | z-index: 7; 796 | overflow: auto; 797 | display: none; 798 | box-sizing: border-box; 799 | } 800 | 801 | .editor-preview-side { 802 | position: fixed; 803 | bottom: 0; 804 | width: 50%; 805 | top: 50px; 806 | right: 0; 807 | z-index: 9; 808 | overflow: auto; 809 | display: none; 810 | box-sizing: border-box; 811 | border: 1px solid #ddd; 812 | word-wrap: break-word; 813 | } 814 | 815 | .editor-preview-active-side { 816 | display: block; 817 | } 818 | 819 | .editor-preview-active { 820 | display: block; 821 | } 822 | 823 | .editor-preview { 824 | padding: 10px; 825 | background: #fafafa; 826 | } 827 | 828 | .editor-preview > p { 829 | margin-top: 0; 830 | } 831 | 832 | .editor-preview pre { 833 | background: #eee; 834 | margin-bottom: 10px; 835 | } 836 | 837 | .editor-preview table td, 838 | .editor-preview table th { 839 | border: 1px solid #ddd; 840 | padding: 5px; 841 | } 842 | 843 | .cm-s-easymde .cm-image-marker { 844 | @apply text-gray-500; 845 | } 846 | 847 | .cm-s-easymde .cm-tag { 848 | color: #63a35c; 849 | } 850 | 851 | .cm-s-easymde .cm-attribute { 852 | color: #795da3; 853 | } 854 | 855 | .cm-s-easymde .cm-string { 856 | color: #183691; 857 | } 858 | 859 | .cm-s-easymde .cm-header { 860 | @apply text-gray-900; 861 | 862 | line-height: 3em; 863 | } 864 | 865 | /* .cm-s-easymde .cm-header-1 { 866 | font-size: 200%; 867 | line-height: 2em; 868 | } 869 | 870 | .cm-s-easymde .cm-header-2 { 871 | font-size: 160%; 872 | line-height: 160%; 873 | } 874 | 875 | .cm-s-easymde .cm-header-3 { 876 | font-size: 125%; 877 | line-height: 125%; 878 | } 879 | 880 | .cm-s-easymde .cm-header-4 { 881 | font-size: 110%; 882 | line-height: 110%; 883 | } */ 884 | 885 | .cm-s-easymde .cm-comment { 886 | /* background: rgba(0, 0, 0, 0.05); */ 887 | 888 | /* border-radius: 2px; */ 889 | 890 | /* line-height: 2; */ 891 | } 892 | 893 | .cm-s-easymde .cm-link { 894 | @apply text-blue-500; 895 | } 896 | 897 | .cm-s-easymde .cm-image-alt-text { 898 | @apply text-gray-800; 899 | } 900 | 901 | .cm-s-easymde .cm-url { 902 | @apply text-gray-500; 903 | } 904 | 905 | .cm-s-easymde .cm-quote { 906 | @apply text-gray-800; 907 | 908 | font-style: italic; 909 | } 910 | 911 | .CodeMirror .cm-spell-error:not(.cm-url):not(.cm-comment):not(.cm-tag):not(.cm-word) { 912 | background: rgba(255, 0, 0, 0.15); 913 | } 914 | 915 | /* outline for webkit */ 916 | .CodeMirror-focused { 917 | outline-width: 2px; 918 | outline-style: solid; 919 | outline-color: Highlight; 920 | } 921 | 922 | @media (-webkit-min-device-pixel-ratio: 0) { 923 | .CodeMirror-focused { 924 | outline: -webkit-focus-ring-color auto 3px; 925 | } 926 | } 927 | -------------------------------------------------------------------------------- /resources/css/vendor/fontawesome.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome 3 | * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) 4 | */ 5 | /* FONT PATH 6 | * -------------------------- */ 7 | @font-face { 8 | font-family: 'FontAwesome'; 9 | src: url('fonts/fontawesome-webfont.eot?v=4.7.0'); 10 | src: url('fonts/fontawesome-webfont.eot?#iefix&v=4.7.0') format('embedded-opentype'), url('fonts/fontawesome-webfont.woff2?v=4.7.0') format('woff2'), url('fonts/fontawesome-webfont.woff?v=4.7.0') format('woff'), url('fonts/fontawesome-webfont.ttf?v=4.7.0') format('truetype'), url('fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular') format('svg'); 11 | font-weight: normal; 12 | font-style: normal; 13 | } 14 | .fa { 15 | display: inline-block; 16 | font: normal normal normal 14px/1 FontAwesome; 17 | font-size: inherit; 18 | text-rendering: auto; 19 | -webkit-font-smoothing: antialiased; 20 | -moz-osx-font-smoothing: grayscale; 21 | } 22 | /* makes the font 33% larger relative to the icon container */ 23 | .fa-lg { 24 | font-size: 1.33333333em; 25 | line-height: 0.75em; 26 | vertical-align: -15%; 27 | } 28 | .fa-2x { 29 | font-size: 2em; 30 | } 31 | .fa-3x { 32 | font-size: 3em; 33 | } 34 | .fa-4x { 35 | font-size: 4em; 36 | } 37 | .fa-5x { 38 | font-size: 5em; 39 | } 40 | .fa-fw { 41 | width: 1.28571429em; 42 | text-align: center; 43 | } 44 | .fa-ul { 45 | padding-left: 0; 46 | margin-left: 2.14285714em; 47 | list-style-type: none; 48 | } 49 | .fa-ul > li { 50 | position: relative; 51 | } 52 | .fa-li { 53 | position: absolute; 54 | left: -2.14285714em; 55 | width: 2.14285714em; 56 | top: 0.14285714em; 57 | text-align: center; 58 | } 59 | .fa-li.fa-lg { 60 | left: -1.85714286em; 61 | } 62 | .fa-border { 63 | padding: .2em .25em .15em; 64 | border: solid 0.08em #eeeeee; 65 | border-radius: .1em; 66 | } 67 | .fa-pull-left { 68 | float: left; 69 | } 70 | .fa-pull-right { 71 | float: right; 72 | } 73 | .fa.fa-pull-left { 74 | margin-right: .3em; 75 | } 76 | .fa.fa-pull-right { 77 | margin-left: .3em; 78 | } 79 | /* Deprecated as of 4.4.0 */ 80 | .pull-right { 81 | float: right; 82 | } 83 | .pull-left { 84 | float: left; 85 | } 86 | .fa.pull-left { 87 | margin-right: .3em; 88 | } 89 | .fa.pull-right { 90 | margin-left: .3em; 91 | } 92 | .fa-spin { 93 | -webkit-animation: fa-spin 2s infinite linear; 94 | animation: fa-spin 2s infinite linear; 95 | } 96 | .fa-pulse { 97 | -webkit-animation: fa-spin 1s infinite steps(8); 98 | animation: fa-spin 1s infinite steps(8); 99 | } 100 | @-webkit-keyframes fa-spin { 101 | 0% { 102 | -webkit-transform: rotate(0deg); 103 | transform: rotate(0deg); 104 | } 105 | 100% { 106 | -webkit-transform: rotate(359deg); 107 | transform: rotate(359deg); 108 | } 109 | } 110 | @keyframes fa-spin { 111 | 0% { 112 | -webkit-transform: rotate(0deg); 113 | transform: rotate(0deg); 114 | } 115 | 100% { 116 | -webkit-transform: rotate(359deg); 117 | transform: rotate(359deg); 118 | } 119 | } 120 | .fa-rotate-90 { 121 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=1)"; 122 | -webkit-transform: rotate(90deg); 123 | -ms-transform: rotate(90deg); 124 | transform: rotate(90deg); 125 | } 126 | .fa-rotate-180 { 127 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2)"; 128 | -webkit-transform: rotate(180deg); 129 | -ms-transform: rotate(180deg); 130 | transform: rotate(180deg); 131 | } 132 | .fa-rotate-270 { 133 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=3)"; 134 | -webkit-transform: rotate(270deg); 135 | -ms-transform: rotate(270deg); 136 | transform: rotate(270deg); 137 | } 138 | .fa-flip-horizontal { 139 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)"; 140 | -webkit-transform: scale(-1, 1); 141 | -ms-transform: scale(-1, 1); 142 | transform: scale(-1, 1); 143 | } 144 | .fa-flip-vertical { 145 | -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"; 146 | -webkit-transform: scale(1, -1); 147 | -ms-transform: scale(1, -1); 148 | transform: scale(1, -1); 149 | } 150 | :root .fa-rotate-90, 151 | :root .fa-rotate-180, 152 | :root .fa-rotate-270, 153 | :root .fa-flip-horizontal, 154 | :root .fa-flip-vertical { 155 | filter: none; 156 | } 157 | .fa-stack { 158 | position: relative; 159 | display: inline-block; 160 | width: 2em; 161 | height: 2em; 162 | line-height: 2em; 163 | vertical-align: middle; 164 | } 165 | .fa-stack-1x, 166 | .fa-stack-2x { 167 | position: absolute; 168 | left: 0; 169 | width: 100%; 170 | text-align: center; 171 | } 172 | .fa-stack-1x { 173 | line-height: inherit; 174 | } 175 | .fa-stack-2x { 176 | font-size: 2em; 177 | } 178 | .fa-inverse { 179 | color: #ffffff; 180 | } 181 | /* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen 182 | readers do not read off random characters that represent icons */ 183 | .fa-glass:before { 184 | content: "\f000"; 185 | } 186 | .fa-music:before { 187 | content: "\f001"; 188 | } 189 | .fa-search:before { 190 | content: "\f002"; 191 | } 192 | .fa-envelope-o:before { 193 | content: "\f003"; 194 | } 195 | .fa-heart:before { 196 | content: "\f004"; 197 | } 198 | .fa-star:before { 199 | content: "\f005"; 200 | } 201 | .fa-star-o:before { 202 | content: "\f006"; 203 | } 204 | .fa-user:before { 205 | content: "\f007"; 206 | } 207 | .fa-film:before { 208 | content: "\f008"; 209 | } 210 | .fa-th-large:before { 211 | content: "\f009"; 212 | } 213 | .fa-th:before { 214 | content: "\f00a"; 215 | } 216 | .fa-th-list:before { 217 | content: "\f00b"; 218 | } 219 | .fa-check:before { 220 | content: "\f00c"; 221 | } 222 | .fa-remove:before, 223 | .fa-close:before, 224 | .fa-times:before { 225 | content: "\f00d"; 226 | } 227 | .fa-search-plus:before { 228 | content: "\f00e"; 229 | } 230 | .fa-search-minus:before { 231 | content: "\f010"; 232 | } 233 | .fa-power-off:before { 234 | content: "\f011"; 235 | } 236 | .fa-signal:before { 237 | content: "\f012"; 238 | } 239 | .fa-gear:before, 240 | .fa-cog:before { 241 | content: "\f013"; 242 | } 243 | .fa-trash-o:before { 244 | content: "\f014"; 245 | } 246 | .fa-home:before { 247 | content: "\f015"; 248 | } 249 | .fa-file-o:before { 250 | content: "\f016"; 251 | } 252 | .fa-clock-o:before { 253 | content: "\f017"; 254 | } 255 | .fa-road:before { 256 | content: "\f018"; 257 | } 258 | .fa-download:before { 259 | content: "\f019"; 260 | } 261 | .fa-arrow-circle-o-down:before { 262 | content: "\f01a"; 263 | } 264 | .fa-arrow-circle-o-up:before { 265 | content: "\f01b"; 266 | } 267 | .fa-inbox:before { 268 | content: "\f01c"; 269 | } 270 | .fa-play-circle-o:before { 271 | content: "\f01d"; 272 | } 273 | .fa-rotate-right:before, 274 | .fa-repeat:before { 275 | content: "\f01e"; 276 | } 277 | .fa-refresh:before { 278 | content: "\f021"; 279 | } 280 | .fa-list-alt:before { 281 | content: "\f022"; 282 | } 283 | .fa-lock:before { 284 | content: "\f023"; 285 | } 286 | .fa-flag:before { 287 | content: "\f024"; 288 | } 289 | .fa-headphones:before { 290 | content: "\f025"; 291 | } 292 | .fa-volume-off:before { 293 | content: "\f026"; 294 | } 295 | .fa-volume-down:before { 296 | content: "\f027"; 297 | } 298 | .fa-volume-up:before { 299 | content: "\f028"; 300 | } 301 | .fa-qrcode:before { 302 | content: "\f029"; 303 | } 304 | .fa-barcode:before { 305 | content: "\f02a"; 306 | } 307 | .fa-tag:before { 308 | content: "\f02b"; 309 | } 310 | .fa-tags:before { 311 | content: "\f02c"; 312 | } 313 | .fa-book:before { 314 | content: "\f02d"; 315 | } 316 | .fa-bookmark:before { 317 | content: "\f02e"; 318 | } 319 | .fa-print:before { 320 | content: "\f02f"; 321 | } 322 | .fa-camera:before { 323 | content: "\f030"; 324 | } 325 | .fa-font:before { 326 | content: "\f031"; 327 | } 328 | .fa-bold:before { 329 | content: "\f032"; 330 | } 331 | .fa-italic:before { 332 | content: "\f033"; 333 | } 334 | .fa-text-height:before { 335 | content: "\f034"; 336 | } 337 | .fa-text-width:before { 338 | content: "\f035"; 339 | } 340 | .fa-align-left:before { 341 | content: "\f036"; 342 | } 343 | .fa-align-center:before { 344 | content: "\f037"; 345 | } 346 | .fa-align-right:before { 347 | content: "\f038"; 348 | } 349 | .fa-align-justify:before { 350 | content: "\f039"; 351 | } 352 | .fa-list:before { 353 | content: "\f03a"; 354 | } 355 | .fa-dedent:before, 356 | .fa-outdent:before { 357 | content: "\f03b"; 358 | } 359 | .fa-indent:before { 360 | content: "\f03c"; 361 | } 362 | .fa-video-camera:before { 363 | content: "\f03d"; 364 | } 365 | .fa-photo:before, 366 | .fa-image:before, 367 | .fa-picture-o:before { 368 | content: "\f03e"; 369 | } 370 | .fa-pencil:before { 371 | content: "\f040"; 372 | } 373 | .fa-map-marker:before { 374 | content: "\f041"; 375 | } 376 | .fa-adjust:before { 377 | content: "\f042"; 378 | } 379 | .fa-tint:before { 380 | content: "\f043"; 381 | } 382 | .fa-edit:before, 383 | .fa-pencil-square-o:before { 384 | content: "\f044"; 385 | } 386 | .fa-share-square-o:before { 387 | content: "\f045"; 388 | } 389 | .fa-check-square-o:before { 390 | content: "\f046"; 391 | } 392 | .fa-arrows:before { 393 | content: "\f047"; 394 | } 395 | .fa-step-backward:before { 396 | content: "\f048"; 397 | } 398 | .fa-fast-backward:before { 399 | content: "\f049"; 400 | } 401 | .fa-backward:before { 402 | content: "\f04a"; 403 | } 404 | .fa-play:before { 405 | content: "\f04b"; 406 | } 407 | .fa-pause:before { 408 | content: "\f04c"; 409 | } 410 | .fa-stop:before { 411 | content: "\f04d"; 412 | } 413 | .fa-forward:before { 414 | content: "\f04e"; 415 | } 416 | .fa-fast-forward:before { 417 | content: "\f050"; 418 | } 419 | .fa-step-forward:before { 420 | content: "\f051"; 421 | } 422 | .fa-eject:before { 423 | content: "\f052"; 424 | } 425 | .fa-chevron-left:before { 426 | content: "\f053"; 427 | } 428 | .fa-chevron-right:before { 429 | content: "\f054"; 430 | } 431 | .fa-plus-circle:before { 432 | content: "\f055"; 433 | } 434 | .fa-minus-circle:before { 435 | content: "\f056"; 436 | } 437 | .fa-times-circle:before { 438 | content: "\f057"; 439 | } 440 | .fa-check-circle:before { 441 | content: "\f058"; 442 | } 443 | .fa-question-circle:before { 444 | content: "\f059"; 445 | } 446 | .fa-info-circle:before { 447 | content: "\f05a"; 448 | } 449 | .fa-crosshairs:before { 450 | content: "\f05b"; 451 | } 452 | .fa-times-circle-o:before { 453 | content: "\f05c"; 454 | } 455 | .fa-check-circle-o:before { 456 | content: "\f05d"; 457 | } 458 | .fa-ban:before { 459 | content: "\f05e"; 460 | } 461 | .fa-arrow-left:before { 462 | content: "\f060"; 463 | } 464 | .fa-arrow-right:before { 465 | content: "\f061"; 466 | } 467 | .fa-arrow-up:before { 468 | content: "\f062"; 469 | } 470 | .fa-arrow-down:before { 471 | content: "\f063"; 472 | } 473 | .fa-mail-forward:before, 474 | .fa-share:before { 475 | content: "\f064"; 476 | } 477 | .fa-expand:before { 478 | content: "\f065"; 479 | } 480 | .fa-compress:before { 481 | content: "\f066"; 482 | } 483 | .fa-plus:before { 484 | content: "\f067"; 485 | } 486 | .fa-minus:before { 487 | content: "\f068"; 488 | } 489 | .fa-asterisk:before { 490 | content: "\f069"; 491 | } 492 | .fa-exclamation-circle:before { 493 | content: "\f06a"; 494 | } 495 | .fa-gift:before { 496 | content: "\f06b"; 497 | } 498 | .fa-leaf:before { 499 | content: "\f06c"; 500 | } 501 | .fa-fire:before { 502 | content: "\f06d"; 503 | } 504 | .fa-eye:before { 505 | content: "\f06e"; 506 | } 507 | .fa-eye-slash:before { 508 | content: "\f070"; 509 | } 510 | .fa-warning:before, 511 | .fa-exclamation-triangle:before { 512 | content: "\f071"; 513 | } 514 | .fa-plane:before { 515 | content: "\f072"; 516 | } 517 | .fa-calendar:before { 518 | content: "\f073"; 519 | } 520 | .fa-random:before { 521 | content: "\f074"; 522 | } 523 | .fa-comment:before { 524 | content: "\f075"; 525 | } 526 | .fa-magnet:before { 527 | content: "\f076"; 528 | } 529 | .fa-chevron-up:before { 530 | content: "\f077"; 531 | } 532 | .fa-chevron-down:before { 533 | content: "\f078"; 534 | } 535 | .fa-retweet:before { 536 | content: "\f079"; 537 | } 538 | .fa-shopping-cart:before { 539 | content: "\f07a"; 540 | } 541 | .fa-folder:before { 542 | content: "\f07b"; 543 | } 544 | .fa-folder-open:before { 545 | content: "\f07c"; 546 | } 547 | .fa-arrows-v:before { 548 | content: "\f07d"; 549 | } 550 | .fa-arrows-h:before { 551 | content: "\f07e"; 552 | } 553 | .fa-bar-chart-o:before, 554 | .fa-bar-chart:before { 555 | content: "\f080"; 556 | } 557 | .fa-twitter-square:before { 558 | content: "\f081"; 559 | } 560 | .fa-facebook-square:before { 561 | content: "\f082"; 562 | } 563 | .fa-camera-retro:before { 564 | content: "\f083"; 565 | } 566 | .fa-key:before { 567 | content: "\f084"; 568 | } 569 | .fa-gears:before, 570 | .fa-cogs:before { 571 | content: "\f085"; 572 | } 573 | .fa-comments:before { 574 | content: "\f086"; 575 | } 576 | .fa-thumbs-o-up:before { 577 | content: "\f087"; 578 | } 579 | .fa-thumbs-o-down:before { 580 | content: "\f088"; 581 | } 582 | .fa-star-half:before { 583 | content: "\f089"; 584 | } 585 | .fa-heart-o:before { 586 | content: "\f08a"; 587 | } 588 | .fa-sign-out:before { 589 | content: "\f08b"; 590 | } 591 | .fa-linkedin-square:before { 592 | content: "\f08c"; 593 | } 594 | .fa-thumb-tack:before { 595 | content: "\f08d"; 596 | } 597 | .fa-external-link:before { 598 | content: "\f08e"; 599 | } 600 | .fa-sign-in:before { 601 | content: "\f090"; 602 | } 603 | .fa-trophy:before { 604 | content: "\f091"; 605 | } 606 | .fa-github-square:before { 607 | content: "\f092"; 608 | } 609 | .fa-upload:before { 610 | content: "\f093"; 611 | } 612 | .fa-lemon-o:before { 613 | content: "\f094"; 614 | } 615 | .fa-phone:before { 616 | content: "\f095"; 617 | } 618 | .fa-square-o:before { 619 | content: "\f096"; 620 | } 621 | .fa-bookmark-o:before { 622 | content: "\f097"; 623 | } 624 | .fa-phone-square:before { 625 | content: "\f098"; 626 | } 627 | .fa-twitter:before { 628 | content: "\f099"; 629 | } 630 | .fa-facebook-f:before, 631 | .fa-facebook:before { 632 | content: "\f09a"; 633 | } 634 | .fa-github:before { 635 | content: "\f09b"; 636 | } 637 | .fa-unlock:before { 638 | content: "\f09c"; 639 | } 640 | .fa-credit-card:before { 641 | content: "\f09d"; 642 | } 643 | .fa-feed:before, 644 | .fa-rss:before { 645 | content: "\f09e"; 646 | } 647 | .fa-hdd-o:before { 648 | content: "\f0a0"; 649 | } 650 | .fa-bullhorn:before { 651 | content: "\f0a1"; 652 | } 653 | .fa-bell:before { 654 | content: "\f0f3"; 655 | } 656 | .fa-certificate:before { 657 | content: "\f0a3"; 658 | } 659 | .fa-hand-o-right:before { 660 | content: "\f0a4"; 661 | } 662 | .fa-hand-o-left:before { 663 | content: "\f0a5"; 664 | } 665 | .fa-hand-o-up:before { 666 | content: "\f0a6"; 667 | } 668 | .fa-hand-o-down:before { 669 | content: "\f0a7"; 670 | } 671 | .fa-arrow-circle-left:before { 672 | content: "\f0a8"; 673 | } 674 | .fa-arrow-circle-right:before { 675 | content: "\f0a9"; 676 | } 677 | .fa-arrow-circle-up:before { 678 | content: "\f0aa"; 679 | } 680 | .fa-arrow-circle-down:before { 681 | content: "\f0ab"; 682 | } 683 | .fa-globe:before { 684 | content: "\f0ac"; 685 | } 686 | .fa-wrench:before { 687 | content: "\f0ad"; 688 | } 689 | .fa-tasks:before { 690 | content: "\f0ae"; 691 | } 692 | .fa-filter:before { 693 | content: "\f0b0"; 694 | } 695 | .fa-briefcase:before { 696 | content: "\f0b1"; 697 | } 698 | .fa-arrows-alt:before { 699 | content: "\f0b2"; 700 | } 701 | .fa-group:before, 702 | .fa-users:before { 703 | content: "\f0c0"; 704 | } 705 | .fa-chain:before, 706 | .fa-link:before { 707 | content: "\f0c1"; 708 | } 709 | .fa-cloud:before { 710 | content: "\f0c2"; 711 | } 712 | .fa-flask:before { 713 | content: "\f0c3"; 714 | } 715 | .fa-cut:before, 716 | .fa-scissors:before { 717 | content: "\f0c4"; 718 | } 719 | .fa-copy:before, 720 | .fa-files-o:before { 721 | content: "\f0c5"; 722 | } 723 | .fa-paperclip:before { 724 | content: "\f0c6"; 725 | } 726 | .fa-save:before, 727 | .fa-floppy-o:before { 728 | content: "\f0c7"; 729 | } 730 | .fa-square:before { 731 | content: "\f0c8"; 732 | } 733 | .fa-navicon:before, 734 | .fa-reorder:before, 735 | .fa-bars:before { 736 | content: "\f0c9"; 737 | } 738 | .fa-list-ul:before { 739 | content: "\f0ca"; 740 | } 741 | .fa-list-ol:before { 742 | content: "\f0cb"; 743 | } 744 | .fa-strikethrough:before { 745 | content: "\f0cc"; 746 | } 747 | .fa-underline:before { 748 | content: "\f0cd"; 749 | } 750 | .fa-table:before { 751 | content: "\f0ce"; 752 | } 753 | .fa-magic:before { 754 | content: "\f0d0"; 755 | } 756 | .fa-truck:before { 757 | content: "\f0d1"; 758 | } 759 | .fa-pinterest:before { 760 | content: "\f0d2"; 761 | } 762 | .fa-pinterest-square:before { 763 | content: "\f0d3"; 764 | } 765 | .fa-google-plus-square:before { 766 | content: "\f0d4"; 767 | } 768 | .fa-google-plus:before { 769 | content: "\f0d5"; 770 | } 771 | .fa-money:before { 772 | content: "\f0d6"; 773 | } 774 | .fa-caret-down:before { 775 | content: "\f0d7"; 776 | } 777 | .fa-caret-up:before { 778 | content: "\f0d8"; 779 | } 780 | .fa-caret-left:before { 781 | content: "\f0d9"; 782 | } 783 | .fa-caret-right:before { 784 | content: "\f0da"; 785 | } 786 | .fa-columns:before { 787 | content: "\f0db"; 788 | } 789 | .fa-unsorted:before, 790 | .fa-sort:before { 791 | content: "\f0dc"; 792 | } 793 | .fa-sort-down:before, 794 | .fa-sort-desc:before { 795 | content: "\f0dd"; 796 | } 797 | .fa-sort-up:before, 798 | .fa-sort-asc:before { 799 | content: "\f0de"; 800 | } 801 | .fa-envelope:before { 802 | content: "\f0e0"; 803 | } 804 | .fa-linkedin:before { 805 | content: "\f0e1"; 806 | } 807 | .fa-rotate-left:before, 808 | .fa-undo:before { 809 | content: "\f0e2"; 810 | } 811 | .fa-legal:before, 812 | .fa-gavel:before { 813 | content: "\f0e3"; 814 | } 815 | .fa-dashboard:before, 816 | .fa-tachometer:before { 817 | content: "\f0e4"; 818 | } 819 | .fa-comment-o:before { 820 | content: "\f0e5"; 821 | } 822 | .fa-comments-o:before { 823 | content: "\f0e6"; 824 | } 825 | .fa-flash:before, 826 | .fa-bolt:before { 827 | content: "\f0e7"; 828 | } 829 | .fa-sitemap:before { 830 | content: "\f0e8"; 831 | } 832 | .fa-umbrella:before { 833 | content: "\f0e9"; 834 | } 835 | .fa-paste:before, 836 | .fa-clipboard:before { 837 | content: "\f0ea"; 838 | } 839 | .fa-lightbulb-o:before { 840 | content: "\f0eb"; 841 | } 842 | .fa-exchange:before { 843 | content: "\f0ec"; 844 | } 845 | .fa-cloud-download:before { 846 | content: "\f0ed"; 847 | } 848 | .fa-cloud-upload:before { 849 | content: "\f0ee"; 850 | } 851 | .fa-user-md:before { 852 | content: "\f0f0"; 853 | } 854 | .fa-stethoscope:before { 855 | content: "\f0f1"; 856 | } 857 | .fa-suitcase:before { 858 | content: "\f0f2"; 859 | } 860 | .fa-bell-o:before { 861 | content: "\f0a2"; 862 | } 863 | .fa-coffee:before { 864 | content: "\f0f4"; 865 | } 866 | .fa-cutlery:before { 867 | content: "\f0f5"; 868 | } 869 | .fa-file-text-o:before { 870 | content: "\f0f6"; 871 | } 872 | .fa-building-o:before { 873 | content: "\f0f7"; 874 | } 875 | .fa-hospital-o:before { 876 | content: "\f0f8"; 877 | } 878 | .fa-ambulance:before { 879 | content: "\f0f9"; 880 | } 881 | .fa-medkit:before { 882 | content: "\f0fa"; 883 | } 884 | .fa-fighter-jet:before { 885 | content: "\f0fb"; 886 | } 887 | .fa-beer:before { 888 | content: "\f0fc"; 889 | } 890 | .fa-h-square:before { 891 | content: "\f0fd"; 892 | } 893 | .fa-plus-square:before { 894 | content: "\f0fe"; 895 | } 896 | .fa-angle-double-left:before { 897 | content: "\f100"; 898 | } 899 | .fa-angle-double-right:before { 900 | content: "\f101"; 901 | } 902 | .fa-angle-double-up:before { 903 | content: "\f102"; 904 | } 905 | .fa-angle-double-down:before { 906 | content: "\f103"; 907 | } 908 | .fa-angle-left:before { 909 | content: "\f104"; 910 | } 911 | .fa-angle-right:before { 912 | content: "\f105"; 913 | } 914 | .fa-angle-up:before { 915 | content: "\f106"; 916 | } 917 | .fa-angle-down:before { 918 | content: "\f107"; 919 | } 920 | .fa-desktop:before { 921 | content: "\f108"; 922 | } 923 | .fa-laptop:before { 924 | content: "\f109"; 925 | } 926 | .fa-tablet:before { 927 | content: "\f10a"; 928 | } 929 | .fa-mobile-phone:before, 930 | .fa-mobile:before { 931 | content: "\f10b"; 932 | } 933 | .fa-circle-o:before { 934 | content: "\f10c"; 935 | } 936 | .fa-quote-left:before { 937 | content: "\f10d"; 938 | } 939 | .fa-quote-right:before { 940 | content: "\f10e"; 941 | } 942 | .fa-spinner:before { 943 | content: "\f110"; 944 | } 945 | .fa-circle:before { 946 | content: "\f111"; 947 | } 948 | .fa-mail-reply:before, 949 | .fa-reply:before { 950 | content: "\f112"; 951 | } 952 | .fa-github-alt:before { 953 | content: "\f113"; 954 | } 955 | .fa-folder-o:before { 956 | content: "\f114"; 957 | } 958 | .fa-folder-open-o:before { 959 | content: "\f115"; 960 | } 961 | .fa-smile-o:before { 962 | content: "\f118"; 963 | } 964 | .fa-frown-o:before { 965 | content: "\f119"; 966 | } 967 | .fa-meh-o:before { 968 | content: "\f11a"; 969 | } 970 | .fa-gamepad:before { 971 | content: "\f11b"; 972 | } 973 | .fa-keyboard-o:before { 974 | content: "\f11c"; 975 | } 976 | .fa-flag-o:before { 977 | content: "\f11d"; 978 | } 979 | .fa-flag-checkered:before { 980 | content: "\f11e"; 981 | } 982 | .fa-terminal:before { 983 | content: "\f120"; 984 | } 985 | .fa-code:before { 986 | content: "\f121"; 987 | } 988 | .fa-mail-reply-all:before, 989 | .fa-reply-all:before { 990 | content: "\f122"; 991 | } 992 | .fa-star-half-empty:before, 993 | .fa-star-half-full:before, 994 | .fa-star-half-o:before { 995 | content: "\f123"; 996 | } 997 | .fa-location-arrow:before { 998 | content: "\f124"; 999 | } 1000 | .fa-crop:before { 1001 | content: "\f125"; 1002 | } 1003 | .fa-code-fork:before { 1004 | content: "\f126"; 1005 | } 1006 | .fa-unlink:before, 1007 | .fa-chain-broken:before { 1008 | content: "\f127"; 1009 | } 1010 | .fa-question:before { 1011 | content: "\f128"; 1012 | } 1013 | .fa-info:before { 1014 | content: "\f129"; 1015 | } 1016 | .fa-exclamation:before { 1017 | content: "\f12a"; 1018 | } 1019 | .fa-superscript:before { 1020 | content: "\f12b"; 1021 | } 1022 | .fa-subscript:before { 1023 | content: "\f12c"; 1024 | } 1025 | .fa-eraser:before { 1026 | content: "\f12d"; 1027 | } 1028 | .fa-puzzle-piece:before { 1029 | content: "\f12e"; 1030 | } 1031 | .fa-microphone:before { 1032 | content: "\f130"; 1033 | } 1034 | .fa-microphone-slash:before { 1035 | content: "\f131"; 1036 | } 1037 | .fa-shield:before { 1038 | content: "\f132"; 1039 | } 1040 | .fa-calendar-o:before { 1041 | content: "\f133"; 1042 | } 1043 | .fa-fire-extinguisher:before { 1044 | content: "\f134"; 1045 | } 1046 | .fa-rocket:before { 1047 | content: "\f135"; 1048 | } 1049 | .fa-maxcdn:before { 1050 | content: "\f136"; 1051 | } 1052 | .fa-chevron-circle-left:before { 1053 | content: "\f137"; 1054 | } 1055 | .fa-chevron-circle-right:before { 1056 | content: "\f138"; 1057 | } 1058 | .fa-chevron-circle-up:before { 1059 | content: "\f139"; 1060 | } 1061 | .fa-chevron-circle-down:before { 1062 | content: "\f13a"; 1063 | } 1064 | .fa-html5:before { 1065 | content: "\f13b"; 1066 | } 1067 | .fa-css3:before { 1068 | content: "\f13c"; 1069 | } 1070 | .fa-anchor:before { 1071 | content: "\f13d"; 1072 | } 1073 | .fa-unlock-alt:before { 1074 | content: "\f13e"; 1075 | } 1076 | .fa-bullseye:before { 1077 | content: "\f140"; 1078 | } 1079 | .fa-ellipsis-h:before { 1080 | content: "\f141"; 1081 | } 1082 | .fa-ellipsis-v:before { 1083 | content: "\f142"; 1084 | } 1085 | .fa-rss-square:before { 1086 | content: "\f143"; 1087 | } 1088 | .fa-play-circle:before { 1089 | content: "\f144"; 1090 | } 1091 | .fa-ticket:before { 1092 | content: "\f145"; 1093 | } 1094 | .fa-minus-square:before { 1095 | content: "\f146"; 1096 | } 1097 | .fa-minus-square-o:before { 1098 | content: "\f147"; 1099 | } 1100 | .fa-level-up:before { 1101 | content: "\f148"; 1102 | } 1103 | .fa-level-down:before { 1104 | content: "\f149"; 1105 | } 1106 | .fa-check-square:before { 1107 | content: "\f14a"; 1108 | } 1109 | .fa-pencil-square:before { 1110 | content: "\f14b"; 1111 | } 1112 | .fa-external-link-square:before { 1113 | content: "\f14c"; 1114 | } 1115 | .fa-share-square:before { 1116 | content: "\f14d"; 1117 | } 1118 | .fa-compass:before { 1119 | content: "\f14e"; 1120 | } 1121 | .fa-toggle-down:before, 1122 | .fa-caret-square-o-down:before { 1123 | content: "\f150"; 1124 | } 1125 | .fa-toggle-up:before, 1126 | .fa-caret-square-o-up:before { 1127 | content: "\f151"; 1128 | } 1129 | .fa-toggle-right:before, 1130 | .fa-caret-square-o-right:before { 1131 | content: "\f152"; 1132 | } 1133 | .fa-euro:before, 1134 | .fa-eur:before { 1135 | content: "\f153"; 1136 | } 1137 | .fa-gbp:before { 1138 | content: "\f154"; 1139 | } 1140 | .fa-dollar:before, 1141 | .fa-usd:before { 1142 | content: "\f155"; 1143 | } 1144 | .fa-rupee:before, 1145 | .fa-inr:before { 1146 | content: "\f156"; 1147 | } 1148 | .fa-cny:before, 1149 | .fa-rmb:before, 1150 | .fa-yen:before, 1151 | .fa-jpy:before { 1152 | content: "\f157"; 1153 | } 1154 | .fa-ruble:before, 1155 | .fa-rouble:before, 1156 | .fa-rub:before { 1157 | content: "\f158"; 1158 | } 1159 | .fa-won:before, 1160 | .fa-krw:before { 1161 | content: "\f159"; 1162 | } 1163 | .fa-bitcoin:before, 1164 | .fa-btc:before { 1165 | content: "\f15a"; 1166 | } 1167 | .fa-file:before { 1168 | content: "\f15b"; 1169 | } 1170 | .fa-file-text:before { 1171 | content: "\f15c"; 1172 | } 1173 | .fa-sort-alpha-asc:before { 1174 | content: "\f15d"; 1175 | } 1176 | .fa-sort-alpha-desc:before { 1177 | content: "\f15e"; 1178 | } 1179 | .fa-sort-amount-asc:before { 1180 | content: "\f160"; 1181 | } 1182 | .fa-sort-amount-desc:before { 1183 | content: "\f161"; 1184 | } 1185 | .fa-sort-numeric-asc:before { 1186 | content: "\f162"; 1187 | } 1188 | .fa-sort-numeric-desc:before { 1189 | content: "\f163"; 1190 | } 1191 | .fa-thumbs-up:before { 1192 | content: "\f164"; 1193 | } 1194 | .fa-thumbs-down:before { 1195 | content: "\f165"; 1196 | } 1197 | .fa-youtube-square:before { 1198 | content: "\f166"; 1199 | } 1200 | .fa-youtube:before { 1201 | content: "\f167"; 1202 | } 1203 | .fa-xing:before { 1204 | content: "\f168"; 1205 | } 1206 | .fa-xing-square:before { 1207 | content: "\f169"; 1208 | } 1209 | .fa-youtube-play:before { 1210 | content: "\f16a"; 1211 | } 1212 | .fa-dropbox:before { 1213 | content: "\f16b"; 1214 | } 1215 | .fa-stack-overflow:before { 1216 | content: "\f16c"; 1217 | } 1218 | .fa-instagram:before { 1219 | content: "\f16d"; 1220 | } 1221 | .fa-flickr:before { 1222 | content: "\f16e"; 1223 | } 1224 | .fa-adn:before { 1225 | content: "\f170"; 1226 | } 1227 | .fa-bitbucket:before { 1228 | content: "\f171"; 1229 | } 1230 | .fa-bitbucket-square:before { 1231 | content: "\f172"; 1232 | } 1233 | .fa-tumblr:before { 1234 | content: "\f173"; 1235 | } 1236 | .fa-tumblr-square:before { 1237 | content: "\f174"; 1238 | } 1239 | .fa-long-arrow-down:before { 1240 | content: "\f175"; 1241 | } 1242 | .fa-long-arrow-up:before { 1243 | content: "\f176"; 1244 | } 1245 | .fa-long-arrow-left:before { 1246 | content: "\f177"; 1247 | } 1248 | .fa-long-arrow-right:before { 1249 | content: "\f178"; 1250 | } 1251 | .fa-apple:before { 1252 | content: "\f179"; 1253 | } 1254 | .fa-windows:before { 1255 | content: "\f17a"; 1256 | } 1257 | .fa-android:before { 1258 | content: "\f17b"; 1259 | } 1260 | .fa-linux:before { 1261 | content: "\f17c"; 1262 | } 1263 | .fa-dribbble:before { 1264 | content: "\f17d"; 1265 | } 1266 | .fa-skype:before { 1267 | content: "\f17e"; 1268 | } 1269 | .fa-foursquare:before { 1270 | content: "\f180"; 1271 | } 1272 | .fa-trello:before { 1273 | content: "\f181"; 1274 | } 1275 | .fa-female:before { 1276 | content: "\f182"; 1277 | } 1278 | .fa-male:before { 1279 | content: "\f183"; 1280 | } 1281 | .fa-gittip:before, 1282 | .fa-gratipay:before { 1283 | content: "\f184"; 1284 | } 1285 | .fa-sun-o:before { 1286 | content: "\f185"; 1287 | } 1288 | .fa-moon-o:before { 1289 | content: "\f186"; 1290 | } 1291 | .fa-archive:before { 1292 | content: "\f187"; 1293 | } 1294 | .fa-bug:before { 1295 | content: "\f188"; 1296 | } 1297 | .fa-vk:before { 1298 | content: "\f189"; 1299 | } 1300 | .fa-weibo:before { 1301 | content: "\f18a"; 1302 | } 1303 | .fa-renren:before { 1304 | content: "\f18b"; 1305 | } 1306 | .fa-pagelines:before { 1307 | content: "\f18c"; 1308 | } 1309 | .fa-stack-exchange:before { 1310 | content: "\f18d"; 1311 | } 1312 | .fa-arrow-circle-o-right:before { 1313 | content: "\f18e"; 1314 | } 1315 | .fa-arrow-circle-o-left:before { 1316 | content: "\f190"; 1317 | } 1318 | .fa-toggle-left:before, 1319 | .fa-caret-square-o-left:before { 1320 | content: "\f191"; 1321 | } 1322 | .fa-dot-circle-o:before { 1323 | content: "\f192"; 1324 | } 1325 | .fa-wheelchair:before { 1326 | content: "\f193"; 1327 | } 1328 | .fa-vimeo-square:before { 1329 | content: "\f194"; 1330 | } 1331 | .fa-turkish-lira:before, 1332 | .fa-try:before { 1333 | content: "\f195"; 1334 | } 1335 | .fa-plus-square-o:before { 1336 | content: "\f196"; 1337 | } 1338 | .fa-space-shuttle:before { 1339 | content: "\f197"; 1340 | } 1341 | .fa-slack:before { 1342 | content: "\f198"; 1343 | } 1344 | .fa-envelope-square:before { 1345 | content: "\f199"; 1346 | } 1347 | .fa-wordpress:before { 1348 | content: "\f19a"; 1349 | } 1350 | .fa-openid:before { 1351 | content: "\f19b"; 1352 | } 1353 | .fa-institution:before, 1354 | .fa-bank:before, 1355 | .fa-university:before { 1356 | content: "\f19c"; 1357 | } 1358 | .fa-mortar-board:before, 1359 | .fa-graduation-cap:before { 1360 | content: "\f19d"; 1361 | } 1362 | .fa-yahoo:before { 1363 | content: "\f19e"; 1364 | } 1365 | .fa-google:before { 1366 | content: "\f1a0"; 1367 | } 1368 | .fa-reddit:before { 1369 | content: "\f1a1"; 1370 | } 1371 | .fa-reddit-square:before { 1372 | content: "\f1a2"; 1373 | } 1374 | .fa-stumbleupon-circle:before { 1375 | content: "\f1a3"; 1376 | } 1377 | .fa-stumbleupon:before { 1378 | content: "\f1a4"; 1379 | } 1380 | .fa-delicious:before { 1381 | content: "\f1a5"; 1382 | } 1383 | .fa-digg:before { 1384 | content: "\f1a6"; 1385 | } 1386 | .fa-pied-piper-pp:before { 1387 | content: "\f1a7"; 1388 | } 1389 | .fa-pied-piper-alt:before { 1390 | content: "\f1a8"; 1391 | } 1392 | .fa-drupal:before { 1393 | content: "\f1a9"; 1394 | } 1395 | .fa-joomla:before { 1396 | content: "\f1aa"; 1397 | } 1398 | .fa-language:before { 1399 | content: "\f1ab"; 1400 | } 1401 | .fa-fax:before { 1402 | content: "\f1ac"; 1403 | } 1404 | .fa-building:before { 1405 | content: "\f1ad"; 1406 | } 1407 | .fa-child:before { 1408 | content: "\f1ae"; 1409 | } 1410 | .fa-paw:before { 1411 | content: "\f1b0"; 1412 | } 1413 | .fa-spoon:before { 1414 | content: "\f1b1"; 1415 | } 1416 | .fa-cube:before { 1417 | content: "\f1b2"; 1418 | } 1419 | .fa-cubes:before { 1420 | content: "\f1b3"; 1421 | } 1422 | .fa-behance:before { 1423 | content: "\f1b4"; 1424 | } 1425 | .fa-behance-square:before { 1426 | content: "\f1b5"; 1427 | } 1428 | .fa-steam:before { 1429 | content: "\f1b6"; 1430 | } 1431 | .fa-steam-square:before { 1432 | content: "\f1b7"; 1433 | } 1434 | .fa-recycle:before { 1435 | content: "\f1b8"; 1436 | } 1437 | .fa-automobile:before, 1438 | .fa-car:before { 1439 | content: "\f1b9"; 1440 | } 1441 | .fa-cab:before, 1442 | .fa-taxi:before { 1443 | content: "\f1ba"; 1444 | } 1445 | .fa-tree:before { 1446 | content: "\f1bb"; 1447 | } 1448 | .fa-spotify:before { 1449 | content: "\f1bc"; 1450 | } 1451 | .fa-deviantart:before { 1452 | content: "\f1bd"; 1453 | } 1454 | .fa-soundcloud:before { 1455 | content: "\f1be"; 1456 | } 1457 | .fa-database:before { 1458 | content: "\f1c0"; 1459 | } 1460 | .fa-file-pdf-o:before { 1461 | content: "\f1c1"; 1462 | } 1463 | .fa-file-word-o:before { 1464 | content: "\f1c2"; 1465 | } 1466 | .fa-file-excel-o:before { 1467 | content: "\f1c3"; 1468 | } 1469 | .fa-file-powerpoint-o:before { 1470 | content: "\f1c4"; 1471 | } 1472 | .fa-file-photo-o:before, 1473 | .fa-file-picture-o:before, 1474 | .fa-file-image-o:before { 1475 | content: "\f1c5"; 1476 | } 1477 | .fa-file-zip-o:before, 1478 | .fa-file-archive-o:before { 1479 | content: "\f1c6"; 1480 | } 1481 | .fa-file-sound-o:before, 1482 | .fa-file-audio-o:before { 1483 | content: "\f1c7"; 1484 | } 1485 | .fa-file-movie-o:before, 1486 | .fa-file-video-o:before { 1487 | content: "\f1c8"; 1488 | } 1489 | .fa-file-code-o:before { 1490 | content: "\f1c9"; 1491 | } 1492 | .fa-vine:before { 1493 | content: "\f1ca"; 1494 | } 1495 | .fa-codepen:before { 1496 | content: "\f1cb"; 1497 | } 1498 | .fa-jsfiddle:before { 1499 | content: "\f1cc"; 1500 | } 1501 | .fa-life-bouy:before, 1502 | .fa-life-buoy:before, 1503 | .fa-life-saver:before, 1504 | .fa-support:before, 1505 | .fa-life-ring:before { 1506 | content: "\f1cd"; 1507 | } 1508 | .fa-circle-o-notch:before { 1509 | content: "\f1ce"; 1510 | } 1511 | .fa-ra:before, 1512 | .fa-resistance:before, 1513 | .fa-rebel:before { 1514 | content: "\f1d0"; 1515 | } 1516 | .fa-ge:before, 1517 | .fa-empire:before { 1518 | content: "\f1d1"; 1519 | } 1520 | .fa-git-square:before { 1521 | content: "\f1d2"; 1522 | } 1523 | .fa-git:before { 1524 | content: "\f1d3"; 1525 | } 1526 | .fa-y-combinator-square:before, 1527 | .fa-yc-square:before, 1528 | .fa-hacker-news:before { 1529 | content: "\f1d4"; 1530 | } 1531 | .fa-tencent-weibo:before { 1532 | content: "\f1d5"; 1533 | } 1534 | .fa-qq:before { 1535 | content: "\f1d6"; 1536 | } 1537 | .fa-wechat:before, 1538 | .fa-weixin:before { 1539 | content: "\f1d7"; 1540 | } 1541 | .fa-send:before, 1542 | .fa-paper-plane:before { 1543 | content: "\f1d8"; 1544 | } 1545 | .fa-send-o:before, 1546 | .fa-paper-plane-o:before { 1547 | content: "\f1d9"; 1548 | } 1549 | .fa-history:before { 1550 | content: "\f1da"; 1551 | } 1552 | .fa-circle-thin:before { 1553 | content: "\f1db"; 1554 | } 1555 | .fa-header:before { 1556 | content: "\f1dc"; 1557 | } 1558 | .fa-paragraph:before { 1559 | content: "\f1dd"; 1560 | } 1561 | .fa-sliders:before { 1562 | content: "\f1de"; 1563 | } 1564 | .fa-share-alt:before { 1565 | content: "\f1e0"; 1566 | } 1567 | .fa-share-alt-square:before { 1568 | content: "\f1e1"; 1569 | } 1570 | .fa-bomb:before { 1571 | content: "\f1e2"; 1572 | } 1573 | .fa-soccer-ball-o:before, 1574 | .fa-futbol-o:before { 1575 | content: "\f1e3"; 1576 | } 1577 | .fa-tty:before { 1578 | content: "\f1e4"; 1579 | } 1580 | .fa-binoculars:before { 1581 | content: "\f1e5"; 1582 | } 1583 | .fa-plug:before { 1584 | content: "\f1e6"; 1585 | } 1586 | .fa-slideshare:before { 1587 | content: "\f1e7"; 1588 | } 1589 | .fa-twitch:before { 1590 | content: "\f1e8"; 1591 | } 1592 | .fa-yelp:before { 1593 | content: "\f1e9"; 1594 | } 1595 | .fa-newspaper-o:before { 1596 | content: "\f1ea"; 1597 | } 1598 | .fa-wifi:before { 1599 | content: "\f1eb"; 1600 | } 1601 | .fa-calculator:before { 1602 | content: "\f1ec"; 1603 | } 1604 | .fa-paypal:before { 1605 | content: "\f1ed"; 1606 | } 1607 | .fa-google-wallet:before { 1608 | content: "\f1ee"; 1609 | } 1610 | .fa-cc-visa:before { 1611 | content: "\f1f0"; 1612 | } 1613 | .fa-cc-mastercard:before { 1614 | content: "\f1f1"; 1615 | } 1616 | .fa-cc-discover:before { 1617 | content: "\f1f2"; 1618 | } 1619 | .fa-cc-amex:before { 1620 | content: "\f1f3"; 1621 | } 1622 | .fa-cc-paypal:before { 1623 | content: "\f1f4"; 1624 | } 1625 | .fa-cc-stripe:before { 1626 | content: "\f1f5"; 1627 | } 1628 | .fa-bell-slash:before { 1629 | content: "\f1f6"; 1630 | } 1631 | .fa-bell-slash-o:before { 1632 | content: "\f1f7"; 1633 | } 1634 | .fa-trash:before { 1635 | content: "\f1f8"; 1636 | } 1637 | .fa-copyright:before { 1638 | content: "\f1f9"; 1639 | } 1640 | .fa-at:before { 1641 | content: "\f1fa"; 1642 | } 1643 | .fa-eyedropper:before { 1644 | content: "\f1fb"; 1645 | } 1646 | .fa-paint-brush:before { 1647 | content: "\f1fc"; 1648 | } 1649 | .fa-birthday-cake:before { 1650 | content: "\f1fd"; 1651 | } 1652 | .fa-area-chart:before { 1653 | content: "\f1fe"; 1654 | } 1655 | .fa-pie-chart:before { 1656 | content: "\f200"; 1657 | } 1658 | .fa-line-chart:before { 1659 | content: "\f201"; 1660 | } 1661 | .fa-lastfm:before { 1662 | content: "\f202"; 1663 | } 1664 | .fa-lastfm-square:before { 1665 | content: "\f203"; 1666 | } 1667 | .fa-toggle-off:before { 1668 | content: "\f204"; 1669 | } 1670 | .fa-toggle-on:before { 1671 | content: "\f205"; 1672 | } 1673 | .fa-bicycle:before { 1674 | content: "\f206"; 1675 | } 1676 | .fa-bus:before { 1677 | content: "\f207"; 1678 | } 1679 | .fa-ioxhost:before { 1680 | content: "\f208"; 1681 | } 1682 | .fa-angellist:before { 1683 | content: "\f209"; 1684 | } 1685 | .fa-cc:before { 1686 | content: "\f20a"; 1687 | } 1688 | .fa-shekel:before, 1689 | .fa-sheqel:before, 1690 | .fa-ils:before { 1691 | content: "\f20b"; 1692 | } 1693 | .fa-meanpath:before { 1694 | content: "\f20c"; 1695 | } 1696 | .fa-buysellads:before { 1697 | content: "\f20d"; 1698 | } 1699 | .fa-connectdevelop:before { 1700 | content: "\f20e"; 1701 | } 1702 | .fa-dashcube:before { 1703 | content: "\f210"; 1704 | } 1705 | .fa-forumbee:before { 1706 | content: "\f211"; 1707 | } 1708 | .fa-leanpub:before { 1709 | content: "\f212"; 1710 | } 1711 | .fa-sellsy:before { 1712 | content: "\f213"; 1713 | } 1714 | .fa-shirtsinbulk:before { 1715 | content: "\f214"; 1716 | } 1717 | .fa-simplybuilt:before { 1718 | content: "\f215"; 1719 | } 1720 | .fa-skyatlas:before { 1721 | content: "\f216"; 1722 | } 1723 | .fa-cart-plus:before { 1724 | content: "\f217"; 1725 | } 1726 | .fa-cart-arrow-down:before { 1727 | content: "\f218"; 1728 | } 1729 | .fa-diamond:before { 1730 | content: "\f219"; 1731 | } 1732 | .fa-ship:before { 1733 | content: "\f21a"; 1734 | } 1735 | .fa-user-secret:before { 1736 | content: "\f21b"; 1737 | } 1738 | .fa-motorcycle:before { 1739 | content: "\f21c"; 1740 | } 1741 | .fa-street-view:before { 1742 | content: "\f21d"; 1743 | } 1744 | .fa-heartbeat:before { 1745 | content: "\f21e"; 1746 | } 1747 | .fa-venus:before { 1748 | content: "\f221"; 1749 | } 1750 | .fa-mars:before { 1751 | content: "\f222"; 1752 | } 1753 | .fa-mercury:before { 1754 | content: "\f223"; 1755 | } 1756 | .fa-intersex:before, 1757 | .fa-transgender:before { 1758 | content: "\f224"; 1759 | } 1760 | .fa-transgender-alt:before { 1761 | content: "\f225"; 1762 | } 1763 | .fa-venus-double:before { 1764 | content: "\f226"; 1765 | } 1766 | .fa-mars-double:before { 1767 | content: "\f227"; 1768 | } 1769 | .fa-venus-mars:before { 1770 | content: "\f228"; 1771 | } 1772 | .fa-mars-stroke:before { 1773 | content: "\f229"; 1774 | } 1775 | .fa-mars-stroke-v:before { 1776 | content: "\f22a"; 1777 | } 1778 | .fa-mars-stroke-h:before { 1779 | content: "\f22b"; 1780 | } 1781 | .fa-neuter:before { 1782 | content: "\f22c"; 1783 | } 1784 | .fa-genderless:before { 1785 | content: "\f22d"; 1786 | } 1787 | .fa-facebook-official:before { 1788 | content: "\f230"; 1789 | } 1790 | .fa-pinterest-p:before { 1791 | content: "\f231"; 1792 | } 1793 | .fa-whatsapp:before { 1794 | content: "\f232"; 1795 | } 1796 | .fa-server:before { 1797 | content: "\f233"; 1798 | } 1799 | .fa-user-plus:before { 1800 | content: "\f234"; 1801 | } 1802 | .fa-user-times:before { 1803 | content: "\f235"; 1804 | } 1805 | .fa-hotel:before, 1806 | .fa-bed:before { 1807 | content: "\f236"; 1808 | } 1809 | .fa-viacoin:before { 1810 | content: "\f237"; 1811 | } 1812 | .fa-train:before { 1813 | content: "\f238"; 1814 | } 1815 | .fa-subway:before { 1816 | content: "\f239"; 1817 | } 1818 | .fa-medium:before { 1819 | content: "\f23a"; 1820 | } 1821 | .fa-yc:before, 1822 | .fa-y-combinator:before { 1823 | content: "\f23b"; 1824 | } 1825 | .fa-optin-monster:before { 1826 | content: "\f23c"; 1827 | } 1828 | .fa-opencart:before { 1829 | content: "\f23d"; 1830 | } 1831 | .fa-expeditedssl:before { 1832 | content: "\f23e"; 1833 | } 1834 | .fa-battery-4:before, 1835 | .fa-battery:before, 1836 | .fa-battery-full:before { 1837 | content: "\f240"; 1838 | } 1839 | .fa-battery-3:before, 1840 | .fa-battery-three-quarters:before { 1841 | content: "\f241"; 1842 | } 1843 | .fa-battery-2:before, 1844 | .fa-battery-half:before { 1845 | content: "\f242"; 1846 | } 1847 | .fa-battery-1:before, 1848 | .fa-battery-quarter:before { 1849 | content: "\f243"; 1850 | } 1851 | .fa-battery-0:before, 1852 | .fa-battery-empty:before { 1853 | content: "\f244"; 1854 | } 1855 | .fa-mouse-pointer:before { 1856 | content: "\f245"; 1857 | } 1858 | .fa-i-cursor:before { 1859 | content: "\f246"; 1860 | } 1861 | .fa-object-group:before { 1862 | content: "\f247"; 1863 | } 1864 | .fa-object-ungroup:before { 1865 | content: "\f248"; 1866 | } 1867 | .fa-sticky-note:before { 1868 | content: "\f249"; 1869 | } 1870 | .fa-sticky-note-o:before { 1871 | content: "\f24a"; 1872 | } 1873 | .fa-cc-jcb:before { 1874 | content: "\f24b"; 1875 | } 1876 | .fa-cc-diners-club:before { 1877 | content: "\f24c"; 1878 | } 1879 | .fa-clone:before { 1880 | content: "\f24d"; 1881 | } 1882 | .fa-balance-scale:before { 1883 | content: "\f24e"; 1884 | } 1885 | .fa-hourglass-o:before { 1886 | content: "\f250"; 1887 | } 1888 | .fa-hourglass-1:before, 1889 | .fa-hourglass-start:before { 1890 | content: "\f251"; 1891 | } 1892 | .fa-hourglass-2:before, 1893 | .fa-hourglass-half:before { 1894 | content: "\f252"; 1895 | } 1896 | .fa-hourglass-3:before, 1897 | .fa-hourglass-end:before { 1898 | content: "\f253"; 1899 | } 1900 | .fa-hourglass:before { 1901 | content: "\f254"; 1902 | } 1903 | .fa-hand-grab-o:before, 1904 | .fa-hand-rock-o:before { 1905 | content: "\f255"; 1906 | } 1907 | .fa-hand-stop-o:before, 1908 | .fa-hand-paper-o:before { 1909 | content: "\f256"; 1910 | } 1911 | .fa-hand-scissors-o:before { 1912 | content: "\f257"; 1913 | } 1914 | .fa-hand-lizard-o:before { 1915 | content: "\f258"; 1916 | } 1917 | .fa-hand-spock-o:before { 1918 | content: "\f259"; 1919 | } 1920 | .fa-hand-pointer-o:before { 1921 | content: "\f25a"; 1922 | } 1923 | .fa-hand-peace-o:before { 1924 | content: "\f25b"; 1925 | } 1926 | .fa-trademark:before { 1927 | content: "\f25c"; 1928 | } 1929 | .fa-registered:before { 1930 | content: "\f25d"; 1931 | } 1932 | .fa-creative-commons:before { 1933 | content: "\f25e"; 1934 | } 1935 | .fa-gg:before { 1936 | content: "\f260"; 1937 | } 1938 | .fa-gg-circle:before { 1939 | content: "\f261"; 1940 | } 1941 | .fa-tripadvisor:before { 1942 | content: "\f262"; 1943 | } 1944 | .fa-odnoklassniki:before { 1945 | content: "\f263"; 1946 | } 1947 | .fa-odnoklassniki-square:before { 1948 | content: "\f264"; 1949 | } 1950 | .fa-get-pocket:before { 1951 | content: "\f265"; 1952 | } 1953 | .fa-wikipedia-w:before { 1954 | content: "\f266"; 1955 | } 1956 | .fa-safari:before { 1957 | content: "\f267"; 1958 | } 1959 | .fa-chrome:before { 1960 | content: "\f268"; 1961 | } 1962 | .fa-firefox:before { 1963 | content: "\f269"; 1964 | } 1965 | .fa-opera:before { 1966 | content: "\f26a"; 1967 | } 1968 | .fa-internet-explorer:before { 1969 | content: "\f26b"; 1970 | } 1971 | .fa-tv:before, 1972 | .fa-television:before { 1973 | content: "\f26c"; 1974 | } 1975 | .fa-contao:before { 1976 | content: "\f26d"; 1977 | } 1978 | .fa-500px:before { 1979 | content: "\f26e"; 1980 | } 1981 | .fa-amazon:before { 1982 | content: "\f270"; 1983 | } 1984 | .fa-calendar-plus-o:before { 1985 | content: "\f271"; 1986 | } 1987 | .fa-calendar-minus-o:before { 1988 | content: "\f272"; 1989 | } 1990 | .fa-calendar-times-o:before { 1991 | content: "\f273"; 1992 | } 1993 | .fa-calendar-check-o:before { 1994 | content: "\f274"; 1995 | } 1996 | .fa-industry:before { 1997 | content: "\f275"; 1998 | } 1999 | .fa-map-pin:before { 2000 | content: "\f276"; 2001 | } 2002 | .fa-map-signs:before { 2003 | content: "\f277"; 2004 | } 2005 | .fa-map-o:before { 2006 | content: "\f278"; 2007 | } 2008 | .fa-map:before { 2009 | content: "\f279"; 2010 | } 2011 | .fa-commenting:before { 2012 | content: "\f27a"; 2013 | } 2014 | .fa-commenting-o:before { 2015 | content: "\f27b"; 2016 | } 2017 | .fa-houzz:before { 2018 | content: "\f27c"; 2019 | } 2020 | .fa-vimeo:before { 2021 | content: "\f27d"; 2022 | } 2023 | .fa-black-tie:before { 2024 | content: "\f27e"; 2025 | } 2026 | .fa-fonticons:before { 2027 | content: "\f280"; 2028 | } 2029 | .fa-reddit-alien:before { 2030 | content: "\f281"; 2031 | } 2032 | .fa-edge:before { 2033 | content: "\f282"; 2034 | } 2035 | .fa-credit-card-alt:before { 2036 | content: "\f283"; 2037 | } 2038 | .fa-codiepie:before { 2039 | content: "\f284"; 2040 | } 2041 | .fa-modx:before { 2042 | content: "\f285"; 2043 | } 2044 | .fa-fort-awesome:before { 2045 | content: "\f286"; 2046 | } 2047 | .fa-usb:before { 2048 | content: "\f287"; 2049 | } 2050 | .fa-product-hunt:before { 2051 | content: "\f288"; 2052 | } 2053 | .fa-mixcloud:before { 2054 | content: "\f289"; 2055 | } 2056 | .fa-scribd:before { 2057 | content: "\f28a"; 2058 | } 2059 | .fa-pause-circle:before { 2060 | content: "\f28b"; 2061 | } 2062 | .fa-pause-circle-o:before { 2063 | content: "\f28c"; 2064 | } 2065 | .fa-stop-circle:before { 2066 | content: "\f28d"; 2067 | } 2068 | .fa-stop-circle-o:before { 2069 | content: "\f28e"; 2070 | } 2071 | .fa-shopping-bag:before { 2072 | content: "\f290"; 2073 | } 2074 | .fa-shopping-basket:before { 2075 | content: "\f291"; 2076 | } 2077 | .fa-hashtag:before { 2078 | content: "\f292"; 2079 | } 2080 | .fa-bluetooth:before { 2081 | content: "\f293"; 2082 | } 2083 | .fa-bluetooth-b:before { 2084 | content: "\f294"; 2085 | } 2086 | .fa-percent:before { 2087 | content: "\f295"; 2088 | } 2089 | .fa-gitlab:before { 2090 | content: "\f296"; 2091 | } 2092 | .fa-wpbeginner:before { 2093 | content: "\f297"; 2094 | } 2095 | .fa-wpforms:before { 2096 | content: "\f298"; 2097 | } 2098 | .fa-envira:before { 2099 | content: "\f299"; 2100 | } 2101 | .fa-universal-access:before { 2102 | content: "\f29a"; 2103 | } 2104 | .fa-wheelchair-alt:before { 2105 | content: "\f29b"; 2106 | } 2107 | .fa-question-circle-o:before { 2108 | content: "\f29c"; 2109 | } 2110 | .fa-blind:before { 2111 | content: "\f29d"; 2112 | } 2113 | .fa-audio-description:before { 2114 | content: "\f29e"; 2115 | } 2116 | .fa-volume-control-phone:before { 2117 | content: "\f2a0"; 2118 | } 2119 | .fa-braille:before { 2120 | content: "\f2a1"; 2121 | } 2122 | .fa-assistive-listening-systems:before { 2123 | content: "\f2a2"; 2124 | } 2125 | .fa-asl-interpreting:before, 2126 | .fa-american-sign-language-interpreting:before { 2127 | content: "\f2a3"; 2128 | } 2129 | .fa-deafness:before, 2130 | .fa-hard-of-hearing:before, 2131 | .fa-deaf:before { 2132 | content: "\f2a4"; 2133 | } 2134 | .fa-glide:before { 2135 | content: "\f2a5"; 2136 | } 2137 | .fa-glide-g:before { 2138 | content: "\f2a6"; 2139 | } 2140 | .fa-signing:before, 2141 | .fa-sign-language:before { 2142 | content: "\f2a7"; 2143 | } 2144 | .fa-low-vision:before { 2145 | content: "\f2a8"; 2146 | } 2147 | .fa-viadeo:before { 2148 | content: "\f2a9"; 2149 | } 2150 | .fa-viadeo-square:before { 2151 | content: "\f2aa"; 2152 | } 2153 | .fa-snapchat:before { 2154 | content: "\f2ab"; 2155 | } 2156 | .fa-snapchat-ghost:before { 2157 | content: "\f2ac"; 2158 | } 2159 | .fa-snapchat-square:before { 2160 | content: "\f2ad"; 2161 | } 2162 | .fa-pied-piper:before { 2163 | content: "\f2ae"; 2164 | } 2165 | .fa-first-order:before { 2166 | content: "\f2b0"; 2167 | } 2168 | .fa-yoast:before { 2169 | content: "\f2b1"; 2170 | } 2171 | .fa-themeisle:before { 2172 | content: "\f2b2"; 2173 | } 2174 | .fa-google-plus-circle:before, 2175 | .fa-google-plus-official:before { 2176 | content: "\f2b3"; 2177 | } 2178 | .fa-fa:before, 2179 | .fa-font-awesome:before { 2180 | content: "\f2b4"; 2181 | } 2182 | .fa-handshake-o:before { 2183 | content: "\f2b5"; 2184 | } 2185 | .fa-envelope-open:before { 2186 | content: "\f2b6"; 2187 | } 2188 | .fa-envelope-open-o:before { 2189 | content: "\f2b7"; 2190 | } 2191 | .fa-linode:before { 2192 | content: "\f2b8"; 2193 | } 2194 | .fa-address-book:before { 2195 | content: "\f2b9"; 2196 | } 2197 | .fa-address-book-o:before { 2198 | content: "\f2ba"; 2199 | } 2200 | .fa-vcard:before, 2201 | .fa-address-card:before { 2202 | content: "\f2bb"; 2203 | } 2204 | .fa-vcard-o:before, 2205 | .fa-address-card-o:before { 2206 | content: "\f2bc"; 2207 | } 2208 | .fa-user-circle:before { 2209 | content: "\f2bd"; 2210 | } 2211 | .fa-user-circle-o:before { 2212 | content: "\f2be"; 2213 | } 2214 | .fa-user-o:before { 2215 | content: "\f2c0"; 2216 | } 2217 | .fa-id-badge:before { 2218 | content: "\f2c1"; 2219 | } 2220 | .fa-drivers-license:before, 2221 | .fa-id-card:before { 2222 | content: "\f2c2"; 2223 | } 2224 | .fa-drivers-license-o:before, 2225 | .fa-id-card-o:before { 2226 | content: "\f2c3"; 2227 | } 2228 | .fa-quora:before { 2229 | content: "\f2c4"; 2230 | } 2231 | .fa-free-code-camp:before { 2232 | content: "\f2c5"; 2233 | } 2234 | .fa-telegram:before { 2235 | content: "\f2c6"; 2236 | } 2237 | .fa-thermometer-4:before, 2238 | .fa-thermometer:before, 2239 | .fa-thermometer-full:before { 2240 | content: "\f2c7"; 2241 | } 2242 | .fa-thermometer-3:before, 2243 | .fa-thermometer-three-quarters:before { 2244 | content: "\f2c8"; 2245 | } 2246 | .fa-thermometer-2:before, 2247 | .fa-thermometer-half:before { 2248 | content: "\f2c9"; 2249 | } 2250 | .fa-thermometer-1:before, 2251 | .fa-thermometer-quarter:before { 2252 | content: "\f2ca"; 2253 | } 2254 | .fa-thermometer-0:before, 2255 | .fa-thermometer-empty:before { 2256 | content: "\f2cb"; 2257 | } 2258 | .fa-shower:before { 2259 | content: "\f2cc"; 2260 | } 2261 | .fa-bathtub:before, 2262 | .fa-s15:before, 2263 | .fa-bath:before { 2264 | content: "\f2cd"; 2265 | } 2266 | .fa-podcast:before { 2267 | content: "\f2ce"; 2268 | } 2269 | .fa-window-maximize:before { 2270 | content: "\f2d0"; 2271 | } 2272 | .fa-window-minimize:before { 2273 | content: "\f2d1"; 2274 | } 2275 | .fa-window-restore:before { 2276 | content: "\f2d2"; 2277 | } 2278 | .fa-times-rectangle:before, 2279 | .fa-window-close:before { 2280 | content: "\f2d3"; 2281 | } 2282 | .fa-times-rectangle-o:before, 2283 | .fa-window-close-o:before { 2284 | content: "\f2d4"; 2285 | } 2286 | .fa-bandcamp:before { 2287 | content: "\f2d5"; 2288 | } 2289 | .fa-grav:before { 2290 | content: "\f2d6"; 2291 | } 2292 | .fa-etsy:before { 2293 | content: "\f2d7"; 2294 | } 2295 | .fa-imdb:before { 2296 | content: "\f2d8"; 2297 | } 2298 | .fa-ravelry:before { 2299 | content: "\f2d9"; 2300 | } 2301 | .fa-eercast:before { 2302 | content: "\f2da"; 2303 | } 2304 | .fa-microchip:before { 2305 | content: "\f2db"; 2306 | } 2307 | .fa-snowflake-o:before { 2308 | content: "\f2dc"; 2309 | } 2310 | .fa-superpowers:before { 2311 | content: "\f2dd"; 2312 | } 2313 | .fa-wpexplorer:before { 2314 | content: "\f2de"; 2315 | } 2316 | .fa-meetup:before { 2317 | content: "\f2e0"; 2318 | } 2319 | .sr-only { 2320 | position: absolute; 2321 | width: 1px; 2322 | height: 1px; 2323 | padding: 0; 2324 | margin: -1px; 2325 | overflow: hidden; 2326 | clip: rect(0, 0, 0, 0); 2327 | border: 0; 2328 | } 2329 | .sr-only-focusable:active, 2330 | .sr-only-focusable:focus { 2331 | position: static; 2332 | width: auto; 2333 | height: auto; 2334 | margin: 0; 2335 | overflow: visible; 2336 | clip: auto; 2337 | } 2338 | -------------------------------------------------------------------------------- /resources/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wingsline/laravel-blog/05d618a1f7b27419075b05e457da8098c7e5f8db/resources/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /resources/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wingsline/laravel-blog/05d618a1f7b27419075b05e457da8098c7e5f8db/resources/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /resources/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wingsline/laravel-blog/05d618a1f7b27419075b05e457da8098c7e5f8db/resources/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /resources/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wingsline/laravel-blog/05d618a1f7b27419075b05e457da8098c7e5f8db/resources/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /resources/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wingsline/laravel-blog/05d618a1f7b27419075b05e457da8098c7e5f8db/resources/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /resources/js/app.js: -------------------------------------------------------------------------------- 1 | // markdown editor 2 | import EasyMDE from "./vendor/easymde/easymde"; 3 | import "./includes/toggle"; 4 | const axios = require('axios').default; 5 | 6 | const editors = document.getElementsByClassName("markdown-editor"); 7 | const token = document.head.querySelector("meta[name=\"csrf-token\"]"); 8 | 9 | if (editors.length) { 10 | const imageUploadEndpoint = editors[0].getAttribute("data-upload-url"); 11 | /* eslint-disable no-new */ 12 | new EasyMDE({ 13 | spellChecker: false, 14 | autoDownloadFontAwesome: false, 15 | imageCSRFToken: token.content, 16 | element: editors[0], 17 | toolbar: [ 18 | "bold", 19 | "italic", 20 | "heading", 21 | "strikethrough", 22 | "|", 23 | "quote", 24 | "unordered-list", 25 | "ordered-list", 26 | "code", 27 | "|", 28 | "link", 29 | imageUploadEndpoint !== "" ? "upload-image" : "image", 30 | "table", 31 | "horizontal-rule", 32 | "|", 33 | "preview", 34 | "side-by-side", 35 | "fullscreen", 36 | "|", 37 | "undo", 38 | "redo" 39 | ], 40 | autosave: { 41 | enabled: true, 42 | delay: 10000, 43 | uniqueId: window.location 44 | }, 45 | uploadImage: imageUploadEndpoint !== "", 46 | imageUploadEndpoint: imageUploadEndpoint, 47 | imageMaxSize: parseInt(editors[0].getAttribute("data-max-size"), 10), 48 | // previewRender: function (plainText) { 49 | // return MarkdownIt.render(plainText); // Returns HTML from a custom parser 50 | // } 51 | previewRender: function(plainText, preview) { // Async method 52 | axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; 53 | axios.defaults.headers.common["X-CSRF-TOKEN"] = token.content; 54 | axios.post(editors[0].getAttribute("data-preview-url"), {payload: plainText}) 55 | .then(function(response) { 56 | preview.innerHTML = response.data.data.html; 57 | }); 58 | return ""; 59 | }, 60 | }); 61 | } 62 | 63 | // basic confirm dialog trigger: 64 | // uses data-confirm attribute and it's content to confirm the click event 65 | (function () { 66 | document.addEventListener( 67 | "click", 68 | function (e) { 69 | if (e.which !== 1) { 70 | return true; 71 | } 72 | const attrName = "data-confirm"; 73 | 74 | const el = e.target || e.srcElement; 75 | if (!el.hasAttribute(attrName)) { 76 | return true; 77 | } 78 | 79 | if (!confirm(el.getAttribute(attrName))) { 80 | e.preventDefault(); 81 | e.stopImmediatePropagation(); 82 | return false; 83 | } 84 | return true; 85 | }, 86 | false 87 | ); 88 | })(); 89 | -------------------------------------------------------------------------------- /resources/js/includes/toggle.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Adds a class to the body when the handler is clicked and toggles the 3 | * handle element aria-expanded value 4 | * 5 | * Example handle: 6 | * -------------------------------------------------------------- 7 | * 8 | * 13 | * 14 | * 15 | * Handle optional attributes: 16 | * -------------------------------------------------------------- 17 | * 18 | * data-toggle-callback - callback after the element was toggled 19 | * 20 | * 21 | * Target: 22 | * -------------------------------------------------------------- 23 | * 24 | *
...
25 | * 26 | * When the handle is clicked we call the callback. 27 | */ 28 | import camelCase from "lodash/camelCase"; 29 | 30 | // handlers 31 | const handlers = {}; 32 | // load the handlers from the toggleHandlers directory using webpack: 33 | // see: https://github.com/chrisvfritz/vue-enterprise-boilerplate/blob/master/src/components/_globals.js 34 | const requireHandlers = require.context( 35 | "./toggleHandlers", 36 | false, 37 | /[\w-]+\.js$/ 38 | ); 39 | requireHandlers.keys().forEach(fileName => { 40 | // Get the handler config 41 | const handlerConfig = requireHandlers(fileName); 42 | const handlerName = camelCase( 43 | fileName 44 | // Remove the "./_" from the beginning 45 | .replace(/^\.\/_/, "") 46 | // Remove the file extension from the end 47 | .replace(/\.\w+$/, "") 48 | ); 49 | handlers[handlerName] = handlerConfig.default || handlerConfig; 50 | }); 51 | 52 | // on click we toggle the target 53 | document.addEventListener("click", function(e) { 54 | if (e.which !== 1) { 55 | return true; 56 | } 57 | 58 | let callbackAttrName = "data-toggle-handler", 59 | el = e.target || e.srcElement; 60 | 61 | if (!el.hasAttribute(callbackAttrName)) { 62 | return true; 63 | } 64 | if (el) { 65 | let callback = el.getAttribute(callbackAttrName), 66 | target = document.querySelector(`#${el.getAttribute("aria-controls")}`); 67 | if (callback) { 68 | e.preventDefault(); 69 | new handlers[callback](el, target).toggle(); 70 | } 71 | } 72 | }); 73 | -------------------------------------------------------------------------------- /resources/js/includes/toggleHandlers/toggleAdminNav.js: -------------------------------------------------------------------------------- 1 | export default class toggleAdminNav { 2 | constructor(el, target) { 3 | this.el = el; 4 | this.target = target; 5 | } 6 | 7 | toggle() { 8 | let status = this.target.getAttribute("aria-expanded") !== "true", 9 | icons = this.el.querySelectorAll('svg'); 10 | this.target.setAttribute("aria-expanded", status); 11 | // switch the svg 12 | icons[0].classList.toggle('hidden', status); 13 | icons[1].classList.toggle('hidden', !status); 14 | // toggle the sr-only class on the target 15 | this.target.classList.toggle('sr-only', !status); 16 | // block scrolling on the body 17 | document.querySelector('body').classList.toggle('block-scroll', status); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /resources/js/vendor/easymde/codemirror/tablist.js: -------------------------------------------------------------------------------- 1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others 2 | // Distributed under an MIT license: http://codemirror.net/LICENSE 3 | 4 | var CodeMirror = require('codemirror'); 5 | 6 | CodeMirror.commands.tabAndIndentMarkdownList = function (cm) { 7 | var ranges = cm.listSelections(); 8 | var pos = ranges[0].head; 9 | var eolState = cm.getStateAfter(pos.line); 10 | var inList = eolState.list !== false; 11 | 12 | if (inList) { 13 | cm.execCommand('indentMore'); 14 | return; 15 | } 16 | 17 | if (cm.options.indentWithTabs) { 18 | cm.execCommand('insertTab'); 19 | } 20 | else { 21 | var spaces = Array(cm.options.tabSize + 1).join(' '); 22 | cm.replaceSelection(spaces); 23 | } 24 | }; 25 | 26 | CodeMirror.commands.shiftTabAndUnindentMarkdownList = function (cm) { 27 | var ranges = cm.listSelections(); 28 | var pos = ranges[0].head; 29 | var eolState = cm.getStateAfter(pos.line); 30 | var inList = eolState.list !== false; 31 | 32 | if (inList) { 33 | cm.execCommand('indentLess'); 34 | return; 35 | } 36 | 37 | if (cm.options.indentWithTabs) { 38 | cm.execCommand('insertTab'); 39 | } 40 | else { 41 | var spaces = Array(cm.options.tabSize + 1).join(' '); 42 | cm.replaceSelection(spaces); 43 | } 44 | }; 45 | -------------------------------------------------------------------------------- /resources/views/account/edit.blade.php: -------------------------------------------------------------------------------- 1 | @extends('blog::layouts.master') 2 | 3 | @section('content') 4 | 5 |
6 | 10 | 11 | 12 | 13 |
14 |

{{ __('Profile') }}

15 |

Edit or update your account 16 | information.

17 |
18 |
19 | 20 | @include("blog::layouts.partials.flash") 21 | 22 | {{-- posts --}} 23 |
25 | 26 | @csrf 27 | @method('PATCH') 28 |
29 | @include('blog::account.partials.form', ['submitText' => 'Update']) 30 |
31 |
32 | @endsection 33 | -------------------------------------------------------------------------------- /resources/views/account/partials/form.blade.php: -------------------------------------------------------------------------------- 1 | {{-- name --}} 2 |
3 | 4 | 5 |

6 | @error('name') {{ $message }} @enderror 7 |

8 |
9 | {{-- email --}} 10 |
11 | 12 | 13 |

14 | @error('email') {{ $message }} @enderror 15 |

16 |
17 | 18 | {{-- new password --}} 19 |
20 | 21 | 22 |

23 | @error('password') {{ $message }} @enderror 24 |

25 |
26 | {{-- new password confirm --}} 27 |
28 | 29 | 30 |

31 | @error('password_confirmation') {{ $message }} @enderror 32 |

33 |
34 | {{-- submit --}} 35 |
36 | 37 |
38 | -------------------------------------------------------------------------------- /resources/views/auth/login.blade.php: -------------------------------------------------------------------------------- 1 | @extends('blog::layouts.master') 2 | 3 | @section('content') 4 |
5 |
6 | @csrf 7 |
8 | 11 | 12 |

13 | @error('email') {{ $message }} @enderror 14 |

15 |
16 |
17 | 20 | 21 |

22 | @error('password') {{ $message }} @enderror 23 |   24 |

25 |
26 |
27 | 30 |
31 |
32 |
33 | @endsection 34 | -------------------------------------------------------------------------------- /resources/views/dashboard.blade.php: -------------------------------------------------------------------------------- 1 | @extends('blog::layouts.master') 2 | 3 | @section('content') 4 | 5 | @include("blog::layouts.partials.flash") 6 | 7 | {{-- latests posts --}} 8 | @include('blog::posts.partials.header', ['title' => 'Latest Posts', 'description' => 'Latest blog posts sorted by publish date.']) 9 | 10 |
    11 | @include('blog::posts.partials.list-header') 12 | @forelse ($latest_posts as $post) 13 | @include('blog::posts.partials.item', compact('post')) 14 | @empty 15 |
  1. 16 |

    17 | There are no posts. Create 19 | one. 20 |

    21 |
  2. 22 | 23 | @endforelse 24 |
25 | @include('blog::posts.partials.legend') 26 | @endsection 27 | -------------------------------------------------------------------------------- /resources/views/layouts/master.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 | Admin | {{ config('app.name') }} 10 | 11 | 12 | 14 | 15 | 16 |
17 |
18 |
19 | @auth 20 | 37 | @endauth 38 | 50 |
51 |
52 | @auth 53 | 54 | @endauth 55 |
56 |
57 |
58 |
59 | @auth 60 | 65 | @endauth 66 |
67 | @yield('content') 68 |
69 |
70 |
71 | 73 | 75 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /resources/views/layouts/nav/account.blade.php: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /resources/views/layouts/nav/blog.blade.php: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /resources/views/layouts/nav/dashboard.blade.php: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /resources/views/layouts/nav/items/account.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | {{ __('Account') }} 10 | 11 | -------------------------------------------------------------------------------- /resources/views/layouts/nav/items/logout.blade.php: -------------------------------------------------------------------------------- 1 |
2 | 17 | 18 | 21 |
22 | -------------------------------------------------------------------------------- /resources/views/layouts/nav/items/site.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 10 | 11 | {{ __('Site') }} 12 | 13 | -------------------------------------------------------------------------------- /resources/views/layouts/partials/flash.blade.php: -------------------------------------------------------------------------------- 1 | @if (flash()->message) 2 | 12 | @endif 13 | -------------------------------------------------------------------------------- /resources/views/layouts/partials/header.blade.php: -------------------------------------------------------------------------------- 1 |
2 |
3 |

4 | Admin 5 |

6 | 7 | @auth 8 | {{-- --}} 9 | @endauth 10 |
11 |
12 | 13 | 14 | -------------------------------------------------------------------------------- /resources/views/layouts/partials/pagination.blade.php: -------------------------------------------------------------------------------- 1 | @if ($paginator->hasPages()) 2 | 46 | @endif 47 | -------------------------------------------------------------------------------- /resources/views/posts/create.blade.php: -------------------------------------------------------------------------------- 1 | @extends('blog::layouts.master') 2 | 3 | @section('content') 4 | 5 |
6 | 10 | 12 | 14 | 15 |
16 |

{{ __('New Post') }}

17 |

{{ __('Create a new blog post.') }}

18 |
19 |
20 | 21 | @include("blog::layouts.partials.flash") 22 | 23 | {{-- form --}} 24 |
26 | @csrf 27 | @include('blog::posts.partials.form', ['submitText' => 'Create']) 28 |
29 | @endsection 30 | -------------------------------------------------------------------------------- /resources/views/posts/edit.blade.php: -------------------------------------------------------------------------------- 1 | @extends('blog::layouts.master') 2 | 3 | @section('content') 4 |
5 | 9 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |

{{ __('Edit Post') }}

18 |

{{ __('Edit an existing blog post.') }}

19 |
20 |
21 | 22 | @include("blog::layouts.partials.flash") 23 | 24 | {{-- posts --}} 25 |
27 | @csrf 28 | @method('PATCH') 29 | @include('blog::posts.partials.form', ['submitText' => 'Update']) 30 |
31 | @endsection 32 | -------------------------------------------------------------------------------- /resources/views/posts/index.blade.php: -------------------------------------------------------------------------------- 1 | @extends('blog::layouts.master') 2 | 3 | @section('content') 4 | @include('blog::posts.partials.header', ['title' => 'Posts', 'description' => 'Blog posts sorted by publish date.']) 5 | 6 | @include("blog::layouts.partials.flash") 7 | 8 | {{-- posts --}} 9 | 10 |
    11 | @include('blog::posts.partials.list-header') 12 | @forelse ($posts as $post) 13 | @include('blog::posts.partials.item', compact('post')) 14 | @empty 15 |
  1. 16 |

    17 | There are no posts. Create one. 19 |

    20 |
  2. 21 | 22 | @endforelse 23 |
24 | {{ $posts->onEachSide(1)->links('blog::layouts.partials.pagination') }} 25 | 26 |
27 | @include('blog::posts.partials.legend') 28 |
29 | @endsection 30 | -------------------------------------------------------------------------------- /resources/views/posts/partials/deleteButton.blade.php: -------------------------------------------------------------------------------- 1 |
2 | @csrf 3 | @method('DELETE') 4 | 7 |
8 | -------------------------------------------------------------------------------- /resources/views/posts/partials/form.blade.php: -------------------------------------------------------------------------------- 1 | {{-- title --}} 2 |
3 | 4 | 5 |

6 | @error('title') {{ $message }} @enderror 7 |

8 |
9 | {{-- post --}} 10 |
11 | 12 | 21 |

22 | @error('text') {{ $message }} @enderror 23 |

24 |
25 | {{-- tags --}} 26 |
27 | 28 | 29 |

30 | @error('tags_text') {{ $message }} @enderror 31 |

32 |
33 | {{-- publish date --}} 34 |
35 | 36 | 37 |

38 | @error('publish_date') {{ $message }} @enderror 39 |

40 |
41 | {{-- external url --}} 42 |
43 | 44 | 45 |

46 | @error('external_url') {{ $message }} @enderror 47 |

48 |
49 | {{-- published --}} 50 |
51 | published ? 'checked' : '' }}> 52 | 53 |

54 | @error('published') {{ $message }} @enderror 55 |

56 |
57 | {{-- original content --}} 58 |
59 | original_content ? 'checked' : '' }}> 60 | 61 |

62 | @error('original_content') {{ $message }} @enderror 63 |

64 |
65 | 66 | {{-- submit --}} 67 |
68 | 69 |
70 | -------------------------------------------------------------------------------- /resources/views/posts/partials/header.blade.php: -------------------------------------------------------------------------------- 1 |
2 |
3 | 8 | 9 | 11 | 12 |
13 |

{{ __($title) }}

14 |

{{ __($description) }}

15 |
16 |
17 | 19 | 23 | 25 | 27 | 28 | New Post 29 | 30 |
31 | -------------------------------------------------------------------------------- /resources/views/posts/partials/item.blade.php: -------------------------------------------------------------------------------- 1 |
  • 2 |
    3 | @if ($post->published) 4 | {{ __('Published') }} 5 | @else 6 | {{ __('Draft') }} 7 | @endif 8 |
    9 | {{ $post->title }} 10 |
    11 | {{ $post->publish_date->diffForHumans() }} 12 |
    13 | 14 |
    15 | @include('blog::posts.partials.deleteButton', compact('post')) 16 |
    17 |
  • 18 | -------------------------------------------------------------------------------- /resources/views/posts/partials/legend.blade.php: -------------------------------------------------------------------------------- 1 |

    Legend:

    2 |
    3 |
      4 |
    • 5 | 8 | 9 | 10 | 11 | {{ __('Published') }} 12 |
    • 13 | 14 |
    • 15 | 18 | 19 | 20 | 21 | 22 | 23 | {{ __('Draft / Unpublished') }} 24 |
    • 25 | 26 |
    • 27 | 30 | 31 | 32 | 33 | 34 | 35 | {{ __('Delete the Post') }} 36 |
    • 37 |
    38 | 39 | 40 | -------------------------------------------------------------------------------- /resources/views/posts/partials/list-header.blade.php: -------------------------------------------------------------------------------- 1 |
  • 2 |
    3 | Post 4 |
    5 |
    Publish Date
    6 |
    7 | 10 |
    11 |
  • 12 | -------------------------------------------------------------------------------- /routes/web.php: -------------------------------------------------------------------------------- 1 | prefix(config('blog.adminprefix')) 14 | ->group(function () { 15 | Route::get('login', [LoginController::class, 'showLoginForm'])->name('admin.login'); 16 | Route::post('login', [LoginController::class, 'login']); 17 | Route::post('logout', [LoginController::class, 'logout'])->name('admin.logout'); 18 | // authorized routes 19 | Route::middleware('blog-auth') 20 | ->name('admin.') 21 | ->group(function () { 22 | Route::get('/', DashboardController::class)->name('dashboard'); 23 | 24 | Route::get('account', [AccountController::class, 'edit'])->name('account.edit'); 25 | Route::match(['PUT', 'PATCH'], 'account', [AccountController::class, 'update'])->name('account.update'); 26 | 27 | Route::post('posts/preview', [PostsController::class, 'preview'])->name('posts.preview'); 28 | Route::post('posts/upload/{post}', [PostsController::class, 'upload'])->name('posts.upload'); 29 | Route::resource('posts', PostsController::class)->except('show'); 30 | }); 31 | }); 32 | 33 | Route::middleware(['web', 'blog-cacheResponse']) 34 | ->prefix(config('blog.blogprefix')) 35 | ->group(function () { 36 | Route::feeds(); 37 | Route::get('/', HomeController::class); 38 | Route::get('tag/{tagSlug}', TaggedPostsController::class)->name('posts.tagged'); 39 | Route::get('{postSlug}', [\Wingsline\Blog\Http\Controllers\Front\PostsController::class, 'detail'])->name('post'); 40 | }); 41 | -------------------------------------------------------------------------------- /src/BlogServiceProvider.php: -------------------------------------------------------------------------------- 1 | app['config'] 25 | ->set( 26 | 'feed.feeds.blog', 27 | $this->app['config']->get('blog.feed') 28 | ); 29 | } 30 | 31 | /** 32 | * Perform post-registration booting of services. 33 | */ 34 | public function boot() 35 | { 36 | // prepend the views from the theme 37 | $this->app['view']->getFinder()->prependLocation(base_path('theme/views')); 38 | 39 | $this->loadViewsFrom(__DIR__.'/../resources/views', 'blog'); 40 | $this->loadMigrationsFrom(__DIR__.'/../database/migrations'); 41 | $this->loadRoutesFrom(__DIR__.'/../routes/web.php'); 42 | 43 | Flash::levels([ 44 | 'success' => '', 45 | 'error' => 'bg-red-500', 46 | ]); 47 | 48 | Menu::macro('blogAdminNavHeader', function () { 49 | return Menu::build( 50 | config('blog.navHeader'), 51 | function (\Spatie\Menu\Laravel\Menu $menu, $view) { 52 | $menu->add(View::create($view)->addParentClass('ml-5 lg:ml-6')); 53 | }) 54 | ->addClass('flex items-end lg:items-center lg:pr-2') 55 | ->addItemClass('p-2') 56 | ->setActiveFromRequest('/'); 57 | }); 58 | 59 | Menu::macro('blogAdminNav', function () { 60 | return Menu::build( 61 | config('blog.navAdmin'), 62 | function (\Spatie\Menu\Laravel\Menu $menu, $view) { 63 | $menu->add(View::create($view)->addParentClass('')); 64 | }) 65 | ->addItemClass('p-2') 66 | ->setActiveFromRequest('/'); 67 | }); 68 | 69 | // register the route middleware groups 70 | $this->app['router']->middlewareGroup('blog-auth', 71 | [Authenticate::class]); 72 | $this->app['router']->middlewareGroup('blog-nocache', 73 | [NoHttpCache::class]); 74 | $this->app['router']->middlewareGroup('blog-cacheResponse', 75 | [CacheResponse::class]); 76 | 77 | // router bindings 78 | $this->registerRouteModelBindings(); 79 | 80 | // model event observers 81 | Post::observe(PostObserver::class); 82 | 83 | // Publishing is only necessary when using the CLI. 84 | if ($this->app->runningInConsole()) { 85 | $this->bootForConsole(); 86 | } 87 | } 88 | 89 | /** 90 | * Register any package services. 91 | */ 92 | public function register() 93 | { 94 | $this->mergeConfigFrom(__DIR__.'/../config/blog.php', 'blog'); 95 | 96 | if (file_exists(base_path('theme/config.php'))) { 97 | $this->mergeConfigFrom(base_path('theme/config.php'), 'theme'); 98 | } 99 | 100 | $this->addFeed(); 101 | 102 | $this->commands([ 103 | InstallCommand::class, 104 | PublishCommand::class, 105 | ThemePublishCommand::class, 106 | ]); 107 | } 108 | 109 | public function registerRouteModelBindings() 110 | { 111 | Route::bind('postSlug', function ($slug) { 112 | if (auth()->check()) { 113 | return Post::where('slug', $slug)->first() ?? abort(404); 114 | } 115 | 116 | $post = Post::where('slug', $slug)->public()->first() ?? abort(404); 117 | 118 | if (! $post->published) { 119 | abort(404); 120 | } 121 | 122 | return $post; 123 | }); 124 | 125 | Route::bind('tagSlug', function ($slug) { 126 | return Tag::where('slug->en', $slug)->first() ?? abort(404); 127 | }); 128 | } 129 | 130 | /** 131 | * Console-specific booting. 132 | */ 133 | protected function bootForConsole() 134 | { 135 | // Publishing the configuration file. 136 | $this->publishes([ 137 | __DIR__.'/../config/blog.php' => config_path('blog.php'), 138 | __DIR__.'/../config/theme.php' => config_path('theme.php'), 139 | ], 'blog.config'); 140 | 141 | // Publishing the views. 142 | $this->publishes([ 143 | __DIR__.'/../resources/views' => base_path('resources/views/vendor/wingsline'), 144 | ], 'blog.views'); 145 | 146 | // Publishing the migrations. 147 | $this->publishes([ 148 | __DIR__.'/../database/migrations' => database_path('migrations'), 149 | ], 'blog.migrations'); 150 | 151 | // Publishing assets. 152 | $this->publishes([ 153 | __DIR__.'/../public' => public_path('vendor/wingsline-blog'), 154 | ], 'blog.assets'); 155 | 156 | // Publishing the translation files. 157 | /*$this->publishes([ 158 | __DIR__.'/../resources/lang' => resource_path('lang/vendor/wingsline'), 159 | ], 'blog.views');*/ 160 | 161 | // Registering package commands. 162 | // $this->commands([]); 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /src/Console/InstallCommand.php: -------------------------------------------------------------------------------- 1 | comment('Publishing the blog assets...'); 47 | // Backup 48 | $this->callSilent( 49 | 'vendor:publish', 50 | [ 51 | '--provider' => BackupServiceProvider::class, 52 | ] 53 | ); 54 | // CSP 55 | $this->callSilent( 56 | 'vendor:publish', 57 | [ 58 | '--tag' => 'config', 59 | '--provider' => CspServiceProvider::class, 60 | ] 61 | ); 62 | // RSS Feed 63 | $this->callSilent( 64 | 'vendor:publish', 65 | [ 66 | '--tag' => 'config', 67 | '--provider' => FeedServiceProvider::class, 68 | ] 69 | ); 70 | // media library 71 | $this->callSilent( 72 | 'vendor:publish', 73 | [ 74 | '--tag' => 'config', 75 | '--provider' => MediaLibraryServiceProvider::class, 76 | ] 77 | ); 78 | // check if media table exists 79 | if (! Schema::hasTable('media')) { 80 | $this->callSilent( 81 | 'vendor:publish', 82 | [ 83 | '--tag' => 'migrations', 84 | '--provider' => MediaLibraryServiceProvider::class, 85 | ] 86 | ); 87 | } 88 | 89 | // Missing page redirector 90 | $this->callSilent( 91 | 'vendor:publish', 92 | [ 93 | '--provider' => MissingPageRedirectorServiceProvider::class, 94 | ] 95 | ); 96 | // Response Cache 97 | $this->callSilent( 98 | 'vendor:publish', 99 | [ 100 | '--provider' => ResponseCacheServiceProvider::class, 101 | ] 102 | ); 103 | // tags 104 | $this->callSilent( 105 | 'vendor:publish', 106 | [ 107 | '--tag' => 'config', 108 | '--provider' => TagsServiceProvider::class, 109 | ] 110 | ); 111 | if (! Schema::hasTable('tags')) { 112 | $this->callSilent( 113 | 'vendor:publish', 114 | [ 115 | '--tag' => 'migrations', 116 | '--provider' => TagsServiceProvider::class, 117 | ] 118 | ); 119 | } 120 | // Blog migrations 121 | $this->callSilent('vendor:publish', ['--tag' => 'blog.config']); 122 | $this->callSilent('vendor:publish', ['--tag' => 'blog.migrations']); 123 | $this->callSilent('vendor:publish', ['--tag' => 'blog.assets']); 124 | $this->info('Blog scaffolding installed successfully.'); 125 | // run the migrations and seeds 126 | $this->comment('Running the database migrations...'); 127 | $this->call('migrate'); 128 | 129 | if (! file_exists(public_path('storage'))) { 130 | $this->call('storage:link'); 131 | } 132 | // Link the theme? 133 | if ($this->confirm('Link the theme\'s public assets?')) { 134 | $this->call('blog:theme-publish'); 135 | } 136 | // Seed the database 137 | if ($this->confirm('Seed the database (recommended for new installations)')) { 138 | $this->comment('Seeding the database with default data...'); 139 | $this->call('db:seed', ['--class' => UsersTableSeeder::class]); 140 | } 141 | 142 | $admin_url = url(config('blog.adminprefix')); 143 | $this->info('Installation complete. You can login to the admin '.$admin_url); 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /src/Console/PublishCommand.php: -------------------------------------------------------------------------------- 1 | call('vendor:publish', [ 28 | '--tag' => 'blog.assets', 29 | '--force' => true, 30 | ]); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Console/ThemePublishCommand.php: -------------------------------------------------------------------------------- 1 | error('The theme doesn\'t have any public assets.'); 31 | } 32 | 33 | $this->laravel->make('files')->delete(public_path('theme')); 34 | 35 | $this->laravel->make('files')->link( 36 | base_path('theme/public'), 37 | public_path('theme') 38 | ); 39 | 40 | $this->info('The theme\'s public assets were linked.'); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Facades/Blog.php: -------------------------------------------------------------------------------- 1 | validated(); 33 | $user->fill([ 34 | 'name' => $validated['name'], 35 | 'email' => $validated['email'], 36 | ]); 37 | 38 | if (null !== $validated['password']) { 39 | $user->password = Hash::make($validated['password']); 40 | } 41 | 42 | $user->save(); 43 | if (\count($user->getChanges())) { 44 | flash()->success('Account updated.'); 45 | } 46 | 47 | return redirect()->route('admin.account.edit'); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Http/Controllers/DashboardController.php: -------------------------------------------------------------------------------- 1 | limit(10)->get(); 25 | 26 | return view('blog::dashboard', compact('latest_posts')); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Http/Controllers/Front/HomeController.php: -------------------------------------------------------------------------------- 1 | public() 23 | ->orderBy('publish_date', 'desc') 24 | ->simplePaginate(20); 25 | 26 | $onFirstPage = $posts->onFirstPage(); 27 | 28 | return view('home.index', compact('posts', 'onFirstPage')); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Http/Controllers/Front/PostsController.php: -------------------------------------------------------------------------------- 1 | public() 22 | ->orderBy('publish_date', 'desc') 23 | ->withAllTags([$tag]) 24 | ->simplePaginate(50); 25 | 26 | return view('taggedPosts.index', compact('tag', 'posts')); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Http/Controllers/LoginController.php: -------------------------------------------------------------------------------- 1 | maxAttempts = config('blog.maxAttempts'); 31 | $this->middleware('guest')->except('logout'); 32 | } 33 | 34 | /** 35 | * Show the application's login form. 36 | * 37 | * @return \Illuminate\Http\Response 38 | */ 39 | public function showLoginForm() 40 | { 41 | return view('blog::auth.login'); 42 | } 43 | 44 | /** 45 | * Username field. 46 | * 47 | * @return string 48 | */ 49 | public function username() 50 | { 51 | return 'email'; 52 | } 53 | 54 | /** 55 | * Redirect after login. 56 | */ 57 | protected function redirectTo() 58 | { 59 | return config('blog.adminprefix'); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/Http/Controllers/PostsController.php: -------------------------------------------------------------------------------- 1 | publish_date = now(); 30 | 31 | return view('blog::posts.create', compact('post')); 32 | } 33 | 34 | /** 35 | * Remove the specified resource from storage. 36 | * 37 | * @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\Response 38 | * @throws \Exception 39 | */ 40 | public function destroy(Post $post) 41 | { 42 | $post->delete(); 43 | 44 | flash()->success('Post deleted.'); 45 | 46 | return redirect()->route('admin.posts.index'); 47 | } 48 | 49 | /** 50 | * Show the form for editing the specified resource. 51 | * 52 | * @param int $id 53 | * 54 | * @return \Illuminate\Contracts\View\Factory|\Illuminate\Http\Response|\Illuminate\View\View 55 | */ 56 | public function edit(Post $post) 57 | { 58 | return view('blog::posts.edit', compact('post')); 59 | } 60 | 61 | /** 62 | * Display a listing of the resource. 63 | * 64 | * @return \Illuminate\Contracts\View\Factory|\Illuminate\Http\Response|\Illuminate\View\View 65 | */ 66 | public function index() 67 | { 68 | $posts = Post::orderBy('publish_date', 69 | 'desc')->paginate(config('blog.per_page')); 70 | 71 | return view('blog::posts.index', compact('posts')); 72 | } 73 | 74 | /** 75 | * Generates a markdown preview for the post. 76 | * 77 | * @return array 78 | */ 79 | public function preview(Post $post) 80 | { 81 | $post->text = request('payload', ''); 82 | 83 | return ['data' => ['html' => $post->text]]; 84 | } 85 | 86 | /** 87 | * Store a newly created resource in storage. 88 | * 89 | * @param \Illuminate\Http\Request $request 90 | * 91 | * @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse 92 | */ 93 | public function store(PostRequest $request) 94 | { 95 | $post = (new Post())->updateAttributes($request->validated()); 96 | 97 | flash()->success('Post saved.'); 98 | 99 | return redirect()->route('admin.posts.edit', $post); 100 | } 101 | 102 | /** 103 | * Update the specified resource in storage. 104 | * 105 | * @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse 106 | */ 107 | public function update(PostRequest $request, Post $post) 108 | { 109 | $post->updateAttributes($request->validated()); 110 | 111 | flash()->success('Post updated.'); 112 | 113 | return redirect()->route('admin.posts.edit', $post); 114 | } 115 | 116 | /** 117 | * Upload an image. 118 | * 119 | * @return array|\Illuminate\Http\JsonResponse 120 | */ 121 | public function upload(Post $post, ImageUploadRequest $request) 122 | { 123 | try { 124 | $media = $post->addMedia($request->file('image')) 125 | ->toMediaCollection('images'); 126 | } catch (FileCannotBeAdded $exception) { 127 | return response()->json(['error' => $exception->getMessage()], 422); 128 | } 129 | 130 | return [ 131 | 'data' => [ 132 | 'filePath' => ltrim( 133 | parse_url($media->getFullUrl(), 134 | PHP_URL_PATH), 135 | '/' 136 | ), 137 | ], 138 | ]; 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /src/Http/Middleware/Authenticate.php: -------------------------------------------------------------------------------- 1 | expectsJson()) { 19 | return route('admin.login'); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Http/Middleware/NoHttpCache.php: -------------------------------------------------------------------------------- 1 | header('Pragma', 'no-cache'); 21 | $response->header('Expires', 'Fri, 01 Jan 1990 00:00:00 GMT'); 22 | $response->header( 23 | 'Cache-Control', 24 | 'no-cache, must-revalidate, no-store, max-age=0, private' 25 | ); 26 | 27 | return $response; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Http/Requests/AccountEditRequest.php: -------------------------------------------------------------------------------- 1 | user(); 27 | 28 | return [ 29 | 'name' => ['required', 'string', 'max:255'], 30 | 'email' => [ 31 | 'required', 32 | 'string', 33 | 'email', 34 | 'max:255', 35 | 'unique:users,email,'.$auth_user->id, 36 | ], 37 | 'password' => [ 38 | 'present', 39 | 'string', 40 | 'nullable', 41 | 'min:8', 42 | 'confirmed', 43 | ], 44 | 'password_confirmation' => ['present', 'string', 'nullable'], 45 | ]; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Http/Requests/ImageUploadRequest.php: -------------------------------------------------------------------------------- 1 | [ 32 | 'required', 33 | 'mimes:jpeg,png', 34 | 'image', 35 | 'max:'.$size, 36 | ], 37 | ]; 38 | } 39 | 40 | protected function failedValidation(Validator $validator) 41 | { 42 | // make sure we return the proper error for easymde 43 | throw new HttpResponseException( 44 | response()->json(['error' => $validator->errors()->first('image')], 45 | 422) 46 | ); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Http/Requests/PostRequest.php: -------------------------------------------------------------------------------- 1 | 'required', 28 | 'text' => 'required', 29 | 'publish_date' => 'date', 30 | 'published' => 'boolean', 31 | 'original_content' => 'boolean', 32 | 'tags_text' => 'present', 33 | 'external_url' => '', 34 | ]; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Markdown/Markdown.php: -------------------------------------------------------------------------------- 1 | getImagePixelDensity($image_url); 38 | $result .= '"'; 39 | 40 | return $result; 41 | } 42 | 43 | /** 44 | * Converts markdown to html. 45 | */ 46 | public function convertToHtml(string $markdown): string 47 | { 48 | return static::defaultTransform($markdown); 49 | } 50 | 51 | /** 52 | * Static method to convert markdown to html. 53 | * 54 | * @return string 55 | */ 56 | public static function convertWithParser(string $markdown) 57 | { 58 | $method = config('blog.markdown_parser.method'); 59 | 60 | return app(config('blog.markdown_parser.class')) 61 | ->{$method}($markdown); 62 | } 63 | 64 | /** 65 | * Returns 2x if the image is high pixel density. 66 | * 67 | * @param string $image_url 68 | * 69 | * @return string 70 | */ 71 | public function getImagePixelDensity($image_url) 72 | { 73 | // Currently we support only imagick 74 | if (! \extension_loaded('imagick')) { 75 | return ''; 76 | } 77 | 78 | try { 79 | $manager = new ImageManager(['driver' => 'imagick']); 80 | $img = $manager->make($image_url)->getCore(); 81 | } catch (\Exception $e) { 82 | return ''; 83 | } 84 | 85 | $unit = $img->getImageUnits(); 86 | $resolution = array_sum($img->getImageResolution()); 87 | 88 | // Based on the units we determine if the image is high dpi. If no 89 | // resolution is set, we default to high dpi, since imagick cannot 90 | // reliably detect for example phone screenshot resolutions. 91 | $pixel_density = ' '; 92 | 93 | switch ($unit) { 94 | case \imagick::RESOLUTION_PIXELSPERINCH: 95 | $max_resolution = (static::MAX_POINT_PER_INCH * 2); 96 | $pixel_density .= $resolution > $max_resolution ? static::HIGH_PIXEL_DENSITY : ''; 97 | 98 | break; 99 | case \imagick::RESOLUTION_PIXELSPERCENTIMETER: 100 | $max_resolution = (static::MAX_POINT_PER_INCH * 2) / 2.54; 101 | $pixel_density .= $resolution > $max_resolution ? static::HIGH_PIXEL_DENSITY : ''; 102 | 103 | break; 104 | default: 105 | $pixel_density .= static::HIGH_PIXEL_DENSITY; 106 | 107 | break; 108 | } 109 | 110 | return rtrim($pixel_density); 111 | } 112 | 113 | /** 114 | * Callback for inline images. 115 | * 116 | * @param array $matches 117 | * 118 | * @return string 119 | */ 120 | protected function _doImages_inline_callback($matches) 121 | { 122 | $whole_match = $matches[1]; 123 | $alt_text = $matches[2]; 124 | $url = '' == $matches[3] ? $matches[4] : $matches[3]; 125 | $title = &$matches[7]; 126 | $attr = $this->doExtraAttributes('img', $dummy = &$matches[8]); 127 | 128 | $alt_text = $this->encodeAttribute($alt_text); 129 | $url = $this->encodeURLAttribute($url); 130 | $result = "\"${alt_text}\"";encodeAttribute($title); 133 | $result .= " title=\"${title}\""; // $title already quoted 134 | } 135 | $result .= $attr; 136 | // srcset 137 | $result .= $this->addSrcSet($url); 138 | $result .= $this->empty_element_suffix; 139 | 140 | return $this->hashPart($result); 141 | } 142 | 143 | /** 144 | * Callback for referenced images. 145 | * 146 | * @param array $matches 147 | * 148 | * @return string 149 | */ 150 | protected function _doImages_reference_callback($matches) 151 | { 152 | $whole_match = $matches[1]; 153 | $alt_text = $matches[2]; 154 | $link_id = strtolower($matches[3]); 155 | 156 | if ('' == $link_id) { 157 | $link_id = strtolower($alt_text); // for shortcut links like ![this][]. 158 | } 159 | 160 | $alt_text = $this->encodeAttribute($alt_text); 161 | if (isset($this->urls[$link_id])) { 162 | $url = $this->encodeURLAttribute($this->urls[$link_id]); 163 | $result = "\"${alt_text}\"";titles[$link_id])) { 165 | $title = $this->titles[$link_id]; 166 | $title = $this->encodeAttribute($title); 167 | $result .= " title=\"${title}\""; 168 | } 169 | if (isset($this->ref_attr[$link_id])) { 170 | $result .= $this->ref_attr[$link_id]; 171 | } 172 | // srcset 173 | $result .= $this->addSrcSet($url); 174 | $result .= $this->empty_element_suffix; 175 | $result = $this->hashPart($result); 176 | } else { 177 | // If there's no such link ID, leave intact: 178 | $result = $whole_match; 179 | } 180 | 181 | return $result; 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /src/Posts/Post.php: -------------------------------------------------------------------------------- 1 | '', 26 | 'published' => 'boolean', 27 | 'original_content' => 'boolean', 28 | ]; 29 | 30 | public $dates = ['publish_date']; 31 | public $with = ['tags']; 32 | 33 | /** 34 | * The table associated with the model. 35 | * 36 | * @var string 37 | */ 38 | protected $table = 'posts'; 39 | 40 | public static function getFeedItems() 41 | { 42 | return static::published() 43 | ->public() 44 | ->orderBy('publish_date', 'desc') 45 | ->limit(100) 46 | ->get(); 47 | } 48 | 49 | /** 50 | * Markdown accessor. 51 | * 52 | * @return string 53 | */ 54 | public function getMarkdownAttribute() 55 | { 56 | return $this->getRawOriginal('text'); 57 | } 58 | 59 | /** 60 | * Slug options. 61 | */ 62 | public function getSlugOptions(): SlugOptions 63 | { 64 | return SlugOptions::create() 65 | ->generateSlugsFrom('title') 66 | ->saveSlugsTo('slug'); 67 | } 68 | 69 | /** 70 | * Text accessor. 71 | * 72 | * @param string $original 73 | * 74 | * @return string 75 | */ 76 | public function getTextAttribute($original) 77 | { 78 | return Markdown::convertWithParser($original); 79 | } 80 | 81 | public function scopePublic(Builder $query) 82 | { 83 | $query->where('publish_date', '<=', now()); 84 | } 85 | 86 | public function scopePublished(Builder $query) 87 | { 88 | $query->where('published', true); 89 | } 90 | 91 | /** 92 | * @return array|\Spatie\Feed\FeedItem 93 | */ 94 | public function toFeedItem() 95 | { 96 | return FeedItem::create() 97 | ->id($this->id) 98 | ->title($this->formatted_title) 99 | ->summary($this->text) 100 | ->updated($this->publish_date) 101 | ->link($this->url) 102 | ->author($this->author); 103 | } 104 | 105 | /** 106 | * Update model attributes from the form. 107 | * 108 | * @return static 109 | */ 110 | public function updateAttributes(array $attributes) 111 | { 112 | $this->title = $attributes['title']; 113 | $this->text = $attributes['text']; 114 | $this->publish_date = $attributes['publish_date']; 115 | $this->published = $attributes['published'] ?? false; 116 | $this->original_content = $attributes['original_content'] ?? false; 117 | $this->external_url = $attributes['external_url']; 118 | $this->author = Auth::user()->name; 119 | 120 | $this->save(); 121 | 122 | if ($attributes['tags_text']) { 123 | $tags = array_map(function (string $tag) { 124 | return trim(strtolower($tag)); 125 | }, explode(',', $attributes['tags_text'])); 126 | 127 | $this->syncTags($tags); 128 | } 129 | 130 | return $this; 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/Posts/PostObserver.php: -------------------------------------------------------------------------------- 1 | clearResponseCache($post); 17 | } 18 | 19 | /** 20 | * Handle the Post "deleted" event. 21 | * 22 | * @return void 23 | */ 24 | public function deleted(Post $post) 25 | { 26 | $this->clearResponseCache($post); 27 | } 28 | 29 | /** 30 | * Handle the Post "updated" event. 31 | * 32 | * @return void 33 | */ 34 | public function updated(Post $post) 35 | { 36 | $this->clearResponseCache($post); 37 | } 38 | 39 | /** 40 | * Clears the respoonse cache. 41 | */ 42 | protected function clearResponseCache(Post $post) 43 | { 44 | ResponseCache::clear(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Posts/PostPresenter.php: -------------------------------------------------------------------------------- 1 | external_url) { 14 | return $this->text; 15 | } 16 | 17 | $excerpt = trim($this->text); 18 | 19 | // before the 1st blockquote 20 | $excerpt = Str::before($excerpt, '
    '); 21 | 22 | // after the h1, since we should have only one h1 on top of the article 23 | $excerpt = Str::after($excerpt, ''); 24 | 25 | // remove html 26 | $excerpt = strip_tags($excerpt); 27 | 28 | // replace multiple spaces 29 | $excerpt = preg_replace('/\\s+/', ' ', $excerpt); 30 | 31 | if (0 == \strlen($excerpt)) { 32 | return ''; 33 | } 34 | 35 | if (\strlen($excerpt) <= 150) { 36 | return $excerpt; 37 | } 38 | 39 | $ww = wordwrap($excerpt, 150, "\n"); 40 | 41 | $excerpt = substr($ww, 0, strpos($ww, "\n")).'…'; 42 | 43 | return $excerpt; 44 | } 45 | 46 | public function getFormattedTitleAttribute(): string 47 | { 48 | $prefix = $this->original_content 49 | ? '★ ' 50 | : ''; 51 | 52 | return $prefix.$this->title; 53 | } 54 | 55 | public function getTagsTextAttribute(): string 56 | { 57 | return $this 58 | ->tags 59 | ->pluck('name') 60 | ->implode(', '); 61 | } 62 | 63 | public function getUrlAttribute(): string 64 | { 65 | if ($this->external_url) { 66 | return $this->external_url; 67 | } 68 | 69 | return route('post', $this->slug); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | purge: [ 3 | "./src/**/*.php", 4 | "./resources/views/**/*.php", 5 | "./resources/js/**/*.js", 6 | "./node_modules/codemirror/**/*.js", 7 | "./node_modules/highlight.js/**/*.js", 8 | ], 9 | future: { 10 | removeDeprecatedGapUtilities: true, 11 | }, 12 | theme: { 13 | container: { 14 | center: true 15 | }, 16 | extend: { 17 | colors: { 18 | "white-50": "hsla(0, 0%, 100%, 0.5)", 19 | "white-90": "hsla(0, 0%, 100%, 0.97)" 20 | } 21 | } 22 | }, 23 | variants: {}, 24 | plugins: [] 25 | }; 26 | -------------------------------------------------------------------------------- /webpack.mix.js: -------------------------------------------------------------------------------- 1 | const mix = require('laravel-mix'); 2 | const autoprefixer = require("autoprefixer"); 3 | const postcssDiscardComments = require("postcss-discard-comments"); 4 | const postCssImport = require("postcss-import"); 5 | const postInlineSvg = require("postcss-inline-svg"); 6 | const tailwindcss = require("tailwindcss"); 7 | require("laravel-mix-purgecss"); 8 | /* 9 | |-------------------------------------------------------------------------- 10 | | Mix Asset Management 11 | |-------------------------------------------------------------------------- 12 | | 13 | | Mix provides a clean, fluent API for defining some Webpack build steps 14 | | for your Laravel application. By default, we are compiling the Sass 15 | | file for the application as well as bundling up all the JS files. 16 | | 17 | */ 18 | 19 | const postCssOptions = [ 20 | postCssImport(), 21 | tailwindcss(), 22 | postInlineSvg(), 23 | autoprefixer(), 24 | postcssDiscardComments({ 25 | removeAll: true 26 | }) 27 | ]; 28 | 29 | mix.options({ 30 | autoprefixer: false, 31 | processCssUrls: false, 32 | postCss: postCssOptions, 33 | terser: { 34 | terserOptions: { 35 | compress: { 36 | drop_console: true, 37 | }, 38 | }, 39 | }, 40 | }) 41 | .setPublicPath('public') 42 | .copyDirectory("resources/fonts", "public/fonts") 43 | .postCss("resources/css/main.css", "public") 44 | .js("resources/js/app.js", "public") 45 | .version() 46 | .extract() 47 | .webpackConfig({ 48 | resolve: { 49 | symlinks: false, 50 | alias: { 51 | '@': path.resolve(__dirname, 'resources/js/'), 52 | }, 53 | } 54 | }); 55 | --------------------------------------------------------------------------------