-
-
Notifications
You must be signed in to change notification settings - Fork 368
fix: handle CLS issues in chart modal #2032
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
6e5af51
c841e6d
aaa3eb6
aaa02a0
31ce284
a96d693
cff4e36
36136da
6595c71
a8afbe1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
| @@ -1,7 +1,7 @@ | ||||||||
| <script setup lang="ts"> | ||||||||
| import type { Theme as VueDataUiTheme, VueUiXyConfig, VueUiXyDatasetItem } from 'vue-data-ui' | ||||||||
| import { VueUiXy } from 'vue-data-ui/vue-ui-xy' | ||||||||
| import { useDebounceFn, useElementSize } from '@vueuse/core' | ||||||||
| import { useDebounceFn, useElementSize, useTimeoutFn } from '@vueuse/core' | ||||||||
| import { useCssVariables } from '~/composables/useColors' | ||||||||
| import { OKLCH_NEUTRAL_FALLBACK, transparentizeOklch, lightenOklch } from '~/utils/colors' | ||||||||
| import { getFrameworkColor, isListedFramework } from '~/utils/frameworks' | ||||||||
|
|
@@ -1350,12 +1350,46 @@ function drawSvgPrintLegend(svg: Record<string, any>) { | |||||||
| return seriesNames.join('\n') | ||||||||
| } | ||||||||
|
|
||||||||
| const showCorrectionControls = shallowRef(false) | ||||||||
| const isResizing = shallowRef(false) | ||||||||
|
|
||||||||
| const chartHeight = computed(() => { | ||||||||
| if (isMobile.value) { | ||||||||
| return 950 | ||||||||
| } | ||||||||
| return showCorrectionControls.value && props.inModal ? 494 : 600 | ||||||||
| }) | ||||||||
|
|
||||||||
| const { start } = useTimeoutFn( | ||||||||
| () => { | ||||||||
| isResizing.value = false | ||||||||
| }, | ||||||||
| 200, | ||||||||
| { immediate: false }, | ||||||||
| ) | ||||||||
|
|
||||||||
| function pauseChartTransitions() { | ||||||||
| isResizing.value = true | ||||||||
| start() | ||||||||
| } | ||||||||
|
|
||||||||
| watch( | ||||||||
| chartHeight, | ||||||||
| (newH, oldH) => { | ||||||||
| if (newH !== oldH) { | ||||||||
| // Avoids triggering chart line transitions when the chart is resized | ||||||||
| pauseChartTransitions() | ||||||||
| } | ||||||||
| }, | ||||||||
| { immediate: true }, | ||||||||
| ) | ||||||||
graphieros marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||
|
|
||||||||
| // VueUiXy chart component configuration | ||||||||
| const chartConfig = computed<VueUiXyConfig>(() => { | ||||||||
| return { | ||||||||
| theme: isDarkMode.value ? 'dark' : ('' as VueDataUiTheme), | ||||||||
| chart: { | ||||||||
| height: isMobile.value ? 950 : 600, | ||||||||
| height: chartHeight.value, | ||||||||
| backgroundColor: colors.value.bg, | ||||||||
| padding: { bottom: displayedGranularity.value === 'yearly' ? 84 : 64, right: 128 }, // padding right is set to leave space of last datapoint label(s) | ||||||||
| userOptions: { | ||||||||
|
|
@@ -1559,7 +1593,6 @@ const chartConfig = computed<VueUiXyConfig>(() => { | |||||||
| }) | ||||||||
|
|
||||||||
| const isDownloadsMetric = computed(() => selectedMetric.value === 'downloads') | ||||||||
| const showCorrectionControls = shallowRef(false) | ||||||||
|
|
||||||||
| const packageAnomalies = computed(() => getAnomaliesForPackages(effectivePackageNames.value)) | ||||||||
| const hasAnomalies = computed(() => packageAnomalies.value.length > 0) | ||||||||
|
|
@@ -1648,6 +1681,8 @@ watch(selectedMetric, value => { | |||||||
|
|
||||||||
| <button | ||||||||
| v-if="showResetButton" | ||||||||
| :aria-expanded="showCorrectionControls" | ||||||||
| aria-controls="trends-correction-controls" | ||||||||
| type="button" | ||||||||
| aria-label="Reset date range" | ||||||||
| class="self-end flex items-center justify-center px-2.5 py-2.25 border border-transparent rounded-md text-fg-subtle hover:text-fg transition-colors hover:border-border focus-visible:outline-accent/70 sm:mb-0" | ||||||||
|
|
@@ -1671,115 +1706,141 @@ watch(selectedMetric, value => { | |||||||
| /> | ||||||||
| {{ $t('package.trends.data_correction') }} | ||||||||
| </button> | ||||||||
| <div v-if="showCorrectionControls" class="grid grid-cols-2 sm:flex items-end gap-3"> | ||||||||
| <label class="flex flex-col gap-1 flex-1"> | ||||||||
| <span class="text-2xs font-mono text-fg-subtle tracking-wide uppercase"> | ||||||||
| {{ $t('package.trends.average_window') }} | ||||||||
| <span class="text-fg-muted">({{ settings.chartFilter.averageWindow }})</span> | ||||||||
| </span> | ||||||||
| <input | ||||||||
| v-model.number="settings.chartFilter.averageWindow" | ||||||||
| type="range" | ||||||||
| min="0" | ||||||||
| max="20" | ||||||||
| step="1" | ||||||||
| class="accent-[var(--accent-color,var(--fg-subtle))]" | ||||||||
| /> | ||||||||
| </label> | ||||||||
| <label class="flex flex-col gap-1 flex-1"> | ||||||||
| <span class="text-2xs font-mono text-fg-subtle tracking-wide uppercase"> | ||||||||
| {{ $t('package.trends.smoothing') }} | ||||||||
| <span class="text-fg-muted">({{ settings.chartFilter.smoothingTau }})</span> | ||||||||
| </span> | ||||||||
| <input | ||||||||
| v-model.number="settings.chartFilter.smoothingTau" | ||||||||
| type="range" | ||||||||
| min="0" | ||||||||
| max="20" | ||||||||
| step="1" | ||||||||
| class="accent-[var(--accent-color,var(--fg-subtle))]" | ||||||||
| /> | ||||||||
| </label> | ||||||||
| <label class="flex flex-col gap-1 flex-1"> | ||||||||
| <span class="text-2xs font-mono text-fg-subtle tracking-wide uppercase"> | ||||||||
| {{ $t('package.trends.prediction') }} | ||||||||
| <span class="text-fg-muted">({{ settings.chartFilter.predictionPoints }})</span> | ||||||||
| </span> | ||||||||
| <input | ||||||||
| v-model.number="settings.chartFilter.predictionPoints" | ||||||||
| type="range" | ||||||||
| min="0" | ||||||||
| max="30" | ||||||||
| step="1" | ||||||||
| class="accent-[var(--accent-color,var(--fg-subtle))]" | ||||||||
| /> | ||||||||
| </label> | ||||||||
| <div class="flex flex-col gap-1 shrink-0"> | ||||||||
| <span | ||||||||
| class="text-2xs font-mono text-fg-subtle tracking-wide uppercase flex items-center justify-between" | ||||||||
| > | ||||||||
| {{ $t('package.trends.known_anomalies') }} | ||||||||
| <TooltipApp interactive :to="inModal ? '#chart-modal' : undefined"> | ||||||||
| <button | ||||||||
| type="button" | ||||||||
| class="i-lucide:info w-3.5 h-3.5 text-fg-muted cursor-help" | ||||||||
| :aria-label="$t('package.trends.known_anomalies')" | ||||||||
| <div | ||||||||
| class="overflow-hidden transition-[opacity] duration-200 ease-out" | ||||||||
| id="trends-correction-controls" | ||||||||
| :aria-hidden="!showCorrectionControls" | ||||||||
| :inert="!showCorrectionControls" | ||||||||
| :class=" | ||||||||
| showCorrectionControls | ||||||||
| ? 'max-h-[220px] opacity-100' | ||||||||
| : 'max-h-0 opacity-0 pointer-events-none' | ||||||||
|
Comment on lines
+1715
to
+1717
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||||||||
| " | ||||||||
| > | ||||||||
| <div class="pt-1 min-h-[160px] sm:min-h-[76px]"> | ||||||||
| <div class="grid grid-cols-2 sm:flex items-end gap-3"> | ||||||||
| <label class="flex flex-col gap-1 flex-1"> | ||||||||
| <span class="text-2xs font-mono text-fg-subtle tracking-wide uppercase"> | ||||||||
| {{ $t('package.trends.average_window') }} | ||||||||
| <span class="text-fg-muted">({{ settings.chartFilter.averageWindow }})</span> | ||||||||
| </span> | ||||||||
| <input | ||||||||
| v-model.number="settings.chartFilter.averageWindow" | ||||||||
| :disabled="!showCorrectionControls" | ||||||||
| type="range" | ||||||||
| min="0" | ||||||||
| max="20" | ||||||||
| step="1" | ||||||||
| class="accent-[var(--accent-color,var(--fg-subtle))]" | ||||||||
| /> | ||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
| <template #content> | ||||||||
| <div class="flex flex-col gap-3"> | ||||||||
| <p class="text-xs text-fg-muted"> | ||||||||
| {{ $t('package.trends.known_anomalies_description') }} | ||||||||
| </p> | ||||||||
| <div v-if="hasAnomalies"> | ||||||||
| <p class="text-xs text-fg-subtle font-medium"> | ||||||||
| {{ $t('package.trends.known_anomalies_ranges') }} | ||||||||
| </p> | ||||||||
| <ul class="text-xs text-fg-subtle list-disc list-inside"> | ||||||||
| <li v-for="a in packageAnomalies" :key="`${a.packageName}-${a.start}`"> | ||||||||
| </label> | ||||||||
| <label class="flex flex-col gap-1 flex-1"> | ||||||||
| <span class="text-2xs font-mono text-fg-subtle tracking-wide uppercase"> | ||||||||
| {{ $t('package.trends.smoothing') }} | ||||||||
| <span class="text-fg-muted">({{ settings.chartFilter.smoothingTau }})</span> | ||||||||
| </span> | ||||||||
| <input | ||||||||
| v-model.number="settings.chartFilter.smoothingTau" | ||||||||
| :disabled="!showCorrectionControls" | ||||||||
| type="range" | ||||||||
| min="0" | ||||||||
| max="20" | ||||||||
| step="1" | ||||||||
| class="accent-[var(--accent-color,var(--fg-subtle))]" | ||||||||
| /> | ||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
| </label> | ||||||||
| <label class="flex flex-col gap-1 flex-1"> | ||||||||
| <span class="text-2xs font-mono text-fg-subtle tracking-wide uppercase"> | ||||||||
| {{ $t('package.trends.prediction') }} | ||||||||
| <span class="text-fg-muted">({{ settings.chartFilter.predictionPoints }})</span> | ||||||||
| </span> | ||||||||
| <input | ||||||||
| v-model.number="settings.chartFilter.predictionPoints" | ||||||||
| :disabled="!showCorrectionControls" | ||||||||
| type="range" | ||||||||
| min="0" | ||||||||
| max="30" | ||||||||
| step="1" | ||||||||
| class="accent-[var(--accent-color,var(--fg-subtle))]" | ||||||||
| /> | ||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
| </label> | ||||||||
| <div class="flex flex-col gap-1 shrink-0"> | ||||||||
| <span | ||||||||
| class="text-2xs font-mono text-fg-subtle tracking-wide uppercase flex items-center justify-between" | ||||||||
| > | ||||||||
| {{ $t('package.trends.known_anomalies') }} | ||||||||
| <TooltipApp | ||||||||
| interactive | ||||||||
| :to="inModal ? '#chart-modal' : undefined" | ||||||||
| v-if="showCorrectionControls" | ||||||||
| > | ||||||||
| <button | ||||||||
| type="button" | ||||||||
| class="i-lucide:info w-3.5 h-3.5 text-fg-muted cursor-help" | ||||||||
| :aria-label="$t('package.trends.known_anomalies')" | ||||||||
| /> | ||||||||
| <template #content> | ||||||||
| <div class="flex flex-col gap-3"> | ||||||||
| <p class="text-xs text-fg-muted"> | ||||||||
| {{ $t('package.trends.known_anomalies_description') }} | ||||||||
| </p> | ||||||||
| <div v-if="hasAnomalies"> | ||||||||
| <p class="text-xs text-fg-subtle font-medium"> | ||||||||
| {{ $t('package.trends.known_anomalies_ranges') }} | ||||||||
| </p> | ||||||||
| <ul class="text-xs text-fg-subtle list-disc list-inside"> | ||||||||
| <li v-for="a in packageAnomalies" :key="`${a.packageName}-${a.start}`"> | ||||||||
| {{ | ||||||||
| isMultiPackageMode | ||||||||
| ? $t('package.trends.known_anomalies_range_named', { | ||||||||
| packageName: a.packageName, | ||||||||
| start: formatAnomalyDate(a.start), | ||||||||
| end: formatAnomalyDate(a.end), | ||||||||
| }) | ||||||||
| : $t('package.trends.known_anomalies_range', { | ||||||||
| start: formatAnomalyDate(a.start), | ||||||||
| end: formatAnomalyDate(a.end), | ||||||||
| }) | ||||||||
| }} | ||||||||
| </li> | ||||||||
| </ul> | ||||||||
| </div> | ||||||||
| <p v-else class="text-xs text-fg-muted"> | ||||||||
| {{ | ||||||||
| isMultiPackageMode | ||||||||
| ? $t('package.trends.known_anomalies_range_named', { | ||||||||
| packageName: a.packageName, | ||||||||
| start: formatAnomalyDate(a.start), | ||||||||
| end: formatAnomalyDate(a.end), | ||||||||
| }) | ||||||||
| : $t('package.trends.known_anomalies_range', { | ||||||||
| start: formatAnomalyDate(a.start), | ||||||||
| end: formatAnomalyDate(a.end), | ||||||||
| }) | ||||||||
| $t('package.trends.known_anomalies_none', effectivePackageNames.length) | ||||||||
| }} | ||||||||
| </li> | ||||||||
| </ul> | ||||||||
| </div> | ||||||||
| <p v-else class="text-xs text-fg-muted"> | ||||||||
| {{ $t('package.trends.known_anomalies_none', effectivePackageNames.length) }} | ||||||||
| </p> | ||||||||
| <div class="flex justify-end"> | ||||||||
| <LinkBase | ||||||||
| to="https://github.com/npmx-dev/npmx.dev/edit/main/app/utils/download-anomalies.data.ts" | ||||||||
| class="text-xs text-accent" | ||||||||
| > | ||||||||
| {{ $t('package.trends.known_anomalies_contribute') }} | ||||||||
| </LinkBase> | ||||||||
| </div> | ||||||||
| </div> | ||||||||
| </template> | ||||||||
| </TooltipApp> | ||||||||
| </span> | ||||||||
| <label | ||||||||
| class="flex items-center gap-1.5 text-2xs font-mono text-fg-subtle cursor-pointer h-4" | ||||||||
| :class="{ 'opacity-50': !hasAnomalies }" | ||||||||
| > | ||||||||
| <input | ||||||||
| :checked="settings.chartFilter.anomaliesFixed" | ||||||||
| @change=" | ||||||||
| settings.chartFilter.anomaliesFixed = ($event.target as HTMLInputElement).checked | ||||||||
| " | ||||||||
| type="checkbox" | ||||||||
| class="accent-[var(--accent-color,var(--fg-subtle))]" | ||||||||
| /> | ||||||||
| {{ $t('package.trends.apply_correction') }} | ||||||||
| </label> | ||||||||
| </p> | ||||||||
| <div class="flex justify-end"> | ||||||||
| <LinkBase | ||||||||
| to="https://github.com/npmx-dev/npmx.dev/edit/main/app/utils/download-anomalies.data.ts" | ||||||||
| class="text-xs text-accent" | ||||||||
| > | ||||||||
| {{ $t('package.trends.known_anomalies_contribute') }} | ||||||||
| </LinkBase> | ||||||||
| </div> | ||||||||
| </div> | ||||||||
| </template> | ||||||||
| </TooltipApp> | ||||||||
| </span> | ||||||||
| <label | ||||||||
| class="flex items-center gap-1.5 text-2xs font-mono text-fg-subtle cursor-pointer h-4" | ||||||||
| :class="{ 'opacity-50': !hasAnomalies }" | ||||||||
| > | ||||||||
| <input | ||||||||
| :checked="settings.chartFilter.anomaliesFixed" | ||||||||
| :disabled="!showCorrectionControls" | ||||||||
| @change=" | ||||||||
| settings.chartFilter.anomaliesFixed = ( | ||||||||
| $event.target as HTMLInputElement | ||||||||
| ).checked | ||||||||
| " | ||||||||
| type="checkbox" | ||||||||
| class="accent-[var(--accent-color,var(--fg-subtle))]" | ||||||||
| /> | ||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
| {{ $t('package.trends.apply_correction') }} | ||||||||
| </label> | ||||||||
| </div> | ||||||||
| </div> | ||||||||
| </div> | ||||||||
| </div> | ||||||||
| </div> | ||||||||
|
|
@@ -1798,14 +1859,23 @@ watch(selectedMetric, value => { | |||||||
| <div | ||||||||
| role="region" | ||||||||
| aria-labelledby="trends-chart-title" | ||||||||
| :class="isMobile === false && width > 0 ? 'min-h-[567px]' : 'min-h-[260px]'" | ||||||||
| :class=" | ||||||||
| isMobile === false && width > 0 | ||||||||
| ? showCorrectionControls | ||||||||
| ? 'h-[491px]' | ||||||||
| : 'h-[567px]' | ||||||||
| : 'min-h-[260px]' | ||||||||
| " | ||||||||
| > | ||||||||
| <ClientOnly v-if="chartData.dataset"> | ||||||||
| <div :data-pending="pending" :data-minimap-visible="maxDatapoints > 6"> | ||||||||
| <VueUiXy | ||||||||
| :dataset="normalisedDataset" | ||||||||
| :config="chartConfig" | ||||||||
| class="[direction:ltr]" | ||||||||
| :class="{ | ||||||||
| '[direction:ltr]': true, | ||||||||
| 'no-transition': isResizing, | ||||||||
| }" | ||||||||
| @zoomStart="setIsZoom" | ||||||||
| @zoomEnd="setIsZoom" | ||||||||
| @zoomReset="isZoomed = false" | ||||||||
|
|
@@ -2102,6 +2172,11 @@ watch(selectedMetric, value => { | |||||||
| top: calc(100% - 2rem) !important; | ||||||||
| } | ||||||||
|
|
||||||||
| .no-transition line, | ||||||||
| .no-transition circle { | ||||||||
| transition: none !important; | ||||||||
| } | ||||||||
|
|
||||||||
| input::-webkit-date-and-time-value { | ||||||||
| margin-inline: 4px; | ||||||||
| } | ||||||||
|
|
||||||||

Uh oh!
There was an error while loading. Please reload this page.