Nuxt Season Finale (#531)

Co-authored-by: Emma Cypress Pointer-Null <emmaffle@modrinth.com>
This commit is contained in:
Prospector
2022-06-18 18:39:53 -07:00
committed by GitHub
parent 2bda7566b4
commit 405a3eda60
26 changed files with 1690 additions and 952 deletions

View File

@@ -1,180 +1,144 @@
<template>
<div class="edit-page">
<div class="left-side">
<div class="profile-picture card">
<h3>Profile picture</h3>
<div class="uploader">
<img
:src="previewImage ? previewImage : $auth.user.avatar_url"
@click="developerMode++"
/>
<file-input
accept="image/png,image/jpeg,image/gif,image/webp"
class="choose-image"
prompt="Choose image or drag it here"
@change="showPreviewImage"
/>
<section class="card account-settings">
<div class="header">
<h2 class="title">Account settings</h2>
<div class="controls">
<button
class="brand-button-colors iconified-button"
title="Save account settings changes"
@click="saveChanges()"
>
<SaveIcon />
Save changes
</button>
</div>
<button
class="iconified-button"
@click="
icon = null
previewImage = null
"
>
<TrashIcon />
Reset
</button>
</div>
<div class="recap card">
<section>
<h2>Profile Recap</h2>
<div>
<Badge
v-if="$auth.user.role === 'admin'"
type="Admin"
color="red"
<div class="left-side">
<h3>Profile picture</h3>
<div class="profile-picture">
<img :src="previewImage ? previewImage : $auth.user.avatar_url" />
<div class="uploader">
<SmartFileInput
:show-icon="false"
:max-size="2097152"
accept="image/png,image/jpeg,image/gif,image/webp"
class="choose-image"
prompt="Choose image or drag it here"
@change="showPreviewImage"
/>
<Badge
v-else-if="$auth.user.role === 'moderator'"
type="Moderator"
color="yellow"
/>
<Badge v-else type="Developer" color="green" />
<div class="stat">
<SunriseIcon />
<span>Joined {{ $dayjs($auth.user.created).fromNow() }}</span>
</div>
<button
class="iconified-button"
@click="
icon = null
previewImage = null
"
>
<TrashIcon />
Reset
</button>
</div>
</section>
<section>
<div class="stat">
<DownloadIcon />
<span>
<strong>{{ sumDownloads() }}</strong> downloads
</span>
</div>
<div class="stat">
<HeartIcon />
<span>
<strong>{{ sumFollows() }}</strong> followers of projects
</span>
</div>
</section>
</div>
</div>
</div>
<div class="right-side">
<section class="card">
<h3>Username</h3>
<div class="right-side">
<label>
<span>
The username used on Modrinth to identify yourself. This must be
unique.
<h3>Username</h3>
<span>This must be unique.</span>
</span>
<input
v-model="username"
type="text"
placeholder="Enter your username"
/>
</label>
<h3>Email</h3>
<label>
<span>
The email for your account. This is private information which is not
exposed in any API routes or on your profile. It is also optional.
<h3>Email (optional)</h3>
<span>This is kept private.</span>
</span>
<input v-model="email" type="email" placeholder="Enter your email" />
</label>
<h3>Bio</h3>
<label>
<span>
A description of yourself which other users can see on your profile.
<h3>Bio</h3>
<span>Describe yourself to other users!</span>
</span>
<input v-model="bio" type="text" placeholder="Enter your bio" />
</label>
<h3>Theme</h3>
<label>
</div>
</section>
<section class="card">
<div class="header">
<h2 class="title">Display settings</h2>
</div>
<label>
<span>
<h3>Theme</h3>
<span>Change the global site theme.</span>
</span>
<Multiselect
v-model="$colorMode.preference"
:options="['system', 'light', 'dark', 'oled']"
:custom-label="
(value) =>
value === 'oled'
? 'OLED'
: value.charAt(0).toUpperCase() + value.slice(1)
"
:searchable="false"
:close-on-select="true"
:show-labels="false"
:allow-empty="false"
/>
</label>
<label>
<span>
<h3>Search sidebar on the right</h3>
<span>
Change the global site theme. It can also be changed between light
and dark in the navigation bar.
Enabling this will put the search page's filters sidebar on the
right side.
</span>
<Multiselect
v-model="$colorMode.preference"
:options="['system', 'light', 'dark', 'oled']"
:searchable="false"
:close-on-select="true"
:show-labels="false"
:allow-empty="false"
/>
</label>
<h3>Search sidebar on right side</h3>
<label>
</span>
<input
v-model="searchLayout"
class="switch stylized-toggle"
type="checkbox"
@change="changeLayout"
/>
</label>
<label>
<span>
<h3>Project sidebar on the right</h3>
<span>
Sets the sidebar direction for search pages. Enabling this will put
the search bar on the right side.
Enabling this will put the project pages' info sidebars on the right
side.
</span>
<input
v-model="searchLayout"
class="switch stylized-toggle"
type="checkbox"
@change="changeLayout"
/>
</label>
<h3>Project sidebar on right side</h3>
<label>
<span>
Sets the sidebar direction for project pages. Enabling this will
make projects look closer to the legacy layout, with project
information on the right side.
</span>
<input
v-model="projectLayout"
class="switch stylized-toggle"
type="checkbox"
@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>
</span>
<input
v-model="projectLayout"
class="switch stylized-toggle"
type="checkbox"
@change="changeLayout"
/>
</label>
</section>
</div>
</template>
<script>
import Multiselect from 'vue-multiselect'
import FileInput from '~/components/ui/FileInput'
import Badge from '~/components/ui/Badge'
import HeartIcon from '~/assets/images/utils/heart.svg?inline'
import SmartFileInput from '~/components/ui/SmartFileInput'
import TrashIcon from '~/assets/images/utils/trash.svg?inline'
import SunriseIcon from '~/assets/images/utils/sunrise.svg?inline'
import DownloadIcon from '~/assets/images/utils/download.svg?inline'
import SaveIcon from '~/assets/images/utils/save.svg?inline'
export default {
components: {
TrashIcon,
SunriseIcon,
DownloadIcon,
HeartIcon,
Badge,
FileInput,
SaveIcon,
SmartFileInput,
Multiselect,
},
asyncData(ctx) {
@@ -190,24 +154,15 @@ export default {
previewImage: null,
searchLayout: false,
projectLayout: false,
apiEndpoint: this.getApiEndpoint(),
developerMode: 0,
}
},
fetch() {
this.searchLayout = this.$store.state.cosmetics.searchLayout
this.projectLayout = this.$store.state.cosmetics.projectLayout
this.$emit('update:action-button', 'Save')
this.$emit('update:action-button-callback', this.saveChanges)
},
head: {
title: 'Settings - Modrinth',
},
created() {
this.$emit('update:action-button', 'Save')
this.$emit('update:action-button-callback', this.saveChanges)
},
methods: {
changeTheme() {
const shift = event.shiftKey
@@ -222,17 +177,6 @@ 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]
@@ -311,76 +255,72 @@ export default {
}
</script>
<style lang="scss" scoped>
.edit-page {
display: flex;
flex-direction: column;
.account-settings {
display: grid;
grid-template: 'header header' auto 'left-side left-side' auto 'right-side right-side' auto;
@media screen and (min-width: 1024px) {
flex-direction: row;
.left-side {
margin-right: var(--spacing-card-bg);
}
grid-template:
'header header' auto
'left-side right-side' auto;
}
}
.left-side {
min-width: 20rem;
.left-side {
grid-area: left-side;
min-width: 20rem;
.profile-picture {
h3 {
font-size: var(--font-size-lg);
}
.uploader {
margin: 1rem 0;
text-align: center;
.profile-picture {
display: flex;
flex-direction: row;
gap: 0.5rem;
align-items: center;
img {
box-shadow: var(--shadow-card);
border-radius: var(--size-rounded-md);
width: 8rem;
width: 10rem;
height: 10rem;
object-fit: contain;
margin-bottom: 0.5rem;
}
}
}
.recap {
section {
h2 {
font-size: var(--font-size-lg);
margin: 0 0 0.5rem 0;
}
.version-badge {
text-transform: none;
margin-bottom: 0.25rem;
&::first-letter {
text-transform: uppercase;
.uploader {
text-align: center;
.iconified-button {
margin-top: 0.5rem;
}
}
}
}
.right-side {
grid-area: right-side;
margin-left: var(--spacing-card-lg);
}
}
.stat {
.card span {
margin-bottom: 1rem;
}
label {
align-items: center;
}
.header {
display: flex;
align-items: center;
margin: 0.5rem 0;
padding-bottom: 1rem;
grid-area: header;
svg {
width: auto;
height: 1.25rem;
margin-right: 0.25rem;
.title {
flex-grow: 1;
margin: 0;
}
span {
strong {
font-weight: bolder;
}
.controls {
display: flex;
flex-direction: row;
gap: 0.5rem;
}
}
</style>

View File

@@ -1,5 +1,26 @@
<template>
<div class="rows card">
<div class="header">
<h2 class="title">Privacy settings</h2>
<div class="controls">
<button class="iconified-button" @click="toggleAll(false)">
<DenyIcon />
Deny all
</button>
<button class="iconified-button" @click="toggleAll(true)">
<AllowIcon />
Allow all
</button>
<button
class="brand-button-colors iconified-button"
title="Confirm privacy settings"
@click="confirm()"
>
<SaveIcon />
Save changes
</button>
</div>
</div>
<div class="privacy-settings-container">
<div>
Modrinth relies on different providers and in-house tools to allow us to
@@ -30,23 +51,23 @@
</div>
</div>
</div>
<div class="actions">
<button class="iconified-button" @click="toggleAll(false)">
Select none
</button>
<button class="iconified-button" @click="toggleAll(true)">
Select all
</button>
</div>
</div>
</template>
<script>
import toggles from '@/privacy-toggles'
import DenyIcon from '~/assets/images/utils/clear.svg?inline'
import AllowIcon from '~/assets/images/utils/check-circle.svg?inline'
import SaveIcon from '~/assets/images/utils/save.svg?inline'
export default {
auth: false,
name: 'Privacy',
components: {
DenyIcon,
AllowIcon,
SaveIcon,
},
data: () => {
const settings = toggles.settings
return {
@@ -54,9 +75,6 @@ export default {
}
},
fetch() {
this.$emit('update:action-button', 'Confirm')
this.$emit('update:action-button-callback', this.confirm)
this.$store.dispatch('consent/loadFromCookies', this.$cookies)
if (this.$store.state.consent.is_consent_given) {
Object.keys(toggles.settings).forEach((key) => {
@@ -76,10 +94,6 @@ export default {
head: {
title: 'Privacy Settings - Modrinth',
},
created() {
this.$emit('update:action-button', 'Confirm')
this.$emit('update:action-button-callback', this.confirm)
},
options: {
auth: false,
},
@@ -91,6 +105,7 @@ export default {
}
this.$forceUpdate()
this.confirm()
},
confirm() {
this.$store.commit('consent/set_consent', true)
@@ -173,4 +188,22 @@ export default {
}
}
}
.header {
display: flex;
align-items: center;
padding-bottom: 1rem;
grid-area: header;
.title {
flex-grow: 1;
margin: 0;
}
.controls {
display: flex;
flex-direction: row;
gap: 0.5rem;
}
}
</style>

View File

@@ -12,12 +12,17 @@
/>
<section class="card">
<h3>Authorization token</h3>
<div class="header">
<h2 class="title">Security settings</h2>
</div>
<label>
<span>
Your authorization token can be used with the Modrinth API, the
Minotaur Gradle plugin, and other applications that interact with
Modrinth's API. Be sure to keep this secret!
<h3>Authorization token</h3>
<span>
Your authorization token can be used with the Modrinth API, the
Minotaur Gradle plugin, and other applications that interact with
Modrinth's API. Be sure to keep this secret!
</span>
</span>
<input
type="button"
@@ -26,12 +31,14 @@
@click="copyToken"
/>
</label>
<h3>Revoke your token</h3>
<label>
<span
>This will log you out of Modrinth, and you will have to log in again
to access Modrinth with a new token.</span
>
<span>
<h3>Revoke your token</h3>
<span
>This will log you out of Modrinth, and you will have to log in
again to access Modrinth with a new token.</span
>
</span>
<input
type="button"
class="iconified-button"
@@ -39,14 +46,16 @@
@click="$router.replace('/settings/revoke-token')"
/>
</label>
<h3>Delete your account</h3>
<label>
<span
>Clicking on this WILL delete your account. Do not click on this
unless you want your account deleted. If you delete your account, all
attached data, including projects, will be removed from our servers.
This cannot be reversed, so be careful!</span
>
<span>
<h3>Delete your account</h3>
<span
>Clicking on this WILL delete your account. Do not click on this
unless you want your account deleted. If you delete your account,
all attached data, including projects, will be removed from our
servers. This cannot be reversed, so be careful!</span
>
</span>
<input
value="Delete account"
type="button"
@@ -96,3 +105,26 @@ export default {
},
}
</script>
<style lang="scss" scoped>
.card span {
margin-bottom: 1rem;
}
.header {
display: flex;
align-items: center;
padding-bottom: 1rem;
grid-area: header;
.title {
flex-grow: 1;
margin: 0;
}
.controls {
display: flex;
flex-direction: row;
gap: 0.5rem;
}
}
</style>