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:
@@ -85,10 +85,6 @@ a {
|
||||
}
|
||||
}
|
||||
|
||||
input {
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
.badge {
|
||||
display: flex;
|
||||
border-radius: var(--radius-md);
|
||||
|
||||
@@ -8,13 +8,12 @@ import {
|
||||
SearchIcon,
|
||||
StopCircleIcon,
|
||||
TrashIcon,
|
||||
XIcon,
|
||||
} from '@modrinth/assets'
|
||||
import {
|
||||
Button,
|
||||
DropdownSelect,
|
||||
formatLoader,
|
||||
injectNotificationManager,
|
||||
StyledInput,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { useStorage } from '@vueuse/core'
|
||||
@@ -250,13 +249,14 @@ const filteredResults = computed(() => {
|
||||
</script>
|
||||
<template>
|
||||
<div class="flex gap-2">
|
||||
<div class="iconified-input flex-1">
|
||||
<SearchIcon />
|
||||
<input v-model="search" type="text" placeholder="Search" />
|
||||
<Button class="r-btn" @click="() => (search = '')">
|
||||
<XIcon />
|
||||
</Button>
|
||||
</div>
|
||||
<StyledInput
|
||||
v-model="search"
|
||||
:icon="SearchIcon"
|
||||
type="text"
|
||||
placeholder="Search"
|
||||
clearable
|
||||
wrapper-class="flex-1"
|
||||
/>
|
||||
<DropdownSelect
|
||||
v-slot="{ selected }"
|
||||
v-model="state.sortBy"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup>
|
||||
import { PlusIcon, XIcon } from '@modrinth/assets'
|
||||
import { Button, Checkbox, injectNotificationManager } from '@modrinth/ui'
|
||||
import { Button, Checkbox, injectNotificationManager, StyledInput } from '@modrinth/ui'
|
||||
import { open } from '@tauri-apps/plugin-dialog'
|
||||
import { ref } from 'vue'
|
||||
|
||||
@@ -110,31 +110,33 @@ const exportPack = async () => {
|
||||
<div class="modal-body">
|
||||
<div class="labeled_input">
|
||||
<p>Modpack Name</p>
|
||||
<div class="iconified-input">
|
||||
<PackageIcon />
|
||||
<input v-model="nameInput" type="text" placeholder="Modpack name" class="input" />
|
||||
<Button class="r-btn" @click="nameInput = ''">
|
||||
<XIcon />
|
||||
</Button>
|
||||
</div>
|
||||
<StyledInput
|
||||
v-model="nameInput"
|
||||
:icon="PackageIcon"
|
||||
type="text"
|
||||
placeholder="Modpack name"
|
||||
clearable
|
||||
/>
|
||||
</div>
|
||||
<div class="labeled_input">
|
||||
<p>Version number</p>
|
||||
<div class="iconified-input">
|
||||
<VersionIcon />
|
||||
<input v-model="versionInput" type="text" placeholder="1.0.0" class="input" />
|
||||
<Button class="r-btn" @click="versionInput = ''">
|
||||
<XIcon />
|
||||
</Button>
|
||||
</div>
|
||||
<StyledInput
|
||||
v-model="versionInput"
|
||||
:icon="VersionIcon"
|
||||
type="text"
|
||||
placeholder="1.0.0"
|
||||
clearable
|
||||
/>
|
||||
</div>
|
||||
<div class="adjacent-input">
|
||||
<div class="labeled_input">
|
||||
<p>Description</p>
|
||||
|
||||
<div class="textarea-wrapper">
|
||||
<textarea v-model="exportDescription" placeholder="Enter modpack description..." />
|
||||
</div>
|
||||
<StyledInput
|
||||
v-model="exportDescription"
|
||||
multiline
|
||||
placeholder="Enter modpack description..."
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -289,17 +291,4 @@ const exportPack = async () => {
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.textarea-wrapper {
|
||||
// margin-top: 1rem;
|
||||
height: 12rem;
|
||||
|
||||
textarea {
|
||||
max-height: 12rem;
|
||||
}
|
||||
|
||||
.preview {
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -20,12 +20,13 @@
|
||||
</div>
|
||||
<div class="input-row">
|
||||
<p class="input-label">Name</p>
|
||||
<input
|
||||
<StyledInput
|
||||
v-model="profile_name"
|
||||
autocomplete="off"
|
||||
class="text-input"
|
||||
type="text"
|
||||
maxlength="100"
|
||||
placeholder="Enter a name for your instance..."
|
||||
:maxlength="100"
|
||||
wrapper-class="w-full"
|
||||
/>
|
||||
</div>
|
||||
<div class="input-row">
|
||||
@@ -93,18 +94,14 @@
|
||||
<div class="path-selection">
|
||||
<h3>{{ selectedProfileType.name }} path</h3>
|
||||
<div class="path-input">
|
||||
<div class="iconified-input">
|
||||
<FolderOpenIcon />
|
||||
<input
|
||||
v-model="selectedProfileType.path"
|
||||
type="text"
|
||||
placeholder="Path to launcher"
|
||||
@change="setPath"
|
||||
/>
|
||||
<Button class="r-btn" @click="() => (selectedProfileType.path = '')">
|
||||
<XIcon />
|
||||
</Button>
|
||||
</div>
|
||||
<StyledInput
|
||||
v-model="selectedProfileType.path"
|
||||
:icon="FolderOpenIcon"
|
||||
type="text"
|
||||
placeholder="Path to launcher"
|
||||
clearable
|
||||
@change="setPath"
|
||||
/>
|
||||
<Button icon-only @click="selectLauncherPath">
|
||||
<FolderSearchIcon />
|
||||
</Button>
|
||||
@@ -197,7 +194,14 @@ import {
|
||||
UploadIcon,
|
||||
XIcon,
|
||||
} from '@modrinth/assets'
|
||||
import { Avatar, Button, Checkbox, Chips, injectNotificationManager } from '@modrinth/ui'
|
||||
import {
|
||||
Avatar,
|
||||
Button,
|
||||
Checkbox,
|
||||
Chips,
|
||||
injectNotificationManager,
|
||||
StyledInput,
|
||||
} from '@modrinth/ui'
|
||||
import { convertFileSrc } from '@tauri-apps/api/core'
|
||||
import { getCurrentWebview } from '@tauri-apps/api/webview'
|
||||
import { open } from '@tauri-apps/plugin-dialog'
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
<template>
|
||||
<JavaDetectionModal ref="detectJavaModal" @submit="(val) => emit('update:modelValue', val)" />
|
||||
<div class="toggle-setting" :class="{ compact }">
|
||||
<input
|
||||
<StyledInput
|
||||
autocomplete="off"
|
||||
:disabled="props.disabled"
|
||||
:value="props.modelValue ? props.modelValue.path : ''"
|
||||
type="text"
|
||||
class="installation-input"
|
||||
:model-value="props.modelValue ? props.modelValue.path : ''"
|
||||
:placeholder="placeholder ?? '/path/to/java'"
|
||||
@input="
|
||||
wrapper-class="installation-input"
|
||||
@update:model-value="
|
||||
(val) => {
|
||||
emit('update:modelValue', {
|
||||
...props.modelValue,
|
||||
path: val.target.value,
|
||||
path: val,
|
||||
})
|
||||
}
|
||||
"
|
||||
@@ -60,7 +59,7 @@ import {
|
||||
SearchIcon,
|
||||
XIcon,
|
||||
} from '@modrinth/assets'
|
||||
import { Button, injectNotificationManager } from '@modrinth/ui'
|
||||
import { Button, injectNotificationManager, StyledInput } from '@modrinth/ui'
|
||||
import { open } from '@tauri-apps/plugin-dialog'
|
||||
import { ref } from 'vue'
|
||||
|
||||
|
||||
@@ -3,10 +3,10 @@ import { MailIcon, SendIcon, UserIcon, UserPlusIcon, XIcon } from '@modrinth/ass
|
||||
import {
|
||||
Avatar,
|
||||
ButtonStyled,
|
||||
commonMessages,
|
||||
defineMessages,
|
||||
injectNotificationManager,
|
||||
IntlFormatted,
|
||||
StyledInput,
|
||||
useRelativeTime,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
@@ -271,15 +271,14 @@ const messages = defineMessages({
|
||||
{{ formatMessage(messages.usernameDescription) }}
|
||||
</p>
|
||||
<div class="flex items-center gap-2 mt-4">
|
||||
<div class="iconified-input flex-1">
|
||||
<UserIcon aria-hidden="true" />
|
||||
<input
|
||||
v-model="username"
|
||||
type="text"
|
||||
:placeholder="formatMessage(messages.usernamePlaceholder)"
|
||||
@keyup.enter="addFriendFromModal"
|
||||
/>
|
||||
</div>
|
||||
<StyledInput
|
||||
v-model="username"
|
||||
:icon="UserIcon"
|
||||
type="text"
|
||||
:placeholder="formatMessage(messages.usernamePlaceholder)"
|
||||
wrapper-class="flex-1"
|
||||
@keyup.enter="addFriendFromModal"
|
||||
/>
|
||||
<ButtonStyled color="brand">
|
||||
<button :disabled="username.length === 0" @click="addFriendFromModal">
|
||||
<SendIcon />
|
||||
@@ -300,23 +299,15 @@ const messages = defineMessages({
|
||||
<UserPlusIcon />
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<div class="iconified-input flex-1">
|
||||
<input
|
||||
v-model="search"
|
||||
type="text"
|
||||
class="friends-search-bar flex w-full"
|
||||
:placeholder="formatMessage(messages.searchFriends)"
|
||||
@keyup.esc="search = ''"
|
||||
/>
|
||||
<button
|
||||
v-if="search"
|
||||
v-tooltip="formatMessage(commonMessages.clearButton)"
|
||||
class="r-btn flex items-center justify-center bg-transparent button-animation p-2 cursor-pointer appearance-none border-none"
|
||||
@click="search = ''"
|
||||
>
|
||||
<XIcon />
|
||||
</button>
|
||||
</div>
|
||||
<StyledInput
|
||||
v-model="search"
|
||||
type="text"
|
||||
:placeholder="formatMessage(messages.searchFriends)"
|
||||
clearable
|
||||
variant="outlined"
|
||||
wrapper-class="flex-1"
|
||||
@keyup.esc="search = ''"
|
||||
/>
|
||||
</template>
|
||||
<h3 v-else class="ml-2 w-full text-base text-primary font-medium m-0">
|
||||
{{ formatMessage(messages.friends) }}
|
||||
@@ -413,16 +404,3 @@ const messages = defineMessages({
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
<style scoped>
|
||||
.friends-search-bar {
|
||||
background: none;
|
||||
border: 2px solid var(--color-button-bg) !important;
|
||||
padding: 8px;
|
||||
border-radius: 12px;
|
||||
height: 36px;
|
||||
}
|
||||
|
||||
.friends-search-bar::placeholder {
|
||||
@apply text-sm font-normal;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -4,10 +4,11 @@ import {
|
||||
DownloadIcon,
|
||||
PlusIcon,
|
||||
RightArrowIcon,
|
||||
SearchIcon,
|
||||
UploadIcon,
|
||||
XIcon,
|
||||
} from '@modrinth/assets'
|
||||
import { Avatar, Button, Card, injectNotificationManager } from '@modrinth/ui'
|
||||
import { Avatar, Button, Card, injectNotificationManager, StyledInput } from '@modrinth/ui'
|
||||
import { convertFileSrc } from '@tauri-apps/api/core'
|
||||
import { open } from '@tauri-apps/plugin-dialog'
|
||||
import { computed, ref } from 'vue'
|
||||
@@ -211,12 +212,12 @@ const createInstance = async () => {
|
||||
<template>
|
||||
<ModalWrapper ref="installModal" header="Install project to instance" :on-hide="onInstall">
|
||||
<div class="modal-body">
|
||||
<input
|
||||
<StyledInput
|
||||
v-model="searchFilter"
|
||||
autocomplete="off"
|
||||
type="text"
|
||||
class="search"
|
||||
:icon="SearchIcon"
|
||||
type="search"
|
||||
placeholder="Search for an instance"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<div class="profiles" :class="{ 'hide-creation': !showCreation }">
|
||||
<div v-for="profile in shownProfiles" :key="profile.name" class="option">
|
||||
@@ -271,7 +272,7 @@ const createInstance = async () => {
|
||||
</div>
|
||||
</div>
|
||||
<div class="creation-settings">
|
||||
<input
|
||||
<StyledInput
|
||||
v-model="name"
|
||||
autocomplete="off"
|
||||
type="text"
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
defineMessages,
|
||||
injectNotificationManager,
|
||||
OverflowMenu,
|
||||
StyledInput,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { convertFileSrc } from '@tauri-apps/api/core'
|
||||
@@ -245,13 +246,12 @@ const messages = defineMessages({
|
||||
{{ formatMessage(messages.name) }}
|
||||
</label>
|
||||
<div class="flex">
|
||||
<input
|
||||
<StyledInput
|
||||
id="instance-name"
|
||||
v-model="title"
|
||||
autocomplete="off"
|
||||
maxlength="80"
|
||||
class="flex-grow"
|
||||
type="text"
|
||||
:maxlength="80"
|
||||
wrapper-class="flex-grow"
|
||||
/>
|
||||
</div>
|
||||
<template v-if="instance.install_stage == 'installed'">
|
||||
@@ -292,9 +292,8 @@ const messages = defineMessages({
|
||||
@click="toggleGroup(group)"
|
||||
/>
|
||||
<div class="flex gap-2 items-center">
|
||||
<input
|
||||
<StyledInput
|
||||
v-model="newCategoryInput"
|
||||
type="text"
|
||||
:placeholder="formatMessage(messages.libraryGroupsEnterName)"
|
||||
@submit="() => addCategory"
|
||||
/>
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
import { Checkbox, defineMessages, injectNotificationManager, useVIntl } from '@modrinth/ui'
|
||||
import {
|
||||
Checkbox,
|
||||
defineMessages,
|
||||
injectNotificationManager,
|
||||
StyledInput,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { computed, ref, watch } from 'vue'
|
||||
|
||||
import { edit } from '@/helpers/profile'
|
||||
@@ -108,14 +114,13 @@ const messages = defineMessages({
|
||||
<p class="m-0">
|
||||
{{ formatMessage(messages.preLaunchDescription) }}
|
||||
</p>
|
||||
<input
|
||||
<StyledInput
|
||||
id="pre-launch"
|
||||
v-model="hooks.pre_launch"
|
||||
autocomplete="off"
|
||||
:disabled="!overrideHooks"
|
||||
type="text"
|
||||
:placeholder="formatMessage(messages.preLaunchEnter)"
|
||||
class="w-full mt-2"
|
||||
wrapper-class="w-full mt-2"
|
||||
/>
|
||||
|
||||
<h2 class="mt-4 mb-1 text-lg font-extrabold text-contrast">
|
||||
@@ -124,14 +129,13 @@ const messages = defineMessages({
|
||||
<p class="m-0">
|
||||
{{ formatMessage(messages.wrapperDescription) }}
|
||||
</p>
|
||||
<input
|
||||
<StyledInput
|
||||
id="wrapper"
|
||||
v-model="hooks.wrapper"
|
||||
autocomplete="off"
|
||||
:disabled="!overrideHooks"
|
||||
type="text"
|
||||
:placeholder="formatMessage(messages.wrapperEnter)"
|
||||
class="w-full mt-2"
|
||||
wrapper-class="w-full mt-2"
|
||||
/>
|
||||
|
||||
<h2 class="mt-4 mb-1 text-lg font-extrabold text-contrast">
|
||||
@@ -140,14 +144,13 @@ const messages = defineMessages({
|
||||
<p class="m-0">
|
||||
{{ formatMessage(messages.postExitDescription) }}
|
||||
</p>
|
||||
<input
|
||||
<StyledInput
|
||||
id="post-exit"
|
||||
v-model="hooks.post_exit"
|
||||
autocomplete="off"
|
||||
:disabled="!overrideHooks"
|
||||
type="text"
|
||||
:placeholder="formatMessage(messages.postExitEnter)"
|
||||
class="w-full mt-2"
|
||||
wrapper-class="w-full mt-2"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
<script setup lang="ts">
|
||||
import { CheckCircleIcon, XCircleIcon } from '@modrinth/assets'
|
||||
import { Checkbox, defineMessages, injectNotificationManager, Slider, useVIntl } from '@modrinth/ui'
|
||||
import {
|
||||
Checkbox,
|
||||
defineMessages,
|
||||
injectNotificationManager,
|
||||
Slider,
|
||||
StyledInput,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { computed, readonly, ref, watch } from 'vue'
|
||||
|
||||
import JavaSelector from '@/components/ui/JavaSelector.vue'
|
||||
@@ -155,27 +162,25 @@ const messages = defineMessages({
|
||||
{{ formatMessage(messages.javaArguments) }}
|
||||
</h2>
|
||||
<Checkbox v-model="overrideJavaArgs" label="Custom java arguments" class="my-2" />
|
||||
<input
|
||||
<StyledInput
|
||||
id="java-args"
|
||||
v-model="javaArgs"
|
||||
autocomplete="off"
|
||||
:disabled="!overrideJavaArgs"
|
||||
type="text"
|
||||
class="w-full"
|
||||
placeholder="Enter java arguments..."
|
||||
wrapper-class="w-full"
|
||||
/>
|
||||
<h2 id="project-name" class="mt-4 mb-1 text-lg font-extrabold text-contrast block">
|
||||
{{ formatMessage(messages.javaEnvironmentVariables) }}
|
||||
</h2>
|
||||
<Checkbox v-model="overrideEnvVars" label="Custom environment variables" class="mb-2" />
|
||||
<input
|
||||
<StyledInput
|
||||
id="env-vars"
|
||||
v-model="envVars"
|
||||
autocomplete="off"
|
||||
:disabled="!overrideEnvVars"
|
||||
type="text"
|
||||
class="w-full"
|
||||
placeholder="Enter environmental variables..."
|
||||
wrapper-class="w-full"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
<script setup lang="ts">
|
||||
import { Checkbox, defineMessages, injectNotificationManager, Toggle, useVIntl } from '@modrinth/ui'
|
||||
import {
|
||||
Checkbox,
|
||||
defineMessages,
|
||||
injectNotificationManager,
|
||||
StyledInput,
|
||||
Toggle,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { computed, type Ref, ref, watch } from 'vue'
|
||||
|
||||
import { edit } from '@/helpers/profile'
|
||||
@@ -121,7 +128,7 @@ const messages = defineMessages({
|
||||
{{ formatMessage(messages.widthDescription) }}
|
||||
</p>
|
||||
</div>
|
||||
<input
|
||||
<StyledInput
|
||||
id="width"
|
||||
v-model="resolution[0]"
|
||||
autocomplete="off"
|
||||
@@ -140,7 +147,7 @@ const messages = defineMessages({
|
||||
{{ formatMessage(messages.heightDescription) }}
|
||||
</p>
|
||||
</div>
|
||||
<input
|
||||
<StyledInput
|
||||
id="height"
|
||||
v-model="resolution[1]"
|
||||
autocomplete="off"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { injectNotificationManager, Slider, Toggle } from '@modrinth/ui'
|
||||
import { injectNotificationManager, Slider, StyledInput, Toggle } from '@modrinth/ui'
|
||||
import { ref, watch } from 'vue'
|
||||
|
||||
import useMemorySlider from '@/composables/useMemorySlider'
|
||||
@@ -73,7 +73,7 @@ watch(
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<input
|
||||
<StyledInput
|
||||
id="width"
|
||||
v-model="settings.game_resolution[0]"
|
||||
:disabled="settings.force_fullscreen"
|
||||
@@ -91,13 +91,12 @@ watch(
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<input
|
||||
<StyledInput
|
||||
id="height"
|
||||
v-model="settings.game_resolution[1]"
|
||||
:disabled="settings.force_fullscreen"
|
||||
autocomplete="off"
|
||||
type="number"
|
||||
class="input"
|
||||
placeholder="Enter height..."
|
||||
/>
|
||||
</div>
|
||||
@@ -118,23 +117,23 @@ watch(
|
||||
/>
|
||||
|
||||
<h2 class="mt-4 mb-2 text-lg font-extrabold text-contrast">Java arguments</h2>
|
||||
<input
|
||||
<StyledInput
|
||||
id="java-args"
|
||||
v-model="settings.launchArgs"
|
||||
autocomplete="off"
|
||||
type="text"
|
||||
placeholder="Enter java arguments..."
|
||||
class="w-full"
|
||||
wrapper-class="w-full"
|
||||
/>
|
||||
|
||||
<h2 class="mt-4 mb-2 text-lg font-extrabold text-contrast">Environmental variables</h2>
|
||||
<input
|
||||
<StyledInput
|
||||
id="env-vars"
|
||||
v-model="settings.envVars"
|
||||
autocomplete="off"
|
||||
type="text"
|
||||
placeholder="Enter environmental variables..."
|
||||
class="w-full"
|
||||
wrapper-class="w-full"
|
||||
/>
|
||||
|
||||
<hr class="mt-4 bg-button-border border-none h-[1px]" />
|
||||
@@ -143,37 +142,37 @@ watch(
|
||||
|
||||
<h3 class="mt-2 m-0 text-base font-extrabold text-primary">Pre launch</h3>
|
||||
<p class="m-0 mt-1 mb-2 leading-tight text-secondary">Ran before the instance is launched.</p>
|
||||
<input
|
||||
<StyledInput
|
||||
id="pre-launch"
|
||||
v-model="settings.hooks.pre_launch"
|
||||
autocomplete="off"
|
||||
type="text"
|
||||
placeholder="Enter pre-launch command..."
|
||||
class="w-full"
|
||||
wrapper-class="w-full"
|
||||
/>
|
||||
|
||||
<h3 class="mt-2 m-0 text-base font-extrabold text-primary">Wrapper</h3>
|
||||
<p class="m-0 mt-1 mb-2 leading-tight text-secondary">
|
||||
Wrapper command for launching Minecraft.
|
||||
</p>
|
||||
<input
|
||||
<StyledInput
|
||||
id="wrapper"
|
||||
v-model="settings.hooks.wrapper"
|
||||
autocomplete="off"
|
||||
type="text"
|
||||
placeholder="Enter wrapper command..."
|
||||
class="w-full"
|
||||
wrapper-class="w-full"
|
||||
/>
|
||||
|
||||
<h3 class="mt-2 m-0 text-base font-extrabold text-primary">Post exit</h3>
|
||||
<p class="m-0 mt-1 mb-2 leading-tight text-secondary">Ran after the game closes.</p>
|
||||
<input
|
||||
<StyledInput
|
||||
id="post-exit"
|
||||
v-model="settings.hooks.post_exit"
|
||||
autocomplete="off"
|
||||
type="text"
|
||||
placeholder="Enter post-exit command..."
|
||||
class="w-full"
|
||||
wrapper-class="w-full"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup>
|
||||
import { BoxIcon, FolderSearchIcon, TrashIcon } from '@modrinth/assets'
|
||||
import { Button, injectNotificationManager, Slider } from '@modrinth/ui'
|
||||
import { Button, injectNotificationManager, Slider, StyledInput } from '@modrinth/ui'
|
||||
import { open } from '@tauri-apps/plugin-dialog'
|
||||
import { ref, watch } from 'vue'
|
||||
|
||||
@@ -65,13 +65,19 @@ async function findLauncherDir() {
|
||||
</p>
|
||||
|
||||
<div class="m-1 my-2">
|
||||
<div class="iconified-input w-full">
|
||||
<BoxIcon />
|
||||
<input id="appDir" v-model="settings.custom_dir" type="text" class="input" />
|
||||
<Button class="r-btn" @click="findLauncherDir">
|
||||
<FolderSearchIcon />
|
||||
</Button>
|
||||
</div>
|
||||
<StyledInput
|
||||
id="appDir"
|
||||
v-model="settings.custom_dir"
|
||||
:icon="BoxIcon"
|
||||
type="text"
|
||||
wrapper-class="w-full"
|
||||
>
|
||||
<template #right>
|
||||
<Button class="r-btn" @click="findLauncherDir">
|
||||
<FolderSearchIcon />
|
||||
</Button>
|
||||
</template>
|
||||
</StyledInput>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
commonMessages,
|
||||
defineMessages,
|
||||
injectNotificationManager,
|
||||
StyledInput,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { computed, ref } from 'vue'
|
||||
@@ -103,12 +104,11 @@ const messages = defineMessages({
|
||||
<h2 class="text-lg font-extrabold text-contrast mt-0 mb-1">
|
||||
{{ formatMessage(messages.name) }}
|
||||
</h2>
|
||||
<input
|
||||
<StyledInput
|
||||
v-model="name"
|
||||
type="text"
|
||||
:placeholder="formatMessage(messages.placeholderName)"
|
||||
class="w-full"
|
||||
autocomplete="off"
|
||||
wrapper-class="w-full"
|
||||
/>
|
||||
<HideFromHomeOption v-model="hideFromHome" class="mt-3" />
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
import { Combobox, defineMessages, type MessageDescriptor, useVIntl } from '@modrinth/ui'
|
||||
import {
|
||||
Combobox,
|
||||
defineMessages,
|
||||
type MessageDescriptor,
|
||||
StyledInput,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
|
||||
import type { ServerPackStatus } from '@/helpers/worlds.ts'
|
||||
|
||||
@@ -52,22 +58,20 @@ defineExpose({ resourcePackOptions })
|
||||
<h2 class="text-lg font-extrabold text-contrast mt-0 mb-1">
|
||||
{{ formatMessage(messages.name) }}
|
||||
</h2>
|
||||
<input
|
||||
<StyledInput
|
||||
v-model="name"
|
||||
type="text"
|
||||
:placeholder="formatMessage(messages.placeholderName)"
|
||||
class="w-full"
|
||||
autocomplete="off"
|
||||
wrapper-class="w-full"
|
||||
/>
|
||||
<h2 class="text-lg font-extrabold text-contrast mt-3 mb-1">
|
||||
{{ formatMessage(messages.address) }}
|
||||
</h2>
|
||||
<input
|
||||
<StyledInput
|
||||
v-model="address"
|
||||
type="text"
|
||||
placeholder="example.modrinth.gg"
|
||||
class="w-full"
|
||||
autocomplete="off"
|
||||
wrapper-class="w-full"
|
||||
/>
|
||||
<h2 class="text-lg font-extrabold text-contrast mt-3 mb-1">
|
||||
{{ formatMessage(messages.resourcePack) }}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { ClipboardCopyIcon, ExternalIcon, GlobeIcon, SearchIcon, XIcon } from '@modrinth/assets'
|
||||
import { ClipboardCopyIcon, ExternalIcon, GlobeIcon, SearchIcon } from '@modrinth/assets'
|
||||
import type { Category, GameVersion, Platform, ProjectType, SortType, Tags } from '@modrinth/ui'
|
||||
import {
|
||||
Button,
|
||||
Checkbox,
|
||||
defineMessages,
|
||||
DropdownSelect,
|
||||
@@ -12,6 +11,7 @@ import {
|
||||
ProjectCardList,
|
||||
SearchFilterControl,
|
||||
SearchSidebarFilter,
|
||||
StyledInput,
|
||||
useSearch,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
@@ -458,20 +458,17 @@ previousFilterState.value = JSON.stringify({
|
||||
<h1 class="m-0 mb-1 text-xl">Install content to instance</h1>
|
||||
</template>
|
||||
<NavTabs :links="selectableProjectTypes" />
|
||||
<div class="iconified-input">
|
||||
<SearchIcon aria-hidden="true" class="text-lg" />
|
||||
<input
|
||||
v-model="query"
|
||||
class="h-12 card-shadow"
|
||||
autocomplete="off"
|
||||
spellcheck="false"
|
||||
type="text"
|
||||
:placeholder="`Search ${projectType}s...`"
|
||||
/>
|
||||
<Button v-if="query" class="r-btn" @click="() => clearSearch()">
|
||||
<XIcon />
|
||||
</Button>
|
||||
</div>
|
||||
<StyledInput
|
||||
v-model="query"
|
||||
:icon="SearchIcon"
|
||||
type="text"
|
||||
autocomplete="off"
|
||||
:placeholder="`Search ${projectType}s...`"
|
||||
clearable
|
||||
wrapper-class="w-full"
|
||||
input-class="h-12"
|
||||
@clear="clearSearch()"
|
||||
/>
|
||||
<div class="flex gap-2">
|
||||
<DropdownSelect
|
||||
v-slot="{ selected }"
|
||||
|
||||
@@ -213,12 +213,11 @@ import { showProfileInFolder } from '@/helpers/utils.js'
|
||||
import { handleSevereError } from '@/store/error.js'
|
||||
import { useBreadcrumbs, useLoading, useTheming } from '@/store/state'
|
||||
|
||||
const themeStore = useTheming()
|
||||
|
||||
dayjs.extend(duration)
|
||||
dayjs.extend(relativeTime)
|
||||
|
||||
const { handleError } = injectNotificationManager()
|
||||
const themeStore = useTheming()
|
||||
const route = useRoute()
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
@@ -39,12 +39,13 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="button-row">
|
||||
<input
|
||||
<StyledInput
|
||||
id="text-filter"
|
||||
v-model="searchFilter"
|
||||
autocomplete="off"
|
||||
type="text"
|
||||
class="text-filter"
|
||||
:icon="SearchIcon"
|
||||
type="search"
|
||||
input-class="text-filter"
|
||||
placeholder="Type to filter logs..."
|
||||
/>
|
||||
<div class="filter-group">
|
||||
@@ -91,8 +92,15 @@
|
||||
<script setup>
|
||||
import 'vue-virtual-scroller/dist/vue-virtual-scroller.css'
|
||||
|
||||
import { CheckIcon, ClipboardCopyIcon, ShareIcon, TrashIcon } from '@modrinth/assets'
|
||||
import { Button, Card, Checkbox, DropdownSelect, injectNotificationManager } from '@modrinth/ui'
|
||||
import { CheckIcon, ClipboardCopyIcon, SearchIcon, ShareIcon, TrashIcon } from '@modrinth/assets'
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
Checkbox,
|
||||
DropdownSelect,
|
||||
injectNotificationManager,
|
||||
StyledInput,
|
||||
} from '@modrinth/ui'
|
||||
import dayjs from 'dayjs'
|
||||
import isToday from 'dayjs/plugin/isToday'
|
||||
import isYesterday from 'dayjs/plugin/isYesterday'
|
||||
|
||||
@@ -2,19 +2,15 @@
|
||||
<div>
|
||||
<template v-if="projects?.length > 0">
|
||||
<div class="flex items-center gap-2 mb-4">
|
||||
<div class="iconified-input flex-grow">
|
||||
<SearchIcon />
|
||||
<input
|
||||
v-model="searchFilter"
|
||||
type="text"
|
||||
:placeholder="`Search ${filteredProjects.length} project${filteredProjects.length === 1 ? '' : 's'}...`"
|
||||
class="text-input search-input"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<Button class="r-btn" @click="() => (searchFilter = '')">
|
||||
<XIcon />
|
||||
</Button>
|
||||
</div>
|
||||
<StyledInput
|
||||
v-model="searchFilter"
|
||||
:icon="SearchIcon"
|
||||
type="text"
|
||||
:placeholder="`Search ${filteredProjects.length} project${filteredProjects.length === 1 ? '' : 's'}...`"
|
||||
autocomplete="off"
|
||||
clearable
|
||||
wrapper-class="flex-grow"
|
||||
/>
|
||||
<AddContentButton :instance="instance" />
|
||||
</div>
|
||||
<div class="flex items-center justify-between">
|
||||
@@ -268,10 +264,8 @@ import {
|
||||
SlashIcon,
|
||||
TrashIcon,
|
||||
UpdatedIcon,
|
||||
XIcon,
|
||||
} from '@modrinth/assets'
|
||||
import {
|
||||
Button,
|
||||
ButtonStyled,
|
||||
ContentListPanel,
|
||||
defineMessages,
|
||||
@@ -279,6 +273,7 @@ import {
|
||||
OverflowMenu,
|
||||
Pagination,
|
||||
RadialHeader,
|
||||
StyledInput,
|
||||
Toggle,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
|
||||
@@ -28,19 +28,15 @@
|
||||
/>
|
||||
<div v-if="worlds.length > 0" class="flex flex-col gap-4">
|
||||
<div class="flex flex-wrap gap-2 items-center">
|
||||
<div class="iconified-input flex-grow">
|
||||
<SearchIcon />
|
||||
<input
|
||||
v-model="searchFilter"
|
||||
type="text"
|
||||
:placeholder="`Search worlds...`"
|
||||
class="text-input search-input"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<Button v-if="searchFilter" class="r-btn" @click="() => (searchFilter = '')">
|
||||
<XIcon />
|
||||
</Button>
|
||||
</div>
|
||||
<StyledInput
|
||||
v-model="searchFilter"
|
||||
:icon="SearchIcon"
|
||||
type="text"
|
||||
placeholder="Search worlds..."
|
||||
autocomplete="off"
|
||||
clearable
|
||||
wrapper-class="flex-grow"
|
||||
/>
|
||||
<ButtonStyled>
|
||||
<button :disabled="refreshingAll" @click="refreshAllWorlds">
|
||||
<template v-if="refreshingAll">
|
||||
@@ -121,9 +117,8 @@
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { PlusIcon, SearchIcon, SpinnerIcon, UpdatedIcon, XIcon } from '@modrinth/assets'
|
||||
import { PlusIcon, SearchIcon, SpinnerIcon, UpdatedIcon } from '@modrinth/assets'
|
||||
import {
|
||||
Button,
|
||||
ButtonStyled,
|
||||
defineMessages,
|
||||
FilterBar,
|
||||
@@ -132,6 +127,7 @@ import {
|
||||
type GameVersion,
|
||||
injectNotificationManager,
|
||||
RadialHeader,
|
||||
StyledInput,
|
||||
} from '@modrinth/ui'
|
||||
import type { Version } from '@modrinth/utils'
|
||||
import { platform } from '@tauri-apps/plugin-os'
|
||||
|
||||
@@ -196,14 +196,7 @@
|
||||
width: 15rem;
|
||||
}
|
||||
|
||||
> :where(
|
||||
input + *,
|
||||
.input-group + *,
|
||||
.textarea-wrapper + *,
|
||||
.chips + *,
|
||||
.resizable-textarea-wrapper + *,
|
||||
.input-div + *
|
||||
) {
|
||||
> :where(input + *, .input-group + *, .chips + *, .input-div + *) {
|
||||
&:not(:empty) {
|
||||
margin-block-start: var(--spacing-card-md);
|
||||
}
|
||||
@@ -643,31 +636,6 @@ tr.button-transparent {
|
||||
}
|
||||
}
|
||||
|
||||
.textarea-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
|
||||
textarea {
|
||||
border-radius: var(--size-rounded-sm);
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
resize: none;
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.resizable-textarea-wrapper {
|
||||
display: block;
|
||||
|
||||
textarea {
|
||||
border-radius: var(--size-rounded-sm);
|
||||
min-height: 10rem;
|
||||
width: calc(100% - var(--spacing-card-lg) - var(--spacing-card-sm));
|
||||
resize: vertical;
|
||||
}
|
||||
}
|
||||
|
||||
.error {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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 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 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'
|
||||
|
||||
@@ -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'
|
||||
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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'
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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[]
|
||||
|
||||
@@ -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<{
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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<{
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -192,20 +192,19 @@
|
||||
: formatMessage(messages.selectGameVersion)
|
||||
}}
|
||||
</template>
|
||||
<div class="iconified-input mb-2 flex w-full">
|
||||
<label for="game-versions-filtering" hidden>{{
|
||||
formatMessage(messages.searchGameVersionsLabel)
|
||||
}}</label>
|
||||
<SearchIcon aria-hidden="true" />
|
||||
<input
|
||||
id="game-versions-filtering"
|
||||
ref="gameVersionFilterInput"
|
||||
v-model="versionFilter"
|
||||
type="search"
|
||||
autocomplete="off"
|
||||
:placeholder="formatMessage(messages.searchGameVersions)"
|
||||
/>
|
||||
</div>
|
||||
<label for="game-versions-filtering" hidden>{{
|
||||
formatMessage(messages.searchGameVersionsLabel)
|
||||
}}</label>
|
||||
<StyledInput
|
||||
id="game-versions-filtering"
|
||||
ref="gameVersionFilterInput"
|
||||
v-model="versionFilter"
|
||||
type="search"
|
||||
autocomplete="off"
|
||||
:icon="SearchIcon"
|
||||
:placeholder="formatMessage(messages.searchGameVersions)"
|
||||
wrapper-class="mb-2 w-full"
|
||||
/>
|
||||
<ScrollablePanel :class="project.game_versions.length > 4 ? 'h-[15rem]' : ''">
|
||||
<ButtonStyled
|
||||
v-for="gameVersion in project.game_versions
|
||||
@@ -615,11 +614,10 @@
|
||||
"
|
||||
/>
|
||||
<template #menu>
|
||||
<input
|
||||
<StyledInput
|
||||
v-model="displayCollectionsSearch"
|
||||
type="text"
|
||||
:placeholder="formatMessage(commonMessages.searchPlaceholder)"
|
||||
class="search-input menu-search"
|
||||
wrapper-class="menu-search"
|
||||
/>
|
||||
<div v-if="collections.length > 0" class="collections-list text-primary">
|
||||
<Checkbox
|
||||
@@ -986,6 +984,7 @@ import {
|
||||
provideProjectPageContext,
|
||||
ScrollablePanel,
|
||||
ServersPromo,
|
||||
StyledInput,
|
||||
TagItem,
|
||||
useRelativeTime,
|
||||
useVIntl,
|
||||
|
||||
@@ -42,28 +42,26 @@
|
||||
<label for="gallery-image-title">
|
||||
<span class="label__title">Title</span>
|
||||
</label>
|
||||
<input
|
||||
<StyledInput
|
||||
id="gallery-image-title"
|
||||
v-model="editTitle"
|
||||
type="text"
|
||||
maxlength="64"
|
||||
:maxlength="64"
|
||||
placeholder="Enter title..."
|
||||
/>
|
||||
<label for="gallery-image-desc">
|
||||
<span class="label__title">Description</span>
|
||||
</label>
|
||||
<div class="textarea-wrapper">
|
||||
<textarea
|
||||
id="gallery-image-desc"
|
||||
v-model="editDescription"
|
||||
maxlength="255"
|
||||
placeholder="Enter description..."
|
||||
/>
|
||||
</div>
|
||||
<StyledInput
|
||||
id="gallery-image-desc"
|
||||
v-model="editDescription"
|
||||
multiline
|
||||
:maxlength="255"
|
||||
placeholder="Enter description..."
|
||||
/>
|
||||
<label for="gallery-image-ordering">
|
||||
<span class="label__title">Order Index</span>
|
||||
</label>
|
||||
<input
|
||||
<StyledInput
|
||||
id="gallery-image-ordering"
|
||||
v-model="editOrder"
|
||||
type="number"
|
||||
@@ -342,6 +340,7 @@ import {
|
||||
FileInput,
|
||||
injectProjectPageContext,
|
||||
NewModal as Modal,
|
||||
StyledInput,
|
||||
} from '@modrinth/ui'
|
||||
import { useEventListener, useLocalStorage } from '@vueuse/core'
|
||||
|
||||
|
||||
@@ -42,28 +42,26 @@
|
||||
<label for="gallery-image-title">
|
||||
<span class="label__title">Title</span>
|
||||
</label>
|
||||
<input
|
||||
<StyledInput
|
||||
id="gallery-image-title"
|
||||
v-model="editTitle"
|
||||
type="text"
|
||||
maxlength="64"
|
||||
:maxlength="64"
|
||||
placeholder="Enter title..."
|
||||
/>
|
||||
<label for="gallery-image-desc">
|
||||
<span class="label__title">Description</span>
|
||||
</label>
|
||||
<div class="textarea-wrapper">
|
||||
<textarea
|
||||
id="gallery-image-desc"
|
||||
v-model="editDescription"
|
||||
maxlength="255"
|
||||
placeholder="Enter description..."
|
||||
/>
|
||||
</div>
|
||||
<StyledInput
|
||||
id="gallery-image-desc"
|
||||
v-model="editDescription"
|
||||
multiline
|
||||
:maxlength="255"
|
||||
placeholder="Enter description..."
|
||||
/>
|
||||
<label for="gallery-image-ordering">
|
||||
<span class="label__title">Order Index</span>
|
||||
</label>
|
||||
<input
|
||||
<StyledInput
|
||||
id="gallery-image-ordering"
|
||||
v-model="editOrder"
|
||||
type="number"
|
||||
@@ -301,6 +299,7 @@ import {
|
||||
FileInput,
|
||||
injectProjectPageContext,
|
||||
NewModal as Modal,
|
||||
StyledInput,
|
||||
} from '@modrinth/ui'
|
||||
|
||||
import { isPermission } from '~/utils/permissions.ts'
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
injectProjectPageContext,
|
||||
type MessageDescriptor,
|
||||
SettingsLabel,
|
||||
StyledInput,
|
||||
UnsavedChangesPopup,
|
||||
useSavable,
|
||||
useVIntl,
|
||||
@@ -134,14 +135,13 @@ const placeholder = computed(() => placeholders[placeholderIndex.value] ?? place
|
||||
:description="messages.nameDescription"
|
||||
/>
|
||||
<div class="flex">
|
||||
<input
|
||||
<StyledInput
|
||||
id="project-name"
|
||||
v-model="current.title"
|
||||
:placeholder="formatMessage(placeholder.name)"
|
||||
autocomplete="off"
|
||||
maxlength="50"
|
||||
class="flex-grow"
|
||||
type="text"
|
||||
:maxlength="50"
|
||||
wrapper-class="flex-grow"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -151,27 +151,20 @@ const placeholder = computed(() => placeholders[placeholderIndex.value] ?? place
|
||||
:title="messages.taglineTitle"
|
||||
:description="messages.taglineDescription"
|
||||
/>
|
||||
<input
|
||||
<StyledInput
|
||||
id="project-tagline"
|
||||
v-model="current.tagline"
|
||||
:placeholder="formatMessage(placeholder.tagline)"
|
||||
autocomplete="off"
|
||||
maxlength="120"
|
||||
class="w-full"
|
||||
type="text"
|
||||
:maxlength="120"
|
||||
wrapper-class="w-full"
|
||||
/>
|
||||
</div>
|
||||
<div class="mt-4">
|
||||
<SettingsLabel id="project-url" :title="messages.urlTitle" />
|
||||
<div class="text-input-wrapper">
|
||||
<div class="text-input-wrapper__before">https://modrinth.com/project/</div>
|
||||
<input
|
||||
id="project-url"
|
||||
v-model="current.url"
|
||||
type="text"
|
||||
maxlength="64"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<StyledInput id="project-url" v-model="current.url" :maxlength="64" autocomplete="off" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -54,13 +54,7 @@
|
||||
<label for="project-name">
|
||||
<span class="label__title">Name</span>
|
||||
</label>
|
||||
<input
|
||||
id="project-name"
|
||||
v-model="name"
|
||||
maxlength="2048"
|
||||
type="text"
|
||||
:disabled="!hasPermission"
|
||||
/>
|
||||
<StyledInput id="project-name" v-model="name" :maxlength="2048" :disabled="!hasPermission" />
|
||||
|
||||
<label for="project-slug">
|
||||
<span class="label__title">URL</span>
|
||||
@@ -71,11 +65,10 @@
|
||||
$getProjectTypeForUrl(project.project_type, project.loaders)
|
||||
}}/
|
||||
</div>
|
||||
<input
|
||||
<StyledInput
|
||||
id="project-slug"
|
||||
v-model="slug"
|
||||
type="text"
|
||||
maxlength="64"
|
||||
:maxlength="64"
|
||||
autocomplete="off"
|
||||
:disabled="!hasPermission"
|
||||
/>
|
||||
@@ -88,14 +81,14 @@
|
||||
<TriangleAlertIcon class="my-auto" />
|
||||
{{ summaryWarning }}
|
||||
</div>
|
||||
<div class="textarea-wrapper summary-input">
|
||||
<textarea
|
||||
id="project-summary"
|
||||
v-model="summary"
|
||||
maxlength="256"
|
||||
:disabled="!hasPermission"
|
||||
/>
|
||||
</div>
|
||||
<StyledInput
|
||||
id="project-summary"
|
||||
v-model="summary"
|
||||
multiline
|
||||
:maxlength="256"
|
||||
:disabled="!hasPermission"
|
||||
wrapper-class="summary-input"
|
||||
/>
|
||||
<template
|
||||
v-if="
|
||||
!flags.newProjectEnvironmentSettings &&
|
||||
@@ -261,6 +254,7 @@ import {
|
||||
ConfirmModal,
|
||||
injectNotificationManager,
|
||||
injectProjectPageContext,
|
||||
StyledInput,
|
||||
} from '@modrinth/ui'
|
||||
import { formatProjectStatus, formatProjectType } from '@modrinth/utils'
|
||||
import { Multiselect } from 'vue-multiselect'
|
||||
|
||||
@@ -71,16 +71,16 @@
|
||||
</label>
|
||||
|
||||
<div class="w-1/2">
|
||||
<input
|
||||
<StyledInput
|
||||
id="license-url"
|
||||
v-model="current.licenseUrl"
|
||||
type="url"
|
||||
maxlength="2048"
|
||||
:maxlength="2048"
|
||||
:placeholder="
|
||||
current.license?.friendly !== 'Custom' ? `License URL (optional)` : `License URL`
|
||||
"
|
||||
:disabled="!hasPermission || licenseId === 'LicenseRef-Unknown'"
|
||||
class="w-full"
|
||||
wrapper-class="w-full"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -104,23 +104,21 @@
|
||||
</label>
|
||||
|
||||
<div class="input-stack w-1/2">
|
||||
<input
|
||||
<StyledInput
|
||||
v-if="!current.nonSpdxLicense"
|
||||
id="license-spdx"
|
||||
v-model="current.license.short"
|
||||
class="w-full"
|
||||
type="text"
|
||||
maxlength="128"
|
||||
wrapper-class="w-full"
|
||||
:maxlength="128"
|
||||
placeholder="SPDX identifier"
|
||||
:disabled="!hasPermission"
|
||||
/>
|
||||
<input
|
||||
<StyledInput
|
||||
v-else
|
||||
id="license-name"
|
||||
v-model="current.license.short"
|
||||
class="w-full"
|
||||
type="text"
|
||||
maxlength="128"
|
||||
wrapper-class="w-full"
|
||||
:maxlength="128"
|
||||
placeholder="License name"
|
||||
:disabled="!hasPermission"
|
||||
/>
|
||||
@@ -158,6 +156,7 @@ import {
|
||||
Checkbox,
|
||||
DropdownSelect,
|
||||
injectProjectPageContext,
|
||||
StyledInput,
|
||||
UnsavedChangesPopup,
|
||||
useSavable,
|
||||
} from '@modrinth/ui'
|
||||
|
||||
@@ -27,12 +27,12 @@
|
||||
v-tooltip="`Link includes a domain which isn't common for this link type.`"
|
||||
class="size-6 animate-pulse text-orange"
|
||||
/>
|
||||
<input
|
||||
<StyledInput
|
||||
id="project-issue-tracker"
|
||||
v-model="issuesUrl"
|
||||
type="url"
|
||||
placeholder="Enter a valid URL"
|
||||
maxlength="2048"
|
||||
:maxlength="2048"
|
||||
:disabled="!hasPermission"
|
||||
/>
|
||||
</div>
|
||||
@@ -61,11 +61,11 @@
|
||||
v-tooltip="`Link includes a domain which isn't common for this link type.`"
|
||||
class="size-6 animate-pulse text-orange"
|
||||
/>
|
||||
<input
|
||||
<StyledInput
|
||||
id="project-source-code"
|
||||
v-model="sourceUrl"
|
||||
type="url"
|
||||
maxlength="2048"
|
||||
:maxlength="2048"
|
||||
placeholder="Enter a valid URL"
|
||||
:disabled="!hasPermission"
|
||||
/>
|
||||
@@ -90,11 +90,11 @@
|
||||
v-tooltip="`Discord invites are not appropriate for this link type.`"
|
||||
class="size-6 animate-pulse text-orange"
|
||||
/>
|
||||
<input
|
||||
<StyledInput
|
||||
id="project-wiki-page"
|
||||
v-model="wikiUrl"
|
||||
type="url"
|
||||
maxlength="2048"
|
||||
:maxlength="2048"
|
||||
placeholder="Enter a valid URL"
|
||||
:disabled="!hasPermission"
|
||||
/>
|
||||
@@ -114,11 +114,11 @@
|
||||
v-tooltip="`You're using a link which isn't common for this link type.`"
|
||||
class="size-6 animate-pulse text-orange"
|
||||
/>
|
||||
<input
|
||||
<StyledInput
|
||||
id="project-discord-invite"
|
||||
v-model="discordUrl"
|
||||
type="url"
|
||||
maxlength="2048"
|
||||
:maxlength="2048"
|
||||
placeholder="Enter a valid URL"
|
||||
:disabled="!hasPermission"
|
||||
/>
|
||||
@@ -135,13 +135,13 @@
|
||||
:key="`donation-link-${index}`"
|
||||
class="input-group donation-link-group"
|
||||
>
|
||||
<input
|
||||
<StyledInput
|
||||
v-model="donationLink.url"
|
||||
type="url"
|
||||
maxlength="2048"
|
||||
:maxlength="2048"
|
||||
placeholder="Enter a valid URL"
|
||||
:disabled="!hasPermission"
|
||||
@input="updateDonationLinks"
|
||||
@update:model-value="updateDonationLinks"
|
||||
/>
|
||||
<DropdownSelect
|
||||
v-model="donationLink.id"
|
||||
@@ -174,7 +174,7 @@
|
||||
<script setup>
|
||||
import { SaveIcon, TriangleAlertIcon } from '@modrinth/assets'
|
||||
import { commonLinkDomains, isCommonUrl, isDiscordUrl, isLinkShortener } from '@modrinth/moderation'
|
||||
import { DropdownSelect, injectProjectPageContext } from '@modrinth/ui'
|
||||
import { DropdownSelect, injectProjectPageContext, StyledInput } from '@modrinth/ui'
|
||||
|
||||
const tags = useGeneratedState()
|
||||
|
||||
|
||||
@@ -22,10 +22,9 @@
|
||||
</span>
|
||||
</span>
|
||||
<div class="input-group">
|
||||
<input
|
||||
<StyledInput
|
||||
id="username"
|
||||
v-model="currentUsername"
|
||||
type="text"
|
||||
placeholder="Username"
|
||||
:disabled="(currentMember?.permissions & MANAGE_INVITES) !== MANAGE_INVITES"
|
||||
@keypress.enter="inviteTeamMember()"
|
||||
@@ -98,10 +97,9 @@
|
||||
The title of the role that this member plays for this project.
|
||||
</span>
|
||||
</label>
|
||||
<input
|
||||
<StyledInput
|
||||
:id="`member-${allTeamMembers[index].user.username}-role`"
|
||||
v-model="allTeamMembers[index].role"
|
||||
type="text"
|
||||
:disabled="(currentMember?.permissions & EDIT_MEMBER) !== EDIT_MEMBER"
|
||||
/>
|
||||
</div>
|
||||
@@ -113,7 +111,7 @@
|
||||
this project's revenue goes to this member.
|
||||
</span>
|
||||
</label>
|
||||
<input
|
||||
<StyledInput
|
||||
:id="`member-${allTeamMembers[index].user.username}-monetization-weight`"
|
||||
v-model="allTeamMembers[index].payouts_split"
|
||||
type="number"
|
||||
@@ -364,10 +362,9 @@
|
||||
The title of the role that this member plays for this project.
|
||||
</span>
|
||||
</label>
|
||||
<input
|
||||
<StyledInput
|
||||
:id="`member-${allOrgMembers[index].user.username}-role`"
|
||||
v-model="allOrgMembers[index].role"
|
||||
type="text"
|
||||
:disabled="
|
||||
(currentMember?.permissions & EDIT_MEMBER) !== EDIT_MEMBER ||
|
||||
!allOrgMembers[index].override
|
||||
@@ -382,7 +379,7 @@
|
||||
this project's revenue goes to this member.
|
||||
</span>
|
||||
</label>
|
||||
<input
|
||||
<StyledInput
|
||||
:id="`member-${allOrgMembers[index].user.username}-monetization-weight`"
|
||||
v-model="allOrgMembers[index].payouts_split"
|
||||
type="number"
|
||||
@@ -550,6 +547,7 @@ import {
|
||||
ConfirmModal,
|
||||
injectNotificationManager,
|
||||
injectProjectPageContext,
|
||||
StyledInput,
|
||||
Toggle,
|
||||
} from '@modrinth/ui'
|
||||
import { Multiselect } from 'vue-multiselect'
|
||||
|
||||
@@ -65,11 +65,10 @@
|
||||
/>
|
||||
<div class="version-header">
|
||||
<template v-if="isEditing">
|
||||
<input
|
||||
<StyledInput
|
||||
v-model="version.name"
|
||||
type="text"
|
||||
placeholder="Enter a version title..."
|
||||
maxlength="256"
|
||||
:maxlength="256"
|
||||
/>
|
||||
</template>
|
||||
<h2 :class="{ 'sr-only': isEditing }">
|
||||
@@ -430,6 +429,7 @@ import {
|
||||
ENVIRONMENTS_COPY,
|
||||
injectNotificationManager,
|
||||
injectProjectPageContext,
|
||||
StyledInput,
|
||||
} from '@modrinth/ui'
|
||||
import { formatBytes, renderHighlightedString } from '@modrinth/utils'
|
||||
import { Multiselect } from 'vue-multiselect'
|
||||
|
||||
@@ -19,20 +19,14 @@
|
||||
>
|
||||
<h1 class="m-0 grow text-2xl font-extrabold">Manage affiliate links</h1>
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="iconified-input">
|
||||
<SearchIcon aria-hidden="true" />
|
||||
<input
|
||||
v-model="filterQuery"
|
||||
class="card-shadow"
|
||||
autocomplete="off"
|
||||
spellcheck="false"
|
||||
type="text"
|
||||
:placeholder="`Search affiliates...`"
|
||||
/>
|
||||
<Button v-if="filterQuery" class="r-btn" @click="() => (filterQuery = '')">
|
||||
<XIcon />
|
||||
</Button>
|
||||
</div>
|
||||
<StyledInput
|
||||
v-model="filterQuery"
|
||||
:icon="SearchIcon"
|
||||
type="text"
|
||||
autocomplete="off"
|
||||
placeholder="Search affiliates..."
|
||||
clearable
|
||||
/>
|
||||
<ButtonStyled color="brand">
|
||||
<button @click="createModal?.show">
|
||||
<PlusIcon />
|
||||
@@ -88,17 +82,17 @@
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { PlusIcon, SearchIcon, XCircleIcon, XIcon } from '@modrinth/assets'
|
||||
import { PlusIcon, SearchIcon, XCircleIcon } from '@modrinth/assets'
|
||||
import {
|
||||
Accordion,
|
||||
Admonition,
|
||||
AffiliateLinkCard,
|
||||
AffiliateLinkCreateModal,
|
||||
Avatar,
|
||||
Button,
|
||||
ButtonStyled,
|
||||
ConfirmModal,
|
||||
injectNotificationManager,
|
||||
StyledInput,
|
||||
} from '@modrinth/ui'
|
||||
import type { AffiliateLink, User } from '@modrinth/utils'
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
{{ selectedCharge.net }})
|
||||
</span>
|
||||
</label>
|
||||
<input id="amount" v-model="refundAmount" type="number" autocomplete="off" />
|
||||
<StyledInput id="amount" v-model="refundAmount" type="number" autocomplete="off" />
|
||||
</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
<label for="unprovision" class="flex flex-col gap-1">
|
||||
@@ -107,7 +107,7 @@
|
||||
<span class="text-lg font-semibold text-contrast">Days to credit</span>
|
||||
<span>Enter the number of days to add to the next due date.</span>
|
||||
</label>
|
||||
<input id="days" v-model.number="creditDays" type="number" min="1" autocomplete="off" />
|
||||
<StyledInput id="days" v-model="creditDays" type="number" :min="1" autocomplete="off" />
|
||||
</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
<label for="sendEmail" class="flex flex-col gap-1">
|
||||
@@ -330,6 +330,7 @@ import {
|
||||
DropdownSelect,
|
||||
injectNotificationManager,
|
||||
NewModal,
|
||||
StyledInput,
|
||||
Toggle,
|
||||
useRelativeTime,
|
||||
useVIntl,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { CopyIcon, LibraryIcon, PlayIcon, SearchIcon } from '@modrinth/assets'
|
||||
import { ButtonStyled, Card } from '@modrinth/ui'
|
||||
import { ButtonStyled, Card, StyledInput } from '@modrinth/ui'
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
|
||||
import docs from '~/templates/docs'
|
||||
@@ -51,18 +51,14 @@ onMounted(() => {
|
||||
<div class="normal-page__content">
|
||||
<Card class="mb-6 flex flex-col gap-4">
|
||||
<div class="flex flex-wrap items-center gap-3">
|
||||
<div class="relative">
|
||||
<SearchIcon
|
||||
class="pointer-events-none absolute left-2 top-1/2 h-4 w-4 -translate-y-1/2 text-secondary"
|
||||
/>
|
||||
<input
|
||||
id="doc-search"
|
||||
v-model="query"
|
||||
type="text"
|
||||
placeholder="Search templates..."
|
||||
class="w-72 rounded-lg border border-divider bg-bg px-7 py-2 text-sm text-primary placeholder-secondary focus:border-green focus:outline-none"
|
||||
/>
|
||||
</div>
|
||||
<StyledInput
|
||||
id="doc-search"
|
||||
v-model="query"
|
||||
type="search"
|
||||
:icon="SearchIcon"
|
||||
placeholder="Search templates..."
|
||||
wrapper-class="w-72"
|
||||
/>
|
||||
|
||||
<ButtonStyled color="brand">
|
||||
<button :disabled="filtered.length === 0" @click="openAll">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { CopyIcon, LibraryIcon, PlayIcon, SearchIcon } from '@modrinth/assets'
|
||||
import { ButtonStyled, Card } from '@modrinth/ui'
|
||||
import { ButtonStyled, Card, StyledInput } from '@modrinth/ui'
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
|
||||
import emails from '~/templates/emails'
|
||||
@@ -51,18 +51,14 @@ onMounted(() => {
|
||||
<div class="normal-page__content">
|
||||
<Card class="mb-6 flex flex-col gap-4">
|
||||
<div class="flex flex-wrap items-center gap-3">
|
||||
<div class="relative">
|
||||
<SearchIcon
|
||||
class="pointer-events-none absolute left-2 top-1/2 h-4 w-4 -translate-y-1/2 text-secondary"
|
||||
/>
|
||||
<input
|
||||
id="email-search"
|
||||
v-model="query"
|
||||
type="text"
|
||||
placeholder="Search templates..."
|
||||
class="w-72 rounded-lg border border-divider bg-bg px-7 py-2 text-sm text-primary placeholder-secondary focus:border-green focus:outline-none"
|
||||
/>
|
||||
</div>
|
||||
<StyledInput
|
||||
id="email-search"
|
||||
v-model="query"
|
||||
type="search"
|
||||
:icon="SearchIcon"
|
||||
placeholder="Search templates..."
|
||||
wrapper-class="w-72"
|
||||
/>
|
||||
|
||||
<ButtonStyled color="brand">
|
||||
<button :disabled="filtered.length === 0" @click="openAll">
|
||||
|
||||
@@ -24,11 +24,10 @@
|
||||
<label for="notice-title" class="flex flex-col gap-1">
|
||||
<span class="text-lg font-semibold text-contrast"> Title </span>
|
||||
</label>
|
||||
<input
|
||||
<StyledInput
|
||||
id="notice-title"
|
||||
v-model="newNoticeTitle"
|
||||
placeholder="E.g. Maintenance"
|
||||
type="text"
|
||||
autocomplete="off"
|
||||
/>
|
||||
</div>
|
||||
@@ -39,17 +38,20 @@
|
||||
<span class="text-brand-red">*</span>
|
||||
</span>
|
||||
</label>
|
||||
<input
|
||||
<StyledInput
|
||||
v-if="newNoticeSurvey"
|
||||
id="notice-message"
|
||||
v-model="newNoticeMessage"
|
||||
placeholder="E.g. rXGtq2"
|
||||
type="text"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<div v-else class="textarea-wrapper h-32">
|
||||
<textarea id="notice-message" v-model="newNoticeMessage" />
|
||||
</div>
|
||||
<StyledInput
|
||||
v-else
|
||||
id="notice-message"
|
||||
v-model="newNoticeMessage"
|
||||
multiline
|
||||
wrapper-class="h-32"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="!newNoticeSurvey" class="flex items-center justify-between gap-2">
|
||||
<label for="dismissable-toggle" class="flex flex-col gap-1">
|
||||
@@ -63,7 +65,7 @@
|
||||
<span class="text-lg font-semibold text-contrast"> Announcement date </span>
|
||||
<span>Leave blank for notice to be available immediately.</span>
|
||||
</label>
|
||||
<input
|
||||
<StyledInput
|
||||
id="scheduled-date"
|
||||
v-model="newNoticeScheduledDate"
|
||||
type="datetime-local"
|
||||
@@ -75,7 +77,7 @@
|
||||
<span class="text-lg font-semibold text-contrast"> Expiration date </span>
|
||||
<span>The notice will automatically be deleted after this date.</span>
|
||||
</label>
|
||||
<input
|
||||
<StyledInput
|
||||
id="expiration-date"
|
||||
v-model="newNoticeExpiresDate"
|
||||
type="datetime-local"
|
||||
@@ -271,6 +273,7 @@ import {
|
||||
injectNotificationManager,
|
||||
NewModal,
|
||||
ServerNotice,
|
||||
StyledInput,
|
||||
TagItem,
|
||||
Toggle,
|
||||
useRelativeTime,
|
||||
|
||||
@@ -10,11 +10,11 @@
|
||||
<span class="text-brand-red">*</span>
|
||||
</span>
|
||||
</label>
|
||||
<input
|
||||
<StyledInput
|
||||
id="name"
|
||||
v-model="userEmail"
|
||||
type="email"
|
||||
maxlength="64"
|
||||
:maxlength="64"
|
||||
:placeholder="`Enter user email...`"
|
||||
autocomplete="off"
|
||||
/>
|
||||
@@ -33,7 +33,7 @@
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { MailIcon } from '@modrinth/assets'
|
||||
import { ButtonStyled, injectNotificationManager } from '@modrinth/ui'
|
||||
import { ButtonStyled, injectNotificationManager, StyledInput } from '@modrinth/ui'
|
||||
|
||||
const { addNotification } = injectNotificationManager()
|
||||
|
||||
|
||||
@@ -7,20 +7,18 @@
|
||||
{{ formatMessage(methodChoiceMessages.description) }}
|
||||
</p>
|
||||
|
||||
<div class="iconified-input">
|
||||
<label for="email" hidden>
|
||||
{{ formatMessage(commonMessages.emailUsernameLabel) }}
|
||||
</label>
|
||||
<MailIcon />
|
||||
<input
|
||||
id="email"
|
||||
v-model="email"
|
||||
type="text"
|
||||
autocomplete="username"
|
||||
class="auth-form__input"
|
||||
:placeholder="formatMessage(commonMessages.emailLabel)"
|
||||
/>
|
||||
</div>
|
||||
<label for="email" hidden>
|
||||
{{ formatMessage(commonMessages.emailUsernameLabel) }}
|
||||
</label>
|
||||
<StyledInput
|
||||
id="email"
|
||||
v-model="email"
|
||||
:icon="MailIcon"
|
||||
type="text"
|
||||
autocomplete="username"
|
||||
:placeholder="formatMessage(commonMessages.emailLabel)"
|
||||
wrapper-class="w-full"
|
||||
/>
|
||||
|
||||
<HCaptcha v-if="globals?.captcha_enabled" ref="captcha" v-model="token" />
|
||||
|
||||
@@ -35,33 +33,29 @@
|
||||
<template v-else-if="step === 'passed_challenge'">
|
||||
<p>{{ formatMessage(postChallengeMessages.description) }}</p>
|
||||
|
||||
<div class="iconified-input">
|
||||
<label for="password" hidden>{{ formatMessage(commonMessages.passwordLabel) }}</label>
|
||||
<KeyIcon />
|
||||
<input
|
||||
id="password"
|
||||
v-model="newPassword"
|
||||
type="password"
|
||||
autocomplete="new-password"
|
||||
class="auth-form__input"
|
||||
:placeholder="formatMessage(commonMessages.passwordLabel)"
|
||||
/>
|
||||
</div>
|
||||
<label for="password" hidden>{{ formatMessage(commonMessages.passwordLabel) }}</label>
|
||||
<StyledInput
|
||||
id="password"
|
||||
v-model="newPassword"
|
||||
:icon="KeyIcon"
|
||||
type="password"
|
||||
autocomplete="new-password"
|
||||
:placeholder="formatMessage(commonMessages.passwordLabel)"
|
||||
wrapper-class="w-full"
|
||||
/>
|
||||
|
||||
<div class="iconified-input">
|
||||
<label for="confirm-password" hidden>
|
||||
{{ formatMessage(commonMessages.passwordLabel) }}
|
||||
</label>
|
||||
<KeyIcon />
|
||||
<input
|
||||
id="confirm-password"
|
||||
v-model="confirmNewPassword"
|
||||
type="password"
|
||||
autocomplete="new-password"
|
||||
class="auth-form__input"
|
||||
:placeholder="formatMessage(postChallengeMessages.confirmPasswordLabel)"
|
||||
/>
|
||||
</div>
|
||||
<label for="confirm-password" hidden>
|
||||
{{ formatMessage(commonMessages.passwordLabel) }}
|
||||
</label>
|
||||
<StyledInput
|
||||
id="confirm-password"
|
||||
v-model="confirmNewPassword"
|
||||
:icon="KeyIcon"
|
||||
type="password"
|
||||
autocomplete="new-password"
|
||||
:placeholder="formatMessage(postChallengeMessages.confirmPasswordLabel)"
|
||||
wrapper-class="w-full"
|
||||
/>
|
||||
|
||||
<button class="auth-form__input btn btn-primary continue-btn" @click="changePassword">
|
||||
{{ formatMessage(postChallengeMessages.action) }}
|
||||
@@ -72,7 +66,13 @@
|
||||
</template>
|
||||
<script setup>
|
||||
import { KeyIcon, MailIcon, SendIcon } from '@modrinth/assets'
|
||||
import { commonMessages, defineMessages, injectNotificationManager, useVIntl } from '@modrinth/ui'
|
||||
import {
|
||||
commonMessages,
|
||||
defineMessages,
|
||||
injectNotificationManager,
|
||||
StyledInput,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
|
||||
import HCaptcha from '@/components/ui/HCaptcha.vue'
|
||||
|
||||
|
||||
@@ -13,15 +13,13 @@
|
||||
{{ formatMessage(messages.twoFactorCodeLabelDescription) }}
|
||||
</span>
|
||||
</label>
|
||||
<input
|
||||
<StyledInput
|
||||
id="two-factor-code"
|
||||
v-model="twoFactorCode"
|
||||
maxlength="11"
|
||||
type="text"
|
||||
:maxlength="11"
|
||||
inputmode="numeric"
|
||||
:placeholder="formatMessage(messages.twoFactorCodeInputPlaceholder)"
|
||||
autocomplete="one-time-code"
|
||||
autofocus
|
||||
@keyup.enter="begin2FASignIn"
|
||||
/>
|
||||
|
||||
@@ -62,32 +60,28 @@
|
||||
<h1>{{ formatMessage(messages.usePasswordLabel) }}</h1>
|
||||
|
||||
<section class="auth-form">
|
||||
<div class="iconified-input">
|
||||
<label for="email" hidden>{{ formatMessage(commonMessages.emailUsernameLabel) }}</label>
|
||||
<MailIcon />
|
||||
<input
|
||||
id="email"
|
||||
v-model="email"
|
||||
type="text"
|
||||
inputmode="email"
|
||||
autocomplete="username"
|
||||
class="auth-form__input"
|
||||
:placeholder="formatMessage(commonMessages.emailUsernameLabel)"
|
||||
/>
|
||||
</div>
|
||||
<label for="email" hidden>{{ formatMessage(commonMessages.emailUsernameLabel) }}</label>
|
||||
<StyledInput
|
||||
id="email"
|
||||
v-model="email"
|
||||
:icon="MailIcon"
|
||||
type="text"
|
||||
inputmode="email"
|
||||
autocomplete="username"
|
||||
:placeholder="formatMessage(commonMessages.emailUsernameLabel)"
|
||||
wrapper-class="w-full"
|
||||
/>
|
||||
|
||||
<div class="iconified-input">
|
||||
<label for="password" hidden>{{ formatMessage(commonMessages.passwordLabel) }}</label>
|
||||
<KeyIcon />
|
||||
<input
|
||||
id="password"
|
||||
v-model="password"
|
||||
type="password"
|
||||
autocomplete="current-password"
|
||||
class="auth-form__input"
|
||||
:placeholder="formatMessage(commonMessages.passwordLabel)"
|
||||
/>
|
||||
</div>
|
||||
<label for="password" hidden>{{ formatMessage(commonMessages.passwordLabel) }}</label>
|
||||
<StyledInput
|
||||
id="password"
|
||||
v-model="password"
|
||||
:icon="KeyIcon"
|
||||
type="password"
|
||||
autocomplete="current-password"
|
||||
:placeholder="formatMessage(commonMessages.passwordLabel)"
|
||||
wrapper-class="w-full"
|
||||
/>
|
||||
|
||||
<HCaptcha v-if="globals?.captcha_enabled" ref="captcha" v-model="token" />
|
||||
|
||||
@@ -147,6 +141,7 @@ import {
|
||||
defineMessages,
|
||||
injectNotificationManager,
|
||||
IntlFormatted,
|
||||
StyledInput,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { useQueryClient } from '@tanstack/vue-query'
|
||||
|
||||
@@ -32,59 +32,49 @@
|
||||
<h1>{{ formatMessage(messages.createAccountTitle) }}</h1>
|
||||
|
||||
<section class="auth-form">
|
||||
<div class="iconified-input">
|
||||
<label for="email" hidden>{{ formatMessage(commonMessages.emailLabel) }}</label>
|
||||
<MailIcon />
|
||||
<input
|
||||
id="email"
|
||||
v-model="email"
|
||||
type="email"
|
||||
autocomplete="username"
|
||||
class="auth-form__input"
|
||||
:placeholder="formatMessage(commonMessages.emailLabel)"
|
||||
/>
|
||||
</div>
|
||||
<label for="email" hidden>{{ formatMessage(commonMessages.emailLabel) }}</label>
|
||||
<StyledInput
|
||||
id="email"
|
||||
v-model="email"
|
||||
:icon="MailIcon"
|
||||
type="email"
|
||||
autocomplete="username"
|
||||
:placeholder="formatMessage(commonMessages.emailLabel)"
|
||||
wrapper-class="w-full"
|
||||
/>
|
||||
|
||||
<div class="iconified-input">
|
||||
<label for="username" hidden>{{ formatMessage(commonMessages.usernameLabel) }}</label>
|
||||
<UserIcon />
|
||||
<input
|
||||
id="username"
|
||||
v-model="username"
|
||||
type="text"
|
||||
autocomplete="username"
|
||||
class="auth-form__input"
|
||||
:placeholder="formatMessage(commonMessages.usernameLabel)"
|
||||
/>
|
||||
</div>
|
||||
<label for="username" hidden>{{ formatMessage(commonMessages.usernameLabel) }}</label>
|
||||
<StyledInput
|
||||
id="username"
|
||||
v-model="username"
|
||||
:icon="UserIcon"
|
||||
type="text"
|
||||
autocomplete="username"
|
||||
:placeholder="formatMessage(commonMessages.usernameLabel)"
|
||||
wrapper-class="w-full"
|
||||
/>
|
||||
|
||||
<div class="iconified-input">
|
||||
<label for="password" hidden>{{ formatMessage(commonMessages.passwordLabel) }}</label>
|
||||
<KeyIcon />
|
||||
<input
|
||||
id="password"
|
||||
v-model="password"
|
||||
class="auth-form__input"
|
||||
type="password"
|
||||
autocomplete="new-password"
|
||||
:placeholder="formatMessage(commonMessages.passwordLabel)"
|
||||
/>
|
||||
</div>
|
||||
<label for="password" hidden>{{ formatMessage(commonMessages.passwordLabel) }}</label>
|
||||
<StyledInput
|
||||
id="password"
|
||||
v-model="password"
|
||||
:icon="KeyIcon"
|
||||
type="password"
|
||||
autocomplete="new-password"
|
||||
:placeholder="formatMessage(commonMessages.passwordLabel)"
|
||||
wrapper-class="w-full"
|
||||
/>
|
||||
|
||||
<div class="iconified-input">
|
||||
<label for="confirm-password" hidden>{{
|
||||
formatMessage(commonMessages.passwordLabel)
|
||||
}}</label>
|
||||
<KeyIcon />
|
||||
<input
|
||||
id="confirm-password"
|
||||
v-model="confirmPassword"
|
||||
type="password"
|
||||
autocomplete="new-password"
|
||||
class="auth-form__input"
|
||||
:placeholder="formatMessage(commonMessages.confirmPasswordLabel)"
|
||||
/>
|
||||
</div>
|
||||
<label for="confirm-password" hidden>{{ formatMessage(commonMessages.passwordLabel) }}</label>
|
||||
<StyledInput
|
||||
id="confirm-password"
|
||||
v-model="confirmPassword"
|
||||
:icon="KeyIcon"
|
||||
type="password"
|
||||
autocomplete="new-password"
|
||||
:placeholder="formatMessage(commonMessages.confirmPasswordLabel)"
|
||||
wrapper-class="w-full"
|
||||
/>
|
||||
|
||||
<Checkbox
|
||||
v-model="subscribe"
|
||||
@@ -153,6 +143,7 @@ import {
|
||||
defineMessages,
|
||||
injectNotificationManager,
|
||||
IntlFormatted,
|
||||
StyledInput,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
|
||||
|
||||
@@ -75,13 +75,12 @@
|
||||
<label class="mb-2 block text-lg font-semibold text-contrast" for="collection-title">
|
||||
{{ formatMessage(commonMessages.titleLabel) }}
|
||||
</label>
|
||||
<input
|
||||
<StyledInput
|
||||
id="collection-title"
|
||||
v-model="current.name"
|
||||
maxlength="255"
|
||||
type="text"
|
||||
:maxlength="255"
|
||||
autocomplete="off"
|
||||
class="w-full"
|
||||
wrapper-class="w-full"
|
||||
/>
|
||||
</div>
|
||||
<label
|
||||
@@ -90,9 +89,13 @@
|
||||
>
|
||||
{{ formatMessage(commonMessages.descriptionLabel) }}
|
||||
</label>
|
||||
<div class="textarea-wrapper h-24">
|
||||
<textarea id="collection-description" v-model="current.description" maxlength="255" />
|
||||
</div>
|
||||
<StyledInput
|
||||
id="collection-description"
|
||||
v-model="current.description"
|
||||
multiline
|
||||
:maxlength="255"
|
||||
wrapper-class="h-24"
|
||||
/>
|
||||
<label for="visibility" class="mb-2 mt-4 block text-lg font-semibold text-contrast">
|
||||
{{ formatMessage(commonMessages.visibilityLabel) }}
|
||||
</label>
|
||||
@@ -405,6 +408,7 @@ import {
|
||||
ProjectCardList,
|
||||
RadioButtons,
|
||||
SidebarCard,
|
||||
StyledInput,
|
||||
useRelativeTime,
|
||||
useSavable,
|
||||
useVIntl,
|
||||
|
||||
@@ -18,20 +18,14 @@
|
||||
{{ formatMessage(messages.yourAffiliateLinks) }}
|
||||
</h1>
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="iconified-input">
|
||||
<SearchIcon aria-hidden="true" />
|
||||
<input
|
||||
v-model="filterQuery"
|
||||
class="card-shadow"
|
||||
autocomplete="off"
|
||||
spellcheck="false"
|
||||
type="text"
|
||||
:placeholder="formatMessage(messages.searchAffiliateLinks)"
|
||||
/>
|
||||
<Button v-if="filterQuery" class="r-btn" @click="() => (filterQuery = '')">
|
||||
<XIcon />
|
||||
</Button>
|
||||
</div>
|
||||
<StyledInput
|
||||
v-model="filterQuery"
|
||||
:icon="SearchIcon"
|
||||
type="text"
|
||||
autocomplete="off"
|
||||
:placeholder="formatMessage(messages.searchAffiliateLinks)"
|
||||
clearable
|
||||
/>
|
||||
<ButtonStyled color="brand">
|
||||
<button @click="createModal?.show">
|
||||
<PlusIcon />
|
||||
@@ -63,16 +57,16 @@
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { PlusIcon, SearchIcon, XCircleIcon, XIcon } from '@modrinth/assets'
|
||||
import { PlusIcon, SearchIcon, XCircleIcon } from '@modrinth/assets'
|
||||
import {
|
||||
Admonition,
|
||||
AffiliateLinkCard,
|
||||
AffiliateLinkCreateModal,
|
||||
Button,
|
||||
ButtonStyled,
|
||||
ConfirmModal,
|
||||
defineMessages,
|
||||
injectNotificationManager,
|
||||
StyledInput,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import type { AffiliateLink } from '@modrinth/utils'
|
||||
|
||||
@@ -3,18 +3,18 @@
|
||||
<CollectionCreateModal ref="modal_creation" />
|
||||
<h2 class="text-2xl">{{ formatMessage(commonMessages.collectionsLabel) }}</h2>
|
||||
<div class="search-row">
|
||||
<div class="iconified-input">
|
||||
<div class="flex-grow">
|
||||
<label for="search-input" hidden>{{ formatMessage(messages.searchInputLabel) }}</label>
|
||||
<SearchIcon aria-hidden="true" />
|
||||
<input id="search-input" v-model="filterQuery" type="text" />
|
||||
<Button
|
||||
v-if="filterQuery"
|
||||
class="r-btn"
|
||||
aria-label="Clear search"
|
||||
@click="() => (filterQuery = '')"
|
||||
>
|
||||
<XIcon aria-hidden="true" />
|
||||
</Button>
|
||||
<StyledInput
|
||||
id="search-input"
|
||||
v-model="filterQuery"
|
||||
:icon="SearchIcon"
|
||||
type="text"
|
||||
clearable
|
||||
placeholder="Search collections..."
|
||||
wrapper-class="w-full"
|
||||
input-class="h-8"
|
||||
/>
|
||||
</div>
|
||||
<Button color="primary" @click="(event) => $refs.modal_creation.show(event)">
|
||||
<PlusIcon aria-hidden="true" />
|
||||
@@ -106,7 +106,7 @@ import {
|
||||
SearchIcon,
|
||||
XIcon,
|
||||
} from '@modrinth/assets'
|
||||
import { Avatar, Button, commonMessages, defineMessages, useVIntl } from '@modrinth/ui'
|
||||
import { Avatar, Button, commonMessages, defineMessages, StyledInput, useVIntl } from '@modrinth/ui'
|
||||
|
||||
import CollectionCreateModal from '~/components/ui/create/CollectionCreateModal.vue'
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<span class="label__title">Issue tracker</span>
|
||||
</label>
|
||||
<div class="input-group shrink-first">
|
||||
<input
|
||||
<StyledInput
|
||||
id="issue-tracker-input"
|
||||
v-model="editLinks.issues.val"
|
||||
:disabled="editLinks.issues.clear"
|
||||
@@ -23,7 +23,7 @@
|
||||
:placeholder="
|
||||
editLinks.issues.clear ? 'Existing link will be cleared' : 'Enter a valid URL'
|
||||
"
|
||||
maxlength="2048"
|
||||
:maxlength="2048"
|
||||
/>
|
||||
<button
|
||||
v-tooltip="'Clear link'"
|
||||
@@ -42,12 +42,12 @@
|
||||
<span class="label__title">Source code</span>
|
||||
</label>
|
||||
<div class="input-group shrink-first">
|
||||
<input
|
||||
<StyledInput
|
||||
id="source-code-input"
|
||||
v-model="editLinks.source.val"
|
||||
:disabled="editLinks.source.clear"
|
||||
type="url"
|
||||
maxlength="2048"
|
||||
:maxlength="2048"
|
||||
:placeholder="
|
||||
editLinks.source.clear ? 'Existing link will be cleared' : 'Enter a valid URL'
|
||||
"
|
||||
@@ -69,12 +69,12 @@
|
||||
<span class="label__title">Wiki page</span>
|
||||
</label>
|
||||
<div class="input-group shrink-first">
|
||||
<input
|
||||
<StyledInput
|
||||
id="wiki-page-input"
|
||||
v-model="editLinks.wiki.val"
|
||||
:disabled="editLinks.wiki.clear"
|
||||
type="url"
|
||||
maxlength="2048"
|
||||
:maxlength="2048"
|
||||
:placeholder="
|
||||
editLinks.wiki.clear ? 'Existing link will be cleared' : 'Enter a valid URL'
|
||||
"
|
||||
@@ -93,12 +93,12 @@
|
||||
<span class="label__title">Discord invite</span>
|
||||
</label>
|
||||
<div class="input-group shrink-first">
|
||||
<input
|
||||
<StyledInput
|
||||
id="discord-invite-input"
|
||||
v-model="editLinks.discord.val"
|
||||
:disabled="editLinks.discord.clear"
|
||||
type="url"
|
||||
maxlength="2048"
|
||||
:maxlength="2048"
|
||||
:placeholder="
|
||||
editLinks.discord.clear
|
||||
? 'Existing link will be cleared'
|
||||
@@ -335,6 +335,7 @@ import {
|
||||
injectNotificationManager,
|
||||
NewModal,
|
||||
ProjectStatusBadge,
|
||||
StyledInput,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { formatProjectType } from '@modrinth/utils'
|
||||
|
||||
@@ -18,7 +18,6 @@ import {
|
||||
} from '@modrinth/assets'
|
||||
import {
|
||||
Avatar,
|
||||
Button,
|
||||
ButtonStyled,
|
||||
Checkbox,
|
||||
defineMessages,
|
||||
@@ -31,6 +30,7 @@ import {
|
||||
SearchFilterControl,
|
||||
SearchSidebarFilter,
|
||||
type SortType,
|
||||
StyledInput,
|
||||
Toggle,
|
||||
useSearch,
|
||||
useVIntl,
|
||||
@@ -583,30 +583,18 @@ useSeoMeta({
|
||||
</aside>
|
||||
<section class="normal-page__content">
|
||||
<div class="flex flex-col gap-3">
|
||||
<div class="iconified-input w-full">
|
||||
<SearchIcon aria-hidden="true" class="text-lg" />
|
||||
<input
|
||||
v-model="query"
|
||||
class="h-12"
|
||||
autocomplete="off"
|
||||
spellcheck="false"
|
||||
type="text"
|
||||
:placeholder="`Search ${projectType?.display ?? 'project'}s...`"
|
||||
@input="throttledSearch()"
|
||||
/>
|
||||
<Button
|
||||
v-if="query"
|
||||
class="r-btn"
|
||||
@click="
|
||||
() => {
|
||||
query = ''
|
||||
updateSearchResults()
|
||||
}
|
||||
"
|
||||
>
|
||||
<XIcon />
|
||||
</Button>
|
||||
</div>
|
||||
<StyledInput
|
||||
v-model="query"
|
||||
:icon="SearchIcon"
|
||||
type="text"
|
||||
autocomplete="off"
|
||||
:placeholder="`Search ${projectType?.display ?? 'project'}s...`"
|
||||
clearable
|
||||
wrapper-class="w-full"
|
||||
input-class="!h-12"
|
||||
@input="throttledSearch()"
|
||||
@clear="updateSearchResults()"
|
||||
/>
|
||||
<div class="flex flex-wrap items-center gap-2">
|
||||
<DropdownSelect
|
||||
v-slot="{ selected }"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { SearchIcon } from '@modrinth/assets'
|
||||
import { Toggle } from '@modrinth/ui'
|
||||
import { StyledInput, Toggle } from '@modrinth/ui'
|
||||
import Fuse from 'fuse.js'
|
||||
import { computed, ref, shallowReactive } from 'vue'
|
||||
|
||||
@@ -38,15 +38,13 @@ useSeoMeta({
|
||||
<template>
|
||||
<div class="mx-auto my-4 box-border w-[calc(100%-2rem)] max-w-[800px]">
|
||||
<h1 class="mb-4 text-2xl font-bold text-contrast">Feature flags</h1>
|
||||
<div class="relative mb-2">
|
||||
<SearchIcon
|
||||
class="pointer-events-none absolute left-3 top-1/2 size-5 -translate-y-1/2 text-secondary"
|
||||
/>
|
||||
<input
|
||||
<div class="mb-2">
|
||||
<StyledInput
|
||||
v-model="searchQuery"
|
||||
type="search"
|
||||
:icon="SearchIcon"
|
||||
placeholder="Search flags..."
|
||||
class="w-full rounded-xl bg-bg-raised py-2 pl-10 pr-4"
|
||||
wrapper-class="w-full rounded-xl bg-bg-raised"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
|
||||
@@ -41,17 +41,14 @@
|
||||
<div class="sticky top-0 z-20 -mt-3 flex items-center justify-between bg-bg py-3">
|
||||
<div class="flex w-full flex-col-reverse items-center gap-2 sm:flex-row">
|
||||
<div class="flex w-full items-center gap-2">
|
||||
<div class="relative flex-1 text-sm">
|
||||
<div class="flex-1 text-sm">
|
||||
<label class="sr-only" for="search">Search</label>
|
||||
<SearchIcon
|
||||
class="pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<input
|
||||
<StyledInput
|
||||
id="search"
|
||||
v-model="searchInput"
|
||||
class="!h-9 !min-h-0 w-full border-[1px] border-solid border-button-border pl-9"
|
||||
wrapper-class="w-full"
|
||||
type="search"
|
||||
:icon="SearchIcon"
|
||||
name="search"
|
||||
autocomplete="off"
|
||||
:placeholder="`Search ${localMods.length} ${type.toLocaleLowerCase()}s...`"
|
||||
@@ -356,6 +353,7 @@ import {
|
||||
ButtonStyled,
|
||||
injectModrinthClient,
|
||||
injectNotificationManager,
|
||||
StyledInput,
|
||||
Toggle,
|
||||
} from '@modrinth/ui'
|
||||
import type { Mod } from '@modrinth/utils'
|
||||
|
||||
@@ -8,12 +8,11 @@
|
||||
<span> This name is only visible on Modrinth.</span>
|
||||
</label>
|
||||
<div class="flex flex-col gap-2">
|
||||
<input
|
||||
<StyledInput
|
||||
id="server-name-field"
|
||||
v-model="serverName"
|
||||
class="w-full md:w-[50%]"
|
||||
maxlength="48"
|
||||
minlength="1"
|
||||
wrapper-class="w-full md:w-[50%]"
|
||||
:maxlength="48"
|
||||
@keyup.enter="!serverName && saveGeneral"
|
||||
/>
|
||||
<span v-if="!serverName" class="text-sm text-rose-400">
|
||||
@@ -42,11 +41,11 @@
|
||||
<span> Your friends can connect to your server using this URL. </span>
|
||||
</label>
|
||||
<div class="flex w-full items-center gap-2 md:w-[60%]">
|
||||
<input
|
||||
<StyledInput
|
||||
id="server-subdomain"
|
||||
v-model="serverSubdomain"
|
||||
class="h-[50%] w-[63%]"
|
||||
maxlength="32"
|
||||
wrapper-class="h-[50%] w-[63%]"
|
||||
:maxlength="32"
|
||||
@keyup.enter="saveGeneral"
|
||||
/>
|
||||
.modrinth.gg
|
||||
@@ -116,7 +115,12 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { EditIcon, TransferIcon } from '@modrinth/assets'
|
||||
import { injectModrinthClient, injectNotificationManager, ServerIcon } from '@modrinth/ui'
|
||||
import {
|
||||
injectModrinthClient,
|
||||
injectNotificationManager,
|
||||
ServerIcon,
|
||||
StyledInput,
|
||||
} from '@modrinth/ui'
|
||||
import ButtonStyled from '@modrinth/ui/src/components/base/ButtonStyled.vue'
|
||||
|
||||
import SaveBanner from '~/components/ui/servers/SaveBanner.vue'
|
||||
|
||||
@@ -3,13 +3,12 @@
|
||||
<NewModal ref="newAllocationModal" header="New allocation">
|
||||
<form class="flex flex-col gap-2 md:w-[600px]" @submit.prevent="addNewAllocation">
|
||||
<label for="new-allocation-name" class="font-semibold text-contrast"> Name </label>
|
||||
<input
|
||||
<StyledInput
|
||||
id="new-allocation-name"
|
||||
ref="newAllocationInput"
|
||||
v-model="newAllocationName"
|
||||
type="text"
|
||||
class="bg-bg-input w-full rounded-lg p-4"
|
||||
maxlength="32"
|
||||
wrapper-class="w-full"
|
||||
:maxlength="32"
|
||||
placeholder="e.g. Secondary allocation"
|
||||
/>
|
||||
<div class="mb-1 mt-4 flex justify-start gap-4">
|
||||
@@ -28,13 +27,12 @@
|
||||
<NewModal ref="editAllocationModal" header="Edit allocation">
|
||||
<form class="flex flex-col gap-2 md:w-[600px]" @submit.prevent="editAllocation">
|
||||
<label for="edit-allocation-name" class="font-semibold text-contrast"> Name </label>
|
||||
<input
|
||||
<StyledInput
|
||||
id="edit-allocation-name"
|
||||
ref="editAllocationInput"
|
||||
v-model="newAllocationName"
|
||||
type="text"
|
||||
class="bg-bg-input w-full rounded-lg p-4"
|
||||
maxlength="32"
|
||||
wrapper-class="w-full"
|
||||
:maxlength="32"
|
||||
placeholder="e.g. Secondary allocation"
|
||||
/>
|
||||
<div class="mb-1 mt-4 flex justify-start gap-4">
|
||||
@@ -107,13 +105,11 @@
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
|
||||
<input
|
||||
<StyledInput
|
||||
id="user-domain"
|
||||
v-model="userDomain"
|
||||
class="w-full md:w-[50%]"
|
||||
maxlength="64"
|
||||
minlength="1"
|
||||
type="text"
|
||||
wrapper-class="w-full md:w-[50%]"
|
||||
:maxlength="64"
|
||||
:placeholder="exampleDomain"
|
||||
/>
|
||||
|
||||
@@ -279,6 +275,7 @@ import {
|
||||
CopyCode,
|
||||
injectNotificationManager,
|
||||
NewModal,
|
||||
StyledInput,
|
||||
} from '@modrinth/ui'
|
||||
import { computed, nextTick, ref } from 'vue'
|
||||
|
||||
|
||||
@@ -21,17 +21,14 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col gap-4 rounded-2xl bg-table-alternateRow p-4">
|
||||
<div class="relative w-full text-sm">
|
||||
<div class="w-full text-sm">
|
||||
<label for="search-server-properties" class="sr-only">Search server properties</label>
|
||||
<SearchIcon
|
||||
class="pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<input
|
||||
<StyledInput
|
||||
id="search-server-properties"
|
||||
v-model="searchInput"
|
||||
class="w-full pl-9"
|
||||
wrapper-class="w-full"
|
||||
type="search"
|
||||
:icon="SearchIcon"
|
||||
name="search"
|
||||
autocomplete="off"
|
||||
placeholder="Search server properties..."
|
||||
@@ -72,41 +69,44 @@
|
||||
v-else-if="typeof property === 'number' && index !== 'level-seed' && index !== 'seed'"
|
||||
class="mt-2 w-full sm:w-[320px]"
|
||||
>
|
||||
<input
|
||||
<StyledInput
|
||||
:id="`server-property-${index}`"
|
||||
v-model.number="liveProperties[index]"
|
||||
:model-value="liveProperties[index]"
|
||||
type="number"
|
||||
class="w-full border p-2"
|
||||
wrapper-class="w-full"
|
||||
:aria-labelledby="`property-label-${index}`"
|
||||
@update:model-value="liveProperties[index] = $event"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-else-if="index === 'level-seed' || index === 'seed'"
|
||||
class="mt-2 w-full sm:w-[320px]"
|
||||
>
|
||||
<input
|
||||
<StyledInput
|
||||
:id="`server-property-${index}`"
|
||||
v-model="liveProperties[index]"
|
||||
type="text"
|
||||
class="w-full rounded-xl border p-2"
|
||||
:model-value="liveProperties[index]"
|
||||
wrapper-class="w-full"
|
||||
:aria-labelledby="`property-label-${index}`"
|
||||
@update:model-value="liveProperties[index] = $event"
|
||||
/>
|
||||
</div>
|
||||
<div v-else-if="isComplexProperty(property)" class="mt-2 w-full sm:w-[320px]">
|
||||
<textarea
|
||||
<StyledInput
|
||||
:id="`server-property-${index}`"
|
||||
v-model="liveProperties[index]"
|
||||
class="w-full resize-y rounded-xl border p-2"
|
||||
multiline
|
||||
resize="vertical"
|
||||
input-class="p-2"
|
||||
:aria-labelledby="`property-label-${index}`"
|
||||
></textarea>
|
||||
/>
|
||||
</div>
|
||||
<div v-else class="mt-2 flex w-full justify-end sm:w-[320px]">
|
||||
<input
|
||||
<StyledInput
|
||||
:id="`server-property-${index}`"
|
||||
v-model="liveProperties[index]"
|
||||
type="text"
|
||||
class="w-full rounded-xl border p-2"
|
||||
:model-value="liveProperties[index]"
|
||||
wrapper-class="w-full"
|
||||
:aria-labelledby="`property-label-${index}`"
|
||||
@update:model-value="liveProperties[index] = $event"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -132,7 +132,13 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { EyeIcon, SearchIcon } from '@modrinth/assets'
|
||||
import { Combobox, injectModrinthClient, injectNotificationManager, Toggle } from '@modrinth/ui'
|
||||
import {
|
||||
Combobox,
|
||||
injectModrinthClient,
|
||||
injectNotificationManager,
|
||||
StyledInput,
|
||||
Toggle,
|
||||
} from '@modrinth/ui'
|
||||
import Fuse from 'fuse.js'
|
||||
import { computed, inject, ref, watch } from 'vue'
|
||||
|
||||
|
||||
@@ -51,10 +51,12 @@
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
<textarea
|
||||
<StyledInput
|
||||
id="startup-command-field"
|
||||
v-model="invocation"
|
||||
class="min-h-[270px] w-full resize-y font-[family-name:var(--mono-font)]"
|
||||
multiline
|
||||
resize="vertical"
|
||||
input-class="min-h-[270px] font-[family-name:var(--mono-font)]"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -108,7 +110,13 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { IssuesIcon, UpdatedIcon } from '@modrinth/assets'
|
||||
import { ButtonStyled, Combobox, injectNotificationManager, Toggle } from '@modrinth/ui'
|
||||
import {
|
||||
ButtonStyled,
|
||||
Combobox,
|
||||
injectNotificationManager,
|
||||
StyledInput,
|
||||
Toggle,
|
||||
} from '@modrinth/ui'
|
||||
|
||||
import SaveBanner from '~/components/ui/servers/SaveBanner.vue'
|
||||
import type { ModrinthServer } from '~/composables/servers/modrinth-servers.ts'
|
||||
|
||||
@@ -91,21 +91,20 @@
|
||||
<div class="blob-demonstration gradient-border bigger">
|
||||
<div class="demo-search">
|
||||
<div class="search-controls">
|
||||
<div class="iconified-input">
|
||||
<label class="hidden" for="search">{{
|
||||
formatMessage(commonMessages.searchLabel)
|
||||
}}</label>
|
||||
<SearchIcon aria-hidden="true" />
|
||||
<input
|
||||
id="search"
|
||||
v-model="searchQuery"
|
||||
type="search"
|
||||
name="search"
|
||||
:placeholder="formatMessage(commonMessages.searchPlaceholder)"
|
||||
autocomplete="off"
|
||||
@input="updateSearchProjects"
|
||||
/>
|
||||
</div>
|
||||
<label class="hidden" for="search">{{
|
||||
formatMessage(commonMessages.searchLabel)
|
||||
}}</label>
|
||||
<StyledInput
|
||||
id="search"
|
||||
v-model="searchQuery"
|
||||
:icon="SearchIcon"
|
||||
type="search"
|
||||
name="search"
|
||||
:placeholder="formatMessage(commonMessages.searchPlaceholder)"
|
||||
autocomplete="off"
|
||||
wrapper-class="w-full"
|
||||
@input="updateSearchProjects"
|
||||
/>
|
||||
<div class="sort-by">
|
||||
<span class="label">{{ formatMessage(commonMessages.sortByLabel) }}</span>
|
||||
<Multiselect
|
||||
@@ -447,6 +446,7 @@ import {
|
||||
defineMessages,
|
||||
IntlFormatted,
|
||||
ProjectCard,
|
||||
StyledInput,
|
||||
useRelativeTime,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
|
||||
@@ -102,7 +102,7 @@
|
||||
<tr>
|
||||
<td>Revenue earned on</td>
|
||||
<td>
|
||||
<input id="revenue-date-picker" v-model="rawSelectedDate" type="date" />
|
||||
<StyledInput id="revenue-date-picker" v-model="rawSelectedDate" type="date" />
|
||||
<noscript
|
||||
>(JavaScript must be enabled for the date picker to function, example date:
|
||||
2024-07-15)
|
||||
@@ -162,6 +162,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { StyledInput } from '@modrinth/ui'
|
||||
import { formatDate, formatMoney } from '@modrinth/utils'
|
||||
import dayjs from 'dayjs'
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
@@ -1,21 +1,17 @@
|
||||
<template>
|
||||
<div class="flex flex-col gap-4">
|
||||
<div class="flex flex-col justify-between gap-3 lg:flex-row">
|
||||
<div class="iconified-input flex-1 lg:max-w-md">
|
||||
<SearchIcon aria-hidden="true" class="text-lg" />
|
||||
<input
|
||||
v-model="query"
|
||||
class="h-[40px]"
|
||||
autocomplete="off"
|
||||
spellcheck="false"
|
||||
type="text"
|
||||
:placeholder="formatMessage(commonMessages.searchPlaceholder)"
|
||||
@input="goToPage(1)"
|
||||
/>
|
||||
<Button v-if="query" class="r-btn" @click="() => (query = '')">
|
||||
<XIcon />
|
||||
</Button>
|
||||
</div>
|
||||
<StyledInput
|
||||
v-model="query"
|
||||
:icon="SearchIcon"
|
||||
type="text"
|
||||
autocomplete="off"
|
||||
:placeholder="formatMessage(commonMessages.searchPlaceholder)"
|
||||
clearable
|
||||
wrapper-class="flex-1 lg:max-w-52"
|
||||
input-class="h-[40px]"
|
||||
@input="goToPage(1)"
|
||||
/>
|
||||
|
||||
<div v-if="totalPages > 1" class="hidden flex-1 justify-center lg:flex">
|
||||
<Pagination :page="currentPage" :count="totalPages" @switch-page="goToPage" />
|
||||
@@ -99,16 +95,8 @@
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ListFilterIcon, ScaleIcon, SearchIcon, SortAscIcon, SortDescIcon } from '@modrinth/assets'
|
||||
import {
|
||||
ListFilterIcon,
|
||||
ScaleIcon,
|
||||
SearchIcon,
|
||||
SortAscIcon,
|
||||
SortDescIcon,
|
||||
XIcon,
|
||||
} from '@modrinth/assets'
|
||||
import {
|
||||
Button,
|
||||
ButtonStyled,
|
||||
Combobox,
|
||||
type ComboboxOption,
|
||||
@@ -116,6 +104,7 @@ import {
|
||||
defineMessages,
|
||||
injectNotificationManager,
|
||||
Pagination,
|
||||
StyledInput,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import Fuse from 'fuse.js'
|
||||
|
||||
@@ -1,21 +1,17 @@
|
||||
<template>
|
||||
<div class="flex flex-col gap-4">
|
||||
<div class="flex flex-col justify-between gap-3 lg:flex-row">
|
||||
<div class="iconified-input flex-1 lg:max-w-md">
|
||||
<SearchIcon aria-hidden="true" class="text-lg" />
|
||||
<input
|
||||
v-model="query"
|
||||
class="h-[40px]"
|
||||
autocomplete="off"
|
||||
spellcheck="false"
|
||||
type="text"
|
||||
:placeholder="formatMessage(commonMessages.searchPlaceholder)"
|
||||
@input="goToPage(1)"
|
||||
/>
|
||||
<Button v-if="query" class="r-btn" @click="() => (query = '')">
|
||||
<XIcon />
|
||||
</Button>
|
||||
</div>
|
||||
<StyledInput
|
||||
v-model="query"
|
||||
:icon="SearchIcon"
|
||||
type="text"
|
||||
autocomplete="off"
|
||||
:placeholder="formatMessage(commonMessages.searchPlaceholder)"
|
||||
clearable
|
||||
wrapper-class="flex-1 lg:max-w-52"
|
||||
input-class="h-[40px]"
|
||||
@input="goToPage(1)"
|
||||
/>
|
||||
|
||||
<div v-if="totalPages > 1" class="hidden flex-1 justify-center lg:flex">
|
||||
<Pagination :page="currentPage" :count="totalPages" @switch-page="goToPage" />
|
||||
@@ -76,14 +72,14 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ListFilterIcon, SearchIcon, SortAscIcon, SortDescIcon, XIcon } from '@modrinth/assets'
|
||||
import { ListFilterIcon, SearchIcon, SortAscIcon, SortDescIcon } from '@modrinth/assets'
|
||||
import type { ExtendedReport } from '@modrinth/moderation'
|
||||
import {
|
||||
Button,
|
||||
Combobox,
|
||||
type ComboboxOption,
|
||||
commonMessages,
|
||||
Pagination,
|
||||
StyledInput,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import type { Report } from '@modrinth/utils'
|
||||
|
||||
@@ -7,16 +7,15 @@ import {
|
||||
SearchIcon,
|
||||
SortAscIcon,
|
||||
SortDescIcon,
|
||||
XIcon,
|
||||
} from '@modrinth/assets'
|
||||
import {
|
||||
Button,
|
||||
Combobox,
|
||||
type ComboboxOption,
|
||||
commonMessages,
|
||||
FloatingPanel,
|
||||
injectModrinthClient,
|
||||
Pagination,
|
||||
StyledInput,
|
||||
Toggle,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
@@ -515,21 +514,17 @@ watch([currentSortType, currentResponseFilter, inOtherQueueFilter, currentFilter
|
||||
/> -->
|
||||
|
||||
<div class="flex flex-col justify-between gap-2 lg:flex-row">
|
||||
<div class="iconified-input flex-1 lg:max-w-56">
|
||||
<SearchIcon aria-hidden="true" class="text-lg" />
|
||||
<input
|
||||
v-model="query"
|
||||
class="!h-10"
|
||||
autocomplete="off"
|
||||
spellcheck="false"
|
||||
type="text"
|
||||
:placeholder="formatMessage(commonMessages.searchPlaceholder)"
|
||||
@input="goToPage(1)"
|
||||
/>
|
||||
<Button v-if="query" class="r-btn" @click="() => (query = '')">
|
||||
<XIcon />
|
||||
</Button>
|
||||
</div>
|
||||
<StyledInput
|
||||
v-model="query"
|
||||
:icon="SearchIcon"
|
||||
type="text"
|
||||
autocomplete="off"
|
||||
:placeholder="formatMessage(commonMessages.searchPlaceholder)"
|
||||
clearable
|
||||
wrapper-class="flex-1 lg:max-w-52"
|
||||
input-class="!h-10"
|
||||
@input="goToPage(1)"
|
||||
/>
|
||||
|
||||
<div v-if="totalPages > 1" class="hidden flex-1 justify-center lg:flex">
|
||||
<LoaderCircleIcon
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
ConfirmModal,
|
||||
FileInput,
|
||||
injectNotificationManager,
|
||||
StyledInput,
|
||||
UnsavedChangesPopup,
|
||||
useSavable,
|
||||
} from '@modrinth/ui'
|
||||
@@ -187,11 +188,10 @@ const onDeleteOrganization = useClientTry(async () => {
|
||||
<label for="project-name">
|
||||
<span class="label__title">Name</span>
|
||||
</label>
|
||||
<input
|
||||
<StyledInput
|
||||
id="project-name"
|
||||
v-model="current.name"
|
||||
maxlength="2048"
|
||||
type="text"
|
||||
:maxlength="2048"
|
||||
:disabled="!hasPermission"
|
||||
/>
|
||||
|
||||
@@ -200,11 +200,10 @@ const onDeleteOrganization = useClientTry(async () => {
|
||||
</label>
|
||||
<div class="text-input-wrapper">
|
||||
<div class="text-input-wrapper__before">https://modrinth.com/organization/</div>
|
||||
<input
|
||||
<StyledInput
|
||||
id="project-slug"
|
||||
v-model="current.slug"
|
||||
type="text"
|
||||
maxlength="64"
|
||||
:maxlength="64"
|
||||
autocomplete="off"
|
||||
:disabled="!hasPermission"
|
||||
/>
|
||||
@@ -213,14 +212,14 @@ const onDeleteOrganization = useClientTry(async () => {
|
||||
<label for="project-summary">
|
||||
<span class="label__title">Summary</span>
|
||||
</label>
|
||||
<div class="textarea-wrapper summary-input">
|
||||
<textarea
|
||||
id="project-summary"
|
||||
v-model="current.summary"
|
||||
maxlength="256"
|
||||
:disabled="!hasPermission"
|
||||
/>
|
||||
</div>
|
||||
<StyledInput
|
||||
id="project-summary"
|
||||
v-model="current.summary"
|
||||
multiline
|
||||
:maxlength="256"
|
||||
:disabled="!hasPermission"
|
||||
wrapper-class="summary-input"
|
||||
/>
|
||||
</div>
|
||||
<div class="universal-card">
|
||||
<div class="label">
|
||||
|
||||
@@ -14,10 +14,9 @@
|
||||
</span>
|
||||
</span>
|
||||
<div class="input-group">
|
||||
<input
|
||||
<StyledInput
|
||||
id="username"
|
||||
v-model="currentUsername"
|
||||
type="text"
|
||||
placeholder="Username"
|
||||
:disabled="
|
||||
!isPermission(
|
||||
@@ -101,10 +100,9 @@
|
||||
The title of the role that this member plays for this organization.
|
||||
</span>
|
||||
</label>
|
||||
<input
|
||||
<StyledInput
|
||||
:id="`member-${member.user.id}-role`"
|
||||
v-model="member.role"
|
||||
type="text"
|
||||
:disabled="
|
||||
!isPermission(
|
||||
currentMember.organization_permissions,
|
||||
@@ -121,7 +119,7 @@
|
||||
the organization projects' revenue goes to this member.
|
||||
</span>
|
||||
</label>
|
||||
<input
|
||||
<StyledInput
|
||||
:id="`member-${member.user.id}-monetization-weight`"
|
||||
v-model="member.payouts_split"
|
||||
type="number"
|
||||
@@ -227,7 +225,14 @@ import {
|
||||
UserPlusIcon,
|
||||
UserXIcon as UserRemoveIcon,
|
||||
} from '@modrinth/assets'
|
||||
import { Avatar, Badge, Button, Checkbox, injectNotificationManager } from '@modrinth/ui'
|
||||
import {
|
||||
Avatar,
|
||||
Badge,
|
||||
Button,
|
||||
Checkbox,
|
||||
injectNotificationManager,
|
||||
StyledInput,
|
||||
} from '@modrinth/ui'
|
||||
import { ref } from 'vue'
|
||||
|
||||
import { removeTeamMember } from '~/helpers/teams.js'
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<span class="label__title">Issue tracker</span>
|
||||
</label>
|
||||
<div class="input-group shrink-first">
|
||||
<input
|
||||
<StyledInput
|
||||
id="issue-tracker-input"
|
||||
v-model="editLinks.issues.val"
|
||||
:disabled="editLinks.issues.clear"
|
||||
@@ -23,7 +23,7 @@
|
||||
:placeholder="
|
||||
editLinks.issues.clear ? 'Existing link will be cleared' : 'Enter a valid URL'
|
||||
"
|
||||
maxlength="2048"
|
||||
:maxlength="2048"
|
||||
/>
|
||||
<button
|
||||
v-tooltip="'Clear link'"
|
||||
@@ -42,12 +42,12 @@
|
||||
<span class="label__title">Source code</span>
|
||||
</label>
|
||||
<div class="input-group shrink-first">
|
||||
<input
|
||||
<StyledInput
|
||||
id="source-code-input"
|
||||
v-model="editLinks.source.val"
|
||||
:disabled="editLinks.source.clear"
|
||||
type="url"
|
||||
maxlength="2048"
|
||||
:maxlength="2048"
|
||||
:placeholder="
|
||||
editLinks.source.clear ? 'Existing link will be cleared' : 'Enter a valid URL'
|
||||
"
|
||||
@@ -69,12 +69,12 @@
|
||||
<span class="label__title">Wiki page</span>
|
||||
</label>
|
||||
<div class="input-group shrink-first">
|
||||
<input
|
||||
<StyledInput
|
||||
id="wiki-page-input"
|
||||
v-model="editLinks.wiki.val"
|
||||
:disabled="editLinks.wiki.clear"
|
||||
type="url"
|
||||
maxlength="2048"
|
||||
:maxlength="2048"
|
||||
:placeholder="
|
||||
editLinks.wiki.clear ? 'Existing link will be cleared' : 'Enter a valid URL'
|
||||
"
|
||||
@@ -93,12 +93,12 @@
|
||||
<span class="label__title">Discord invite</span>
|
||||
</label>
|
||||
<div class="input-group shrink-first">
|
||||
<input
|
||||
<StyledInput
|
||||
id="discord-invite-input"
|
||||
v-model="editLinks.discord.val"
|
||||
:disabled="editLinks.discord.clear"
|
||||
type="url"
|
||||
maxlength="2048"
|
||||
:maxlength="2048"
|
||||
:placeholder="
|
||||
editLinks.discord.clear
|
||||
? 'Existing link will be cleared'
|
||||
@@ -334,6 +334,7 @@ import {
|
||||
injectNotificationManager,
|
||||
NewModal,
|
||||
ProjectStatusBadge,
|
||||
StyledInput,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { formatProjectType } from '@modrinth/utils'
|
||||
|
||||
@@ -136,14 +136,13 @@
|
||||
}}
|
||||
</span>
|
||||
<div class="flex gap-4">
|
||||
<input
|
||||
<StyledInput
|
||||
id="report-item-id"
|
||||
v-model="reportItemID"
|
||||
type="text"
|
||||
placeholder="ex: Dc7EYhxG"
|
||||
autocomplete="off"
|
||||
:disabled="reportItem === ''"
|
||||
class="w-40"
|
||||
wrapper-class="w-40"
|
||||
@blur="
|
||||
() => {
|
||||
prefilled = false
|
||||
@@ -293,6 +292,7 @@ import {
|
||||
type MessageDescriptor,
|
||||
RadialHeader,
|
||||
RadioButtons,
|
||||
StyledInput,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import type { Project, Report, User, Version } from '@modrinth/utils'
|
||||
|
||||
@@ -13,10 +13,10 @@
|
||||
<div class="universal-modal">
|
||||
<p>Your account information is not displayed publicly.</p>
|
||||
<label for="email-input"><span class="label__title">Email address</span> </label>
|
||||
<input
|
||||
<StyledInput
|
||||
id="email-input"
|
||||
v-model="email"
|
||||
maxlength="2048"
|
||||
:maxlength="2048"
|
||||
type="email"
|
||||
:placeholder="`Enter your email address...`"
|
||||
@keyup.enter="saveEmail()"
|
||||
@@ -58,21 +58,21 @@
|
||||
<label v-else-if="auth.user.has_password" for="old-password">
|
||||
<span class="label__title">Old password</span>
|
||||
</label>
|
||||
<input
|
||||
<StyledInput
|
||||
v-if="auth.user.has_password"
|
||||
id="old-password"
|
||||
v-model="oldPassword"
|
||||
maxlength="2048"
|
||||
:maxlength="2048"
|
||||
type="password"
|
||||
autocomplete="current-password"
|
||||
:placeholder="`${removePasswordMode ? 'Confirm' : 'Old'} password`"
|
||||
/>
|
||||
<template v-if="!removePasswordMode">
|
||||
<label for="new-password"><span class="label__title">New password</span></label>
|
||||
<input
|
||||
<StyledInput
|
||||
id="new-password"
|
||||
v-model="newPassword"
|
||||
maxlength="2048"
|
||||
:maxlength="2048"
|
||||
type="password"
|
||||
autocomplete="new-password"
|
||||
placeholder="New password"
|
||||
@@ -80,10 +80,10 @@
|
||||
<label for="confirm-new-password"
|
||||
><span class="label__title">Confirm new password</span></label
|
||||
>
|
||||
<input
|
||||
<StyledInput
|
||||
id="confirm-new-password"
|
||||
v-model="confirmNewPassword"
|
||||
maxlength="2048"
|
||||
:maxlength="2048"
|
||||
type="password"
|
||||
autocomplete="new-password"
|
||||
placeholder="Confirm new password"
|
||||
@@ -145,11 +145,10 @@
|
||||
<span class="label__title">Enter two-factor code</span>
|
||||
<span class="label__description">Please enter a two-factor code to proceed.</span>
|
||||
</label>
|
||||
<input
|
||||
<StyledInput
|
||||
id="two-factor-code"
|
||||
v-model="twoFactorCode"
|
||||
maxlength="11"
|
||||
type="text"
|
||||
:maxlength="11"
|
||||
placeholder="Enter code..."
|
||||
@keyup.enter="removeTwoFactor()"
|
||||
/>
|
||||
@@ -197,11 +196,10 @@
|
||||
>Enter the one-time code from authenticator to verify access.
|
||||
</span>
|
||||
</label>
|
||||
<input
|
||||
<StyledInput
|
||||
id="verify-code"
|
||||
v-model="twoFactorCode"
|
||||
maxlength="6"
|
||||
type="text"
|
||||
:maxlength="6"
|
||||
autocomplete="one-time-code"
|
||||
placeholder="Enter code..."
|
||||
@keyup.enter="verifyTwoFactorCode()"
|
||||
@@ -421,7 +419,7 @@ import {
|
||||
UpdatedIcon,
|
||||
XIcon,
|
||||
} from '@modrinth/assets'
|
||||
import { ConfirmModal, injectNotificationManager } from '@modrinth/ui'
|
||||
import { ConfirmModal, injectNotificationManager, StyledInput } from '@modrinth/ui'
|
||||
import KeyIcon from 'assets/icons/auth/key.svg'
|
||||
import DiscordIcon from 'assets/icons/auth/sso-discord.svg'
|
||||
import GithubIcon from 'assets/icons/auth/sso-github.svg'
|
||||
|
||||
@@ -12,11 +12,10 @@
|
||||
<label for="app-name"
|
||||
><span class="label__title">{{ formatMessage(messages.nameLabel) }}</span>
|
||||
</label>
|
||||
<input
|
||||
<StyledInput
|
||||
id="app-name"
|
||||
v-model="name"
|
||||
maxlength="2048"
|
||||
type="text"
|
||||
:maxlength="2048"
|
||||
autocomplete="off"
|
||||
:placeholder="formatMessage(messages.namePlaceholder)"
|
||||
/>
|
||||
@@ -38,11 +37,11 @@
|
||||
<label v-if="editingId" for="app-url">
|
||||
<span class="label__title">{{ formatMessage(messages.urlLabel) }}</span>
|
||||
</label>
|
||||
<input
|
||||
<StyledInput
|
||||
v-if="editingId"
|
||||
id="app-url"
|
||||
v-model="url"
|
||||
maxlength="255"
|
||||
:maxlength="255"
|
||||
type="url"
|
||||
autocomplete="off"
|
||||
:placeholder="formatMessage(messages.urlPlaceholder)"
|
||||
@@ -50,15 +49,15 @@
|
||||
<label v-if="editingId" for="app-description">
|
||||
<span class="label__title">{{ formatMessage(messages.descriptionLabel) }}</span>
|
||||
</label>
|
||||
<textarea
|
||||
<StyledInput
|
||||
v-if="editingId"
|
||||
id="app-description"
|
||||
v-model="description"
|
||||
class="description-textarea"
|
||||
maxlength="255"
|
||||
type="text"
|
||||
multiline
|
||||
:maxlength="255"
|
||||
autocomplete="off"
|
||||
:placeholder="formatMessage(messages.descriptionPlaceholder)"
|
||||
input-class="h-24 resize-y"
|
||||
/>
|
||||
<label for="app-scopes"
|
||||
><span class="label__title">{{ formatMessage(messages.scopesLabel) }}</span>
|
||||
@@ -88,9 +87,9 @@
|
||||
<div class="uri-input-list">
|
||||
<div v-for="(_, index) in redirectUris" :key="index">
|
||||
<div class="input-group url-input-group-fixes">
|
||||
<input
|
||||
<StyledInput
|
||||
v-model="redirectUris[index]"
|
||||
maxlength="2048"
|
||||
:maxlength="2048"
|
||||
type="url"
|
||||
autocomplete="off"
|
||||
:placeholder="formatMessage(messages.redirectUriPlaceholder)"
|
||||
@@ -257,6 +256,7 @@ import {
|
||||
injectNotificationManager,
|
||||
IntlFormatted,
|
||||
normalizeChildren,
|
||||
StyledInput,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
|
||||
@@ -697,11 +697,6 @@ async function removeApp() {
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.description-textarea {
|
||||
height: 6rem;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
.secret_disclaimer {
|
||||
font-size: var(--font-size-sm);
|
||||
}
|
||||
|
||||
@@ -19,11 +19,10 @@
|
||||
<label for="pat-name">
|
||||
<span class="label__title">{{ formatMessage(createModalMessages.nameLabel) }}</span>
|
||||
</label>
|
||||
<input
|
||||
<StyledInput
|
||||
id="pat-name"
|
||||
v-model="name"
|
||||
maxlength="2048"
|
||||
type="email"
|
||||
:maxlength="2048"
|
||||
:placeholder="formatMessage(createModalMessages.namePlaceholder)"
|
||||
/>
|
||||
<label for="pat-scopes">
|
||||
@@ -51,7 +50,7 @@
|
||||
<label for="pat-name" class="mt-4">
|
||||
<span class="label__title">{{ formatMessage(createModalMessages.expiresLabel) }}</span>
|
||||
</label>
|
||||
<input id="pat-name" v-model="expires" type="date" />
|
||||
<StyledInput id="pat-expires" v-model="expires" type="date" />
|
||||
<p></p>
|
||||
<div class="input-group push-right">
|
||||
<button class="iconified-button" @click="$refs.patModal.hide()">
|
||||
@@ -222,6 +221,7 @@ import {
|
||||
defineMessages,
|
||||
injectNotificationManager,
|
||||
IntlFormatted,
|
||||
StyledInput,
|
||||
useRelativeTime,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
|
||||
@@ -56,15 +56,15 @@
|
||||
{{ formatMessage(messages.usernameDescription) }}
|
||||
</span>
|
||||
</label>
|
||||
<input id="username-field" v-model="current.username" type="text" />
|
||||
<StyledInput id="username-field" v-model="current.username" />
|
||||
<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="current.bio" type="text" />
|
||||
<div class="input-group">
|
||||
<StyledInput id="bio-field" v-model="current.bio" multiline />
|
||||
<div class="input-group mt-4">
|
||||
<Button :link="`/user/${auth.user.username}`">
|
||||
<UserIcon /> {{ formatMessage(commonMessages.visitYourProfile) }}
|
||||
</Button>
|
||||
@@ -90,6 +90,7 @@ import {
|
||||
FileInput,
|
||||
injectNotificationManager,
|
||||
IntlFormatted,
|
||||
StyledInput,
|
||||
UnsavedChangesPopup,
|
||||
useSavable,
|
||||
useVIntl,
|
||||
@@ -250,10 +251,4 @@ async function save() {
|
||||
gap: var(--gap-lg);
|
||||
margin-top: var(--gap-md);
|
||||
}
|
||||
|
||||
textarea {
|
||||
height: 6rem;
|
||||
width: 40rem;
|
||||
margin-bottom: var(--gap-lg);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
|
||||
import type { FunctionalComponent, SVGAttributes } from 'vue'
|
||||
|
||||
export type IconComponent = FunctionalComponent<SVGAttributes>
|
||||
|
||||
import _AffiliateIcon from './icons/affiliate.svg?component'
|
||||
import _AlignLeftIcon from './icons/align-left.svg?component'
|
||||
import _ArchiveIcon from './icons/archive.svg?component'
|
||||
@@ -327,6 +325,8 @@ import _XCircleIcon from './icons/x-circle.svg?component'
|
||||
import _ZoomInIcon from './icons/zoom-in.svg?component'
|
||||
import _ZoomOutIcon from './icons/zoom-out.svg?component'
|
||||
|
||||
export type IconComponent = FunctionalComponent<SVGAttributes>
|
||||
|
||||
export const AffiliateIcon = _AffiliateIcon
|
||||
export const AlignLeftIcon = _AlignLeftIcon
|
||||
export const ArchiveIcon = _ArchiveIcon
|
||||
|
||||
@@ -45,14 +45,7 @@
|
||||
width: 15rem;
|
||||
}
|
||||
|
||||
> :where(
|
||||
input + *,
|
||||
.input-group + *,
|
||||
.textarea-wrapper + *,
|
||||
.chips + *,
|
||||
.resizable-textarea-wrapper + *,
|
||||
.input-div + *
|
||||
) {
|
||||
> :where(input + *, .input-group + *, .chips + *, .input-div + *) {
|
||||
margin-block-start: var(--gap-md);
|
||||
}
|
||||
|
||||
@@ -679,33 +672,6 @@ a:not(.no-click-animation),
|
||||
|
||||
// CUSTOM COMPONENTS
|
||||
// TODO: MOST OF THESE SHOULD BE MOVED TO AN OMORPHIA COMPONENT
|
||||
.textarea-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
|
||||
textarea {
|
||||
border-radius: var(--radius-sm);
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
resize: none;
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.resizable-textarea-wrapper {
|
||||
display: block;
|
||||
flex-grow: 1;
|
||||
width: 100%;
|
||||
margin-bottom: 0;
|
||||
|
||||
textarea {
|
||||
height: 100%;
|
||||
border-radius: var(--radius-sm);
|
||||
width: calc(100% - var(--gap-xl) - var(--gap-sm));
|
||||
resize: vertical;
|
||||
}
|
||||
}
|
||||
|
||||
// TOOLTIPS
|
||||
|
||||
|
||||
@@ -43,50 +43,8 @@ a.uncolored {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
input[type='text'],
|
||||
input[type='url'],
|
||||
input[type='number'],
|
||||
input[type='password'],
|
||||
textarea,
|
||||
.input-text-inherit,
|
||||
.cm-content {
|
||||
border-radius: var(--radius-md);
|
||||
box-sizing: border-box;
|
||||
// safari iOS rounds inputs by default
|
||||
// set the appearance to none to prevent this
|
||||
appearance: none !important;
|
||||
background: var(--color-button-bg);
|
||||
color: var(--color-base);
|
||||
padding: 0.5rem 1rem;
|
||||
font-weight: var(--font-weight-medium);
|
||||
transition: box-shadow 0.1s ease-in-out;
|
||||
min-height: 36px;
|
||||
box-shadow:
|
||||
var(--shadow-inset-sm),
|
||||
0 0 0 0 transparent;
|
||||
border: none;
|
||||
outline: none;
|
||||
|
||||
&:disabled,
|
||||
&[disabled] {
|
||||
opacity: 0.6;
|
||||
pointer-events: none;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
&:focus::placeholder {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
&::placeholder {
|
||||
color: var(--color-base);
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
|
||||
.cm-content {
|
||||
white-space: pre-wrap !important;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
input[type='number'] {
|
||||
@@ -122,46 +80,6 @@ input[type='number'] {
|
||||
}
|
||||
}
|
||||
|
||||
.iconified-input {
|
||||
align-items: center;
|
||||
display: inline-flex;
|
||||
position: relative;
|
||||
|
||||
input {
|
||||
padding: 0 0.5rem 0 2.5rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&:focus-within svg {
|
||||
opacity: 1;
|
||||
color: var(--color-contrast);
|
||||
}
|
||||
|
||||
svg {
|
||||
position: absolute;
|
||||
left: 0.75rem;
|
||||
height: 1.25rem;
|
||||
width: 1.25rem;
|
||||
z-index: 1;
|
||||
|
||||
color: var(--color-base);
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.r-btn {
|
||||
@extend .transparent, .icon-only;
|
||||
|
||||
position: absolute;
|
||||
right: 0.125rem;
|
||||
z-index: 1;
|
||||
|
||||
svg {
|
||||
position: relative;
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
svg {
|
||||
height: 1em;
|
||||
width: 1em;
|
||||
|
||||
@@ -7,23 +7,17 @@
|
||||
</span>
|
||||
<span class="text-secondary mb-2">{{ formatMessage(messages.createUserDescription) }}</span>
|
||||
</label>
|
||||
<div v-if="showUserField" class="mb-4">
|
||||
<div class="iconified-input">
|
||||
<UserIcon aria-hidden="true" />
|
||||
<input
|
||||
id="create-affiliate-user-input"
|
||||
v-model="affiliateUsername"
|
||||
class="card-shadow"
|
||||
autocomplete="off"
|
||||
spellcheck="false"
|
||||
type="text"
|
||||
:placeholder="formatMessage(messages.createUserPlaceholder)"
|
||||
/>
|
||||
<Button v-if="affiliateUsername" class="r-btn" @click="() => (affiliateUsername = '')">
|
||||
<XIcon />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<StyledInput
|
||||
v-if="showUserField"
|
||||
id="create-affiliate-user-input"
|
||||
v-model="affiliateUsername"
|
||||
:icon="UserIcon"
|
||||
autocomplete="off"
|
||||
type="text"
|
||||
:placeholder="formatMessage(messages.createUserPlaceholder)"
|
||||
clearable
|
||||
wrapper-class="mb-4"
|
||||
/>
|
||||
<label class="contents" for="create-affiliate-title-input">
|
||||
<span class="text-lg font-semibold text-contrast mb-1">
|
||||
{{ formatMessage(messages.createTitleLabel) }}
|
||||
@@ -33,22 +27,24 @@
|
||||
}}</span>
|
||||
</label>
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="iconified-input">
|
||||
<AutoBrandIcon :keyword="affiliateLinkTitle" aria-hidden="true">
|
||||
<div class="relative inline-flex items-center flex-1">
|
||||
<AutoBrandIcon
|
||||
:keyword="affiliateLinkTitle"
|
||||
aria-hidden="true"
|
||||
class="absolute left-3 h-5 w-5 z-[1] pointer-events-none text-secondary"
|
||||
>
|
||||
<AffiliateIcon />
|
||||
</AutoBrandIcon>
|
||||
<input
|
||||
<StyledInput
|
||||
id="create-affiliate-title-input"
|
||||
v-model="affiliateLinkTitle"
|
||||
class="card-shadow"
|
||||
autocomplete="off"
|
||||
spellcheck="false"
|
||||
type="text"
|
||||
:placeholder="formatMessage(messages.createTitlePlaceholder)"
|
||||
clearable
|
||||
wrapper-class="w-full"
|
||||
input-class="pl-10"
|
||||
/>
|
||||
<Button v-if="affiliateLinkTitle" class="r-btn" @click="() => (affiliateLinkTitle = '')">
|
||||
<XIcon />
|
||||
</Button>
|
||||
</div>
|
||||
<ButtonStyled color="brand">
|
||||
<button :disabled="creatingLink || !canCreate" @click="createAffiliateLink">
|
||||
@@ -63,12 +59,12 @@
|
||||
</template>
|
||||
<script lang="ts"></script>
|
||||
<script setup lang="ts">
|
||||
import { AffiliateIcon, PlusIcon, SpinnerIcon, UserIcon, XIcon } from '@modrinth/assets'
|
||||
import { AffiliateIcon, PlusIcon, SpinnerIcon, UserIcon } from '@modrinth/assets'
|
||||
import { computed, ref, useTemplateRef } from 'vue'
|
||||
|
||||
import { defineMessages, useVIntl } from '../../composables/i18n'
|
||||
import { commonMessages } from '../../utils/common-messages'
|
||||
import { AutoBrandIcon, Button, ButtonStyled, NewModal } from '../index'
|
||||
import { AutoBrandIcon, ButtonStyled, NewModal, StyledInput } from '../index'
|
||||
export type CreateAffiliateProps = { sourceName: string; username?: string }
|
||||
|
||||
const props = withDefaults(
|
||||
|
||||
@@ -57,18 +57,17 @@
|
||||
@keydown="handleDropdownKeydown"
|
||||
>
|
||||
<div v-if="searchable" class="p-4">
|
||||
<div class="iconified-input w-full border-surface-5 border-[1px] border-solid rounded-xl">
|
||||
<SearchIcon aria-hidden="true" />
|
||||
<input
|
||||
ref="searchInputRef"
|
||||
v-model="searchQuery"
|
||||
type="text"
|
||||
:placeholder="searchPlaceholder"
|
||||
class=""
|
||||
@keydown.stop="handleSearchKeydown"
|
||||
@input="emit('searchInput', searchQuery)"
|
||||
/>
|
||||
</div>
|
||||
<StyledInput
|
||||
ref="searchInputRef"
|
||||
v-model="searchQuery"
|
||||
:icon="SearchIcon"
|
||||
type="text"
|
||||
:placeholder="searchPlaceholder"
|
||||
wrapper-class="w-full"
|
||||
input-class="!border !border-solid !border-surface-5"
|
||||
@keydown.stop="handleSearchKeydown"
|
||||
@input="emit('searchInput', searchQuery)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div v-if="searchable && filteredOptions.length > 0" class="h-px bg-surface-5"></div>
|
||||
@@ -134,6 +133,8 @@ import {
|
||||
watch,
|
||||
} from 'vue'
|
||||
|
||||
import StyledInput from './StyledInput.vue'
|
||||
|
||||
export interface ComboboxOption<T> {
|
||||
value: T
|
||||
label: string
|
||||
|
||||
@@ -18,22 +18,21 @@
|
||||
<slot />
|
||||
<DropdownIcon class="h-5 w-5 text-secondary" />
|
||||
<template #menu>
|
||||
<div v-if="search" class="iconified-input mb-2 w-full">
|
||||
<label for="search-input" hidden>Search...</label>
|
||||
<SearchIcon aria-hidden="true" />
|
||||
<input
|
||||
id="search-input"
|
||||
ref="searchInput"
|
||||
v-model="searchQuery"
|
||||
placeholder="Search..."
|
||||
type="text"
|
||||
@keydown.enter="
|
||||
() => {
|
||||
toggleOption(filteredOptions[0])
|
||||
}
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
<StyledInput
|
||||
v-if="search"
|
||||
id="search-input"
|
||||
ref="searchInput"
|
||||
v-model="searchQuery"
|
||||
:icon="SearchIcon"
|
||||
placeholder="Search..."
|
||||
type="text"
|
||||
wrapper-class="mb-2 w-full"
|
||||
@keydown.enter="
|
||||
() => {
|
||||
toggleOption(filteredOptions[0])
|
||||
}
|
||||
"
|
||||
/>
|
||||
<ScrollablePanel v-if="search">
|
||||
<Button
|
||||
v-for="(option, index) in filteredOptions"
|
||||
@@ -75,7 +74,7 @@
|
||||
import { CheckIcon, DropdownIcon, SearchIcon } from '@modrinth/assets'
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
import { Button, ButtonStyled, PopoutMenu } from '../index'
|
||||
import { Button, ButtonStyled, PopoutMenu, StyledInput } from '../index'
|
||||
import ScrollablePanel from './ScrollablePanel.vue'
|
||||
|
||||
type Option = string | number | object
|
||||
|
||||
@@ -4,29 +4,28 @@
|
||||
<label class="label" for="insert-link-label">
|
||||
<span class="label__title">Label</span>
|
||||
</label>
|
||||
<div class="iconified-input">
|
||||
<AlignLeftIcon />
|
||||
<input id="insert-link-label" v-model="linkText" type="text" placeholder="Enter label..." />
|
||||
<Button class="r-btn" @click="() => (linkText = '')">
|
||||
<XIcon />
|
||||
</Button>
|
||||
</div>
|
||||
<StyledInput
|
||||
id="insert-link-label"
|
||||
v-model="linkText"
|
||||
:icon="AlignLeftIcon"
|
||||
type="text"
|
||||
placeholder="Enter label..."
|
||||
clearable
|
||||
wrapper-class="w-full"
|
||||
/>
|
||||
<label class="label" for="insert-link-url">
|
||||
<span class="label__title">URL<span class="required">*</span></span>
|
||||
</label>
|
||||
<div class="iconified-input">
|
||||
<LinkIcon />
|
||||
<input
|
||||
id="insert-link-url"
|
||||
v-model="linkUrl"
|
||||
type="text"
|
||||
placeholder="Enter the link's URL..."
|
||||
@input="validateURL"
|
||||
/>
|
||||
<Button class="r-btn" @click="() => (linkUrl = '')">
|
||||
<XIcon />
|
||||
</Button>
|
||||
</div>
|
||||
<StyledInput
|
||||
id="insert-link-url"
|
||||
v-model="linkUrl"
|
||||
:icon="LinkIcon"
|
||||
type="text"
|
||||
placeholder="Enter the link's URL..."
|
||||
clearable
|
||||
wrapper-class="w-full"
|
||||
@input="validateURL"
|
||||
/>
|
||||
<template v-if="linkValidationErrorMessage">
|
||||
<span class="label">
|
||||
<span class="label__title">Error</span>
|
||||
@@ -68,18 +67,15 @@
|
||||
Describe the image completely as you would to someone who could not see the image.
|
||||
</span>
|
||||
</label>
|
||||
<div class="iconified-input">
|
||||
<AlignLeftIcon />
|
||||
<input
|
||||
id="insert-image-alt"
|
||||
v-model="linkText"
|
||||
type="text"
|
||||
placeholder="Describe the image..."
|
||||
/>
|
||||
<Button class="r-btn" @click="() => (linkText = '')">
|
||||
<XIcon />
|
||||
</Button>
|
||||
</div>
|
||||
<StyledInput
|
||||
id="insert-image-alt"
|
||||
v-model="linkText"
|
||||
:icon="AlignLeftIcon"
|
||||
type="text"
|
||||
placeholder="Describe the image..."
|
||||
clearable
|
||||
wrapper-class="w-full"
|
||||
/>
|
||||
<label class="label" for="insert-link-url">
|
||||
<span class="label__title">URL<span class="required">*</span></span>
|
||||
</label>
|
||||
@@ -101,19 +97,17 @@
|
||||
<UploadIcon />
|
||||
</FileInput>
|
||||
</div>
|
||||
<div v-if="!props.onImageUpload || imageUploadOption === 'link'" class="iconified-input">
|
||||
<ImageIcon />
|
||||
<input
|
||||
id="insert-link-url"
|
||||
v-model="linkUrl"
|
||||
type="text"
|
||||
placeholder="Enter the image URL..."
|
||||
@input="validateURL"
|
||||
/>
|
||||
<Button class="r-btn" @click="() => (linkUrl = '')">
|
||||
<XIcon />
|
||||
</Button>
|
||||
</div>
|
||||
<StyledInput
|
||||
v-if="!props.onImageUpload || imageUploadOption === 'link'"
|
||||
id="insert-link-url"
|
||||
v-model="linkUrl"
|
||||
:icon="ImageIcon"
|
||||
type="text"
|
||||
placeholder="Enter the image URL..."
|
||||
clearable
|
||||
wrapper-class="w-full"
|
||||
@input="validateURL"
|
||||
/>
|
||||
<template v-if="linkValidationErrorMessage">
|
||||
<span class="label">
|
||||
<span class="label__title">Error</span>
|
||||
@@ -154,19 +148,16 @@
|
||||
<span class="label__title">YouTube video URL<span class="required">*</span></span>
|
||||
<span class="label__description"> Enter a valid link to a YouTube video. </span>
|
||||
</label>
|
||||
<div class="iconified-input">
|
||||
<YouTubeIcon />
|
||||
<input
|
||||
id="insert-video-url"
|
||||
v-model="linkUrl"
|
||||
type="text"
|
||||
placeholder="Enter YouTube video URL"
|
||||
@input="validateURL"
|
||||
/>
|
||||
<Button class="r-btn" @click="() => (linkUrl = '')">
|
||||
<XIcon />
|
||||
</Button>
|
||||
</div>
|
||||
<StyledInput
|
||||
id="insert-video-url"
|
||||
v-model="linkUrl"
|
||||
:icon="YouTubeIcon"
|
||||
type="text"
|
||||
placeholder="Enter YouTube video URL"
|
||||
clearable
|
||||
wrapper-class="w-full"
|
||||
@input="validateURL"
|
||||
/>
|
||||
<template v-if="linkValidationErrorMessage">
|
||||
<span class="label">
|
||||
<span class="label__title">Error</span>
|
||||
@@ -202,7 +193,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</NewModal>
|
||||
<div class="resizable-textarea-wrapper">
|
||||
<div class="block grow w-full">
|
||||
<div class="editor-action-row">
|
||||
<div class="editor-actions">
|
||||
<template
|
||||
@@ -300,6 +291,7 @@ import NewModal from '../modal/NewModal.vue'
|
||||
import Button from './Button.vue'
|
||||
import Chips from './Chips.vue'
|
||||
import FileInput from './FileInput.vue'
|
||||
import StyledInput from './StyledInput.vue'
|
||||
import Toggle from './Toggle.vue'
|
||||
|
||||
const props = withDefaults(
|
||||
@@ -894,11 +886,6 @@ function openVideoModal() {
|
||||
}
|
||||
}
|
||||
|
||||
.resizable-textarea-wrapper textarea {
|
||||
min-height: 10rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.info-blurb {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -928,10 +915,6 @@ function openVideoModal() {
|
||||
.modal-insert {
|
||||
padding: var(--gap-lg);
|
||||
|
||||
.iconified-input {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.label {
|
||||
margin-block: var(--gap-lg) var(--gap-sm);
|
||||
display: block;
|
||||
|
||||
181
packages/ui/src/components/base/StyledInput.vue
Normal file
181
packages/ui/src/components/base/StyledInput.vue
Normal file
@@ -0,0 +1,181 @@
|
||||
<template>
|
||||
<div
|
||||
class="relative"
|
||||
:class="[
|
||||
wrapperClass,
|
||||
multiline ? 'flex' : 'inline-flex',
|
||||
{ 'opacity-50 cursor-not-allowed': disabled },
|
||||
!multiline && variant === 'outlined' ? 'items-stretch' : 'items-center',
|
||||
]"
|
||||
>
|
||||
<!-- Left icon (filled variant, single-line only) -->
|
||||
<component
|
||||
:is="icon"
|
||||
v-if="icon && variant === 'filled' && !multiline"
|
||||
class="absolute left-3 h-5 w-5 z-[1] pointer-events-none transition-colors"
|
||||
:class="[isFocused ? 'opacity-100 text-contrast' : 'opacity-60 text-secondary']"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
|
||||
<!-- Multiline textarea -->
|
||||
<textarea
|
||||
v-if="multiline"
|
||||
ref="inputRef"
|
||||
:id="id"
|
||||
:value="model"
|
||||
:placeholder="placeholder"
|
||||
:disabled="disabled"
|
||||
:readonly="readonly"
|
||||
:name="name"
|
||||
:autocomplete="autocomplete"
|
||||
:maxlength="maxlength"
|
||||
:rows="rows"
|
||||
class="w-full text-primary placeholder:text-secondary focus:text-contrast font-medium transition-[shadow,color] appearance-none shadow-none focus:ring-4 focus:ring-brand-shadow bg-surface-4 border-none rounded-xl"
|
||||
:class="[
|
||||
inputClass,
|
||||
'pl-3 pr-3 py-2 text-base',
|
||||
error ? 'outline outline-2 outline-red bg-warning-bg' : 'outline-none',
|
||||
disabled ? 'cursor-not-allowed' : '',
|
||||
resizeClass,
|
||||
]"
|
||||
@input="onInput"
|
||||
@focus="isFocused = true"
|
||||
@blur="isFocused = false"
|
||||
/>
|
||||
|
||||
<!-- Single-line input -->
|
||||
<input
|
||||
v-else
|
||||
ref="inputRef"
|
||||
:id="id"
|
||||
:type="type"
|
||||
:value="model"
|
||||
:placeholder="placeholder"
|
||||
:disabled="disabled"
|
||||
:readonly="readonly"
|
||||
:name="name"
|
||||
:autocomplete="autocomplete"
|
||||
:inputmode="inputmode"
|
||||
:maxlength="maxlength"
|
||||
:min="min"
|
||||
:max="max"
|
||||
:step="step"
|
||||
class="w-full text-primary placeholder:text-secondary focus:text-contrast font-medium transition-[shadow,color] appearance-none shadow-none focus:ring-4 focus:ring-brand-shadow"
|
||||
:class="[
|
||||
inputClass,
|
||||
variant === 'filled' && icon ? 'pl-10' : 'pl-3',
|
||||
clearable && model && variant === 'filled' ? 'pr-8' : 'pr-3',
|
||||
size === 'small' ? 'h-8 py-1.5 text-sm' : 'h-9 py-2 text-base',
|
||||
error ? 'outline outline-2 outline-red bg-warning-bg' : 'outline-none',
|
||||
disabled ? 'cursor-not-allowed' : '',
|
||||
variant === 'outlined'
|
||||
? 'bg-transparent border border-solid border-button-bg rounded-l-xl border-r-0'
|
||||
: 'bg-surface-4 border-none rounded-xl',
|
||||
]"
|
||||
@input="onInput"
|
||||
@focus="isFocused = true"
|
||||
@blur="isFocused = false"
|
||||
/>
|
||||
|
||||
<!-- Clear button (right side, filled variant, single-line only) -->
|
||||
<button
|
||||
v-if="!multiline && clearable && model && !disabled && !readonly && variant === 'filled'"
|
||||
type="button"
|
||||
class="absolute right-0.5 z-[1] p-2 bg-transparent border-none text-secondary hover:text-contrast transition-colors cursor-pointer select-none"
|
||||
aria-label="Clear input"
|
||||
@click="clear"
|
||||
>
|
||||
<XIcon class="h-5 w-5" />
|
||||
</button>
|
||||
|
||||
<!-- Right icon button (outlined variant, single-line only) -->
|
||||
<button
|
||||
v-if="!multiline && variant === 'outlined'"
|
||||
type="button"
|
||||
class="flex items-center justify-center px-2 bg-transparent border border-solid border-button-bg rounded-r-xl text-secondary hover:text-contrast transition-colors shrink-0"
|
||||
:aria-label="clearable && model ? 'Clear input' : 'Search'"
|
||||
:tabindex="clearable && model ? undefined : -1"
|
||||
@click="clearable && model ? clear() : undefined"
|
||||
>
|
||||
<XIcon v-if="clearable && model" class="h-4 w-4" />
|
||||
<component :is="icon" v-else-if="icon" class="h-4 w-4" />
|
||||
<SearchIcon v-else class="h-4 w-4" />
|
||||
</button>
|
||||
|
||||
<!-- Custom rightside slot -->
|
||||
<slot name="right" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { SearchIcon, XIcon } from '@modrinth/assets'
|
||||
import { type Component, computed, ref } from 'vue'
|
||||
|
||||
const model = defineModel<string | number | undefined>()
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
icon?: Component
|
||||
type?: 'text' | 'email' | 'password' | 'number' | 'url' | 'search' | 'date' | 'datetime-local'
|
||||
placeholder?: string
|
||||
id?: string
|
||||
name?: string
|
||||
autocomplete?: string
|
||||
inputmode?: 'none' | 'text' | 'decimal' | 'numeric' | 'tel' | 'search' | 'email' | 'url'
|
||||
maxlength?: number
|
||||
min?: number
|
||||
max?: number
|
||||
step?: number
|
||||
disabled?: boolean
|
||||
readonly?: boolean
|
||||
error?: boolean
|
||||
size?: 'standard' | 'small'
|
||||
variant?: 'filled' | 'outlined'
|
||||
clearable?: boolean
|
||||
multiline?: boolean
|
||||
rows?: number
|
||||
resize?: 'none' | 'vertical' | 'both'
|
||||
inputClass?: string
|
||||
wrapperClass?: string
|
||||
}>(),
|
||||
{
|
||||
type: 'text',
|
||||
size: 'standard',
|
||||
variant: 'filled',
|
||||
disabled: false,
|
||||
readonly: false,
|
||||
error: false,
|
||||
clearable: false,
|
||||
multiline: false,
|
||||
rows: 3,
|
||||
resize: 'none',
|
||||
},
|
||||
)
|
||||
|
||||
const emit = defineEmits<{
|
||||
clear: []
|
||||
}>()
|
||||
|
||||
const inputRef = ref<HTMLInputElement | HTMLTextAreaElement>()
|
||||
const isFocused = ref(false)
|
||||
const resizeClass = computed(
|
||||
() => ({ none: 'resize-none', vertical: 'resize-y', both: 'resize' })[props.resize ?? 'none'],
|
||||
)
|
||||
|
||||
defineExpose({ focus: () => inputRef.value?.focus() })
|
||||
|
||||
function onInput(event: Event) {
|
||||
const target = event.target as HTMLInputElement | HTMLTextAreaElement
|
||||
model.value =
|
||||
props.type === 'number' && !props.multiline
|
||||
? target.value === ''
|
||||
? undefined
|
||||
: Number(target.value)
|
||||
: target.value
|
||||
}
|
||||
|
||||
function clear() {
|
||||
model.value = props.type === 'number' && !props.multiline ? undefined : ''
|
||||
emit('clear')
|
||||
}
|
||||
</script>
|
||||
@@ -57,6 +57,7 @@ export { default as SettingsLabel } from './SettingsLabel.vue'
|
||||
export { default as SimpleBadge } from './SimpleBadge.vue'
|
||||
export { default as Slider } from './Slider.vue'
|
||||
export { default as SmartClickable } from './SmartClickable.vue'
|
||||
export { default as StyledInput } from './StyledInput.vue'
|
||||
export type { TableColumn } from './Table.vue'
|
||||
export { default as Table } from './Table.vue'
|
||||
export { default as TagItem } from './TagItem.vue'
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
<div v-if="!existingSubscription">
|
||||
<p class="my-2 text-lg font-bold">Configure your server</p>
|
||||
<div class="flex flex-col gap-4">
|
||||
<input v-model="serverName" placeholder="Server name" class="input" maxlength="48" />
|
||||
<StyledInput v-model="serverName" placeholder="Server name" :maxlength="48" />
|
||||
<!-- <DropdownSelect
|
||||
v-model="serverLoader"
|
||||
v-tooltip="'Select the mod loader for your server'"
|
||||
@@ -136,7 +136,7 @@
|
||||
>
|
||||
<div class="flex flex-col w-full gap-2">
|
||||
<div class="font-semibold">Shared CPUs</div>
|
||||
<input :value="sharedCpus" disabled class="input w-full" />
|
||||
<StyledInput :model-value="sharedCpus" disabled wrapper-class="w-full" />
|
||||
</div>
|
||||
<div class="flex flex-col w-full gap-2">
|
||||
<div class="font-semibold flex items-center gap-1">
|
||||
@@ -148,14 +148,18 @@
|
||||
class="h-4 w-4text-secondary opacity-60"
|
||||
/>
|
||||
</div>
|
||||
<input :value="mutatedProduct.metadata.cpu" disabled class="input w-full" />
|
||||
<StyledInput
|
||||
:model-value="mutatedProduct.metadata.cpu"
|
||||
disabled
|
||||
wrapper-class="w-full"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-col w-full gap-2">
|
||||
<div class="font-semibold">Storage</div>
|
||||
<input
|
||||
<StyledInput
|
||||
v-model="customServerConfig.storageGbFormatted"
|
||||
disabled
|
||||
class="input w-full"
|
||||
wrapper-class="w-full"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -551,6 +555,7 @@ import { paymentMethodMessages } from '../../utils/common-messages'
|
||||
import Admonition from '../base/Admonition.vue'
|
||||
import Checkbox from '../base/Checkbox.vue'
|
||||
import Slider from '../base/Slider.vue'
|
||||
import StyledInput from '../base/StyledInput.vue'
|
||||
import AnimatedLogo from '../brand/AnimatedLogo.vue'
|
||||
import NewModal from '../modal/NewModal.vue'
|
||||
import LoaderIcon from '../servers/icons/LoaderIcon.vue'
|
||||
|
||||
@@ -9,15 +9,13 @@
|
||||
<div class="flex h-[550px] border-solid border-transparent border-[1px] border-b-surface-4">
|
||||
<div class="w-[300px] flex flex-col relative">
|
||||
<div class="p-4 pb-2">
|
||||
<div class="iconified-input w-full border-solid border-[1px] border-surface-4 rounded-xl">
|
||||
<SearchIcon class="transition-colors" />
|
||||
<input
|
||||
v-model="searchQuery"
|
||||
type="text"
|
||||
:placeholder="formatMessage(messages.searchVersionPlaceholder)"
|
||||
class="!bg-transparent rounded-xl transition-colors"
|
||||
/>
|
||||
</div>
|
||||
<StyledInput
|
||||
v-model="searchQuery"
|
||||
:icon="SearchIcon"
|
||||
type="text"
|
||||
:placeholder="formatMessage(messages.searchVersionPlaceholder)"
|
||||
wrapper-class="w-full"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="flex-1 overflow-y-auto px-4 pb-16">
|
||||
@@ -186,6 +184,7 @@ import { defineMessages, useVIntl } from '../../../composables/i18n'
|
||||
import { commonMessages } from '../../../utils/common-messages'
|
||||
import Avatar from '../../base/Avatar.vue'
|
||||
import ButtonStyled from '../../base/ButtonStyled.vue'
|
||||
import StyledInput from '../../base/StyledInput.vue'
|
||||
import NewModal from '../../modal/NewModal.vue'
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
@@ -23,13 +23,12 @@
|
||||
<span class="italic font-bold">{{ confirmationText }}</span> below:
|
||||
</span>
|
||||
</label>
|
||||
<input
|
||||
<StyledInput
|
||||
v-if="hasToType"
|
||||
id="confirmation"
|
||||
v-model="confirmation_typed"
|
||||
type="text"
|
||||
placeholder="Type here..."
|
||||
class="max-w-[20rem]"
|
||||
wrapper-class="max-w-[20rem]"
|
||||
/>
|
||||
<div class="flex gap-2">
|
||||
<ButtonStyled :color="danger ? 'red' : 'brand'">
|
||||
@@ -55,6 +54,7 @@ import { renderString } from '@modrinth/utils'
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
import ButtonStyled from '../base/ButtonStyled.vue'
|
||||
import StyledInput from '../base/StyledInput.vue'
|
||||
import NewModal from './NewModal.vue'
|
||||
|
||||
const props = defineProps({
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
import {
|
||||
ClipboardCopyIcon,
|
||||
GlobeIcon,
|
||||
LinkIcon,
|
||||
MailIcon,
|
||||
MastodonIcon,
|
||||
RedditIcon,
|
||||
@@ -12,7 +11,7 @@ import {
|
||||
import QrcodeVue from 'qrcode.vue'
|
||||
import { computed, nextTick, ref } from 'vue'
|
||||
|
||||
import { Button, Modal } from '../index'
|
||||
import { Button, Modal, StyledInput } from '../index'
|
||||
|
||||
const props = defineProps({
|
||||
header: {
|
||||
@@ -142,26 +141,27 @@ defineExpose({
|
||||
<ClipboardCopyIcon aria-hidden="true" />
|
||||
</Button>
|
||||
</div>
|
||||
<div v-else class="resizable-textarea-wrapper">
|
||||
<textarea v-model="content" />
|
||||
<Button
|
||||
v-tooltip="'Copy Text'"
|
||||
icon-only
|
||||
aria-label="Copy Text"
|
||||
class="copy-button transparent"
|
||||
@click="copyText"
|
||||
>
|
||||
<ClipboardCopyIcon aria-hidden="true" />
|
||||
</Button>
|
||||
</div>
|
||||
<div class="all-buttons">
|
||||
<div v-if="link" class="iconified-input">
|
||||
<LinkIcon />
|
||||
<input type="text" :value="url" readonly />
|
||||
<Button v-tooltip="'Copy Text'" aria-label="Copy Text" class="r-btn" @click="copyText">
|
||||
<StyledInput v-else v-model="content" multiline resize="vertical" wrapper-class="h-full">
|
||||
<template #right>
|
||||
<Button
|
||||
v-tooltip="'Copy Text'"
|
||||
icon-only
|
||||
aria-label="Copy Text"
|
||||
class="copy-button transparent"
|
||||
@click="copyText"
|
||||
>
|
||||
<ClipboardCopyIcon aria-hidden="true" />
|
||||
</Button>
|
||||
</div>
|
||||
</template>
|
||||
</StyledInput>
|
||||
<div class="all-buttons">
|
||||
<StyledInput v-if="link" type="text" :model-value="url" readonly wrapper-class="w-full">
|
||||
<template #right>
|
||||
<Button v-tooltip="'Copy Text'" aria-label="Copy Text" class="r-btn" @click="copyText">
|
||||
<ClipboardCopyIcon aria-hidden="true" />
|
||||
</Button>
|
||||
</template>
|
||||
</StyledInput>
|
||||
<div class="button-row">
|
||||
<Button v-if="canShare" v-tooltip="'Share'" aria-label="Share" icon-only @click="share">
|
||||
<ShareIcon aria-hidden="true" />
|
||||
@@ -236,14 +236,6 @@ defineExpose({
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.iconified-input {
|
||||
width: 100%;
|
||||
|
||||
input {
|
||||
flex-basis: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.button-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
@@ -295,19 +287,4 @@ defineExpose({
|
||||
transition: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
.resizable-textarea-wrapper {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
|
||||
textarea {
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.btn {
|
||||
opacity: 1;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -65,25 +65,18 @@
|
||||
</template>
|
||||
<template v-else #default>
|
||||
<slot name="prefix" />
|
||||
<div v-if="filterType.searchable" class="iconified-input mx-2 my-1 !flex">
|
||||
<SearchIcon aria-hidden="true" />
|
||||
<input
|
||||
:id="`search-${filterType.id}`"
|
||||
v-model="query"
|
||||
class="!min-h-9 text-sm"
|
||||
type="text"
|
||||
:placeholder="formatMessage(messages.searchPlaceholder)"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<Button
|
||||
v-if="query"
|
||||
class="r-btn"
|
||||
:aria-label="formatMessage(messages.clearSearchAriaLabel)"
|
||||
@click="() => (query = '')"
|
||||
>
|
||||
<XIcon aria-hidden="true" />
|
||||
</Button>
|
||||
</div>
|
||||
<StyledInput
|
||||
v-if="filterType.searchable"
|
||||
:id="`search-${filterType.id}`"
|
||||
v-model="query"
|
||||
:icon="SearchIcon"
|
||||
type="text"
|
||||
:placeholder="formatMessage(messages.searchPlaceholder)"
|
||||
autocomplete="off"
|
||||
clearable
|
||||
size="small"
|
||||
wrapper-class="mx-2 my-1 w-[calc(100%-1rem)]"
|
||||
/>
|
||||
|
||||
<ScrollablePanel :class="{ 'h-[16rem]': scrollable }" :disable-scrolling="!scrollable">
|
||||
<div :class="innerPanelClass ? innerPanelClass : ''" class="flex flex-col gap-1">
|
||||
@@ -165,21 +158,14 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
BanIcon,
|
||||
DropdownIcon,
|
||||
LockOpenIcon,
|
||||
SearchIcon,
|
||||
UpdatedIcon,
|
||||
XIcon,
|
||||
} from '@modrinth/assets'
|
||||
import { BanIcon, DropdownIcon, LockOpenIcon, SearchIcon, UpdatedIcon } from '@modrinth/assets'
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
import { defineMessages, useVIntl } from '../../composables/i18n'
|
||||
import type { FilterOption, FilterType, FilterValue } from '../../utils/search'
|
||||
import Accordion from '../base/Accordion.vue'
|
||||
import ButtonStyled from '../base/ButtonStyled.vue'
|
||||
import { Button, Checkbox, ScrollablePanel } from '../index'
|
||||
import { Checkbox, ScrollablePanel, StyledInput } from '../index'
|
||||
import SearchFilterOption from './SearchFilterOption.vue'
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
@@ -4,14 +4,13 @@
|
||||
<label for="backup-name-input">
|
||||
<span class="text-lg font-semibold text-contrast">Name</span>
|
||||
</label>
|
||||
<input
|
||||
<StyledInput
|
||||
id="backup-name-input"
|
||||
ref="input"
|
||||
v-model="backupName"
|
||||
type="text"
|
||||
class="w-full rounded-lg bg-bg-input p-4"
|
||||
:placeholder="`Backup #${newBackupAmount}`"
|
||||
maxlength="48"
|
||||
:maxlength="48"
|
||||
wrapper-class="w-full"
|
||||
/>
|
||||
<Transition
|
||||
enter-active-class="transition-all duration-300 ease-out"
|
||||
@@ -76,6 +75,7 @@ import {
|
||||
injectNotificationManager,
|
||||
} from '../../../providers'
|
||||
import ButtonStyled from '../../base/ButtonStyled.vue'
|
||||
import StyledInput from '../../base/StyledInput.vue'
|
||||
import NewModal from '../../modal/NewModal.vue'
|
||||
|
||||
const { addNotification } = injectNotificationManager()
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user