Add expanding gallery images by clicking on them (#371)

* Random css variable cleanup

* Add an option for developers to temporarily switch between staging and production API

* Added a feature to expand gallery images to view them larger.
This commit is contained in:
Prospector
2022-03-03 20:18:42 -08:00
committed by GitHub
parent 36a8f044ae
commit 6ca40afac0
4 changed files with 238 additions and 18 deletions

View File

@@ -639,7 +639,7 @@ label {
color: var(--color-text);
span::before {
background-color: var(--color-brand-disabled);
background-color: var(--tab-underline-hovered);
}
}

View File

@@ -20,11 +20,9 @@ html {
--color-brand: #30b27b;
--color-brand-hover: #1e9565;
--color-brand-active: #177955;
--color-brand-light: #30b27b;
--color-brand-inverted: #ffffff;
--color-brand-2: #30b27b;
--color-brand-3: #30b27b;
--color-brand-disabled: #e2e8f0;
--tab-underline-hovered: #e2e8f0;
--color-button-bg: #e0e0e5;
--color-button-text: var(--color-text-dark);
@@ -98,11 +96,9 @@ html {
--color-brand: #1bd96a;
--color-brand-hover: #30b366;
--color-brand-active: #55f5ae;
--color-brand-light: #30b27b;
--color-brand-inverted: #000;
--color-brand-2: #30b27b;
--color-brand-3: #30b27b;
--color-brand-disabled: #414146;
--tab-underline-hovered: #414146;
--color-button-bg: #3e434b;
--color-button-text: var(--color-text);

View File

@@ -1,5 +1,50 @@
<template>
<div>
<div
v-if="expandedGalleryItem != null"
class="expanded-image-modal"
@click="expandedGalleryItem = null"
>
<div class="content" @click.stop="">
<button class="close circle-button" @click="expandedGalleryItem = null">
<CrossIcon aria-hidden="true" />
</button>
<img
class="image"
:src="
expandedGalleryItem.url
? expandedGalleryItem.url
: 'https://cdn.modrinth.com/placeholder-banner.svg'
"
:alt="
expandedGalleryItem.title
? expandedGalleryItem.title
: 'gallery-image'
"
/>
<div class="footer">
<div class="description">
<h2 v-if="expandedGalleryItem.title">
{{ expandedGalleryItem.title }}
</h2>
<p v-if="expandedGalleryItem.description">
{{ expandedGalleryItem.description }}
</p>
</div>
<div v-if="gallery.length > 1" class="buttons">
<button class="previous circle-button" @click="previousImage()">
<LeftArrowIcon aria-hidden="true" />
</button>
<button class="next circle-button" @click="nextImage()">
<RightArrowIcon aria-hidden="true" />
</button>
</div>
</div>
</div>
</div>
<div class="buttons">
<button
v-if="currentMember"
@@ -47,14 +92,16 @@
:key="index"
class="card gallery-item"
>
<img
:src="
item.url
? item.url
: 'https://cdn.modrinth.com/placeholder-banner.svg'
"
:alt="item.title ? item.title : 'gallery-image'"
/>
<a class="gallery-thumbnail" @click="expandImage(item, index)">
<img
:src="
item.url
? item.url
: 'https://cdn.modrinth.com/placeholder-banner.svg'
"
:alt="item.title ? item.title : 'gallery-image'"
/>
</a>
<div class="gallery-body">
<div v-if="editGalleryIndexes.includes(index)" class="gallery-info">
<input
@@ -172,6 +219,8 @@ import UploadIcon from '~/assets/images/utils/upload.svg?inline'
import CalendarIcon from '~/assets/images/utils/calendar.svg?inline'
import TrashIcon from '~/assets/images/utils/trash.svg?inline'
import CrossIcon from '~/assets/images/utils/x.svg?inline'
import RightArrowIcon from '~/assets/images/utils/right-arrow.svg?inline'
import LeftArrowIcon from '~/assets/images/utils/left-arrow.svg?inline'
import EditIcon from '~/assets/images/utils/edit.svg?inline'
import CheckIcon from '~/assets/images/utils/check.svg?inline'
@@ -188,6 +237,8 @@ export default {
CheckIcon,
SmartFileInput,
CrossIcon,
RightArrowIcon,
LeftArrowIcon,
},
auth: false,
beforeRouteLeave(to, from, next) {
@@ -215,6 +266,8 @@ export default {
newGalleryItems: [],
editGalleryIndexes: [],
deleteGalleryUrls: [],
expandedGalleryItem: null,
expandedGalleryIndex: 0,
}
},
fetch() {
@@ -308,11 +361,136 @@ export default {
this.deleteGalleryUrls = []
this.gallery = JSON.parse(JSON.stringify(this.project.gallery))
},
nextImage() {
this.expandedGalleryIndex++
if (this.expandedGalleryIndex >= this.gallery.length) {
this.expandedGalleryIndex = 0
}
this.expandedGalleryItem = this.gallery[this.expandedGalleryIndex]
},
previousImage() {
this.expandedGalleryIndex--
if (this.expandedGalleryIndex < 0) {
this.expandedGalleryIndex = this.gallery.length - 1
}
this.expandedGalleryItem = this.gallery[this.expandedGalleryIndex]
},
expandImage(item, index) {
this.expandedGalleryItem = item
this.expandedGalleryIndex = index
},
},
}
</script>
<style lang="scss" scoped>
.expanded-image-modal {
position: fixed;
z-index: 20;
overflow: auto;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: #000000;
background-color: rgba(0, 0, 0, 0.7);
display: flex;
justify-content: center;
align-items: center;
.content {
position: relative;
width: auto;
height: auto;
max-height: 96vh;
max-width: 96vw;
background-color: var(--color-raised-bg);
overflow: auto;
border-radius: var(--size-rounded-card);
display: flex;
flex-direction: column;
.close {
position: absolute;
top: 0.5rem;
right: 0.5rem;
}
.next {
top: 20rem;
right: 0.5rem;
}
.previous {
top: 20rem;
left: 0.5rem;
}
.circle-button {
padding: 0.5rem;
line-height: 1;
display: flex;
max-width: 2rem;
background-color: var(--color-raised-bg);
border-radius: var(--size-rounded-max);
margin: 0 0.5rem 0 0;
box-shadow: inset 0px -1px 1px rgb(17 24 39 / 10%);
&:hover,
&:active {
background-color: var(--color-button-bg-hover) !important;
svg {
color: var(--color-button-text-hover) !important;
}
}
svg {
height: 1rem;
width: 1rem;
}
}
.image {
object-fit: contain;
max-height: 80vh;
max-width: 80vw;
}
.footer {
display: flex;
flex-direction: row;
margin: 0.5rem 0.75rem 0.75rem 0.75rem;
.buttons {
display: flex;
flex-direction: row;
flex-grow: 0;
align-items: center;
.circle-button {
background-color: var(--color-button-bg);
}
}
.description {
flex-grow: 1;
width: min-content;
h2 {
margin-bottom: 0.25rem;
font-size: 1.25rem;
}
p {
margin: 0;
font-size: 1rem;
}
}
}
}
}
.buttons {
display: flex;
@@ -390,6 +568,18 @@ export default {
}
}
.gallery-thumbnail {
cursor: pointer;
img {
transition: filter 0.25s ease-in-out;
&:hover {
filter: brightness(0.7);
}
}
}
.gallery-bottom {
width: calc(100% - 2 * var(--spacing-card-md));
padding: 0 var(--spacing-card-md) var(--spacing-card-sm)

View File

@@ -4,7 +4,10 @@
<div class="profile-picture card">
<h3>Profile picture</h3>
<div class="uploader">
<img :src="previewImage ? previewImage : $auth.user.avatar_url" />
<img
:src="previewImage ? previewImage : $auth.user.avatar_url"
@click="developerMode++"
/>
<file-input
accept="image/png,image/jpeg,image/gif,image/webp"
class="choose-image"
@@ -131,6 +134,24 @@
@change="changeLayout"
/>
</label>
<section v-if="developerMode > 6">
<h3>Developer options</h3>
<label>
<span>
Set the API endpoint. This value is not stored, and is intended
for temporary usage.</span
>
<Multiselect
v-model="apiEndpoint"
:options="['production', 'staging']"
:searchable="false"
:close-on-select="true"
:show-labels="false"
:allow-empty="false"
@input="changeApiEndpoint()"
/>
</label>
</section>
</section>
</div>
</div>
@@ -169,6 +190,8 @@ export default {
previewImage: null,
searchLayout: false,
projectLayout: false,
apiEndpoint: this.getApiEndpoint(),
developerMode: 0,
}
},
fetch() {
@@ -199,6 +222,17 @@ export default {
this.$colorMode.preference = shift ? 'oled' : 'dark'
}
},
changeApiEndpoint() {
const subdomain =
this.apiEndpoint === 'production' ? 'api' : 'staging-api'
this.$axios.defaults.baseURL =
'https://' + subdomain + '.modrinth.com/v2/'
},
getApiEndpoint() {
return this.$axios.defaults.baseURL === 'https://api.modrinth.com/v2/'
? 'production'
: 'staging'
},
showPreviewImage(files) {
const reader = new FileReader()
this.icon = files[0]