update dashboard metrics and move away from round corners
This commit is contained in:
@@ -12,7 +12,7 @@ export function StickyBelowHeader({
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
'top-0 z-20 rounded-lg border-b border-border bg-background md:sticky [[id=dashboard]_&]:top-16 [[id=dashboard]_&]:rounded-none',
|
'top-0 z-20 border-b border-border bg-background md:sticky [[id=dashboard]_&]:top-16 [[id=dashboard]_&]:rounded-none',
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -41,9 +41,6 @@ export default function Page({
|
|||||||
<OverviewFiltersButtons />
|
<OverviewFiltersButtons />
|
||||||
</StickyBelowHeader>
|
</StickyBelowHeader>
|
||||||
<div className="grid grid-cols-6 gap-4 p-4">
|
<div className="grid grid-cols-6 gap-4 p-4">
|
||||||
<div className="col-span-6">
|
|
||||||
<OverviewLiveHistogram projectId={projectId} />
|
|
||||||
</div>
|
|
||||||
<OverviewMetrics projectId={projectId} />
|
<OverviewMetrics projectId={projectId} />
|
||||||
<OverviewTopSources projectId={projectId} />
|
<OverviewTopSources projectId={projectId} />
|
||||||
<OverviewTopPages projectId={projectId} />
|
<OverviewTopPages projectId={projectId} />
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import {
|
|||||||
eachDayOfInterval,
|
eachDayOfInterval,
|
||||||
endOfMonth,
|
endOfMonth,
|
||||||
format,
|
format,
|
||||||
|
formatISO,
|
||||||
startOfMonth,
|
startOfMonth,
|
||||||
subMonths,
|
subMonths,
|
||||||
} from 'date-fns';
|
} from 'date-fns';
|
||||||
@@ -60,7 +61,9 @@ const ProfileActivity = ({ data }: Props) => {
|
|||||||
end: endOfMonth(subMonths(startDate, 1)),
|
end: endOfMonth(subMonths(startDate, 1)),
|
||||||
}).map((date) => {
|
}).map((date) => {
|
||||||
const hit = data.find((item) =>
|
const hit = data.find((item) =>
|
||||||
item.date.includes(date.toISOString().split('T')[0])
|
item.date.includes(
|
||||||
|
formatISO(date, { representation: 'date' })
|
||||||
|
)
|
||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@@ -82,7 +85,9 @@ const ProfileActivity = ({ data }: Props) => {
|
|||||||
end: endDate,
|
end: endDate,
|
||||||
}).map((date) => {
|
}).map((date) => {
|
||||||
const hit = data.find((item) =>
|
const hit = data.find((item) =>
|
||||||
item.date.includes(date.toISOString().split('T')[0])
|
item.date.includes(
|
||||||
|
formatISO(date, { representation: 'date' })
|
||||||
|
)
|
||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -18,9 +18,15 @@ interface PageProps {
|
|||||||
params: {
|
params: {
|
||||||
id: string;
|
id: string;
|
||||||
};
|
};
|
||||||
|
searchParams: {
|
||||||
|
header: string;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function Page({ params: { id } }: PageProps) {
|
export default async function Page({
|
||||||
|
params: { id },
|
||||||
|
searchParams,
|
||||||
|
}: PageProps) {
|
||||||
const share = await getShareOverviewById(id);
|
const share = await getShareOverviewById(id);
|
||||||
if (!share) {
|
if (!share) {
|
||||||
return notFound();
|
return notFound();
|
||||||
@@ -32,20 +38,23 @@ export default async function Page({ params: { id } }: PageProps) {
|
|||||||
const organization = await getOrganizationBySlug(share.organizationSlug);
|
const organization = await getOrganizationBySlug(share.organizationSlug);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-gradient-to-tl from-blue-950 to-blue-600 p-4 md:p-16">
|
<div>
|
||||||
<div className="mx-auto max-w-6xl">
|
{searchParams.header !== '0' && (
|
||||||
<div className="mb-4 flex items-end justify-between">
|
<div className="flex items-center justify-between border-b border-border bg-white p-4">
|
||||||
<div className="leading-none">
|
<div className="leading-none">
|
||||||
<span className="mb-4 text-white">{organization?.name}</span>
|
<span className="mb-4">{organization?.name}</span>
|
||||||
<h1 className="text-xl font-medium text-white">
|
<h1 className="text-xl font-medium">{share.project?.name}</h1>
|
||||||
{share.project?.name}
|
|
||||||
</h1>
|
|
||||||
</div>
|
</div>
|
||||||
<a href="https://openpanel.dev?utm_source=openpanel.dev&utm_medium=share">
|
<a
|
||||||
<Logo className="text-white max-sm:[&_span]:hidden" />
|
href="https://openpanel.dev?utm_source=openpanel.dev&utm_medium=share"
|
||||||
|
className="flex flex-col items-end text-lg font-medium"
|
||||||
|
>
|
||||||
|
<span className="text-xs">POWERED BY</span>
|
||||||
|
<span>openpanel.dev</span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div className="rounded-lg bg-slate-100 shadow ring-8 ring-blue-600/50 max-sm:-mx-3">
|
)}
|
||||||
|
<div className="">
|
||||||
<StickyBelowHeader>
|
<StickyBelowHeader>
|
||||||
<div className="flex justify-between gap-2 p-4">
|
<div className="flex justify-between gap-2 p-4">
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
@@ -58,10 +67,7 @@ export default async function Page({ params: { id } }: PageProps) {
|
|||||||
</div>
|
</div>
|
||||||
<OverviewFiltersButtons />
|
<OverviewFiltersButtons />
|
||||||
</StickyBelowHeader>
|
</StickyBelowHeader>
|
||||||
<div className="grid grid-cols-6 gap-4 p-4">
|
<div className="mx-auto grid max-w-7xl grid-cols-6 gap-4 p-4">
|
||||||
<div className="col-span-6">
|
|
||||||
<OverviewLiveHistogram projectId={projectId} />
|
|
||||||
</div>
|
|
||||||
<OverviewMetrics projectId={projectId} />
|
<OverviewMetrics projectId={projectId} />
|
||||||
<OverviewTopSources projectId={projectId} />
|
<OverviewTopSources projectId={projectId} />
|
||||||
<OverviewTopPages projectId={projectId} />
|
<OverviewTopPages projectId={projectId} />
|
||||||
@@ -71,6 +77,5 @@ export default async function Page({ params: { id } }: PageProps) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,8 +12,6 @@ import { useQueryClient } from '@tanstack/react-query';
|
|||||||
import dynamic from 'next/dynamic';
|
import dynamic from 'next/dynamic';
|
||||||
import { toast } from 'sonner';
|
import { toast } from 'sonner';
|
||||||
|
|
||||||
import { useOverviewOptions } from '../useOverviewOptions';
|
|
||||||
|
|
||||||
export interface LiveCounterProps {
|
export interface LiveCounterProps {
|
||||||
data: number;
|
data: number;
|
||||||
projectId: string;
|
projectId: string;
|
||||||
@@ -27,7 +25,6 @@ const AnimatedNumbers = dynamic(() => import('react-animated-numbers'), {
|
|||||||
const FIFTEEN_SECONDS = 1000 * 15;
|
const FIFTEEN_SECONDS = 1000 * 15;
|
||||||
|
|
||||||
export default function LiveCounter({ data = 0, projectId }: LiveCounterProps) {
|
export default function LiveCounter({ data = 0, projectId }: LiveCounterProps) {
|
||||||
const { setLiveHistogram } = useOverviewOptions();
|
|
||||||
const client = useQueryClient();
|
const client = useQueryClient();
|
||||||
const [counter, setCounter] = useState(data);
|
const [counter, setCounter] = useState(data);
|
||||||
const lastRefresh = useRef(Date.now());
|
const lastRefresh = useRef(Date.now());
|
||||||
@@ -47,24 +44,20 @@ export default function LiveCounter({ data = 0, projectId }: LiveCounterProps) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Tooltip>
|
<Tooltip>
|
||||||
<TooltipTrigger asChild>
|
<TooltipTrigger className="flex h-8 items-center gap-2 rounded border border-border px-3 font-medium leading-none">
|
||||||
<button
|
|
||||||
onClick={() => setLiveHistogram((p) => !p)}
|
|
||||||
className="flex h-8 items-center gap-2 rounded border border-border px-3 font-medium leading-none"
|
|
||||||
>
|
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
'h-3 w-3 animate-ping rounded-full bg-emerald-500 opacity-100 transition-all',
|
'h-3 w-3 animate-ping rounded-full bg-emerald-500 opacity-100 transition-all',
|
||||||
counter === 0 && 'bg-destructive opacity-0'
|
counter === 0 && 'bg-destructive opacity-0'
|
||||||
)}
|
)}
|
||||||
></div>
|
/>
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
'absolute left-0 top-0 h-3 w-3 rounded-full bg-emerald-500 transition-all',
|
'absolute left-0 top-0 h-3 w-3 rounded-full bg-emerald-500 transition-all',
|
||||||
counter === 0 && 'bg-destructive'
|
counter === 0 && 'bg-destructive'
|
||||||
)}
|
)}
|
||||||
></div>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<AnimatedNumbers
|
<AnimatedNumbers
|
||||||
includeComma
|
includeComma
|
||||||
@@ -78,7 +71,6 @@ export default function LiveCounter({ data = 0, projectId }: LiveCounterProps) {
|
|||||||
animateToNumber={counter}
|
animateToNumber={counter}
|
||||||
locale="en"
|
locale="en"
|
||||||
/>
|
/>
|
||||||
</button>
|
|
||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
<TooltipContent side="bottom">
|
<TooltipContent side="bottom">
|
||||||
<p>{counter} unique visitors last 5 minutes</p>
|
<p>{counter} unique visitors last 5 minutes</p>
|
||||||
|
|||||||
@@ -5,9 +5,7 @@ import { cn } from '@/utils/cn';
|
|||||||
|
|
||||||
import type { IChartInput } from '@openpanel/validation';
|
import type { IChartInput } from '@openpanel/validation';
|
||||||
|
|
||||||
import AnimateHeight from '../animate-height';
|
|
||||||
import { Tooltip, TooltipContent, TooltipTrigger } from '../ui/tooltip';
|
import { Tooltip, TooltipContent, TooltipTrigger } from '../ui/tooltip';
|
||||||
import { useOverviewOptions } from './useOverviewOptions';
|
|
||||||
|
|
||||||
interface OverviewLiveHistogramProps {
|
interface OverviewLiveHistogramProps {
|
||||||
projectId: string;
|
projectId: string;
|
||||||
@@ -16,7 +14,6 @@ interface OverviewLiveHistogramProps {
|
|||||||
export function OverviewLiveHistogram({
|
export function OverviewLiveHistogram({
|
||||||
projectId,
|
projectId,
|
||||||
}: OverviewLiveHistogramProps) {
|
}: OverviewLiveHistogramProps) {
|
||||||
const { liveHistogram } = useOverviewOptions();
|
|
||||||
const report: IChartInput = {
|
const report: IChartInput = {
|
||||||
projectId,
|
projectId,
|
||||||
events: [
|
events: [
|
||||||
@@ -80,11 +77,11 @@ export function OverviewLiveHistogram({
|
|||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Wrapper count={0} open={liveHistogram}>
|
<Wrapper count={0}>
|
||||||
{staticArray.map((percent, i) => (
|
{staticArray.map((percent, i) => (
|
||||||
<div
|
<div
|
||||||
key={i}
|
key={i}
|
||||||
className="flex-1 animate-pulse rounded-md bg-slate-200 dark:bg-slate-800"
|
className="flex-1 animate-pulse rounded bg-slate-200 dark:bg-slate-800"
|
||||||
style={{ height: `${percent}%` }}
|
style={{ height: `${percent}%` }}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
@@ -97,14 +94,14 @@ export function OverviewLiveHistogram({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Wrapper open={liveHistogram} count={liveCount}>
|
<Wrapper count={liveCount}>
|
||||||
{minutes.map((minute) => {
|
{minutes.map((minute) => {
|
||||||
return (
|
return (
|
||||||
<Tooltip key={minute.date}>
|
<Tooltip key={minute.date}>
|
||||||
<TooltipTrigger asChild>
|
<TooltipTrigger asChild>
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex-1 rounded-md transition-all ease-in-out hover:scale-110',
|
'flex-1 rounded transition-all ease-in-out hover:scale-110',
|
||||||
minute.count === 0 ? 'bg-slate-200' : 'bg-blue-600'
|
minute.count === 0 ? 'bg-slate-200' : 'bg-blue-600'
|
||||||
)}
|
)}
|
||||||
style={{
|
style={{
|
||||||
@@ -127,22 +124,19 @@ export function OverviewLiveHistogram({
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface WrapperProps {
|
interface WrapperProps {
|
||||||
open: boolean;
|
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
count: number;
|
count: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
function Wrapper({ open, children, count }: WrapperProps) {
|
function Wrapper({ children, count }: WrapperProps) {
|
||||||
return (
|
return (
|
||||||
<AnimateHeight open={open}>
|
<div className="flex h-full flex-col">
|
||||||
<div className="flex flex-col">
|
<div className="relative mb-1 text-xs font-medium text-muted-foreground">
|
||||||
<div className="relative -top-2 text-center text-xs font-medium text-muted-foreground">
|
|
||||||
{count} unique vistors last 30 minutes
|
{count} unique vistors last 30 minutes
|
||||||
</div>
|
</div>
|
||||||
<div className="relative flex aspect-[6/1] max-h-[150px] w-full flex-1 items-end gap-0.5 md:aspect-[10/1] md:gap-2">
|
<div className="relative flex h-full w-full flex-1 items-end gap-1">
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</AnimateHeight>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { WidgetHead } from '@/components/overview/overview-widget';
|
|
||||||
import { useOverviewOptions } from '@/components/overview/useOverviewOptions';
|
import { useOverviewOptions } from '@/components/overview/useOverviewOptions';
|
||||||
import { ChartSwitch } from '@/components/report/chart';
|
import { ChartSwitch } from '@/components/report/chart';
|
||||||
import { Widget, WidgetBody } from '@/components/widget';
|
|
||||||
import { useEventQueryFilters } from '@/hooks/useEventQueryFilters';
|
import { useEventQueryFilters } from '@/hooks/useEventQueryFilters';
|
||||||
import { cn } from '@/utils/cn';
|
import { cn } from '@/utils/cn';
|
||||||
|
|
||||||
import type { IChartInput } from '@openpanel/validation';
|
import type { IChartInput } from '@openpanel/validation';
|
||||||
|
|
||||||
|
import { OverviewLiveHistogram } from './overview-live-histogram';
|
||||||
|
|
||||||
interface OverviewMetricsProps {
|
interface OverviewMetricsProps {
|
||||||
projectId: string;
|
projectId: string;
|
||||||
}
|
}
|
||||||
@@ -191,24 +191,32 @@ export default function OverviewMetrics({ projectId }: OverviewMetricsProps) {
|
|||||||
const selectedMetric = reports[metric]!;
|
const selectedMetric = reports[metric]!;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="card col-span-6 p-4">
|
<>
|
||||||
<div className="-mx-2 -mt-2 mb-2 grid grid-cols-6 gap-2">
|
<div className="relative -top-0.5 col-span-6 -m-4 mb-0 md:m-0">
|
||||||
|
<div className="card mb-2 grid grid-cols-4">
|
||||||
{reports.map((report, index) => (
|
{reports.map((report, index) => (
|
||||||
<button
|
<button
|
||||||
key={index}
|
key={index}
|
||||||
className={cn(
|
className={cn(
|
||||||
'col-span-3 rounded-lg border border-background p-2 transition-all max-md:flex-1 md:col-span-2 lg:col-span-1 [&_[role="heading"]]:text-xs',
|
'col-span-2 flex-1 p-4 shadow-[0_0_0_0.5px] shadow-border md:col-span-1',
|
||||||
index === metric && 'border-border'
|
index === metric && 'bg-slate-50'
|
||||||
)}
|
)}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setMetric(index);
|
setMetric(index);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ChartSwitch hideID {...report} />
|
<ChartSwitch hideID {...report} />
|
||||||
{/* add active border */}
|
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
'col-span-4 min-h-28 flex-1 p-4 shadow-[0_0_0_0.5px] shadow-border max-md:row-start-1 md:col-span-2'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<OverviewLiveHistogram projectId={projectId} />
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="card col-span-6 p-4">
|
||||||
<ChartSwitch
|
<ChartSwitch
|
||||||
key={selectedMetric.id}
|
key={selectedMetric.id}
|
||||||
hideID
|
hideID
|
||||||
@@ -216,5 +224,7 @@ export default function OverviewMetrics({ projectId }: OverviewMetricsProps) {
|
|||||||
chartType="linear"
|
chartType="linear"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,12 +46,6 @@ export function useOverviewOptions() {
|
|||||||
parseAsInteger.withDefault(0).withOptions(nuqsOptions)
|
parseAsInteger.withDefault(0).withOptions(nuqsOptions)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Toggles
|
|
||||||
const [liveHistogram, setLiveHistogram] = useQueryState(
|
|
||||||
'live',
|
|
||||||
parseAsBoolean.withDefault(true).withOptions(nuqsOptions)
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
previous,
|
previous,
|
||||||
setPrevious,
|
setPrevious,
|
||||||
@@ -72,9 +66,5 @@ export function useOverviewOptions() {
|
|||||||
|
|
||||||
// Computed
|
// Computed
|
||||||
interval,
|
interval,
|
||||||
|
|
||||||
// Toggles
|
|
||||||
liveHistogram,
|
|
||||||
setLiveHistogram,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,9 +71,9 @@ export function MetricCard({
|
|||||||
{({ width, height }) => (
|
{({ width, height }) => (
|
||||||
<AreaChart
|
<AreaChart
|
||||||
width={width}
|
width={width}
|
||||||
height={height / 2.5}
|
height={height / 3}
|
||||||
data={serie.data}
|
data={serie.data}
|
||||||
style={{ marginTop: (height / 2.5) * 1.5 }}
|
style={{ marginTop: (height / 3) * 2 }}
|
||||||
>
|
>
|
||||||
<Area
|
<Area
|
||||||
dataKey="count"
|
dataKey="count"
|
||||||
@@ -89,12 +89,9 @@ export function MetricCard({
|
|||||||
</div>
|
</div>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<div className="flex items-center justify-between gap-2">
|
<div className="flex items-center justify-between gap-2">
|
||||||
<div className="flex min-w-0 items-center gap-2 text-left font-medium">
|
<div className="flex min-w-0 items-center gap-2 text-left font-semibold">
|
||||||
<ColorSquare>{serie.event.id}</ColorSquare>
|
<ColorSquare>{serie.event.id}</ColorSquare>
|
||||||
<span
|
<span className="overflow-hidden text-ellipsis whitespace-nowrap text-muted-foreground">
|
||||||
role="heading"
|
|
||||||
className="overflow-hidden text-ellipsis whitespace-nowrap"
|
|
||||||
>
|
|
||||||
{serie.name || serie.event.displayName || serie.event.name}
|
{serie.name || serie.event.displayName || serie.event.name}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ function BarHover({ x, y, width, height, top, left, right, bottom }: any) {
|
|||||||
return (
|
return (
|
||||||
<rect
|
<rect
|
||||||
{...{ x, y, width, height, top, left, right, bottom }}
|
{...{ x, y, width, height, top, left, right, bottom }}
|
||||||
rx="8"
|
rx="3"
|
||||||
fill={bg}
|
fill={bg}
|
||||||
fillOpacity={0.5}
|
fillOpacity={0.5}
|
||||||
/>
|
/>
|
||||||
@@ -79,7 +79,7 @@ export function ReportHistogramChart({
|
|||||||
dataKey={`${serie.id}:prev:count`}
|
dataKey={`${serie.id}:prev:count`}
|
||||||
fill={getChartColor(serie.index)}
|
fill={getChartColor(serie.index)}
|
||||||
fillOpacity={0.2}
|
fillOpacity={0.2}
|
||||||
radius={8}
|
radius={3}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<Bar
|
<Bar
|
||||||
@@ -87,7 +87,7 @@ export function ReportHistogramChart({
|
|||||||
name={serie.name}
|
name={serie.name}
|
||||||
dataKey={`${serie.id}:count`}
|
dataKey={`${serie.id}:count`}
|
||||||
fill={getChartColor(serie.index)}
|
fill={getChartColor(serie.index)}
|
||||||
radius={8}
|
radius={3}
|
||||||
/>
|
/>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -144,9 +144,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.card {
|
.card {
|
||||||
box-shadow: 0 1px 2px 0.5px rgba(0, 0, 0, 0.08);
|
@apply border border-border bg-background;
|
||||||
border: 0 !important;
|
|
||||||
@apply rounded-xl bg-background;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ export async function Hero() {
|
|||||||
<div className="mt-16 w-full md:pt-16">
|
<div className="mt-16 w-full md:pt-16">
|
||||||
<div className="flex h-[max(90vh,650px)] rounded-2xl bg-black/5 md:p-2">
|
<div className="flex h-[max(90vh,650px)] rounded-2xl bg-black/5 md:p-2">
|
||||||
<iframe
|
<iframe
|
||||||
src="https://dashboard.openpanel.dev/share/overview/ZQsEhG"
|
src="https://dashboard.openpanel.dev/share/overview/ZQsEhG?header=0"
|
||||||
className="h-[max(90vh,650px)] w-full rounded-xl"
|
className="h-[max(90vh,650px)] w-full rounded-xl"
|
||||||
title="Openpanel Dashboard"
|
title="Openpanel Dashboard"
|
||||||
scrolling="no"
|
scrolling="no"
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ export default function Page() {
|
|||||||
Analytics 😉 Curious how it looks?
|
Analytics 😉 Curious how it looks?
|
||||||
</Lead2>
|
</Lead2>
|
||||||
<ALink
|
<ALink
|
||||||
href="https://dashboard.openpanel.dev/share/overview/ZQsEhG"
|
href="https://dashboard.openpanel.dev/share/overview/ZQsEhG?header=0"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
className="mt-8"
|
className="mt-8"
|
||||||
variant={'outline'}
|
variant={'outline'}
|
||||||
|
|||||||
Reference in New Issue
Block a user