Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions app/components/Code/DirectoryListing.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
import type { PackageFileTree } from '#shared/types'
import type { RouteLocationRaw } from 'vue-router'
import { getFileIcon } from '~/utils/file-icons'
import { formatBytes } from '~/utils/formatters'

const props = defineProps<{
tree: PackageFileTree[]
Expand Down Expand Up @@ -51,6 +50,8 @@ function getCodeRoute(nodePath?: string): RouteLocationRaw {
params: { path: pathSegments as [string, ...string[]] },
}
}

const bytesFormatter = useBytesFormatter()
</script>

<template>
Expand Down Expand Up @@ -107,7 +108,7 @@ function getCodeRoute(nodePath?: string): RouteLocationRaw {
v-if="node.type === 'file' && node.size"
class="text-end font-mono text-xs text-fg-subtle"
>
{{ formatBytes(node.size) }}
{{ bytesFormatter.format(node.size) }}
</span>
</NuxtLink>
</td>
Expand Down
6 changes: 4 additions & 2 deletions app/components/Compare/PackageSelector.vue
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ const filteredResults = computed(() => {
.filter(r => !packages.value.includes(r.name))
})

const numberFormatter = useNumberFormatter()

function addPackage(name: string) {
if (packages.value.length >= maxPackages.value) return
if (packages.value.includes(name)) return
Expand Down Expand Up @@ -209,8 +211,8 @@ function handleBlur() {
<p class="text-xs text-fg-subtle">
{{
$t('compare.selector.packages_selected', {
count: packages.length,
max: maxPackages,
count: numberFormatter.format(packages.length),
max: numberFormatter.format(maxPackages),
})
}}
<span v-if="packages.length < 2">{{ $t('compare.selector.add_hint') }}</span>
Expand Down
4 changes: 3 additions & 1 deletion app/components/Package/Card.vue
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ const pkgDescription = useMarkdown(() => ({
plain: true,
packageName: props.result.package.name,
}))

const numberFormatter = useNumberFormatter()
</script>

<template>
Expand Down Expand Up @@ -180,7 +182,7 @@ const pkgDescription = useMarkdown(() => ({
class="text-fg-subtle text-xs pointer-events-auto"
:title="result.package.keywords.slice(5).join(', ')"
>
+{{ result.package.keywords.length - 5 }}
+{{ numberFormatter.format(result.package.keywords.length - 5) }}
</span>
</div>
</BaseCard>
Expand Down
54 changes: 40 additions & 14 deletions app/components/Package/Dependencies.vue
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ const sortedOptionalDependencies = computed(() => {
if (!props.optionalDependencies) return []
return Object.entries(props.optionalDependencies).sort(([a], [b]) => a.localeCompare(b))
})

const numberFormatter = useNumberFormatter()
</script>

<template>
Expand All @@ -73,7 +75,15 @@ const sortedOptionalDependencies = computed(() => {
<CollapsibleSection
v-if="sortedDependencies.length > 0"
id="dependencies"
:title="$t('package.dependencies.title', { count: sortedDependencies.length })"
:title="
$t(
'package.dependencies.title',
{
count: numberFormatter.format(sortedDependencies.length),
},
sortedDependencies.length,
)
"
>
<ul class="space-y-1 list-none m-0" :aria-label="$t('package.dependencies.list_label')">
<li
Expand Down Expand Up @@ -137,9 +147,13 @@ const sortedOptionalDependencies = computed(() => {
@click="depsExpanded = true"
>
{{
$t('package.dependencies.show_all', {
count: sortedDependencies.length,
})
$t(
'package.dependencies.show_all',
{
count: numberFormatter.format(sortedDependencies.length),
},
sortedDependencies.length,
)
}}
</button>
</CollapsibleSection>
Expand All @@ -150,7 +164,7 @@ const sortedOptionalDependencies = computed(() => {
id="peer-dependencies"
:title="
$t('package.peer_dependencies.title', {
count: sortedPeerDependencies.length,
count: numberFormatter.format(sortedPeerDependencies.length),
})
"
>
Expand Down Expand Up @@ -185,9 +199,13 @@ const sortedOptionalDependencies = computed(() => {
@click="peerDepsExpanded = true"
>
{{
$t('package.peer_dependencies.show_all', {
count: sortedPeerDependencies.length,
})
$t(
'package.peer_dependencies.show_all',
{
count: numberFormatter.format(sortedPeerDependencies.length),
},
sortedPeerDependencies.length,
)
}}
</button>
</CollapsibleSection>
Expand All @@ -197,9 +215,13 @@ const sortedOptionalDependencies = computed(() => {
v-if="sortedOptionalDependencies.length > 0"
id="optional-dependencies"
:title="
$t('package.optional_dependencies.title', {
count: sortedOptionalDependencies.length,
})
$t(
'package.optional_dependencies.title',
{
count: numberFormatter.format(sortedOptionalDependencies.length),
},
sortedOptionalDependencies.length,
)
"
>
<ul
Expand Down Expand Up @@ -229,9 +251,13 @@ const sortedOptionalDependencies = computed(() => {
@click="optionalDepsExpanded = true"
>
{{
$t('package.optional_dependencies.show_all', {
count: sortedOptionalDependencies.length,
})
$t(
'package.optional_dependencies.show_all',
{
count: numberFormatter.format(sortedOptionalDependencies.length),
},
sortedOptionalDependencies.length,
)
}}
</button>
</CollapsibleSection>
Expand Down
8 changes: 4 additions & 4 deletions app/components/Package/DownloadAnalytics.vue
Original file line number Diff line number Diff line change
Expand Up @@ -750,8 +750,6 @@ const chartData = computed<{ dataset: VueUiXyDatasetItem[] | null; dates: number
return { dataset, dates }
})

const formatter = ({ value }: { value: number }) => formatCompactNumber(value, { decimals: 1 })

const loadFile = (link: string, filename: string) => {
const a = document.createElement('a')
a.href = link
Expand Down Expand Up @@ -800,6 +798,8 @@ function getGranularityLabel(granularity: ChartTimeGranularity) {
return granularityLabels.value[granularity]
}

const compactNumberFormatter = useCompactNumberFormatter()

// VueUiXy chart component configuration
const chartConfig = computed(() => {
return {
Expand Down Expand Up @@ -867,7 +867,7 @@ const chartConfig = computed(() => {
},
},
yAxis: {
formatter,
formatter: compactNumberFormatter.value.format,
useNiceScale: true,
gap: 24, // vertical gap between individual series in stacked mode
},
Expand Down Expand Up @@ -899,7 +899,7 @@ const chartConfig = computed(() => {
.map((d: any) => {
const label = String(d?.name ?? '').trim()
const raw = Number(d?.value ?? 0)
const v = formatter({ value: Number.isFinite(raw) ? raw : 0 })
const v = compactNumberFormatter.value.format(Number.isFinite(raw) ? raw : 0)

if (!hasMultipleItems) {
// We don't need the name of the package in this case, since it is shown in the xAxis label
Expand Down
24 changes: 21 additions & 3 deletions app/components/Settings/TranslationHelper.vue
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ const contributionGuideUrl =
// Copy missing keys as JSON template to clipboard
const { copy, copied } = useClipboard()

const numberFormatter = useNumberFormatter()
const percentageFormatter = useNumberFormatter({ style: 'percent' })

function copyMissingKeysTemplate() {
// Create a template showing what needs to be added
const template = props.status.missingKeys.map(key => ` "${key}": ""`).join(',\n')
Expand All @@ -49,7 +52,10 @@ ${template}`
<div class="flex items-center justify-between text-xs text-fg-muted">
<span>{{ $t('settings.translation_progress') }}</span>
<span class="tabular-nums"
>{{ status.completedKeys }}/{{ status.totalKeys }} ({{ status.percentComplete }}%)</span
>{{ numberFormatter.format(status.completedKeys) }}/{{
numberFormatter.format(status.totalKeys)
}}
({{ percentageFormatter.format(status.percentComplete / 100) }})</span
>
</div>
<div class="h-1.5 bg-bg rounded-full overflow-hidden">
Expand All @@ -64,7 +70,13 @@ ${template}`
<div v-if="status.missingKeys.length > 0" class="space-y-2">
<div class="flex items-center justify-between">
<h4 class="text-xs text-fg-muted font-medium">
{{ $t('i18n.missing_keys', { count: status.missingKeys.length }) }}
{{
$t(
'i18n.missing_keys',
{ count: numberFormatter.format(status.missingKeys.length) },
status.missingKeys.length,
)
}}
</h4>
<button
type="button"
Expand All @@ -87,7 +99,13 @@ ${template}`
class="text-xs text-fg-muted hover:text-fg rounded focus-visible:outline-accent/70"
@click="showAll = true"
>
{{ $t('i18n.show_more_keys', { count: remainingCount }) }}
{{
$t(
'i18n.show_more_keys',
{ count: numberFormatter.format(remainingCount) },
remainingCount,
)
}}
</button>
</div>

Expand Down
35 changes: 35 additions & 0 deletions app/composables/useNumberFormatter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
export function useNumberFormatter(options?: Intl.NumberFormatOptions) {
const { locale } = useI18n()

return computed(() => new Intl.NumberFormat(locale.value, options))
}

export const useCompactNumberFormatter = () =>
useNumberFormatter({
notation: 'compact',
compactDisplay: 'short',
maximumFractionDigits: 1,
})

export const useBytesFormatter = () => {
const { t } = useI18n()
const decimalNumberFormatter = useNumberFormatter({
maximumFractionDigits: 1,
})

return {
format: (bytes: number) => {
if (bytes < 1024)
return t('package.size.b', {
size: decimalNumberFormatter.value.format(bytes),
})
if (bytes < 1024 * 1024)
return t('package.size.kb', {
size: decimalNumberFormatter.value.format(bytes / 1024),
})
return t('package.size.mb', {
size: decimalNumberFormatter.value.format(bytes / (1024 * 1024)),
})
},
}
}
20 changes: 16 additions & 4 deletions app/composables/usePackageComparison.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import type { PackageLikes } from '#shared/types/social'
import { encodePackageName } from '#shared/utils/npm'
import type { PackageAnalysisResponse } from './usePackageAnalysis'
import { isBinaryOnlyPackage } from '#shared/utils/binary-detection'
import { formatBytes } from '~/utils/formatters'
import { getDependencyCount } from '~/utils/npm/dependency-count'

/** Special identifier for the "What Would James Do?" comparison column */
Expand Down Expand Up @@ -71,6 +70,9 @@ export interface PackageComparisonData {
*/
export function usePackageComparison(packageNames: MaybeRefOrGetter<string[]>) {
const { t } = useI18n()
const numberFormatter = useNumberFormatter()
const compactNumberFormatter = useCompactNumberFormatter()
const bytesFormatter = useBytesFormatter()
const packages = computed(() => toValue(packageNames))

// Cache of fetched data by package name (source of truth)
Expand Down Expand Up @@ -260,7 +262,14 @@ export function usePackageComparison(packageNames: MaybeRefOrGetter<string[]>) {

return packagesData.value.map(pkg => {
if (!pkg) return null
return computeFacetValue(facet, pkg, t)
return computeFacetValue(
facet,
pkg,
numberFormatter.value.format,
compactNumberFormatter.value.format,
bytesFormatter.format,
t,
)
})
}

Expand Down Expand Up @@ -342,6 +351,9 @@ function resolveNoDependencyDisplay(
function computeFacetValue(
facet: ComparisonFacet,
data: PackageComparisonData,
formatNumber: (num: number) => string,
formatCompactNumber: (num: number) => string,
formatBytes: (num: number) => string,
t: (key: string, params?: Record<string, unknown>) => string,
): FacetValue | null {
const { isNoDependency } = data
Expand Down Expand Up @@ -513,7 +525,7 @@ function computeFacetValue(
if (depCount == null) return null
return {
raw: depCount,
display: String(depCount),
display: formatNumber(depCount),
status: depCount > 10 ? 'warning' : 'neutral',
}
}
Expand All @@ -532,7 +544,7 @@ function computeFacetValue(
const totalDepCount = data.installSize.dependencyCount
return {
raw: totalDepCount,
display: String(totalDepCount),
display: formatNumber(totalDepCount),
status: totalDepCount > 50 ? 'warning' : 'neutral',
}
}
Expand Down
9 changes: 6 additions & 3 deletions app/pages/package-code/[...path].vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import type {
PackageFileTreeResponse,
PackageFileContentResponse,
} from '#shared/types'
import { formatBytes } from '~/utils/formatters'

definePageMeta({
name: 'code',
Expand Down Expand Up @@ -269,6 +268,8 @@ const markdownViewModes = [

const markdownViewMode = shallowRef<(typeof markdownViewModes)[number]['key']>('preview')

const bytesFormatter = useBytesFormatter()

useHead({
link: [{ rel: 'canonical', href: canonicalUrl }],
})
Expand Down Expand Up @@ -443,7 +444,7 @@ defineOgImageComponent('Default', {
$t('code.lines', { count: fileContent.lines })
}}</span>
<span v-if="currentNode?.size" class="text-fg-subtle">{{
formatBytes(currentNode.size)
bytesFormatter.format(currentNode.size)
}}</span>
</div>
</div>
Expand Down Expand Up @@ -489,7 +490,9 @@ defineOgImageComponent('Default', {
<div class="i-carbon:document w-12 h-12 mx-auto text-fg-subtle mb-4" />
<p class="text-fg-muted mb-2">{{ $t('code.file_too_large') }}</p>
<p class="text-fg-subtle text-sm mb-4">
{{ $t('code.file_size_warning', { size: formatBytes(currentNode?.size ?? 0) }) }}
{{
$t('code.file_size_warning', { size: bytesFormatter.format(currentNode?.size ?? 0) })
}}
</p>
<LinkBase
variant="button-secondary"
Expand Down
Loading
Loading