mirror of
https://github.com/umami-software/umami.git
synced 2026-02-04 12:47:13 +01:00
New menu layout.
This commit is contained in:
parent
0cfee43814
commit
1c22c18de5
17 changed files with 103 additions and 47 deletions
|
|
@ -19,6 +19,7 @@ export function App({ children }) {
|
|||
|
||||
if (error) {
|
||||
window.location.href = `${process.env.basePath || ''}/login`;
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!user || !config) {
|
||||
|
|
@ -30,7 +31,7 @@ export function App({ children }) {
|
|||
}
|
||||
|
||||
return (
|
||||
<Grid height="100vh" width="100%" columns="auto 1fr" rows="auto 1fr" overflow="hidden">
|
||||
<Grid height="100vh" width="100%" columns="auto 1fr" rows="auto 1fr">
|
||||
<Nav gridColumn="1 / 2" gridRow="1 / 3" />
|
||||
<MenuBar gridColumn="2 / 3" gridRow="1 / 2" />
|
||||
<Column
|
||||
|
|
@ -39,6 +40,7 @@ export function App({ children }) {
|
|||
alignItems="center"
|
||||
overflow="auto"
|
||||
backgroundColor="2"
|
||||
position="relative"
|
||||
>
|
||||
<Page>
|
||||
{children}
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ export function Nav(props: any) {
|
|||
].filter(n => n);
|
||||
|
||||
return (
|
||||
<SideNav {...props} isCollapsed={isCollapsed} variant="0" showBorder={true}>
|
||||
<SideNav {...props} isCollapsed={isCollapsed} variant="2" showBorder={true}>
|
||||
<SideNavSection>
|
||||
<SideNavHeader label="umami" icon={<Icons.Logo />} />
|
||||
</SideNavSection>
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import { Panel } from '@/components/common/Panel';
|
|||
import { useNavigation } from '@/components/hooks';
|
||||
import { WebsiteChart } from './WebsiteChart';
|
||||
import { WebsiteExpandedView } from './WebsiteExpandedView';
|
||||
import { WebsiteHeader } from './WebsiteHeader';
|
||||
import { WebsiteMetricsBar } from './WebsiteMetricsBar';
|
||||
import { WebsiteTableView } from './WebsiteTableView';
|
||||
import { WebsiteCompareTables } from './WebsiteCompareTables';
|
||||
|
|
@ -15,8 +14,7 @@ export function WebsiteDetailsPage({ websiteId }: { websiteId: string }) {
|
|||
} = useNavigation();
|
||||
|
||||
return (
|
||||
<Column gap="3">
|
||||
<WebsiteHeader websiteId={websiteId} />
|
||||
<Column gap>
|
||||
<Panel>
|
||||
<WebsiteMetricsBar websiteId={websiteId} showFilter={true} showChange={true} />
|
||||
</Panel>
|
||||
|
|
|
|||
13
src/app/(main)/websites/[websiteId]/WebsiteLayout.tsx
Normal file
13
src/app/(main)/websites/[websiteId]/WebsiteLayout.tsx
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
'use client';
|
||||
import { ReactNode } from 'react';
|
||||
import { WebsiteProvider } from './WebsiteProvider';
|
||||
import { WebsiteHeader } from '@/app/(main)/websites/[websiteId]/WebsiteHeader';
|
||||
|
||||
export function WebsiteLayout({ websiteId, children }: { websiteId: string; children: ReactNode }) {
|
||||
return (
|
||||
<WebsiteProvider websiteId={websiteId}>
|
||||
<WebsiteHeader websiteId={websiteId} />
|
||||
{children}
|
||||
</WebsiteProvider>
|
||||
);
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
import { Tabs, TabList, Tab, Icon, Text, Row } from '@umami/react-zen';
|
||||
import { Column, Icon, Text, Row } from '@umami/react-zen';
|
||||
import { Icons } from '@/components/icons';
|
||||
import { useMessages, useNavigation } from '@/components/hooks';
|
||||
import Link from 'next/link';
|
||||
|
||||
export function WebsiteTabs({ websiteId }: { websiteId: string }) {
|
||||
const { formatMessage, labels } = useMessages();
|
||||
|
|
@ -31,6 +32,54 @@ export function WebsiteTabs({ websiteId }: { websiteId: string }) {
|
|||
icon: <Icons.Clock />,
|
||||
path: '/realtime',
|
||||
},
|
||||
{
|
||||
id: 'insights',
|
||||
label: formatMessage(labels.insights),
|
||||
icon: <Icons.Lightbulb />,
|
||||
path: '/insights',
|
||||
},
|
||||
{
|
||||
id: 'goals',
|
||||
label: formatMessage(labels.goals),
|
||||
icon: <Icons.Target />,
|
||||
path: '/goals',
|
||||
},
|
||||
{
|
||||
id: 'funnel',
|
||||
label: formatMessage(labels.funnel),
|
||||
icon: <Icons.Funnel />,
|
||||
path: '/funnels',
|
||||
},
|
||||
{
|
||||
id: 'journeys',
|
||||
label: formatMessage(labels.journey),
|
||||
icon: <Icons.Path />,
|
||||
path: '/goals',
|
||||
},
|
||||
{
|
||||
id: 'retention',
|
||||
label: formatMessage(labels.retention),
|
||||
icon: <Icons.Magnet />,
|
||||
path: '/funnels',
|
||||
},
|
||||
{
|
||||
id: 'utm',
|
||||
label: formatMessage(labels.utm),
|
||||
icon: <Icons.Tag />,
|
||||
path: '/utm',
|
||||
},
|
||||
{
|
||||
id: 'revenue',
|
||||
label: formatMessage(labels.revenue),
|
||||
icon: <Icons.Money />,
|
||||
path: '/revenue',
|
||||
},
|
||||
{
|
||||
id: 'attribution',
|
||||
label: formatMessage(labels.attribution),
|
||||
icon: <Icons.Network />,
|
||||
path: '/attribution',
|
||||
},
|
||||
{
|
||||
id: 'reports',
|
||||
label: formatMessage(labels.reports),
|
||||
|
|
@ -39,24 +88,29 @@ export function WebsiteTabs({ websiteId }: { websiteId: string }) {
|
|||
},
|
||||
];
|
||||
|
||||
const selectedKey = links
|
||||
const selected = links
|
||||
? links.find(({ path }) => path && pathname.endsWith(path))?.id
|
||||
: 'overview';
|
||||
|
||||
return (
|
||||
<Tabs selectedKey={selectedKey}>
|
||||
<TabList items={links}>
|
||||
{({ id, label, icon, path }) => {
|
||||
return (
|
||||
<Tab id={id} href={renderTeamUrl(`/websites/${websiteId}/${path}`)}>
|
||||
<Row gap="3" alignItems="center">
|
||||
<Icon fillColor="currentColor">{icon}</Icon>
|
||||
<Text>{label}</Text>
|
||||
</Row>
|
||||
</Tab>
|
||||
);
|
||||
}}
|
||||
</TabList>
|
||||
</Tabs>
|
||||
<Column gap="2" position="absolute" padding="4" style={{ top: 0, left: 0, bottom: 0 }}>
|
||||
{links.map(({ id, label, icon, path }) => {
|
||||
return (
|
||||
<Link key={id} href={renderTeamUrl(`/websites/${websiteId}/${path}`)}>
|
||||
<Row
|
||||
alignItems="center"
|
||||
padding
|
||||
gap
|
||||
hoverBackgroundColor="3"
|
||||
borderRadius
|
||||
width="160px"
|
||||
>
|
||||
<Icon fillColor="currentColor">{icon}</Icon>
|
||||
<Text weight={selected === id ? 'bold' : undefined}>{label}</Text>
|
||||
</Row>
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
</Column>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
import { TabList, Tab, Tabs, TabPanel, Column } from '@umami/react-zen';
|
||||
import { EventsTable } from '@/components/metrics/EventsTable';
|
||||
import { useState } from 'react';
|
||||
import { WebsiteHeader } from '../WebsiteHeader';
|
||||
import { EventsDataTable } from './EventsDataTable';
|
||||
import { EventsMetricsBar } from './EventsMetricsBar';
|
||||
import { Panel } from '@/components/common/Panel';
|
||||
|
|
@ -22,7 +21,6 @@ export function EventsPage({ websiteId }) {
|
|||
|
||||
return (
|
||||
<Column gap="3">
|
||||
<WebsiteHeader websiteId={websiteId} />
|
||||
<Panel>
|
||||
<EventsMetricsBar websiteId={websiteId} />
|
||||
</Panel>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { Metadata } from 'next';
|
||||
import { WebsiteProvider } from './WebsiteProvider';
|
||||
import { WebsiteLayout } from '@/app/(main)/websites/[websiteId]/WebsiteLayout';
|
||||
|
||||
export default async function ({
|
||||
children,
|
||||
|
|
@ -10,7 +10,7 @@ export default async function ({
|
|||
}) {
|
||||
const { websiteId } = await params;
|
||||
|
||||
return <WebsiteProvider websiteId={websiteId}>{children}</WebsiteProvider>;
|
||||
return <WebsiteLayout websiteId={websiteId}>{children}</WebsiteLayout>;
|
||||
}
|
||||
|
||||
export const metadata: Metadata = {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ import { RealtimeLog } from './RealtimeLog';
|
|||
import { RealtimeHeader } from './RealtimeHeader';
|
||||
import { RealtimeUrls } from './RealtimeUrls';
|
||||
import { RealtimeCountries } from './RealtimeCountries';
|
||||
import { WebsiteHeader } from '../WebsiteHeader';
|
||||
import { percentFilter } from '@/lib/filters';
|
||||
|
||||
export function WebsiteRealtimePage({ websiteId }: { websiteId: string }) {
|
||||
|
|
@ -29,7 +28,6 @@ export function WebsiteRealtimePage({ websiteId }: { websiteId: string }) {
|
|||
|
||||
return (
|
||||
<Grid gap="3">
|
||||
<WebsiteHeader websiteId={websiteId} />
|
||||
<Panel>
|
||||
<RealtimeHeader data={data} />
|
||||
</Panel>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
import Link from 'next/link';
|
||||
import { Button, Flexbox, Icon, Icons, Text } from '@umami/react-zen';
|
||||
import { useMessages, useNavigation } from '@/components/hooks';
|
||||
import { WebsiteHeader } from '../WebsiteHeader';
|
||||
import { ReportsDataTable } from '@/app/(main)/reports/ReportsDataTable';
|
||||
|
||||
export function WebsiteReportsPage({ websiteId }) {
|
||||
|
|
@ -11,7 +10,6 @@ export function WebsiteReportsPage({ websiteId }) {
|
|||
|
||||
return (
|
||||
<>
|
||||
<WebsiteHeader websiteId={websiteId} />
|
||||
<Flexbox alignItems="center" justifyContent="end">
|
||||
<Link href={renderTeamUrl('/reports/create')}>
|
||||
<Button variant="primary">
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
'use client';
|
||||
import { useState } from 'react';
|
||||
import { TabList, Tab, Tabs, TabPanel, Column } from '@umami/react-zen';
|
||||
import { WebsiteHeader } from '../WebsiteHeader';
|
||||
import { SessionsDataTable } from './SessionsDataTable';
|
||||
import { SessionsMetricsBar } from './SessionsMetricsBar';
|
||||
import { SessionProperties } from './SessionProperties';
|
||||
|
|
@ -17,7 +16,6 @@ export function SessionsPage({ websiteId }) {
|
|||
|
||||
return (
|
||||
<Column gap="3">
|
||||
<WebsiteHeader websiteId={websiteId} />
|
||||
<Panel>
|
||||
<SessionsMetricsBar websiteId={websiteId} />
|
||||
</Panel>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ import { Grid, Row, Column } from '@umami/react-zen';
|
|||
import { Avatar } from '@/components/common/Avatar';
|
||||
import { LoadingPanel } from '@/components/common/LoadingPanel';
|
||||
import { useWebsiteSessionQuery } from '@/components/hooks';
|
||||
import { WebsiteHeader } from '@/app/(main)/websites/[websiteId]/WebsiteHeader';
|
||||
import { SessionActivity } from './SessionActivity';
|
||||
import { SessionData } from './SessionData';
|
||||
import { SessionInfo } from './SessionInfo';
|
||||
|
|
@ -21,7 +20,6 @@ export function SessionDetailsPage({
|
|||
|
||||
return (
|
||||
<LoadingPanel {...query} loadingIcon="spinner" data={data}>
|
||||
<WebsiteHeader websiteId={websiteId} />
|
||||
<Grid
|
||||
gap
|
||||
columns={{ xs: '1fr', sm: '1fr', md: '1fr 1fr', lg: '1fr 2fr 1fr', xl: '1fr 2fr 1fr' }}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { Icon, Row, Text } from '@umami/react-zen';
|
||||
import { differenceInDays, isSameDay } from 'date-fns';
|
||||
import { useLocale } from '@/components/hooks';
|
||||
import { Icons } from '@/components/icons';
|
||||
import { Lucide } from '@/components/icons';
|
||||
import { formatDate } from '@/lib/date';
|
||||
|
||||
export function DateDisplay({ startDate, endDate }) {
|
||||
|
|
@ -11,7 +11,7 @@ export function DateDisplay({ startDate, endDate }) {
|
|||
return (
|
||||
<Row gap="3" alignItems="center" wrap="nowrap">
|
||||
<Icon>
|
||||
<Icons.Calendar />
|
||||
<Lucide.Calendar />
|
||||
</Icon>
|
||||
<Text wrap="nowrap">
|
||||
{isSingleDate ? (
|
||||
|
|
|
|||
|
|
@ -106,6 +106,7 @@ export function DateFilter({
|
|||
placeholder={formatMessage(labels.selectDate)}
|
||||
onChange={handleChange}
|
||||
renderValue={renderValue}
|
||||
popoverProps={{ style: { width: 200 } }}
|
||||
>
|
||||
{options.map(({ label, value, divider }: any) => {
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -85,8 +85,8 @@ export function WebsiteDateFilter({
|
|||
/>
|
||||
{!isAllTime && compare && (
|
||||
<Row alignItems="center" gap>
|
||||
<Text>VS</Text>
|
||||
<Select selectedKey={compare} onSelectionChange={handleSelect} style={{ width: '200px' }}>
|
||||
<Text weight="bold">VS</Text>
|
||||
<Select value={compare} onChange={handleSelect} popoverProps={{ style: { width: 200 } }}>
|
||||
<ListItem id="prev">{formatMessage(labels.previousPeriod)}</ListItem>
|
||||
<ListItem id="yoy">{formatMessage(labels.previousYear)}</ListItem>
|
||||
</Select>
|
||||
|
|
|
|||
|
|
@ -26,16 +26,16 @@ export function FilterBar({ websiteId }: { websiteId: string }) {
|
|||
return (
|
||||
<Row
|
||||
gap
|
||||
backgroundColor="1"
|
||||
backgroundColor="3"
|
||||
alignItems="center"
|
||||
justifyContent="space-between"
|
||||
paddingY="3"
|
||||
paddingLeft="5"
|
||||
paddingY="2"
|
||||
paddingLeft="3"
|
||||
paddingRight="2"
|
||||
border
|
||||
borderRadius="2"
|
||||
>
|
||||
<Row alignItems="center" gap="3" wrap="wrap">
|
||||
<Row alignItems="center" gap="3" wrap="wrap" paddingX="2">
|
||||
<Text color="11" weight="bold">
|
||||
{formatMessage(labels.filters)}
|
||||
</Text>
|
||||
|
|
@ -61,11 +61,9 @@ export function FilterBar({ websiteId }: { websiteId: string }) {
|
|||
<Text color="11">{operatorLabels[operator]}</Text>
|
||||
<Text weight="bold">{paramValue}</Text>
|
||||
</Row>
|
||||
<Button variant="quiet" size="xs" style={{ left: '5px' }}>
|
||||
<Icon onClick={e => handleCloseFilter(name, e)} size="xs">
|
||||
<Icons.Close />
|
||||
</Icon>
|
||||
</Button>
|
||||
<Icon onClick={e => handleCloseFilter(name, e)} size="xs">
|
||||
<Icons.Close />
|
||||
</Icon>
|
||||
</Row>
|
||||
</Row>
|
||||
);
|
||||
|
|
|
|||
1
src/declaration.d.ts
vendored
1
src/declaration.d.ts
vendored
|
|
@ -6,3 +6,4 @@ declare module 'fs-extra';
|
|||
declare module 'jsonwebtoken';
|
||||
declare module 'md5';
|
||||
declare module 'prettier';
|
||||
declare module 'semver';
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ body {
|
|||
background-color: var(--background-color);
|
||||
width: 100%;
|
||||
min-height: 100vh;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
a,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue