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
|
||||
.claude
|
||||
.letta
|
||||
|
||||
# labrinth demo fixtures
|
||||
apps/labrinth/fixtures/demo
|
||||
|
||||
@@ -1647,6 +1647,15 @@ async function resetVersions() {
|
||||
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
|
||||
const patchProjectMutation = useMutation({
|
||||
mutationFn: async ({ projectId, data }) => {
|
||||
@@ -1691,12 +1700,7 @@ const patchProjectMutation = useMutation({
|
||||
},
|
||||
|
||||
onSettled: async (_data, _error, { projectId }) => {
|
||||
// Invalidate both slug-based and ID-based cache keys to ensure consistency
|
||||
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] })
|
||||
await invalidateProjectQueries(projectId)
|
||||
},
|
||||
})
|
||||
|
||||
@@ -1741,11 +1745,7 @@ const patchStatusMutation = useMutation({
|
||||
},
|
||||
|
||||
onSettled: async (_data, _error, { projectId }) => {
|
||||
// Invalidate both slug-based and ID-based cache keys to ensure consistency
|
||||
await queryClient.invalidateQueries({ queryKey: ['project', 'v2', routeProjectId.value] })
|
||||
if (routeProjectId.value !== projectId) {
|
||||
await queryClient.invalidateQueries({ queryKey: ['project', 'v2', projectId] })
|
||||
}
|
||||
await invalidateProjectQueries(projectId)
|
||||
},
|
||||
})
|
||||
|
||||
@@ -1779,8 +1779,171 @@ const patchIconMutation = useMutation({
|
||||
},
|
||||
|
||||
onSettled: async (_data, _error, { projectId }) => {
|
||||
await queryClient.invalidateQueries({ queryKey: ['project', 'v2', projectId] })
|
||||
await queryClient.invalidateQueries({ queryKey: ['project', 'v3', projectId] })
|
||||
await invalidateProjectQueries(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() {
|
||||
// Simply invalidate and refetch - the computed allMembers will auto-update
|
||||
await queryClient.invalidateQueries({ queryKey: ['project', projectId.value, 'members'] })
|
||||
@@ -2103,6 +2311,11 @@ provideProjectPageContext({
|
||||
patchProject,
|
||||
patchIcon,
|
||||
setProcessing,
|
||||
|
||||
// Gallery mutation functions
|
||||
createGalleryItem,
|
||||
editGalleryItem,
|
||||
deleteGalleryItem,
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
</span>
|
||||
</div>
|
||||
<MarkdownEditor
|
||||
v-model="description"
|
||||
v-model="current.description"
|
||||
:disabled="
|
||||
!currentMember ||
|
||||
(currentMember?.permissions! & TeamMemberPermission.EDIT_BODY) !==
|
||||
@@ -26,36 +26,42 @@
|
||||
<TriangleAlertIcon class="my-auto" />
|
||||
{{ descriptionWarning }}
|
||||
</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>
|
||||
<UnsavedChangesPopup
|
||||
:original="saved"
|
||||
:modified="current"
|
||||
:saving="saving"
|
||||
@reset="reset"
|
||||
@save="save"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { SaveIcon, TriangleAlertIcon } from '@modrinth/assets'
|
||||
import { TriangleAlertIcon } from '@modrinth/assets'
|
||||
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 { computed, ref } from 'vue'
|
||||
import { computed } from 'vue'
|
||||
|
||||
import { useImageUpload } from '~/composables/image-upload.ts'
|
||||
|
||||
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 text = description.value?.trim() || ''
|
||||
const text = current.value.description?.trim() || ''
|
||||
const charCount = countText(text)
|
||||
|
||||
if (charCount < MIN_DESCRIPTION_CHARS) {
|
||||
@@ -65,26 +71,6 @@ const descriptionWarning = computed(() => {
|
||||
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) {
|
||||
const response = await useImageUpload(file, {
|
||||
context: 'project',
|
||||
|
||||
@@ -299,15 +299,19 @@ import {
|
||||
ConfirmModal,
|
||||
DropArea,
|
||||
FileInput,
|
||||
injectNotificationManager,
|
||||
injectProjectPageContext,
|
||||
NewModal as Modal,
|
||||
} from '@modrinth/ui'
|
||||
|
||||
import { isPermission } from '~/utils/permissions.ts'
|
||||
|
||||
const { addNotification } = injectNotificationManager()
|
||||
const { projectV2: project, currentMember, refreshProject } = injectProjectPageContext()
|
||||
const {
|
||||
projectV2: project,
|
||||
currentMember,
|
||||
createGalleryItem: createGalleryItemMutation,
|
||||
editGalleryItem: editGalleryItemMutation,
|
||||
deleteGalleryItem: deleteGalleryItemMutation,
|
||||
} = injectProjectPageContext()
|
||||
|
||||
const title = `${project.value.title} - Gallery`
|
||||
const description = `View ${project.value.gallery?.length ?? 0} images of ${project.value.title} on Modrinth.`
|
||||
@@ -391,103 +395,42 @@ const showPreviewImage = () => {
|
||||
|
||||
const createGalleryItem = async () => {
|
||||
shouldPreventActions.value = true
|
||||
startLoading()
|
||||
|
||||
try {
|
||||
let url = `project/${project.value.id}/gallery?ext=${
|
||||
editFile.value
|
||||
? editFile.value.type.split('/')[editFile.value.type.split('/').length - 1]
|
||||
: null
|
||||
}&featured=${editFeatured.value}`
|
||||
|
||||
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()
|
||||
const success = await createGalleryItemMutation(
|
||||
editFile.value,
|
||||
editTitle.value || undefined,
|
||||
editDescription.value || undefined,
|
||||
editFeatured.value,
|
||||
editOrder.value ?? undefined,
|
||||
)
|
||||
|
||||
if (success) {
|
||||
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
|
||||
}
|
||||
|
||||
const editGalleryItem = async () => {
|
||||
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) {
|
||||
url += `&title=${encodeURIComponent(editTitle.value)}`
|
||||
}
|
||||
if (editDescription.value) {
|
||||
url += `&description=${encodeURIComponent(editDescription.value)}`
|
||||
}
|
||||
if (editOrder.value) {
|
||||
url += `&ordering=${editOrder.value}`
|
||||
}
|
||||
const success = await editGalleryItemMutation(
|
||||
project.value.gallery[editIndex.value].url,
|
||||
editTitle.value || undefined,
|
||||
editDescription.value || undefined,
|
||||
editFeatured.value,
|
||||
editOrder.value ?? undefined,
|
||||
)
|
||||
|
||||
await useBaseFetch(url, {
|
||||
method: 'PATCH',
|
||||
})
|
||||
|
||||
await refreshProject()
|
||||
if (success) {
|
||||
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
|
||||
}
|
||||
|
||||
const deleteGalleryImage = async () => {
|
||||
startLoading()
|
||||
|
||||
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()
|
||||
await deleteGalleryItemMutation(project.value.gallery[deleteIndex.value].url)
|
||||
}
|
||||
|
||||
const handleKeydown = (e) => {
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
import {
|
||||
defineMessages,
|
||||
IconSelect,
|
||||
injectModrinthClient,
|
||||
injectNotificationManager,
|
||||
injectProjectPageContext,
|
||||
type MessageDescriptor,
|
||||
SettingsLabel,
|
||||
@@ -14,34 +12,21 @@ import {
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
const { projectV2: project, refreshProject } = injectProjectPageContext()
|
||||
const { handleError } = injectNotificationManager()
|
||||
const client = injectModrinthClient()
|
||||
const { projectV2: project, patchProject } = injectProjectPageContext()
|
||||
|
||||
const saving = ref(false)
|
||||
|
||||
const { saved, current, reset, save } = useSavable(
|
||||
const { saved, current, saving, reset, save } = useSavable(
|
||||
() => ({
|
||||
title: project.value.title,
|
||||
tagline: project.value.description,
|
||||
url: project.value.slug,
|
||||
icon: project.value.icon_url,
|
||||
}),
|
||||
({ title, tagline, url }) => {
|
||||
const data: Record<string, string> = {
|
||||
async ({ title, tagline, url }) => {
|
||||
await patchProject({
|
||||
...(title !== undefined && { title }),
|
||||
...(tagline !== undefined && { description: tagline }),
|
||||
...(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">
|
||||
<DropdownSelect
|
||||
v-model="license"
|
||||
v-model="current.license"
|
||||
name="License selector"
|
||||
:options="builtinLicenses"
|
||||
:display-name="(chosen: BuiltinLicense) => chosen.friendly"
|
||||
@@ -37,7 +37,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="license.requiresOnlyOrLater" class="adjacent-input">
|
||||
<div v-if="current.license.requiresOnlyOrLater" class="adjacent-input">
|
||||
<label for="or-later-checkbox">
|
||||
<span class="label__title">Later editions</span>
|
||||
<span class="label__description">
|
||||
@@ -48,7 +48,7 @@
|
||||
|
||||
<Checkbox
|
||||
id="or-later-checkbox"
|
||||
v-model="allowOrLater"
|
||||
v-model="current.allowOrLater"
|
||||
:disabled="!hasPermission"
|
||||
description="Allow later editions"
|
||||
class="w-1/2"
|
||||
@@ -60,7 +60,7 @@
|
||||
<div class="adjacent-input">
|
||||
<label for="license-url">
|
||||
<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
|
||||
will be displayed instead.
|
||||
</span>
|
||||
@@ -73,18 +73,20 @@
|
||||
<div class="w-1/2">
|
||||
<input
|
||||
id="license-url"
|
||||
v-model="licenseUrl"
|
||||
v-model="current.licenseUrl"
|
||||
type="url"
|
||||
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'"
|
||||
class="w-full"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="license?.friendly === 'Custom'" class="adjacent-input">
|
||||
<label v-if="!nonSpdxLicense" for="license-spdx">
|
||||
<div v-if="current.license?.friendly === 'Custom'" class="adjacent-input">
|
||||
<label v-if="!current.nonSpdxLicense" for="license-spdx">
|
||||
<span class="label__title">SPDX identifier</span>
|
||||
<span class="label__description">
|
||||
If your license does not have an offical
|
||||
@@ -93,7 +95,7 @@
|
||||
>, check the box and enter the name of the license instead.
|
||||
</span>
|
||||
</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__description"
|
||||
>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">
|
||||
<input
|
||||
v-if="!nonSpdxLicense"
|
||||
v-if="!current.nonSpdxLicense"
|
||||
id="license-spdx"
|
||||
v-model="license.short"
|
||||
v-model="current.license.short"
|
||||
class="w-full"
|
||||
type="text"
|
||||
maxlength="128"
|
||||
@@ -115,7 +117,7 @@
|
||||
<input
|
||||
v-else
|
||||
id="license-name"
|
||||
v-model="license.short"
|
||||
v-model="current.license.short"
|
||||
class="w-full"
|
||||
type="text"
|
||||
maxlength="128"
|
||||
@@ -124,8 +126,8 @@
|
||||
/>
|
||||
|
||||
<Checkbox
|
||||
v-if="license?.friendly === 'Custom'"
|
||||
v-model="nonSpdxLicense"
|
||||
v-if="current.license?.friendly === 'Custom'"
|
||||
v-model="current.nonSpdxLicense"
|
||||
:disabled="!hasPermission"
|
||||
description="License does not have a SPDX identifier"
|
||||
>
|
||||
@@ -133,74 +135,91 @@
|
||||
</Checkbox>
|
||||
</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>
|
||||
<UnsavedChangesPopup
|
||||
:original="saved"
|
||||
:modified="current"
|
||||
:saving="saving"
|
||||
:can-save="
|
||||
hasPermission &&
|
||||
!(
|
||||
current.license.friendly === 'Custom' &&
|
||||
(current.license.short === '' || current.licenseUrl === '')
|
||||
)
|
||||
"
|
||||
@reset="reset"
|
||||
@save="save"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { SaveIcon } from '@modrinth/assets'
|
||||
import { Checkbox, DropdownSelect, injectProjectPageContext } from '@modrinth/ui'
|
||||
import {
|
||||
Checkbox,
|
||||
DropdownSelect,
|
||||
injectProjectPageContext,
|
||||
UnsavedChangesPopup,
|
||||
useSavable,
|
||||
} from '@modrinth/ui'
|
||||
import {
|
||||
type BuiltinLicense,
|
||||
builtinLicenses,
|
||||
formatProjectType,
|
||||
TeamMemberPermission,
|
||||
} from '@modrinth/utils'
|
||||
import { computed, type Ref, ref } from 'vue'
|
||||
import { computed } from 'vue'
|
||||
|
||||
const { projectV2: project, currentMember, patchProject } = injectProjectPageContext()
|
||||
|
||||
const licenseUrl = ref(project.value.license.url)
|
||||
const license: Ref<{
|
||||
friendly: string
|
||||
short: string
|
||||
requiresOnlyOrLater?: boolean
|
||||
}> = ref({
|
||||
friendly: '',
|
||||
short: '',
|
||||
requiresOnlyOrLater: false,
|
||||
})
|
||||
function getInitialLicense() {
|
||||
const oldLicenseId = project.value.license.id
|
||||
const trimmedLicenseId = oldLicenseId
|
||||
.replaceAll('-only', '')
|
||||
.replaceAll('-or-later', '')
|
||||
.replaceAll('LicenseRef-', '')
|
||||
|
||||
const allowOrLater = ref(project.value.license.id.includes('-or-later'))
|
||||
const nonSpdxLicense = ref(project.value.license.id.includes('LicenseRef-'))
|
||||
|
||||
const oldLicenseId = project.value.license.id
|
||||
const trimmedLicenseId = oldLicenseId
|
||||
.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,
|
||||
if (oldLicenseId === 'LicenseRef-Unknown') {
|
||||
return {
|
||||
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(() => {
|
||||
return (currentMember.value?.permissions ?? 0) & TeamMemberPermission.EDIT_DETAILS
|
||||
})
|
||||
@@ -209,47 +228,22 @@ const licenseId = computed(() => {
|
||||
let id = ''
|
||||
|
||||
if (
|
||||
(nonSpdxLicense.value && license.value.friendly === 'Custom') ||
|
||||
license.value.short === 'All-Rights-Reserved' ||
|
||||
license.value.short === 'Unknown'
|
||||
(current.value.nonSpdxLicense && current.value.license.friendly === 'Custom') ||
|
||||
current.value.license.short === 'All-Rights-Reserved' ||
|
||||
current.value.license.short === 'Unknown'
|
||||
) {
|
||||
id += 'LicenseRef-'
|
||||
}
|
||||
|
||||
id += license.value.short
|
||||
if (license.value.requiresOnlyOrLater) {
|
||||
id += allowOrLater.value ? '-or-later' : '-only'
|
||||
id += current.value.license.short
|
||||
if (current.value.license.requiresOnlyOrLater) {
|
||||
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(' ', '-')
|
||||
}
|
||||
|
||||
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>
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
<Checkbox
|
||||
v-for="category in categoryLists[header]"
|
||||
:key="`category-${header}-${category.name}`"
|
||||
:model-value="selectedTags.includes(category)"
|
||||
:model-value="current.selectedTags.includes(category)"
|
||||
:description="formatCategory(category.name)"
|
||||
class="category-selector"
|
||||
@update:model-value="toggleCategory(category)"
|
||||
@@ -91,17 +91,17 @@
|
||||
featured if you do not select all 3.
|
||||
</span>
|
||||
</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.
|
||||
</p>
|
||||
<div class="category-list input-div">
|
||||
<Checkbox
|
||||
v-for="category in selectedTags"
|
||||
v-for="category in current.selectedTags"
|
||||
:key="`featured-category-${category.name}`"
|
||||
class="category-selector"
|
||||
:model-value="featuredTags.includes(category)"
|
||||
:model-value="current.featuredTags.includes(category)"
|
||||
: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)"
|
||||
>
|
||||
<div class="category-selector__label">
|
||||
@@ -116,32 +116,27 @@
|
||||
</Checkbox>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="button-group">
|
||||
<button
|
||||
type="button"
|
||||
class="iconified-button brand-button"
|
||||
:disabled="!hasChanges"
|
||||
@click="saveChanges()"
|
||||
>
|
||||
<SaveIcon />
|
||||
Save changes
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
<UnsavedChangesPopup
|
||||
:original="saved"
|
||||
:modified="current"
|
||||
:saving="saving"
|
||||
@reset="reset"
|
||||
@save="save"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { SaveIcon, StarIcon, TriangleAlertIcon } from '@modrinth/assets'
|
||||
import { Checkbox, injectProjectPageContext } from '@modrinth/ui'
|
||||
import { StarIcon, TriangleAlertIcon } from '@modrinth/assets'
|
||||
import { Checkbox, injectProjectPageContext, UnsavedChangesPopup, useSavable } from '@modrinth/ui'
|
||||
import {
|
||||
formatCategory,
|
||||
formatCategoryHeader,
|
||||
formatProjectType,
|
||||
sortedCategories,
|
||||
} from '@modrinth/utils'
|
||||
import { computed, ref } from 'vue'
|
||||
import { computed } from 'vue'
|
||||
|
||||
interface Category {
|
||||
name: string
|
||||
@@ -154,21 +149,56 @@ const tags = useGeneratedState()
|
||||
|
||||
const { projectV2: project, patchProject } = injectProjectPageContext()
|
||||
|
||||
const selectedTags = ref<Category[]>(
|
||||
sortedCategories(tags.value).filter(
|
||||
(x: Category) =>
|
||||
x.project_type === project.value.actualProjectType &&
|
||||
(project.value.categories.includes(x.name) ||
|
||||
project.value.additional_categories.includes(x.name)),
|
||||
),
|
||||
)
|
||||
const { saved, current, saving, reset, save } = useSavable(
|
||||
() => ({
|
||||
selectedTags: sortedCategories(tags.value).filter(
|
||||
(x: Category) =>
|
||||
x.project_type === project.value.actualProjectType &&
|
||||
(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[]>(
|
||||
sortedCategories(tags.value).filter(
|
||||
(x: Category) =>
|
||||
x.project_type === project.value.actualProjectType &&
|
||||
project.value.categories.includes(x.name),
|
||||
),
|
||||
// Convert selected and featured categories to backend-usable arrays
|
||||
const categories = newFeaturedTags.map((x) => x.name)
|
||||
const additionalCategories = current.value.selectedTags
|
||||
.filter((x) => !newFeaturedTags.includes(x))
|
||||
.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(() => {
|
||||
@@ -186,7 +216,7 @@ const categoryLists = computed(() => {
|
||||
})
|
||||
|
||||
const tooManyTagsWarning = computed(() => {
|
||||
const tagCount = selectedTags.value.length
|
||||
const tagCount = current.value.selectedTags.length
|
||||
if (tagCount > 8) {
|
||||
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(() => {
|
||||
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),
|
||||
)
|
||||
|
||||
@@ -217,7 +247,7 @@ const allTagsSelectedWarning = computed(() => {
|
||||
const categoriesForProjectType = sortedCategories(tags.value).filter(
|
||||
(x: Category) => x.project_type === project.value.actualProjectType,
|
||||
)
|
||||
const totalSelectedTags = selectedTags.value.length
|
||||
const totalSelectedTags = current.value.selectedTags.length
|
||||
|
||||
if (
|
||||
totalSelectedTags === categoriesForProjectType.length &&
|
||||
@@ -228,68 +258,22 @@ const allTagsSelectedWarning = computed(() => {
|
||||
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) => {
|
||||
if (selectedTags.value.includes(category)) {
|
||||
selectedTags.value = selectedTags.value.filter((x) => x !== category)
|
||||
if (featuredTags.value.includes(category)) {
|
||||
featuredTags.value = featuredTags.value.filter((x) => x !== category)
|
||||
if (current.value.selectedTags.includes(category)) {
|
||||
current.value.selectedTags = current.value.selectedTags.filter((x) => x !== category)
|
||||
if (current.value.featuredTags.includes(category)) {
|
||||
current.value.featuredTags = current.value.featuredTags.filter((x) => x !== category)
|
||||
}
|
||||
} else {
|
||||
selectedTags.value.push(category)
|
||||
current.value.selectedTags = [...current.value.selectedTags, category]
|
||||
}
|
||||
}
|
||||
|
||||
const toggleFeaturedCategory = (category: Category) => {
|
||||
if (featuredTags.value.includes(category)) {
|
||||
featuredTags.value = featuredTags.value.filter((x) => x !== category)
|
||||
if (current.value.featuredTags.includes(category)) {
|
||||
current.value.featuredTags = current.value.featuredTags.filter((x) => x !== category)
|
||||
} else {
|
||||
featuredTags.value.push(category)
|
||||
}
|
||||
}
|
||||
|
||||
const saveChanges = () => {
|
||||
if (hasChanges.value) {
|
||||
patchProject(patchData.value)
|
||||
current.value.featuredTags = [...current.value.featuredTags, category]
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
<script setup>
|
||||
import { SaveIcon, TrashIcon, UploadIcon } from '@modrinth/assets'
|
||||
import { Avatar, Button, ConfirmModal, FileInput, injectNotificationManager } from '@modrinth/ui'
|
||||
import { TrashIcon, UploadIcon } from '@modrinth/assets'
|
||||
import {
|
||||
Avatar,
|
||||
Button,
|
||||
ConfirmModal,
|
||||
FileInput,
|
||||
injectNotificationManager,
|
||||
UnsavedChangesPopup,
|
||||
useSavable,
|
||||
} from '@modrinth/ui'
|
||||
|
||||
import { injectOrganizationContext } from '~/providers/organization-context.ts'
|
||||
|
||||
@@ -14,32 +22,49 @@ const {
|
||||
patchOrganization,
|
||||
} = injectOrganizationContext()
|
||||
|
||||
// Icon state (separate from useSavable, like collection page)
|
||||
const icon = ref(null)
|
||||
const deletedIcon = ref(false)
|
||||
const previewImage = ref(null)
|
||||
|
||||
const name = ref(organization.value.name)
|
||||
const slug = ref(organization.value.slug)
|
||||
const {
|
||||
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 data = {}
|
||||
if (name.value !== organization.value.name) {
|
||||
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 modifiedState = computed(() => ({
|
||||
...current.value,
|
||||
iconChanged: !!(deletedIcon.value || icon.value),
|
||||
}))
|
||||
|
||||
const hasChanges = computed(() => {
|
||||
return Object.keys(patchData.value).length > 0 || deletedIcon.value || icon.value
|
||||
})
|
||||
const reset = () => {
|
||||
resetFields()
|
||||
icon.value = null
|
||||
deletedIcon.value = false
|
||||
previewImage.value = null
|
||||
}
|
||||
|
||||
const markIconForDeletion = () => {
|
||||
deletedIcon.value = true
|
||||
@@ -61,11 +86,16 @@ const showPreviewImage = (files) => {
|
||||
|
||||
const orgId = useRouteId()
|
||||
|
||||
const onSaveChanges = useClientTry(async () => {
|
||||
// Only PATCH organization details if there are actual field changes
|
||||
const hasOrgFieldChanges = Object.keys(patchData.value).length > 0
|
||||
if (hasOrgFieldChanges) {
|
||||
await patchOrganization(patchData.value)
|
||||
const save = async () => {
|
||||
// Save field changes via useSavable
|
||||
if (hasFieldChanges.value) {
|
||||
await patchOrganization({
|
||||
...(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
|
||||
@@ -85,7 +115,7 @@ const onSaveChanges = useClientTry(async () => {
|
||||
text: 'Your organization has been updated.',
|
||||
type: 'success',
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const onDeleteOrganization = useClientTry(async () => {
|
||||
await useBaseFetch(`organization/${orgId}`, {
|
||||
@@ -159,7 +189,7 @@ const onDeleteOrganization = useClientTry(async () => {
|
||||
</label>
|
||||
<input
|
||||
id="project-name"
|
||||
v-model="name"
|
||||
v-model="current.name"
|
||||
maxlength="2048"
|
||||
type="text"
|
||||
:disabled="!hasPermission"
|
||||
@@ -172,7 +202,7 @@ const onDeleteOrganization = useClientTry(async () => {
|
||||
<div class="text-input-wrapper__before">https://modrinth.com/organization/</div>
|
||||
<input
|
||||
id="project-slug"
|
||||
v-model="slug"
|
||||
v-model="current.slug"
|
||||
type="text"
|
||||
maxlength="64"
|
||||
autocomplete="off"
|
||||
@@ -186,17 +216,11 @@ const onDeleteOrganization = useClientTry(async () => {
|
||||
<div class="textarea-wrapper summary-input">
|
||||
<textarea
|
||||
id="project-summary"
|
||||
v-model="summary"
|
||||
v-model="current.summary"
|
||||
maxlength="256"
|
||||
:disabled="!hasPermission"
|
||||
/>
|
||||
</div>
|
||||
<div class="button-group">
|
||||
<Button color="primary" :disabled="!hasChanges" @click="onSaveChanges">
|
||||
<SaveIcon />
|
||||
Save changes
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="universal-card">
|
||||
<div class="label">
|
||||
@@ -213,6 +237,13 @@ const onDeleteOrganization = useClientTry(async () => {
|
||||
Delete organization
|
||||
</Button>
|
||||
</div>
|
||||
<UnsavedChangesPopup
|
||||
:original="originalState"
|
||||
:modified="modifiedState"
|
||||
:saving="saving"
|
||||
@reset="reset"
|
||||
@save="save"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -56,41 +56,32 @@
|
||||
{{ formatMessage(messages.usernameDescription) }}
|
||||
</span>
|
||||
</label>
|
||||
<input id="username-field" v-model="username" type="text" />
|
||||
<input id="username-field" v-model="current.username" type="text" />
|
||||
<label for="bio-field">
|
||||
<span class="label__title">{{ formatMessage(messages.bioTitle) }}</span>
|
||||
<span class="label__description">
|
||||
{{ formatMessage(messages.bioDescription) }}
|
||||
</span>
|
||||
</label>
|
||||
<textarea id="bio-field" v-model="bio" type="text" />
|
||||
<div v-if="hasUnsavedChanges" 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>
|
||||
<textarea id="bio-field" v-model="current.bio" type="text" />
|
||||
<div class="input-group">
|
||||
<Button :link="`/user/${auth.user.username}`">
|
||||
<UserIcon /> {{ formatMessage(commonMessages.visitYourProfile) }}
|
||||
</Button>
|
||||
</div>
|
||||
</section>
|
||||
<UnsavedChangesPopup
|
||||
:original="originalState"
|
||||
:modified="modifiedState"
|
||||
:saving="saving"
|
||||
@reset="reset"
|
||||
@save="save"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { SaveIcon, TrashIcon, UndoIcon, UploadIcon, UserIcon, XIcon } from '@modrinth/assets'
|
||||
import { TrashIcon, UndoIcon, UploadIcon, UserIcon } from '@modrinth/assets'
|
||||
import {
|
||||
Avatar,
|
||||
Button,
|
||||
@@ -99,6 +90,8 @@ import {
|
||||
FileInput,
|
||||
injectNotificationManager,
|
||||
IntlFormatted,
|
||||
UnsavedChangesPopup,
|
||||
useSavable,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
|
||||
@@ -151,21 +144,43 @@ const messages = defineMessages({
|
||||
|
||||
const auth = await useAuth()
|
||||
|
||||
const username = ref(auth.value.user.username)
|
||||
const bio = ref(auth.value.user.bio)
|
||||
// Avatar state (separate from useSavable)
|
||||
const avatarUrl = ref(auth.value.user.avatar_url)
|
||||
const icon = shallowRef(null)
|
||||
const previewImage = shallowRef(null)
|
||||
const pendingAvatarDeletion = ref(false)
|
||||
const saved = ref(false)
|
||||
const saving = ref(false)
|
||||
|
||||
const hasUnsavedChanges = computed(
|
||||
() =>
|
||||
username.value !== auth.value.user.username ||
|
||||
bio.value !== auth.value.user.bio ||
|
||||
previewImage.value,
|
||||
const {
|
||||
saved,
|
||||
current,
|
||||
reset: resetFields,
|
||||
} = 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) {
|
||||
const reader = new FileReader()
|
||||
icon.value = files[0]
|
||||
@@ -180,16 +195,8 @@ function removePreviewImage() {
|
||||
previewImage.value = 'https://cdn.modrinth.com/placeholder.png'
|
||||
}
|
||||
|
||||
function cancel() {
|
||||
icon.value = null
|
||||
previewImage.value = null
|
||||
pendingAvatarDeletion.value = false
|
||||
username.value = auth.value.user.username
|
||||
bio.value = auth.value.user.bio
|
||||
}
|
||||
|
||||
async function saveChanges() {
|
||||
startLoading()
|
||||
async function save() {
|
||||
saving.value = true
|
||||
try {
|
||||
if (pendingAvatarDeletion.value) {
|
||||
await useBaseFetch(`user/${auth.value.user.id}/icon`, {
|
||||
@@ -215,12 +222,12 @@ async function saveChanges() {
|
||||
|
||||
const body = {}
|
||||
|
||||
if (auth.value.user.username !== username.value) {
|
||||
body.username = username.value
|
||||
if (auth.value.user.username !== current.value.username) {
|
||||
body.username = current.value.username
|
||||
}
|
||||
|
||||
if (auth.value.user.bio !== bio.value) {
|
||||
body.bio = bio.value
|
||||
if (auth.value.user.bio !== current.value.bio) {
|
||||
body.bio = current.value.bio
|
||||
}
|
||||
|
||||
await useBaseFetch(`user/${auth.value.user.id}`, {
|
||||
@@ -229,7 +236,6 @@ async function saveChanges() {
|
||||
})
|
||||
await useAuth(auth.value.token)
|
||||
avatarUrl.value = auth.value.user.avatar_url
|
||||
saved.value = true
|
||||
} catch (err) {
|
||||
addNotification({
|
||||
title: 'An error occurred',
|
||||
@@ -243,7 +249,7 @@ async function saveChanges() {
|
||||
type: 'error',
|
||||
})
|
||||
}
|
||||
stopLoading()
|
||||
saving.value = false
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -53,8 +53,6 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@codemirror/commands": "^6.3.2",
|
||||
"intl-messageformat": "^10.7.7",
|
||||
"vue-i18n": "^10.0.0",
|
||||
"@codemirror/lang-markdown": "^6.2.3",
|
||||
"@codemirror/language": "^6.9.3",
|
||||
"@codemirror/state": "^6.3.2",
|
||||
@@ -73,13 +71,16 @@
|
||||
"ace-builds": "^1.43.5",
|
||||
"apexcharts": "^4.0.0",
|
||||
"dayjs": "^1.11.10",
|
||||
"es-toolkit": "^1.44.0",
|
||||
"floating-vue": "^5.2.2",
|
||||
"fuse.js": "^6.6.2",
|
||||
"highlight.js": "^11.9.0",
|
||||
"intl-messageformat": "^10.7.7",
|
||||
"markdown-it": "^13.0.2",
|
||||
"postprocessing": "^6.37.6",
|
||||
"qrcode.vue": "^3.4.1",
|
||||
"three": "^0.172.0",
|
||||
"vue-i18n": "^10.0.0",
|
||||
"vue-multiselect": "3.0.0",
|
||||
"vue-select": "4.0.0-beta.6",
|
||||
"vue-typed-virtual-list": "^1.0.10",
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script setup lang="ts" generic="T">
|
||||
import { HistoryIcon, SaveIcon, SpinnerIcon } from '@modrinth/assets'
|
||||
import { isEqual } from 'es-toolkit'
|
||||
import { type Component, computed } from 'vue'
|
||||
|
||||
import { defineMessage, type MessageDescriptor, useVIntl } from '../../composables/i18n'
|
||||
@@ -38,15 +39,9 @@ const props = withDefaults(
|
||||
},
|
||||
)
|
||||
|
||||
const shown = computed(() => {
|
||||
let changed = false
|
||||
for (const key of Object.keys(props.modified)) {
|
||||
if (props.original[key] !== props.modified[key]) {
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
return changed
|
||||
})
|
||||
const shown = computed(() =>
|
||||
Object.keys(props.modified).some((key) => !isEqual(props.original[key], props.modified[key])),
|
||||
)
|
||||
|
||||
function localizeIfPossible(message: MessageDescriptor | string) {
|
||||
return typeof message === 'string' ? message : formatMessage(message)
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
useSavable,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { computed, ref } from 'vue'
|
||||
import { computed } from 'vue'
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
@@ -20,8 +20,6 @@ const { currentMember, projectV2, projectV3, refreshProject } = injectProjectPag
|
||||
const { handleError } = injectNotificationManager()
|
||||
const client = injectModrinthClient()
|
||||
|
||||
const saving = ref(false)
|
||||
|
||||
const supportsEnvironment = computed(() =>
|
||||
projectV3.value.project_types.some((type) => ['mod', 'modpack'].includes(type)),
|
||||
)
|
||||
@@ -36,26 +34,29 @@ const needsToVerify = computed(
|
||||
|
||||
const hasPermission = computed(() => {
|
||||
const EDIT_DETAILS = 1 << 2
|
||||
return (currentMember.value?.permissions & EDIT_DETAILS) === EDIT_DETAILS
|
||||
return ((currentMember.value?.permissions ?? 0) & EDIT_DETAILS) === EDIT_DETAILS
|
||||
})
|
||||
|
||||
function getInitialEnv() {
|
||||
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(),
|
||||
side_types_migration_review_status: projectV3.value.side_types_migration_review_status,
|
||||
}),
|
||||
({ environment, side_types_migration_review_status }) => {
|
||||
saving.value = true
|
||||
side_types_migration_review_status = 'reviewed'
|
||||
client.labrinth.projects_v3
|
||||
.edit(projectV2.value.id, { environment, side_types_migration_review_status })
|
||||
.then(() => refreshProject().then(reset))
|
||||
.catch(handleError)
|
||||
.finally(() => (saving.value = false))
|
||||
async ({ environment }) => {
|
||||
try {
|
||||
await client.labrinth.projects_v3.edit(projectV2.value.id, {
|
||||
environment,
|
||||
side_types_migration_review_status: 'reviewed',
|
||||
})
|
||||
await refreshProject()
|
||||
reset()
|
||||
} catch (err) {
|
||||
handleError(err as Error)
|
||||
}
|
||||
},
|
||||
)
|
||||
// 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>
|
||||
patchIcon: (icon: File) => Promise<boolean>
|
||||
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] =
|
||||
|
||||
@@ -1,37 +1,56 @@
|
||||
import { isEqual } from 'es-toolkit'
|
||||
import type { ComputedRef, Ref } from 'vue'
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
export function useSavable<T extends Record<string, unknown>>(
|
||||
data: () => T,
|
||||
save: (changes: Partial<T>) => void,
|
||||
save: (changes: Partial<T>) => void | Promise<void>,
|
||||
): {
|
||||
saved: ComputedRef<T>
|
||||
current: Ref<T>
|
||||
changes: ComputedRef<Partial<T>>
|
||||
hasChanges: ComputedRef<boolean>
|
||||
saving: Ref<boolean>
|
||||
reset: () => void
|
||||
save: () => void
|
||||
save: () => Promise<void>
|
||||
} {
|
||||
const savedValues = computed(data)
|
||||
const currentValues = ref({ ...data() }) as Ref<T>
|
||||
const saving = ref(false)
|
||||
|
||||
const changes = computed<Partial<T>>(() => {
|
||||
const values: Partial<T> = {}
|
||||
const keys = Object.keys(currentValues.value) as (keyof T)[]
|
||||
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]
|
||||
}
|
||||
}
|
||||
return values
|
||||
})
|
||||
|
||||
const hasChanges = computed(() => Object.keys(changes.value).length > 0)
|
||||
|
||||
const reset = () => {
|
||||
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 {
|
||||
saved: savedValues,
|
||||
current: currentValues,
|
||||
changes,
|
||||
hasChanges,
|
||||
saving,
|
||||
reset,
|
||||
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)))
|
||||
'@sentry/nuxt':
|
||||
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':
|
||||
specifier: ^5.90.7
|
||||
version: 5.92.5(vue@3.5.26(typescript@5.9.3))
|
||||
@@ -392,7 +392,7 @@ importers:
|
||||
version: 10.5.0
|
||||
nuxt:
|
||||
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:
|
||||
specifier: ^8.4.39
|
||||
version: 8.5.6
|
||||
@@ -634,6 +634,9 @@ importers:
|
||||
dayjs:
|
||||
specifier: ^1.11.10
|
||||
version: 1.11.19
|
||||
es-toolkit:
|
||||
specifier: ^1.44.0
|
||||
version: 1.44.0
|
||||
floating-vue:
|
||||
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))
|
||||
@@ -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)
|
||||
eslint-plugin-storybook:
|
||||
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:
|
||||
specifier: ^1.57.0
|
||||
version: 1.57.0
|
||||
@@ -748,7 +751,7 @@ importers:
|
||||
version: 5.1.0(vue@3.5.26(typescript@5.9.3))
|
||||
vitest:
|
||||
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:
|
||||
specifier: ^3.5.13
|
||||
version: 3.5.26(typescript@5.9.3)
|
||||
@@ -5433,6 +5436,9 @@ packages:
|
||||
resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
es-toolkit@1.44.0:
|
||||
resolution: {integrity: sha512-6penXeZalaV88MM3cGkFZZfOoLGWshWWfdy0tWw/RlVVyhvMaWSBTOvXNeiW3e5FwdS5ePW0LGEu17zT139ktg==}
|
||||
|
||||
esast-util-from-estree@2.0.0:
|
||||
resolution: {integrity: sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==}
|
||||
|
||||
@@ -8485,6 +8491,7 @@ packages:
|
||||
tar@7.5.2:
|
||||
resolution: {integrity: sha512-7NyxrTE4Anh8km8iEy7o0QYPs+0JKBTj5ZaqHg6B39erLg0qYXN3BijtShwbsNSvQ+LN75+KV+C4QR/f6Gwnpg==}
|
||||
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:
|
||||
resolution: {integrity: sha512-t/R3R/n0MSwnnazuPpPNVO60LX0SKL45pyl9YlvxIdkH0Of7D5qM2EVe+yASRIlY5pZ73nclYJfNANGWPwFDZw==}
|
||||
@@ -9245,8 +9252,8 @@ packages:
|
||||
vue-component-type-helpers@3.2.1:
|
||||
resolution: {integrity: sha512-gKV7XOkQl4urSuLHNY1tnVQf7wVgtb/mKbRyxSLWGZUY9RK7aDPhBenTjm+i8ZFe0zC2PZeHMPtOZXZfyaFOzQ==}
|
||||
|
||||
vue-component-type-helpers@3.2.2:
|
||||
resolution: {integrity: sha512-x8C2nx5XlUNM0WirgfTkHjJGO/ABBxlANZDtHw2HclHtQnn+RFPTnbjMJn8jHZW4TlUam0asHcA14lf1C6Jb+A==}
|
||||
vue-component-type-helpers@3.2.4:
|
||||
resolution: {integrity: sha512-05lR16HeZDcDpB23ku5b5f1fBOoHqFnMiKRr2CiEvbG5Ux4Yi0McmQBOET0dR0nxDXosxyVqv67q6CzS3AK8rw==}
|
||||
|
||||
vue-confetti-explosion@1.0.2:
|
||||
resolution: {integrity: sha512-80OboM3/6BItIoZ6DpNcZFqGpF607kjIVc5af56oKgtFmt5yWehvJeoYhkzYlqxrqdBe0Ko4Ie3bWrmLau+dJw==}
|
||||
@@ -10415,7 +10422,6 @@ snapshots:
|
||||
dependencies:
|
||||
eslint: 9.39.2(jiti@1.21.7)
|
||||
eslint-visitor-keys: 3.4.3
|
||||
optional: true
|
||||
|
||||
'@eslint-community/eslint-utils@4.9.1(eslint@9.39.2(jiti@2.6.1))':
|
||||
dependencies:
|
||||
@@ -11000,7 +11006,7 @@ snapshots:
|
||||
dependencies:
|
||||
'@nuxt/kit': 4.2.2(magicast@0.5.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:
|
||||
- magicast
|
||||
|
||||
@@ -11045,7 +11051,7 @@ snapshots:
|
||||
sirv: 3.0.2
|
||||
structured-clone-es: 1.0.0
|
||||
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-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
|
||||
@@ -11141,7 +11147,7 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- 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:
|
||||
'@nuxt/devalue': 2.0.2
|
||||
'@nuxt/kit': 3.20.2(magicast@0.5.1)
|
||||
@@ -11159,7 +11165,7 @@ snapshots:
|
||||
klona: 2.0.6
|
||||
mocked-exports: 0.1.1
|
||||
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
|
||||
pkg-types: 2.3.0
|
||||
radix3: 1.1.2
|
||||
@@ -11230,7 +11236,7 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- 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:
|
||||
'@nuxt/kit': 3.20.2(magicast@0.5.1)
|
||||
'@rollup/plugin-replace': 6.0.3(rollup@4.54.0)
|
||||
@@ -11251,7 +11257,7 @@ snapshots:
|
||||
magic-string: 0.30.21
|
||||
mlly: 1.8.0
|
||||
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
|
||||
pathe: 2.0.3
|
||||
perfect-debounce: 2.0.0
|
||||
@@ -11262,9 +11268,9 @@ snapshots:
|
||||
std-env: 3.10.0
|
||||
ufo: 1.6.1
|
||||
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-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-bundle-renderer: 2.2.0
|
||||
transitivePeerDependencies:
|
||||
@@ -12148,7 +12154,7 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- 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:
|
||||
'@nuxt/kit': 3.20.2(magicast@0.5.1)
|
||||
'@sentry/browser': 10.33.0
|
||||
@@ -12159,7 +12165,7 @@ snapshots:
|
||||
'@sentry/rollup-plugin': 4.6.1(rollup@4.54.0)
|
||||
'@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))
|
||||
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:
|
||||
- '@cloudflare/workers-types'
|
||||
- '@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-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: 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:
|
||||
- react
|
||||
- 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)
|
||||
type-fest: 2.19.0
|
||||
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': {}
|
||||
|
||||
@@ -12894,6 +12900,17 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- 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)':
|
||||
dependencies:
|
||||
'@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)
|
||||
'@rolldown/pluginutils': 1.0.0-beta.58
|
||||
'@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)
|
||||
transitivePeerDependencies:
|
||||
- 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))':
|
||||
dependencies:
|
||||
'@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)
|
||||
|
||||
'@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))
|
||||
playwright: 1.57.0
|
||||
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:
|
||||
- bufferutil
|
||||
- msw
|
||||
@@ -13052,7 +13069,7 @@ snapshots:
|
||||
pngjs: 7.0.0
|
||||
sirv: 3.0.2
|
||||
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
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
@@ -13073,7 +13090,7 @@ snapshots:
|
||||
obug: 2.1.1
|
||||
std-env: 3.10.0
|
||||
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:
|
||||
'@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:
|
||||
@@ -13112,13 +13129,13 @@ snapshots:
|
||||
optionalDependencies:
|
||||
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:
|
||||
'@vitest/spy': 4.0.16
|
||||
estree-walker: 3.0.3
|
||||
magic-string: 0.30.21
|
||||
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':
|
||||
dependencies:
|
||||
@@ -14495,6 +14512,8 @@ snapshots:
|
||||
dependencies:
|
||||
es-errors: 1.3.0
|
||||
|
||||
es-toolkit@1.44.0: {}
|
||||
|
||||
esast-util-from-estree@2.0.0:
|
||||
dependencies:
|
||||
'@types/estree-jsx': 1.0.5
|
||||
@@ -14710,10 +14729,10 @@ snapshots:
|
||||
dependencies:
|
||||
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:
|
||||
'@typescript-eslint/utils': 8.51.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
|
||||
eslint: 9.39.2(jiti@2.6.1)
|
||||
'@typescript-eslint/utils': 8.51.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3)
|
||||
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)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@@ -14827,7 +14846,6 @@ snapshots:
|
||||
jiti: 1.21.7
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
optional: true
|
||||
|
||||
eslint@9.39.2(jiti@2.6.1):
|
||||
dependencies:
|
||||
@@ -16790,16 +16808,16 @@ snapshots:
|
||||
dependencies:
|
||||
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:
|
||||
'@dxup/nuxt': 0.2.2(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/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/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))
|
||||
'@vue/shared': 3.5.26
|
||||
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)):
|
||||
dependencies:
|
||||
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)):
|
||||
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):
|
||||
dependencies:
|
||||
@@ -18986,7 +19004,7 @@ snapshots:
|
||||
- tsx
|
||||
- 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:
|
||||
'@babel/code-frame': 7.27.1
|
||||
chokidar: 4.0.3
|
||||
@@ -18995,10 +19013,10 @@ snapshots:
|
||||
picomatch: 4.0.3
|
||||
tiny-invariant: 1.3.3
|
||||
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
|
||||
optionalDependencies:
|
||||
eslint: 9.39.2(jiti@1.21.7)
|
||||
eslint: 9.39.2(jiti@2.6.1)
|
||||
optionator: 0.9.4
|
||||
typescript: 5.9.3
|
||||
vue-tsc: 2.2.12(typescript@5.9.3)
|
||||
@@ -19013,7 +19031,7 @@ snapshots:
|
||||
perfect-debounce: 2.0.0
|
||||
sirv: 3.0.2
|
||||
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))
|
||||
optionalDependencies:
|
||||
'@nuxt/kit': 4.2.2(magicast@0.5.1)
|
||||
@@ -19027,7 +19045,7 @@ snapshots:
|
||||
magic-string: 0.30.21
|
||||
pathe: 2.0.3
|
||||
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)
|
||||
|
||||
vite-svg-loader@5.1.0(vue@3.5.26(typescript@5.9.3)):
|
||||
@@ -19047,6 +19065,23 @@ snapshots:
|
||||
sass: 1.97.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):
|
||||
dependencies:
|
||||
esbuild: 0.25.12
|
||||
@@ -19064,23 +19099,6 @@ snapshots:
|
||||
terser: 5.44.1
|
||||
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):
|
||||
dependencies:
|
||||
esbuild: 0.27.2
|
||||
@@ -19102,10 +19120,10 @@ snapshots:
|
||||
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)
|
||||
|
||||
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:
|
||||
'@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/runner': 4.0.16
|
||||
'@vitest/snapshot': 4.0.16
|
||||
@@ -19122,7 +19140,7 @@ snapshots:
|
||||
tinyexec: 1.0.2
|
||||
tinyglobby: 0.2.15
|
||||
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
|
||||
optionalDependencies:
|
||||
'@opentelemetry/api': 1.9.0
|
||||
@@ -19257,7 +19275,7 @@ snapshots:
|
||||
|
||||
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)):
|
||||
dependencies:
|
||||
|
||||
Reference in New Issue
Block a user