diff --git a/app/assets/logos/sponsors/index.ts b/app/assets/logos/sponsors/index.ts
index 6a4347eeee..de52c48609 100644
--- a/app/assets/logos/sponsors/index.ts
+++ b/app/assets/logos/sponsors/index.ts
@@ -40,7 +40,7 @@ export const SPONSORS = {
light: LogoCodeRabbitLight,
},
normalisingIndent: '0.875rem',
- url: 'https://www.coderabbit.ai',
+ url: 'https://coderabbit.link/npmx',
},
],
silver: [
diff --git a/app/assets/main.css b/app/assets/main.css
index 1735c87de6..e824da64da 100644
--- a/app/assets/main.css
+++ b/app/assets/main.css
@@ -15,13 +15,14 @@
/* text colors */
--fg: oklch(0.982 0 0);
- --fg-muted: oklch(0.749 0 0);
- --fg-subtle: oklch(0.673 0 0);
+ --fg-muted: oklch(0.849 0 0);
+ --fg-subtle: oklch(0.773 0 0);
/* border, separator colors */
--border: oklch(0.269 0 0);
--border-subtle: oklch(0.239 0 0);
--border-hover: oklch(0.371 0 0);
+ --border-elevated: oklch(0.369 0 0);
/* accent color, set by user from settings */
--accent: var(--accent-color, oklch(0.787 0.128 230.318));
@@ -81,19 +82,38 @@
--bg-elevated: oklch(0.264 0 0);
}
+:root[data-theme='dark'][data-fg-theme='contrast'] {
+ --fg: oklch(1 0 0);
+ --fg-muted: oklch(0.95 0 0);
+ --fg-subtle: oklch(0.9 0 0);
+}
+
+:root[data-theme='dark'][data-fg-theme='standard'] {
+ --fg: oklch(0.982 0 0);
+ --fg-muted: oklch(0.849 0 0);
+ --fg-subtle: oklch(0.773 0 0);
+}
+
+:root[data-theme='dark'][data-fg-theme='muted'] {
+ --fg: oklch(0.969 0 0);
+ --fg-muted: oklch(0.749 0 0);
+ --fg-subtle: oklch(0.673 0 0);
+}
+
:root[data-theme='light'] {
--bg: var(--bg-color, oklch(1 0 0));
--bg-subtle: var(--bg-subtle-color, oklch(0.979 0.001 286.375));
--bg-muted: var(--bg-muted-color, oklch(0.955 0.001 286.76));
--bg-elevated: var(--bg-elevated-color, oklch(0.94 0.002 287.29));
- --fg: oklch(0.146 0 0);
- --fg-muted: oklch(0.398 0 0);
- --fg-subtle: oklch(0.48 0 0);
+ --fg: oklch(0.046 0 0);
+ --fg-muted: oklch(0.198 0 0);
+ --fg-subtle: oklch(0.28 0 0);
--border: oklch(0.8514 0 0);
--border-subtle: oklch(0.922 0 0);
--border-hover: oklch(0.715 0 0);
+ --border-elevated: oklch(0.75 0 0);
--accent: var(--accent-color, oklch(0.5 0.16 247.27));
--accent-muted: var(--accent-color, oklch(0.205 0 0));
@@ -147,29 +167,49 @@
--bg-subtle: var(--bg-subtle-color, oklch(0.979 0 0));
}
+:root[data-theme='light'][data-fg-theme='contrast'] {
+ --fg: oklch(0 0 0);
+ --fg-muted: oklch(0.1 0 0);
+ --fg-subtle: oklch(0.2 0 0);
+}
+
+:root[data-theme='light'][data-fg-theme='standard'] {
+ --fg: oklch(0.046 0 0);
+ --fg-muted: oklch(0.198 0 0);
+ --fg-subtle: oklch(0.28 0 0);
+}
+
+:root[data-theme='light'][data-fg-theme='muted'] {
+ --fg: oklch(0.146 0 0);
+ --fg-muted: oklch(0.398 0 0);
+ --fg-subtle: oklch(0.48 0 0);
+}
+
@media (prefers-contrast: more) {
:root[data-theme='dark'] {
/* text colors */
--fg: oklch(1 0 0);
- --fg-muted: oklch(0.769 0 0);
- --fg-subtle: oklch(0.693 0 0);
+ --fg-muted: oklch(0.869 0 0);
+ --fg-subtle: oklch(0.793 0 0);
/* border, separator colors */
--border: oklch(0.769 0 0);
--border-subtle: oklch(0.739 0 0);
--border-hover: oklch(0.771 0 0);
+ --border-elevated: oklch(0.869 0 0);
}
:root[data-theme='light'] {
/* text colors */
--fg: oklch(0 0 0);
- --fg-muted: oklch(0.329 0 0);
- --fg-subtle: oklch(0.4 0 0);
+ --fg-muted: oklch(0.229 0 0);
+ --fg-subtle: oklch(0.3 0 0);
/* border, separator colors */
--border: oklch(0.3514 0 0);
--border-subtle: oklch(0.422 0 0);
--border-hover: oklch(0.315 0 0);
+ --border-elevated: oklch(0.25 0 0);
}
}
diff --git a/app/components/Button/Base.vue b/app/components/Button/Base.vue
index 1a321e888d..be7926289c 100644
--- a/app/components/Button/Base.vue
+++ b/app/components/Button/Base.vue
@@ -48,7 +48,7 @@ defineExpose({
diff --git a/app/components/Noodle/GifDay/GifText.vue b/app/components/Noodle/GifDay/GifText.vue
new file mode 100644
index 0000000000..c586cb3abc
--- /dev/null
+++ b/app/components/Noodle/GifDay/GifText.vue
@@ -0,0 +1,48 @@
+
+
+
+
+
+ {{ text }}
+
+
+
diff --git a/app/components/Noodle/GifDay/Logo.vue b/app/components/Noodle/GifDay/Logo.vue
new file mode 100644
index 0000000000..24e2082ee9
--- /dev/null
+++ b/app/components/Noodle/GifDay/Logo.vue
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
diff --git a/app/components/Noodle/index.ts b/app/components/Noodle/index.ts
index 9e611daf54..a73644a0a4 100644
--- a/app/components/Noodle/index.ts
+++ b/app/components/Noodle/index.ts
@@ -9,6 +9,7 @@ import NoodlePride2Logo from './Pride2/Logo.vue'
import NoodlePride3Logo from './Pride3/Logo.vue'
import NoodleTetrisLogo from './Tetris/Logo.vue'
import NoodleEmojiDayLogo from './EmojiDay/Logo.vue'
+import NoodleGifDayLogo from './GifDay/Logo.vue'
export type Noodle = {
// Unique identifier for the noodle
@@ -72,6 +73,13 @@ export const ACTIVE_NOODLES: Noodle[] = [
dateTo: '2026-07-19',
timezone: 'auto',
},
+ {
+ key: 'gif-day',
+ logo: NoodleGifDayLogo,
+ date: '2026-09-05',
+ dateTo: '2026-09-08',
+ timezone: 'auto',
+ },
]
// Logo registry for the /noodles archive, keyed by the entry's `key` in
@@ -86,6 +94,7 @@ const NOODLE_LOGOS: Record = {
'pride-1': NoodlePride1Logo,
'tetris': NoodleTetrisLogo,
'emoji-day': NoodleEmojiDayLogo,
+ 'gif-day': NoodleGifDayLogo,
}
export function resolveNoodleLogo(key: string): Component | undefined {
diff --git a/app/components/Package/Dependencies.vue b/app/components/Package/Dependencies.vue
index 76df6e4a77..649bfb34a5 100644
--- a/app/components/Package/Dependencies.vue
+++ b/app/components/Package/Dependencies.vue
@@ -142,7 +142,7 @@ const numberFormatter = useNumberFormatter()
class="inline-flex items-center justify-center p-2 -m-2"
:aria-label="getOutdatedTooltip(outdatedDeps[dep], $t)"
>
-
+
props.pkg?.requestedVersion ?? null)
const { repositoryUrl } = useRepositoryUrl(displayVersion)
-const { meta: repoMeta, repoRef, stars, starsLink, forks, forksLink } = useRepoMeta(repositoryUrl)
+const { meta: repoMeta, repoRef, stars, forks, forksLink, repoLink } = useRepoMeta(repositoryUrl)
const compactNumberFormatter = useCompactNumberFormatter()
const homepageUrl = computed(() => {
@@ -55,14 +55,14 @@ useCommandPaletteContextCommands(
})
}
- if (repositoryUrl.value && starsLink.value) {
+ if (repositoryUrl.value && repoLink.value) {
commands.push({
id: 'package-link-stars',
group: 'links',
label: $t('command_palette.package_links.stars'),
keywords: [...packageKeywords, $t('command_palette.package_links.stars')],
iconClass: 'i-lucide:star',
- href: starsLink.value,
+ href: repoLink.value,
})
}
@@ -143,8 +143,8 @@ useCommandPaletteContextCommands(
{{ $t('package.links.repo') }}
-
-
+
+
{{ compactNumberFormatter.format(stars) }}
diff --git a/app/components/Package/Header.vue b/app/components/Package/Header.vue
index d0306d3706..ea7e9bed85 100644
--- a/app/components/Package/Header.vue
+++ b/app/components/Package/Header.vue
@@ -75,6 +75,11 @@ const { copied: copiedPkgName, copy: copyPkgName } = useClipboard({
copiedDuring: 2000,
})
+const { copied: copiedPkgVersion, copy: copyPkgVersion } = useClipboard({
+ source: () => props.resolvedVersion ?? '',
+ copiedDuring: 2000,
+})
+
function hasProvenance(version: PackumentVersion | null): boolean {
if (!version?.dist) return false
return !!(version.dist as { attestations?: unknown }).attestations
@@ -98,6 +103,17 @@ useCommandPaletteContextCommands(
announce($t('command_palette.announcements.copied_to_clipboard'))
},
},
+ {
+ id: 'package-copy-version',
+ group: 'package',
+ label: $t('package.copy_version'),
+ keywords: [packageName.value],
+ iconClass: 'i-lucide:copy',
+ action: () => {
+ copyPkgVersion()
+ announce($t('command_palette.announcements.copied_to_clipboard'))
+ },
+ },
]
if (fundingUrl.value) {
@@ -206,26 +222,37 @@ useShortcuts({
-
-
@{{ orgName }}
/
-
+
{{ orgName ? pkg?.name.replace(`@${orgName}/`, '') : pkg?.name }}
-
-
+
+
+ @
+
+ {{ resolvedVersion }}
+
+
+
{
}
})
-const activeTab = shallowRef('totalSize')
+const timelineChartMetrics = new Set([
+ 'totalSize',
+ 'dependencyCount',
+ 'dependencySize',
+])
+
+const activeTab = usePermalink('metric', 'totalSize', {
+ permanent: true,
+})
+
+watch(
+ activeTab,
+ value => {
+ if (!timelineChartMetrics.has(value)) {
+ activeTab.value = 'totalSize'
+ }
+ },
+ { immediate: true },
+)
const shouldPauseChartAnimations = shallowRef(true)
@@ -194,8 +212,8 @@ const { start: startChartAnimationPauseTimer } = useTimeoutFn(
() => {
shouldPauseChartAnimations.value = false
},
- 1000,
- { immediate: false },
+ 300,
+ { immediate: true },
)
function pauseChartAnimations() {
@@ -859,7 +877,7 @@ const timelineMetricTabs = computed(() => [
@@ -967,7 +985,7 @@ const timelineMetricTabs = computed(() => [
:markersNegative="getNegativeDatapointPlots(svg.data[0], svg.slicer.start)"
:colors
:gradientColors="E18E_GRADIENT_COLORS"
- :pauseAnimations="shouldPauseChartAnimations"
+ :pauseAnimations="shouldPauseChartAnimations || loading"
/>
@@ -1040,6 +1058,10 @@ const timelineMetricTabs = computed(() => [
:dataset="datasets.dependencySize"
:config="stackbarConfig"
:selected-x-index="indexSelection"
+ :style="{
+ opacity: shouldPauseChartAnimations || loading ? 0 : 1,
+ transition: 'opacity 0.15s',
+ }"
ref="chartRef"
>
@@ -1058,7 +1080,7 @@ const timelineMetricTabs = computed(() => [
"
:activeVersionPlot="getActiveVersionDatapointBar(svg.data, svg.barWidth)"
:colors
- :pauseAnimations="shouldPauseChartAnimations"
+ :pauseAnimations="shouldPauseChartAnimations || loading"
/>
@@ -1112,7 +1134,10 @@ const timelineMetricTabs = computed(() => [
-
+
@@ -1198,9 +1223,9 @@ const timelineMetricTabs = computed(() => [
animation: indeterminate 1.5s ease-in-out infinite;
}
-.loaded :deep(.vue-data-ui-component .serie_line_0 path),
-.loaded :deep(.vdui-shape-circle),
-.loaded :deep(.vue-ui-stackbar rect) {
+.loading :deep(.vue-data-ui-component .serie_line_0 path),
+.loading :deep(.vdui-shape-circle),
+.loading :deep(.vue-ui-stackbar rect) {
transition: none !important;
animation: none !important;
}
diff --git a/app/components/Package/Versions.vue b/app/components/Package/Versions.vue
index 8e6c4a4c5a..cd31b75e87 100644
--- a/app/components/Package/Versions.vue
+++ b/app/components/Package/Versions.vue
@@ -1,5 +1,5 @@
+
+
+
+
+
+
diff --git a/app/components/Terminal/Execute.vue b/app/components/Terminal/Execute.vue
index c2ee26ac64..c9106d0126 100644
--- a/app/components/Terminal/Execute.vue
+++ b/app/components/Terminal/Execute.vue
@@ -1,10 +1,11 @@