Skip to content

Commit

Permalink
feat: basic show dimension details
Browse files Browse the repository at this point in the history
Signed-off-by: Henry Gressmann <mail@henrygressmann.de>
  • Loading branch information
explodingcamera committed Aug 20, 2024
1 parent 757fff0 commit 6e2b982
Show file tree
Hide file tree
Showing 11 changed files with 146 additions and 20 deletions.
2 changes: 1 addition & 1 deletion biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@
"defaultBranch": "main"
},
"files": {
"ignore": ["**/node_modules/*"]
"ignore": ["**/node_modules/*", "**/api/dashboard.ts"]
}
}
19 changes: 19 additions & 0 deletions web/src/components/dialog.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
position: fixed;
inset: 0;
animation: overlayShow 150ms cubic-bezier(0.16, 1, 0.3, 1);
z-index: 100;
}

.title {
Expand All @@ -31,6 +32,7 @@

.content {
position: fixed;
z-index: 100;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
Expand All @@ -40,4 +42,21 @@
padding: 1rem;
padding-bottom: 0.5rem;
animation: contentShow 150ms cubic-bezier(0.16, 1, 0.3, 1);
overflow-y: auto;
}

.close {
position: fixed;
z-index: 1000;
background-color: white;
border: none;
right: 0;
margin: 1rem;
pointer-events: auto;
border-radius: 1rem;
display: flex;
width: 2.5rem;
height: 2.5rem;
justify-content: center;
align-items: center;
}
46 changes: 41 additions & 5 deletions web/src/components/dialog.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import * as Dia from "@radix-ui/react-dialog";
import { XIcon } from "lucide-react";
import { cls } from "../utils";
import styles from "./dialog.module.css";

export const Dialog = ({
Expand All @@ -8,23 +10,38 @@ export const Dialog = ({
trigger,
children,
onOpenChange,
className,
showClose,
hideTitle,
}: {
title?: string;
title: string;
description?: string;
hideDescription?: boolean;
trigger: React.ReactNode;
trigger: React.ReactNode | (() => React.ReactNode);
children: React.ReactNode;
onOpenChange?: (open: boolean) => void;
className?: string;
showClose?: boolean;
hideTitle?: boolean;
}) => {
return (
<Dia.Root onOpenChange={onOpenChange}>
<Dia.Trigger asChild>{trigger}</Dia.Trigger>
<Dia.Trigger asChild>{typeof trigger === "function" ? trigger() : trigger}</Dia.Trigger>
<Dia.Portal>
<Dia.Overlay className={styles.overlay} />
{showClose && (
<Dia.Close asChild>
<button type="button" className={styles.close}>
<XIcon size="24" />
</button>
</Dia.Close>
)}

<Dia.Content asChild>
<article className={styles.content}>
{title && <Dia.Title className={styles.title}>{title}</Dia.Title>}
<article className={cls(styles.content, className)}>
<Dia.Title className={styles.title} hidden={hideTitle}>
{title}
</Dia.Title>
{description && (
<Dia.Description hidden={hideDescription} className={styles.description}>
{description}
Expand All @@ -39,3 +56,22 @@ export const Dialog = ({
};

Dialog.Close = Dia.Close;

const Hidden = ({ children }: { children: React.ReactNode }) => (
<span
style={{
position: "absolute",
border: 0,
width: 1,
height: 1,
padding: 0,
margin: -1,
overflow: "hidden",
clip: "rect(0, 0, 0, 0)",
whiteSpace: "nowrap",
wordWrap: "normal",
}}
>
{children}
</span>
);
4 changes: 4 additions & 0 deletions web/src/components/dimensions/dimensions.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -120,3 +120,7 @@
margin-bottom: 1rem;
opacity: 0.6;
}

.detailsModal.detailsModal {
max-width: 35em;
}
72 changes: 64 additions & 8 deletions web/src/components/dimensions/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import {
useDimension,
} from "../../api";

import { cls } from "../../utils";
import { Dialog } from "../dialog";
import { BrowserIcon, MobileDeviceIcon, OSIcon, ReferrerIcon } from "../icons";
import { countryCodeToFlag, formatFullUrl, formatHost, getHref, tryParseUrl } from "./utils";

Expand Down Expand Up @@ -113,18 +115,72 @@ export const DimensionTable = ({
</div>
)}
</div>
<button
type="button"
className={`${styles.showMore} ${(dataTruncated?.length ?? 0) === 0 ? styles.showMoreHidden : ""}`}
onClick={() => console.log("show more")}
>
<ZoomIn size={16} />
Show details
</button>
<DetailsModal project={project} dimension={dimension} metric={metric} range={range} />
</>
);
};

const DetailsModal = ({
project,
dimension,
metric,
range,
}: { project: ProjectResponse; dimension: Dimension; metric: Metric; range: DateRange }) => {
const { data, biggest, order, isLoading } = useDimension({ project, dimension, metric, range });

return (
<Dialog
title={`${dimensionNames[dimension]} - ${metricNames[metric]}`}
description={`Detailed breakdown of ${dimensionNames[dimension]} by ${metricNames[metric]}`}
hideTitle
hideDescription
showClose
className={styles.detailsModal}
trigger={() => (
<button
type="button"
className={cls(styles.showMore, (data?.length ?? 0) === 0 && styles.showMoreHidden)}
onClick={() => console.log("show more")}
>
<ZoomIn size={16} />
Show details
</button>
)}
>
<div className={styles.dimensionTable} style={{ "--count": data?.length } as React.CSSProperties}>
<div className={styles.dimensionHeader}>
<div>{dimensionNames[dimension]}</div>
<div>{metricNames[metric]}</div>
</div>
{data?.map((d) => {
return (
<div
key={d.dimensionValue}
style={{ order: order?.indexOf(d.dimensionValue) }}
className={styles.dimensionRow}
>
<DimensionValueBar value={d.value} biggest={biggest}>
<DimensionLabel dimension={dimension} value={d} />
</DimensionValueBar>
<div>{formatMetricVal(metric, d.value)}</div>
</div>
);
})}
{isLoading && data?.length === 0 && (
<div className={styles.dimensionEmpty}>
<div>Loading...</div>
</div>
)}
{!isLoading && data?.length === 0 && (
<div className={styles.dimensionEmpty}>
<div>No data available</div>
</div>
)}
</div>
</Dialog>
);
};

const dimensionLabels: Record<Dimension, (value: DimensionTableRow) => React.ReactNode> = {
platform: (value) => (
<>
Expand Down
3 changes: 2 additions & 1 deletion web/src/components/project.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { api, useDimension, useQuery } from "../api";
import type { DateRange, Metric, ProjectResponse, StatsResponse } from "../api";
import { type RangeName, resolveRange } from "../api/ranges";

import { cls } from "../utils";
import { DimensionCard, DimensionTabs, DimensionTabsCard, cardStyles } from "./dimensions";
import { LiveVisitorCount, ProjectOverview, SelectRange } from "./projects";

Expand Down Expand Up @@ -96,7 +97,7 @@ const GeoCard = ({ project, metric, range }: { project: ProjectResponse; metric:
});

return (
<div className={`${cardStyles} ${styles.geoCard}`} data-full-width="true">
<div className={cls(cardStyles, styles.geoCard)} data-full-width="true">
<div className={styles.geoMap}>
<Suspense fallback={null}>
<WorldMap data={data ?? []} metric={metric} />
Expand Down
5 changes: 3 additions & 2 deletions web/src/components/projects.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import CountUp from "react-countup";
import { type Metric, type ProjectResponse, type StatsResponse, api, metricNames, useMe, useQuery } from "../api";
import { type RangeName, rangeNames, resolveRange } from "../api/ranges";
import { getUsername } from "../api/utils";
import { cls } from "../utils";
import { LineGraph, toDataPoints } from "./graph";

const signedIn = getUsername();
Expand Down Expand Up @@ -106,7 +107,7 @@ export const SelectRange = ({ onSelect, range }: { onSelect: (name: RangeName) =
};

return (
<details ref={detailsRef} className={`dropdown ${styles.selectRange}`}>
<details ref={detailsRef} className={cls("dropdown", styles.selectRange)}>
<summary>{rangeNames[range]}</summary>
<ul>
{Object.entries(rangeNames).map(([key, value]) => (
Expand Down Expand Up @@ -221,7 +222,7 @@ export const ProjectOverview = ({
{detailsElement?.()}
</div>

<div className={`${graphClassName} ${styles.graph}`}>
<div className={cls(graphClassName, styles.graph)}>
<LineGraph title={metricNames[metric]} data={chartData || []} range={graphRange} />
</div>
</div>
Expand Down
3 changes: 2 additions & 1 deletion web/src/components/settings/tables.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,15 @@ import {
useProjects,
useUsers,
} from "../../api";
import { cls } from "../../utils";
import { createToast } from "../toast";

type DropdownOptions = Record<string, ((close: () => void) => JSX.Element) | null>;

const Dropdown = ({ options }: { options: DropdownOptions }) => {
const detailsRef = useRef<HTMLDetailsElement>(null);
return (
<details className={`dropdown ${styles.edit}`} ref={detailsRef}>
<details className={cls("dropdown", styles.edit)} ref={detailsRef}>
<summary>
<EllipsisVerticalIcon />
</summary>
Expand Down
3 changes: 2 additions & 1 deletion web/src/components/userInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import styles from "./userInfo.module.css";

import { LogOutIcon, SettingsIcon, UserIcon } from "lucide-react";
import { api, getUsername } from "../api";
import { cls } from "../utils";

export const LoginButton = () => {
const username = getUsername();
Expand All @@ -18,7 +19,7 @@ export const LoginButton = () => {
);

return (
<details className={`dropdown ${styles.user}`}>
<details className={cls("dropdown", styles.user)}>
<summary role="button" className="outline secondary">
<UserIcon size="24" />
{username}
Expand Down
2 changes: 1 addition & 1 deletion web/src/components/worldmap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export const WorldMap = ({
</Geographies>
</ZoomableGroup>
</ComposableMap>
<Tooltip id="map" className={`${styles.tooltipContainer}`} classNameArrow={styles.reset} disableStyleInjection>
<Tooltip id="map" className={styles.tooltipContainer} classNameArrow={styles.reset} disableStyleInjection>
{currentGeo && (
<div className={styles.tooltip} data-theme="dark">
<h2>{metricNames[metric]}</h2>
Expand Down
7 changes: 7 additions & 0 deletions web/src/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
type ClassName = string | undefined | null | false;

export const cls = (class1: ClassName | ClassName[], ...classes: (ClassName | ClassName[])[]) =>
[class1, ...classes.flat()]
.flat()
.filter((cls): cls is string => typeof cls === "string" && cls.length > 0)
.join(" ");

0 comments on commit 6e2b982

Please sign in to comment.