diff --git a/src/app/loading.js b/src/app/loading.js
deleted file mode 100644
index afba6f4..0000000
--- a/src/app/loading.js
+++ /dev/null
@@ -1,5 +0,0 @@
-import LoadingComponent from '@/components/Loading'
-
-export default function Loading() {
- return ()
-}
\ No newline at end of file
diff --git a/src/components/Charts/Bar.jsx b/src/components/Charts/Bar.jsx
index e09a415..0cd734a 100644
--- a/src/components/Charts/Bar.jsx
+++ b/src/components/Charts/Bar.jsx
@@ -1,6 +1,5 @@
'use client';
import React, { useRef, useState } from 'react';
-import ReactECharts from 'echarts-for-react';
import isEqual from 'lodash/isEqual';
import Loading from '../Loading';
import Link from 'next/link';
@@ -8,6 +7,13 @@ import {
ArrowTopRightOnSquareIcon,
} from '@heroicons/react/20/solid';
import CopyDropdown from '../CopyDropdown';
+import dynamic from 'next/dynamic'
+
+// ECharts depends on browser APIs (window/document), so it breaks during Next.js SSR.
+// We load it dynamically on the client only.
+const ReactECharts = dynamic(() => import('echarts-for-react'), {
+ ssr: false,
+})
export default function Bar({ data, stack, onSelect, link, metabaseLink }) {
const [loading, setLoading] = useState(true);
@@ -115,7 +121,8 @@ export default function Bar({ data, stack, onSelect, link, metabaseLink }) {
};
const onMouseOver = () => {
- const echartsInstance = chartRef.current.getEchartsInstance();
+ const echartsInstance = chartRef.current?.getEchartsInstance();
+ if (!echartsInstance) return;
echartsInstance.dispatchAction({
type: 'takeGlobalCursor',
key: 'brush',
@@ -127,7 +134,8 @@ export default function Bar({ data, stack, onSelect, link, metabaseLink }) {
const onBrushEnd = (params) => {
if (params.areas.length > 0) {
- const echartsInstance = chartRef.current.getEchartsInstance();
+ const echartsInstance = chartRef.current?.getEchartsInstance();
+ if (!echartsInstance) return;
let start = echartsInstance.convertFromPixel(
{ xAxisIndex: 0 },
params.areas[0].range[0]
diff --git a/src/components/Charts/CountryMap.jsx b/src/components/Charts/CountryMap.jsx
index 66f0b8d..c867822 100644
--- a/src/components/Charts/CountryMap.jsx
+++ b/src/components/Charts/CountryMap.jsx
@@ -1,5 +1,4 @@
'use client';
-import ReactECharts from 'echarts-for-react';
import 'echarts-countries-js/echarts-countries-js/world';
import isEqual from 'lodash/isEqual';
import Loading from '../Loading';
@@ -9,6 +8,13 @@ import {
ArrowTopRightOnSquareIcon,
} from '@heroicons/react/20/solid';
import CopyDropdown from '../CopyDropdown';
+import dynamic from 'next/dynamic'
+
+// ECharts depends on browser APIs (window/document), so it breaks during Next.js SSR.
+// We load it dynamically on the client only.
+const ReactECharts = dynamic(() => import('echarts-for-react'), {
+ ssr: false,
+})
export default function CountryMap({ data, selected, onClick, link, metabaseLink }) {
const [loading, setLoading] = useState(true);
diff --git a/src/components/Charts/Gauge.jsx b/src/components/Charts/Gauge.jsx
index d50df77..a45711f 100644
--- a/src/components/Charts/Gauge.jsx
+++ b/src/components/Charts/Gauge.jsx
@@ -1,8 +1,14 @@
'use client'
import React, { useState } from 'react'
-import ReactECharts from 'echarts-for-react';
import isEqual from 'lodash/isEqual'
import Loading from '../Loading'
+import dynamic from 'next/dynamic'
+
+// ECharts depends on browser APIs (window/document), so it breaks during Next.js SSR.
+// We load it dynamically on the client only.
+const ReactECharts = dynamic(() => import('echarts-for-react'), {
+ ssr: false,
+})
export default function Gauge({ data }) {
const [loading, setLoading] = useState(true)
diff --git a/src/components/Charts/HeatMap.jsx b/src/components/Charts/HeatMap.jsx
index cb3185c..d46ae9a 100644
--- a/src/components/Charts/HeatMap.jsx
+++ b/src/components/Charts/HeatMap.jsx
@@ -1,7 +1,6 @@
'use client';
import React, { useRef, useState } from 'react';
import isEqual from 'lodash/isEqual';
-import ReactECharts from 'echarts-for-react';
import styles from './styles.module.css';
import Loading from '../Loading';
import Link from 'next/link';
@@ -9,6 +8,13 @@ import {
ArrowTopRightOnSquareIcon,
} from '@heroicons/react/20/solid';
import CopyDropdown from '../CopyDropdown';
+import dynamic from 'next/dynamic'
+
+// ECharts depends on browser APIs (window/document), so it breaks during Next.js SSR.
+// We load it dynamically on the client only.
+const ReactECharts = dynamic(() => import('echarts-for-react'), {
+ ssr: false,
+})
export default function HeatMap({ data, title, subtitle, onClick, link, metabaseLink }) {
const chartRef = useRef();
@@ -96,7 +102,8 @@ export default function HeatMap({ data, title, subtitle, onClick, link, metabase
},
extraCssText: 'visibility: hidden;padding:0px;',
position: (point, params, dom, rect, size) => {
- const echartsInstance = chartRef.current.getEchartsInstance();
+ const echartsInstance = chartRef.current?.getEchartsInstance();
+ if (!echartsInstance) return;
const pos = echartsInstance.convertToPixel({ seriesIndex: 0 }, [
params.value[0],
params.value[1]
diff --git a/src/components/Charts/HorizontalBar.jsx b/src/components/Charts/HorizontalBar.jsx
index bd94034..5ea3dbf 100644
--- a/src/components/Charts/HorizontalBar.jsx
+++ b/src/components/Charts/HorizontalBar.jsx
@@ -1,7 +1,6 @@
'use client';
import React, { useRef, useState } from 'react';
import isEqual from 'lodash/isEqual';
-import ReactECharts from 'echarts-for-react';
import styles from './styles.module.css';
import { formatNumber, toValidStyleName } from '@/utils/utils';
import Loading from '../Loading';
@@ -10,6 +9,13 @@ import {
ArrowTopRightOnSquareIcon,
} from '@heroicons/react/20/solid';
import CopyDropdown from '../CopyDropdown';
+import dynamic from 'next/dynamic'
+
+// ECharts depends on browser APIs (window/document), so it breaks during Next.js SSR.
+// We load it dynamically on the client only.
+const ReactECharts = dynamic(() => import('echarts-for-react'), {
+ ssr: false,
+})
export default function HorizontalBar({
data,
@@ -170,7 +176,8 @@ export default function HorizontalBar({
};
const onMouseOver = () => {
- const echartsInstance = chartRef.current.getEchartsInstance();
+ const echartsInstance = chartRef.current?.getEchartsInstance();
+ if (!echartsInstance) return;
};
const onChartReady = (echarts) => {
diff --git a/src/components/Charts/Line.jsx b/src/components/Charts/Line.jsx
index 19ede2e..8170c3c 100644
--- a/src/components/Charts/Line.jsx
+++ b/src/components/Charts/Line.jsx
@@ -1,8 +1,6 @@
'use client';
import React, { useRef, useState } from 'react';
import isEqual from 'lodash/isEqual';
-import ReactECharts from 'echarts-for-react';
-
import styles from './styles.module.css';
import Loading from '../Loading';
import Link from 'next/link';
@@ -10,6 +8,13 @@ import {
ArrowTopRightOnSquareIcon,
} from '@heroicons/react/20/solid';
import CopyDropdown from '../CopyDropdown';
+import dynamic from 'next/dynamic'
+
+// ECharts depends on browser APIs (window/document), so it breaks during Next.js SSR.
+// We load it dynamically on the client only.
+const ReactECharts = dynamic(() => import('echarts-for-react'), {
+ ssr: false,
+})
export default function Line({ data, onSelect, onClear, link, metabaseLink }) {
const [loading, setLoading] = useState(true);
@@ -17,7 +22,8 @@ export default function Line({ data, onSelect, onClear, link, metabaseLink }) {
const chartRef = useRef();
const xAxis = data.map((p) => p.x);
const onMouseOver = () => {
- const echartsInstance = chartRef.current.getEchartsInstance();
+ const echartsInstance = chartRef.current?.getEchartsInstance();
+ if (!echartsInstance) return;
const newOptions = echartsInstance.getOption();
newOptions.series[0].lineStyle.opacity = 1;
newOptions.series[0].lineStyle.shadowColor = '#FAFF69';
@@ -111,7 +117,8 @@ export default function Line({ data, onSelect, onClear, link, metabaseLink }) {
},
extraCssText: 'visibility: hidden;padding:0px;',
position: (point, params, dom, rect, size) => {
- const echartsInstance = chartRef.current.getEchartsInstance();
+ const echartsInstance = chartRef.current?.getEchartsInstance();
+ if (!echartsInstance) return;
const pos = echartsInstance.convertToPixel({ seriesIndex: 0 }, [
params[0].axisValue,
params[0].value
@@ -132,13 +139,15 @@ export default function Line({ data, onSelect, onClear, link, metabaseLink }) {
}
const onMouseOut = () => {
- const echartsInstance = chartRef.current.getEchartsInstance();
+ const echartsInstance = chartRef.current?.getEchartsInstance();
+ if (!echartsInstance) return;
echartsInstance.setOption(options);
};
const onBrushEnd = (params) => {
if (params.areas.length > 0) {
- const echartsInstance = chartRef.current.getEchartsInstance();
+ const echartsInstance = chartRef.current?.getEchartsInstance();
+ if (!echartsInstance) return;
let start = echartsInstance.convertFromPixel(
{ xAxisIndex: 0 },
params.areas[0].range[0]
diff --git a/src/components/Charts/MultiLine.jsx b/src/components/Charts/MultiLine.jsx
index 2f76078..e46e854 100644
--- a/src/components/Charts/MultiLine.jsx
+++ b/src/components/Charts/MultiLine.jsx
@@ -1,6 +1,5 @@
'use client';
import React, { useRef, useState } from 'react';
-import ReactECharts from 'echarts-for-react';
import isEqual from 'lodash/isEqual';
import Loading from '../Loading';
import Link from 'next/link';
@@ -8,6 +7,13 @@ import {
ArrowTopRightOnSquareIcon,
} from '@heroicons/react/20/solid';
import CopyDropdown from '../CopyDropdown';
+import dynamic from 'next/dynamic'
+
+// ECharts depends on browser APIs (window/document), so it breaks during Next.js SSR.
+// We load it dynamically on the client only.
+const ReactECharts = dynamic(() => import('echarts-for-react'), {
+ ssr: false,
+})
export default function MultiLine({ data, stack, fill, onSelect, link, metabaseLink }) {
const [loading, setLoading] = useState(true);
@@ -117,7 +123,8 @@ export default function MultiLine({ data, stack, fill, onSelect, link, metabaseL
};
const onMouseOver = () => {
- const echartsInstance = chartRef.current.getEchartsInstance();
+ const echartsInstance = chartRef.current?.getEchartsInstance();
+ if (!echartsInstance) return;
echartsInstance.dispatchAction({
type: 'takeGlobalCursor',
key: 'brush',
@@ -129,7 +136,8 @@ export default function MultiLine({ data, stack, fill, onSelect, link, metabaseL
const onBrushEnd = (params) => {
if (params.areas.length > 0) {
- const echartsInstance = chartRef.current.getEchartsInstance();
+ const echartsInstance = chartRef.current?.getEchartsInstance();
+ if (!echartsInstance) return;
let start = echartsInstance.convertFromPixel(
{ xAxisIndex: 0 },
params.areas[0].range[0]
diff --git a/src/components/Charts/Pie.jsx b/src/components/Charts/Pie.jsx
index 47ed393..ab4ca3e 100644
--- a/src/components/Charts/Pie.jsx
+++ b/src/components/Charts/Pie.jsx
@@ -1,4 +1,3 @@
-import ReactECharts from 'echarts-for-react';
import Loading from '../Loading';
import isEqual from 'lodash/isEqual';
import { useState } from 'react';
@@ -7,6 +6,13 @@ import {
ArrowTopRightOnSquareIcon,
} from '@heroicons/react/20/solid';
import CopyDropdown from '../CopyDropdown';
+import dynamic from 'next/dynamic'
+
+// ECharts depends on browser APIs (window/document), so it breaks during Next.js SSR.
+// We load it dynamically on the client only.
+const ReactECharts = dynamic(() => import('echarts-for-react'), {
+ ssr: false,
+})
export default function Pie({ data, onClick, link, metabaseLink }) {
const [loading, setLoading] = useState(true);
diff --git a/src/components/Charts/PunchCard.jsx b/src/components/Charts/PunchCard.jsx
index 9afc666..f133936 100644
--- a/src/components/Charts/PunchCard.jsx
+++ b/src/components/Charts/PunchCard.jsx
@@ -1,6 +1,5 @@
'use client';
import React, { useState } from 'react';
-import ReactECharts from 'echarts-for-react';
import isEqual from 'lodash/isEqual';
import Loading from '../Loading';
import Link from 'next/link';
@@ -8,6 +7,13 @@ import {
ArrowTopRightOnSquareIcon,
} from '@heroicons/react/20/solid';
import CopyDropdown from '../CopyDropdown';
+import dynamic from 'next/dynamic'
+
+// ECharts depends on browser APIs (window/document), so it breaks during Next.js SSR.
+// We load it dynamically on the client only.
+const ReactECharts = dynamic(() => import('echarts-for-react'), {
+ ssr: false,
+})
export default function PunchCard({
data,
diff --git a/src/components/Charts/Radar.jsx b/src/components/Charts/Radar.jsx
index 5d2b064..5b318c0 100644
--- a/src/components/Charts/Radar.jsx
+++ b/src/components/Charts/Radar.jsx
@@ -1,5 +1,4 @@
'use client';
-import ReactECharts from 'echarts-for-react';
import isEqual from 'lodash/isEqual';
import Loading from '../Loading';
import { useState } from 'react';
@@ -7,6 +6,13 @@ import Link from 'next/link';
import {
ArrowTopRightOnSquareIcon,
} from '@heroicons/react/20/solid';
+import dynamic from 'next/dynamic'
+
+// ECharts depends on browser APIs (window/document), so it breaks during Next.js SSR.
+// We load it dynamically on the client only.
+const ReactECharts = dynamic(() => import('echarts-for-react'), {
+ ssr: false,
+})
export default function Radar({ data, onClick, link }) {
const [loading, setLoading] = useState(true);
diff --git a/src/components/Charts/Spark.jsx b/src/components/Charts/Spark.jsx
index 0ccc418..e5d3592 100644
--- a/src/components/Charts/Spark.jsx
+++ b/src/components/Charts/Spark.jsx
@@ -1,12 +1,18 @@
'use client';
import React, { useRef, useState } from 'react';
-import ReactECharts from 'echarts-for-react';
import { ArrowTopRightOnSquareIcon } from '@heroicons/react/20/solid';
import Link from 'next/link';
import { useRouter } from 'next/navigation';
import isEqual from 'lodash/isEqual';
import Image from 'next/image';
import CopyDropdown from '../CopyDropdown';
+import dynamic from 'next/dynamic'
+
+// ECharts depends on browser APIs (window/document), so it breaks during Next.js SSR.
+// We load it dynamically on the client only.
+const ReactECharts = dynamic(() => import('echarts-for-react'), {
+ ssr: false,
+})
export default function Spark({ name, data, link, metabaseLink, type='bar' }) {
const chartRef = useRef();
@@ -20,7 +26,8 @@ export default function Spark({ name, data, link, metabaseLink, type='bar' }) {
};
const onMouseOver = () => {
- const echartsInstance = chartRef.current.getEchartsInstance();
+ const echartsInstance = chartRef.current?.getEchartsInstance();
+ if (!echartsInstance) return;
const newOptions = echartsInstance.getOption();
newOptions.series[0].lineStyle.opacity = 0.8;
newOptions.series[0].lineStyle.shadowColor = '#262626';
@@ -59,8 +66,6 @@ export default function Spark({ name, data, link, metabaseLink, type='bar' }) {
top: '10px'
},
xAxis: {
- type: 'category',
- data: data.map((p) => p.x),
show: true,
type: 'category',
data: xAxis,
@@ -116,7 +121,8 @@ export default function Spark({ name, data, link, metabaseLink, type='bar' }) {
};
const onMouseOut = () => {
- const echartsInstance = chartRef.current.getEchartsInstance();
+ const echartsInstance = chartRef.current?.getEchartsInstance();
+ if (!echartsInstance) return;
echartsInstance.setOption(options);
setSelected(false);
};
diff --git a/src/components/Charts/treemap.js b/src/components/Charts/treemap.js
index 9aebaf6..bc3a680 100644
--- a/src/components/Charts/treemap.js
+++ b/src/components/Charts/treemap.js
@@ -1,6 +1,12 @@
'use client'
import React, { useRef } from 'react'
-import ReactECharts from 'echarts-for-react'
+import dynamic from 'next/dynamic'
+
+// ECharts depends on browser APIs (window/document), so it breaks during Next.js SSR.
+// We load it dynamically on the client only.
+const ReactECharts = dynamic(() => import('echarts-for-react'), {
+ ssr: false,
+})
export default function TreeMap ({data, onSelect}) {
diff --git a/src/components/DownloadList.jsx b/src/components/DownloadList.jsx
index b3dc62e..fc78c8c 100644
--- a/src/components/DownloadList.jsx
+++ b/src/components/DownloadList.jsx
@@ -34,7 +34,7 @@ async function DownloadList({
}
const { total, last_day, last_week, last_month } = data[0];
return (
-
+
@@ -47,29 +47,29 @@ async function DownloadList({
width={16}
height={16}
/>
-
-
Downloads
-
by period
-
-
-
-
-
{formatNumber(last_day)}
-
last day
-
-
-
{formatNumber(last_week)}
-
last week
-
-
-
{formatNumber(last_month)}
-
last month
-
-
-
{formatNumber(total)}
-
total
-
+
+ Downloads
+ by period
+
+
+ -
+ {formatNumber(last_day)}
+ last day
+
+ -
+ {formatNumber(last_week)}
+ last week
+
+ -
+ {formatNumber(last_month)}
+ last month
+
+ -
+ {formatNumber(total)}
+ total
+
+
@@ -81,7 +81,7 @@ async function DownloadList({
-
+
);
}
diff --git a/src/components/PackageDetails.jsx b/src/components/PackageDetails.jsx
index 7e9a95f..61fda0a 100644
--- a/src/components/PackageDetails.jsx
+++ b/src/components/PackageDetails.jsx
@@ -1,5 +1,5 @@
-import { ArrowTopRightOnSquareIcon } from '@heroicons/react/20/solid';
import Image from 'next/image';
+import Link from 'next/link';
export default function PackageDetails({
name,
@@ -7,95 +7,66 @@ export default function PackageDetails({
author_email,
licenses,
summary,
- home_page,
repo_name
}) {
return (
-
{name}
- {home_page && (
-
-
-
- )
- }
- {
- repo_name && repo_name != '' && (
-
-
-
- )
- }
+
{name}
+ {repo_name && String(repo_name).trim().length > 0 && (
+
+
+
+ )}
- { authors || author_email || licenses || summary ? (
-
+ {(authors || author_email || licenses || summary) ? (
+
{authors && (
-
- Authors:
-
- {authors.split(',').length > 3
- ? (
- <>
- {authors.split(',').slice(0, 3).join(',').trim()}...
-
- (+{authors.split(',').length - 3} more)
-
- >
- )
- : authors
- }
-
-
+ -
+ Authors:
+ {authors.split(',').length > 3 ? (
+ <>
+ {authors.split(',').slice(0, 3).join(',').trim()}...
+
+ (+{authors.split(',').length - 3} more)
+
+ >
+ ) : authors}
+
)}
{author_email && (
-
- Author Email:
- {author_email}
-
+ -
+ Author Email:
+ {author_email}
+
)}
{licenses && (
-
- License:
-
- {licenses.replace(/^[-\s]+|[-\s]+$/g, '').split(' ').slice(0, 10).join(' ')}{licenses.split(' ').length > 10 && '...'}
-
-
+ -
+ License:
+ {licenses.replace(/^[-\s]+|[-\s]+$/g, '').split(' ').slice(0, 10).join(' ')}{licenses.split(' ').length > 10 && '...'}
+
)}
{summary && (
-
- Summary:
-
- {summary.split(' ').length > 25
- ? `${summary.split(' ').slice(0, 25).join(' ')}...`
- : summary
- }
-
-
+ -
+ Summary:
+ {summary.split(' ').length > 25 ? `${summary.split(' ').slice(0, 25).join(' ')}...` : summary}
+
)}
-
+
) : (
No package details available
- )
- }
+ )}
);
}