├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── better-log-viewer.png ├── composer.json ├── fonts └── vendor │ └── font-awesome │ ├── fontawesome-webfont.eot │ ├── fontawesome-webfont.svg │ ├── fontawesome-webfont.ttf │ ├── fontawesome-webfont.woff │ └── fontawesome-webfont.woff2 ├── package-lock.json ├── package.json ├── public ├── css │ └── app.css └── js │ └── app.js ├── readme.md ├── src ├── BetterLogViewerProvider.php ├── FileLogViewerService.php ├── Http │ └── Controllers │ │ ├── Api │ │ └── LogsController.php │ │ ├── AssetController.php │ │ └── LogViewerController.php ├── Tools │ └── BladeDirectives.php ├── config │ └── better-log-viewer.php ├── resources │ ├── js │ │ ├── app.js │ │ ├── bootstrap.js │ │ ├── components │ │ │ ├── AppLayout.vue │ │ │ ├── Btn.vue │ │ │ ├── Dropdown.vue │ │ │ ├── LogFile.vue │ │ │ ├── LogItem.vue │ │ │ ├── LogList.vue │ │ │ ├── Modal.vue │ │ │ ├── Paginate.vue │ │ │ ├── SettingsControl.vue │ │ │ ├── SidebarNav.vue │ │ │ └── Spinner.vue │ │ └── settings.js │ ├── sass │ │ ├── _variables.scss │ │ └── app.scss │ └── views │ │ └── logs │ │ └── index.blade.php └── routes │ ├── api.php │ ├── assets.php │ └── web.php ├── tailwind.js └── webpack.mix.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | mix-manifest.json 3 | .vscode/ 4 | .idea/ -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.8.0 2 | 3 | (new) Support for Laravel 9.x. 4 | (fix) NPM dependency security fixes 5 | (change) increased maximum log file size from 50 MB to 100 MB. 6 | 7 | ## 0.7.0 8 | 9 | (fix) Fix an issue with Laravel 7/8 generated logs not being parsed correctly 10 | (fix) NPM dependency security fixes 11 | 12 | ## 0.6.0 13 | 14 | (new) Support for Laravel 8.x. 15 | 16 | ## 0.5.2 17 | 18 | (fix) Missing namespace on index page 19 | (fix) NPM dependency security fixes 20 | 21 | ## 0.5.1 22 | 23 | (fix) Clicking on the stack trace no longer collapses the entry. 24 | 25 | ## 0.5.0 26 | 27 | (new) Support for Laravel 7.x. 28 | 29 | ## 0.4.0 30 | 31 | (new) Support for Laravel 6.x. 32 | 33 | ## 0.3.1 34 | 35 | (fix) NPM dependency security fixes. 36 | 37 | ## 0.3.0 38 | 39 | (new) You can now filter out some parts of the stack trace for easier lookup. 40 | (update) Full screen toggle has been moved to the "Settings" dropdown, along with the Shorter Stack Traces toggle. 41 | (update) Better Log Viewer now remembers even more of the settings. Active log levels, as well as pagination result size is now saved in your browser's localStorage along with the settings from the "Settings" dropdown. 42 | (fix) Fix the left sidebar to be full screen height. 43 | (fix) Security update to our `lodash` dependency. 44 | 45 | ## 0.2.6 46 | 47 | (fix) Security update of our dependencies `axios` and `js-yaml`. 48 | 49 | ## 0.2.5 50 | 51 | (fix) Fixes an issue where having a non-empty query while changing files would throw an error. 52 | (fix) Fixes occasional duplicate log loading when changing files. 53 | 54 | ## 0.2.4 55 | 56 | Initial release, the first point of this Changelog. 57 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Arunas Skirius 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /better-log-viewer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arukompas/better-log-viewer/1ab2c2c7ef1f4cc6fcbaf17c34ef378e2c06c233/better-log-viewer.png -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "arukompas/better-log-viewer", 3 | "description": "A speedy and clean Laravel Log viewer with pagination and search", 4 | "type": "library", 5 | "version": "0.8.0", 6 | "license": "MIT", 7 | "authors": [ 8 | { 9 | "name": "Arunas Skirius", 10 | "email": "arukomp@gmail.com" 11 | } 12 | ], 13 | "minimum-stability": "dev", 14 | "require": { 15 | "php": ">=5.6", 16 | "laravel/framework": "5.x || 6.x || 7.x || 8.x || 9.x" 17 | }, 18 | "autoload": { 19 | "psr-4": { 20 | "Arukompas\\BetterLogViewer\\": "src/" 21 | } 22 | }, 23 | "extra": { 24 | "laravel": { 25 | "providers": [ 26 | "Arukompas\\BetterLogViewer\\BetterLogViewerProvider" 27 | ] 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /fonts/vendor/font-awesome/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arukompas/better-log-viewer/1ab2c2c7ef1f4cc6fcbaf17c34ef378e2c06c233/fonts/vendor/font-awesome/fontawesome-webfont.eot -------------------------------------------------------------------------------- /fonts/vendor/font-awesome/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arukompas/better-log-viewer/1ab2c2c7ef1f4cc6fcbaf17c34ef378e2c06c233/fonts/vendor/font-awesome/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /fonts/vendor/font-awesome/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arukompas/better-log-viewer/1ab2c2c7ef1f4cc6fcbaf17c34ef378e2c06c233/fonts/vendor/font-awesome/fontawesome-webfont.woff -------------------------------------------------------------------------------- /fonts/vendor/font-awesome/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arukompas/better-log-viewer/1ab2c2c7ef1f4cc6fcbaf17c34ef378e2c06c233/fonts/vendor/font-awesome/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /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.2", 14 | "cross-env": "^5.2.1", 15 | "laravel-mix": "^4.1.4", 16 | "laravel-mix-tailwind": "^0.1.0", 17 | "resolve-url-loader": "2.3.1", 18 | "sass": "^1.23.0", 19 | "sass-loader": "^7.3.1", 20 | "tailwindcss": "^0.7.4", 21 | "vue": "^2.6.10", 22 | "object-path": "^0.11.8", 23 | "vue-template-compiler": "^2.6.10" 24 | }, 25 | "dependencies": { 26 | "sweetalert": "^2.1.2", 27 | "vue-clickaway": "^2.2.2", 28 | "vue-snotify": "^3.2.1" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | > :warning: **This package is no longer maintained.** 2 | > 3 | > Brand new Log Viewer, written from scratch, is available at [https://github.com/opcodesio/log-viewer](https://github.com/opcodesio/log-viewer) 4 | 5 | --- 6 | 7 | [![Packagist](https://img.shields.io/packagist/v/arukompas/better-log-viewer.svg)](https://packagist.org/packages/arukompas/better-log-viewer) 8 | [![Packagist](https://img.shields.io/packagist/dm/arukompas/better-log-viewer.svg)](https://packagist.org/packages/arukompas/better-log-viewer) 9 | [![PHP from Packagist](https://img.shields.io/packagist/php-v/arukompas/better-log-viewer.svg)](https://packagist.org/packages/arukompas/better-log-viewer) 10 | [![Laravel Version](https://img.shields.io/badge/Laravel-5.x,%206.x,%207.x,%208.x,%209.x-brightgreen.svg)](https://packagist.org/packages/arukompas/better-log-viewer) 11 | 12 | 13 | # Better Log Viewer 14 | 15 | Better Log Viewer is a Laravel package for viewing your Laravel logs in a clean and intuitive web interface. 16 | 17 | **Supports all Laravel 5, 6, 7, 8 and 9 versions.** 18 | 19 | 20 | ![Better Log Viewer](better-log-viewer.png) 21 | 22 | 23 | ## Installation 24 | 25 | ### 1. Require the package 26 | 27 | ``` 28 | composer require arukompas/better-log-viewer 29 | ``` 30 | 31 | ### 2. (Laravel 5.4 and older only) - Provider 32 | 33 | Add the service provider to your `config/app.php` configuration's `'providers'` array: 34 | 35 | ``` 36 | Arukompas\BetterLogViewer\BetterLogViewerProvider::class, 37 | ``` 38 | 39 | ### 3. (optional) Publish the config 40 | 41 | You can publish the config using this artisan command: 42 | ``` 43 | php artisan vendor:publish --tag=config 44 | ``` 45 | 46 | ### 4. Visit `/log-viewer` 47 | 48 | ## Configuration 49 | 50 | You can configure the middleware and the route for the log viewer in the `config/better-log-viewer.php` file which was previously copied over by the vendor publish command. 51 | -------------------------------------------------------------------------------- /src/BetterLogViewerProvider.php: -------------------------------------------------------------------------------- 1 | mapWebRoutes(); 22 | $this->mapApiRoutes(); 23 | $this->mapAssetRoutes(); 24 | $this->loadTools(); 25 | 26 | $this->publishes([ 27 | __DIR__.'/config/better-log-viewer.php' => config_path('better-log-viewer.php'), 28 | ], 'config'); 29 | } 30 | 31 | /** 32 | * Register services. 33 | * 34 | * @return void 35 | */ 36 | public function register() 37 | { 38 | $this->loadViewsFrom(__DIR__.'/resources/views', 'better-log-viewer'); 39 | 40 | $this->mergeConfigFrom( 41 | __DIR__.'/config/better-log-viewer.php', 'better-log-viewer' 42 | ); 43 | } 44 | 45 | protected function mapWebRoutes() 46 | { 47 | Route::group([ 48 | 'prefix' => config('better-log-viewer.route_path', 'log-viewer'), 49 | 'middleware' => config('better-log-viewer.middleware', ''), 50 | 'namespace' => $this->namespace, 51 | ], function () { 52 | require __DIR__.'/routes/web.php'; 53 | }); 54 | } 55 | 56 | protected function mapApiRoutes() 57 | { 58 | Route::group([ 59 | 'prefix' => Str::finish(config('better-log-viewer.route_path'), '/') . 'api', 60 | 'middleware' => config('better-log-viewer.api_middleware', ''), 61 | 'namespace' => $this->namespace . '\Api', 62 | ], function () { 63 | require __DIR__.'/routes/api.php'; 64 | }); 65 | } 66 | 67 | protected function mapAssetRoutes() 68 | { 69 | Route::group([ 70 | 'prefix' => Str::finish(config('better-log-viewer.route_path', 'log-viewer'), '/') . 'assets', 71 | 'middleware' => config('better-log-viewer.api_middleware', ''), 72 | 'namespace' => $this->namespace, 73 | ], function () { 74 | require __DIR__.'/routes/assets.php'; 75 | }); 76 | } 77 | 78 | protected function loadTools() 79 | { 80 | (new BladeDirectives)->load(); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/FileLogViewerService.php: -------------------------------------------------------------------------------- 1 | '/\[\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(\.\d{6}[\+-]\d\d:\d\d)?\].*/', 22 | 'current_log' => [ 23 | '/^\[(\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(\.\d{6}[\+-]\d\d:\d\d)?)\](?:.*?(\w+)\.|.*?)', 24 | ': (.*?)( in .*?:[0-9]+)?$/i' 25 | ], 26 | 'files' => '/\{.*?\,.*?\}/i', 27 | ]; 28 | 29 | /** 30 | * @var array 31 | */ 32 | public $levels_classes = [ 33 | 'debug' => 'info', 34 | 'info' => 'info', 35 | 'notice' => 'info', 36 | 'warning' => 'warning', 37 | 'error' => 'danger', 38 | 'critical' => 'danger', 39 | 'alert' => 'danger', 40 | 'emergency' => 'danger', 41 | 'processed' => 'info', 42 | 'failed' => 'warning', 43 | ]; 44 | /** 45 | * @var array 46 | */ 47 | private $levels_imgs = [ 48 | 'debug' => 'info-circle', 49 | 'info' => 'info-circle', 50 | 'notice' => 'info-circle', 51 | 'warning' => 'exclamation-triangle', 52 | 'error' => 'exclamation-triangle', 53 | 'critical' => 'exclamation-triangle', 54 | 'alert' => 'exclamation-triangle', 55 | 'emergency' => 'exclamation-triangle', 56 | 'processed' => 'info-circle', 57 | 'failed' => 'exclamation-triangle' 58 | ]; 59 | 60 | public function getFiles($withCachedCounts = false) 61 | { 62 | $files = []; 63 | foreach (config('better-log-viewer.include_files', []) as $pattern) { 64 | $files = array_merge($files, glob(storage_path() . '/logs/' . $pattern)); 65 | } 66 | 67 | foreach (config('better-log-viewer.exclude_files', []) as $pattern) { 68 | $files = array_diff($files, glob(storage_path() . '/logs/' . $pattern)); 69 | } 70 | 71 | $files = array_reverse($files); 72 | $files = array_filter($files, 'is_file'); 73 | 74 | if (is_array($files)) { 75 | foreach ($files as $k => $file) { 76 | $fileEntry = [ 77 | 'public_url' => route('better-log-viewer::api.logs.show', basename($file)), 78 | 'name' => basename($file), 79 | 'path' => $file, 80 | 'size' => filesize($file), 81 | ]; 82 | 83 | if ($withCachedCounts) { 84 | $key = $file . '::' . md5_file($file) . '::counts'; 85 | 86 | if (Cache::has($key)) { 87 | $counts = Cache::get($key); 88 | $fileEntry['counts'] = $counts; 89 | } 90 | } 91 | 92 | $files[$k] = $fileEntry; 93 | } 94 | } 95 | 96 | return collect($files)->sortByDesc('name'); 97 | } 98 | 99 | public function getFile($name) 100 | { 101 | $files = $this->getFiles(); 102 | 103 | foreach ($files as $file) { 104 | if ($file['name'] == $name) { 105 | return $file; 106 | } 107 | } 108 | } 109 | 110 | public function getLevelCountsForFile($file) 111 | { 112 | $key = $file['path'] . '::' . md5_file($file['path']) . '::counts'; 113 | 114 | if (Cache::has($key)) { 115 | $counts = Cache::get($key); 116 | } else { 117 | $counts = []; 118 | 119 | foreach (array_keys($this->levels_classes) as $level) { 120 | $counts[$level] = [ 121 | 'count' => 0, 122 | 'level_class' => $this->levels_classes[$level] 123 | ]; 124 | } 125 | 126 | $this->getLogsForFile($file, null, $counts); 127 | 128 | Cache::put($key, $counts, 60 * 24 * 30); // 30 days expiry 129 | } 130 | 131 | return $counts; 132 | } 133 | 134 | public function getLogsForFile($file, $levels = null, &$count = null) 135 | { 136 | if (is_null($levels)) { 137 | $levels = array_keys($this->levels_classes); 138 | } 139 | 140 | $log = array(); 141 | 142 | if (app('files')->size($file['path']) > self::MAX_FILE_SIZE) { 143 | return null; 144 | } 145 | 146 | $file = app('files')->get($file['path']); 147 | $headings = null; 148 | preg_match_all($this->patterns['logs'], $file, $headings); 149 | 150 | if (!is_array($headings)) { 151 | return $log; 152 | } 153 | 154 | $log_data = preg_split($this->patterns['logs'], $file); 155 | 156 | if ($log_data[0] < 1) { 157 | array_shift($log_data); 158 | } 159 | 160 | $timezone = config('app.timezone', 'UTC'); 161 | 162 | foreach ($headings as $h) { 163 | for ($i = 0, $j = count($h); $i < $j; $i++) { 164 | foreach (array_keys($this->levels_classes) as $level) { 165 | if (strpos(strtolower($h[$i]), '.' . $level) || strpos(strtolower($h[$i]), $level . ':')) { 166 | $current = []; 167 | preg_match($this->patterns['current_log'][0] . $level . $this->patterns['current_log'][1], $h[$i], $current); 168 | 169 | if (!isset($current[4])) continue; 170 | 171 | if (in_array($level, $levels)) { 172 | $log[] = array( 173 | 'context' => $current[3], 174 | 'level' => $level, 175 | 'level_class' => $this->levels_classes[$level], 176 | 'level_img' => $this->levels_imgs[$level], 177 | 'date' => Carbon::parse($current[1])->tz($timezone)->toDateTimeString(), 178 | 'text' => mb_convert_encoding($current[4], 'UTF-8', 'UTF-8'), 179 | 'in_file' => isset($current[5]) ? $current[5] : null, 180 | 'stack' => mb_convert_encoding(preg_replace("/^\n*/", '', $log_data[$i]), 'UTF-8', 'UTF-8') 181 | ); 182 | } 183 | 184 | if (!is_null($count) && isset($count[$level])) { 185 | $count[$level]['count']++; 186 | } 187 | } 188 | } 189 | } 190 | } 191 | 192 | if (empty($log)) { 193 | $lines = explode(PHP_EOL, $file); 194 | $log = []; 195 | foreach ($lines as $key => $line) { 196 | $log[] = [ 197 | 'context' => '', 198 | 'level' => '', 199 | 'level_class' => '', 200 | 'level_img' => '', 201 | 'date' => $key + 1, 202 | 'text' => $line, 203 | 'in_file' => null, 204 | 'stack' => '', 205 | ]; 206 | } 207 | } 208 | 209 | return array_reverse($log); 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /src/Http/Controllers/Api/LogsController.php: -------------------------------------------------------------------------------- 1 | getFiles(true); 17 | } 18 | 19 | public function show(Request $request, $name, FileLogViewerService $logViewer) 20 | { 21 | $levels = explode(",", $request->query('levels', '')); 22 | $perPage = (int)$request->query('perPage', 10); 23 | $query = $request->query('query', ''); 24 | $counts = []; 25 | foreach (array_keys($logViewer->levels_classes) as $level) { 26 | $counts[$level] = [ 27 | 'count' => 0, 28 | 'level_class' => $logViewer->levels_classes[$level] 29 | ]; 30 | } 31 | 32 | if (empty($levels) || (count($levels) == 1) && $levels[0] == '') { 33 | $logs = []; 34 | } else { 35 | $file = $logViewer->getFile($name); 36 | $logs = collect($logViewer->getLogsForFile($file, $levels)); 37 | } 38 | 39 | if (!empty($query)) { 40 | $query = "/" . $query . "/i"; 41 | $logs = $logs->filter(function ($log) use ($query) { 42 | return preg_match($query, $log['date']) 43 | || preg_match($query, $log['text']) 44 | || preg_match($query, $log['stack']); 45 | }); 46 | } 47 | 48 | return array_merge($this->paginate($logs, $perPage)->toArray(), [ 49 | 'counts' => $counts, 50 | 'response_time' => microtime(true) - LARAVEL_START, 51 | 'response_peak_memory' => memory_get_peak_usage() 52 | ]); 53 | } 54 | 55 | public function download($name, FileLogViewerService $logViewer) 56 | { 57 | $file = $logViewer->getFile($name); 58 | 59 | if ($file && app('files')->exists($file['path'])) { 60 | return response()->download($file['path']); 61 | } 62 | 63 | abort(404); 64 | } 65 | 66 | public function destroy($name, FileLogViewerService $logViewer) 67 | { 68 | $file = $logViewer->getFile($name); 69 | 70 | if ($file && app('files')->exists($file['path'])) { 71 | app('files')->delete($file['path']); 72 | } 73 | 74 | return response(['success' => true], 200); 75 | } 76 | 77 | public function levelCounts($name, FileLogViewerService $logViewer) 78 | { 79 | $file = $logViewer->getFile($name); 80 | 81 | if ($file) { 82 | return $logViewer->getLevelCountsForFile($file); 83 | } 84 | 85 | return []; 86 | } 87 | 88 | /** 89 | * Paginate a collection of items 90 | * 91 | * @param array|Collection $items 92 | * @param int $perPage 93 | * @param int $page 94 | * @param array $options 95 | * 96 | * @return LengthAwarePaginator 97 | */ 98 | protected function paginate($items, $perPage = 10, $page = null, $options = []) 99 | { 100 | $page = $page ?: (Paginator::resolveCurrentPage() ?: 1); 101 | $items = $items instanceof Collection ? $items : Collection::make($items); 102 | return new LengthAwarePaginator($items->forPage($page, $perPage), $items->count(), $perPage, $page, $options); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/Http/Controllers/AssetController.php: -------------------------------------------------------------------------------- 1 | make(file_get_contents(__DIR__.'/../../../public/css/app.css'), 200) 14 | ->header('Content-Type', 'text/css'); 15 | } 16 | 17 | public function js() 18 | { 19 | return response() 20 | ->make(file_get_contents(__DIR__.'/../../../public/js/app.js'), 200) 21 | ->header('Content-Type', 'application/javascript'); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Http/Controllers/LogViewerController.php: -------------------------------------------------------------------------------- 1 | registerAssetDirectives(); 17 | } 18 | 19 | /** 20 | * Register asset directives. 21 | * 22 | * @return void 23 | */ 24 | public function registerAssetDirectives() 25 | { 26 | Blade::directive('better_log_viewer_css', function() { 27 | return "getAssetPath()."/css/app.css')); ?>\">"; 28 | }); 29 | 30 | Blade::directive('better_log_viewer_js', function() { 31 | return ""; 32 | }); 33 | } 34 | 35 | protected function getAssetPath() 36 | { 37 | return __DIR__.'/../../public'; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/config/better-log-viewer.php: -------------------------------------------------------------------------------- 1 | 'log-viewer', 8 | 9 | /** 10 | * Log Viewer route middleware 11 | */ 12 | 'middleware' => [], 13 | 14 | /** 15 | * Log Viewer API middleware 16 | */ 17 | 'api_middleware' => [], 18 | 19 | /** 20 | * Include file patterns 21 | */ 22 | 'include_files' => ['*.log'], 23 | 24 | /** 25 | * Exclude file patterns. This will take precedence 26 | */ 27 | 'exclude_files' => [], 28 | 29 | /** 30 | * Shorter stack trace filters. Any lines matching these regex patters will be excluded. 31 | */ 32 | 'shorter_stack_trace_excludes' => [ 33 | '/vendor/symfony/', 34 | '/vendor/laravel/framework/', 35 | '/vendor/barryvdh/laravel-debugbar/' 36 | ] 37 | ]; 38 | -------------------------------------------------------------------------------- /src/resources/js/app.js: -------------------------------------------------------------------------------- 1 | require('./bootstrap'); 2 | 3 | window.Vue = require('vue'); 4 | 5 | import { directive as onClickaway } from 'vue-clickaway'; 6 | Vue.directive('onClickaway', onClickaway); 7 | 8 | Vue.component('paginate', require('./components/Paginate.vue').default); 9 | Vue.component('spinner', require('./components/Spinner.vue').default); 10 | Vue.component('sidebar-nav', require('./components/SidebarNav.vue').default); 11 | Vue.component('log-file', require('./components/LogFile.vue').default); 12 | Vue.component('log-list', require('./components/LogList.vue').default); 13 | Vue.component('log-item', require('./components/LogItem.vue').default); 14 | Vue.component('app-layout', require('./components/AppLayout.vue').default); 15 | Vue.component('btn', require('./components/Btn.vue').default); 16 | Vue.component('dropdown', require('./components/Dropdown.vue').default); 17 | 18 | Vue.filter('fileSize', function (size) { 19 | if (size > 1024 * 1024 * 1024) { 20 | return Math.round((size / (1024 * 1024 * 1024)) * 100) / 100 + ' GB'; 21 | } else if (size > 1024 * 1024) { 22 | return Math.round((size / (1024 * 1024)) * 100) / 100 + ' MB'; 23 | } else if (size > 1024) { 24 | return Math.round((size / 1024) * 100) / 100 + ' KB'; 25 | } else { 26 | return size + ' B'; 27 | } 28 | }); 29 | 30 | import Snotify from 'vue-snotify' 31 | Vue.use(Snotify); 32 | 33 | const event_bus = new Vue({}); 34 | 35 | Vue.prototype.$bus = event_bus; 36 | 37 | const app = new Vue({ 38 | data: {} 39 | }); 40 | 41 | window.axios.interceptors.response.use(function (response) { 42 | return response; 43 | }, function (error) { 44 | if (error.response.data.message) { 45 | app.$snotify.error(error.response.data.message); 46 | } 47 | return Promise.reject(error); 48 | }); 49 | 50 | app.$mount('#app'); 51 | -------------------------------------------------------------------------------- /src/resources/js/bootstrap.js: -------------------------------------------------------------------------------- 1 | import swal from 'sweetalert'; 2 | window.swal = swal; 3 | window.axios = require('axios'); 4 | window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; 5 | 6 | let token = document.head.querySelector('meta[name="csrf-token"]'); 7 | 8 | if (token) { 9 | window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content; 10 | } else { 11 | console.error('CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token'); 12 | } 13 | -------------------------------------------------------------------------------- /src/resources/js/components/AppLayout.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 26 | -------------------------------------------------------------------------------- /src/resources/js/components/Btn.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 65 | 66 | -------------------------------------------------------------------------------- /src/resources/js/components/Dropdown.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 42 | -------------------------------------------------------------------------------- /src/resources/js/components/LogFile.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 57 | 58 | 67 | -------------------------------------------------------------------------------- /src/resources/js/components/LogItem.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 68 | 69 | 130 | -------------------------------------------------------------------------------- /src/resources/js/components/LogList.vue: -------------------------------------------------------------------------------- 1 | 111 | 112 | 276 | 277 | 304 | -------------------------------------------------------------------------------- /src/resources/js/components/Modal.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 46 | 47 | -------------------------------------------------------------------------------- /src/resources/js/components/Paginate.vue: -------------------------------------------------------------------------------- 1 | 38 | 39 | 255 | 256 | 261 | -------------------------------------------------------------------------------- /src/resources/js/components/SettingsControl.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 37 | -------------------------------------------------------------------------------- /src/resources/js/components/SidebarNav.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 86 | 87 | 102 | -------------------------------------------------------------------------------- /src/resources/js/components/Spinner.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 39 | 40 | 161 | -------------------------------------------------------------------------------- /src/resources/js/settings.js: -------------------------------------------------------------------------------- 1 | 2 | import Vue from 'vue'; 3 | 4 | function saveToStorage(value) { 5 | let storageKey = `better-log-viewer::settings`; 6 | window.localStorage.setItem(storageKey, JSON.stringify(value)); 7 | } 8 | 9 | let storageKey = `better-log-viewer::settings`; 10 | let loadedSettings = JSON.parse(window.localStorage.getItem(storageKey)); 11 | 12 | export const settings = Vue.observable({ 13 | fullscreen: false, 14 | shorterStackTraces: false, 15 | perPage: 10, 16 | levelActive: { 17 | debug: true, 18 | info: true, 19 | notice: true, 20 | warning: true, 21 | error: true, 22 | critical: true, 23 | alert: true, 24 | emergency: true, 25 | processed: true, 26 | failed: true, 27 | }, 28 | ...loadedSettings 29 | }); 30 | 31 | export function setSetting(name, value) { 32 | Vue.set(settings, name, value); 33 | 34 | saveToStorage(settings); 35 | } 36 | 37 | export function setLevelActive(level, value) { 38 | Vue.set(settings.levelActive, level, value); 39 | 40 | saveToStorage(settings); 41 | } 42 | -------------------------------------------------------------------------------- /src/resources/sass/_variables.scss: -------------------------------------------------------------------------------- 1 | 2 | // Body 3 | $body-bg: #f1f1f1; 4 | 5 | // Typography 6 | $font-family-sans-serif: "Nunito", sans-serif; 7 | $font-size-base: 0.9rem; 8 | $line-height-base: 1.6; 9 | 10 | // Colors 11 | $blue: #3490dc; 12 | $indigo: #6574cd; 13 | $purple: #9561e2; 14 | $pink: #f66D9b; 15 | $red: #e3342f; 16 | $orange: #f6993f; 17 | $yellow: #ffed4a; 18 | $green: #38c172; 19 | $teal: #4dc0b5; 20 | $cyan: #6cb2eb; 21 | -------------------------------------------------------------------------------- /src/resources/sass/app.scss: -------------------------------------------------------------------------------- 1 | 2 | // Fonts 3 | @import url('https://fonts.googleapis.com/css?family=Nunito'); 4 | 5 | // Variables 6 | @import 'variables'; 7 | 8 | /** 9 | * This injects Tailwind's base styles, which is a combination of 10 | * Normalize.css and some additional base styles. 11 | * 12 | * You can see the styles here: 13 | * https://github.com/tailwindcss/tailwindcss/blob/master/css/preflight.css 14 | * 15 | * If using `postcss-import`, use this import instead: 16 | * 17 | * @import "tailwindcss/preflight"; 18 | */ 19 | @tailwind preflight; 20 | 21 | /** 22 | * This injects any component classes registered by plugins. 23 | * 24 | * If using `postcss-import`, use this import instead: 25 | * 26 | * @import "tailwindcss/components"; 27 | */ 28 | @tailwind components; 29 | 30 | /** 31 | * Here you would add any of your custom component classes; stuff that you'd 32 | * want loaded *before* the utilities so that the utilities could still 33 | * override them. 34 | * 35 | * Example: 36 | * 37 | * .btn { ... } 38 | * .form-input { ... } 39 | * 40 | * Or if using a preprocessor or `postcss-import`: 41 | * 42 | * @import "components/buttons"; 43 | * @import "components/forms"; 44 | */ 45 | 46 | /** 47 | * This injects all of Tailwind's utility classes, generated based on your 48 | * config file. 49 | * 50 | * If using `postcss-import`, use this import instead: 51 | * 52 | * @import "tailwindcss/utilities"; 53 | */ 54 | @tailwind utilities; 55 | 56 | /** 57 | * Here you would add any custom utilities you need that don't come out of the 58 | * box with Tailwind. 59 | * 60 | * Example : 61 | * 62 | * .bg-pattern-graph-paper { ... } 63 | * .skew-45 { ... } 64 | * 65 | * Or if using a preprocessor or `postcss-import`: 66 | * 67 | * @import "utilities/background-patterns"; 68 | * @import "utilities/skew-transforms"; 69 | */ 70 | 71 | @import "~vue-snotify/styles/material"; 72 | 73 | .text-danger { 74 | @apply .text-red-light; 75 | } 76 | 77 | .text-info { 78 | @apply .text-blue-light 79 | } 80 | 81 | .text-primary { 82 | @apply .text-blue 83 | } 84 | 85 | .text-warning { 86 | @apply .text-orange-light 87 | } 88 | -------------------------------------------------------------------------------- /src/resources/views/logs/index.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Better Log Viewer 8 | 9 | 10 | 11 | @better_log_viewer_css 12 | 13 | 17 | 18 | 19 |
20 | 21 |
22 | 23 | @better_log_viewer_js 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/routes/api.php: -------------------------------------------------------------------------------- 1 | 'better-log-viewer::api.logs.index', 'uses' => 'LogsController@index']); 4 | Route::get('file/{name}/download', ['as' => 'better-log-viewer::api.logs.download', 'uses' => 'LogsController@download']); 5 | Route::delete('file/{name}', ['as' => 'better-log-viewer::api.logs.destroy', 'uses' => 'LogsController@destroy']); 6 | Route::get('file/{name}/level-counts', ['as' => 'better-log-viewer::api.logs.level-counts', 'uses' => 'LogsController@levelCounts']); 7 | Route::get('file/{name}', ['as' => 'better-log-viewer::api.logs.show', 'uses' => 'LogsController@show']); 8 | -------------------------------------------------------------------------------- /src/routes/assets.php: -------------------------------------------------------------------------------- 1 | 'better-log-viewer::assets.css', 'uses' => 'AssetController@css']); 4 | Route::get('js/{cache_breaker}/app.js', ['as' => 'better-log-viewer::assets.js', 'uses' => 'AssetController@js']); 5 | -------------------------------------------------------------------------------- /src/routes/web.php: -------------------------------------------------------------------------------- 1 | 'better-log-viewer::log.index', 'uses' => 'LogViewerController@index']); 4 | -------------------------------------------------------------------------------- /tailwind.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Tailwind - The Utility-First CSS Framework 4 | 5 | A project by Adam Wathan (@adamwathan), Jonathan Reinink (@reinink), 6 | David Hemphill (@davidhemphill) and Steve Schoger (@steveschoger). 7 | 8 | Welcome to the Tailwind config file. This is where you can customize 9 | Tailwind specifically for your project. Don't be intimidated by the 10 | length of this file. It's really just a big JavaScript object and 11 | we've done our very best to explain each section. 12 | 13 | View the full documentation at https://tailwindcss.com. 14 | 15 | 16 | |------------------------------------------------------------------------------- 17 | | The default config 18 | |------------------------------------------------------------------------------- 19 | | 20 | | This variable contains the default Tailwind config. You don't have 21 | | to use it, but it can sometimes be helpful to have available. For 22 | | example, you may choose to merge your custom configuration 23 | | values with some of the Tailwind defaults. 24 | | 25 | */ 26 | 27 | let defaultConfig = require('tailwindcss/defaultConfig')() 28 | 29 | 30 | /* 31 | |------------------------------------------------------------------------------- 32 | | Colors https://tailwindcss.com/docs/colors 33 | |------------------------------------------------------------------------------- 34 | | 35 | | Here you can specify the colors used in your project. To get you started, 36 | | we've provided a generous palette of great looking colors that are perfect 37 | | for prototyping, but don't hesitate to change them for your project. You 38 | | own these colors, nothing will break if you change everything about them. 39 | | 40 | | We've used literal color names ("red", "blue", etc.) for the default 41 | | palette, but if you'd rather use functional names like "primary" and 42 | | "secondary", or even a numeric scale like "100" and "200", go for it. 43 | | 44 | */ 45 | 46 | let colors = { 47 | 'transparent': 'transparent', 48 | 49 | 'black': '#22292f', 50 | 'grey-darkest': '#3d4852', 51 | 'grey-darker': '#606f7b', 52 | 'grey-dark': '#8795a1', 53 | 'grey': '#b8c2cc', 54 | 'grey-light': '#dae1e7', 55 | 'grey-lighter': '#f1f5f8', 56 | 'grey-lightest': '#f8fafc', 57 | 'white': '#ffffff', 58 | 59 | 'red-darkest': '#3b0d0c', 60 | 'red-darker': '#621b18', 61 | 'red-dark': '#cc1f1a', 62 | 'red': '#e3342f', 63 | 'red-light': '#ef5753', 64 | 'red-lighter': '#f9acaa', 65 | 'red-lightest': '#fcebea', 66 | 67 | 'orange-darkest': '#462a16', 68 | 'orange-darker': '#613b1f', 69 | 'orange-dark': '#de751f', 70 | 'orange': '#f6993f', 71 | 'orange-light': '#faad63', 72 | 'orange-lighter': '#fcd9b6', 73 | 'orange-lightest': '#fff5eb', 74 | 75 | 'yellow-darkest': '#453411', 76 | 'yellow-darker': '#684f1d', 77 | 'yellow-dark': '#f2d024', 78 | 'yellow': '#ffed4a', 79 | 'yellow-light': '#fff382', 80 | 'yellow-lighter': '#fff9c2', 81 | 'yellow-lightest': '#fcfbeb', 82 | 83 | 'green-darkest': '#0f2f21', 84 | 'green-darker': '#1a4731', 85 | 'green-dark': '#1f9d55', 86 | 'green': '#38c172', 87 | 'green-light': '#51d88a', 88 | 'green-lighter': '#a2f5bf', 89 | 'green-lightest': '#e3fcec', 90 | 91 | 'teal-darkest': '#0d3331', 92 | 'teal-darker': '#20504f', 93 | 'teal-dark': '#38a89d', 94 | 'teal': '#4dc0b5', 95 | 'teal-light': '#64d5ca', 96 | 'teal-lighter': '#a0f0ed', 97 | 'teal-lightest': '#e8fffe', 98 | 99 | 'blue-darkest': '#12283a', 100 | 'blue-darker': '#1c3d5a', 101 | 'blue-dark': '#2779bd', 102 | 'blue': '#3490dc', 103 | 'blue-light': '#6cb2eb', 104 | 'blue-lighter': '#bcdefa', 105 | 'blue-lightest': '#eff8ff', 106 | 107 | 'indigo-darkest': '#191e38', 108 | 'indigo-darker': '#2f365f', 109 | 'indigo-dark': '#5661b3', 110 | 'indigo': '#6574cd', 111 | 'indigo-light': '#7886d7', 112 | 'indigo-lighter': '#b2b7ff', 113 | 'indigo-lightest': '#e6e8ff', 114 | 115 | 'purple-darkest': '#21183c', 116 | 'purple-darker': '#382b5f', 117 | 'purple-dark': '#794acf', 118 | 'purple': '#9561e2', 119 | 'purple-light': '#a779e9', 120 | 'purple-lighter': '#d6bbfc', 121 | 'purple-lightest': '#f3ebff', 122 | 123 | 'pink-darkest': '#451225', 124 | 'pink-darker': '#6f213f', 125 | 'pink-dark': '#eb5286', 126 | 'pink': '#f66d9b', 127 | 'pink-light': '#fa7ea8', 128 | 'pink-lighter': '#ffbbca', 129 | 'pink-lightest': '#ffebef', 130 | 131 | 'smoke-darkest': 'rgba(0, 0, 0, 0.9)', 132 | 'smoke-darker': 'rgba(0, 0, 0, 0.75)', 133 | 'smoke-dark': 'rgba(0, 0, 0, 0.6)', 134 | 'smoke': 'rgba(0, 0, 0, 0.5)', 135 | 'smoke-light': 'rgba(0, 0, 0, 0.4)', 136 | 'smoke-lighter': 'rgba(0, 0, 0, 0.25)', 137 | 'smoke-lightest': 'rgba(0, 0, 0, 0.1)', 138 | } 139 | 140 | module.exports = { 141 | 142 | /* 143 | |----------------------------------------------------------------------------- 144 | | Colors https://tailwindcss.com/docs/colors 145 | |----------------------------------------------------------------------------- 146 | | 147 | | The color palette defined above is also assigned to the "colors" key of 148 | | your Tailwind config. This makes it easy to access them in your CSS 149 | | using Tailwind's config helper. For example: 150 | | 151 | | .error { color: config('colors.red') } 152 | | 153 | */ 154 | 155 | colors: colors, 156 | 157 | 158 | /* 159 | |----------------------------------------------------------------------------- 160 | | Screens https://tailwindcss.com/docs/responsive-design 161 | |----------------------------------------------------------------------------- 162 | | 163 | | Screens in Tailwind are translated to CSS media queries. They define the 164 | | responsive breakpoints for your project. By default Tailwind takes a 165 | | "mobile first" approach, where each screen size represents a minimum 166 | | viewport width. Feel free to have as few or as many screens as you 167 | | want, naming them in whatever way you'd prefer for your project. 168 | | 169 | | Tailwind also allows for more complex screen definitions, which can be 170 | | useful in certain situations. Be sure to see the full responsive 171 | | documentation for a complete list of options. 172 | | 173 | | Class name: .{screen}:{utility} 174 | | 175 | */ 176 | 177 | screens: { 178 | 'sm': '576px', 179 | 'md': '768px', 180 | 'lg': '992px', 181 | 'xl': '1200px', 182 | }, 183 | 184 | 185 | /* 186 | |----------------------------------------------------------------------------- 187 | | Fonts https://tailwindcss.com/docs/fonts 188 | |----------------------------------------------------------------------------- 189 | | 190 | | Here is where you define your project's font stack, or font families. 191 | | Keep in mind that Tailwind doesn't actually load any fonts for you. 192 | | If you're using custom fonts you'll need to import them prior to 193 | | defining them here. 194 | | 195 | | By default we provide a native font stack that works remarkably well on 196 | | any device or OS you're using, since it just uses the default fonts 197 | | provided by the platform. 198 | | 199 | | Class name: .font-{name} 200 | | CSS property: font-family 201 | | 202 | */ 203 | 204 | fonts: { 205 | 'sans': [ 206 | 'Nunito', 207 | 'system-ui', 208 | 'BlinkMacSystemFont', 209 | '-apple-system', 210 | 'Segoe UI', 211 | 'Roboto', 212 | 'Oxygen', 213 | 'Ubuntu', 214 | 'Cantarell', 215 | 'Fira Sans', 216 | 'Droid Sans', 217 | 'Helvetica Neue', 218 | 'sans-serif', 219 | ], 220 | 'serif': [ 221 | 'Constantia', 222 | 'Lucida Bright', 223 | 'Lucidabright', 224 | 'Lucida Serif', 225 | 'Lucida', 226 | 'DejaVu Serif', 227 | 'Bitstream Vera Serif', 228 | 'Liberation Serif', 229 | 'Georgia', 230 | 'serif', 231 | ], 232 | 'mono': [ 233 | 'Menlo', 234 | 'Monaco', 235 | 'Consolas', 236 | 'Liberation Mono', 237 | 'Courier New', 238 | 'monospace', 239 | ], 240 | }, 241 | 242 | 243 | /* 244 | |----------------------------------------------------------------------------- 245 | | Text sizes https://tailwindcss.com/docs/text-sizing 246 | |----------------------------------------------------------------------------- 247 | | 248 | | Here is where you define your text sizes. Name these in whatever way 249 | | makes the most sense to you. We use size names by default, but 250 | | you're welcome to use a numeric scale or even something else 251 | | entirely. 252 | | 253 | | By default Tailwind uses the "rem" unit type for most measurements. 254 | | This allows you to set a root font size which all other sizes are 255 | | then based on. That said, you are free to use whatever units you 256 | | prefer, be it rems, ems, pixels or other. 257 | | 258 | | Class name: .text-{size} 259 | | CSS property: font-size 260 | | 261 | */ 262 | 263 | textSizes: { 264 | 'xs': '.75rem', // 12px 265 | 'sm': '.875rem', // 14px 266 | 'base': '1rem', // 16px 267 | 'lg': '1.125rem', // 18px 268 | 'xl': '1.25rem', // 20px 269 | '2xl': '1.5rem', // 24px 270 | '3xl': '1.875rem', // 30px 271 | '4xl': '2.25rem', // 36px 272 | '5xl': '3rem', // 48px 273 | }, 274 | 275 | 276 | /* 277 | |----------------------------------------------------------------------------- 278 | | Font weights https://tailwindcss.com/docs/font-weight 279 | |----------------------------------------------------------------------------- 280 | | 281 | | Here is where you define your font weights. We've provided a list of 282 | | common font weight names with their respective numeric scale values 283 | | to get you started. It's unlikely that your project will require 284 | | all of these, so we recommend removing those you don't need. 285 | | 286 | | Class name: .font-{weight} 287 | | CSS property: font-weight 288 | | 289 | */ 290 | 291 | fontWeights: { 292 | 'hairline': 100, 293 | 'thin': 200, 294 | 'light': 300, 295 | 'normal': 400, 296 | 'medium': 500, 297 | 'semibold': 600, 298 | 'bold': 700, 299 | 'extrabold': 800, 300 | 'black': 900, 301 | }, 302 | 303 | 304 | /* 305 | |----------------------------------------------------------------------------- 306 | | Leading (line height) https://tailwindcss.com/docs/line-height 307 | |----------------------------------------------------------------------------- 308 | | 309 | | Here is where you define your line height values, or as we call 310 | | them in Tailwind, leadings. 311 | | 312 | | Class name: .leading-{size} 313 | | CSS property: line-height 314 | | 315 | */ 316 | 317 | leading: { 318 | 'none': 1, 319 | 'tight': 1.25, 320 | 'normal': 1.5, 321 | 'loose': 2, 322 | }, 323 | 324 | 325 | /* 326 | |----------------------------------------------------------------------------- 327 | | Tracking (letter spacing) https://tailwindcss.com/docs/letter-spacing 328 | |----------------------------------------------------------------------------- 329 | | 330 | | Here is where you define your letter spacing values, or as we call 331 | | them in Tailwind, tracking. 332 | | 333 | | Class name: .tracking-{size} 334 | | CSS property: letter-spacing 335 | | 336 | */ 337 | 338 | tracking: { 339 | 'tight': '-0.05em', 340 | 'normal': '0', 341 | 'wide': '0.05em', 342 | }, 343 | 344 | 345 | /* 346 | |----------------------------------------------------------------------------- 347 | | Text colors https://tailwindcss.com/docs/text-color 348 | |----------------------------------------------------------------------------- 349 | | 350 | | Here is where you define your text colors. By default these use the 351 | | color palette we defined above, however you're welcome to set these 352 | | independently if that makes sense for your project. 353 | | 354 | | Class name: .text-{color} 355 | | CSS property: color 356 | | 357 | */ 358 | 359 | textColors: colors, 360 | 361 | 362 | /* 363 | |----------------------------------------------------------------------------- 364 | | Background colors https://tailwindcss.com/docs/background-color 365 | |----------------------------------------------------------------------------- 366 | | 367 | | Here is where you define your background colors. By default these use 368 | | the color palette we defined above, however you're welcome to set 369 | | these independently if that makes sense for your project. 370 | | 371 | | Class name: .bg-{color} 372 | | CSS property: background-color 373 | | 374 | */ 375 | 376 | backgroundColors: colors, 377 | 378 | 379 | /* 380 | |----------------------------------------------------------------------------- 381 | | Background sizes https://tailwindcss.com/docs/background-size 382 | |----------------------------------------------------------------------------- 383 | | 384 | | Here is where you define your background sizes. We provide some common 385 | | values that are useful in most projects, but feel free to add other sizes 386 | | that are specific to your project here as well. 387 | | 388 | | Class name: .bg-{size} 389 | | CSS property: background-size 390 | | 391 | */ 392 | 393 | backgroundSize: { 394 | 'auto': 'auto', 395 | 'cover': 'cover', 396 | 'contain': 'contain', 397 | }, 398 | 399 | 400 | /* 401 | |----------------------------------------------------------------------------- 402 | | Border widths https://tailwindcss.com/docs/border-width 403 | |----------------------------------------------------------------------------- 404 | | 405 | | Here is where you define your border widths. Take note that border 406 | | widths require a special "default" value set as well. This is the 407 | | width that will be used when you do not specify a border width. 408 | | 409 | | Class name: .border{-side?}{-width?} 410 | | CSS property: border-width 411 | | 412 | */ 413 | 414 | borderWidths: { 415 | default: '1px', 416 | '0': '0', 417 | '2': '2px', 418 | '4': '4px', 419 | '8': '8px', 420 | }, 421 | 422 | 423 | /* 424 | |----------------------------------------------------------------------------- 425 | | Border colors https://tailwindcss.com/docs/border-color 426 | |----------------------------------------------------------------------------- 427 | | 428 | | Here is where you define your border colors. By default these use the 429 | | color palette we defined above, however you're welcome to set these 430 | | independently if that makes sense for your project. 431 | | 432 | | Take note that border colors require a special "default" value set 433 | | as well. This is the color that will be used when you do not 434 | | specify a border color. 435 | | 436 | | Class name: .border-{color} 437 | | CSS property: border-color 438 | | 439 | */ 440 | 441 | borderColors: global.Object.assign({ default: colors['grey-light'] }, colors), 442 | 443 | 444 | /* 445 | |----------------------------------------------------------------------------- 446 | | Border radius https://tailwindcss.com/docs/border-radius 447 | |----------------------------------------------------------------------------- 448 | | 449 | | Here is where you define your border radius values. If a `default` radius 450 | | is provided, it will be made available as the non-suffixed `.rounded` 451 | | utility. 452 | | 453 | | If your scale includes a `0` value to reset already rounded corners, it's 454 | | a good idea to put it first so other values are able to override it. 455 | | 456 | | Class name: .rounded{-side?}{-size?} 457 | | CSS property: border-radius 458 | | 459 | */ 460 | 461 | borderRadius: { 462 | 'none': '0', 463 | 'sm': '.125rem', 464 | default: '.25rem', 465 | 'lg': '.5rem', 466 | 'full': '9999px', 467 | }, 468 | 469 | 470 | /* 471 | |----------------------------------------------------------------------------- 472 | | Width https://tailwindcss.com/docs/width 473 | |----------------------------------------------------------------------------- 474 | | 475 | | Here is where you define your width utility sizes. These can be 476 | | percentage based, pixels, rems, or any other units. By default 477 | | we provide a sensible rem based numeric scale, a percentage 478 | | based fraction scale, plus some other common use-cases. You 479 | | can, of course, modify these values as needed. 480 | | 481 | | 482 | | It's also worth mentioning that Tailwind automatically escapes 483 | | invalid CSS class name characters, which allows you to have 484 | | awesome classes like .w-2/3. 485 | | 486 | | Class name: .w-{size} 487 | | CSS property: width 488 | | 489 | */ 490 | 491 | width: { 492 | 'auto': 'auto', 493 | 'px': '1px', 494 | '1': '0.25rem', 495 | '2': '0.5rem', 496 | '3': '0.75rem', 497 | '4': '1rem', 498 | '5': '1.25rem', 499 | '6': '1.5rem', 500 | '8': '2rem', 501 | '10': '2.5rem', 502 | '12': '3rem', 503 | '16': '4rem', 504 | '24': '6rem', 505 | '32': '8rem', 506 | '48': '12rem', 507 | '64': '16rem', 508 | '1/2': '50%', 509 | '1/3': '33.33333%', 510 | '2/3': '66.66667%', 511 | '1/4': '25%', 512 | '3/4': '75%', 513 | '1/5': '20%', 514 | '2/5': '40%', 515 | '3/5': '60%', 516 | '4/5': '80%', 517 | '1/6': '16.66667%', 518 | '5/6': '83.33333%', 519 | 'full': '100%', 520 | 'screen': '100vw', 521 | }, 522 | 523 | 524 | /* 525 | |----------------------------------------------------------------------------- 526 | | Height https://tailwindcss.com/docs/height 527 | |----------------------------------------------------------------------------- 528 | | 529 | | Here is where you define your height utility sizes. These can be 530 | | percentage based, pixels, rems, or any other units. By default 531 | | we provide a sensible rem based numeric scale plus some other 532 | | common use-cases. You can, of course, modify these values as 533 | | needed. 534 | | 535 | | Class name: .h-{size} 536 | | CSS property: height 537 | | 538 | */ 539 | 540 | height: { 541 | 'auto': 'auto', 542 | 'px': '1px', 543 | '1': '0.25rem', 544 | '2': '0.5rem', 545 | '3': '0.75rem', 546 | '4': '1rem', 547 | '5': '1.25rem', 548 | '6': '1.5rem', 549 | '8': '2rem', 550 | '10': '2.5rem', 551 | '12': '3rem', 552 | '16': '4rem', 553 | '24': '6rem', 554 | '32': '8rem', 555 | '48': '12rem', 556 | '64': '16rem', 557 | 'full': '100%', 558 | 'screen': '100vh', 559 | }, 560 | 561 | 562 | /* 563 | |----------------------------------------------------------------------------- 564 | | Minimum width https://tailwindcss.com/docs/min-width 565 | |----------------------------------------------------------------------------- 566 | | 567 | | Here is where you define your minimum width utility sizes. These can 568 | | be percentage based, pixels, rems, or any other units. We provide a 569 | | couple common use-cases by default. You can, of course, modify 570 | | these values as needed. 571 | | 572 | | Class name: .min-w-{size} 573 | | CSS property: min-width 574 | | 575 | */ 576 | 577 | minWidth: { 578 | '0': '0', 579 | 'full': '100%', 580 | }, 581 | 582 | 583 | /* 584 | |----------------------------------------------------------------------------- 585 | | Minimum height https://tailwindcss.com/docs/min-height 586 | |----------------------------------------------------------------------------- 587 | | 588 | | Here is where you define your minimum height utility sizes. These can 589 | | be percentage based, pixels, rems, or any other units. We provide a 590 | | few common use-cases by default. You can, of course, modify these 591 | | values as needed. 592 | | 593 | | Class name: .min-h-{size} 594 | | CSS property: min-height 595 | | 596 | */ 597 | 598 | minHeight: { 599 | '0': '0', 600 | 'full': '100%', 601 | 'screen': '100vh', 602 | }, 603 | 604 | 605 | /* 606 | |----------------------------------------------------------------------------- 607 | | Maximum width https://tailwindcss.com/docs/max-width 608 | |----------------------------------------------------------------------------- 609 | | 610 | | Here is where you define your maximum width utility sizes. These can 611 | | be percentage based, pixels, rems, or any other units. By default 612 | | we provide a sensible rem based scale and a "full width" size, 613 | | which is basically a reset utility. You can, of course, 614 | | modify these values as needed. 615 | | 616 | | Class name: .max-w-{size} 617 | | CSS property: max-width 618 | | 619 | */ 620 | 621 | maxWidth: { 622 | 'xs': '20rem', 623 | 'sm': '30rem', 624 | 'md': '40rem', 625 | 'lg': '50rem', 626 | 'xl': '60rem', 627 | '2xl': '70rem', 628 | '3xl': '80rem', 629 | '4xl': '90rem', 630 | '5xl': '100rem', 631 | 'full': '100%', 632 | }, 633 | 634 | 635 | /* 636 | |----------------------------------------------------------------------------- 637 | | Maximum height https://tailwindcss.com/docs/max-height 638 | |----------------------------------------------------------------------------- 639 | | 640 | | Here is where you define your maximum height utility sizes. These can 641 | | be percentage based, pixels, rems, or any other units. We provide a 642 | | couple common use-cases by default. You can, of course, modify 643 | | these values as needed. 644 | | 645 | | Class name: .max-h-{size} 646 | | CSS property: max-height 647 | | 648 | */ 649 | 650 | maxHeight: { 651 | 'full': '100%', 652 | 'screen': '100vh', 653 | }, 654 | 655 | 656 | /* 657 | |----------------------------------------------------------------------------- 658 | | Padding https://tailwindcss.com/docs/padding 659 | |----------------------------------------------------------------------------- 660 | | 661 | | Here is where you define your padding utility sizes. These can be 662 | | percentage based, pixels, rems, or any other units. By default we 663 | | provide a sensible rem based numeric scale plus a couple other 664 | | common use-cases like "1px". You can, of course, modify these 665 | | values as needed. 666 | | 667 | | Class name: .p{side?}-{size} 668 | | CSS property: padding 669 | | 670 | */ 671 | 672 | padding: { 673 | 'px': '1px', 674 | '0': '0', 675 | '1': '0.25rem', 676 | '2': '0.5rem', 677 | '3': '0.75rem', 678 | '4': '1rem', 679 | '5': '1.25rem', 680 | '6': '1.5rem', 681 | '8': '2rem', 682 | '10': '2.5rem', 683 | '12': '3rem', 684 | '16': '4rem', 685 | '20': '5rem', 686 | '24': '6rem', 687 | '32': '8rem', 688 | }, 689 | 690 | 691 | /* 692 | |----------------------------------------------------------------------------- 693 | | Margin https://tailwindcss.com/docs/margin 694 | |----------------------------------------------------------------------------- 695 | | 696 | | Here is where you define your margin utility sizes. These can be 697 | | percentage based, pixels, rems, or any other units. By default we 698 | | provide a sensible rem based numeric scale plus a couple other 699 | | common use-cases like "1px". You can, of course, modify these 700 | | values as needed. 701 | | 702 | | Class name: .m{side?}-{size} 703 | | CSS property: margin 704 | | 705 | */ 706 | 707 | margin: { 708 | 'auto': 'auto', 709 | 'px': '1px', 710 | '0': '0', 711 | '1': '0.25rem', 712 | '2': '0.5rem', 713 | '3': '0.75rem', 714 | '4': '1rem', 715 | '5': '1.25rem', 716 | '6': '1.5rem', 717 | '8': '2rem', 718 | '10': '2.5rem', 719 | '12': '3rem', 720 | '16': '4rem', 721 | '20': '5rem', 722 | '24': '6rem', 723 | '32': '8rem', 724 | }, 725 | 726 | 727 | /* 728 | |----------------------------------------------------------------------------- 729 | | Negative margin https://tailwindcss.com/docs/negative-margin 730 | |----------------------------------------------------------------------------- 731 | | 732 | | Here is where you define your negative margin utility sizes. These can 733 | | be percentage based, pixels, rems, or any other units. By default we 734 | | provide matching values to the padding scale since these utilities 735 | | generally get used together. You can, of course, modify these 736 | | values as needed. 737 | | 738 | | Class name: .-m{side?}-{size} 739 | | CSS property: margin 740 | | 741 | */ 742 | 743 | negativeMargin: { 744 | 'px': '1px', 745 | '0': '0', 746 | '1': '0.25rem', 747 | '2': '0.5rem', 748 | '3': '0.75rem', 749 | '4': '1rem', 750 | '5': '1.25rem', 751 | '6': '1.5rem', 752 | '8': '2rem', 753 | '10': '2.5rem', 754 | '12': '3rem', 755 | '16': '4rem', 756 | '20': '5rem', 757 | '24': '6rem', 758 | '32': '8rem', 759 | }, 760 | 761 | 762 | /* 763 | |----------------------------------------------------------------------------- 764 | | Shadows https://tailwindcss.com/docs/shadows 765 | |----------------------------------------------------------------------------- 766 | | 767 | | Here is where you define your shadow utilities. As you can see from 768 | | the defaults we provide, it's possible to apply multiple shadows 769 | | per utility using comma separation. 770 | | 771 | | If a `default` shadow is provided, it will be made available as the non- 772 | | suffixed `.shadow` utility. 773 | | 774 | | Class name: .shadow-{size?} 775 | | CSS property: box-shadow 776 | | 777 | */ 778 | 779 | shadows: { 780 | default: '0 2px 4px 0 rgba(0,0,0,0.10)', 781 | 'md': '0 4px 8px 0 rgba(0,0,0,0.12), 0 2px 4px 0 rgba(0,0,0,0.08)', 782 | 'lg': '0 15px 30px 0 rgba(0,0,0,0.11), 0 5px 15px 0 rgba(0,0,0,0.08)', 783 | 'inner': 'inset 0 2px 4px 0 rgba(0,0,0,0.06)', 784 | 'outline': '0 0 0 3px rgba(52,144,220,0.5)', 785 | 'none': 'none', 786 | }, 787 | 788 | 789 | /* 790 | |----------------------------------------------------------------------------- 791 | | Z-index https://tailwindcss.com/docs/z-index 792 | |----------------------------------------------------------------------------- 793 | | 794 | | Here is where you define your z-index utility values. By default we 795 | | provide a sensible numeric scale. You can, of course, modify these 796 | | values as needed. 797 | | 798 | | Class name: .z-{index} 799 | | CSS property: z-index 800 | | 801 | */ 802 | 803 | zIndex: { 804 | 'auto': 'auto', 805 | '0': 0, 806 | '10': 10, 807 | '20': 20, 808 | '30': 30, 809 | '40': 40, 810 | '50': 50, 811 | }, 812 | 813 | 814 | /* 815 | |----------------------------------------------------------------------------- 816 | | Opacity https://tailwindcss.com/docs/opacity 817 | |----------------------------------------------------------------------------- 818 | | 819 | | Here is where you define your opacity utility values. By default we 820 | | provide a sensible numeric scale. You can, of course, modify these 821 | | values as needed. 822 | | 823 | | Class name: .opacity-{name} 824 | | CSS property: opacity 825 | | 826 | */ 827 | 828 | opacity: { 829 | '0': '0', 830 | '25': '.25', 831 | '50': '.5', 832 | '75': '.75', 833 | '100': '1', 834 | }, 835 | 836 | 837 | /* 838 | |----------------------------------------------------------------------------- 839 | | SVG fill https://tailwindcss.com/docs/svg 840 | |----------------------------------------------------------------------------- 841 | | 842 | | Here is where you define your SVG fill colors. By default we just provide 843 | | `fill-current` which sets the fill to the current text color. This lets you 844 | | specify a fill color using existing text color utilities and helps keep the 845 | | generated CSS file size down. 846 | | 847 | | Class name: .fill-{name} 848 | | CSS property: fill 849 | | 850 | */ 851 | 852 | svgFill: { 853 | 'current': 'currentColor', 854 | }, 855 | 856 | 857 | /* 858 | |----------------------------------------------------------------------------- 859 | | SVG stroke https://tailwindcss.com/docs/svg 860 | |----------------------------------------------------------------------------- 861 | | 862 | | Here is where you define your SVG stroke colors. By default we just provide 863 | | `stroke-current` which sets the stroke to the current text color. This lets 864 | | you specify a stroke color using existing text color utilities and helps 865 | | keep the generated CSS file size down. 866 | | 867 | | Class name: .stroke-{name} 868 | | CSS property: stroke 869 | | 870 | */ 871 | 872 | svgStroke: { 873 | 'current': 'currentColor', 874 | }, 875 | 876 | 877 | /* 878 | |----------------------------------------------------------------------------- 879 | | Modules https://tailwindcss.com/docs/configuration#modules 880 | |----------------------------------------------------------------------------- 881 | | 882 | | Here is where you control which modules are generated and what variants are 883 | | generated for each of those modules. 884 | | 885 | | Currently supported variants: 886 | | - responsive 887 | | - hover 888 | | - focus 889 | | - focus-within 890 | | - active 891 | | - group-hover 892 | | 893 | | To disable a module completely, use `false` instead of an array. 894 | | 895 | */ 896 | 897 | modules: { 898 | appearance: ['responsive'], 899 | backgroundAttachment: ['responsive'], 900 | backgroundColors: ['responsive', 'hover', 'focus'], 901 | backgroundPosition: ['responsive'], 902 | backgroundRepeat: ['responsive'], 903 | backgroundSize: ['responsive'], 904 | borderCollapse: [], 905 | borderColors: ['responsive', 'hover', 'focus'], 906 | borderRadius: ['responsive'], 907 | borderStyle: ['responsive'], 908 | borderWidths: ['responsive'], 909 | cursor: ['responsive'], 910 | display: ['responsive'], 911 | flexbox: ['responsive'], 912 | float: ['responsive'], 913 | fonts: ['responsive'], 914 | fontWeights: ['responsive', 'hover', 'focus'], 915 | height: ['responsive'], 916 | leading: ['responsive'], 917 | lists: ['responsive'], 918 | margin: ['responsive'], 919 | maxHeight: ['responsive'], 920 | maxWidth: ['responsive'], 921 | minHeight: ['responsive'], 922 | minWidth: ['responsive'], 923 | negativeMargin: ['responsive'], 924 | objectFit: false, 925 | objectPosition: false, 926 | opacity: ['responsive'], 927 | outline: ['focus'], 928 | overflow: ['responsive'], 929 | padding: ['responsive'], 930 | pointerEvents: ['responsive'], 931 | position: ['responsive'], 932 | resize: ['responsive'], 933 | shadows: ['responsive', 'hover', 'focus'], 934 | svgFill: [], 935 | svgStroke: [], 936 | tableLayout: ['responsive'], 937 | textAlign: ['responsive'], 938 | textColors: ['responsive', 'hover', 'focus'], 939 | textSizes: ['responsive'], 940 | textStyle: ['responsive', 'hover', 'focus'], 941 | tracking: ['responsive'], 942 | userSelect: ['responsive'], 943 | verticalAlign: ['responsive'], 944 | visibility: ['responsive'], 945 | whitespace: ['responsive'], 946 | width: ['responsive'], 947 | zIndex: ['responsive'], 948 | }, 949 | 950 | 951 | /* 952 | |----------------------------------------------------------------------------- 953 | | Plugins https://tailwindcss.com/docs/plugins 954 | |----------------------------------------------------------------------------- 955 | | 956 | | Here is where you can register any plugins you'd like to use in your 957 | | project. Tailwind's built-in `container` plugin is enabled by default to 958 | | give you a Bootstrap-style responsive container component out of the box. 959 | | 960 | | Be sure to view the complete plugin documentation to learn more about how 961 | | the plugin system works. 962 | | 963 | */ 964 | 965 | plugins: [ 966 | require('tailwindcss/plugins/container')({ 967 | // center: true, 968 | // padding: '1rem', 969 | }), 970 | ], 971 | 972 | 973 | /* 974 | |----------------------------------------------------------------------------- 975 | | Advanced Options https://tailwindcss.com/docs/configuration#options 976 | |----------------------------------------------------------------------------- 977 | | 978 | | Here is where you can tweak advanced configuration options. We recommend 979 | | leaving these options alone unless you absolutely need to change them. 980 | | 981 | */ 982 | 983 | options: { 984 | prefix: '', 985 | important: false, 986 | separator: ':', 987 | }, 988 | 989 | } 990 | -------------------------------------------------------------------------------- /webpack.mix.js: -------------------------------------------------------------------------------- 1 | const mix = require('laravel-mix'); 2 | require('laravel-mix-tailwind'); 3 | 4 | /* 5 | |-------------------------------------------------------------------------- 6 | | Mix Asset Management 7 | |-------------------------------------------------------------------------- 8 | | 9 | | Mix provides a clean, fluent API for defining some Webpack build steps 10 | | for your Laravel application. By default, we are compiling the Sass 11 | | file for the application as well as bundling up all the JS files. 12 | | 13 | */ 14 | 15 | mix.js('src/resources/js/app.js', 'public/js') 16 | .sass('src/resources/sass/app.scss', 'public/css') 17 | .tailwind(); 18 | --------------------------------------------------------------------------------