summaryrefslogtreecommitdiff
path: root/src/SMAPI.Web/Views
diff options
context:
space:
mode:
Diffstat (limited to 'src/SMAPI.Web/Views')
-rw-r--r--src/SMAPI.Web/Views/Index/Index.cshtml46
-rw-r--r--src/SMAPI.Web/Views/LogParser/Index.cshtml227
-rw-r--r--src/SMAPI.Web/Views/Shared/_Layout.cshtml7
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>