From 7629d6e9510a128d787e80bd1e0254c2aea3bdf9 Mon Sep 17 00:00:00 2001 From: Pat Hartl Date: Tue, 18 Apr 2023 20:17:50 -0500 Subject: [PATCH] Make tabbed text editor, styled somewhat after VS Code --- .../Pages/Servers/Components/TextEditor.razor | 110 ++++++++++++++---- .../Servers/Components/TextEditorPane.razor | 93 +++++++++++++++ 2 files changed, 183 insertions(+), 20 deletions(-) create mode 100644 LANCommander/Pages/Servers/Components/TextEditorPane.razor diff --git a/LANCommander/Pages/Servers/Components/TextEditor.razor b/LANCommander/Pages/Servers/Components/TextEditor.razor index 1cd05c9..bc8d6b5 100644 --- a/LANCommander/Pages/Servers/Components/TextEditor.razor +++ b/LANCommander/Pages/Servers/Components/TextEditor.razor @@ -1,6 +1,6 @@ @using LANCommander.Extensions; - + - - @foreach (var part in CurrentFile.Split(Path.DirectorySeparatorChar)) + + @foreach (var file in OpenFiles) { - @part + } - - + @@ -26,6 +25,73 @@ .monaco-editor-container { min-height: 600px; } + + .text-editor { + background: #252525; + min-height: 600px; + } + + .text-editor .ant-tree { + background: none; + color: #ccc; + padding-top: 16px; + padding-left: 8px; + } + + .text-editor .ant-tree-node-content-wrapper:hover { + background: none; + } + + .text-editor .ant-tree-treenode:hover { + background: #37373d; + } + + .text-editor .text-editor-info-bar { + padding-left: 16px; + padding-right: 16px; + margin-top: 0; + margin-bottom: 0; + padding-top: 8px; + padding-bottom: 8px; + background: #1e1e1e; + } + + .text-editor .text-editor-info-bar .ant-breadcrumb, + .text-editor .ant-breadcrumb-separator, + .text-editor .ant-breadcrumb li:last-child { + color: #a9a9a9; + } + + .text-editor .ant-tabs-card.ant-tabs-top > .ant-tabs-nav .ant-tabs-tab, + .text-editor .ant-tabs-card.ant-tabs-top > div > .ant-tabs-nav .ant-tabs-tab { + border-radius: 0; + background: #2d2d2d; + padding: 4px 10px; + color: #a9a9a9; + border: none; + } + + .text-editor .ant-tabs-card > .ant-tabs-nav .ant-tabs-tab-active, + .text-editor .ant-tabs-card > div > .ant-tabs-nav .ant-tabs-tab-active { + background: #1e1e1e !important; + } + + .text-editor .ant-tabs-tab .ant-tabs-tab-remove .anticon { + color: #a9a9a9; + } + + .text-editor .ant-tabs-tab.ant-tabs-tab-active .ant-tabs-tab-btn, + .text-editor .ant-tabs-tab.ant-tabs-tab-active .ant-tabs-tab-remove .anticon { + color: #fff; + } + + .text-editor .ant-tabs-top > .ant-tabs-nav::before { + border: none; + } + + .text-editor .ant-tabs-nav { + margin: 0; + } @code { @@ -37,6 +103,9 @@ HashSet FileTree { get; set; } = new HashSet(); string CurrentFile = ""; + List OpenFiles = new List(); + string ActiveFile; + private StandaloneEditorConstructionOptions EditorConstructionOptions(StandaloneCodeEditor editor) { return new StandaloneEditorConstructionOptions @@ -57,26 +126,27 @@ root.PopulateChildren(WorkingDirectory); - FileTree.Add(root); + foreach (var child in root.Children) + { + FileTree.Add(child); + } } private void OpenFile(FileTreeNode node) { - if (File.Exists(node.FullName)) - { - var file = new FileInfo(node.FullName); + if (!OpenFiles.Contains(node.FullName)) + OpenFiles.Add(node.FullName); - CurrentFile = node.FullName; + ActiveFile = node.FullName; - if (!file.IsBinaryFile()) - { - Editor.SetValue(File.ReadAllText(file.FullName)); - } - else - { - Editor.SetValue("This file cannot be edited because it is a binary file."); - } - } + StateHasChanged(); + } + + private void OnTabClose(string key) + { + OpenFiles.Remove(key); + + StateHasChanged(); } public class FileTreeNode diff --git a/LANCommander/Pages/Servers/Components/TextEditorPane.razor b/LANCommander/Pages/Servers/Components/TextEditorPane.razor new file mode 100644 index 0000000..d0c0ac7 --- /dev/null +++ b/LANCommander/Pages/Servers/Components/TextEditorPane.razor @@ -0,0 +1,93 @@ +@using LANCommander.Extensions; + +@if (FileInfo != null) +{ + + + + + + @foreach (var part in FileInfo.FullName.Split(Path.DirectorySeparatorChar)) + { + @part + } + + + + + + + + + + + + +} + +@code { + [Parameter] public string FilePath { get; set; } + + TabPane Pane; + FileInfo FileInfo; + StandaloneCodeEditor Editor; + string Contents; + bool HasUnsavedChanges = false; + + private StandaloneEditorConstructionOptions EditorConstructionOptions(StandaloneCodeEditor editor) + { + return new StandaloneEditorConstructionOptions + { + AutomaticLayout = true, + Theme = "vs-dark" + }; + } + + protected override async Task OnParametersSetAsync() + { + FileInfo = new FileInfo(FilePath); + } + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (Editor != null && firstRender) + { + if (File.Exists(FileInfo.FullName)) + { + if (!FileInfo.IsBinaryFile()) + { + Contents = await File.ReadAllTextAsync(FileInfo.FullName); + + await Editor.SetValue(Contents); + } + else + { + await Editor.SetValue("This file cannot be edited because it is a binary file."); + } + } + + await Editor.AddCommand((int)BlazorMonaco.KeyMod.CtrlCmd | (int)BlazorMonaco.KeyCode.KeyS, async (editor) => + { + await Save(); + }, null); + } + } + + private void OnChange(ModelContentChangedEvent eventArgs) + { + if (!HasUnsavedChanges) + { + HasUnsavedChanges = true; + StateHasChanged(); + } + } + + private async Task Save() + { + await File.WriteAllTextAsync(FileInfo.FullName, await Editor.GetValue()); + + HasUnsavedChanges = false; + + StateHasChanged(); + } +}