mirror of
https://github.com/vitodeploy/vito.git
synced 2025-04-17 17:01:37 +00:00
Add ace editor (#269)
This commit is contained in:
parent
a67e586a5d
commit
8c487a64fa
47
app/View/Components/Editor.php
Normal file
47
app/View/Components/Editor.php
Normal file
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace App\View\Components;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Contracts\View\View;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\View\Component;
|
||||
|
||||
class Editor extends Component
|
||||
{
|
||||
public string $id;
|
||||
|
||||
public string $name;
|
||||
|
||||
public ?string $value;
|
||||
|
||||
public array $options;
|
||||
|
||||
public function __construct(
|
||||
string $name,
|
||||
?string $value,
|
||||
public string $lang,
|
||||
public bool $readonly = false,
|
||||
public bool $lineNumbers = true,
|
||||
) {
|
||||
$this->id = $name.'-'.Str::random(8);
|
||||
$this->name = $name;
|
||||
$this->value = json_encode($value ?? '');
|
||||
$this->options = $this->getOptions();
|
||||
}
|
||||
|
||||
private function getOptions(): array
|
||||
{
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'name' => $this->name,
|
||||
'lang' => $this->lang,
|
||||
'value' => $this->value,
|
||||
];
|
||||
}
|
||||
|
||||
public function render(): View|Closure|string
|
||||
{
|
||||
return view('components.editor');
|
||||
}
|
||||
}
|
8
package-lock.json
generated
8
package-lock.json
generated
@ -4,13 +4,13 @@
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "vito",
|
||||
"devDependencies": {
|
||||
"@tailwindcss/forms": "^0.5.2",
|
||||
"@tailwindcss/typography": "^0.5.9",
|
||||
"alpinejs": "^3.4.2",
|
||||
"apexcharts": "^3.44.2",
|
||||
"autoprefixer": "^10.4.2",
|
||||
"brace": "^0.11.1",
|
||||
"flowbite": "^2.3.0",
|
||||
"flowbite-datepicker": "^1.2.6",
|
||||
"htmx.org": "^1.9.10",
|
||||
@ -685,6 +685,12 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/brace": {
|
||||
"version": "0.11.1",
|
||||
"resolved": "https://registry.npmjs.org/brace/-/brace-0.11.1.tgz",
|
||||
"integrity": "sha512-Fc8Ne62jJlKHiG/ajlonC4Sd66Pq68fFwK4ihJGNZpGqboc324SQk+lRvMzpPRuJOmfrJefdG8/7JdWX4bzJ2Q==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||
|
@ -10,8 +10,11 @@
|
||||
"@tailwindcss/forms": "^0.5.2",
|
||||
"@tailwindcss/typography": "^0.5.9",
|
||||
"alpinejs": "^3.4.2",
|
||||
"apexcharts": "^3.44.2",
|
||||
"autoprefixer": "^10.4.2",
|
||||
"brace": "^0.11.1",
|
||||
"flowbite": "^2.3.0",
|
||||
"flowbite-datepicker": "^1.2.6",
|
||||
"htmx.org": "^1.9.10",
|
||||
"laravel-echo": "^1.15.0",
|
||||
"laravel-vite-plugin": "^0.7.2",
|
||||
@ -21,8 +24,6 @@
|
||||
"prettier-plugin-tailwindcss": "^0.5.11",
|
||||
"tailwindcss": "^3.1.0",
|
||||
"tippy.js": "^6.3.7",
|
||||
"vite": "^4.5.3",
|
||||
"apexcharts": "^3.44.2",
|
||||
"flowbite-datepicker": "^1.2.6"
|
||||
"vite": "^4.5.3"
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
807
public/build/assets/app-d9a3bf01.js
Normal file
807
public/build/assets/app-d9a3bf01.js
Normal file
File diff suppressed because one or more lines are too long
1
public/build/assets/app-db36ac12.css
Normal file
1
public/build/assets/app-db36ac12.css
Normal file
File diff suppressed because one or more lines are too long
@ -1,6 +1,6 @@
|
||||
{
|
||||
"resources/css/app.css": {
|
||||
"file": "assets/app-7f487305.css",
|
||||
"file": "assets/app-db36ac12.css",
|
||||
"isEntry": true,
|
||||
"src": "resources/css/app.css"
|
||||
},
|
||||
@ -12,7 +12,7 @@
|
||||
"css": [
|
||||
"assets/app-a1ae07b3.css"
|
||||
],
|
||||
"file": "assets/app-01264060.js",
|
||||
"file": "assets/app-d9a3bf01.js",
|
||||
"isEntry": true,
|
||||
"src": "resources/js/app.js"
|
||||
}
|
||||
|
40
resources/js/ace-editor/ace-editor.js
Normal file
40
resources/js/ace-editor/ace-editor.js
Normal file
@ -0,0 +1,40 @@
|
||||
import ace from 'brace';
|
||||
import 'brace/mode/javascript';
|
||||
import 'brace/mode/plain_text';
|
||||
import 'brace/mode/sh';
|
||||
import 'brace/mode/ini';
|
||||
import 'brace/ext/searchbox'
|
||||
import './theme-vito'
|
||||
import './mode-env';
|
||||
import './mode-nginx';
|
||||
|
||||
window.initAceEditor = function (options = {}) {
|
||||
const editorValue = JSON.parse(options.value || '');
|
||||
const editor = ace.edit(options.id);
|
||||
editor.setTheme("ace/theme/vito");
|
||||
editor.getSession().setMode(`ace/mode/${options.lang || 'plain_text'}`);
|
||||
editor.setValue(editorValue, -1);
|
||||
editor.clearSelection();
|
||||
editor.focus();
|
||||
editor.setOptions({
|
||||
enableBasicAutocompletion: true,
|
||||
enableSnippets: true,
|
||||
enableLiveAutocompletion: true,
|
||||
printMargin: false,
|
||||
});
|
||||
|
||||
editor.renderer.setScrollMargin(15, 15, 0, 0)
|
||||
editor.renderer.setPadding(15);
|
||||
|
||||
editor.getSession().on('change', function () {
|
||||
document.getElementById(`textarea-${options.id}`).value = editor.getValue();
|
||||
});
|
||||
|
||||
window.addEventListener('resize', function () {
|
||||
editor.resize();
|
||||
})
|
||||
|
||||
document.getElementById(`textarea-${options.id}`).innerHTML = editorValue;
|
||||
|
||||
return editor;
|
||||
}
|
136
resources/js/ace-editor/mode-env.js
Normal file
136
resources/js/ace-editor/mode-env.js
Normal file
@ -0,0 +1,136 @@
|
||||
ace.define("ace/mode/env", ["require", "exports", "module", "ace/lib/oop", "ace/mode/text", "ace/mode/env_highlight_rules", "ace/mode/folding/ini","ace/mode/behaviour"], function (require, exports) {
|
||||
var oop = require("../lib/oop");
|
||||
var TextMode = require("./text").Mode;
|
||||
var Behaviour = require("./behaviour").Behaviour;
|
||||
var envHighlightRules = require("./env_highlight_rules").envHighlightRules;
|
||||
|
||||
var Mode = function () {
|
||||
this.HighlightRules = envHighlightRules;
|
||||
this.$behaviour = new Behaviour
|
||||
};
|
||||
|
||||
oop.inherits(Mode, TextMode);
|
||||
|
||||
(function() {
|
||||
this.lineCommentStart = "#",
|
||||
this.blockComment = null,
|
||||
this.$id = "ace/mode/env"
|
||||
}).call(Mode.prototype),
|
||||
|
||||
exports.Mode = Mode;
|
||||
})
|
||||
ace.define("ace/mode/env_highlight_rules", ["require", "exports", "module", "ace/lib/oop", "ace/mode/text_highlight_rules"], function (require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
var oop = require("../lib/oop");
|
||||
var TextHighlightRules =
|
||||
require("./text_highlight_rules").TextHighlightRules;
|
||||
|
||||
var envHighlightRules = function () {
|
||||
this.$rules = {
|
||||
start: [
|
||||
{
|
||||
token: "punctuation.definition.comment.env",
|
||||
regex: "#.*",
|
||||
push_: [
|
||||
{
|
||||
token: "comment.line.number-sign.env",
|
||||
regex: "$|^",
|
||||
next: "pop",
|
||||
},
|
||||
{
|
||||
defaultToken: "comment.line.number-sign.env",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
token: "punctuation.definition.comment.env",
|
||||
regex: "#.*",
|
||||
push_: [
|
||||
{
|
||||
token: "comment.line.semicolon.env",
|
||||
regex: "$|^",
|
||||
next: "pop",
|
||||
},
|
||||
{
|
||||
defaultToken: "comment.line.semicolon.env",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
token: [
|
||||
"keyword.other.definition.env",
|
||||
"text",
|
||||
"punctuation.separator.key-value.env",
|
||||
],
|
||||
regex: "\\b([a-zA-Z0-9_.-]+)\\b(\\s*)(=)",
|
||||
},
|
||||
{
|
||||
token: [
|
||||
"punctuation.definition.entity.env",
|
||||
"constant.section.group-title.env",
|
||||
"punctuation.definition.entity.env",
|
||||
],
|
||||
regex: "^(\\[)(.*?)(\\])",
|
||||
},
|
||||
{
|
||||
token: "punctuation.definition.string.begin.env",
|
||||
regex: "'",
|
||||
push: [
|
||||
{
|
||||
token: "punctuation.definition.string.end.env",
|
||||
regex: "'",
|
||||
next: "pop",
|
||||
},
|
||||
{
|
||||
token: "constant.language.escape",
|
||||
regex: "\\\\(?:[\\\\0abtrn;#=:]|x[a-fA-F\\d]{4})",
|
||||
},
|
||||
{
|
||||
defaultToken: "string.quoted.single.env",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
token: "punctuation.definition.string.begin.env",
|
||||
regex: '"',
|
||||
push: [
|
||||
{
|
||||
token: "constant.language.escape",
|
||||
regex: "\\\\(?:[\\\\0abtrn;#=:]|x[a-fA-F\\d]{4})",
|
||||
},
|
||||
{
|
||||
token: "support.constant.color",
|
||||
regex: /\${[\w]+}/,
|
||||
},
|
||||
{
|
||||
token: "punctuation.definition.string.end.env",
|
||||
regex: '"',
|
||||
next: "pop",
|
||||
},
|
||||
{
|
||||
defaultToken: "string.quoted.double.env",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
token: "constant.language.boolean",
|
||||
regex: /(?:true|false)\b/,
|
||||
},
|
||||
],
|
||||
};
|
||||
this.normalizeRules();
|
||||
};
|
||||
|
||||
envHighlightRules.metaData = {
|
||||
fileTypes: ["env"],
|
||||
keyEquivalent: "^~I",
|
||||
name: "Env",
|
||||
scopeName: "source.env",
|
||||
};
|
||||
|
||||
oop.inherits(envHighlightRules, TextHighlightRules);
|
||||
|
||||
exports.envHighlightRules = envHighlightRules;
|
||||
});
|
||||
|
143
resources/js/ace-editor/mode-nginx.js
Normal file
143
resources/js/ace-editor/mode-nginx.js
Normal file
File diff suppressed because one or more lines are too long
47
resources/js/ace-editor/theme-vito.js
Normal file
47
resources/js/ace-editor/theme-vito.js
Normal file
@ -0,0 +1,47 @@
|
||||
ace.define(
|
||||
"ace/theme/vito",
|
||||
["require", "exports", "module", "ace/lib/dom"],
|
||||
function (require, exports) {
|
||||
(exports.isDark = true),
|
||||
(exports.cssClass = "ace-vito rounded-lg w-full"),
|
||||
(exports.cssText = `
|
||||
.ace-vito .ace_scrollbar::-webkit-scrollbar { width: 12px;}
|
||||
.ace-vito .ace_scrollbar::-webkit-scrollbar-track { background: #111827;}
|
||||
.ace-vito .ace_scrollbar::-webkit-scrollbar-thumb { background: #374151; border-radius: 4px;}
|
||||
.ace-vito .ace_gutter {background: #151c27;color: rgb(128,145,160)}
|
||||
.ace-vito .ace_print-margin {width: 1px;background: #555555}
|
||||
.ace-vito {background-color: #0f172a;color: #F9FAFB}
|
||||
.ace-vito .ace_cursor {color: #F9FAFB}
|
||||
.ace-vito .ace_marker-layer .ace_selection {background: rgba(179, 101, 57, 0.75)}
|
||||
.ace-vito.ace_multiselect .ace_selection.ace_start {box-shadow: 0 0 3px 0px #002240;}
|
||||
.ace-vito .ace_marker-layer .ace_step {background: rgb(127, 111, 19)}
|
||||
.ace-vito .ace_marker-layer .ace_bracket {margin: -1px 0 0 -1px;border: 1px solid rgba(255, 255, 255, 0.15)}
|
||||
.ace-vito .ace_marker-layer .ace_active-line {background: rgba(24, 182, 155, 0.10)}
|
||||
.ace-vito .ace_gutter-active-line {background-color: rgba(0, 0, 0, 0.35)}
|
||||
.ace-vito .ace_marker-layer .ace_selected-word {border: 1px solid rgba(179, 101, 57, 0.75)}
|
||||
.ace-vito .ace_invisible {color: rgba(255, 255, 255, 0.15)}
|
||||
.ace-vito .ace_keyword,.ace-vito .ace_meta {color: #FF9D00}
|
||||
.ace-vito .ace_constant,.ace-vito .ace_constant.ace_character,.ace-vito .ace_constant.ace_character.ace_escape,.ace-vito .ace_constant.ace_other {color: #FF628C}
|
||||
.ace-vito .ace_invalid {color: #F8F8F8;background-color: #800F00}
|
||||
.ace-vito .ace_support {color: #80FFBB}
|
||||
.ace-vito .ace_support.ace_constant {color: #EB939A}
|
||||
.ace-vito .ace_fold {background-color: #FF9D00;border-color: #F9FAFB}
|
||||
.ace-vito .ace_support.ace_function {color: #FFB054}
|
||||
.ace-vito .ace_storage {color: #FFEE80}
|
||||
.ace-vito .ace_entity {color: #FFDD00}
|
||||
.ace-vito .ace_string {color: #7cd827}
|
||||
.ace-vito .ace_string.ace_regexp {color: #80FFC2}
|
||||
.ace-vito .ace_comment {font-style: italic;color: #6B7280}
|
||||
.ace-vito .ace_heading,.ace-vito
|
||||
.ace_markup.ace_heading {color: #C8E4FD;background-color: #001221}
|
||||
.ace-vito .ace_list,.ace-vito .ace_markup.ace_list {background-color: #130D26}
|
||||
.ace-vito .ace_variable {color: #CCCCCC}
|
||||
.ace-vito .ace_variable.ace_language {color: #FF80E1}
|
||||
.ace-vito .ace_meta.ace_tag {color: #9EFFFF}
|
||||
.ace-vito .ace_indent-guide {background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWNgYGBgYHCLSvkPAAP3AgSDTRd4AAAAAElFTkSuQmCC) right repeat-y}
|
||||
`);
|
||||
|
||||
var dom = require("../lib/dom");
|
||||
dom.importCssString(exports.cssText, exports.cssClass);
|
||||
},
|
||||
);
|
@ -1,5 +1,6 @@
|
||||
import 'flowbite';
|
||||
import 'flowbite/dist/datepicker.js';
|
||||
import './ace-editor/ace-editor';
|
||||
|
||||
import Alpine from 'alpinejs';
|
||||
window.Alpine = Alpine;
|
||||
|
@ -16,9 +16,8 @@ class="p-6"
|
||||
|
||||
<div class="mt-6">
|
||||
<x-input-label for="script" :value="__('Script')" />
|
||||
<x-textarea id="script" name="script" class="mt-1 min-h-[400px] w-full font-mono">
|
||||
{{ old("script", $site->deploymentScript?->content) }}
|
||||
</x-textarea>
|
||||
@php($value = old("script", $site->deploymentScript?->content))
|
||||
<x-editor id="script" name="script" lang="sh" :value="$value" />
|
||||
@error("script")
|
||||
<x-input-error class="mt-2" :messages="$message" />
|
||||
@enderror
|
||||
|
@ -21,9 +21,8 @@ class="mt-6"
|
||||
>
|
||||
<x-input-label for="env" :value="__('.env')" />
|
||||
<div id="env-content">
|
||||
<x-textarea id="env" name="env" rows="10" class="mt-1 block min-h-[400px] w-full font-mono">
|
||||
{{ old("env", session()->get("env") ?? "Loading...") }}
|
||||
</x-textarea>
|
||||
@php($envValue = old("env", session()->get("env") ?? "Loading..."))
|
||||
<x-editor id="env" name="env" lang="env" :value="$envValue" />
|
||||
</div>
|
||||
@error("env")
|
||||
<x-input-error class="mt-2" :messages="$message" />
|
||||
|
17
resources/views/components/editor.blade.php
Normal file
17
resources/views/components/editor.blade.php
Normal file
@ -0,0 +1,17 @@
|
||||
<div>
|
||||
<div
|
||||
id="{{ $id }}"
|
||||
{{ $attributes->merge(["class" => "mt-1 min-h-[400px] w-full"]) }}
|
||||
class="ace-vito ace_dark"
|
||||
></div>
|
||||
<textarea id="textarea-{{ $id }}" name="{{ $name }}" style="display: none"></textarea>
|
||||
<script>
|
||||
if (window.initAceEditor) {
|
||||
window.initAceEditor(@json($options));
|
||||
} else {
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
window.initAceEditor(@json($options));
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</div>
|
@ -40,7 +40,7 @@ class="cursor-pointer"
|
||||
@foreach ([\App\Enums\PHPIniType::FPM, \App\Enums\PHPIniType::CLI] as $type)
|
||||
<x-dropdown-link
|
||||
class="cursor-pointer"
|
||||
x-on:click="version = '{{ $php->version }}'; $dispatch('open-modal', 'update-php-ini-{{ $type }}'); document.getElementById('ini').value = 'Loading...';"
|
||||
x-on:click="version = '{{ $php->version }}'; $dispatch('open-modal', 'update-php-ini-{{ $type }}');"
|
||||
hx-get="{{ route('servers.php.get-ini', ['server' => $server, 'version' => $php->version, 'type' => $type]) }}"
|
||||
hx-swap="outerHTML"
|
||||
hx-target="#update-php-ini-{{ $type }}-form"
|
||||
|
@ -15,9 +15,8 @@ class="p-6"
|
||||
|
||||
<div class="mt-6">
|
||||
<x-input-label for="ini" value="php.ini" />
|
||||
<x-textarea id="ini" name="ini" class="mt-1 w-full font-mono" rows="15">
|
||||
{{ old("ini", session()->get("ini")) }}
|
||||
</x-textarea>
|
||||
@php($ini = old("ini", session()->get("ini") ?? "Loading..."))
|
||||
<x-editor id="ini" name="ini" lang="ini" :value="$ini" />
|
||||
@error("ini")
|
||||
<x-input-error class="mt-2" :messages="$message" />
|
||||
@enderror
|
||||
|
@ -1,7 +1,5 @@
|
||||
<x-input-label for="content" :value="__('Content')" />
|
||||
<x-textarea id="content" name="content" class="mt-1 min-h-[400px] w-full font-mono">
|
||||
{{ $value }}
|
||||
</x-textarea>
|
||||
<x-editor name="content" lang="sh" :value="$value" />
|
||||
@error("content")
|
||||
<x-input-error class="mt-2" :messages="$message" />
|
||||
@enderror
|
||||
|
@ -22,9 +22,8 @@ class="space-y-6"
|
||||
hx-swap="outerHTML"
|
||||
>
|
||||
<div id="vhost-container">
|
||||
<x-textarea id="vhost" name="vhost" rows="10" class="mt-1 block min-h-[400px] w-full font-mono">
|
||||
{{ session()->has("vhost") ? session()->get("vhost") : "Loading..." }}
|
||||
</x-textarea>
|
||||
@php($vhost = old("vhost", session()->get("vhost") ?? "Loading..."))
|
||||
<x-editor id="vhost" name="vhost" lang="nginx" :value="$vhost" />
|
||||
</div>
|
||||
@error("vhost")
|
||||
<x-input-error class="mt-2" :messages="$message" />
|
||||
|
Loading…
x
Reference in New Issue
Block a user