-
- {user ? (
- <>
-
-
-
-
-
-
-
-
- >
- ) : (
-
- )}
+
+ {user && (
+
+
+
+
+
+
+
+
+ )}
+
+
diff --git a/components/layout/Header.module.css b/components/layout/Header.module.css
index 6853eeda..63d68ab9 100644
--- a/components/layout/Header.module.css
+++ b/components/layout/Header.module.css
@@ -13,18 +13,33 @@
.nav {
display: flex;
- justify-content: flex-end;
+ justify-content: center;
align-items: center;
font-size: var(--font-size-normal);
font-weight: 600;
}
-.nav > * {
+.nav a + a {
margin-left: 40px;
}
-@media only screen and (max-width: 768px) {
+.buttons {
+ display: flex;
+ justify-content: flex-end;
+}
+
+@media only screen and (max-width: 992px) {
.title {
text-align: center;
}
+
+ .nav {
+ font-size: var(--font-size-large);
+ justify-content: center;
+ padding: 20px 0;
+ }
+
+ .buttons {
+ justify-content: center;
+ }
}
diff --git a/components/layout/Layout.js b/components/layout/Layout.js
index 021745cc..b16a0717 100644
--- a/components/layout/Layout.js
+++ b/components/layout/Layout.js
@@ -16,8 +16,8 @@ export default function Layout({ title, children, header = true, footer = true }
{header &&
}
{children}
-
{footer &&
}
+
>
);
}
diff --git a/components/layout/Layout.module.css b/components/layout/Layout.module.css
new file mode 100644
index 00000000..90b6c876
--- /dev/null
+++ b/components/layout/Layout.module.css
@@ -0,0 +1,6 @@
+.layout {
+ display: flex;
+ flex-direction: column;
+ width: 100%;
+ height: 100%;
+}
diff --git a/components/layout/Page.module.css b/components/layout/Page.module.css
index a16b2229..c80d0f1b 100644
--- a/components/layout/Page.module.css
+++ b/components/layout/Page.module.css
@@ -1,6 +1,7 @@
.page {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
padding: 0 30px;
background: var(--gray50);
- height: 100%;
- overflow: hidden;
}
diff --git a/components/layout/PageHeader.js b/components/layout/PageHeader.js
index 62ec1947..f356235e 100644
--- a/components/layout/PageHeader.js
+++ b/components/layout/PageHeader.js
@@ -1,6 +1,7 @@
import React from 'react';
+import classNames from 'classnames';
import styles from './PageHeader.module.css';
-export default function PageHeader({ children }) {
- return
{children}
;
+export default function PageHeader({ children, className }) {
+ return
{children}
;
}
diff --git a/components/metrics/BarChart.js b/components/metrics/BarChart.js
index 1c66504d..4f10e83e 100644
--- a/components/metrics/BarChart.js
+++ b/components/metrics/BarChart.js
@@ -6,6 +6,8 @@ import { formatLongNumber } from 'lib/format';
import { dateFormat } from 'lib/lang';
import useLocale from 'hooks/useLocale';
import styles from './BarChart.module.css';
+import useTheme from 'hooks/useTheme';
+import { THEME_COLORS } from 'lib/constants';
export default function BarChart({
chartId,
@@ -16,15 +18,23 @@ export default function BarChart({
animationDuration = 300,
className,
stacked = false,
+ loading = false,
onCreate = () => {},
onUpdate = () => {},
}) {
const canvas = useRef();
const chart = useRef();
- const [tooltip, setTooltip] = useState({});
+ const [tooltip, setTooltip] = useState(null);
const [locale] = useLocale();
+ const [theme] = useTheme();
+ const colors = {
+ text: THEME_COLORS[theme].gray700,
+ line: THEME_COLORS[theme].gray200,
+ zeroLine: THEME_COLORS[theme].gray500,
+ };
function renderXLabel(label, index, values) {
+ if (loading) return '';
const d = new Date(values[index].value);
const w = canvas.current.width;
@@ -59,18 +69,19 @@ export default function BarChart({
function renderTooltip(model) {
const { opacity, title, body, labelColors } = model;
- if (!opacity) {
+ if (!opacity || !title) {
setTooltip(null);
- } else {
- const [label, value] = body[0].lines[0].split(':');
-
- setTooltip({
- title: dateFormat(new Date(+title[0]), getTooltipFormat(unit), locale),
- value,
- label,
- labelColor: labelColors[0].backgroundColor,
- });
+ return;
}
+
+ const [label, value] = body[0].lines[0].split(':');
+
+ setTooltip({
+ title: dateFormat(new Date(+title[0]), getTooltipFormat(unit), locale),
+ value,
+ label,
+ labelColor: labelColors[0].backgroundColor,
+ });
}
function getTooltipFormat(unit) {
@@ -97,6 +108,11 @@ export default function BarChart({
responsive: true,
responsiveAnimationDuration: 0,
maintainAspectRatio: false,
+ legend: {
+ labels: {
+ fontColor: colors.text,
+ },
+ },
scales: {
xAxes: [
{
@@ -110,6 +126,7 @@ export default function BarChart({
callback: renderXLabel,
minRotation: 0,
maxRotation: 0,
+ fontColor: colors.text,
},
gridLines: {
display: false,
@@ -123,6 +140,11 @@ export default function BarChart({
ticks: {
callback: renderYLabel,
beginAtZero: true,
+ fontColor: colors.text,
+ },
+ gridLines: {
+ color: colors.line,
+ zeroLineColor: colors.zeroLine,
},
stacked,
},
@@ -144,8 +166,13 @@ export default function BarChart({
function updateChart() {
const { options } = chart.current;
+ options.legend.labels.fontColor = colors.text;
options.scales.xAxes[0].time.unit = unit;
options.scales.xAxes[0].ticks.callback = renderXLabel;
+ options.scales.xAxes[0].ticks.fontColor = colors.text;
+ options.scales.yAxes[0].ticks.fontColor = colors.text;
+ options.scales.yAxes[0].gridLines.color = colors.line;
+ options.scales.yAxes[0].gridLines.zeroLineColor = colors.zeroLine;
options.animation.duration = animationDuration;
options.tooltips.custom = renderTooltip;
@@ -161,7 +188,7 @@ export default function BarChart({
updateChart();
}
}
- }, [datasets, unit, animationDuration, locale]);
+ }, [datasets, unit, animationDuration, locale, theme]);
return (
<>
diff --git a/components/metrics/BarChart.module.css b/components/metrics/BarChart.module.css
index 88b785ca..cd26d3af 100644
--- a/components/metrics/BarChart.module.css
+++ b/components/metrics/BarChart.module.css
@@ -3,6 +3,7 @@
}
.tooltip {
+ color: var(--msgColor);
pointer-events: none;
z-index: 1;
}
@@ -12,7 +13,6 @@
flex-direction: column;
justify-content: center;
align-items: center;
- color: var(--gray50);
text-align: center;
}
diff --git a/components/metrics/EventsChart.js b/components/metrics/EventsChart.js
index 48fb6f2b..afc3e952 100644
--- a/components/metrics/EventsChart.js
+++ b/components/metrics/EventsChart.js
@@ -5,17 +5,7 @@ import { getDateArray, getDateLength } from 'lib/date';
import useFetch from 'hooks/useFetch';
import useDateRange from 'hooks/useDateRange';
import useTimezone from 'hooks/useTimezone';
-
-const COLORS = [
- '#2680eb',
- '#9256d9',
- '#44b556',
- '#e68619',
- '#e34850',
- '#1b959a',
- '#d83790',
- '#85d044',
-];
+import { EVENT_COLORS } from 'lib/constants';
export default function EventsChart({ websiteId, token }) {
const [dateRange] = useDateRange(websiteId);
@@ -51,13 +41,13 @@ export default function EventsChart({ websiteId, token }) {
});
return Object.keys(map).map((key, index) => {
- const color = tinycolor(COLORS[index]);
+ const color = tinycolor(EVENT_COLORS[index]);
return {
label: key,
data: map[key],
lineTension: 0,
- backgroundColor: color.setAlpha(0.4).toRgbString(),
- borderColor: color.setAlpha(0.5).toRgbString(),
+ backgroundColor: color.setAlpha(0.6).toRgbString(),
+ borderColor: color.setAlpha(0.7).toRgbString(),
borderWidth: 1,
};
});
diff --git a/components/metrics/MetricCard.module.css b/components/metrics/MetricCard.module.css
index 3f3405ee..50b92ac8 100644
--- a/components/metrics/MetricCard.module.css
+++ b/components/metrics/MetricCard.module.css
@@ -3,7 +3,6 @@
flex-direction: column;
justify-content: center;
min-width: 140px;
- padding-right: 20px;
}
.value {
diff --git a/components/metrics/MetricsBar.module.css b/components/metrics/MetricsBar.module.css
index 5f5cb1a7..4546f893 100644
--- a/components/metrics/MetricsBar.module.css
+++ b/components/metrics/MetricsBar.module.css
@@ -3,11 +3,15 @@
cursor: pointer;
}
+.bar > div + div {
+ padding-left: 20px;
+}
+
@media only screen and (max-width: 992px) {
.bar {
justify-content: space-between;
}
- .bar > div:last-child {
+ .bar > div:nth-child(n + 3) {
display: none;
}
}
diff --git a/components/metrics/MetricsTable.js b/components/metrics/MetricsTable.js
index eed5fca2..eca58dc2 100644
--- a/components/metrics/MetricsTable.js
+++ b/components/metrics/MetricsTable.js
@@ -24,7 +24,6 @@ export default function MetricsTable({
dataFilter,
filterOptions,
limit,
- headerComponent,
renderLabel,
onDataLoad = () => {},
onExpand = () => {},
@@ -85,7 +84,6 @@ export default function MetricsTable({
<>
{title}
- {headerComponent}
{metric}
diff --git a/components/metrics/MetricsTable.module.css b/components/metrics/MetricsTable.module.css
index 65680634..34fa77ad 100644
--- a/components/metrics/MetricsTable.module.css
+++ b/components/metrics/MetricsTable.module.css
@@ -2,7 +2,6 @@
position: relative;
min-height: 460px;
font-size: var(--font-size-small);
- padding: 20px 0;
display: flex;
flex-direction: column;
}
@@ -74,7 +73,7 @@
position: relative;
width: 50px;
color: #6e6e6e;
- border-left: 1px solid var(--gray600);
+ border-left: 1px solid var(--gray500);
padding-left: 10px;
z-index: 1;
}
diff --git a/components/metrics/PagesTable.js b/components/metrics/PagesTable.js
index 5730cf90..ba04f871 100644
--- a/components/metrics/PagesTable.js
+++ b/components/metrics/PagesTable.js
@@ -4,6 +4,7 @@ import ButtonGroup from 'components/common/ButtonGroup';
import { urlFilter } from 'lib/filters';
import { FILTER_COMBINED, FILTER_RAW } from 'lib/constants';
import MetricsTable from './MetricsTable';
+import ButtonLayout from '../layout/ButtonLayout';
export default function PagesTable({ websiteId, token, websiteDomain, limit, onExpand }) {
const [filter, setFilter] = useState(FILTER_COMBINED);
@@ -17,24 +18,28 @@ export default function PagesTable({ websiteId, token, websiteDomain, limit, onE
];
return (
-
}
- type="url"
- metric={
}
- headerComponent={
- limit ? null :
- }
- websiteId={websiteId}
- token={token}
- limit={limit}
- dataFilter={urlFilter}
- filterOptions={{ domain: websiteDomain, raw: filter === FILTER_RAW }}
- renderLabel={({ x }) => decodeURI(x)}
- onExpand={onExpand}
- />
+ <>
+ {!limit &&
}
+
}
+ type="url"
+ metric={
}
+ websiteId={websiteId}
+ token={token}
+ limit={limit}
+ dataFilter={urlFilter}
+ filterOptions={{ domain: websiteDomain, raw: filter === FILTER_RAW }}
+ renderLabel={({ x }) => decodeURI(x)}
+ onExpand={onExpand}
+ />
+ >
);
}
const FilterButtons = ({ buttons, selected, onClick }) => {
- return
;
+ return (
+
+
+
+ );
};
diff --git a/components/metrics/PageviewsChart.js b/components/metrics/PageviewsChart.js
index 9c112798..9120a6c3 100644
--- a/components/metrics/PageviewsChart.js
+++ b/components/metrics/PageviewsChart.js
@@ -1,10 +1,25 @@
import React from 'react';
import { useIntl } from 'react-intl';
+import tinycolor from 'tinycolor2';
import CheckVisible from 'components/helpers/CheckVisible';
import BarChart from './BarChart';
+import useTheme from 'hooks/useTheme';
+import { THEME_COLORS } from 'lib/constants';
-export default function PageviewsChart({ websiteId, data, unit, records, className }) {
+export default function PageviewsChart({ websiteId, data, unit, records, className, loading }) {
const intl = useIntl();
+ const [theme] = useTheme();
+ const primaryColor = tinycolor(THEME_COLORS[theme].primary);
+ const colors = {
+ views: {
+ background: primaryColor.setAlpha(0.4).toRgbString(),
+ border: primaryColor.setAlpha(0.5).toRgbString(),
+ },
+ visitors: {
+ background: primaryColor.setAlpha(0.6).toRgbString(),
+ border: primaryColor.setAlpha(0.7).toRgbString(),
+ },
+ };
const handleUpdate = chart => {
const {
@@ -43,8 +58,8 @@ export default function PageviewsChart({ websiteId, data, unit, records, classNa
}),
data: data.uniques,
lineTension: 0,
- backgroundColor: 'rgb(38, 128, 235, 0.4)',
- borderColor: 'rgb(13, 102, 208, 0.4)',
+ backgroundColor: colors.visitors.background,
+ borderColor: colors.visitors.border,
borderWidth: 1,
},
{
@@ -54,8 +69,8 @@ export default function PageviewsChart({ websiteId, data, unit, records, classNa
}),
data: data.pageviews,
lineTension: 0,
- backgroundColor: 'rgb(38, 128, 235, 0.2)',
- borderColor: 'rgb(13, 102, 208, 0.2)',
+ backgroundColor: colors.views.background,
+ borderColor: colors.views.border,
borderWidth: 1,
},
]}
@@ -63,6 +78,7 @@ export default function PageviewsChart({ websiteId, data, unit, records, classNa
records={records}
animationDuration={visible ? 300 : 0}
onUpdate={handleUpdate}
+ loading={loading}
/>
)}
diff --git a/components/metrics/ReferrersTable.js b/components/metrics/ReferrersTable.js
index 39136a71..93552cc5 100644
--- a/components/metrics/ReferrersTable.js
+++ b/components/metrics/ReferrersTable.js
@@ -4,6 +4,7 @@ import MetricsTable from './MetricsTable';
import { refFilter } from 'lib/filters';
import ButtonGroup from 'components/common/ButtonGroup';
import { FILTER_DOMAIN_ONLY, FILTER_COMBINED, FILTER_RAW } from 'lib/constants';
+import ButtonLayout from '../layout/ButtonLayout';
export default function ReferrersTable({
websiteId,
@@ -37,29 +38,33 @@ export default function ReferrersTable({
};
return (
-
}
- type="referrer"
- metric={
}
- headerComponent={
- limit ? null :
- }
- websiteId={websiteId}
- websiteDomain={websiteDomain}
- token={token}
- limit={limit}
- dataFilter={refFilter}
- filterOptions={{
- domain: websiteDomain,
- domainOnly: filter === FILTER_DOMAIN_ONLY,
- raw: filter === FILTER_RAW,
- }}
- onExpand={onExpand}
- renderLabel={renderLink}
- />
+ <>
+ {!limit &&
}
+
}
+ type="referrer"
+ metric={
}
+ websiteId={websiteId}
+ websiteDomain={websiteDomain}
+ token={token}
+ limit={limit}
+ dataFilter={refFilter}
+ filterOptions={{
+ domain: websiteDomain,
+ domainOnly: filter === FILTER_DOMAIN_ONLY,
+ raw: filter === FILTER_RAW,
+ }}
+ onExpand={onExpand}
+ renderLabel={renderLink}
+ />
+ >
);
}
const FilterButtons = ({ buttons, selected, onClick }) => {
- return
;
+ return (
+
+
+
+ );
};
diff --git a/components/metrics/WebsiteChart.js b/components/metrics/WebsiteChart.js
index 5c6e8988..ecbd0798 100644
--- a/components/metrics/WebsiteChart.js
+++ b/components/metrics/WebsiteChart.js
@@ -23,7 +23,7 @@ export default function WebsiteChart({
const { startDate, endDate, unit, value, modified } = dateRange;
const [timezone] = useTimezone();
- const { data } = useFetch(
+ const { data, loading } = useFetch(
`/api/website/${websiteId}/pageviews`,
{
start_at: +startDate,
@@ -74,6 +74,7 @@ export default function WebsiteChart({
data={{ pageviews, uniques }}
unit={unit}
records={getDateLength(startDate, endDate, unit)}
+ loading={loading}
/>
diff --git a/components/metrics/WebsiteHeader.js b/components/metrics/WebsiteHeader.js
index d8f53421..71c0db69 100644
--- a/components/metrics/WebsiteHeader.js
+++ b/components/metrics/WebsiteHeader.js
@@ -14,7 +14,7 @@ export default function WebsiteHeader({ websiteId, token, title, showLink = fals