1
0

[WIP] Rework design (#34)

* WIP: Redesign the default layout

* Merge old & new default layouts

* Fix login logic; add proper user controls dropdown

* Fix latest version listing (#31) (#32)

Co-authored-by: Aeledfyr <45501007+Aeledfyr@users.noreply.github.com>

* First pass of design cleanup

* Improve ad integration and fix light theme

* Begin splitting up variables, change some styling to new mockup

* Continue redesign progress

* Work on some more pages

* Add missing dark theme variables for text

* Continue working on modularizing

* Continue progress, redo pagination

* Fix auth buttons in navbar layout

* Continue progress

* Continue progress more

* Redo ModResult

* Scope ModPage :irritater:

* Continue Dashboard

* Continue progress on Dashboard and cleanup

* Add missing variables for dark theme

* Small tweaks, cleanup, and continue mod page progress

* Fix user not being able to see hidden mods that they own

* Start reworking mod creation

* Continue revamp of mod creation page

* Yank v-html out

* Hotfix markdown rendering and some spacing issues

* Move legal; continue with mod creation; create reusable footer

* Create README.md

* Update README.md

* Update README.md

* Add in basic usage instructions

* Fix some stuff

* Continue with mod creation; fix some CSS errors

* Start user page

* Start transition to vue-select; fix a few bugs

* Continue mod creation page

* Finish mod pages

* Add very raw version editing

* Mod editing + creation

* Fixed versions that were in processing causing a 404 (#39)

Co-authored-by: Mikhail Oleynikov <falseresync@gmail.com>
Co-authored-by: Aeledfyr <45501007+Aeledfyr@users.noreply.github.com>
Co-authored-by: Jai A <jai.a@tuta.io>
Co-authored-by: MulverineX <mulverin3@gmail.com>
Co-authored-by: diabolical17 <calumproh28@gmail.com>
Co-authored-by: Geometrically <18202329+Geometrically@users.noreply.github.com>
This commit is contained in:
Prospector
2020-11-30 13:55:01 -08:00
committed by GitHub
parent e025df0824
commit 7b84d8c3d5
70 changed files with 10339 additions and 3284 deletions
+356 -399
View File
@@ -1,276 +1,294 @@
<template>
<div class="columns">
<div class="content column-grow-5">
<h2>Mods</h2>
<section class="search-bar">
<div class="iconified-input column-grow-2">
<label class="hidden" for="search">Search Mods</label>
<input
id="search"
v-model="query"
type="search"
name="search"
placeholder="Search mods"
@input="onSearchChange(1)"
<div class="page-container">
<div class="page-contents">
<div class="content">
<section class="search-nav">
<div class="iconified-input column-grow-2">
<label class="hidden" for="search">Search Mods</label>
<input
id="search"
v-model="query"
type="search"
name="search"
placeholder="Search..."
autocomplete="off"
@input="onSearchChange(1)"
/>
<SearchIcon />
</div>
<div class="sort-paginate">
<div class="labeled-control">
<h3>Sort By</h3>
<Multiselect
v-model="sortType"
class="sort-types"
placeholder="Select one"
track-by="display"
label="display"
:options="sortTypes"
:searchable="false"
:close-on-select="true"
:show-labels="false"
:allow-empty="false"
@input="onSearchChange(1)"
>
<template slot="singleLabel" slot-scope="{ option }">{{
option.display
}}</template>
</Multiselect>
</div>
<div class="labeled-control per-page">
<h3>Per Page</h3>
<Multiselect
v-model="maxResults"
class="max-results"
placeholder="Select one"
:options="[5, 10, 15, 20, 50, 100]"
:searchable="false"
:close-on-select="true"
:show-labels="false"
:allow-empty="false"
@input="onSearchChange(currentPage)"
>
</Multiselect>
</div>
<div class="mobile-filters-button">
<button @click="toggleFiltersMenu">Filter</button>
</div>
</div>
<pagination
:current-page="currentPage"
:pages="pages"
@switch-page="onSearchChange"
></pagination>
</section>
<div class="results column-grow-4">
<client-only>
<EthicalAd type="text" />
</client-only>
<SearchResult
v-for="(result, index) in results"
:id="result.mod_id.split('-')[1]"
:key="result.mod_id"
:author="result.author"
:name="result.title"
:description="result.description"
:latest-version="result.latest_version"
:created-at="result.date_created"
:updated-at="result.date_modified"
:downloads="result.downloads.toString()"
:icon-url="result.icon_url"
:author-url="result.author_url"
:page-url="result.page_url"
:categories="result.categories"
:is-ad="index === -1"
:is-modrinth="result.host === 'modrinth'"
/>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<circle cx="11" cy="11" r="8" />
<line x1="21" y1="21" x2="16.65" y2="16.65" />
</svg>
</div>
<div class="sort-paginate">
<Multiselect
v-model="sortType"
class="sort-types"
placeholder="Select one"
track-by="display"
label="display"
:options="sortTypes"
:searchable="false"
:close-on-select="true"
:show-labels="false"
:allow-empty="false"
@input="onSearchChange(1)"
>
<template slot="singleLabel" slot-scope="{ option }">{{
option.display
}}</template>
</Multiselect>
<div class="mobile-filters-button">
<button @click="toggleFiltersMenu">Filter...</button>
<div v-if="results.length === 0" class="no-results">
<p>No results found for your query!</p>
</div>
</div>
<pagination
:current-page="currentPage"
:pages="pages"
@switch-page="onSearchChange"
></pagination>
</section>
<div class="results column-grow-4">
<client-only>
<EthicalAd type="text" />
</client-only>
<SearchResult
v-for="(result, index) in results"
:id="result.mod_id"
:key="result.mod_id"
:author="result.author"
:name="result.title"
:description="result.description"
:latest-version="result.latest_version"
:created-at="result.date_created"
:updated-at="result.date_modified"
:downloads="result.downloads.toString()"
:icon-url="result.icon_url"
:author-url="result.author_url"
:page-url="result.page_url"
:categories="result.categories"
:is-ad="index === -1"
/>
<div v-if="results.length === 0" class="no-results">
<p>No results found for your query!</p>
</div>
<section v-if="pages.length > 1" class="search-bottom">
<div class="labeled-control">
<h3>Per Page</h3>
<Multiselect
v-model="maxResults"
class="max-results"
placeholder="Select one"
:options="[5, 10, 15, 20, 50, 100]"
:searchable="false"
:close-on-select="true"
:show-labels="false"
:allow-empty="false"
@input="onSearchChange(currentPage)"
>
</Multiselect>
</div>
<pagination
:current-page="currentPage"
:pages="pages"
@switch-page="onSearchChangeToTop"
></pagination>
</section>
</div>
<section v-if="pages.length > 1" class="search-bottom">
<Multiselect
v-model="maxResults"
class="max-results"
placeholder="Select one"
:options="[5, 10, 15, 20, 50, 100]"
:searchable="false"
:close-on-select="true"
:show-labels="false"
:allow-empty="false"
@input="onSearchChange(currentPage)"
>
</Multiselect>
<pagination
:current-page="currentPage"
:pages="pages"
@switch-page="onSearchChangeToTop"
></pagination>
<section id="filters" class="filters">
<div class="filters-wrapper">
<section class="filter-group">
<button class="filter-button-done" @click="toggleFiltersMenu">
Done
</button>
<button @click="clearFilters">Reset filters</button>
<h3>Categories</h3>
<SearchFilter
:active-filters="facets"
display-name="Technology"
facet-name="categories:technology"
@toggle="toggleFacet"
>
<TechCategory />
</SearchFilter>
<SearchFilter
:active-filters="facets"
display-name="Adventure"
facet-name="categories:adventure"
@toggle="toggleFacet"
>
<AdventureCategory />
</SearchFilter>
<SearchFilter
:active-filters="facets"
display-name="Magic"
facet-name="categories:magic"
@toggle="toggleFacet"
>
<MagicCategory />
</SearchFilter>
<SearchFilter
:active-filters="facets"
display-name="Utility"
facet-name="categories:utility"
@toggle="toggleFacet"
>
<UtilityCategory />
</SearchFilter>
<SearchFilter
:active-filters="facets"
display-name="Decoration"
facet-name="categories:decoration"
@toggle="toggleFacet"
>
<DecorationCategory />
</SearchFilter>
<SearchFilter
:active-filters="facets"
display-name="Library"
facet-name="categories:library"
@toggle="toggleFacet"
>
<LibraryCategory />
</SearchFilter>
<SearchFilter
:active-filters="facets"
display-name="Cursed"
facet-name="categories:cursed"
@toggle="toggleFacet"
>
<CursedCategory />
</SearchFilter>
<SearchFilter
:active-filters="facets"
display-name="World Generation"
facet-name="categories:worldgen"
@toggle="toggleFacet"
>
<WorldGenCategory />
</SearchFilter>
<SearchFilter
:active-filters="facets"
display-name="Storage"
facet-name="categories:storage"
@toggle="toggleFacet"
>
<StorageCategory />
</SearchFilter>
<SearchFilter
:active-filters="facets"
display-name="Food"
facet-name="categories:food"
@toggle="toggleFacet"
>
<FoodCategory />
</SearchFilter>
<SearchFilter
:active-filters="facets"
display-name="Equipment"
facet-name="categories:equipment"
@toggle="toggleFacet"
>
<EquipmentCategory />
</SearchFilter>
<SearchFilter
:active-filters="facets"
display-name="Miscellaneous"
facet-name="categories:misc"
@toggle="toggleFacet"
>
<MiscCategory />
</SearchFilter>
<h3>Mod Loaders</h3>
<SearchFilter
:active-filters="facets"
display-name="Fabric"
facet-name="categories:fabric"
@toggle="toggleFacet"
>
<FabricLoader />
</SearchFilter>
<SearchFilter
:active-filters="facets"
display-name="Forge"
facet-name="categories:forge"
@toggle="toggleFacet"
>
<ForgeLoader />
</SearchFilter>
<h3>Host</h3>
<SearchFilter
:active-filters="facets"
display-name="Modrinth"
facet-name="host:modrinth"
@toggle="toggleFacet"
>
<Modrinth />
</SearchFilter>
<SearchFilter
:active-filters="facets"
display-name="CurseForge"
facet-name="host:curseforge"
@toggle="toggleFacet"
>
<FlameAnvil />
</SearchFilter>
<h3>Versions</h3>
<SearchFilter
:active-filters="showVersions"
display-name="Include snapshots"
facet-name="snapshots"
style="margin-bottom: 10px"
@toggle="fillInitialVersions"
/>
</section>
<multiselect
v-model="selectedVersions"
:options="versions"
:loading="versions.length === 0"
:multiple="true"
:searchable="true"
:show-no-results="false"
:close-on-select="false"
:clear-on-select="false"
:show-labels="false"
:limit="6"
:hide-selected="true"
placeholder="Choose versions..."
@input="onSearchChange(1)"
></multiselect>
</div>
<m-footer class="footer" />
</section>
</div>
<section id="filters" class="filters">
<div class="filters-wrapper">
<section class="filter-group">
<button class="filter-button-done" @click="toggleFiltersMenu">
Done
</button>
<button @click="clearFilters">Clear Filters</button>
<h3>Categories</h3>
<SearchFilter
:active-filters="facets"
display-name="Technology"
facet-name="categories:technology"
@toggle="toggleFacet"
>
<TechCategory />
</SearchFilter>
<SearchFilter
:active-filters="facets"
display-name="Adventure"
facet-name="categories:adventure"
@toggle="toggleFacet"
>
<AdventureCategory />
</SearchFilter>
<SearchFilter
:active-filters="facets"
display-name="Magic"
facet-name="categories:magic"
@toggle="toggleFacet"
>
<MagicCategory />
</SearchFilter>
<SearchFilter
:active-filters="facets"
display-name="Utility"
facet-name="categories:utility"
@toggle="toggleFacet"
>
<UtilityCategory />
</SearchFilter>
<SearchFilter
:active-filters="facets"
display-name="Decoration"
facet-name="categories:decoration"
@toggle="toggleFacet"
>
<DecorationCategory />
</SearchFilter>
<SearchFilter
:active-filters="facets"
display-name="Library"
facet-name="categories:library"
@toggle="toggleFacet"
>
<LibraryCategory />
</SearchFilter>
<SearchFilter
:active-filters="facets"
display-name="Cursed"
facet-name="categories:cursed"
@toggle="toggleFacet"
>
<CursedCategory />
</SearchFilter>
<SearchFilter
:active-filters="facets"
display-name="Worldgen"
facet-name="categories:worldgen"
@toggle="toggleFacet"
>
<WorldGenCategory />
</SearchFilter>
<SearchFilter
:active-filters="facets"
display-name="Storage"
facet-name="categories:storage"
@toggle="toggleFacet"
>
<StorageCategory />
</SearchFilter>
<SearchFilter
:active-filters="facets"
display-name="Food"
facet-name="categories:food"
@toggle="toggleFacet"
>
<FoodCategory />
</SearchFilter>
<SearchFilter
:active-filters="facets"
display-name="Equipment"
facet-name="categories:equipment"
@toggle="toggleFacet"
>
<EquipmentCategory />
</SearchFilter>
<SearchFilter
:active-filters="facets"
display-name="Misc"
facet-name="categories:misc"
@toggle="toggleFacet"
>
<MiscCategory />
</SearchFilter>
<h3>Loaders</h3>
<SearchFilter
:active-filters="facets"
display-name="Forge"
facet-name="categories:forge"
@toggle="toggleFacet"
>
<ForgeLoader />
</SearchFilter>
<SearchFilter
:active-filters="facets"
display-name="Fabric"
facet-name="categories:fabric"
@toggle="toggleFacet"
>
<FabricLoader />
</SearchFilter>
<h3>Platforms</h3>
<SearchFilter
:active-filters="facets"
display-name="Modrinth"
facet-name="host:modrinth"
@toggle="toggleFacet"
>
</SearchFilter>
<SearchFilter
:active-filters="facets"
display-name="Curseforge"
facet-name="host:curseforge"
@toggle="toggleFacet"
>
</SearchFilter>
<h3>Versions</h3>
<SearchFilter
:active-filters="showVersions"
display-name="Snapshots"
facet-name="snapshots"
style="margin-bottom: 10px"
@toggle="fillInitialVersions"
/>
</section>
<multiselect
v-model="selectedVersions"
:options="versions"
:loading="versions.length === 0"
:multiple="true"
:searchable="true"
:show-no-results="false"
:close-on-select="false"
:clear-on-select="false"
:show-labels="false"
:limit="6"
:hide-selected="true"
placeholder="Choose versions..."
@input="onSearchChange(1)"
></multiselect>
</div>
</section>
</div>
</template>
<script>
import Multiselect from 'vue-multiselect'
import axios from 'axios'
import SearchResult from '@/components/ModResult'
import SearchResult from '@/components/ProjectCard'
import Pagination from '@/components/Pagination'
import SearchFilter from '@/components/SearchFilter'
import EthicalAd from '@/components/EthicalAd'
import MFooter from '@/components/MFooter'
import TechCategory from '~/assets/images/categories/tech.svg?inline'
import AdventureCategory from '~/assets/images/categories/adventure.svg?inline'
import CursedCategory from '~/assets/images/categories/cursed.svg?inline'
@@ -287,9 +305,15 @@ import WorldGenCategory from '~/assets/images/categories/worldgen.svg?inline'
import ForgeLoader from '~/assets/images/categories/forge.svg?inline'
import FabricLoader from '~/assets/images/categories/fabric.svg?inline'
import Modrinth from '~/assets/images/categories/modrinth.svg?inline'
import FlameAnvil from '~/assets/images/categories/flameanvil.svg?inline'
import SearchIcon from '~/assets/images/utils/search.svg?inline'
export default {
auth: false,
components: {
MFooter,
EthicalAd,
SearchResult,
Pagination,
@@ -309,6 +333,9 @@ export default {
WorldGenCategory,
ForgeLoader,
FabricLoader,
Modrinth,
FlameAnvil,
SearchIcon,
},
async fetch() {
if (this.$route.query.q) this.query = this.$route.query.q
@@ -345,12 +372,12 @@ export default {
currentPage: 1,
sortTypes: [
{ display: 'Relevance', name: 'relevance' },
{ display: 'Total Downloads', name: 'downloads' },
{ display: 'Newest', name: 'newest' },
{ display: 'Updated', name: 'updated' },
{ display: 'Download count', name: 'downloads' },
{ display: 'Recently created', name: 'newest' },
{ display: 'Recently updated', name: 'updated' },
],
sortType: { display: 'Relevance', name: 'relevance' },
maxResults: 5,
maxResults: 20,
}
},
methods: {
@@ -482,7 +509,7 @@ export default {
url += `&v=${encodeURIComponent(this.selectedVersions)}`
if (this.sortType.name !== 'relevance')
url += `&s=${encodeURIComponent(this.sortType.name)}`
if (this.maxResults > 5)
if (this.maxResults > 20)
url += `&m=${encodeURIComponent(this.maxResults)}`
window.history.pushState(new Date(), 'Mods', url)
@@ -525,17 +552,32 @@ export default {
<style src="vue-multiselect/dist/vue-multiselect.min.css"></style>
<style lang="scss">
.search-bar {
.search-nav {
align-items: center;
display: flex;
justify-content: space-between;
flex-flow: column;
background: var(--color-raised-bg);
border-radius: var(--size-rounded-card);
padding: 0.25rem 1rem 0.25rem 1rem;
margin-bottom: var(--spacing-card-md);
input {
border: none;
background: transparent;
min-width: 200px;
}
.iconified-input {
width: 100%;
}
.sort-paginate {
margin-left: 0.5rem;
margin-right: 0.5rem;
display: flex;
width: 100%;
.per-page {
margin-left: 0.5rem;
display: none;
}
}
@media screen and (min-width: 900px) {
flex-flow: row;
@@ -543,34 +585,45 @@ export default {
width: auto;
}
.sort-paginate {
display: block;
width: auto;
}
}
@media screen and (min-width: 1024px) {
.sort-paginate {
.per-page {
display: unset;
}
}
}
}
.search-bottom {
align-items: center;
display: flex;
justify-content: flex-end;
background: var(--color-raised-bg);
border-radius: var(--size-rounded-card);
padding: 0.25rem 1rem 0.25rem 1rem;
select {
width: 100px;
margin-right: 20px;
}
}
.content {
min-height: 96vh;
.labeled-control {
h3 {
@extend %small-label;
margin-left: 0.5rem;
}
}
.mobile-filters-button {
display: inline-block;
button {
background: var(--color-bg);
color: var(--color-text);
border: 2px solid var(--color-grey-3);
border-radius: var(--size-rounded-sm);
padding: 0.5rem;
margin-top: 0;
height: 2.5rem;
padding-left: 1rem;
padding-right: 1rem;
}
// Hide button on larger screens where it's not needed
@@ -581,48 +634,47 @@ export default {
.filters {
overflow-y: auto;
background-color: var(--color-bg);
border-left: 1px solid var(--color-grey-2);
position: fixed;
width: 100vw;
right: -100vw;
max-height: 100vh;
min-width: 15%;
top: 3.5rem;
height: calc(100vh - 3.5rem);
top: var(--size-navbar-height);
height: calc(100vh - var(--size-navbar-height));
transition: right 150ms;
background-color: var(--color-raised-bg);
flex-shrink: 0; // Stop shrinking when page contents change
.filters-wrapper {
padding: 0 0.75rem;
padding: 0.25rem 0.75rem 0.75rem 0.75rem;
}
h3 {
color: #718096;
font-size: 0.8rem;
letter-spacing: 0.02rem;
margin-bottom: 0.5rem;
margin-top: 1.5rem;
text-transform: uppercase;
@extend %large-label;
margin-top: 1.25em;
}
// Larger screens that don't need to collapse
@media screen and (min-width: 900px) {
position: sticky;
width: 215px;
padding-right: 1rem;
transition: none;
}
// Desktop
@media screen and (min-width: 1145px) {
top: 0;
height: 100vh;
}
&.active {
right: 0;
}
// Larger screens that don't need to collapse
@media screen and (min-width: 900px) {
top: 0;
right: auto;
position: unset;
height: unset;
max-height: unset;
transition: none;
margin-left: var(--spacing-card-lg);
overflow-y: unset;
padding-right: 1rem;
width: 18vw;
background-color: transparent;
.filters-wrapper {
background-color: var(--color-raised-bg);
border-radius: var(--size-rounded-card);
}
}
@media screen and (min-width: 1024px) {
width: 300px;
}
}
.filter-group {
@@ -631,17 +683,6 @@ export default {
button {
cursor: pointer;
width: 100%;
padding: 5px 0;
outline: none;
color: var(--color-grey-5);
background-color: var(--color-grey-1);
border: none;
border-radius: 5px;
&:hover {
background-color: var(--color-grey-2);
color: var(--color-text);
}
}
.filter-button-done {
@@ -654,65 +695,12 @@ export default {
display: none;
}
}
// Desktop
@media screen and (min-width: 1145px) {
margin-top: 2em;
}
}
.iconified-select {
margin-left: 1em;
align-items: center;
display: inline-flex;
flex-direction: row-reverse;
select {
padding-left: 2.5rem;
&:hover {
& + svg {
color: var(--color-grey-6);
}
}
&:focus {
& + svg {
color: var(--color-text);
}
}
}
svg {
color: var(--color-grey-5);
margin-right: -2rem;
width: 24px;
height: 24px;
}
}
select {
width: 220px;
padding: 0.5rem 1rem;
background: var(--color-bg);
border: 2px solid var(--color-grey-3);
border-radius: var(--size-rounded-sm);
color: var(--color-grey-9);
font-size: 1rem;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
&:hover {
border-color: var(--color-grey-4);
color: var(--color-text);
}
}
.sort-types {
min-width: 200px;
border: 2px solid var(--color-grey-3);
border-radius: var(--size-rounded-sm);
border: none;
border-radius: var(--size-rounded-control);
.multiselect__tags {
padding: 10px 50px 0 8px;
@@ -723,45 +711,14 @@ select {
.no-results {
text-align: center;
padding: 20px 0;
font-size: 30px;
font-size: 1.25rem;
color: var(--color-text);
background-color: var(--color-grey-1);
margin-bottom: var(--spacing-card-md);
background: var(--color-raised-bg);
border-radius: var(--size-rounded-card);
}
.max-results {
max-width: 80px;
}
.multiselect__content-wrapper {
overflow-x: hidden;
}
.multiselect__tags {
border: 2px solid var(--color-grey-3);
border-radius: var(--size-rounded-sm);
}
.multiselect__tags,
.multiselect__spinner {
background: var(--color-bg);
cursor: pointer;
}
.multiselect__spinner::before,
.multiselect__spinner::after {
border-top-color: var(--color-brand);
}
.multiselect__option--selected.multiselect__option--highlight,
.multiselect__option,
.multiselect__single,
.multiselect__input {
color: var(--color-text);
background: var(--color-bg);
}
.multiselect__option--highlight,
.multiselect__tag {
background: var(--color-brand);
}
</style>