diff --git a/package.json b/package.json index 1ff1730d..64e09463 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "umami", - "version": "2.5.0", + "version": "2.6.0", "description": "A simple, fast, privacy-focused alternative to Google Analytics.", "author": "Mike Cao ", "license": "MIT", diff --git a/rollup.components.config.mjs b/rollup.components.config.mjs index a0b8efbd..c4481d0e 100644 --- a/rollup.components.config.mjs +++ b/rollup.components.config.mjs @@ -29,16 +29,6 @@ const aliasConfig = { customResolver, }; -const external = [ - 'react', - 'react-dom', - 'react/jsx-runtime', - 'react-intl', - 'react-basics', - 'classnames', - 'next', -]; - const jsBundle = { input: 'src/index.ts', output: [ diff --git a/scripts/download-country-names.js b/scripts/download-country-names.js index f56d91f9..6dbbbbdc 100644 --- a/scripts/download-country-names.js +++ b/scripts/download-country-names.js @@ -4,7 +4,7 @@ const path = require('path'); const https = require('https'); const chalk = require('chalk'); -const src = path.resolve(__dirname, '../lang'); +const src = path.resolve(__dirname, '../src/lang'); const dest = path.resolve(__dirname, '../public/intl/country'); const files = fs.readdirSync(src); diff --git a/scripts/download-language-names.js b/scripts/download-language-names.js index 5cea88cf..5478fb8d 100644 --- a/scripts/download-language-names.js +++ b/scripts/download-language-names.js @@ -4,7 +4,7 @@ const path = require('path'); const https = require('https'); const chalk = require('chalk'); -const src = path.resolve(__dirname, '../lang'); +const src = path.resolve(__dirname, '../src/lang'); const dest = path.resolve(__dirname, '../public/intl/language'); const files = fs.readdirSync(src); diff --git a/scripts/format-lang.js b/scripts/format-lang.js index 941fd672..593e296d 100644 --- a/scripts/format-lang.js +++ b/scripts/format-lang.js @@ -3,7 +3,7 @@ const path = require('path'); const del = require('del'); const prettier = require('prettier'); -const src = path.resolve(__dirname, '../lang'); +const src = path.resolve(__dirname, '../src/lang'); const dest = path.resolve(__dirname, '../build/messages'); const files = fs.readdirSync(src); @@ -17,7 +17,7 @@ async function run() { await fs.ensureDir(dest); files.forEach(file => { - const lang = require(`../lang/${file}`); + const lang = require(`../src/lang/${file}`); const keys = Object.keys(lang).sort(); const formatted = keys.reduce((obj, key) => { diff --git a/src/components/common/MobileMenu.js b/src/components/common/MobileMenu.js index 2228a3e9..de1e9ffa 100644 --- a/src/components/common/MobileMenu.js +++ b/src/components/common/MobileMenu.js @@ -1,3 +1,4 @@ +import { createPortal } from 'react-dom'; import classNames from 'classnames'; import { useRouter } from 'next/router'; import Link from 'next/link'; @@ -28,10 +29,11 @@ export function MobileMenu({ items = [], onClose }) { ); - return ( + return createPortal(
-
+ , + document.body, ); } diff --git a/src/components/input/WebsiteDateFilter.js b/src/components/input/WebsiteDateFilter.js index 5ab19e60..6903a708 100644 --- a/src/components/input/WebsiteDateFilter.js +++ b/src/components/input/WebsiteDateFilter.js @@ -8,9 +8,10 @@ import styles from './WebsiteDateFilter.module.css'; export function WebsiteDateFilter({ websiteId }) { const [dateRange, setDateRange] = useDateRange(websiteId); const { value, startDate, endDate, selectedUnit } = dateRange; - const isFutureDate = - value !== 'all' && isAfter(incrementDateRange(dateRange, -1).startDate, new Date()); + value !== 'all' && + selectedUnit && + isAfter(incrementDateRange(dateRange, -1).startDate, new Date()); const handleChange = value => { setDateRange(value); @@ -21,7 +22,21 @@ export function WebsiteDateFilter({ websiteId }) { }; return ( - <> + + {value !== 'all' && selectedUnit && ( + + + + + )} - {value !== 'all' && ( - - - - - - )} - + ); } diff --git a/src/components/input/WebsiteDateFilter.module.css b/src/components/input/WebsiteDateFilter.module.css index 13234c55..986f5c17 100644 --- a/src/components/input/WebsiteDateFilter.module.css +++ b/src/components/input/WebsiteDateFilter.module.css @@ -1,3 +1,14 @@ .dropdown { min-width: 200px; } + +.buttons button:first-child { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} + +.buttons button:last-child { + border-top-left-radius: 0; + border-bottom-left-radius: 0; + border-left: 1px solid var(--base400) !important; +} diff --git a/src/components/layout/AppLayout.module.css b/src/components/layout/AppLayout.module.css index be51f83c..bcce963f 100644 --- a/src/components/layout/AppLayout.module.css +++ b/src/components/layout/AppLayout.module.css @@ -10,7 +10,7 @@ width: 100vw; grid-column: 1; grid-row: 1 / 2; - z-index: 1; + z-index: var(--z-index-popup); } .body { diff --git a/src/components/metrics/FilterTags.js b/src/components/metrics/FilterTags.js index 30857a6b..cb88a7db 100644 --- a/src/components/metrics/FilterTags.js +++ b/src/components/metrics/FilterTags.js @@ -1,8 +1,8 @@ import { safeDecodeURI } from 'next-basics'; import { Button, Icon, Icons, Text } from 'react-basics'; import usePageQuery from 'components/hooks/usePageQuery'; -import styles from './FilterTags.module.css'; import useMessages from 'components/hooks/useMessages'; +import styles from './FilterTags.module.css'; export function FilterTags({ params }) { const { formatMessage, labels } = useMessages(); @@ -26,6 +26,7 @@ export function FilterTags({ params }) { return (
+
{formatMessage(labels.filters)}
{Object.keys(params).map(key => { if (!params[key]) { return null; diff --git a/src/components/metrics/FilterTags.module.css b/src/components/metrics/FilterTags.module.css index 1c8458ac..c228dc4e 100644 --- a/src/components/metrics/FilterTags.module.css +++ b/src/components/metrics/FilterTags.module.css @@ -4,19 +4,23 @@ gap: 10px; } +.label { + font-weight: 700; +} + .tag { display: flex; flex-direction: row; align-items: center; gap: 10px; font-size: var(--font-size-sm); - border: 1px solid var(--base600); + border: 1px solid var(--blue400); border-radius: var(--border-radius); - line-height: 30px; - padding: 0 8px; + padding: 8px 16px; cursor: pointer; + background: var(--blue100); } .tag:hover { - background: var(--base75); + background: var(--blue200); } diff --git a/src/components/pages/websites/WebsiteDetailsPage.js b/src/components/pages/websites/WebsiteDetailsPage.js index c5ac4775..222d94d9 100644 --- a/src/components/pages/websites/WebsiteDetailsPage.js +++ b/src/components/pages/websites/WebsiteDetailsPage.js @@ -22,12 +22,12 @@ export default function WebsiteDetailsPage({ websiteId }) { return ( - - + + {!website && } {website && ( <> diff --git a/src/components/pages/websites/WebsiteEventData.js b/src/components/pages/websites/WebsiteEventData.js index ea8e473b..d38ca1ad 100644 --- a/src/components/pages/websites/WebsiteEventData.js +++ b/src/components/pages/websites/WebsiteEventData.js @@ -1,4 +1,4 @@ -import { Flexbox } from 'react-basics'; +import { Flexbox, Loading } from 'react-basics'; import EventDataTable from 'components/pages/event-data/EventDataTable'; import EventDataValueTable from 'components/pages/event-data/EventDataValueTable'; import { EventDataMetricsBar } from 'components/pages/event-data/EventDataMetricsBar'; @@ -28,13 +28,14 @@ export default function WebsiteEventData({ websiteId }) { const { query: { event }, } = usePageQuery(); - const { data } = useData(websiteId, event); + const { data, isLoading } = useData(websiteId, event); return ( {!event && } - {event && } + {isLoading && } + {event && data && } ); } diff --git a/src/components/pages/websites/WebsiteMetricsBar.js b/src/components/pages/websites/WebsiteMetricsBar.js index 35605804..0d1a20f0 100644 --- a/src/components/pages/websites/WebsiteMetricsBar.js +++ b/src/components/pages/websites/WebsiteMetricsBar.js @@ -7,10 +7,10 @@ import MetricsBar from 'components/metrics/MetricsBar'; import FilterSelectForm from 'components/pages/reports/FilterSelectForm'; import PopupForm from 'components/pages/reports/PopupForm'; import { formatShortTime } from 'lib/format'; -import { Button, Column, Icon, Icons, Popup, PopupTrigger, Row, TooltipPopup } from 'react-basics'; +import { Button, Column, Icon, Icons, Popup, PopupTrigger, Row } from 'react-basics'; import styles from './WebsiteMetricsBar.module.css'; -export function WebsiteMetricsBar({ websiteId, showFilter = true, sticky }) { +export function WebsiteMetricsBar({ websiteId, showFilter = true, showRefresh = true, sticky }) { const { formatMessage, labels } = useMessages(); const { get, useQuery } = useApi(); @@ -71,14 +71,12 @@ export function WebsiteMetricsBar({ websiteId, showFilter = true, sticky }) { const WebsiteFilterButton = () => { return ( - - - + {close => { return ( @@ -163,8 +161,8 @@ export function WebsiteMetricsBar({ websiteId, showFilter = true, sticky }) {
{showFilter && } + {showRefresh && } -