refactor: project saving logic (#5225)
* fix: project data saving not visually shown immediately * feat: useSavable improvements * feat: migrate where possible to useSavable * fix: gitignore * feat: use es-toolkit
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -65,6 +65,7 @@ app-playground-data/*
|
|||||||
|
|
||||||
.astro
|
.astro
|
||||||
.claude
|
.claude
|
||||||
|
.letta
|
||||||
|
|
||||||
# labrinth demo fixtures
|
# labrinth demo fixtures
|
||||||
apps/labrinth/fixtures/demo
|
apps/labrinth/fixtures/demo
|
||||||
|
|||||||
@@ -1647,6 +1647,15 @@ async function resetVersions() {
|
|||||||
await resetVersionsV3()
|
await resetVersionsV3()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper to invalidate project queries after mutations settle
|
||||||
|
async function invalidateProjectQueries(projectId) {
|
||||||
|
await queryClient.invalidateQueries({ queryKey: ['project', 'v2', routeProjectId.value] })
|
||||||
|
if (routeProjectId.value !== projectId) {
|
||||||
|
await queryClient.invalidateQueries({ queryKey: ['project', 'v2', projectId] })
|
||||||
|
}
|
||||||
|
await queryClient.invalidateQueries({ queryKey: ['project', 'v3', projectId] })
|
||||||
|
}
|
||||||
|
|
||||||
// Mutation for patching project data
|
// Mutation for patching project data
|
||||||
const patchProjectMutation = useMutation({
|
const patchProjectMutation = useMutation({
|
||||||
mutationFn: async ({ projectId, data }) => {
|
mutationFn: async ({ projectId, data }) => {
|
||||||
@@ -1691,12 +1700,7 @@ const patchProjectMutation = useMutation({
|
|||||||
},
|
},
|
||||||
|
|
||||||
onSettled: async (_data, _error, { projectId }) => {
|
onSettled: async (_data, _error, { projectId }) => {
|
||||||
// Invalidate both slug-based and ID-based cache keys to ensure consistency
|
await invalidateProjectQueries(projectId)
|
||||||
await queryClient.invalidateQueries({ queryKey: ['project', 'v2', routeProjectId.value] })
|
|
||||||
if (routeProjectId.value !== projectId) {
|
|
||||||
await queryClient.invalidateQueries({ queryKey: ['project', 'v2', projectId] })
|
|
||||||
}
|
|
||||||
await queryClient.invalidateQueries({ queryKey: ['project', 'v3', projectId] })
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -1741,11 +1745,7 @@ const patchStatusMutation = useMutation({
|
|||||||
},
|
},
|
||||||
|
|
||||||
onSettled: async (_data, _error, { projectId }) => {
|
onSettled: async (_data, _error, { projectId }) => {
|
||||||
// Invalidate both slug-based and ID-based cache keys to ensure consistency
|
await invalidateProjectQueries(projectId)
|
||||||
await queryClient.invalidateQueries({ queryKey: ['project', 'v2', routeProjectId.value] })
|
|
||||||
if (routeProjectId.value !== projectId) {
|
|
||||||
await queryClient.invalidateQueries({ queryKey: ['project', 'v2', projectId] })
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -1779,8 +1779,171 @@ const patchIconMutation = useMutation({
|
|||||||
},
|
},
|
||||||
|
|
||||||
onSettled: async (_data, _error, { projectId }) => {
|
onSettled: async (_data, _error, { projectId }) => {
|
||||||
await queryClient.invalidateQueries({ queryKey: ['project', 'v2', projectId] })
|
await invalidateProjectQueries(projectId)
|
||||||
await queryClient.invalidateQueries({ queryKey: ['project', 'v3', projectId] })
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const createGalleryItemMutation = useMutation({
|
||||||
|
mutationFn: async ({ projectId, file, title, description, featured, ordering }) => {
|
||||||
|
let url = `project/${projectId}/gallery?ext=${
|
||||||
|
file.type.split('/')[file.type.split('/').length - 1]
|
||||||
|
}&featured=${featured ?? false}`
|
||||||
|
|
||||||
|
if (title) {
|
||||||
|
url += `&title=${encodeURIComponent(title)}`
|
||||||
|
}
|
||||||
|
if (description) {
|
||||||
|
url += `&description=${encodeURIComponent(description)}`
|
||||||
|
}
|
||||||
|
if (ordering !== null && ordering !== undefined) {
|
||||||
|
url += `&ordering=${ordering}`
|
||||||
|
}
|
||||||
|
|
||||||
|
await useBaseFetch(url, {
|
||||||
|
method: 'POST',
|
||||||
|
body: file,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
onMutate: async ({ title, description, featured, ordering }) => {
|
||||||
|
await queryClient.cancelQueries({ queryKey: ['project', 'v2', routeProjectId.value] })
|
||||||
|
|
||||||
|
const previousProject = queryClient.getQueryData(['project', 'v2', routeProjectId.value])
|
||||||
|
|
||||||
|
queryClient.setQueryData(['project', 'v2', routeProjectId.value], (old) => {
|
||||||
|
if (!old) return old
|
||||||
|
const newItem = {
|
||||||
|
url: '',
|
||||||
|
raw_url: '',
|
||||||
|
featured: featured ?? false,
|
||||||
|
title: title ?? '',
|
||||||
|
description: description ?? '',
|
||||||
|
created: new Date().toISOString(),
|
||||||
|
ordering: ordering ?? old.gallery.length,
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...old,
|
||||||
|
gallery: [...old.gallery, newItem],
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return { previousProject }
|
||||||
|
},
|
||||||
|
|
||||||
|
onError: (err, _variables, context) => {
|
||||||
|
if (context?.previousProject) {
|
||||||
|
queryClient.setQueryData(['project', 'v2', routeProjectId.value], context.previousProject)
|
||||||
|
}
|
||||||
|
addNotification({
|
||||||
|
title: formatMessage(commonMessages.errorNotificationTitle),
|
||||||
|
text: err.data ? err.data.description : err.message,
|
||||||
|
type: 'error',
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
onSettled: async (_data, _error, { projectId }) => {
|
||||||
|
await invalidateProjectQueries(projectId)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const editGalleryItemMutation = useMutation({
|
||||||
|
mutationFn: async ({ projectId, imageUrl, title, description, featured, ordering }) => {
|
||||||
|
let url = `project/${projectId}/gallery?url=${encodeURIComponent(imageUrl)}&featured=${featured ?? false}`
|
||||||
|
|
||||||
|
if (title) {
|
||||||
|
url += `&title=${encodeURIComponent(title)}`
|
||||||
|
}
|
||||||
|
if (description) {
|
||||||
|
url += `&description=${encodeURIComponent(description)}`
|
||||||
|
}
|
||||||
|
if (ordering !== null && ordering !== undefined) {
|
||||||
|
url += `&ordering=${ordering}`
|
||||||
|
}
|
||||||
|
|
||||||
|
await useBaseFetch(url, {
|
||||||
|
method: 'PATCH',
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
onMutate: async ({ imageUrl, title, description, featured, ordering }) => {
|
||||||
|
await queryClient.cancelQueries({ queryKey: ['project', 'v2', routeProjectId.value] })
|
||||||
|
|
||||||
|
const previousProject = queryClient.getQueryData(['project', 'v2', routeProjectId.value])
|
||||||
|
|
||||||
|
queryClient.setQueryData(['project', 'v2', routeProjectId.value], (old) => {
|
||||||
|
if (!old) return old
|
||||||
|
return {
|
||||||
|
...old,
|
||||||
|
gallery: old.gallery.map((item) => {
|
||||||
|
if (item.url === imageUrl) {
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
title: title ?? item.title,
|
||||||
|
description: description ?? item.description,
|
||||||
|
featured: featured ?? item.featured,
|
||||||
|
ordering: ordering ?? item.ordering,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return item
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return { previousProject }
|
||||||
|
},
|
||||||
|
|
||||||
|
onError: (err, _variables, context) => {
|
||||||
|
if (context?.previousProject) {
|
||||||
|
queryClient.setQueryData(['project', 'v2', routeProjectId.value], context.previousProject)
|
||||||
|
}
|
||||||
|
addNotification({
|
||||||
|
title: formatMessage(commonMessages.errorNotificationTitle),
|
||||||
|
text: err.data ? err.data.description : err.message,
|
||||||
|
type: 'error',
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
onSettled: async (_data, _error, { projectId }) => {
|
||||||
|
await invalidateProjectQueries(projectId)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const deleteGalleryItemMutation = useMutation({
|
||||||
|
mutationFn: async ({ projectId, imageUrl }) => {
|
||||||
|
await useBaseFetch(`project/${projectId}/gallery?url=${encodeURIComponent(imageUrl)}`, {
|
||||||
|
method: 'DELETE',
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
onMutate: async ({ imageUrl }) => {
|
||||||
|
await queryClient.cancelQueries({ queryKey: ['project', 'v2', routeProjectId.value] })
|
||||||
|
|
||||||
|
const previousProject = queryClient.getQueryData(['project', 'v2', routeProjectId.value])
|
||||||
|
|
||||||
|
queryClient.setQueryData(['project', 'v2', routeProjectId.value], (old) => {
|
||||||
|
if (!old) return old
|
||||||
|
return {
|
||||||
|
...old,
|
||||||
|
gallery: old.gallery.filter((item) => item.url !== imageUrl),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return { previousProject }
|
||||||
|
},
|
||||||
|
|
||||||
|
onError: (err, _variables, context) => {
|
||||||
|
if (context?.previousProject) {
|
||||||
|
queryClient.setQueryData(['project', 'v2', routeProjectId.value], context.previousProject)
|
||||||
|
}
|
||||||
|
addNotification({
|
||||||
|
title: formatMessage(commonMessages.errorNotificationTitle),
|
||||||
|
text: err.data ? err.data.description : err.message,
|
||||||
|
type: 'error',
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
onSettled: async (_data, _error, { projectId }) => {
|
||||||
|
await invalidateProjectQueries(projectId)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -1971,6 +2134,51 @@ async function patchIcon(icon) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function createGalleryItem(file, title, description, featured, ordering) {
|
||||||
|
startLoading()
|
||||||
|
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
createGalleryItemMutation.mutate(
|
||||||
|
{ projectId: project.value.id, file, title, description, featured, ordering },
|
||||||
|
{
|
||||||
|
onSuccess: () => resolve(true),
|
||||||
|
onError: () => resolve(false),
|
||||||
|
onSettled: () => stopLoading(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function editGalleryItem(imageUrl, title, description, featured, ordering) {
|
||||||
|
startLoading()
|
||||||
|
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
editGalleryItemMutation.mutate(
|
||||||
|
{ projectId: project.value.id, imageUrl, title, description, featured, ordering },
|
||||||
|
{
|
||||||
|
onSuccess: () => resolve(true),
|
||||||
|
onError: () => resolve(false),
|
||||||
|
onSettled: () => stopLoading(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function deleteGalleryItem(imageUrl) {
|
||||||
|
startLoading()
|
||||||
|
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
deleteGalleryItemMutation.mutate(
|
||||||
|
{ projectId: project.value.id, imageUrl },
|
||||||
|
{
|
||||||
|
onSuccess: () => resolve(true),
|
||||||
|
onError: () => resolve(false),
|
||||||
|
onSettled: () => stopLoading(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
async function refreshMembers() {
|
async function refreshMembers() {
|
||||||
// Simply invalidate and refetch - the computed allMembers will auto-update
|
// Simply invalidate and refetch - the computed allMembers will auto-update
|
||||||
await queryClient.invalidateQueries({ queryKey: ['project', projectId.value, 'members'] })
|
await queryClient.invalidateQueries({ queryKey: ['project', projectId.value, 'members'] })
|
||||||
@@ -2103,6 +2311,11 @@ provideProjectPageContext({
|
|||||||
patchProject,
|
patchProject,
|
||||||
patchIcon,
|
patchIcon,
|
||||||
setProcessing,
|
setProcessing,
|
||||||
|
|
||||||
|
// Gallery mutation functions
|
||||||
|
createGalleryItem,
|
||||||
|
editGalleryItem,
|
||||||
|
deleteGalleryItem,
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<MarkdownEditor
|
<MarkdownEditor
|
||||||
v-model="description"
|
v-model="current.description"
|
||||||
:disabled="
|
:disabled="
|
||||||
!currentMember ||
|
!currentMember ||
|
||||||
(currentMember?.permissions! & TeamMemberPermission.EDIT_BODY) !==
|
(currentMember?.permissions! & TeamMemberPermission.EDIT_BODY) !==
|
||||||
@@ -26,36 +26,42 @@
|
|||||||
<TriangleAlertIcon class="my-auto" />
|
<TriangleAlertIcon class="my-auto" />
|
||||||
{{ descriptionWarning }}
|
{{ descriptionWarning }}
|
||||||
</div>
|
</div>
|
||||||
<div class="input-group markdown-disclaimer">
|
|
||||||
<button
|
|
||||||
:disabled="!hasChanges"
|
|
||||||
class="iconified-button brand-button"
|
|
||||||
type="button"
|
|
||||||
@click="saveChanges()"
|
|
||||||
>
|
|
||||||
<SaveIcon />
|
|
||||||
Save changes
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<UnsavedChangesPopup
|
||||||
|
:original="saved"
|
||||||
|
:modified="current"
|
||||||
|
:saving="saving"
|
||||||
|
@reset="reset"
|
||||||
|
@save="save"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { SaveIcon, TriangleAlertIcon } from '@modrinth/assets'
|
import { TriangleAlertIcon } from '@modrinth/assets'
|
||||||
import { countText, MIN_DESCRIPTION_CHARS } from '@modrinth/moderation'
|
import { countText, MIN_DESCRIPTION_CHARS } from '@modrinth/moderation'
|
||||||
import { injectProjectPageContext, MarkdownEditor } from '@modrinth/ui'
|
import {
|
||||||
|
injectProjectPageContext,
|
||||||
|
MarkdownEditor,
|
||||||
|
UnsavedChangesPopup,
|
||||||
|
useSavable,
|
||||||
|
} from '@modrinth/ui'
|
||||||
import { TeamMemberPermission } from '@modrinth/utils'
|
import { TeamMemberPermission } from '@modrinth/utils'
|
||||||
import { computed, ref } from 'vue'
|
import { computed } from 'vue'
|
||||||
|
|
||||||
import { useImageUpload } from '~/composables/image-upload.ts'
|
import { useImageUpload } from '~/composables/image-upload.ts'
|
||||||
|
|
||||||
const { projectV2: project, currentMember, patchProject } = injectProjectPageContext()
|
const { projectV2: project, currentMember, patchProject } = injectProjectPageContext()
|
||||||
|
|
||||||
const description = ref(project.value.body)
|
const { saved, current, saving, reset, save } = useSavable(
|
||||||
|
() => ({ description: project.value.body }),
|
||||||
|
async ({ description }) => {
|
||||||
|
await patchProject({ body: description })
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
const descriptionWarning = computed(() => {
|
const descriptionWarning = computed(() => {
|
||||||
const text = description.value?.trim() || ''
|
const text = current.value.description?.trim() || ''
|
||||||
const charCount = countText(text)
|
const charCount = countText(text)
|
||||||
|
|
||||||
if (charCount < MIN_DESCRIPTION_CHARS) {
|
if (charCount < MIN_DESCRIPTION_CHARS) {
|
||||||
@@ -65,26 +71,6 @@ const descriptionWarning = computed(() => {
|
|||||||
return null
|
return null
|
||||||
})
|
})
|
||||||
|
|
||||||
const patchRequestPayload = computed(() => {
|
|
||||||
const payload: {
|
|
||||||
body?: string
|
|
||||||
} = {}
|
|
||||||
|
|
||||||
if (description.value !== project.value.body) {
|
|
||||||
payload.body = description.value
|
|
||||||
}
|
|
||||||
|
|
||||||
return payload
|
|
||||||
})
|
|
||||||
|
|
||||||
const hasChanges = computed(() => {
|
|
||||||
return Object.keys(patchRequestPayload.value).length > 0
|
|
||||||
})
|
|
||||||
|
|
||||||
function saveChanges() {
|
|
||||||
patchProject(patchRequestPayload.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
async function onUploadHandler(file: File) {
|
async function onUploadHandler(file: File) {
|
||||||
const response = await useImageUpload(file, {
|
const response = await useImageUpload(file, {
|
||||||
context: 'project',
|
context: 'project',
|
||||||
|
|||||||
@@ -299,15 +299,19 @@ import {
|
|||||||
ConfirmModal,
|
ConfirmModal,
|
||||||
DropArea,
|
DropArea,
|
||||||
FileInput,
|
FileInput,
|
||||||
injectNotificationManager,
|
|
||||||
injectProjectPageContext,
|
injectProjectPageContext,
|
||||||
NewModal as Modal,
|
NewModal as Modal,
|
||||||
} from '@modrinth/ui'
|
} from '@modrinth/ui'
|
||||||
|
|
||||||
import { isPermission } from '~/utils/permissions.ts'
|
import { isPermission } from '~/utils/permissions.ts'
|
||||||
|
|
||||||
const { addNotification } = injectNotificationManager()
|
const {
|
||||||
const { projectV2: project, currentMember, refreshProject } = injectProjectPageContext()
|
projectV2: project,
|
||||||
|
currentMember,
|
||||||
|
createGalleryItem: createGalleryItemMutation,
|
||||||
|
editGalleryItem: editGalleryItemMutation,
|
||||||
|
deleteGalleryItem: deleteGalleryItemMutation,
|
||||||
|
} = injectProjectPageContext()
|
||||||
|
|
||||||
const title = `${project.value.title} - Gallery`
|
const title = `${project.value.title} - Gallery`
|
||||||
const description = `View ${project.value.gallery?.length ?? 0} images of ${project.value.title} on Modrinth.`
|
const description = `View ${project.value.gallery?.length ?? 0} images of ${project.value.title} on Modrinth.`
|
||||||
@@ -391,103 +395,42 @@ const showPreviewImage = () => {
|
|||||||
|
|
||||||
const createGalleryItem = async () => {
|
const createGalleryItem = async () => {
|
||||||
shouldPreventActions.value = true
|
shouldPreventActions.value = true
|
||||||
startLoading()
|
|
||||||
|
|
||||||
try {
|
const success = await createGalleryItemMutation(
|
||||||
let url = `project/${project.value.id}/gallery?ext=${
|
editFile.value,
|
||||||
editFile.value
|
editTitle.value || undefined,
|
||||||
? editFile.value.type.split('/')[editFile.value.type.split('/').length - 1]
|
editDescription.value || undefined,
|
||||||
: null
|
editFeatured.value,
|
||||||
}&featured=${editFeatured.value}`
|
editOrder.value ?? undefined,
|
||||||
|
)
|
||||||
if (editTitle.value) {
|
|
||||||
url += `&title=${encodeURIComponent(editTitle.value)}`
|
|
||||||
}
|
|
||||||
if (editDescription.value) {
|
|
||||||
url += `&description=${encodeURIComponent(editDescription.value)}`
|
|
||||||
}
|
|
||||||
if (editOrder.value) {
|
|
||||||
url += `&ordering=${editOrder.value}`
|
|
||||||
}
|
|
||||||
|
|
||||||
await useBaseFetch(url, {
|
|
||||||
method: 'POST',
|
|
||||||
body: editFile.value,
|
|
||||||
})
|
|
||||||
await refreshProject()
|
|
||||||
|
|
||||||
|
if (success) {
|
||||||
modal_edit_item.value.hide()
|
modal_edit_item.value.hide()
|
||||||
} catch (err) {
|
|
||||||
addNotification({
|
|
||||||
title: 'An error occurred',
|
|
||||||
text: err.data ? err.data.description : err,
|
|
||||||
type: 'error',
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
stopLoading()
|
|
||||||
shouldPreventActions.value = false
|
shouldPreventActions.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
const editGalleryItem = async () => {
|
const editGalleryItem = async () => {
|
||||||
shouldPreventActions.value = true
|
shouldPreventActions.value = true
|
||||||
startLoading()
|
|
||||||
try {
|
|
||||||
let url = `project/${project.value.id}/gallery?url=${encodeURIComponent(
|
|
||||||
project.value.gallery[editIndex.value].url,
|
|
||||||
)}&featured=${editFeatured.value}`
|
|
||||||
|
|
||||||
if (editTitle.value) {
|
const success = await editGalleryItemMutation(
|
||||||
url += `&title=${encodeURIComponent(editTitle.value)}`
|
project.value.gallery[editIndex.value].url,
|
||||||
}
|
editTitle.value || undefined,
|
||||||
if (editDescription.value) {
|
editDescription.value || undefined,
|
||||||
url += `&description=${encodeURIComponent(editDescription.value)}`
|
editFeatured.value,
|
||||||
}
|
editOrder.value ?? undefined,
|
||||||
if (editOrder.value) {
|
)
|
||||||
url += `&ordering=${editOrder.value}`
|
|
||||||
}
|
|
||||||
|
|
||||||
await useBaseFetch(url, {
|
if (success) {
|
||||||
method: 'PATCH',
|
|
||||||
})
|
|
||||||
|
|
||||||
await refreshProject()
|
|
||||||
modal_edit_item.value.hide()
|
modal_edit_item.value.hide()
|
||||||
} catch (err) {
|
|
||||||
addNotification({
|
|
||||||
title: 'An error occurred',
|
|
||||||
text: err.data ? err.data.description : err,
|
|
||||||
type: 'error',
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
stopLoading()
|
|
||||||
shouldPreventActions.value = false
|
shouldPreventActions.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
const deleteGalleryImage = async () => {
|
const deleteGalleryImage = async () => {
|
||||||
startLoading()
|
await deleteGalleryItemMutation(project.value.gallery[deleteIndex.value].url)
|
||||||
|
|
||||||
try {
|
|
||||||
await useBaseFetch(
|
|
||||||
`project/${project.value.id}/gallery?url=${encodeURIComponent(
|
|
||||||
project.value.gallery[deleteIndex.value].url,
|
|
||||||
)}`,
|
|
||||||
{
|
|
||||||
method: 'DELETE',
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
await refreshProject()
|
|
||||||
} catch (err) {
|
|
||||||
addNotification({
|
|
||||||
title: 'An error occurred',
|
|
||||||
text: err.data ? err.data.description : err,
|
|
||||||
type: 'error',
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
stopLoading()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleKeydown = (e) => {
|
const handleKeydown = (e) => {
|
||||||
|
|||||||
@@ -2,8 +2,6 @@
|
|||||||
import {
|
import {
|
||||||
defineMessages,
|
defineMessages,
|
||||||
IconSelect,
|
IconSelect,
|
||||||
injectModrinthClient,
|
|
||||||
injectNotificationManager,
|
|
||||||
injectProjectPageContext,
|
injectProjectPageContext,
|
||||||
type MessageDescriptor,
|
type MessageDescriptor,
|
||||||
SettingsLabel,
|
SettingsLabel,
|
||||||
@@ -14,34 +12,21 @@ import {
|
|||||||
|
|
||||||
const { formatMessage } = useVIntl()
|
const { formatMessage } = useVIntl()
|
||||||
|
|
||||||
const { projectV2: project, refreshProject } = injectProjectPageContext()
|
const { projectV2: project, patchProject } = injectProjectPageContext()
|
||||||
const { handleError } = injectNotificationManager()
|
|
||||||
const client = injectModrinthClient()
|
|
||||||
|
|
||||||
const saving = ref(false)
|
const { saved, current, saving, reset, save } = useSavable(
|
||||||
|
|
||||||
const { saved, current, reset, save } = useSavable(
|
|
||||||
() => ({
|
() => ({
|
||||||
title: project.value.title,
|
title: project.value.title,
|
||||||
tagline: project.value.description,
|
tagline: project.value.description,
|
||||||
url: project.value.slug,
|
url: project.value.slug,
|
||||||
icon: project.value.icon_url,
|
icon: project.value.icon_url,
|
||||||
}),
|
}),
|
||||||
({ title, tagline, url }) => {
|
async ({ title, tagline, url }) => {
|
||||||
const data: Record<string, string> = {
|
await patchProject({
|
||||||
...(title !== undefined && { title }),
|
...(title !== undefined && { title }),
|
||||||
...(tagline !== undefined && { description: tagline }),
|
...(tagline !== undefined && { description: tagline }),
|
||||||
...(url !== undefined && { slug: url }),
|
...(url !== undefined && { slug: url }),
|
||||||
}
|
})
|
||||||
|
|
||||||
if (data) {
|
|
||||||
saving.value = true
|
|
||||||
client.labrinth.projects_v2
|
|
||||||
.edit(project.value.id, { title, description: tagline, slug: url })
|
|
||||||
.then(() => refreshProject().then(reset))
|
|
||||||
.catch(handleError)
|
|
||||||
.finally(() => (saving.value = false))
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
|
|
||||||
<div class="w-1/2">
|
<div class="w-1/2">
|
||||||
<DropdownSelect
|
<DropdownSelect
|
||||||
v-model="license"
|
v-model="current.license"
|
||||||
name="License selector"
|
name="License selector"
|
||||||
:options="builtinLicenses"
|
:options="builtinLicenses"
|
||||||
:display-name="(chosen: BuiltinLicense) => chosen.friendly"
|
:display-name="(chosen: BuiltinLicense) => chosen.friendly"
|
||||||
@@ -37,7 +37,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="license.requiresOnlyOrLater" class="adjacent-input">
|
<div v-if="current.license.requiresOnlyOrLater" class="adjacent-input">
|
||||||
<label for="or-later-checkbox">
|
<label for="or-later-checkbox">
|
||||||
<span class="label__title">Later editions</span>
|
<span class="label__title">Later editions</span>
|
||||||
<span class="label__description">
|
<span class="label__description">
|
||||||
@@ -48,7 +48,7 @@
|
|||||||
|
|
||||||
<Checkbox
|
<Checkbox
|
||||||
id="or-later-checkbox"
|
id="or-later-checkbox"
|
||||||
v-model="allowOrLater"
|
v-model="current.allowOrLater"
|
||||||
:disabled="!hasPermission"
|
:disabled="!hasPermission"
|
||||||
description="Allow later editions"
|
description="Allow later editions"
|
||||||
class="w-1/2"
|
class="w-1/2"
|
||||||
@@ -60,7 +60,7 @@
|
|||||||
<div class="adjacent-input">
|
<div class="adjacent-input">
|
||||||
<label for="license-url">
|
<label for="license-url">
|
||||||
<span class="label__title">License URL</span>
|
<span class="label__title">License URL</span>
|
||||||
<span v-if="license?.friendly !== 'Custom'" class="label__description">
|
<span v-if="current.license?.friendly !== 'Custom'" class="label__description">
|
||||||
The web location of the full license text. If you don't provide a link, the license text
|
The web location of the full license text. If you don't provide a link, the license text
|
||||||
will be displayed instead.
|
will be displayed instead.
|
||||||
</span>
|
</span>
|
||||||
@@ -73,18 +73,20 @@
|
|||||||
<div class="w-1/2">
|
<div class="w-1/2">
|
||||||
<input
|
<input
|
||||||
id="license-url"
|
id="license-url"
|
||||||
v-model="licenseUrl"
|
v-model="current.licenseUrl"
|
||||||
type="url"
|
type="url"
|
||||||
maxlength="2048"
|
maxlength="2048"
|
||||||
:placeholder="license?.friendly !== 'Custom' ? `License URL (optional)` : `License URL`"
|
:placeholder="
|
||||||
|
current.license?.friendly !== 'Custom' ? `License URL (optional)` : `License URL`
|
||||||
|
"
|
||||||
:disabled="!hasPermission || licenseId === 'LicenseRef-Unknown'"
|
:disabled="!hasPermission || licenseId === 'LicenseRef-Unknown'"
|
||||||
class="w-full"
|
class="w-full"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="license?.friendly === 'Custom'" class="adjacent-input">
|
<div v-if="current.license?.friendly === 'Custom'" class="adjacent-input">
|
||||||
<label v-if="!nonSpdxLicense" for="license-spdx">
|
<label v-if="!current.nonSpdxLicense" for="license-spdx">
|
||||||
<span class="label__title">SPDX identifier</span>
|
<span class="label__title">SPDX identifier</span>
|
||||||
<span class="label__description">
|
<span class="label__description">
|
||||||
If your license does not have an offical
|
If your license does not have an offical
|
||||||
@@ -93,7 +95,7 @@
|
|||||||
>, check the box and enter the name of the license instead.
|
>, check the box and enter the name of the license instead.
|
||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
<label v-else for="license-name">
|
<label v-if="current.nonSpdxLicense" for="license-name">
|
||||||
<span class="label__title">License name</span>
|
<span class="label__title">License name</span>
|
||||||
<span class="label__description"
|
<span class="label__description"
|
||||||
>The full name of the license. If the license has a SPDX identifier, please uncheck the
|
>The full name of the license. If the license has a SPDX identifier, please uncheck the
|
||||||
@@ -103,9 +105,9 @@
|
|||||||
|
|
||||||
<div class="input-stack w-1/2">
|
<div class="input-stack w-1/2">
|
||||||
<input
|
<input
|
||||||
v-if="!nonSpdxLicense"
|
v-if="!current.nonSpdxLicense"
|
||||||
id="license-spdx"
|
id="license-spdx"
|
||||||
v-model="license.short"
|
v-model="current.license.short"
|
||||||
class="w-full"
|
class="w-full"
|
||||||
type="text"
|
type="text"
|
||||||
maxlength="128"
|
maxlength="128"
|
||||||
@@ -115,7 +117,7 @@
|
|||||||
<input
|
<input
|
||||||
v-else
|
v-else
|
||||||
id="license-name"
|
id="license-name"
|
||||||
v-model="license.short"
|
v-model="current.license.short"
|
||||||
class="w-full"
|
class="w-full"
|
||||||
type="text"
|
type="text"
|
||||||
maxlength="128"
|
maxlength="128"
|
||||||
@@ -124,8 +126,8 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<Checkbox
|
<Checkbox
|
||||||
v-if="license?.friendly === 'Custom'"
|
v-if="current.license?.friendly === 'Custom'"
|
||||||
v-model="nonSpdxLicense"
|
v-model="current.nonSpdxLicense"
|
||||||
:disabled="!hasPermission"
|
:disabled="!hasPermission"
|
||||||
description="License does not have a SPDX identifier"
|
description="License does not have a SPDX identifier"
|
||||||
>
|
>
|
||||||
@@ -133,74 +135,91 @@
|
|||||||
</Checkbox>
|
</Checkbox>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="input-stack">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="iconified-button brand-button"
|
|
||||||
:disabled="
|
|
||||||
!hasChanges ||
|
|
||||||
!hasPermission ||
|
|
||||||
(license.friendly === 'Custom' && (license.short === '' || licenseUrl === ''))
|
|
||||||
"
|
|
||||||
@click="saveChanges()"
|
|
||||||
>
|
|
||||||
<SaveIcon />
|
|
||||||
Save changes
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</section>
|
</section>
|
||||||
|
<UnsavedChangesPopup
|
||||||
|
:original="saved"
|
||||||
|
:modified="current"
|
||||||
|
:saving="saving"
|
||||||
|
:can-save="
|
||||||
|
hasPermission &&
|
||||||
|
!(
|
||||||
|
current.license.friendly === 'Custom' &&
|
||||||
|
(current.license.short === '' || current.licenseUrl === '')
|
||||||
|
)
|
||||||
|
"
|
||||||
|
@reset="reset"
|
||||||
|
@save="save"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { SaveIcon } from '@modrinth/assets'
|
import {
|
||||||
import { Checkbox, DropdownSelect, injectProjectPageContext } from '@modrinth/ui'
|
Checkbox,
|
||||||
|
DropdownSelect,
|
||||||
|
injectProjectPageContext,
|
||||||
|
UnsavedChangesPopup,
|
||||||
|
useSavable,
|
||||||
|
} from '@modrinth/ui'
|
||||||
import {
|
import {
|
||||||
type BuiltinLicense,
|
type BuiltinLicense,
|
||||||
builtinLicenses,
|
builtinLicenses,
|
||||||
formatProjectType,
|
formatProjectType,
|
||||||
TeamMemberPermission,
|
TeamMemberPermission,
|
||||||
} from '@modrinth/utils'
|
} from '@modrinth/utils'
|
||||||
import { computed, type Ref, ref } from 'vue'
|
import { computed } from 'vue'
|
||||||
|
|
||||||
const { projectV2: project, currentMember, patchProject } = injectProjectPageContext()
|
const { projectV2: project, currentMember, patchProject } = injectProjectPageContext()
|
||||||
|
|
||||||
const licenseUrl = ref(project.value.license.url)
|
function getInitialLicense() {
|
||||||
const license: Ref<{
|
const oldLicenseId = project.value.license.id
|
||||||
friendly: string
|
const trimmedLicenseId = oldLicenseId
|
||||||
short: string
|
.replaceAll('-only', '')
|
||||||
requiresOnlyOrLater?: boolean
|
.replaceAll('-or-later', '')
|
||||||
}> = ref({
|
.replaceAll('LicenseRef-', '')
|
||||||
friendly: '',
|
|
||||||
short: '',
|
|
||||||
requiresOnlyOrLater: false,
|
|
||||||
})
|
|
||||||
|
|
||||||
const allowOrLater = ref(project.value.license.id.includes('-or-later'))
|
if (oldLicenseId === 'LicenseRef-Unknown') {
|
||||||
const nonSpdxLicense = ref(project.value.license.id.includes('LicenseRef-'))
|
return {
|
||||||
|
friendly: '',
|
||||||
const oldLicenseId = project.value.license.id
|
short: oldLicenseId.replaceAll('LicenseRef-', ''),
|
||||||
const trimmedLicenseId = oldLicenseId
|
requiresOnlyOrLater: false,
|
||||||
.replaceAll('-only', '')
|
}
|
||||||
.replaceAll('-or-later', '')
|
|
||||||
.replaceAll('LicenseRef-', '')
|
|
||||||
|
|
||||||
license.value = builtinLicenses.find((x) => x.short === trimmedLicenseId) ?? {
|
|
||||||
friendly: 'Custom',
|
|
||||||
short: oldLicenseId.replaceAll('LicenseRef-', ''),
|
|
||||||
requiresOnlyOrLater: oldLicenseId.includes('-or-later'),
|
|
||||||
}
|
|
||||||
|
|
||||||
if (oldLicenseId === 'LicenseRef-Unknown') {
|
|
||||||
// Mark it as not having a license, forcing the user to select one
|
|
||||||
license.value = {
|
|
||||||
friendly: '',
|
|
||||||
short: oldLicenseId.replaceAll('LicenseRef-', ''),
|
|
||||||
requiresOnlyOrLater: false,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
builtinLicenses.find((x) => x.short === trimmedLicenseId) ?? {
|
||||||
|
friendly: 'Custom',
|
||||||
|
short: oldLicenseId.replaceAll('LicenseRef-', ''),
|
||||||
|
requiresOnlyOrLater: oldLicenseId.includes('-or-later'),
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { saved, current, saving, reset, save } = useSavable(
|
||||||
|
() => ({
|
||||||
|
license: getInitialLicense(),
|
||||||
|
licenseUrl: project.value.license.url ?? '',
|
||||||
|
allowOrLater: project.value.license.id.includes('-or-later'),
|
||||||
|
nonSpdxLicense: project.value.license.id.includes('LicenseRef-'),
|
||||||
|
}),
|
||||||
|
async () => {
|
||||||
|
const payload: {
|
||||||
|
license_id?: string
|
||||||
|
license_url?: string | null
|
||||||
|
} = {}
|
||||||
|
|
||||||
|
if (licenseId.value !== project.value.license.id) {
|
||||||
|
payload.license_id = licenseId.value
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current.value.licenseUrl !== project.value.license.url) {
|
||||||
|
payload.license_url = current.value.licenseUrl ? current.value.licenseUrl : null
|
||||||
|
}
|
||||||
|
|
||||||
|
await patchProject(payload)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
const hasPermission = computed(() => {
|
const hasPermission = computed(() => {
|
||||||
return (currentMember.value?.permissions ?? 0) & TeamMemberPermission.EDIT_DETAILS
|
return (currentMember.value?.permissions ?? 0) & TeamMemberPermission.EDIT_DETAILS
|
||||||
})
|
})
|
||||||
@@ -209,47 +228,22 @@ const licenseId = computed(() => {
|
|||||||
let id = ''
|
let id = ''
|
||||||
|
|
||||||
if (
|
if (
|
||||||
(nonSpdxLicense.value && license.value.friendly === 'Custom') ||
|
(current.value.nonSpdxLicense && current.value.license.friendly === 'Custom') ||
|
||||||
license.value.short === 'All-Rights-Reserved' ||
|
current.value.license.short === 'All-Rights-Reserved' ||
|
||||||
license.value.short === 'Unknown'
|
current.value.license.short === 'Unknown'
|
||||||
) {
|
) {
|
||||||
id += 'LicenseRef-'
|
id += 'LicenseRef-'
|
||||||
}
|
}
|
||||||
|
|
||||||
id += license.value.short
|
id += current.value.license.short
|
||||||
if (license.value.requiresOnlyOrLater) {
|
if (current.value.license.requiresOnlyOrLater) {
|
||||||
id += allowOrLater.value ? '-or-later' : '-only'
|
id += current.value.allowOrLater ? '-or-later' : '-only'
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nonSpdxLicense.value && license.value.friendly === 'Custom') {
|
if (current.value.nonSpdxLicense && current.value.license.friendly === 'Custom') {
|
||||||
id = id.replaceAll(' ', '-')
|
id = id.replaceAll(' ', '-')
|
||||||
}
|
}
|
||||||
|
|
||||||
return id
|
return id
|
||||||
})
|
})
|
||||||
|
|
||||||
const patchRequestPayload = computed(() => {
|
|
||||||
const payload: {
|
|
||||||
license_id?: string
|
|
||||||
license_url?: string | null // null = remove url
|
|
||||||
} = {}
|
|
||||||
|
|
||||||
if (licenseId.value !== project.value.license.id) {
|
|
||||||
payload.license_id = licenseId.value
|
|
||||||
}
|
|
||||||
|
|
||||||
if (licenseUrl.value !== project.value.license.url) {
|
|
||||||
payload.license_url = licenseUrl.value ? licenseUrl.value : null
|
|
||||||
}
|
|
||||||
|
|
||||||
return payload
|
|
||||||
})
|
|
||||||
|
|
||||||
const hasChanges = computed(() => {
|
|
||||||
return Object.keys(patchRequestPayload.value).length > 0
|
|
||||||
})
|
|
||||||
|
|
||||||
function saveChanges() {
|
|
||||||
patchProject(patchRequestPayload.value)
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -65,7 +65,7 @@
|
|||||||
<Checkbox
|
<Checkbox
|
||||||
v-for="category in categoryLists[header]"
|
v-for="category in categoryLists[header]"
|
||||||
:key="`category-${header}-${category.name}`"
|
:key="`category-${header}-${category.name}`"
|
||||||
:model-value="selectedTags.includes(category)"
|
:model-value="current.selectedTags.includes(category)"
|
||||||
:description="formatCategory(category.name)"
|
:description="formatCategory(category.name)"
|
||||||
class="category-selector"
|
class="category-selector"
|
||||||
@update:model-value="toggleCategory(category)"
|
@update:model-value="toggleCategory(category)"
|
||||||
@@ -91,17 +91,17 @@
|
|||||||
featured if you do not select all 3.
|
featured if you do not select all 3.
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<p v-if="selectedTags.length < 1">
|
<p v-if="current.selectedTags.length < 1">
|
||||||
Select at least one category in order to feature a category.
|
Select at least one category in order to feature a category.
|
||||||
</p>
|
</p>
|
||||||
<div class="category-list input-div">
|
<div class="category-list input-div">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
v-for="category in selectedTags"
|
v-for="category in current.selectedTags"
|
||||||
:key="`featured-category-${category.name}`"
|
:key="`featured-category-${category.name}`"
|
||||||
class="category-selector"
|
class="category-selector"
|
||||||
:model-value="featuredTags.includes(category)"
|
:model-value="current.featuredTags.includes(category)"
|
||||||
:description="formatCategory(category.name)"
|
:description="formatCategory(category.name)"
|
||||||
:disabled="featuredTags.length >= 3 && !featuredTags.includes(category)"
|
:disabled="current.featuredTags.length >= 3 && !current.featuredTags.includes(category)"
|
||||||
@update:model-value="toggleFeaturedCategory(category)"
|
@update:model-value="toggleFeaturedCategory(category)"
|
||||||
>
|
>
|
||||||
<div class="category-selector__label">
|
<div class="category-selector__label">
|
||||||
@@ -116,32 +116,27 @@
|
|||||||
</Checkbox>
|
</Checkbox>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<div class="button-group">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="iconified-button brand-button"
|
|
||||||
:disabled="!hasChanges"
|
|
||||||
@click="saveChanges()"
|
|
||||||
>
|
|
||||||
<SaveIcon />
|
|
||||||
Save changes
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</section>
|
</section>
|
||||||
|
<UnsavedChangesPopup
|
||||||
|
:original="saved"
|
||||||
|
:modified="current"
|
||||||
|
:saving="saving"
|
||||||
|
@reset="reset"
|
||||||
|
@save="save"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { SaveIcon, StarIcon, TriangleAlertIcon } from '@modrinth/assets'
|
import { StarIcon, TriangleAlertIcon } from '@modrinth/assets'
|
||||||
import { Checkbox, injectProjectPageContext } from '@modrinth/ui'
|
import { Checkbox, injectProjectPageContext, UnsavedChangesPopup, useSavable } from '@modrinth/ui'
|
||||||
import {
|
import {
|
||||||
formatCategory,
|
formatCategory,
|
||||||
formatCategoryHeader,
|
formatCategoryHeader,
|
||||||
formatProjectType,
|
formatProjectType,
|
||||||
sortedCategories,
|
sortedCategories,
|
||||||
} from '@modrinth/utils'
|
} from '@modrinth/utils'
|
||||||
import { computed, ref } from 'vue'
|
import { computed } from 'vue'
|
||||||
|
|
||||||
interface Category {
|
interface Category {
|
||||||
name: string
|
name: string
|
||||||
@@ -154,21 +149,56 @@ const tags = useGeneratedState()
|
|||||||
|
|
||||||
const { projectV2: project, patchProject } = injectProjectPageContext()
|
const { projectV2: project, patchProject } = injectProjectPageContext()
|
||||||
|
|
||||||
const selectedTags = ref<Category[]>(
|
const { saved, current, saving, reset, save } = useSavable(
|
||||||
sortedCategories(tags.value).filter(
|
() => ({
|
||||||
(x: Category) =>
|
selectedTags: sortedCategories(tags.value).filter(
|
||||||
x.project_type === project.value.actualProjectType &&
|
(x: Category) =>
|
||||||
(project.value.categories.includes(x.name) ||
|
x.project_type === project.value.actualProjectType &&
|
||||||
project.value.additional_categories.includes(x.name)),
|
(project.value.categories.includes(x.name) ||
|
||||||
),
|
project.value.additional_categories.includes(x.name)),
|
||||||
)
|
) as Category[],
|
||||||
|
featuredTags: sortedCategories(tags.value).filter(
|
||||||
|
(x: Category) =>
|
||||||
|
x.project_type === project.value.actualProjectType &&
|
||||||
|
project.value.categories.includes(x.name),
|
||||||
|
) as Category[],
|
||||||
|
}),
|
||||||
|
async () => {
|
||||||
|
// Promote selected categories to featured if there are less than 3 featured
|
||||||
|
const newFeaturedTags = current.value.featuredTags.slice()
|
||||||
|
if (newFeaturedTags.length < 1 && current.value.selectedTags.length > newFeaturedTags.length) {
|
||||||
|
const nonFeaturedCategories = current.value.selectedTags.filter(
|
||||||
|
(x) => !newFeaturedTags.includes(x),
|
||||||
|
)
|
||||||
|
nonFeaturedCategories
|
||||||
|
.slice(0, Math.min(nonFeaturedCategories.length, 3 - newFeaturedTags.length))
|
||||||
|
.forEach((x) => newFeaturedTags.push(x))
|
||||||
|
}
|
||||||
|
|
||||||
const featuredTags = ref<Category[]>(
|
// Convert selected and featured categories to backend-usable arrays
|
||||||
sortedCategories(tags.value).filter(
|
const categories = newFeaturedTags.map((x) => x.name)
|
||||||
(x: Category) =>
|
const additionalCategories = current.value.selectedTags
|
||||||
x.project_type === project.value.actualProjectType &&
|
.filter((x) => !newFeaturedTags.includes(x))
|
||||||
project.value.categories.includes(x.name),
|
.map((x) => x.name)
|
||||||
),
|
|
||||||
|
const data: Record<string, string[]> = {}
|
||||||
|
|
||||||
|
if (
|
||||||
|
categories.length !== project.value.categories.length ||
|
||||||
|
categories.some((value) => !project.value.categories.includes(value))
|
||||||
|
) {
|
||||||
|
data.categories = categories
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
additionalCategories.length !== project.value.additional_categories.length ||
|
||||||
|
additionalCategories.some((value) => !project.value.additional_categories.includes(value))
|
||||||
|
) {
|
||||||
|
data.additional_categories = additionalCategories
|
||||||
|
}
|
||||||
|
|
||||||
|
await patchProject(data)
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
const categoryLists = computed(() => {
|
const categoryLists = computed(() => {
|
||||||
@@ -186,7 +216,7 @@ const categoryLists = computed(() => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const tooManyTagsWarning = computed(() => {
|
const tooManyTagsWarning = computed(() => {
|
||||||
const tagCount = selectedTags.value.length
|
const tagCount = current.value.selectedTags.length
|
||||||
if (tagCount > 8) {
|
if (tagCount > 8) {
|
||||||
return `You've selected ${tagCount} tags. Consider reducing to 8 or fewer to keep your project focused and easier to discover.`
|
return `You've selected ${tagCount} tags. Consider reducing to 8 or fewer to keep your project focused and easier to discover.`
|
||||||
}
|
}
|
||||||
@@ -196,7 +226,7 @@ const tooManyTagsWarning = computed(() => {
|
|||||||
const multipleResolutionTagsWarning = computed(() => {
|
const multipleResolutionTagsWarning = computed(() => {
|
||||||
if (project.value.actualProjectType !== 'resourcepack') return null
|
if (project.value.actualProjectType !== 'resourcepack') return null
|
||||||
|
|
||||||
const resolutionTags = selectedTags.value.filter((tag) =>
|
const resolutionTags = current.value.selectedTags.filter((tag) =>
|
||||||
['8x-', '16x', '32x', '48x', '64x', '128x', '256x', '512x+'].includes(tag.name),
|
['8x-', '16x', '32x', '48x', '64x', '128x', '256x', '512x+'].includes(tag.name),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -217,7 +247,7 @@ const allTagsSelectedWarning = computed(() => {
|
|||||||
const categoriesForProjectType = sortedCategories(tags.value).filter(
|
const categoriesForProjectType = sortedCategories(tags.value).filter(
|
||||||
(x: Category) => x.project_type === project.value.actualProjectType,
|
(x: Category) => x.project_type === project.value.actualProjectType,
|
||||||
)
|
)
|
||||||
const totalSelectedTags = selectedTags.value.length
|
const totalSelectedTags = current.value.selectedTags.length
|
||||||
|
|
||||||
if (
|
if (
|
||||||
totalSelectedTags === categoriesForProjectType.length &&
|
totalSelectedTags === categoriesForProjectType.length &&
|
||||||
@@ -228,68 +258,22 @@ const allTagsSelectedWarning = computed(() => {
|
|||||||
return null
|
return null
|
||||||
})
|
})
|
||||||
|
|
||||||
const patchData = computed(() => {
|
|
||||||
const data: Record<string, string[]> = {}
|
|
||||||
|
|
||||||
// Promote selected categories to featured if there are less than 3 featured
|
|
||||||
const newFeaturedTags = featuredTags.value.slice()
|
|
||||||
if (newFeaturedTags.length < 1 && selectedTags.value.length > newFeaturedTags.length) {
|
|
||||||
const nonFeaturedCategories = selectedTags.value.filter((x) => !newFeaturedTags.includes(x))
|
|
||||||
|
|
||||||
nonFeaturedCategories
|
|
||||||
.slice(0, Math.min(nonFeaturedCategories.length, 3 - newFeaturedTags.length))
|
|
||||||
.forEach((x) => newFeaturedTags.push(x))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert selected and featured categories to backend-usable arrays
|
|
||||||
const categories = newFeaturedTags.map((x) => x.name)
|
|
||||||
const additionalCategories = selectedTags.value
|
|
||||||
.filter((x) => !newFeaturedTags.includes(x))
|
|
||||||
.map((x) => x.name)
|
|
||||||
|
|
||||||
if (
|
|
||||||
categories.length !== project.value.categories.length ||
|
|
||||||
categories.some((value) => !project.value.categories.includes(value))
|
|
||||||
) {
|
|
||||||
data.categories = categories
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
additionalCategories.length !== project.value.additional_categories.length ||
|
|
||||||
additionalCategories.some((value) => !project.value.additional_categories.includes(value))
|
|
||||||
) {
|
|
||||||
data.additional_categories = additionalCategories
|
|
||||||
}
|
|
||||||
|
|
||||||
return data
|
|
||||||
})
|
|
||||||
|
|
||||||
const hasChanges = computed(() => {
|
|
||||||
return Object.keys(patchData.value).length > 0
|
|
||||||
})
|
|
||||||
|
|
||||||
const toggleCategory = (category: Category) => {
|
const toggleCategory = (category: Category) => {
|
||||||
if (selectedTags.value.includes(category)) {
|
if (current.value.selectedTags.includes(category)) {
|
||||||
selectedTags.value = selectedTags.value.filter((x) => x !== category)
|
current.value.selectedTags = current.value.selectedTags.filter((x) => x !== category)
|
||||||
if (featuredTags.value.includes(category)) {
|
if (current.value.featuredTags.includes(category)) {
|
||||||
featuredTags.value = featuredTags.value.filter((x) => x !== category)
|
current.value.featuredTags = current.value.featuredTags.filter((x) => x !== category)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
selectedTags.value.push(category)
|
current.value.selectedTags = [...current.value.selectedTags, category]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const toggleFeaturedCategory = (category: Category) => {
|
const toggleFeaturedCategory = (category: Category) => {
|
||||||
if (featuredTags.value.includes(category)) {
|
if (current.value.featuredTags.includes(category)) {
|
||||||
featuredTags.value = featuredTags.value.filter((x) => x !== category)
|
current.value.featuredTags = current.value.featuredTags.filter((x) => x !== category)
|
||||||
} else {
|
} else {
|
||||||
featuredTags.value.push(category)
|
current.value.featuredTags = [...current.value.featuredTags, category]
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const saveChanges = () => {
|
|
||||||
if (hasChanges.value) {
|
|
||||||
patchProject(patchData.value)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,6 +1,14 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { SaveIcon, TrashIcon, UploadIcon } from '@modrinth/assets'
|
import { TrashIcon, UploadIcon } from '@modrinth/assets'
|
||||||
import { Avatar, Button, ConfirmModal, FileInput, injectNotificationManager } from '@modrinth/ui'
|
import {
|
||||||
|
Avatar,
|
||||||
|
Button,
|
||||||
|
ConfirmModal,
|
||||||
|
FileInput,
|
||||||
|
injectNotificationManager,
|
||||||
|
UnsavedChangesPopup,
|
||||||
|
useSavable,
|
||||||
|
} from '@modrinth/ui'
|
||||||
|
|
||||||
import { injectOrganizationContext } from '~/providers/organization-context.ts'
|
import { injectOrganizationContext } from '~/providers/organization-context.ts'
|
||||||
|
|
||||||
@@ -14,32 +22,49 @@ const {
|
|||||||
patchOrganization,
|
patchOrganization,
|
||||||
} = injectOrganizationContext()
|
} = injectOrganizationContext()
|
||||||
|
|
||||||
|
// Icon state (separate from useSavable, like collection page)
|
||||||
const icon = ref(null)
|
const icon = ref(null)
|
||||||
const deletedIcon = ref(false)
|
const deletedIcon = ref(false)
|
||||||
const previewImage = ref(null)
|
const previewImage = ref(null)
|
||||||
|
|
||||||
const name = ref(organization.value.name)
|
const {
|
||||||
const slug = ref(organization.value.slug)
|
saved,
|
||||||
|
current,
|
||||||
|
saving,
|
||||||
|
hasChanges: hasFieldChanges,
|
||||||
|
reset: resetFields,
|
||||||
|
} = useSavable(
|
||||||
|
() => ({
|
||||||
|
name: organization.value.name,
|
||||||
|
slug: organization.value.slug,
|
||||||
|
summary: organization.value.description,
|
||||||
|
}),
|
||||||
|
async ({ name, slug, summary }) => {
|
||||||
|
await patchOrganization({
|
||||||
|
...(name !== undefined && { name }),
|
||||||
|
...(slug !== undefined && { slug }),
|
||||||
|
...(summary !== undefined && { description: summary }),
|
||||||
|
})
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
const summary = ref(organization.value.description)
|
// Combined state for UnsavedChangesPopup
|
||||||
|
const originalState = computed(() => ({
|
||||||
|
...saved.value,
|
||||||
|
iconChanged: false,
|
||||||
|
}))
|
||||||
|
|
||||||
const patchData = computed(() => {
|
const modifiedState = computed(() => ({
|
||||||
const data = {}
|
...current.value,
|
||||||
if (name.value !== organization.value.name) {
|
iconChanged: !!(deletedIcon.value || icon.value),
|
||||||
data.name = name.value
|
}))
|
||||||
}
|
|
||||||
if (slug.value !== organization.value.slug) {
|
|
||||||
data.slug = slug.value
|
|
||||||
}
|
|
||||||
if (summary.value !== organization.value.description) {
|
|
||||||
data.description = summary.value
|
|
||||||
}
|
|
||||||
return data
|
|
||||||
})
|
|
||||||
|
|
||||||
const hasChanges = computed(() => {
|
const reset = () => {
|
||||||
return Object.keys(patchData.value).length > 0 || deletedIcon.value || icon.value
|
resetFields()
|
||||||
})
|
icon.value = null
|
||||||
|
deletedIcon.value = false
|
||||||
|
previewImage.value = null
|
||||||
|
}
|
||||||
|
|
||||||
const markIconForDeletion = () => {
|
const markIconForDeletion = () => {
|
||||||
deletedIcon.value = true
|
deletedIcon.value = true
|
||||||
@@ -61,11 +86,16 @@ const showPreviewImage = (files) => {
|
|||||||
|
|
||||||
const orgId = useRouteId()
|
const orgId = useRouteId()
|
||||||
|
|
||||||
const onSaveChanges = useClientTry(async () => {
|
const save = async () => {
|
||||||
// Only PATCH organization details if there are actual field changes
|
// Save field changes via useSavable
|
||||||
const hasOrgFieldChanges = Object.keys(patchData.value).length > 0
|
if (hasFieldChanges.value) {
|
||||||
if (hasOrgFieldChanges) {
|
await patchOrganization({
|
||||||
await patchOrganization(patchData.value)
|
...(current.value.name !== organization.value.name && { name: current.value.name }),
|
||||||
|
...(current.value.slug !== organization.value.slug && { slug: current.value.slug }),
|
||||||
|
...(current.value.summary !== organization.value.description && {
|
||||||
|
description: current.value.summary,
|
||||||
|
}),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle icon deletion / upload separately
|
// Handle icon deletion / upload separately
|
||||||
@@ -85,7 +115,7 @@ const onSaveChanges = useClientTry(async () => {
|
|||||||
text: 'Your organization has been updated.',
|
text: 'Your organization has been updated.',
|
||||||
type: 'success',
|
type: 'success',
|
||||||
})
|
})
|
||||||
})
|
}
|
||||||
|
|
||||||
const onDeleteOrganization = useClientTry(async () => {
|
const onDeleteOrganization = useClientTry(async () => {
|
||||||
await useBaseFetch(`organization/${orgId}`, {
|
await useBaseFetch(`organization/${orgId}`, {
|
||||||
@@ -159,7 +189,7 @@ const onDeleteOrganization = useClientTry(async () => {
|
|||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
id="project-name"
|
id="project-name"
|
||||||
v-model="name"
|
v-model="current.name"
|
||||||
maxlength="2048"
|
maxlength="2048"
|
||||||
type="text"
|
type="text"
|
||||||
:disabled="!hasPermission"
|
:disabled="!hasPermission"
|
||||||
@@ -172,7 +202,7 @@ const onDeleteOrganization = useClientTry(async () => {
|
|||||||
<div class="text-input-wrapper__before">https://modrinth.com/organization/</div>
|
<div class="text-input-wrapper__before">https://modrinth.com/organization/</div>
|
||||||
<input
|
<input
|
||||||
id="project-slug"
|
id="project-slug"
|
||||||
v-model="slug"
|
v-model="current.slug"
|
||||||
type="text"
|
type="text"
|
||||||
maxlength="64"
|
maxlength="64"
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
@@ -186,17 +216,11 @@ const onDeleteOrganization = useClientTry(async () => {
|
|||||||
<div class="textarea-wrapper summary-input">
|
<div class="textarea-wrapper summary-input">
|
||||||
<textarea
|
<textarea
|
||||||
id="project-summary"
|
id="project-summary"
|
||||||
v-model="summary"
|
v-model="current.summary"
|
||||||
maxlength="256"
|
maxlength="256"
|
||||||
:disabled="!hasPermission"
|
:disabled="!hasPermission"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="button-group">
|
|
||||||
<Button color="primary" :disabled="!hasChanges" @click="onSaveChanges">
|
|
||||||
<SaveIcon />
|
|
||||||
Save changes
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="universal-card">
|
<div class="universal-card">
|
||||||
<div class="label">
|
<div class="label">
|
||||||
@@ -213,6 +237,13 @@ const onDeleteOrganization = useClientTry(async () => {
|
|||||||
Delete organization
|
Delete organization
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
<UnsavedChangesPopup
|
||||||
|
:original="originalState"
|
||||||
|
:modified="modifiedState"
|
||||||
|
:saving="saving"
|
||||||
|
@reset="reset"
|
||||||
|
@save="save"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -56,41 +56,32 @@
|
|||||||
{{ formatMessage(messages.usernameDescription) }}
|
{{ formatMessage(messages.usernameDescription) }}
|
||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
<input id="username-field" v-model="username" type="text" />
|
<input id="username-field" v-model="current.username" type="text" />
|
||||||
<label for="bio-field">
|
<label for="bio-field">
|
||||||
<span class="label__title">{{ formatMessage(messages.bioTitle) }}</span>
|
<span class="label__title">{{ formatMessage(messages.bioTitle) }}</span>
|
||||||
<span class="label__description">
|
<span class="label__description">
|
||||||
{{ formatMessage(messages.bioDescription) }}
|
{{ formatMessage(messages.bioDescription) }}
|
||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
<textarea id="bio-field" v-model="bio" type="text" />
|
<textarea id="bio-field" v-model="current.bio" type="text" />
|
||||||
<div v-if="hasUnsavedChanges" class="input-group">
|
<div class="input-group">
|
||||||
<Button color="primary" :action="() => saveChanges()">
|
|
||||||
<SaveIcon /> {{ formatMessage(commonMessages.saveChangesButton) }}
|
|
||||||
</Button>
|
|
||||||
<Button :action="() => cancel()">
|
|
||||||
<XIcon /> {{ formatMessage(commonMessages.cancelButton) }}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
<div v-else class="input-group">
|
|
||||||
<Button disabled color="primary" :action="() => saveChanges()">
|
|
||||||
<SaveIcon />
|
|
||||||
{{
|
|
||||||
saved
|
|
||||||
? formatMessage(commonMessages.changesSavedLabel)
|
|
||||||
: formatMessage(commonMessages.saveChangesButton)
|
|
||||||
}}
|
|
||||||
</Button>
|
|
||||||
<Button :link="`/user/${auth.user.username}`">
|
<Button :link="`/user/${auth.user.username}`">
|
||||||
<UserIcon /> {{ formatMessage(commonMessages.visitYourProfile) }}
|
<UserIcon /> {{ formatMessage(commonMessages.visitYourProfile) }}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
<UnsavedChangesPopup
|
||||||
|
:original="originalState"
|
||||||
|
:modified="modifiedState"
|
||||||
|
:saving="saving"
|
||||||
|
@reset="reset"
|
||||||
|
@save="save"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { SaveIcon, TrashIcon, UndoIcon, UploadIcon, UserIcon, XIcon } from '@modrinth/assets'
|
import { TrashIcon, UndoIcon, UploadIcon, UserIcon } from '@modrinth/assets'
|
||||||
import {
|
import {
|
||||||
Avatar,
|
Avatar,
|
||||||
Button,
|
Button,
|
||||||
@@ -99,6 +90,8 @@ import {
|
|||||||
FileInput,
|
FileInput,
|
||||||
injectNotificationManager,
|
injectNotificationManager,
|
||||||
IntlFormatted,
|
IntlFormatted,
|
||||||
|
UnsavedChangesPopup,
|
||||||
|
useSavable,
|
||||||
useVIntl,
|
useVIntl,
|
||||||
} from '@modrinth/ui'
|
} from '@modrinth/ui'
|
||||||
|
|
||||||
@@ -151,21 +144,43 @@ const messages = defineMessages({
|
|||||||
|
|
||||||
const auth = await useAuth()
|
const auth = await useAuth()
|
||||||
|
|
||||||
const username = ref(auth.value.user.username)
|
// Avatar state (separate from useSavable)
|
||||||
const bio = ref(auth.value.user.bio)
|
|
||||||
const avatarUrl = ref(auth.value.user.avatar_url)
|
const avatarUrl = ref(auth.value.user.avatar_url)
|
||||||
const icon = shallowRef(null)
|
const icon = shallowRef(null)
|
||||||
const previewImage = shallowRef(null)
|
const previewImage = shallowRef(null)
|
||||||
const pendingAvatarDeletion = ref(false)
|
const pendingAvatarDeletion = ref(false)
|
||||||
const saved = ref(false)
|
const saving = ref(false)
|
||||||
|
|
||||||
const hasUnsavedChanges = computed(
|
const {
|
||||||
() =>
|
saved,
|
||||||
username.value !== auth.value.user.username ||
|
current,
|
||||||
bio.value !== auth.value.user.bio ||
|
reset: resetFields,
|
||||||
previewImage.value,
|
} = useSavable(
|
||||||
|
() => ({
|
||||||
|
username: auth.value.user.username,
|
||||||
|
bio: auth.value.user.bio ?? '',
|
||||||
|
}),
|
||||||
|
async () => {}, // Save is handled manually due to complex icon logic
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Combined state for UnsavedChangesPopup
|
||||||
|
const originalState = computed(() => ({
|
||||||
|
...saved.value,
|
||||||
|
avatarChanged: false,
|
||||||
|
}))
|
||||||
|
|
||||||
|
const modifiedState = computed(() => ({
|
||||||
|
...current.value,
|
||||||
|
avatarChanged: !!(previewImage.value || pendingAvatarDeletion.value),
|
||||||
|
}))
|
||||||
|
|
||||||
|
const reset = () => {
|
||||||
|
resetFields()
|
||||||
|
icon.value = null
|
||||||
|
previewImage.value = null
|
||||||
|
pendingAvatarDeletion.value = false
|
||||||
|
}
|
||||||
|
|
||||||
function showPreviewImage(files) {
|
function showPreviewImage(files) {
|
||||||
const reader = new FileReader()
|
const reader = new FileReader()
|
||||||
icon.value = files[0]
|
icon.value = files[0]
|
||||||
@@ -180,16 +195,8 @@ function removePreviewImage() {
|
|||||||
previewImage.value = 'https://cdn.modrinth.com/placeholder.png'
|
previewImage.value = 'https://cdn.modrinth.com/placeholder.png'
|
||||||
}
|
}
|
||||||
|
|
||||||
function cancel() {
|
async function save() {
|
||||||
icon.value = null
|
saving.value = true
|
||||||
previewImage.value = null
|
|
||||||
pendingAvatarDeletion.value = false
|
|
||||||
username.value = auth.value.user.username
|
|
||||||
bio.value = auth.value.user.bio
|
|
||||||
}
|
|
||||||
|
|
||||||
async function saveChanges() {
|
|
||||||
startLoading()
|
|
||||||
try {
|
try {
|
||||||
if (pendingAvatarDeletion.value) {
|
if (pendingAvatarDeletion.value) {
|
||||||
await useBaseFetch(`user/${auth.value.user.id}/icon`, {
|
await useBaseFetch(`user/${auth.value.user.id}/icon`, {
|
||||||
@@ -215,12 +222,12 @@ async function saveChanges() {
|
|||||||
|
|
||||||
const body = {}
|
const body = {}
|
||||||
|
|
||||||
if (auth.value.user.username !== username.value) {
|
if (auth.value.user.username !== current.value.username) {
|
||||||
body.username = username.value
|
body.username = current.value.username
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auth.value.user.bio !== bio.value) {
|
if (auth.value.user.bio !== current.value.bio) {
|
||||||
body.bio = bio.value
|
body.bio = current.value.bio
|
||||||
}
|
}
|
||||||
|
|
||||||
await useBaseFetch(`user/${auth.value.user.id}`, {
|
await useBaseFetch(`user/${auth.value.user.id}`, {
|
||||||
@@ -229,7 +236,6 @@ async function saveChanges() {
|
|||||||
})
|
})
|
||||||
await useAuth(auth.value.token)
|
await useAuth(auth.value.token)
|
||||||
avatarUrl.value = auth.value.user.avatar_url
|
avatarUrl.value = auth.value.user.avatar_url
|
||||||
saved.value = true
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
addNotification({
|
addNotification({
|
||||||
title: 'An error occurred',
|
title: 'An error occurred',
|
||||||
@@ -243,7 +249,7 @@ async function saveChanges() {
|
|||||||
type: 'error',
|
type: 'error',
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
stopLoading()
|
saving.value = false
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|||||||
@@ -53,8 +53,6 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/commands": "^6.3.2",
|
"@codemirror/commands": "^6.3.2",
|
||||||
"intl-messageformat": "^10.7.7",
|
|
||||||
"vue-i18n": "^10.0.0",
|
|
||||||
"@codemirror/lang-markdown": "^6.2.3",
|
"@codemirror/lang-markdown": "^6.2.3",
|
||||||
"@codemirror/language": "^6.9.3",
|
"@codemirror/language": "^6.9.3",
|
||||||
"@codemirror/state": "^6.3.2",
|
"@codemirror/state": "^6.3.2",
|
||||||
@@ -73,13 +71,16 @@
|
|||||||
"ace-builds": "^1.43.5",
|
"ace-builds": "^1.43.5",
|
||||||
"apexcharts": "^4.0.0",
|
"apexcharts": "^4.0.0",
|
||||||
"dayjs": "^1.11.10",
|
"dayjs": "^1.11.10",
|
||||||
|
"es-toolkit": "^1.44.0",
|
||||||
"floating-vue": "^5.2.2",
|
"floating-vue": "^5.2.2",
|
||||||
"fuse.js": "^6.6.2",
|
"fuse.js": "^6.6.2",
|
||||||
"highlight.js": "^11.9.0",
|
"highlight.js": "^11.9.0",
|
||||||
|
"intl-messageformat": "^10.7.7",
|
||||||
"markdown-it": "^13.0.2",
|
"markdown-it": "^13.0.2",
|
||||||
"postprocessing": "^6.37.6",
|
"postprocessing": "^6.37.6",
|
||||||
"qrcode.vue": "^3.4.1",
|
"qrcode.vue": "^3.4.1",
|
||||||
"three": "^0.172.0",
|
"three": "^0.172.0",
|
||||||
|
"vue-i18n": "^10.0.0",
|
||||||
"vue-multiselect": "3.0.0",
|
"vue-multiselect": "3.0.0",
|
||||||
"vue-select": "4.0.0-beta.6",
|
"vue-select": "4.0.0-beta.6",
|
||||||
"vue-typed-virtual-list": "^1.0.10",
|
"vue-typed-virtual-list": "^1.0.10",
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<script setup lang="ts" generic="T">
|
<script setup lang="ts" generic="T">
|
||||||
import { HistoryIcon, SaveIcon, SpinnerIcon } from '@modrinth/assets'
|
import { HistoryIcon, SaveIcon, SpinnerIcon } from '@modrinth/assets'
|
||||||
|
import { isEqual } from 'es-toolkit'
|
||||||
import { type Component, computed } from 'vue'
|
import { type Component, computed } from 'vue'
|
||||||
|
|
||||||
import { defineMessage, type MessageDescriptor, useVIntl } from '../../composables/i18n'
|
import { defineMessage, type MessageDescriptor, useVIntl } from '../../composables/i18n'
|
||||||
@@ -38,15 +39,9 @@ const props = withDefaults(
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
const shown = computed(() => {
|
const shown = computed(() =>
|
||||||
let changed = false
|
Object.keys(props.modified).some((key) => !isEqual(props.original[key], props.modified[key])),
|
||||||
for (const key of Object.keys(props.modified)) {
|
)
|
||||||
if (props.original[key] !== props.modified[key]) {
|
|
||||||
changed = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return changed
|
|
||||||
})
|
|
||||||
|
|
||||||
function localizeIfPossible(message: MessageDescriptor | string) {
|
function localizeIfPossible(message: MessageDescriptor | string) {
|
||||||
return typeof message === 'string' ? message : formatMessage(message)
|
return typeof message === 'string' ? message : formatMessage(message)
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import {
|
|||||||
useSavable,
|
useSavable,
|
||||||
useVIntl,
|
useVIntl,
|
||||||
} from '@modrinth/ui'
|
} from '@modrinth/ui'
|
||||||
import { computed, ref } from 'vue'
|
import { computed } from 'vue'
|
||||||
|
|
||||||
const { formatMessage } = useVIntl()
|
const { formatMessage } = useVIntl()
|
||||||
|
|
||||||
@@ -20,8 +20,6 @@ const { currentMember, projectV2, projectV3, refreshProject } = injectProjectPag
|
|||||||
const { handleError } = injectNotificationManager()
|
const { handleError } = injectNotificationManager()
|
||||||
const client = injectModrinthClient()
|
const client = injectModrinthClient()
|
||||||
|
|
||||||
const saving = ref(false)
|
|
||||||
|
|
||||||
const supportsEnvironment = computed(() =>
|
const supportsEnvironment = computed(() =>
|
||||||
projectV3.value.project_types.some((type) => ['mod', 'modpack'].includes(type)),
|
projectV3.value.project_types.some((type) => ['mod', 'modpack'].includes(type)),
|
||||||
)
|
)
|
||||||
@@ -36,26 +34,29 @@ const needsToVerify = computed(
|
|||||||
|
|
||||||
const hasPermission = computed(() => {
|
const hasPermission = computed(() => {
|
||||||
const EDIT_DETAILS = 1 << 2
|
const EDIT_DETAILS = 1 << 2
|
||||||
return (currentMember.value?.permissions & EDIT_DETAILS) === EDIT_DETAILS
|
return ((currentMember.value?.permissions ?? 0) & EDIT_DETAILS) === EDIT_DETAILS
|
||||||
})
|
})
|
||||||
|
|
||||||
function getInitialEnv() {
|
function getInitialEnv() {
|
||||||
return projectV3.value.environment?.length === 1 ? projectV3.value.environment[0] : undefined
|
return projectV3.value.environment?.length === 1 ? projectV3.value.environment[0] : undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
const { saved, current, reset, save } = useSavable(
|
const { saved, current, saving, reset, save } = useSavable(
|
||||||
() => ({
|
() => ({
|
||||||
environment: getInitialEnv(),
|
environment: getInitialEnv(),
|
||||||
side_types_migration_review_status: projectV3.value.side_types_migration_review_status,
|
side_types_migration_review_status: projectV3.value.side_types_migration_review_status,
|
||||||
}),
|
}),
|
||||||
({ environment, side_types_migration_review_status }) => {
|
async ({ environment }) => {
|
||||||
saving.value = true
|
try {
|
||||||
side_types_migration_review_status = 'reviewed'
|
await client.labrinth.projects_v3.edit(projectV2.value.id, {
|
||||||
client.labrinth.projects_v3
|
environment,
|
||||||
.edit(projectV2.value.id, { environment, side_types_migration_review_status })
|
side_types_migration_review_status: 'reviewed',
|
||||||
.then(() => refreshProject().then(reset))
|
})
|
||||||
.catch(handleError)
|
await refreshProject()
|
||||||
.finally(() => (saving.value = false))
|
reset()
|
||||||
|
} catch (err) {
|
||||||
|
handleError(err as Error)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
// Set current to reviewed, which will trigger unsaved changes popup.
|
// Set current to reviewed, which will trigger unsaved changes popup.
|
||||||
|
|||||||
@@ -31,6 +31,21 @@ export interface ProjectPageContext {
|
|||||||
patchProject: (data: Record<string, unknown>, quiet?: boolean) => Promise<boolean>
|
patchProject: (data: Record<string, unknown>, quiet?: boolean) => Promise<boolean>
|
||||||
patchIcon: (icon: File) => Promise<boolean>
|
patchIcon: (icon: File) => Promise<boolean>
|
||||||
setProcessing: () => Promise<void>
|
setProcessing: () => Promise<void>
|
||||||
|
createGalleryItem: (
|
||||||
|
file: File,
|
||||||
|
title?: string,
|
||||||
|
description?: string,
|
||||||
|
featured?: boolean,
|
||||||
|
ordering?: number,
|
||||||
|
) => Promise<boolean>
|
||||||
|
editGalleryItem: (
|
||||||
|
imageUrl: string,
|
||||||
|
title?: string,
|
||||||
|
description?: string,
|
||||||
|
featured?: boolean,
|
||||||
|
ordering?: number,
|
||||||
|
) => Promise<boolean>
|
||||||
|
deleteGalleryItem: (imageUrl: string) => Promise<boolean>
|
||||||
}
|
}
|
||||||
|
|
||||||
export const [injectProjectPageContext, provideProjectPageContext] =
|
export const [injectProjectPageContext, provideProjectPageContext] =
|
||||||
|
|||||||
@@ -1,37 +1,56 @@
|
|||||||
|
import { isEqual } from 'es-toolkit'
|
||||||
import type { ComputedRef, Ref } from 'vue'
|
import type { ComputedRef, Ref } from 'vue'
|
||||||
import { computed, ref } from 'vue'
|
import { computed, ref } from 'vue'
|
||||||
|
|
||||||
export function useSavable<T extends Record<string, unknown>>(
|
export function useSavable<T extends Record<string, unknown>>(
|
||||||
data: () => T,
|
data: () => T,
|
||||||
save: (changes: Partial<T>) => void,
|
save: (changes: Partial<T>) => void | Promise<void>,
|
||||||
): {
|
): {
|
||||||
saved: ComputedRef<T>
|
saved: ComputedRef<T>
|
||||||
current: Ref<T>
|
current: Ref<T>
|
||||||
|
changes: ComputedRef<Partial<T>>
|
||||||
|
hasChanges: ComputedRef<boolean>
|
||||||
|
saving: Ref<boolean>
|
||||||
reset: () => void
|
reset: () => void
|
||||||
save: () => void
|
save: () => Promise<void>
|
||||||
} {
|
} {
|
||||||
const savedValues = computed(data)
|
const savedValues = computed(data)
|
||||||
const currentValues = ref({ ...data() }) as Ref<T>
|
const currentValues = ref({ ...data() }) as Ref<T>
|
||||||
|
const saving = ref(false)
|
||||||
|
|
||||||
const changes = computed<Partial<T>>(() => {
|
const changes = computed<Partial<T>>(() => {
|
||||||
const values: Partial<T> = {}
|
const values: Partial<T> = {}
|
||||||
const keys = Object.keys(currentValues.value) as (keyof T)[]
|
const keys = Object.keys(currentValues.value) as (keyof T)[]
|
||||||
for (const key of keys) {
|
for (const key of keys) {
|
||||||
if (savedValues.value[key] !== currentValues.value[key]) {
|
if (!isEqual(savedValues.value[key], currentValues.value[key])) {
|
||||||
values[key] = currentValues.value[key]
|
values[key] = currentValues.value[key]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return values
|
return values
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const hasChanges = computed(() => Object.keys(changes.value).length > 0)
|
||||||
|
|
||||||
const reset = () => {
|
const reset = () => {
|
||||||
currentValues.value = data()
|
currentValues.value = data()
|
||||||
}
|
}
|
||||||
|
|
||||||
const saveInternal = () => (changes.value ? save(changes.value) : {})
|
const saveInternal = async () => {
|
||||||
|
if (!hasChanges.value) return
|
||||||
|
saving.value = true
|
||||||
|
try {
|
||||||
|
await save(changes.value)
|
||||||
|
} finally {
|
||||||
|
saving.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
saved: savedValues,
|
saved: savedValues,
|
||||||
current: currentValues,
|
current: currentValues,
|
||||||
|
changes,
|
||||||
|
hasChanges,
|
||||||
|
saving,
|
||||||
reset,
|
reset,
|
||||||
save: saveInternal,
|
save: saveInternal,
|
||||||
}
|
}
|
||||||
|
|||||||
140
pnpm-lock.yaml
generated
140
pnpm-lock.yaml
generated
@@ -265,7 +265,7 @@ importers:
|
|||||||
version: 0.11.3(magicast@0.5.1)(pinia@3.0.4(typescript@5.9.3)(vue@3.5.26(typescript@5.9.3)))
|
version: 0.11.3(magicast@0.5.1)(pinia@3.0.4(typescript@5.9.3)(vue@3.5.26(typescript@5.9.3)))
|
||||||
'@sentry/nuxt':
|
'@sentry/nuxt':
|
||||||
specifier: ^10.33.0
|
specifier: ^10.33.0
|
||||||
version: 10.33.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.3.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.3.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.208.0(@opentelemetry/api@1.9.0))(@opentelemetry/resources@2.3.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.3.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.38.0)(magicast@0.5.1)(nuxt@3.20.2(@parcel/watcher@2.5.1)(@types/node@20.19.27)(@vue/compiler-sfc@3.5.26)(cac@6.7.14)(db0@0.3.4)(eslint@9.39.2(jiti@1.21.7))(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.5.1)(optionator@0.9.4)(rollup@4.54.0)(sass@1.97.1)(terser@5.44.1)(typescript@5.9.3)(vite@7.3.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))(vue-tsc@2.2.12(typescript@5.9.3))(xml2js@0.6.2)(yaml@2.8.2))(pinia@3.0.4(typescript@5.9.3)(vue@3.5.26(typescript@5.9.3)))(rollup@4.54.0)(vue@3.5.26(typescript@5.9.3))
|
version: 10.33.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.3.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.3.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.208.0(@opentelemetry/api@1.9.0))(@opentelemetry/resources@2.3.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.3.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.38.0)(magicast@0.5.1)(nuxt@3.20.2(@parcel/watcher@2.5.1)(@types/node@20.19.27)(@vue/compiler-sfc@3.5.26)(cac@6.7.14)(db0@0.3.4)(eslint@9.39.2(jiti@2.6.1))(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.5.1)(optionator@0.9.4)(rollup@4.54.0)(sass@1.97.1)(terser@5.44.1)(typescript@5.9.3)(vite@7.3.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))(vue-tsc@2.2.12(typescript@5.9.3))(xml2js@0.6.2)(yaml@2.8.2))(pinia@3.0.4(typescript@5.9.3)(vue@3.5.26(typescript@5.9.3)))(rollup@4.54.0)(vue@3.5.26(typescript@5.9.3))
|
||||||
'@tanstack/vue-query':
|
'@tanstack/vue-query':
|
||||||
specifier: ^5.90.7
|
specifier: ^5.90.7
|
||||||
version: 5.92.5(vue@3.5.26(typescript@5.9.3))
|
version: 5.92.5(vue@3.5.26(typescript@5.9.3))
|
||||||
@@ -392,7 +392,7 @@ importers:
|
|||||||
version: 10.5.0
|
version: 10.5.0
|
||||||
nuxt:
|
nuxt:
|
||||||
specifier: ^3.20.2
|
specifier: ^3.20.2
|
||||||
version: 3.20.2(@parcel/watcher@2.5.1)(@types/node@20.19.27)(@vue/compiler-sfc@3.5.26)(cac@6.7.14)(db0@0.3.4)(eslint@9.39.2(jiti@1.21.7))(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.5.1)(optionator@0.9.4)(rollup@4.54.0)(sass@1.97.1)(terser@5.44.1)(typescript@5.9.3)(vite@7.3.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))(vue-tsc@2.2.12(typescript@5.9.3))(xml2js@0.6.2)(yaml@2.8.2)
|
version: 3.20.2(@parcel/watcher@2.5.1)(@types/node@20.19.27)(@vue/compiler-sfc@3.5.26)(cac@6.7.14)(db0@0.3.4)(eslint@9.39.2(jiti@2.6.1))(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.5.1)(optionator@0.9.4)(rollup@4.54.0)(sass@1.97.1)(terser@5.44.1)(typescript@5.9.3)(vite@7.3.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))(vue-tsc@2.2.12(typescript@5.9.3))(xml2js@0.6.2)(yaml@2.8.2)
|
||||||
postcss:
|
postcss:
|
||||||
specifier: ^8.4.39
|
specifier: ^8.4.39
|
||||||
version: 8.5.6
|
version: 8.5.6
|
||||||
@@ -634,6 +634,9 @@ importers:
|
|||||||
dayjs:
|
dayjs:
|
||||||
specifier: ^1.11.10
|
specifier: ^1.11.10
|
||||||
version: 1.11.19
|
version: 1.11.19
|
||||||
|
es-toolkit:
|
||||||
|
specifier: ^1.44.0
|
||||||
|
version: 1.44.0
|
||||||
floating-vue:
|
floating-vue:
|
||||||
specifier: ^5.2.2
|
specifier: ^5.2.2
|
||||||
version: 5.2.2(@nuxt/kit@3.20.2(magicast@0.5.1))(vue@3.5.26(typescript@5.9.3))
|
version: 5.2.2(@nuxt/kit@3.20.2(magicast@0.5.1))(vue@3.5.26(typescript@5.9.3))
|
||||||
@@ -724,7 +727,7 @@ importers:
|
|||||||
version: 4.0.16(@vitest/browser@4.0.16(vite@5.4.21(@types/node@20.19.27)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1))(vitest@4.0.16))(vitest@4.0.16)
|
version: 4.0.16(@vitest/browser@4.0.16(vite@5.4.21(@types/node@20.19.27)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1))(vitest@4.0.16))(vitest@4.0.16)
|
||||||
eslint-plugin-storybook:
|
eslint-plugin-storybook:
|
||||||
specifier: ^10.1.10
|
specifier: ^10.1.10
|
||||||
version: 10.1.11(eslint@9.39.2(jiti@2.6.1))(storybook@10.1.11(@testing-library/dom@10.4.1)(prettier@3.7.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(typescript@5.9.3)
|
version: 10.1.11(eslint@9.39.2(jiti@1.21.7))(storybook@10.1.11(@testing-library/dom@10.4.1)(prettier@3.7.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(typescript@5.9.3)
|
||||||
playwright:
|
playwright:
|
||||||
specifier: ^1.57.0
|
specifier: ^1.57.0
|
||||||
version: 1.57.0
|
version: 1.57.0
|
||||||
@@ -748,7 +751,7 @@ importers:
|
|||||||
version: 5.1.0(vue@3.5.26(typescript@5.9.3))
|
version: 5.1.0(vue@3.5.26(typescript@5.9.3))
|
||||||
vitest:
|
vitest:
|
||||||
specifier: ^4.0.16
|
specifier: ^4.0.16
|
||||||
version: 4.0.16(@opentelemetry/api@1.9.0)(@types/node@20.19.27)(@vitest/browser-playwright@4.0.16)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)
|
version: 4.0.16(@opentelemetry/api@1.9.0)(@types/node@20.19.27)(@vitest/browser-playwright@4.0.16)(jiti@1.21.7)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)
|
||||||
vue:
|
vue:
|
||||||
specifier: ^3.5.13
|
specifier: ^3.5.13
|
||||||
version: 3.5.26(typescript@5.9.3)
|
version: 3.5.26(typescript@5.9.3)
|
||||||
@@ -5433,6 +5436,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}
|
resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
|
es-toolkit@1.44.0:
|
||||||
|
resolution: {integrity: sha512-6penXeZalaV88MM3cGkFZZfOoLGWshWWfdy0tWw/RlVVyhvMaWSBTOvXNeiW3e5FwdS5ePW0LGEu17zT139ktg==}
|
||||||
|
|
||||||
esast-util-from-estree@2.0.0:
|
esast-util-from-estree@2.0.0:
|
||||||
resolution: {integrity: sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==}
|
resolution: {integrity: sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==}
|
||||||
|
|
||||||
@@ -8485,6 +8491,7 @@ packages:
|
|||||||
tar@7.5.2:
|
tar@7.5.2:
|
||||||
resolution: {integrity: sha512-7NyxrTE4Anh8km8iEy7o0QYPs+0JKBTj5ZaqHg6B39erLg0qYXN3BijtShwbsNSvQ+LN75+KV+C4QR/f6Gwnpg==}
|
resolution: {integrity: sha512-7NyxrTE4Anh8km8iEy7o0QYPs+0JKBTj5ZaqHg6B39erLg0qYXN3BijtShwbsNSvQ+LN75+KV+C4QR/f6Gwnpg==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
|
deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exhorbitant rates) by contacting i@izs.me
|
||||||
|
|
||||||
terser@5.44.1:
|
terser@5.44.1:
|
||||||
resolution: {integrity: sha512-t/R3R/n0MSwnnazuPpPNVO60LX0SKL45pyl9YlvxIdkH0Of7D5qM2EVe+yASRIlY5pZ73nclYJfNANGWPwFDZw==}
|
resolution: {integrity: sha512-t/R3R/n0MSwnnazuPpPNVO60LX0SKL45pyl9YlvxIdkH0Of7D5qM2EVe+yASRIlY5pZ73nclYJfNANGWPwFDZw==}
|
||||||
@@ -9245,8 +9252,8 @@ packages:
|
|||||||
vue-component-type-helpers@3.2.1:
|
vue-component-type-helpers@3.2.1:
|
||||||
resolution: {integrity: sha512-gKV7XOkQl4urSuLHNY1tnVQf7wVgtb/mKbRyxSLWGZUY9RK7aDPhBenTjm+i8ZFe0zC2PZeHMPtOZXZfyaFOzQ==}
|
resolution: {integrity: sha512-gKV7XOkQl4urSuLHNY1tnVQf7wVgtb/mKbRyxSLWGZUY9RK7aDPhBenTjm+i8ZFe0zC2PZeHMPtOZXZfyaFOzQ==}
|
||||||
|
|
||||||
vue-component-type-helpers@3.2.2:
|
vue-component-type-helpers@3.2.4:
|
||||||
resolution: {integrity: sha512-x8C2nx5XlUNM0WirgfTkHjJGO/ABBxlANZDtHw2HclHtQnn+RFPTnbjMJn8jHZW4TlUam0asHcA14lf1C6Jb+A==}
|
resolution: {integrity: sha512-05lR16HeZDcDpB23ku5b5f1fBOoHqFnMiKRr2CiEvbG5Ux4Yi0McmQBOET0dR0nxDXosxyVqv67q6CzS3AK8rw==}
|
||||||
|
|
||||||
vue-confetti-explosion@1.0.2:
|
vue-confetti-explosion@1.0.2:
|
||||||
resolution: {integrity: sha512-80OboM3/6BItIoZ6DpNcZFqGpF607kjIVc5af56oKgtFmt5yWehvJeoYhkzYlqxrqdBe0Ko4Ie3bWrmLau+dJw==}
|
resolution: {integrity: sha512-80OboM3/6BItIoZ6DpNcZFqGpF607kjIVc5af56oKgtFmt5yWehvJeoYhkzYlqxrqdBe0Ko4Ie3bWrmLau+dJw==}
|
||||||
@@ -10415,7 +10422,6 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
eslint: 9.39.2(jiti@1.21.7)
|
eslint: 9.39.2(jiti@1.21.7)
|
||||||
eslint-visitor-keys: 3.4.3
|
eslint-visitor-keys: 3.4.3
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@eslint-community/eslint-utils@4.9.1(eslint@9.39.2(jiti@2.6.1))':
|
'@eslint-community/eslint-utils@4.9.1(eslint@9.39.2(jiti@2.6.1))':
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -11000,7 +11006,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@nuxt/kit': 4.2.2(magicast@0.5.1)
|
'@nuxt/kit': 4.2.2(magicast@0.5.1)
|
||||||
execa: 8.0.1
|
execa: 8.0.1
|
||||||
vite: 7.3.0(@types/node@20.19.27)(jiti@1.21.7)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)
|
vite: 7.3.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- magicast
|
- magicast
|
||||||
|
|
||||||
@@ -11045,7 +11051,7 @@ snapshots:
|
|||||||
sirv: 3.0.2
|
sirv: 3.0.2
|
||||||
structured-clone-es: 1.0.0
|
structured-clone-es: 1.0.0
|
||||||
tinyglobby: 0.2.15
|
tinyglobby: 0.2.15
|
||||||
vite: 7.3.0(@types/node@20.19.27)(jiti@1.21.7)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)
|
vite: 7.3.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)
|
||||||
vite-plugin-inspect: 11.3.3(@nuxt/kit@4.2.2(magicast@0.5.1))(vite@7.3.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))
|
vite-plugin-inspect: 11.3.3(@nuxt/kit@4.2.2(magicast@0.5.1))(vite@7.3.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))
|
||||||
vite-plugin-vue-tracer: 1.2.0(vite@7.3.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))(vue@3.5.26(typescript@5.9.3))
|
vite-plugin-vue-tracer: 1.2.0(vite@7.3.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))(vue@3.5.26(typescript@5.9.3))
|
||||||
which: 5.0.0
|
which: 5.0.0
|
||||||
@@ -11141,7 +11147,7 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- magicast
|
- magicast
|
||||||
|
|
||||||
'@nuxt/nitro-server@3.20.2(db0@0.3.4)(ioredis@5.8.2)(magicast@0.5.1)(nuxt@3.20.2(@parcel/watcher@2.5.1)(@types/node@20.19.27)(@vue/compiler-sfc@3.5.26)(cac@6.7.14)(db0@0.3.4)(eslint@9.39.2(jiti@1.21.7))(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.5.1)(optionator@0.9.4)(rollup@4.54.0)(sass@1.97.1)(terser@5.44.1)(typescript@5.9.3)(vite@7.3.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))(vue-tsc@2.2.12(typescript@5.9.3))(xml2js@0.6.2)(yaml@2.8.2))(typescript@5.9.3)(xml2js@0.6.2)':
|
'@nuxt/nitro-server@3.20.2(db0@0.3.4)(ioredis@5.8.2)(magicast@0.5.1)(nuxt@3.20.2(@parcel/watcher@2.5.1)(@types/node@20.19.27)(@vue/compiler-sfc@3.5.26)(cac@6.7.14)(db0@0.3.4)(eslint@9.39.2(jiti@2.6.1))(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.5.1)(optionator@0.9.4)(rollup@4.54.0)(sass@1.97.1)(terser@5.44.1)(typescript@5.9.3)(vite@7.3.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))(vue-tsc@2.2.12(typescript@5.9.3))(xml2js@0.6.2)(yaml@2.8.2))(typescript@5.9.3)(xml2js@0.6.2)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@nuxt/devalue': 2.0.2
|
'@nuxt/devalue': 2.0.2
|
||||||
'@nuxt/kit': 3.20.2(magicast@0.5.1)
|
'@nuxt/kit': 3.20.2(magicast@0.5.1)
|
||||||
@@ -11159,7 +11165,7 @@ snapshots:
|
|||||||
klona: 2.0.6
|
klona: 2.0.6
|
||||||
mocked-exports: 0.1.1
|
mocked-exports: 0.1.1
|
||||||
nitropack: 2.12.9(xml2js@0.6.2)
|
nitropack: 2.12.9(xml2js@0.6.2)
|
||||||
nuxt: 3.20.2(@parcel/watcher@2.5.1)(@types/node@20.19.27)(@vue/compiler-sfc@3.5.26)(cac@6.7.14)(db0@0.3.4)(eslint@9.39.2(jiti@1.21.7))(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.5.1)(optionator@0.9.4)(rollup@4.54.0)(sass@1.97.1)(terser@5.44.1)(typescript@5.9.3)(vite@7.3.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))(vue-tsc@2.2.12(typescript@5.9.3))(xml2js@0.6.2)(yaml@2.8.2)
|
nuxt: 3.20.2(@parcel/watcher@2.5.1)(@types/node@20.19.27)(@vue/compiler-sfc@3.5.26)(cac@6.7.14)(db0@0.3.4)(eslint@9.39.2(jiti@2.6.1))(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.5.1)(optionator@0.9.4)(rollup@4.54.0)(sass@1.97.1)(terser@5.44.1)(typescript@5.9.3)(vite@7.3.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))(vue-tsc@2.2.12(typescript@5.9.3))(xml2js@0.6.2)(yaml@2.8.2)
|
||||||
pathe: 2.0.3
|
pathe: 2.0.3
|
||||||
pkg-types: 2.3.0
|
pkg-types: 2.3.0
|
||||||
radix3: 1.1.2
|
radix3: 1.1.2
|
||||||
@@ -11230,7 +11236,7 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- magicast
|
- magicast
|
||||||
|
|
||||||
'@nuxt/vite-builder@3.20.2(@types/node@20.19.27)(eslint@9.39.2(jiti@1.21.7))(lightningcss@1.30.2)(magicast@0.5.1)(nuxt@3.20.2(@parcel/watcher@2.5.1)(@types/node@20.19.27)(@vue/compiler-sfc@3.5.26)(cac@6.7.14)(db0@0.3.4)(eslint@9.39.2(jiti@1.21.7))(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.5.1)(optionator@0.9.4)(rollup@4.54.0)(sass@1.97.1)(terser@5.44.1)(typescript@5.9.3)(vite@7.3.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))(vue-tsc@2.2.12(typescript@5.9.3))(xml2js@0.6.2)(yaml@2.8.2))(optionator@0.9.4)(rollup@4.54.0)(sass@1.97.1)(terser@5.44.1)(typescript@5.9.3)(vue-tsc@2.2.12(typescript@5.9.3))(vue@3.5.26(typescript@5.9.3))(yaml@2.8.2)':
|
'@nuxt/vite-builder@3.20.2(@types/node@20.19.27)(eslint@9.39.2(jiti@2.6.1))(lightningcss@1.30.2)(magicast@0.5.1)(nuxt@3.20.2(@parcel/watcher@2.5.1)(@types/node@20.19.27)(@vue/compiler-sfc@3.5.26)(cac@6.7.14)(db0@0.3.4)(eslint@9.39.2(jiti@2.6.1))(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.5.1)(optionator@0.9.4)(rollup@4.54.0)(sass@1.97.1)(terser@5.44.1)(typescript@5.9.3)(vite@7.3.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))(vue-tsc@2.2.12(typescript@5.9.3))(xml2js@0.6.2)(yaml@2.8.2))(optionator@0.9.4)(rollup@4.54.0)(sass@1.97.1)(terser@5.44.1)(typescript@5.9.3)(vue-tsc@2.2.12(typescript@5.9.3))(vue@3.5.26(typescript@5.9.3))(yaml@2.8.2)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@nuxt/kit': 3.20.2(magicast@0.5.1)
|
'@nuxt/kit': 3.20.2(magicast@0.5.1)
|
||||||
'@rollup/plugin-replace': 6.0.3(rollup@4.54.0)
|
'@rollup/plugin-replace': 6.0.3(rollup@4.54.0)
|
||||||
@@ -11251,7 +11257,7 @@ snapshots:
|
|||||||
magic-string: 0.30.21
|
magic-string: 0.30.21
|
||||||
mlly: 1.8.0
|
mlly: 1.8.0
|
||||||
mocked-exports: 0.1.1
|
mocked-exports: 0.1.1
|
||||||
nuxt: 3.20.2(@parcel/watcher@2.5.1)(@types/node@20.19.27)(@vue/compiler-sfc@3.5.26)(cac@6.7.14)(db0@0.3.4)(eslint@9.39.2(jiti@1.21.7))(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.5.1)(optionator@0.9.4)(rollup@4.54.0)(sass@1.97.1)(terser@5.44.1)(typescript@5.9.3)(vite@7.3.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))(vue-tsc@2.2.12(typescript@5.9.3))(xml2js@0.6.2)(yaml@2.8.2)
|
nuxt: 3.20.2(@parcel/watcher@2.5.1)(@types/node@20.19.27)(@vue/compiler-sfc@3.5.26)(cac@6.7.14)(db0@0.3.4)(eslint@9.39.2(jiti@2.6.1))(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.5.1)(optionator@0.9.4)(rollup@4.54.0)(sass@1.97.1)(terser@5.44.1)(typescript@5.9.3)(vite@7.3.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))(vue-tsc@2.2.12(typescript@5.9.3))(xml2js@0.6.2)(yaml@2.8.2)
|
||||||
ohash: 2.0.11
|
ohash: 2.0.11
|
||||||
pathe: 2.0.3
|
pathe: 2.0.3
|
||||||
perfect-debounce: 2.0.0
|
perfect-debounce: 2.0.0
|
||||||
@@ -11262,9 +11268,9 @@ snapshots:
|
|||||||
std-env: 3.10.0
|
std-env: 3.10.0
|
||||||
ufo: 1.6.1
|
ufo: 1.6.1
|
||||||
unenv: 2.0.0-rc.24
|
unenv: 2.0.0-rc.24
|
||||||
vite: 7.3.0(@types/node@20.19.27)(jiti@1.21.7)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)
|
vite: 7.3.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)
|
||||||
vite-node: 5.2.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)
|
vite-node: 5.2.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)
|
||||||
vite-plugin-checker: 0.12.0(eslint@9.39.2(jiti@1.21.7))(optionator@0.9.4)(typescript@5.9.3)(vite@7.3.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))(vue-tsc@2.2.12(typescript@5.9.3))
|
vite-plugin-checker: 0.12.0(eslint@9.39.2(jiti@2.6.1))(optionator@0.9.4)(typescript@5.9.3)(vite@7.3.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))(vue-tsc@2.2.12(typescript@5.9.3))
|
||||||
vue: 3.5.26(typescript@5.9.3)
|
vue: 3.5.26(typescript@5.9.3)
|
||||||
vue-bundle-renderer: 2.2.0
|
vue-bundle-renderer: 2.2.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
@@ -12148,7 +12154,7 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
'@sentry/nuxt@10.33.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.3.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.3.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.208.0(@opentelemetry/api@1.9.0))(@opentelemetry/resources@2.3.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.3.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.38.0)(magicast@0.5.1)(nuxt@3.20.2(@parcel/watcher@2.5.1)(@types/node@20.19.27)(@vue/compiler-sfc@3.5.26)(cac@6.7.14)(db0@0.3.4)(eslint@9.39.2(jiti@1.21.7))(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.5.1)(optionator@0.9.4)(rollup@4.54.0)(sass@1.97.1)(terser@5.44.1)(typescript@5.9.3)(vite@7.3.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))(vue-tsc@2.2.12(typescript@5.9.3))(xml2js@0.6.2)(yaml@2.8.2))(pinia@3.0.4(typescript@5.9.3)(vue@3.5.26(typescript@5.9.3)))(rollup@4.54.0)(vue@3.5.26(typescript@5.9.3))':
|
'@sentry/nuxt@10.33.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.3.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.3.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.208.0(@opentelemetry/api@1.9.0))(@opentelemetry/resources@2.3.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.3.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.38.0)(magicast@0.5.1)(nuxt@3.20.2(@parcel/watcher@2.5.1)(@types/node@20.19.27)(@vue/compiler-sfc@3.5.26)(cac@6.7.14)(db0@0.3.4)(eslint@9.39.2(jiti@2.6.1))(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.5.1)(optionator@0.9.4)(rollup@4.54.0)(sass@1.97.1)(terser@5.44.1)(typescript@5.9.3)(vite@7.3.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))(vue-tsc@2.2.12(typescript@5.9.3))(xml2js@0.6.2)(yaml@2.8.2))(pinia@3.0.4(typescript@5.9.3)(vue@3.5.26(typescript@5.9.3)))(rollup@4.54.0)(vue@3.5.26(typescript@5.9.3))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@nuxt/kit': 3.20.2(magicast@0.5.1)
|
'@nuxt/kit': 3.20.2(magicast@0.5.1)
|
||||||
'@sentry/browser': 10.33.0
|
'@sentry/browser': 10.33.0
|
||||||
@@ -12159,7 +12165,7 @@ snapshots:
|
|||||||
'@sentry/rollup-plugin': 4.6.1(rollup@4.54.0)
|
'@sentry/rollup-plugin': 4.6.1(rollup@4.54.0)
|
||||||
'@sentry/vite-plugin': 4.6.1
|
'@sentry/vite-plugin': 4.6.1
|
||||||
'@sentry/vue': 10.33.0(pinia@3.0.4(typescript@5.9.3)(vue@3.5.26(typescript@5.9.3)))(vue@3.5.26(typescript@5.9.3))
|
'@sentry/vue': 10.33.0(pinia@3.0.4(typescript@5.9.3)(vue@3.5.26(typescript@5.9.3)))(vue@3.5.26(typescript@5.9.3))
|
||||||
nuxt: 3.20.2(@parcel/watcher@2.5.1)(@types/node@20.19.27)(@vue/compiler-sfc@3.5.26)(cac@6.7.14)(db0@0.3.4)(eslint@9.39.2(jiti@1.21.7))(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.5.1)(optionator@0.9.4)(rollup@4.54.0)(sass@1.97.1)(terser@5.44.1)(typescript@5.9.3)(vite@7.3.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))(vue-tsc@2.2.12(typescript@5.9.3))(xml2js@0.6.2)(yaml@2.8.2)
|
nuxt: 3.20.2(@parcel/watcher@2.5.1)(@types/node@20.19.27)(@vue/compiler-sfc@3.5.26)(cac@6.7.14)(db0@0.3.4)(eslint@9.39.2(jiti@2.6.1))(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.5.1)(optionator@0.9.4)(rollup@4.54.0)(sass@1.97.1)(terser@5.44.1)(typescript@5.9.3)(vite@7.3.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))(vue-tsc@2.2.12(typescript@5.9.3))(xml2js@0.6.2)(yaml@2.8.2)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@cloudflare/workers-types'
|
- '@cloudflare/workers-types'
|
||||||
- '@opentelemetry/api'
|
- '@opentelemetry/api'
|
||||||
@@ -12336,7 +12342,7 @@ snapshots:
|
|||||||
'@vitest/browser': 4.0.16(vite@5.4.21(@types/node@20.19.27)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1))(vitest@4.0.16)
|
'@vitest/browser': 4.0.16(vite@5.4.21(@types/node@20.19.27)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1))(vitest@4.0.16)
|
||||||
'@vitest/browser-playwright': 4.0.16(playwright@1.57.0)(vite@5.4.21(@types/node@20.19.27)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1))(vitest@4.0.16)
|
'@vitest/browser-playwright': 4.0.16(playwright@1.57.0)(vite@5.4.21(@types/node@20.19.27)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1))(vitest@4.0.16)
|
||||||
'@vitest/runner': 4.0.16
|
'@vitest/runner': 4.0.16
|
||||||
vitest: 4.0.16(@opentelemetry/api@1.9.0)(@types/node@20.19.27)(@vitest/browser-playwright@4.0.16)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)
|
vitest: 4.0.16(@opentelemetry/api@1.9.0)(@types/node@20.19.27)(@vitest/browser-playwright@4.0.16)(jiti@1.21.7)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- react
|
- react
|
||||||
- react-dom
|
- react-dom
|
||||||
@@ -12399,7 +12405,7 @@ snapshots:
|
|||||||
storybook: 10.1.11(@testing-library/dom@10.4.1)(prettier@3.7.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
|
storybook: 10.1.11(@testing-library/dom@10.4.1)(prettier@3.7.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
|
||||||
type-fest: 2.19.0
|
type-fest: 2.19.0
|
||||||
vue: 3.5.26(typescript@5.9.3)
|
vue: 3.5.26(typescript@5.9.3)
|
||||||
vue-component-type-helpers: 3.2.2
|
vue-component-type-helpers: 3.2.4
|
||||||
|
|
||||||
'@stripe/stripe-js@7.9.0': {}
|
'@stripe/stripe-js@7.9.0': {}
|
||||||
|
|
||||||
@@ -12894,6 +12900,17 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
|
'@typescript-eslint/utils@8.51.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3)':
|
||||||
|
dependencies:
|
||||||
|
'@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@1.21.7))
|
||||||
|
'@typescript-eslint/scope-manager': 8.51.0
|
||||||
|
'@typescript-eslint/types': 8.51.0
|
||||||
|
'@typescript-eslint/typescript-estree': 8.51.0(typescript@5.9.3)
|
||||||
|
eslint: 9.39.2(jiti@1.21.7)
|
||||||
|
typescript: 5.9.3
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
'@typescript-eslint/utils@8.51.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)':
|
'@typescript-eslint/utils@8.51.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1))
|
'@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1))
|
||||||
@@ -13008,7 +13025,7 @@ snapshots:
|
|||||||
'@babel/plugin-transform-typescript': 7.28.5(@babel/core@7.28.5)
|
'@babel/plugin-transform-typescript': 7.28.5(@babel/core@7.28.5)
|
||||||
'@rolldown/pluginutils': 1.0.0-beta.58
|
'@rolldown/pluginutils': 1.0.0-beta.58
|
||||||
'@vue/babel-plugin-jsx': 2.0.1(@babel/core@7.28.5)
|
'@vue/babel-plugin-jsx': 2.0.1(@babel/core@7.28.5)
|
||||||
vite: 7.3.0(@types/node@20.19.27)(jiti@1.21.7)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)
|
vite: 7.3.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)
|
||||||
vue: 3.5.26(typescript@5.9.3)
|
vue: 3.5.26(typescript@5.9.3)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
@@ -13027,7 +13044,7 @@ snapshots:
|
|||||||
'@vitejs/plugin-vue@6.0.3(vite@7.3.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))(vue@3.5.26(typescript@5.9.3))':
|
'@vitejs/plugin-vue@6.0.3(vite@7.3.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))(vue@3.5.26(typescript@5.9.3))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@rolldown/pluginutils': 1.0.0-beta.53
|
'@rolldown/pluginutils': 1.0.0-beta.53
|
||||||
vite: 7.3.0(@types/node@20.19.27)(jiti@1.21.7)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)
|
vite: 7.3.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)
|
||||||
vue: 3.5.26(typescript@5.9.3)
|
vue: 3.5.26(typescript@5.9.3)
|
||||||
|
|
||||||
'@vitest/browser-playwright@4.0.16(playwright@1.57.0)(vite@5.4.21(@types/node@20.19.27)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1))(vitest@4.0.16)':
|
'@vitest/browser-playwright@4.0.16(playwright@1.57.0)(vite@5.4.21(@types/node@20.19.27)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1))(vitest@4.0.16)':
|
||||||
@@ -13036,7 +13053,7 @@ snapshots:
|
|||||||
'@vitest/mocker': 4.0.16(vite@5.4.21(@types/node@20.19.27)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1))
|
'@vitest/mocker': 4.0.16(vite@5.4.21(@types/node@20.19.27)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1))
|
||||||
playwright: 1.57.0
|
playwright: 1.57.0
|
||||||
tinyrainbow: 3.0.3
|
tinyrainbow: 3.0.3
|
||||||
vitest: 4.0.16(@opentelemetry/api@1.9.0)(@types/node@20.19.27)(@vitest/browser-playwright@4.0.16)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)
|
vitest: 4.0.16(@opentelemetry/api@1.9.0)(@types/node@20.19.27)(@vitest/browser-playwright@4.0.16)(jiti@1.21.7)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- bufferutil
|
- bufferutil
|
||||||
- msw
|
- msw
|
||||||
@@ -13052,7 +13069,7 @@ snapshots:
|
|||||||
pngjs: 7.0.0
|
pngjs: 7.0.0
|
||||||
sirv: 3.0.2
|
sirv: 3.0.2
|
||||||
tinyrainbow: 3.0.3
|
tinyrainbow: 3.0.3
|
||||||
vitest: 4.0.16(@opentelemetry/api@1.9.0)(@types/node@20.19.27)(@vitest/browser-playwright@4.0.16)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)
|
vitest: 4.0.16(@opentelemetry/api@1.9.0)(@types/node@20.19.27)(@vitest/browser-playwright@4.0.16)(jiti@1.21.7)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)
|
||||||
ws: 8.18.3
|
ws: 8.18.3
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- bufferutil
|
- bufferutil
|
||||||
@@ -13073,7 +13090,7 @@ snapshots:
|
|||||||
obug: 2.1.1
|
obug: 2.1.1
|
||||||
std-env: 3.10.0
|
std-env: 3.10.0
|
||||||
tinyrainbow: 3.0.3
|
tinyrainbow: 3.0.3
|
||||||
vitest: 4.0.16(@opentelemetry/api@1.9.0)(@types/node@20.19.27)(@vitest/browser-playwright@4.0.16)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)
|
vitest: 4.0.16(@opentelemetry/api@1.9.0)(@types/node@20.19.27)(@vitest/browser-playwright@4.0.16)(jiti@1.21.7)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@vitest/browser': 4.0.16(vite@5.4.21(@types/node@20.19.27)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1))(vitest@4.0.16)
|
'@vitest/browser': 4.0.16(vite@5.4.21(@types/node@20.19.27)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1))(vitest@4.0.16)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
@@ -13112,13 +13129,13 @@ snapshots:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
vite: 5.4.21(@types/node@20.19.27)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)
|
vite: 5.4.21(@types/node@20.19.27)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)
|
||||||
|
|
||||||
'@vitest/mocker@4.0.16(vite@6.4.1(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))':
|
'@vitest/mocker@4.0.16(vite@6.4.1(@types/node@20.19.27)(jiti@1.21.7)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vitest/spy': 4.0.16
|
'@vitest/spy': 4.0.16
|
||||||
estree-walker: 3.0.3
|
estree-walker: 3.0.3
|
||||||
magic-string: 0.30.21
|
magic-string: 0.30.21
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
vite: 6.4.1(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)
|
vite: 6.4.1(@types/node@20.19.27)(jiti@1.21.7)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)
|
||||||
|
|
||||||
'@vitest/pretty-format@3.2.4':
|
'@vitest/pretty-format@3.2.4':
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -14495,6 +14512,8 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
es-errors: 1.3.0
|
es-errors: 1.3.0
|
||||||
|
|
||||||
|
es-toolkit@1.44.0: {}
|
||||||
|
|
||||||
esast-util-from-estree@2.0.0:
|
esast-util-from-estree@2.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/estree-jsx': 1.0.5
|
'@types/estree-jsx': 1.0.5
|
||||||
@@ -14710,10 +14729,10 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
eslint: 9.39.2(jiti@2.6.1)
|
eslint: 9.39.2(jiti@2.6.1)
|
||||||
|
|
||||||
eslint-plugin-storybook@10.1.11(eslint@9.39.2(jiti@2.6.1))(storybook@10.1.11(@testing-library/dom@10.4.1)(prettier@3.7.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(typescript@5.9.3):
|
eslint-plugin-storybook@10.1.11(eslint@9.39.2(jiti@1.21.7))(storybook@10.1.11(@testing-library/dom@10.4.1)(prettier@3.7.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(typescript@5.9.3):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@typescript-eslint/utils': 8.51.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
|
'@typescript-eslint/utils': 8.51.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3)
|
||||||
eslint: 9.39.2(jiti@2.6.1)
|
eslint: 9.39.2(jiti@1.21.7)
|
||||||
storybook: 10.1.11(@testing-library/dom@10.4.1)(prettier@3.7.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
|
storybook: 10.1.11(@testing-library/dom@10.4.1)(prettier@3.7.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
@@ -14827,7 +14846,6 @@ snapshots:
|
|||||||
jiti: 1.21.7
|
jiti: 1.21.7
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
optional: true
|
|
||||||
|
|
||||||
eslint@9.39.2(jiti@2.6.1):
|
eslint@9.39.2(jiti@2.6.1):
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -16790,16 +16808,16 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
boolbase: 1.0.0
|
boolbase: 1.0.0
|
||||||
|
|
||||||
nuxt@3.20.2(@parcel/watcher@2.5.1)(@types/node@20.19.27)(@vue/compiler-sfc@3.5.26)(cac@6.7.14)(db0@0.3.4)(eslint@9.39.2(jiti@1.21.7))(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.5.1)(optionator@0.9.4)(rollup@4.54.0)(sass@1.97.1)(terser@5.44.1)(typescript@5.9.3)(vite@7.3.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))(vue-tsc@2.2.12(typescript@5.9.3))(xml2js@0.6.2)(yaml@2.8.2):
|
nuxt@3.20.2(@parcel/watcher@2.5.1)(@types/node@20.19.27)(@vue/compiler-sfc@3.5.26)(cac@6.7.14)(db0@0.3.4)(eslint@9.39.2(jiti@2.6.1))(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.5.1)(optionator@0.9.4)(rollup@4.54.0)(sass@1.97.1)(terser@5.44.1)(typescript@5.9.3)(vite@7.3.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))(vue-tsc@2.2.12(typescript@5.9.3))(xml2js@0.6.2)(yaml@2.8.2):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@dxup/nuxt': 0.2.2(magicast@0.5.1)
|
'@dxup/nuxt': 0.2.2(magicast@0.5.1)
|
||||||
'@nuxt/cli': 3.31.3(cac@6.7.14)(magicast@0.5.1)
|
'@nuxt/cli': 3.31.3(cac@6.7.14)(magicast@0.5.1)
|
||||||
'@nuxt/devtools': 3.1.1(vite@7.3.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))(vue@3.5.26(typescript@5.9.3))
|
'@nuxt/devtools': 3.1.1(vite@7.3.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))(vue@3.5.26(typescript@5.9.3))
|
||||||
'@nuxt/kit': 3.20.2(magicast@0.5.1)
|
'@nuxt/kit': 3.20.2(magicast@0.5.1)
|
||||||
'@nuxt/nitro-server': 3.20.2(db0@0.3.4)(ioredis@5.8.2)(magicast@0.5.1)(nuxt@3.20.2(@parcel/watcher@2.5.1)(@types/node@20.19.27)(@vue/compiler-sfc@3.5.26)(cac@6.7.14)(db0@0.3.4)(eslint@9.39.2(jiti@1.21.7))(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.5.1)(optionator@0.9.4)(rollup@4.54.0)(sass@1.97.1)(terser@5.44.1)(typescript@5.9.3)(vite@7.3.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))(vue-tsc@2.2.12(typescript@5.9.3))(xml2js@0.6.2)(yaml@2.8.2))(typescript@5.9.3)(xml2js@0.6.2)
|
'@nuxt/nitro-server': 3.20.2(db0@0.3.4)(ioredis@5.8.2)(magicast@0.5.1)(nuxt@3.20.2(@parcel/watcher@2.5.1)(@types/node@20.19.27)(@vue/compiler-sfc@3.5.26)(cac@6.7.14)(db0@0.3.4)(eslint@9.39.2(jiti@2.6.1))(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.5.1)(optionator@0.9.4)(rollup@4.54.0)(sass@1.97.1)(terser@5.44.1)(typescript@5.9.3)(vite@7.3.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))(vue-tsc@2.2.12(typescript@5.9.3))(xml2js@0.6.2)(yaml@2.8.2))(typescript@5.9.3)(xml2js@0.6.2)
|
||||||
'@nuxt/schema': 3.20.2
|
'@nuxt/schema': 3.20.2
|
||||||
'@nuxt/telemetry': 2.6.6(magicast@0.5.1)
|
'@nuxt/telemetry': 2.6.6(magicast@0.5.1)
|
||||||
'@nuxt/vite-builder': 3.20.2(@types/node@20.19.27)(eslint@9.39.2(jiti@1.21.7))(lightningcss@1.30.2)(magicast@0.5.1)(nuxt@3.20.2(@parcel/watcher@2.5.1)(@types/node@20.19.27)(@vue/compiler-sfc@3.5.26)(cac@6.7.14)(db0@0.3.4)(eslint@9.39.2(jiti@1.21.7))(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.5.1)(optionator@0.9.4)(rollup@4.54.0)(sass@1.97.1)(terser@5.44.1)(typescript@5.9.3)(vite@7.3.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))(vue-tsc@2.2.12(typescript@5.9.3))(xml2js@0.6.2)(yaml@2.8.2))(optionator@0.9.4)(rollup@4.54.0)(sass@1.97.1)(terser@5.44.1)(typescript@5.9.3)(vue-tsc@2.2.12(typescript@5.9.3))(vue@3.5.26(typescript@5.9.3))(yaml@2.8.2)
|
'@nuxt/vite-builder': 3.20.2(@types/node@20.19.27)(eslint@9.39.2(jiti@2.6.1))(lightningcss@1.30.2)(magicast@0.5.1)(nuxt@3.20.2(@parcel/watcher@2.5.1)(@types/node@20.19.27)(@vue/compiler-sfc@3.5.26)(cac@6.7.14)(db0@0.3.4)(eslint@9.39.2(jiti@2.6.1))(ioredis@5.8.2)(lightningcss@1.30.2)(magicast@0.5.1)(optionator@0.9.4)(rollup@4.54.0)(sass@1.97.1)(terser@5.44.1)(typescript@5.9.3)(vite@7.3.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))(vue-tsc@2.2.12(typescript@5.9.3))(xml2js@0.6.2)(yaml@2.8.2))(optionator@0.9.4)(rollup@4.54.0)(sass@1.97.1)(terser@5.44.1)(typescript@5.9.3)(vue-tsc@2.2.12(typescript@5.9.3))(vue@3.5.26(typescript@5.9.3))(yaml@2.8.2)
|
||||||
'@unhead/vue': 2.1.1(vue@3.5.26(typescript@5.9.3))
|
'@unhead/vue': 2.1.1(vue@3.5.26(typescript@5.9.3))
|
||||||
'@vue/shared': 3.5.26
|
'@vue/shared': 3.5.26
|
||||||
c12: 3.3.3(magicast@0.5.1)
|
c12: 3.3.3(magicast@0.5.1)
|
||||||
@@ -18959,12 +18977,12 @@ snapshots:
|
|||||||
vite-dev-rpc@1.1.0(vite@7.3.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)):
|
vite-dev-rpc@1.1.0(vite@7.3.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)):
|
||||||
dependencies:
|
dependencies:
|
||||||
birpc: 2.9.0
|
birpc: 2.9.0
|
||||||
vite: 7.3.0(@types/node@20.19.27)(jiti@1.21.7)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)
|
vite: 7.3.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)
|
||||||
vite-hot-client: 2.1.0(vite@7.3.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))
|
vite-hot-client: 2.1.0(vite@7.3.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))
|
||||||
|
|
||||||
vite-hot-client@2.1.0(vite@7.3.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)):
|
vite-hot-client@2.1.0(vite@7.3.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)):
|
||||||
dependencies:
|
dependencies:
|
||||||
vite: 7.3.0(@types/node@20.19.27)(jiti@1.21.7)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)
|
vite: 7.3.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)
|
||||||
|
|
||||||
vite-node@5.2.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2):
|
vite-node@5.2.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2):
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -18986,7 +19004,7 @@ snapshots:
|
|||||||
- tsx
|
- tsx
|
||||||
- yaml
|
- yaml
|
||||||
|
|
||||||
vite-plugin-checker@0.12.0(eslint@9.39.2(jiti@1.21.7))(optionator@0.9.4)(typescript@5.9.3)(vite@7.3.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))(vue-tsc@2.2.12(typescript@5.9.3)):
|
vite-plugin-checker@0.12.0(eslint@9.39.2(jiti@2.6.1))(optionator@0.9.4)(typescript@5.9.3)(vite@7.3.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))(vue-tsc@2.2.12(typescript@5.9.3)):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/code-frame': 7.27.1
|
'@babel/code-frame': 7.27.1
|
||||||
chokidar: 4.0.3
|
chokidar: 4.0.3
|
||||||
@@ -18995,10 +19013,10 @@ snapshots:
|
|||||||
picomatch: 4.0.3
|
picomatch: 4.0.3
|
||||||
tiny-invariant: 1.3.3
|
tiny-invariant: 1.3.3
|
||||||
tinyglobby: 0.2.15
|
tinyglobby: 0.2.15
|
||||||
vite: 7.3.0(@types/node@20.19.27)(jiti@1.21.7)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)
|
vite: 7.3.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)
|
||||||
vscode-uri: 3.1.0
|
vscode-uri: 3.1.0
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
eslint: 9.39.2(jiti@1.21.7)
|
eslint: 9.39.2(jiti@2.6.1)
|
||||||
optionator: 0.9.4
|
optionator: 0.9.4
|
||||||
typescript: 5.9.3
|
typescript: 5.9.3
|
||||||
vue-tsc: 2.2.12(typescript@5.9.3)
|
vue-tsc: 2.2.12(typescript@5.9.3)
|
||||||
@@ -19013,7 +19031,7 @@ snapshots:
|
|||||||
perfect-debounce: 2.0.0
|
perfect-debounce: 2.0.0
|
||||||
sirv: 3.0.2
|
sirv: 3.0.2
|
||||||
unplugin-utils: 0.3.1
|
unplugin-utils: 0.3.1
|
||||||
vite: 7.3.0(@types/node@20.19.27)(jiti@1.21.7)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)
|
vite: 7.3.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)
|
||||||
vite-dev-rpc: 1.1.0(vite@7.3.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))
|
vite-dev-rpc: 1.1.0(vite@7.3.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@nuxt/kit': 4.2.2(magicast@0.5.1)
|
'@nuxt/kit': 4.2.2(magicast@0.5.1)
|
||||||
@@ -19027,7 +19045,7 @@ snapshots:
|
|||||||
magic-string: 0.30.21
|
magic-string: 0.30.21
|
||||||
pathe: 2.0.3
|
pathe: 2.0.3
|
||||||
source-map-js: 1.2.1
|
source-map-js: 1.2.1
|
||||||
vite: 7.3.0(@types/node@20.19.27)(jiti@1.21.7)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)
|
vite: 7.3.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)
|
||||||
vue: 3.5.26(typescript@5.9.3)
|
vue: 3.5.26(typescript@5.9.3)
|
||||||
|
|
||||||
vite-svg-loader@5.1.0(vue@3.5.26(typescript@5.9.3)):
|
vite-svg-loader@5.1.0(vue@3.5.26(typescript@5.9.3)):
|
||||||
@@ -19047,6 +19065,23 @@ snapshots:
|
|||||||
sass: 1.97.1
|
sass: 1.97.1
|
||||||
terser: 5.44.1
|
terser: 5.44.1
|
||||||
|
|
||||||
|
vite@6.4.1(@types/node@20.19.27)(jiti@1.21.7)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2):
|
||||||
|
dependencies:
|
||||||
|
esbuild: 0.25.12
|
||||||
|
fdir: 6.5.0(picomatch@4.0.3)
|
||||||
|
picomatch: 4.0.3
|
||||||
|
postcss: 8.5.6
|
||||||
|
rollup: 4.54.0
|
||||||
|
tinyglobby: 0.2.15
|
||||||
|
optionalDependencies:
|
||||||
|
'@types/node': 20.19.27
|
||||||
|
fsevents: 2.3.3
|
||||||
|
jiti: 1.21.7
|
||||||
|
lightningcss: 1.30.2
|
||||||
|
sass: 1.97.1
|
||||||
|
terser: 5.44.1
|
||||||
|
yaml: 2.8.2
|
||||||
|
|
||||||
vite@6.4.1(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2):
|
vite@6.4.1(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2):
|
||||||
dependencies:
|
dependencies:
|
||||||
esbuild: 0.25.12
|
esbuild: 0.25.12
|
||||||
@@ -19064,23 +19099,6 @@ snapshots:
|
|||||||
terser: 5.44.1
|
terser: 5.44.1
|
||||||
yaml: 2.8.2
|
yaml: 2.8.2
|
||||||
|
|
||||||
vite@7.3.0(@types/node@20.19.27)(jiti@1.21.7)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2):
|
|
||||||
dependencies:
|
|
||||||
esbuild: 0.27.2
|
|
||||||
fdir: 6.5.0(picomatch@4.0.3)
|
|
||||||
picomatch: 4.0.3
|
|
||||||
postcss: 8.5.6
|
|
||||||
rollup: 4.54.0
|
|
||||||
tinyglobby: 0.2.15
|
|
||||||
optionalDependencies:
|
|
||||||
'@types/node': 20.19.27
|
|
||||||
fsevents: 2.3.3
|
|
||||||
jiti: 1.21.7
|
|
||||||
lightningcss: 1.30.2
|
|
||||||
sass: 1.97.1
|
|
||||||
terser: 5.44.1
|
|
||||||
yaml: 2.8.2
|
|
||||||
|
|
||||||
vite@7.3.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2):
|
vite@7.3.0(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2):
|
||||||
dependencies:
|
dependencies:
|
||||||
esbuild: 0.27.2
|
esbuild: 0.27.2
|
||||||
@@ -19102,10 +19120,10 @@ snapshots:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
vite: 6.4.1(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)
|
vite: 6.4.1(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)
|
||||||
|
|
||||||
vitest@4.0.16(@opentelemetry/api@1.9.0)(@types/node@20.19.27)(@vitest/browser-playwright@4.0.16)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2):
|
vitest@4.0.16(@opentelemetry/api@1.9.0)(@types/node@20.19.27)(@vitest/browser-playwright@4.0.16)(jiti@1.21.7)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vitest/expect': 4.0.16
|
'@vitest/expect': 4.0.16
|
||||||
'@vitest/mocker': 4.0.16(vite@6.4.1(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))
|
'@vitest/mocker': 4.0.16(vite@6.4.1(@types/node@20.19.27)(jiti@1.21.7)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2))
|
||||||
'@vitest/pretty-format': 4.0.16
|
'@vitest/pretty-format': 4.0.16
|
||||||
'@vitest/runner': 4.0.16
|
'@vitest/runner': 4.0.16
|
||||||
'@vitest/snapshot': 4.0.16
|
'@vitest/snapshot': 4.0.16
|
||||||
@@ -19122,7 +19140,7 @@ snapshots:
|
|||||||
tinyexec: 1.0.2
|
tinyexec: 1.0.2
|
||||||
tinyglobby: 0.2.15
|
tinyglobby: 0.2.15
|
||||||
tinyrainbow: 3.0.3
|
tinyrainbow: 3.0.3
|
||||||
vite: 6.4.1(@types/node@20.19.27)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)
|
vite: 6.4.1(@types/node@20.19.27)(jiti@1.21.7)(lightningcss@1.30.2)(sass@1.97.1)(terser@5.44.1)(yaml@2.8.2)
|
||||||
why-is-node-running: 2.3.0
|
why-is-node-running: 2.3.0
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@opentelemetry/api': 1.9.0
|
'@opentelemetry/api': 1.9.0
|
||||||
@@ -19257,7 +19275,7 @@ snapshots:
|
|||||||
|
|
||||||
vue-component-type-helpers@3.2.1: {}
|
vue-component-type-helpers@3.2.1: {}
|
||||||
|
|
||||||
vue-component-type-helpers@3.2.2: {}
|
vue-component-type-helpers@3.2.4: {}
|
||||||
|
|
||||||
vue-confetti-explosion@1.0.2(vue@3.5.26(typescript@5.9.3)):
|
vue-confetti-explosion@1.0.2(vue@3.5.26(typescript@5.9.3)):
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|||||||
Reference in New Issue
Block a user