mirror of
https://github.com/modrinth/code.git
synced 2026-08-30 19:46:33 +00:00
feat: add show validation message with debounce
This commit is contained in:
@@ -28,7 +28,7 @@
|
||||
<script setup lang="ts">
|
||||
import { LightBulbIcon, TriangleAlertIcon, XCircleIcon } from '@modrinth/assets'
|
||||
import { type MessageDescriptor, useVIntl } from '@modrinth/ui'
|
||||
import { computed } from 'vue'
|
||||
import { computed, onScopeDispose, shallowRef, watch } from 'vue'
|
||||
|
||||
interface ValidationCheck {
|
||||
code?: string
|
||||
@@ -37,15 +37,46 @@ interface ValidationCheck {
|
||||
values?: Record<string, unknown>
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<{ check?: ValidationCheck | ValidationCheck[] | null }>(), {
|
||||
check: null,
|
||||
})
|
||||
type ValidationCheckInput = ValidationCheck | ValidationCheck[] | null
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
check?: ValidationCheckInput
|
||||
debounce?: number
|
||||
}>(),
|
||||
{
|
||||
check: null,
|
||||
debounce: 300,
|
||||
},
|
||||
)
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
const displayedCheck = shallowRef<ValidationCheckInput>(props.check)
|
||||
let debounceTimer: ReturnType<typeof setTimeout> | undefined
|
||||
|
||||
watch(
|
||||
() => props.check,
|
||||
(check) => {
|
||||
clearTimeout(debounceTimer)
|
||||
if (props.debounce <= 0) {
|
||||
displayedCheck.value = check
|
||||
return
|
||||
}
|
||||
|
||||
debounceTimer = setTimeout(() => {
|
||||
displayedCheck.value = check
|
||||
}, props.debounce)
|
||||
},
|
||||
)
|
||||
|
||||
onScopeDispose(() => clearTimeout(debounceTimer))
|
||||
|
||||
const validations = computed(() =>
|
||||
(Array.isArray(props.check) ? props.check : props.check ? [props.check] : []).filter(
|
||||
(validation) => validation.severity !== 'valid',
|
||||
),
|
||||
(Array.isArray(displayedCheck.value)
|
||||
? displayedCheck.value
|
||||
: displayedCheck.value
|
||||
? [displayedCheck.value]
|
||||
: []
|
||||
).filter((validation) => validation.severity !== 'valid'),
|
||||
)
|
||||
</script>
|
||||
|
||||
@@ -40,7 +40,6 @@
|
||||
autocomplete="off"
|
||||
:disabled="hasHitLimit"
|
||||
@update:model-value="updatedName()"
|
||||
@blur="nameForValidation = name"
|
||||
/>
|
||||
<ValidationMessage :check="nameValidation" />
|
||||
</div>
|
||||
@@ -335,8 +334,7 @@ const visibilities = ref<VisibilityOption[]>([
|
||||
])
|
||||
const visibility = ref<VisibilityOption>(visibilities.value[0])
|
||||
|
||||
const nameForValidation = ref(name.value)
|
||||
const nameValidation = useProjectTitleValidation(nameForValidation)
|
||||
const nameValidation = useProjectTitleValidation(name)
|
||||
const summaryValidation = useProjectSummaryValidation(description, name)
|
||||
|
||||
const disableCreate = computed(() => {
|
||||
@@ -516,7 +514,6 @@ async function createProject() {
|
||||
|
||||
async function show(event?: MouseEvent, options?: ShowOptions) {
|
||||
name.value = ''
|
||||
nameForValidation.value = name.value
|
||||
slug.value = ''
|
||||
description.value = ''
|
||||
manualSlug.value = false
|
||||
|
||||
@@ -57,8 +57,7 @@ const {
|
||||
|
||||
const { confirmLeaveModal } = usePageLeaveSafety(hasChanges)
|
||||
|
||||
const titleForValidation = ref(current.value.title)
|
||||
const titleValidation = useProjectTitleValidation(titleForValidation)
|
||||
const titleValidation = useProjectTitleValidation(() => current.value.title)
|
||||
const taglineValidation = useProjectSummaryValidation(
|
||||
() => current.value.tagline,
|
||||
() => current.value.title,
|
||||
@@ -88,7 +87,6 @@ async function save() {
|
||||
|
||||
function reset() {
|
||||
resetForm()
|
||||
titleForValidation.value = current.value.title
|
||||
}
|
||||
|
||||
const messages = defineMessages({
|
||||
@@ -204,7 +202,6 @@ const placeholder = computed(() => placeholders[placeholderIndex.value] ?? place
|
||||
autocomplete="off"
|
||||
:maxlength="50"
|
||||
wrapper-class="flex-grow"
|
||||
@blur="titleForValidation = current.title"
|
||||
/>
|
||||
</div>
|
||||
<ValidationMessage :check="titleValidation" class="mt-2" />
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
:maxlength="2048"
|
||||
wrapper-class="w-full max-w-72"
|
||||
:disabled="!hasPermission"
|
||||
@blur="nameForValidation = name"
|
||||
/>
|
||||
<ValidationMessage :check="nameValidation" class="mt-2" />
|
||||
</div>
|
||||
@@ -437,8 +436,7 @@ const hasPermission = computed(() => {
|
||||
)
|
||||
})
|
||||
|
||||
const nameForValidation = ref(name.value)
|
||||
const nameValidation = useProjectTitleValidation(nameForValidation)
|
||||
const nameValidation = useProjectTitleValidation(name)
|
||||
const summaryValidation = useProjectSummaryValidation(summary, name)
|
||||
const hasValidationIssues = computed(
|
||||
() =>
|
||||
@@ -545,7 +543,6 @@ const { confirmLeaveModal } = usePageLeaveSafety(hasChanges)
|
||||
|
||||
function resetChanges() {
|
||||
name.value = project.value.name
|
||||
nameForValidation.value = name.value
|
||||
slug.value = project.value.slug ?? ''
|
||||
summary.value = project.value.summary
|
||||
visibility.value = tags.value.approvedStatuses.includes(project.value.status)
|
||||
|
||||
Reference in New Issue
Block a user