chore: clean up a bunch of legacy styles (#5973)

* remove unused experimental-styles-within

* remove unused styles

* more cleanup + prepr

* Refactor nearly all legacy buttons to use ButtonStyled

* prepr

* Update MC account selector to modern version

* prepr

---------

Co-authored-by: Calum H. <calum@modrinth.com>
This commit is contained in:
Prospector
2026-05-03 11:53:06 -07:00
committed by GitHub
parent 8a72ee9968
commit 7dbbbe590f
153 changed files with 2596 additions and 3817 deletions

View File

@@ -45,15 +45,7 @@
</div>
</div>
<div v-else class="experimental-styles-within">
<NewModal ref="settingsModal">
<template #title>
<Avatar :src="project.icon_url" :alt="project.title" class="icon" size="32px" />
<span class="text-lg font-extrabold text-contrast">
{{ formatMessage(messages.settingsTitle) }}
</span>
</template>
</NewModal>
<div v-else>
<NewModal
ref="modalLicense"
:header="project.license.name ? project.license.name : formatMessage(messages.licenseTitle)"
@@ -464,30 +456,19 @@
:member="!!currentMember"
>
<template #actions>
<ButtonStyled
v-if="auth.user && currentMember"
size="large"
color="brand"
class="lg:!hidden"
circular
>
<ButtonStyled v-if="auth.user && currentMember" size="large" color="brand" circular>
<nuxt-link
v-tooltip="'Edit project'"
:to="`/${project.project_type}/${project.slug ? project.slug : project.id}/settings`"
class="!font-bold"
class="!font-bold lg:!hidden"
>
<SettingsIcon aria-hidden="true" />
</nuxt-link>
</ButtonStyled>
<ButtonStyled
v-if="auth.user && currentMember"
size="large"
color="brand"
class="max-lg:!hidden"
>
<ButtonStyled v-if="auth.user && currentMember" size="large" color="brand">
<nuxt-link
:to="`/${project.project_type}/${project.slug ? project.slug : project.id}/settings`"
class="!font-bold"
class="!font-bold max-lg:!hidden"
>
<SettingsIcon aria-hidden="true" />
Edit project
@@ -594,7 +575,7 @@
</nuxt-link>
</ButtonStyled>
<template #popper>
<div class="experimental-styles-within grid grid-cols-[min-content] gap-1">
<div class="grid grid-cols-[min-content] gap-1">
<div class="flex min-w-60 items-center justify-between gap-4">
<h3
class="m-0 flex items-center gap-2 whitespace-nowrap text-base font-bold text-contrast"
@@ -724,13 +705,15 @@
<div v-else class="menu-text">
<p class="popout-text">{{ formatMessage(messages.noCollectionsFound) }}</p>
</div>
<button
class="btn collection-button"
@click="(event) => $refs.modal_collection.show(event)"
>
<PlusIcon aria-hidden="true" />
{{ formatMessage(messages.createNewCollection) }}
</button>
<ButtonStyled>
<button
class="mx-3 mb-3"
@click="(event) => $refs.modal_collection.show(event)"
>
<PlusIcon aria-hidden="true" />
{{ formatMessage(messages.createNewCollection) }}
</button>
</ButtonStyled>
</template>
</PopoutMenu>
<nuxt-link v-else v-tooltip="'Save'" :to="signInRouteObj" aria-label="Save">
@@ -890,32 +873,29 @@
:supported-versions="serverSupportedVersions"
:loaders="serverModpackLoaders"
:status-online="projectV3?.minecraft_java_server?.ping?.data != null"
class="card flex-card experimental-styles-within"
class="card flex-card"
/>
<ProjectSidebarCompatibility
v-if="projectV3Loaded && !isServerProject"
:project="project"
:tags="tags"
:project-v3="projectV3"
class="card flex-card experimental-styles-within"
class="card flex-card"
/>
<AdPlaceholder v-if="!auth.user && tags.approvedStatuses.includes(project.status)" />
<ProjectSidebarLinks
:project="project"
:project-v3="projectV3"
:link-target="$external()"
class="card flex-card experimental-styles-within"
/>
<ProjectSidebarTags
:project="project"
class="card flex-card experimental-styles-within"
class="card flex-card"
/>
<ProjectSidebarTags :project="project" class="card flex-card" />
<ProjectSidebarCreators
:organization="organization"
:members="members"
:org-link="(slug) => `/organization/${slug}`"
:user-link="(username) => `/user/${username}`"
class="card flex-card experimental-styles-within"
class="card flex-card"
/>
<!-- TODO: Finish license modal and enable -->
<ProjectSidebarDetails
@@ -924,9 +904,9 @@
:has-versions="versions.length > 0"
:link-target="$external()"
:show-followers="isServerProject"
class="card flex-card experimental-styles-within"
class="card flex-card"
/>
<div class="card flex-card experimental-styles-within">
<div class="card flex-card">
<h2>{{ formatMessage(detailsMessages.title) }}</h2>
<div class="details-list">
@@ -1177,7 +1157,6 @@ const formatDateTime = useFormatDateTime({
const debug = useDebugLogger('DownloadModal')
const settingsModal = ref()
const downloadModal = ref()
const openInAppModal = ref()
const overTheTopDownloadAnimation = ref()
@@ -2748,11 +2727,6 @@ provideProjectPageContext({
color: var(--color-secondary);
}
.collection-button {
margin: var(--gap-sm) var(--gap-md);
white-space: nowrap;
}
.menu-text {
padding: 0 var(--gap-md);
font-size: var(--font-size-nm);

View File

@@ -53,14 +53,16 @@
{{ formatDate(version.date_published) }}</span
>
</div>
<a
:href="version.primaryFile?.url"
class="iconified-button download"
:title="`Download ${version.name}`"
>
<DownloadIcon aria-hidden="true" />
Download
</a>
<ButtonStyled color="brand" type="transparent">
<a
class="ml-auto"
:href="version.primaryFile?.url"
:title="`Download ${version.name}`"
>
<DownloadIcon aria-hidden="true" />
Download
</a>
</ButtonStyled>
</div>
<div
v-if="version.changelog && !version.duplicate"
@@ -87,6 +89,7 @@
<script setup>
import { DownloadIcon, SpinnerIcon } from '@modrinth/assets'
import {
ButtonStyled,
injectModrinthClient,
injectProjectPageContext,
Pagination,

View File

@@ -10,23 +10,24 @@
<div class="file-header">
<ImageIcon aria-hidden="true" />
<strong>{{ editFile ? editFile.name : 'Current image' }}</strong>
<FileInput
v-if="editIndex === -1"
class="iconified-button raised-button"
prompt="Replace"
:accept="acceptFileTypes"
:max-size="5242880"
should-always-reset
aria-label="Replace image"
@change="
(x) => {
editFile = x[0]
showPreviewImage()
}
"
>
<TransferIcon aria-hidden="true" />
</FileInput>
<ButtonStyled v-if="editIndex === -1" type="outlined">
<FileInput
class="button-like"
prompt="Replace"
:accept="acceptFileTypes"
:max-size="5242880"
should-always-reset
aria-label="Replace image"
@change="
(x) => {
editFile = x[0]
showPreviewImage()
}
"
>
<TransferIcon aria-hidden="true" />
</FileInput>
</ButtonStyled>
</div>
<img
:src="
@@ -68,53 +69,42 @@
placeholder="Enter order index..."
/>
<label for="gallery-image-featured">
<span class="label__title">Featured</span>
<span class="label__title">Banner image</span>
<span class="label__description">
A featured gallery image shows up in search and your project card. Only one gallery
image can be featured.
You can feature one image on your project to be used as a banner image.
</span>
</label>
<button
v-if="!editFeatured"
id="gallery-image-featured"
class="iconified-button"
@click="editFeatured = true"
>
<StarIcon aria-hidden="true" />
Feature image
</button>
<button
v-else
id="gallery-image-featured"
class="iconified-button"
@click="editFeatured = false"
>
<StarIcon fill="currentColor" aria-hidden="true" />
Unfeature image
</button>
<ButtonStyled v-if="!editFeatured">
<button id="gallery-image-featured" class="w-fit" @click="editFeatured = true">
<StarIcon aria-hidden="true" />
Set as banner
</button>
</ButtonStyled>
<ButtonStyled v-else>
<button id="gallery-image-featured" class="w-fit" @click="editFeatured = false">
<StarIcon fill="currentColor" aria-hidden="true" />
Unset as banner
</button>
</ButtonStyled>
<div class="button-group">
<button class="iconified-button" @click="modalEditItem?.hide()">
<XIcon aria-hidden="true" />
Cancel
</button>
<button
v-if="editIndex === -1"
class="iconified-button brand-button"
:disabled="shouldPreventActions"
@click="createGalleryItem"
>
<PlusIcon aria-hidden="true" />
Add gallery image
</button>
<button
v-else
class="iconified-button brand-button"
:disabled="shouldPreventActions"
@click="editGalleryItem"
>
<SaveIcon aria-hidden="true" />
Save changes
</button>
<ButtonStyled type="outlined">
<button @click="modalEditItem?.hide()">
<XIcon aria-hidden="true" />
Cancel
</button>
</ButtonStyled>
<ButtonStyled v-if="editIndex === -1" color="brand">
<button :disabled="shouldPreventActions" @click="createGalleryItem">
<PlusIcon aria-hidden="true" />
Add gallery image
</button>
</ButtonStyled>
<ButtonStyled v-else color="brand">
<button :disabled="shouldPreventActions" @click="editGalleryItem">
<SaveIcon aria-hidden="true" />
Save changes
</button>
</ButtonStyled>
</div>
</div>
</Modal>
@@ -155,39 +145,41 @@
</p>
</div>
<div class="controls">
<div class="buttons">
<button class="close circle-button" @click="expandedGalleryItem = null">
<XIcon aria-hidden="true" />
</button>
<a
class="open circle-button"
target="_blank"
:href="
expandedGalleryItem?.raw_url
? expandedGalleryItem?.raw_url
: 'https://cdn.modrinth.com/placeholder-banner.svg'
"
>
<ExternalIcon aria-hidden="true" />
</a>
<button class="circle-button" @click="zoomedIn = !zoomedIn">
<ExpandIcon v-if="!zoomedIn" aria-hidden="true" />
<ContractIcon v-else aria-hidden="true" />
</button>
<button
v-if="filteredGallery.length > 1"
class="previous circle-button"
@click="previousImage()"
>
<LeftArrowIcon aria-hidden="true" />
</button>
<button
v-if="filteredGallery.length > 1"
class="next circle-button"
@click="nextImage()"
>
<RightArrowIcon aria-hidden="true" />
</button>
<div class="flex gap-2">
<ButtonStyled circular>
<button class="close" @click="expandedGalleryItem = null">
<XIcon aria-hidden="true" />
</button>
</ButtonStyled>
<ButtonStyled circular>
<a
class="open"
target="_blank"
:href="
expandedGalleryItem?.raw_url
? expandedGalleryItem?.raw_url
: 'https://cdn.modrinth.com/placeholder-banner.svg'
"
>
<ExternalIcon aria-hidden="true" />
</a>
</ButtonStyled>
<ButtonStyled circular>
<button @click="zoomedIn = !zoomedIn">
<ExpandIcon v-if="!zoomedIn" aria-hidden="true" />
<ContractIcon v-else aria-hidden="true" />
</button>
</ButtonStyled>
<ButtonStyled v-if="filteredGallery.length > 1" circular>
<button class="previous" @click="previousImage()">
<LeftArrowIcon aria-hidden="true" />
</button>
</ButtonStyled>
<ButtonStyled v-if="filteredGallery.length > 1" circular>
<button class="next" @click="nextImage()">
<RightArrowIcon aria-hidden="true" />
</button>
</ButtonStyled>
</div>
</div>
</div>
@@ -195,17 +187,19 @@
</div>
<div v-if="currentMember && filteredGallery.length" class="card header-buttons">
<FileInput
:max-size="5242880"
:accept="acceptFileTypes"
prompt="Upload an image"
aria-label="Upload an image"
class="iconified-button brand-button"
:disabled="!isPermission(currentMember?.permissions, 1 << 2)"
@change="handleFiles"
>
<UploadIcon aria-hidden="true" />
</FileInput>
<ButtonStyled color="brand">
<FileInput
:max-size="5242880"
:accept="acceptFileTypes"
prompt="Upload an image"
aria-label="Upload an image"
class="button-like"
:disabled="!isPermission(currentMember?.permissions, 1 << 2)"
@change="handleFiles"
>
<UploadIcon aria-hidden="true" />
</FileInput>
</ButtonStyled>
<span class="indicator">
<InfoIcon aria-hidden="true" /> Click to choose an image or drag one onto this page
</span>
@@ -239,35 +233,37 @@
{{ formatDate(item.created) }}
</div>
<div v-if="currentMember" class="gallery-buttons input-group">
<button
class="iconified-button"
@click="
() => {
resetEdit()
editIndex = index
editTitle = item.title ?? ''
editDescription = item.description ?? ''
editFeatured = item.featured
editOrder = item.ordering
modalEditItem?.show()
}
"
>
<EditIcon aria-hidden="true" />
Edit
</button>
<button
class="iconified-button"
@click="
() => {
deleteIndex = index
modalConfirm?.show()
}
"
>
<TrashIcon aria-hidden="true" />
Remove
</button>
<ButtonStyled>
<button
@click="
() => {
resetEdit()
editIndex = index
editTitle = item.title ?? ''
editDescription = item.description ?? ''
editFeatured = item.featured
editOrder = item.ordering
modalEditItem?.show()
}
"
>
<EditIcon aria-hidden="true" />
Edit
</button>
</ButtonStyled>
<ButtonStyled>
<button
@click="
() => {
deleteIndex = index
modalConfirm?.show()
}
"
>
<TrashIcon aria-hidden="true" />
Remove
</button>
</ButtonStyled>
</div>
</div>
</div>
@@ -304,6 +300,7 @@ import {
XIcon,
} from '@modrinth/assets'
import {
ButtonStyled,
ConfirmModal,
DropArea,
FileInput,
@@ -541,43 +538,6 @@ async function deleteGalleryImage() {
width: calc(100vw - 2 * var(--spacing-card-lg));
height: calc(100vh - 2 * var(--spacing-card-lg));
.circle-button {
padding: 0.5rem;
line-height: 1;
display: flex;
max-width: 2rem;
color: var(--color-button-text);
background-color: var(--color-button-bg);
border-radius: var(--size-rounded-max);
margin: 0;
box-shadow: inset 0px -1px 1px rgb(17 24 39 / 10%);
&:not(:last-child) {
margin-right: 0.5rem;
}
&:hover {
background-color: var(--color-button-bg-hover) !important;
svg {
color: var(--color-button-text-hover) !important;
}
}
&:active {
background-color: var(--color-button-bg-active) !important;
svg {
color: var(--color-button-text-active) !important;
}
}
svg {
height: 1rem;
width: 1rem;
}
}
.image {
position: absolute;
left: 50%;
@@ -653,14 +613,6 @@ async function deleteGalleryImage() {
}
}
.buttons {
display: flex;
button {
margin-right: 0.5rem;
}
}
.items {
display: grid;
grid-template-rows: 1fr;
@@ -762,10 +714,6 @@ async function deleteGalleryImage() {
strong {
word-wrap: anywhere;
}
.iconified-button {
margin-left: auto;
}
}
img {
@@ -778,8 +726,4 @@ async function deleteGalleryImage() {
}
}
}
.brand-button {
color: var(--color-accent-contrast);
}
</style>

View File

@@ -152,7 +152,7 @@ watch(route, () => {
@toggle-collapsed="() => (collapsedChecklist = !collapsedChecklist)"
@set-processing="setProcessing"
/>
<div class="experimental-styles-within grid gap-4 lg:grid-cols-[1fr_3fr]">
<div class="grid gap-4 lg:grid-cols-[1fr_3fr]">
<div>
<NavStack :items="navItems" />
</div>

View File

@@ -1,6 +1,6 @@
<template>
<LoadingIndicator v-if="!projectV3" class="py-6" />
<div v-else-if="showEnvironmentMigration" class="card experimental-styles-within">
<div v-else-if="showEnvironmentMigration" class="card">
<h2 class="m-0 mb-2 block text-lg font-extrabold text-contrast">Project environment</h2>
<EnvironmentMigration />
</div>

View File

@@ -10,23 +10,24 @@
<div class="file-header">
<ImageIcon aria-hidden="true" />
<strong>{{ editFile ? editFile.name : 'Current image' }}</strong>
<FileInput
v-if="editIndex === -1"
class="iconified-button raised-button"
prompt="Replace"
:accept="acceptFileTypes"
:max-size="5242880"
should-always-reset
aria-label="Replace image"
@change="
(x) => {
editFile = x[0]
showPreviewImage()
}
"
>
<TransferIcon aria-hidden="true" />
</FileInput>
<ButtonStyled v-if="editIndex === -1" type="outlined">
<FileInput
class="button-like"
prompt="Replace"
:accept="acceptFileTypes"
:max-size="5242880"
should-always-reset
aria-label="Replace image"
@change="
(x) => {
editFile = x[0]
showPreviewImage()
}
"
>
<TransferIcon aria-hidden="true" />
</FileInput>
</ButtonStyled>
</div>
<img
:src="
@@ -68,53 +69,42 @@
placeholder="Enter order index..."
/>
<label for="gallery-image-featured">
<span class="label__title">Featured</span>
<span class="label__title">Banner image</span>
<span class="label__description">
A featured gallery image shows up in search and your project card. Only one gallery
image can be featured.
You can feature one image on your project to be used as a banner image.
</span>
</label>
<button
v-if="!editFeatured"
id="gallery-image-featured"
class="iconified-button"
@click="editFeatured = true"
>
<StarIcon aria-hidden="true" />
Feature image
</button>
<button
v-else
id="gallery-image-featured"
class="iconified-button"
@click="editFeatured = false"
>
<StarIcon fill="currentColor" aria-hidden="true" />
Unfeature image
</button>
<ButtonStyled v-if="!editFeatured">
<button id="gallery-image-featured" class="w-fit" @click="editFeatured = true">
<StarIcon aria-hidden="true" />
Set as banner
</button>
</ButtonStyled>
<ButtonStyled v-else>
<button id="gallery-image-featured" class="w-fit" @click="editFeatured = false">
<StarIcon fill="currentColor" aria-hidden="true" />
Unset as banner
</button>
</ButtonStyled>
<div class="button-group">
<button class="iconified-button" @click="modal_edit_item.hide()">
<XIcon aria-hidden="true" />
Cancel
</button>
<button
v-if="editIndex === -1"
class="iconified-button brand-button"
:disabled="shouldPreventActions"
@click="createGalleryItem"
>
<PlusIcon aria-hidden="true" />
Add gallery image
</button>
<button
v-else
class="iconified-button brand-button"
:disabled="shouldPreventActions"
@click="editGalleryItem"
>
<SaveIcon aria-hidden="true" />
Save changes
</button>
<ButtonStyled type="outlined">
<button @click="modal_edit_item.hide()">
<XIcon aria-hidden="true" />
Cancel
</button>
</ButtonStyled>
<ButtonStyled v-if="editIndex === -1" color="brand">
<button :disabled="shouldPreventActions" @click="createGalleryItem">
<PlusIcon aria-hidden="true" />
Add gallery image
</button>
</ButtonStyled>
<ButtonStyled v-else color="brand">
<button :disabled="shouldPreventActions" @click="editGalleryItem">
<SaveIcon aria-hidden="true" />
Save changes
</button>
</ButtonStyled>
</div>
</div>
</Modal>
@@ -155,56 +145,60 @@
</p>
</div>
<div class="controls">
<div class="buttons">
<button class="close circle-button" @click="expandedGalleryItem = null">
<XIcon aria-hidden="true" />
</button>
<a
class="open circle-button"
target="_blank"
:href="
expandedGalleryItem.raw_url
? expandedGalleryItem.raw_url
: 'https://cdn.modrinth.com/placeholder-banner.svg'
"
>
<ExternalIcon aria-hidden="true" />
</a>
<button class="circle-button" @click="zoomedIn = !zoomedIn">
<ExpandIcon v-if="!zoomedIn" aria-hidden="true" />
<ContractIcon v-else aria-hidden="true" />
</button>
<button
v-if="filteredGallery.length > 1"
class="previous circle-button"
@click="previousImage()"
>
<LeftArrowIcon aria-hidden="true" />
</button>
<button
v-if="filteredGallery.length > 1"
class="next circle-button"
@click="nextImage()"
>
<RightArrowIcon aria-hidden="true" />
</button>
<div class="flex gap-2">
<ButtonStyled circular>
<button class="close" @click="expandedGalleryItem = null">
<XIcon aria-hidden="true" />
</button>
</ButtonStyled>
<ButtonStyled circular>
<a
class="open"
target="_blank"
:href="
expandedGalleryItem.raw_url
? expandedGalleryItem.raw_url
: 'https://cdn.modrinth.com/placeholder-banner.svg'
"
>
<ExternalIcon aria-hidden="true" />
</a>
</ButtonStyled>
<ButtonStyled circular>
<button @click="zoomedIn = !zoomedIn">
<ExpandIcon v-if="!zoomedIn" aria-hidden="true" />
<ContractIcon v-else aria-hidden="true" />
</button>
</ButtonStyled>
<ButtonStyled v-if="filteredGallery.length > 1" circular>
<button class="previous" @click="previousImage()">
<LeftArrowIcon aria-hidden="true" />
</button>
</ButtonStyled>
<ButtonStyled v-if="filteredGallery.length > 1" circular>
<button class="next" @click="nextImage()">
<RightArrowIcon aria-hidden="true" />
</button>
</ButtonStyled>
</div>
</div>
</div>
</div>
</div>
<div v-if="currentMember" class="card header-buttons">
<FileInput
:max-size="5242880"
:accept="acceptFileTypes"
prompt="Upload an image"
aria-label="Upload an image"
class="iconified-button brand-button"
:disabled="!isPermission(currentMember?.permissions, 1 << 2)"
@change="handleFiles"
>
<UploadIcon aria-hidden="true" />
</FileInput>
<ButtonStyled color="brand">
<FileInput
:max-size="5242880"
:accept="acceptFileTypes"
prompt="Upload an image"
aria-label="Upload an image"
class="button-like"
:disabled="!isPermission(currentMember?.permissions, 1 << 2)"
@change="handleFiles"
>
<UploadIcon aria-hidden="true" />
</FileInput>
</ButtonStyled>
<span class="indicator">
<InfoIcon aria-hidden="true" /> Click to choose an image or drag one onto this page
</span>
@@ -238,35 +232,37 @@
{{ formatDate(item.created) }}
</div>
<div v-if="currentMember" class="gallery-buttons input-group">
<button
class="iconified-button"
@click="
() => {
resetEdit()
editIndex = index
editTitle = item.title
editDescription = item.description
editFeatured = item.featured
editOrder = item.ordering
modal_edit_item.show()
}
"
>
<EditIcon aria-hidden="true" />
Edit
</button>
<button
class="iconified-button"
@click="
() => {
deleteIndex = index
modal_confirm.show()
}
"
>
<TrashIcon aria-hidden="true" />
Remove
</button>
<ButtonStyled>
<button
@click="
() => {
resetEdit()
editIndex = index
editTitle = item.title
editDescription = item.description
editFeatured = item.featured
editOrder = item.ordering
modal_edit_item.show()
}
"
>
<EditIcon aria-hidden="true" />
Edit
</button>
</ButtonStyled>
<ButtonStyled>
<button
@click="
() => {
deleteIndex = index
modal_confirm.show()
}
"
>
<TrashIcon aria-hidden="true" />
Remove
</button>
</ButtonStyled>
</div>
</div>
</div>
@@ -294,6 +290,7 @@ import {
XIcon,
} from '@modrinth/assets'
import {
ButtonStyled,
ConfirmModal,
DropArea,
FileInput,
@@ -501,43 +498,6 @@ onUnmounted(() => {
width: calc(100vw - 2 * var(--spacing-card-lg));
height: calc(100vh - 2 * var(--spacing-card-lg));
.circle-button {
padding: 0.5rem;
line-height: 1;
display: flex;
max-width: 2rem;
color: var(--color-button-text);
background-color: var(--color-button-bg);
border-radius: var(--size-rounded-max);
margin: 0;
box-shadow: inset 0px -1px 1px rgb(17 24 39 / 10%);
&:not(:last-child) {
margin-right: 0.5rem;
}
&:hover {
background-color: var(--color-button-bg-hover) !important;
svg {
color: var(--color-button-text-hover) !important;
}
}
&:active {
background-color: var(--color-button-bg-active) !important;
svg {
color: var(--color-button-text-active) !important;
}
}
svg {
height: 1rem;
width: 1rem;
}
}
.image {
position: absolute;
left: 50%;
@@ -613,14 +573,6 @@ onUnmounted(() => {
}
}
.buttons {
display: flex;
button {
margin-right: 0.5rem;
}
}
.items {
display: grid;
grid-template-rows: 1fr;
@@ -723,7 +675,7 @@ onUnmounted(() => {
word-wrap: anywhere;
}
.iconified-button {
label.button-like {
margin-left: auto;
}
}
@@ -738,8 +690,4 @@ onUnmounted(() => {
}
}
}
.brand-button {
color: var(--color-accent-contrast);
}
</style>

View File

@@ -81,29 +81,28 @@
size="md"
class="project__icon"
/>
<div class="input-stack">
<FileInput
id="project-icon"
:max-size="262144000"
:show-icon="true"
accept="image/png,image/jpeg,image/gif,image/webp"
class="choose-image iconified-button"
prompt="Upload icon"
aria-label="Upload icon"
:disabled="!hasPermission"
@change="showPreviewImage"
>
<UploadIcon aria-hidden="true" />
</FileInput>
<button
v-if="!deletedIcon && (previewImage || project.icon_url)"
class="iconified-button"
:disabled="!hasPermission"
@click="markIconForDeletion"
>
<TrashIcon aria-hidden="true" />
Remove icon
</button>
<div class="flex flex-col gap-2">
<ButtonStyled>
<FileInput
id="project-icon"
:max-size="262144000"
:show-icon="true"
accept="image/png,image/jpeg,image/gif,image/webp"
class="button-like choose-image"
prompt="Upload icon"
aria-label="Upload icon"
:disabled="!hasPermission"
@change="showPreviewImage"
>
<UploadIcon aria-hidden="true" />
</FileInput>
</ButtonStyled>
<ButtonStyled v-if="!deletedIcon && (previewImage || project.icon_url)">
<button :disabled="!hasPermission" @click="markIconForDeletion">
<TrashIcon aria-hidden="true" />
Remove icon
</button>
</ButtonStyled>
</div>
</div>
</div>
@@ -157,26 +156,25 @@
</label>
</div>
<div class="mt-2 flex items-center gap-2">
<FileInput
:max-size="524288"
:show-icon="true"
accept="image/png,image/jpeg,image/gif,image/webp"
class="iconified-button"
prompt="Upload banner"
:disabled="!hasPermission"
@change="showBannerPreview"
>
<UploadIcon aria-hidden="true" />
</FileInput>
<button
v-if="!deletedBanner && (bannerPreview || bannerGalleryImage?.url)"
class="iconified-button"
:disabled="!hasPermission"
@click="markBannerForDeletion"
>
<TrashIcon aria-hidden="true" />
Remove banner
</button>
<ButtonStyled>
<FileInput
:max-size="524288"
:show-icon="true"
accept="image/png,image/jpeg,image/gif,image/webp"
class="button-like"
prompt="Upload banner"
:disabled="!hasPermission"
@change="showBannerPreview"
>
<UploadIcon aria-hidden="true" />
</FileInput>
</ButtonStyled>
<ButtonStyled v-if="!deletedBanner && (bannerPreview || bannerGalleryImage?.url)">
<button :disabled="!hasPermission" @click="markBannerForDeletion">
<TrashIcon aria-hidden="true" />
Remove banner
</button>
</ButtonStyled>
</div>
<div class="mt-2 text-secondary">Gif, 468×60px recommended.</div>
</div>
@@ -285,15 +283,12 @@
Removes your project from Modrinth's servers and search. Clicking on this will delete your
project, so be extra careful!
</p>
<button
type="button"
class="iconified-button danger-button"
:disabled="!hasDeletePermission"
@click="$refs.modal_confirm.show()"
>
<TrashIcon aria-hidden="true" />
Delete project
</button>
<ButtonStyled color="red">
<button :disabled="!hasDeletePermission" @click="$refs.modal_confirm.show()">
<TrashIcon aria-hidden="true" />
Delete project
</button>
</ButtonStyled>
</section>
<UnsavedChangesPopup
:original="original"
@@ -319,6 +314,7 @@ import {
import { MIN_SUMMARY_CHARS } from '@modrinth/moderation'
import {
Avatar,
ButtonStyled,
Combobox,
ConfirmLeaveModal,
ConfirmModal,

View File

@@ -104,7 +104,7 @@
>
</label>
<div class="input-stack w-1/2">
<div class="flex w-1/2 flex-col gap-2">
<StyledInput
v-if="!current.nonSpdxLicense"
id="license-spdx"

View File

@@ -105,15 +105,12 @@
/>
</div>
<div class="button-group">
<button
type="button"
class="iconified-button brand-button"
:disabled="!hasServerChanges"
@click="saveServerChanges()"
>
<SaveIcon />
Save changes
</button>
<ButtonStyled color="brand">
<button :disabled="!hasServerChanges" @click="saveServerChanges()">
<SaveIcon />
Save changes
</button>
</ButtonStyled>
</div>
</section>
@@ -275,15 +272,12 @@
/>
</div>
<div class="button-group">
<button
type="button"
class="iconified-button brand-button"
:disabled="!hasChanges"
@click="saveChanges()"
>
<SaveIcon />
Save changes
</button>
<ButtonStyled color="brand">
<button :disabled="!hasChanges" @click="saveChanges()">
<SaveIcon />
Save changes
</button>
</ButtonStyled>
</div>
</section>
</div>
@@ -293,6 +287,7 @@
import { SaveIcon, TriangleAlertIcon } from '@modrinth/assets'
import { commonLinkDomains, isCommonUrl, isDiscordUrl, isLinkShortener } from '@modrinth/moderation'
import {
ButtonStyled,
DropdownSelect,
injectModrinthClient,
injectNotificationManager,

View File

@@ -41,31 +41,33 @@
@keypress.enter="inviteTeamMember()"
/>
<label for="username" class="hidden">Username</label>
<button
class="iconified-button brand-button"
:disabled="(currentMember?.permissions & MANAGE_INVITES) !== MANAGE_INVITES"
@click="inviteTeamMember()"
>
<UserPlusIcon />
Invite
</button>
<ButtonStyled color="brand">
<button
:disabled="(currentMember?.permissions & MANAGE_INVITES) !== MANAGE_INVITES"
@click="inviteTeamMember()"
>
<UserPlusIcon />
Invite
</button>
</ButtonStyled>
</div>
<div class="adjacent-input">
<span class="label">
<span class="label__title">Leave project</span>
<span class="label__description"> Remove yourself as a member of this project. </span>
</span>
<button
class="iconified-button danger-button"
:disabled="currentMember?.is_owner"
:title="
currentMember?.is_owner ? 'You cannot leave the project if you are the owner!' : ''
"
@click="leaveProject()"
>
<UserXIcon />
Leave project
</button>
<ButtonStyled color="red">
<button
:disabled="currentMember?.is_owner"
:title="
currentMember?.is_owner ? 'You cannot leave the project if you are the owner!' : ''
"
@click="leaveProject()"
>
<UserXIcon />
Leave project
</button>
</ButtonStyled>
</div>
</Card>
<div
@@ -88,16 +90,18 @@
<div class="side-buttons">
<Badge v-if="member.accepted" type="accepted" />
<Badge v-else type="pending" />
<button
class="square-button dropdown-icon"
@click="
openTeamMembers.indexOf(member.user.id) === -1
? openTeamMembers.push(member.user.id)
: (openTeamMembers = openTeamMembers.filter((it) => it !== member.user.id))
"
>
<DropdownIcon />
</button>
<ButtonStyled circular>
<button
class="dropdown-icon"
@click="
openTeamMembers.indexOf(member.user.id) === -1
? openTeamMembers.push(member.user.id)
: (openTeamMembers = openTeamMembers.filter((it) => it !== member.user.id))
"
>
<DropdownIcon />
</button>
</ButtonStyled>
</div>
</div>
<div class="content">
@@ -225,31 +229,30 @@
</div>
</template>
<div class="input-group">
<button
class="iconified-button brand-button"
:disabled="(currentMember?.permissions & EDIT_MEMBER) !== EDIT_MEMBER"
@click="updateTeamMember(index)"
>
<SaveIcon />
Save changes
</button>
<button
v-if="!member.is_owner"
class="iconified-button danger-button"
:disabled="(currentMember?.permissions & EDIT_MEMBER) !== EDIT_MEMBER"
@click="removeTeamMember(index)"
>
<UserXIcon />
Remove member
</button>
<button
v-if="!member.is_owner && currentMember?.is_owner && member.accepted"
class="iconified-button"
@click="openTransferModal(index, $event)"
>
<TransferIcon />
Transfer ownership
</button>
<ButtonStyled color="brand">
<button
:disabled="(currentMember?.permissions & EDIT_MEMBER) !== EDIT_MEMBER"
@click="updateTeamMember(index)"
>
<SaveIcon />
Save changes
</button>
</ButtonStyled>
<ButtonStyled v-if="!member.is_owner" color="red">
<button
:disabled="(currentMember?.permissions & EDIT_MEMBER) !== EDIT_MEMBER"
@click="removeTeamMember(index)"
>
<UserXIcon />
Remove member
</button>
</ButtonStyled>
<ButtonStyled v-if="!member.is_owner && currentMember?.is_owner && member.accepted">
<button @click="openTransferModal(index, $event)">
<TransferIcon />
Transfer ownership
</button>
</ButtonStyled>
</div>
</div>
</div>
@@ -305,19 +308,19 @@
force-direction="up"
:disabled="!currentMember?.is_owner || organizationOptions.length === 0"
/>
<button
class="btn btn-primary"
:disabled="!selectedOrganization"
@click="openTransferToOrgModal($event)"
>
<CheckIcon />
<span class="w-max"> Transfer management </span>
</button>
<ButtonStyled color="brand">
<button :disabled="!selectedOrganization" @click="openTransferToOrgModal($event)">
<CheckIcon />
<span class="w-max"> Transfer management </span>
</button>
</ButtonStyled>
</div>
<button v-if="organization" class="btn" @click="$refs.modal_remove.show()">
<OrganizationIcon />
Remove from organization
</button>
<ButtonStyled v-if="organization">
<button @click="$refs.modal_remove.show()">
<OrganizationIcon />
Remove from organization
</button>
</ButtonStyled>
</section>
<div
v-for="(member, index) in allOrgMembers"
@@ -339,16 +342,18 @@
<div class="side-buttons">
<Badge v-if="member.accepted" type="accepted" />
<Badge v-else type="pending" />
<button
class="square-button dropdown-icon"
@click="
openTeamMembers.indexOf(member.user.id) === -1
? openTeamMembers.push(member.user.id)
: (openTeamMembers = openTeamMembers.filter((it) => it !== member.user.id))
"
>
<DropdownIcon />
</button>
<ButtonStyled circular>
<button
class="dropdown-icon"
@click="
openTeamMembers.indexOf(member.user.id) === -1
? openTeamMembers.push(member.user.id)
: (openTeamMembers = openTeamMembers.filter((it) => it !== member.user.id))
"
>
<DropdownIcon />
</button>
</ButtonStyled>
</div>
</div>
<div class="content">
@@ -522,17 +527,18 @@
we don't allow clicking the button in that last case.
-->
<button
class="iconified-button brand-button"
:disabled="
(currentMember?.permissions & EDIT_MEMBER) !== EDIT_MEMBER ||
(!allOrgMembers[index].oldOverride && !allOrgMembers[index].override)
"
@click="updateOrgMember(index)"
>
<SaveIcon />
Save changes
</button>
<ButtonStyled color="brand">
<button
:disabled="
(currentMember?.permissions & EDIT_MEMBER) !== EDIT_MEMBER ||
(!allOrgMembers[index].oldOverride && !allOrgMembers[index].override)
"
@click="updateOrgMember(index)"
>
<SaveIcon />
Save changes
</button>
</ButtonStyled>
</div>
</div>
</div>
@@ -554,6 +560,7 @@ import {
import {
Avatar,
Badge,
ButtonStyled,
Card,
Checkbox,
Combobox,

View File

@@ -1,5 +1,5 @@
<template>
<section class="experimental-styles-within overflow-visible">
<section class="overflow-visible">
<!-- Loading state -->
<div
v-if="versionsLoading && !versions?.length"

View File

@@ -132,7 +132,7 @@
</div>
</div>
</NewModal>
<div class="page experimental-styles-within">
<div class="page">
<div
class="mb-4 flex items-center justify-between border-0 border-b border-solid border-divider pb-4"
>

View File

@@ -96,8 +96,8 @@ onMounted(() => {
</div>
<div class="mt-auto flex gap-2">
<ButtonStyled color="brand" class="flex-1">
<button class="w-full justify-center" @click="openPreview(id)">
<ButtonStyled color="brand">
<button class="w-full flex-1 justify-center" @click="openPreview(id)">
<PlayIcon class="h-4 w-4" aria-hidden="true" />
Preview
</button>

View File

@@ -1,6 +1,6 @@
<script setup lang="ts">
import { CopyIcon, LibraryIcon, PlayIcon, SearchIcon } from '@modrinth/assets'
import { ButtonStyled, Card, NewModal, StyledInput } from '@modrinth/ui'
import { ButtonStyled, NewModal, StyledInput } from '@modrinth/ui'
import { computed, onMounted, ref } from 'vue'
import emails from '~/templates/emails'
@@ -178,84 +178,82 @@ onMounted(() => {
</div>
<div class="input-group mt-4">
<button class="iconified-button transparent" type="button" @click="closePreview">
Close
</button>
<ButtonStyled type="transparent">
<button @click="closePreview">Close</button>
</ButtonStyled>
</div>
</div>
</div>
</NewModal>
<div class="normal-page__content">
<Card class="mb-6 flex flex-col gap-4">
<div class="flex flex-wrap items-center gap-3">
<StyledInput
id="email-search"
v-model="query"
type="search"
:icon="SearchIcon"
placeholder="Search templates..."
wrapper-class="w-72"
/>
<div class="flex flex-wrap items-center gap-3">
<StyledInput
id="email-search"
v-model="query"
type="search"
:icon="SearchIcon"
placeholder="Search templates..."
wrapper-class="w-72"
/>
<ButtonStyled color="brand">
<button :disabled="filtered.length === 0" @click="openAll">
<LibraryIcon class="h-4 w-4" aria-hidden="true" />
Open all ({{ counts.shown }})
</button>
</ButtonStyled>
<ButtonStyled color="brand">
<button :disabled="filtered.length === 0" @click="openAll">
<LibraryIcon class="h-4 w-4" aria-hidden="true" />
Open all ({{ counts.shown }})
</button>
</ButtonStyled>
<span class="text-sm text-secondary">
Showing <span class="font-medium text-contrast">{{ counts.shown }}</span> of
<span class="font-medium text-contrast">{{ counts.total }}</span>
</span>
</div>
<span class="text-sm text-secondary">
Showing <span class="font-medium text-contrast">{{ counts.shown }}</span> of
<span class="font-medium text-contrast">{{ counts.total }}</span>
</span>
</div>
<div
v-if="filtered.length === 0"
class="rounded-lg border border-dashed border-divider px-6 py-10 text-center text-sm text-secondary"
<div
v-if="filtered.length === 0"
class="mt-4 border-0 border-b border-solid border-surface-4 pb-4"
>
No templates match your search.
</div>
<ul v-else class="m-0 mt-4 grid gap-3 p-0 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
<li
v-for="id in filtered"
:key="id"
class="group flex flex-col justify-between rounded-2xl border border-solid border-surface-4 bg-surface-3 p-4 shadow-sm transition hover:shadow"
>
No templates match your search.
</div>
<ul v-else class="grid gap-4 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
<li
v-for="id in filtered"
:key="id"
class="hover:border-green/70 group flex flex-col justify-between rounded-lg border border-divider bg-button-bg p-4 shadow-sm transition hover:shadow"
>
<div class="mb-3">
<div class="font-mono text-sm font-semibold tracking-tight text-contrast">
{{ id }}
</div>
<div class="mt-1 truncate text-xs text-secondary">
/_internal/templates/email/{{ id }}
</div>
<div class="mb-3">
<div class="font-mono text-sm font-semibold tracking-tight text-contrast">
{{ id }}
</div>
<div class="mt-auto flex gap-2">
<ButtonStyled color="brand" class="flex-1">
<button class="w-full justify-center" @click="openPreview(id, $event)">
<PlayIcon class="h-4 w-4" aria-hidden="true" />
Preview
</button>
</ButtonStyled>
<ButtonStyled>
<button class="justify-center" title="Copy preview URL" @click="copy(id)">
<CopyIcon class="h-4 w-4" aria-hidden="true" />
</button>
</ButtonStyled>
<div class="mt-1 truncate text-xs text-secondary">
/_internal/templates/email/{{ id }}
</div>
</li>
</ul>
</Card>
</div>
<p class="mt-2 text-xs text-secondary">
<div class="mt-auto flex gap-2">
<ButtonStyled color="brand">
<button @click="openPreview(id, $event)">
<PlayIcon aria-hidden="true" />
Preview
</button>
</ButtonStyled>
<ButtonStyled circular type="outlined">
<button title="Copy preview URL" @click="copy(id)">
<CopyIcon aria-hidden="true" />
</button>
</ButtonStyled>
</div>
</li>
</ul>
<p class="mt-4">
All templates come from
<code class="rounded bg-code-bg px-1 py-0.5 text-[11px] text-code-text"
<code class="rounded bg-code-bg px-1 py-0.5 text-sm text-code-text"
>src/emails/index.ts</code
>. Popouts render via
<code class="rounded bg-code-bg px-1 py-0.5 text-[11px] text-code-text"
<code class="rounded bg-code-bg px-1 py-0.5 text-sm text-code-text"
>/_internal/templates/email/[template]</code
>.
</p>

View File

@@ -120,7 +120,7 @@
</div>
</NewModal>
<AssignNoticeModal ref="assignNoticeModal" @close="refreshNotices" />
<div class="page experimental-styles-within">
<div class="page">
<div
class="mb-6 flex items-end justify-between border-0 border-b border-solid border-divider pb-4"
>

View File

@@ -8,7 +8,7 @@
proceed-label="Cancel transfer"
@proceed="confirmCancel"
/>
<div class="experimental-styles-within mx-auto max-w-[78.5rem] p-4">
<div class="mx-auto max-w-[78.5rem] p-4">
<div
class="mb-6 flex items-end justify-between border-0 border-b border-solid border-divider pb-4"
>

File diff suppressed because one or more lines are too long

View File

@@ -31,17 +31,19 @@ useSeoMeta({
margin: 0;
}
.auth-container .btn {
.auth-container .btn-wrapper :is(a, button) {
font-weight: 700;
min-height: 2.5rem;
text-decoration: none;
}
.centered-btn {
.centered-btn :is(a, button),
.centered-btn:is(a, button) {
margin-inline: auto;
}
.btn.continue-btn svg {
.continue-btn :is(a, button) svg,
.continue-btn:is(a, button) svg {
margin: 0 0 0 0.5rem;
}
@@ -52,19 +54,19 @@ useSeoMeta({
width: 100%;
}
.third-party .btn {
.third-party a {
width: 100%;
vertical-align: middle;
}
.third-party .btn svg {
.third-party a svg {
margin-right: var(--gap-sm);
width: 1.25rem;
height: 1.25rem;
}
@media screen and (max-width: 25.5rem) {
.third-party .btn {
.third-party a {
grid-column: 1 / 3;
}
}

View File

@@ -55,14 +55,18 @@
</div>
</div>
<div class="button-row">
<Button class="wide-button" large :action="onReject" :disabled="pending">
<XIcon />
{{ formatMessage(messages.decline) }}
</Button>
<Button class="wide-button" color="primary" large :action="onAuthorize" :disabled="pending">
<CheckIcon />
{{ formatMessage(messages.authorize) }}
</Button>
<ButtonStyled size="large">
<button class="wide-button" :disabled="pending" @click="onReject">
<XIcon />
{{ formatMessage(messages.decline) }}
</button>
</ButtonStyled>
<ButtonStyled color="brand" size="large">
<button class="wide-button" :disabled="pending" @click="onAuthorize">
<CheckIcon />
{{ formatMessage(messages.authorize) }}
</button>
</ButtonStyled>
</div>
<div class="redirection-notice">
<p class="redirect-instructions">
@@ -83,7 +87,7 @@
import { CheckIcon, XIcon } from '@modrinth/assets'
import {
Avatar,
Button,
ButtonStyled,
commonMessages,
defineMessages,
injectModrinthClient,

View File

@@ -22,13 +22,15 @@
<HCaptcha v-if="globals?.captcha_enabled" ref="captcha" v-model="token" />
<button
class="btn btn-primary centered-btn"
:disabled="globals?.captcha_enabled ? !token : false"
@click="recovery"
>
<SendIcon /> {{ formatMessage(methodChoiceMessages.action) }}
</button>
<ButtonStyled color="brand">
<button
class="mx-auto"
:disabled="globals?.captcha_enabled ? !token : false"
@click="recovery"
>
<SendIcon /> {{ formatMessage(methodChoiceMessages.action) }}
</button>
</ButtonStyled>
</template>
<template v-else-if="step === 'passed_challenge'">
<p>{{ formatMessage(postChallengeMessages.description) }}</p>
@@ -57,9 +59,11 @@
wrapper-class="w-full"
/>
<button class="auth-form__input btn btn-primary continue-btn" @click="changePassword">
{{ formatMessage(postChallengeMessages.action) }}
</button>
<ButtonStyled color="brand">
<button class="auth-form__input continue-btn" @click="changePassword">
{{ formatMessage(postChallengeMessages.action) }}
</button>
</ButtonStyled>
</template>
</section>
</div>
@@ -67,6 +71,7 @@
<script setup>
import { KeyIcon, MailIcon, SendIcon } from '@modrinth/assets'
import {
ButtonStyled,
commonMessages,
defineMessages,
injectModrinthClient,

View File

@@ -23,38 +23,52 @@
@keyup.enter="begin2FASignIn"
/>
<button class="btn btn-primary continue-btn" @click="begin2FASignIn">
{{ formatMessage(commonMessages.signInButton) }} <RightArrowIcon />
</button>
<ButtonStyled color="brand">
<button class="continue-btn" @click="begin2FASignIn">
{{ formatMessage(commonMessages.signInButton) }} <RightArrowIcon />
</button>
</ButtonStyled>
</template>
<template v-else>
<h1>{{ formatMessage(messages.signInWithLabel) }}</h1>
<section class="third-party">
<a class="btn" :href="getAuthUrl('discord', redirectTarget)">
<DiscordColorIcon />
<span>Discord</span>
</a>
<a class="btn" :href="getAuthUrl('github', redirectTarget)">
<GitHubColorIcon />
<span>GitHub</span>
</a>
<a class="btn" :href="getAuthUrl('microsoft', redirectTarget)">
<MicrosoftColorIcon />
<span>Microsoft</span>
</a>
<a class="btn" :href="getAuthUrl('google', redirectTarget)">
<GoogleColorIcon />
<span>Google</span>
</a>
<a class="btn" :href="getAuthUrl('steam', redirectTarget)">
<SteamColorIcon />
<span>Steam</span>
</a>
<a class="btn" :href="getAuthUrl('gitlab', redirectTarget)">
<GitLabColorIcon />
<span>GitLab</span>
</a>
<ButtonStyled>
<a :href="getAuthUrl('discord', redirectTarget)">
<DiscordColorIcon />
<span>Discord</span>
</a>
</ButtonStyled>
<ButtonStyled>
<a :href="getAuthUrl('github', redirectTarget)">
<GitHubColorIcon />
<span>GitHub</span>
</a>
</ButtonStyled>
<ButtonStyled>
<a :href="getAuthUrl('microsoft', redirectTarget)">
<MicrosoftColorIcon />
<span>Microsoft</span>
</a>
</ButtonStyled>
<ButtonStyled>
<a :href="getAuthUrl('google', redirectTarget)">
<GoogleColorIcon />
<span>Google</span>
</a>
</ButtonStyled>
<ButtonStyled>
<a :href="getAuthUrl('steam', redirectTarget)">
<SteamColorIcon />
<span>Steam</span>
</a>
</ButtonStyled>
<ButtonStyled>
<a :href="getAuthUrl('gitlab', redirectTarget)">
<GitLabColorIcon />
<span>GitLab</span>
</a>
</ButtonStyled>
</section>
<h1>{{ formatMessage(messages.usePasswordLabel) }}</h1>
@@ -85,13 +99,15 @@
<HCaptcha v-if="globals?.captcha_enabled" ref="captcha" v-model="token" />
<button
class="btn btn-primary continue-btn centered-btn"
:disabled="globals?.captcha_enabled ? !token : false"
@click="beginPasswordSignIn()"
>
{{ formatMessage(commonMessages.signInButton) }} <RightArrowIcon />
</button>
<ButtonStyled color="brand">
<button
class="continue-btn centered-btn"
:disabled="globals?.captcha_enabled ? !token : false"
@click="beginPasswordSignIn()"
>
{{ formatMessage(commonMessages.signInButton) }} <RightArrowIcon />
</button>
</ButtonStyled>
<div class="auth-form__additional-options">
<IntlFormatted :message-id="messages.additionalOptionsLabel">
@@ -137,6 +153,7 @@ import {
SteamColorIcon,
} from '@modrinth/assets'
import {
ButtonStyled,
commonMessages,
defineMessages,
injectModrinthClient,

View File

@@ -3,30 +3,42 @@
<h1>{{ formatMessage(messages.signUpWithTitle) }}</h1>
<section class="third-party">
<a class="btn discord-btn" :href="getAuthUrl('discord', redirectTarget)">
<DiscordColorIcon />
<span>Discord</span>
</a>
<a class="btn" :href="getAuthUrl('github', redirectTarget)">
<GitHubColorIcon />
<span>GitHub</span>
</a>
<a class="btn" :href="getAuthUrl('microsoft', redirectTarget)">
<MicrosoftColorIcon />
<span>Microsoft</span>
</a>
<a class="btn" :href="getAuthUrl('google', redirectTarget)">
<GoogleColorIcon />
<span>Google</span>
</a>
<a class="btn" :href="getAuthUrl('steam', redirectTarget)">
<SteamColorIcon />
<span>Steam</span>
</a>
<a class="btn" :href="getAuthUrl('gitlab', redirectTarget)">
<GitLabColorIcon />
<span>GitLab</span>
</a>
<ButtonStyled>
<a class="discord-btn" :href="getAuthUrl('discord', redirectTarget)">
<DiscordColorIcon />
<span>Discord</span>
</a>
</ButtonStyled>
<ButtonStyled>
<a :href="getAuthUrl('github', redirectTarget)">
<GitHubColorIcon />
<span>GitHub</span>
</a>
</ButtonStyled>
<ButtonStyled>
<a :href="getAuthUrl('microsoft', redirectTarget)">
<MicrosoftColorIcon />
<span>Microsoft</span>
</a>
</ButtonStyled>
<ButtonStyled>
<a :href="getAuthUrl('google', redirectTarget)">
<GoogleColorIcon />
<span>Google</span>
</a>
</ButtonStyled>
<ButtonStyled>
<a :href="getAuthUrl('steam', redirectTarget)">
<SteamColorIcon />
<span>Steam</span>
</a>
</ButtonStyled>
<ButtonStyled>
<a :href="getAuthUrl('gitlab', redirectTarget)">
<GitLabColorIcon />
<span>GitLab</span>
</a>
</ButtonStyled>
</section>
<h1>{{ formatMessage(messages.createAccountTitle) }}</h1>
@@ -100,13 +112,15 @@
<HCaptcha v-if="globals?.captcha_enabled" ref="captcha" v-model="token" />
<button
class="btn btn-primary continue-btn centered-btn"
:disabled="globals?.captcha_enabled ? !token : false"
@click="createAccount"
>
{{ formatMessage(messages.createAccountButton) }} <RightArrowIcon />
</button>
<ButtonStyled color="brand">
<button
class="continue-btn centered-btn"
:disabled="globals?.captcha_enabled ? !token : false"
@click="createAccount"
>
{{ formatMessage(messages.createAccountButton) }} <RightArrowIcon />
</button>
</ButtonStyled>
<div class="auth-form__additional-options">
{{ formatMessage(messages.alreadyHaveAccountLabel) }}
@@ -138,6 +152,7 @@ import {
UserIcon,
} from '@modrinth/assets'
import {
ButtonStyled,
Checkbox,
commonMessages,
defineMessages,

View File

@@ -6,9 +6,11 @@
<section class="auth-form">
<p>{{ formatMessage(alreadyVerifiedMessages.description) }}</p>
<NuxtLink class="btn" to="/settings/account">
<SettingsIcon /> {{ formatMessage(messages.accountSettings) }}
</NuxtLink>
<ButtonStyled>
<NuxtLink to="/settings/account">
<SettingsIcon /> {{ formatMessage(messages.accountSettings) }}
</NuxtLink>
</ButtonStyled>
</section>
</template>

View File

@@ -24,10 +24,12 @@
:description="formatMessage(messages.subscribeCheckbox)"
/>
<button class="btn btn-primary centered-btn" @click="continueSignUp">
{{ formatMessage(commonMessages.continueButton) }}
<RightArrowIcon />
</button>
<ButtonStyled color="brand">
<button class="centered-btn" @click="continueSignUp">
{{ formatMessage(commonMessages.continueButton) }}
<RightArrowIcon />
</button>
</ButtonStyled>
<p class="tos-text">
<IntlFormatted :message-id="messages.tosLabel">
@@ -50,6 +52,7 @@
<script setup>
import { RightArrowIcon, WavingRinthbot } from '@modrinth/assets'
import {
ButtonStyled,
Checkbox,
commonMessages,
defineMessages,

View File

@@ -116,14 +116,14 @@
</RadioButtons>
</div>
<div class="flex justify-end gap-2">
<ButtonStyled class="w-24">
<button @click="() => editModal?.hide()">
<ButtonStyled>
<button class="w-24" @click="() => editModal?.hide()">
<XIcon aria-hidden="true" />
{{ formatMessage(commonMessages.cancelButton) }}
</button>
</ButtonStyled>
<ButtonStyled color="brand" class="w-36">
<button :disabled="saving" @click="save()">
<ButtonStyled color="brand">
<button class="w-36" :disabled="saving" @click="save()">
<SpinnerIcon v-if="saving" class="animate-spin" aria-hidden="true" />
<SaveIcon v-else aria-hidden="true" />
{{
@@ -193,7 +193,7 @@
}"
>
<template #stat="{ children }">
<span class="primary-stat__counter">
<span>
<component :is="() => normalizeChildren(children)" />
</span>
</template>
@@ -333,24 +333,19 @@
"
>
<template v-if="canEdit || collection.id === 'following'" #actions>
<button
v-if="canEdit"
class="iconified-button remove-btn"
:disabled="removing"
@click="() => removeProject(project)"
>
<SpinnerIcon v-if="removing" class="animate-spin" aria-hidden="true" />
<XIcon v-else aria-hidden="true" />
{{ formatMessage(messages.removeProjectButton) }}
</button>
<button
v-if="collection.id === 'following'"
class="iconified-button"
@click="unfollowProject(project)"
>
<HeartMinusIcon aria-hidden="true" />
{{ formatMessage(messages.unfollowProjectButton) }}
</button>
<ButtonStyled v-if="canEdit">
<button class="remove-btn" :disabled="removing" @click="() => removeProject(project)">
<SpinnerIcon v-if="removing" class="animate-spin" aria-hidden="true" />
<XIcon v-else aria-hidden="true" />
{{ formatMessage(messages.removeProjectButton) }}
</button>
</ButtonStyled>
<ButtonStyled v-if="collection.id === 'following'">
<button @click="unfollowProject(project)">
<HeartMinusIcon aria-hidden="true" />
{{ formatMessage(messages.unfollowProjectButton) }}
</button>
</ButtonStyled>
</template>
</ProjectCard>
</ProjectCardList>

View File

@@ -30,14 +30,12 @@
<span class="font-semibold text-secondary">{{ selected }}</span>
</DropdownSelect>
<Button
color="primary"
class="ml-auto"
@click="(event) => $refs.modal_creation.show(event)"
>
<PlusIcon aria-hidden="true" />
{{ formatMessage(messages.createNewButton) }}
</Button>
<ButtonStyled color="brand">
<button class="ml-auto" @click="(event) => $refs.modal_creation.show(event)">
<PlusIcon aria-hidden="true" />
{{ formatMessage(messages.createNewButton) }}
</button>
</ButtonStyled>
</div>
</div>
<div class="collections-grid">
@@ -146,7 +144,7 @@ import {
} from '@modrinth/assets'
import {
Avatar,
Button,
ButtonStyled,
commonMessages,
defineMessages,
DropdownSelect,

View File

@@ -1,5 +1,5 @@
<template>
<div class="dashboard-overview">
<div>
<section class="universal-card dashboard-header">
<Avatar :src="auth.user.avatar_url" size="md" circle :alt="auth.user.username" />
<div class="username">
@@ -12,7 +12,7 @@
</NuxtLink>
</div>
</section>
<div class="dashboard-notifications">
<div>
<section class="universal-card">
<div class="header__row">
<h2 class="header__title text-2xl">
@@ -50,44 +50,12 @@
</template>
<div v-else class="universal-body">
<p>{{ formatMessage(messages.noUnreadNotifications) }}</p>
<nuxt-link class="iconified-button !mt-4" to="/dashboard/notifications/history">
<HistoryIcon />
{{ formatMessage(messages.viewNotificationHistory) }}
</nuxt-link>
</div>
</section>
</div>
<div class="dashboard-analytics">
<section class="universal-card">
<h2>{{ formatMessage(commonMessages.analyticsButton) }}</h2>
<div class="grid-display">
<div class="grid-display__item">
<div class="label">{{ formatMessage(messages.totalDownloads) }}</div>
<div class="value">
{{ $formatNumber(projects.reduce((agg, x) => agg + x.downloads, 0)) }}
</div>
<span>{{
formatMessage(messages.fromProjects, { count: downloadsProjectCount })
}}</span>
<!-- <NuxtLink class="goto-link" to="/dashboard/analytics"-->
<!-- >View breakdown-->
<!-- <ChevronRightIcon-->
<!-- class="featured-header-chevron"-->
<!-- aria-hidden="true"-->
<!-- /></NuxtLink>-->
</div>
<div class="grid-display__item">
<div class="label">{{ formatMessage(messages.totalFollowers) }}</div>
<div class="value">
{{ $formatNumber(projects.reduce((agg, x) => agg + x.followers, 0)) }}
</div>
<span>
<span>{{
formatMessage(messages.fromProjects, { count: followersProjectCount })
}}</span>
</span>
</div>
<ButtonStyled>
<nuxt-link to="/dashboard/notifications/history" class="!mt-4 w-fit">
<HistoryIcon />
{{ formatMessage(messages.viewNotificationHistory) }}
</nuxt-link>
</ButtonStyled>
</div>
</section>
</div>
@@ -97,6 +65,7 @@
import { ChevronRightIcon, HistoryIcon } from '@modrinth/assets'
import {
Avatar,
ButtonStyled,
commonMessages,
defineMessages,
injectModrinthClient,
@@ -152,19 +121,6 @@ useHead({
const auth = await useAuth()
const client = injectModrinthClient()
const { data: projects } = useQuery({
queryKey: computed(() => ['user', auth.value?.user?.id, 'projects']),
queryFn: () => client.labrinth.users_v2.getProjects(auth.value?.user?.id),
placeholderData: [],
})
const downloadsProjectCount = computed(
() => projects.value.filter((project) => project.downloads > 0).length,
)
const followersProjectCount = computed(
() => projects.value.filter((project) => project.followers > 0).length,
)
const { data, refetch } = useQuery({
queryKey: computed(() => ['user', auth.value?.user?.id, 'notifications']),
queryFn: async () => {
@@ -190,40 +146,6 @@ const notifications = computed(() => {
const extraNotifs = computed(() => (data.value ? data.value.extraNotifs : 0))
</script>
<style lang="scss">
.dashboard-overview {
display: grid;
grid-template:
'header header'
'notifications analytics' / 1fr auto;
gap: var(--spacing-card-md);
> .universal-card {
margin: 0;
}
@media screen and (max-width: 750px) {
display: flex;
flex-direction: column;
}
}
.dashboard-notifications {
grid-area: notifications;
//display: flex;
//flex-direction: column;
//gap: var(--spacing-card-md);
a.view-more-notifs {
display: flex;
width: fit-content;
margin-left: auto;
}
}
.dashboard-analytics {
grid-area: analytics;
}
.dashboard-header {
display: flex;
gap: var(--spacing-card-bg);

View File

@@ -21,14 +21,18 @@
</h2>
</div>
<template v-if="!history">
<Button v-if="data.hasRead" @click="updateRoute()">
<HistoryIcon />
{{ formatMessage(messages.viewHistory) }}
</Button>
<Button v-if="notifications.length > 0" color="danger" @click="readAll()">
<CheckCheckIcon />
{{ formatMessage(messages.markAllAsRead) }}
</Button>
<ButtonStyled v-if="data.hasRead">
<button @click="updateRoute()">
<HistoryIcon />
{{ formatMessage(messages.viewHistory) }}
</button>
</ButtonStyled>
<ButtonStyled v-if="notifications.length > 0" color="red">
<button @click="readAll()">
<CheckCheckIcon />
{{ formatMessage(messages.markAllAsRead) }}
</button>
</ButtonStyled>
</template>
</div>
<Chips
@@ -67,7 +71,7 @@
<script setup>
import { CheckCheckIcon, HistoryIcon } from '@modrinth/assets'
import {
Button,
ButtonStyled,
Chips,
commonMessages,
defineMessages,

View File

@@ -5,10 +5,12 @@
<div class="header__row">
<h2 class="header__title text-2xl">{{ formatMessage(messages.organizationsTitle) }}</h2>
<div class="input-group">
<button class="iconified-button brand-button" @click="openCreateOrgModal">
<PlusIcon aria-hidden="true" />
{{ formatMessage(messages.createOrganization) }}
</button>
<ButtonStyled color="brand">
<button @click="openCreateOrgModal">
<PlusIcon aria-hidden="true" />
{{ formatMessage(messages.createOrganization) }}
</button>
</ButtonStyled>
</div>
</div>
<template v-if="orgs?.length > 0">
@@ -51,7 +53,7 @@
<script setup>
import { PlusIcon, UsersIcon } from '@modrinth/assets'
import { Avatar, defineMessages, injectModrinthClient, useVIntl } from '@modrinth/ui'
import { Avatar, ButtonStyled, defineMessages, injectModrinthClient, useVIntl } from '@modrinth/ui'
import { useQuery } from '@tanstack/vue-query'
import OrganizationCreateModal from '~/components/ui/create/OrganizationCreateModal.vue'

View File

@@ -7,68 +7,77 @@
<label for="issue-tracker-input" :title="formatMessage(messages.issueTrackerDescription)">
<span class="label__title">{{ formatMessage(messages.issueTrackerLabel) }}</span>
</label>
<div class="input-group shrink-first">
<div class="flex gap-2">
<StyledInput
id="issue-tracker-input"
v-model="editLinks.issues.val"
:disabled="editLinks.issues.clear"
type="url"
class="w-full"
:placeholder="getLinkInputPlaceholder(editLinks.issues.clear)"
:maxlength="2048"
/>
<button
v-tooltip="formatMessage(messages.clearLinkLabel)"
:aria-label="formatMessage(messages.clearLinkLabel)"
class="square-button label-button"
:data-active="editLinks.issues.clear"
@click="editLinks.issues.clear = !editLinks.issues.clear"
>
<TrashIcon />
</button>
<ButtonStyled circular>
<button
v-tooltip="formatMessage(messages.clearLinkLabel)"
class="label-button"
:aria-label="formatMessage(messages.clearLinkLabel)"
:data-active="editLinks.issues.clear"
@click="editLinks.issues.clear = !editLinks.issues.clear"
>
<TrashIcon />
</button>
</ButtonStyled>
</div>
<label for="source-code-input" :title="formatMessage(messages.sourceCodeDescription)">
<span class="label__title">{{ formatMessage(messages.sourceCodeLabel) }}</span>
</label>
<div class="input-group shrink-first">
<div class="flex gap-2">
<StyledInput
id="source-code-input"
v-model="editLinks.source.val"
:disabled="editLinks.source.clear"
type="url"
class="w-full"
:maxlength="2048"
:placeholder="getLinkInputPlaceholder(editLinks.source.clear)"
/>
<button
v-tooltip="formatMessage(messages.clearLinkLabel)"
:aria-label="formatMessage(messages.clearLinkLabel)"
class="square-button label-button"
:data-active="editLinks.source.clear"
@click="editLinks.source.clear = !editLinks.source.clear"
>
<TrashIcon />
</button>
<ButtonStyled circular>
<button
v-tooltip="formatMessage(messages.clearLinkLabel)"
class="label-button"
:aria-label="formatMessage(messages.clearLinkLabel)"
:data-active="editLinks.source.clear"
@click="editLinks.source.clear = !editLinks.source.clear"
>
<TrashIcon />
</button>
</ButtonStyled>
</div>
<label for="wiki-page-input" :title="formatMessage(messages.wikiPageDescription)">
<span class="label__title">{{ formatMessage(messages.wikiPageLabel) }}</span>
</label>
<div class="input-group shrink-first">
<div class="flex gap-2">
<StyledInput
id="wiki-page-input"
v-model="editLinks.wiki.val"
:disabled="editLinks.wiki.clear"
type="url"
class="w-full"
:maxlength="2048"
:placeholder="getLinkInputPlaceholder(editLinks.wiki.clear)"
/>
<button
v-tooltip="formatMessage(messages.clearLinkLabel)"
:aria-label="formatMessage(messages.clearLinkLabel)"
class="square-button label-button"
:data-active="editLinks.wiki.clear"
@click="editLinks.wiki.clear = !editLinks.wiki.clear"
>
<TrashIcon />
</button>
<ButtonStyled circular>
<button
v-tooltip="formatMessage(messages.clearLinkLabel)"
class="label-button"
:aria-label="formatMessage(messages.clearLinkLabel)"
:data-active="editLinks.wiki.clear"
@click="editLinks.wiki.clear = !editLinks.wiki.clear"
>
<TrashIcon />
</button>
</ButtonStyled>
</div>
<label
for="discord-invite-input"
@@ -76,24 +85,27 @@
>
<span class="label__title">{{ formatMessage(messages.discordInviteLabel) }}</span>
</label>
<div class="input-group shrink-first">
<div class="flex gap-2">
<StyledInput
id="discord-invite-input"
v-model="editLinks.discord.val"
:disabled="editLinks.discord.clear"
class="w-full"
type="url"
:maxlength="2048"
:placeholder="getLinkInputPlaceholder(editLinks.discord.clear, true)"
/>
<button
v-tooltip="formatMessage(messages.clearLinkLabel)"
:aria-label="formatMessage(messages.clearLinkLabel)"
class="square-button label-button"
:data-active="editLinks.discord.clear"
@click="editLinks.discord.clear = !editLinks.discord.clear"
>
<TrashIcon />
</button>
<ButtonStyled circular>
<button
v-tooltip="formatMessage(messages.clearLinkLabel)"
class="label-button"
:aria-label="formatMessage(messages.clearLinkLabel)"
:data-active="editLinks.discord.clear"
@click="editLinks.discord.clear = !editLinks.discord.clear"
>
<TrashIcon />
</button>
</ButtonStyled>
</div>
</section>
<p>
@@ -128,15 +140,19 @@
:label="formatMessage(messages.showAllProjects)"
:description="formatMessage(messages.showAllProjects)"
/>
<div class="push-right input-group">
<button class="iconified-button" @click="$refs.editLinksModal.hide()">
<XIcon />
{{ formatMessage(commonMessages.cancelButton) }}
</button>
<button class="iconified-button brand-button" @click="bulkEditLinks()">
<SaveIcon />
{{ formatMessage(commonMessages.saveChangesButton) }}
</button>
<div class="input-group ml-auto mt-4">
<ButtonStyled type="outlined">
<button @click="$refs.editLinksModal.hide()">
<XIcon />
{{ formatMessage(commonMessages.cancelButton) }}
</button>
</ButtonStyled>
<ButtonStyled color="brand">
<button @click="bulkEditLinks()">
<SaveIcon />
{{ formatMessage(commonMessages.saveChangesButton) }}
</button>
</ButtonStyled>
</div>
</div>
</NewModal>
@@ -145,10 +161,12 @@
<div class="header__row">
<h2 class="header__title text-2xl">{{ formatMessage(messages.headTitle) }}</h2>
<div class="input-group">
<button class="iconified-button brand-button" @click="$refs.modal_creation.show($event)">
<PlusIcon />
{{ formatMessage(commonMessages.createAProjectButton) }}
</button>
<ButtonStyled color="brand">
<button @click="$refs.modal_creation.show($event)">
<PlusIcon />
{{ formatMessage(commonMessages.createAProjectButton) }}
</button>
</ButtonStyled>
</div>
</div>
<p v-if="projects.length < 1">
@@ -157,14 +175,12 @@
<template v-else>
<p>{{ formatMessage(messages.bulkEditHint) }}</p>
<div class="input-group">
<button
class="iconified-button"
:disabled="selectedProjects.length === 0"
@click="$refs.editLinksModal.show()"
>
<EditIcon />
{{ formatMessage(messages.editLinksButton) }}
</button>
<ButtonStyled>
<button :disabled="selectedProjects.length === 0" @click="$refs.editLinksModal.show()">
<EditIcon />
{{ formatMessage(messages.editLinksButton) }}
</button>
</ButtonStyled>
<div class="push-right">
<div class="labeled-control-row">
{{ formatMessage(commonMessages.sortByLabel) }}
@@ -175,14 +191,15 @@
:options="sortOptions"
@update:model-value="projects = updateSort(projects, sortBy, descending)"
/>
<button
v-tooltip="formatMessage(descending ? messages.descending : messages.ascending)"
class="square-button"
@click="updateDescending()"
>
<SortDescIcon v-if="descending" />
<SortAscIcon v-else />
</button>
<ButtonStyled circular>
<button
v-tooltip="formatMessage(descending ? messages.descending : messages.ascending)"
@click="updateDescending()"
>
<SortDescIcon v-if="descending" />
<SortAscIcon v-else />
</button>
</ButtonStyled>
</div>
</div>
</div>

View File

@@ -603,9 +603,7 @@
</h2>
</div>
<div
class="experimental-styles-within flex w-full flex-col-reverse gap-2 md:w-auto md:flex-col md:items-center"
>
<div class="flex w-full flex-col-reverse gap-2 md:w-auto md:flex-col md:items-center">
<ButtonStyled color="standard" size="large">
<button class="w-full md:w-fit" @click="selectProduct('custom')">
{{ formatMessage(messages.getStartedButton) }}

View File

@@ -208,7 +208,7 @@
<p>
<IntlFormatted :message-id="messages.playWithLauncherDescription">
<template #link="{ children }">
<nuxt-link class="title-link" to="/app">
<nuxt-link class="underline hover:brightness-[--hover-brightness]" to="/app">
<component :is="() => children" />
</nuxt-link>
</template>

View File

@@ -1,7 +1,5 @@
<template>
<div
class="experimental-styles-within relative mx-auto mb-6 flex min-h-screen w-full max-w-[1280px] flex-col px-6"
>
<div class="relative mx-auto mb-6 flex min-h-screen w-full max-w-[1280px] flex-col px-6">
<h1>Moderation</h1>
<NavTabs :links="moderationLinks" class="mb-4 hidden sm:flex" />
<div class="mb-4 sm:hidden">

View File

@@ -57,7 +57,7 @@
</Combobox>
</div>
<ButtonStyled color="orange" class="w-full sm:w-auto">
<ButtonStyled color="orange">
<button
class="flex !h-[40px] w-full items-center justify-center gap-2 sm:w-auto"
:disabled="paginatedProjects?.length === 0"

View File

@@ -108,7 +108,7 @@ onMounted(() => {
</script>
<template>
<div class="page experimental-styles-within py-6">
<div class="page py-6">
<div
class="flex flex-wrap items-center justify-between gap-4 border-0 border-b-[1px] border-solid border-divider px-6 pb-6"
>
@@ -122,7 +122,7 @@ onMounted(() => {
<RssIcon />
</a>
</ButtonStyled>
<ButtonStyled circular icon-only>
<ButtonStyled circular>
<a v-tooltip="`Changelog`" href="/news/changelog" aria-label="Changelog">
<GitGraphIcon />
</a>

View File

@@ -1,5 +1,5 @@
<template>
<div class="page experimental-styles-within">
<div class="page">
<h1 class="m-0 text-3xl font-extrabold">Changelog</h1>
<p class="my-3">Keep up-to-date on what's new with Modrinth.</p>
<NuxtPage />

View File

@@ -41,7 +41,7 @@ useSeoMeta({
</script>
<template>
<div class="page experimental-styles-within py-6">
<div class="page py-6">
<div class="flex flex-wrap items-center justify-between gap-4 px-6">
<div>
<h1 class="m-0 text-3xl font-extrabold">News</h1>
@@ -53,7 +53,7 @@ useSeoMeta({
<RssIcon />
</a>
</ButtonStyled>
<ButtonStyled circular icon-only>
<ButtonStyled circular>
<a v-tooltip="`Changelog`" href="/news/changelog" aria-label="Changelog">
<GitGraphIcon />
</a>

View File

@@ -4,7 +4,7 @@
</div>
<div
v-else-if="organization"
class="experimental-styles-within new-page sidebar"
class="new-page sidebar"
:class="{ 'alt-layout': cosmetics.leftContentLayout || routeHasSettings }"
>
<ModalCreation ref="modal_creation" :organization-id="organization.id" />
@@ -176,14 +176,18 @@
<h2>Invitation to join {{ organization.name }}</h2>
<p>You have been invited to join {{ organization.name }}.</p>
<div class="input-group">
<button class="iconified-button brand-button" @click="onAcceptInvite">
<CheckIcon />
Accept
</button>
<button class="iconified-button danger-button" @click="onDeclineInvite">
<XIcon />
Decline
</button>
<ButtonStyled color="brand">
<button @click="onAcceptInvite">
<CheckIcon />
Accept
</button>
</ButtonStyled>
<ButtonStyled color="red">
<button @click="onDeclineInvite">
<XIcon />
Decline
</button>
</ButtonStyled>
</div>
</div>
<div v-if="navLinks.length > 2" class="mb-4 max-w-full overflow-x-auto">

View File

@@ -2,7 +2,7 @@
import { TrashIcon, UploadIcon } from '@modrinth/assets'
import {
Avatar,
Button,
ButtonStyled,
ConfirmModal,
FileInput,
injectNotificationManager,
@@ -161,27 +161,27 @@ const onDeleteOrganization = useClientTry(async () => {
size="md"
class="project__icon"
/>
<div class="input-stack">
<FileInput
id="project-icon"
:max-size="262144"
:show-icon="true"
accept="image/png,image/jpeg,image/gif,image/webp"
class="btn"
prompt="Upload icon"
:disabled="!hasPermission"
@change="showPreviewImage"
>
<UploadIcon />
</FileInput>
<Button
v-if="!deletedIcon && (previewImage || organization.icon_url)"
:disabled="!hasPermission"
@click="markIconForDeletion"
>
<TrashIcon />
Remove icon
</Button>
<div class="flex flex-col gap-2">
<ButtonStyled>
<FileInput
id="project-icon"
:max-size="262144"
:show-icon="true"
accept="image/png,image/jpeg,image/gif,image/webp"
class="button-like"
prompt="Upload icon"
:disabled="!hasPermission"
@change="showPreviewImage"
>
<UploadIcon />
</FileInput>
</ButtonStyled>
<ButtonStyled v-if="!deletedIcon && (previewImage || organization.icon_url)">
<button :disabled="!hasPermission" @click="markIconForDeletion">
<TrashIcon />
Remove icon
</button>
</ButtonStyled>
</div>
</div>
@@ -231,10 +231,12 @@ const onDeleteOrganization = useClientTry(async () => {
Deleting your organization will transfer all of its projects to the organization owner. This
action cannot be undone.
</p>
<Button color="danger" @click="() => $refs.modal_deletion.show()">
<TrashIcon />
Delete organization
</Button>
<ButtonStyled color="red">
<button @click="() => $refs.modal_deletion.show()">
<TrashIcon />
Delete organization
</button>
</ButtonStyled>
</div>
<UnsavedChangesPopup
:original="originalState"

View File

@@ -43,19 +43,20 @@
@keypress.enter="() => onInviteTeamMember(organization.team, currentUsername)"
/>
<label for="username" class="hidden">Username</label>
<Button
color="primary"
:disabled="
!isPermission(
currentMember.organization_permissions,
organizationPermissions.MANAGE_INVITES,
)
"
@click="() => onInviteTeamMember(organization.team_id, currentUsername)"
>
<UserPlusIcon />
Invite
</Button>
<ButtonStyled color="brand">
<button
:disabled="
!isPermission(
currentMember.organization_permissions,
organizationPermissions.MANAGE_INVITES,
)
"
@click="() => onInviteTeamMember(organization.team_id, currentUsername)"
>
<UserPlusIcon />
Invite
</button>
</ButtonStyled>
</div>
<div class="adjacent-input">
<span class="label">
@@ -64,14 +65,15 @@
Remove yourself as a member of this organization.
</span>
</span>
<Button
color="danger"
:disabled="currentMember.is_owner"
@click="() => onLeaveProject(organization.team_id, auth.user.id)"
>
<UserRemoveIcon />
Leave organization
</Button>
<ButtonStyled color="red">
<button
:disabled="currentMember.is_owner"
@click="() => onLeaveProject(organization.team_id, auth.user.id)"
>
<UserRemoveIcon />
Leave organization
</button>
</ButtonStyled>
</div>
</div>
<div
@@ -94,18 +96,18 @@
<div class="side-buttons">
<Badge v-if="member.accepted" type="accepted" />
<Badge v-else type="pending" />
<Button
icon-only
transparent
class="dropdown-icon"
@click="
openTeamMembers.indexOf(member.user.id) === -1
? openTeamMembers.push(member.user.id)
: (openTeamMembers = openTeamMembers.filter((it) => it !== member.user.id))
"
>
<DropdownIcon />
</Button>
<ButtonStyled circular type="transparent">
<button
class="dropdown-icon"
@click="
openTeamMembers.indexOf(member.user.id) === -1
? openTeamMembers.push(member.user.id)
: (openTeamMembers = openTeamMembers.filter((it) => it !== member.user.id))
"
>
<DropdownIcon />
</button>
</ButtonStyled>
</div>
</div>
<div class="content">
@@ -188,44 +190,44 @@
</div>
</template>
<div class="input-group">
<Button
color="primary"
:disabled="
!isPermission(
currentMember.organization_permissions,
organizationPermissions.EDIT_MEMBER,
)
"
@click="onUpdateTeamMember(organization.team_id, member)"
>
<SaveIcon />
Save changes
</Button>
<Button
v-if="!member.is_owner"
color="danger"
:disabled="
!isPermission(
currentMember.organization_permissions,
organizationPermissions.EDIT_MEMBER,
) &&
!isPermission(
currentMember.organization_permissions,
organizationPermissions.REMOVE_MEMBER,
)
"
@click="onRemoveMember(organization.team_id, member)"
>
<UserRemoveIcon />
Remove member
</Button>
<Button
v-if="!member.is_owner && currentMember.is_owner && member.accepted"
@click="(e) => openTransferModal(member, e)"
>
<TransferIcon />
Transfer ownership
</Button>
<ButtonStyled color="brand">
<button
:disabled="
!isPermission(
currentMember.organization_permissions,
organizationPermissions.EDIT_MEMBER,
)
"
@click="onUpdateTeamMember(organization.team_id, member)"
>
<SaveIcon />
Save changes
</button>
</ButtonStyled>
<ButtonStyled v-if="!member.is_owner" color="red">
<button
:disabled="
!isPermission(
currentMember.organization_permissions,
organizationPermissions.EDIT_MEMBER,
) &&
!isPermission(
currentMember.organization_permissions,
organizationPermissions.REMOVE_MEMBER,
)
"
@click="onRemoveMember(organization.team_id, member)"
>
<UserRemoveIcon />
Remove member
</button>
</ButtonStyled>
<ButtonStyled v-if="!member.is_owner && currentMember.is_owner && member.accepted">
<button @click="(e) => openTransferModal(member, e)">
<TransferIcon />
Transfer ownership
</button>
</ButtonStyled>
</div>
</div>
</div>
@@ -244,7 +246,7 @@ import {
import {
Avatar,
Badge,
Button,
ButtonStyled,
Checkbox,
injectNotificationManager,
StyledInput,

View File

@@ -25,15 +25,17 @@
"
:maxlength="2048"
/>
<button
v-tooltip="'Clear link'"
aria-label="Clear link"
class="square-button label-button"
:data-active="editLinks.issues.clear"
@click="editLinks.issues.clear = !editLinks.issues.clear"
>
<TrashIcon />
</button>
<ButtonStyled circular>
<button
v-tooltip="'Clear link'"
class="label-button"
aria-label="Clear link"
:data-active="editLinks.issues.clear"
@click="editLinks.issues.clear = !editLinks.issues.clear"
>
<TrashIcon />
</button>
</ButtonStyled>
</div>
<label
for="source-code-input"
@@ -52,15 +54,17 @@
editLinks.source.clear ? 'Existing link will be cleared' : 'Enter a valid URL'
"
/>
<button
v-tooltip="'Clear link'"
aria-label="Clear link"
class="square-button label-button"
:data-active="editLinks.source.clear"
@click="editLinks.source.clear = !editLinks.source.clear"
>
<TrashIcon />
</button>
<ButtonStyled circular>
<button
v-tooltip="'Clear link'"
class="label-button"
aria-label="Clear link"
:data-active="editLinks.source.clear"
@click="editLinks.source.clear = !editLinks.source.clear"
>
<TrashIcon />
</button>
</ButtonStyled>
</div>
<label
for="wiki-page-input"
@@ -79,15 +83,17 @@
editLinks.wiki.clear ? 'Existing link will be cleared' : 'Enter a valid URL'
"
/>
<button
v-tooltip="'Clear link'"
aria-label="Clear link"
class="square-button label-button"
:data-active="editLinks.wiki.clear"
@click="editLinks.wiki.clear = !editLinks.wiki.clear"
>
<TrashIcon />
</button>
<ButtonStyled circular>
<button
v-tooltip="'Clear link'"
class="label-button"
aria-label="Clear link"
:data-active="editLinks.wiki.clear"
@click="editLinks.wiki.clear = !editLinks.wiki.clear"
>
<TrashIcon />
</button>
</ButtonStyled>
</div>
<label for="discord-invite-input" title="An invitation link to your Discord server.">
<span class="label__title">Discord invite</span>
@@ -105,15 +111,17 @@
: 'Enter a valid Discord invite URL'
"
/>
<button
v-tooltip="'Clear link'"
aria-label="Clear link"
class="square-button label-button"
:data-active="editLinks.discord.clear"
@click="editLinks.discord.clear = !editLinks.discord.clear"
>
<TrashIcon />
</button>
<ButtonStyled circular>
<button
v-tooltip="'Clear link'"
class="label-button"
aria-label="Clear link"
:data-active="editLinks.discord.clear"
@click="editLinks.discord.clear = !editLinks.discord.clear"
>
<TrashIcon />
</button>
</ButtonStyled>
</div>
</section>
<p>
@@ -143,14 +151,18 @@
description="Show all projects"
/>
<div class="push-right input-group">
<button class="iconified-button" @click="$refs.editLinksModal.hide()">
<XIcon />
Cancel
</button>
<button class="iconified-button brand-button" @click="onBulkEditLinks">
<SaveIcon />
Save changes
</button>
<ButtonStyled>
<button @click="$refs.editLinksModal.hide()">
<XIcon />
Cancel
</button>
</ButtonStyled>
<ButtonStyled color="brand">
<button @click="onBulkEditLinks">
<SaveIcon />
Save changes
</button>
</ButtonStyled>
</div>
</div>
</NewModal>
@@ -159,10 +171,12 @@
<div class="header__row">
<h2 class="header__title text-2xl">Projects</h2>
<div class="input-group">
<button class="iconified-button brand-button" @click="$refs.modal_creation.show($event)">
<PlusIcon />
{{ formatMessage(commonMessages.createAProjectButton) }}
</button>
<ButtonStyled color="brand">
<button @click="$refs.modal_creation.show($event)">
<PlusIcon />
{{ formatMessage(commonMessages.createAProjectButton) }}
</button>
</ButtonStyled>
<OrganizationProjectTransferModal
:projects="usersOwnedProjects || []"
@submit="onProjectTransferSubmit"
@@ -175,14 +189,12 @@
<template v-else>
<p>You can edit multiple projects at once by selecting them below.</p>
<div class="input-group">
<button
class="iconified-button"
:disabled="selectedProjects.length === 0"
@click="$refs.editLinksModal.show()"
>
<EditIcon />
Edit links
</button>
<ButtonStyled>
<button :disabled="selectedProjects.length === 0" @click="$refs.editLinksModal.show()">
<EditIcon />
Edit links
</button>
</ButtonStyled>
<div class="push-right">
<div class="labeled-control-row">
Sort by
@@ -193,14 +205,15 @@
:options="sortOptions"
@change="sortedProjects = updateSort(sortedProjects, sortBy, descending)"
/>
<button
v-tooltip="descending ? 'Descending' : 'Ascending'"
class="square-button"
@click="updateDescending()"
>
<SortDescIcon v-if="descending" />
<SortAscIcon v-else />
</button>
<ButtonStyled circular>
<button
v-tooltip="descending ? 'Descending' : 'Ascending'"
@click="updateDescending()"
>
<SortDescIcon v-if="descending" />
<SortAscIcon v-else />
</button>
</ButtonStyled>
</div>
</div>
</div>

View File

@@ -38,24 +38,24 @@
{{ calculateSavings(price.prices.intervals.monthly, price.prices.intervals.yearly) }}% with
annual billing!
</p>
<nuxt-link
<ButtonStyled
v-if="auth.user && isPermission(auth.user.badges, 1 << 0)"
to="/settings/billing"
class="btn btn-purple btn-large"
color="purple"
size="large"
>
<SettingsIcon aria-hidden="true" />
Manage subscription
</nuxt-link>
<button v-else-if="auth.user" class="btn btn-purple btn-large" @click="purchaseModal.show()">
Subscribe
</button>
<nuxt-link
v-else
:to="`/auth/sign-in?redirect=${encodeURIComponent('/plus?showModal=true')}`"
class="btn btn-purple btn-large"
>
Subscribe
</nuxt-link>
<nuxt-link to="/settings/billing">
<SettingsIcon aria-hidden="true" />
Manage subscription
</nuxt-link>
</ButtonStyled>
<ButtonStyled v-else-if="auth.user" color="purple" size="large">
<button @click="purchaseModal.show()">Subscribe</button>
</ButtonStyled>
<ButtonStyled v-else color="purple" size="large">
<nuxt-link :to="`/auth/sign-in?redirect=${encodeURIComponent('/plus?showModal=true')}`">
Subscribe
</nuxt-link>
</ButtonStyled>
</div>
</div>
<div class="perks-hero">
@@ -86,7 +86,12 @@
</template>
<script setup>
import { HeartIcon, ModrinthPlusIcon, SettingsIcon, SparklesIcon, StarIcon } from '@modrinth/assets'
import { injectNotificationManager, PurchaseModal, useFormatPrice } from '@modrinth/ui'
import {
ButtonStyled,
injectNotificationManager,
PurchaseModal,
useFormatPrice,
} from '@modrinth/ui'
import { calculateSavings, getCurrency } from '@modrinth/utils'
import { useBaseFetch } from '@/composables/fetch.js'

View File

@@ -1,6 +1,6 @@
<template>
<div class="page">
<div class="experimental-styles-within flex flex-col gap-2">
<div class="flex flex-col gap-2">
<RadialHeader class="top-box mb-2 flex flex-col items-center justify-center" color="orange">
<ScaleIcon class="h-12 w-12 text-brand-orange" />
<h1 class="m-3 gap-2 text-3xl font-extrabold">

View File

@@ -27,19 +27,18 @@
@keyup.enter="saveEmail()"
/>
<div class="input-group push-right">
<button class="iconified-button" @click="$refs.changeEmailModal.hide()">
<XIcon />
{{ formatMessage(commonMessages.cancelButton) }}
</button>
<button
type="button"
class="iconified-button brand-button"
:disabled="!email"
@click="saveEmail()"
>
<SaveIcon />
{{ formatMessage(messages.saveEmailButton) }}
</button>
<ButtonStyled>
<button @click="$refs.changeEmailModal.hide()">
<XIcon />
{{ formatMessage(commonMessages.cancelButton) }}
</button>
</ButtonStyled>
<ButtonStyled color="brand">
<button :disabled="!email" @click="saveEmail()">
<SaveIcon />
{{ formatMessage(messages.saveEmailButton) }}
</button>
</ButtonStyled>
</div>
</div>
</Modal>
@@ -108,44 +107,43 @@
</template>
<p></p>
<div class="input-group push-right">
<button class="iconified-button" @click="$refs.managePasswordModal.hide()">
<XIcon />
{{ formatMessage(commonMessages.cancelButton) }}
</button>
<template v-if="removePasswordMode">
<button
type="button"
class="iconified-button danger-button"
:disabled="!oldPassword"
@click="savePassword"
>
<TrashIcon />
{{ formatMessage(messages.removePasswordButton) }}
<ButtonStyled>
<button @click="$refs.managePasswordModal.hide()">
<XIcon />
{{ formatMessage(commonMessages.cancelButton) }}
</button>
</ButtonStyled>
<template v-if="removePasswordMode">
<ButtonStyled color="red">
<button :disabled="!oldPassword" @click="savePassword">
<TrashIcon />
{{ formatMessage(messages.removePasswordButton) }}
</button>
</ButtonStyled>
</template>
<template v-else>
<button
<ButtonStyled
v-if="auth.user.has_password && auth.user.auth_providers.length > 0"
type="button"
class="iconified-button danger-button"
@click="removePasswordMode = true"
color="red"
>
<TrashIcon />
{{ formatMessage(messages.removePasswordButton) }}
</button>
<button
type="button"
class="iconified-button brand-button"
:disabled="
newPassword.length == 0 ||
(auth.user.has_password && oldPassword.length == 0) ||
newPassword !== confirmNewPassword
"
@click="savePassword"
>
<SaveIcon />
{{ formatMessage(messages.savePasswordButton) }}
</button>
<button @click="removePasswordMode = true">
<TrashIcon />
{{ formatMessage(messages.removePasswordButton) }}
</button>
</ButtonStyled>
<ButtonStyled color="brand">
<button
:disabled="
newPassword.length == 0 ||
(auth.user.has_password && oldPassword.length == 0) ||
newPassword !== confirmNewPassword
"
@click="savePassword"
>
<SaveIcon />
{{ formatMessage(messages.savePasswordButton) }}
</button>
</ButtonStyled>
</template>
</div>
</div>
@@ -173,14 +171,18 @@
{{ formatMessage(messages.twoFactorIncorrectError) }}
</p>
<div class="input-group push-right">
<button class="iconified-button" @click="$refs.manageTwoFactorModal.hide()">
<XIcon />
{{ formatMessage(commonMessages.cancelButton) }}
</button>
<button class="iconified-button danger-button" @click="removeTwoFactor">
<TrashIcon />
{{ formatMessage(messages.twoFactorRemoveButton) }}
</button>
<ButtonStyled>
<button @click="$refs.manageTwoFactorModal.hide()">
<XIcon />
{{ formatMessage(commonMessages.cancelButton) }}
</button>
</ButtonStyled>
<ButtonStyled color="red">
<button @click="removeTwoFactor">
<TrashIcon />
{{ formatMessage(messages.twoFactorRemoveButton) }}
</button>
</ButtonStyled>
</div>
</template>
<template v-else>
@@ -247,34 +249,30 @@
</ul>
</template>
<div class="input-group push-right">
<button v-if="twoFactorStep === 1" class="iconified-button" @click="twoFactorStep = 0">
<LeftArrowIcon />
{{ formatMessage(commonMessages.backButton) }}
</button>
<button
v-if="twoFactorStep !== 2"
class="iconified-button"
@click="$refs.manageTwoFactorModal.hide()"
>
<XIcon />
{{ formatMessage(commonMessages.cancelButton) }}
</button>
<button
v-if="twoFactorStep <= 1"
class="iconified-button brand-button"
@click="twoFactorStep === 1 ? verifyTwoFactorCode() : (twoFactorStep = 1)"
>
<RightArrowIcon />
{{ formatMessage(commonMessages.continueButton) }}
</button>
<button
v-if="twoFactorStep === 2"
class="iconified-button brand-button"
@click="$refs.manageTwoFactorModal.hide()"
>
<CheckIcon />
{{ formatMessage(messages.completeSetupButton) }}
</button>
<ButtonStyled v-if="twoFactorStep === 1">
<button @click="twoFactorStep = 0">
<LeftArrowIcon />
{{ formatMessage(commonMessages.backButton) }}
</button>
</ButtonStyled>
<ButtonStyled v-if="twoFactorStep !== 2">
<button @click="$refs.manageTwoFactorModal.hide()">
<XIcon />
{{ formatMessage(commonMessages.cancelButton) }}
</button>
</ButtonStyled>
<ButtonStyled v-if="twoFactorStep <= 1" color="brand">
<button @click="twoFactorStep === 1 ? verifyTwoFactorCode() : (twoFactorStep = 1)">
<RightArrowIcon />
{{ formatMessage(commonMessages.continueButton) }}
</button>
</ButtonStyled>
<ButtonStyled v-if="twoFactorStep === 2" color="brand">
<button @click="$refs.manageTwoFactorModal.hide()">
<CheckIcon />
{{ formatMessage(messages.completeSetupButton) }}
</button>
</ButtonStyled>
</div>
</template>
</div>
@@ -295,29 +293,27 @@
<span><component :is="provider.icon" /> {{ provider.display }}</span>
</div>
<div class="table-text manage table-cell">
<button
v-if="auth.user.auth_providers.includes(provider.id)"
class="btn"
@click="handleRemoveAuthProvider(provider.id)"
>
<TrashIcon /> {{ formatMessage(commonMessages.removeButton) }}
</button>
<a
v-else
class="btn"
:href="`${getAuthUrl(provider.id, '/settings/account')}&token=${auth.token}`"
>
<ExternalIcon /> {{ formatMessage(messages.providerAddButton) }}
</a>
<ButtonStyled v-if="auth.user.auth_providers.includes(provider.id)">
<button @click="handleRemoveAuthProvider(provider.id)">
<TrashIcon /> {{ formatMessage(commonMessages.removeButton) }}
</button>
</ButtonStyled>
<ButtonStyled v-else>
<a :href="`${getAuthUrl(provider.id, '/settings/account')}&token=${auth.token}`">
<ExternalIcon /> {{ formatMessage(messages.providerAddButton) }}
</a>
</ButtonStyled>
</div>
</div>
</div>
<p></p>
<div class="input-group push-right">
<button class="iconified-button" @click="$refs.manageProvidersModal.hide()">
<XIcon />
{{ formatMessage(commonMessages.closeButton) }}
</button>
<ButtonStyled>
<button @click="$refs.manageProvidersModal.hide()">
<XIcon />
{{ formatMessage(commonMessages.closeButton) }}
</button>
</ButtonStyled>
</div>
</div>
</Modal>
@@ -332,16 +328,18 @@
}}</span>
</label>
<div>
<button class="iconified-button" @click="$refs.changeEmailModal.show()">
<template v-if="auth.user.email">
<EditIcon />
{{ formatMessage(messages.changeEmailButton) }}
</template>
<template v-else>
<PlusIcon />
{{ formatMessage(messages.addEmailButton) }}
</template>
</button>
<ButtonStyled>
<button @click="$refs.changeEmailModal.show()">
<template v-if="auth.user.email">
<EditIcon />
{{ formatMessage(messages.changeEmailButton) }}
</template>
<template v-else>
<PlusIcon />
{{ formatMessage(messages.addEmailButton) }}
</template>
</button>
</ButtonStyled>
</div>
</div>
<div class="adjacent-input">
@@ -359,24 +357,25 @@
</span>
</label>
<div>
<button
class="iconified-button"
@click="
() => {
oldPassword = ''
newPassword = ''
confirmNewPassword = ''
removePasswordMode = false
$refs.managePasswordModal.show()
}
"
>
<KeyIcon />
<template v-if="auth.user.has_password">{{
formatMessage(messages.changePasswordButton)
}}</template>
<template v-else> {{ formatMessage(messages.addPasswordButton) }} </template>
</button>
<ButtonStyled>
<button
@click="
() => {
oldPassword = ''
newPassword = ''
confirmNewPassword = ''
removePasswordMode = false
$refs.managePasswordModal.show()
}
"
>
<KeyIcon />
<template v-if="auth.user.has_password">{{
formatMessage(messages.changePasswordButton)
}}</template>
<template v-else> {{ formatMessage(messages.addPasswordButton) }} </template>
</button>
</ButtonStyled>
</div>
</div>
<div class="adjacent-input">
@@ -387,14 +386,16 @@
}}</span>
</label>
<div>
<button class="iconified-button" @click="showTwoFactorModal">
<template v-if="auth.user.has_totp">
<TrashIcon /> {{ formatMessage(messages.twoFactorRemoveButton) }}
</template>
<template v-else>
<PlusIcon /> {{ formatMessage(messages.twoFactorSetupButton) }}
</template>
</button>
<ButtonStyled>
<button @click="showTwoFactorModal">
<template v-if="auth.user.has_totp">
<TrashIcon /> {{ formatMessage(messages.twoFactorRemoveButton) }}
</template>
<template v-else>
<PlusIcon /> {{ formatMessage(messages.twoFactorSetupButton) }}
</template>
</button>
</ButtonStyled>
</div>
</div>
<div class="adjacent-input">
@@ -405,9 +406,11 @@
}}</span>
</label>
<div>
<button class="iconified-button" @click="$refs.manageProvidersModal.show()">
<SettingsIcon /> {{ formatMessage(messages.manageProvidersButton) }}
</button>
<ButtonStyled>
<button @click="$refs.manageProvidersModal.show()">
<SettingsIcon /> {{ formatMessage(messages.manageProvidersButton) }}
</button>
</ButtonStyled>
</div>
</div>
</section>
@@ -415,31 +418,33 @@
<section id="data-export" class="universal-card">
<h2>{{ formatMessage(messages.dataExportTitle) }}</h2>
<p>{{ formatMessage(messages.dataExportDescription) }}</p>
<a v-if="generated" class="iconified-button" :href="generated" download="export.json">
<DownloadIcon />
{{ formatMessage(messages.downloadExportButton) }}
</a>
<button v-else class="iconified-button" :disabled="generatingExport" @click="exportData">
<template v-if="generatingExport">
<UpdatedIcon /> {{ formatMessage(messages.generatingExportButton) }}
</template>
<template v-else>
<UpdatedIcon /> {{ formatMessage(messages.generateExportButton) }}
</template>
</button>
<ButtonStyled v-if="generated">
<a :href="generated" download="export.json">
<DownloadIcon />
{{ formatMessage(messages.downloadExportButton) }}
</a>
</ButtonStyled>
<ButtonStyled v-else>
<button :disabled="generatingExport" @click="exportData">
<template v-if="generatingExport">
<UpdatedIcon /> {{ formatMessage(messages.generatingExportButton) }}
</template>
<template v-else>
<UpdatedIcon /> {{ formatMessage(messages.generateExportButton) }}
</template>
</button>
</ButtonStyled>
</section>
<section id="delete-account" class="universal-card">
<h2>{{ formatMessage(messages.deleteAccountSectionTitle) }}</h2>
<p>{{ formatMessage(messages.deleteAccountSectionDescription) }}</p>
<button
type="button"
class="iconified-button danger-button"
@click="$refs.modal_confirm.show()"
>
<TrashIcon />
{{ formatMessage(messages.deleteAccountButton) }}
</button>
<ButtonStyled color="red">
<button type="button" @click="$refs.modal_confirm.show()">
<TrashIcon />
{{ formatMessage(messages.deleteAccountButton) }}
</button>
</ButtonStyled>
</section>
</div>
</template>
@@ -460,6 +465,7 @@ import {
XIcon,
} from '@modrinth/assets'
import {
ButtonStyled,
commonMessages,
ConfirmModal,
defineMessages,

View File

@@ -24,15 +24,17 @@
</label>
<div v-if="editingId" class="icon-submission">
<Avatar size="md" :src="icon" />
<FileInput
:max-size="262144"
class="btn"
:prompt="formatMessage(messages.uploadIcon)"
accept="image/png,image/jpeg,image/gif,image/webp"
@change="onImageSelection"
>
<UploadIcon />
</FileInput>
<ButtonStyled>
<FileInput
:max-size="262144"
class="button-like"
:prompt="formatMessage(messages.uploadIcon)"
accept="image/png,image/jpeg,image/gif,image/webp"
@change="onImageSelection"
>
<UploadIcon />
</FileInput>
</ButtonStyled>
</div>
<label v-if="editingId" for="app-url">
<span class="label__title">{{ formatMessage(messages.urlLabel) }}</span>
@@ -94,51 +96,46 @@
autocomplete="off"
:placeholder="formatMessage(messages.redirectUriPlaceholder)"
/>
<Button v-if="index !== 0" icon-only @click="() => redirectUris.splice(index, 1)">
<TrashIcon />
</Button>
<Button
v-if="index === 0"
color="primary"
icon-only
@click="() => redirectUris.push('')"
>
<PlusIcon /> {{ formatMessage(messages.addMore) }}
</Button>
<ButtonStyled v-if="index !== 0" circular>
<button @click="() => redirectUris.splice(index, 1)">
<TrashIcon />
</button>
</ButtonStyled>
<ButtonStyled v-if="index === 0" color="brand">
<button @click="() => redirectUris.push('')">
<PlusIcon /> {{ formatMessage(messages.addMore) }}
</button>
</ButtonStyled>
</div>
</div>
<div v-if="redirectUris.length <= 0">
<Button color="primary" icon-only @click="() => redirectUris.push('')">
<PlusIcon /> {{ formatMessage(messages.addRedirectUri) }}
</Button>
<ButtonStyled color="brand">
<button @click="() => redirectUris.push('')">
<PlusIcon /> {{ formatMessage(messages.addRedirectUri) }}
</button>
</ButtonStyled>
</div>
</div>
<div class="submit-row input-group push-right">
<button class="iconified-button" @click="$refs.appModal.hide()">
<XIcon />
{{ formatMessage(messages.cancel) }}
</button>
<button
v-if="editingId"
:disabled="!canSubmit"
type="button"
class="iconified-button brand-button"
@click="editApp"
>
<SaveIcon />
{{ formatMessage(messages.saveChanges) }}
</button>
<button
v-else
:disabled="!canSubmit"
type="button"
class="iconified-button brand-button"
@click="createApp"
>
<PlusIcon />
{{ formatMessage(messages.createApp) }}
</button>
<ButtonStyled>
<button @click="$refs.appModal.hide()">
<XIcon />
{{ formatMessage(messages.cancel) }}
</button>
</ButtonStyled>
<ButtonStyled v-if="editingId" color="brand">
<button :disabled="!canSubmit" @click="editApp">
<SaveIcon />
{{ formatMessage(messages.saveChanges) }}
</button>
</ButtonStyled>
<ButtonStyled v-else color="brand">
<button :disabled="!canSubmit" @click="createApp">
<PlusIcon />
{{ formatMessage(messages.createApp) }}
</button>
</ButtonStyled>
</div>
</div>
</Modal>
@@ -147,22 +144,22 @@
<div class="header__title">
<h2 class="text-2xl">{{ formatMessage(commonSettingsMessages.applications) }}</h2>
</div>
<button
class="btn btn-primary"
@click="
() => {
name = null
icon = null
scopesVal = 0
redirectUris = ['']
editingId = null
expires = null
$refs.appModal.show()
}
"
>
<PlusIcon /> {{ formatMessage(messages.newApplication) }}
</button>
<ButtonStyled color="brand">
<button
@click="
() => {
name = null
icon = null
scopesVal = 0
redirectUris = ['']
editingId = null
$refs.appModal.show()
}
"
>
<PlusIcon /> {{ formatMessage(messages.newApplication) }}
</button>
</ButtonStyled>
</div>
<p>
<IntlFormatted :message-id="messages.descriptionIntro">
@@ -210,34 +207,35 @@
</div>
</div>
<div class="input-group">
<Button
icon-only
@click="
() => {
setForm({
...app,
redirect_uris: app.redirect_uris.map((u) => u.uri) || [],
})
$refs.appModal.show()
}
"
>
<EditIcon />
{{ formatMessage(messages.edit) }}
</Button>
<Button
color="danger"
icon-only
@click="
() => {
editingId = app.id
$refs.modal_confirm.show()
}
"
>
<TrashIcon />
{{ formatMessage(messages.delete) }}
</Button>
<ButtonStyled>
<button
@click="
() => {
setForm({
...app,
redirect_uris: app.redirect_uris.map((u) => u.uri) || [],
})
$refs.appModal.show()
}
"
>
<EditIcon />
{{ formatMessage(messages.edit) }}
</button>
</ButtonStyled>
<ButtonStyled color="red">
<button
@click="
() => {
editingId = app.id
$refs.modal_confirm.show()
}
"
>
<TrashIcon />
{{ formatMessage(messages.delete) }}
</button>
</ButtonStyled>
</div>
</div>
</div>
@@ -246,7 +244,7 @@
import { EditIcon, PlusIcon, SaveIcon, TrashIcon, UploadIcon, XIcon } from '@modrinth/assets'
import {
Avatar,
Button,
ButtonStyled,
Checkbox,
commonMessages,
commonSettingsMessages,

View File

@@ -69,19 +69,19 @@
</div>
<div class="input-group">
<Button
color="danger"
icon-only
@click="
() => {
revokingId = authorization.app_id
$refs.modal_confirm.show()
}
"
>
<TrashIcon />
{{ formatMessage(messages.revokeAction) }}
</Button>
<ButtonStyled color="red">
<button
@click="
() => {
revokingId = authorization.app_id
$refs.modal_confirm.show()
}
"
>
<TrashIcon />
{{ formatMessage(messages.revokeAction) }}
</button>
</ButtonStyled>
</div>
</div>
</div>
@@ -90,7 +90,7 @@
import { CheckIcon, TrashIcon } from '@modrinth/assets'
import {
Avatar,
Button,
ButtonStyled,
commonMessages,
commonSettingsMessages,
ConfirmModal,

View File

@@ -1,7 +1,7 @@
<template>
<ServersUpgradeModalWrapper ref="upgradeModal" />
<ResubscribeModal ref="pyroResubscribeModal" @resubscribe="handlePyroResubscribeConfirm" />
<section class="universal-card experimental-styles-within">
<section class="universal-card">
<h2>{{ formatMessage(messages.subscriptionTitle) }}</h2>
<p>{{ formatMessage(messages.subscriptionDescription) }}</p>
<div class="universal-card recessed">
@@ -533,7 +533,7 @@
</div>
</section>
<section class="universal-card experimental-styles-within">
<section class="universal-card">
<ConfirmModal
ref="modal_confirm"
:title="formatMessage(deleteModalMessages.title)"
@@ -573,12 +573,16 @@
<div class="header__title">
<h2 class="text-2xl">{{ formatMessage(messages.paymentMethodTitle) }}</h2>
</div>
<nuxt-link class="btn" to="/settings/billing/charges">
<HistoryIcon /> {{ formatMessage(messages.paymentMethodHistory) }}
</nuxt-link>
<button class="btn" @click="addPaymentMethod">
<PlusIcon /> {{ formatMessage(messages.paymentMethodAdd) }}
</button>
<ButtonStyled>
<nuxt-link to="/settings/billing/charges">
<HistoryIcon /> {{ formatMessage(messages.paymentMethodHistory) }}
</nuxt-link>
</ButtonStyled>
<ButtonStyled>
<button @click="addPaymentMethod">
<PlusIcon /> {{ formatMessage(messages.paymentMethodAdd) }}
</button>
</ButtonStyled>
</div>
<div
v-if="!paymentMethods || paymentMethods.length === 0"
@@ -637,41 +641,43 @@
</div>
</div>
</div>
<OverflowMenu
:dropdown-id="`${baseId}-payment-method-overflow-${index}`"
class="btn icon-only transparent"
:options="
[
{
id: 'primary',
action: () => editPaymentMethod(index, true),
},
{
id: 'remove',
action: () => {
removePaymentMethodIndex = index
$refs.modal_confirm.show()
<ButtonStyled circular type="transparent">
<OverflowMenu
:dropdown-id="`${baseId}-payment-method-overflow-${index}`"
class="btn-dropdown-animation !w-10"
:options="
[
{
id: 'primary',
action: () => editPaymentMethod(index, true),
},
color: 'red',
hoverOnly: true,
},
].slice(primaryPaymentMethodId === method.id ? 1 : 0, 2)
"
>
<MoreVerticalIcon />
<template #primary>
<StarIcon />
{{ formatMessage(messages.paymentMethodMakePrimary) }}
</template>
<template #edit>
<EditIcon />
{{ formatMessage(commonMessages.editButton) }}
</template>
<template #remove>
<TrashIcon />
{{ formatMessage(commonMessages.deleteLabel) }}
</template>
</OverflowMenu>
{
id: 'remove',
action: () => {
removePaymentMethodIndex = index
$refs.modal_confirm.show()
},
color: 'red',
hoverOnly: true,
},
].slice(primaryPaymentMethodId === method.id ? 1 : 0, 2)
"
>
<MoreVerticalIcon />
<template #primary>
<StarIcon />
{{ formatMessage(messages.paymentMethodMakePrimary) }}
</template>
<template #edit>
<EditIcon />
{{ formatMessage(commonMessages.editButton) }}
</template>
<template #remove>
<TrashIcon />
{{ formatMessage(commonMessages.deleteLabel) }}
</template>
</OverflowMenu>
</ButtonStyled>
</div>
</div>
</section>

View File

@@ -9,9 +9,11 @@
</strong>
</template>
</IntlFormatted>
<Button :action="() => disableDeveloperMode()">
{{ formatMessage(developerModeBanner.deactivate) }}
</Button>
<ButtonStyled color="red" type="highlight">
<button class="mt-3" @click="disableDeveloperMode()">
{{ formatMessage(developerModeBanner.deactivate) }}
</button>
</ButtonStyled>
</MessageBanner>
<section class="universal-card">
<h2 class="text-2xl">{{ formatMessage(colorTheme.title) }}</h2>
@@ -178,7 +180,7 @@
<script setup lang="ts">
import { CodeIcon, RadioButtonCheckedIcon, RadioButtonIcon } from '@modrinth/assets'
import {
Button,
ButtonStyled,
defineMessages,
injectNotificationManager,
IntlFormatted,
@@ -506,9 +508,5 @@ const listTypes = computed(() => {
margin-bottom: 2px;
margin-right: 0.5rem;
}
.btn {
margin-top: var(--gap-sm);
}
}
</style>

View File

@@ -66,31 +66,25 @@
<p></p>
</div>
<div class="input-group push-right">
<button class="iconified-button" @click="$refs.patModal.hide()">
<XIcon />
{{ formatMessage(commonMessages.cancelButton) }}
</button>
<button
v-if="editPatId !== null"
:disabled="loading || !name || !expires"
type="button"
class="iconified-button brand-button"
@click="editPat"
>
<SaveIcon />
{{ formatMessage(commonMessages.saveChangesButton) }}
</button>
<button
v-else
:disabled="loading || !name || !expires"
type="button"
class="iconified-button brand-button"
@click="createPat"
>
<PlusIcon />
{{ formatMessage(createModalMessages.action) }}
</button>
<div class="ml-auto flex gap-2">
<ButtonStyled type="outlined">
<button @click="$refs.patModal.hide()">
<XIcon />
{{ formatMessage(commonMessages.cancelButton) }}
</button>
</ButtonStyled>
<ButtonStyled v-if="editPatId !== null" color="brand">
<button :disabled="loading || !name || !expires" @click="editPat">
<SaveIcon />
{{ formatMessage(commonMessages.saveChangesButton) }}
</button>
</ButtonStyled>
<ButtonStyled v-else color="brand">
<button :disabled="loading || !name || !expires" @click="createPat">
<PlusIcon />
{{ formatMessage(createModalMessages.action) }}
</button>
</ButtonStyled>
</div>
</div>
</NewModal>
@@ -99,20 +93,21 @@
<div class="header__title">
<h2 class="text-2xl">{{ formatMessage(commonSettingsMessages.pats) }}</h2>
</div>
<button
class="btn btn-primary"
@click="
() => {
name = null
scopesVal = 0
expires = null
editPatId = null
$refs.patModal.show()
}
"
>
<PlusIcon /> {{ formatMessage(messages.create) }}
</button>
<ButtonStyled color="brand">
<button
@click="
() => {
name = null
scopesVal = 0
expires = null
editPatId = null
$refs.patModal.show()
}
"
>
<PlusIcon /> {{ formatMessage(messages.create) }}
</button>
</ButtonStyled>
</div>
<p>
<IntlFormatted :message-id="messages.description">
@@ -172,31 +167,33 @@
</div>
</div>
<div class="token-actions ml-auto flex flex-col gap-2">
<button
class="iconified-button raised-button"
@click="
() => {
editPatId = pat.id
name = pat.name
scopesVal = pat.scopes
expires = $dayjs(pat.expires).format('YYYY-MM-DD')
$refs.patModal.show()
}
"
>
<EditIcon /> {{ formatMessage(tokenMessages.edit) }}
</button>
<button
class="iconified-button raised-button"
@click="
() => {
deletePatIndex = pat.id
$refs.modal_confirm.show()
}
"
>
<TrashIcon /> {{ formatMessage(tokenMessages.revoke) }}
</button>
<ButtonStyled>
<button
@click="
() => {
editPatId = pat.id
name = pat.name
scopesVal = pat.scopes
expires = $dayjs(pat.expires).format('YYYY-MM-DD')
$refs.patModal.show()
}
"
>
<EditIcon /> {{ formatMessage(tokenMessages.edit) }}
</button>
</ButtonStyled>
<ButtonStyled>
<button
@click="
() => {
deletePatIndex = pat.id
$refs.modal_confirm.show()
}
"
>
<TrashIcon /> {{ formatMessage(tokenMessages.revoke) }}
</button>
</ButtonStyled>
</div>
</div>
</div>
@@ -204,6 +201,7 @@
<script setup>
import { EditIcon, PlusIcon, SaveIcon, TrashIcon, XIcon } from '@modrinth/assets'
import {
ButtonStyled,
Checkbox,
commonMessages,
commonSettingsMessages,

View File

@@ -21,33 +21,38 @@
circle
:alt="auth.user.username"
/>
<div class="input-stack">
<FileInput
:max-size="262144"
:show-icon="true"
class="btn"
:prompt="formatMessage(commonMessages.uploadImageButton)"
accept="image/png,image/jpeg,image/gif,image/webp"
@change="showPreviewImage"
>
<UploadIcon />
</FileInput>
<Button v-if="avatarUrl !== null" :action="removePreviewImage">
<TrashIcon />
{{ formatMessage(commonMessages.removeImageButton) }}
</Button>
<Button
v-if="previewImage"
:action="
() => {
icon = null
previewImage = null
}
"
>
<UndoIcon />
{{ formatMessage(commonMessages.resetButton) }}
</Button>
<div class="flex flex-col gap-2">
<ButtonStyled>
<FileInput
:max-size="262144"
:show-icon="true"
class="button-like"
:prompt="formatMessage(commonMessages.uploadImageButton)"
accept="image/png,image/jpeg,image/gif,image/webp"
@change="showPreviewImage"
>
<UploadIcon />
</FileInput>
</ButtonStyled>
<ButtonStyled v-if="avatarUrl !== null">
<button @click="removePreviewImage">
<TrashIcon />
{{ formatMessage(commonMessages.removeImageButton) }}
</button>
</ButtonStyled>
<ButtonStyled v-if="previewImage">
<button
@click="
() => {
icon = null
previewImage = null
}
"
>
<UndoIcon />
{{ formatMessage(commonMessages.resetButton) }}
</button>
</ButtonStyled>
</div>
</div>
<label for="username-field">
@@ -65,9 +70,11 @@
</label>
<StyledInput id="bio-field" v-model="current.bio" multiline />
<div class="input-group mt-4">
<Button :link="`/user/${auth.user.username}`">
<UserIcon /> {{ formatMessage(commonMessages.visitYourProfile) }}
</Button>
<ButtonStyled>
<NuxtLink :to="`/user/${auth.user.username}`">
<UserIcon /> {{ formatMessage(commonMessages.visitYourProfile) }}
</NuxtLink>
</ButtonStyled>
</div>
</section>
<UnsavedChangesPopup
@@ -84,7 +91,7 @@
import { TrashIcon, UndoIcon, UploadIcon, UserIcon } from '@modrinth/assets'
import {
Avatar,
Button,
ButtonStyled,
commonMessages,
defineMessages,
FileInput,

View File

@@ -34,9 +34,11 @@
</div>
<div class="input-group">
<i v-if="session.current">{{ formatMessage(messages.currentSessionLabel) }}</i>
<button v-else class="iconified-button raised-button" @click="revokeSession(session.id)">
<XIcon /> {{ formatMessage(messages.revokeSessionButton) }}
</button>
<ButtonStyled v-else>
<button @click="revokeSession(session.id)">
<XIcon /> {{ formatMessage(messages.revokeSessionButton) }}
</button>
</ButtonStyled>
</div>
</div>
</div>
@@ -44,6 +46,7 @@
<script setup>
import { XIcon } from '@modrinth/assets'
import {
ButtonStyled,
commonMessages,
commonSettingsMessages,
defineMessages,

View File

@@ -1,5 +1,5 @@
<template>
<div v-if="user" class="experimental-styles-within">
<div v-if="user">
<ModalCreation ref="modal_creation" />
<CollectionCreateModal ref="modal_collection_creation" />
<NewModal ref="editRoleModal" header="Edit role">