fix: description nag
This commit is contained in:
parent
dc258de3c2
commit
ad1fed91cf
@ -43,7 +43,7 @@
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { SaveIcon, TriangleAlertIcon } from "@modrinth/assets";
|
import { SaveIcon, TriangleAlertIcon } from "@modrinth/assets";
|
||||||
import { MIN_DESCRIPTION_CHARS } from "@modrinth/moderation";
|
import { countText, MIN_DESCRIPTION_CHARS } from "@modrinth/moderation";
|
||||||
import { MarkdownEditor } from "@modrinth/ui";
|
import { MarkdownEditor } from "@modrinth/ui";
|
||||||
import { type Project, type TeamMember, TeamMemberPermission } from "@modrinth/utils";
|
import { type Project, type TeamMember, TeamMemberPermission } from "@modrinth/utils";
|
||||||
import { computed, ref } from "vue";
|
import { computed, ref } from "vue";
|
||||||
@ -60,10 +60,10 @@ const description = ref(props.project.body);
|
|||||||
|
|
||||||
const descriptionWarning = computed(() => {
|
const descriptionWarning = computed(() => {
|
||||||
const text = description.value?.trim() || "";
|
const text = description.value?.trim() || "";
|
||||||
const charCount = text.length;
|
const charCount = countText(text);
|
||||||
|
|
||||||
if (charCount < MIN_DESCRIPTION_CHARS) {
|
if (charCount < MIN_DESCRIPTION_CHARS) {
|
||||||
return `It's recommended to have a description with at least ${MIN_DESCRIPTION_CHARS} characters. (${charCount}/${MIN_DESCRIPTION_CHARS})`;
|
return `It's recommended to have a description with at least ${MIN_DESCRIPTION_CHARS} readable characters. (${charCount}/${MIN_DESCRIPTION_CHARS})`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { renderHighlightedString } from '@modrinth/utils'
|
||||||
import type { Nag, NagContext } from '../../types/nags'
|
import type { Nag, NagContext } from '../../types/nags'
|
||||||
import { useVIntl, defineMessage } from '@vintl/vintl'
|
import { useVIntl, defineMessage } from '@vintl/vintl'
|
||||||
|
|
||||||
@ -5,7 +6,10 @@ export const MIN_DESCRIPTION_CHARS = 500
|
|||||||
export const MAX_HEADER_LENGTH = 100
|
export const MAX_HEADER_LENGTH = 100
|
||||||
export const MIN_SUMMARY_CHARS = 35
|
export const MIN_SUMMARY_CHARS = 35
|
||||||
|
|
||||||
function analyzeHeaderLength(markdown: string): { hasLongHeaders: boolean; longHeaders: string[] } {
|
export function analyzeHeaderLength(markdown: string): {
|
||||||
|
hasLongHeaders: boolean
|
||||||
|
longHeaders: string[]
|
||||||
|
} {
|
||||||
if (!markdown) return { hasLongHeaders: false, longHeaders: [] }
|
if (!markdown) return { hasLongHeaders: false, longHeaders: [] }
|
||||||
|
|
||||||
const withoutCodeBlocks = markdown.replace(/```[\s\S]*?```/g, '').replace(/`[^`]*`/g, '')
|
const withoutCodeBlocks = markdown.replace(/```[\s\S]*?```/g, '').replace(/`[^`]*`/g, '')
|
||||||
@ -35,7 +39,10 @@ function analyzeHeaderLength(markdown: string): { hasLongHeaders: boolean; longH
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function analyzeImageContent(markdown: string): { imageHeavy: boolean; hasEmptyAltText: boolean } {
|
export function analyzeImageContent(markdown: string): {
|
||||||
|
imageHeavy: boolean
|
||||||
|
hasEmptyAltText: boolean
|
||||||
|
} {
|
||||||
if (!markdown) return { imageHeavy: false, hasEmptyAltText: false }
|
if (!markdown) return { imageHeavy: false, hasEmptyAltText: false }
|
||||||
|
|
||||||
const withoutCodeBlocks = markdown.replace(/```[\s\S]*?```/g, '').replace(/`[^`]*`/g, '')
|
const withoutCodeBlocks = markdown.replace(/```[\s\S]*?```/g, '').replace(/`[^`]*`/g, '')
|
||||||
@ -68,6 +75,25 @@ function analyzeImageContent(markdown: string): { imageHeavy: boolean; hasEmptyA
|
|||||||
return { imageHeavy, hasEmptyAltText }
|
return { imageHeavy, hasEmptyAltText }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function countText(markdown: string): number {
|
||||||
|
const htmlString = renderHighlightedString(markdown)
|
||||||
|
const parser = new DOMParser()
|
||||||
|
const doc = parser.parseFromString(htmlString, 'text/html')
|
||||||
|
const walker = document.createTreeWalker(doc, NodeFilter.SHOW_TEXT)
|
||||||
|
|
||||||
|
const textList: string[] = []
|
||||||
|
let currentNode: Node | null = walker.currentNode
|
||||||
|
|
||||||
|
while (currentNode) {
|
||||||
|
if (currentNode.textContent !== null) {
|
||||||
|
textList.push(currentNode.textContent)
|
||||||
|
}
|
||||||
|
currentNode = walker.nextNode()
|
||||||
|
}
|
||||||
|
|
||||||
|
return textList.join(' ').trim().length
|
||||||
|
}
|
||||||
|
|
||||||
export const descriptionNags: Nag[] = [
|
export const descriptionNags: Nag[] = [
|
||||||
{
|
{
|
||||||
id: 'description-too-short',
|
id: 'description-too-short',
|
||||||
@ -77,23 +103,24 @@ export const descriptionNags: Nag[] = [
|
|||||||
}),
|
}),
|
||||||
description: (context: NagContext) => {
|
description: (context: NagContext) => {
|
||||||
const { formatMessage } = useVIntl()
|
const { formatMessage } = useVIntl()
|
||||||
|
const readableLength = countText(context.project.body || '')
|
||||||
|
|
||||||
return formatMessage(
|
return formatMessage(
|
||||||
defineMessage({
|
defineMessage({
|
||||||
id: 'nags.description-too-short.description',
|
id: 'nags.description-too-short.description',
|
||||||
defaultMessage:
|
defaultMessage:
|
||||||
"Your description is {length} characters. It's recommended to have at least {minChars} characters to provide users with enough information about your project.",
|
"Your description is {length} readable characters. It's recommended to have at least {minChars} readable characters to provide users with enough information about your project.",
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
length: context.project.body?.length || 0,
|
length: readableLength,
|
||||||
minChars: MIN_DESCRIPTION_CHARS,
|
minChars: MIN_DESCRIPTION_CHARS,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
status: 'warning',
|
status: 'warning',
|
||||||
shouldShow: (context: NagContext) => {
|
shouldShow: (context: NagContext) => {
|
||||||
const bodyLength = context.project.body?.trim()?.length || 0
|
const readableLength = countText(context.project.body || '')
|
||||||
return bodyLength < MIN_DESCRIPTION_CHARS && bodyLength !== 0
|
return readableLength < MIN_DESCRIPTION_CHARS && readableLength > 0
|
||||||
},
|
},
|
||||||
link: {
|
link: {
|
||||||
path: 'settings/description',
|
path: 'settings/description',
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user