mirror of
https://github.com/modrinth/code.git
synced 2026-08-31 03:55:59 +00:00
feat(instance-sync): screenshots sync (#7218)
* pnpm prepr * feat(instance-sync): screenshots sync * fix: prepr + fmt * fix: qa * feat: screenshit editor * feat: screenshot* editor qa * fix: qa * fix: lint * fix: aecsocket rev * qa: a11y tab navigation focus is cut off * qa: Change “Edited” badge to be bg-highlight-green * qa: friends list input style wrong * qa: toolbar width + labels * qa: multiselect changes * qa: anim changes * qa: card hover colors * qa: copy feedback * qa: hide date * qa: instance icon in overflow/contextmenu * qa: spacing * qa: group empty state text * qa: drag preview badge * qa: group deletion skip warning if no screenshots * qa: redesign editor * qa: remove screenshot parent/edited badge stuff * qa: control font size consistency * qa: viewer copy control * qa: editor fixes * qa: redirect on disable screenshot sync * qa: margin police * fix: crop * fix: qa * feat: initial start on basic instance file syncing (#7220) * qa: final * qa: final 2 * fix: lint + prepr * fix: copy * fix: screenshot editing outside of app causing ghost files in db + sync fail rollback impl * chore: split up * fix: fmt --------- Co-authored-by: tdgao <mr.trumgao@gmail.com>
This commit is contained in:
@@ -67,7 +67,7 @@ const router = useRouter()
|
||||
const { addNotification } = injectNotificationManager()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'play' | 'play-instance' | 'update' | 'stop' | 'refresh' | 'edit' | 'delete'): void
|
||||
(e: 'play' | 'play-instance' | 'update' | 'stop' | 'refresh' | 'edit' | 'delete' | 'desync'): void
|
||||
(e: 'open-folder', world: SingleplayerWorld): void
|
||||
}>()
|
||||
|
||||
@@ -95,6 +95,8 @@ const props = withDefaults(
|
||||
}
|
||||
|
||||
managed?: boolean
|
||||
showPlayButton?: boolean
|
||||
cardBackground?: 'raised' | 'surface-2'
|
||||
|
||||
// Instance
|
||||
instanceId?: string
|
||||
@@ -117,6 +119,8 @@ const props = withDefaults(
|
||||
|
||||
gameMode: undefined,
|
||||
managed: false,
|
||||
showPlayButton: true,
|
||||
cardBackground: 'raised',
|
||||
|
||||
instanceId: undefined,
|
||||
instanceName: undefined,
|
||||
@@ -218,6 +222,10 @@ const messages = defineMessages({
|
||||
id: 'instance.worlds.copy_address',
|
||||
defaultMessage: 'Copy address',
|
||||
},
|
||||
desync: {
|
||||
id: 'instance.worlds.desync_server',
|
||||
defaultMessage: 'Desync',
|
||||
},
|
||||
viewInstance: {
|
||||
id: 'instance.worlds.view_instance',
|
||||
defaultMessage: 'View instance',
|
||||
@@ -270,7 +278,10 @@ const messages = defineMessages({
|
||||
|
||||
const cardOptions = useTemplateRef('cardOptions')
|
||||
const showStop = computed(
|
||||
() => (props.playingWorld || (locked.value && props.playingInstance)) && !props.startingInstance,
|
||||
() =>
|
||||
props.showPlayButton &&
|
||||
(props.playingWorld || (locked.value && props.playingInstance)) &&
|
||||
!props.startingInstance,
|
||||
)
|
||||
const playDisabled = computed(
|
||||
() =>
|
||||
@@ -327,6 +338,17 @@ const overflowOptions = computed((): ButtonMenuOption[] => [
|
||||
shown: props.world.type === 'server',
|
||||
action: () => copyToClipboard((props.world as ServerWorld).address),
|
||||
},
|
||||
{
|
||||
id: 'desync',
|
||||
label: formatMessage(messages.desync),
|
||||
icon: XIcon,
|
||||
action: () => emit('desync'),
|
||||
shown:
|
||||
!props.instanceId &&
|
||||
props.world.type === 'server' &&
|
||||
(props.world as ServerWorld).source === 'user_synced' &&
|
||||
!!(props.world as ServerWorld).server_id,
|
||||
},
|
||||
{
|
||||
id: 'edit',
|
||||
label: formatMessage(commonMessages.editButton),
|
||||
@@ -404,6 +426,7 @@ const contextMenuOptions = computed((): ButtonMenuOption[] => [
|
||||
label: formatMessage(commonMessages.stopButton),
|
||||
icon: StopCircleIcon,
|
||||
tone: 'red',
|
||||
shown: props.showPlayButton,
|
||||
action: () => emit('stop'),
|
||||
}
|
||||
: {
|
||||
@@ -411,11 +434,12 @@ const contextMenuOptions = computed((): ButtonMenuOption[] => [
|
||||
label: formatMessage(messages.playWorld),
|
||||
icon: PlayIcon,
|
||||
tone: 'brand',
|
||||
shown: props.showPlayButton,
|
||||
disabled: playDisabled.value,
|
||||
tooltip: playTooltip.value ?? undefined,
|
||||
action: () => emit('play'),
|
||||
},
|
||||
{ type: 'divider' },
|
||||
{ type: 'divider', shown: props.showPlayButton },
|
||||
...overflowOptions.value,
|
||||
])
|
||||
|
||||
@@ -433,9 +457,11 @@ function openContextMenu(event: MouseEvent) {
|
||||
/>
|
||||
</template>
|
||||
<div
|
||||
class="clickable-card grid grid-cols-[auto_minmax(0,3fr)_minmax(0,4fr)_auto] items-center gap-2 p-3 bg-bg-raised border border-solid border-surface-4 smart-clickable:highlight-on-hover rounded-[20px] transition-[filter] ease-out [--hover-brightness:1.25] min-h-20"
|
||||
class="clickable-card grid grid-cols-[auto_minmax(0,3fr)_minmax(0,4fr)_auto] items-center gap-2 p-3 border border-solid border-surface-4 smart-clickable:highlight-on-hover rounded-[20px] transition-[filter] ease-out [--hover-brightness:1.25] min-h-20"
|
||||
:class="{
|
||||
'world-item-highlighted': highlighted,
|
||||
'bg-bg-raised': cardBackground === 'raised',
|
||||
'bg-surface-2': cardBackground === 'surface-2',
|
||||
}"
|
||||
>
|
||||
<Avatar
|
||||
@@ -592,12 +618,17 @@ function openContextMenu(event: MouseEvent) {
|
||||
</template>
|
||||
</div>
|
||||
<div class="flex gap-1 justify-end smart-clickable:allow-pointer-events">
|
||||
<Button v-if="showStop" type="colored" color="red" @click="emit('stop')">
|
||||
<Button
|
||||
v-if="showPlayButton && showStop"
|
||||
type="colored"
|
||||
color="red"
|
||||
@click="emit('stop')"
|
||||
>
|
||||
<StopCircleIcon aria-hidden="true" />
|
||||
{{ formatMessage(commonMessages.stopButton) }}
|
||||
</Button>
|
||||
<Button
|
||||
v-else
|
||||
v-else-if="showPlayButton"
|
||||
v-tooltip="playTooltip"
|
||||
:disabled="playDisabled"
|
||||
type="colored"
|
||||
|
||||
@@ -16,6 +16,7 @@ const { formatMessage } = useVIntl()
|
||||
|
||||
const props = defineProps<{
|
||||
world: World | null
|
||||
otherSyncedInstanceCount: number
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
@@ -44,6 +45,11 @@ const messages = defineMessages({
|
||||
defaultMessage:
|
||||
'This server will be removed from your server list and from the in-game server list. You can add it again later if you know the address.',
|
||||
},
|
||||
syncedServerRemovalNotice: {
|
||||
id: 'app.instance.worlds.remove-server-modal.synced-removal-notice',
|
||||
defaultMessage:
|
||||
'This server will also be removed from {count, plural, one {# other instance} other {# other instances}} because it’s synced.',
|
||||
},
|
||||
deleteWorldWarningBody: {
|
||||
id: 'app.instance.worlds.delete-world-modal.warning-body',
|
||||
defaultMessage:
|
||||
@@ -62,6 +68,9 @@ const messages = defineMessages({
|
||||
const modal = ref<InstanceType<typeof NewModal>>()
|
||||
|
||||
const isServer = computed(() => props.world?.type === 'server')
|
||||
const isSyncedServer = computed(
|
||||
() => props.world?.type === 'server' && props.world.source === 'user_synced',
|
||||
)
|
||||
const isSingleplayer = computed(() => props.world?.type === 'singleplayer')
|
||||
const titleMessage = computed(() =>
|
||||
isServer.value ? messages.removeServerTitle : messages.deleteWorldTitle,
|
||||
@@ -102,6 +111,13 @@ defineExpose({ show, hide })
|
||||
>
|
||||
{{ formatMessage(warningBodyMessage) }}
|
||||
</Admonition>
|
||||
<p v-if="isSyncedServer" class="m-0 text-secondary">
|
||||
{{
|
||||
formatMessage(messages.syncedServerRemovalNotice, {
|
||||
count: otherSyncedInstanceCount,
|
||||
})
|
||||
}}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<template #actions>
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
<script setup lang="ts">
|
||||
import { LinkIcon, TrashIcon, XIcon } from '@modrinth/assets'
|
||||
import { Button, commonMessages, defineMessages, NewModal, useVIntl } from '@modrinth/ui'
|
||||
import { ref } from 'vue'
|
||||
|
||||
import type { DesyncServerMode, ServerWorld } from '@/helpers/worlds'
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
const modal = ref<InstanceType<typeof NewModal> | null>(null)
|
||||
const server = ref<ServerWorld | null>(null)
|
||||
|
||||
const emit = defineEmits<{
|
||||
confirm: [server: ServerWorld, mode: DesyncServerMode]
|
||||
}>()
|
||||
|
||||
const messages = defineMessages({
|
||||
title: {
|
||||
id: 'instance.worlds.desync-server.title',
|
||||
defaultMessage: 'Desync server',
|
||||
},
|
||||
description: {
|
||||
id: 'instance.worlds.desync-server.description',
|
||||
defaultMessage:
|
||||
'Do you want to keep this server in other synced instances, or remove it from them?',
|
||||
},
|
||||
keep: {
|
||||
id: 'instance.worlds.desync-server.keep',
|
||||
defaultMessage: 'Keep',
|
||||
},
|
||||
remove: {
|
||||
id: 'instance.worlds.desync-server.remove',
|
||||
defaultMessage: 'Remove',
|
||||
},
|
||||
})
|
||||
|
||||
function show(value: ServerWorld) {
|
||||
server.value = value
|
||||
modal.value?.show()
|
||||
}
|
||||
|
||||
function confirm(mode: DesyncServerMode) {
|
||||
if (server.value) emit('confirm', server.value, mode)
|
||||
modal.value?.hide()
|
||||
}
|
||||
|
||||
defineExpose({ show })
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NewModal ref="modal" :header="formatMessage(messages.title)" max-width="540px">
|
||||
<p class="m-0 text-secondary">{{ formatMessage(messages.description) }}</p>
|
||||
<template #actions>
|
||||
<div class="flex justify-end gap-2">
|
||||
<Button type="outlined" class="whitespace-nowrap" @click="modal?.hide()">
|
||||
<XIcon />
|
||||
{{ formatMessage(commonMessages.cancelButton) }}
|
||||
</Button>
|
||||
<Button class="whitespace-nowrap" @click="confirm('keep_in_other_instances')">
|
||||
<LinkIcon />
|
||||
{{ formatMessage(messages.keep) }}
|
||||
</Button>
|
||||
<Button
|
||||
type="colored"
|
||||
color="red"
|
||||
class="whitespace-nowrap"
|
||||
@click="confirm('remove_from_other_instances')"
|
||||
>
|
||||
<TrashIcon />
|
||||
{{ formatMessage(messages.remove) }}
|
||||
</Button>
|
||||
</div>
|
||||
</template>
|
||||
</NewModal>
|
||||
</template>
|
||||
Reference in New Issue
Block a user