refactor: migrate all input fields to StyledInput (#5306)

* feat: StyledInput component

* migrate: auth pages to styledInput

* migrate: search/filter inputs

* migrate: dashboard inputs

* migrate: app frontend

* migrate: search related inputs

* migrate: all of app-frontend

* fix: missing inputs on app-frontend

* migrate: frontend

* feat: multiline

* migrate: textareas

* fix: storybook use text-primary

* fix: lint

* fix: merge conflict

* feat: cleanup
This commit is contained in:
Calum H.
2026-02-09 14:57:31 +00:00
committed by GitHub
parent 90438a1ad5
commit 37eac92329
108 changed files with 1670 additions and 1479 deletions

View File

@@ -20,12 +20,12 @@
<label for="days" class="flex flex-col gap-1">
<span class="text-lg font-semibold text-contrast"> Days to credit </span>
</label>
<input
<StyledInput
id="days"
v-model.number="days"
class="w-32"
v-model="days"
wrapper-class="w-32"
type="number"
min="1"
:min="1"
autocomplete="off"
/>
</div>
@@ -36,11 +36,10 @@
<span class="text-lg font-semibold text-contrast"> Node hostnames </span>
</label>
<div class="flex items-center gap-2">
<input
<StyledInput
id="node-input"
v-model="nodeInput"
class="w-32"
type="text"
wrapper-class="w-32"
autocomplete="off"
/>
<ButtonStyled color="blue" color-fill="text">
@@ -93,14 +92,13 @@
class="text-muted flex flex-col gap-2 rounded-lg border border-surface-5 bg-button-bg p-4"
>
<span>Hi {user.name},</span>
<div class="textarea-wrapper">
<textarea
id="message-batch"
v-model="message"
rows="3"
class="w-full overflow-hidden !bg-surface-3"
/>
</div>
<StyledInput
id="message-batch"
v-model="message"
multiline
:rows="3"
input-class="!bg-surface-3"
/>
<span>
To make up for it, we've added {{ days }} day{{ pluralize(days) }} to your Modrinth
Servers subscription.
@@ -137,6 +135,7 @@ import {
Combobox,
injectNotificationManager,
NewModal,
StyledInput,
TagItem,
Toggle,
} from '@modrinth/ui'

View File

@@ -25,15 +25,14 @@
</span>
<span>Server IDs (one per line or comma-separated.)</span>
</label>
<div class="textarea-wrapper">
<textarea
id="server-ids"
v-model="serverIdsInput"
rows="4"
class="w-full bg-surface-3"
placeholder="123e4569-e89b-12d3-a456-426614174005&#10;123e9569-e89b-12d3-a456-413678919876"
/>
</div>
<StyledInput
id="server-ids"
v-model="serverIdsInput"
multiline
:rows="4"
input-class="bg-surface-3"
placeholder="123e4569-e89b-12d3-a456-426614174005&#10;123e9569-e89b-12d3-a456-413678919876"
/>
<span v-if="parsedServerIds.length" class="text-sm text-secondary">
{{ parsedServerIds.length }} server{{ parsedServerIds.length === 1 ? '' : 's' }} selected
</span>
@@ -49,11 +48,10 @@
<span>Add nodes to transfer (comma or space-separated).</span>
</label>
<div class="flex items-center gap-2">
<input
<StyledInput
id="node-input"
v-model="nodeInput"
class="w-64"
type="text"
wrapper-class="w-64"
autocomplete="off"
placeholder="us-vin200, us-vin201"
@keydown.enter.prevent="addNodes"
@@ -88,11 +86,10 @@
<span class="text-lg font-semibold text-contrast">Tag transferred nodes</span>
<span>Optional tag to add to the transferred nodes.</span>
</label>
<input
<StyledInput
id="tag-nodes"
v-model="tagNodes"
class="max-w-[12rem]"
type="text"
wrapper-class="max-w-[12rem]"
autocomplete="off"
/>
</div>
@@ -117,11 +114,10 @@
<span>Optional preferred node tags for node selection.</span>
</label>
<div class="flex items-center gap-2">
<input
<StyledInput
id="tag-input"
v-model="tagInput"
class="w-40"
type="text"
wrapper-class="w-40"
autocomplete="off"
placeholder="ovh-gen4"
@keydown.enter.prevent="addTag"
@@ -151,11 +147,11 @@
:format-label="(item) => scheduleOptionLabels[item]"
:capitalize="false"
/>
<input
<StyledInput
v-if="scheduleOption === 'later'"
v-model="scheduledDate"
type="datetime-local"
class="mt-2 max-w-[16rem]"
wrapper-class="mt-2 max-w-[16rem]"
autocomplete="off"
/>
</div>
@@ -168,15 +164,14 @@
</span>
<span>Provide a reason for this transfer batch.</span>
</label>
<div class="textarea-wrapper">
<textarea
id="reason"
v-model="reason"
rows="2"
class="w-full bg-surface-3"
placeholder="Node maintenance scheduled"
/>
</div>
<StyledInput
id="reason"
v-model="reason"
multiline
:rows="2"
input-class="bg-surface-3"
placeholder="Node maintenance scheduled"
/>
</div>
<div class="flex gap-2">
@@ -205,6 +200,7 @@ import {
Combobox,
injectNotificationManager,
NewModal,
StyledInput,
TagItem,
Toggle,
} from '@modrinth/ui'

View File

@@ -13,10 +13,13 @@
size="small"
/>
</div>
<div class="iconified-input w-full">
<SearchIcon aria-hidden="true" />
<input v-model="searchQuery" type="text" placeholder="Search versions" />
</div>
<StyledInput
v-model="searchQuery"
:icon="SearchIcon"
type="text"
placeholder="Search versions"
wrapper-class="w-full"
/>
<div
class="flex h-72 select-none flex-col gap-3 overflow-y-auto rounded-xl border border-solid border-surface-5 p-3 py-4"
>
@@ -64,7 +67,7 @@
<script lang="ts" setup>
import type { Labrinth } from '@modrinth/api-client'
import { SearchIcon } from '@modrinth/assets'
import { ButtonStyled, Chips } from '@modrinth/ui'
import { ButtonStyled, Chips, StyledInput } from '@modrinth/ui'
import { useMagicKeys } from '@vueuse/core'
import { computed, nextTick, onMounted, ref } from 'vue'

View File

@@ -16,26 +16,24 @@
<span class="font-semibold text-contrast">
Version number <span class="text-red">*</span>
</span>
<input
<StyledInput
id="version-number"
v-model="draftVersion.version_number"
:disabled="isUploading"
placeholder="Enter version number, e.g. 1.2.3-alpha.1"
type="text"
autocomplete="off"
maxlength="32"
:maxlength="32"
/>
<span> The version number differentiates this specific version from others. </span>
</div>
<div class="flex flex-col gap-2">
<span class="font-semibold text-contrast"> Version subtitle </span>
<input
<StyledInput
id="version-number"
v-model="draftVersion.name"
placeholder="Enter subtitle..."
type="text"
autocomplete="off"
maxlength="256"
:maxlength="256"
:disabled="isUploading"
/>
</div>
@@ -55,7 +53,7 @@
</template>
<script lang="ts" setup>
import { Chips, MarkdownEditor } from '@modrinth/ui'
import { Chips, MarkdownEditor, StyledInput } from '@modrinth/ui'
import { useImageUpload } from '~/composables/image-upload.ts'
import { injectManageVersionContext } from '~/providers/version/manage-version-modal'

View File

@@ -9,11 +9,10 @@
<span class="text-brand-red">*</span>
</span>
</label>
<input
<StyledInput
id="name"
v-model="name"
type="text"
maxlength="64"
:maxlength="64"
:placeholder="formatMessage(messages.namePlaceholder)"
autocomplete="off"
:disabled="hasHitLimit"
@@ -26,15 +25,14 @@
}}</span>
<span>{{ formatMessage(messages.summaryDescription) }}</span>
</label>
<div class="textarea-wrapper">
<textarea
id="additional-information"
v-model="description"
maxlength="256"
:placeholder="formatMessage(messages.summaryPlaceholder)"
:disabled="hasHitLimit"
/>
</div>
<StyledInput
id="additional-information"
v-model="description"
multiline
:maxlength="256"
:placeholder="formatMessage(messages.summaryPlaceholder)"
:disabled="hasHitLimit"
/>
</div>
<p class="m-0">
{{ formatMessage(messages.collectionInfo, { count: projectIds.length }) }}
@@ -64,6 +62,7 @@ import {
defineMessages,
injectNotificationManager,
NewModal,
StyledInput,
useVIntl,
} from '@modrinth/ui'
@@ -172,10 +171,6 @@ defineExpose({
width: 100%;
}
textarea {
min-height: 5rem;
}
.input-group {
margin-top: var(--gap-md);
}

View File

@@ -9,15 +9,14 @@
<span class="text-brand-red">*</span>
</span>
</label>
<input
<StyledInput
id="name"
v-model="name"
type="text"
maxlength="64"
:maxlength="64"
:placeholder="formatMessage(messages.namePlaceholder)"
autocomplete="off"
:disabled="hasHitLimit"
@input="updateSlug"
@update:model-value="updateSlug"
/>
</div>
<div class="flex flex-col gap-2">
@@ -29,14 +28,13 @@
</label>
<div class="text-input-wrapper">
<div class="text-input-wrapper__before">https://modrinth.com/organization/</div>
<input
<StyledInput
id="slug"
v-model="slug"
type="text"
maxlength="64"
:maxlength="64"
autocomplete="off"
:disabled="hasHitLimit"
@input="setManualSlug"
@update:model-value="setManualSlug"
/>
</div>
</div>
@@ -48,15 +46,14 @@
</span>
<span>{{ formatMessage(messages.summaryDescription) }}</span>
</label>
<div class="textarea-wrapper">
<textarea
id="additional-information"
v-model="description"
maxlength="256"
:placeholder="formatMessage(messages.summaryPlaceholder)"
:disabled="hasHitLimit"
/>
</div>
<StyledInput
id="additional-information"
v-model="description"
multiline
:maxlength="256"
:placeholder="formatMessage(messages.summaryPlaceholder)"
:disabled="hasHitLimit"
/>
</div>
<p class="m-0">
{{ formatMessage(messages.ownershipInfo) }}
@@ -87,6 +84,7 @@ import {
defineMessages,
injectNotificationManager,
NewModal,
StyledInput,
useVIntl,
} from '@modrinth/ui'
import { ref } from 'vue'
@@ -214,10 +212,6 @@ defineExpose({
width: 100%;
}
textarea {
min-height: 5rem;
}
.input-group {
margin-top: var(--gap-md);
}

View File

@@ -9,15 +9,14 @@
<span class="text-brand-red">*</span>
</span>
</label>
<input
<StyledInput
id="name"
v-model="name"
type="text"
maxlength="64"
:maxlength="64"
:placeholder="formatMessage(messages.namePlaceholder)"
autocomplete="off"
:disabled="hasHitLimit"
@input="updatedName()"
@update:model-value="updatedName()"
/>
</div>
<div class="flex flex-col gap-2">
@@ -29,14 +28,13 @@
</label>
<div class="text-input-wrapper">
<div class="text-input-wrapper__before">https://modrinth.com/project/</div>
<input
<StyledInput
id="slug"
v-model="slug"
type="text"
maxlength="64"
:maxlength="64"
autocomplete="off"
:disabled="hasHitLimit"
@input="manualSlug = true"
@update:model-value="manualSlug = true"
/>
</div>
</div>
@@ -65,15 +63,14 @@
</span>
<span>{{ formatMessage(messages.summaryDescription) }}</span>
</label>
<div class="textarea-wrapper">
<textarea
id="additional-information"
v-model="description"
maxlength="256"
:placeholder="formatMessage(messages.summaryPlaceholder)"
:disabled="hasHitLimit"
/>
</div>
<StyledInput
id="additional-information"
v-model="description"
multiline
:maxlength="256"
:placeholder="formatMessage(messages.summaryPlaceholder)"
:disabled="hasHitLimit"
/>
</div>
<div class="flex justify-end gap-2">
<ButtonStyled class="w-24">
@@ -102,6 +99,7 @@ import {
defineMessages,
injectNotificationManager,
NewModal,
StyledInput,
useVIntl,
} from '@modrinth/ui'

View File

@@ -2,17 +2,17 @@
<div class="flex flex-col gap-2">
<div class="flex items-center gap-2">
<div class="relative flex-1">
<input
<StyledInput
ref="amountInput"
:value="modelValue"
:model-value="modelValue"
type="number"
step="0.01"
:step="0.01"
:min="minAmount"
:max="safeMaxAmount"
:disabled="isDisabled"
:placeholder="formatMessage(formFieldPlaceholders.amountPlaceholder)"
class="w-full rounded-[14px] bg-surface-4 py-2.5 pl-4 pr-4 text-contrast placeholder:text-secondary"
@input="handleInput"
wrapper-class="w-full"
@update:model-value="handleStyledInput"
/>
</div>
<Combobox
@@ -54,10 +54,11 @@ import {
Combobox,
commonMessages,
formFieldPlaceholders,
StyledInput,
useVIntl,
} from '@modrinth/ui'
import { formatMoney } from '@modrinth/utils'
import { computed, nextTick, ref, watch } from 'vue'
import { computed, ref, watch } from 'vue'
const props = withDefaults(
defineProps<{
@@ -81,7 +82,7 @@ const emit = defineEmits<{
}>()
const { formatMessage } = useVIntl()
const amountInput = ref<HTMLInputElement | null>(null)
const amountInput = ref<InstanceType<typeof StyledInput> | null>(null)
const safeMaxAmount = computed(() => {
return Math.max(0, props.maxAmount)
@@ -101,26 +102,19 @@ const isAboveMaximum = computed(() => {
return props.modelValue !== undefined && props.modelValue > safeMaxAmount.value
})
async function setMaxAmount() {
function setMaxAmount() {
const maxValue = safeMaxAmount.value
emit('update:modelValue', maxValue)
await nextTick()
if (amountInput.value) {
amountInput.value.value = maxValue.toFixed(2)
}
}
function handleInput(event: Event) {
const input = event.target as HTMLInputElement
const value = input.value
function handleStyledInput(val: string | number) {
const value = String(val)
if (value && value.includes('.')) {
const parts = value.split('.')
if (parts[1] && parts[1].length > 2) {
const rounded = Math.floor(parseFloat(value) * 100) / 100
emit('update:modelValue', rounded)
input.value = rounded.toString()
return
}
}
@@ -131,14 +125,10 @@ function handleInput(event: Event) {
watch(
() => props.modelValue,
async (newAmount) => {
(newAmount) => {
if (newAmount !== undefined && newAmount !== null) {
if (newAmount > safeMaxAmount.value) {
emit('update:modelValue', safeMaxAmount.value)
await nextTick()
if (amountInput.value) {
amountInput.value.value = safeMaxAmount.value.toFixed(2)
}
} else if (newAmount < 0) {
emit('update:modelValue', 0)
}

View File

@@ -41,11 +41,10 @@
>
</label>
<div class="flex flex-row gap-2">
<input
<StyledInput
v-model="venmoHandle"
type="text"
:placeholder="formatMessage(messages.venmoHandlePlaceholder)"
class="w-full rounded-[14px] bg-surface-4 px-4 py-3 text-contrast placeholder:text-secondary sm:py-2.5"
wrapper-class="w-full"
/>
<ButtonStyled color="brand">
<button
@@ -113,6 +112,7 @@ import {
formFieldLabels,
IntlFormatted,
normalizeChildren,
StyledInput,
useVIntl,
} from '@modrinth/ui'
import { useDebounceFn } from '@vueuse/core'

View File

@@ -56,21 +56,19 @@
</span>
<div class="flex flex-col gap-3 sm:flex-row sm:gap-4">
<div class="flex flex-1 flex-col gap-2.5">
<input
<StyledInput
v-model="formData.bankAccountOwnerFirstName"
type="text"
:placeholder="formatMessage(formFieldPlaceholders.firstNamePlaceholder)"
autocomplete="given-name"
class="w-full rounded-[14px] bg-surface-4 px-4 py-3 text-contrast placeholder:text-secondary sm:py-2.5"
wrapper-class="w-full"
/>
</div>
<div class="flex flex-1 flex-col gap-2.5">
<input
<StyledInput
v-model="formData.bankAccountOwnerLastName"
type="text"
:placeholder="formatMessage(formFieldPlaceholders.lastNamePlaceholder)"
autocomplete="family-name"
class="w-full rounded-[14px] bg-surface-4 px-4 py-3 text-contrast placeholder:text-secondary sm:py-2.5"
wrapper-class="w-full"
/>
</div>
</div>
@@ -93,13 +91,12 @@
class="h-10"
/>
<input
<StyledInput
v-else
v-model="formData.bankName"
type="text"
:placeholder="formatMessage(formFieldPlaceholders.bankNamePlaceholder)"
autocomplete="off"
class="w-full rounded-[14px] bg-surface-4 px-4 py-3 text-contrast placeholder:text-secondary sm:py-2.5"
wrapper-class="w-full"
/>
</div>
@@ -111,14 +108,14 @@
</span>
</label>
<input
<StyledInput
v-if="['text', 'email', 'tel'].includes(field.type)"
v-model="formData[field.name]"
:type="field.type"
:type="field.type === 'tel' ? undefined : field.type === 'text' ? undefined : field.type"
:inputmode="field.type === 'tel' ? 'tel' : undefined"
:placeholder="field.placeholder ? formatMessage(field.placeholder) : undefined"
:pattern="field.pattern"
:autocomplete="field.autocomplete || 'off'"
class="w-full rounded-[14px] bg-surface-4 px-4 py-3 text-contrast placeholder:text-secondary sm:py-2.5"
wrapper-class="w-full"
/>
<Combobox
@@ -134,11 +131,11 @@
class="h-10"
/>
<input
<StyledInput
v-else-if="field.type === 'date'"
v-model="formData[field.name]"
type="date"
class="w-full rounded-[14px] bg-surface-4 px-4 py-2.5 text-contrast placeholder:text-secondary"
wrapper-class="w-full"
/>
<span v-if="field.helpText" class="text-sm text-secondary">
@@ -162,12 +159,11 @@
<span v-if="dynamicDocumentNumberField.required" class="text-red">*</span>
</span>
</label>
<input
<StyledInput
v-model="formData.documentNumber"
:type="dynamicDocumentNumberField.type"
:placeholder="dynamicDocumentNumberField.placeholder"
autocomplete="off"
class="w-full rounded-[14px] bg-surface-4 px-4 py-3 text-contrast placeholder:text-secondary sm:py-2.5"
wrapper-class="w-full"
/>
</div>
</div>
@@ -244,6 +240,7 @@ import {
getCurrencyIcon,
IntlFormatted,
normalizeChildren,
StyledInput,
useVIntl,
} from '@modrinth/ui'
import { useDebounceFn } from '@vueuse/core'

View File

@@ -32,12 +32,11 @@
<span class="text-red">*</span>
</span>
</label>
<input
<StyledInput
v-model="formData.businessName"
type="text"
:placeholder="formatMessage(formFieldPlaceholders.businessNamePlaceholder)"
autocomplete="organization"
class="w-full rounded-[14px] bg-surface-4 px-4 py-2.5 text-contrast placeholder:text-secondary"
wrapper-class="w-full"
/>
</div>
@@ -48,12 +47,12 @@
<span class="text-red">*</span>
</span>
</label>
<input
<StyledInput
v-model="formData.email"
type="email"
:placeholder="formatMessage(formFieldPlaceholders.emailPlaceholder)"
autocomplete="email"
class="w-full rounded-[14px] bg-surface-4 px-4 py-2.5 text-contrast placeholder:text-secondary"
wrapper-class="w-full"
/>
</div>
@@ -66,12 +65,11 @@
<span class="text-red">*</span>
</span>
</label>
<input
<StyledInput
v-model="formData.firstName"
type="text"
:placeholder="formatMessage(formFieldPlaceholders.firstNamePlaceholder)"
autocomplete="given-name"
class="w-full rounded-[14px] bg-surface-4 px-4 py-3 text-contrast placeholder:text-secondary sm:py-2.5"
wrapper-class="w-full"
/>
</div>
<div class="flex flex-1 flex-col gap-2.5">
@@ -81,12 +79,11 @@
<span class="text-red">*</span>
</span>
</label>
<input
<StyledInput
v-model="formData.lastName"
type="text"
:placeholder="formatMessage(formFieldPlaceholders.lastNamePlaceholder)"
autocomplete="family-name"
class="w-full rounded-[14px] bg-surface-4 px-4 py-3 text-contrast placeholder:text-secondary sm:py-2.5"
wrapper-class="w-full"
/>
</div>
</div>
@@ -98,12 +95,12 @@
<span class="text-red">*</span>
</span>
</label>
<input
<StyledInput
v-model="formData.dateOfBirth"
type="date"
:max="maxDate"
autocomplete="bday"
class="w-full rounded-[14px] bg-surface-4 px-4 py-2.5 text-contrast placeholder:text-secondary"
wrapper-class="w-full"
/>
</div>
</div>
@@ -115,12 +112,11 @@
<span class="text-red">*</span>
</span>
</label>
<input
<StyledInput
v-model="formData.physicalAddress.address1"
type="text"
:placeholder="formatMessage(formFieldPlaceholders.addressPlaceholder)"
autocomplete="address-line1"
class="w-full rounded-[14px] bg-surface-4 px-4 py-2.5 text-contrast placeholder:text-secondary"
wrapper-class="w-full"
/>
</div>
@@ -130,12 +126,11 @@
{{ formatMessage(formFieldLabels.addressLine2) }}
</span>
</label>
<input
<StyledInput
v-model="formData.physicalAddress.address2"
type="text"
:placeholder="formatMessage(formFieldPlaceholders.address2Placeholder)"
autocomplete="address-line2"
class="w-full rounded-[14px] bg-surface-4 px-4 py-2.5 text-contrast placeholder:text-secondary"
wrapper-class="w-full"
/>
</div>
@@ -147,12 +142,11 @@
<span class="text-red">*</span>
</span>
</label>
<input
<StyledInput
v-model="formData.physicalAddress.city"
type="text"
:placeholder="formatMessage(formFieldPlaceholders.cityPlaceholder)"
autocomplete="address-level2"
class="w-full rounded-[14px] bg-surface-4 px-4 py-3 text-contrast placeholder:text-secondary sm:py-2.5"
wrapper-class="w-full"
/>
</div>
<div class="flex flex-1 flex-col gap-2.5">
@@ -170,13 +164,12 @@
searchable
search-placeholder="Search subdivisions..."
/>
<input
<StyledInput
v-else
v-model="formData.physicalAddress.state"
type="text"
:placeholder="formatMessage(formFieldPlaceholders.statePlaceholder)"
autocomplete="address-level1"
class="w-full rounded-[14px] bg-surface-4 px-4 py-3 text-contrast placeholder:text-secondary sm:py-2.5"
wrapper-class="w-full"
/>
</div>
</div>
@@ -189,12 +182,11 @@
<span class="text-red">*</span>
</span>
</label>
<input
<StyledInput
v-model="formData.physicalAddress.zip"
type="text"
:placeholder="formatMessage(formFieldPlaceholders.postalCodePlaceholder)"
autocomplete="postal-code"
class="w-full rounded-[14px] bg-surface-4 px-4 py-3 text-contrast placeholder:text-secondary sm:py-2.5"
wrapper-class="w-full"
/>
</div>
<div class="flex flex-1 flex-col gap-2.5">
@@ -224,6 +216,7 @@ import {
defineMessages,
formFieldLabels,
formFieldPlaceholders,
StyledInput,
useVIntl,
} from '@modrinth/ui'
// TODO: Switch to using Muralpay's improved endpoint when it's available.

View File

@@ -39,12 +39,12 @@
>{{ formatMessage(formFieldLabels.email) }} <span class="text-red">*</span></span
>
</label>
<input
<StyledInput
v-model="deliveryEmail"
type="email"
:placeholder="formatMessage(formFieldPlaceholders.emailPlaceholder)"
autocomplete="email"
class="w-full rounded-[14px] bg-surface-4 px-4 py-3 text-contrast placeholder:text-secondary sm:py-2.5"
wrapper-class="w-full"
/>
</div>
@@ -149,19 +149,17 @@
<div v-if="showGiftCardSelector && useFixedDenominations" class="flex flex-col gap-2.5">
<template v-if="useDenominationSuggestions">
<div class="iconified-input w-full">
<SearchIcon aria-hidden="true" />
<input
v-model.number="denominationSearchInput"
type="number"
step="0.01"
:min="0"
:disabled="effectiveMinAmount > roundedMaxAmount"
:placeholder="formatMessage(messages.enterDenominationPlaceholder)"
class="!bg-surface-4"
@input="hasTouchedSuggestions = true"
/>
</div>
<StyledInput
v-model="denominationSearchInput"
type="number"
:icon="SearchIcon"
:step="0.01"
:min="0"
:disabled="effectiveMinAmount > roundedMaxAmount"
:placeholder="formatMessage(messages.enterDenominationPlaceholder)"
wrapper-class="w-full"
@update:model-value="hasTouchedSuggestions = true"
/>
<Transition
enter-active-class="transition-opacity duration-200 ease-out"
enter-from-class="opacity-0"
@@ -350,6 +348,7 @@ import {
IntlFormatted,
normalizeChildren,
paymentMethodMessages,
StyledInput,
useDebugLogger,
useVIntl,
} from '@modrinth/ui'

View File

@@ -149,13 +149,13 @@
:disabled="false"
:heading-buttons="false"
/>
<textarea
<StyledInput
v-else
v-model="message"
type="text"
class="bg-bg-input h-[400px] w-full rounded-lg border border-solid border-surface-5 px-3 py-2 font-mono text-base"
multiline
placeholder="No message generated."
autocomplete="off"
input-class="h-[400px] font-mono"
@input="persistState"
/>
</div>
@@ -298,13 +298,12 @@
<span v-if="input.required" class="required">*</span>
</span>
</label>
<input
<StyledInput
:id="`input-${getActionId(action)}-${inputIndex}`"
v-model="textInputValues[`${getActionId(action)}-${inputIndex}`]"
type="text"
:placeholder="input.placeholder"
autocomplete="off"
@input="persistState"
@update:model-value="persistState"
/>
</template>
</div>
@@ -471,6 +470,7 @@ import {
MarkdownEditor,
OverflowMenu,
type OverflowMenuOption,
StyledInput,
useDebugLogger,
} from '@modrinth/ui'
import {

View File

@@ -34,35 +34,32 @@
<label for="proof">
<span class="label__title">Proof</span>
</label>
<input
<StyledInput
id="proof"
v-model="(modPackData[currentIndex] as ModerationUnknownModpackItem).proof"
type="text"
autocomplete="off"
placeholder="Enter proof of status..."
@input="persistAll()"
@update:model-value="persistAll()"
/>
<label for="link">
<span class="label__title">Link</span>
</label>
<input
<StyledInput
id="link"
v-model="(modPackData[currentIndex] as ModerationUnknownModpackItem).url"
type="text"
autocomplete="off"
placeholder="Enter link of project..."
@input="persistAll()"
@update:model-value="persistAll()"
/>
<label for="title">
<span class="label__title">Title</span>
</label>
<input
<StyledInput
id="title"
v-model="(modPackData[currentIndex] as ModerationUnknownModpackItem).title"
type="text"
autocomplete="off"
placeholder="Enter title of project..."
@input="persistAll()"
@update:model-value="persistAll()"
/>
</div>
</div>
@@ -146,7 +143,7 @@
<script setup lang="ts">
import { LeftArrowIcon, RightArrowIcon } from '@modrinth/assets'
import { ButtonStyled } from '@modrinth/ui'
import { ButtonStyled, StyledInput } from '@modrinth/ui'
import type {
ModerationFlameModpackItem,
ModerationJudgements,

View File

@@ -63,19 +63,17 @@
</nav>
<div class="flex flex-shrink-0 items-center gap-2">
<div class="iconified-input w-full sm:w-[280px]">
<SearchIcon aria-hidden="true" class="!text-secondary" />
<input
id="search-folder"
:value="searchQuery"
type="search"
name="search"
autocomplete="off"
class="h-10 w-full rounded-[14px] border-0 bg-surface-4 text-sm"
placeholder="Search files"
@input="$emit('update:searchQuery', ($event.target as HTMLInputElement).value)"
/>
</div>
<StyledInput
id="search-folder"
:model-value="searchQuery"
:icon="SearchIcon"
type="search"
name="search"
autocomplete="off"
placeholder="Search files"
wrapper-class="w-full sm:w-[280px]"
@update:model-value="$emit('update:searchQuery', $event)"
/>
<ButtonStyled type="outlined">
<OverflowMenu
@@ -128,7 +126,7 @@ import {
SearchIcon,
UploadIcon,
} from '@modrinth/assets'
import { ButtonStyled, OverflowMenu } from '@modrinth/ui'
import { ButtonStyled, OverflowMenu, StyledInput } from '@modrinth/ui'
defineProps<{
breadcrumbSegments: string[]

View File

@@ -3,14 +3,12 @@
<form class="flex flex-col gap-4 md:w-[600px]" @submit.prevent="handleSubmit">
<div class="flex flex-col gap-2">
<div class="font-semibold text-contrast">Name</div>
<input
<StyledInput
ref="createInput"
v-model="itemName"
autofocus
type="text"
class="bg-bg-input w-full rounded-lg p-4"
wrapper-class="bg-bg-input w-full rounded-lg p-4"
:placeholder="`e.g. ${type === 'file' ? 'config.yml' : 'plugins'}`"
required
/>
<div v-if="submitted && error" class="text-red">{{ error }}</div>
</div>
@@ -34,7 +32,7 @@
<script setup lang="ts">
import { PlusIcon, XIcon } from '@modrinth/assets'
import { ButtonStyled, NewModal } from '@modrinth/ui'
import { ButtonStyled, NewModal, StyledInput } from '@modrinth/ui'
import { computed, nextTick, ref } from 'vue'
const props = defineProps<{

View File

@@ -2,14 +2,12 @@
<NewModal ref="modal" :header="`Moving ${item?.name}`">
<form class="flex flex-col gap-4 md:w-[600px]" @submit.prevent="handleSubmit">
<div class="flex flex-col gap-2">
<input
<StyledInput
ref="destinationInput"
v-model="destination"
autofocus
type="text"
class="bg-bg-input w-full rounded-lg p-4"
wrapper-class="bg-bg-input w-full rounded-lg p-4"
placeholder="e.g. /mods/modname"
required
/>
</div>
<div class="flex items-center gap-2 text-nowrap">
@@ -38,7 +36,7 @@
<script setup lang="ts">
import { ArrowBigUpDashIcon, XIcon } from '@modrinth/assets'
import { ButtonStyled, NewModal } from '@modrinth/ui'
import { ButtonStyled, NewModal, StyledInput } from '@modrinth/ui'
import { computed, nextTick, ref } from 'vue'
const destinationInput = ref<HTMLInputElement | null>(null)

View File

@@ -3,13 +3,11 @@
<form class="flex flex-col gap-4 md:w-[600px]" @submit.prevent="handleSubmit">
<div class="flex flex-col gap-2">
<div class="font-semibold text-contrast">Name</div>
<input
<StyledInput
ref="renameInput"
v-model="itemName"
autofocus
type="text"
class="bg-bg-input w-full rounded-lg p-4"
required
wrapper-class="bg-bg-input w-full rounded-lg p-4"
/>
<div v-if="submitted && error" class="text-red">{{ error }}</div>
</div>
@@ -33,7 +31,7 @@
<script setup lang="ts">
import { EditIcon, XIcon } from '@modrinth/assets'
import { ButtonStyled, NewModal } from '@modrinth/ui'
import { ButtonStyled, NewModal, StyledInput } from '@modrinth/ui'
import { computed, nextTick, ref } from 'vue'
const props = defineProps<{

View File

@@ -33,16 +33,14 @@
</li>
</ol>
<p v-else class="mb-1 mt-0">Copy and paste the direct download URL of a .zip file.</p>
<input
<StyledInput
ref="urlInput"
v-model="url"
autofocus
:disabled="submitted"
type="text"
data-1p-ignore
data-lpignore="true"
data-protonpass-ignore="true"
required
:placeholder="
cf
? 'https://www.curseforge.com/minecraft/modpacks/.../files/6412259'
@@ -81,6 +79,7 @@ import {
injectModrinthServerContext,
injectNotificationManager,
NewModal,
StyledInput,
} from '@modrinth/ui'
import { ModrinthServersFetchError } from '@modrinth/utils'
import { computed, nextTick, ref } from 'vue'

View File

@@ -2,15 +2,16 @@
<div class="contents">
<div class="flex items-center gap-4">
<div class="relative w-full">
<input
<StyledInput
v-model="searchInput"
type="text"
type="search"
:icon="SearchIcon"
placeholder="Search logs"
class="h-12 !w-full !pl-10 !pr-48"
wrapper-class="h-12 !w-full"
input-class="!pr-48"
:disabled="loading"
@keydown.escape="clearSearch"
/>
<SearchIcon class="absolute left-4 top-1/2 -translate-y-1/2" />
<ButtonStyled v-if="searchInput && !loading" @click="clearSearch">
<button class="absolute right-2 top-1/2 -translate-y-1/2">
<XIcon class="h-5 w-5" />
@@ -298,7 +299,7 @@
<script setup lang="ts">
import { CopyIcon, EyeIcon, RightArrowIcon, SearchIcon, XIcon } from '@modrinth/assets'
import { NewModal } from '@modrinth/ui'
import { NewModal, StyledInput } from '@modrinth/ui'
import ButtonStyled from '@modrinth/ui/src/components/base/ButtonStyled.vue'
import { useDebounceFn } from '@vueuse/core'
import DOMPurify from 'dompurify'

View File

@@ -6,6 +6,7 @@ import {
injectNotificationManager,
NewModal,
ServerNotice,
StyledInput,
TagItem,
} from '@modrinth/ui'
import type { ServerNotice as ServerNoticeType } from '@modrinth/utils'
@@ -180,11 +181,10 @@ defineExpose({ show, hide })
<span v-else class="mb-2"> No nodes assigned yet </span>
</div>
<div class="flex w-[45rem] items-center gap-2">
<input
<StyledInput
id="server-assign-field"
v-model="inputField"
class="w-full"
type="text"
wrapper-class="w-full"
autocomplete="off"
/>
<ButtonStyled color="green" color-fill="text">

View File

@@ -506,23 +506,6 @@ const requestedStatus = computed(() => props.project.requested_status ?? 'approv
padding: var(--spacing-card-md);
}
.resizable-textarea-wrapper {
margin-bottom: var(--spacing-card-sm);
textarea {
padding: var(--spacing-card-bg);
width: 100%;
}
.chips {
margin-bottom: var(--spacing-card-md);
}
.preview {
overflow-y: auto;
}
}
.thread-id {
margin-bottom: var(--spacing-card-md);
font-weight: bold;