Compare commits

...
Author SHA1 Message Date
Calum H. (IMB11) 4bdd0e4155 prepr 2026-07-31 12:17:07 +01:00
Calum H. (IMB11) cb4462374c refactor: rename component 2026-07-31 12:05:45 +01:00
Calum H. (IMB11) f08f2d8405 Merge remote-tracking branch 'origin/main' into cal/change-styled-input
# Conflicts:
#	packages/ui/.storybook/main.ts
#	packages/ui/src/components/base/StyledInput.vue
#	packages/ui/src/components/search/SearchSidebarFilter.vue
2026-07-31 11:39:08 +01:00
Prospector 65a3ac4b34 changelog 2026-07-30 23:10:28 -07:00
ProspectorandGitHub 295db3fb7a only refresh tokens and clear auth cookies on auth fails, not any ran… (#6947)
only refresh tokens and clear auth cookies on auth fails, not any random error
2026-07-30 23:10:08 -07:00
Michael H. 7abe6f8c73 feat: sccache on windows 2026-07-30 20:27:08 +02:00
Michael H. c5ce5bc9b3 fix: create clickhouse db in tests only 2026-07-30 20:08:49 +02:00
Michael H. 572b8027ff fix: clickhouse migrations should not run normally 2026-07-30 19:23:10 +02:00
aecsocketandGitHub 0a53211389 fix: analytics event endpoint (#6938)
* fix: analytics event endpoint

* split admin-only routes into internal

* fix pr comment
2026-07-30 04:40:52 +00:00
Prospector 22b2b7746e changelog 2026-07-29 14:34:41 -07:00
39b3e20d0a fix: feedback file limit (#6931)
* fix: feedback file limit

* prepr

* prepr again

---------

Co-authored-by: Prospector <6166773+Prospector@users.noreply.github.com>
2026-07-29 20:47:05 +00:00
Calum H.andGitHub 3892b62451 fix: reinstall jobs not cleaning up if instance deleted (#6927) 2026-07-29 20:31:26 +00:00
Calum H.andGitHub 5ffffec2e5 fix: gracefully handle shared instance icons 404ing (#6928)
* fix: icon handling

* fix: cleanup impl

* fix: fmt
2026-07-29 20:30:52 +00:00
Truman GaoandGitHub a0724cc5fb feat: dont show analytics incomplete current day revenue (#6933) 2026-07-29 20:26:25 +00:00
ProspectorandGitHub a0320f425e install version matching filters if possible (#6932) 2026-07-29 13:26:39 -07:00
Michael H. 06262e7bb1 feat: clickhouse partitioning and header TTL 2026-07-29 22:10:20 +02:00
ProspectorandGitHub 9ccaab5fad add toggle to hide already-installed modpacks (#6917)
* add toggle to hide already-installed modpacks, on by default

* make false by default
2026-07-29 17:54:21 +00:00
ProspectorandGitHub 39745086fa fix warning when passing extraneous props to floating action bar (#6919) 2026-07-29 13:02:40 +00:00
Truman GaoandGitHub a8dcfa8a5d fix: download modal suggested dep can use wrong mc version (#6925) 2026-07-29 12:44:34 +00:00
Truman GaoandGitHub 0f6a74b87f fix: pats page code invalidating in same session (#6924) 2026-07-29 12:44:30 +00:00
ProspectorandGitHub d5b763c8e3 Fix tauri overlay in modal closing on drag (#6920)
* Fix tauri overlay in modal closing on drag

* prepr
2026-07-29 12:44:28 +00:00
ProspectorandGitHub 7a98f45c3d add installation settings tooltip (#6916) 2026-07-29 12:44:16 +00:00
ProspectorandGitHub 0ea47ad7ef add new instance button (#6918) 2026-07-29 12:43:17 +00:00
ProspectorandGitHub cc804625ec Replace final usage of legacy modal (#6921)
* Replace final usage of legacy modal

* prepr
2026-07-29 12:42:59 +00:00
Calum H. (IMB11) 22bfca467a refactor: migrate to new input components 2026-07-15 14:46:08 +01:00
Calum H. (IMB11) 1186a8a027 feat: new input components 2026-07-15 14:45:57 +01:00
Calum H. (IMB11) 3dd16180b0 feat: align style 2026-07-15 14:21:04 +01:00
210 changed files with 2185 additions and 2048 deletions
-2
View File
@@ -92,7 +92,6 @@ jobs:
run: corepack enable
- name: Set up caches
if: contains(matrix.artifact-target-name, 'linux') || contains(matrix.artifact-target-name, 'darwin')
uses: namespacelabs/nscloud-cache-action@c5f8dab7560444c4bf8dbc64f1b203431873c547 # v1.6.1
with:
cache: |
@@ -100,7 +99,6 @@ jobs:
pnpm
- name: Configure sccache
if: contains(matrix.artifact-target-name, 'linux') || contains(matrix.artifact-target-name, 'darwin')
run: nsc cache sccache setup --cache_name default >> "$GITHUB_ENV"
- name: Generate tauri-dev.conf.json
@@ -14,7 +14,7 @@ import {
DropdownSelect,
formatLoader,
injectNotificationManager,
StyledInput,
Input,
useVIntl,
} from '@modrinth/ui'
import { useStorage } from '@vueuse/core'
@@ -275,7 +275,7 @@ const filteredResults = computed(() => {
</script>
<template>
<div class="flex gap-2">
<StyledInput
<Input
v-model="search"
:icon="SearchIcon"
type="text"
@@ -6,8 +6,9 @@ import {
defineMessages,
FileTreeSelect,
injectNotificationManager,
Input,
NewModal,
StyledInput,
Textarea,
useVIntl,
} from '@modrinth/ui'
import { save } from '@tauri-apps/plugin-dialog'
@@ -244,7 +245,7 @@ function isExportCandidateDisabled(path) {
<div class="grid grid-cols-2 gap-4">
<div class="labeled_input w-full">
<p class="text-contrast font-semibold">{{ formatMessage(messages.modpackNameLabel) }}</p>
<StyledInput
<Input
v-model="nameInput"
type="text"
:placeholder="formatMessage(messages.modpackNamePlaceholder)"
@@ -256,7 +257,7 @@ function isExportCandidateDisabled(path) {
<p class="text-contrast font-semibold">
{{ formatMessage(messages.versionNumberLabel) }}
</p>
<StyledInput
<Input
v-model="versionInput"
type="text"
:placeholder="formatMessage(messages.versionNumberPlaceholder)"
@@ -269,9 +270,8 @@ function isExportCandidateDisabled(path) {
<p class="m-0 text-contrast font-semibold">
{{ formatMessage(commonMessages.descriptionLabel) }}
</p>
<StyledInput
<Textarea
v-model="exportDescription"
multiline
:placeholder="formatMessage(messages.descriptionPlaceholder)"
wrapper-class="w-full"
/>
@@ -2,7 +2,7 @@
<JavaDetectionModal ref="detectJavaModal" @submit="(val) => emit('update:modelValue', val)" />
<div :id="props.id" class="toggle-setting" :class="{ compact }">
<div class="input-with-status">
<StyledInput
<Input
autocomplete="off"
:disabled="props.disabled"
:model-value="props.modelValue ? props.modelValue.path : ''"
@@ -93,7 +93,7 @@ import {
ButtonStyled,
defineMessages,
injectNotificationManager,
StyledInput,
Input,
useVIntl,
} from '@modrinth/ui'
import { open } from '@tauri-apps/plugin-dialog'
@@ -5,8 +5,8 @@ import {
ButtonStyled,
defineMessages,
injectNotificationManager,
Input,
IntlFormatted,
StyledInput,
useRelativeTime,
useVIntl,
} from '@modrinth/ui'
@@ -232,7 +232,7 @@ const messages = defineMessages({
{{ formatMessage(messages.usernameDescription) }}
</p>
<div class="flex items-center gap-2 mt-4">
<StyledInput
<Input
v-model="username"
:icon="UserIcon"
type="text"
@@ -260,7 +260,7 @@ const messages = defineMessages({
<UserPlusIcon />
</button>
</ButtonStyled>
<StyledInput
<Input
v-model="search"
:icon="SearchIcon"
type="text"
@@ -1,12 +1,6 @@
<script setup>
import { CheckIcon, PlusIcon, SearchIcon } from '@modrinth/assets'
import {
Admonition,
Avatar,
ButtonStyled,
injectNotificationManager,
StyledInput,
} from '@modrinth/ui'
import { Admonition, Avatar, ButtonStyled, injectNotificationManager, Input } from '@modrinth/ui'
import { useQueryClient } from '@tanstack/vue-query'
import { convertFileSrc } from '@tauri-apps/api/core'
import { computed, ref } from 'vue'
@@ -85,7 +79,7 @@ async function addServer(instance) {
<ModalWrapper ref="modal" header="Add server to instance">
<div class="flex flex-col gap-4 min-w-[350px]">
<Admonition type="warning" body="This server may not be compatible with all instances." />
<StyledInput
<Input
v-model="searchFilter"
:icon="SearchIcon"
type="search"
@@ -7,8 +7,8 @@ import {
Chips,
defineMessages,
injectNotificationManager,
Input,
OverflowMenu,
StyledInput,
useVIntl,
} from '@modrinth/ui'
import { useQueryClient } from '@tanstack/vue-query'
@@ -339,7 +339,7 @@ const messages = defineMessages({
{{ formatMessage(messages.name) }}
</label>
<div class="flex">
<StyledInput
<Input
id="instance-name"
v-model="title"
autocomplete="off"
@@ -382,7 +382,7 @@ const messages = defineMessages({
@click="toggleGroup(group)"
/>
<div class="flex gap-2 items-center">
<StyledInput
<Input
v-model="newCategoryInput"
:placeholder="formatMessage(messages.libraryGroupsEnterName)"
class="w-full max-w-[300px]"
@@ -1,11 +1,5 @@
<script setup lang="ts">
import {
Checkbox,
defineMessages,
injectNotificationManager,
StyledInput,
useVIntl,
} from '@modrinth/ui'
import { Checkbox, defineMessages, injectNotificationManager, Input, useVIntl } from '@modrinth/ui'
import { computed, ref, watch } from 'vue'
import { edit } from '@/helpers/instance'
@@ -112,7 +106,7 @@ const messages = defineMessages({
<h2 class="mt-6 m-0 text-lg font-semibold text-contrast">
{{ formatMessage(messages.preLaunch) }}
</h2>
<StyledInput
<Input
id="pre-launch"
v-model="hooks.pre_launch"
autocomplete="off"
@@ -127,7 +121,7 @@ const messages = defineMessages({
<h2 class="mt-6 m-0 text-lg font-semibold text-contrast">
{{ formatMessage(messages.wrapper) }}
</h2>
<StyledInput
<Input
id="wrapper"
v-model="hooks.wrapper"
autocomplete="off"
@@ -142,7 +136,7 @@ const messages = defineMessages({
<h2 class="mt-6 m-0 text-lg font-semibold text-contrast">
{{ formatMessage(messages.postExit) }}
</h2>
<StyledInput
<Input
id="post-exit"
v-model="hooks.post_exit"
autocomplete="off"
@@ -13,8 +13,8 @@ import {
Checkbox,
defineMessages,
injectNotificationManager,
Input,
Slider,
StyledInput,
useVIntl,
} from '@modrinth/ui'
import { open } from '@tauri-apps/plugin-dialog'
@@ -216,7 +216,7 @@ const messages = defineMessages({
>Java {{ optimalJava?.parsed_version }}</span
>
<div class="flex gap-2 items-center">
<StyledInput
<Input
:model-value="activePath"
:disabled="!overrideJavaInstall"
autocomplete="off"
@@ -294,7 +294,7 @@ const messages = defineMessages({
:label="formatMessage(messages.customJavaArguments)"
class="my-2"
/>
<StyledInput
<Input
id="java-args"
v-model="javaArgs"
autocomplete="off"
@@ -310,7 +310,7 @@ const messages = defineMessages({
:label="formatMessage(messages.customEnvironmentVariables)"
class="mb-2"
/>
<StyledInput
<Input
id="env-vars"
v-model="envVars"
autocomplete="off"
@@ -3,7 +3,7 @@ import {
Checkbox,
defineMessages,
injectNotificationManager,
StyledInput,
Input,
Toggle,
useVIntl,
} from '@modrinth/ui'
@@ -129,7 +129,7 @@ const messages = defineMessages({
{{ formatMessage(messages.widthDescription) }}
</p>
</div>
<StyledInput
<Input
id="width"
v-model="resolution[0]"
autocomplete="off"
@@ -148,7 +148,7 @@ const messages = defineMessages({
{{ formatMessage(messages.heightDescription) }}
</p>
</div>
<StyledInput
<Input
id="height"
v-model="resolution[1]"
autocomplete="off"
@@ -2,8 +2,8 @@
import {
defineMessages,
injectNotificationManager,
Input,
Slider,
StyledInput,
Toggle,
useVIntl,
} from '@modrinth/ui'
@@ -187,7 +187,7 @@ watch(
</p>
</div>
<StyledInput
<Input
id="width"
v-model="settings.game_resolution[0]"
:disabled="settings.force_fullscreen"
@@ -207,7 +207,7 @@ watch(
</p>
</div>
<StyledInput
<Input
id="height"
v-model="settings.game_resolution[1]"
:disabled="settings.force_fullscreen"
@@ -244,7 +244,7 @@ watch(
<h2 class="m-0 text-lg font-semibold text-contrast">
{{ formatMessage(messages.javaArgumentsTitle) }}
</h2>
<StyledInput
<Input
id="java-args"
v-model="settings.launchArgs"
autocomplete="off"
@@ -261,7 +261,7 @@ watch(
<h2 class="m-0 text-lg font-semibold text-contrast">
{{ formatMessage(messages.environmentVariablesTitle) }}
</h2>
<StyledInput
<Input
id="env-vars"
v-model="settings.envVars"
autocomplete="off"
@@ -282,7 +282,7 @@ watch(
<h3 class="m-0 text-lg font-semibold text-contrast">
{{ formatMessage(messages.preLaunchHookTitle) }}
</h3>
<StyledInput
<Input
id="pre-launch"
v-model="settings.hooks.pre_launch"
autocomplete="off"
@@ -299,7 +299,7 @@ watch(
<h3 class="m-0 text-lg font-semibold text-contrast">
{{ formatMessage(messages.wrapperHookTitle) }}
</h3>
<StyledInput
<Input
id="wrapper"
v-model="settings.hooks.wrapper"
autocomplete="off"
@@ -316,7 +316,7 @@ watch(
<h3 class="m-0 text-lg font-semibold text-contrast">
{{ formatMessage(messages.postExitHookTitle) }}
</h3>
<StyledInput
<Input
id="post-exit"
v-model="settings.hooks.post_exit"
autocomplete="off"
@@ -4,8 +4,8 @@ import {
ButtonStyled,
defineMessages,
injectNotificationManager,
Input,
Slider,
StyledInput,
Toggle,
useVIntl,
} from '@modrinth/ui'
@@ -175,7 +175,7 @@ async function findLauncherDir() {
<h2 class="m-0 text-lg font-semibold text-contrast">
{{ formatMessage(messages.appDirectoryTitle) }}
</h2>
<StyledInput
<Input
id="appDir"
v-model="settings.custom_dir"
:icon="BoxIcon"
@@ -194,7 +194,7 @@ async function findLauncherDir() {
</button>
</ButtonStyled>
</template>
</StyledInput>
</Input>
<p class="m-0 leading-tight text-secondary">
{{ formatMessage(messages.appDirectoryDescription) }}
</p>
@@ -26,12 +26,13 @@
</span>
</template>
<div class="flex min-w-0 flex-col gap-3 pt-4">
<div class="max-h-[292px] overflow-y-auto rounded-[20px]">
<div ref="configFileTreeContainer" class="max-h-[292px] overflow-y-auto rounded-[20px]">
<FileTreeSelect
v-model="selectedConfigPaths"
:items="configFileItems"
:show-size="false"
:show-modified="false"
@navigate="scrollConfigFileTreeToTop"
/>
</div>
</div>
@@ -75,6 +76,7 @@ const emit = defineEmits<{
const { formatMessage } = useVIntl()
const { notifySharedInstanceError, notifySharedInstanceUnavailable } = useSharedInstanceErrors()
const publishReviewModal = ref<InstanceType<typeof ContentDiffModal>>()
const configFileTreeContainer = ref<HTMLElement>()
const publishDiffs = ref<ContentDiffItem[]>([])
const configFilePaths = ref<string[]>([])
const selectedConfigPaths = ref<string[]>([])
@@ -132,6 +134,12 @@ async function publishChanges() {
}
}
function scrollConfigFileTreeToTop() {
if (configFileTreeContainer.value) {
configFileTreeContainer.value.scrollTop = 0
}
}
function finishReview() {
if (state.value === 'reviewing') {
setState('idle')
@@ -6,7 +6,7 @@ import {
commonMessages,
defineMessages,
injectNotificationManager,
StyledInput,
Input,
useVIntl,
} from '@modrinth/ui'
import { computed, ref } from 'vue'
@@ -104,7 +104,7 @@ const messages = defineMessages({
<h2 class="text-lg font-extrabold text-contrast mt-0 mb-1">
{{ formatMessage(messages.name) }}
</h2>
<StyledInput
<Input
v-model="name"
:placeholder="formatMessage(messages.placeholderName)"
autocomplete="off"
@@ -1,11 +1,5 @@
<script setup lang="ts">
import {
Combobox,
defineMessages,
type MessageDescriptor,
StyledInput,
useVIntl,
} from '@modrinth/ui'
import { Combobox, defineMessages, Input, type MessageDescriptor, useVIntl } from '@modrinth/ui'
import type { ServerPackStatus } from '@/helpers/worlds.ts'
@@ -65,7 +59,7 @@ defineExpose({ resourcePackOptions })
<div class="space-y-4 w-full">
<label class="flex flex-col gap-2">
<span class="font-semibold text-contrast">{{ formatMessage(messages.name) }}</span>
<StyledInput
<Input
v-model="name"
:placeholder="formatMessage(messages.placeholderName)"
autocomplete="off"
@@ -74,7 +68,7 @@ defineExpose({ resourcePackOptions })
</label>
<label class="flex flex-col gap-2">
<span class="font-semibold text-contrast">{{ formatMessage(messages.address) }}</span>
<StyledInput
<Input
v-model="address"
:placeholder="formatMessage(messages.placeholderAddress)"
autocomplete="off"
@@ -260,6 +260,9 @@
"app.browse.hide-added-servers": {
"message": "Hide servers already added"
},
"app.browse.hide-installed-modpacks": {
"message": "Hide already installed"
},
"app.browse.project-type.modpacks": {
"message": "Modpacks"
},
+118 -29
View File
@@ -25,6 +25,7 @@ import {
preferencesDiffer,
provideBrowseManager,
requestInstall,
resolveInstallPlan,
stripServerRuntimeInstallFilters,
stripServerRuntimeInstallOverrides,
useBrowseSearch,
@@ -50,6 +51,7 @@ import { instance_listener } from '@/helpers/events.js'
import {
get as getInstance,
get_installed_project_ids as getInstalledProjectIds,
list as listInstances,
} from '@/helpers/instance'
import { get_loader_versions as getLoaderManifest } from '@/helpers/metadata'
import { get as getSettings, set as setSettings } from '@/helpers/settings.ts'
@@ -171,7 +173,7 @@ const instance: Ref<Instance | null> = ref(
queryClient.getQueryData<Instance>(['instances', 'summary', initialInstanceId]) ?? null,
)
const installedProjectIds: Ref<string[] | null> = ref(null)
const instanceHideInstalled = ref(false)
const instanceHideInstalled = ref(route.query.ai === 'true')
const newlyInstalled = ref<string[]>([])
const hiddenInstanceProjectIds = ref<Set<string>>(new Set())
const hiddenInstanceProjectIdsInitialized = ref(false)
@@ -288,7 +290,17 @@ watchServerContextChanges()
await initInstanceContext()
async function refreshInstalledProjectIds() {
if (!route.query.i) return
if (!route.query.i) {
const instances = await listInstances().catch(handleError)
if (!instances) return
const ids = instances
.map((gameInstance) => gameInstance.link?.project_id)
.filter((id): id is string => !!id)
debugLog('installedInstanceProjectIds loaded', { count: ids.length })
installedProjectIds.value = ids
return
}
if (route.query.from === 'worlds') {
const worlds = await get_instance_worlds(route.query.i as string).catch(handleError)
@@ -318,6 +330,7 @@ async function initInstanceContext() {
queryFrom: route.query.from,
})
await initServerContext()
await refreshInstalledProjectIds()
if (route.query.i) {
instance.value = (await getInstance(route.query.i as string).catch(handleError)) ?? null
@@ -327,8 +340,6 @@ async function initInstanceContext() {
gameVersion: instance.value?.game_version,
})
await refreshInstalledProjectIds()
if (instance.value?.link?.project_id) {
debugLog('checking linked project for server status', instance.value.link.project_id)
const projectV3 = await get_project_v3(
@@ -341,13 +352,23 @@ async function initInstanceContext() {
}
}
}
if (route.query.ai && !(route.params.projectType === 'modpack')) {
debugLog('setting instanceHideInstalled from query', route.query.ai)
instanceHideInstalled.value = route.query.ai === 'true'
}
}
function setBrowseHideInstalledFlag(flag: 'hide_installed_modpacks', value: boolean) {
themeStore.featureFlags[flag] = value
getSettings()
.then((settings) => {
settings.feature_flags[flag] = value
return setSettings(settings)
})
.catch(handleError)
}
const hideInstalledModpacks = computed({
get: () => themeStore.getFeatureFlag('hide_installed_modpacks'),
set: (value: boolean) => setBrowseHideInstalledFlag('hide_installed_modpacks', value),
})
const instanceFilters = computed(() => {
const filters = []
@@ -367,11 +388,15 @@ const instanceFilters = computed(() => {
if (isServerInstance.value) {
filters.push({ type: 'environment', option: 'client' })
}
}
if (instanceHideInstalled.value && hiddenInstanceProjectIds.value.size > 0) {
for (const id of hiddenInstanceProjectIds.value) {
filters.push({ type: 'project_id', option: `project_id:${id}`, negative: true })
}
if (
(instance.value || projectType.value === 'modpack') &&
(projectType.value === 'modpack' ? hideInstalledModpacks.value : instanceHideInstalled.value) &&
hiddenInstanceProjectIds.value.size > 0
) {
for (const id of hiddenInstanceProjectIds.value) {
filters.push({ type: 'project_id', option: `project_id:${id}`, negative: true })
}
}
@@ -430,6 +455,12 @@ const serverContextFilters = computed(() => {
{ type: 'environment', option: 'client' },
{ type: 'environment', option: 'server' },
)
if (hideInstalledModpacks.value && hiddenInstanceProjectIds.value.size > 0) {
for (const id of hiddenInstanceProjectIds.value) {
filters.push({ type: 'project_id', option: `project_id:${id}`, negative: true })
}
}
}
if (serverHideInstalled.value && hiddenServerContentProjectIds.value.size > 0) {
@@ -500,6 +531,10 @@ const messages = defineMessages({
id: 'app.browse.hide-added-servers',
defaultMessage: 'Hide servers already added',
},
hideInstalledModpacks: {
id: 'app.browse.hide-installed-modpacks',
defaultMessage: 'Hide already installed',
},
installingToServer: {
id: 'app.browse.server.installing',
defaultMessage: 'Installing',
@@ -553,6 +588,7 @@ function resetInstanceContext() {
hiddenInstanceProjectIdsInitialized.value = false
isServerInstance.value = false
browseBreadcrumb.reset()
void refreshInstalledProjectIds()
}
watch(
@@ -763,6 +799,27 @@ async function chooseInstanceInstallVersion(
return { versionId: selectedVersion.id }
}
async function chooseFilterMatchingInstallVersion(
project: Labrinth.Search.v3.ResultSearchProject,
projectTypeValue: string,
) {
const plan = await resolveInstallPlan({
project: {
project_id: project.project_id,
title: project.title,
icon_url: project.icon_url,
},
contentType: projectTypeValue as BrowseInstallContentType,
selectedFilters: searchState.currentFilters.value,
providedFilters: combinedProvidedFilters.value,
overriddenProvidedFilterTypes: searchState.overriddenProvidedFilterTypes.value,
targetPreferences: {},
getProjectVersions: getInstallProjectVersions,
})
return { versionId: plan.versionId }
}
function getCardActions(
result: Labrinth.Search.v3.ResultSearchProject,
currentProjectType: string,
@@ -781,6 +838,7 @@ function getCardActions(
serverContentProjectIds.value.has(projectResult.project_id || '') ||
serverContextServerData.value?.upstream?.project_id === projectResult.project_id
const isInstalling = installingProjectIds.value.has(projectResult.project_id)
const showAsInstalled = isInstalled && currentProjectType !== 'modpack'
if (
isServerContext.value &&
@@ -790,7 +848,7 @@ function getCardActions(
const isInstallingSelection = isInstallingQueuedServerInstalls.value
const validatingInstall =
isInstalling && currentProjectType !== 'modpack' && !isInstallingSelection
const installLabel = isInstalled
const installLabel = showAsInstalled
? commonMessages.installedLabel
: isQueued
? isInstalling || isInstallingSelection
@@ -810,11 +868,11 @@ function getCardActions(
icon:
isInstalling || isInstallingSelection
? SpinnerIcon
: isQueued || isInstalled
: isQueued || showAsInstalled
? CheckIcon
: PlusIcon,
iconClass: isInstalling || isInstallingSelection ? 'animate-spin' : undefined,
disabled: isInstalled || isInstalling || isInstallingSelection,
disabled: showAsInstalled || isInstalling || isInstallingSelection,
color: isQueued && !isInstalling && !isInstallingSelection ? 'green' : 'brand',
type: 'outlined',
onClick: async () => {
@@ -875,15 +933,15 @@ function getCardActions(
label: formatMessage(
isInstalling
? messages.installingToServer
: isInstalled
: showAsInstalled
? commonMessages.installedLabel
: shouldUseInstallIcon
? commonMessages.installButton
: messages.addToAnInstance,
),
icon: isInstalling ? SpinnerIcon : isInstalled ? CheckIcon : PlusIcon,
icon: isInstalling ? SpinnerIcon : showAsInstalled ? CheckIcon : PlusIcon,
iconClass: isInstalling ? 'animate-spin' : undefined,
disabled: isInstalled || isInstalling,
disabled: showAsInstalled || isInstalling,
color: 'brand',
type: 'outlined',
onClick: async () => {
@@ -891,7 +949,9 @@ function getCardActions(
try {
const selectedInstall = instance.value
? await chooseInstanceInstallVersion(projectResult, currentProjectType)
: { versionId: null as string | null }
: isModpack
? await chooseFilterMatchingInstallVersion(projectResult, currentProjectType)
: { versionId: null as string | null }
if (selectedInstall === null) {
setProjectInstalling(projectResult.project_id, false)
return
@@ -994,10 +1054,11 @@ async function search(requestParams: string) {
...hit,
}
if (instance.value || isServerContext.value) {
const installedIds = instance.value
? new Set([...newlyInstalled.value, ...(installedProjectIds.value ?? [])])
: serverContentProjectIds.value
if (instance.value || isServerContext.value || projectType.value === 'modpack') {
const installedIds =
isServerContext.value && projectType.value !== 'modpack'
? serverContentProjectIds.value
: new Set([...newlyInstalled.value, ...(installedProjectIds.value ?? [])])
mapped.installed = installedIds.has(hit.project_id)
}
@@ -1057,9 +1118,9 @@ watch(
() => projectType.value,
],
() => {
if (isServerContext.value) {
if (isServerContext.value && projectType.value !== 'modpack') {
syncHiddenServerContentProjectIds()
} else if (instance.value) {
} else if (instance.value || projectType.value === 'modpack') {
syncHiddenInstanceProjectIds()
}
},
@@ -1091,6 +1152,18 @@ let unlistenInstances: UnlistenFn | null = null
onMounted(() => {
instance_listener(async (event: { event: string; instance_id: string }) => {
if (event.event === 'added' || event.event === 'created' || event.event === 'removed') {
if (!route.query.i) {
await refreshInstalledProjectIds()
if (projectType.value === 'modpack') {
if (event.event === 'removed') {
syncHiddenInstanceProjectIds()
}
await searchState.refreshSearch()
}
}
}
if (instance.value && event.instance_id === instance.value.id && event.event === 'synced') {
await refreshInstalledProjectIds()
await searchState.refreshSearch()
@@ -1156,8 +1229,17 @@ provideBrowseManager({
installContext,
providedFilters: combinedProvidedFilters,
hideInstalled: computed({
get: () => (isServerContext.value ? serverHideInstalled.value : instanceHideInstalled.value),
get: () => {
if (projectType.value === 'modpack') return hideInstalledModpacks.value
if (isServerContext.value) return serverHideInstalled.value
return instanceHideInstalled.value
},
set: (val: boolean) => {
if (projectType.value === 'modpack') {
hideInstalledModpacks.value = val
if (val) syncHiddenInstanceProjectIds()
return
}
if (isServerContext.value) {
serverHideInstalled.value = val
if (val) syncHiddenServerContentProjectIds()
@@ -1168,11 +1250,18 @@ provideBrowseManager({
},
}),
showHideInstalled: computed(
() => (isServerContext.value && projectType.value !== 'modpack') || !!instance.value,
() =>
projectType.value === 'modpack' ||
(isServerContext.value && projectType.value !== 'modpack') ||
!!instance.value,
),
hideInstalledLabel: computed(() =>
formatMessage(
isFromWorlds.value ? messages.hideAddedServers : commonMessages.hideInstalledContentLabel,
isFromWorlds.value
? messages.hideAddedServers
: projectType.value === 'modpack'
? messages.hideInstalledModpacks
: commonMessages.hideInstalledContentLabel,
),
),
hideSelected: hideSelectedServerInstalls,
@@ -21,7 +21,7 @@
<ReadyTransition :pending="worldsReadyPending">
<div v-if="dedupedWorlds.length > 0" class="flex flex-col gap-4">
<div class="flex flex-wrap items-center gap-2">
<StyledInput
<Input
v-model="searchFilter"
:icon="SearchIcon"
type="text"
@@ -154,8 +154,8 @@ import {
GAME_MODES,
type GameVersion,
injectNotificationManager,
Input,
ReadyTransition,
StyledInput,
useReadyState,
useVIntl,
} from '@modrinth/ui'
@@ -2,7 +2,7 @@
<div class="flex flex-col gap-4">
<div class="flex flex-col gap-4">
<div class="flex items-center gap-2">
<StyledInput
<Input
v-model="search"
:icon="SearchIcon"
:placeholder="`Search ${rows.length} users...`"
@@ -150,8 +150,8 @@ import {
Avatar,
ButtonStyled,
defineMessages,
Input,
type SortDirection,
StyledInput,
Table,
type TableColumn,
truncatedTooltip,
+18 -10
View File
@@ -42,16 +42,24 @@ onUnmounted(() => {
<template>
<div class="p-6 flex flex-col gap-3">
<h1 class="m-0 text-2xl hidden">Library</h1>
<NavTabs
:links="[
{ label: 'All instances', href: `/library` },
{ label: 'Modpacks', href: `/library/modpacks` },
{ label: 'Servers', href: `/library/servers` },
{ label: 'Custom', href: `/library/custom` },
{ label: 'Shared with me', href: `/library/shared`, shown: false },
{ label: 'Saved', href: `/library/saved`, shown: false },
]"
/>
<div class="flex items-center justify-between gap-3">
<NavTabs
:links="[
{ label: 'All instances', href: `/library` },
{ label: 'Modpacks', href: `/library/modpacks` },
{ label: 'Servers', href: `/library/servers` },
{ label: 'Custom', href: `/library/custom` },
{ label: 'Shared with me', href: `/library/shared`, shown: false },
{ label: 'Saved', href: `/library/saved`, shown: false },
]"
/>
<ButtonStyled color="brand">
<button :disabled="offline" @click="showCreationModal?.()">
<PlusIcon />
New instance
</button>
</ButtonStyled>
</div>
<template v-if="instances && instances.length > 0">
<RouterView v-if="route.path.startsWith('/library')" :instances="instances" />
</template>
@@ -1,6 +1,11 @@
import type { Labrinth } from '@modrinth/api-client'
import type { ContentInstallInstance, ContentInstallProjectInfo, ContentItem } from '@modrinth/ui'
import { createContext, defineMessage, useVIntl } from '@modrinth/ui'
import {
createContext,
defineMessage,
getLatestMatchingInstallVersion,
useVIntl,
} from '@modrinth/ui'
import { convertFileSrc } from '@tauri-apps/api/core'
import { openUrl } from '@tauri-apps/plugin-opener'
import dayjs from 'dayjs'
@@ -813,7 +818,22 @@ export function createContentInstall(opts: {
}
if (project.project_type === 'modpack') {
const version = versionId ?? project.versions[project.versions.length - 1]
let version = versionId ?? null
if (!version) {
const hasHints = !!(hints?.preferredGameVersion || hints?.preferredLoader)
if (hasHints) {
const versions = (await get_version_many(
project.versions,
'must_revalidate',
)) as Labrinth.Versions.v2.Version[]
const matching = getLatestMatchingInstallVersion(versions, {
gameVersions: hints?.preferredGameVersion ? [hints.preferredGameVersion] : undefined,
loaders: hints?.preferredLoader ? [hints.preferredLoader] : undefined,
})
version = matching?.id ?? null
}
version ??= project.versions[project.versions.length - 1]
}
const packs = await list()
const existingPack = packs.find((pack) => pack.link?.project_id === project.id)
+1
View File
@@ -17,6 +17,7 @@ export const DEFAULT_FEATURE_FLAGS = {
show_instance_play_time: true,
advanced_filters_collapsed: true,
always_show_copy_details: false,
hide_installed_modpacks: false,
}
export const THEME_OPTIONS = ['dark', 'light', 'oled', 'retro', 'system'] as const
@@ -27,6 +27,7 @@ import {
LineController,
LineElement,
PointElement,
type ScriptableLineSegmentContext,
Tooltip,
} from 'chart.js'
@@ -446,6 +447,12 @@ function buildDatasets() {
pointHoverBackgroundColor: colors.borderColor,
pointHoverBorderWidth: 0,
pointHitRadius: 16,
segment: dataset.lastDataPointUnavailable
? {
borderColor: (context: ScriptableLineSegmentContext) =>
context.p1DataIndex === dataset.data.length - 1 ? 'transparent' : undefined,
}
: undefined,
stack: props.stacked ? 'analytics' : undefined,
}
})
@@ -59,7 +59,9 @@
<span class="font-medium text-primary">
{{ formatMessage(analyticsChartMessages.total) }}
</span>
<span class="font-semibold text-contrast">{{ formattedTotal }}</span>
<span class="font-semibold" :class="totalHasData ? 'text-contrast' : 'text-primary'">
{{ formattedTotal }}
</span>
</div>
<div
v-for="entry in entries"
@@ -111,7 +113,11 @@
:class="[
'shrink-0',
entry.isPreviousPeriod ? 'font-medium text-secondary' : 'font-semibold',
entry.hidden ? 'text-primary line-through opacity-70' : 'text-contrast',
entry.hidden
? 'text-primary line-through opacity-70'
: entry.noData
? 'text-primary'
: 'text-contrast',
]"
>
{{ entry.formattedValue }}
@@ -148,6 +154,7 @@ export type AnalyticsChartTooltipEntry = {
tooltip?: string
color: string
formattedValue: string
noData: boolean
hidden: boolean
toggleDisabled: boolean
isPreviousPeriod?: boolean
@@ -164,6 +171,7 @@ const props = defineProps<{
chartStart: Date | null
chartEnd: Date | null
formattedTotal: string
totalHasData: boolean
entries: AnalyticsChartTooltipEntry[]
containerWidth: number
containerHeight: number
@@ -64,6 +64,7 @@
:chart-start="chartRangeBounds?.start ?? null"
:chart-end="chartRangeBounds?.end ?? null"
:formatted-total="hoverFormattedTotal"
:total-has-data="hoverHasData"
:entries="hoverEntries"
:container-width="containerSize.width"
:container-height="containerSize.height"
@@ -89,6 +90,7 @@ import type {
AnalyticsGroupByPreset,
} from '~/providers/analytics/analytics'
import { analyticsChartMessages } from '../../analytics-messages.ts'
import type {
AnalyticsChartLegendEntry,
AnalyticsChartRangeBounds,
@@ -188,7 +190,26 @@ const hoverTotalValue = computed(() => {
}, 0)
})
function hasDatasetDataAtSlice(dataset: ChartDataset | undefined, sliceIndex: number) {
if (!dataset) return false
return !dataset.lastDataPointUnavailable || sliceIndex !== dataset.data.length - 1
}
const hoverHasData = computed(() => {
if (hoverState.sliceIndex === null) return false
const sliceIndex = hoverState.sliceIndex
return props.currentLegendEntries.some((legendEntry) => {
if (legendEntry.hidden) return false
const dataset = props.chartDatasetById.get(legendEntry.id)
return hasDatasetDataAtSlice(dataset, sliceIndex)
})
})
const hoverFormattedTotal = computed(() => {
if (!hoverHasData.value) {
return formatMessage(analyticsChartMessages.noData)
}
if (props.isRatioMode) {
return hoverTotalValue.value > 0 ? '100%' : '0%'
}
@@ -203,6 +224,7 @@ const hoverEntries = computed(() => {
return props.legendEntries.map((legendEntry) => {
const dataset = props.chartDatasetById.get(legendEntry.id)
const value = dataset?.data[sliceIndex] ?? 0
const hasData = hasDatasetDataAtSlice(dataset, sliceIndex)
const ratioValue = legendEntry.hidden || totalValue === 0 ? 0 : (value / totalValue) * 100
return {
projectId: legendEntry.id,
@@ -210,9 +232,12 @@ const hoverEntries = computed(() => {
projectName: legendEntry.projectName,
tooltip: legendEntry.tooltip,
color: legendEntry.color,
formattedValue: props.isRatioMode
? `${ratioValue.toFixed(1)}%`
: formatMetricValue(value, props.activeStat, formatNumber, formatMessage),
formattedValue: hasData
? props.isRatioMode
? `${ratioValue.toFixed(1)}%`
: formatMetricValue(value, props.activeStat, formatNumber, formatMessage)
: formatMessage(analyticsChartMessages.noData),
noData: !hasData,
hidden: legendEntry.hidden,
toggleDisabled: !legendEntry.hidden && isLegendEntryToggleDisabled(legendEntry),
isPreviousPeriod: legendEntry.isPreviousPeriod,
@@ -38,6 +38,7 @@ export type ChartDataset = {
projectName?: string
tooltip?: string
data: number[]
lastDataPointUnavailable?: boolean
borderColor: string
backgroundColor: string
borderDash?: number[]
@@ -32,6 +32,7 @@ import {
type ChartDataset,
getChartDatasetTotal,
getShortHourlyAxisTickLimit,
getSliceBucketRange,
getSliceCount,
shouldCapitalizeBreakdownLabel,
} from './analytics-chart-utils'
@@ -161,8 +162,8 @@ export function useAnalyticsChartDatasets(
)
: undefined
})
const chartDatasetsByStat = computed<Record<AnalyticsDashboardStat, ChartDataset[]>>(() =>
buildDatasetsByStat(
const chartDatasetsByStat = computed<Record<AnalyticsDashboardStat, ChartDataset[]>>(() => {
const datasets = buildDatasetsByStat(
context.displayedTimeSlices.value,
selectedProjects.value,
legendPalette.value,
@@ -175,8 +176,20 @@ export function useAnalyticsChartDatasets(
showProjectVersionNames.value ? context.getVersionProjectName : undefined,
formatMessage,
sliceCount.value,
),
)
)
const nextFetchRequest = context.displayedFetchRequest.value
if (
nextFetchRequest &&
context.displayedSelectedGroupBy.value === 'day' &&
isLastBucketCurrentDay(nextFetchRequest.time_range, sliceCount.value)
) {
datasets.revenue = datasets.revenue.map((dataset) => ({
...dataset,
lastDataPointUnavailable: true,
}))
}
return datasets
})
const previousChartDatasetsByStat = computed<Record<AnalyticsDashboardStat, ChartDataset[]>>(() =>
buildDatasetsByStat(
context.displayedPreviousTimeSlices.value,
@@ -406,6 +419,16 @@ function buildDatasetsByStat(
return datasetsByStat
}
function isLastBucketCurrentDay(timeRange: Labrinth.Analytics.v3.TimeRange, sliceCount: number) {
const lastBucket = getSliceBucketRange(timeRange, sliceCount, sliceCount - 1)
const todayStart = new Date()
todayStart.setHours(0, 0, 0, 0)
const tomorrowStart = new Date(todayStart)
tomorrowStart.setDate(tomorrowStart.getDate() + 1)
return lastBucket.start < tomorrowStart && lastBucket.end > todayStart
}
function sortDatasetsByTotal(datasets: ChartDataset[]) {
return [...datasets]
.sort((a, b) => {
@@ -688,6 +688,10 @@ export const analyticsChartMessages = defineMessages({
id: 'analytics.chart.tooltip.hide-entry',
defaultMessage: 'Hide {name} in graph',
},
noData: {
id: 'analytics.chart.tooltip.no-data',
defaultMessage: 'No data',
},
durationDays: {
id: 'analytics.chart.tooltip.duration.days',
defaultMessage: '{count, plural, one {# day} other {# days}}',
@@ -23,7 +23,7 @@
</div>
<div class="flex w-full flex-wrap items-center gap-2 md:w-auto">
<StyledInput
<Input
v-model="searchQuery"
:icon="SearchIcon"
:placeholder="formatMessage(analyticsTableMessages.searchPlaceholder)"
@@ -193,10 +193,10 @@
import { DownloadIcon, DropdownIcon, SearchIcon, UserIcon } from '@modrinth/assets'
import {
ButtonStyled,
Input,
OverflowMenu,
type OverflowMenuOption,
Pagination,
StyledInput,
Table,
useFormatNumber,
useVIntl,
@@ -48,7 +48,7 @@
To confirm this transfer, type
<span class="font-bold text-contrast">{{ organization.name }}</span> below
</p>
<StyledInput
<Input
v-model="confirmationText"
:placeholder="`Enter ${organization.name}`"
wrapper-class="w-full"
@@ -76,7 +76,7 @@
<script setup lang="ts">
import { RightArrowIcon, TransferIcon, XIcon } from '@modrinth/assets'
import { Admonition, Avatar, ButtonStyled, NewModal, StyledInput } from '@modrinth/ui'
import { Admonition, Avatar, ButtonStyled, Input, NewModal } from '@modrinth/ui'
import { computed, ref } from 'vue'
const props = defineProps<{
@@ -55,7 +55,7 @@
To confirm this transfer, type
<span class="font-bold text-contrast">{{ project.name }}</span> below
</p>
<StyledInput
<Input
v-model="confirmationText"
:placeholder="`Enter ${project.name}`"
wrapper-class="w-full"
@@ -83,7 +83,7 @@
<script setup lang="ts">
import { RightArrowIcon, TransferIcon, XIcon } from '@modrinth/assets'
import { Admonition, Avatar, ButtonStyled, NewModal, StyledInput } from '@modrinth/ui'
import { Admonition, Avatar, ButtonStyled, Input, NewModal } from '@modrinth/ui'
import { computed, ref } from 'vue'
const props = defineProps<{
-156
View File
@@ -1,156 +0,0 @@
<template>
<div v-if="shown">
<div
:class="{
shown: actuallyShown,
noblur: !$orElse(cosmetics.advancedRendering, true),
}"
class="modal-overlay"
@click="hide"
/>
<div class="modal-container" :class="{ shown: actuallyShown }">
<div class="modal-body">
<div v-if="header" class="header">
<strong>{{ header }}</strong>
<ButtonStyled circular type="transparent">
<button @click="hide">
<XIcon />
</button>
</ButtonStyled>
</div>
<div class="content">
<slot />
</div>
</div>
</div>
</div>
<div v-else />
</template>
<script>
import { XIcon } from '@modrinth/assets'
import { ButtonStyled } from '@modrinth/ui'
export default {
components: {
ButtonStyled,
XIcon,
},
props: {
header: {
type: String,
default: null,
},
},
setup() {
const cosmetics = useCosmetics()
return { cosmetics }
},
data() {
return {
shown: false,
actuallyShown: false,
}
},
methods: {
show() {
this.shown = true
setTimeout(() => {
this.actuallyShown = true
}, 50)
},
hide() {
this.actuallyShown = false
setTimeout(() => {
this.shown = false
}, 300)
},
},
}
</script>
<style lang="scss" scoped>
.modal-overlay {
visibility: hidden;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 20;
transition: all 0.3s ease-in-out;
&.shown {
opacity: 1;
visibility: visible;
background: hsla(0, 0%, 0%, 0.5);
backdrop-filter: blur(3px);
}
&.noblur {
backdrop-filter: none;
}
}
.modal-container {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
z-index: 21;
visibility: hidden;
pointer-events: none;
&.shown {
visibility: visible;
.modal-body {
opacity: 1;
visibility: visible;
transform: translateY(0);
}
}
.modal-body {
position: fixed;
box-shadow: var(--shadow-raised), var(--shadow-inset);
border-radius: var(--size-rounded-lg);
max-height: calc(100% - 2 * var(--spacing-card-bg));
overflow-y: auto;
width: 600px;
pointer-events: auto;
outline: 3px solid transparent;
.header {
display: flex;
justify-content: space-between;
align-items: center;
background-color: var(--color-bg);
padding: var(--spacing-card-md) var(--spacing-card-lg);
strong {
font-size: 1.25rem;
margin: 0.67em 0;
}
}
.content {
background-color: var(--color-raised-bg);
}
transform: translateY(50vh);
visibility: hidden;
opacity: 0;
transition: all 0.25s ease-in-out;
@media screen and (max-width: 650px) {
width: calc(100% - 2 * var(--spacing-card-bg));
}
}
}
</style>
@@ -11,7 +11,7 @@
>
<BookmarkIcon aria-hidden="true" :fill="saved ? 'currentColor' : 'none'" />
<template #menu>
<StyledInput
<Input
v-model="displayCollectionsSearch"
:placeholder="formatMessage(commonMessages.searchPlaceholder)"
wrapper-class="menu-search"
@@ -52,14 +52,7 @@
<script setup lang="ts">
import { BookmarkIcon, PlusIcon } from '@modrinth/assets'
import {
ButtonStyled,
Checkbox,
commonMessages,
PopoutMenu,
StyledInput,
useVIntl,
} from '@modrinth/ui'
import { ButtonStyled, Checkbox, commonMessages, Input, PopoutMenu, useVIntl } from '@modrinth/ui'
import { computed, ref } from 'vue'
import type { RouteLocationRaw } from 'vue-router'
@@ -86,10 +86,17 @@ export function provideDownloadModalProvider(
const tags = useGeneratedState()
const shouldResolveDependencies = computed(
() => !!options.project.value && !!options.selectedVersion.value,
() =>
!!options.project.value &&
!!options.selectedVersion.value &&
!!options.currentGameVersion.value,
)
const dependencyResolutionPreferences = computed(() =>
createResolutionPreferences(options.selectedVersion.value, options.currentPlatform.value),
createResolutionPreferences(
options.selectedVersion.value,
options.currentGameVersion.value,
options.currentPlatform.value,
),
)
const { data: dependencyResolution, isFetching: dependencyResolutionFetching } = useQuery({
@@ -309,10 +316,12 @@ export function provideDownloadModalProvider(
})
async function preloadDependenciesForSelection(selection: ProjectDownloadSelection) {
if (!options.project.value || !selection.selectedVersion) return
if (!options.project.value || !selection.selectedVersion || !selection.currentGameVersion)
return
const preferences = createResolutionPreferences(
selection.selectedVersion,
selection.currentGameVersion,
selection.currentPlatform,
)
@@ -548,10 +557,11 @@ function dependencyProjectsQueryOptions(
function createResolutionPreferences(
version: Labrinth.Versions.v3.Version | null,
currentGameVersion: string | null,
currentPlatform: string | null,
): Labrinth.Content.v3.ResolutionPreferences {
return {
game_versions: version?.game_versions || [],
game_versions: currentGameVersion ? [currentGameVersion] : [],
loaders: currentPlatform ? [currentPlatform] : version?.loaders || [],
}
}
@@ -6,9 +6,9 @@ import {
ButtonStyled,
injectModrinthClient,
injectNotificationManager,
Input,
NewModal,
ServerNotice,
StyledInput,
TagItem,
} from '@modrinth/ui'
import { ref } from 'vue'
@@ -175,7 +175,7 @@ defineExpose({ show, hide })
<span v-else class="mb-2"> No nodes assigned yet </span>
</div>
<div class="flex w-[45rem] items-center gap-2">
<StyledInput
<Input
id="server-assign-field"
v-model="inputField"
wrapper-class="w-full"
@@ -20,7 +20,7 @@
<label for="days" class="flex flex-col gap-1">
<span class="text-lg font-semibold text-contrast"> Days to credit </span>
</label>
<StyledInput
<Input
id="days"
v-model="days"
wrapper-class="w-32"
@@ -36,12 +36,7 @@
<span class="text-lg font-semibold text-contrast"> Node hostnames </span>
</label>
<div class="flex items-center gap-2">
<StyledInput
id="node-input"
v-model="nodeInput"
wrapper-class="w-32"
autocomplete="off"
/>
<Input id="node-input" v-model="nodeInput" wrapper-class="w-32" autocomplete="off" />
<ButtonStyled color="blue" color-fill="text">
<button class="shrink-0" @click="addNode">
<PlusIcon />
@@ -92,13 +87,7 @@
class="text-muted flex flex-col gap-2 rounded-lg border border-surface-5 bg-button-bg p-4"
>
<span>Hi {user.name},</span>
<StyledInput
id="message-batch"
v-model="message"
multiline
:rows="3"
input-class="!bg-surface-3"
/>
<Textarea id="message-batch" v-model="message" :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.
@@ -135,9 +124,10 @@ import {
Combobox,
injectModrinthClient,
injectNotificationManager,
Input,
NewModal,
StyledInput,
TagItem,
Textarea,
Toggle,
} from '@modrinth/ui'
import { DEFAULT_CREDIT_EMAIL_MESSAGE } from '@modrinth/utils/utils.ts'
@@ -25,10 +25,9 @@
</span>
<span>Server IDs (one per line or comma-separated.)</span>
</label>
<StyledInput
<Textarea
id="server-ids"
v-model="serverIdsInput"
multiline
:rows="4"
input-class="bg-surface-3"
placeholder="123e4569-e89b-12d3-a456-426614174005&#10;123e9569-e89b-12d3-a456-413678919876"
@@ -48,7 +47,7 @@
<span>Add nodes to transfer (comma or space-separated).</span>
</label>
<div class="flex items-center gap-2">
<StyledInput
<Input
id="node-input"
v-model="nodeInput"
wrapper-class="w-64"
@@ -86,7 +85,7 @@
<span class="text-lg font-semibold text-contrast">Tag transferred nodes</span>
<span>Optional tag to add to the transferred nodes.</span>
</label>
<StyledInput
<Input
id="tag-nodes"
v-model="tagNodes"
wrapper-class="max-w-[12rem]"
@@ -114,7 +113,7 @@
<span>Optional preferred node tags for node selection.</span>
</label>
<div class="flex items-center gap-2">
<StyledInput
<Input
id="tag-input"
v-model="tagInput"
wrapper-class="w-40"
@@ -147,7 +146,7 @@
:format-label="(item) => scheduleOptionLabels[item]"
:capitalize="false"
/>
<StyledInput
<DateInput
v-if="scheduleOption === 'later'"
v-model="scheduledDate"
type="datetime-local"
@@ -164,10 +163,9 @@
</span>
<span>Provide a reason for this transfer batch.</span>
</label>
<StyledInput
<Textarea
id="reason"
v-model="reason"
multiline
:rows="2"
input-class="bg-surface-3"
placeholder="Node maintenance scheduled"
@@ -198,11 +196,13 @@ import {
ButtonStyled,
Chips,
Combobox,
DateInput,
injectModrinthClient,
injectNotificationManager,
Input,
NewModal,
StyledInput,
TagItem,
Textarea,
Toggle,
} from '@modrinth/ui'
import dayjs from 'dayjs'
@@ -45,7 +45,7 @@
<label class="text-md font-semibold text-contrast" for="create-account-username">
{{ formatMessage(messages.usernameOptionalLabel) }}
</label>
<StyledInput
<Input
id="create-account-username"
v-model="usernameModel"
type="text"
@@ -106,7 +106,7 @@ import {
DatePicker,
defineMessages,
injectNotificationManager,
StyledInput,
Input,
useVIntl,
} from '@modrinth/ui'
import { computed, ref } from 'vue'
@@ -111,7 +111,7 @@
<div class="text-md font-semibold text-contrast">
{{ formatMessage(messages.passkeyNameLabel) }}
</div>
<StyledInput
<Input
id="passkey-name"
v-model="pendingPasskeyName"
:maxlength="255"
@@ -150,7 +150,7 @@
<div class="text-md font-semibold text-contrast">
{{ formatMessage(messages.passkeyNameLabel) }}
</div>
<StyledInput
<Input
id="passkey-rename"
v-model="passkeyToRenameName"
:maxlength="255"
@@ -215,8 +215,8 @@ import {
defineMessages,
injectModrinthClient,
injectNotificationManager,
Input,
NewModal,
StyledInput,
useFormatDateTime,
useRelativeTime,
useVIntl,
@@ -18,7 +18,7 @@
{{ formatMessage(messages.twoFactorCodeLabelDescription) }}
</span>
</label>
<StyledInput
<Input
id="two-factor-code"
v-model="twoFactorCodeModel"
:maxlength="11"
@@ -89,7 +89,7 @@
<section class="mx-auto flex w-full flex-col gap-2.5">
<label for="email" hidden>{{ formatMessage(commonMessages.emailUsernameLabel) }}</label>
<StyledInput
<Input
id="email"
v-model="emailModel"
:icon="MailIcon"
@@ -101,7 +101,7 @@
/>
<label for="password" hidden>{{ formatMessage(commonMessages.passwordLabel) }}</label>
<StyledInput
<Input
id="password"
v-model="passwordModel"
:icon="KeyIcon"
@@ -167,7 +167,7 @@ import {
SteamColorIcon,
UserKeyIcon,
} from '@modrinth/assets'
import { ButtonStyled, commonMessages, defineMessages, StyledInput, useVIntl } from '@modrinth/ui'
import { ButtonStyled, commonMessages, defineMessages, Input, useVIntl } from '@modrinth/ui'
import { useStorage } from '@vueuse/core'
import { computed } from 'vue'
import type { LocationQuery } from 'vue-router'
@@ -84,7 +84,7 @@
<section class="flex flex-col gap-2.5">
<label for="email" hidden>{{ formatMessage(commonMessages.emailLabel) }}</label>
<StyledInput
<Input
id="email"
v-model="emailModel"
:icon="MailIcon"
@@ -95,7 +95,7 @@
/>
<label for="password" hidden>{{ formatMessage(commonMessages.passwordLabel) }}</label>
<StyledInput
<Input
id="password"
v-model="passwordModel"
:icon="KeyIcon"
@@ -162,8 +162,8 @@ import {
ButtonStyled,
commonMessages,
defineMessages,
Input,
IntlFormatted,
StyledInput,
useVIntl,
} from '@modrinth/ui'
import { useStorage } from '@vueuse/core'
@@ -13,7 +13,7 @@
size="small"
/>
</div>
<StyledInput
<Input
v-model="searchQuery"
:icon="SearchIcon"
type="text"
@@ -68,7 +68,7 @@
<script lang="ts" setup>
import type { Labrinth } from '@modrinth/api-client'
import { SearchIcon } from '@modrinth/assets'
import { ButtonStyled, Chips, StyledInput } from '@modrinth/ui'
import { ButtonStyled, Chips, Input } from '@modrinth/ui'
import { useMagicKeys } from '@vueuse/core'
import { computed, nextTick, onMounted, ref } from 'vue'
@@ -24,7 +24,7 @@
<span class="font-semibold text-contrast">
{{ formatMessage(messages.versionNumber) }} <span class="text-red">*</span>
</span>
<StyledInput
<Input
id="version-number"
v-model="draftVersion.version_number"
:disabled="isUploading"
@@ -36,7 +36,7 @@
</div>
<div class="flex flex-col gap-2">
<span class="font-semibold text-contrast">{{ formatMessage(messages.versionSubtitle) }}</span>
<StyledInput
<Input
id="version-number"
v-model="draftVersion.name"
:placeholder="formatMessage(messages.versionSubtitlePlaceholder)"
@@ -66,8 +66,8 @@
import {
Chips,
defineMessages,
Input,
MarkdownEditor,
StyledInput,
Tabs,
type TabsTab,
useVIntl,
@@ -9,7 +9,7 @@
<span class="text-brand-red">*</span>
</span>
</label>
<StyledInput
<Input
id="name"
v-model="name"
:maxlength="64"
@@ -25,10 +25,9 @@
}}</span>
<span>{{ formatMessage(messages.summaryDescription) }}</span>
</label>
<StyledInput
<Textarea
id="additional-information"
v-model="description"
multiline
:maxlength="256"
:placeholder="formatMessage(messages.summaryPlaceholder)"
:disabled="hasHitLimit"
@@ -61,8 +60,9 @@ import {
commonMessages,
defineMessages,
injectNotificationManager,
Input,
NewModal,
StyledInput,
Textarea,
useVIntl,
} from '@modrinth/ui'
@@ -9,7 +9,7 @@
<span class="text-brand-red">*</span>
</span>
</label>
<StyledInput
<Input
id="name"
v-model="name"
:maxlength="64"
@@ -28,7 +28,7 @@
</label>
<div class="text-input-wrapper">
<div class="text-input-wrapper__before">https://modrinth.com/organization/</div>
<StyledInput
<Input
id="slug"
v-model="slug"
:maxlength="64"
@@ -46,10 +46,9 @@
</span>
<span>{{ formatMessage(messages.summaryDescription) }}</span>
</label>
<StyledInput
<Textarea
id="additional-information"
v-model="description"
multiline
:maxlength="256"
:placeholder="formatMessage(messages.summaryPlaceholder)"
:disabled="hasHitLimit"
@@ -83,8 +82,9 @@ import {
commonMessages,
defineMessages,
injectNotificationManager,
Input,
NewModal,
StyledInput,
Textarea,
useVIntl,
} from '@modrinth/ui'
import { ref } from 'vue'
@@ -32,7 +32,7 @@
{{ formatMessage(messages.nameLabel) }}
</span>
</label>
<StyledInput
<Input
id="name"
v-model="name"
:maxlength="64"
@@ -48,7 +48,7 @@
</span>
<div class="text-input-wrapper !w-full">
<div class="text-input-wrapper__before">https://modrinth.com/project/</div>
<StyledInput
<Input
id="slug"
v-model="slug"
:maxlength="64"
@@ -100,10 +100,9 @@
{{ formatMessage(messages.summaryLabel) }}
</span>
</label>
<StyledInput
<Textarea
id="additional-information"
v-model="description"
multiline
:maxlength="256"
:placeholder="formatMessage(messages.summaryPlaceholder)"
:disabled="hasHitLimit"
@@ -140,8 +139,9 @@ import {
defineMessages,
injectModrinthClient,
injectNotificationManager,
Input,
NewModal,
StyledInput,
Textarea,
useVIntl,
} from '@modrinth/ui'
import { computed, defineAsyncComponent, h } from 'vue'
@@ -2,7 +2,7 @@
<div class="flex flex-col gap-2">
<div class="flex items-center gap-2">
<div class="relative flex-1">
<StyledInput
<Input
ref="amountInput"
:model-value="modelValue"
type="number"
@@ -12,7 +12,7 @@
:disabled="isDisabled"
:placeholder="formatMessage(formFieldPlaceholders.amountPlaceholder)"
wrapper-class="w-full"
@update:model-value="handleStyledInput"
@update:model-value="handleInput"
/>
</div>
<Combobox
@@ -54,7 +54,7 @@ import {
Combobox,
commonMessages,
formFieldPlaceholders,
StyledInput,
Input,
useFormatMoney,
useVIntl,
} from '@modrinth/ui'
@@ -83,7 +83,7 @@ const emit = defineEmits<{
const { formatMessage } = useVIntl()
const formatMoney = useFormatMoney()
const amountInput = ref<InstanceType<typeof StyledInput> | null>(null)
const amountInput = ref<InstanceType<typeof Input> | null>(null)
const safeMaxAmount = computed(() => {
return Math.max(0, props.maxAmount)
@@ -108,7 +108,7 @@ function setMaxAmount() {
emit('update:modelValue', maxValue)
}
function handleStyledInput(val: string | number) {
function handleInput(val: string | number) {
const value = String(val)
if (value && value.includes('.')) {
@@ -41,7 +41,7 @@
>
</label>
<div class="flex flex-row gap-2">
<StyledInput
<Input
v-model="venmoHandle"
:placeholder="formatMessage(messages.venmoHandlePlaceholder)"
wrapper-class="w-full"
@@ -110,9 +110,9 @@ import {
defineMessages,
financialMessages,
formFieldLabels,
Input,
IntlFormatted,
normalizeChildren,
StyledInput,
useVIntl,
} from '@modrinth/ui'
import { useDebounceFn } from '@vueuse/core'
@@ -56,7 +56,7 @@
</span>
<div class="flex flex-col gap-3 sm:flex-row sm:gap-4">
<div class="flex flex-1 flex-col gap-2.5">
<StyledInput
<Input
v-model="formData.bankAccountOwnerFirstName"
:placeholder="formatMessage(formFieldPlaceholders.firstNamePlaceholder)"
autocomplete="given-name"
@@ -64,7 +64,7 @@
/>
</div>
<div class="flex flex-1 flex-col gap-2.5">
<StyledInput
<Input
v-model="formData.bankAccountOwnerLastName"
:placeholder="formatMessage(formFieldPlaceholders.lastNamePlaceholder)"
autocomplete="family-name"
@@ -91,7 +91,7 @@
class="h-10"
/>
<StyledInput
<Input
v-else
v-model="formData.bankName"
:placeholder="formatMessage(formFieldPlaceholders.bankNamePlaceholder)"
@@ -108,7 +108,7 @@
</span>
</label>
<StyledInput
<Input
v-if="['text', 'email', 'tel'].includes(field.type)"
v-model="formData[field.name]"
:type="field.type === 'tel' ? undefined : field.type === 'text' ? undefined : field.type"
@@ -158,7 +158,7 @@
<span v-if="dynamicDocumentNumberField.required" class="text-red">*</span>
</span>
</label>
<StyledInput
<Input
v-model="formData.documentNumber"
:placeholder="dynamicDocumentNumberField.placeholder"
autocomplete="off"
@@ -238,9 +238,9 @@ import {
getBlockchainIcon,
getCurrencyColor,
getCurrencyIcon,
Input,
IntlFormatted,
normalizeChildren,
StyledInput,
useVIntl,
} from '@modrinth/ui'
import { useDebounceFn } from '@vueuse/core'
@@ -32,7 +32,7 @@
<span class="text-red">*</span>
</span>
</label>
<StyledInput
<Input
v-model="formData.businessName"
:placeholder="formatMessage(formFieldPlaceholders.businessNamePlaceholder)"
autocomplete="organization"
@@ -47,7 +47,7 @@
<span class="text-red">*</span>
</span>
</label>
<StyledInput
<Input
v-model="formData.email"
type="email"
:placeholder="formatMessage(formFieldPlaceholders.emailPlaceholder)"
@@ -65,7 +65,7 @@
<span class="text-red">*</span>
</span>
</label>
<StyledInput
<Input
v-model="formData.firstName"
:placeholder="formatMessage(formFieldPlaceholders.firstNamePlaceholder)"
autocomplete="given-name"
@@ -79,7 +79,7 @@
<span class="text-red">*</span>
</span>
</label>
<StyledInput
<Input
v-model="formData.lastName"
:placeholder="formatMessage(formFieldPlaceholders.lastNamePlaceholder)"
autocomplete="family-name"
@@ -112,7 +112,7 @@
<span class="text-red">*</span>
</span>
</label>
<StyledInput
<Input
v-model="formData.physicalAddress.address1"
:placeholder="formatMessage(formFieldPlaceholders.addressPlaceholder)"
autocomplete="address-line1"
@@ -126,7 +126,7 @@
{{ formatMessage(formFieldLabels.addressLine2) }}
</span>
</label>
<StyledInput
<Input
v-model="formData.physicalAddress.address2"
:placeholder="formatMessage(formFieldPlaceholders.address2Placeholder)"
autocomplete="address-line2"
@@ -142,7 +142,7 @@
<span class="text-red">*</span>
</span>
</label>
<StyledInput
<Input
v-model="formData.physicalAddress.city"
:placeholder="formatMessage(formFieldPlaceholders.cityPlaceholder)"
autocomplete="address-level2"
@@ -164,7 +164,7 @@
searchable
:search-placeholder="formatMessage(messages.searchSubdivisionsPlaceholder)"
/>
<StyledInput
<Input
v-else
v-model="formData.physicalAddress.state"
:placeholder="formatMessage(formFieldPlaceholders.statePlaceholder)"
@@ -182,7 +182,7 @@
<span class="text-red">*</span>
</span>
</label>
<StyledInput
<Input
v-model="formData.physicalAddress.zip"
:placeholder="formatMessage(formFieldPlaceholders.postalCodePlaceholder)"
autocomplete="postal-code"
@@ -217,7 +217,7 @@ import {
defineMessages,
formFieldLabels,
formFieldPlaceholders,
StyledInput,
Input,
useVIntl,
} from '@modrinth/ui'
// TODO: Switch to using Muralpay's improved endpoint when it's available.
@@ -39,7 +39,7 @@
>{{ formatMessage(formFieldLabels.email) }} <span class="text-red">*</span></span
>
</label>
<StyledInput
<Input
v-model="deliveryEmail"
type="email"
:placeholder="formatMessage(formFieldPlaceholders.emailPlaceholder)"
@@ -131,7 +131,7 @@
<div v-if="showGiftCardSelector && useFixedDenominations" class="flex flex-col gap-2.5">
<template v-if="useDenominationSuggestions">
<StyledInput
<Input
v-model="denominationSearchInput"
type="number"
:icon="SearchIcon"
@@ -321,10 +321,10 @@ import {
financialMessages,
formFieldLabels,
formFieldPlaceholders,
Input,
IntlFormatted,
normalizeChildren,
paymentMethodMessages,
StyledInput,
useDebugLogger,
useFormatMoney,
useVIntl,
@@ -1,7 +1,7 @@
<template>
<div>
<form class="flex flex-col gap-2 sm:flex-row" @submit.prevent="executeSearch">
<StyledInput
<Input
v-model="query"
:icon="SearchIcon"
type="text"
@@ -128,8 +128,8 @@ import {
EmptyState,
injectModrinthClient,
injectNotificationManager,
Input,
Pagination,
StyledInput,
} from '@modrinth/ui'
import GlobalDetailLocalTraceCard from '~/components/ui/moderation/GlobalDetailLocalTraceCard.vue'
@@ -218,10 +218,9 @@
:heading-buttons="false"
:on-image-upload="onUploadHandler"
/>
<StyledInput
<Textarea
v-else
v-model="messageText"
multiline
placeholder="No message generated."
autocomplete="off"
input-class="h-[400px] font-mono"
@@ -414,7 +413,7 @@ import {
injectNotificationManager,
injectProjectPageContext,
MarkdownEditor,
StyledInput,
Textarea,
useDebugLogger,
} from '@modrinth/ui'
import TeleportOverflowMenu from '@modrinth/ui/src/components/base/TeleportOverflowMenu.vue'
@@ -34,7 +34,7 @@
<label for="proof">
<span class="label__title">Proof</span>
</label>
<StyledInput
<Input
id="proof"
v-model="(modPackData[currentIndex] as ModerationUnknownModpackItem).proof"
autocomplete="off"
@@ -44,7 +44,7 @@
<label for="link">
<span class="label__title">Link</span>
</label>
<StyledInput
<Input
id="link"
v-model="(modPackData[currentIndex] as ModerationUnknownModpackItem).url"
autocomplete="off"
@@ -54,7 +54,7 @@
<label for="title">
<span class="label__title">Title</span>
</label>
<StyledInput
<Input
id="title"
v-model="(modPackData[currentIndex] as ModerationUnknownModpackItem).title"
autocomplete="off"
@@ -143,7 +143,7 @@
<script setup lang="ts">
import { LeftArrowIcon, RightArrowIcon } from '@modrinth/assets'
import { ButtonStyled, StyledInput } from '@modrinth/ui'
import { ButtonStyled, Input } from '@modrinth/ui'
import type {
ModerationFlameModpackItem,
ModerationJudgements,
@@ -30,11 +30,11 @@ import {
Checkbox,
Combobox,
injectProjectPageContext,
Input,
MarkdownEditor,
StyledInput,
} from '@modrinth/ui'
import { renderHighlightedString, renderString } from '@modrinth/utils'
import { inject, nextTick, onMounted, reactive, watchEffect } from 'vue'
import { inject, onMounted, reactive, watchEffect } from 'vue'
import { NODE_META_KEY, STATE_KEY } from './checklist-context'
@@ -266,7 +266,6 @@ function setTextState(node: IdentifiedNodeBuilder, v: string): void {
const def = resolveDefault(node as ValueNodeBuilder)
const defStr = typeof def === 'string' ? def : ''
setNodeState(node, ov === defStr ? undefined : ov || undefined)
nextTick(() => textInputRefs.get(node)?.setValue(ov))
return
}
@@ -277,7 +276,7 @@ function setTextState(node: IdentifiedNodeBuilder, v: string): void {
function handleButtonClick(node: ButtonNodeBuilder): void {
const before = new Map<NodeBuilder, string>()
for (const inputNode of textInputRefs.keys()) {
for (const inputNode of textInputNodes) {
before.set(inputNode, getTextState(asIdentified(inputNode)))
}
node._onClick?.(props.showContext)
@@ -288,7 +287,7 @@ function handleButtonClick(node: ButtonNodeBuilder): void {
}
onMounted(() => {
for (const inputNode of textInputRefs.keys()) {
for (const inputNode of textInputNodes) {
setTextState(asIdentified(inputNode), getTextState(asIdentified(inputNode)))
}
})
@@ -325,7 +324,7 @@ function toggleChip(parent: IdentifiedNodeBuilder, child: IdentifiedNodeBuilder)
setNodeState(parent, selected.size > 0 ? selected : undefined)
}
const textInputRefs = new Map<NodeBuilder, { setValue: (v: string) => void }>()
const textInputNodes = new Set<NodeBuilder>()
const overrideHelpers = { override: (v: string): OverrideValue => ({ __override: v }) }
function isOverrideValue(v: unknown): v is OverrideValue {
@@ -720,9 +719,9 @@ watchEffect(async () => {
<!-- text -->
<template v-else-if="item.type === 'text'">
<StyledInput
<Input
:id="`node-${asIdentified(item).id}`"
:ref="(el: any) => (el ? textInputRefs.set(item, el) : textInputRefs.delete(item))"
:ref="(el: any) => (el ? textInputNodes.add(item) : textInputNodes.delete(item))"
v-tooltip="getTooltipConfig(item, showContext)"
:model-value="getTextState(asIdentified(item))"
:placeholder="getPlaceholder(asInput(item))"
+48 -16
View File
@@ -30,6 +30,29 @@ const normalizeAuthToken = (value: unknown) => {
return ''
}
const getErrorStatus = (error: unknown): number | undefined => {
if (!error || typeof error !== 'object') {
return undefined
}
const typedError = error as { statusCode?: unknown; status?: unknown }
const status = typedError.statusCode ?? typedError.status
return typeof status === 'number' ? status : undefined
}
// only when labrinth actually gives us an auth error
const isAuthFailure = (error: unknown): boolean => {
const status = getErrorStatus(error)
return status === 401 || status === 403
}
const clearAuthCookie = (auth: AuthState, authCookie: { value: string | null }) => {
authCookie.value = null
auth.token = ''
auth.user = null
}
const getQueryString = (value: QueryValue) => {
if (Array.isArray(value)) {
return value[0] ?? null
@@ -90,6 +113,7 @@ export const initAuth = async (oldToken: string | null | undefined = null) => {
}
const tokenStr = normalizeAuthToken(authCookie.value)
let shouldRefresh = false
if (authCookie.value != null && tokenStr === '') {
authCookie.value = null
@@ -111,12 +135,13 @@ export const initAuth = async (oldToken: string | null | undefined = null) => {
},
true,
)) as Labrinth.Users.v2.User
} catch {
/* empty */
} catch (error) {
// only refresh when the token was rejected. not on timeouts or other errors (think this was the cause of random logouts)
shouldRefresh = isAuthFailure(error)
}
}
if (!auth.user && auth.token) {
if (!auth.user && auth.token && shouldRefresh) {
try {
const session = (await useBaseFetch(
'session/refresh',
@@ -132,22 +157,29 @@ export const initAuth = async (oldToken: string | null | undefined = null) => {
auth.token = normalizeAuthToken(session.session)
if (auth.token) {
authCookie.value = auth.token
auth.user = (await useBaseFetch(
'user',
{
apiVersion: 3,
headers: {
Authorization: auth.token,
try {
auth.user = (await useBaseFetch(
'user',
{
apiVersion: 3,
headers: {
Authorization: auth.token,
},
},
},
true,
)) as Labrinth.Users.v2.User
true,
)) as Labrinth.Users.v2.User
} catch (error) {
if (isAuthFailure(error)) {
clearAuthCookie(auth, authCookie)
}
}
} else {
authCookie.value = null
auth.token = ''
clearAuthCookie(auth, authCookie)
}
} catch (error) {
if (isAuthFailure(error)) {
clearAuthCookie(auth, authCookie)
}
} catch {
authCookie.value = null
}
}
@@ -2744,24 +2744,15 @@
"settings.applications.about": {
"message": "O"
},
"settings.applications.button.cancel": {
"message": "Zrušit"
},
"settings.applications.button.create": {
"message": "Vytvořit aplikaci"
},
"settings.applications.button.delete": {
"message": "Smazat"
},
"settings.applications.button.edit": {
"message": "Upravit"
},
"settings.applications.button.new": {
"message": "Nová aplikace"
},
"settings.applications.button.save-changes": {
"message": "Uložit změny"
},
"settings.applications.button.upload-icon": {
"message": "Nahrát ikonu"
},
@@ -2945,24 +2945,15 @@
"settings.applications.button.add-more": {
"message": "Tilføj mere"
},
"settings.applications.button.cancel": {
"message": "Annuller"
},
"settings.applications.button.create": {
"message": "Opret app"
},
"settings.applications.button.delete": {
"message": "Slet"
},
"settings.applications.button.edit": {
"message": "Rediger"
},
"settings.applications.button.new": {
"message": "Ny applikation"
},
"settings.applications.button.save-changes": {
"message": "Gem ændringer"
},
"settings.applications.button.upload-icon": {
"message": "Upload ikon"
},
@@ -4679,24 +4679,15 @@
"settings.applications.button.add-redirect-uri": {
"message": "Weiterleitungs-URI hinzufügen"
},
"settings.applications.button.cancel": {
"message": "Abbrechen"
},
"settings.applications.button.create": {
"message": "App erstellen"
},
"settings.applications.button.delete": {
"message": "Löschen"
},
"settings.applications.button.edit": {
"message": "Bearbeiten"
},
"settings.applications.button.new": {
"message": "Neue Anwendung"
},
"settings.applications.button.save-changes": {
"message": "Änderungen speichern"
},
"settings.applications.button.upload-icon": {
"message": "Icon hochladen"
},
@@ -4679,24 +4679,15 @@
"settings.applications.button.add-redirect-uri": {
"message": "Weiterleitungs-URI hinzufügen"
},
"settings.applications.button.cancel": {
"message": "Abbrechen"
},
"settings.applications.button.create": {
"message": "Anwendung erstellen"
},
"settings.applications.button.delete": {
"message": "Löschen"
},
"settings.applications.button.edit": {
"message": "Bearbeiten"
},
"settings.applications.button.new": {
"message": "Neue Anwendung"
},
"settings.applications.button.save-changes": {
"message": "Änderungen speichern"
},
"settings.applications.button.upload-icon": {
"message": "Icon hochladen"
},
+3 -9
View File
@@ -191,6 +191,9 @@
"analytics.chart.tooltip.hide-entry": {
"message": "Hide {name} in graph"
},
"analytics.chart.tooltip.no-data": {
"message": "No data"
},
"analytics.chart.tooltip.pinned": {
"message": "Chart tooltip pinned"
},
@@ -4709,24 +4712,15 @@
"settings.applications.button.add-redirect-uri": {
"message": "Add a redirect URI"
},
"settings.applications.button.cancel": {
"message": "Cancel"
},
"settings.applications.button.create": {
"message": "Create app"
},
"settings.applications.button.delete": {
"message": "Delete"
},
"settings.applications.button.edit": {
"message": "Edit"
},
"settings.applications.button.new": {
"message": "New application"
},
"settings.applications.button.save-changes": {
"message": "Save changes"
},
"settings.applications.button.upload-icon": {
"message": "Upload icon"
},
@@ -4187,24 +4187,15 @@
"settings.applications.button.add-redirect-uri": {
"message": "Agregar un URI de redirección"
},
"settings.applications.button.cancel": {
"message": "Cancelar"
},
"settings.applications.button.create": {
"message": "Crear aplicación"
},
"settings.applications.button.delete": {
"message": "Borrar"
},
"settings.applications.button.edit": {
"message": "Editar"
},
"settings.applications.button.new": {
"message": "Nueva aplicación"
},
"settings.applications.button.save-changes": {
"message": "Guardar cambios"
},
"settings.applications.button.upload-icon": {
"message": "Cargar icono"
},
@@ -3860,24 +3860,15 @@
"settings.applications.button.add-redirect-uri": {
"message": "Añadir una URI de redirección"
},
"settings.applications.button.cancel": {
"message": "Cancelar"
},
"settings.applications.button.create": {
"message": "Crear aplicación"
},
"settings.applications.button.delete": {
"message": "Eliminar"
},
"settings.applications.button.edit": {
"message": "Editar"
},
"settings.applications.button.new": {
"message": "Nueva aplicación"
},
"settings.applications.button.save-changes": {
"message": "Guardar cambios"
},
"settings.applications.button.upload-icon": {
"message": "Subir icono"
},
@@ -2840,24 +2840,15 @@
"settings.applications.button.add-redirect-uri": {
"message": "Magdagdag ng redirect URI"
},
"settings.applications.button.cancel": {
"message": "Kanselahin"
},
"settings.applications.button.create": {
"message": "Lumikha ng app"
},
"settings.applications.button.delete": {
"message": "Tanggalin"
},
"settings.applications.button.edit": {
"message": "Baguhin"
},
"settings.applications.button.new": {
"message": "Bagong aplikasyon"
},
"settings.applications.button.save-changes": {
"message": "I-save ang mga pagbabago"
},
"settings.applications.button.upload-icon": {
"message": "I-upload ang ikono"
},
@@ -4667,24 +4667,15 @@
"settings.applications.button.add-redirect-uri": {
"message": "Ajouter une URI de redirection"
},
"settings.applications.button.cancel": {
"message": "Annuler"
},
"settings.applications.button.create": {
"message": "Créer une appli"
},
"settings.applications.button.delete": {
"message": "Supprimer"
},
"settings.applications.button.edit": {
"message": "Modifier"
},
"settings.applications.button.new": {
"message": "Nouvelle application"
},
"settings.applications.button.save-changes": {
"message": "Sauvegarder les changements"
},
"settings.applications.button.upload-icon": {
"message": "Charger une icône"
},
@@ -2282,9 +2282,6 @@
"settings.account.data-export.description": {
"message": "תבקש עותק של כל הדאטה האישי שהעלית ל-Modrinth. זה יכול לקחת כמה דקות."
},
"settings.applications.button.edit": {
"message": "ערוך"
},
"settings.applications.field.name": {
"message": "שם"
},
@@ -4130,24 +4130,15 @@
"settings.applications.button.add-redirect-uri": {
"message": "Átírányítás URI hozzáadása"
},
"settings.applications.button.cancel": {
"message": "Mégse"
},
"settings.applications.button.create": {
"message": "Alkalmazás létrehozása"
},
"settings.applications.button.delete": {
"message": "Törlés"
},
"settings.applications.button.edit": {
"message": "Szerkesztés"
},
"settings.applications.button.new": {
"message": "Új alkalmazás"
},
"settings.applications.button.save-changes": {
"message": "Módosítások mentése"
},
"settings.applications.button.upload-icon": {
"message": "Ikon feltöltése"
},
@@ -2918,24 +2918,15 @@
"settings.applications.button.add-redirect-uri": {
"message": "Tambah URI pengarahan ulang"
},
"settings.applications.button.cancel": {
"message": "Batal"
},
"settings.applications.button.create": {
"message": "Buat aplikasi"
},
"settings.applications.button.delete": {
"message": "Hapus"
},
"settings.applications.button.edit": {
"message": "Sunting"
},
"settings.applications.button.new": {
"message": "Aplikasi baru"
},
"settings.applications.button.save-changes": {
"message": "Simpan perubahan"
},
"settings.applications.button.upload-icon": {
"message": "Unggah ikon"
},
@@ -4667,24 +4667,15 @@
"settings.applications.button.add-redirect-uri": {
"message": "Aggiungi reindirizzamento"
},
"settings.applications.button.cancel": {
"message": "Annulla"
},
"settings.applications.button.create": {
"message": "Crea app"
},
"settings.applications.button.delete": {
"message": "Elimina"
},
"settings.applications.button.edit": {
"message": "Modifica"
},
"settings.applications.button.new": {
"message": "Nuova applicazione"
},
"settings.applications.button.save-changes": {
"message": "Salva modifiche"
},
"settings.applications.button.upload-icon": {
"message": "Carica icona"
},
@@ -3620,24 +3620,15 @@
"settings.applications.button.add-redirect-uri": {
"message": "リダイレクトURIを追加"
},
"settings.applications.button.cancel": {
"message": "キャンセル"
},
"settings.applications.button.create": {
"message": "アプリを作成する"
},
"settings.applications.button.delete": {
"message": "削除"
},
"settings.applications.button.edit": {
"message": "編集"
},
"settings.applications.button.new": {
"message": "新規アプリケーション"
},
"settings.applications.button.save-changes": {
"message": "変更を保存する"
},
"settings.applications.button.upload-icon": {
"message": "アイコンをアップロード"
},
@@ -4631,24 +4631,15 @@
"settings.applications.button.add-redirect-uri": {
"message": "리디렉션 URI 를 추가하세요"
},
"settings.applications.button.cancel": {
"message": "취소"
},
"settings.applications.button.create": {
"message": "앱 만들기"
},
"settings.applications.button.delete": {
"message": "지우기"
},
"settings.applications.button.edit": {
"message": "편집"
},
"settings.applications.button.new": {
"message": "새 애플리케이션"
},
"settings.applications.button.save-changes": {
"message": "변경사항 저장"
},
"settings.applications.button.upload-icon": {
"message": "아이콘 업로드"
},
@@ -3653,24 +3653,15 @@
"settings.applications.button.add-redirect-uri": {
"message": "Tambah URI pengubah hala"
},
"settings.applications.button.cancel": {
"message": "Batal"
},
"settings.applications.button.create": {
"message": "Cipta aplikasi"
},
"settings.applications.button.delete": {
"message": "Padam"
},
"settings.applications.button.edit": {
"message": "Sunting"
},
"settings.applications.button.new": {
"message": "Aplikasi baharu"
},
"settings.applications.button.save-changes": {
"message": "Simpan perubahan"
},
"settings.applications.button.upload-icon": {
"message": "Muat naik ikon"
},
@@ -4706,24 +4706,15 @@
"settings.applications.button.add-redirect-uri": {
"message": "Voeg een URI toe"
},
"settings.applications.button.cancel": {
"message": "Annuleren"
},
"settings.applications.button.create": {
"message": "Maak nieuwe"
},
"settings.applications.button.delete": {
"message": "Verwijder"
},
"settings.applications.button.edit": {
"message": "Bewerk"
},
"settings.applications.button.new": {
"message": "Nieuw project"
},
"settings.applications.button.save-changes": {
"message": "Wijzigingen opslaan"
},
"settings.applications.button.upload-icon": {
"message": "Pictogram uploaden"
},
@@ -3539,24 +3539,15 @@
"settings.applications.button.add-redirect-uri": {
"message": "Legg til en omdirings-URI"
},
"settings.applications.button.cancel": {
"message": "Avbryt"
},
"settings.applications.button.create": {
"message": "Lag app"
},
"settings.applications.button.delete": {
"message": "Slett"
},
"settings.applications.button.edit": {
"message": "Regiser"
},
"settings.applications.button.new": {
"message": "Ny søknad"
},
"settings.applications.button.save-changes": {
"message": "Lagre endringer"
},
"settings.applications.button.upload-icon": {
"message": "Last opp ikon"
},
@@ -4622,24 +4622,15 @@
"settings.applications.button.add-redirect-uri": {
"message": "Dodaj URI przekierowywania"
},
"settings.applications.button.cancel": {
"message": "Anuluj"
},
"settings.applications.button.create": {
"message": "Stwórz aplikację"
},
"settings.applications.button.delete": {
"message": "Usuń"
},
"settings.applications.button.edit": {
"message": "Edytuj"
},
"settings.applications.button.new": {
"message": "Nowa aplikacja"
},
"settings.applications.button.save-changes": {
"message": "Zapisz zmiany"
},
"settings.applications.button.upload-icon": {
"message": "Prześlij ikonę"
},
@@ -4709,24 +4709,15 @@
"settings.applications.button.add-redirect-uri": {
"message": "Adicionar URI de redirecionamento"
},
"settings.applications.button.cancel": {
"message": "Cancelar"
},
"settings.applications.button.create": {
"message": "Criar app"
},
"settings.applications.button.delete": {
"message": "Excluir"
},
"settings.applications.button.edit": {
"message": "Editar"
},
"settings.applications.button.new": {
"message": "Novo aplicativo"
},
"settings.applications.button.save-changes": {
"message": "Salvar alterações"
},
"settings.applications.button.upload-icon": {
"message": "Enviar ícone"
},
@@ -3350,24 +3350,15 @@
"settings.applications.button.add-redirect-uri": {
"message": "Adicionar um endereço de redirecionamento"
},
"settings.applications.button.cancel": {
"message": "Cancelar"
},
"settings.applications.button.create": {
"message": "Criar app"
},
"settings.applications.button.delete": {
"message": "Apagar"
},
"settings.applications.button.edit": {
"message": "Editar"
},
"settings.applications.button.new": {
"message": "Nova aplicação"
},
"settings.applications.button.save-changes": {
"message": "Guardar alterações"
},
"settings.applications.button.upload-icon": {
"message": "Carregar ícone"
},
@@ -1814,21 +1814,12 @@
"settings.applications.about": {
"message": "Despre"
},
"settings.applications.button.cancel": {
"message": "Anuleaza"
},
"settings.applications.button.create": {
"message": "Creaza aplicația"
},
"settings.applications.button.delete": {
"message": "Sterge"
},
"settings.applications.button.edit": {
"message": "Editeaza"
},
"settings.applications.button.save-changes": {
"message": "Salvează schimbările"
},
"settings.applications.client-id": {
"message": "ID Client"
},
@@ -4655,24 +4655,15 @@
"settings.applications.button.add-redirect-uri": {
"message": "Добавить адрес перенаправления"
},
"settings.applications.button.cancel": {
"message": "Отмена"
},
"settings.applications.button.create": {
"message": "Создать приложение"
},
"settings.applications.button.delete": {
"message": "Удалить"
},
"settings.applications.button.edit": {
"message": "Изменить"
},
"settings.applications.button.new": {
"message": "Новое приложение"
},
"settings.applications.button.save-changes": {
"message": "Сохранить изменения"
},
"settings.applications.button.upload-icon": {
"message": "Загрузить иконку"
},
@@ -3713,24 +3713,15 @@
"settings.applications.button.add-more": {
"message": "Lägg till mer"
},
"settings.applications.button.cancel": {
"message": "Avbryt"
},
"settings.applications.button.create": {
"message": "Skapa app"
},
"settings.applications.button.delete": {
"message": "Ta bort"
},
"settings.applications.button.edit": {
"message": "Redigera"
},
"settings.applications.button.new": {
"message": "Ny applikation"
},
"settings.applications.button.save-changes": {
"message": "Spara ändringar"
},
"settings.applications.button.upload-icon": {
"message": "Ladda upp ikon"
},
@@ -4118,24 +4118,15 @@
"settings.applications.button.add-redirect-uri": {
"message": "Yönlendirme URI'ları ekle"
},
"settings.applications.button.cancel": {
"message": "İptal"
},
"settings.applications.button.create": {
"message": "Uygulama oluştur"
},
"settings.applications.button.delete": {
"message": "Sil"
},
"settings.applications.button.edit": {
"message": "Düzenle"
},
"settings.applications.button.new": {
"message": "Yeni uygulama"
},
"settings.applications.button.save-changes": {
"message": "Değişiklikleri kaydet"
},
"settings.applications.button.upload-icon": {
"message": "Simge yükle"
},
@@ -4631,24 +4631,15 @@
"settings.applications.button.add-redirect-uri": {
"message": "Додати переадресацію URI"
},
"settings.applications.button.cancel": {
"message": "Скасувати"
},
"settings.applications.button.create": {
"message": "Створити застосунок"
},
"settings.applications.button.delete": {
"message": "Видалити"
},
"settings.applications.button.edit": {
"message": "Редагувати"
},
"settings.applications.button.new": {
"message": "Новий застосунок"
},
"settings.applications.button.save-changes": {
"message": "Зберегти зміни"
},
"settings.applications.button.upload-icon": {
"message": "Завантажити значок"
},
@@ -3818,24 +3818,15 @@
"settings.applications.button.add-redirect-uri": {
"message": "Thêm URI chuyển hướng"
},
"settings.applications.button.cancel": {
"message": "Huỷ"
},
"settings.applications.button.create": {
"message": "Tạo ứng dụng"
},
"settings.applications.button.delete": {
"message": "Xoá"
},
"settings.applications.button.edit": {
"message": "Chỉnh sửa"
},
"settings.applications.button.new": {
"message": "Ứng dụng mới"
},
"settings.applications.button.save-changes": {
"message": "Lưu thay đổi"
},
"settings.applications.button.upload-icon": {
"message": "Tải lên biểu tượng"
},
@@ -4709,24 +4709,15 @@
"settings.applications.button.add-redirect-uri": {
"message": "添加重定向 URI"
},
"settings.applications.button.cancel": {
"message": "取消"
},
"settings.applications.button.create": {
"message": "新建 App"
},
"settings.applications.button.delete": {
"message": "删除"
},
"settings.applications.button.edit": {
"message": "编辑"
},
"settings.applications.button.new": {
"message": "新建应用程序"
},
"settings.applications.button.save-changes": {
"message": "保存更改"
},
"settings.applications.button.upload-icon": {
"message": "上传图标"
},
@@ -4709,24 +4709,15 @@
"settings.applications.button.add-redirect-uri": {
"message": "新增重新導向 URI"
},
"settings.applications.button.cancel": {
"message": "取消"
},
"settings.applications.button.create": {
"message": "建立應用程式"
},
"settings.applications.button.delete": {
"message": "刪除"
},
"settings.applications.button.edit": {
"message": "編輯"
},
"settings.applications.button.new": {
"message": "新的應用程式"
},
"settings.applications.button.save-changes": {
"message": "儲存變更"
},
"settings.applications.button.upload-icon": {
"message": "上傳圖示"
},
@@ -43,7 +43,7 @@
<label for="gallery-image-title">
<span class="label__title">Title</span>
</label>
<StyledInput
<Input
id="gallery-image-title"
v-model="editTitle"
:maxlength="64"
@@ -52,17 +52,16 @@
<label for="gallery-image-desc">
<span class="label__title">Description</span>
</label>
<StyledInput
<Textarea
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>
<StyledInput
<Input
id="gallery-image-ordering"
v-model="editOrder"
type="number"
@@ -305,8 +304,9 @@ import {
DropArea,
FileInput,
injectProjectPageContext,
Input,
NewModal as Modal,
StyledInput,
Textarea,
useFormatDateTime,
} from '@modrinth/ui'
import { useEventListener } from '@vueuse/core'
@@ -43,7 +43,7 @@
<label for="gallery-image-title">
<span class="label__title">Title</span>
</label>
<StyledInput
<Input
id="gallery-image-title"
v-model="editTitle"
:maxlength="64"
@@ -52,17 +52,16 @@
<label for="gallery-image-desc">
<span class="label__title">Description</span>
</label>
<StyledInput
<Textarea
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>
<StyledInput
<Input
id="gallery-image-ordering"
v-model="editOrder"
type="number"
@@ -295,8 +294,9 @@ import {
DropArea,
FileInput,
injectProjectPageContext,
Input,
NewModal as Modal,
StyledInput,
Textarea,
useFormatDateTime,
} from '@modrinth/ui'
@@ -4,9 +4,9 @@ import {
defineMessages,
IconSelect,
injectProjectPageContext,
Input,
type MessageDescriptor,
SettingsLabel,
StyledInput,
UnsavedChangesPopup,
usePageLeaveSafety,
useSavable,
@@ -140,7 +140,7 @@ const placeholder = computed(() => placeholders[placeholderIndex.value] ?? place
:description="messages.nameDescription"
/>
<div class="flex">
<StyledInput
<Input
id="project-name"
v-model="current.title"
:placeholder="formatMessage(placeholder.name)"
@@ -156,7 +156,7 @@ const placeholder = computed(() => placeholders[placeholderIndex.value] ?? place
:title="messages.taglineTitle"
:description="messages.taglineDescription"
/>
<StyledInput
<Input
id="project-tagline"
v-model="current.tagline"
:placeholder="formatMessage(placeholder.tagline)"
@@ -169,7 +169,7 @@ const placeholder = computed(() => placeholders[placeholderIndex.value] ?? place
<SettingsLabel id="project-url" :title="messages.urlTitle" />
<div class="text-input-wrapper">
<div class="text-input-wrapper__before">https://modrinth.com/project/</div>
<StyledInput id="project-url" v-model="current.url" :maxlength="64" autocomplete="off" />
<Input id="project-url" v-model="current.url" :maxlength="64" autocomplete="off" />
</div>
</div>
</div>
@@ -21,12 +21,7 @@
<label for="project-name">
<span class="label__title">Name</span>
</label>
<StyledInput
id="project-name"
v-model="name"
:maxlength="2048"
:disabled="!hasPermission"
/>
<Input id="project-name" v-model="name" :maxlength="2048" :disabled="!hasPermission" />
</div>
<div>
@@ -39,7 +34,7 @@
$getProjectTypeForUrl(project.project_type, project.loaders)
}}/
</div>
<StyledInput
<Input
id="project-slug"
v-model="slug"
:maxlength="64"
@@ -53,10 +48,9 @@
<label for="project-summary">
<span class="label__title">Summary</span>
</label>
<StyledInput
<Textarea
id="project-summary"
v-model="summary"
multiline
:maxlength="256"
:disabled="!hasPermission"
resize="vertical"
@@ -341,7 +335,8 @@ import {
injectModrinthClient,
injectNotificationManager,
injectProjectPageContext,
StyledInput,
Input,
Textarea,
Toggle,
UnsavedChangesPopup,
useFormatBytes,
@@ -72,7 +72,7 @@
</label>
<div class="w-1/2">
<StyledInput
<Input
id="license-url"
v-model="current.licenseUrl"
type="url"
@@ -105,7 +105,7 @@
</label>
<div class="flex w-1/2 flex-col gap-2">
<StyledInput
<Input
v-if="!current.nonSpdxLicense"
id="license-spdx"
v-model="current.license.short"
@@ -114,7 +114,7 @@
placeholder="SPDX identifier"
:disabled="!hasPermission"
/>
<StyledInput
<Input
v-else
id="license-name"
v-model="current.license.short"
@@ -158,7 +158,7 @@ import {
ConfirmLeaveModal,
DropdownSelect,
injectProjectPageContext,
StyledInput,
Input,
UnsavedChangesPopup,
usePageLeaveSafety,
useSavable,
@@ -142,7 +142,7 @@
v-tooltip="`Link includes a domain which isn't common for this link type.`"
class="size-6 animate-pulse text-orange"
/>
<StyledInput
<Input
id="project-issue-tracker"
v-model="issuesUrl"
type="url"
@@ -176,7 +176,7 @@
v-tooltip="`Link includes a domain which isn't common for this link type.`"
class="size-6 animate-pulse text-orange"
/>
<StyledInput
<Input
id="project-source-code"
v-model="sourceUrl"
type="url"
@@ -205,7 +205,7 @@
v-tooltip="`Discord invites are not appropriate for this link type.`"
class="size-6 animate-pulse text-orange"
/>
<StyledInput
<Input
id="project-wiki-page"
v-model="wikiUrl"
type="url"
@@ -229,7 +229,7 @@
v-tooltip="`You're using a link which isn't common for this link type.`"
class="size-6 animate-pulse text-orange"
/>
<StyledInput
<Input
id="project-discord-invite"
v-model="discordUrl"
type="url"
@@ -250,7 +250,7 @@
:key="`donation-link-${index}`"
class="input-group donation-link-group"
>
<StyledInput
<Input
v-model="donationLink.url"
type="url"
:maxlength="2048"
@@ -292,7 +292,7 @@ import {
injectModrinthClient,
injectNotificationManager,
injectProjectPageContext,
StyledInput,
Input,
} from '@modrinth/ui'
const tags = useGeneratedState()
@@ -33,7 +33,7 @@
</span>
</span>
<div class="input-group">
<StyledInput
<Input
id="username"
v-model="currentUsername"
placeholder="Username"
@@ -112,7 +112,7 @@
The title of the role that this member plays for this project.
</span>
</label>
<StyledInput
<Input
:id="`member-${allTeamMembers[index].user.username}-role`"
v-model="allTeamMembers[index].role"
:disabled="(currentMember?.permissions & EDIT_MEMBER) !== EDIT_MEMBER"
@@ -126,7 +126,7 @@
this project's revenue goes to this member.
</span>
</label>
<StyledInput
<Input
:id="`member-${allTeamMembers[index].user.username}-monetization-weight`"
v-model="allTeamMembers[index].payouts_split"
type="number"
@@ -378,7 +378,7 @@
The title of the role that this member plays for this project.
</span>
</label>
<StyledInput
<Input
:id="`member-${allOrgMembers[index].user.username}-role`"
v-model="allOrgMembers[index].role"
:disabled="
@@ -395,7 +395,7 @@
this project's revenue goes to this member.
</span>
</label>
<StyledInput
<Input
:id="`member-${allOrgMembers[index].user.username}-monetization-weight`"
v-model="allOrgMembers[index].payouts_split"
type="number"
@@ -568,7 +568,7 @@ import {
injectModrinthClient,
injectNotificationManager,
injectProjectPageContext,
StyledInput,
Input,
Toggle,
} from '@modrinth/ui'
import { useQuery } from '@tanstack/vue-query'
@@ -29,8 +29,8 @@ import {
injectModrinthClient,
injectNotificationManager,
injectProjectPageContext,
Input,
IntlFormatted,
StyledInput,
useVIntl,
} from '@modrinth/ui'
import { isStaff } from '@modrinth/utils'
@@ -563,7 +563,7 @@ function dismissInfoBanner() {
</template>
<div class="flex flex-col gap-2">
<div class="grid grid-cols-1 gap-2 sm:grid-cols-[minmax(0,1fr)_auto_auto_auto]">
<StyledInput
<Input
v-model="searchQuery"
type="text"
autocomplete="off"
@@ -62,7 +62,7 @@
}
"
>
<StyledInput
<Input
id="java-address"
v-model="javaAddress"
:placeholder="formatMessage(messages.enterAddressPlaceholder)"
@@ -142,7 +142,7 @@
</span>
</label>
<div class="mt-2 flex items-center gap-2">
<StyledInput
<Input
id="bedrock-address"
v-model="bedrockAddress"
:placeholder="formatMessage(messages.enterAddressPlaceholder)"
@@ -177,12 +177,12 @@ import {
injectModrinthClient,
injectNotificationManager,
injectProjectPageContext,
Input,
IntlFormatted,
MultiSelect,
normalizeChildren,
SERVER_LANGUAGES,
SERVER_REGIONS,
StyledInput,
UnsavedChangesPopup,
usePageLeaveSafety,
useVIntl,
+2 -2
View File
@@ -19,7 +19,7 @@
>
<h1 class="m-0 grow text-2xl font-extrabold">Manage affiliate links</h1>
<div class="flex items-center gap-2">
<StyledInput
<Input
v-model="filterQuery"
:icon="SearchIcon"
type="text"
@@ -94,7 +94,7 @@ import {
ConfirmModal,
injectModrinthClient,
injectNotificationManager,
StyledInput,
Input,
} from '@modrinth/ui'
import type { User } from '@modrinth/utils'
import { useQuery } from '@tanstack/vue-query'
@@ -18,7 +18,7 @@
<div class="flex flex-col gap-5" @submit.prevent="saveEvent">
<div class="flex flex-col gap-2">
<span class="label__title font-semibold">Title</span>
<StyledInput
<Input
id="analytics-event-title"
ref="titleInput"
v-model="form.title"
@@ -48,7 +48,7 @@
</ButtonStyled>
</div>
<div class="flex items-center gap-2">
<StyledInput
<Input
id="analytics-event-link"
v-model="form.announcementUrl"
type="url"
@@ -129,7 +129,7 @@
<h1 class="m-0 text-2xl font-extrabold text-contrast">Analytics Events</h1>
<div class="flex flex-col gap-2 sm:flex-row sm:items-center">
<StyledInput
<Input
v-model="searchQuery"
:icon="SearchIcon"
type="search"
@@ -245,11 +245,11 @@ import {
DatePicker,
injectModrinthClient,
injectNotificationManager,
Input,
MultiSelect,
type MultiSelectOption,
NewModal,
type SortDirection,
StyledInput,
Table,
type TableColumn,
} from '@modrinth/ui'
@@ -319,7 +319,7 @@ const allMetricKinds = metricKindOptions.map((option) => option.value)
const deleteEventModal = ref<InstanceType<typeof ConfirmModal> | null>(null)
const eventModal = ref<InstanceType<typeof NewModal> | null>(null)
const titleInput = ref<InstanceType<typeof StyledInput> | null>(null)
const titleInput = ref<InstanceType<typeof Input> | null>(null)
const searchQuery = ref('')
const sortColumn = ref<EventColumnKey | undefined>('date')
const sortDirection = ref<SortDirection>('desc')
@@ -485,9 +485,9 @@ async function saveEvent() {
const payload = buildEventPayload()
if (modalMode.value === 'edit' && editingEventId.value !== null) {
await client.labrinth.analytics_v3.editEvent(editingEventId.value, payload)
await client.labrinth.analytics_internal.editEvent(editingEventId.value, payload)
} else {
await client.labrinth.analytics_v3.createEvent(payload)
await client.labrinth.analytics_internal.createEvent(payload)
}
await queryClient.invalidateQueries({ queryKey: analyticsEventsQueryKey })
@@ -528,7 +528,7 @@ async function deleteEvent(eventId: Labrinth.Analytics.v3.AnalyticsEventId) {
setDeletingEvent(eventId, true)
try {
await client.labrinth.analytics_v3.deleteEvent(eventId)
await client.labrinth.analytics_internal.deleteEvent(eventId)
await queryClient.invalidateQueries({ queryKey: analyticsEventsQueryKey })
addNotification({
title: 'Analytics event deleted',
@@ -581,7 +581,7 @@ function commitAnnouncementUrl() {
committedAnnouncementUrl.value = form.value.announcementUrl
}
function buildEventPayload(): Labrinth.Analytics.v3.AnalyticsEventUpsert {
function buildEventPayload(): Labrinth.Analytics.Internal.AnalyticsEventUpsert {
const selectedRange = getEventFormDateRange()
if (!selectedRange) {
throw new Error('Select a valid start and end date')
@@ -30,7 +30,7 @@
{{ selectedCharge.net }})
</span>
</label>
<StyledInput id="amount" v-model="refundAmount" type="number" autocomplete="off" />
<Input 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>
<StyledInput id="days" v-model="creditDays" type="number" :min="1" autocomplete="off" />
<Input 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">
@@ -232,8 +232,8 @@ import {
DropdownSelect,
injectModrinthClient,
injectNotificationManager,
Input,
NewModal,
StyledInput,
Toggle,
useFormatDateTime,
useRelativeTime,
+2 -2
View File
@@ -1,6 +1,6 @@
<script setup lang="ts">
import { CopyIcon, LibraryIcon, PlayIcon, SearchIcon } from '@modrinth/assets'
import { ButtonStyled, Card, StyledInput } from '@modrinth/ui'
import { ButtonStyled, Card, Input } from '@modrinth/ui'
import { computed, onMounted, ref } from 'vue'
import docs from '~/templates/docs'
@@ -51,7 +51,7 @@ onMounted(() => {
<div class="normal-page__content">
<Card class="mb-6 flex flex-col gap-4">
<div class="flex flex-wrap items-center gap-3">
<StyledInput
<Input
id="doc-search"
v-model="query"
type="search"
+3 -3
View File
@@ -1,6 +1,6 @@
<script setup lang="ts">
import { CopyIcon, LibraryIcon, PlayIcon, SearchIcon } from '@modrinth/assets'
import { ButtonStyled, NewModal, StyledInput } from '@modrinth/ui'
import { ButtonStyled, Input, NewModal } from '@modrinth/ui'
import { computed, onMounted, ref } from 'vue'
import emails from '~/templates/emails'
@@ -153,7 +153,7 @@ onMounted(() => {
class="flex flex-col"
>
<span class="label__title">{{ variable }}</span>
<StyledInput
<Input
:id="`preview-${variable}`"
v-model="variableValues[variable]"
type="text"
@@ -191,7 +191,7 @@ onMounted(() => {
</NewModal>
<div class="normal-page__content">
<div class="flex flex-wrap items-center gap-3">
<StyledInput
<Input
id="email-search"
v-model="query"
type="search"
@@ -24,7 +24,7 @@
<label for="notice-title" class="flex flex-col gap-1">
<span class="text-lg font-semibold text-contrast"> Title </span>
</label>
<StyledInput
<Input
id="notice-title"
v-model="newNoticeTitle"
placeholder="E.g. Maintenance"
@@ -38,20 +38,14 @@
<span class="text-brand-red">*</span>
</span>
</label>
<StyledInput
<Input
v-if="newNoticeSurvey"
id="notice-message"
v-model="newNoticeMessage"
placeholder="E.g. rXGtq2"
autocomplete="off"
/>
<StyledInput
v-else
id="notice-message"
v-model="newNoticeMessage"
multiline
wrapper-class="h-32"
/>
<Textarea v-else id="notice-message" v-model="newNoticeMessage" 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">
@@ -65,7 +59,7 @@
<span class="text-lg font-semibold text-contrast"> Announcement date </span>
<span>Leave blank for notice to be available immediately.</span>
</label>
<StyledInput
<DateInput
id="scheduled-date"
v-model="newNoticeScheduledDate"
type="datetime-local"
@@ -77,7 +71,7 @@
<span class="text-lg font-semibold text-contrast"> Expiration date </span>
<span>The notice will automatically be deleted after this date.</span>
</label>
<StyledInput
<DateInput
id="expiration-date"
v-model="newNoticeExpiresDate"
type="datetime-local"
@@ -267,13 +261,15 @@ import {
Combobox,
commonMessages,
CopyCode,
DateInput,
defineMessages,
injectModrinthClient,
injectNotificationManager,
Input,
NewModal,
ServerNotice,
StyledInput,
TagItem,
Textarea,
Toggle,
useFormatDateTime,
useRelativeTime,

Some files were not shown because too many files have changed in this diff Show More