Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
7b354ed
fix(i18n): update Russian translations (#3330)
dragomano Oct 18, 2026
df45d36
fix(i18n): add missing translations and fix some existing for ua-UK l…
maxdzin Oct 18, 2026
32b115e
chore(ui): add stories for Sponsors page (#3312)
IestynGage Oct 18, 2026
cc5cc82
fix: add spacing to changelog loading skeleton (#3328)
iiio2 Oct 18, 2026
cd19533
feat(ui): add upm package manager support (#3296)
2u841r Oct 18, 2026
33f2ed7
chore: update storybook and @storybook-vue/nuxt (#3300)
huang-julien Oct 18, 2026
dc0319f
fix: clarify trust downgrade for trusted pub w/o provenance (#3285)
danielroe Oct 18, 2026
bb06de4
feat: add downloads heatmap chart in stats page (#3324)
graphieros Oct 18, 2026
af56812
perf: fetch abbreviated packument wherever possible (#3318)
serhalp Oct 18, 2026
943f069
fix: allow relative paths in fetch cache allow list check (#3325)
serhalp Oct 18, 2026
debc1d0
chore(deps): update vite+ (#3338)
renovate[bot] Oct 19, 2026
2074c81
chore(deps): update dependency @nuxt/fonts to v1 (#3339)
renovate[bot] Oct 19, 2026
66a92c4
fix: preserve download chart gaps when data is interpolated and high…
graphieros Oct 21, 2026
7ae4670
chore(i18n): add empty translation keys generated by i18n:check (#3349)
cylewaitforit Oct 23, 2026
f43a253
chore(deps): update devdependency markdown-it-anchor to v10 (#3229)
renovate[bot] Oct 23, 2026
bc37274
chore(deps): enable pnpm strictPeerDependencies (#3344)
cylewaitforit Oct 23, 2026
c5c237e
feat: show staged publishing status (#3115)
BittuBarnwal7479 Oct 23, 2026
3472596
chore(deps): update devdependency knip to v6.42.1 (#3345)
cylewaitforit Oct 23, 2026
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
111 changes: 0 additions & 111 deletions .storybook/main.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import type { StorybookConfig } from '@storybook-vue/nuxt'
import { readFileSync } from 'node:fs'
import { resolve } from 'node:path'

const config = {
stories: [
Expand All @@ -23,115 +21,6 @@ const config = {
async viteFinal(newConfig) {
newConfig.plugins ??= []

// Fix: Nuxt's generated #internal/nuxt/paths (<buildDir>/paths.mjs) calls
// getAppConfig() during module evaluation (#build/fetch.mjs → baseURL()). Without an
// SSR payload, Nuxt's client useRuntimeConfig shim returns undefined and `.app`
// throws, so fall back to an empty config.
newConfig.plugins.unshift({
name: 'storybook-nuxt-paths-app-config',
enforce: 'pre',
transform(code, id) {
if (!/paths\.mjs(?:$|\?)/.test(id)) return
return code.replace(
'const getAppConfig = () => useRuntimeConfig().app',
'const getAppConfig = () => useRuntimeConfig()?.app ?? {}',
)
},
})

// Fix: nuxt:components:imports-alias relies on internal Nuxt state that is
// cleaned up after nuxt.close() in @storybook-vue/nuxt's loadNuxtViteConfig.
// When that state is gone, `import X from '#components'` is left unresolved
// and Vite 8 falls through to package-subpath resolution, which fails with
// "Missing '#components' specifier in 'nuxt' package".
// This plugin intercepts #components first and serves a virtual module built
// from the components.d.ts written during the same Nuxt boot.
// Resolve the Nuxt build dir from Vite's alias map, which can be either a
// plain-object (Record<string, string>) or Vite's resolved array form
// (readonly Alias[] where find is string | RegExp). We must handle both
// without casting to Record<string, string>, which would be unsound for the
// array form.
const aliases = newConfig.resolve?.alias
const buildDir = (() => {
if (!aliases) return undefined
if (Array.isArray(aliases)) {
const entry = aliases.find(a => a.find === '#build')
return typeof entry?.replacement === 'string' ? entry.replacement : undefined
}
const value = (aliases as Record<string, unknown>)['#build']
return typeof value === 'string' ? value : undefined
})()
newConfig.plugins.unshift({
name: 'storybook-nuxt-components',
enforce: 'pre',
resolveId(id) {
if (id === '#components') return '\0virtual:#components'
return null
},
load(id) {
if (id !== '\0virtual:#components') return
if (!buildDir) {
throw new Error('[storybook-nuxt-components] Could not resolve the `#build` alias.')
}
const dtsPath = resolve(buildDir, 'components.d.ts')
// Wire the generated declaration file into Vite's file-watch graph so
// that the virtual module is invalidated when Nuxt regenerates it.
this.addWatchFile(dtsPath)
const dts = readFileSync(dtsPath, 'utf-8')
const lines: string[] = []
// Match only the direct `typeof import("…").default` form.
// Lazy/island wrappers (LazyComponent<T>, IslandComponent<T>) are
// excluded intentionally — Storybook only needs the concrete type.
// The format has been stable across all Nuxt 3 releases.
const re =
/^export const (\w+): typeof import\("([^"]+)"\)(?:\.default|\[['"]default['"]\])\s*;?$/gm
let match: RegExpExecArray | null
while ((match = re.exec(dts)) !== null) {
const [, name, rel] = match
if (!name || !rel) continue
const abs = resolve(buildDir, rel).replaceAll('\\', '/')
lines.push(`export { default as ${name} } from ${JSON.stringify(abs)}`)
}
if (lines.length === 0) {
throw new Error(
`[storybook-nuxt-components] No component exports were found in ${dtsPath}.`,
)
}
return lines.join('\n')
},
})

// Bridge compatibility between Storybook v10 core and v9 @storybook-vue/nuxt
// v10 expects module federation globals that v9 doesn't provide
newConfig.plugins.push({
name: 'storybook-v10-compat',
transformIndexHtml: {
order: 'pre',
handler() {
return [
{
tag: 'script',
injectTo: 'head-prepend' as const,
children: [
'// Minimal shims for Storybook v10 module federation system',
'// These will be replaced when Storybook runtime loads',
'window.__STORYBOOK_MODULE_GLOBAL__ = { global: window };',
'window.__STORYBOOK_MODULE_CLIENT_LOGGER__ = {',
" deprecate: console.warn.bind(console, '[deprecated]'),",
' once: console.log.bind(console),',
' logger: console',
'};',
'window.__STORYBOOK_MODULE_CHANNELS__ = {',
' Channel: class { on() {} off() {} emit() {} once() {} },',
' createBrowserChannel: () => new window.__STORYBOOK_MODULE_CHANNELS__.Channel()',
'};',
].join('\n'),
},
]
},
},
})

newConfig.plugins.push({
name: 'ignore-internals',
transform(_, id) {
Expand Down
18 changes: 10 additions & 8 deletions app/components/Changelog/Skeleton.vue
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
<template>
<SkeletonBlock class="h-8 w-40 rounded" />
<ul class="ms-3 list-disc my-4 ps-6 marker:color-[--border-hover]">
<li class="mb-1" v-for="_n in 5">
<SkeletonBlock class="h-7 w-full max-w-2xl rounded" />
</li>
</ul>
<div class="flex flex-col gap-2 pt-3 pb-8">
<SkeletonBlock class="h-8 w-40 rounded" />
<ul class="ms-3 list-disc my-4 ps-6 marker:color-[--border-hover]">
<li class="mb-1" v-for="_n in 5">
<SkeletonBlock class="h-7 w-full max-w-2xl rounded" />
</li>
</ul>

<SkeletonBlock class="h-5 w-5/6 max-w-2xl rounded" />
<SkeletonBlock class="h-5 w-3/4 max-w-2xl rounded" />
<SkeletonBlock class="h-5 w-5/6 max-w-2xl rounded" />
<SkeletonBlock class="h-5 w-3/4 max-w-2xl rounded" />
</div>
</template>
19 changes: 6 additions & 13 deletions app/components/Chart/SplitSparkline.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const props = defineProps<{
dataset?: Array<
VueUiXyDatasetItem & {
color?: string
series: number[]
series: Array<number | null>
dashIndices?: number[]
}
>
Expand All @@ -29,7 +29,6 @@ const props = defineProps<{
day: string
}
showLastDatapointEstimation: boolean
nullifyZeroValues?: boolean
largePackageSeries?: boolean[]
granularity: ChartTimeGranularity
}>()
Expand Down Expand Up @@ -94,12 +93,13 @@ function formatDataLabel(seriesIndex: number, value: number): string {
}
}

if (rawLastValue == null) return $t('package.trends.no_data_short')
return numberFormatter.value.format(value)
}

// Hover | kbd interaction: show the actual value at the hovered index
const rawValue = series[selectedIndex.value]
if (isLargeSeries(seriesIndex) && isMissingDownloadValue(rawValue)) {
if (rawValue == null || (isLargeSeries(seriesIndex) && isMissingDownloadValue(rawValue))) {
return $t('package.trends.no_data_short')
}

Expand All @@ -124,14 +124,7 @@ const datasets = computed<VueUiSparklineDatasetItem[][]>(() => {

return {
period,
value:
rawValue === 0
? props.nullifyZeroValues && hasNoDataTail
? index === props.dates.length - 1
? 0
: null
: 0
: rawValue || (index === props.dates.length - 1 ? 0 : null),
value: rawValue ?? null,
}
})
})
Expand Down Expand Up @@ -234,9 +227,9 @@ const configs = computed(() => {
strokeWidth: 1,
dashIndices,
dashArray: 3,
cutNullValues: false,
cutNullValues: true,
nullDashes: {
show: true,
show: false,
},
},
plot: {
Expand Down
Loading
Loading