mirror of
https://github.com/kremalicious/umami.git
synced 2024-11-15 01:35:17 +01:00
Initial expanded view in details.
This commit is contained in:
parent
b392a51676
commit
f535dca7b9
@ -1,4 +1,4 @@
|
|||||||
import React from 'react';
|
import React, { useState } from 'react';
|
||||||
import Page from 'components/layout/Page';
|
import Page from 'components/layout/Page';
|
||||||
import MenuLayout from 'components/layout/MenuLayout';
|
import MenuLayout from 'components/layout/MenuLayout';
|
||||||
import WebsiteSettings from './WebsiteSettings';
|
import WebsiteSettings from './WebsiteSettings';
|
||||||
@ -8,21 +8,16 @@ import { useSelector } from 'react-redux';
|
|||||||
|
|
||||||
export default function Settings() {
|
export default function Settings() {
|
||||||
const user = useSelector(state => state.user);
|
const user = useSelector(state => state.user);
|
||||||
|
const [option, setOption] = useState('Websites');
|
||||||
|
|
||||||
const menuOptions = ['Websites', user.is_admin && 'Accounts', 'Profile'];
|
const menuOptions = ['Websites', user.is_admin && 'Accounts', 'Profile'];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Page>
|
<Page>
|
||||||
<MenuLayout menu={menuOptions} selectedOption="Websites">
|
<MenuLayout menu={menuOptions} selectedOption={option} onMenuSelect={setOption}>
|
||||||
{option => {
|
{option === 'Websites' && <WebsiteSettings />}
|
||||||
if (option === 'Websites') {
|
{option === 'Accounts' && <AccountSettings />}
|
||||||
return <WebsiteSettings />;
|
{option === 'Profile' && <ProfileSettings />}
|
||||||
} else if (option === 'Accounts') {
|
|
||||||
return <AccountSettings />;
|
|
||||||
} else if (option === 'Profile') {
|
|
||||||
return <ProfileSettings />;
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
</MenuLayout>
|
</MenuLayout>
|
||||||
</Page>
|
</Page>
|
||||||
);
|
);
|
||||||
|
@ -9,15 +9,18 @@ import { get } from 'lib/web';
|
|||||||
import { browserFilter, urlFilter, refFilter, deviceFilter, countryFilter } from 'lib/filters';
|
import { browserFilter, urlFilter, refFilter, deviceFilter, countryFilter } from 'lib/filters';
|
||||||
import styles from './WebsiteDetails.module.css';
|
import styles from './WebsiteDetails.module.css';
|
||||||
import PageHeader from './layout/PageHeader';
|
import PageHeader from './layout/PageHeader';
|
||||||
|
import MenuLayout from './layout/MenuLayout';
|
||||||
|
|
||||||
const pageviewClasses = 'col-md-12 col-lg-6';
|
const pageviewClasses = 'col-md-12 col-lg-6';
|
||||||
const sessionClasses = 'col-12 col-lg-4';
|
const sessionClasses = 'col-12 col-lg-4';
|
||||||
|
const menuOptions = ['Pages', 'Referrers', 'Browsers', 'Operating system', 'Devices', 'Countries'];
|
||||||
|
|
||||||
export default function WebsiteDetails({ websiteId, defaultDateRange = '7day' }) {
|
export default function WebsiteDetails({ websiteId, defaultDateRange = '7day' }) {
|
||||||
const [data, setData] = useState();
|
const [data, setData] = useState();
|
||||||
const [chartLoaded, setChartLoaded] = useState(false);
|
const [chartLoaded, setChartLoaded] = useState(false);
|
||||||
const [countryData, setCountryData] = useState();
|
const [countryData, setCountryData] = useState();
|
||||||
const [dateRange, setDateRange] = useState(getDateRange(defaultDateRange));
|
const [dateRange, setDateRange] = useState(getDateRange(defaultDateRange));
|
||||||
|
const [expand, setExpand] = useState();
|
||||||
const { startDate, endDate } = dateRange;
|
const { startDate, endDate } = dateRange;
|
||||||
|
|
||||||
async function loadData() {
|
async function loadData() {
|
||||||
@ -32,6 +35,14 @@ export default function WebsiteDetails({ websiteId, defaultDateRange = '7day' })
|
|||||||
setTimeout(() => setDateRange(values), 300);
|
setTimeout(() => setDateRange(values), 300);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleExpand(title) {
|
||||||
|
setExpand(title);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleMenuSelect(title) {
|
||||||
|
setExpand(title);
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (websiteId) {
|
if (websiteId) {
|
||||||
loadData();
|
loadData();
|
||||||
@ -55,7 +66,7 @@ export default function WebsiteDetails({ websiteId, defaultDateRange = '7day' })
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{chartLoaded && (
|
{chartLoaded && !expand && (
|
||||||
<>
|
<>
|
||||||
<div className={classNames(styles.row, 'row')}>
|
<div className={classNames(styles.row, 'row')}>
|
||||||
<div className={pageviewClasses}>
|
<div className={pageviewClasses}>
|
||||||
@ -67,6 +78,7 @@ export default function WebsiteDetails({ websiteId, defaultDateRange = '7day' })
|
|||||||
startDate={startDate}
|
startDate={startDate}
|
||||||
endDate={endDate}
|
endDate={endDate}
|
||||||
dataFilter={urlFilter}
|
dataFilter={urlFilter}
|
||||||
|
onExpand={handleExpand}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className={pageviewClasses}>
|
<div className={pageviewClasses}>
|
||||||
@ -78,6 +90,7 @@ export default function WebsiteDetails({ websiteId, defaultDateRange = '7day' })
|
|||||||
startDate={startDate}
|
startDate={startDate}
|
||||||
endDate={endDate}
|
endDate={endDate}
|
||||||
dataFilter={refFilter(data.domain)}
|
dataFilter={refFilter(data.domain)}
|
||||||
|
onExpand={handleExpand}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -91,6 +104,7 @@ export default function WebsiteDetails({ websiteId, defaultDateRange = '7day' })
|
|||||||
startDate={startDate}
|
startDate={startDate}
|
||||||
endDate={endDate}
|
endDate={endDate}
|
||||||
dataFilter={browserFilter}
|
dataFilter={browserFilter}
|
||||||
|
onExpand={handleExpand}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className={sessionClasses}>
|
<div className={sessionClasses}>
|
||||||
@ -101,6 +115,7 @@ export default function WebsiteDetails({ websiteId, defaultDateRange = '7day' })
|
|||||||
websiteId={websiteId}
|
websiteId={websiteId}
|
||||||
startDate={startDate}
|
startDate={startDate}
|
||||||
endDate={endDate}
|
endDate={endDate}
|
||||||
|
onExpand={handleExpand}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className={sessionClasses}>
|
<div className={sessionClasses}>
|
||||||
@ -112,6 +127,7 @@ export default function WebsiteDetails({ websiteId, defaultDateRange = '7day' })
|
|||||||
startDate={startDate}
|
startDate={startDate}
|
||||||
endDate={endDate}
|
endDate={endDate}
|
||||||
dataFilter={deviceFilter}
|
dataFilter={deviceFilter}
|
||||||
|
onExpand={handleExpand}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -129,11 +145,21 @@ export default function WebsiteDetails({ websiteId, defaultDateRange = '7day' })
|
|||||||
endDate={endDate}
|
endDate={endDate}
|
||||||
dataFilter={countryFilter}
|
dataFilter={countryFilter}
|
||||||
onDataLoad={data => setCountryData(data)}
|
onDataLoad={data => setCountryData(data)}
|
||||||
|
onExpand={handleExpand}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
{expand && (
|
||||||
|
<MenuLayout
|
||||||
|
className={styles.expand}
|
||||||
|
menuClassName={styles.menu}
|
||||||
|
menu={menuOptions}
|
||||||
|
selectedOption={expand}
|
||||||
|
onMenuSelect={handleMenuSelect}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</Page>
|
</Page>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,14 @@
|
|||||||
margin-bottom: 30px;
|
margin-bottom: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.expand {
|
||||||
|
border-top: 1px solid var(--gray300);
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu {
|
||||||
|
font-size: var(--font-size-small);
|
||||||
|
}
|
||||||
|
|
||||||
.row {
|
.row {
|
||||||
border-top: 1px solid var(--gray300);
|
border-top: 1px solid var(--gray300);
|
||||||
min-height: 430px;
|
min-height: 430px;
|
||||||
|
@ -27,6 +27,7 @@ export default function WebsiteList() {
|
|||||||
{data?.map(({ website_id, name }) => (
|
{data?.map(({ website_id, name }) => (
|
||||||
<div key={website_id} className={styles.website}>
|
<div key={website_id} className={styles.website}>
|
||||||
<PageHeader>
|
<PageHeader>
|
||||||
|
<div>
|
||||||
<Link
|
<Link
|
||||||
href="/website/[...id]"
|
href="/website/[...id]"
|
||||||
as={`/website/${website_id}/${name}`}
|
as={`/website/${website_id}/${name}`}
|
||||||
@ -34,6 +35,7 @@ export default function WebsiteList() {
|
|||||||
>
|
>
|
||||||
{name}
|
{name}
|
||||||
</Link>
|
</Link>
|
||||||
|
</div>
|
||||||
<Button
|
<Button
|
||||||
icon={<Arrow />}
|
icon={<Arrow />}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
.buttons {
|
.buttons {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
align-content: center;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
@ -10,7 +11,7 @@
|
|||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button {
|
.buttons .button {
|
||||||
font-size: var(--font-size-xsmall);
|
font-size: var(--font-size-xsmall);
|
||||||
padding: 4px 8px;
|
padding: 4px 8px;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
import React, { useState, useEffect, useMemo } from 'react';
|
import React, { useState, useEffect, useMemo } from 'react';
|
||||||
import { useSpring, animated, config } from 'react-spring';
|
import { useSpring, animated, config } from 'react-spring';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import CheckVisible from '../helpers/CheckVisible';
|
import CheckVisible from 'components/helpers/CheckVisible';
|
||||||
|
import Button from 'components/common/Button';
|
||||||
|
import Arrow from 'assets/arrow-right.svg';
|
||||||
import { get } from 'lib/web';
|
import { get } from 'lib/web';
|
||||||
import { percentFilter } from 'lib/filters';
|
import { percentFilter } from 'lib/filters';
|
||||||
import styles from './RankingsChart.module.css';
|
import styles from './RankingsChart.module.css';
|
||||||
@ -16,6 +18,7 @@ export default function RankingsChart({
|
|||||||
className,
|
className,
|
||||||
dataFilter,
|
dataFilter,
|
||||||
onDataLoad = () => {},
|
onDataLoad = () => {},
|
||||||
|
onExpand = () => {},
|
||||||
}) {
|
}) {
|
||||||
const [data, setData] = useState();
|
const [data, setData] = useState();
|
||||||
|
|
||||||
@ -62,6 +65,11 @@ export default function RankingsChart({
|
|||||||
<Row key={x} label={x} value={y} percent={z} animate={visible} />
|
<Row key={x} label={x} value={y} percent={z} animate={visible} />
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
<div className={styles.footer}>
|
||||||
|
<Button icon={<Arrow />} size="xsmall" onClick={() => onExpand(title)}>
|
||||||
|
<div>More</div>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</CheckVisible>
|
</CheckVisible>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
.container {
|
.container {
|
||||||
position: relative;
|
position: relative;
|
||||||
min-height: 430px;
|
min-height: 460px;
|
||||||
font-size: var(--font-size-small);
|
font-size: var(--font-size-small);
|
||||||
padding: 20px 0;
|
padding: 20px 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -90,6 +90,11 @@
|
|||||||
transform: translate(-50%, -50%);
|
transform: translate(-50%, -50%);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: 992px) {
|
@media only screen and (max-width: 992px) {
|
||||||
.container {
|
.container {
|
||||||
min-height: auto;
|
min-height: auto;
|
||||||
|
@ -16,8 +16,9 @@ export default function Button({
|
|||||||
<button
|
<button
|
||||||
type={type}
|
type={type}
|
||||||
className={classNames(styles.button, className, {
|
className={classNames(styles.button, className, {
|
||||||
[styles.small]: size === 'small',
|
|
||||||
[styles.large]: size === 'large',
|
[styles.large]: size === 'large',
|
||||||
|
[styles.small]: size === 'small',
|
||||||
|
[styles.xsmall]: size === 'xsmall',
|
||||||
[styles.action]: variant === 'action',
|
[styles.action]: variant === 'action',
|
||||||
[styles.danger]: variant === 'danger',
|
[styles.danger]: variant === 'danger',
|
||||||
})}
|
})}
|
||||||
|
@ -20,12 +20,20 @@
|
|||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.large {
|
||||||
|
font-size: var(--font-size-large);
|
||||||
|
}
|
||||||
|
|
||||||
|
.medium {
|
||||||
|
font-size: var(--font-size-normal);
|
||||||
|
}
|
||||||
|
|
||||||
.small {
|
.small {
|
||||||
font-size: var(--font-size-small);
|
font-size: var(--font-size-small);
|
||||||
}
|
}
|
||||||
|
|
||||||
.large {
|
.xsmall {
|
||||||
font-size: var(--font-size-large);
|
font-size: var(--font-size-xsmall);
|
||||||
}
|
}
|
||||||
|
|
||||||
.action {
|
.action {
|
||||||
|
@ -2,7 +2,7 @@ import React from 'react';
|
|||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import styles from './Icon.module.css';
|
import styles from './Icon.module.css';
|
||||||
|
|
||||||
export default function Icon({ icon, className, size = 'M' }) {
|
export default function Icon({ icon, className, size = 'medium' }) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={classNames(styles.icon, className, {
|
className={classNames(styles.icon, className, {
|
||||||
@ -10,6 +10,7 @@ export default function Icon({ icon, className, size = 'M' }) {
|
|||||||
[styles.large]: size === 'large',
|
[styles.large]: size === 'large',
|
||||||
[styles.medium]: size === 'medium',
|
[styles.medium]: size === 'medium',
|
||||||
[styles.small]: size === 'small',
|
[styles.small]: size === 'small',
|
||||||
|
[styles.xsmall]: size === 'xsmall',
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{icon}
|
{icon}
|
||||||
|
@ -32,3 +32,8 @@
|
|||||||
width: 12px;
|
width: 12px;
|
||||||
height: 12px;
|
height: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.xsmall > svg {
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
}
|
||||||
|
@ -2,26 +2,34 @@ import React, { useState } from 'react';
|
|||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import styles from './MenuLayout.module.css';
|
import styles from './MenuLayout.module.css';
|
||||||
|
|
||||||
export default function MenuLayout({ menu, selectedOption, onMenuSelect, children }) {
|
export default function MenuLayout({
|
||||||
const [option, setOption] = useState(selectedOption);
|
menu,
|
||||||
|
selectedOption,
|
||||||
|
onMenuSelect,
|
||||||
|
className,
|
||||||
|
menuClassName,
|
||||||
|
contentClassName,
|
||||||
|
children,
|
||||||
|
}) {
|
||||||
|
function handleMenuSelect(option) {
|
||||||
|
onMenuSelect(option);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.container}>
|
<div className={classNames(styles.container, className)}>
|
||||||
<div className={styles.menu}>
|
<div className={classNames(styles.menu, menuClassName)}>
|
||||||
{menu.map(item =>
|
{menu.map(option =>
|
||||||
item ? (
|
option ? (
|
||||||
<div
|
<div
|
||||||
className={classNames(styles.option, { [styles.active]: option === item })}
|
className={classNames(styles.option, { [styles.active]: option === selectedOption })}
|
||||||
onClick={() => setOption(item)}
|
onClick={() => handleMenuSelect(option)}
|
||||||
>
|
>
|
||||||
{item}
|
{option}
|
||||||
</div>
|
</div>
|
||||||
) : null,
|
) : null,
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.content}>
|
<div className={classNames(styles.content, contentClassName)}>{children}</div>
|
||||||
{typeof children === 'function' ? children(option) : children}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
.option {
|
.option {
|
||||||
padding: 8px 16px;
|
padding: 8px 16px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
min-width: 140px;
|
min-width: 160px;
|
||||||
margin-right: 30px;
|
margin-right: 30px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
align-content: center;
|
||||||
line-height: 80px;
|
line-height: 80px;
|
||||||
font-size: var(--font-size-large);
|
font-size: var(--font-size-large);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user