diff --git a/Seenginx.Models/ConfigFile.cs b/Seenginx.Models/ConfigFile.cs index a8f9975..0a6a5ac 100644 --- a/Seenginx.Models/ConfigFile.cs +++ b/Seenginx.Models/ConfigFile.cs @@ -6,18 +6,19 @@ namespace Seenginx.Models { public class ConfigFile { + public string FullPath { get; set; } public string Folder { get; set; } public string Name { get; set; } - public bool HasDraft => !string.IsNullOrEmpty(DraftName); public string DraftName { get; set; } - public string OriginalBody { get; set; } + public string Body { get; set; } public string DraftBody { get; set; } + public string Permissions { get; set; } public DateTime LastUpdated { get; set; } public string[] Owners { get; set; } - public string Permissions { get; set; } - public bool CanBeDeleted { get; set; } = true; public string IsVisible { get; set; } = string.Empty; public string IsSelected { get; set; } = string.Empty; + public bool HasDraft => !string.IsNullOrEmpty(DraftName); + public bool CanBeDeleted { get; set; } = true; public void Hide() { IsVisible = "is-hidden"; } public void Unhide() { IsVisible = string.Empty; } diff --git a/Seenginx.Models/Result.cs b/Seenginx.Models/Result.cs index 9baf79f..b722a90 100644 --- a/Seenginx.Models/Result.cs +++ b/Seenginx.Models/Result.cs @@ -11,6 +11,12 @@ namespace Seenginx.Models public Exception Exception { get; private set; } = null; public D Data { get; private set; } + public Result() { } + public Result(D data) + { + Data = data; + } + public Result Invalidate(string errorMessage, Exception exception = null) { AllOk = false; diff --git a/Seenginx.Models/WeatherForecast.cs b/Seenginx.Models/WeatherForecast.cs deleted file mode 100644 index 0dd5c3f..0000000 --- a/Seenginx.Models/WeatherForecast.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; - -namespace Seenginx.Models -{ - public class WeatherForecast - { - public DateTime Date { get; set; } - - public int TemperatureC { get; set; } - - public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); - - public string Summary { get; set; } - } -} diff --git a/Seenginx/Components/FilesWithEditor.razor b/Seenginx/Components/FilesWithEditor.razor index a7e96e1..08f7d17 100644 --- a/Seenginx/Components/FilesWithEditor.razor +++ b/Seenginx/Components/FilesWithEditor.razor @@ -12,7 +12,7 @@
- @foreach (var filter in Filters) { @@ -37,7 +37,7 @@ @onchange="e => SelectedFile.DraftName = e.Value.ToString()">
- - - - - + + + +
} else diff --git a/Seenginx/Components/FilesWithEditor.razor.cs b/Seenginx/Components/FilesWithEditor.razor.cs index 66e7dbd..9f7e85d 100644 --- a/Seenginx/Components/FilesWithEditor.razor.cs +++ b/Seenginx/Components/FilesWithEditor.razor.cs @@ -29,7 +29,7 @@ namespace Seenginx.Components [Parameter] public EventCallback UpdateFile { get; set; } [Parameter] - public EventCallback DeleteFile { get; set; } + public EventCallback DeleteFile { get; set; } [Parameter] public RenderFragment Editor { get; set; } = null; @@ -134,7 +134,7 @@ namespace Seenginx.Components { Files.ForEach(f => f.Deselect()); file.Select(); - await JsRuntime.InvokeVoidAsync("UpdateEditor", file.OriginalBody); + await JsRuntime.InvokeVoidAsync("UpdateEditor", file.Body); await SelectedFileChanged.InvokeAsync(file); } @@ -152,13 +152,13 @@ namespace Seenginx.Components } protected async Task OnUndoChanges(MouseEventArgs e) { - SelectedFile.DraftBody = SelectedFile.OriginalBody; - await JsRuntime.InvokeVoidAsync("UpdateEditor", SelectedFile.OriginalBody); + SelectedFile.DraftBody = SelectedFile.Body; + await JsRuntime.InvokeVoidAsync("UpdateEditor", SelectedFile.Body); } protected async Task OnSave(MouseEventArgs e) { var draftCode = await JsRuntime.InvokeAsync("GetEditorCode"); - SelectedFile.OriginalBody = draftCode; + SelectedFile.Body = draftCode; } protected async Task OnTest(MouseEventArgs e) { @@ -170,7 +170,7 @@ namespace Seenginx.Components } protected async Task OnDeleteDialog() { - await UpdateFile.InvokeAsync(SelectedFile); + await DeleteFile.InvokeAsync(null); } } } diff --git a/Seenginx/Pages/Nginx.razor b/Seenginx/Pages/Nginx.razor index 2ee1aa3..d17fb23 100644 --- a/Seenginx/Pages/Nginx.razor +++ b/Seenginx/Pages/Nginx.razor @@ -1,10 +1,11 @@ @inherits NginxBase @page "/nginx" +

ciao

+ AddFile="AddFile" DeleteFile="DeleteFile"> diff --git a/Seenginx/Pages/Nginx.razor.cs b/Seenginx/Pages/Nginx.razor.cs index e1aa50c..d9d78f3 100644 --- a/Seenginx/Pages/Nginx.razor.cs +++ b/Seenginx/Pages/Nginx.razor.cs @@ -14,6 +14,8 @@ namespace Seenginx.Pages { [Inject] public INginxService NginxService { get; set; } + [Inject] + public IFileManager FileService { get; set; } public string InputSearch { get; set; } @@ -57,11 +59,17 @@ namespace Seenginx.Pages { ShowModal(); } - public async Task UpdateFile(ConfigFile configFile) - { - } - public async Task DeleteFile(ConfigFile configFile) + + public async Task> SaveDraftFileAsync() => + await FileService.SaveUpdateDraftFileAsync(SelectedFile); + + public async Task> SaveFileAsync() => + await FileService.SaveUpdateFileAsync(SelectedFile); + + public Result DeleteFile(EventArgs eventArgs) { + return FileService.DeleteFile(SelectedFile); } + } } diff --git a/Seenginx/SCSS/utility.scss b/Seenginx/SCSS/utility.scss index 82b6b76..28e4210 100644 --- a/Seenginx/SCSS/utility.scss +++ b/Seenginx/SCSS/utility.scss @@ -85,6 +85,26 @@ border: none !important; transform: scale(1.1); } + + &Small { + box-shadow: -2px -2px 4px rgba($light-shadow, .5), 2px 2px 4px rgba($dark-shadow, .5); + background: none !important; + border: none !important; + transition: all .2s linear; + -webkit-backface-visibility: hidden; + backface-visibility: hidden; + + &:focus { + box-shadow: -2px -2px 4px rgba($light-shadow, .5), 2px 2px 4px rgba($dark-shadow, .5) !important; + } + + &:hover { + box-shadow: -4px -4px 8px rgba($light-shadow, .5), 4px 4px 8px rgba($dark-shadow, .5); + background: none !important; + border: none !important; + transform: scale(1.1); + } + } } &File { diff --git a/Seenginx/Services/FileManager.cs b/Seenginx/Services/FileManager.cs new file mode 100644 index 0000000..a96e23b --- /dev/null +++ b/Seenginx/Services/FileManager.cs @@ -0,0 +1,83 @@ +using Seenginx.Models; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; + +namespace Seenginx.Services +{ + public class FileManager : IFileManager + { + public async Task> SaveUpdateFileAsync(ConfigFile configFile) + { + var result = new Result(configFile); + try + { + var validationResult = ValidForUpdate(configFile); + if (!validationResult.AllOk) + return result.Invalidate($"Failed validation for: {validationResult.ErrorMessage}"); + + await File.WriteAllTextAsync(configFile.FullPath, configFile.Body); + + return result; + } + catch (Exception ex) + { + return result.Invalidate($"Exception at {nameof(SaveUpdateFileAsync)}(), with {nameof(ConfigFile.Name)}=[{nameof(configFile.Name)}]", ex); + } + } + + public async Task> SaveUpdateDraftFileAsync(ConfigFile configFile) + { + var result = new Result(configFile); + try + { + var validationResult = ValidForUpdate(configFile); + if (!validationResult.AllOk) + return result.Invalidate($"Failed validation for: {validationResult.ErrorMessage}"); + + await File.WriteAllTextAsync($"{configFile.FullPath}.draft", configFile.DraftBody); + + return result; + } + catch (Exception ex) + { + return result.Invalidate($"Exception at {nameof(SaveUpdateDraftFileAsync)}(), with {nameof(ConfigFile.Name)}=[{nameof(configFile.Name)}]", ex); + } + } + + public Result DeleteFile(ConfigFile configFile) + { + var result = new Result(); + try + { + var validationResult = ValidForUpdate(configFile); + + if (!validationResult.AllOk) + return result.Invalidate($"Failed validation for: {validationResult.ErrorMessage}"); + + File.Delete(configFile.FullPath); + if (File.Exists($"{configFile.FullPath}.draft")) + File.Delete($"{configFile.FullPath}.draft"); + + return result; + } + catch (Exception ex) + { + return result.Invalidate($"Exception at {nameof(DeleteFile)}(), with {nameof(ConfigFile.Name)}=[{nameof(configFile.Name)}]", ex); + } + } + + private Result ValidForUpdate(ConfigFile configFile) + { + var result = new Result(); + if (!Directory.Exists(Directory.GetDirectoryRoot(configFile.FullPath))) + return result.Invalidate($"Directory '{Directory.GetDirectoryRoot(configFile.FullPath)}' doesn't exist."); + if (!File.Exists(configFile.FullPath)) + return result.Invalidate($"File '{configFile.FullPath}' doesn't exist."); + return result; + } + + } +} diff --git a/Seenginx/Services/IFileManager.cs b/Seenginx/Services/IFileManager.cs new file mode 100644 index 0000000..8cb7242 --- /dev/null +++ b/Seenginx/Services/IFileManager.cs @@ -0,0 +1,15 @@ +using Seenginx.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Seenginx.Services +{ + public interface IFileManager + { + Task> SaveUpdateFileAsync(ConfigFile configFile); + Task> SaveUpdateDraftFileAsync(ConfigFile configFile); + Result DeleteFile(ConfigFile configFile); + } +} diff --git a/Seenginx/Services/NginxService.cs b/Seenginx/Services/NginxService.cs index d996359..2b21432 100644 --- a/Seenginx/Services/NginxService.cs +++ b/Seenginx/Services/NginxService.cs @@ -33,7 +33,8 @@ namespace Seenginx.Services configFile.Folder = "/"; configFile.LastUpdated = File.GetLastWriteTime(fp); configFile.Name = fileName; - configFile.OriginalBody = File.ReadAllText(fp); + configFile.FullPath = Path.Combine(ConfigPaths.NginxPath, configFile.Folder, configFile.Name); + configFile.Body = File.ReadAllText(fp); return configFile; }); var confdConfigFiles = confdConfigs.Select(fp => @@ -44,7 +45,8 @@ namespace Seenginx.Services configFile.Folder = "/conf.d"; configFile.LastUpdated = File.GetLastWriteTime(fp); configFile.Name = fileName; - configFile.OriginalBody = File.ReadAllText(fp); + configFile.FullPath = Path.Combine(ConfigPaths.NginxPath, configFile.Folder, configFile.Name); + configFile.Body = File.ReadAllText(fp); return configFile; }); var sitesAvailableConfigFiles = sitesAvailableConfigs.Select(fp => @@ -55,7 +57,8 @@ namespace Seenginx.Services configFile.Folder = "/sites-available"; configFile.LastUpdated = File.GetLastWriteTime(fp); configFile.Name = fileName; - configFile.OriginalBody = File.ReadAllText(fp); + configFile.FullPath = Path.Combine(ConfigPaths.NginxPath, configFile.Folder, configFile.Name); + configFile.Body = File.ReadAllText(fp); return configFile; }); var sitesEnabledConfigFiles = sitesEnabledConfigs.Select(fp => @@ -66,7 +69,8 @@ namespace Seenginx.Services configFile.Folder = "/sites-enabled"; configFile.LastUpdated = File.GetLastWriteTime(fp); configFile.Name = fileName; - configFile.OriginalBody = File.ReadAllText(fp); + configFile.FullPath = Path.Combine(ConfigPaths.NginxPath, configFile.Folder, configFile.Name); + configFile.Body = File.ReadAllText(fp); return configFile; }); var finalList = new List(); diff --git a/Seenginx/Startup.cs b/Seenginx/Startup.cs index 65bd7a5..ab20eb7 100644 --- a/Seenginx/Startup.cs +++ b/Seenginx/Startup.cs @@ -48,6 +48,7 @@ namespace Seenginx services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. diff --git a/Seenginx/wwwroot/css/main.css b/Seenginx/wwwroot/css/main.css index 3397b14..4dc51a3 100644 --- a/Seenginx/wwwroot/css/main.css +++ b/Seenginx/wwwroot/css/main.css @@ -90,6 +90,20 @@ html { background: none !important; border: none !important; transform: scale(1.1); } + .neoBtnSmall { + box-shadow: -2px -2px 4px rgba(251, 238, 208, 0.5), 2px 2px 4px rgba(241, 185, 65, 0.5); + background: none !important; + border: none !important; + transition: all .2s linear; + -webkit-backface-visibility: hidden; + backface-visibility: hidden; } + .neoBtnSmall:focus { + box-shadow: -2px -2px 4px rgba(251, 238, 208, 0.5), 2px 2px 4px rgba(241, 185, 65, 0.5) !important; } + .neoBtnSmall:hover { + box-shadow: -4px -4px 8px rgba(251, 238, 208, 0.5), 4px 4px 8px rgba(241, 185, 65, 0.5); + background: none !important; + border: none !important; + transform: scale(1.1); } .neoFile { box-shadow: 0px 0px 0px rgba(251, 238, 208, 0.5), 0px 0px 0px rgba(241, 185, 65, 0.5) !important; diff --git a/Seenginx/wwwroot/css/main.min.css b/Seenginx/wwwroot/css/main.min.css index 2ef4f57..feddacf 100644 --- a/Seenginx/wwwroot/css/main.min.css +++ b/Seenginx/wwwroot/css/main.min.css @@ -1 +1 @@ -#blazor-error-ui{background:#ffffe0;bottom:0;box-shadow:0 -1px 2px rgba(0,0,0,.2);display:none;left:0;padding:.6rem 1.25rem .7rem 1.25rem;position:fixed;width:100%;z-index:1000;}#blazor-error-ui .dismiss{cursor:pointer;position:absolute;right:.75rem;top:.5rem;}button::-moz-focus-inner,input::-moz-focus-inner{border:0;}html{scrollbar-color:#f1b941 #fbeed0;scrollbar-width:thin;scrollbar-arrow-color:#fbeed0;scrollbar-base-color:#f6d287;scrollbar-darkshadow-color:#f1b941;}*{scrollbar-width:inherit;}.isHidden{display:none;}@media only screen and (max-width:37.5em){.isHiddenMobile{display:none;}}.petiteCaps{font-variant:petite-caps;}.flexCenter{display:flex;align-content:center;align-items:center;}.noBottomMargin{margin-bottom:0 !important;}.isNoWrap{white-space:nowrap;}.isFinger{cursor:pointer;}.neomorph{box-shadow:-8px -8px 16px rgba(251,238,208,.5),8px 8px 16px rgba(241,185,65,.5);}.neomorphSmall{box-shadow:-6px -6px 12px rgba(251,238,208,.5),6px 6px 12px rgba(241,185,65,.5);}.neomorphXSmall{box-shadow:-3px -3px 6px rgba(251,238,208,.5),3px 3px 6px rgba(241,185,65,.5);}.neomorphBottom{filter:drop-shadow(8px 8px 14px #f1b941);}.neomorphInset{box-shadow:inset 8px 8px 16px rgba(241,185,65,.5),inset -8px -8px 16px rgba(251,238,208,.5);}.neomorphInsetSmall{box-shadow:inset 6px 6px 12px rgba(241,185,65,.5),inset -6px -6px 12px rgba(251,238,208,.5);}.neomorphInsetXSmall{box-shadow:inset 3px 3px 6px rgba(241,185,65,.5),inset -3px -3px 6px rgba(251,238,208,.5);}.neoBtn{box-shadow:-3px -3px 6px rgba(251,238,208,.5),3px 3px 6px rgba(241,185,65,.5);background:none !important;border:none !important;transition:all .2s linear;-webkit-backface-visibility:hidden;backface-visibility:hidden;}.neoBtn:focus{box-shadow:-3px -3px 6px rgba(251,238,208,.5),3px 3px 6px rgba(241,185,65,.5) !important;}.neoBtn:hover{box-shadow:-6px -6px 12px rgba(251,238,208,.5),6px 6px 12px rgba(241,185,65,.5);background:none !important;border:none !important;transform:scale(1.1);}.neoFile{box-shadow:0 0 0 rgba(251,238,208,.5),0 0 0 rgba(241,185,65,.5) !important;transition:all .2s linear;-webkit-backface-visibility:hidden !important;backface-visibility:hidden !important;background:#f6d287 !important;}.neoFile:hover{box-shadow:-3px -3px 6px rgba(251,238,208,.5),3px 3px 6px rgba(241,185,65,.5) !important;}.neoFile.isSelected{box-shadow:inset 3px 3px 6px rgba(241,185,65,.5),inset -3px -3px 6px rgba(251,238,208,.5) !important;}.neoFile.is-active,.neoFile.active{box-shadow:inset 3px 3px 6px rgba(241,185,65,.5),inset -3px -3px 6px rgba(251,238,208,.5) !important;color:#181515 !important;}.neoInput{box-shadow:inset 2px 2px 4px rgba(241,185,65,.5),inset -2px -2px 4px rgba(251,238,208,.5) !important;background:#f6d287 !important;border:none !important;}.neoInput:focus{border:none !important;}.gradientBackground{background:linear-gradient(to right bottom,#f7d794,#f5cd79);}.borderR{border-radius:14px;}.borderRSmall{border-radius:7px !important;}.borderRBig{border-radius:28px;}.bg{background:#f6d287;}.sameMarginBottom{margin-bottom:1rem !important;}.ellipsis{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}@font-face{font-family:'Ubuntu';src:url(/fonts/ubuntu-light-webfont.woff2) format("woff2");font-weight:300;font-style:normal;}@font-face{font-family:'Ubuntu-Mono';src:url(/fonts/ubuntumono-regular-webfont.woff2) format("woff2");font-style:normal;}html{font-family:Ubuntu,sans-serif;}.menu-list li a{font-family:Ubuntu-Mono,'Noto Mono';}#editor{position:absolute;top:0;right:0;bottom:0;left:0;}.select:not(.is-multiple):not(.is-loading)::after{border-color:#f1b941;}.select:not(.is-multiple):not(.is-loading):hover::after{border-color:#be860e;}.ace-solarized-light{background:#f6d287;}.ace-solarized-light .ace_gutter{background:#f5cd79;}.ace-solarized-light .ace_gutter-active-line{border-radius:50px 0 0 50px;}.ace-solarized-light .ace_marker-layer .ace_active-line{border-radius:0 50px 50px 0;}:root{--stripe-size:200px;--color1:#f6d287;--color2:#f1b941;--duration:10s;}.stripe{position:relative;display:flex;justify-content:center;align-items:center;justify-items:center;width:100%;height:100%;overflow:hidden;}.stripe_inner{position:relative;display:flex;justify-content:center;align-items:center;width:100%;height:100%;font-size:8rem;text-align:center;font-family:'Anton',sans-serif;color:rgba(255,255,255,0);background:repeating-linear-gradient(45deg,var(--color1) 25%,var(--color1) 50%,var(--color2) 50%,var(--color2) 75%);background-size:var(--stripe-size) var(--stripe-size);background-clip:text;animation:stripeBackgroundPosition var(--duration) linear infinite;}.stripe::before{content:'';position:absolute;top:0;left:0;width:calc(100% + var(--stripe-size));height:100%;background:repeating-linear-gradient(45deg,var(--color2) 25%,var(--color2) 50%,var(--color1) 50%,var(--color1) 75%);background-size:var(--stripe-size) var(--stripe-size);animation:stripeTransform var(--duration) linear infinite;}.stripe::after{content:'';position:absolute;width:100%;height:100%;}@keyframes stripeTransform{0%{transform:translateX(0);}100%{transform:translateX(calc(var(--stripe-size)*-1));}}@keyframes stripeBackgroundPosition{0%{background-position:0 0;}100%{background-position:calc(var(--stripe-size)*-1) 0;}}.main{display:flex;flex-wrap:nowrap;align-items:start;width:100%;height:100vh;padding:2.5%;}.mainNav{overflow-y:auto;padding:14px;width:17%;margin-right:40px;}.mainPage{overflow-y:auto;padding:28px;width:calc(83% - 40px);align-self:stretch;}.filesWithEditor{display:grid;grid-template-areas:"filterFiles fileTitle" "files codeEditor" "filesActions editorActions";grid-gap:25px;height:100%;max-height:100%;min-height:10%;grid-template-rows:30px auto 30px;grid-template-columns:30% auto;width:100%;}.filesWithEditor .filterFiles{grid-area:filterFiles;}.filesWithEditor .fileTitle{grid-area:fileTitle;}.filesWithEditor .fileTitle .field,.filesWithEditor .fileTitle .control{height:100%;}.filesWithEditor .files{grid-area:files;display:block;min-height:10%;padding:4% 0;}.filesWithEditor .files .confFile{padding:4% 6%;margin-bottom:3%;}.filesWithEditor .filesList{display:flex;flex-direction:column;align-items:stretch;height:100%;min-height:10%;width:100%;padding:4% 8%;overflow-y:auto;}.filesWithEditor .codeEditor{grid-area:codeEditor;min-height:0;height:100%;position:relative;display:flex;justify-content:center;align-items:center;}.filesWithEditor .codeEditor .editor{height:100%;margin:0;width:100%;}.filesWithEditor .filesActions{grid-area:filesActions;}.filesWithEditor .editorActions{grid-area:editorActions;}.menu-list>li>.neoFile{margin-bottom:4%;} \ No newline at end of file +#blazor-error-ui{background:#ffffe0;bottom:0;box-shadow:0 -1px 2px rgba(0,0,0,.2);display:none;left:0;padding:.6rem 1.25rem .7rem 1.25rem;position:fixed;width:100%;z-index:1000;}#blazor-error-ui .dismiss{cursor:pointer;position:absolute;right:.75rem;top:.5rem;}button::-moz-focus-inner,input::-moz-focus-inner{border:0;}html{scrollbar-color:#f1b941 #fbeed0;scrollbar-width:thin;scrollbar-arrow-color:#fbeed0;scrollbar-base-color:#f6d287;scrollbar-darkshadow-color:#f1b941;}*{scrollbar-width:inherit;}.isHidden{display:none;}@media only screen and (max-width:37.5em){.isHiddenMobile{display:none;}}.petiteCaps{font-variant:petite-caps;}.flexCenter{display:flex;align-content:center;align-items:center;}.noBottomMargin{margin-bottom:0 !important;}.isNoWrap{white-space:nowrap;}.isFinger{cursor:pointer;}.neomorph{box-shadow:-8px -8px 16px rgba(251,238,208,.5),8px 8px 16px rgba(241,185,65,.5);}.neomorphSmall{box-shadow:-6px -6px 12px rgba(251,238,208,.5),6px 6px 12px rgba(241,185,65,.5);}.neomorphXSmall{box-shadow:-3px -3px 6px rgba(251,238,208,.5),3px 3px 6px rgba(241,185,65,.5);}.neomorphBottom{filter:drop-shadow(8px 8px 14px #f1b941);}.neomorphInset{box-shadow:inset 8px 8px 16px rgba(241,185,65,.5),inset -8px -8px 16px rgba(251,238,208,.5);}.neomorphInsetSmall{box-shadow:inset 6px 6px 12px rgba(241,185,65,.5),inset -6px -6px 12px rgba(251,238,208,.5);}.neomorphInsetXSmall{box-shadow:inset 3px 3px 6px rgba(241,185,65,.5),inset -3px -3px 6px rgba(251,238,208,.5);}.neoBtn{box-shadow:-3px -3px 6px rgba(251,238,208,.5),3px 3px 6px rgba(241,185,65,.5);background:none !important;border:none !important;transition:all .2s linear;-webkit-backface-visibility:hidden;backface-visibility:hidden;}.neoBtn:focus{box-shadow:-3px -3px 6px rgba(251,238,208,.5),3px 3px 6px rgba(241,185,65,.5) !important;}.neoBtn:hover{box-shadow:-6px -6px 12px rgba(251,238,208,.5),6px 6px 12px rgba(241,185,65,.5);background:none !important;border:none !important;transform:scale(1.1);}.neoBtnSmall{box-shadow:-2px -2px 4px rgba(251,238,208,.5),2px 2px 4px rgba(241,185,65,.5);background:none !important;border:none !important;transition:all .2s linear;-webkit-backface-visibility:hidden;backface-visibility:hidden;}.neoBtnSmall:focus{box-shadow:-2px -2px 4px rgba(251,238,208,.5),2px 2px 4px rgba(241,185,65,.5) !important;}.neoBtnSmall:hover{box-shadow:-4px -4px 8px rgba(251,238,208,.5),4px 4px 8px rgba(241,185,65,.5);background:none !important;border:none !important;transform:scale(1.1);}.neoFile{box-shadow:0 0 0 rgba(251,238,208,.5),0 0 0 rgba(241,185,65,.5) !important;transition:all .2s linear;-webkit-backface-visibility:hidden !important;backface-visibility:hidden !important;background:#f6d287 !important;}.neoFile:hover{box-shadow:-3px -3px 6px rgba(251,238,208,.5),3px 3px 6px rgba(241,185,65,.5) !important;}.neoFile.isSelected{box-shadow:inset 3px 3px 6px rgba(241,185,65,.5),inset -3px -3px 6px rgba(251,238,208,.5) !important;}.neoFile.is-active,.neoFile.active{box-shadow:inset 3px 3px 6px rgba(241,185,65,.5),inset -3px -3px 6px rgba(251,238,208,.5) !important;color:#181515 !important;}.neoInput{box-shadow:inset 2px 2px 4px rgba(241,185,65,.5),inset -2px -2px 4px rgba(251,238,208,.5) !important;background:#f6d287 !important;border:none !important;}.neoInput:focus{border:none !important;}.gradientBackground{background:linear-gradient(to right bottom,#f7d794,#f5cd79);}.borderR{border-radius:14px;}.borderRSmall{border-radius:7px !important;}.borderRBig{border-radius:28px;}.bg{background:#f6d287;}.sameMarginBottom{margin-bottom:1rem !important;}.ellipsis{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}@font-face{font-family:'Ubuntu';src:url(/fonts/ubuntu-light-webfont.woff2) format("woff2");font-weight:300;font-style:normal;}@font-face{font-family:'Ubuntu-Mono';src:url(/fonts/ubuntumono-regular-webfont.woff2) format("woff2");font-style:normal;}html{font-family:Ubuntu,sans-serif;}.menu-list li a{font-family:Ubuntu-Mono,'Noto Mono';}#editor{position:absolute;top:0;right:0;bottom:0;left:0;}.select:not(.is-multiple):not(.is-loading)::after{border-color:#f1b941;}.select:not(.is-multiple):not(.is-loading):hover::after{border-color:#be860e;}.ace-solarized-light{background:#f6d287;}.ace-solarized-light .ace_gutter{background:#f5cd79;}.ace-solarized-light .ace_gutter-active-line{border-radius:50px 0 0 50px;}.ace-solarized-light .ace_marker-layer .ace_active-line{border-radius:0 50px 50px 0;}:root{--stripe-size:200px;--color1:#f6d287;--color2:#f1b941;--duration:10s;}.stripe{position:relative;display:flex;justify-content:center;align-items:center;justify-items:center;width:100%;height:100%;overflow:hidden;}.stripe_inner{position:relative;display:flex;justify-content:center;align-items:center;width:100%;height:100%;font-size:8rem;text-align:center;font-family:'Anton',sans-serif;color:rgba(255,255,255,0);background:repeating-linear-gradient(45deg,var(--color1) 25%,var(--color1) 50%,var(--color2) 50%,var(--color2) 75%);background-size:var(--stripe-size) var(--stripe-size);background-clip:text;animation:stripeBackgroundPosition var(--duration) linear infinite;}.stripe::before{content:'';position:absolute;top:0;left:0;width:calc(100% + var(--stripe-size));height:100%;background:repeating-linear-gradient(45deg,var(--color2) 25%,var(--color2) 50%,var(--color1) 50%,var(--color1) 75%);background-size:var(--stripe-size) var(--stripe-size);animation:stripeTransform var(--duration) linear infinite;}.stripe::after{content:'';position:absolute;width:100%;height:100%;}@keyframes stripeTransform{0%{transform:translateX(0);}100%{transform:translateX(calc(var(--stripe-size)*-1));}}@keyframes stripeBackgroundPosition{0%{background-position:0 0;}100%{background-position:calc(var(--stripe-size)*-1) 0;}}.main{display:flex;flex-wrap:nowrap;align-items:start;width:100%;height:100vh;padding:2.5%;}.mainNav{overflow-y:auto;padding:14px;width:17%;margin-right:40px;}.mainPage{overflow-y:auto;padding:28px;width:calc(83% - 40px);align-self:stretch;}.filesWithEditor{display:grid;grid-template-areas:"filterFiles fileTitle" "files codeEditor" "filesActions editorActions";grid-gap:25px;height:100%;max-height:100%;min-height:10%;grid-template-rows:30px auto 30px;grid-template-columns:30% auto;width:100%;}.filesWithEditor .filterFiles{grid-area:filterFiles;}.filesWithEditor .fileTitle{grid-area:fileTitle;}.filesWithEditor .fileTitle .field,.filesWithEditor .fileTitle .control{height:100%;}.filesWithEditor .files{grid-area:files;display:block;min-height:10%;padding:4% 0;}.filesWithEditor .files .confFile{padding:4% 6%;margin-bottom:3%;}.filesWithEditor .filesList{display:flex;flex-direction:column;align-items:stretch;height:100%;min-height:10%;width:100%;padding:4% 8%;overflow-y:auto;}.filesWithEditor .codeEditor{grid-area:codeEditor;min-height:0;height:100%;position:relative;display:flex;justify-content:center;align-items:center;}.filesWithEditor .codeEditor .editor{height:100%;margin:0;width:100%;}.filesWithEditor .filesActions{grid-area:filesActions;}.filesWithEditor .editorActions{grid-area:editorActions;}.menu-list>li>.neoFile{margin-bottom:4%;} \ No newline at end of file