diff options
Diffstat (limited to 'src/SMAPI.Web/Views')
-rw-r--r-- | src/SMAPI.Web/Views/Index/Index.cshtml | 46 | ||||
-rw-r--r-- | src/SMAPI.Web/Views/LogParser/Index.cshtml | 227 | ||||
-rw-r--r-- | src/SMAPI.Web/Views/Shared/_Layout.cshtml | 7 |
3 files changed, 171 insertions, 109 deletions
diff --git a/src/SMAPI.Web/Views/Index/Index.cshtml b/src/SMAPI.Web/Views/Index/Index.cshtml index 4efb9f8a..361d01de 100644 --- a/src/SMAPI.Web/Views/Index/Index.cshtml +++ b/src/SMAPI.Web/Views/Index/Index.cshtml @@ -3,7 +3,9 @@ } @model StardewModdingAPI.Web.ViewModels.IndexModel @section Head { - <link rel="stylesheet" href="~/Content/css/index.css" /> + <link rel="stylesheet" href="~/Content/css/index.css?r=20180615" /> + <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js" crossorigin="anonymous"></script> + <script src="~/Content/js/index.js?r=20180615"></script> } <p id="blurb"> @@ -13,17 +15,29 @@ </p> <div id="call-to-action"> - <a href="@Model.StableVersion.DownloadUrl" class="main-cta">Download SMAPI @Model.StableVersion.Version</a><br /> + <div class="cta-dropdown"> + <a href="@Model.StableVersion.DownloadUrl" class="main-cta download">Download SMAPI @Model.StableVersion.Version</a><br/> + <div class="dropdown-content"> + <a href="https://www.nexusmods.com/stardewvalley/mods/2400"><img src="Content/images/nexus-icon.png" /> Download from Nexus</a> + <a href="@Model.StableVersion.DownloadUrl"><img src="Content/images/direct-download-icon.png" /> Direct download</a> + </div> + </div><br /> + @if (Model.BetaVersion != null) { - <a href="@Model.BetaVersion.DownloadUrl" class="secondary-cta">Download SMAPI @Model.BetaVersion.Version<br /><small>for Stardew Valley 1.3 beta</small></a><br /> + <div class="cta-dropdown secondary-cta-dropdown"> + <a href="@Model.BetaVersion.DownloadUrl" class="secondary-cta download">Download SMAPI @Model.BetaVersion.Version<br/><small>for Stardew Valley 1.3 beta</small></a><br/> + <div class="dropdown-content"> + <a href="https://www.nexusmods.com/stardewvalley/mods/2400"><img src="Content/images/nexus-icon.png" /> Download from Nexus</a> + <a href="@Model.BetaVersion.DownloadUrl"><img src="Content/images/direct-download-icon.png" /> Direct download</a> + </div> + </div><br /> } - <a href="https://stardewvalleywiki.com/Modding:Installing_SMAPI" class="secondary-cta">Install guide</a><br /> - <a href="https://stardewvalleywiki.com/Modding:Player_FAQs" class="secondary-cta">FAQs</a><br /> - <img src="favicon.ico" /> + <a href="https://stardewvalleywiki.com/Modding:Player_Guide" class="secondary-cta">Player guide</a><br /> + <img id="pufferchick" src="Content/images/pufferchick.png" /> </div> -<h2>Get help</h2> +<h2 id="help">Get help</h2> <ul> <li><a href="https://stardewvalleywiki.com/Modding:SMAPI_compatibility">Mod compatibility list</a></li> <li>Get help <a href="https://stardewvalleywiki.com/Modding:Community#Discord">on Discord</a> or <a href="https://community.playstarbound.com/threads/smapi-stardew-modding-api.108375/">in the forums</a></li> @@ -31,7 +45,7 @@ @if (Model.BetaVersion == null) { - <h2>What's new in SMAPI @Model.StableVersion.Version?</h2> + <h2 id="whatsnew">What's new in SMAPI @Model.StableVersion.Version?</h2> <div class="github-description"> @Html.Raw(Markdig.Markdown.ToHtml(Model.StableVersion.Description)) </div> @@ -39,7 +53,7 @@ } else { - <h2>What's new in...</h2> + <h2 id="whatsnew">What's new in...</h2> <h3>SMAPI @Model.StableVersion.Version?</h3> <div class="github-description"> @Html.Raw(Markdig.Markdown.ToHtml(Model.StableVersion.Description)) @@ -53,7 +67,7 @@ else <p>See the <a href="https://github.com/Pathoschild/SMAPI/blob/develop/docs/release-notes.md#release-notes">release notes</a> and <a href="https://stardewvalleywiki.com/Modding:SMAPI_compatibility">mod compatibility list</a> for more info.</p> } -<h2>Donate to support SMAPI ♥</h2> +<h2 id="donate">Donate to support SMAPI ♥</h2> <p> SMAPI is an open-source project by Pathoschild. It will always be free, but donations are much appreciated to help pay for development, server hosting, domain fees, coffee, etc. @@ -75,15 +89,23 @@ else Special thanks to acerbicon, <a href="https://www.nexusmods.com/stardewvalley/users/31393530">ChefRude</a>, + cheesysteak, + hawkfalcon, jwdred, - OfficialPiAddict, + KNakamura, + Kono Tyran, + Pucklynn, Robby LaFarge, and a few anonymous users for their ongoing support; you're awesome! 🏅 </p> -<h2>For mod creators</h2> +<h2 id="modcreators">For mod creators</h2> <ul> <li><a href="@Model.StableVersion.DevDownloadUrl">SMAPI @Model.StableVersion.Version for developers</a> (includes <a href="https://docs.microsoft.com/en-us/visualstudio/ide/using-intellisense">intellisense</a> and full console output)</li> + @if (Model.BetaVersion != null) + { + <li><a href="@Model.BetaVersion.DevDownloadUrl">SMAPI @Model.BetaVersion.Version for developers</a> (includes <a href="https://docs.microsoft.com/en-us/visualstudio/ide/using-intellisense">intellisense</a> and full console output)</li> + } <li><a href="https://stardewvalleywiki.com/Modding:Index">Modding documentation</a></li> <li>Need help? Come <a href="https://stardewvalleywiki.com/Modding:Community#Discord">chat on Discord</a>.</li> </ul> diff --git a/src/SMAPI.Web/Views/LogParser/Index.cshtml b/src/SMAPI.Web/Views/LogParser/Index.cshtml index 2d1c1b44..e735e8f3 100644 --- a/src/SMAPI.Web/Views/LogParser/Index.cshtml +++ b/src/SMAPI.Web/Views/LogParser/Index.cshtml @@ -1,76 +1,120 @@ +@using Newtonsoft.Json +@using StardewModdingAPI.Web.Framework.LogParsing.Models +@model StardewModdingAPI.Web.ViewModels.LogParserModel + @{ ViewData["Title"] = "SMAPI log parser"; + IDictionary<string, LogModInfo[]> contentPacks = Model.GetContentPacksByMod(); + IDictionary<string, bool> defaultFilters = Enum + .GetValues(typeof(LogLevel)) + .Cast<LogLevel>() + .ToDictionary(level => level.ToString().ToLower(), level => level != LogLevel.Trace); + JsonSerializerSettings noFormatting = new JsonSerializerSettings { Formatting = Formatting.None }; +} - IDictionary<string, LogModInfo[]> contentPacks = Model.ParsedLog?.Mods - ?.GroupBy(mod => mod.ContentPackFor) - .Where(group => group.Key != null) - .ToDictionary(group => group.Key, group => group.ToArray()); - - Regex slugInvalidCharPattern = new Regex("[^a-z0-9]", RegexOptions.Compiled | RegexOptions.IgnoreCase); - string GetSlug(string modName) +@section Head { + @if (Model.PasteID != null) { - return slugInvalidCharPattern.Replace(modName, ""); + <meta name="robots" content="noindex" /> } -} -@using System.Text.RegularExpressions -@using Newtonsoft.Json -@using StardewModdingAPI.Web.Framework.LogParsing.Models -@model StardewModdingAPI.Web.ViewModels.LogParserModel -@section Head { - <link rel="stylesheet" href="~/Content/css/log-parser.css?r=20180225" /> + <link rel="stylesheet" href="~/Content/css/log-parser.css?r=20180627" /> <script src="https://cdn.jsdelivr.net/npm/vue"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js" crossorigin="anonymous"></script> - <script src="~/Content/js/log-parser.js?r=20180225"></script> + <script src="~/Content/js/log-parser.js?r=20180627"></script> <script> $(function() { smapi.logParser({ logStarted: new Date(@Json.Serialize(Model.ParsedLog?.Timestamp)), showPopup: @Json.Serialize(Model.ParsedLog == null), - showMods: @Json.Serialize(Model.ParsedLog?.Mods?.Select(p => GetSlug(p.Name)).Distinct().ToDictionary(slug => slug, slug => true), new JsonSerializerSettings { Formatting = Formatting.None }), - showLevels: { - trace: false, - debug: false, - info: true, - alert: true, - warn: true, - error: true - } + showMods: @Json.Serialize(Model.ParsedLog?.Mods?.Select(p => Model.GetSlug(p.Name)).Distinct().ToDictionary(slug => slug, slug => true), noFormatting), + showLevels: @Json.Serialize(defaultFilters, noFormatting), + enableFilters: @Json.Serialize(!Model.ShowRaw) }, '@Model.SectionUrl'); }); </script> } -@********* -** Intro -*********@ -<p id="blurb">This page lets you upload, view, and share a SMAPI log to help troubleshoot mod issues.</p> - -@if (Model.ParsedLog?.IsValid == true) +@* upload result banner *@ +@if (Model.UploadError != null) { - <div class="banner success" v-pre> - <strong>The log was uploaded successfully!</strong><br/> - Share this URL when asking for help: <code>@(new Uri(new Uri(Model.SectionUrl), Model.PasteID))</code><br/> - (Or <a id="upload-button" href="#">upload a new log</a>.) + <div class="banner error" v-pre> + <strong>Oops, the server ran into trouble saving that file.</strong><br /> + <small v-pre>Error details: @Model.UploadError</small> </div> } -else if (Model.ParsedLog?.IsValid == false) +else if (Model.ParseError != null) { <div class="banner error" v-pre> - <strong>Oops, couldn't parse that file. (Make sure you upload the log file, not the console text.)</strong><br /> + <strong>Oops, couldn't parse that log. (Make sure you upload the log file, not the console text.)</strong><br /> Share this URL when asking for help: <code>@(new Uri(new Uri(Model.SectionUrl), Model.PasteID))</code><br /> - (Or <a id="upload-button" href="#">upload a new log</a>.)<br /> + (Or <a href="@Model.SectionUrl">upload a new log</a>.)<br /> <br /> - <small v-pre>Error details: @Model.ParsedLog.Error</small> + <small v-pre>Error details: @Model.ParseError</small> </div> } -else +else if (Model.ParsedLog?.IsValid == true) { - <input type="button" id="upload-button" value="Share a new log" /> + <div class="banner success" v-pre> + <strong>Share this link to let someone else see the log:</strong> <code>@(new Uri(new Uri(Model.SectionUrl), Model.PasteID))</code><br /> + (Or <a href="@Model.SectionUrl">upload a new log</a>.) + </div> } -@********* -** Parsed log -*********@ +@* upload new log *@ +@if (Model.ParsedLog == null) +{ + <h2>Where do I find my SMAPI log?</h2> + <div>What system do you use?</div> + <ul id="os-list"> + <li><input type="radio" name="os" value="linux" id="os-linux" /> <label for="os-linux">Linux</label></li> + <li><input type="radio" name="os" value="mac" id="os-mac" /> <label for="os-mac">Mac</label></li> + <li><input type="radio" name="os" value="windows" id="os-windows" /> <label for="os-windows">Windows</label></li> + </ul> + <div data-os="linux"> + On Linux: + <ol> + <li>Open the Files app.</li> + <li>Click the options menu (might be labeled <em>Go</em> or <code>⋮</code>).</li> + <li>Choose <em>Enter Location</em>.</li> + <li>Enter this exact text: <pre>~/.config/StardewValley/ErrorLogs</pre></li> + <li>The log file is <code>SMAPI-crash.txt</code> if it exists, otherwise <code>SMAPI-latest.txt</code>.</li> + </ol> + </div> + <div data-os="mac"> + On Mac: + <ol> + <li>Open the Finder app.</li> + <li>Click <em>Go</em> at the top, then <em>Enter Location</em>.</li> + <li>Enter this exact text: <pre>~/.config/StardewValley/ErrorLogs</pre></li> + <li>The log file is <code>SMAPI-crash.txt</code> if it exists, otherwise <code>SMAPI-latest.txt</code>.</li> + </ol> + </div> + <div data-os="windows"> + On Windows: + <ol> + <li>Press the <code>Windows</code> and <code>R</code> buttons at the same time.</li> + <li>In the 'run' box that appears, enter this exact text: <pre>%appdata%\StardewValley\ErrorLogs</pre></li> + <li>The log file is <code>SMAPI-crash.txt</code> if it exists, otherwise <code>SMAPI-latest.txt</code>.</li> + </ol> + </div> + + <h2>How do I share my log?</h2> + <form action="@Model.SectionUrl" method="post"> + <ol> + <li> + Drag the file onto this textbox (or paste the text in):<br /> + <textarea id="input" name="input" placeholder="paste log here"></textarea> + </li> + <li> + Click this button:<br /> + <input type="submit" id="submit" value="save log" /> + </li> + <li>On the new page, copy the URL and send it to the person helping you.</li> + </ol> + </form> +} + +@* parsed log *@ @if (Model.ParsedLog?.IsValid == true) { <h2>Log info</h2> @@ -95,17 +139,20 @@ else </tr> </table> <br /> - <table id="mods"> + <table id="mods" class="@(Model.ShowRaw ? "filters-disabled" : null)"> <caption> Installed mods: - <span class="notice txt"><i>click any mod to filter</i></span> - <span class="notice btn txt" v-on:click="showAllMods" v-show="stats.modsHidden > 0">show all</span> - <span class="notice btn txt" v-on:click="hideAllMods" v-show="stats.modsShown > 0 && stats.modsHidden > 0">hide all</span> + @if (!Model.ShowRaw) + { + <span class="notice txt"><i>click any mod to filter</i></span> + <span class="notice btn txt" v-on:click="showAllMods" v-show="stats.modsHidden > 0">show all</span> + <span class="notice btn txt" v-on:click="hideAllMods" v-show="stats.modsShown > 0 && stats.modsHidden > 0">hide all</span> + } </caption> @foreach (var mod in Model.ParsedLog.Mods.Where(p => p.ContentPackFor == null)) { - <tr v-on:click="toggleMod('@GetSlug(mod.Name)')" class="mod-entry" v-bind:class="{ hidden: !showMods['@GetSlug(mod.Name)'] }"> - <td><input type="checkbox" v-bind:checked="showMods['@GetSlug(mod.Name)']" v-show="anyModsHidden" /></td> + <tr v-on:click="toggleMod('@Model.GetSlug(mod.Name)')" class="mod-entry" v-bind:class="{ hidden: !showMods['@Model.GetSlug(mod.Name)'] }"> + <td><input type="checkbox" v-bind:checked="showMods['@Model.GetSlug(mod.Name)']" v-show="anyModsHidden" /></td> <td v-pre> <strong>@mod.Name</strong> @mod.Version @if (contentPacks != null && contentPacks.TryGetValue(mod.Name, out LogModInfo[] contentPackList)) @@ -134,36 +181,47 @@ else </tr> } </table> - <div id="filters"> - Filter messages: - <span v-bind:class="{ active: showLevels['trace'] }" v-on:click="toggleLevel('trace')">TRACE</span> | - <span v-bind:class="{ active: showLevels['debug'] }" v-on:click="toggleLevel('debug')">DEBUG</span> | - <span v-bind:class="{ active: showLevels['info'] }" v-on:click="toggleLevel('info')">INFO</span> | - <span v-bind:class="{ active: showLevels['alert'] }" v-on:click="toggleLevel('alert')">ALERT</span> | - <span v-bind:class="{ active: showLevels['warn'] }" v-on:click="toggleLevel('warn')">WARN</span> | - <span v-bind:class="{ active: showLevels['error'] }" v-on:click="toggleLevel('error')">ERROR</span> - </div> - <table id="log"> - @foreach (var message in Model.ParsedLog.Messages) - { - string levelStr = message.Level.ToString().ToLower(); + @if (!Model.ShowRaw) + { + <div id="filters"> + Filter messages: + <span v-bind:class="{ active: showLevels['trace'] }" v-on:click="toggleLevel('trace')">TRACE</span> | + <span v-bind:class="{ active: showLevels['debug'] }" v-on:click="toggleLevel('debug')">DEBUG</span> | + <span v-bind:class="{ active: showLevels['info'] }" v-on:click="toggleLevel('info')">INFO</span> | + <span v-bind:class="{ active: showLevels['alert'] }" v-on:click="toggleLevel('alert')">ALERT</span> | + <span v-bind:class="{ active: showLevels['warn'] }" v-on:click="toggleLevel('warn')">WARN</span> | + <span v-bind:class="{ active: showLevels['error'] }" v-on:click="toggleLevel('error')">ERROR</span> + </div> - <tr class="@levelStr mod" v-show="filtersAllow('@GetSlug(message.Mod)', '@levelStr')"> - <td v-pre>@message.Time</td> - <td v-pre>@message.Level.ToString().ToUpper()</td> - <td v-pre data-title="@message.Mod">@message.Mod</td> - <td v-pre>@message.Text</td> - </tr> - if (message.Repeated > 0) + <table id="log"> + @foreach (var message in Model.ParsedLog.Messages) { - <tr class="@levelStr mod mod-repeat" v-show="filtersAllow('@GetSlug(message.Mod)', '@levelStr')"> - <td colspan="3"></td> - <td v-pre><i>repeats [@message.Repeated] times.</i></td> + string levelStr = message.Level.ToString().ToLower(); + + <tr class="@levelStr mod" v-show="filtersAllow('@Model.GetSlug(message.Mod)', '@levelStr')"> + <td v-pre>@message.Time</td> + <td v-pre>@message.Level.ToString().ToUpper()</td> + <td v-pre data-title="@message.Mod">@message.Mod</td> + <td v-pre>@message.Text</td> </tr> + if (message.Repeated > 0) + { + <tr class="@levelStr mod mod-repeat" v-show="filtersAllow('@Model.GetSlug(message.Mod)', '@levelStr')"> + <td colspan="3"></td> + <td v-pre><i>repeats [@message.Repeated] times.</i></td> + </tr> + } } - } - </table> + </table> + + <small><a href="@(new Uri(new Uri(Model.SectionUrl), Model.PasteID))?raw=true">view raw log</a></small> + } + else + { + <pre v-pre>@Model.ParsedLog.RawText</pre> + <small><a href="@(new Uri(new Uri(Model.SectionUrl), Model.PasteID))">view parsed log</a></small> + } </div> } else if (Model.ParsedLog?.IsValid == false) @@ -171,22 +229,3 @@ else if (Model.ParsedLog?.IsValid == false) <h3>Raw log</h3> <pre v-pre>@Model.ParsedLog.RawText</pre> } - -<div id="upload-area"> - <div id="popup-upload" class="popup"> - <h1>Upload log file</h1> - <div class="frame"> - <ol> - <li><a href="https://stardewvalleywiki.com/Modding:Player_FAQs#SMAPI_log" target="_blank">Find your SMAPI log file</a> (not the console text).</li> - <li>Drag the file onto the textbox below (or paste the text in).</li> - <li>Click <em>Parse</em>.</li> - </ol> - <textarea id="input" placeholder="Paste or drag the log here"></textarea> - <div class="buttons"> - <input type="button" id="submit" value="Parse" /> - <input type="button" id="cancel" value="Cancel" /> - </div> - </div> - </div> - <div id="uploader"></div> -</div> diff --git a/src/SMAPI.Web/Views/Shared/_Layout.cshtml b/src/SMAPI.Web/Views/Shared/_Layout.cshtml index ac98c71b..29da9100 100644 --- a/src/SMAPI.Web/Views/Shared/_Layout.cshtml +++ b/src/SMAPI.Web/Views/Shared/_Layout.cshtml @@ -1,11 +1,12 @@ @using Microsoft.Extensions.Options @using StardewModdingAPI.Web.Framework.ConfigModels -@inject IOptions<ContextConfig> ContextConfig +@inject IOptions<SiteConfig> SiteConfig <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1"> <title>@ViewData["Title"] - SMAPI.io</title> <link rel="stylesheet" href="~/Content/css/main.css" /> @RenderSection("Head", required: false) @@ -14,8 +15,8 @@ <div id="sidebar"> <h4>SMAPI</h4> <ul> - <li><a href="@ContextConfig.Value.RootUrl">About SMAPI</a></li> - <li><a href="@ContextConfig.Value.LogParserUrl">Log parser</a></li> + <li><a href="@SiteConfig.Value.RootUrl">About SMAPI</a></li> + <li><a href="@SiteConfig.Value.LogParserUrl">Log parser</a></li> <li><a href="https://stardewvalleywiki.com/Modding:Index">Docs</a></li> </ul> </div> |