diff options
Diffstat (limited to 'src/SMAPI.Web')
-rw-r--r-- | src/SMAPI.Web/ViewModels/ModCompatibilityModel.cs | 2 | ||||
-rw-r--r-- | src/SMAPI.Web/ViewModels/ModModel.cs | 3 | ||||
-rw-r--r-- | src/SMAPI.Web/Views/Mods/Index.cshtml | 34 | ||||
-rw-r--r-- | src/SMAPI.Web/wwwroot/Content/css/mods.css | 47 | ||||
-rw-r--r-- | src/SMAPI.Web/wwwroot/Content/js/mods.js | 144 |
5 files changed, 199 insertions, 31 deletions
diff --git a/src/SMAPI.Web/ViewModels/ModCompatibilityModel.cs b/src/SMAPI.Web/ViewModels/ModCompatibilityModel.cs index 61756176..85bf1e46 100644 --- a/src/SMAPI.Web/ViewModels/ModCompatibilityModel.cs +++ b/src/SMAPI.Web/ViewModels/ModCompatibilityModel.cs @@ -29,6 +29,8 @@ namespace StardewModdingAPI.Web.ViewModels public ModCompatibilityModel(WikiCompatibilityInfo info) { this.Status = info.Status.ToString(); + this.Status = this.Status.Substring(0, 1).ToLower() + this.Status.Substring(1); + this.Summary = info.Summary; this.BrokeIn = info.BrokeIn; if (info.UnofficialVersion != null) diff --git a/src/SMAPI.Web/ViewModels/ModModel.cs b/src/SMAPI.Web/ViewModels/ModModel.cs index 309ed828..0e7d2076 100644 --- a/src/SMAPI.Web/ViewModels/ModModel.cs +++ b/src/SMAPI.Web/ViewModels/ModModel.cs @@ -40,6 +40,9 @@ namespace StardewModdingAPI.Web.ViewModels /// <summary>A unique identifier for the mod that can be used in an anchor URL.</summary> public string Slug { get; set; } + /// <summary>The sites where the mod can be downloaded.</summary> + public string[] ModPageSites => this.ModPages.Select(p => p.Text).ToArray(); + /********* ** Public methods diff --git a/src/SMAPI.Web/Views/Mods/Index.cshtml b/src/SMAPI.Web/Views/Mods/Index.cshtml index b326fd36..372d6706 100644 --- a/src/SMAPI.Web/Views/Mods/Index.cshtml +++ b/src/SMAPI.Web/Views/Mods/Index.cshtml @@ -4,11 +4,11 @@ ViewData["Title"] = "SMAPI mod compatibility"; } @section Head { - <link rel="stylesheet" href="~/Content/css/mods.css?r=20181021" /> + <link rel="stylesheet" href="~/Content/css/mods.css?r=20181109" /> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.min.js" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/jquery@3.3.1/dist/jquery.min.js" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/tablesorter@2.31.0/dist/js/jquery.tablesorter.combined.min.js" crossorigin="anonymous"></script> - <script src="~/Content/js/mods.js?r=20181021"></script> + <script src="~/Content/js/mods.js?r=20181109"></script> <script> $(function() { var data = @Json.Serialize(Model.Mods, new JsonSerializerSettings { Formatting = Formatting.None }); @@ -29,14 +29,22 @@ </div> <div id="app"> - <div> - <label for="search-box">Search: </label> - <input type="text" id="search-box" v-model="search" v-on:input="applySearch" /> - </div> - <div id="show-fields-option"> - <input type="checkbox" id="show-all-fields" v-model="showAllFields" /> - <label for="show-all-fields">show advanced fields</label> + <div id="options"> + <div> + <label for="search-box">Search: </label> + <input type="text" id="search-box" v-model="search" v-on:input="applyFilters" /> + </div> + <div id="filter-area"> + <input type="checkbox" id="show-advanced" v-model="showAdvanced" /> + <label for="show-advanced">show detailed options</label> + <div id="filters" v-show="showAdvanced"> + <div v-for="(filterGroup, key) in filters"> + {{key}}: <span v-for="filter in filterGroup" v-bind:class="{ active: filter.value }"><input type="checkbox" v-bind:id="filter.id" v-model="filter.value" v-on:change="applyFilters" /> <label v-bind:for="filter.id">{{filter.label}}</label></span> + </div> + </div> + </div> </div> + <div id="mod-count" v-show="showAdvanced">{{visibleCount}} mods shown.</div> <table class="wikitable" id="mod-list"> <thead> <tr> @@ -44,8 +52,8 @@ <th>links</th> <th>author</th> <th>compatibility</th> - <th v-show="showAllFields">broke in</th> - <th v-show="showAllFields">code</th> + <th v-show="showAdvanced">broke in</th> + <th v-show="showAdvanced">code</th> <th> </th> </tr> </thead> @@ -72,8 +80,8 @@ </div> <div v-for="(warning, i) in mod.Warnings">⚠ {{warning}}</div> </td> - <td class="mod-broke-in" v-html="mod.BetaCompatibility ? mod.BetaCompatibility.BrokeIn : mod.Compatibility.BrokeIn" v-show="showAllFields"></td> - <td v-show="showAllFields"> + <td class="mod-broke-in" v-html="mod.BetaCompatibility ? mod.BetaCompatibility.BrokeIn : mod.Compatibility.BrokeIn" v-show="showAdvanced"></td> + <td v-show="showAdvanced"> <span v-if="mod.SourceUrl"><a v-bind:href="mod.SourceUrl">source</a></span> <span v-else class="mod-closed-source">no source</span> </td> diff --git a/src/SMAPI.Web/wwwroot/Content/css/mods.css b/src/SMAPI.Web/wwwroot/Content/css/mods.css index 9f82e3e6..730bfc2e 100644 --- a/src/SMAPI.Web/wwwroot/Content/css/mods.css +++ b/src/SMAPI.Web/wwwroot/Content/css/mods.css @@ -18,7 +18,6 @@ table.wikitable { background-color:#f8f9fa; color:#222; - margin:1em 0; border:1px solid #a2a9b1; border-collapse:collapse } @@ -40,10 +39,40 @@ table.wikitable > caption { font-weight:bold } -#show-fields-option { +#options { + margin-bottom: 1em; +} + +#options #filter-area { opacity: 0.7; } +#options #filters { + margin-left: 2em; + padding-left: 0.5em; + border-left: 2px solid gray; +} + +#options #filters span { + padding: 2px; + margin: 2px; + display: inline-block; + border-radius: 3px; + color: #000; + border-color: #880000; + background-color: #fcc; + font-size: 0.9em; +} + +#options #filters span.active { + background: #cfc; +} + +#mod-count { + font-size: 0.8em; + opacity: 0.5; +} + #mod-list { font-size: 0.9em; } @@ -79,22 +108,22 @@ table.wikitable > caption { display: block; } -#mod-list tr[data-status="Ok"], -#mod-list tr[data-status="Optional"] { +#mod-list tr[data-status="ok"], +#mod-list tr[data-status="optional"] { background: #BFB; } -#mod-list tr[data-status="Workaround"], -#mod-list tr[data-status="Unofficial"] { +#mod-list tr[data-status="workaround"], +#mod-list tr[data-status="unofficial"] { background: #FFFEC6; } -#mod-list tr[data-status="Broken"] { +#mod-list tr[data-status="broken"] { background: #FBB; } -#mod-list tr[data-status="Obsolete"], -#mod-list tr[data-status="Abandoned"] { +#mod-list tr[data-status="obsolete"], +#mod-list tr[data-status="abandoned"] { background: #BBB; opacity: 0.7; } diff --git a/src/SMAPI.Web/wwwroot/Content/js/mods.js b/src/SMAPI.Web/wwwroot/Content/js/mods.js index 1af53906..2cff551f 100644 --- a/src/SMAPI.Web/wwwroot/Content/js/mods.js +++ b/src/SMAPI.Web/wwwroot/Content/js/mods.js @@ -6,7 +6,76 @@ smapi.modList = function (mods) { // init data var data = { mods: mods, - showAllFields: false, + visibleCount: mods.length, + showAdvanced: false, + filters: { + source: { + open: { + label: "open", + id: "show-open-source", + value: true + }, + closed: { + label: "closed", + id: "show-closed-source", + value: true + } + }, + status: { + ok: { + label: "ok", + id: "show-status-ok", + value: true + }, + optional: { + label: "optional", + id: "show-status-optional", + value: true + }, + unofficial: { + label: "unofficial", + id: "show-status-unofficial", + value: true + }, + workaround: { + label: "workaround", + id: "show-status-workaround", + value: true + }, + broken: { + label: "broken", + id: "show-status-broken", + value: true + }, + abandoned: { + label: "abandoned", + id: "show-status-abandoned", + value: true + }, + obsolete: { + label: "obsolete", + id: "show-status-obsolete", + value: true + } + }, + download: { + chucklefish: { + label: "Chucklefish", + id: "show-chucklefish", + value: true + }, + nexus: { + label: "Nexus", + id: "show-nexus", + value: true + }, + custom: { + label: "custom", + id: "show-custom", + value: true + } + } + }, search: "" }; for (var i = 0; i < data.mods.length; i++) { @@ -54,25 +123,82 @@ smapi.modList = function (mods) { }, methods: { /** - * Update the visibility of all mods based on the current search text. + * Update the visibility of all mods based on the current search text and filters. */ - applySearch: function () { + applyFilters: function () { // get search terms var words = data.search.toLowerCase().split(" "); - // make sure all words match + // apply criteria + data.visibleCount = data.mods.length; for (var i = 0; i < data.mods.length; i++) { var mod = data.mods[i]; - var match = true; - for (var w = 0; w < words.length; w++) { - if (mod.SearchableText.indexOf(words[w]) === -1) { - match = false; + mod.Visible = true; + + // check filters + if (!this.matchesFilters(mod)) { + mod.Visible = false; + data.visibleCount--; + continue; + } + + // check search terms (all search words should match) + if (words.length) { + for (var w = 0; w < words.length; w++) { + if (mod.SearchableText.indexOf(words[w]) === -1) { + mod.Visible = false; + data.visibleCount--; + break; + } + } + } + } + }, + + + /** + * Get whether a mod matches the current filters. + * @param {object} mod The mod to check. + * @returns {bool} Whether the mod matches the filters. + */ + matchesFilters: function(mod) { + var filters = data.filters; + + // check source + if (!filters.source.open.value && mod.SourceUrl) + return false; + if (!filters.source.closed.value && !mod.SourceUrl) + return false; + + // check status + var status = (mod.BetaCompatibility || mod.Compatibility).Status; + if (filters.status[status] && !filters.status[status].value) + return false; + + // check download sites + var ignoreSites = []; + + if (!filters.download.chucklefish.value) + ignoreSites.push("Chucklefish"); + if (!filters.download.nexus.value) + ignoreSites.push("Nexus"); + if (!filters.download.custom.value) + ignoreSites.push("custom"); + + if (ignoreSites.length) { + var anyLeft = false; + for (var i = 0; i < mod.ModPageSites.length; i++) { + if (ignoreSites.indexOf(mod.ModPageSites[i]) === -1) { + anyLeft = true; break; } } - mod.Visible = match; + if (!anyLeft) + return false; } + + return true; } } }); |