├── .gitignore
├── .github
├── FUNDING.yml
└── workflows
│ └── tests.yaml
├── screenshots.jpg
├── resources
├── css
│ ├── app.css
│ ├── components
│ │ ├── output.css
│ │ ├── layout.css
│ │ ├── codemirror.css
│ │ └── github-markdown.css
│ └── bootstrap.css
├── js
│ ├── components
│ │ ├── SoarOutput.vue
│ │ ├── Soar.vue
│ │ └── SoarInput.vue
│ └── app.js
└── views
│ └── web-soar.blade.php
├── public
├── mix-manifest.json
└── github.css
├── postcss.config.js
├── phpstan.neon
├── webpack.mix.js
├── .vscode
└── settings.json
├── LICENSE.md
├── src
├── Console
│ ├── PublishCommand.php
│ ├── InstallCommand.php
│ └── Concerns
│ │ └── InstallSoar.php
├── Http
│ ├── Middleware
│ │ └── Authorize.php
│ └── Controllers
│ │ └── WebSoarController.php
└── WebSoarServiceProvider.php
├── config
└── web-soar.php
├── package.json
├── composer.json
├── README.md
├── .php-cs-fixer.php
└── tailwind.js
/.gitignore:
--------------------------------------------------------------------------------
1 | vendor
2 | node_modules
3 | composer.lock
4 | package-lock.json
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: huangdijia
2 | custom: https://hdj.me/sponsors/
3 |
--------------------------------------------------------------------------------
/screenshots.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huangdijia/laravel-web-soar/HEAD/screenshots.jpg
--------------------------------------------------------------------------------
/resources/css/app.css:
--------------------------------------------------------------------------------
1 | @charset 'UTF-8';
2 |
3 | @import './bootstrap.css';
4 | @import './components/*';
5 |
6 | @tailwind utilities;
7 |
--------------------------------------------------------------------------------
/public/mix-manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "/app.js": "/app.js?id=20522025b6ec7bcf5abc",
3 | "/app.css": "/app.css?id=6f5e91558c710a495e26"
4 | }
5 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: [
3 | require('postcss-easy-import')(),
4 | require('tailwindcss')('./tailwind.js'),
5 | require('postcss-nesting'),
6 | ],
7 | };
8 |
--------------------------------------------------------------------------------
/resources/js/components/SoarOutput.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
13 |
--------------------------------------------------------------------------------
/resources/js/app.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import axios from 'axios';
3 |
4 | let token = document.head.querySelector('meta[name="csrf-token"]');
5 |
6 | if (token) {
7 | axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
8 | }
9 |
10 | Vue.component('soar', require('./components/Soar.vue'));
11 |
12 | new Vue({
13 | el: '#web-soar',
14 | });
15 |
--------------------------------------------------------------------------------
/phpstan.neon:
--------------------------------------------------------------------------------
1 | # Magic behaviour with __get, __set, __call and __callStatic is not exactly static analyser-friendly :)
2 | # Fortunately, You can ingore it by the following config.
3 | #
4 | # vendor/bin/phpstan analyse app --memory-limit 200M -l 0
5 | #
6 | parameters:
7 | reportUnmatchedIgnoredErrors: false
8 | ignoreErrors:
9 | # - '#Unsafe usage of new static\(\)#'
10 |
--------------------------------------------------------------------------------
/resources/css/components/output.css:
--------------------------------------------------------------------------------
1 | .output {
2 | @apply bg-gutter;
3 | @apply px-8 py-4;
4 | @apply overflow-scroll;
5 |
6 | & warning {
7 | @apply block;
8 | @apply px-2;
9 | @apply bg-warning;
10 | @apply whitespace-normal;
11 | }
12 |
13 | & error {
14 | @apply block;
15 | @apply px-2;
16 | @apply bg-error;
17 | @apply whitespace-normal;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/webpack.mix.js:
--------------------------------------------------------------------------------
1 | const mix = require('laravel-mix');
2 | require('laravel-mix-purgecss');
3 |
4 | mix
5 | .setPublicPath('public')
6 | .postCss('resources/css/app.css', 'public')
7 | .purgeCss({
8 | whitelistPatterns: [/CodeMirror/, /cm/, /^theme-/],
9 | })
10 | .js('resources/js/app.js', 'public')
11 | .version()
12 | .options({
13 | // Our PostCSS plugins are defined in a standard `postcss.config.js`
14 | // file, which we'll read for plugins.
15 | postCss: require('./postcss.config').plugins,
16 | })
17 | .copy('public', '../web-soar-app/public/vendor/web-soar');
18 |
--------------------------------------------------------------------------------
/resources/css/components/layout.css:
--------------------------------------------------------------------------------
1 | .layout {
2 | @apply fixed;
3 | @apply h-screen w-screen;
4 | display: grid;
5 | grid-template-columns: 100vw;
6 | }
7 |
8 | .layout-gutter {
9 | @apply flex items-center justify-center;
10 | @apply bg-line;
11 | height: auto;
12 | cursor: ns-resize;
13 |
14 | &:after {
15 | @apply text-dimmed;
16 | @apply text-center;
17 | content: '•••';
18 | font-size: 10px;
19 | line-height: 6px;
20 | word-break: break-all;
21 | }
22 | }
23 |
24 | .layout-columns {
25 | &.layout {
26 | grid-template-rows: 100vh;
27 | }
28 |
29 | & .layout-gutter {
30 | cursor: ew-resize;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "php.suggest.basic": false,
3 | "[php]": {
4 | "editor.formatOnSave": true,
5 | "editor.defaultFormatter": "junstyle.php-cs-fixer",
6 | },
7 | "php-cs-fixer.executablePath": "php-cs-fixer",
8 | "php-cs-fixer.executablePathWindows": "php-cs-fixer",
9 | "php-cs-fixer.onsave": true,
10 | "php-cs-fixer.rules": "@PSR2",
11 | "php-cs-fixer.config": ".php_cs;.php_cs.dist",
12 | "php-cs-fixer.allowRisky": false,
13 | "php-cs-fixer.pathMode": "override",
14 | "php-cs-fixer.exclude": [],
15 | "php-cs-fixer.autoFixByBracket": true,
16 | "php-cs-fixer.autoFixBySemicolon": false,
17 | "php-cs-fixer.formatHtml": true,
18 | "php-cs-fixer.documentFormattingProvider": true,
19 | }
--------------------------------------------------------------------------------
/resources/views/web-soar.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Web Soar
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/.github/workflows/tests.yaml:
--------------------------------------------------------------------------------
1 | name: tests
2 |
3 | on: [push, pull_request]
4 |
5 | jobs:
6 | ci:
7 | name: Test on PHP ${{ matrix.php-version }}
8 | runs-on: "${{ matrix.os }}"
9 | strategy:
10 | matrix:
11 | os: [ubuntu-latest]
12 | php-version: ['8.0', '8.1']
13 | max-parallel: 4
14 | steps:
15 | - name: Checkout
16 | uses: actions/checkout@v2
17 | - name: Setup PHP
18 | uses: shivammathur/setup-php@v2
19 | with:
20 | php-version: ${{ matrix.php-version }}
21 | extensions: redis, pdo, pdo_mysql, bcmath
22 | tools: phpize
23 | coverage: none
24 | - name: Setup Packages
25 | run: composer update -o
26 | - name: Run Analyse
27 | run: |
28 | composer analyse src
29 | # - name: Run Test Cases
30 | # run: |
31 | # composer test
--------------------------------------------------------------------------------
/public/github.css:
--------------------------------------------------------------------------------
1 | .CodeMirror-lines {
2 | padding: 8px 0;
3 | }
4 |
5 | .CodeMirror-gutters {
6 | box-shadow: 1px 0 2px 0 rgba(0, 0, 0, .5);
7 | -webkit-box-shadow: 1px 0 2px 0 rgba(0, 0, 0, .5);
8 | background-color: #f8f8ff;
9 | padding-right: 10px;
10 | z-index: 3;
11 | border: none;
12 | }
13 |
14 | div.CodeMirror-cursor {
15 | border-left: 3px solid #000;
16 | }
17 |
18 | .CodeMirror-activeline-background {
19 | background: #00000012;
20 | }
21 |
22 | .CodeMirror-selected {
23 | background: #bcd5fa;
24 | }
25 |
26 | .cm-comment {
27 | font-style: italic;
28 | color: #998;
29 | }
30 |
31 | .cm-number {
32 | color: null;
33 | }
34 |
35 | .cm-atom {
36 | color: null;
37 | }
38 |
39 | .cm-string {
40 | color: #e020a3;
41 | }
42 |
43 | .cm-variable-2 {
44 | color: #099;
45 | }
46 |
47 | .cm-property {
48 | color: null;
49 | }
50 |
51 | .cm-keyword {
52 | color: null;
53 | }
54 |
55 | .cm-operator {
56 | color: null;
57 | }
58 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) Spatie bvba
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 |
--------------------------------------------------------------------------------
/src/Console/PublishCommand.php:
--------------------------------------------------------------------------------
1 | callSilent('vendor:publish', [
30 | '--tag' => 'view',
31 | '--force' => (bool) $this->option('force'),
32 | ]);
33 |
34 | $this->callSilent('vendor:publish', [
35 | '--tag' => 'web-soar-assets',
36 | '--force' => (bool) $this->option('force'),
37 | ]);
38 |
39 | $this->info('Web soar published successfully.');
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/config/web-soar.php:
--------------------------------------------------------------------------------
1 | '/soar',
13 | 'theme' => 'auto',
14 | 'enabled' => env('SOAR_ENABLED', env('APP_ENV') === 'local'),
15 | 'hint' => [
16 | 'enabled' => env('SOAR_HINT_ENABLED', true),
17 | 'connection' => env('SOAR_HINT_CONNECTION', 'mysql'),
18 | 'excludes' => [],
19 | ],
20 |
21 | '-soar-path' => env('SOAR_PATH', base_path('vendor/bin/soar')),
22 | '-test-dsn' => [
23 | 'host' => env('SOAR_TEST_DSN_HOST', '127.0.0.1'),
24 | 'port' => env('SOAR_TEST_DSN_PORT', '3306'),
25 | 'dbname' => env('SOAR_TEST_DSN_DBNAME', 'database'),
26 | 'username' => env('SOAR_TEST_DSN_USER', 'root'),
27 | 'password' => env('SOAR_TEST_DSN_PASSWORD', ''),
28 | ],
29 | '-log-output' => env('SOAR_LOG_OUTPUT', storage_path('logs/soar.log')),
30 | '-report-type' => env('SOAR_REPORT_TYPE', 'markdown'),
31 | ];
32 |
--------------------------------------------------------------------------------
/src/Console/InstallCommand.php:
--------------------------------------------------------------------------------
1 | comment('Publishing Web Soar Assets...');
33 |
34 | if (! $this->isSoarInstalled()) {
35 | $this->downloadSoarBinary();
36 | }
37 |
38 | $this->callSilent('vendor:publish', [
39 | '--tag' => 'config',
40 | '--force' => (bool) $this->option('force'),
41 | ]);
42 |
43 | $this->info('Web soar installed successfully.');
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/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 | "format": "prettier --write 'resources/**/*.{css,js,vue}'"
12 | },
13 | "dependencies": {
14 | "axios": ">=0.21.1",
15 | "bootstrap": "^4.0.0",
16 | "codemirror": "^5.42.0",
17 | "cross-env": "^5.1",
18 | "jquery": "^3.2",
19 | "laravel-mix": "^2.0",
20 | "laravel-mix-purgecss": "^3.0.0",
21 | "lodash": "^4.17.4",
22 | "postcss-easy-import": "^2.1.0",
23 | "postcss-nesting": "^7.0.0",
24 | "prettier": "^1.15.3",
25 | "split-grid": "^1.0.9",
26 | "tailwindcss": "^0.7.2",
27 | "vue": "^2.5.7"
28 | }
29 | }
--------------------------------------------------------------------------------
/src/Http/Middleware/Authorize.php:
--------------------------------------------------------------------------------
1 | allowedToUseSoar()) {
34 | abort(403);
35 | }
36 |
37 | return $next($request);
38 | }
39 |
40 | /**
41 | * @throws BindingResolutionException
42 | */
43 | protected function allowedToUseSoar(): bool
44 | {
45 | if (! config('web-soar.enabled')) {
46 | return false;
47 | }
48 |
49 | return Gate::check('viewWebSoar');
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/resources/css/components/codemirror.css:
--------------------------------------------------------------------------------
1 | .CodeMirror.cm-s-tinker {
2 | @apply h-full;
3 | @apply font-code;
4 | @apply leading-normal;
5 | @apply bg-background;
6 | color: inherit;
7 |
8 | & .CodeMirror-cursor {
9 | border-color: var(--color-text);
10 | }
11 |
12 | & .CodeMirror-lines {
13 | @apply py-4;
14 | }
15 |
16 | & .CodeMirror-gutters {
17 | @apply bg-gutter;
18 | @apply pl-2;
19 | @apply border-r-2 border-line;
20 | }
21 |
22 | & .CodeMirror-linenumber {
23 | @apply text-dimmed;
24 | @apply text-base;
25 | }
26 |
27 | & .CodeMirror pre {
28 | @apply font-code;
29 | @apply whitespace-no-wrap;
30 | }
31 |
32 | & .CodeMirror-selected {
33 | background: rgba(150, 120, 200, 0.2);
34 | }
35 |
36 | & .CodeMirror-focused .CodeMirror-selected {
37 | background: rgba(150, 120, 200, 0.3);
38 | }
39 |
40 | & .cm-comment {
41 | @apply text-dimmed;
42 | font-style: italic;
43 | }
44 |
45 | & .cm-number {
46 | @apply text-number;
47 | }
48 |
49 | & .cm-string {
50 | @apply text-string;
51 | }
52 |
53 | & .cm-variable-2 {
54 | @apply text-variable;
55 | }
56 |
57 | & .cm-operator {
58 | @apply text-operator;
59 | }
60 |
61 | & .cm-keyword {
62 | @apply text-keyword;
63 | @apply font-bold;
64 | color: #708;
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "huangdijia/laravel-web-soar",
3 | "description": "Artisan soar in your browser",
4 | "keywords": [
5 | "huangdijia",
6 | "web-soar",
7 | "laravel",
8 | "soar",
9 | "debug",
10 | "development"
11 | ],
12 | "homepage": "https://github.com/huangdijia/laravel-web-soar",
13 | "license": "MIT",
14 | "authors": [{
15 | "name": "Huangdijia",
16 | "email": "huangdijia@gmail.com",
17 | "homepage": "https://hdj.me",
18 | "role": "Developer"
19 | }],
20 | "require": {
21 | "php": ">=8.0",
22 | "guanguans/soar-php": "^2.0",
23 | "illuminate/cookie": "^9.0",
24 | "illuminate/session": "^9.0",
25 | "illuminate/support": "^9.0",
26 | "symfony/process": "^6.0"
27 | },
28 | "require-dev": {
29 | "laravel/framework": "^9.0",
30 | "friendsofphp/php-cs-fixer": "^3.0",
31 | "phpstan/phpstan": "^1.0"
32 | },
33 | "autoload": {
34 | "psr-4": {
35 | "Huangdijia\\WebSoar\\": "src"
36 | }
37 | },
38 | "config": {
39 | "sort-packages": true
40 | },
41 | "extra": {
42 | "laravel": {
43 | "providers": [
44 | "Huangdijia\\WebSoar\\WebSoarServiceProvider"
45 | ]
46 | }
47 | },
48 | "scripts": {
49 | "cs-fix": "php-cs-fixer fix $1",
50 | "analyse": "phpstan analyse --memory-limit 300M -l 0 -c phpstan.neon ./src ./config"
51 | }
52 | }
--------------------------------------------------------------------------------
/src/Console/Concerns/InstallSoar.php:
--------------------------------------------------------------------------------
1 | urlFormat, $this->soarVersion, Str::lower(PHP_OS_FAMILY));
55 |
56 | tap(new Process(array_filter([
57 | 'wget',
58 | $url,
59 | '-O',
60 | $soarPath,
61 | ]), base_path(), null, null, null))->mustRun(function ($type, $buffer) {
62 | $this->output->write($buffer);
63 | });
64 |
65 | chmod(base_path($soarPath), 755);
66 |
67 | $this->line('');
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/resources/css/bootstrap.css:
--------------------------------------------------------------------------------
1 | @tailwind preflight;
2 |
3 | :root {
4 | --color-text: #000;
5 | --color-warning: #ffffcf;
6 | --color-error: #dd1144;
7 | --color-keyword: #000;
8 | --color-operator: #000;
9 | --color-variable: #a09f91;
10 | --color-number: #009999;
11 | --color-string: #dd1144;
12 | --color-dimmed: #a09f91;
13 | --color-background: #fff;
14 | --color-line: #f3f7f9;
15 | --color-gutter: #fafdfc;
16 | }
17 |
18 | :root.theme-dark {
19 | --color-text: #fff;
20 | --color-warning: #eab21c;
21 | --color-error: #dd1144;
22 | --color-keyword: #fff;
23 | --color-operator: #dd1144;
24 | --color-variable: #a6e22e;
25 | --color-number: #ae81ff;
26 | --color-string: #e6db74;
27 | --color-dimmed: #706b5c;
28 | --color-background: #272822;
29 | --color-line: #3b3d34;
30 | --color-gutter: #2f3129;
31 | }
32 |
33 | @media (prefers-color-scheme: dark) {
34 | :root.theme-auto {
35 | --color-text: #fff;
36 | --color-warning: #eab21c;
37 | --color-error: #dd1144;
38 | --color-keyword: #fff;
39 | --color-operator: #dd1144;
40 | --color-variable: #a6e22e;
41 | --color-number: #ae81ff;
42 | --color-string: #e6db74;
43 | --color-dimmed: #706b5c;
44 | --color-background: #272822;
45 | --color-line: #3b3d34;
46 | --color-gutter: #2f3129;
47 | }
48 | }
49 |
50 | * {
51 | position: relative;
52 | box-sizing: inherit;
53 | margin: 0;
54 | padding: 0;
55 | color: inherit;
56 | font: inherit;
57 | &:after,
58 | &:before {
59 | box-sizing: inherit;
60 | }
61 | }
62 |
63 | html {
64 | @apply bg-background;
65 | @apply font-code;
66 | @apply leading-normal;
67 | @apply text-text;
68 | box-sizing: border-box;
69 | font-size: 14px;
70 | }
71 |
72 | h1 {
73 | font-size: inherit;
74 | }
75 |
76 | a {
77 | text-decoration: none;
78 | }
79 |
80 | ol,
81 | ul {
82 | list-style: none;
83 | }
84 |
85 | img,
86 | svg {
87 | display: block;
88 | }
89 |
90 | pre,
91 | code {
92 | @apply font-code;
93 | }
94 |
95 | ::selection {
96 | background-color: rgba(150, 120, 200, 0.3);
97 | }
98 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # laravel-web-soar
2 |
3 | [](https://github.com/huangdijia/laravel-web-soar/actions)
4 | [](https://packagist.org/packages/huangdijia/laravel-web-soar)
5 | [](https://packagist.org/packages/huangdijia/laravel-web-soar)
6 | [](https://github.com/huangdijia/laravel-web-soar)
7 |
8 | 
9 |
10 | ## Installation
11 |
12 | ~~~bash
13 | composer require huangdijia/laravel-web-soar --dev
14 | ~~~
15 |
16 | ### Publish
17 |
18 | ~~~bash
19 | # php artisan vendor:publish --provider="Huangdijia\WebSoar\WebSoarServiceProvider"
20 | php artisan web-soar:install
21 | php artisan web-soar:publish
22 | ~~~
23 |
24 | ### Download soar
25 |
26 | ~~~bash
27 | # macOS
28 | wget https://github.com/XiaoMi/soar/releases/download/0.11.0/soar.darwin-amd64 -O vendor/bin/soar
29 | # linux
30 | wget https://github.com/XiaoMi/soar/releases/download/0.11.0/soar.linux-amd64 -O vendor/bin/soar
31 | # windows
32 | wget https://github.com/XiaoMi/soar/releases/download/0.11.0/soar.windows-amd64 -O vendor/bin/soar
33 | # authorization
34 | chmod +x vendor/bin/soar
35 | ~~~
36 |
37 | ## Configure
38 |
39 | ### Env
40 |
41 | ~~~env
42 | SOAR_ENABLED=true
43 | SOAR_HINT_ENABLED=true
44 | SOAR_HINT_CONNECTION=mysql
45 | SOAR_PATH=/usr/local/bin/soar # linux
46 | SOAR_TEST_DSN_HOST=127.0.0.1
47 | SOAR_TEST_DSN_PORT=3306
48 | SOAR_TEST_DSN_DBNAME=yourdb
49 | SOAR_TEST_DSN_USER=root
50 | SOAR_TEST_DSN_PASSWORD=
51 | SOAR_LOG_OUTPUT=/tmp/soar.log
52 | SOAR_REPORT_TYPE=markdown
53 | ~~~
54 |
55 | ### Gate
56 |
57 | ~~~php
58 | // AuthServiceProvider
59 | Gate::define('viewWebSoar', function($user = null) {
60 | return app()->environment('local', 'dev');
61 | });
62 | ~~~
63 |
64 | ## Run
65 |
66 | * [http://youdomain.com/soar](http://youdomain.com/soar)
67 |
68 | ## Thanks
69 |
70 | * [soar](https://github.com/XiaoMi/soar)
71 | * [soar-php](https://github.com/guanguans/soar-php)
72 | * [laravel-web-tinker](https://github.com/spatie/laravel-web-tinker)
73 |
--------------------------------------------------------------------------------
/src/Http/Controllers/WebSoarController.php:
--------------------------------------------------------------------------------
1 | select('SHOW TABLES');
38 |
39 | return collect(array_map('reset', $tables))
40 | ->reject(function ($table) {
41 | return in_array($table, config('web-soar.hint.excludes', []));
42 | })
43 | ->mapWithKeys(function ($table) {
44 | return [$table => Schema::getColumnListing($table)];
45 | })
46 | ->all();
47 | });
48 | }
49 |
50 | return view('web-soar::web-soar', [
51 | 'path' => config('web-soar.path'),
52 | 'tables' => $tables,
53 | ]);
54 | }
55 |
56 | /**
57 | * @throws InvalidArgumentException
58 | * @throws RuntimeException
59 | * @return string
60 | */
61 | public function execute(Request $request, Soar $soar)
62 | {
63 | $validated = $request->validate([
64 | 'code' => 'required',
65 | ]);
66 | $pattern = '/^\s*explain\s*/i';
67 |
68 | if (preg_match($pattern, $validated['code'])) {
69 | $validated['code'] = preg_replace($pattern, '', $validated['code']);
70 | $body = $soar->explain($validated['code'], 'md');
71 | } else {
72 | $body = $soar->score($validated['code']);
73 | }
74 |
75 | return '' . Markdown::parse($body) . '
';
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/resources/js/components/Soar.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
94 |
--------------------------------------------------------------------------------
/resources/js/components/SoarInput.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
95 |
96 |
97 |
98 |
--------------------------------------------------------------------------------
/src/WebSoarServiceProvider.php:
--------------------------------------------------------------------------------
1 | app->runningInConsole()) {
30 | $this->publishes([
31 | __DIR__ . '/../config/web-soar.php' => config_path('web-soar.php'),
32 | ], 'config');
33 |
34 | $this->publishes([
35 | __DIR__ . '/../resources/views' => base_path('resources/views/vendor/web-soar'),
36 | ], 'views');
37 |
38 | $this->publishes([
39 | __DIR__ . '/../public' => public_path('vendor/web-soar'),
40 | ], 'web-soar-assets');
41 | }
42 |
43 | $this->loadViewsFrom(__DIR__ . '/../resources/views', 'web-soar');
44 |
45 | $this->registerRoutes();
46 | $this->registerWebSoarGate();
47 | }
48 |
49 | public function register()
50 | {
51 | $this->mergeConfigFrom(__DIR__ . '/../config/web-soar.php', 'web-soar');
52 |
53 | $this->app->when(Soar::class)
54 | ->needs('$config')
55 | ->give(function () {
56 | return collect(config('web-soar'))
57 | ->filter(function ($item, $key) {
58 | return Str::startsWith($key, '-');
59 | })
60 | ->all();
61 | });
62 |
63 | $this->app->singleton(Soar::class);
64 | $this->app->alias(Soar::class, 'soar');
65 |
66 | $this->commands(InstallCommand::class);
67 | $this->commands(PublishCommand::class);
68 | }
69 |
70 | protected function registerRoutes()
71 | {
72 | Route::prefix(config('web-soar.path'))->middleware([
73 | EncryptCookies::class,
74 | StartSession::class,
75 | Authorize::class,
76 | ])->group(function () {
77 | Route::get('/', [WebSoarController::class, 'index']);
78 | Route::post('/', [WebSoarController::class, 'execute']);
79 | });
80 | }
81 |
82 | protected function registerWebSoarGate()
83 | {
84 | Gate::define('viewWebSoar', function ($user = null) {
85 | return app()->environment('local');
86 | // return true;
87 | });
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/.php-cs-fixer.php:
--------------------------------------------------------------------------------
1 | setRiskyAllowed(true)
21 | ->setRules([
22 | '@PSR2' => true,
23 | '@Symfony' => true,
24 | '@DoctrineAnnotation' => true,
25 | '@PhpCsFixer' => true,
26 | 'header_comment' => [
27 | 'comment_type' => 'PHPDoc',
28 | 'header' => $header,
29 | 'separate' => 'none',
30 | 'location' => 'after_declare_strict',
31 | ],
32 | 'array_syntax' => [
33 | 'syntax' => 'short',
34 | ],
35 | 'list_syntax' => [
36 | 'syntax' => 'short',
37 | ],
38 | 'concat_space' => [
39 | 'spacing' => 'one',
40 | ],
41 | 'blank_line_before_statement' => [
42 | 'statements' => [
43 | 'declare',
44 | ],
45 | ],
46 | 'general_phpdoc_annotation_remove' => [
47 | 'annotations' => [
48 | 'author',
49 | ],
50 | ],
51 | 'ordered_imports' => [
52 | 'imports_order' => [
53 | 'class', 'function', 'const',
54 | ],
55 | 'sort_algorithm' => 'alpha',
56 | ],
57 | 'single_line_comment_style' => [
58 | 'comment_types' => [
59 | ],
60 | ],
61 | 'yoda_style' => [
62 | 'always_move_variable' => false,
63 | 'equal' => false,
64 | 'identical' => false,
65 | ],
66 | 'phpdoc_align' => [
67 | 'align' => 'left',
68 | ],
69 | 'multiline_whitespace_before_semicolons' => [
70 | 'strategy' => 'no_multi_line',
71 | ],
72 | 'constant_case' => [
73 | 'case' => 'lower',
74 | ],
75 | 'class_attributes_separation' => true,
76 | 'combine_consecutive_unsets' => true,
77 | 'declare_strict_types' => true,
78 | 'linebreak_after_opening_tag' => true,
79 | 'lowercase_static_reference' => true,
80 | 'no_useless_else' => true,
81 | 'no_unused_imports' => true,
82 | 'not_operator_with_successor_space' => true,
83 | 'not_operator_with_space' => false,
84 | 'ordered_class_elements' => true,
85 | 'php_unit_strict' => false,
86 | 'phpdoc_separation' => false,
87 | 'single_quote' => true,
88 | 'standardize_not_equals' => true,
89 | 'multiline_comment_opening_closing' => true,
90 | ])
91 | ->setFinder(
92 | PhpCsFixer\Finder::create()
93 | ->exclude('bin')
94 | ->exclude('public')
95 | ->exclude('runtime')
96 | ->exclude('vendor')
97 | ->in(__DIR__)
98 | )
99 | ->setUsingCache(false);
100 |
--------------------------------------------------------------------------------
/resources/css/components/github-markdown.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: octicons-link;
3 | src: url(data:font/woff;charset=utf-8;base64,d09GRgABAAAAAAZwABAAAAAACFQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABEU0lHAAAGaAAAAAgAAAAIAAAAAUdTVUIAAAZcAAAACgAAAAoAAQAAT1MvMgAAAyQAAABJAAAAYFYEU3RjbWFwAAADcAAAAEUAAACAAJThvmN2dCAAAATkAAAABAAAAAQAAAAAZnBnbQAAA7gAAACyAAABCUM+8IhnYXNwAAAGTAAAABAAAAAQABoAI2dseWYAAAFsAAABPAAAAZwcEq9taGVhZAAAAsgAAAA0AAAANgh4a91oaGVhAAADCAAAABoAAAAkCA8DRGhtdHgAAAL8AAAADAAAAAwGAACfbG9jYQAAAsAAAAAIAAAACABiATBtYXhwAAACqAAAABgAAAAgAA8ASm5hbWUAAAToAAABQgAAAlXu73sOcG9zdAAABiwAAAAeAAAAME3QpOBwcmVwAAAEbAAAAHYAAAB/aFGpk3jaTY6xa8JAGMW/O62BDi0tJLYQincXEypYIiGJjSgHniQ6umTsUEyLm5BV6NDBP8Tpts6F0v+k/0an2i+itHDw3v2+9+DBKTzsJNnWJNTgHEy4BgG3EMI9DCEDOGEXzDADU5hBKMIgNPZqoD3SilVaXZCER3/I7AtxEJLtzzuZfI+VVkprxTlXShWKb3TBecG11rwoNlmmn1P2WYcJczl32etSpKnziC7lQyWe1smVPy/Lt7Kc+0vWY/gAgIIEqAN9we0pwKXreiMasxvabDQMM4riO+qxM2ogwDGOZTXxwxDiycQIcoYFBLj5K3EIaSctAq2kTYiw+ymhce7vwM9jSqO8JyVd5RH9gyTt2+J/yUmYlIR0s04n6+7Vm1ozezUeLEaUjhaDSuXHwVRgvLJn1tQ7xiuVv/ocTRF42mNgZGBgYGbwZOBiAAFGJBIMAAizAFoAAABiAGIAznjaY2BkYGAA4in8zwXi+W2+MjCzMIDApSwvXzC97Z4Ig8N/BxYGZgcgl52BCSQKAA3jCV8CAABfAAAAAAQAAEB42mNgZGBg4f3vACQZQABIMjKgAmYAKEgBXgAAeNpjYGY6wTiBgZWBg2kmUxoDA4MPhGZMYzBi1AHygVLYQUCaawqDA4PChxhmh/8ODDEsvAwHgMKMIDnGL0x7gJQCAwMAJd4MFwAAAHjaY2BgYGaA4DAGRgYQkAHyGMF8NgYrIM3JIAGVYYDT+AEjAwuDFpBmA9KMDEwMCh9i/v8H8sH0/4dQc1iAmAkALaUKLgAAAHjaTY9LDsIgEIbtgqHUPpDi3gPoBVyRTmTddOmqTXThEXqrob2gQ1FjwpDvfwCBdmdXC5AVKFu3e5MfNFJ29KTQT48Ob9/lqYwOGZxeUelN2U2R6+cArgtCJpauW7UQBqnFkUsjAY/kOU1cP+DAgvxwn1chZDwUbd6CFimGXwzwF6tPbFIcjEl+vvmM/byA48e6tWrKArm4ZJlCbdsrxksL1AwWn/yBSJKpYbq8AXaaTb8AAHja28jAwOC00ZrBeQNDQOWO//sdBBgYGRiYWYAEELEwMTE4uzo5Zzo5b2BxdnFOcALxNjA6b2ByTswC8jYwg0VlNuoCTWAMqNzMzsoK1rEhNqByEyerg5PMJlYuVueETKcd/89uBpnpvIEVomeHLoMsAAe1Id4AAAAAAAB42oWQT07CQBTGv0JBhagk7HQzKxca2sJCE1hDt4QF+9JOS0nbaaYDCQfwCJ7Au3AHj+LO13FMmm6cl7785vven0kBjHCBhfpYuNa5Ph1c0e2Xu3jEvWG7UdPDLZ4N92nOm+EBXuAbHmIMSRMs+4aUEd4Nd3CHD8NdvOLTsA2GL8M9PODbcL+hD7C1xoaHeLJSEao0FEW14ckxC+TU8TxvsY6X0eLPmRhry2WVioLpkrbp84LLQPGI7c6sOiUzpWIWS5GzlSgUzzLBSikOPFTOXqly7rqx0Z1Q5BAIoZBSFihQYQOOBEdkCOgXTOHA07HAGjGWiIjaPZNW13/+lm6S9FT7rLHFJ6fQbkATOG1j2OFMucKJJsxIVfQORl+9Jyda6Sl1dUYhSCm1dyClfoeDve4qMYdLEbfqHf3O/AdDumsjAAB42mNgYoAAZQYjBmyAGYQZmdhL8zLdDEydARfoAqIAAAABAAMABwAKABMAB///AA8AAQAAAAAAAAAAAAAAAAABAAAAAA==) format('woff');
4 | }
5 |
6 | .markdown-body .octicon {
7 | display: inline-block;
8 | fill: currentColor;
9 | vertical-align: text-bottom;
10 | }
11 |
12 | .markdown-body .anchor {
13 | float: left;
14 | line-height: 1;
15 | margin-left: -20px;
16 | padding-right: 4px;
17 | }
18 |
19 | .markdown-body .anchor:focus {
20 | outline: none;
21 | }
22 |
23 | .markdown-body h1 .octicon-link,
24 | .markdown-body h2 .octicon-link,
25 | .markdown-body h3 .octicon-link,
26 | .markdown-body h4 .octicon-link,
27 | .markdown-body h5 .octicon-link,
28 | .markdown-body h6 .octicon-link {
29 | color: #1b1f23;
30 | vertical-align: middle;
31 | visibility: hidden;
32 | }
33 |
34 | .markdown-body h1:hover .anchor,
35 | .markdown-body h2:hover .anchor,
36 | .markdown-body h3:hover .anchor,
37 | .markdown-body h4:hover .anchor,
38 | .markdown-body h5:hover .anchor,
39 | .markdown-body h6:hover .anchor {
40 | text-decoration: none;
41 | }
42 |
43 | .markdown-body h1:hover .anchor .octicon-link,
44 | .markdown-body h2:hover .anchor .octicon-link,
45 | .markdown-body h3:hover .anchor .octicon-link,
46 | .markdown-body h4:hover .anchor .octicon-link,
47 | .markdown-body h5:hover .anchor .octicon-link,
48 | .markdown-body h6:hover .anchor .octicon-link {
49 | visibility: visible;
50 | }
51 |
52 | .markdown-body {
53 | -ms-text-size-adjust: 100%;
54 | -webkit-text-size-adjust: 100%;
55 | color: #24292e;
56 | line-height: 1.5;
57 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol;
58 | font-size: 16px;
59 | line-height: 1.5;
60 | word-wrap: break-word;
61 | }
62 |
63 | .markdown-body .pl-c {
64 | color: #6a737d;
65 | }
66 |
67 | .markdown-body .pl-c1,
68 | .markdown-body .pl-s .pl-v {
69 | color: #005cc5;
70 | }
71 |
72 | .markdown-body .pl-e,
73 | .markdown-body .pl-en {
74 | color: #6f42c1;
75 | }
76 |
77 | .markdown-body .pl-s .pl-s1,
78 | .markdown-body .pl-smi {
79 | color: #24292e;
80 | }
81 |
82 | .markdown-body .pl-ent {
83 | color: #22863a;
84 | }
85 |
86 | .markdown-body .pl-k {
87 | color: #d73a49;
88 | }
89 |
90 | .markdown-body .pl-pds,
91 | .markdown-body .pl-s,
92 | .markdown-body .pl-s .pl-pse .pl-s1,
93 | .markdown-body .pl-sr,
94 | .markdown-body .pl-sr .pl-cce,
95 | .markdown-body .pl-sr .pl-sra,
96 | .markdown-body .pl-sr .pl-sre {
97 | color: #032f62;
98 | }
99 |
100 | .markdown-body .pl-smw,
101 | .markdown-body .pl-v {
102 | color: #e36209;
103 | }
104 |
105 | .markdown-body .pl-bu {
106 | color: #b31d28;
107 | }
108 |
109 | .markdown-body .pl-ii {
110 | background-color: #b31d28;
111 | color: #fafbfc;
112 | }
113 |
114 | .markdown-body .pl-c2 {
115 | background-color: #d73a49;
116 | color: #fafbfc;
117 | }
118 |
119 | .markdown-body .pl-c2:before {
120 | content: "^M";
121 | }
122 |
123 | .markdown-body .pl-sr .pl-cce {
124 | color: #22863a;
125 | font-weight: 700;
126 | }
127 |
128 | .markdown-body .pl-ml {
129 | color: #735c0f;
130 | }
131 |
132 | .markdown-body .pl-mh,
133 | .markdown-body .pl-mh .pl-en,
134 | .markdown-body .pl-ms {
135 | color: #005cc5;
136 | font-weight: 700;
137 | }
138 |
139 | .markdown-body .pl-mi {
140 | color: #24292e;
141 | font-style: italic;
142 | }
143 |
144 | .markdown-body .pl-mb {
145 | color: #24292e;
146 | font-weight: 700;
147 | }
148 |
149 | .markdown-body .pl-md {
150 | background-color: #ffeef0;
151 | color: #b31d28;
152 | }
153 |
154 | .markdown-body .pl-mi1 {
155 | background-color: #f0fff4;
156 | color: #22863a;
157 | }
158 |
159 | .markdown-body .pl-mc {
160 | background-color: #ffebda;
161 | color: #e36209;
162 | }
163 |
164 | .markdown-body .pl-mi2 {
165 | background-color: #005cc5;
166 | color: #f6f8fa;
167 | }
168 |
169 | .markdown-body .pl-mdr {
170 | color: #6f42c1;
171 | font-weight: 700;
172 | }
173 |
174 | .markdown-body .pl-ba {
175 | color: #586069;
176 | }
177 |
178 | .markdown-body .pl-sg {
179 | color: #959da5;
180 | }
181 |
182 | .markdown-body .pl-corl {
183 | color: #032f62;
184 | text-decoration: underline;
185 | }
186 |
187 | .markdown-body details {
188 | display: block;
189 | }
190 |
191 | .markdown-body summary {
192 | display: list-item;
193 | }
194 |
195 | .markdown-body a {
196 | background-color: transparent;
197 | }
198 |
199 | .markdown-body a:active,
200 | .markdown-body a:hover {
201 | outline-width: 0;
202 | }
203 |
204 | .markdown-body strong {
205 | font-weight: inherit;
206 | font-weight: bolder;
207 | }
208 |
209 | .markdown-body h1 {
210 | font-size: 2em;
211 | margin: .67em 0;
212 | }
213 |
214 | .markdown-body img {
215 | border-style: none;
216 | }
217 |
218 | .markdown-body code,
219 | .markdown-body kbd,
220 | .markdown-body pre {
221 | font-family: monospace, monospace;
222 | font-size: 1em;
223 | }
224 |
225 | .markdown-body hr {
226 | box-sizing: content-box;
227 | height: 0;
228 | overflow: visible;
229 | }
230 |
231 | .markdown-body input {
232 | font: inherit;
233 | margin: 0;
234 | }
235 |
236 | .markdown-body input {
237 | overflow: visible;
238 | }
239 |
240 | .markdown-body [type=checkbox] {
241 | box-sizing: border-box;
242 | padding: 0;
243 | }
244 |
245 | .markdown-body * {
246 | box-sizing: border-box;
247 | }
248 |
249 | .markdown-body input {
250 | font-family: inherit;
251 | font-size: inherit;
252 | line-height: inherit;
253 | }
254 |
255 | .markdown-body a {
256 | color: #0366d6;
257 | text-decoration: none;
258 | }
259 |
260 | .markdown-body a:hover {
261 | text-decoration: underline;
262 | }
263 |
264 | .markdown-body strong {
265 | font-weight: 600;
266 | }
267 |
268 | .markdown-body hr {
269 | background: transparent;
270 | border: 0;
271 | border-bottom: 1px solid #dfe2e5;
272 | height: 0;
273 | margin: 15px 0;
274 | overflow: hidden;
275 | }
276 |
277 | .markdown-body hr:before {
278 | content: "";
279 | display: table;
280 | }
281 |
282 | .markdown-body hr:after {
283 | clear: both;
284 | content: "";
285 | display: table;
286 | }
287 |
288 | .markdown-body table {
289 | border-collapse: collapse;
290 | border-spacing: 0;
291 | }
292 |
293 | .markdown-body td,
294 | .markdown-body th {
295 | padding: 0;
296 | }
297 |
298 | .markdown-body details summary {
299 | cursor: pointer;
300 | }
301 |
302 | .markdown-body h1,
303 | .markdown-body h2,
304 | .markdown-body h3,
305 | .markdown-body h4,
306 | .markdown-body h5,
307 | .markdown-body h6 {
308 | margin-bottom: 0;
309 | margin-top: 0;
310 | }
311 |
312 | .markdown-body h1 {
313 | font-size: 32px;
314 | }
315 |
316 | .markdown-body h1,
317 | .markdown-body h2 {
318 | font-weight: 600;
319 | }
320 |
321 | .markdown-body h2 {
322 | font-size: 24px;
323 | }
324 |
325 | .markdown-body h3 {
326 | font-size: 20px;
327 | }
328 |
329 | .markdown-body h3,
330 | .markdown-body h4 {
331 | font-weight: 600;
332 | }
333 |
334 | .markdown-body h4 {
335 | font-size: 16px;
336 | }
337 |
338 | .markdown-body h5 {
339 | font-size: 14px;
340 | }
341 |
342 | .markdown-body h5,
343 | .markdown-body h6 {
344 | font-weight: 600;
345 | }
346 |
347 | .markdown-body h6 {
348 | font-size: 12px;
349 | }
350 |
351 | .markdown-body p {
352 | margin-bottom: 10px;
353 | margin-top: 0;
354 | }
355 |
356 | .markdown-body blockquote {
357 | margin: 0;
358 | }
359 |
360 | .markdown-body ol,
361 | .markdown-body ul {
362 | margin-bottom: 0;
363 | margin-top: 0;
364 | padding-left: 0;
365 | }
366 |
367 | .markdown-body ol ol,
368 | .markdown-body ul ol {
369 | list-style-type: lower-roman;
370 | }
371 |
372 | .markdown-body ol ol ol,
373 | .markdown-body ol ul ol,
374 | .markdown-body ul ol ol,
375 | .markdown-body ul ul ol {
376 | list-style-type: lower-alpha;
377 | }
378 |
379 | .markdown-body dd {
380 | margin-left: 0;
381 | }
382 |
383 | .markdown-body code,
384 | .markdown-body pre {
385 | font-family: SFMono-Regular, Consolas, Liberation Mono, Menlo, Courier, monospace;
386 | font-size: 12px;
387 | }
388 |
389 | .markdown-body pre {
390 | margin-bottom: 0;
391 | margin-top: 0;
392 | }
393 |
394 | .markdown-body input::-webkit-inner-spin-button,
395 | .markdown-body input::-webkit-outer-spin-button {
396 | -webkit-appearance: none;
397 | appearance: none;
398 | margin: 0;
399 | }
400 |
401 | .markdown-body .border {
402 | border: 1px solid #e1e4e8!important;
403 | }
404 |
405 | .markdown-body .border-0 {
406 | border: 0!important;
407 | }
408 |
409 | .markdown-body .border-bottom {
410 | border-bottom: 1px solid #e1e4e8!important;
411 | }
412 |
413 | .markdown-body .rounded-1 {
414 | border-radius: 3px!important;
415 | }
416 |
417 | .markdown-body .bg-white {
418 | background-color: #fff!important;
419 | }
420 |
421 | .markdown-body .bg-gray-light {
422 | background-color: #fafbfc!important;
423 | }
424 |
425 | .markdown-body .text-gray-light {
426 | color: #6a737d!important;
427 | }
428 |
429 | .markdown-body .mb-0 {
430 | margin-bottom: 0!important;
431 | }
432 |
433 | .markdown-body .my-2 {
434 | margin-bottom: 8px!important;
435 | margin-top: 8px!important;
436 | }
437 |
438 | .markdown-body .pl-0 {
439 | padding-left: 0!important;
440 | }
441 |
442 | .markdown-body .py-0 {
443 | padding-bottom: 0!important;
444 | padding-top: 0!important;
445 | }
446 |
447 | .markdown-body .pl-1 {
448 | padding-left: 4px!important;
449 | }
450 |
451 | .markdown-body .pl-2 {
452 | padding-left: 8px!important;
453 | }
454 |
455 | .markdown-body .py-2 {
456 | padding-bottom: 8px!important;
457 | padding-top: 8px!important;
458 | }
459 |
460 | .markdown-body .pl-3,
461 | .markdown-body .px-3 {
462 | padding-left: 16px!important;
463 | }
464 |
465 | .markdown-body .px-3 {
466 | padding-right: 16px!important;
467 | }
468 |
469 | .markdown-body .pl-4 {
470 | padding-left: 24px!important;
471 | }
472 |
473 | .markdown-body .pl-5 {
474 | padding-left: 32px!important;
475 | }
476 |
477 | .markdown-body .pl-6 {
478 | padding-left: 40px!important;
479 | }
480 |
481 | .markdown-body .f6 {
482 | font-size: 12px!important;
483 | }
484 |
485 | .markdown-body .lh-condensed {
486 | line-height: 1.25!important;
487 | }
488 |
489 | .markdown-body .text-bold {
490 | font-weight: 600!important;
491 | }
492 |
493 | .markdown-body:before {
494 | content: "";
495 | display: table;
496 | }
497 |
498 | .markdown-body:after {
499 | clear: both;
500 | content: "";
501 | display: table;
502 | }
503 |
504 | .markdown-body>:first-child {
505 | margin-top: 0!important;
506 | }
507 |
508 | .markdown-body>:last-child {
509 | margin-bottom: 0!important;
510 | }
511 |
512 | .markdown-body a:not([href]) {
513 | color: inherit;
514 | text-decoration: none;
515 | }
516 |
517 | .markdown-body blockquote,
518 | .markdown-body dl,
519 | .markdown-body ol,
520 | .markdown-body p,
521 | .markdown-body pre,
522 | .markdown-body table,
523 | .markdown-body ul {
524 | margin-bottom: 16px;
525 | margin-top: 0;
526 | }
527 |
528 | .markdown-body hr {
529 | background-color: #e1e4e8;
530 | border: 0;
531 | height: .25em;
532 | margin: 24px 0;
533 | padding: 0;
534 | }
535 |
536 | .markdown-body blockquote {
537 | border-left: .25em solid #dfe2e5;
538 | color: #6a737d;
539 | padding: 0 1em;
540 | }
541 |
542 | .markdown-body blockquote>:first-child {
543 | margin-top: 0;
544 | }
545 |
546 | .markdown-body blockquote>:last-child {
547 | margin-bottom: 0;
548 | }
549 |
550 | .markdown-body kbd {
551 | background-color: #fafbfc;
552 | border: 1px solid #c6cbd1;
553 | border-bottom-color: #959da5;
554 | border-radius: 3px;
555 | box-shadow: inset 0 -1px 0 #959da5;
556 | color: #444d56;
557 | display: inline-block;
558 | font-size: 11px;
559 | line-height: 10px;
560 | padding: 3px 5px;
561 | vertical-align: middle;
562 | }
563 |
564 | .markdown-body h1,
565 | .markdown-body h2,
566 | .markdown-body h3,
567 | .markdown-body h4,
568 | .markdown-body h5,
569 | .markdown-body h6 {
570 | font-weight: 600;
571 | line-height: 1.25;
572 | margin-bottom: 16px;
573 | margin-top: 24px;
574 | }
575 |
576 | .markdown-body h1 {
577 | font-size: 2em;
578 | }
579 |
580 | .markdown-body h1,
581 | .markdown-body h2 {
582 | border-bottom: 1px solid #eaecef;
583 | padding-bottom: .3em;
584 | }
585 |
586 | .markdown-body h2 {
587 | font-size: 1.5em;
588 | }
589 |
590 | .markdown-body h3 {
591 | font-size: 1.25em;
592 | }
593 |
594 | .markdown-body h4 {
595 | font-size: 1em;
596 | }
597 |
598 | .markdown-body h5 {
599 | font-size: .875em;
600 | }
601 |
602 | .markdown-body h6 {
603 | color: #6a737d;
604 | font-size: .85em;
605 | }
606 |
607 | .markdown-body ol,
608 | .markdown-body ul {
609 | padding-left: 2em;
610 | }
611 |
612 | .markdown-body ol ol,
613 | .markdown-body ol ul,
614 | .markdown-body ul ol,
615 | .markdown-body ul ul {
616 | margin-bottom: 0;
617 | margin-top: 0;
618 | }
619 |
620 | .markdown-body li {
621 | word-wrap: break-all;
622 | }
623 |
624 | .markdown-body li>p {
625 | margin-top: 16px;
626 | }
627 |
628 | .markdown-body li+li {
629 | margin-top: .25em;
630 | }
631 |
632 | .markdown-body dl {
633 | padding: 0;
634 | }
635 |
636 | .markdown-body dl dt {
637 | font-size: 1em;
638 | font-style: italic;
639 | font-weight: 600;
640 | margin-top: 16px;
641 | padding: 0;
642 | }
643 |
644 | .markdown-body dl dd {
645 | margin-bottom: 16px;
646 | padding: 0 16px;
647 | }
648 |
649 | .markdown-body table {
650 | display: block;
651 | overflow: auto;
652 | width: 100%;
653 | }
654 |
655 | .markdown-body table th {
656 | font-weight: 600;
657 | }
658 |
659 | .markdown-body table td,
660 | .markdown-body table th {
661 | border: 1px solid #dfe2e5;
662 | padding: 6px 13px;
663 | }
664 |
665 | .markdown-body table tr {
666 | background-color: #fff;
667 | border-top: 1px solid #c6cbd1;
668 | }
669 |
670 | .markdown-body table tr:nth-child(2n) {
671 | background-color: #f6f8fa;
672 | }
673 |
674 | .markdown-body img {
675 | background-color: #fff;
676 | box-sizing: content-box;
677 | max-width: 100%;
678 | }
679 |
680 | .markdown-body img[align=right] {
681 | padding-left: 20px;
682 | }
683 |
684 | .markdown-body img[align=left] {
685 | padding-right: 20px;
686 | }
687 |
688 | .markdown-body code {
689 | background-color: rgba(27, 31, 35, .05);
690 | border-radius: 3px;
691 | font-size: 85%;
692 | margin: 0;
693 | padding: .2em .4em;
694 | }
695 |
696 | .markdown-body pre {
697 | word-wrap: normal;
698 | }
699 |
700 | .markdown-body pre>code {
701 | background: transparent;
702 | border: 0;
703 | font-size: 100%;
704 | margin: 0;
705 | padding: 0;
706 | white-space: pre;
707 | word-break: normal;
708 | }
709 |
710 | .markdown-body .highlight {
711 | margin-bottom: 16px;
712 | }
713 |
714 | .markdown-body .highlight pre {
715 | margin-bottom: 0;
716 | word-break: normal;
717 | }
718 |
719 | .markdown-body .highlight pre,
720 | .markdown-body pre {
721 | background-color: #f6f8fa;
722 | border-radius: 3px;
723 | font-size: 85%;
724 | line-height: 1.45;
725 | overflow: auto;
726 | padding: 16px;
727 | }
728 |
729 | .markdown-body pre code {
730 | background-color: transparent;
731 | border: 0;
732 | display: inline;
733 | line-height: inherit;
734 | margin: 0;
735 | max-width: auto;
736 | overflow: visible;
737 | padding: 0;
738 | word-wrap: normal;
739 | }
740 |
741 | .markdown-body .commit-tease-sha {
742 | color: #444d56;
743 | display: inline-block;
744 | font-family: SFMono-Regular, Consolas, Liberation Mono, Menlo, Courier, monospace;
745 | font-size: 90%;
746 | }
747 |
748 | .markdown-body .blob-wrapper {
749 | border-bottom-left-radius: 3px;
750 | border-bottom-right-radius: 3px;
751 | overflow-x: auto;
752 | overflow-y: hidden;
753 | }
754 |
755 | .markdown-body .blob-wrapper-embedded {
756 | max-height: 240px;
757 | overflow-y: auto;
758 | }
759 |
760 | .markdown-body .blob-num {
761 | -moz-user-select: none;
762 | -ms-user-select: none;
763 | -webkit-user-select: none;
764 | color: rgba(27, 31, 35, .3);
765 | cursor: pointer;
766 | font-family: SFMono-Regular, Consolas, Liberation Mono, Menlo, Courier, monospace;
767 | font-size: 12px;
768 | line-height: 20px;
769 | min-width: 50px;
770 | padding-left: 10px;
771 | padding-right: 10px;
772 | text-align: right;
773 | user-select: none;
774 | vertical-align: top;
775 | white-space: nowrap;
776 | width: 1%;
777 | }
778 |
779 | .markdown-body .blob-num:hover {
780 | color: rgba(27, 31, 35, .6);
781 | }
782 |
783 | .markdown-body .blob-num:before {
784 | content: attr(data-line-number);
785 | }
786 |
787 | .markdown-body .blob-code {
788 | line-height: 20px;
789 | padding-left: 10px;
790 | padding-right: 10px;
791 | position: relative;
792 | vertical-align: top;
793 | }
794 |
795 | .markdown-body .blob-code-inner {
796 | color: #24292e;
797 | font-family: SFMono-Regular, Consolas, Liberation Mono, Menlo, Courier, monospace;
798 | font-size: 12px;
799 | overflow: visible;
800 | white-space: pre;
801 | word-wrap: normal;
802 | }
803 |
804 | .markdown-body .pl-token.active,
805 | .markdown-body .pl-token:hover {
806 | background: #ffea7f;
807 | cursor: pointer;
808 | }
809 |
810 | .markdown-body kbd {
811 | background-color: #fafbfc;
812 | border: 1px solid #d1d5da;
813 | border-bottom-color: #c6cbd1;
814 | border-radius: 3px;
815 | box-shadow: inset 0 -1px 0 #c6cbd1;
816 | color: #444d56;
817 | display: inline-block;
818 | font: 11px SFMono-Regular, Consolas, Liberation Mono, Menlo, Courier, monospace;
819 | line-height: 10px;
820 | padding: 3px 5px;
821 | vertical-align: middle;
822 | }
823 |
824 | .markdown-body :checked+.radio-label {
825 | border-color: #0366d6;
826 | position: relative;
827 | z-index: 1;
828 | }
829 |
830 | .markdown-body .tab-size[data-tab-size="1"] {
831 | -moz-tab-size: 1;
832 | tab-size: 1;
833 | }
834 |
835 | .markdown-body .tab-size[data-tab-size="2"] {
836 | -moz-tab-size: 2;
837 | tab-size: 2;
838 | }
839 |
840 | .markdown-body .tab-size[data-tab-size="3"] {
841 | -moz-tab-size: 3;
842 | tab-size: 3;
843 | }
844 |
845 | .markdown-body .tab-size[data-tab-size="4"] {
846 | -moz-tab-size: 4;
847 | tab-size: 4;
848 | }
849 |
850 | .markdown-body .tab-size[data-tab-size="5"] {
851 | -moz-tab-size: 5;
852 | tab-size: 5;
853 | }
854 |
855 | .markdown-body .tab-size[data-tab-size="6"] {
856 | -moz-tab-size: 6;
857 | tab-size: 6;
858 | }
859 |
860 | .markdown-body .tab-size[data-tab-size="7"] {
861 | -moz-tab-size: 7;
862 | tab-size: 7;
863 | }
864 |
865 | .markdown-body .tab-size[data-tab-size="8"] {
866 | -moz-tab-size: 8;
867 | tab-size: 8;
868 | }
869 |
870 | .markdown-body .tab-size[data-tab-size="9"] {
871 | -moz-tab-size: 9;
872 | tab-size: 9;
873 | }
874 |
875 | .markdown-body .tab-size[data-tab-size="10"] {
876 | -moz-tab-size: 10;
877 | tab-size: 10;
878 | }
879 |
880 | .markdown-body .tab-size[data-tab-size="11"] {
881 | -moz-tab-size: 11;
882 | tab-size: 11;
883 | }
884 |
885 | .markdown-body .tab-size[data-tab-size="12"] {
886 | -moz-tab-size: 12;
887 | tab-size: 12;
888 | }
889 |
890 | .markdown-body .task-list-item {
891 | list-style-type: none;
892 | }
893 |
894 | .markdown-body .task-list-item+.task-list-item {
895 | margin-top: 3px;
896 | }
897 |
898 | .markdown-body .task-list-item input {
899 | margin: 0 .2em .25em -1.6em;
900 | vertical-align: middle;
901 | }
902 |
903 | .markdown-body hr {
904 | border-bottom-color: #eee;
905 | }
906 |
907 | .markdown-body .pl-0 {
908 | padding-left: 0!important;
909 | }
910 |
911 | .markdown-body .pl-1 {
912 | padding-left: 4px!important;
913 | }
914 |
915 | .markdown-body .pl-2 {
916 | padding-left: 8px!important;
917 | }
918 |
919 | .markdown-body .pl-3 {
920 | padding-left: 16px!important;
921 | }
922 |
923 | .markdown-body .pl-4 {
924 | padding-left: 24px!important;
925 | }
926 |
927 | .markdown-body .pl-5 {
928 | padding-left: 32px!important;
929 | }
930 |
931 | .markdown-body .pl-6 {
932 | padding-left: 40px!important;
933 | }
934 |
935 | .markdown-body .pl-7 {
936 | padding-left: 48px!important;
937 | }
938 |
939 | .markdown-body .pl-8 {
940 | padding-left: 64px!important;
941 | }
942 |
943 | .markdown-body .pl-9 {
944 | padding-left: 80px!important;
945 | }
946 |
947 | .markdown-body .pl-10 {
948 | padding-left: 96px!important;
949 | }
950 |
951 | .markdown-body .pl-11 {
952 | padding-left: 112px!important;
953 | }
954 |
955 | .markdown-body .pl-12 {
956 | padding-left: 128px!important;
957 | }
958 |
959 |
960 | /* dark */
961 |
962 | :root.theme-dark .markdown-body * {
963 | color: #BBB;
964 | }
965 |
966 | :root.theme-dark .markdown-body h2 {
967 | border-color: #BBB;
968 | }
969 |
970 | :root.theme-dark .markdown-body pre code {
971 | color: #000;
972 | }
973 |
974 | @media (prefers-color-scheme: dark) {
975 | :root.theme-auto .markdown-body * {
976 | color: #BBB;
977 | }
978 | :root.theme-auto .markdown-body h2 {
979 | border-color: #BBB;
980 | }
981 | :root.theme-auto .markdown-body pre code {
982 | color: #000;
983 | }
984 | }
--------------------------------------------------------------------------------
/tailwind.js:
--------------------------------------------------------------------------------
1 | /*
2 | Tailwind - The Utility-First CSS Framework
3 | A project by Adam Wathan (@adamwathan), Jonathan Reinink (@reinink),
4 | David Hemphill (@davidhemphill) and Steve Schoger (@steveschoger).
5 | Welcome to the Tailwind config file. This is where you can customize
6 | Tailwind specifically for your project. Don't be intimidated by the
7 | length of this file. It's really just a big JavaScript object and
8 | we've done our very best to explain each section.
9 | View the full documentation at https://tailwindcss.com.
10 | |-------------------------------------------------------------------------------
11 | | The default config
12 | |-------------------------------------------------------------------------------
13 | |
14 | | This variable contains the default Tailwind config. You don't have
15 | | to use it, but it can sometimes be helpful to have available. For
16 | | example, you may choose to merge your custom configuration
17 | | values with some of the Tailwind defaults.
18 | |
19 | */
20 |
21 | var defaultConfig = require('tailwindcss/defaultConfig')()
22 |
23 |
24 | /*
25 | |-------------------------------------------------------------------------------
26 | | Colors https://tailwindcss.com/docs/colors
27 | |-------------------------------------------------------------------------------
28 | |
29 | | Here you can specify the colors used in your project. To get you started,
30 | | we've provided a generous palette of great looking colors that are perfect
31 | | for prototyping, but don't hesitate to change them for your project. You
32 | | own these colors, nothing will break if you change everything about them.
33 | |
34 | | We've used literal color names ("red", "blue", etc.) for the default
35 | | palette, but if you'd rather use functional names like "primary" and
36 | | "secondary", or even a numeric scale like "100" and "200", go for it.
37 | |
38 | */
39 |
40 | var colors = {
41 | 'transparent': 'transparent',
42 |
43 | 'text': 'var(--color-text)',
44 | 'invers': 'var(--color-invers)',
45 | 'output': 'var(--color-output)',
46 | 'warning': 'var(--color-warning)',
47 | 'error': 'var(--color-error)',
48 | 'keyword': 'var(--color-keyword)',
49 | 'variable': 'var(--color-variable)',
50 | 'operator': 'var(--color-operator)',
51 | 'number': 'var(--color-number)',
52 | 'string': 'var(--color-string)',
53 | 'dimmed': 'var(--color-dimmed)',
54 | 'background': 'var(--color-background)',
55 | 'line': 'var(--color-line)',
56 | 'gutter': 'var(--color-gutter)',
57 | }
58 |
59 | module.exports = {
60 |
61 | /*
62 | |-----------------------------------------------------------------------------
63 | | Colors https://tailwindcss.com/docs/colors
64 | |-----------------------------------------------------------------------------
65 | |
66 | | The color palette defined above is also assigned to the "colors" key of
67 | | your Tailwind config. This makes it easy to access them in your CSS
68 | | using Tailwind's config helper. For example:
69 | |
70 | | .error { color: config('colors.red') }
71 | |
72 | */
73 |
74 | colors: colors,
75 |
76 |
77 | /*
78 | |-----------------------------------------------------------------------------
79 | | Screens https://tailwindcss.com/docs/responsive-design
80 | |-----------------------------------------------------------------------------
81 | |
82 | | Screens in Tailwind are translated to CSS media queries. They define the
83 | | responsive breakpoints for your project. By default Tailwind takes a
84 | | "mobile first" approach, where each screen size represents a minimum
85 | | viewport width. Feel free to have as few or as many screens as you
86 | | want, naming them in whatever way you'd prefer for your project.
87 | |
88 | | Tailwind also allows for more complex screen definitions, which can be
89 | | useful in certain situations. Be sure to see the full responsive
90 | | documentation for a complete list of options.
91 | |
92 | | Class name: .{screen}:{utility}
93 | |
94 | */
95 |
96 | screens: {
97 | 'xs': '576px',
98 | 'sm': '680px',
99 | 'md': '768px',
100 | 'lg': '992px',
101 | 'xl': '1200px',
102 | },
103 |
104 |
105 | /*
106 | |-----------------------------------------------------------------------------
107 | | Fonts https://tailwindcss.com/docs/fonts
108 | |-----------------------------------------------------------------------------
109 | |
110 | | Here is where you define your project's font stack, or font families.
111 | | Keep in mind that Tailwind doesn't actually load any fonts for you.
112 | | If you're using custom fonts you'll need to import them prior to
113 | | defining them here.
114 | |
115 | | By default we provide a native font stack that works remarkably well on
116 | | any device or OS you're using, since it just uses the default fonts
117 | | provided by the platform.
118 | |
119 | | Class name: .font-{name}
120 | |
121 | */
122 |
123 | fonts: {
124 | 'code': [
125 | 'IBM Plex Mono',
126 | 'Menlo',
127 | 'Monaco',
128 | 'Consolas',
129 | 'Liberation Mono',
130 | 'Courier New',
131 | 'monospace',
132 | ]
133 | },
134 |
135 |
136 | /*
137 | |-----------------------------------------------------------------------------
138 | | Text sizes https://tailwindcss.com/docs/text-sizing
139 | |-----------------------------------------------------------------------------
140 | |
141 | | Here is where you define your text sizes. Name these in whatever way
142 | | makes the most sense to you. We use size names by default, but
143 | | you're welcome to use a numeric scale or even something else
144 | | entirely.
145 | |
146 | | By default Tailwind uses the "rem" unit type for most measurements.
147 | | This allows you to set a root font size which all other sizes are
148 | | then based on. That said, you are free to use whatever units you
149 | | prefer, be it rems, ems, pixels or other.
150 | |
151 | | Class name: .text-{size}
152 | |
153 | */
154 |
155 | textSizes: {
156 | '3xs': '.5625rem', // 9px
157 | '2xs': '.625rem', // 10px
158 | 'xs': '.75rem', // 12px
159 | 'sm': '.875rem', // 14px
160 | 'base': '1rem', // 16px
161 | 'lg': '1.125rem', // 18px
162 | 'xl': '1.25rem', // 20px
163 | '2xl': '1.5rem', // 24px
164 | '3xl': '1.875rem', // 30px
165 | '4xl': '2.25rem', // 36px
166 | '5xl': '3rem', // 48px
167 | },
168 |
169 |
170 | /*
171 | |-----------------------------------------------------------------------------
172 | | Font weights https://tailwindcss.com/docs/font-weight
173 | |-----------------------------------------------------------------------------
174 | |
175 | | Here is where you define your font weights. We've provided a list of
176 | | common font weight names with their respective numeric scale values
177 | | to get you started. It's unlikely that your project will require
178 | | all of these, so we recommend removing those you don't need.
179 | |
180 | | Class name: .font-{weight}
181 | |
182 | */
183 |
184 | fontWeights: {
185 | 'normal': 400,
186 | 'bold': 600,
187 |
188 | },
189 |
190 |
191 | /*
192 | |-----------------------------------------------------------------------------
193 | | Leading (line height) https://tailwindcss.com/docs/line-height
194 | |-----------------------------------------------------------------------------
195 | |
196 | | Here is where you define your line height values, or as we call
197 | | them in Tailwind, leadings.
198 | |
199 | | Class name: .leading-{size}
200 | |
201 | */
202 |
203 | leading: {
204 | 'none': 1,
205 | 'tight': 1.25,
206 | 'normal': 1.5,
207 | 'loose': 2,
208 | },
209 |
210 |
211 | /*
212 | |-----------------------------------------------------------------------------
213 | | Tracking (letter spacing) https://tailwindcss.com/docs/letter-spacing
214 | |-----------------------------------------------------------------------------
215 | |
216 | | Here is where you define your letter spacing values, or as we call
217 | | them in Tailwind, tracking.
218 | |
219 | | Class name: .tracking-{size}
220 | |
221 | */
222 |
223 | tracking: {
224 | 'tight': '-0.05em',
225 | 'normal': '0',
226 | 'wide': '0.05em',
227 | },
228 |
229 |
230 | /*
231 | |-----------------------------------------------------------------------------
232 | | Text colors https://tailwindcss.com/docs/text-color
233 | |-----------------------------------------------------------------------------
234 | |
235 | | Here is where you define your text colors. By default these use the
236 | | color palette we defined above, however you're welcome to set these
237 | | independently if that makes sense for your project.
238 | |
239 | | Class name: .text-{color}
240 | |
241 | */
242 |
243 | textColors: colors,
244 |
245 |
246 | /*
247 | |-----------------------------------------------------------------------------
248 | | Background colors https://tailwindcss.com/docs/background-color
249 | |-----------------------------------------------------------------------------
250 | |
251 | | Here is where you define your background colors. By default these use
252 | | the color palette we defined above, however you're welcome to set
253 | | these independently if that makes sense for your project.
254 | |
255 | | Class name: .bg-{color}
256 | |
257 | */
258 |
259 | backgroundColors: colors,
260 |
261 |
262 | /*
263 | |-----------------------------------------------------------------------------
264 | | Border widths https://tailwindcss.com/docs/border-width
265 | |-----------------------------------------------------------------------------
266 | |
267 | | Here is where you define your border widths. Take note that border
268 | | widths require a special "default" value set as well. This is the
269 | | width that will be used when you do not specify a border width.
270 | |
271 | | Class name: .border{-side?}{-width?}
272 | |
273 | */
274 |
275 | borderWidths: {
276 | default: '1px',
277 | '0': '0',
278 | '2': '2px',
279 | '4': '4px',
280 | '8': '8px',
281 | },
282 |
283 |
284 | /*
285 | |-----------------------------------------------------------------------------
286 | | Border colors https://tailwindcss.com/docs/border-color
287 | |-----------------------------------------------------------------------------
288 | |
289 | | Here is where you define your border colors. By default these use the
290 | | color palette we defined above, however you're welcome to set these
291 | | independently if that makes sense for your project.
292 | |
293 | | Take note that border colors require a special "default" value set
294 | | as well. This is the color that will be used when you do not
295 | | specify a border color.
296 | |
297 | | Class name: .border-{color}
298 | |
299 | */
300 |
301 | borderColors: Object.assign({ default: colors['grey-light'] }, colors),
302 |
303 |
304 | /*
305 | |-----------------------------------------------------------------------------
306 | | Border radius https://tailwindcss.com/docs/border-radius
307 | |-----------------------------------------------------------------------------
308 | |
309 | | Here is where you define your border radius values. If a `default` radius
310 | | is provided, it will be made available as the non-suffixed `.rounded`
311 | | utility.
312 | |
313 | | If your scale includes a `0` value to reset already rounded corners, it's
314 | | a good idea to put it first so other values are able to override it.
315 | |
316 | | Class name: .rounded{-side?}{-size?}
317 | |
318 | */
319 |
320 | borderRadius: {
321 | 'none': '0',
322 | 'sm': '.125rem',
323 | default: '.25rem',
324 | 'lg': '.5rem',
325 | 'full': '9999px',
326 | },
327 |
328 |
329 | /*
330 | |-----------------------------------------------------------------------------
331 | | Width https://tailwindcss.com/docs/width
332 | |-----------------------------------------------------------------------------
333 | |
334 | | Here is where you define your width utility sizes. These can be
335 | | percentage based, pixels, rems, or any other units. By default
336 | | we provide a sensible rem based numeric scale, a percentage
337 | | based fraction scale, plus some other common use-cases. You
338 | | can, of course, modify these values as needed.
339 | |
340 | |
341 | | It's also worth mentioning that Tailwind automatically escapes
342 | | invalid CSS class name characters, which allows you to have
343 | | awesome classes like .w-2/3.
344 | |
345 | | Class name: .w-{size}
346 | |
347 | */
348 |
349 | width: {
350 | 'auto': 'auto',
351 | 'px': '1px',
352 | '1': '0.25rem',
353 | '2': '0.5rem',
354 | '3': '0.75rem',
355 | '4': '1rem',
356 | '6': '1.5rem',
357 | '8': '2rem',
358 | '10': '2.5rem',
359 | '12': '3rem',
360 | '14': '3.5rem',
361 | '16': '4rem',
362 | '18': '4.5rem',
363 | '20': '5rem',
364 | '22': '5.5rem',
365 | '24': '6rem',
366 | '26': '6.5rem',
367 | '28': '7rem',
368 | '30': '7.5rem',
369 | '32': '8rem',
370 | '36': '9rem',
371 | '40': '10rem',
372 | '48': '12rem',
373 | '64': '16rem',
374 | '1/2': '50%',
375 | '1/3': '33.33333%',
376 | '2/3': '66.66667%',
377 | '1/4': '25%',
378 | '3/4': '75%',
379 | '1/5': '20%',
380 | '2/5': '40%',
381 | '3/5': '60%',
382 | '4/5': '80%',
383 | 'full': '100%',
384 | 'screen': '100vw',
385 | 'grid': '92%'
386 | },
387 |
388 |
389 | /*
390 | |-----------------------------------------------------------------------------
391 | | Height https://tailwindcss.com/docs/height
392 | |-----------------------------------------------------------------------------
393 | |
394 | | Here is where you define your height utility sizes. These can be
395 | | percentage based, pixels, rems, or any other units. By default
396 | | we provide a sensible rem based numeric scale plus some other
397 | | common use-cases. You can, of course, modify these values as
398 | | needed.
399 | |
400 | | Class name: .h-{size}
401 | |
402 | */
403 |
404 | height: {
405 | 'auto': 'auto',
406 | 'px': '1px',
407 | '1': '0.25rem',
408 | '2': '0.5rem',
409 | '3': '0.75rem',
410 | '4': '1rem',
411 | '6': '1.5rem',
412 | '8': '2rem',
413 | '10': '2.5rem',
414 | '12': '3rem',
415 | '14': '3.5rem',
416 | '16': '4rem',
417 | '18': '4.5rem',
418 | '20': '5rem',
419 | '22': '5.5rem',
420 | '24': '6rem',
421 | '26': '6.5rem',
422 | '28': '7rem',
423 | '30': '7.5rem',
424 | '32': '8rem',
425 | '36': '9rem',
426 | '40': '10rem',
427 | '48': '12rem',
428 | '64': '16rem',
429 | '1/2': '50%',
430 | 'full': '100%',
431 | 'screen': '100vh'
432 | },
433 |
434 |
435 | /*
436 | |-----------------------------------------------------------------------------
437 | | Minimum width https://tailwindcss.com/docs/min-width
438 | |-----------------------------------------------------------------------------
439 | |
440 | | Here is where you define your minimum width utility sizes. These can
441 | | be percentage based, pixels, rems, or any other units. We provide a
442 | | couple common use-cases by default. You can, of course, modify
443 | | these values as needed.
444 | |
445 | | Class name: .min-w-{size}
446 | |
447 | */
448 |
449 | minWidth: {
450 | '0': '0',
451 | 'full': '100%',
452 | },
453 |
454 |
455 | /*
456 | |-----------------------------------------------------------------------------
457 | | Minimum height https://tailwindcss.com/docs/min-height
458 | |-----------------------------------------------------------------------------
459 | |
460 | | Here is where you define your minimum height utility sizes. These can
461 | | be percentage based, pixels, rems, or any other units. We provide a
462 | | few common use-cases by default. You can, of course, modify these
463 | | values as needed.
464 | |
465 | | Class name: .min-h-{size}
466 | |
467 | */
468 |
469 | minHeight: {
470 | '0': '0',
471 | 'full': '100%',
472 | 'screen': '100vh'
473 | },
474 |
475 |
476 | /*
477 | |-----------------------------------------------------------------------------
478 | | Maximum width https://tailwindcss.com/docs/max-width
479 | |-----------------------------------------------------------------------------
480 | |
481 | | Here is where you define your maximum width utility sizes. These can
482 | | be percentage based, pixels, rems, or any other units. By default
483 | | we provide a sensible rem based scale and a "full width" size,
484 | | which is basically a reset utility. You can, of course,
485 | | modify these values as needed.
486 | |
487 | | Class name: .max-w-{size}
488 | |
489 | */
490 |
491 | maxWidth: {
492 | 'xs': '20rem',
493 | 'sm': '30rem',
494 | 'md': '40rem',
495 | 'lg': '50rem',
496 | 'xl': '60rem',
497 | '2xl': '70rem',
498 | '3xl': '80rem',
499 | '4xl': '90rem',
500 | '5xl': '100rem',
501 | 'full': '100%',
502 | 'screen': '100vw',
503 | },
504 |
505 |
506 | /*
507 | |-----------------------------------------------------------------------------
508 | | Maximum height https://tailwindcss.com/docs/max-height
509 | |-----------------------------------------------------------------------------
510 | |
511 | | Here is where you define your maximum height utility sizes. These can
512 | | be percentage based, pixels, rems, or any other units. We provide a
513 | | couple common use-cases by default. You can, of course, modify
514 | | these values as needed.
515 | |
516 | | Class name: .max-h-{size}
517 | |
518 | */
519 |
520 | maxHeight: {
521 | 'full': '100%',
522 | 'screen': '100vh',
523 | },
524 |
525 |
526 | /*
527 | |-----------------------------------------------------------------------------
528 | | Padding https://tailwindcss.com/docs/padding
529 | |-----------------------------------------------------------------------------
530 | |
531 | | Here is where you define your padding utility sizes. These can be
532 | | percentage based, pixels, rems, or any other units. By default we
533 | | provide a sensible rem based numeric scale plus a couple other
534 | | common use-cases like "1px". You can, of course, modify these
535 | | values as needed.
536 | |
537 | | Class name: .p{side?}-{size}
538 | |
539 | */
540 |
541 | padding: {
542 | 'px': '1px',
543 | '0': '0',
544 | '1': '0.25rem',
545 | '2': '0.5rem',
546 | '3': '0.75rem',
547 | '4': '1rem',
548 | '6': '1.5rem',
549 | '8': '2rem',
550 | '10': '2.5rem',
551 | '12': '3rem',
552 | '14': '3.5rem',
553 | '16': '4rem',
554 | '20': '5rem',
555 | '24': '6rem',
556 | '28': '7rem',
557 | '32': '8rem',
558 | },
559 |
560 |
561 | /*
562 | |-----------------------------------------------------------------------------
563 | | Margin https://tailwindcss.com/docs/margin
564 | |-----------------------------------------------------------------------------
565 | |
566 | | Here is where you define your margin utility sizes. These can be
567 | | percentage based, pixels, rems, or any other units. By default we
568 | | provide a sensible rem based numeric scale plus a couple other
569 | | common use-cases like "1px". You can, of course, modify these
570 | | values as needed.
571 | |
572 | | Class name: .m{side?}-{size}
573 | |
574 | */
575 |
576 | margin: {
577 | 'auto': 'auto',
578 | 'px': '1px',
579 | '0': '0',
580 | '1': '0.25rem',
581 | '2': '0.5rem',
582 | '3': '0.75rem',
583 | '4': '1rem',
584 | '6': '1.5rem',
585 | '8': '2rem',
586 | '10': '2.5rem',
587 | '12': '3rem',
588 | '14': '3.5rem',
589 | '16': '4rem',
590 | '20': '5rem',
591 | '24': '6rem',
592 | '28': '7rem',
593 | '32': '8rem',
594 | },
595 |
596 |
597 | /*
598 | |-----------------------------------------------------------------------------
599 | | Negative margin https://tailwindcss.com/docs/negative-margin
600 | |-----------------------------------------------------------------------------
601 | |
602 | | Here is where you define your negative margin utility sizes. These can
603 | | be percentage based, pixels, rems, or any other units. By default we
604 | | provide matching values to the padding scale since these utilities
605 | | generally get used together. You can, of course, modify these
606 | | values as needed.
607 | |
608 | | Class name: .-m{side?}-{size}
609 | |
610 | */
611 |
612 | negativeMargin: {
613 | 'px': '1px',
614 | '0': '0',
615 | '1': '0.25rem',
616 | '2': '0.5rem',
617 | '3': '0.75rem',
618 | '4': '1rem',
619 | '6': '1.5rem',
620 | '8': '2rem',
621 | '10': '2.5rem',
622 | '12': '3rem',
623 | '14': '3.5rem',
624 | '16': '4rem',
625 | '20': '5rem',
626 | '24': '6rem',
627 | '28': '7rem',
628 | '32': '8rem',
629 | },
630 |
631 |
632 | /*
633 | |-----------------------------------------------------------------------------
634 | | Shadows https://tailwindcss.com/docs/shadows
635 | |-----------------------------------------------------------------------------
636 | |
637 | | Here is where you define your shadow utilities. As you can see from
638 | | the defaults we provide, it's possible to apply multiple shadows
639 | | per utility using comma separation.
640 | |
641 | | If a `default` shadow is provided, it will be made available as the non-
642 | | suffixed `.shadow` utility.
643 | |
644 | | Class name: .shadow-{size?}
645 | |
646 | */
647 |
648 | shadows: {
649 | default: '0 2px 4px 0 rgba(0,0,0,0.10)',
650 | 'md': '0 4px 8px 0 rgba(0,0,0,0.12), 0 2px 4px 0 rgba(0,0,0,0.08)',
651 | 'lg': '0 15px 30px 0 rgba(0,0,0,0.11), 0 5px 15px 0 rgba(0,0,0,0.08)',
652 | 'inner': 'inset 0 2px 4px 0 rgba(0,0,0,0.06)',
653 | 'none': 'none',
654 | },
655 |
656 |
657 | /*
658 | |-----------------------------------------------------------------------------
659 | | Z-index https://tailwindcss.com/docs/z-index
660 | |-----------------------------------------------------------------------------
661 | |
662 | | Here is where you define your z-index utility values. By default we
663 | | provide a sensible numeric scale. You can, of course, modify these
664 | | values as needed.
665 | |
666 | | Class name: .z-{index}
667 | |
668 | */
669 |
670 | zIndex: {
671 | 'auto': 'auto',
672 | '0': 0,
673 | '10': 10,
674 | '20': 20,
675 | '30': 30,
676 | '40': 40,
677 | '50': 50,
678 | },
679 |
680 |
681 | /*
682 | |-----------------------------------------------------------------------------
683 | | Opacity https://tailwindcss.com/docs/opacity
684 | |-----------------------------------------------------------------------------
685 | |
686 | | Here is where you define your opacity utility values. By default we
687 | | provide a sensible numeric scale. You can, of course, modify these
688 | | values as needed.
689 | |
690 | | Class name: .opacity-{name}
691 | |
692 | */
693 |
694 | opacity: {
695 | '0': '0',
696 | '25': '.25',
697 | '50': '.5',
698 | '75': '.75',
699 | '100': '1',
700 | },
701 |
702 |
703 | /*
704 | |-----------------------------------------------------------------------------
705 | | SVG fill https://tailwindcss.com/docs/svg
706 | |-----------------------------------------------------------------------------
707 | |
708 | | Here is where you define your SVG fill colors. By default we just provide
709 | | `fill-current` which sets the fill to the current text color. This lets you
710 | | specify a fill color using existing text color utilities and helps keep the
711 | | generated CSS file size down.
712 | |
713 | | Class name: .fill-{name}
714 | |
715 | */
716 |
717 | svgFill: {
718 | 'current': 'currentColor',
719 | 'logo': colors['logo'],
720 | },
721 |
722 |
723 | /*
724 | |-----------------------------------------------------------------------------
725 | | SVG stroke https://tailwindcss.com/docs/svg
726 | |-----------------------------------------------------------------------------
727 | |
728 | | Here is where you define your SVG stroke colors. By default we just provide
729 | | `stroke-current` which sets the stroke to the current text color. This lets
730 | | you specify a stroke color using existing text color utilities and helps
731 | | keep the generated CSS file size down.
732 | |
733 | | Class name: .stroke-{name}
734 | |
735 | */
736 |
737 | svgStroke: {
738 | 'current': 'currentColor',
739 | },
740 |
741 |
742 | /*
743 | |-----------------------------------------------------------------------------
744 | | Modules https://tailwindcss.com/docs/configuration#modules
745 | |-----------------------------------------------------------------------------
746 | |
747 | | Here is where you control which modules are generated and what variants are
748 | | generated for each of those modules.
749 | |
750 | | Currently supported variants: 'responsive', 'hover', 'focus'
751 | |
752 | | To disable a module completely, use `false` instead of an array.
753 | |
754 | */
755 |
756 | modules: {
757 | appearance: ['responsive'],
758 | backgroundAttachment: ['responsive'],
759 | backgroundColors: ['responsive', 'hover'],
760 | backgroundPosition: ['responsive'],
761 | backgroundRepeat: ['responsive'],
762 | backgroundSize: ['responsive'],
763 | borderColors: ['responsive', 'hover'],
764 | borderRadius: ['responsive'],
765 | borderStyle: ['responsive'],
766 | borderWidths: ['responsive'],
767 | cursor: ['responsive'],
768 | display: ['responsive'],
769 | flexbox: ['responsive'],
770 | float: ['responsive'],
771 | fonts: ['responsive'],
772 | fontWeights: ['responsive', 'hover'],
773 | height: ['responsive'],
774 | leading: ['responsive'],
775 | lists: ['responsive'],
776 | margin: ['responsive'],
777 | maxHeight: ['responsive'],
778 | maxWidth: ['responsive'],
779 | minHeight: ['responsive'],
780 | minWidth: ['responsive'],
781 | negativeMargin: ['responsive'],
782 | opacity: ['responsive'],
783 | overflow: ['responsive'],
784 | padding: ['responsive'],
785 | pointerEvents: ['responsive'],
786 | position: ['responsive'],
787 | resize: ['responsive'],
788 | shadows: ['responsive'],
789 | svgFill: [],
790 | svgStroke: [],
791 | textAlign: ['responsive'],
792 | textColors: ['responsive', 'hover'],
793 | textSizes: ['responsive'],
794 | textStyle: ['responsive', 'hover'],
795 | tracking: ['responsive'],
796 | userSelect: ['responsive'],
797 | verticalAlign: ['responsive'],
798 | visibility: ['responsive'],
799 | whitespace: ['responsive'],
800 | width: ['responsive'],
801 | zIndex: ['responsive'],
802 | },
803 |
804 |
805 | /*
806 | |-----------------------------------------------------------------------------
807 | | Advanced Options https://tailwindcss.com/docs/configuration#options
808 | |-----------------------------------------------------------------------------
809 | |
810 | | Here is where you can tweak advanced configuration options. We recommend
811 | | leaving these options alone unless you absolutely need to change them.
812 | |
813 | */
814 |
815 | options: {
816 | prefix: '',
817 | important: false,
818 | separator: ':',
819 | },
820 |
821 | };
822 |
--------------------------------------------------------------------------------