Replace CodeEditor with MonacoEditor (#2013)

Co-authored-by: Boy132 <mail@boy132.de>
This commit is contained in:
Charles 2025-12-19 18:31:55 -05:00 committed by GitHub
parent 5a47948a93
commit 2ab4c81e2a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 712 additions and 40 deletions

View File

@ -0,0 +1,141 @@
<?php
namespace App\Enums;
use Filament\Support\Contracts\HasLabel;
enum EditorLanguages: string implements HasLabel
{
case plaintext = 'plaintext';
case abap = 'abap';
case apex = 'apex';
case azcali = 'azcali';
case bat = 'bat';
case bicep = 'bicep';
case cameligo = 'cameligo';
case clojure = 'clojure';
case coffeescript = 'coffeescript';
case c = 'c';
case cpp = 'cpp';
case csharp = 'csharp';
case csp = 'csp';
case css = 'css';
case cypher = 'cypher';
case dart = 'dart';
case dockerfile = 'dockerfile';
case ecl = 'ecl';
case elixir = 'elixir';
case flow9 = 'flow9';
case fsharp = 'fsharp';
case go = 'go';
case graphql = 'graphql';
case handlebars = 'handlebars';
case hcl = 'hcl';
case html = 'html';
case ini = 'ini';
case java = 'java';
case javascript = 'javascript';
case julia = 'julia';
case json = 'json';
case kotlin = 'kotlin';
case less = 'less';
case lexon = 'lexon';
case lua = 'lua';
case liquid = 'liquid';
case m3 = 'm3';
case markdown = 'markdown';
case mdx = 'mdx';
case mips = 'mips';
case msdax = 'msdax';
case mysql = 'mysql';
case objectivec = 'objective-c';
case pascal = 'pascal';
case pascaligo = 'pascaligo';
case perl = 'perl';
case pgsql = 'pgsql';
case php = 'php';
case pla = 'pla';
case postiats = 'postiats';
case powerquery = 'powerquery';
case powershell = 'powershell';
case proto = 'proto';
case pug = 'pug';
case python = 'python';
case qsharp = 'qsharp';
case r = 'r';
case razor = 'razor';
case redis = 'redis';
case redshift = 'redshift';
case restructuredtext = 'restructuredtext';
case ruby = 'ruby';
case rust = 'rust';
case sb = 'sb';
case scala = 'scala';
case scheme = 'scheme';
case scss = 'scss';
case shell = 'shell';
case sol = 'sol';
case aes = 'aes';
case sparql = 'sparql';
case sql = 'sql';
case st = 'st';
case swift = 'swift';
case systemverilog = 'systemverilog';
case verilog = 'verilog';
case tcl = 'tcl';
case twig = 'twig';
case typescript = 'typescript';
case typespec = 'typespec';
case vb = 'vb';
case wgsl = 'wgsl';
case xml = 'xml';
case yaml = 'yaml';
public static function fromWithAlias(string $match): self
{
return match ($match) {
'h' => self::c,
'cc', 'hpp' => self::cpp,
'cs' => self::csharp,
'class' => self::java,
'htm' => self::html,
'js', 'mjs', 'cjs' => self::javascript,
'kt', 'kts' => self::kotlin,
'md' => self::markdown,
'm' => self::objectivec,
'pl', 'pm' => self::perl,
'php3', 'php4', 'php5', 'phtml' => self::php,
'py', 'pyc', 'pyo', 'pyi' => self::python,
'rdata', 'rds' => self::r,
'rb', 'erb' => self::ruby,
'sc' => self::scala,
'sh', 'zsh' => self::shell,
'ts', 'tsx' => self::typescript,
'yml' => self::yaml,
default => self::tryFrom($match) ?? self::plaintext,
};
}
public function getLabel(): string
{
return $this->name;
}
}

View File

@ -2,8 +2,10 @@
namespace App\Filament\Admin\Resources\Eggs\Pages; namespace App\Filament\Admin\Resources\Eggs\Pages;
use App\Enums\EditorLanguages;
use App\Filament\Admin\Resources\Eggs\EggResource; use App\Filament\Admin\Resources\Eggs\EggResource;
use App\Filament\Components\Forms\Fields\CopyFrom; use App\Filament\Components\Forms\Fields\CopyFrom;
use App\Filament\Components\Forms\Fields\MonacoEditor;
use App\Models\EggVariable; use App\Models\EggVariable;
use App\Traits\Filament\CanCustomizeHeaderActions; use App\Traits\Filament\CanCustomizeHeaderActions;
use App\Traits\Filament\CanCustomizeHeaderWidgets; use App\Traits\Filament\CanCustomizeHeaderWidgets;
@ -11,7 +13,6 @@ use Exception;
use Filament\Actions\Action; use Filament\Actions\Action;
use Filament\Actions\ActionGroup; use Filament\Actions\ActionGroup;
use Filament\Forms\Components\Checkbox; use Filament\Forms\Components\Checkbox;
use Filament\Forms\Components\CodeEditor;
use Filament\Forms\Components\Hidden; use Filament\Forms\Components\Hidden;
use Filament\Forms\Components\KeyValue; use Filament\Forms\Components\KeyValue;
use Filament\Forms\Components\Repeater; use Filament\Forms\Components\Repeater;
@ -268,8 +269,9 @@ class CreateEgg extends CreateRecord
'/bin/bash' => '/bin/bash', '/bin/bash' => '/bin/bash',
]) ])
->required(), ->required(),
CodeEditor::make('script_install') MonacoEditor::make('script_install')
->label(trans('admin/egg.script_install')) ->label(trans('admin/egg.script_install'))
->language(EditorLanguages::shell)
->columnSpanFull() ->columnSpanFull()
->lazy(), ->lazy(),
]), ]),

View File

@ -2,10 +2,12 @@
namespace App\Filament\Admin\Resources\Eggs\Pages; namespace App\Filament\Admin\Resources\Eggs\Pages;
use App\Enums\EditorLanguages;
use App\Filament\Admin\Resources\Eggs\EggResource; use App\Filament\Admin\Resources\Eggs\EggResource;
use App\Filament\Components\Actions\ExportEggAction; use App\Filament\Components\Actions\ExportEggAction;
use App\Filament\Components\Actions\ImportEggAction; use App\Filament\Components\Actions\ImportEggAction;
use App\Filament\Components\Forms\Fields\CopyFrom; use App\Filament\Components\Forms\Fields\CopyFrom;
use App\Filament\Components\Forms\Fields\MonacoEditor;
use App\Models\Egg; use App\Models\Egg;
use App\Models\EggVariable; use App\Models\EggVariable;
use App\Traits\Filament\CanCustomizeHeaderActions; use App\Traits\Filament\CanCustomizeHeaderActions;
@ -15,7 +17,6 @@ use Filament\Actions\Action;
use Filament\Actions\ActionGroup; use Filament\Actions\ActionGroup;
use Filament\Actions\DeleteAction; use Filament\Actions\DeleteAction;
use Filament\Forms\Components\Checkbox; use Filament\Forms\Components\Checkbox;
use Filament\Forms\Components\CodeEditor;
use Filament\Forms\Components\FileUpload; use Filament\Forms\Components\FileUpload;
use Filament\Forms\Components\Hidden; use Filament\Forms\Components\Hidden;
use Filament\Forms\Components\KeyValue; use Filament\Forms\Components\KeyValue;
@ -424,8 +425,9 @@ class EditEgg extends EditRecord
'/bin/bash' => '/bin/bash', '/bin/bash' => '/bin/bash',
]) ])
->required(), ->required(),
CodeEditor::make('script_install') MonacoEditor::make('script_install')
->hiddenLabel() ->hiddenLabel()
->language(EditorLanguages::shell)
->columnSpanFull(), ->columnSpanFull(),
]), ]),
])->columnSpanFull()->persistTabInQueryString(), ])->columnSpanFull()->persistTabInQueryString(),

View File

@ -8,6 +8,7 @@ use App\Filament\Admin\Resources\Servers\RelationManagers\DatabasesRelationManag
use App\Filament\Admin\Resources\Servers\ServerResource; use App\Filament\Admin\Resources\Servers\ServerResource;
use App\Filament\Components\Actions\DeleteServerIcon; use App\Filament\Components\Actions\DeleteServerIcon;
use App\Filament\Components\Actions\PreviewStartupAction; use App\Filament\Components\Actions\PreviewStartupAction;
use App\Filament\Components\Forms\Fields\MonacoEditor;
use App\Filament\Components\Forms\Fields\StartupVariable; use App\Filament\Components\Forms\Fields\StartupVariable;
use App\Filament\Components\StateCasts\ServerConditionStateCast; use App\Filament\Components\StateCasts\ServerConditionStateCast;
use App\Filament\Server\Pages\Console; use App\Filament\Server\Pages\Console;
@ -28,7 +29,6 @@ use App\Traits\Filament\CanCustomizeHeaderWidgets;
use Exception; use Exception;
use Filament\Actions\Action; use Filament\Actions\Action;
use Filament\Actions\ActionGroup; use Filament\Actions\ActionGroup;
use Filament\Forms\Components\CodeEditor;
use Filament\Forms\Components\FileUpload; use Filament\Forms\Components\FileUpload;
use Filament\Forms\Components\Hidden; use Filament\Forms\Components\Hidden;
use Filament\Forms\Components\KeyValue; use Filament\Forms\Components\KeyValue;
@ -303,7 +303,7 @@ class EditServer extends EditRecord
->modalFooterActionsAlignment(Alignment::Right) ->modalFooterActionsAlignment(Alignment::Right)
->modalCancelActionLabel(trans('filament::components/modal.actions.close.label')) ->modalCancelActionLabel(trans('filament::components/modal.actions.close.label'))
->schema([ ->schema([
CodeEditor::make('logs') MonacoEditor::make('logs')
->hiddenLabel() ->hiddenLabel()
->formatStateUsing(function (Server $server, DaemonServerRepository $serverRepository) { ->formatStateUsing(function (Server $server, DaemonServerRepository $serverRepository) {
try { try {

View File

@ -0,0 +1,124 @@
<?php
namespace App\Filament\Components\Forms\Fields;
use App\Enums\EditorLanguages;
use Closure;
use Exception;
use Filament\Forms\Components\Field;
class MonacoEditor extends Field
{
public bool|Closure $showLoader = true;
public bool|Closure $automaticLayout = true;
public int|Closure $lineNumbersMinChars = 3;
public string|Closure $fontSize = '15px';
public EditorLanguages|Closure $language = EditorLanguages::html;
public string|Closure $theme = 'blackboard';
protected string $view = 'filament.components.monaco-editor';
protected function setUp(): void
{
$this->showLoader = config('monaco-editor.general.show-loader');
$this->fontSize = config('monaco-editor.general.font-size');
$this->lineNumbersMinChars = config('monaco-editor.general.line-numbers-min-chars');
$this->automaticLayout = config('monaco-editor.general.automatic-layout');
$this->theme = config('monaco-editor.general.default-theme');
}
public function editorTheme(): string
{
$theme = $this->evaluate($this->theme);
if (!isset(config('monaco-editor.themes')[$theme])) {
throw new Exception("Theme {$theme} not found in config file.");
}
return json_encode([
'base' => config("monaco-editor.themes.{$theme}.base"),
'inherit' => config("monaco-editor.themes.{$theme}.inherit"),
'rules' => config("monaco-editor.themes.{$theme}.rules"),
'colors' => config("monaco-editor.themes.{$theme}.colors"),
], JSON_THROW_ON_ERROR);
}
public function language(EditorLanguages|Closure $lang = EditorLanguages::html): static
{
$this->language = $lang;
return $this;
}
public function showLoader(bool|Closure $condition = true): static
{
$this->showLoader = $condition;
return $this;
}
public function hideLoader(): static
{
$this->showLoader = false;
return $this;
}
public function fontSize(string|Closure $size = '15px'): static
{
$this->fontSize = $size;
return $this;
}
public function lineNumbersMinChars(int|Closure $value = 3): static
{
$this->lineNumbersMinChars = $value;
return $this;
}
public function automaticLayout(bool|Closure $condition = true): static
{
$this->automaticLayout = $condition;
return $this;
}
public function theme(string|Closure $name = 'blackboard'): static
{
$this->theme = $name;
return $this;
}
public function getLanguage(): EditorLanguages
{
return $this->evaluate($this->language);
}
public function getShowLoader(): bool
{
return (bool) $this->evaluate($this->showLoader);
}
public function getFontSize(): string
{
return $this->evaluate($this->fontSize);
}
public function getLineNumbersMinChars(): int
{
return (int) $this->evaluate($this->lineNumbersMinChars);
}
public function getAutomaticLayout(): bool
{
return (bool) $this->evaluate($this->automaticLayout);
}
}

View File

@ -2,10 +2,12 @@
namespace App\Filament\Server\Resources\Files\Pages; namespace App\Filament\Server\Resources\Files\Pages;
use App\Enums\EditorLanguages;
use App\Enums\SubuserPermission; use App\Enums\SubuserPermission;
use App\Exceptions\Http\Server\FileSizeTooLargeException; use App\Exceptions\Http\Server\FileSizeTooLargeException;
use App\Exceptions\Repository\FileNotEditableException; use App\Exceptions\Repository\FileNotEditableException;
use App\Facades\Activity; use App\Facades\Activity;
use App\Filament\Components\Forms\Fields\MonacoEditor;
use App\Filament\Server\Resources\Files\FileResource; use App\Filament\Server\Resources\Files\FileResource;
use App\Livewire\AlertBanner; use App\Livewire\AlertBanner;
use App\Models\File; use App\Models\File;
@ -16,8 +18,6 @@ use App\Traits\Filament\CanCustomizeHeaderWidgets;
use Closure; use Closure;
use Filament\Actions\Action; use Filament\Actions\Action;
use Filament\Facades\Filament; use Filament\Facades\Filament;
use Filament\Forms\Components\CodeEditor;
use Filament\Forms\Components\CodeEditor\Enums\Language;
use Filament\Forms\Components\Select; use Filament\Forms\Components\Select;
use Filament\Forms\Concerns\InteractsWithForms; use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Notifications\Notification; use Filament\Notifications\Notification;
@ -137,36 +137,11 @@ class EditFiles extends Page
->label(trans('server/file.actions.new_file.syntax')) ->label(trans('server/file.actions.new_file.syntax'))
->searchable() ->searchable()
->live() ->live()
->options(Language::class) ->options(EditorLanguages::class)
->selectablePlaceholder(false) ->selectablePlaceholder(false)
->default(fn () => match (pathinfo($this->path, PATHINFO_EXTENSION)) { ->afterStateUpdated(fn ($state) => $this->dispatch('setLanguage', lang: $state))
'cc', 'hpp' => Language::Cpp, ->default(fn () => EditorLanguages::fromWithAlias(pathinfo($this->path, PATHINFO_EXTENSION))),
MonacoEditor::make('editor')
'css', 'scss' => Language::Css,
'go' => Language::Go,
'html' => Language::Html,
'class', 'kt', 'kts' => Language::Java,
'js', 'mjs', 'cjs', 'ts', 'tsx' => Language::JavaScript,
'json', 'json5' => Language::Json,
'md' => Language::Markdown,
'php3', 'php4', 'php5', 'phtml', 'php' => Language::Php,
'py', 'pyc', 'pyo', 'pyi' => Language::Python,
'xml' => Language::Xml,
'yml', 'yaml' => Language::Yaml,
default => null,
}),
CodeEditor::make('editor')
->hiddenLabel() ->hiddenLabel()
->language(fn (Get $get) => $get('lang')) ->language(fn (Get $get) => $get('lang'))
->default(function () { ->default(function () {
@ -196,6 +171,7 @@ class EditFiles extends Page
} catch (ConnectionException) { } catch (ConnectionException) {
// Alert banner for this one will be handled by ListFiles // Alert banner for this one will be handled by ListFiles
} }
$this->redirectToList(); $this->redirectToList();
}), }),
]) ])

View File

@ -2,9 +2,11 @@
namespace App\Filament\Server\Resources\Files\Pages; namespace App\Filament\Server\Resources\Files\Pages;
use App\Enums\EditorLanguages;
use App\Enums\SubuserPermission; use App\Enums\SubuserPermission;
use App\Exceptions\Repository\FileExistsException; use App\Exceptions\Repository\FileExistsException;
use App\Facades\Activity; use App\Facades\Activity;
use App\Filament\Components\Forms\Fields\MonacoEditor;
use App\Filament\Components\Tables\Columns\BytesColumn; use App\Filament\Components\Tables\Columns\BytesColumn;
use App\Filament\Components\Tables\Columns\DateTimeColumn; use App\Filament\Components\Tables\Columns\DateTimeColumn;
use App\Filament\Server\Resources\Files\FileResource; use App\Filament\Server\Resources\Files\FileResource;
@ -26,7 +28,6 @@ use Filament\Actions\DeleteBulkAction;
use Filament\Actions\EditAction; use Filament\Actions\EditAction;
use Filament\Facades\Filament; use Filament\Facades\Filament;
use Filament\Forms\Components\CheckboxList; use Filament\Forms\Components\CheckboxList;
use Filament\Forms\Components\CodeEditor;
use Filament\Forms\Components\Select; use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput; use Filament\Forms\Components\TextInput;
use Filament\Infolists\Components\TextEntry; use Filament\Infolists\Components\TextEntry;
@ -495,8 +496,17 @@ class ListFiles extends ListRecords
TextInput::make('name') TextInput::make('name')
->label(trans('server/file.actions.new_file.file_name')) ->label(trans('server/file.actions.new_file.file_name'))
->required(), ->required(),
CodeEditor::make('editor') Select::make('lang')
->hiddenLabel(), ->label(trans('server/file.actions.new_file.syntax'))
->searchable()
->live()
->options(EditorLanguages::class)
->selectablePlaceholder(false)
->afterStateUpdated(fn ($state) => $this->dispatch('setLanguage', lang: $state))
->default(EditorLanguages::plaintext->value),
MonacoEditor::make('editor')
->hiddenLabel()
->language(fn (Get $get) => $get('lang') ?? 'plaintext'),
]), ]),
Action::make('new_folder') Action::make('new_folder')
->authorize(fn () => user()?->can(SubuserPermission::FileCreate, $server)) ->authorize(fn () => user()?->can(SubuserPermission::FileCreate, $server))

268
config/monaco-editor.php Normal file
View File

@ -0,0 +1,268 @@
<?php
return [
'general' => [
'enable-preview' => false,
'show-full-screen-toggle' => false,
'show-loader' => false,
'font-size' => '15px',
'line-numbers-min-chars' => 3,
'automatic-layout' => true,
'default-theme' => 'blackboard',
],
'themes' => [
'blackboard' => [
'base' => 'vs-dark',
'inherit' => true,
'rules' => [
[
'background' => '161F27',
'token' => '',
],
[
'foreground' => 'aeaeae',
'token' => 'comment',
],
[
'foreground' => 'd8fa3c',
'token' => 'constant',
],
[
'foreground' => 'ff6400',
'token' => 'entity',
],
[
'foreground' => 'fbde2d',
'token' => 'keyword',
],
[
'foreground' => 'fbde2d',
'token' => 'storage',
],
[
'foreground' => '61ce3c',
'token' => 'string',
],
[
'foreground' => '61ce3c',
'token' => 'meta.verbatim',
],
[
'foreground' => '8da6ce',
'token' => 'support',
],
[
'foreground' => 'ab2a1d',
'fontStyle' => 'italic',
'token' => 'invalid.deprecated',
],
[
'foreground' => 'f8f8f8',
'background' => '9d1e15',
'token' => 'invalid.illegal',
],
[
'foreground' => 'ff6400',
'fontStyle' => 'italic',
'token' => 'entity.other.inherited-class',
],
[
'foreground' => 'ff6400',
'token' => 'string constant.other.placeholder',
],
[
'foreground' => 'becde6',
'token' => 'meta.function-call.py',
],
[
'foreground' => '7f90aa',
'token' => 'meta.tag',
],
[
'foreground' => '7f90aa',
'token' => 'meta.tag entity',
],
[
'foreground' => 'ffffff',
'token' => 'entity.name.section',
],
[
'foreground' => 'd5e0f3',
'token' => 'keyword.type.variant',
],
[
'foreground' => 'f8f8f8',
'token' => 'source.ocaml keyword.operator.symbol',
],
[
'foreground' => '8da6ce',
'token' => 'source.ocaml keyword.operator.symbol.infix',
],
[
'foreground' => '8da6ce',
'token' => 'source.ocaml keyword.operator.symbol.prefix',
],
[
'fontStyle' => 'underline',
'token' => 'source.ocaml keyword.operator.symbol.infix.floating-point',
],
[
'fontStyle' => 'underline',
'token' => 'source.ocaml keyword.operator.symbol.prefix.floating-point',
],
[
'fontStyle' => 'underline',
'token' => 'source.ocaml constant.numeric.floating-point',
],
[
'background' => 'ffffff08',
'token' => 'text.tex.latex meta.function.environment',
],
[
'background' => '7a96fa08',
'token' => 'text.tex.latex meta.function.environment meta.function.environment',
],
[
'foreground' => 'fbde2d',
'token' => 'text.tex.latex support.function',
],
[
'foreground' => 'ffffff',
'token' => 'source.plist string.unquoted',
],
[
'foreground' => 'ffffff',
'token' => 'source.plist keyword.operator',
],
],
'colors' => [
'editor.foreground' => '#F8F8F8',
'editor.background' => '#101519',
'editor.selectionBackground' => '#5a5f63',
'editor.lineHighlightBackground' => '#FFFFFF0F',
'editorCursor.foreground' => '#FFFFFFA6',
'editorWhitespace.foreground' => '#FFFFFF40',
],
],
'iPlastic' => [
'base' => 'vs',
'inherit' => true,
'rules' => [
[
'background' => 'EEEEEEEB',
'token' => '',
],
[
'foreground' => '009933',
'token' => 'string',
],
[
'foreground' => '0066ff',
'token' => 'constant.numeric',
],
[
'foreground' => 'ff0080',
'token' => 'string.regexp',
],
[
'foreground' => '0000ff',
'token' => 'keyword',
],
[
'foreground' => '9700cc',
'token' => 'constant.language',
],
[
'foreground' => '990000',
'token' => 'support.class.exception',
],
[
'foreground' => 'ff8000',
'token' => 'entity.name.function',
],
[
'fontStyle' => 'bold underline',
'token' => 'entity.name.type',
],
[
'fontStyle' => 'italic',
'token' => 'variable.parameter',
],
[
'foreground' => '0066ff',
'fontStyle' => 'italic',
'token' => 'comment',
],
[
'foreground' => 'ff0000',
'background' => 'e71a114d',
'token' => 'invalid',
],
[
'background' => 'e71a1100',
'token' => 'invalid.deprecated.trailing-whitespace',
],
[
'foreground' => '000000',
'background' => 'fafafafc',
'token' => 'text source',
],
[
'foreground' => '0033cc',
'token' => 'meta.tag',
],
[
'foreground' => '0033cc',
'token' => 'declaration.tag',
],
[
'foreground' => '6782d3',
'token' => 'constant',
],
[
'foreground' => '6782d3',
'token' => 'support.constant',
],
[
'foreground' => '3333ff',
'fontStyle' => 'bold',
'token' => 'support',
],
[
'fontStyle' => 'bold',
'token' => 'storage',
],
[
'fontStyle' => 'bold underline',
'token' => 'entity.name.section',
],
[
'foreground' => '000000',
'fontStyle' => 'bold',
'token' => 'entity.name.function.frame',
],
[
'foreground' => '333333',
'token' => 'meta.tag.preprocessor.xml',
],
[
'foreground' => '3366cc',
'fontStyle' => 'italic',
'token' => 'entity.other.attribute-name',
],
[
'fontStyle' => 'bold',
'token' => 'entity.name.tag',
],
],
'colors' => [
'editor.foreground' => '#000000',
'editor.background' => '#EEEEEEEB',
'editor.selectionBackground' => '#BAD6FD',
'editor.lineHighlightBackground' => '#0000001A',
'editorCursor.foreground' => '#000000',
'editorWhitespace.foreground' => '#B3B3B3F4',
],
],
],
];

View File

@ -0,0 +1,5 @@
.-rotate-180,.-translate-x-5,.-translate-y-12,.fme-placeholder,.rotate-180,.scale-100,.scale-95,.transform,.translate-x-0,.translate-x-12,.translate-x-5,.translate-x-full,.translate-y-12{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.fme-full-screen-btn-icon,.fme-placeholder,.group\/button:hover .group-hover\/button\:text-gray-500{color:rgba(var(--gray-500),var(--tw-text-opacity));--tw-text-opacity:1}.fme-full-screen-btn:focus,input:checked+.\[input\:checked\+\&\]\:ring-0{--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(var(--tw-ring-offset-width)) var(--tw-ring-color);--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.fme-wrapper{display:flex;width:100%;flex-direction:column}.fme-full-screen{position:fixed;top:64px;left:300px;z-index:1;width:100vw;height:100vw;overflow:hidden;border-top-width:.5px;border-color:#65656d;--tw-bg-opacity:1;background-color:rgb(24 24 27 / var(--tw-bg-opacity))}.fme-control-section{display:flex;justify-content:space-between;padding:.5rem}.fme-full-screen-btn{border-radius:.25rem;padding:.25rem .5rem}.fme-full-screen-btn:focus{--tw-bg-opacity:1;background-color:rgba(var(--gray-100),var(--tw-bg-opacity))}.fme-full-screen-btn-icon{height:1rem;width:1rem}.fme-container{flex-direction:column;justify-content:flex-start;--tw-bg-opacity:1}.fme-container,.fme-loader{display:flex;height:100%;width:100%}.fme-element-wrapper{position:relative;z-index:10;height:100%;width:100%;border-radius:.25rem}.fme-element{height:100%;width:100%;font-size:1.125rem;line-height:1.75rem}.fme-placeholder{position:absolute;left:0;top:0;z-index:50;margin-left:3.5rem;margin-top:.125rem;width:100%;--tw-translate-x:-0.125rem;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:.875rem;line-height:1.25rem}.grow{flex-grow:1}.truncate,.whitespace-nowrap{white-space:nowrap}.\!bg-gray-50,.\!bg-gray-700{--tw-bg-opacity:1!important}.pb-6,.py-6{padding-bottom:1.5rem}.opacity-25{opacity:.25}.opacity-75{opacity:.75}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.focus-visible\:ring-1:focus-visible,.focus-visible\:ring-2:focus-visible{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.disabled\:placeholder\:\[-webkit-text-fill-color\:theme\(colors\.gray\.400\)\]:disabled::-moz-placeholder,.disabled\:placeholder\:\[-webkit-text-fill-color\:theme\(colors\.gray\.400\)\]:disabled::placeholder{-webkit-text-fill-color:rgba(var(--gray-400),1)}.group\/item:focus-visible .group-focus-visible\/item\:underline,.group\/link:focus-visible .group-focus-visible\/link\:underline{text-decoration-line:underline}.dark\:disabled\:placeholder\:\[-webkit-text-fill-color\:theme\(colors\.gray\.500\)\]:disabled:is(
.dark *
)::-moz-placeholder,.dark\:disabled\:placeholder\:\[-webkit-text-fill-color\:theme\(colors\.gray\.500\)\]:disabled:is(
.dark *
)::placeholder{-webkit-text-fill-color:rgba(var(--gray-500),1)}.group:focus-visible .dark\:group-focus-visible\:text-gray-200:is(.dark *),.group:hover .dark\:group-hover\:text-gray-200:is(.dark *){--tw-text-opacity:1;color:rgba(var(--gray-200),var(--tw-text-opacity))}:checked+*>.\[\:checked\+\*\>\&\]\:text-white,input:checked+.\[input\:checked\+\&\]\:text-white{--tw-text-opacity:1;color:rgb(255 255 255 / var(--tw-text-opacity))}input:checked+.\[input\:checked\+\&\]\:bg-custom-600{--tw-bg-opacity:1;background-color:rgba(var(--c-600),var(--tw-bg-opacity))}input:checked+.\[input\:checked\+\&\]\:hover\:bg-custom-500:hover,input:checked+.dark\:\[input\:checked\+\&\]\:bg-custom-500:is(.dark *){--tw-bg-opacity:1;background-color:rgba(var(--c-500),var(--tw-bg-opacity))}input:checked+.dark\:\[input\:checked\+\&\]\:hover\:bg-custom-400:hover:is(.dark *){--tw-bg-opacity:1;background-color:rgba(var(--c-400),var(--tw-bg-opacity))}input:checked:focus-visible+.\[input\:checked\:focus-visible\+\&\]\:ring-custom-500\/50{--tw-ring-color:rgba(var(--c-500), 0.5)}input:checked:focus-visible+.dark\:\[input\:checked\:focus-visible\+\&\]\:ring-custom-400\/50:is(.dark *){--tw-ring-color:rgba(var(--c-400), 0.5)}input:focus-visible+.\[input\:focus-visible\+\&\]\:z-10{z-index:10}input:focus-visible+.\[input\:focus-visible\+\&\]\:ring-2{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px+var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}input:focus-visible+.\[input\:focus-visible\+\&\]\:ring-gray-950\/10{--tw-ring-color:rgba(var(--gray-950), 0.1)}input:focus-visible+.dark\:\[input\:focus-visible\+\&\]\:ring-white\/20:is(.dark *){--tw-ring-color:#fff3}

View File

@ -0,0 +1,144 @@
@script
<script>
$wire.on('setContent', ({ content }) => {
document.getElementById('{{ $getId() }}').editor.getModel().setValue(content);
});
$wire.on('setLanguage', ({ lang }) => {
monaco.editor.setModelLanguage(document.getElementById('{{ $getId() }}').editor.getModel(), lang);
});
</script>
@endscript
@vite(['resources/css/monaco-editor.css'])
<x-dynamic-component :component="$getFieldWrapperView()" :field="$field" class="overflow-hidden">
<div x-data="{
monacoContent: $wire.$entangle('{{ $getStatePath() }}'),
fullScreenModeEnabled: false,
monacoLanguage: '{{ $getLanguage() }}',
monacoLoader: {{ (int) $getShowLoader() }},
monacoFontSize: '{{ $getFontSize() }}',
lineNumbersMinChars: {{ $getLineNumbersMinChars() }},
automaticLayout: {{ (int) $getAutomaticLayout() }},
monacoId: '{{ $getId() }}',
toggleFullScreenMode() {
this.fullScreenModeEnabled = !this.fullScreenModeEnabled;
this.fullScreenModeEnabled ? document.body.classList.add('overflow-hidden')
: document.body.classList.remove('overflow-hidden');
$el.style.width = this.fullScreenModeEnabled ? '100vw'
: $el.parentElement.clientWidth + 'px';
},
monacoEditor(editor){
editor.onDidChangeModelContent((e) => {
this.monacoContent = editor.getValue();
});
},
monacoEditorFocus(){
document.getElementById(this.monacoId).dispatchEvent(
new CustomEvent('monaco-editor-focused', { monacoId: this.monacoId })
);
},
monacoEditorAddLoaderScriptToHead() {
script = document.createElement('script');
script.src = 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.49.0/min/vs/loader.min.js';
document.head.appendChild(script);
},
}" x-init="
$el.style.height = '650px';
$watch('fullScreenModeEnabled', value => {
if (value) {
$el.style.height = '100vh';
} else {
$el.style.height = '650px';
}
});
if(typeof _amdLoaderGlobal == 'undefined'){
monacoEditorAddLoaderScriptToHead();
}
monacoLoaderInterval = setInterval(() => {
if(typeof _amdLoaderGlobal !== 'undefined'){
// Based on https://jsfiddle.net/developit/bwgkr6uq/ which works without needing service worker. Provided by loader.min.js.
require.config({ paths: { 'vs': 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.49.0/min/vs' }});
let proxy = URL.createObjectURL(new Blob([` self.MonacoEnvironment = { baseUrl: 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.49.0/min' }; importScripts('https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.49.0/min/vs/base/worker/workerMain.min.js');`], { type: 'text/javascript' }));
window.MonacoEnvironment = { getWorkerUrl: () => proxy };
require(['vs/editor/editor.main'], () => {
monaco.editor.defineTheme('custom', {{ $editorTheme() }});
document.getElementById(monacoId).editor = monaco.editor.create($refs.monacoEditorElement, {
value: monacoContent,
theme: localStorage.getItem('theme') === 'light' ? 'iPlastic' : 'custom',
fontSize: monacoFontSize,
lineNumbersMinChars: lineNumbersMinChars,
automaticLayout: automaticLayout,
language: monacoLanguage,
scrollbar: {
horizontal: 'auto',
horizontalScrollbarSize: 15,
vertical: 'auto',
verticalScrollbarSize: 15
},
wordWrap: 'on',
wrappingIndent: 'same',
});
$el.style.zIndex = '1';
monacoEditor(document.getElementById(monacoId).editor);
});
clearInterval(monacoLoaderInterval);
monacoLoader = false;
}
}, 5); " :id="monacoId"
class="fme-wrapper"
:class="{ 'fme-full-screen': fullScreenModeEnabled }" x-cloak>
{{-- <div class="fme-control-section">--}}
{{-- <div class="flex items-center ml-auto">--}}
{{-- @if($getShowFullScreenToggle())--}}
{{-- <button type="button" aria-label="{{ __("full_screen_btn_label") }}" class="fme-full-screen-btn"--}}
{{-- @click="toggleFullScreenMode()">--}}
{{-- <svg class="fme-full-screen-btn-icon" x-show="!fullScreenModeEnabled"--}}
{{-- xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"--}}
{{-- stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">--}}
{{-- <path stroke="none" d="M0 0h24v24H0z" fill="none" />--}}
{{-- <path d="M16 4l4 0l0 4" />--}}
{{-- <path d="M14 10l6 -6" />--}}
{{-- <path d="M8 20l-4 0l0 -4" />--}}
{{-- <path d="M4 20l6 -6" />--}}
{{-- <path d="M16 20l4 0l0 -4" />--}}
{{-- <path d="M14 14l6 6" />--}}
{{-- <path d="M8 4l-4 0l0 4" />--}}
{{-- <path d="M4 4l6 6" />--}}
{{-- </svg>--}}
{{-- <svg class="fme-full-screen-btn-icon" x-show="fullScreenModeEnabled"--}}
{{-- xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"--}}
{{-- stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">--}}
{{-- <path stroke="none" d="M0 0h24v24H0z" fill="none" />--}}
{{-- <path d="M5 9l4 0l0 -4" />--}}
{{-- <path d="M3 3l6 6" />--}}
{{-- <path d="M5 15l4 0l0 4" />--}}
{{-- <path d="M3 21l6 -6" />--}}
{{-- <path d="M19 9l-4 0l0 -4" />--}}
{{-- <path d="M15 9l6 -6" />--}}
{{-- <path d="M19 15l-4 0l0 4" />--}}
{{-- <path d="M15 15l6 6" />--}}
{{-- </svg>--}}
{{-- </button>--}}
{{-- @endif--}}
{{-- </div>--}}
{{-- </div>--}}
<div class="fme-container">
<div x-show="!monacoLoader" class="fme-element-wrapper">
<div x-ref="monacoEditorElement" class="fme-element" wire:ignore style="height: 100%"></div>
</div>
</div>
</div>
</x-dynamic-component>