mirror of
https://github.com/kremalicious/umami.git
synced 2025-02-14 21:10:34 +01:00
Merge branch 'dev' of https://github.com/mikecao/umami into dev
This commit is contained in:
commit
7bd49e6caf
66
components/common/OverflowText.js
Normal file
66
components/common/OverflowText.js
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
|
import ReactTooltip from 'react-tooltip';
|
||||||
|
|
||||||
|
import styles from './OverflowText.module.css';
|
||||||
|
|
||||||
|
const OverflowText = ({ children, tooltipId }) => {
|
||||||
|
const measureEl = useRef();
|
||||||
|
const [isOverflown, setIsOverflown] = useState(false);
|
||||||
|
|
||||||
|
const measure = useCallback(
|
||||||
|
el => {
|
||||||
|
if (!el) return;
|
||||||
|
setIsOverflown(el.scrollWidth > el.clientWidth);
|
||||||
|
},
|
||||||
|
[setIsOverflown],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Do one measure on mount
|
||||||
|
useEffect(() => {
|
||||||
|
measure(measureEl.current);
|
||||||
|
}, [measure]);
|
||||||
|
|
||||||
|
// Set up resize listener for subsequent measures
|
||||||
|
useEffect(() => {
|
||||||
|
if (!measureEl.current) return;
|
||||||
|
|
||||||
|
// Destructure ref in case it changes out from under us
|
||||||
|
const el = measureEl.current;
|
||||||
|
|
||||||
|
if ('ResizeObserver' in global) {
|
||||||
|
// Ideally, we have access to ResizeObservers
|
||||||
|
const observer = new ResizeObserver(() => {
|
||||||
|
measure(el);
|
||||||
|
});
|
||||||
|
observer.observe(el);
|
||||||
|
return () => observer.unobserve(el);
|
||||||
|
} else {
|
||||||
|
// Otherwise, fall back to measuring on window resizes
|
||||||
|
const handler = () => measure(el);
|
||||||
|
|
||||||
|
window.addEventListener('resize', handler, { passive: true });
|
||||||
|
return () => window.removeEventListener('resize', handler, { passive: true });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span
|
||||||
|
ref={measureEl}
|
||||||
|
data-tip={children.toString()}
|
||||||
|
data-effect="solid"
|
||||||
|
data-for={tooltipId}
|
||||||
|
className={styles.root}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
{isOverflown && <ReactTooltip id={tooltipId}>{children}</ReactTooltip>}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
OverflowText.propTypes = {
|
||||||
|
children: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired,
|
||||||
|
tooltipId: PropTypes.string.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default OverflowText;
|
6
components/common/OverflowText.module.css
Normal file
6
components/common/OverflowText.module.css
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
.root {
|
||||||
|
max-width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
@ -19,7 +19,6 @@ const MetricCard = ({
|
|||||||
<animated.div className={styles.value}>{props.x.interpolate(x => format(x))}</animated.div>
|
<animated.div className={styles.value}>{props.x.interpolate(x => format(x))}</animated.div>
|
||||||
<div className={styles.label}>
|
<div className={styles.label}>
|
||||||
{label}
|
{label}
|
||||||
{~~change === 0 && !hideComparison && <span className={styles.change}>{format(0)}</span>}
|
|
||||||
{~~change !== 0 && !hideComparison && (
|
{~~change !== 0 && !hideComparison && (
|
||||||
<animated.span
|
<animated.span
|
||||||
className={`${styles.change} ${
|
className={`${styles.change} ${
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
import Link from 'components/common/Link';
|
import Link from 'components/common/Link';
|
||||||
|
import OverflowText from 'components/common/OverflowText';
|
||||||
import PageHeader from 'components/layout/PageHeader';
|
import PageHeader from 'components/layout/PageHeader';
|
||||||
import RefreshButton from 'components/common/RefreshButton';
|
import RefreshButton from 'components/common/RefreshButton';
|
||||||
import ButtonLayout from 'components/layout/ButtonLayout';
|
import ButtonLayout from 'components/layout/ButtonLayout';
|
||||||
@ -13,15 +14,19 @@ export default function WebsiteHeader({ websiteId, title, domain, showLink = fal
|
|||||||
const header = showLink ? (
|
const header = showLink ? (
|
||||||
<>
|
<>
|
||||||
<Favicon domain={domain} />
|
<Favicon domain={domain} />
|
||||||
<Link href="/website/[...id]" as={`/website/${websiteId}/${title}`}>
|
<Link
|
||||||
{title}
|
className={styles.titleLink}
|
||||||
|
href="/website/[...id]"
|
||||||
|
as={`/website/${websiteId}/${title}`}
|
||||||
|
>
|
||||||
|
<OverflowText tooltipId={`${websiteId}-title`}>{title}</OverflowText>
|
||||||
</Link>
|
</Link>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<div>
|
<>
|
||||||
<Favicon domain={domain} />
|
<Favicon domain={domain} />
|
||||||
{title}
|
<OverflowText tooltipId={`${websiteId}-title`}>{title}</OverflowText>
|
||||||
</div>
|
</>
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -2,6 +2,14 @@
|
|||||||
color: var(--gray900);
|
color: var(--gray900);
|
||||||
font-size: var(--font-size-large);
|
font-size: var(--font-size-large);
|
||||||
line-height: var(--font-size-large);
|
line-height: var(--font-size-large);
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
max-width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.titleLink {
|
||||||
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.link {
|
.link {
|
||||||
|
@ -4,6 +4,7 @@ import classNames from 'classnames';
|
|||||||
import Link from 'components/common/Link';
|
import Link from 'components/common/Link';
|
||||||
import Table from 'components/common/Table';
|
import Table from 'components/common/Table';
|
||||||
import Button from 'components/common/Button';
|
import Button from 'components/common/Button';
|
||||||
|
import OverflowText from 'components/common/OverflowText';
|
||||||
import PageHeader from 'components/layout/PageHeader';
|
import PageHeader from 'components/layout/PageHeader';
|
||||||
import Modal from 'components/common/Modal';
|
import Modal from 'components/common/Modal';
|
||||||
import WebsiteEditForm from 'components/forms/WebsiteEditForm';
|
import WebsiteEditForm from 'components/forms/WebsiteEditForm';
|
||||||
@ -84,12 +85,20 @@ export default function WebsiteSettings() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const DetailsLink = ({ website_id, name, domain }) => (
|
const DetailsLink = ({ website_id, name, domain }) => (
|
||||||
<Link href="/website/[...id]" as={`/website/${website_id}/${name}`}>
|
<Link
|
||||||
|
className={styles.detailLink}
|
||||||
|
href="/website/[...id]"
|
||||||
|
as={`/website/${website_id}/${name}`}
|
||||||
|
>
|
||||||
<Favicon domain={domain} />
|
<Favicon domain={domain} />
|
||||||
{name}
|
<OverflowText tooltipId={`${website_id}-name`}>{name}</OverflowText>
|
||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const Domain = ({ domain, website_id }) => (
|
||||||
|
<OverflowText tooltipId={`${website_id}-domain`}>{domain}</OverflowText>
|
||||||
|
);
|
||||||
|
|
||||||
const adminColumns = [
|
const adminColumns = [
|
||||||
{
|
{
|
||||||
key: 'name',
|
key: 'name',
|
||||||
@ -101,6 +110,7 @@ export default function WebsiteSettings() {
|
|||||||
key: 'domain',
|
key: 'domain',
|
||||||
label: <FormattedMessage id="label.domain" defaultMessage="Domain" />,
|
label: <FormattedMessage id="label.domain" defaultMessage="Domain" />,
|
||||||
className: 'col-4 col-xl-3',
|
className: 'col-4 col-xl-3',
|
||||||
|
render: Domain,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'account',
|
key: 'account',
|
||||||
@ -125,6 +135,7 @@ export default function WebsiteSettings() {
|
|||||||
key: 'domain',
|
key: 'domain',
|
||||||
label: <FormattedMessage id="label.domain" defaultMessage="Domain" />,
|
label: <FormattedMessage id="label.domain" defaultMessage="Domain" />,
|
||||||
className: 'col-6 col-xl-4',
|
className: 'col-6 col-xl-4',
|
||||||
|
render: Domain,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'action',
|
key: 'action',
|
||||||
|
@ -5,3 +5,7 @@
|
|||||||
.buttons {
|
.buttons {
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.detailLink {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
2
netlify.toml
Normal file
2
netlify.toml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
[functions]
|
||||||
|
included_files = ["public/geo/*.mmdb"]
|
Loading…
Reference in New Issue
Block a user