From 6d974808020875a8f2ed2e94ea2f6f5e508f864c Mon Sep 17 00:00:00 2001 From: tdgao Date: Mon, 12 Oct 2026 12:54:43 -0600 Subject: [PATCH 1/2] feat: update slug suggestions --- .../composables/project-slug-suggestions.ts | 22 +++++++++---------- packages/moderation/src/utils.ts | 11 ++++++++++ 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/apps/frontend/src/composables/project-slug-suggestions.ts b/apps/frontend/src/composables/project-slug-suggestions.ts index 4c0476864a0..0ae16150866 100644 --- a/apps/frontend/src/composables/project-slug-suggestions.ts +++ b/apps/frontend/src/composables/project-slug-suggestions.ts @@ -1,12 +1,12 @@ import { ModrinthApiError } from '@modrinth/api-client' +import { generateUrlSlug } from '@modrinth/moderation/src/utils' import { injectModrinthClient } from '@modrinth/ui' import { useQueryClient } from '@tanstack/vue-query' import { type MaybeRefOrGetter, onScopeDispose, ref, toValue, watch } from 'vue' const STALE_TIME = 1000 * 60 * 5 const CHECK_DEBOUNCE = 300 -const PROJECT_SLUG_UNSAFE_CHARS = /[^a-zA-Z0-9._-]/g -const PROJECT_SLUG_REGEX = /^[a-zA-Z0-9._-]{3,64}$/ +const PROJECT_SLUG_REGEX = /^[a-z0-9._-]{3,64}$/ interface ProjectSlugSuggestionOptions { title: MaybeRefOrGetter @@ -15,17 +15,15 @@ interface ProjectSlugSuggestionOptions { enabled?: MaybeRefOrGetter } -export function generateUrlSlug(value: string) { - return value - .trim() - .toLowerCase() - .replaceAll(' ', '-') - .replaceAll(PROJECT_SLUG_UNSAFE_CHARS, '') - .replaceAll(/--+/gm, '-') -} +export { generateUrlSlug } function isValidProjectSlug(value: string) { - return PROJECT_SLUG_REGEX.test(value) + return ( + PROJECT_SLUG_REGEX.test(value) && + !value.startsWith('-') && + !value.endsWith('-') && + !value.includes('--') + ) } function generateProjectSlugSuggestions(title: string, username?: string | null) { @@ -40,7 +38,7 @@ function generateProjectSlugSuggestions(title: string, username?: string | null) const usernameSlug = username ? generateUrlSlug(username) : '' let withUsername = '' - if (titleSlug && usernameSlug) { + if (titleSlug && usernameSlug && usernameSlug.length <= 62) { const availableTitleLength = 64 - usernameSlug.length - 1 const truncatedTitle = titleSlug.slice(0, availableTitleLength).replace(/-+$/, '') if (truncatedTitle) withUsername = `${truncatedTitle}-${usernameSlug}` diff --git a/packages/moderation/src/utils.ts b/packages/moderation/src/utils.ts index b556685b429..25316e2eef5 100644 --- a/packages/moderation/src/utils.ts +++ b/packages/moderation/src/utils.ts @@ -1,5 +1,16 @@ import type { Labrinth } from '@modrinth/api-client' +export function generateUrlSlug(value: string) { + return value + .trim() + .toLowerCase() + .replaceAll('+', '-plus') + .replaceAll(/[!"'`]/g, '') + .replaceAll(/[^a-z0-9._-]+/g, '-') + .replaceAll(/-+/g, '-') + .replaceAll(/^-+|-+$/g, '') +} + export function expandVariables( template: string, project: Labrinth.Projects.v2.Project, From 43eb996702e864c6e7412e646a1ed1ff0dedf290 Mon Sep 17 00:00:00 2001 From: tdgao Date: Mon, 12 Oct 2026 12:57:23 -0600 Subject: [PATCH 2/2] refactor: remove from moderation pacakge --- .../src/composables/project-slug-suggestions.ts | 12 ++++++++++-- packages/moderation/src/utils.ts | 11 ----------- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/apps/frontend/src/composables/project-slug-suggestions.ts b/apps/frontend/src/composables/project-slug-suggestions.ts index 0ae16150866..519dbb24800 100644 --- a/apps/frontend/src/composables/project-slug-suggestions.ts +++ b/apps/frontend/src/composables/project-slug-suggestions.ts @@ -1,5 +1,4 @@ import { ModrinthApiError } from '@modrinth/api-client' -import { generateUrlSlug } from '@modrinth/moderation/src/utils' import { injectModrinthClient } from '@modrinth/ui' import { useQueryClient } from '@tanstack/vue-query' import { type MaybeRefOrGetter, onScopeDispose, ref, toValue, watch } from 'vue' @@ -15,7 +14,16 @@ interface ProjectSlugSuggestionOptions { enabled?: MaybeRefOrGetter } -export { generateUrlSlug } +export function generateUrlSlug(value: string) { + return value + .trim() + .toLowerCase() + .replaceAll('+', '-plus') + .replaceAll(/[!"'`]/g, '') + .replaceAll(/[^a-z0-9._-]+/g, '-') + .replaceAll(/-+/g, '-') + .replaceAll(/^-+|-+$/g, '') +} function isValidProjectSlug(value: string) { return ( diff --git a/packages/moderation/src/utils.ts b/packages/moderation/src/utils.ts index 25316e2eef5..b556685b429 100644 --- a/packages/moderation/src/utils.ts +++ b/packages/moderation/src/utils.ts @@ -1,16 +1,5 @@ import type { Labrinth } from '@modrinth/api-client' -export function generateUrlSlug(value: string) { - return value - .trim() - .toLowerCase() - .replaceAll('+', '-plus') - .replaceAll(/[!"'`]/g, '') - .replaceAll(/[^a-z0-9._-]+/g, '-') - .replaceAll(/-+/g, '-') - .replaceAll(/^-+|-+$/g, '') -} - export function expandVariables( template: string, project: Labrinth.Projects.v2.Project,