+
+
+
{{ checkResult.name }}
+
-
-
-
-
-
{{ checkResult.name }}
-
+
+
+
{{ $t('claim.modal.invalid_name') }}
+
+
-
-
-
{{ $t('claim.modal.invalid_name') }}
-
-
+
+
+
{{ $t('common.warnings') }}
+
+
-
-
-
{{ $t('common.warnings') }}
-
-
+
+
+
+
+
{{ $t('claim.modal.available') }}
+
-
-
-
-
-
{{ $t('claim.modal.available') }}
-
-
-
-
-
{{ $t('claim.modal.taken') }}
-
-
+
+
+
{{ $t('claim.modal.taken') }}
+
+
-
-
-
+
+
+
+
+ {{ $t('claim.modal.similar_warning') }}
+
+ {{ $t('claim.modal.related') }}
+
+
+
+
+
+
-
-
- {{ publishError }}
-
+
+
+ {{ publishError }}
+
-
-
-
-
-
{{ $t('claim.modal.scope_warning_title') }}
-
- {{
- $t('claim.modal.scope_warning_text', {
- username: npmUser || 'username',
- name: packageName,
- })
- }}
-
-
-
-
-
-
-
{{ $t('claim.modal.connect_required') }}
-
-
-
-
-
-
-
- {{ $t('claim.modal.publish_hint') }}
-
-
-
-
-
- {{ $t('claim.modal.preview_json') }}
-
- {{
- JSON.stringify(previewPackageJson, null, 2)
- }}
-
-
-
-
-
+
+
+
+
+
{{ $t('claim.modal.scope_warning_title') }}
+
+ {{
+ $t('claim.modal.scope_warning_text', {
+ username: npmUser || 'username',
+ name: packageName,
+ })
+ }}
+
+
-
-
-
-
-
-
-
- {{ publishError }}
-
-
-
+
+
+
+
{{ $t('claim.modal.connect_required') }}
+
+
+
+
+
+
+ {{ $t('claim.modal.publish_hint') }}
+
+
+
+
+
+ {{ $t('claim.modal.preview_json') }}
+
+ {{
+ JSON.stringify(previewPackageJson, null, 2)
+ }}
+
+
+
-
-
-
-
+
+
+
+
+
+
+
+ {{ publishError }}
+
+
+
+
diff --git a/app/components/ConnectorModal.vue b/app/components/ConnectorModal.vue
index ec5973ac90..16a6d1d703 100644
--- a/app/components/ConnectorModal.vue
+++ b/app/components/ConnectorModal.vue
@@ -1,6 +1,4 @@
-
-
-
+
+
+
+ {{ $t('connector.modal.warning') }}
+
+
+ {{ $t('connector.modal.warning_text') }}
+
-
-
+
+
+
+
diff --git a/app/components/HeaderAccountMenu.client.vue b/app/components/HeaderAccountMenu.client.vue
index 4a2ae3bc13..85bd64ad25 100644
--- a/app/components/HeaderAccountMenu.client.vue
+++ b/app/components/HeaderAccountMenu.client.vue
@@ -1,4 +1,6 @@
@@ -118,7 +126,7 @@ function openAuthModal() {
leave-to-class="opacity-0 translate-y-1"
>
-
+
@@ -194,7 +202,7 @@ function openAuthModal() {
v-if="!isNpmConnected"
type="button"
role="menuitem"
- class="w-full px-3 py-2.5 flex items-center gap-3 hover:bg-bg-subtle transition-colors text-start"
+ class="w-full px-3 py-2.5 flex items-center gap-3 hover:bg-bg-subtle transition-colors text-start rounded-md"
@click="openConnectorModal"
>
@@ -221,7 +229,7 @@ function openAuthModal() {
v-if="!atprotoUser"
type="button"
role="menuitem"
- class="w-full px-3 py-2.5 flex items-center gap-3 hover:bg-bg-subtle transition-colors text-start"
+ class="w-full px-3 py-2.5 flex items-center gap-3 hover:bg-bg-subtle transition-colors text-start rounded-md"
@click="openAuthModal"
>
@@ -238,9 +246,7 @@ function openAuthModal() {
-
-
-
-
+
+
diff --git a/app/components/MobileMenu.vue b/app/components/MobileMenu.vue
index 2d1b2de540..add244fa45 100644
--- a/app/components/MobileMenu.vue
+++ b/app/components/MobileMenu.vue
@@ -4,21 +4,24 @@ const isOpen = defineModel
('open', { default: false })
const { isConnected, npmUser, avatar: npmAvatar } = useConnector()
const { user: atprotoUser } = useAtproto()
-const showConnectorModal = shallowRef(false)
-const showAuthModal = shallowRef(false)
-
function closeMenu() {
isOpen.value = false
}
function handleShowConnector() {
- showConnectorModal.value = true
- closeMenu()
+ const connectorModal = document.querySelector('#connector-modal')
+ if (connectorModal) {
+ closeMenu()
+ connectorModal.showModal()
+ }
}
function handleShowAuth() {
- showAuthModal.value = true
- closeMenu()
+ const authModal = document.querySelector('#auth-modal')
+ if (authModal) {
+ closeMenu()
+ authModal.showModal()
+ }
}
// Close menu on route change
@@ -279,9 +282,5 @@ watch(isOpen, open => (isLocked.value = open))
-
-
-
-
diff --git a/app/components/Modal.client.vue b/app/components/Modal.client.vue
new file mode 100644
index 0000000000..0791d3aa2b
--- /dev/null
+++ b/app/components/Modal.client.vue
@@ -0,0 +1,80 @@
+
+
+
+
+
+
+
+
+
diff --git a/app/components/PackageDownloadAnalytics.vue b/app/components/PackageDownloadAnalytics.vue
index d4a23e872d..2ae1dc2566 100644
--- a/app/components/PackageDownloadAnalytics.vue
+++ b/app/components/PackageDownloadAnalytics.vue
@@ -5,12 +5,7 @@ import { useDebounceFn, useElementSize } from '@vueuse/core'
import { useCssVariables } from '../composables/useColors'
import { OKLCH_NEUTRAL_FALLBACK, transparentizeOklch } from '../utils/colors'
-const {
- weeklyDownloads,
- inModal = false,
- packageName,
- createdIso,
-} = defineProps<{
+const props = defineProps<{
weeklyDownloads: WeeklyDownloadPoint[]
inModal?: boolean
packageName: string
@@ -131,7 +126,7 @@ function formatXyDataset(
return {
dataset: [
{
- name: packageName,
+ name: props.packageName,
type: 'line',
series: dataset.map(d => d.downloads),
color: accent.value,
@@ -149,7 +144,7 @@ function formatXyDataset(
return {
dataset: [
{
- name: packageName,
+ name: props.packageName,
type: 'line',
series: dataset.map(d => d.downloads),
color: accent.value,
@@ -162,7 +157,7 @@ function formatXyDataset(
return {
dataset: [
{
- name: packageName,
+ name: props.packageName,
type: 'line',
series: dataset.map(d => d.downloads),
color: accent.value,
@@ -175,7 +170,7 @@ function formatXyDataset(
return {
dataset: [
{
- name: packageName,
+ name: props.packageName,
type: 'line',
series: dataset.map(d => d.downloads),
color: accent.value,
@@ -235,10 +230,10 @@ const hasUserEditedDates = shallowRef(false)
function initDateRangeFromWeekly() {
if (hasUserEditedDates.value) return
- if (!weeklyDownloads?.length) return
+ if (!props.weeklyDownloads?.length) return
- const first = weeklyDownloads[0]
- const last = weeklyDownloads[weeklyDownloads.length - 1]
+ const first = props.weeklyDownloads[0]
+ const last = props.weeklyDownloads[props.weeklyDownloads.length - 1]
const start = first?.weekStart ? toIsoDateOnly(first.weekStart) : ''
const end = last?.weekEnd ? toIsoDateOnly(last.weekEnd) : ''
if (isValidIsoDateOnly(start)) startDate.value = start
@@ -265,7 +260,7 @@ function initDateRangeFallbackClient() {
}
watch(
- () => weeklyDownloads?.length,
+ () => props.weeklyDownloads?.length,
() => {
initDateRangeFromWeekly()
initDateRangeFallbackClient()
@@ -342,7 +337,7 @@ watch(
const { fetchPackageDownloadEvolution } = useCharts()
-const evolution = shallowRef
(weeklyDownloads)
+const evolution = shallowRef(props.weeklyDownloads)
const pending = shallowRef(false)
let lastRequestKey = ''
@@ -354,7 +349,7 @@ const debouncedLoad = useDebounceFn(() => {
async function load() {
if (!import.meta.client) return
- if (!inModal) return
+ if (!props.inModal) return
const o = options.value
const extraBase =
@@ -366,14 +361,14 @@ async function load() {
const startKey = (o as any).startDate ?? ''
const endKey = (o as any).endDate ?? ''
- const requestKey = `${packageName}|${createdIso ?? ''}|${o.granularity}|${extraBase}|${startKey}|${endKey}`
+ const requestKey = `${props.packageName}|${props.createdIso ?? ''}|${o.granularity}|${extraBase}|${startKey}|${endKey}`
if (requestKey === lastRequestKey) return
lastRequestKey = requestKey
const hasExplicitRange = Boolean((o as any).startDate || (o as any).endDate)
- if (o.granularity === 'week' && weeklyDownloads?.length && !hasExplicitRange) {
- evolution.value = weeklyDownloads
+ if (o.granularity === 'week' && props.weeklyDownloads?.length && !hasExplicitRange) {
+ evolution.value = props.weeklyDownloads
pending.value = false
displayedGranularity.value = 'weekly'
return
@@ -384,8 +379,8 @@ async function load() {
try {
const result = await fetchPackageDownloadEvolution(
- () => packageName,
- () => createdIso,
+ () => props.packageName,
+ () => props.createdIso,
() => o as any, // FIXME: any
)
@@ -404,7 +399,7 @@ async function load() {
}
watch(
- () => inModal,
+ () => props.inModal,
() => {
// modal open/close should be immediate
load()
@@ -414,8 +409,8 @@ watch(
watch(
() => [
- packageName,
- createdIso,
+ props.packageName,
+ props.createdIso,
options.value.granularity,
(options.value as any).weeks,
(options.value as any).months,
@@ -437,9 +432,9 @@ watch(
)
const effectiveData = computed(() => {
- if (displayedGranularity.value === 'weekly' && weeklyDownloads?.length) {
+ if (displayedGranularity.value === 'weekly' && props.weeklyDownloads?.length) {
if (isWeeklyDataset(evolution.value) && evolution.value.length) return evolution.value
- return weeklyDownloads
+ return props.weeklyDownloads
}
return evolution.value
})
@@ -481,7 +476,7 @@ const config = computed(() => {
img: ({ imageUri }: { imageUri: string }) => {
loadFile(
imageUri,
- `${packageName}-${selectedGranularity.value}_${startDate.value}_${endDate.value}.png`,
+ `${props.packageName}-${selectedGranularity.value}_${startDate.value}_${endDate.value}.png`,
)
},
csv: (csvStr: string) => {
@@ -502,7 +497,7 @@ const config = computed(() => {
const url = URL.createObjectURL(blob)
loadFile(
url,
- `${packageName}-${selectedGranularity.value}_${startDate.value}_${endDate.value}.csv`,
+ `${props.packageName}-${selectedGranularity.value}_${startDate.value}_${endDate.value}.csv`,
)
URL.revokeObjectURL(url)
},
@@ -510,7 +505,7 @@ const config = computed(() => {
const url = URL.createObjectURL(blob)
loadFile(
url,
- `${packageName}-${selectedGranularity.value}_${startDate.value}_${endDate.value}.svg`,
+ `${props.packageName}-${selectedGranularity.value}_${startDate.value}_${endDate.value}.svg`,
)
URL.revokeObjectURL(url)
},
@@ -525,7 +520,7 @@ const config = computed(() => {
yLabel: $t('package.downloads.y_axis_label', {
granularity: $t(`package.downloads.granularity_${selectedGranularity.value}`),
}),
- xLabel: packageName,
+ xLabel: props.packageName,
yLabelOffsetX: 12,
fontSize: isMobile.value ? 32 : 24,
},
diff --git a/app/components/PackageWeeklyDownloadStats.vue b/app/components/PackageWeeklyDownloadStats.vue
index e7dd4eed4b..46ee35022f 100644
--- a/app/components/PackageWeeklyDownloadStats.vue
+++ b/app/components/PackageWeeklyDownloadStats.vue
@@ -3,13 +3,20 @@ import { VueUiSparkline } from 'vue-data-ui/vue-ui-sparkline'
import { useCssVariables } from '../composables/useColors'
import { OKLCH_NEUTRAL_FALLBACK, lightenOklch } from '../utils/colors'
-const { packageName } = defineProps<{
+const props = defineProps<{
packageName: string
}>()
-const showModal = shallowRef(false)
+const chartModal = useModal('chart-modal')
-const { data: packument } = usePackage(() => packageName)
+const isChartModalOpen = shallowRef(false)
+function openChartModal() {
+ isChartModalOpen.value = true
+ // ensure the component renders before opening the dialog
+ nextTick(() => chartModal.open())
+}
+
+const { data: packument } = usePackage(() => props.packageName)
const createdIso = computed(() => packument.value?.time?.created ?? null)
const { fetchPackageDownloadEvolution } = useCharts()
@@ -84,7 +91,7 @@ async function loadWeeklyDownloads() {
try {
const result = await fetchPackageDownloadEvolution(
- () => packageName,
+ () => props.packageName,
() => createdIso.value,
() => ({ granularity: 'week' as const, weeks: 52 }),
)
@@ -99,7 +106,7 @@ onMounted(() => {
})
watch(
- () => packageName,
+ () => props.packageName,
() => loadWeeklyDownloads(),
)
@@ -194,7 +201,7 @@ const config = computed(() => {