Skip to content

Commit cfd2241

Browse files
committed
Merge branch 'main' of github.com:npmx-dev/npmx.dev into feat/pkg-description-link
2 parents 6049a73 + ec10662 commit cfd2241

48 files changed

Lines changed: 991 additions & 251 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.oxlintrc.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
"no-console": "warn",
1111
"no-await-in-loop": "off",
1212
"unicorn/no-array-sort": "off",
13-
"no-restricted-globals": "error"
13+
"no-restricted-globals": "error",
14+
"typescript/consistent-type-imports": "error"
1415
},
1516
"ignorePatterns": [
1617
".output/**",

app/app.vue

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,10 @@ button {
195195
margin-top: 2rem;
196196
margin-bottom: 1rem;
197197
line-height: 1.3;
198+
199+
a {
200+
text-decoration: none;
201+
}
198202
}
199203
200204
/* Visual styling based on original README heading level */

app/components/AppFooter.vue

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
<script setup lang="ts">
2-
const isMounted = ref(false)
3-
const isVisible = ref(false)
4-
const isScrollable = ref(true)
5-
const lastScrollY = ref(0)
6-
const footerRef = ref<HTMLElement>()
2+
const isMounted = shallowRef(false)
3+
const isVisible = shallowRef(false)
4+
const isScrollable = shallowRef(true)
5+
const lastScrollY = shallowRef(0)
6+
const footerRef = useTemplateRef('footerRef')
77
88
// Check if CSS scroll-state container queries are supported
99
// Once this becomes baseline, we can remove the JS scroll handling entirely
10-
const supportsScrollStateQueries = ref(false)
10+
const supportsScrollStateQueries = useSupported(() => {
11+
return isMounted.value && CSS.supports('container-type', 'scroll-state')
12+
})
1113
1214
function checkScrollable() {
1315
return document.documentElement.scrollHeight > window.innerHeight
@@ -48,26 +50,17 @@ function onResize() {
4850
updateFooterPadding()
4951
}
5052
51-
onMounted(() => {
52-
// Feature detect CSS scroll-state container queries (Chrome 133+)
53-
// @see https://developer.mozilla.org/en-US/docs/Web/CSS/@container#scroll-state_container_descriptors
54-
supportsScrollStateQueries.value = CSS.supports('container-type', 'scroll-state')
53+
useEventListener('scroll', onScroll, { passive: true })
54+
useEventListener('resize', onResize, { passive: true })
5555
56+
onMounted(() => {
5657
nextTick(() => {
5758
lastScrollY.value = window.scrollY
5859
isScrollable.value = checkScrollable()
5960
updateFooterPadding()
6061
// Only apply dynamic classes after mount to avoid hydration mismatch
6162
isMounted.value = true
6263
})
63-
64-
window.addEventListener('scroll', onScroll, { passive: true })
65-
window.addEventListener('resize', onResize, { passive: true })
66-
})
67-
68-
onUnmounted(() => {
69-
window.removeEventListener('scroll', onScroll)
70-
window.removeEventListener('resize', onResize)
7164
})
7265
</script>
7366

app/components/AppTooltip.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ const props = defineProps<{
66
position?: 'top' | 'bottom' | 'left' | 'right'
77
}>()
88
9-
const isVisible = ref(false)
9+
const isVisible = shallowRef(false)
1010
const tooltipId = useId()
1111
1212
const positionClasses: Record<string, string> = {

app/components/ClaimPackageModal.vue

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@ const {
1919
} = useConnector()
2020
2121
// Fetch name availability when modal opens
22-
const checkResult = ref<CheckNameResult | null>(null)
22+
const checkResult = shallowRef<CheckNameResult | null>(null)
2323
24-
const isChecking = ref(false)
25-
const isPublishing = ref(false)
26-
const publishError = ref<string | null>(null)
27-
const publishSuccess = ref(false)
24+
const isChecking = shallowRef(false)
25+
const isPublishing = shallowRef(false)
26+
const publishError = shallowRef<string | null>(null)
27+
const publishSuccess = shallowRef(false)
2828
2929
async function checkAvailability() {
3030
isChecking.value = true
@@ -125,7 +125,7 @@ const previewPackageJson = computed(() => {
125125
}
126126
})
127127
128-
const connectorModalOpen = ref(false)
128+
const connectorModalOpen = shallowRef(false)
129129
</script>
130130

131131
<template>

app/components/CodeMobileTreeDrawer.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ defineProps<{
77
baseUrl: string
88
}>()
99
10-
const isOpen = ref(false)
10+
const isOpen = shallowRef(false)
1111
1212
// Close drawer on navigation
1313
const route = useRoute()

app/components/CodeViewer.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const emit = defineEmits<{
99
lineClick: [lineNum: number, event: MouseEvent]
1010
}>()
1111
12-
const codeRef = ref<HTMLElement>()
12+
const codeRef = useTemplateRef('codeRef')
1313
1414
// Generate line numbers array
1515
const lineNumbers = computed(() => {

app/components/ConnectorModal.vue

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ const open = defineModel<boolean>('open', { default: false })
44
const { isConnected, isConnecting, npmUser, error, hasOperations, connect, disconnect } =
55
useConnector()
66
7-
const tokenInput = ref('')
8-
const portInput = ref('31415')
9-
const copied = ref(false)
7+
const tokenInput = shallowRef('')
8+
const portInput = shallowRef('31415')
9+
const copied = shallowRef(false)
1010
1111
async function handleConnect() {
1212
const port = Number.parseInt(portInput.value, 10) || 31415

app/components/ConnectorStatus.client.vue

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
<script setup lang="ts">
2-
const { isConnected, isConnecting, npmUser, error, activeOperations, hasPendingOperations } =
3-
useConnector()
2+
const {
3+
isConnected,
4+
isConnecting,
5+
npmUser,
6+
avatar,
7+
error,
8+
activeOperations,
9+
hasPendingOperations,
10+
} = useConnector()
411
5-
const showModal = ref(false)
6-
const showTooltip = ref(false)
12+
const showModal = shallowRef(false)
13+
const showTooltip = shallowRef(false)
714
815
const statusText = computed(() => {
916
if (isConnecting.value) return 'connecting…'
@@ -41,8 +48,16 @@ const ariaLabel = computed(() => {
4148
@focus="showTooltip = true"
4249
@blur="showTooltip = false"
4350
>
44-
<!-- Status dot -->
51+
<!-- Avatar (when connected with avatar) -->
52+
<img
53+
v-if="isConnected && avatar"
54+
:src="avatar"
55+
:alt="`${npmUser}'s avatar`"
56+
class="w-6 h-6 rounded-full"
57+
/>
58+
<!-- Status dot (when not connected or no avatar) -->
4559
<span
60+
v-else
4661
class="w-2.5 h-2.5 rounded-full transition-colors duration-200"
4762
:class="statusColor"
4863
aria-hidden="true"

app/components/LicenseDisplay.vue

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<script setup lang="ts">
2+
import { parseLicenseExpression } from '#shared/utils/spdx'
3+
4+
const props = defineProps<{
5+
license: string
6+
}>()
7+
8+
const tokens = computed(() => parseLicenseExpression(props.license))
9+
10+
const hasAnyValidLicense = computed(() => tokens.value.some(t => t.type === 'license' && t.url))
11+
</script>
12+
13+
<template>
14+
<span class="inline-flex items-baseline gap-x-1.5 flex-wrap gap-y-0.5">
15+
<template v-for="(token, i) in tokens" :key="i">
16+
<a
17+
v-if="token.type === 'license' && token.url"
18+
:href="token.url"
19+
target="_blank"
20+
rel="noopener noreferrer"
21+
class="link-subtle"
22+
title="View license text on SPDX"
23+
>
24+
{{ token.value }}
25+
</a>
26+
<span v-else-if="token.type === 'license'">{{ token.value }}</span>
27+
<span v-else-if="token.type === 'operator'" class="text-[0.65em]">{{ token.value }}</span>
28+
</template>
29+
<span
30+
v-if="hasAnyValidLicense"
31+
class="i-carbon-scales w-3.5 h-3.5 text-fg-subtle flex-shrink-0"
32+
aria-hidden="true"
33+
/>
34+
</span>
35+
</template>

0 commit comments

Comments
 (0)