You've already forked AstralRinth
forked from didirus/AstralRinth
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:
@@ -639,7 +639,7 @@ label {
|
|||||||
color: var(--color-text);
|
color: var(--color-text);
|
||||||
|
|
||||||
span::before {
|
span::before {
|
||||||
background-color: var(--color-brand-disabled);
|
background-color: var(--tab-underline-hovered);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,11 +20,9 @@ html {
|
|||||||
--color-brand: #30b27b;
|
--color-brand: #30b27b;
|
||||||
--color-brand-hover: #1e9565;
|
--color-brand-hover: #1e9565;
|
||||||
--color-brand-active: #177955;
|
--color-brand-active: #177955;
|
||||||
--color-brand-light: #30b27b;
|
|
||||||
--color-brand-inverted: #ffffff;
|
--color-brand-inverted: #ffffff;
|
||||||
--color-brand-2: #30b27b;
|
|
||||||
--color-brand-3: #30b27b;
|
--tab-underline-hovered: #e2e8f0;
|
||||||
--color-brand-disabled: #e2e8f0;
|
|
||||||
|
|
||||||
--color-button-bg: #e0e0e5;
|
--color-button-bg: #e0e0e5;
|
||||||
--color-button-text: var(--color-text-dark);
|
--color-button-text: var(--color-text-dark);
|
||||||
@@ -98,11 +96,9 @@ html {
|
|||||||
--color-brand: #1bd96a;
|
--color-brand: #1bd96a;
|
||||||
--color-brand-hover: #30b366;
|
--color-brand-hover: #30b366;
|
||||||
--color-brand-active: #55f5ae;
|
--color-brand-active: #55f5ae;
|
||||||
--color-brand-light: #30b27b;
|
|
||||||
--color-brand-inverted: #000;
|
--color-brand-inverted: #000;
|
||||||
--color-brand-2: #30b27b;
|
|
||||||
--color-brand-3: #30b27b;
|
--tab-underline-hovered: #414146;
|
||||||
--color-brand-disabled: #414146;
|
|
||||||
|
|
||||||
--color-button-bg: #3e434b;
|
--color-button-bg: #3e434b;
|
||||||
--color-button-text: var(--color-text);
|
--color-button-text: var(--color-text);
|
||||||
|
|||||||
@@ -1,5 +1,50 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<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">
|
<div class="buttons">
|
||||||
<button
|
<button
|
||||||
v-if="currentMember"
|
v-if="currentMember"
|
||||||
@@ -47,14 +92,16 @@
|
|||||||
:key="index"
|
:key="index"
|
||||||
class="card gallery-item"
|
class="card gallery-item"
|
||||||
>
|
>
|
||||||
<img
|
<a class="gallery-thumbnail" @click="expandImage(item, index)">
|
||||||
:src="
|
<img
|
||||||
item.url
|
:src="
|
||||||
? item.url
|
item.url
|
||||||
: 'https://cdn.modrinth.com/placeholder-banner.svg'
|
? item.url
|
||||||
"
|
: 'https://cdn.modrinth.com/placeholder-banner.svg'
|
||||||
:alt="item.title ? item.title : 'gallery-image'"
|
"
|
||||||
/>
|
:alt="item.title ? item.title : 'gallery-image'"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
<div class="gallery-body">
|
<div class="gallery-body">
|
||||||
<div v-if="editGalleryIndexes.includes(index)" class="gallery-info">
|
<div v-if="editGalleryIndexes.includes(index)" class="gallery-info">
|
||||||
<input
|
<input
|
||||||
@@ -172,6 +219,8 @@ import UploadIcon from '~/assets/images/utils/upload.svg?inline'
|
|||||||
import CalendarIcon from '~/assets/images/utils/calendar.svg?inline'
|
import CalendarIcon from '~/assets/images/utils/calendar.svg?inline'
|
||||||
import TrashIcon from '~/assets/images/utils/trash.svg?inline'
|
import TrashIcon from '~/assets/images/utils/trash.svg?inline'
|
||||||
import CrossIcon from '~/assets/images/utils/x.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 EditIcon from '~/assets/images/utils/edit.svg?inline'
|
||||||
import CheckIcon from '~/assets/images/utils/check.svg?inline'
|
import CheckIcon from '~/assets/images/utils/check.svg?inline'
|
||||||
|
|
||||||
@@ -188,6 +237,8 @@ export default {
|
|||||||
CheckIcon,
|
CheckIcon,
|
||||||
SmartFileInput,
|
SmartFileInput,
|
||||||
CrossIcon,
|
CrossIcon,
|
||||||
|
RightArrowIcon,
|
||||||
|
LeftArrowIcon,
|
||||||
},
|
},
|
||||||
auth: false,
|
auth: false,
|
||||||
beforeRouteLeave(to, from, next) {
|
beforeRouteLeave(to, from, next) {
|
||||||
@@ -215,6 +266,8 @@ export default {
|
|||||||
newGalleryItems: [],
|
newGalleryItems: [],
|
||||||
editGalleryIndexes: [],
|
editGalleryIndexes: [],
|
||||||
deleteGalleryUrls: [],
|
deleteGalleryUrls: [],
|
||||||
|
expandedGalleryItem: null,
|
||||||
|
expandedGalleryIndex: 0,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
fetch() {
|
fetch() {
|
||||||
@@ -308,11 +361,136 @@ export default {
|
|||||||
this.deleteGalleryUrls = []
|
this.deleteGalleryUrls = []
|
||||||
this.gallery = JSON.parse(JSON.stringify(this.project.gallery))
|
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>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<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 {
|
.buttons {
|
||||||
display: flex;
|
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 {
|
.gallery-bottom {
|
||||||
width: calc(100% - 2 * var(--spacing-card-md));
|
width: calc(100% - 2 * var(--spacing-card-md));
|
||||||
padding: 0 var(--spacing-card-md) var(--spacing-card-sm)
|
padding: 0 var(--spacing-card-md) var(--spacing-card-sm)
|
||||||
|
|||||||
@@ -4,7 +4,10 @@
|
|||||||
<div class="profile-picture card">
|
<div class="profile-picture card">
|
||||||
<h3>Profile picture</h3>
|
<h3>Profile picture</h3>
|
||||||
<div class="uploader">
|
<div class="uploader">
|
||||||
<img :src="previewImage ? previewImage : $auth.user.avatar_url" />
|
<img
|
||||||
|
:src="previewImage ? previewImage : $auth.user.avatar_url"
|
||||||
|
@click="developerMode++"
|
||||||
|
/>
|
||||||
<file-input
|
<file-input
|
||||||
accept="image/png,image/jpeg,image/gif,image/webp"
|
accept="image/png,image/jpeg,image/gif,image/webp"
|
||||||
class="choose-image"
|
class="choose-image"
|
||||||
@@ -131,6 +134,24 @@
|
|||||||
@change="changeLayout"
|
@change="changeLayout"
|
||||||
/>
|
/>
|
||||||
</label>
|
</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>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -169,6 +190,8 @@ export default {
|
|||||||
previewImage: null,
|
previewImage: null,
|
||||||
searchLayout: false,
|
searchLayout: false,
|
||||||
projectLayout: false,
|
projectLayout: false,
|
||||||
|
apiEndpoint: this.getApiEndpoint(),
|
||||||
|
developerMode: 0,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
fetch() {
|
fetch() {
|
||||||
@@ -199,6 +222,17 @@ export default {
|
|||||||
this.$colorMode.preference = shift ? 'oled' : 'dark'
|
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) {
|
showPreviewImage(files) {
|
||||||
const reader = new FileReader()
|
const reader = new FileReader()
|
||||||
this.icon = files[0]
|
this.icon = files[0]
|
||||||
|
|||||||
Reference in New Issue
Block a user