mirror of
https://github.com/modrinth/code.git
synced 2026-08-31 03:55:59 +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:
@@ -27,18 +27,17 @@
|
||||
</div>
|
||||
</div>
|
||||
<template v-if="contentError" #top-right-actions>
|
||||
<ButtonStyled color="red" type="outlined">
|
||||
<button
|
||||
v-tooltip="retryDisabled ? retryDisabledTooltip : undefined"
|
||||
class="!border"
|
||||
type="button"
|
||||
:disabled="retryDisabled"
|
||||
@click="emit('retry')"
|
||||
>
|
||||
<RotateCounterClockwiseIcon class="size-5" />
|
||||
{{ formatMessage(commonMessages.retryButton) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<Button
|
||||
v-tooltip="retryDisabled ? retryDisabledTooltip : undefined"
|
||||
type="outlined"
|
||||
class="!border !text-red [&>svg]:!text-red !shadow-[inset_0_0_0_1px_var(--color-red)]"
|
||||
native-type="button"
|
||||
:disabled="retryDisabled"
|
||||
@click="emit('retry')"
|
||||
>
|
||||
<RotateCounterClockwiseIcon class="size-5" />
|
||||
{{ formatMessage(commonMessages.retryButton) }}
|
||||
</Button>
|
||||
</template>
|
||||
</Admonition>
|
||||
</template>
|
||||
@@ -47,11 +46,11 @@
|
||||
import { RotateCounterClockwiseIcon } from '@modrinth/assets'
|
||||
import { computed, onMounted, onUnmounted, ref } from 'vue'
|
||||
|
||||
import { Button } from '#ui/components/base/buttons'
|
||||
import { defineMessages, useVIntl } from '#ui/composables/i18n'
|
||||
import { commonMessages } from '#ui/utils/common-messages'
|
||||
|
||||
import Admonition from '../base/Admonition.vue'
|
||||
import ButtonStyled from '../base/ButtonStyled.vue'
|
||||
|
||||
export interface SyncProgress {
|
||||
phase: 'Analyzing' | 'InstallingPack' | 'InstallingLoader' | 'Addons'
|
||||
|
||||
@@ -3,22 +3,29 @@
|
||||
<FloatingActionBar :shown="props.isVisible">
|
||||
<p class="m-0 font-semibold text-sm md:text-base">You have unsaved changes.</p>
|
||||
<div class="ml-auto flex gap-2">
|
||||
<ButtonStyled type="transparent">
|
||||
<button :disabled="props.isUpdating" @click="props.reset"><HistoryIcon /> Reset</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled :color="props.restart ? 'standard' : 'brand'">
|
||||
<button :disabled="props.isUpdating" @click="props.save">
|
||||
<SpinnerIcon v-if="props.isUpdating" class="animate-spin" />
|
||||
<SaveIcon v-else />
|
||||
{{ props.isUpdating ? 'Saving...' : 'Save' }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled v-if="props.restart" color="brand">
|
||||
<button :disabled="props.isUpdating || isTransitioning" @click="saveAndPower">
|
||||
<SpinnerIcon v-if="props.isUpdating || isTransitioning" class="animate-spin" />
|
||||
{{ powerButtonLabel }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<Button type="quiet" :disabled="props.isUpdating" @click="props.reset"
|
||||
><HistoryIcon /> Reset</Button
|
||||
>
|
||||
<Button
|
||||
:type="props.restart ? 'base' : 'colored'"
|
||||
:color="props.restart ? undefined : 'brand'"
|
||||
:disabled="props.isUpdating"
|
||||
@click="props.save"
|
||||
>
|
||||
<SpinnerIcon v-if="props.isUpdating" class="animate-spin" />
|
||||
<SaveIcon v-else />
|
||||
{{ props.isUpdating ? 'Saving...' : 'Save' }}
|
||||
</Button>
|
||||
<Button
|
||||
v-if="props.restart"
|
||||
type="colored"
|
||||
color="brand"
|
||||
:disabled="props.isUpdating || isTransitioning"
|
||||
@click="saveAndPower"
|
||||
>
|
||||
<SpinnerIcon v-if="props.isUpdating || isTransitioning" class="animate-spin" />
|
||||
{{ powerButtonLabel }}
|
||||
</Button>
|
||||
</div>
|
||||
</FloatingActionBar>
|
||||
</Teleport>
|
||||
@@ -28,7 +35,7 @@
|
||||
import { HistoryIcon, SaveIcon, SpinnerIcon } from '@modrinth/assets'
|
||||
import { computed } from 'vue'
|
||||
|
||||
import ButtonStyled from '#ui/components/base/ButtonStyled.vue'
|
||||
import { Button } from '#ui/components/base/buttons'
|
||||
import FloatingActionBar from '#ui/components/base/FloatingActionBar.vue'
|
||||
import { injectModrinthClient, injectModrinthServerContext } from '#ui/providers'
|
||||
|
||||
|
||||
@@ -183,46 +183,53 @@
|
||||
</div>
|
||||
|
||||
<div v-if="noticeButtons" class="flex gap-2">
|
||||
<ButtonStyled
|
||||
<IconButton
|
||||
v-if="noticeButtons.downloadBackup && onDownloadBackup && isBackupDownloadEnabled"
|
||||
v-tooltip="formatMessage(messages.downloadLatestBackupTooltip)"
|
||||
type="outlined"
|
||||
circular
|
||||
:label="formatMessage(messages.downloadLatestBackupTooltip)"
|
||||
data-server-listing-button
|
||||
@click="onDownloadBackup"
|
||||
>
|
||||
<button
|
||||
v-tooltip="formatMessage(messages.downloadLatestBackupTooltip)"
|
||||
data-server-listing-button
|
||||
@click="onDownloadBackup"
|
||||
>
|
||||
<DownloadIcon />
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled v-if="noticeButtons.copyId" type="outlined">
|
||||
<button
|
||||
v-tooltip="formatMessage(messages.copyCodeToClipboardTooltip)"
|
||||
data-server-listing-button
|
||||
@click="copyToClipboard(server_id)"
|
||||
>
|
||||
<template v-if="copied">
|
||||
{{ formatMessage(messages.copiedLabel) }} <CheckIcon class="text-green" />
|
||||
</template>
|
||||
<template v-else> {{ formatMessage(messages.copyIdLabel) }} <CopyIcon /> </template>
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled v-if="noticeButtons.support">
|
||||
<a href="https://support.modrinth.com/en/" target="_blank" data-server-listing-button
|
||||
><MessagesSquareIcon /> {{ formatMessage(messages.supportLabel) }}
|
||||
</a>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled v-if="noticeButtons.manageBilling" color="brand">
|
||||
<AutoLink :to="`/settings/billing#server-${server_id}`" data-server-listing-button>
|
||||
<CardIcon /> {{ formatMessage(messages.manageBillingLabel) }}
|
||||
</AutoLink>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled v-if="noticeButtons.resubscribe && onResubscribe" color="brand">
|
||||
<button data-server-listing-button @click="onResubscribe">
|
||||
<RotateCounterClockwiseIcon /> {{ formatMessage(messages.resubscribeLabel) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<DownloadIcon />
|
||||
</IconButton>
|
||||
<Button
|
||||
v-if="noticeButtons.copyId"
|
||||
v-tooltip="formatMessage(messages.copyCodeToClipboardTooltip)"
|
||||
type="outlined"
|
||||
data-server-listing-button
|
||||
@click="copyToClipboard(server_id)"
|
||||
>
|
||||
<template v-if="copied">
|
||||
{{ formatMessage(messages.copiedLabel) }} <CheckIcon class="text-green" />
|
||||
</template>
|
||||
<template v-else> {{ formatMessage(messages.copyIdLabel) }} <CopyIcon /> </template>
|
||||
</Button>
|
||||
<ButtonLink
|
||||
v-if="noticeButtons.support"
|
||||
href="https://support.modrinth.com/en/"
|
||||
target="_blank"
|
||||
data-server-listing-button
|
||||
><MessagesSquareIcon /> {{ formatMessage(messages.supportLabel) }}
|
||||
</ButtonLink>
|
||||
<ButtonLink
|
||||
v-if="noticeButtons.manageBilling"
|
||||
type="colored"
|
||||
color="brand"
|
||||
:to="`/settings/billing#server-${server_id}`"
|
||||
data-server-listing-button
|
||||
>
|
||||
<CardIcon /> {{ formatMessage(messages.manageBillingLabel) }}
|
||||
</ButtonLink>
|
||||
<Button
|
||||
v-if="noticeButtons.resubscribe && onResubscribe"
|
||||
type="colored"
|
||||
color="brand"
|
||||
data-server-listing-button
|
||||
@click="onResubscribe"
|
||||
>
|
||||
<RotateCounterClockwiseIcon /> {{ formatMessage(messages.resubscribeLabel) }}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -261,11 +268,12 @@ import {
|
||||
SparklesIcon,
|
||||
SpinnerIcon,
|
||||
} from '@modrinth/assets'
|
||||
import { AutoLink, ButtonStyled } from '@modrinth/ui'
|
||||
import { useQuery } from '@tanstack/vue-query'
|
||||
import { computed, ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
import { Button, ButtonLink, IconButton } from '#ui/components/base/buttons'
|
||||
|
||||
import {
|
||||
CardIcon,
|
||||
CheckIcon,
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { ModrinthIcon, RightArrowIcon, XIcon } from '@modrinth/assets'
|
||||
|
||||
import AutoLink from '../base/AutoLink.vue'
|
||||
import ButtonStyled from '../base/ButtonStyled.vue'
|
||||
import { ButtonLink, IconButton } from '#ui/components/base/buttons'
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'close'): void
|
||||
@@ -36,16 +35,21 @@ withDefaults(
|
||||
<span class="text-sm font-medium">Create a server with Modrinth in just a few clicks.</span>
|
||||
</div>
|
||||
<div class="flex flex-col items-end justify-end z-10">
|
||||
<ButtonStyled color="brand">
|
||||
<AutoLink :to="link"> View plans <RightArrowIcon /> </AutoLink>
|
||||
</ButtonStyled>
|
||||
<ButtonLink type="colored" color="brand" :to="link">
|
||||
View plans <RightArrowIcon />
|
||||
</ButtonLink>
|
||||
</div>
|
||||
<div class="absolute top-2 right-2 z-10">
|
||||
<ButtonStyled v-if="closable" size="small" circular>
|
||||
<button v-tooltip="`Don't show again`" @click="emit('close')">
|
||||
<XIcon aria-hidden="true" />
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<IconButton
|
||||
v-if="closable"
|
||||
v-tooltip="`Don't show again`"
|
||||
class="!size-6"
|
||||
size="xs"
|
||||
:label="`Don't show again`"
|
||||
@click="emit('close')"
|
||||
>
|
||||
<XIcon aria-hidden="true" />
|
||||
</IconButton>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -74,29 +74,28 @@
|
||||
|
||||
<template #cell-actions="{ row: member }">
|
||||
<div v-if="!member.isOwner" class="flex items-center justify-end gap-1">
|
||||
<ButtonStyled v-if="member.pending" circular type="transparent">
|
||||
<button
|
||||
v-tooltip="resendInviteTooltip(member)"
|
||||
:aria-label="resendInviteLabel(member)"
|
||||
:disabled="resendInviteDisabled(member)"
|
||||
class="text-secondary hover:!filter-none hover:text-contrast focus-visible:!filter-none active:!scale-100 active:!filter-none disabled:cursor-not-allowed disabled:opacity-50 disabled:hover:text-secondary"
|
||||
@click="handleResendInvite(member)"
|
||||
>
|
||||
<SendIcon aria-hidden="true" />
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled circular type="transparent">
|
||||
<button
|
||||
v-tooltip="memberAccessActionTooltip(member)"
|
||||
:aria-label="memberAccessActionLabel(member)"
|
||||
:disabled="!canManageUsers"
|
||||
class="text-secondary hover:!filter-none hover:text-red focus-visible:!filter-none active:!scale-100 active:!filter-none disabled:cursor-not-allowed disabled:opacity-50 disabled:hover:text-secondary"
|
||||
@click="member.pending ? handleCancelInvite(member) : handleRemoveMember(member)"
|
||||
>
|
||||
<XIcon v-if="member.pending" aria-hidden="true" />
|
||||
<UserXIcon v-else aria-hidden="true" />
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<IconButton
|
||||
v-if="member.pending"
|
||||
v-tooltip="resendInviteTooltip(member)"
|
||||
type="quiet"
|
||||
:label="resendInviteLabel(member)"
|
||||
:disabled="resendInviteDisabled(member)"
|
||||
class="text-secondary hover:!filter-none hover:text-contrast focus-visible:!filter-none active:!scale-100 active:!filter-none disabled:cursor-not-allowed disabled:opacity-50 disabled:hover:text-secondary"
|
||||
@click="handleResendInvite(member)"
|
||||
>
|
||||
<SendIcon aria-hidden="true" />
|
||||
</IconButton>
|
||||
<IconButton
|
||||
v-tooltip="memberAccessActionTooltip(member)"
|
||||
type="quiet"
|
||||
:label="memberAccessActionLabel(member)"
|
||||
:disabled="!canManageUsers"
|
||||
class="text-secondary hover:!filter-none hover:text-red focus-visible:!filter-none active:!scale-100 active:!filter-none disabled:cursor-not-allowed disabled:opacity-50 disabled:hover:text-secondary"
|
||||
@click="member.pending ? handleCancelInvite(member) : handleRemoveMember(member)"
|
||||
>
|
||||
<XIcon v-if="member.pending" aria-hidden="true" />
|
||||
<UserXIcon v-else aria-hidden="true" />
|
||||
</IconButton>
|
||||
</div>
|
||||
</template>
|
||||
</Table>
|
||||
@@ -223,29 +222,30 @@
|
||||
<span v-else>{{ formatMessage(messages.unknownJoinedDate) }}</span>
|
||||
</div>
|
||||
<div class="flex min-w-0 items-center justify-end pr-4">
|
||||
<ButtonStyled v-if="!member.isOwner" circular type="transparent">
|
||||
<TeleportOverflowMenu
|
||||
:options="memberActionOptions(member)"
|
||||
btn-class="hover:!filter-none focus-visible:!filter-none active:!scale-100 active:!filter-none"
|
||||
>
|
||||
<MoreVerticalIcon aria-hidden="true" class="size-5" />
|
||||
<span class="sr-only">
|
||||
{{ formatMessage(messages.memberActionsLabel, { username: member.user.username }) }}
|
||||
</span>
|
||||
<template #resend-invite>
|
||||
<SendIcon aria-hidden="true" />
|
||||
{{ resendInviteLabel(member) }}
|
||||
</template>
|
||||
<template #cancel-invite>
|
||||
<XIcon aria-hidden="true" />
|
||||
{{ formatMessage(messages.cancelInvite) }}
|
||||
</template>
|
||||
<template #remove-user>
|
||||
<UserXIcon aria-hidden="true" />
|
||||
{{ formatMessage(messages.removeUser) }}
|
||||
</template>
|
||||
</TeleportOverflowMenu>
|
||||
</ButtonStyled>
|
||||
<TeleportOverflowMenu
|
||||
v-if="!member.isOwner"
|
||||
type="quiet"
|
||||
:label="formatMessage(messages.memberActionsLabel, { username: member.user.username })"
|
||||
:options="memberActionOptions(member)"
|
||||
class="hover:!filter-none focus-visible:!filter-none active:!scale-100 active:!filter-none"
|
||||
>
|
||||
<MoreVerticalIcon aria-hidden="true" class="size-5" />
|
||||
<span class="sr-only">
|
||||
{{ formatMessage(messages.memberActionsLabel, { username: member.user.username }) }}
|
||||
</span>
|
||||
<template #resend-invite>
|
||||
<SendIcon aria-hidden="true" />
|
||||
{{ resendInviteLabel(member) }}
|
||||
</template>
|
||||
<template #cancel-invite>
|
||||
<XIcon aria-hidden="true" />
|
||||
{{ formatMessage(messages.cancelInvite) }}
|
||||
</template>
|
||||
<template #remove-user>
|
||||
<UserXIcon aria-hidden="true" />
|
||||
{{ formatMessage(messages.removeUser) }}
|
||||
</template>
|
||||
</TeleportOverflowMenu>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -284,17 +284,21 @@ import {
|
||||
UserXIcon,
|
||||
XIcon,
|
||||
} from '@modrinth/assets'
|
||||
import { type Component, computed, onMounted, onUnmounted, ref } from 'vue'
|
||||
import { computed, onMounted, onUnmounted, ref } from 'vue'
|
||||
|
||||
import {
|
||||
IconButton,
|
||||
type OverflowMenuOption,
|
||||
TeleportOverflowMenu,
|
||||
} from '#ui/components/base/buttons'
|
||||
|
||||
import { useFormatDateTime, useRelativeTime } from '../../../composables'
|
||||
import { defineMessages, useVIntl } from '../../../composables/i18n'
|
||||
import { commonMessages } from '../../../utils/common-messages'
|
||||
import AutoLink from '../../base/AutoLink.vue'
|
||||
import Avatar from '../../base/Avatar.vue'
|
||||
import ButtonStyled from '../../base/ButtonStyled.vue'
|
||||
import Combobox, { type ComboboxOption } from '../../base/Combobox.vue'
|
||||
import Table, { type SortDirection, type TableColumn } from '../../base/Table.vue'
|
||||
import TeleportOverflowMenu from '../../base/TeleportOverflowMenu.vue'
|
||||
import type {
|
||||
ServerAccessMember,
|
||||
ServerAccessRole,
|
||||
@@ -396,16 +400,6 @@ const messages = defineMessages({
|
||||
type AccessTableColumn = 'user' | 'role' | 'joined' | 'actions'
|
||||
type AccessTableSortableColumn = Exclude<AccessTableColumn, 'actions'>
|
||||
type AccessTableRow = ServerAccessMember & Record<string, unknown>
|
||||
type OverflowMenuOption = {
|
||||
id: string
|
||||
icon?: Component
|
||||
action: () => void
|
||||
shown?: boolean
|
||||
color?: 'standard' | 'brand' | 'red' | 'orange' | 'green' | 'blue' | 'purple'
|
||||
disabled?: boolean
|
||||
tooltip?: string
|
||||
}
|
||||
|
||||
const columns = computed<TableColumn<AccessTableColumn>[]>(() => [
|
||||
{ key: 'user', label: formatMessage(messages.userColumn), width: '32%', enableSorting: true },
|
||||
{ key: 'role', label: formatMessage(messages.roleColumn), width: '28%', enableSorting: true },
|
||||
@@ -609,6 +603,7 @@ function memberActionOptions(member: ServerAccessMember): OverflowMenuOption[] {
|
||||
return [
|
||||
{
|
||||
id: 'resend-invite',
|
||||
label: resendInviteLabel(member),
|
||||
icon: SendIcon,
|
||||
action: () => handleResendInvite(member),
|
||||
shown: member.pending,
|
||||
@@ -617,18 +612,20 @@ function memberActionOptions(member: ServerAccessMember): OverflowMenuOption[] {
|
||||
},
|
||||
{
|
||||
id: 'cancel-invite',
|
||||
label: formatMessage(messages.cancelInvite),
|
||||
icon: XIcon,
|
||||
action: () => handleCancelInvite(member),
|
||||
color: 'red',
|
||||
tone: 'red',
|
||||
shown: member.pending,
|
||||
disabled: !canManageUsers.value,
|
||||
tooltip: memberAccessActionTooltip(member),
|
||||
},
|
||||
{
|
||||
id: 'remove-user',
|
||||
label: formatMessage(messages.removeUser),
|
||||
icon: UserXIcon,
|
||||
action: () => handleRemoveMember(member),
|
||||
color: 'red',
|
||||
tone: 'red',
|
||||
shown: !member.pending,
|
||||
disabled: !canManageUsers.value,
|
||||
tooltip: memberAccessActionTooltip(member),
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
v-model:custom-start-date="timeframeCustomStartDate"
|
||||
v-model:custom-end-date="timeframeCustomEndDate"
|
||||
:class="timeframePickerClass"
|
||||
trigger-size="lg"
|
||||
:trigger-class="timeframePickerTriggerClass"
|
||||
/>
|
||||
<template v-if="slots.filters">
|
||||
@@ -363,7 +364,7 @@ const timeframePickerClass = computed(() =>
|
||||
slots.filters ? '!w-full @[640px]:!w-[225px] shrink-0' : '!w-full @[640px]:!w-[225px]',
|
||||
)
|
||||
const timeframePickerTriggerClass =
|
||||
'!h-10 !min-h-10 !w-full !rounded-[14px] !bg-surface-4 !py-2.5 !pl-4 !pr-3 !text-base shadow-[0px_1px_1px_rgba(0,0,0,0.3),0px_1px_1.5px_rgba(0,0,0,0.15)]'
|
||||
'!w-full !rounded-[14px] !bg-surface-4 !py-2.5 !pl-4 !pr-3 !text-base shadow-[0px_1px_1px_rgba(0,0,0,0.3),0px_1px_1.5px_rgba(0,0,0,0.15)]'
|
||||
|
||||
onMounted(() => {
|
||||
updateLoadMoreObserver()
|
||||
|
||||
@@ -126,18 +126,20 @@
|
||||
|
||||
<template #actions>
|
||||
<div class="flex justify-end gap-2">
|
||||
<ButtonStyled type="outlined">
|
||||
<button @click="hide">
|
||||
<XIcon aria-hidden="true" />
|
||||
{{ formatMessage(messages.cancelButton) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled color="brand">
|
||||
<button v-tooltip="grantPermissionTooltip" :disabled="!canSubmit" @click="submit">
|
||||
<UserPlusIcon aria-hidden="true" />
|
||||
{{ formatMessage(messages.inviteButton) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<Button type="outlined" @click="hide">
|
||||
<XIcon aria-hidden="true" />
|
||||
{{ formatMessage(messages.cancelButton) }}
|
||||
</Button>
|
||||
<Button
|
||||
v-tooltip="grantPermissionTooltip"
|
||||
type="colored"
|
||||
color="brand"
|
||||
:disabled="!canSubmit"
|
||||
@click="submit"
|
||||
>
|
||||
<UserPlusIcon aria-hidden="true" />
|
||||
{{ formatMessage(messages.inviteButton) }}
|
||||
</Button>
|
||||
</div>
|
||||
</template>
|
||||
</NewModal>
|
||||
@@ -148,10 +150,11 @@ import { EyeIcon, PencilIcon, UserPlusIcon, XIcon } from '@modrinth/assets'
|
||||
import { useDebounceFn } from '@vueuse/core'
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
import { Button } from '#ui/components/base/buttons'
|
||||
|
||||
import { defineMessages, useVIntl } from '../../../composables/i18n'
|
||||
import { commonMessages } from '../../../utils/common-messages'
|
||||
import Avatar from '../../base/Avatar.vue'
|
||||
import ButtonStyled from '../../base/ButtonStyled.vue'
|
||||
import Checkbox from '../../base/Checkbox.vue'
|
||||
import Combobox, { type ComboboxOption } from '../../base/Combobox.vue'
|
||||
import IntlFormatted from '../../base/IntlFormatted.vue'
|
||||
|
||||
@@ -62,21 +62,23 @@
|
||||
</div>
|
||||
|
||||
<div class="flex justify-end gap-2 pt-1">
|
||||
<ButtonStyled type="outlined">
|
||||
<button class="!border !border-surface-5" @click="hide">
|
||||
<XIcon aria-hidden="true" />
|
||||
{{ formatMessage(commonMessages.cancelButton) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled color="orange">
|
||||
<button v-tooltip="removePermissionTooltip" :disabled="!canRemove" @click="confirm">
|
||||
<TrashIcon v-if="modalState.shouldCancel" aria-hidden="true" />
|
||||
<UserXIcon v-else aria-hidden="true" />
|
||||
{{
|
||||
formatMessage(modalState.shouldCancel ? messages.cancelButton : messages.removeButton)
|
||||
}}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<Button type="outlined" class="!border !border-surface-5" @click="hide">
|
||||
<XIcon aria-hidden="true" />
|
||||
{{ formatMessage(commonMessages.cancelButton) }}
|
||||
</Button>
|
||||
<Button
|
||||
v-tooltip="removePermissionTooltip"
|
||||
type="colored"
|
||||
color="orange"
|
||||
:disabled="!canRemove"
|
||||
@click="confirm"
|
||||
>
|
||||
<TrashIcon v-if="modalState.shouldCancel" aria-hidden="true" />
|
||||
<UserXIcon v-else aria-hidden="true" />
|
||||
{{
|
||||
formatMessage(modalState.shouldCancel ? messages.cancelButton : messages.removeButton)
|
||||
}}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</NewModal>
|
||||
@@ -86,12 +88,13 @@
|
||||
import { TrashIcon, UserXIcon, XIcon } from '@modrinth/assets'
|
||||
import { computed, ref, watch } from 'vue'
|
||||
|
||||
import { Button } from '#ui/components/base/buttons'
|
||||
|
||||
import { useRelativeTime } from '../../../composables'
|
||||
import { defineMessages, useVIntl } from '../../../composables/i18n'
|
||||
import { commonMessages } from '../../../utils/common-messages'
|
||||
import Admonition from '../../base/Admonition.vue'
|
||||
import Avatar from '../../base/Avatar.vue'
|
||||
import ButtonStyled from '../../base/ButtonStyled.vue'
|
||||
import NewModal from '../../modal/NewModal.vue'
|
||||
import type { ServerAccessRole } from './types'
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
} from '@modrinth/assets'
|
||||
|
||||
import Admonition from '#ui/components/base/Admonition.vue'
|
||||
import ButtonStyled from '#ui/components/base/ButtonStyled.vue'
|
||||
import { Button } from '#ui/components/base/buttons'
|
||||
import type { MessageDescriptor } from '#ui/composables/i18n'
|
||||
import { defineMessages, useVIntl } from '#ui/composables/i18n'
|
||||
import { commonMessages } from '#ui/utils/common-messages'
|
||||
@@ -279,29 +279,29 @@ function getDescription(item: BackupAdmonitionEntry): string {
|
||||
</span>
|
||||
</div>
|
||||
<template #top-right-actions>
|
||||
<ButtonStyled v-if="canCancel(item)" type="outlined" color="blue">
|
||||
<button
|
||||
v-tooltip="canManageBackups === false ? permissionDeniedMessage : undefined"
|
||||
class="!border"
|
||||
type="button"
|
||||
:disabled="cancelling || canManageBackups === false"
|
||||
@click="$emit('cancel')"
|
||||
>
|
||||
{{ formatMessage(commonMessages.cancelButton) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled v-if="canRetry(item)" color="red" type="outlined">
|
||||
<button
|
||||
v-tooltip="canManageBackups === false ? permissionDeniedMessage : undefined"
|
||||
class="!border"
|
||||
type="button"
|
||||
:disabled="canManageBackups === false"
|
||||
@click="$emit('retry')"
|
||||
>
|
||||
<RotateCounterClockwiseIcon class="size-5" />
|
||||
{{ formatMessage(commonMessages.retryButton) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<Button
|
||||
v-if="canCancel(item)"
|
||||
v-tooltip="canManageBackups === false ? permissionDeniedMessage : undefined"
|
||||
type="outlined"
|
||||
class="!border !text-blue [&>svg]:!text-blue !shadow-[inset_0_0_0_1px_var(--color-blue)]"
|
||||
native-type="button"
|
||||
:disabled="cancelling || canManageBackups === false"
|
||||
@click="$emit('cancel')"
|
||||
>
|
||||
{{ formatMessage(commonMessages.cancelButton) }}
|
||||
</Button>
|
||||
<Button
|
||||
v-if="canRetry(item)"
|
||||
v-tooltip="canManageBackups === false ? permissionDeniedMessage : undefined"
|
||||
type="outlined"
|
||||
class="!border !text-red [&>svg]:!text-red !shadow-[inset_0_0_0_1px_var(--color-red)]"
|
||||
native-type="button"
|
||||
:disabled="canManageBackups === false"
|
||||
@click="$emit('retry')"
|
||||
>
|
||||
<RotateCounterClockwiseIcon class="size-5" />
|
||||
{{ formatMessage(commonMessages.retryButton) }}
|
||||
</Button>
|
||||
</template>
|
||||
</Admonition>
|
||||
</template>
|
||||
|
||||
@@ -24,17 +24,17 @@
|
||||
</span>
|
||||
</span>
|
||||
<template v-if="op.id" #top-right-actions>
|
||||
<ButtonStyled v-if="!isTerminal" type="outlined" color="blue">
|
||||
<button
|
||||
v-tooltip="!canWriteFiles ? permissionDeniedMessage : undefined"
|
||||
class="!border"
|
||||
type="button"
|
||||
:disabled="!canWriteFiles"
|
||||
@click="cancelOperation"
|
||||
>
|
||||
{{ formatMessage(commonMessages.cancelButton) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<Button
|
||||
v-if="!isTerminal"
|
||||
v-tooltip="!canWriteFiles ? permissionDeniedMessage : undefined"
|
||||
type="outlined"
|
||||
class="!border !text-blue [&>svg]:!text-blue !shadow-[inset_0_0_0_1px_var(--color-blue)]"
|
||||
native-type="button"
|
||||
:disabled="!canWriteFiles"
|
||||
@click="cancelOperation"
|
||||
>
|
||||
{{ formatMessage(commonMessages.cancelButton) }}
|
||||
</Button>
|
||||
</template>
|
||||
</Admonition>
|
||||
</template>
|
||||
@@ -44,7 +44,7 @@ import { PackageOpenIcon } from '@modrinth/assets'
|
||||
import { computed } from 'vue'
|
||||
|
||||
import Admonition from '#ui/components/base/Admonition.vue'
|
||||
import ButtonStyled from '#ui/components/base/ButtonStyled.vue'
|
||||
import { Button } from '#ui/components/base/buttons'
|
||||
import { useFormatBytes } from '#ui/composables'
|
||||
import { defineMessages, useVIntl } from '#ui/composables/i18n'
|
||||
import { useServerPermissions } from '#ui/composables/server-permissions'
|
||||
|
||||
@@ -16,11 +16,15 @@
|
||||
}}%)
|
||||
</span>
|
||||
<template v-if="cancelable" #top-right-actions>
|
||||
<ButtonStyled type="outlined" color="blue">
|
||||
<button class="!border" type="button" :disabled="cancelling" @click="$emit('cancel')">
|
||||
Cancel
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<Button
|
||||
type="outlined"
|
||||
class="!border !text-blue [&>svg]:!text-blue !shadow-[inset_0_0_0_1px_var(--color-blue)]"
|
||||
native-type="button"
|
||||
:disabled="cancelling"
|
||||
@click="$emit('cancel')"
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
</template>
|
||||
</Admonition>
|
||||
</template>
|
||||
@@ -30,7 +34,7 @@ import { UploadIcon } from '@modrinth/assets'
|
||||
import { computed } from 'vue'
|
||||
|
||||
import Admonition from '#ui/components/base/Admonition.vue'
|
||||
import ButtonStyled from '#ui/components/base/ButtonStyled.vue'
|
||||
import { Button } from '#ui/components/base/buttons'
|
||||
import { useFormatBytes } from '#ui/composables'
|
||||
import { injectModrinthServerContext } from '#ui/providers'
|
||||
|
||||
|
||||
@@ -46,22 +46,20 @@
|
||||
</div>
|
||||
<template #actions>
|
||||
<div class="flex gap-2 justify-end">
|
||||
<ButtonStyled type="outlined">
|
||||
<button @click="hideModal">
|
||||
<XIcon />
|
||||
Cancel
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled color="brand">
|
||||
<button
|
||||
v-tooltip="createDisabledTooltip"
|
||||
:disabled="createDisabled"
|
||||
@click="createBackup"
|
||||
>
|
||||
<PlusIcon />
|
||||
Create backup
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<Button type="outlined" @click="hideModal">
|
||||
<XIcon />
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
v-tooltip="createDisabledTooltip"
|
||||
type="colored"
|
||||
color="brand"
|
||||
:disabled="createDisabled"
|
||||
@click="createBackup"
|
||||
>
|
||||
<PlusIcon />
|
||||
Create backup
|
||||
</Button>
|
||||
</div>
|
||||
</template>
|
||||
</NewModal>
|
||||
@@ -73,6 +71,8 @@ import { IssuesIcon, PlusIcon, XIcon } from '@modrinth/assets'
|
||||
import { useMutation, useQueryClient } from '@tanstack/vue-query'
|
||||
import { computed, nextTick, ref } from 'vue'
|
||||
|
||||
import { Button } from '#ui/components/base/buttons'
|
||||
|
||||
import { useVIntl } from '../../../composables/i18n'
|
||||
import {
|
||||
injectModrinthClient,
|
||||
@@ -80,7 +80,6 @@ import {
|
||||
injectNotificationManager,
|
||||
} from '../../../providers'
|
||||
import { commonMessages } from '../../../utils'
|
||||
import ButtonStyled from '../../base/ButtonStyled.vue'
|
||||
import StyledInput from '../../base/StyledInput.vue'
|
||||
import NewModal from '../../modal/NewModal.vue'
|
||||
|
||||
|
||||
@@ -60,22 +60,20 @@
|
||||
|
||||
<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
|
||||
v-tooltip="deleteDisabledTooltip"
|
||||
:disabled="!props.canDelete"
|
||||
@click="confirmDelete"
|
||||
>
|
||||
<TrashIcon />
|
||||
{{ formatMessage(messages.confirm, { count }) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<Button type="outlined" @click="modal?.hide()">
|
||||
<XIcon />
|
||||
{{ formatMessage(commonMessages.cancelButton) }}
|
||||
</Button>
|
||||
<Button
|
||||
v-tooltip="deleteDisabledTooltip"
|
||||
type="colored"
|
||||
color="red"
|
||||
:disabled="!props.canDelete"
|
||||
@click="confirmDelete"
|
||||
>
|
||||
<TrashIcon />
|
||||
{{ formatMessage(messages.confirm, { count }) }}
|
||||
</Button>
|
||||
</div>
|
||||
</template>
|
||||
</NewModal>
|
||||
@@ -86,11 +84,12 @@ import type { Archon } from '@modrinth/api-client'
|
||||
import { TrashIcon, XIcon } from '@modrinth/assets'
|
||||
import { computed, nextTick, ref } from 'vue'
|
||||
|
||||
import { Button } from '#ui/components/base/buttons'
|
||||
|
||||
import { defineMessages, useVIntl } from '../../../composables/i18n'
|
||||
import { useScrollIndicator } from '../../../composables/scroll-indicator'
|
||||
import { commonMessages } from '../../../utils'
|
||||
import Admonition from '../../base/Admonition.vue'
|
||||
import ButtonStyled from '../../base/ButtonStyled.vue'
|
||||
import NewModal from '../../modal/NewModal.vue'
|
||||
import BackupItem from './BackupItem.vue'
|
||||
|
||||
|
||||
@@ -13,13 +13,14 @@ import {
|
||||
} from '@modrinth/assets'
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
import type { OverflowMenuOption } from '#ui/components/base/buttons'
|
||||
import { Button, TeleportOverflowMenu } from '#ui/components/base/buttons'
|
||||
|
||||
import { useFormatDateTime } from '../../../composables'
|
||||
import { defineMessages, useVIntl } from '../../../composables/i18n'
|
||||
import { commonMessages, truncatedTooltip } from '../../../utils'
|
||||
import AutoLink from '../../base/AutoLink.vue'
|
||||
import Avatar from '../../base/Avatar.vue'
|
||||
import ButtonStyled from '../../base/ButtonStyled.vue'
|
||||
import OverflowMenu, { type Option as OverflowOption } from '../../base/OverflowMenu.vue'
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
const formatDateTime = useFormatDateTime({
|
||||
@@ -93,38 +94,41 @@ const itemBorderClass = computed(() => {
|
||||
return 'border-transparent'
|
||||
})
|
||||
|
||||
const overflowMenuOptions = computed<OverflowOption[]>(() => {
|
||||
const options: OverflowOption[] = []
|
||||
const overflowMenuOptions = computed<OverflowMenuOption[]>(() => {
|
||||
const options: OverflowMenuOption[] = []
|
||||
|
||||
if (props.showCopyIdAction) {
|
||||
options.push({
|
||||
id: 'copy-id',
|
||||
label: formatMessage(commonMessages.copyIdButton),
|
||||
action: () => copyId(),
|
||||
})
|
||||
}
|
||||
|
||||
if (options.length > 0) {
|
||||
options.push({ divider: true })
|
||||
options.push({ type: 'divider' })
|
||||
}
|
||||
|
||||
options.push({
|
||||
id: 'download',
|
||||
label: formatMessage(commonMessages.downloadButton),
|
||||
action: () => emit('download'),
|
||||
link: `https://${props.kyrosUrl}/modrinth/v0/backups/${props.backup.id}/download?auth=${props.jwt}`,
|
||||
disabled: !props.kyrosUrl || !props.jwt,
|
||||
})
|
||||
|
||||
options.push({
|
||||
id: 'rename',
|
||||
label: formatMessage(messages.rename),
|
||||
action: () => emit('rename'),
|
||||
disabled: props.writeDisabled,
|
||||
tooltip: props.writeDisabled ? props.writeDisabledTooltip : undefined,
|
||||
})
|
||||
|
||||
options.push({ divider: true })
|
||||
options.push({ type: 'divider' })
|
||||
options.push({
|
||||
id: 'delete',
|
||||
color: 'red',
|
||||
label: formatMessage(commonMessages.deleteLabel),
|
||||
tone: 'red',
|
||||
action: () => emit('delete'),
|
||||
disabled: props.writeDisabled,
|
||||
tooltip: props.writeDisabled ? props.writeDisabledTooltip : undefined,
|
||||
@@ -265,35 +269,32 @@ const creatorAvatarSrc = computed(() =>
|
||||
|
||||
<!-- Right side actions -->
|
||||
<div v-if="!preview" class="flex min-w-0 flex-1 items-center justify-end gap-2">
|
||||
<ButtonStyled color="brand" type="outlined">
|
||||
<button
|
||||
v-tooltip="props.restoreDisabled"
|
||||
class="!border"
|
||||
:disabled="!!props.restoreDisabled"
|
||||
@click="() => emit('restore')"
|
||||
>
|
||||
<RotateCounterClockwiseIcon class="size-5" />
|
||||
{{ formatMessage(messages.restore) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled circular type="transparent">
|
||||
<OverflowMenu :options="overflowMenuOptions">
|
||||
<MoreVerticalIcon class="size-5" />
|
||||
<template #copy-id>
|
||||
<ClipboardCopyIcon class="size-5" />
|
||||
{{ formatMessage(commonMessages.copyIdButton) }}
|
||||
</template>
|
||||
<template #download>
|
||||
<DownloadIcon class="size-5" /> {{ formatMessage(commonMessages.downloadButton) }}
|
||||
</template>
|
||||
<template #rename>
|
||||
<EditIcon class="size-5" /> {{ formatMessage(messages.rename) }}
|
||||
</template>
|
||||
<template #delete>
|
||||
<TrashIcon class="size-5" /> {{ formatMessage(commonMessages.deleteLabel) }}
|
||||
</template>
|
||||
</OverflowMenu>
|
||||
</ButtonStyled>
|
||||
<Button
|
||||
v-tooltip="props.restoreDisabled"
|
||||
type="outlined"
|
||||
class="!border !text-brand [&>svg]:!text-brand !shadow-[inset_0_0_0_1px_var(--color-brand)]"
|
||||
:disabled="!!props.restoreDisabled"
|
||||
@click="() => emit('restore')"
|
||||
>
|
||||
<RotateCounterClockwiseIcon class="size-5" />
|
||||
{{ formatMessage(messages.restore) }}
|
||||
</Button>
|
||||
<TeleportOverflowMenu type="quiet" label="More options" :options="overflowMenuOptions">
|
||||
<MoreVerticalIcon class="size-5" />
|
||||
<template #copy-id>
|
||||
<ClipboardCopyIcon class="size-5" />
|
||||
{{ formatMessage(commonMessages.copyIdButton) }}
|
||||
</template>
|
||||
<template #download>
|
||||
<DownloadIcon class="size-5" /> {{ formatMessage(commonMessages.downloadButton) }}
|
||||
</template>
|
||||
<template #rename>
|
||||
<EditIcon class="size-5" /> {{ formatMessage(messages.rename) }}
|
||||
</template>
|
||||
<template #delete>
|
||||
<TrashIcon class="size-5" /> {{ formatMessage(commonMessages.deleteLabel) }}
|
||||
</template>
|
||||
</TeleportOverflowMenu>
|
||||
</div>
|
||||
|
||||
<pre v-if="!preview && showDebugInfo" class="w-full rounded-xl bg-surface-4 p-2 text-xs">{{
|
||||
|
||||
@@ -22,28 +22,26 @@
|
||||
</div>
|
||||
<template #actions>
|
||||
<div class="flex gap-2 justify-end">
|
||||
<ButtonStyled type="outlined">
|
||||
<button @click="hide">
|
||||
<XIcon />
|
||||
Cancel
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled color="brand">
|
||||
<button
|
||||
v-tooltip="renameDisabledTooltip"
|
||||
:disabled="renameDisabled"
|
||||
@click="renameBackup"
|
||||
>
|
||||
<template v-if="renameMutation.isPending.value">
|
||||
<SpinnerIcon class="animate-spin" />
|
||||
Renaming...
|
||||
</template>
|
||||
<template v-else>
|
||||
<SaveIcon />
|
||||
Save changes
|
||||
</template>
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<Button type="outlined" @click="hide">
|
||||
<XIcon />
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
v-tooltip="renameDisabledTooltip"
|
||||
type="colored"
|
||||
color="brand"
|
||||
:disabled="renameDisabled"
|
||||
@click="renameBackup"
|
||||
>
|
||||
<template v-if="renameMutation.isPending.value">
|
||||
<SpinnerIcon class="animate-spin" />
|
||||
Renaming...
|
||||
</template>
|
||||
<template v-else>
|
||||
<SaveIcon />
|
||||
Save changes
|
||||
</template>
|
||||
</Button>
|
||||
</div>
|
||||
</template>
|
||||
</NewModal>
|
||||
@@ -55,6 +53,8 @@ import { IssuesIcon, SaveIcon, SpinnerIcon, XIcon } from '@modrinth/assets'
|
||||
import { useMutation, useQueryClient } from '@tanstack/vue-query'
|
||||
import { computed, nextTick, ref } from 'vue'
|
||||
|
||||
import { Button } from '#ui/components/base/buttons'
|
||||
|
||||
import { useVIntl } from '../../../composables/i18n'
|
||||
import {
|
||||
injectModrinthClient,
|
||||
@@ -62,7 +62,6 @@ import {
|
||||
injectNotificationManager,
|
||||
} from '../../../providers'
|
||||
import { commonMessages } from '../../../utils'
|
||||
import ButtonStyled from '../../base/ButtonStyled.vue'
|
||||
import StyledInput from '../../base/StyledInput.vue'
|
||||
import NewModal from '../../modal/NewModal.vue'
|
||||
|
||||
|
||||
@@ -17,23 +17,21 @@
|
||||
|
||||
<template #actions>
|
||||
<div class="flex gap-2 justify-end">
|
||||
<ButtonStyled type="outlined">
|
||||
<button @click="modal?.hide()">
|
||||
<XIcon />
|
||||
Cancel
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled color="red">
|
||||
<button
|
||||
v-tooltip="restoreDisabledTooltip"
|
||||
:disabled="restoreDisabled"
|
||||
@click="restoreBackup"
|
||||
>
|
||||
<SpinnerIcon v-if="isRestoring" class="animate-spin" />
|
||||
<RotateCounterClockwiseIcon v-else />
|
||||
{{ isRestoring ? 'Restoring...' : 'Restore backup' }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<Button type="outlined" @click="modal?.hide()">
|
||||
<XIcon />
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
v-tooltip="restoreDisabledTooltip"
|
||||
type="colored"
|
||||
color="red"
|
||||
:disabled="restoreDisabled"
|
||||
@click="restoreBackup"
|
||||
>
|
||||
<SpinnerIcon v-if="isRestoring" class="animate-spin" />
|
||||
<RotateCounterClockwiseIcon v-else />
|
||||
{{ isRestoring ? 'Restoring...' : 'Restore backup' }}
|
||||
</Button>
|
||||
</div>
|
||||
</template>
|
||||
</NewModal>
|
||||
@@ -45,6 +43,8 @@ import { RotateCounterClockwiseIcon, SpinnerIcon, XIcon } from '@modrinth/assets
|
||||
import { useMutation, useQueryClient } from '@tanstack/vue-query'
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
import { Button } from '#ui/components/base/buttons'
|
||||
|
||||
import { useVIntl } from '../../../composables/i18n'
|
||||
import {
|
||||
injectModrinthClient,
|
||||
@@ -53,7 +53,6 @@ import {
|
||||
} from '../../../providers'
|
||||
import { commonMessages } from '../../../utils'
|
||||
import Admonition from '../../base/Admonition.vue'
|
||||
import ButtonStyled from '../../base/ButtonStyled.vue'
|
||||
import NewModal from '../../modal/NewModal.vue'
|
||||
import BackupItem from './BackupItem.vue'
|
||||
|
||||
|
||||
@@ -2,19 +2,25 @@
|
||||
<div class="flex flex-col gap-2.5">
|
||||
<span class="text-lg font-semibold text-contrast">Icon</span>
|
||||
<div class="group relative w-fit">
|
||||
<OverflowMenu
|
||||
v-tooltip="editIconTooltip"
|
||||
class="m-0 cursor-pointer appearance-none border-none bg-transparent p-0 transition-transform group-active:scale-95"
|
||||
<TeleportOverflowMenu
|
||||
:label="editIconTooltip"
|
||||
:tooltip="editIconTooltip"
|
||||
: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"
|
||||
:disabled="isIconActionDisabled"
|
||||
:options="[
|
||||
{
|
||||
id: 'upload',
|
||||
label: 'Upload icon',
|
||||
action: () => triggerFileInput(),
|
||||
disabled: !props.canEdit,
|
||||
tooltip: !props.canEdit ? editIconTooltip : undefined,
|
||||
},
|
||||
{
|
||||
id: 'sync',
|
||||
label: 'Sync icon',
|
||||
action: () => resetIcon(),
|
||||
disabled: !props.canEdit,
|
||||
tooltip: !props.canEdit ? editIconTooltip : undefined,
|
||||
@@ -39,7 +45,7 @@
|
||||
</div>
|
||||
<template #upload> <UploadIcon /> Upload icon </template>
|
||||
<template #sync> <TransferIcon /> Sync icon </template>
|
||||
</OverflowMenu>
|
||||
</TeleportOverflowMenu>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -49,7 +55,7 @@ import { EditIcon, SpinnerIcon, TransferIcon, UploadIcon } from '@modrinth/asset
|
||||
import { useQueryClient } from '@tanstack/vue-query'
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
import { OverflowMenu, ServerIcon } from '#ui/components'
|
||||
import { ServerIcon, TeleportOverflowMenu } from '#ui/components'
|
||||
import { useServerImage } from '#ui/composables'
|
||||
import { useVIntl } from '#ui/composables/i18n'
|
||||
import {
|
||||
|
||||
@@ -30,9 +30,10 @@
|
||||
</Transition>
|
||||
</div>
|
||||
|
||||
<ButtonStyled color="medal-promo" type="outlined" size="large">
|
||||
<button class="z-10 my-auto" @click="openUpgradeModal"><RocketIcon /> Upgrade</button>
|
||||
</ButtonStyled>
|
||||
<Button type="outlined" size="xl" class="z-10 my-auto" @click="openUpgradeModal">
|
||||
<RocketIcon aria-hidden="true" />
|
||||
Upgrade
|
||||
</Button>
|
||||
</div>
|
||||
<ServersUpgradeModalWrapper
|
||||
ref="upgradeModal"
|
||||
@@ -50,7 +51,7 @@ import dayjs from 'dayjs'
|
||||
import dayjsDuration from 'dayjs/plugin/duration'
|
||||
import { type ComponentPublicInstance, computed, onMounted, onUnmounted, ref } from 'vue'
|
||||
|
||||
import ButtonStyled from '#ui/components/base/ButtonStyled.vue'
|
||||
import { Button } from '#ui/components/base/buttons'
|
||||
import ServersUpgradeModalWrapper from '#ui/components/billing/ServersUpgradeModalWrapper.vue'
|
||||
import { injectModrinthClient } from '#ui/providers'
|
||||
|
||||
|
||||
@@ -120,11 +120,17 @@
|
||||
</div>
|
||||
|
||||
<div class="z-10 ml-auto">
|
||||
<ButtonStyled color="medal-promo" type="outlined" size="large">
|
||||
<button class="my-auto" data-server-listing-button @click="handleUpgrade">
|
||||
<RocketIcon /> {{ formatMessage(messages.upgradeButton) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<Button
|
||||
type="outlined"
|
||||
color="medal_promotion"
|
||||
size="xl"
|
||||
class="my-auto"
|
||||
data-server-listing-button
|
||||
@click="handleUpgrade"
|
||||
>
|
||||
<RocketIcon aria-hidden="true" />
|
||||
{{ formatMessage(messages.upgradeButton) }}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -168,10 +174,11 @@ import dayjsDuration from 'dayjs/plugin/duration'
|
||||
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
import { Button } from '#ui/components/base/buttons'
|
||||
|
||||
import { defineMessages, useVIntl } from '../../../composables/i18n'
|
||||
import { injectModrinthClient } from '../../../providers/api-client'
|
||||
import Avatar from '../../base/Avatar.vue'
|
||||
import ButtonStyled from '../../base/ButtonStyled.vue'
|
||||
import CopyCode from '../../base/CopyCode.vue'
|
||||
import IntlFormatted from '../../base/IntlFormatted.vue'
|
||||
import type { ServerListingOwner } from '../access/types'
|
||||
|
||||
@@ -1,60 +1,75 @@
|
||||
<template>
|
||||
<div class="contents">
|
||||
<div class="flex flex-row items-center gap-2 rounded-lg">
|
||||
<ButtonStyled v-if="isInstalling" type="standard" color="brand" size="large">
|
||||
<button disabled class="flex-shrink-0">
|
||||
<LoaderCircleIcon class="size-5 animate-spin" /> Installing...
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<Button
|
||||
v-if="isInstalling"
|
||||
type="colored"
|
||||
color="brand"
|
||||
size="xl"
|
||||
disabled
|
||||
class="flex-shrink-0"
|
||||
>
|
||||
<LoaderCircleIcon class="size-5 animate-spin" /> Installing...
|
||||
</Button>
|
||||
|
||||
<template v-else-if="showRestartButton">
|
||||
<ButtonStyled type="standard" color="orange" size="large">
|
||||
<button v-tooltip="busyTooltip" :disabled="!canTakeAction" @click="handlePrimaryAction">
|
||||
<UpdatedIcon />
|
||||
<span>{{ primaryActionText }}</span>
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
|
||||
<JoinedButtons
|
||||
color="red"
|
||||
size="large"
|
||||
:actions="stopSplitActions"
|
||||
:primary-disabled="!canTakeAction"
|
||||
:dropdown-disabled="!canKill"
|
||||
:primary-tooltip="busyTooltip"
|
||||
:dropdown-tooltip="busyTooltip"
|
||||
<Button
|
||||
v-tooltip="busyTooltip"
|
||||
type="colored"
|
||||
color="orange"
|
||||
size="xl"
|
||||
:disabled="!canTakeAction"
|
||||
@click="handlePrimaryAction"
|
||||
>
|
||||
<template #kill_server>
|
||||
<SlashIcon class="h-5 w-5" />
|
||||
Kill server
|
||||
</template>
|
||||
</JoinedButtons>
|
||||
<UpdatedIcon />
|
||||
<span>{{ primaryActionText }}</span>
|
||||
</Button>
|
||||
|
||||
<SplitButton
|
||||
v-tooltip="busyTooltip"
|
||||
type="colored"
|
||||
color="red"
|
||||
size="xl"
|
||||
:options="stopMenuOptions"
|
||||
menu-label="Force stop options"
|
||||
:primary-disabled="!canTakeAction"
|
||||
:menu-disabled="!canKill"
|
||||
@click="initiateAction('Stop')"
|
||||
>
|
||||
<StopCircleIcon />
|
||||
{{ isStopping ? 'Stopping' : 'Stop' }}
|
||||
</SplitButton>
|
||||
</template>
|
||||
|
||||
<template v-else-if="isStopping">
|
||||
<JoinedButtons
|
||||
<SplitButton
|
||||
v-tooltip="busyTooltip"
|
||||
type="colored"
|
||||
color="red"
|
||||
size="large"
|
||||
:actions="stopSplitActions"
|
||||
size="xl"
|
||||
:options="stopMenuOptions"
|
||||
menu-label="Force stop options"
|
||||
:primary-disabled="true"
|
||||
:dropdown-disabled="!canKill"
|
||||
:primary-muted="true"
|
||||
:dropdown-tooltip="busyTooltip"
|
||||
:menu-disabled="!canKill"
|
||||
class="opacity-60"
|
||||
>
|
||||
<template #kill_server>
|
||||
<SlashIcon class="h-5 w-5" />
|
||||
Kill server
|
||||
</template>
|
||||
</JoinedButtons>
|
||||
<StopCircleIcon />
|
||||
Stopping
|
||||
</SplitButton>
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
<ButtonStyled type="standard" color="brand" size="large">
|
||||
<button v-tooltip="busyTooltip" :disabled="!canTakeAction" @click="handlePrimaryAction">
|
||||
<PlayIcon />
|
||||
<span>{{ primaryActionText }}</span>
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<Button
|
||||
v-tooltip="busyTooltip"
|
||||
type="colored"
|
||||
color="brand"
|
||||
size="xl"
|
||||
:disabled="!canTakeAction"
|
||||
@click="handlePrimaryAction"
|
||||
>
|
||||
<PlayIcon />
|
||||
<span>{{ primaryActionText }}</span>
|
||||
</Button>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
@@ -70,7 +85,8 @@ import {
|
||||
} from '@modrinth/assets'
|
||||
import { computed } from 'vue'
|
||||
|
||||
import { ButtonStyled, type JoinedButtonAction, JoinedButtons } from '#ui/components'
|
||||
import type { OverflowMenuOption } from '#ui/components/base/buttons'
|
||||
import { Button, SplitButton } from '#ui/components/base/buttons'
|
||||
|
||||
import { useServerPowerAction } from './use-server-power-action'
|
||||
|
||||
@@ -97,13 +113,7 @@ const {
|
||||
disabled: computed(() => props.disabled),
|
||||
})
|
||||
|
||||
const stopSplitActions = computed<JoinedButtonAction[]>(() => [
|
||||
{
|
||||
id: 'stop',
|
||||
label: isStopping.value ? 'Stopping' : 'Stop',
|
||||
icon: StopCircleIcon,
|
||||
action: () => initiateAction('Stop'),
|
||||
},
|
||||
const stopMenuOptions = computed<OverflowMenuOption[]>(() => [
|
||||
{
|
||||
id: 'kill_server',
|
||||
label: 'Kill server',
|
||||
|
||||
@@ -66,12 +66,10 @@
|
||||
<!-- CTA section -->
|
||||
<div class="flex flex-col gap-6 items-start">
|
||||
<div class="flex flex-col gap-3 items-start">
|
||||
<ButtonStyled color="brand">
|
||||
<button @click="onClickNewServer?.()">
|
||||
<PlusIcon aria-hidden="true" />
|
||||
{{ formatMessage(messages.newServerButton) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<Button type="colored" color="brand" @click="onClickNewServer?.()">
|
||||
<PlusIcon aria-hidden="true" />
|
||||
{{ formatMessage(messages.newServerButton) }}
|
||||
</Button>
|
||||
|
||||
<AutoLink
|
||||
to="https://modrinth.com/hosting"
|
||||
@@ -90,12 +88,10 @@
|
||||
<p class="text-base font-normal text-primary">
|
||||
{{ formatMessage(messages.alreadyHaveServerLabel) }}
|
||||
</p>
|
||||
<ButtonStyled>
|
||||
<button @click="onClickSignIn?.()">
|
||||
<LogInIcon aria-hidden="true" />
|
||||
{{ formatMessage(messages.signInButton) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<Button @click="onClickSignIn?.()">
|
||||
<LogInIcon aria-hidden="true" />
|
||||
{{ formatMessage(messages.signInButton) }}
|
||||
</Button>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
@@ -153,7 +149,7 @@ import {
|
||||
} from '@modrinth/assets'
|
||||
import { AutoLink } from '@modrinth/ui'
|
||||
|
||||
import ButtonStyled from '#ui/components/base/ButtonStyled.vue'
|
||||
import { Button } from '#ui/components/base/buttons'
|
||||
|
||||
import { defineMessages, useVIntl } from '../../../composables/i18n'
|
||||
import imgAircraft from './grid-images/aircraft.png'
|
||||
|
||||
Reference in New Issue
Block a user