Skip to content

Commit 98af9ef

Browse files
chore: QOL improvements & changelog
Signed-off-by: Henry Gressmann <[email protected]>
1 parent 288316e commit 98af9ef

File tree

12 files changed

+117
-69
lines changed

12 files changed

+117
-69
lines changed

CHANGELOG.md

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,20 @@ The format is roughly based on the output of `git-cliff` and this project adhere
1616
Since this is not a library, this changelog focuses on the changes that are relevant to the end-users. For a detailed list of changes, see the commit history, which adheres to [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/). New releases are created automatically when a new tag is pushed (Commit message: chore(release): vX.X.X).
1717
-->
1818

19-
## [Unreleased]
19+
<!-- ## [Unreleased] -->
2020

21-
:rocket: This is the first release of the Liwan.
21+
## **Liwan v0.1.0** - 2024-09-18
22+
23+
This is the first full release of the Liwan! 🎉
24+
All essential features for web analytics are now available, including:
25+
26+
- Live tracking of page views
27+
- Geolocation of visitors
28+
- Automatic GeoIP database updates
29+
- Basic user management
30+
- Filtering and searching
31+
- Multiple tracking dimensions: URL, referrer, browser, OS, device type, country, and city
32+
- Multiple metrics: page views, unique visitors, sessions, and average views per session
33+
- Multiple date ranges (custom date ranges are coming soon!)
34+
- Documentation and a simple setup guide at [liwan.dev](https://liwan.dev)
35+
- A simple and clean UI

web/public/favicon.ico

165 KB
Binary file not shown.

web/src/api/hooks.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ export const useProjectData = ({
138138
refetchInterval,
139139
staleTime,
140140
enabled: project !== undefined,
141-
queryKey: ["project_graph", project?.id, range, graphRange, metric, dataPoints],
141+
queryKey: ["project_graph", project?.id, range, graphRange, metric, filters, dataPoints],
142142
queryFn: () =>
143143
api["/api/dashboard/project/{project_id}/graph"]
144144
.post({ json: { range, metric, dataPoints, filters }, params: { project_id: project?.id ?? "" } })

web/src/components/dimensions/dimensions.module.css

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
.tabsList > button {
1616
all: unset;
1717
cursor: pointer;
18+
user-select: none;
1819

1920
&[aria-selected="true"] {
2021
text-decoration: underline;
@@ -80,6 +81,19 @@
8081
display: flex;
8182
flex-direction: column;
8283
min-height: calc(var(--count) * (2.1rem + 0.2rem));
84+
position: relative;
85+
86+
.spinner {
87+
position: absolute;
88+
height: 100%;
89+
width: 100%;
90+
}
91+
92+
&.loading {
93+
.dimensionRow {
94+
opacity: 0.2;
95+
}
96+
}
8397
}
8498

8599
.showMore {
@@ -127,6 +141,7 @@
127141
all: unset;
128142
position: relative;
129143
color: var(--pico-h2-color);
144+
padding: 0.5rem 0;
130145

131146
&:hover {
132147
text-decoration: underline;

web/src/components/dimensions/index.tsx

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,11 @@
11
import * as Tabs from "@radix-ui/react-tabs";
2-
import { LinkIcon, SquareArrowOutUpRightIcon, ZoomIn } from "lucide-react";
2+
import { LinkIcon, SquareArrowOutUpRightIcon } from "lucide-react";
33
import styles from "./dimensions.module.css";
44

5-
import {
6-
type DateRange,
7-
type Dimension,
8-
type DimensionTableRow,
9-
type Metric,
10-
type ProjectResponse,
11-
dimensionNames,
12-
metricNames,
13-
useDimension,
14-
} from "../../api";
5+
import { type Dimension, type DimensionTableRow, dimensionNames, metricNames, useDimension } from "../../api";
156

167
import { BrowserIcon, MobileDeviceIcon, OSIcon, ReferrerIcon } from "../icons";
17-
import { countryCodeToFlag, formatFullUrl, formatHost, formatPath, getHref, tryParseUrl } from "../../utils";
8+
import { cls, countryCodeToFlag, formatHost, formatPath, getHref, tryParseUrl } from "../../utils";
189
import { DetailsModal } from "./modal";
1910
import { formatMetricVal } from "../../utils";
2011
import type { ProjectQuery } from "../project";
@@ -85,11 +76,15 @@ export const DimensionTabs = ({
8576

8677
export const DimensionTable = (props: DimensionProps) => {
8778
const { data, biggest, order, isLoading } = useDimension({ dimension: props.dimension, ...props.query });
88-
8979
const dataTruncated = data?.slice(0, 6);
80+
9081
return (
9182
<>
92-
<div className={styles.dimensionTable} style={{ "--count": 6 } as React.CSSProperties}>
83+
<div
84+
className={cls(styles.dimensionTable, isLoading && styles.loading)}
85+
style={{ "--count": 6 } as React.CSSProperties}
86+
>
87+
{isLoading && <div className={cls("loading-spinner", styles.spinner)} />}
9388
{dataTruncated?.map((d) => {
9489
return (
9590
<div

web/src/components/dimensions/modal.tsx

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,19 @@ import styles from "./dimensions.module.css";
55
import { cls, formatMetricVal } from "../../utils";
66
import { Dialog } from "../dialog";
77
import { DimensionLabel, DimensionValueBar } from ".";
8-
import {
9-
dimensionNames,
10-
metricNames,
11-
useDimension,
12-
type DateRange,
13-
type Dimension,
14-
type Metric,
15-
type ProjectResponse,
16-
} from "../../api";
8+
import { dimensionNames, metricNames, useDimension, type Dimension, type DimensionTableRow } from "../../api";
179
import { useDeferredValue, useMemo, useState } from "react";
1810
import type { ProjectQuery } from "../project";
1911

20-
export const DetailsModal = ({ dimension, query }: { dimension: Dimension; query: ProjectQuery }) => {
12+
export const DetailsModal = ({
13+
dimension,
14+
query,
15+
onSelect,
16+
}: {
17+
dimension: Dimension;
18+
query: ProjectQuery;
19+
onSelect: (value: DimensionTableRow, dimension: Dimension) => void;
20+
}) => {
2121
const { data, biggest, order, isLoading } = useDimension({ dimension, ...query });
2222

2323
const [filter, setFilter] = useState("");
@@ -64,7 +64,7 @@ export const DetailsModal = ({ dimension, query }: { dimension: Dimension; query
6464
className={styles.dimensionRow}
6565
>
6666
<DimensionValueBar value={d.value} biggest={biggest}>
67-
<DimensionLabel dimension={dimension} value={d} />
67+
<DimensionLabel dimension={dimension} value={d} onSelect={() => onSelect(d, dimension)} />
6868
</DimensionValueBar>
6969
<div>{formatMetricVal(d.value)}</div>
7070
</div>

web/src/components/graph/graph.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { ResponsiveLine, type SliceTooltipProps } from "@nivo/line";
55
import { addMonths } from "date-fns";
66
import type { DataPoint } from ".";
77
import { formatMetricVal } from "../../utils";
8+
import { useWindowSize } from "@uidotdev/usehooks";
89

910
export type GraphRange = "year" | "month" | "day" | "hour";
1011

@@ -47,11 +48,19 @@ export const LineGraph = ({
4748
const max = useMemo(() => Math.max(...data.map((d) => d.y)), [data]);
4849
const yCount = 5;
4950

51+
const size = useWindowSize();
52+
let xCount = Math.min(data.length, 8);
53+
if (size.width && size.width < 1000) {
54+
xCount = Math.min(data.length, 6);
55+
} else if (size.width && size.width < 600) {
56+
xCount = Math.min(data.length, 4);
57+
}
58+
5059
return (
5160
<ResponsiveLine
5261
data={[{ data, id: "data", color: "hsl(0, 70%, 50%)" }]}
5362
margin={{ top: 10, right: 40, bottom: 30, left: 40 }}
54-
xScale={data.length > 14 ? { type: "time" } : { type: "point" }}
63+
xScale={{ type: "time" }}
5564
yScale={{
5665
type: "linear",
5766
nice: true,
@@ -68,6 +77,7 @@ export const LineGraph = ({
6877
axisBottom={{
6978
legend: "",
7079
format: (value: Date) => formatDate(value, range),
80+
tickValues: xCount,
7181
}}
7282
axisLeft={{
7383
legend: "",

web/src/components/project.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11
import styles from "./project.module.css";
22
import _map from "./worldmap.module.css";
33

4-
import { useLocalStorage } from "@uidotdev/usehooks";
54
import { Suspense, lazy, useEffect, useState } from "react";
5+
import { useLocalStorage } from "@uidotdev/usehooks";
66

7+
import { type RangeName, resolveRange } from "../api/ranges";
78
import { metricNames, useDimension, useProject, useProjectData } from "../api";
89
import type { DimensionFilter, DateRange, Metric, ProjectResponse, DimensionTableRow, Dimension } from "../api";
9-
import { type RangeName, resolveRange } from "../api/ranges";
1010

1111
import { cls } from "../utils";
12-
import { DimensionCard, DimensionTabs, DimensionTabsCard, cardStyles } from "./dimensions";
12+
import { LineGraph } from "./graph";
1313
import { SelectRange } from "./project/range";
1414
import { ProjectHeader } from "./project/project";
1515
import { SelectMetrics } from "./project/metric";
16-
import { LineGraph } from "./graph";
1716
import { SelectFilters } from "./project/filter";
17+
import { DimensionCard, DimensionTabs, DimensionTabsCard, cardStyles } from "./dimensions";
1818

1919
const WorldMap = lazy(() => import("./worldmap").then((module) => ({ default: module.WorldMap })));
2020

web/src/components/settings/me.module.css

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,6 @@ form.password {
66
label {
77
width: 100%;
88
}
9-
10-
h2 {
11-
font-size: 1.2rem;
12-
}
139
}
1410

1511
.header {
@@ -39,4 +35,22 @@ form.password {
3935
flex-direction: column;
4036
width: 100%;
4137
}
38+
39+
h2 {
40+
font-size: 1.2rem;
41+
}
42+
43+
code {
44+
font-size: 0.9rem;
45+
background-color: var(--pico-background-color);
46+
padding: 1rem 1rem;
47+
border-radius: var(--pico-border-radius);
48+
49+
.tag {
50+
color: var(--pico-primary-background);
51+
}
52+
.entity {
53+
color: var(--pico-secondary-inverse);
54+
}
55+
}
4256
}

web/src/components/settings/me.tsx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,22 @@ export const MyAccount = () => {
4747
</div>
4848
</div>
4949
</article>
50+
<article>
51+
<h2>Snippet code</h2>
52+
<p>
53+
You can copy the tracking snippet for a specific entity <a href="/settings/entities">here</a>, use the{" "}
54+
<a href="https://npmjs.com/package/liwan-tracker">liwan-tracker</a> npm package, or use the following code:
55+
</p>
56+
<code>
57+
<span className={styles.tag}>{"<script"}</span> type="module" data-entity="
58+
<span className={styles.entity}>YOUR_ENTITY_ID</span>" src="
59+
{window.location.origin}/script.js"
60+
<span className={styles.tag}>
61+
{">"}
62+
{"</script>"}
63+
</span>
64+
</code>
65+
</article>
5066
<article>
5167
<form className={styles.password} onSubmit={handleSubmit} ref={formRef}>
5268
<h2>Update Password</h2>

0 commit comments

Comments
 (0)