mirror of
https://github.com/modrinth/code.git
synced 2026-08-27 01:54:47 +00:00
refactor: Button components (#6929)
* feat: refactor button components
* fix: qa
* fix: storybook
* a11y: pass
* fix: build
* fix: rename default ->md
* fix: lint
* docs: buttons.md
* refactor part 1
* refactor part 2
* fix: undo refactor for fresh restart
* refactor
* Revert "refactor"
This reverts commit 96d65902d7.
* refactor: part 1
* fix: qa
* fix: qa
* fix: qa
* fix: qa
* fix: qa
* fix: qa
* fix: qa
* fix: qa
* fix: remove text-contrast
* fix: qa
* fix: v-tooltip
* fix: lint
* fix: split broken
* fix: passkey qa
* fix: qa
* fix: qa
* fix: prepr
* fix: splitbutton
* improve button group seam
---------
Signed-off-by: Calum H. <calum@modrinth.com>
Co-authored-by: Prospector <6166773+Prospector@users.noreply.github.com>
This commit is contained in:
@@ -10,7 +10,7 @@ import {
|
||||
SpinnerIcon,
|
||||
} from '@modrinth/assets'
|
||||
import {
|
||||
ButtonStyled,
|
||||
Button,
|
||||
commonMessages,
|
||||
ConfirmModal,
|
||||
defineMessages,
|
||||
@@ -1112,13 +1112,15 @@ await loadSkins()
|
||||
class="skin-preview-actions flex w-full items-center justify-center gap-1.5"
|
||||
:class="selectedSkinHasEarsFeatures ? 'flex-nowrap' : 'flex-wrap'"
|
||||
>
|
||||
<button
|
||||
<Button
|
||||
v-tooltip="
|
||||
selectedSkinHasEarsFeatures
|
||||
? formatMessage(commonMessages.resetButton)
|
||||
: undefined
|
||||
"
|
||||
class="skin-preview-action-button flex h-10 min-w-0 cursor-pointer items-center justify-center gap-2 rounded-[14px] border-0 bg-surface-4 px-4 py-2.5 text-base font-semibold leading-5 text-contrast shadow-md transition-[filter,transform] duration-200 enabled:hover:brightness-[--hover-brightness] enabled:focus-visible:brightness-[--hover-brightness] enabled:active:scale-95 disabled:cursor-not-allowed disabled:opacity-50 [&>svg]:size-5 [&>svg]:shrink-0"
|
||||
type="base"
|
||||
size="lg"
|
||||
class="skin-preview-action-button"
|
||||
:disabled="isApplyingSkin || isSkinManagementReadOnly"
|
||||
:aria-label="formatMessage(commonMessages.resetButton)"
|
||||
@click="resetSelectedSkin"
|
||||
@@ -1127,12 +1129,15 @@ await loadSkins()
|
||||
<span class="skin-preview-action-label">
|
||||
{{ formatMessage(commonMessages.resetButton) }}
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
</Button>
|
||||
<Button
|
||||
v-tooltip="
|
||||
selectedSkinHasEarsFeatures ? formatMessage(messages.applyButton) : undefined
|
||||
"
|
||||
class="skin-preview-action-button flex h-10 min-w-0 cursor-pointer items-center justify-center gap-2 rounded-[14px] border-0 bg-brand px-4 py-2.5 text-base font-semibold leading-5 text-[rgba(0,0,0,0.9)] shadow-md transition-[filter,transform] duration-200 enabled:hover:brightness-[--hover-brightness] enabled:focus-visible:brightness-[--hover-brightness] enabled:active:scale-95 disabled:cursor-not-allowed disabled:opacity-50 [&>svg]:size-5 [&>svg]:shrink-0"
|
||||
type="colored"
|
||||
color="brand"
|
||||
size="lg"
|
||||
class="skin-preview-action-button"
|
||||
:disabled="isApplyingSkin || isSkinManagementReadOnly"
|
||||
:aria-label="formatMessage(messages.applyButton)"
|
||||
@click="applySelectedSkin"
|
||||
@@ -1142,17 +1147,18 @@ await loadSkins()
|
||||
<span class="skin-preview-action-label">
|
||||
{{ formatMessage(messages.applyButton) }}
|
||||
</span>
|
||||
</button>
|
||||
</Button>
|
||||
</div>
|
||||
<button
|
||||
<Button
|
||||
v-else
|
||||
class="flex h-10 min-w-0 cursor-pointer items-center justify-center gap-2 rounded-[14px] border-0 bg-surface-4 px-4 py-2.5 text-base font-semibold leading-5 shadow-md transition-[filter,transform] duration-200 enabled:hover:brightness-[--hover-brightness] enabled:focus-visible:brightness-[--hover-brightness] enabled:active:scale-95 disabled:cursor-not-allowed disabled:opacity-50 [&>svg]:size-5 [&>svg]:shrink-0"
|
||||
type="base"
|
||||
size="lg"
|
||||
:disabled="!selectedSkin || isSkinManagementReadOnly"
|
||||
@click="(e: MouseEvent) => selectedSkin && editSkinModal?.show(e, selectedSkin)"
|
||||
>
|
||||
<EditIcon />
|
||||
{{ formatMessage(messages.editSkinButton) }}
|
||||
</button>
|
||||
</Button>
|
||||
|
||||
<div
|
||||
v-if="selectedSkinHasEarsFeatures"
|
||||
@@ -1181,28 +1187,28 @@ await loadSkins()
|
||||
>Ears</router-link
|
||||
>
|
||||
</div>
|
||||
<ButtonStyled type="outlined">
|
||||
<button
|
||||
class="ears-feature-toggle-button !h-10 !rounded-[14px] !px-4 shadow-md"
|
||||
:aria-pressed="earsFeaturesEnabled"
|
||||
:aria-label="
|
||||
formatMessage(
|
||||
earsFeaturesEnabled
|
||||
? messages.toggleEarsFeaturesOff
|
||||
: messages.toggleEarsFeaturesOn,
|
||||
)
|
||||
"
|
||||
@click="earsFeaturesEnabled = !earsFeaturesEnabled"
|
||||
>
|
||||
{{
|
||||
formatMessage(
|
||||
earsFeaturesEnabled
|
||||
? messages.toggleEarsFeaturesOff
|
||||
: messages.toggleEarsFeaturesOn,
|
||||
)
|
||||
}}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<Button
|
||||
type="outlined"
|
||||
size="lg"
|
||||
class="ears-feature-toggle-button shadow-md"
|
||||
:aria-pressed="earsFeaturesEnabled"
|
||||
:aria-label="
|
||||
formatMessage(
|
||||
earsFeaturesEnabled
|
||||
? messages.toggleEarsFeaturesOff
|
||||
: messages.toggleEarsFeaturesOn,
|
||||
)
|
||||
"
|
||||
@click="earsFeaturesEnabled = !earsFeaturesEnabled"
|
||||
>
|
||||
{{
|
||||
formatMessage(
|
||||
earsFeaturesEnabled
|
||||
? messages.toggleEarsFeaturesOff
|
||||
: messages.toggleEarsFeaturesOn,
|
||||
)
|
||||
}}
|
||||
</Button>
|
||||
<Toggle
|
||||
v-model="earsFeaturesEnabled"
|
||||
v-tooltip="
|
||||
@@ -1279,13 +1285,17 @@ await loadSkins()
|
||||
<p class="text-lg m-0">
|
||||
{{ formatMessage(messages.signInDescription) }}
|
||||
</p>
|
||||
<ButtonStyled v-show="accountsCard" color="brand" :disabled="accountsCard.loginDisabled">
|
||||
<button :disabled="accountsCard.loginDisabled" @click="login">
|
||||
<LogInIcon v-if="!accountsCard.loginDisabled" />
|
||||
<SpinnerIcon v-else class="animate-spin" />
|
||||
{{ formatMessage(messages.signInButton) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<Button
|
||||
v-show="accountsCard"
|
||||
type="colored"
|
||||
color="brand"
|
||||
:disabled="accountsCard.loginDisabled"
|
||||
@click="login"
|
||||
>
|
||||
<LogInIcon v-if="!accountsCard.loginDisabled" />
|
||||
<SpinnerIcon v-else class="animate-spin" />
|
||||
{{ formatMessage(messages.signInButton) }}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="w-full px-2 pt-2">
|
||||
<div class="w-full p-2">
|
||||
<UserProfilePageLayout
|
||||
:user-id="userId"
|
||||
:project-type="projectType"
|
||||
@@ -8,16 +8,47 @@
|
||||
project-link-mode="app"
|
||||
:edit-profile-link="openProfileSettings"
|
||||
external-navigation
|
||||
/>
|
||||
>
|
||||
<template #project-actions="{ project }">
|
||||
<Button
|
||||
type="outlined"
|
||||
class="!text-brand [&>svg]:!text-brand !shadow-[inset_0_0_0_1px_var(--color-brand)]"
|
||||
:disabled="isProjectInstalling(project.id)"
|
||||
@click.stop="installProject(project)"
|
||||
>
|
||||
<SpinnerIcon v-if="isProjectInstalling(project.id)" class="animate-spin" />
|
||||
<DownloadIcon v-else-if="project.project_type === 'modpack'" />
|
||||
<PlusIcon v-else />
|
||||
{{
|
||||
formatMessage(
|
||||
isProjectInstalling(project.id)
|
||||
? commonMessages.installingLabel
|
||||
: project.project_type === 'modpack'
|
||||
? commonMessages.installButton
|
||||
: messages.installToInstance,
|
||||
)
|
||||
}}
|
||||
</Button>
|
||||
</template>
|
||||
</UserProfilePageLayout>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { Labrinth } from '@modrinth/api-client'
|
||||
import { provideUserProfile, UserProfilePageLayout } from '@modrinth/ui'
|
||||
import { DownloadIcon, PlusIcon, SpinnerIcon } from '@modrinth/assets'
|
||||
import {
|
||||
Button,
|
||||
commonMessages,
|
||||
defineMessages,
|
||||
injectNotificationManager,
|
||||
provideUserProfile,
|
||||
UserProfilePageLayout,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { useQuery, useQueryClient } from '@tanstack/vue-query'
|
||||
import { computed, inject, ref, watch } from 'vue'
|
||||
import { onBeforeRouteUpdate, useRoute } from 'vue-router'
|
||||
import { onBeforeRouteUpdate, useRoute, useRouter } from 'vue-router'
|
||||
|
||||
import {
|
||||
block_user,
|
||||
@@ -31,10 +62,57 @@ import {
|
||||
} from '@/helpers/users'
|
||||
import { appSettingsModalOpenProfileKey } from '@/providers/app-settings-modal'
|
||||
import { useBreadcrumb } from '@/providers/breadcrumbs'
|
||||
import { injectContentInstall } from '@/providers/content-install'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const openProfileSettings = inject(appSettingsModalOpenProfileKey, () => {})
|
||||
const queryClient = useQueryClient()
|
||||
const { formatMessage } = useVIntl()
|
||||
const { handleError } = injectNotificationManager()
|
||||
const { install: installVersion } = injectContentInstall()
|
||||
const installingProjectIds = ref(new Set<string>())
|
||||
|
||||
const messages = defineMessages({
|
||||
installToInstance: {
|
||||
id: 'app.user.project.install-to-instance',
|
||||
defaultMessage: 'Install to instance',
|
||||
},
|
||||
})
|
||||
|
||||
function isProjectInstalling(projectId: string): boolean {
|
||||
return installingProjectIds.value.has(projectId)
|
||||
}
|
||||
|
||||
function setProjectInstalling(projectId: string, installing: boolean): void {
|
||||
const next = new Set(installingProjectIds.value)
|
||||
if (installing) {
|
||||
next.add(projectId)
|
||||
} else {
|
||||
next.delete(projectId)
|
||||
}
|
||||
installingProjectIds.value = next
|
||||
}
|
||||
|
||||
async function installProject(project: Labrinth.Projects.v2.Project): Promise<void> {
|
||||
if (isProjectInstalling(project.id)) return
|
||||
|
||||
setProjectInstalling(project.id, true)
|
||||
try {
|
||||
await installVersion(
|
||||
project.id,
|
||||
null,
|
||||
null,
|
||||
'UserPage',
|
||||
() => setProjectInstalling(project.id, false),
|
||||
(instanceId) => router.push(`/instance/${encodeURIComponent(instanceId)}`),
|
||||
)
|
||||
} catch (error) {
|
||||
setProjectInstalling(project.id, false)
|
||||
handleError(error)
|
||||
}
|
||||
}
|
||||
|
||||
const userProfile = provideUserProfile({
|
||||
getUser: get_user_profile,
|
||||
getProjects: get_user_projects,
|
||||
|
||||
+22
-18
@@ -6,23 +6,27 @@
|
||||
>
|
||||
{{ formatMessage(messages.sharedInstanceChangesBody) }}
|
||||
<template #actions>
|
||||
<ButtonStyled color="blue">
|
||||
<button class="!h-10" :disabled="isPublishButtonDisabled" @click="reviewChanges">
|
||||
<SpinnerIcon
|
||||
v-if="isReviewingPublish || isPublishing"
|
||||
class="animate-spin"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<UploadIcon v-else aria-hidden="true" />
|
||||
{{
|
||||
isPublishing
|
||||
? formatMessage(messages.sharedInstancePublishingButton)
|
||||
: isReviewingPublish
|
||||
? formatMessage(messages.sharedInstanceReviewingButton)
|
||||
: formatMessage(messages.sharedInstancePublishButton)
|
||||
}}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<Button
|
||||
type="colored"
|
||||
color="blue"
|
||||
size="lg"
|
||||
:disabled="isPublishButtonDisabled"
|
||||
@click="reviewChanges"
|
||||
>
|
||||
<SpinnerIcon
|
||||
v-if="isReviewingPublish || isPublishing"
|
||||
class="animate-spin"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<UploadIcon v-else aria-hidden="true" />
|
||||
{{
|
||||
isPublishing
|
||||
? formatMessage(messages.sharedInstancePublishingButton)
|
||||
: isReviewingPublish
|
||||
? formatMessage(messages.sharedInstanceReviewingButton)
|
||||
: formatMessage(messages.sharedInstancePublishButton)
|
||||
}}
|
||||
</Button>
|
||||
</template>
|
||||
</Admonition>
|
||||
|
||||
@@ -36,7 +40,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { SpinnerIcon, UploadIcon } from '@modrinth/assets'
|
||||
import { Admonition, ButtonStyled, useVIntl } from '@modrinth/ui'
|
||||
import { Admonition, Button, useVIntl } from '@modrinth/ui'
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
import SharedInstancePublishModal from '@/components/ui/shared-instances/SharedInstancePublishModal.vue'
|
||||
|
||||
+5
-7
@@ -8,19 +8,17 @@
|
||||
>
|
||||
{{ formatSharedInstanceUnavailable(reason ?? null, manager) }}
|
||||
<template v-if="reason === 'quarantined'" #actions>
|
||||
<ButtonStyled color="orange">
|
||||
<button class="!h-10" @click="emit('delete')">
|
||||
<TrashIcon aria-hidden="true" />
|
||||
{{ formatMessage(messages.deleteInstance) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<Button type="colored" color="orange" size="lg" @click="emit('delete')">
|
||||
<TrashIcon aria-hidden="true" />
|
||||
{{ formatMessage(messages.deleteInstance) }}
|
||||
</Button>
|
||||
</template>
|
||||
</Admonition>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { TrashIcon } from '@modrinth/assets'
|
||||
import { Admonition, ButtonStyled, defineMessages, useVIntl } from '@modrinth/ui'
|
||||
import { Admonition, Button, defineMessages, useVIntl } from '@modrinth/ui'
|
||||
|
||||
import type { SharedInstanceUnavailableReason } from '@/helpers/install'
|
||||
import {
|
||||
|
||||
+5
-7
@@ -6,19 +6,17 @@
|
||||
>
|
||||
{{ formatMessage(messages.sharedInstanceUpdateAvailableBody, { name: instanceName }) }}
|
||||
<template #actions>
|
||||
<ButtonStyled color="blue">
|
||||
<button class="!h-10" @click="emit('review', $event)">
|
||||
<DownloadIcon aria-hidden="true" />
|
||||
{{ formatMessage(messages.sharedInstanceReviewUpdateButton) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<Button type="colored" color="blue" size="lg" @click="emit('review', $event)">
|
||||
<DownloadIcon aria-hidden="true" />
|
||||
{{ formatMessage(messages.sharedInstanceReviewUpdateButton) }}
|
||||
</Button>
|
||||
</template>
|
||||
</Admonition>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { DownloadIcon } from '@modrinth/assets'
|
||||
import { Admonition, ButtonStyled, useVIntl } from '@modrinth/ui'
|
||||
import { Admonition, Button, useVIntl } from '@modrinth/ui'
|
||||
|
||||
import { instanceAdmonitionsMessages as messages } from './messages'
|
||||
|
||||
|
||||
@@ -85,66 +85,98 @@
|
||||
|
||||
<template #actions>
|
||||
<PageHeaderActions>
|
||||
<ButtonStyled v-if="isInstalling" color="brand" size="large">
|
||||
<button type="button" disabled>
|
||||
{{ formatMessage(commonMessages.installingLabel) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled v-else-if="playing" color="red" size="large">
|
||||
<button type="button" :disabled="stopping" @click="emit('stop')">
|
||||
<StopCircleIcon />
|
||||
{{
|
||||
stopping ? formatMessage(messages.stopping) : formatMessage(commonMessages.stopButton)
|
||||
}}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled v-else-if="instance.quarantined" color="brand" size="large">
|
||||
<button v-tooltip="formatMessage(messages.lockedPlayTooltip)" type="button" disabled>
|
||||
<PlayIcon />
|
||||
{{ formatMessage(commonMessages.playButton) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled v-else-if="instance.install_stage !== 'installed'" color="brand" size="large">
|
||||
<button type="button" @click="emit('repair')">
|
||||
<DownloadIcon />
|
||||
{{ formatMessage(messages.repair) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<JoinedButtons
|
||||
v-else-if="!loading && isServerInstance"
|
||||
:actions="serverPlayActions"
|
||||
<Button
|
||||
v-if="isInstalling"
|
||||
type="colored"
|
||||
color="brand"
|
||||
size="large"
|
||||
/>
|
||||
<ButtonStyled v-else-if="!loading" color="brand" size="large">
|
||||
<button type="button" @click="emit('play')">
|
||||
<PlayIcon />
|
||||
{{ formatMessage(commonMessages.playButton) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled v-else color="brand" size="large">
|
||||
<button type="button" disabled>{{ formatMessage(messages.starting) }}</button>
|
||||
</ButtonStyled>
|
||||
size="xl"
|
||||
native-type="button"
|
||||
disabled
|
||||
>
|
||||
{{ formatMessage(commonMessages.installingLabel) }}
|
||||
</Button>
|
||||
<Button
|
||||
v-else-if="playing"
|
||||
type="colored"
|
||||
color="red"
|
||||
size="xl"
|
||||
native-type="button"
|
||||
:disabled="stopping"
|
||||
@click="emit('stop')"
|
||||
>
|
||||
<StopCircleIcon />
|
||||
{{
|
||||
stopping ? formatMessage(messages.stopping) : formatMessage(commonMessages.stopButton)
|
||||
}}
|
||||
</Button>
|
||||
<Button
|
||||
v-else-if="instance.quarantined"
|
||||
v-tooltip="formatMessage(messages.lockedPlayTooltip)"
|
||||
type="colored"
|
||||
color="brand"
|
||||
size="xl"
|
||||
native-type="button"
|
||||
disabled
|
||||
>
|
||||
<PlayIcon />
|
||||
{{ formatMessage(commonMessages.playButton) }}
|
||||
</Button>
|
||||
<Button
|
||||
v-else-if="instance.install_stage !== 'installed'"
|
||||
type="colored"
|
||||
color="brand"
|
||||
size="xl"
|
||||
native-type="button"
|
||||
@click="emit('repair')"
|
||||
>
|
||||
<DownloadIcon />
|
||||
{{ formatMessage(messages.repair) }}
|
||||
</Button>
|
||||
<SplitButton
|
||||
v-else-if="!loading && isServerInstance"
|
||||
type="colored"
|
||||
color="brand"
|
||||
size="xl"
|
||||
:options="serverPlayOptions"
|
||||
:menu-label="formatMessage(messages.launchInstance)"
|
||||
@click="emit('playServer')"
|
||||
>
|
||||
<PlayIcon />
|
||||
{{ formatMessage(commonMessages.playButton) }}
|
||||
</SplitButton>
|
||||
<Button
|
||||
v-else-if="!loading"
|
||||
type="colored"
|
||||
color="brand"
|
||||
size="xl"
|
||||
native-type="button"
|
||||
@click="emit('play')"
|
||||
>
|
||||
<PlayIcon />
|
||||
{{ formatMessage(commonMessages.playButton) }}
|
||||
</Button>
|
||||
<Button v-else type="colored" color="brand" size="xl" native-type="button" disabled>{{
|
||||
formatMessage(messages.starting)
|
||||
}}</Button>
|
||||
|
||||
<ButtonStyled circular size="large">
|
||||
<button
|
||||
v-tooltip="formatMessage(messages.instanceSettings)"
|
||||
type="button"
|
||||
:aria-label="formatMessage(messages.instanceSettings)"
|
||||
@click="emit('settings')"
|
||||
>
|
||||
<SettingsIcon />
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled circular size="large" type="transparent">
|
||||
<TeleportOverflowMenu
|
||||
:options="moreActions"
|
||||
:tooltip="formatMessage(messages.moreActions)"
|
||||
:aria-label="formatMessage(messages.moreActions)"
|
||||
>
|
||||
<MoreVerticalIcon />
|
||||
</TeleportOverflowMenu>
|
||||
</ButtonStyled>
|
||||
<IconButton
|
||||
v-tooltip="formatMessage(messages.instanceSettings)"
|
||||
size="xl"
|
||||
:label="formatMessage(messages.instanceSettings)"
|
||||
native-type="button"
|
||||
@click="emit('settings')"
|
||||
>
|
||||
<SettingsIcon />
|
||||
</IconButton>
|
||||
<TeleportOverflowMenu
|
||||
type="quiet"
|
||||
size="xl"
|
||||
:label="formatMessage(messages.moreActions)"
|
||||
:tooltip="formatMessage(messages.moreActions)"
|
||||
:options="moreActions"
|
||||
>
|
||||
<MoreVerticalIcon />
|
||||
</TeleportOverflowMenu>
|
||||
</PageHeaderActions>
|
||||
</template>
|
||||
</PageHeader>
|
||||
@@ -167,23 +199,20 @@ import {
|
||||
TimerIcon,
|
||||
UnknownIcon,
|
||||
} from '@modrinth/assets'
|
||||
import { Button, IconButton, SplitButton, TeleportOverflowMenu } from '@modrinth/ui'
|
||||
import {
|
||||
Avatar,
|
||||
ButtonStyled,
|
||||
commonMessages,
|
||||
defineMessages,
|
||||
formatLoaderLabel,
|
||||
type JoinedButtonAction,
|
||||
JoinedButtons,
|
||||
LoaderIcon as ServerLoaderIcon,
|
||||
type OverflowMenuOption,
|
||||
PageHeader,
|
||||
PageHeaderActions,
|
||||
PageHeaderBadgeItem,
|
||||
PageHeaderMetadata,
|
||||
PageHeaderMetadataItem,
|
||||
type ServerLoader,
|
||||
TeleportOverflowMenu,
|
||||
type TeleportOverflowMenuItem,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { computed } from 'vue'
|
||||
@@ -350,13 +379,7 @@ const playtimeLabel = computed(() => {
|
||||
const seconds = Math.floor(props.timePlayed)
|
||||
return `${seconds} second${seconds > 1 ? 's' : ''}`
|
||||
})
|
||||
const serverPlayActions = computed<JoinedButtonAction[]>(() => [
|
||||
{
|
||||
id: 'join_server',
|
||||
label: formatMessage(commonMessages.playButton),
|
||||
icon: PlayIcon,
|
||||
action: () => emit('playServer'),
|
||||
},
|
||||
const serverPlayOptions = computed<OverflowMenuOption[]>(() => [
|
||||
{
|
||||
id: 'launch_instance',
|
||||
label: formatMessage(messages.launchInstance),
|
||||
@@ -364,8 +387,8 @@ const serverPlayActions = computed<JoinedButtonAction[]>(() => [
|
||||
action: () => emit('play'),
|
||||
},
|
||||
])
|
||||
const moreActions = computed<TeleportOverflowMenuItem[]>(() => {
|
||||
const actions: TeleportOverflowMenuItem[] = [
|
||||
const moreActions = computed<OverflowMenuOption[]>(() => {
|
||||
const actions: OverflowMenuOption[] = [
|
||||
{
|
||||
id: 'open-folder',
|
||||
label: formatMessage(messages.openFolder),
|
||||
@@ -393,12 +416,12 @@ const moreActions = computed<TeleportOverflowMenuItem[]>(() => {
|
||||
|
||||
if (props.instance.shared_instance?.role === 'member') {
|
||||
actions.push(
|
||||
{ divider: true },
|
||||
{ type: 'divider' },
|
||||
{
|
||||
id: 'report-shared-instance',
|
||||
label: formatMessage(commonMessages.reportButton),
|
||||
icon: ReportIcon,
|
||||
color: 'red',
|
||||
tone: 'red',
|
||||
action: (event) => emit('report', event),
|
||||
},
|
||||
)
|
||||
|
||||
+9
-13
@@ -10,18 +10,14 @@
|
||||
|
||||
<template #actions>
|
||||
<div class="flex justify-end gap-2">
|
||||
<ButtonStyled type="outlined">
|
||||
<button @click="modal?.hide()">
|
||||
<XIcon />
|
||||
{{ formatMessage(commonMessages.cancelButton) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled color="red">
|
||||
<button @click="confirm">
|
||||
<XIcon />
|
||||
{{ formatMessage(messages.revokeButton) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<Button type="outlined" @click="modal?.hide()">
|
||||
<XIcon />
|
||||
{{ formatMessage(commonMessages.cancelButton) }}
|
||||
</Button>
|
||||
<Button type="colored" color="red" @click="confirm">
|
||||
<XIcon />
|
||||
{{ formatMessage(messages.revokeButton) }}
|
||||
</Button>
|
||||
</div>
|
||||
</template>
|
||||
</NewModal>
|
||||
@@ -31,7 +27,7 @@
|
||||
import { XIcon } from '@modrinth/assets'
|
||||
import {
|
||||
Admonition,
|
||||
ButtonStyled,
|
||||
Button,
|
||||
commonMessages,
|
||||
defineMessages,
|
||||
IntlFormatted,
|
||||
|
||||
+42
-39
@@ -2,13 +2,13 @@
|
||||
import { CopyIcon, EditIcon, PlusIcon, SpinnerIcon, TrashIcon, UploadIcon } from '@modrinth/assets'
|
||||
import {
|
||||
Avatar,
|
||||
ButtonStyled,
|
||||
Button,
|
||||
Checkbox,
|
||||
Chips,
|
||||
defineMessages,
|
||||
injectNotificationManager,
|
||||
OverflowMenu,
|
||||
StyledInput,
|
||||
TeleportOverflowMenu,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { useQueryClient } from '@tanstack/vue-query'
|
||||
@@ -298,17 +298,24 @@ const messages = defineMessages({
|
||||
<div class="flex flex-col gap-1">
|
||||
<span class="text-lg font-semibold text-contrast">Icon</span>
|
||||
<div class="group relative w-fit">
|
||||
<OverflowMenu
|
||||
v-tooltip="formatMessage(messages.editIcon)"
|
||||
class="bg-transparent border-none appearance-none p-0 m-0 cursor-pointer group-active:scale-95 transition-transform"
|
||||
<TeleportOverflowMenu
|
||||
:label="formatMessage(messages.editIcon)"
|
||||
:tooltip="formatMessage(messages.editIcon)"
|
||||
:icon-only="false"
|
||||
type="quiet"
|
||||
interaction="none"
|
||||
class="m-0 !h-auto cursor-pointer appearance-none border-none bg-transparent !p-0 transition-transform group-active:scale-95"
|
||||
:options="[
|
||||
{
|
||||
id: 'select',
|
||||
label: icon
|
||||
? formatMessage(messages.replaceIcon)
|
||||
: formatMessage(messages.selectIcon),
|
||||
action: () => setIcon(),
|
||||
},
|
||||
{
|
||||
id: 'remove',
|
||||
color: 'danger',
|
||||
label: formatMessage(messages.removeIcon),
|
||||
action: () => resetIcon(),
|
||||
shown: !!icon,
|
||||
},
|
||||
@@ -331,7 +338,7 @@ const messages = defineMessages({
|
||||
{{ icon ? formatMessage(messages.replaceIcon) : formatMessage(messages.selectIcon) }}
|
||||
</template>
|
||||
<template #remove> <TrashIcon /> {{ formatMessage(messages.removeIcon) }} </template>
|
||||
</OverflowMenu>
|
||||
</TeleportOverflowMenu>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -352,17 +359,15 @@ const messages = defineMessages({
|
||||
<h2 id="duplicate-instance-label" class="m-0 text-lg font-semibold text-contrast block">
|
||||
{{ formatMessage(messages.duplicateInstance) }}
|
||||
</h2>
|
||||
<ButtonStyled>
|
||||
<button
|
||||
v-tooltip="installing ? formatMessage(messages.duplicateButtonTooltipInstalling) : null"
|
||||
aria-labelledby="duplicate-instance-label"
|
||||
:disabled="installing"
|
||||
class="w-max !shadow-none"
|
||||
@click="duplicateInstance"
|
||||
>
|
||||
<CopyIcon /> {{ formatMessage(messages.duplicateButton) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<Button
|
||||
v-tooltip="installing ? formatMessage(messages.duplicateButtonTooltipInstalling) : null"
|
||||
aria-labelledby="duplicate-instance-label"
|
||||
:disabled="installing"
|
||||
class="w-max"
|
||||
@click="duplicateInstance"
|
||||
>
|
||||
<CopyIcon /> {{ formatMessage(messages.duplicateButton) }}
|
||||
</Button>
|
||||
<p class="m-0">
|
||||
{{ formatMessage(messages.duplicateInstanceDescription) }}
|
||||
</p>
|
||||
@@ -388,11 +393,9 @@ const messages = defineMessages({
|
||||
class="w-full max-w-[300px]"
|
||||
@submit="() => addCategory"
|
||||
/>
|
||||
<ButtonStyled>
|
||||
<button class="w-fit !shadow-none" @click="() => addCategory()">
|
||||
<PlusIcon /> {{ formatMessage(messages.libraryGroupsCreate) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<Button class="w-fit" @click="() => addCategory()">
|
||||
<PlusIcon /> {{ formatMessage(messages.libraryGroupsCreate) }}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<p class="m-0">
|
||||
@@ -421,22 +424,22 @@ const messages = defineMessages({
|
||||
<h2 id="delete-instance-label" class="m-0 text-lg font-semibold text-contrast block">
|
||||
{{ formatMessage(messages.deleteInstance) }}
|
||||
</h2>
|
||||
<ButtonStyled color="red">
|
||||
<button
|
||||
aria-labelledby="delete-instance-label"
|
||||
:disabled="removing"
|
||||
class="w-fit !shadow-none"
|
||||
@click="deleteConfirmModal.show()"
|
||||
>
|
||||
<SpinnerIcon v-if="removing" class="animate-spin" />
|
||||
<TrashIcon v-else />
|
||||
{{
|
||||
removing
|
||||
? formatMessage(messages.deletingInstanceButton)
|
||||
: formatMessage(messages.deleteInstanceButton)
|
||||
}}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<Button
|
||||
type="colored"
|
||||
color="red"
|
||||
aria-labelledby="delete-instance-label"
|
||||
:disabled="removing"
|
||||
class="w-fit"
|
||||
@click="deleteConfirmModal.show()"
|
||||
>
|
||||
<SpinnerIcon v-if="removing" class="animate-spin" />
|
||||
<TrashIcon v-else />
|
||||
{{
|
||||
removing
|
||||
? formatMessage(messages.deletingInstanceButton)
|
||||
: formatMessage(messages.deleteInstanceButton)
|
||||
}}
|
||||
</Button>
|
||||
<p class="m-0">
|
||||
{{ formatMessage(messages.deleteInstanceDescription) }}
|
||||
</p>
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
XCircleIcon,
|
||||
} from '@modrinth/assets'
|
||||
import {
|
||||
ButtonStyled,
|
||||
Button,
|
||||
Checkbox,
|
||||
defineMessages,
|
||||
injectNotificationManager,
|
||||
@@ -224,45 +224,60 @@ const messages = defineMessages({
|
||||
wrapper-class="flex-1 min-w-0"
|
||||
@update:model-value="(val) => (javaPath = String(val))"
|
||||
/>
|
||||
<ButtonStyled
|
||||
<Button
|
||||
type="quiet"
|
||||
:color="
|
||||
!hoveringTest && !testingJava
|
||||
? javaTestResult === true
|
||||
? 'green'
|
||||
: 'red'
|
||||
: 'standard'
|
||||
: undefined
|
||||
"
|
||||
color-fill="text"
|
||||
:disabled="!overrideJavaInstall || testingJava"
|
||||
:style="{
|
||||
'--legacy-button-color':
|
||||
(!hoveringTest && !testingJava
|
||||
? javaTestResult === true
|
||||
? 'green'
|
||||
: 'red'
|
||||
: 'standard') &&
|
||||
(!hoveringTest && !testingJava
|
||||
? javaTestResult === true
|
||||
? 'green'
|
||||
: 'red'
|
||||
: 'standard') !== 'standard'
|
||||
? `var(--color-${
|
||||
!hoveringTest && !testingJava
|
||||
? javaTestResult === true
|
||||
? 'green'
|
||||
: 'red'
|
||||
: 'standard'
|
||||
})`
|
||||
: undefined,
|
||||
}"
|
||||
class="!text-[var(--legacy-button-color,var(--color-base))] [&>svg]:!text-[var(--legacy-button-color,var(--color-primary))]"
|
||||
@click="testJavaInstallation(activePath, optimalJava?.parsed_version, true)"
|
||||
@mouseenter="overrideJavaInstall && (hoveringTest = true)"
|
||||
@mouseleave="hoveringTest = false"
|
||||
>
|
||||
<button
|
||||
:disabled="!overrideJavaInstall || testingJava"
|
||||
@click="testJavaInstallation(activePath, optimalJava?.parsed_version, true)"
|
||||
@mouseenter="overrideJavaInstall && (hoveringTest = true)"
|
||||
@mouseleave="hoveringTest = false"
|
||||
>
|
||||
<SpinnerIcon v-if="testingJava" class="animate-spin h-4 w-4" />
|
||||
<CheckCircleIcon
|
||||
v-else-if="javaTestResult === true && !hoveringTest"
|
||||
class="h-4 w-4"
|
||||
/>
|
||||
<XCircleIcon v-else-if="javaTestResult !== true && !hoveringTest" class="h-4 w-4" />
|
||||
<RefreshCwIcon v-else-if="overrideJavaInstall" class="h-4 w-4" />
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<SpinnerIcon v-if="testingJava" class="animate-spin h-4 w-4" />
|
||||
<CheckCircleIcon
|
||||
v-else-if="javaTestResult === true && !hoveringTest"
|
||||
class="h-4 w-4"
|
||||
/>
|
||||
<XCircleIcon v-else-if="javaTestResult !== true && !hoveringTest" class="h-4 w-4" />
|
||||
<RefreshCwIcon v-else-if="overrideJavaInstall" class="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
<div v-if="overrideJavaInstall" class="flex gap-2">
|
||||
<ButtonStyled>
|
||||
<button @click="handleDetectJava">
|
||||
<SearchIcon />
|
||||
Detect
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled>
|
||||
<button @click="handleBrowseJava">
|
||||
<FolderSearchIcon />
|
||||
Browse
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<Button @click="handleDetectJava">
|
||||
<SearchIcon />
|
||||
Detect
|
||||
</Button>
|
||||
<Button @click="handleBrowseJava">
|
||||
<FolderSearchIcon />
|
||||
Browse
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+25
-32
@@ -2,13 +2,11 @@
|
||||
<div v-if="canUnpublish" class="flex flex-col gap-2.5">
|
||||
<span class="text-lg font-semibold text-contrast">{{ formatMessage(messages.title) }}</span>
|
||||
<div>
|
||||
<ButtonStyled color="orange">
|
||||
<button :disabled="busy" @click="unpublishModal?.show()">
|
||||
<SpinnerIcon v-if="unpublishing" class="animate-spin" />
|
||||
<UnlinkIcon v-else class="size-5" />
|
||||
{{ formatMessage(unpublishing ? messages.unpublishingButton : messages.unpublishButton) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<Button type="colored" color="orange" :disabled="busy" @click="unpublishModal?.show()">
|
||||
<SpinnerIcon v-if="unpublishing" class="animate-spin" />
|
||||
<UnlinkIcon v-else class="size-5" />
|
||||
{{ formatMessage(unpublishing ? messages.unpublishingButton : messages.unpublishButton) }}
|
||||
</Button>
|
||||
</div>
|
||||
<span class="text-primary">{{ formatMessage(messages.unpublishDescription) }}</span>
|
||||
</div>
|
||||
@@ -17,13 +15,11 @@
|
||||
formatMessage(messages.linkedTitle)
|
||||
}}</span>
|
||||
<div>
|
||||
<ButtonStyled color="orange">
|
||||
<button :disabled="busy" @click="unlinkModal?.show()">
|
||||
<SpinnerIcon v-if="unlinking" class="animate-spin" />
|
||||
<UnlinkIcon v-else class="size-5" />
|
||||
{{ formatMessage(unlinking ? messages.unlinkingButton : messages.unlinkButton) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<Button type="colored" color="orange" :disabled="busy" @click="unlinkModal?.show()">
|
||||
<SpinnerIcon v-if="unlinking" class="animate-spin" />
|
||||
<UnlinkIcon v-else class="size-5" />
|
||||
{{ formatMessage(unlinking ? messages.unlinkingButton : messages.unlinkButton) }}
|
||||
</Button>
|
||||
</div>
|
||||
<span class="text-primary">{{ formatMessage(messages.unlinkDescription) }}</span>
|
||||
</div>
|
||||
@@ -39,15 +35,11 @@
|
||||
}}</Admonition>
|
||||
<template #actions
|
||||
><div class="flex justify-end gap-2">
|
||||
<ButtonStyled type="outlined"
|
||||
><button class="!border" @click="unpublishModal?.hide()">
|
||||
<XIcon />{{ formatMessage(commonMessages.cancelButton) }}
|
||||
</button></ButtonStyled
|
||||
><ButtonStyled color="orange"
|
||||
><button :disabled="busy" @click="confirmUnpublish">
|
||||
<UnlinkIcon />{{ formatMessage(messages.unpublishButton) }}
|
||||
</button></ButtonStyled
|
||||
>
|
||||
<Button type="outlined" class="!border" @click="unpublishModal?.hide()">
|
||||
<XIcon />{{ formatMessage(commonMessages.cancelButton) }} </Button
|
||||
><Button type="colored" color="orange" :disabled="busy" @click="confirmUnpublish">
|
||||
<UnlinkIcon />{{ formatMessage(messages.unpublishButton) }}
|
||||
</Button>
|
||||
</div></template
|
||||
>
|
||||
</NewModal>
|
||||
@@ -70,15 +62,16 @@
|
||||
</div>
|
||||
<template #actions
|
||||
><div class="flex justify-end gap-2">
|
||||
<ButtonStyled type="outlined"
|
||||
><button class="!border" @click="unlinkModal?.hide()">
|
||||
<XIcon />{{ formatMessage(commonMessages.cancelButton) }}
|
||||
</button></ButtonStyled
|
||||
><ButtonStyled color="orange"
|
||||
><button :disabled="busy || backupBusy" @click="confirmUnlink">
|
||||
<UnlinkIcon />{{ formatMessage(messages.unlinkButton) }}
|
||||
</button></ButtonStyled
|
||||
<Button type="outlined" class="!border" @click="unlinkModal?.hide()">
|
||||
<XIcon />{{ formatMessage(commonMessages.cancelButton) }} </Button
|
||||
><Button
|
||||
type="colored"
|
||||
color="orange"
|
||||
:disabled="busy || backupBusy"
|
||||
@click="confirmUnlink"
|
||||
>
|
||||
<UnlinkIcon />{{ formatMessage(messages.unlinkButton) }}
|
||||
</Button>
|
||||
</div></template
|
||||
>
|
||||
</NewModal>
|
||||
@@ -88,7 +81,7 @@
|
||||
import { SpinnerIcon, UnlinkIcon, XIcon } from '@modrinth/assets'
|
||||
import {
|
||||
Admonition,
|
||||
ButtonStyled,
|
||||
Button,
|
||||
commonMessages,
|
||||
defineMessages,
|
||||
InlineBackupCreator,
|
||||
|
||||
+22
-23
@@ -40,29 +40,28 @@
|
||||
</template>
|
||||
<template #cell-actions="{ row }">
|
||||
<div class="flex justify-end">
|
||||
<ButtonStyled circular type="transparent">
|
||||
<button
|
||||
v-tooltip="formatMessage(messages.revokeInvite)"
|
||||
:aria-label="
|
||||
formatMessage(messages.revokeInviteWithCode, {
|
||||
code: row.id,
|
||||
})
|
||||
<IconButton
|
||||
v-tooltip="formatMessage(messages.revokeInvite)"
|
||||
type="quiet"
|
||||
:label="
|
||||
formatMessage(messages.revokeInviteWithCode, {
|
||||
code: row.id,
|
||||
})
|
||||
"
|
||||
:disabled="revokeInviteMutation.isPending.value || isBusy"
|
||||
class="text-secondary hover:!filter-none hover:text-red focus-visible:!filter-none"
|
||||
@click="revokeInviteModal?.show(row.id)"
|
||||
>
|
||||
<SpinnerIcon
|
||||
v-if="
|
||||
revokeInviteMutation.isPending.value &&
|
||||
revokeInviteMutation.variables.value?.inviteId === row.id
|
||||
"
|
||||
:disabled="revokeInviteMutation.isPending.value || isBusy"
|
||||
class="text-secondary hover:!filter-none hover:text-red focus-visible:!filter-none"
|
||||
@click="revokeInviteModal?.show(row.id)"
|
||||
>
|
||||
<SpinnerIcon
|
||||
v-if="
|
||||
revokeInviteMutation.isPending.value &&
|
||||
revokeInviteMutation.variables.value?.inviteId === row.id
|
||||
"
|
||||
class="animate-spin"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<XIcon v-else aria-hidden="true" />
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
class="animate-spin"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<XIcon v-else aria-hidden="true" />
|
||||
</IconButton>
|
||||
</div>
|
||||
</template>
|
||||
</Table>
|
||||
@@ -81,8 +80,8 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { SpinnerIcon, XIcon } from '@modrinth/assets'
|
||||
import { IconButton } from '@modrinth/ui'
|
||||
import {
|
||||
ButtonStyled,
|
||||
CopyCode,
|
||||
defineMessages,
|
||||
Table,
|
||||
|
||||
@@ -1307,14 +1307,16 @@ function getOverflowOptions(item: ContentItem): OverflowMenuOption[] {
|
||||
const options: OverflowMenuOption[] = []
|
||||
|
||||
options.push({
|
||||
id: formatMessage(commonMessages.showFileButton),
|
||||
id: 'show-file',
|
||||
label: formatMessage(commonMessages.showFileButton),
|
||||
icon: FolderOpenIcon,
|
||||
action: () => highlightModInInstance(instance.value.id, item.file_path),
|
||||
})
|
||||
|
||||
if (item.project?.slug) {
|
||||
options.push({
|
||||
id: formatMessage(commonMessages.copyLinkButton),
|
||||
id: 'copy-link',
|
||||
label: formatMessage(commonMessages.copyLinkButton),
|
||||
icon: ClipboardCopyIcon,
|
||||
action: async () => {
|
||||
await navigator.clipboard.writeText(
|
||||
|
||||
@@ -96,11 +96,9 @@
|
||||
</span>
|
||||
</template>
|
||||
<template #actions>
|
||||
<ButtonStyled color="brand"
|
||||
><button class="!h-10" @click="signInToShare">
|
||||
<LogInIcon aria-hidden="true" />{{ formatMessage(lockedActionButton) }}
|
||||
</button></ButtonStyled
|
||||
>
|
||||
<Button type="colored" color="brand" size="lg" @click="signInToShare">
|
||||
<LogInIcon aria-hidden="true" />{{ formatMessage(lockedActionButton) }}
|
||||
</Button>
|
||||
</template>
|
||||
</SharedInstanceShareEmptyState>
|
||||
|
||||
@@ -110,21 +108,21 @@
|
||||
:description="formatMessage(messages.noFriendsInvitedDescription)"
|
||||
>
|
||||
<template #actions>
|
||||
<ButtonStyled color="brand"
|
||||
><button
|
||||
class="!h-10"
|
||||
:disabled="inviteLink.pending.value || !hasRemainingUserSlots"
|
||||
@click="showInvitePlayers($event)"
|
||||
>
|
||||
<SpinnerIcon
|
||||
v-if="inviteLink.pending.value"
|
||||
class="animate-spin"
|
||||
aria-hidden="true"
|
||||
/><UserPlusIcon v-else aria-hidden="true" />{{
|
||||
formatMessage(messages.inviteFriendsButton)
|
||||
}}
|
||||
</button></ButtonStyled
|
||||
<Button
|
||||
type="colored"
|
||||
color="brand"
|
||||
size="lg"
|
||||
:disabled="inviteLink.pending.value || !hasRemainingUserSlots"
|
||||
@click="showInvitePlayers($event)"
|
||||
>
|
||||
<SpinnerIcon
|
||||
v-if="inviteLink.pending.value"
|
||||
class="animate-spin"
|
||||
aria-hidden="true"
|
||||
/><UserPlusIcon v-else aria-hidden="true" />{{
|
||||
formatMessage(messages.inviteFriendsButton)
|
||||
}}
|
||||
</Button>
|
||||
</template>
|
||||
</SharedInstanceShareEmptyState>
|
||||
</div>
|
||||
@@ -134,7 +132,7 @@
|
||||
import { LogInIcon, SpinnerIcon, UserPlusIcon } from '@modrinth/assets'
|
||||
import {
|
||||
Avatar,
|
||||
ButtonStyled,
|
||||
Button,
|
||||
ConfirmUnlinkModal,
|
||||
defineMessages,
|
||||
injectAuth,
|
||||
|
||||
@@ -11,28 +11,29 @@
|
||||
clearable
|
||||
/>
|
||||
<template v-if="!actionsLocked">
|
||||
<ButtonStyled type="outlined">
|
||||
<button
|
||||
class="flex !h-10 shrink-0 items-center gap-2 !border"
|
||||
:disabled="pushUpdateDisabled"
|
||||
@click="management.pushUpdate($event)"
|
||||
>
|
||||
<SpinnerIcon v-if="pushUpdatePending" class="animate-spin" aria-hidden="true" />
|
||||
<UploadIcon v-else aria-hidden="true" />
|
||||
{{ formatMessage(messages.pushUpdate) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled color="brand">
|
||||
<button
|
||||
class="flex !h-10 shrink-0 items-center gap-2"
|
||||
:disabled="invitePending || inviteDisabled"
|
||||
@click="management.invite($event)"
|
||||
>
|
||||
<SpinnerIcon v-if="invitePending" class="animate-spin" aria-hidden="true" />
|
||||
<UserPlusIcon v-else aria-hidden="true" />
|
||||
Invite friends
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<Button
|
||||
type="outlined"
|
||||
size="lg"
|
||||
class="shrink-0 !border"
|
||||
:disabled="pushUpdateDisabled"
|
||||
@click="management.pushUpdate($event)"
|
||||
>
|
||||
<SpinnerIcon v-if="pushUpdatePending" class="animate-spin" aria-hidden="true" />
|
||||
<UploadIcon v-else aria-hidden="true" />
|
||||
{{ formatMessage(messages.pushUpdate) }}
|
||||
</Button>
|
||||
<Button
|
||||
type="colored"
|
||||
color="brand"
|
||||
size="lg"
|
||||
class="shrink-0"
|
||||
:disabled="invitePending || inviteDisabled"
|
||||
@click="management.invite($event)"
|
||||
>
|
||||
<SpinnerIcon v-if="invitePending" class="animate-spin" aria-hidden="true" />
|
||||
<UserPlusIcon v-else aria-hidden="true" />
|
||||
Invite friends
|
||||
</Button>
|
||||
</template>
|
||||
</div>
|
||||
<div v-if="hasMultipleMethods" class="flex flex-wrap items-center gap-1.5">
|
||||
@@ -120,15 +121,15 @@
|
||||
</template>
|
||||
<template #cell-actions="{ row }">
|
||||
<div v-if="!actionsLocked" class="flex items-center justify-end">
|
||||
<ButtonStyled circular type="transparent"
|
||||
><button
|
||||
v-tooltip="'Revoke access'"
|
||||
:aria-label="`Revoke access for ${row.username}`"
|
||||
class="text-secondary hover:!filter-none hover:text-red focus-visible:!filter-none"
|
||||
@click="management.remove(row)"
|
||||
>
|
||||
<XIcon aria-hidden="true" /></button
|
||||
></ButtonStyled>
|
||||
<IconButton
|
||||
v-tooltip="'Revoke access'"
|
||||
type="quiet"
|
||||
:label="`Revoke access for ${row.username}`"
|
||||
class="text-secondary hover:!filter-none hover:text-red focus-visible:!filter-none"
|
||||
@click="management.remove(row)"
|
||||
>
|
||||
<XIcon aria-hidden="true"
|
||||
/></IconButton>
|
||||
</div>
|
||||
</template>
|
||||
</Table>
|
||||
@@ -145,10 +146,10 @@ import {
|
||||
UserPlusIcon,
|
||||
XIcon,
|
||||
} from '@modrinth/assets'
|
||||
import { Button, IconButton } from '@modrinth/ui'
|
||||
import {
|
||||
AutoLink,
|
||||
Avatar,
|
||||
ButtonStyled,
|
||||
defineMessages,
|
||||
type SortDirection,
|
||||
StyledInput,
|
||||
|
||||
@@ -32,16 +32,12 @@
|
||||
</ul>
|
||||
</div>
|
||||
<div class="flex justify-end gap-2 pt-1">
|
||||
<ButtonStyled type="outlined"
|
||||
><button class="!border !border-surface-5" @click="modal?.hide()">
|
||||
<XIcon aria-hidden="true" />{{ formatMessage(commonMessages.cancelButton) }}
|
||||
</button></ButtonStyled
|
||||
>
|
||||
<ButtonStyled color="orange"
|
||||
><button :disabled="!row" @click="confirm">
|
||||
<UserXIcon aria-hidden="true" />{{ formatMessage(messages.removeButton) }}
|
||||
</button></ButtonStyled
|
||||
>
|
||||
<Button type="outlined" class="!border !border-surface-5" @click="modal?.hide()">
|
||||
<XIcon aria-hidden="true" />{{ formatMessage(commonMessages.cancelButton) }}
|
||||
</Button>
|
||||
<Button type="colored" color="orange" :disabled="!row" @click="confirm">
|
||||
<UserXIcon aria-hidden="true" />{{ formatMessage(messages.removeButton) }}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</NewModal>
|
||||
@@ -52,7 +48,7 @@ import { UserXIcon, XIcon } from '@modrinth/assets'
|
||||
import {
|
||||
Admonition,
|
||||
Avatar,
|
||||
ButtonStyled,
|
||||
Button,
|
||||
commonMessages,
|
||||
defineMessages,
|
||||
NewModal,
|
||||
|
||||
@@ -35,18 +35,14 @@
|
||||
"
|
||||
/>
|
||||
<div class="flex gap-2">
|
||||
<ButtonStyled type="outlined">
|
||||
<button class="!h-10" @click="addServerModal?.show()">
|
||||
<PlusIcon class="size-5" />
|
||||
{{ formatMessage(messages.addServer) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled color="brand">
|
||||
<button class="!h-10 flex items-center gap-2" @click="instancePage.browseServers">
|
||||
<CompassIcon class="size-5" />
|
||||
<span>{{ formatMessage(messages.browseServers) }}</span>
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<Button type="outlined" size="lg" @click="addServerModal?.show()">
|
||||
<PlusIcon class="size-5" />
|
||||
{{ formatMessage(messages.addServer) }}
|
||||
</Button>
|
||||
<Button type="colored" color="brand" size="lg" @click="instancePage.browseServers">
|
||||
<CompassIcon class="size-5" />
|
||||
<span>{{ formatMessage(messages.browseServers) }}</span>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-wrap items-center justify-between gap-2">
|
||||
@@ -67,16 +63,17 @@
|
||||
{{ option.label }}
|
||||
</button>
|
||||
</div>
|
||||
<ButtonStyled type="transparent" hover-color-fill="none">
|
||||
<button :disabled="refreshingAll" @click="refreshAllWorlds">
|
||||
<RefreshCwIcon :class="refreshingAll ? 'animate-spin' : ''" />
|
||||
{{
|
||||
formatMessage(
|
||||
refreshingAll ? messages.refreshingButton : commonMessages.refreshButton,
|
||||
)
|
||||
}}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<Button
|
||||
type="quiet"
|
||||
:disabled="refreshingAll"
|
||||
class="hover:!bg-transparent focus-visible:!bg-transparent"
|
||||
@click="refreshAllWorlds"
|
||||
>
|
||||
<RefreshCwIcon :class="refreshingAll ? 'animate-spin' : ''" />
|
||||
{{
|
||||
formatMessage(refreshingAll ? messages.refreshingButton : commonMessages.refreshButton)
|
||||
}}
|
||||
</Button>
|
||||
</div>
|
||||
<div class="flex flex-col w-full gap-2">
|
||||
<WorldItem
|
||||
@@ -122,26 +119,22 @@
|
||||
:description="formatMessage(messages.noWorldsDescription)"
|
||||
>
|
||||
<template #actions>
|
||||
<ButtonStyled type="outlined">
|
||||
<button class="!h-10" @click="addServerModal?.show()">
|
||||
<PlusIcon class="size-5" />
|
||||
{{ formatMessage(messages.addServer) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled color="brand">
|
||||
<button class="!h-10 flex items-center gap-2" @click="instancePage.browseServers">
|
||||
<CompassIcon class="size-5" />
|
||||
<span>{{ formatMessage(messages.browseServers) }}</span>
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<Button type="outlined" size="lg" @click="addServerModal?.show()">
|
||||
<PlusIcon class="size-5" />
|
||||
{{ formatMessage(messages.addServer) }}
|
||||
</Button>
|
||||
<Button type="colored" color="brand" size="lg" @click="instancePage.browseServers">
|
||||
<CompassIcon class="size-5" />
|
||||
<span>{{ formatMessage(messages.browseServers) }}</span>
|
||||
</Button>
|
||||
</template>
|
||||
</EmptyState>
|
||||
</ReadyTransition>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { CompassIcon, FilterIcon, PlusIcon, RefreshCwIcon, SearchIcon } from '@modrinth/assets'
|
||||
import { Button } from '@modrinth/ui'
|
||||
import {
|
||||
ButtonStyled,
|
||||
commonMessages,
|
||||
defineMessages,
|
||||
EmptyState,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { LibraryIcon, PlusIcon } from '@modrinth/assets'
|
||||
import { ButtonStyled, injectNotificationManager, NavTabs } from '@modrinth/ui'
|
||||
import { Button, injectNotificationManager, NavTabs } from '@modrinth/ui'
|
||||
import { inject, onUnmounted, ref, shallowRef } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
|
||||
@@ -53,12 +53,10 @@ onUnmounted(() => {
|
||||
{ label: 'Saved', href: `/library/saved`, shown: false },
|
||||
]"
|
||||
/>
|
||||
<ButtonStyled color="brand">
|
||||
<button :disabled="offline" @click="showCreationModal?.()">
|
||||
<PlusIcon />
|
||||
New instance
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<Button type="colored" color="brand" :disabled="offline" @click="showCreationModal?.()">
|
||||
<PlusIcon />
|
||||
New instance
|
||||
</Button>
|
||||
</div>
|
||||
<template v-if="instances && instances.length > 0">
|
||||
<RouterView v-if="route.path.startsWith('/library')" :instances="instances" />
|
||||
@@ -68,12 +66,10 @@ onUnmounted(() => {
|
||||
<NewInstanceImage />
|
||||
</div>
|
||||
<h3>No instances found</h3>
|
||||
<ButtonStyled color="brand">
|
||||
<button :disabled="offline" @click="showCreationModal?.()">
|
||||
<PlusIcon />
|
||||
Create new instance
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<Button type="colored" color="brand" :disabled="offline" @click="showCreationModal?.()">
|
||||
<PlusIcon />
|
||||
Create new instance
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -39,40 +39,40 @@
|
||||
</div>
|
||||
<div class="controls">
|
||||
<div class="buttons">
|
||||
<ButtonStyled circular>
|
||||
<button class="close" @click="hideImage">
|
||||
<XIcon aria-hidden="true" />
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled circular>
|
||||
<a
|
||||
class="open btn icon-only"
|
||||
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>
|
||||
<IconButton label="Close" class="close" @click="hideImage">
|
||||
<XIcon aria-hidden="true" />
|
||||
</IconButton>
|
||||
<ButtonLink
|
||||
class="open btn icon-only !w-9 !px-0 !rounded-full"
|
||||
target="_blank"
|
||||
:href="
|
||||
expandedGalleryItem.raw_url
|
||||
? expandedGalleryItem.raw_url
|
||||
: 'https://cdn.modrinth.com/placeholder-banner.svg'
|
||||
"
|
||||
>
|
||||
<ExternalIcon aria-hidden="true" />
|
||||
</ButtonLink>
|
||||
<IconButton label="Toggle zoom" @click="zoomedIn = !zoomedIn">
|
||||
<ExpandIcon v-if="!zoomedIn" aria-hidden="true" />
|
||||
<ContractIcon v-else aria-hidden="true" />
|
||||
</IconButton>
|
||||
<IconButton
|
||||
v-if="filteredGallery.length > 1"
|
||||
label="Previous image"
|
||||
class="previous"
|
||||
@click="previousImage()"
|
||||
>
|
||||
<LeftArrowIcon aria-hidden="true" />
|
||||
</IconButton>
|
||||
<IconButton
|
||||
v-if="filteredGallery.length > 1"
|
||||
label="Next image"
|
||||
class="next"
|
||||
@click="nextImage()"
|
||||
>
|
||||
<RightArrowIcon aria-hidden="true" />
|
||||
</IconButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -90,7 +90,7 @@ import {
|
||||
RightArrowIcon,
|
||||
XIcon,
|
||||
} from '@modrinth/assets'
|
||||
import { ButtonStyled, Card, useFormatDateTime } from '@modrinth/ui'
|
||||
import { ButtonLink, Card, IconButton, useFormatDateTime } from '@modrinth/ui'
|
||||
import { computed, onMounted, onUnmounted, ref } from 'vue'
|
||||
|
||||
import { hide_ads_window, show_ads_window } from '@/helpers/ads.js'
|
||||
|
||||
@@ -70,87 +70,104 @@
|
||||
>
|
||||
<template #actions>
|
||||
<template v-if="isServerProject">
|
||||
<ButtonStyled v-if="serverPlaying" color="red" size="large">
|
||||
<button type="button" @click="handleStopServer">
|
||||
<StopCircleIcon />
|
||||
{{ formatMessage(commonMessages.stopButton) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled v-else color="brand" size="large">
|
||||
<button type="button" :disabled="serverInstallLoading" @click="handleClickPlay">
|
||||
<PlayIcon />
|
||||
{{
|
||||
serverInstallLoading
|
||||
? formatMessage(commonMessages.installingLabel)
|
||||
: formatMessage(commonMessages.playButton)
|
||||
}}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled circular size="large">
|
||||
<button
|
||||
v-tooltip="formatMessage(commonMessages.addServerToInstanceButton)"
|
||||
type="button"
|
||||
:aria-label="formatMessage(commonMessages.addServerToInstanceButton)"
|
||||
@click="handleAddServerToInstance"
|
||||
>
|
||||
<PlusIcon />
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled circular size="large" type="transparent">
|
||||
<TeleportOverflowMenu
|
||||
:options="serverProjectHeaderMoreActions"
|
||||
tooltip="More options"
|
||||
aria-label="More options"
|
||||
>
|
||||
<MoreVerticalIcon />
|
||||
</TeleportOverflowMenu>
|
||||
</ButtonStyled>
|
||||
<Button
|
||||
v-if="serverPlaying"
|
||||
type="colored"
|
||||
color="red"
|
||||
size="xl"
|
||||
native-type="button"
|
||||
@click="handleStopServer"
|
||||
>
|
||||
<StopCircleIcon />
|
||||
{{ formatMessage(commonMessages.stopButton) }}
|
||||
</Button>
|
||||
<Button
|
||||
v-else
|
||||
type="colored"
|
||||
color="brand"
|
||||
size="xl"
|
||||
native-type="button"
|
||||
:disabled="serverInstallLoading"
|
||||
@click="handleClickPlay"
|
||||
>
|
||||
<PlayIcon />
|
||||
{{
|
||||
serverInstallLoading
|
||||
? formatMessage(commonMessages.installingLabel)
|
||||
: formatMessage(commonMessages.playButton)
|
||||
}}
|
||||
</Button>
|
||||
<IconButton
|
||||
v-tooltip="formatMessage(commonMessages.addServerToInstanceButton)"
|
||||
size="xl"
|
||||
:label="formatMessage(commonMessages.addServerToInstanceButton)"
|
||||
native-type="button"
|
||||
@click="handleAddServerToInstance"
|
||||
>
|
||||
<PlusIcon />
|
||||
</IconButton>
|
||||
<TeleportOverflowMenu
|
||||
type="quiet"
|
||||
size="xl"
|
||||
label="More options"
|
||||
:options="serverProjectHeaderMoreActions"
|
||||
>
|
||||
<MoreVerticalIcon />
|
||||
</TeleportOverflowMenu>
|
||||
</template>
|
||||
<template v-else>
|
||||
<ButtonStyled v-if="showSwitchVersion && onVersionsPage" size="large">
|
||||
<button v-tooltip="formatMessage(messages.alreadyInstalled)" type="button" disabled>
|
||||
<CheckIcon />
|
||||
{{ formatMessage(commonMessages.installedLabel) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled v-else-if="showSwitchVersion" size="large">
|
||||
<button type="button" @click="goToVersions">
|
||||
<SwapIcon />
|
||||
{{ formatMessage(messages.switchVersion) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled v-else color="brand" size="large">
|
||||
<button
|
||||
v-tooltip="
|
||||
installButtonInstalled ? formatMessage(messages.alreadyInstalled) : undefined
|
||||
"
|
||||
type="button"
|
||||
:disabled="installButtonDisabled"
|
||||
@click="install(null)"
|
||||
>
|
||||
<component :is="installButtonIcon" :class="installButtonIconClass" />
|
||||
{{
|
||||
installButtonInstalled
|
||||
? formatMessage(commonMessages.installedLabel)
|
||||
: installButtonValidating
|
||||
? formatMessage(commonMessages.validatingLabel)
|
||||
: installButtonLoading
|
||||
? formatMessage(commonMessages.installingLabel)
|
||||
: serverProjectSelected
|
||||
? formatMessage(commonMessages.selectedLabel)
|
||||
: formatMessage(commonMessages.installButton)
|
||||
}}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled circular size="large" type="transparent">
|
||||
<TeleportOverflowMenu
|
||||
:options="projectHeaderMoreActions"
|
||||
tooltip="More options"
|
||||
aria-label="More options"
|
||||
>
|
||||
<MoreVerticalIcon />
|
||||
</TeleportOverflowMenu>
|
||||
</ButtonStyled>
|
||||
<Button
|
||||
v-if="showSwitchVersion && onVersionsPage"
|
||||
v-tooltip="formatMessage(messages.alreadyInstalled)"
|
||||
size="xl"
|
||||
native-type="button"
|
||||
disabled
|
||||
>
|
||||
<CheckIcon />
|
||||
{{ formatMessage(commonMessages.installedLabel) }}
|
||||
</Button>
|
||||
<Button
|
||||
v-else-if="showSwitchVersion"
|
||||
size="xl"
|
||||
native-type="button"
|
||||
@click="goToVersions"
|
||||
>
|
||||
<SwapIcon />
|
||||
{{ formatMessage(messages.switchVersion) }}
|
||||
</Button>
|
||||
<Button
|
||||
v-else
|
||||
v-tooltip="
|
||||
installButtonInstalled ? formatMessage(messages.alreadyInstalled) : undefined
|
||||
"
|
||||
type="colored"
|
||||
color="brand"
|
||||
size="xl"
|
||||
native-type="button"
|
||||
:disabled="installButtonDisabled"
|
||||
@click="install(null)"
|
||||
>
|
||||
<component :is="installButtonIcon" :class="installButtonIconClass" />
|
||||
{{
|
||||
installButtonInstalled
|
||||
? formatMessage(commonMessages.installedLabel)
|
||||
: installButtonValidating
|
||||
? formatMessage(commonMessages.validatingLabel)
|
||||
: installButtonLoading
|
||||
? formatMessage(commonMessages.installingLabel)
|
||||
: serverProjectSelected
|
||||
? formatMessage(commonMessages.selectedLabel)
|
||||
: formatMessage(commonMessages.installButton)
|
||||
}}
|
||||
</Button>
|
||||
<TeleportOverflowMenu
|
||||
type="quiet"
|
||||
size="xl"
|
||||
label="More options"
|
||||
:options="projectHeaderMoreActions"
|
||||
>
|
||||
<MoreVerticalIcon />
|
||||
</TeleportOverflowMenu>
|
||||
</template>
|
||||
</template>
|
||||
</ProjectPageHeader>
|
||||
@@ -241,11 +258,12 @@ import {
|
||||
} from '@modrinth/assets'
|
||||
import {
|
||||
BrowseInstallHeader,
|
||||
ButtonStyled,
|
||||
Button,
|
||||
commonMessages,
|
||||
CreationFlowModal,
|
||||
defineMessages,
|
||||
getTargetInstallPreferences,
|
||||
IconButton,
|
||||
injectNotificationManager,
|
||||
NavTabs,
|
||||
ProjectBackgroundGradient,
|
||||
@@ -571,13 +589,13 @@ const serverProjectHeaderMoreActions = computed(() => [
|
||||
action: openProjectInBrowser,
|
||||
},
|
||||
{
|
||||
divider: true,
|
||||
type: 'divider',
|
||||
},
|
||||
{
|
||||
id: 'report',
|
||||
label: formatMessage(commonMessages.reportButton),
|
||||
icon: ReportIcon,
|
||||
color: 'red',
|
||||
tone: 'red',
|
||||
action: reportProject,
|
||||
},
|
||||
])
|
||||
@@ -605,13 +623,13 @@ const projectHeaderMoreActions = computed(() => [
|
||||
action: openProjectInBrowser,
|
||||
},
|
||||
{
|
||||
divider: true,
|
||||
type: 'divider',
|
||||
},
|
||||
{
|
||||
id: 'report',
|
||||
label: formatMessage(commonMessages.reportButton),
|
||||
icon: ReportIcon,
|
||||
color: 'red',
|
||||
tone: 'red',
|
||||
action: reportProject,
|
||||
},
|
||||
])
|
||||
|
||||
@@ -15,62 +15,62 @@
|
||||
:dependency-link-creator="createDependencyLink"
|
||||
>
|
||||
<template #headerActions>
|
||||
<ButtonStyled color="brand">
|
||||
<button
|
||||
:disabled="installing || (installed && installedVersion === version.id)"
|
||||
@click="() => version && install(version.id)"
|
||||
>
|
||||
<DownloadIcon v-if="!installed" />
|
||||
<SwapIcon v-else-if="installedVersion !== version.id" />
|
||||
<CheckIcon v-else />
|
||||
{{
|
||||
installing
|
||||
? formatMessage(messages.installing)
|
||||
: installed && installedVersion === version.id
|
||||
? formatMessage(commonMessages.installedLabel)
|
||||
: installed
|
||||
? formatMessage(commonMessages.switchToVersionButton)
|
||||
: formatMessage(commonMessages.installButton)
|
||||
}}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled type="outlined" circular>
|
||||
<OverflowMenu
|
||||
v-tooltip="formatMessage(commonMessages.moreOptionsButton)"
|
||||
:options="[
|
||||
{
|
||||
id: 'open-in-browser',
|
||||
link: `https://modrinth.com/${project.project_type}/${project.slug}/version/${version.id}`,
|
||||
external: true,
|
||||
},
|
||||
{
|
||||
id: 'report',
|
||||
color: 'red',
|
||||
hoverFilled: true,
|
||||
link: `https://modrinth.com/report?item=version&itemID=${version.id}`,
|
||||
external: true,
|
||||
},
|
||||
]"
|
||||
aria-label="More options"
|
||||
>
|
||||
<MoreVerticalIcon aria-hidden="true" />
|
||||
<template #open-in-browser>
|
||||
<ExternalIcon aria-hidden="true" />
|
||||
{{ formatMessage(commonMessages.openInBrowserButton) }}
|
||||
</template>
|
||||
<template #report>
|
||||
<ReportIcon aria-hidden="true" /> {{ formatMessage(commonMessages.reportButton) }}
|
||||
</template>
|
||||
</OverflowMenu>
|
||||
</ButtonStyled>
|
||||
<Button
|
||||
type="colored"
|
||||
color="brand"
|
||||
:disabled="installing || (installed && installedVersion === version.id)"
|
||||
@click="() => version && install(version.id)"
|
||||
>
|
||||
<DownloadIcon v-if="!installed" />
|
||||
<SwapIcon v-else-if="installedVersion !== version.id" />
|
||||
<CheckIcon v-else />
|
||||
{{
|
||||
installing
|
||||
? formatMessage(messages.installing)
|
||||
: installed && installedVersion === version.id
|
||||
? formatMessage(commonMessages.installedLabel)
|
||||
: installed
|
||||
? formatMessage(commonMessages.switchToVersionButton)
|
||||
: formatMessage(commonMessages.installButton)
|
||||
}}
|
||||
</Button>
|
||||
<TeleportOverflowMenu
|
||||
type="outlined"
|
||||
label="More options"
|
||||
:tooltip="formatMessage(commonMessages.moreOptionsButton)"
|
||||
:options="[
|
||||
{
|
||||
id: 'open-in-browser',
|
||||
label: formatMessage(commonMessages.openInBrowserButton),
|
||||
type: 'link',
|
||||
href: `https://modrinth.com/${project.project_type}/${project.slug}/version/${version.id}`,
|
||||
target: '_blank',
|
||||
},
|
||||
{
|
||||
id: 'report',
|
||||
label: formatMessage(commonMessages.reportButton),
|
||||
type: 'link',
|
||||
tone: 'red',
|
||||
href: `https://modrinth.com/report?item=version&itemID=${version.id}`,
|
||||
target: '_blank',
|
||||
},
|
||||
]"
|
||||
>
|
||||
<MoreVerticalIcon aria-hidden="true" />
|
||||
<template #open-in-browser>
|
||||
<ExternalIcon aria-hidden="true" />
|
||||
{{ formatMessage(commonMessages.openInBrowserButton) }}
|
||||
</template>
|
||||
<template #report>
|
||||
<ReportIcon aria-hidden="true" /> {{ formatMessage(commonMessages.reportButton) }}
|
||||
</template>
|
||||
</TeleportOverflowMenu>
|
||||
</template>
|
||||
<template #supplementaryResourceActions="{ file }">
|
||||
<ButtonStyled>
|
||||
<a :href="file.url" :download="file.filename" target="_blank">
|
||||
<DownloadIcon aria-hidden="true" />
|
||||
{{ formatMessage(messages.downloadInBrowser) }}
|
||||
</a>
|
||||
</ButtonStyled>
|
||||
<ButtonLink :href="file.url" :download="file.filename" target="_blank">
|
||||
<DownloadIcon aria-hidden="true" />
|
||||
{{ formatMessage(messages.downloadInBrowser) }}
|
||||
</ButtonLink>
|
||||
</template>
|
||||
</VersionPage>
|
||||
</div>
|
||||
@@ -87,12 +87,11 @@ import {
|
||||
ReportIcon,
|
||||
VersionIcon,
|
||||
} from '@modrinth/assets'
|
||||
import { Button, ButtonLink, TeleportOverflowMenu } from '@modrinth/ui'
|
||||
import {
|
||||
ButtonStyled,
|
||||
commonMessages,
|
||||
defineMessages,
|
||||
type DependencyContext,
|
||||
OverflowMenu,
|
||||
useVIntl,
|
||||
VersionPage,
|
||||
} from '@modrinth/ui'
|
||||
|
||||
@@ -9,76 +9,53 @@
|
||||
:version-link="(version) => buildProjectHref(`/project/${project.id}/version/${version.id}`)"
|
||||
>
|
||||
<template #actions="{ version }">
|
||||
<ButtonStyled
|
||||
circular
|
||||
type="transparent"
|
||||
:color="installed && version.id === installedVersion ? 'standard' : 'green'"
|
||||
<IconButton
|
||||
v-tooltip="
|
||||
!installed
|
||||
? formatMessage(commonMessages.installButton)
|
||||
: version.id !== installedVersion
|
||||
? formatMessage(commonMessages.switchToVersionButton)
|
||||
: formatMessage(messages.alreadyInstalled)
|
||||
"
|
||||
type="quiet"
|
||||
:color="installed && version.id === installedVersion ? undefined : 'green'"
|
||||
:label="
|
||||
!installed
|
||||
? formatMessage(commonMessages.installButton)
|
||||
: version.id !== installedVersion
|
||||
? formatMessage(commonMessages.switchToVersionButton)
|
||||
: formatMessage(messages.alreadyInstalled)
|
||||
"
|
||||
:disabled="installing || (installed && version.id === installedVersion)"
|
||||
@click.stop="() => install(version.id)"
|
||||
>
|
||||
<button
|
||||
v-tooltip="
|
||||
!installed
|
||||
? formatMessage(commonMessages.installButton)
|
||||
: version.id !== installedVersion
|
||||
? formatMessage(commonMessages.switchToVersionButton)
|
||||
: formatMessage(messages.alreadyInstalled)
|
||||
"
|
||||
:disabled="installing || (installed && version.id === installedVersion)"
|
||||
@click.stop="() => install(version.id)"
|
||||
>
|
||||
<DownloadIcon v-if="!installed" />
|
||||
<SwapIcon v-else-if="installed && version.id !== installedVersion" />
|
||||
<CheckIcon v-else />
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled circular type="transparent">
|
||||
<OverflowMenu
|
||||
v-if="false"
|
||||
:options="[
|
||||
{
|
||||
id: 'install-elsewhere',
|
||||
action: () => {},
|
||||
shown: false && !!instance,
|
||||
color: 'primary',
|
||||
hoverFilled: true,
|
||||
},
|
||||
{
|
||||
id: 'open-in-browser',
|
||||
link: `https://modrinth.com/${project.project_type}/${project.slug}/version/${version.id}`,
|
||||
},
|
||||
]"
|
||||
aria-label="More options"
|
||||
>
|
||||
<MoreVerticalIcon aria-hidden="true" />
|
||||
<template #install-elsewhere>
|
||||
<DownloadIcon aria-hidden="true" />
|
||||
Add to another instance
|
||||
</template>
|
||||
<template #open-in-browser>
|
||||
<ExternalIcon /> {{ formatMessage(commonMessages.openInBrowserButton) }}
|
||||
</template>
|
||||
</OverflowMenu>
|
||||
<a
|
||||
v-else
|
||||
v-tooltip="formatMessage(commonMessages.openInBrowserButton)"
|
||||
:href="`https://modrinth.com/${project.project_type}/${project.slug}/version/${version.id}`"
|
||||
target="_blank"
|
||||
>
|
||||
<ExternalIcon />
|
||||
</a>
|
||||
</ButtonStyled>
|
||||
<DownloadIcon v-if="!installed" />
|
||||
<SwapIcon v-else-if="installed && version.id !== installedVersion" />
|
||||
<CheckIcon v-else />
|
||||
</IconButton>
|
||||
<ButtonLink
|
||||
v-tooltip="formatMessage(commonMessages.openInBrowserButton)"
|
||||
type="quiet"
|
||||
:href="`https://modrinth.com/${project.project_type}/${project.slug}/version/${version.id}`"
|
||||
target="_blank"
|
||||
:aria-label="formatMessage(commonMessages.openInBrowserButton)"
|
||||
class="!w-9 !px-0 !rounded-full"
|
||||
>
|
||||
<ExternalIcon />
|
||||
</ButtonLink>
|
||||
</template>
|
||||
</ProjectPageVersions>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { CheckIcon, DownloadIcon, ExternalIcon, MoreVerticalIcon } from '@modrinth/assets'
|
||||
import { CheckIcon, DownloadIcon, ExternalIcon } from '@modrinth/assets'
|
||||
import {
|
||||
ButtonStyled,
|
||||
ButtonLink,
|
||||
commonMessages,
|
||||
defineMessages,
|
||||
IconButton,
|
||||
injectNotificationManager,
|
||||
OverflowMenu,
|
||||
ProjectPageVersions,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
|
||||
Reference in New Issue
Block a user