Merge branch 'master' into f-nikin-fix-main-page-layout
|
@ -8,10 +8,12 @@ import { THEME_COLORS } from 'lib/constants';
|
|||
import styles from './WorldMap.module.css';
|
||||
import useCountryNames from 'hooks/useCountryNames';
|
||||
import useLocale from 'hooks/useLocale';
|
||||
import { useRouter } from 'next/router';
|
||||
|
||||
const geoUrl = '/world-110m.json';
|
||||
|
||||
export default function WorldMap({ data, className }) {
|
||||
const { basePath } = useRouter();
|
||||
const [tooltip, setTooltip] = useState();
|
||||
const [theme] = useTheme();
|
||||
const colors = useMemo(
|
||||
|
@ -57,7 +59,7 @@ export default function WorldMap({ data, className }) {
|
|||
>
|
||||
<ComposableMap projection="geoMercator">
|
||||
<ZoomableGroup zoom={0.8} minZoom={0.7} center={[0, 40]}>
|
||||
<Geographies geography={geoUrl}>
|
||||
<Geographies geography={`${basePath}${geoUrl}`}>
|
||||
{({ geographies }) => {
|
||||
return geographies.map(geo => {
|
||||
const code = geo.properties.ISO_A2;
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
import React, { useState } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { Formik, Form, Field } from 'formik';
|
||||
import { useRouter } from 'next/router';
|
||||
import { post } from 'lib/web';
|
||||
import Button from 'components/common/Button';
|
||||
import FormLayout, {
|
||||
FormButtons,
|
||||
|
@ -10,6 +8,7 @@ import FormLayout, {
|
|||
FormMessage,
|
||||
FormRow,
|
||||
} from 'components/layout/FormLayout';
|
||||
import usePost from 'hooks/usePost';
|
||||
|
||||
const initialValues = {
|
||||
username: '',
|
||||
|
@ -30,11 +29,11 @@ const validate = ({ user_id, username, password }) => {
|
|||
};
|
||||
|
||||
export default function AccountEditForm({ values, onSave, onClose }) {
|
||||
const { basePath } = useRouter();
|
||||
const post = usePost();
|
||||
const [message, setMessage] = useState();
|
||||
|
||||
const handleSubmit = async values => {
|
||||
const { ok, data } = await post(`${basePath}/api/account`, values);
|
||||
const { ok, data } = await post('/api/account', values);
|
||||
|
||||
if (ok) {
|
||||
onSave();
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
import React, { useState } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { useRouter } from 'next/router';
|
||||
import { Formik, Form, Field } from 'formik';
|
||||
import { post } from 'lib/web';
|
||||
import Button from 'components/common/Button';
|
||||
import FormLayout, {
|
||||
FormButtons,
|
||||
|
@ -10,6 +8,7 @@ import FormLayout, {
|
|||
FormMessage,
|
||||
FormRow,
|
||||
} from 'components/layout/FormLayout';
|
||||
import usePost from 'hooks/usePost';
|
||||
|
||||
const initialValues = {
|
||||
current_password: '',
|
||||
|
@ -38,11 +37,11 @@ const validate = ({ current_password, new_password, confirm_password }) => {
|
|||
};
|
||||
|
||||
export default function ChangePasswordForm({ values, onSave, onClose }) {
|
||||
const { basePath } = useRouter();
|
||||
const post = usePost();
|
||||
const [message, setMessage] = useState();
|
||||
|
||||
const handleSubmit = async values => {
|
||||
const { ok, data } = await post(`${basePath}/api/account/password`, values);
|
||||
const { ok, data } = await post('/api/account/password', values);
|
||||
|
||||
if (ok) {
|
||||
onSave();
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
import React, { useState } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { useRouter } from 'next/router';
|
||||
import { Formik, Form, Field } from 'formik';
|
||||
import { del } from 'lib/web';
|
||||
import Button from 'components/common/Button';
|
||||
import FormLayout, {
|
||||
FormButtons,
|
||||
|
@ -10,6 +8,7 @@ import FormLayout, {
|
|||
FormMessage,
|
||||
FormRow,
|
||||
} from 'components/layout/FormLayout';
|
||||
import useDelete from 'hooks/useDelete';
|
||||
|
||||
const CONFIRMATION_WORD = 'DELETE';
|
||||
|
||||
|
@ -28,11 +27,11 @@ const validate = ({ confirmation }) => {
|
|||
};
|
||||
|
||||
export default function DeleteForm({ values, onSave, onClose }) {
|
||||
const { basePath } = useRouter();
|
||||
const del = useDelete();
|
||||
const [message, setMessage] = useState();
|
||||
|
||||
const handleSubmit = async ({ type, id }) => {
|
||||
const { ok, data } = await del(`${basePath}/api/${type}/${id}`);
|
||||
const { ok, data } = await del(`/api/${type}/${id}`);
|
||||
|
||||
if (ok) {
|
||||
onSave();
|
||||
|
|
|
@ -2,7 +2,6 @@ import React, { useState } from 'react';
|
|||
import { FormattedMessage } from 'react-intl';
|
||||
import { Formik, Form, Field } from 'formik';
|
||||
import { useRouter } from 'next/router';
|
||||
import { post } from 'lib/web';
|
||||
import Button from 'components/common/Button';
|
||||
import FormLayout, {
|
||||
FormButtons,
|
||||
|
@ -13,6 +12,7 @@ import FormLayout, {
|
|||
import Icon from 'components/common/Icon';
|
||||
import Logo from 'assets/logo.svg';
|
||||
import styles from './LoginForm.module.css';
|
||||
import usePost from 'hooks/usePost';
|
||||
|
||||
const validate = ({ username, password }) => {
|
||||
const errors = {};
|
||||
|
@ -28,11 +28,12 @@ const validate = ({ username, password }) => {
|
|||
};
|
||||
|
||||
export default function LoginForm() {
|
||||
const post = usePost();
|
||||
const router = useRouter();
|
||||
const [message, setMessage] = useState();
|
||||
|
||||
const handleSubmit = async ({ username, password }) => {
|
||||
const { ok, status, data } = await post(`${router.basePath}/api/auth/login`, {
|
||||
const { ok, status, data } = await post('/api/auth/login', {
|
||||
username,
|
||||
password,
|
||||
});
|
||||
|
@ -65,8 +66,10 @@ export default function LoginForm() {
|
|||
>
|
||||
{() => (
|
||||
<Form>
|
||||
<Icon icon={<Logo />} size="xlarge" className={styles.icon} />
|
||||
<h1 className="center">umami</h1>
|
||||
<div className={styles.header}>
|
||||
<Icon icon={<Logo />} size="xlarge" className={styles.icon} />
|
||||
<h1 className="center">umami</h1>
|
||||
</div>
|
||||
<FormRow>
|
||||
<label htmlFor="username">
|
||||
<FormattedMessage id="label.username" defaultMessage="Username" />
|
||||
|
|
|
@ -13,3 +13,11 @@
|
|||
justify-content: center;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.header {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
margin: 12px 0;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import React, { useState } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { Formik, Form, Field } from 'formik';
|
||||
import { post } from 'lib/web';
|
||||
import Button from 'components/common/Button';
|
||||
import FormLayout, {
|
||||
FormButtons,
|
||||
|
@ -11,7 +10,7 @@ import FormLayout, {
|
|||
} from 'components/layout/FormLayout';
|
||||
import Checkbox from 'components/common/Checkbox';
|
||||
import { DOMAIN_REGEX } from 'lib/constants';
|
||||
import { useRouter } from 'next/router';
|
||||
import usePost from 'hooks/usePost';
|
||||
|
||||
const initialValues = {
|
||||
name: '',
|
||||
|
@ -35,11 +34,11 @@ const validate = ({ name, domain }) => {
|
|||
};
|
||||
|
||||
export default function WebsiteEditForm({ values, onSave, onClose }) {
|
||||
const { basePath } = useRouter();
|
||||
const post = usePost();
|
||||
const [message, setMessage] = useState();
|
||||
|
||||
const handleSubmit = async values => {
|
||||
const { ok, data } = await post(`${basePath}/api/website`, values);
|
||||
const { ok, data } = await post('/api/website', values);
|
||||
|
||||
if (ok) {
|
||||
onSave();
|
||||
|
|
|
@ -60,7 +60,7 @@ export default function MetricsBar({ websiteId, className }) {
|
|||
/>
|
||||
<MetricCard
|
||||
label={<FormattedMessage id="metrics.bounce-rate" defaultMessage="Bounce rate" />}
|
||||
value={pageviews ? (bounces / pageviews) * 100 : 0}
|
||||
value={uniques ? (bounces / uniques) * 100 : 0}
|
||||
format={n => Number(n).toFixed(0) + '%'}
|
||||
/>
|
||||
<MetricCard
|
||||
|
|
|
@ -29,7 +29,7 @@ const TYPE_ICONS = {
|
|||
[TYPE_EVENT]: <Bolt />,
|
||||
};
|
||||
|
||||
export default function RealtimeLog({ data, websites }) {
|
||||
export default function RealtimeLog({ data, websites, websiteId }) {
|
||||
const intl = useIntl();
|
||||
const [locale] = useLocale();
|
||||
const countryNames = useCountryNames(locale);
|
||||
|
@ -88,7 +88,7 @@ export default function RealtimeLog({ data, websites }) {
|
|||
}
|
||||
|
||||
function getWebsite({ website_id }) {
|
||||
return websites.find(n => n.website_id === website_id)?.name;
|
||||
return websites.find(n => n.website_id === website_id);
|
||||
}
|
||||
|
||||
function getDetail({
|
||||
|
@ -111,7 +111,7 @@ export default function RealtimeLog({ data, websites }) {
|
|||
);
|
||||
}
|
||||
if (view_id) {
|
||||
const domain = getWebsite({ website_id });
|
||||
const domain = getWebsite({ website_id })?.domain;
|
||||
return (
|
||||
<a
|
||||
className={styles.link}
|
||||
|
@ -161,7 +161,9 @@ export default function RealtimeLog({ data, websites }) {
|
|||
<Icon className={styles.icon} icon={getIcon(row)} />
|
||||
{getDetail(row)}
|
||||
</div>
|
||||
<div className={styles.website}>{getWebsite(row)}</div>
|
||||
{!websiteId && websites.length > 1 && (
|
||||
<div className={styles.website}>{getWebsite(row)?.domain}</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -28,6 +28,15 @@ export default function RealtimeViews({ websiteId, data, websites }) {
|
|||
},
|
||||
];
|
||||
|
||||
const renderLink = ({ x }) => {
|
||||
const domain = x.startsWith('/') ? getDomain(websiteId) : '';
|
||||
return (
|
||||
<a href={`//${domain}${x}`} target="_blank" rel="noreferrer noopener">
|
||||
{x}
|
||||
</a>
|
||||
);
|
||||
};
|
||||
|
||||
const [referrers, pages] = useMemo(() => {
|
||||
if (pageviews) {
|
||||
const referrers = percentFilter(
|
||||
|
@ -55,7 +64,7 @@ export default function RealtimeViews({ websiteId, data, websites }) {
|
|||
pageviews
|
||||
.reduce((arr, { url, website_id }) => {
|
||||
if (url?.startsWith('/')) {
|
||||
if (!websiteId) {
|
||||
if (!websiteId && websites.length > 1) {
|
||||
url = `${getDomain(website_id)}${url}`;
|
||||
}
|
||||
const row = arr.find(({ x }) => x === url);
|
||||
|
@ -91,6 +100,7 @@ export default function RealtimeViews({ websiteId, data, websites }) {
|
|||
<DataTable
|
||||
title={<FormattedMessage id="metrics.pages" defaultMessage="Pages" />}
|
||||
metric={<FormattedMessage id="metrics.views" defaultMessage="Views" />}
|
||||
renderLabel={renderLink}
|
||||
data={pages}
|
||||
height={400}
|
||||
/>
|
||||
|
|
|
@ -135,7 +135,7 @@ export default function RealtimeDashboard() {
|
|||
<RealtimeViews websiteId={websiteId} data={realtimeData} websites={websites} />
|
||||
</GridColumn>
|
||||
<GridColumn xs={12} lg={8}>
|
||||
<RealtimeLog data={realtimeData} websites={websites} />
|
||||
<RealtimeLog websiteId={websiteId} data={realtimeData} websites={websites} />
|
||||
</GridColumn>
|
||||
</GridRow>
|
||||
<GridRow>
|
||||
|
|
|
@ -43,19 +43,12 @@ export default function WebsiteDetails({ websiteId }) {
|
|||
const [eventsData, setEventsData] = useState();
|
||||
const {
|
||||
resolve,
|
||||
router,
|
||||
query: { view },
|
||||
} = usePageQuery();
|
||||
|
||||
const BackButton = () => (
|
||||
<div key="back-button" className={styles.backButton}>
|
||||
<Link
|
||||
key="back-button"
|
||||
href={router.pathname}
|
||||
as={resolve({ view: undefined })}
|
||||
icon={<Arrow />}
|
||||
size="small"
|
||||
>
|
||||
<Link key="back-button" href={resolve({ view: undefined })} icon={<Arrow />} size="small">
|
||||
<FormattedMessage id="label.back" defaultMessage="Back" />
|
||||
</Link>
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
import { useCallback } from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
import { del } from 'lib/web';
|
||||
|
||||
export default function useDelete() {
|
||||
const { basePath } = useRouter();
|
||||
|
||||
return useCallback(async (url, params, headers) => {
|
||||
return del(`${basePath}${url}`, params, headers);
|
||||
}, []);
|
||||
}
|
|
@ -6,8 +6,7 @@ import { useRouter } from 'next/router';
|
|||
|
||||
export default function useFetch(url, options = {}, update = []) {
|
||||
const dispatch = useDispatch();
|
||||
const [data, setData] = useState();
|
||||
const [status, setStatus] = useState();
|
||||
const [response, setResponse] = useState();
|
||||
const [error, setError] = useState();
|
||||
const [loading, setLoadiing] = useState(false);
|
||||
const [count, setCount] = useState(0);
|
||||
|
@ -19,18 +18,17 @@ export default function useFetch(url, options = {}, update = []) {
|
|||
setLoadiing(true);
|
||||
setError(null);
|
||||
const time = performance.now();
|
||||
const { data, status } = await get(`${basePath}${url}`, params, headers);
|
||||
const { data, status, ok } = await get(`${basePath}${url}`, params, headers);
|
||||
|
||||
dispatch(updateQuery({ url, time: performance.now() - time, completed: Date.now() }));
|
||||
|
||||
if (status >= 400) {
|
||||
setError(data);
|
||||
setData(null);
|
||||
setResponse({ data: null, status, ok });
|
||||
} else {
|
||||
setData(data);
|
||||
setResponse({ data, status, ok });
|
||||
}
|
||||
|
||||
setStatus(status);
|
||||
onDataLoad?.(data);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
|
@ -60,5 +58,5 @@ export default function useFetch(url, options = {}, update = []) {
|
|||
}
|
||||
}, [interval, !!disabled]);
|
||||
|
||||
return { data, status, error, loading };
|
||||
return { ...response, error, loading };
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { useMemo } from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
import { getQueryString } from '../lib/url';
|
||||
import { getQueryString } from 'lib/url';
|
||||
|
||||
export default function usePageQuery() {
|
||||
const router = useRouter();
|
||||
|
@ -25,7 +25,9 @@ export default function usePageQuery() {
|
|||
function resolve(params) {
|
||||
const search = getQueryString({ ...query, ...params });
|
||||
|
||||
return `${pathname}${search}`;
|
||||
const { asPath } = router;
|
||||
|
||||
return `${asPath.split('?')[0]}${search}`;
|
||||
}
|
||||
|
||||
return { pathname, query, resolve, router };
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
import { useCallback } from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
import { post } from 'lib/web';
|
||||
|
||||
export default function usePost() {
|
||||
const { basePath } = useRouter();
|
||||
|
||||
return useCallback(async (url, params, headers) => {
|
||||
return post(`${basePath}${url}`, params, headers);
|
||||
}, []);
|
||||
}
|
|
@ -2,17 +2,7 @@ import { useState, useEffect } from 'react';
|
|||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { updateUser } from 'redux/actions/user';
|
||||
import { useRouter } from 'next/router';
|
||||
import { get } from '../lib/web';
|
||||
|
||||
export async function fetchUser() {
|
||||
const res = await fetch('/api/auth/verify');
|
||||
|
||||
if (!res.ok) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return await res.json();
|
||||
}
|
||||
import { get } from 'lib/web';
|
||||
|
||||
export default function useRequireLogin() {
|
||||
const router = useRouter();
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
"label.add-account": "Tilføj konto",
|
||||
"label.add-website": "Tilføj hjemmeside",
|
||||
"label.administrator": "Administrator",
|
||||
"label.all": "All",
|
||||
"label.all-websites": "All websites",
|
||||
"label.all": "Alle",
|
||||
"label.all-websites": "Alle websites",
|
||||
"label.back": "Tilbage",
|
||||
"label.cancel": "Afvis",
|
||||
"label.change-password": "Skift adgangskode",
|
||||
|
@ -14,11 +14,11 @@
|
|||
"label.custom-range": "Tilpasset interval",
|
||||
"label.dashboard": "Betjeningspanel",
|
||||
"label.date-range": "Datointerval",
|
||||
"label.default-date-range": "Default date range",
|
||||
"label.default-date-range": "Standard datointerval",
|
||||
"label.delete": "Slet",
|
||||
"label.delete-account": "Slet konto",
|
||||
"label.delete-website": "Slet hjemmeside",
|
||||
"label.dismiss": "Dismiss",
|
||||
"label.dismiss": "Afvis",
|
||||
"label.domain": "Domæne",
|
||||
"label.edit": "Rediger",
|
||||
"label.edit-account": "Rediger konto",
|
||||
|
@ -37,8 +37,8 @@
|
|||
"label.password": "Adgangskode",
|
||||
"label.passwords-dont-match": "Adgangskoder matcher ikke",
|
||||
"label.profile": "Profil",
|
||||
"label.realtime": "Realtime",
|
||||
"label.realtime-logs": "Realtime logs",
|
||||
"label.realtime": "Realtid",
|
||||
"label.realtime-logs": "Realtid logs",
|
||||
"label.refresh": "Opdater",
|
||||
"label.required": "Påkrævet",
|
||||
"label.reset": "Reset",
|
||||
|
@ -49,7 +49,7 @@
|
|||
"label.this-month": "Denne måned",
|
||||
"label.this-week": "Denne uge",
|
||||
"label.this-year": "Dette år",
|
||||
"label.timezone": "Timezone",
|
||||
"label.timezone": "Tidszone",
|
||||
"label.today": "Idag",
|
||||
"label.tracking-code": "Sporingskode",
|
||||
"label.unknown": "Ukendt",
|
||||
|
@ -65,8 +65,8 @@
|
|||
"message.get-tracking-code": "Få sporingskode",
|
||||
"message.go-to-settings": "Gå til betjeningspanel",
|
||||
"message.incorrect-username-password": "Ugyldigt brugernavn/adgangskode.",
|
||||
"message.log.visitor": "Visitor from {country} using {browser} on {os} {device}",
|
||||
"message.new-version-available": "A new version of umami {version} is available!",
|
||||
"message.log.visitor": "Besøgende fra {country} bruger {browser} på {os} {device}",
|
||||
"message.new-version-available": "Ny udgave af Umami {version} er tilgængelig!",
|
||||
"message.no-data-available": "Ingen data tilgængelig.",
|
||||
"message.no-websites-configured": "Du har ikke konfigureret nogen websteder.",
|
||||
"message.page-not-found": "Side ikke fundet.",
|
||||
|
|
|
@ -65,7 +65,7 @@
|
|||
"message.get-tracking-code": "トラッキングコードを取得",
|
||||
"message.go-to-settings": "設定する",
|
||||
"message.incorrect-username-password": "ユーザー名/パスワードが正しくありません。",
|
||||
"message.log.visitor": "Visitor from {country} using {browser} on {os} {device}",
|
||||
"message.log.visitor": "{os}({device})で{browser}を使用している{country}からの訪問者",
|
||||
"message.new-version-available": "新しいバージョン({version})が利用可能です!",
|
||||
"message.no-data-available": "データがありません。",
|
||||
"message.no-websites-configured": "Webサイトが設定されていません。",
|
||||
|
|
|
@ -93,7 +93,7 @@
|
|||
"metrics.page-views": "Хуудас үзсэн",
|
||||
"metrics.pages": "Хуудас",
|
||||
"metrics.referrers": "Чиглүүлэгч",
|
||||
"metrics.unique-visitors": "Зочид",
|
||||
"metrics.unique-visitors": "Зочин",
|
||||
"metrics.views": "Үзсэн",
|
||||
"metrics.visitors": "Зочид"
|
||||
"metrics.visitors": "Зочин"
|
||||
}
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
{
|
||||
"label.accounts": "Konta",
|
||||
"label.add-account": "Dodaj konto",
|
||||
"label.add-website": "Dodaj witrynę",
|
||||
"label.administrator": "Administrator",
|
||||
"label.all": "Wszystkie",
|
||||
"label.all-websites": "Wszystkie witryny",
|
||||
"label.back": "Powrót",
|
||||
"label.cancel": "Anuluj",
|
||||
"label.change-password": "Zmień hasło",
|
||||
"label.confirm-password": "Potwierdź hasło",
|
||||
"label.copy-to-clipboard": "Skopiuj do schowka",
|
||||
"label.current-password": "Aktualne hasło",
|
||||
"label.custom-range": "Zakres niestandardowy",
|
||||
"label.dashboard": "Dashboard",
|
||||
"label.date-range": "Zakres dat",
|
||||
"label.default-date-range": "Domyślny zakres dat",
|
||||
"label.delete": "Usuń",
|
||||
"label.delete-account": "Usuń konto",
|
||||
"label.delete-website": "Usuń witrynę",
|
||||
"label.dismiss": "Odrzuć",
|
||||
"label.domain": "Domena",
|
||||
"label.edit": "Edytuj",
|
||||
"label.edit-account": "Edytuj konto",
|
||||
"label.edit-website": "Edytuj witrynę",
|
||||
"label.enable-share-url": "Włącz udostępnianie adresu URL",
|
||||
"label.invalid": "Nieprawidłowy",
|
||||
"label.invalid-domain": "Nieprawidłowa witryna",
|
||||
"label.last-days": "Ostatnie {x} dni",
|
||||
"label.last-hours": "Ostatnie {x} godzin",
|
||||
"label.logged-in-as": "Zalogowano jako {username}",
|
||||
"label.login": "Zaloguj sie",
|
||||
"label.logout": "Wyloguj",
|
||||
"label.more": "Więcej",
|
||||
"label.name": "Name",
|
||||
"label.new-password": "Nowe hasło",
|
||||
"label.password": "Hasło",
|
||||
"label.passwords-dont-match": "Hasła się nie zgadzają",
|
||||
"label.profile": "Profil",
|
||||
"label.realtime": "Czas rzeczywisty",
|
||||
"label.realtime-logs": "Logi w czasie rzeczywistym",
|
||||
"label.refresh": "Odśwież",
|
||||
"label.required": "Wymagany",
|
||||
"label.reset": "Zresetuj",
|
||||
"label.save": "Zapisz",
|
||||
"label.settings": "Ustawienia",
|
||||
"label.share-url": "Udostępnij adres URL",
|
||||
"label.single-day": "W tym dniu",
|
||||
"label.this-month": "W tym miesiącu",
|
||||
"label.this-week": "W tym tygodniu",
|
||||
"label.this-year": "W tym roku",
|
||||
"label.timezone": "Strefa czasowa",
|
||||
"label.today": "Dzisiaj",
|
||||
"label.tracking-code": "Kod śledzenia",
|
||||
"label.unknown": "Nieznany",
|
||||
"label.username": "Nazwa użytkownika",
|
||||
"label.view-details": "Pokaż szczegóły",
|
||||
"label.websites": "Witryny",
|
||||
"message.active-users": "{x} aktualnie {x, plural, one {odwiedzający} other {odwiedzających}}",
|
||||
"message.confirm-delete": "Czy na pewno chcesz usunąć {target}?",
|
||||
"message.copied": "Skopiowano!",
|
||||
"message.delete-warning": "Wszystkie powiązane dane również zostaną usunięte.",
|
||||
"message.failure": "Coś poszło nie tak.",
|
||||
"message.get-share-url": "Uzyskaj adres URL udostępniania",
|
||||
"message.get-tracking-code": "Pobierz kod śledzenia",
|
||||
"message.go-to-settings": "Przejdź do ustawień",
|
||||
"message.incorrect-username-password": "Nieprawidłowa nazwa użytkownika/hasło.",
|
||||
"message.log.visitor": "Odwiedzający z {country} używa {browser} na {os} {device}",
|
||||
"message.new-version-available": "Nowa wersja umami {version} jest dostępna!",
|
||||
"message.no-data-available": "Brak dostępnych danych.",
|
||||
"message.no-websites-configured": "Nie masz skonfigurowanych żadnych witryn internetowych.",
|
||||
"message.page-not-found": "Strona nie znaleziona.",
|
||||
"message.powered-by": "Obsługiwane przez {name}",
|
||||
"message.save-success": "Zapisano pomyślnie.",
|
||||
"message.share-url": "To jest publicznie udostępniany adres URL dla {target}.",
|
||||
"message.track-stats": "Aby śledzić statystyki dla {target}, umieść poniższy kod w sekcji {head} swojej witryny.",
|
||||
"message.type-delete": "Wpisz {delete} w polu poniżej, aby potwierdzić.",
|
||||
"metrics.actions": "Działania",
|
||||
"metrics.average-visit-time": "Średni czas wizyty",
|
||||
"metrics.bounce-rate": "Współczynnik odrzuceń",
|
||||
"metrics.browsers": "Przeglądarki",
|
||||
"metrics.countries": "Kraje",
|
||||
"metrics.device.desktop": "Komputer",
|
||||
"metrics.device.laptop": "Laptop",
|
||||
"metrics.device.mobile": "Smartfon",
|
||||
"metrics.device.tablet": "Tablet",
|
||||
"metrics.devices": "Urządzenia",
|
||||
"metrics.events": "Zdarzenia",
|
||||
"metrics.filter.combined": "Połączone",
|
||||
"metrics.filter.domain-only": "Tylko domena",
|
||||
"metrics.filter.raw": "Surowe dane",
|
||||
"metrics.operating-systems": "System operacyjny",
|
||||
"metrics.page-views": "Wyświetlenia strony",
|
||||
"metrics.pages": "Strony",
|
||||
"metrics.referrers": "Źródła odsyłające",
|
||||
"metrics.unique-visitors": "Unikalni odwiedzający",
|
||||
"metrics.views": "Wyświetlenia",
|
||||
"metrics.visitors": "Odwiedzający"
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
{
|
||||
"label.accounts": "Облікові записи",
|
||||
"label.add-account": "Додати обліковий запис",
|
||||
"label.add-website": "Додати вебсайт",
|
||||
"label.add-website": "Додати сайт",
|
||||
"label.administrator": "Адміністратор",
|
||||
"label.all": "Всі",
|
||||
"label.all-websites": "Всі вебсайти",
|
||||
"label.all-websites": "Всі сайти",
|
||||
"label.back": "Назад",
|
||||
"label.cancel": "Відмінити",
|
||||
"label.change-password": "Змінити пароль",
|
||||
|
@ -14,15 +14,15 @@
|
|||
"label.custom-range": "Довільний період",
|
||||
"label.dashboard": "Інформаційна панель",
|
||||
"label.date-range": "Діапазон дат",
|
||||
"label.default-date-range": "Діапазон дат за умовчанням",
|
||||
"label.default-date-range": "Діапазон дат за замовчуванням",
|
||||
"label.delete": "Видалити",
|
||||
"label.delete-account": "Видалити обліковий запис",
|
||||
"label.delete-website": "Видалити вебсайт",
|
||||
"label.delete-website": "Видалити сайт",
|
||||
"label.dismiss": "Відхилити",
|
||||
"label.domain": "Домен",
|
||||
"label.edit": "Редагувати",
|
||||
"label.edit-account": "Редагувати обліковий запис",
|
||||
"label.edit-website": "Редагувати вебсайт",
|
||||
"label.edit-website": "Редагувати сайт",
|
||||
"label.enable-share-url": "Дозволити ділитися посиланням",
|
||||
"label.invalid": "Некоректний",
|
||||
"label.invalid-domain": "Некоректний домен",
|
||||
|
@ -46,16 +46,16 @@
|
|||
"label.settings": "Налаштування",
|
||||
"label.share-url": "Поділитися посилання",
|
||||
"label.single-day": "Один день",
|
||||
"label.this-month": "Поточний місяць",
|
||||
"label.this-week": "Поточний тиждень",
|
||||
"label.this-year": "Поточний рік",
|
||||
"label.this-month": "Цього місяця",
|
||||
"label.this-week": "Цього тижня",
|
||||
"label.this-year": "Цього ріку",
|
||||
"label.timezone": "Часовий пояс",
|
||||
"label.today": "Сьогодні",
|
||||
"label.tracking-code": "Код для відслідковування",
|
||||
"label.unknown": "Невідомо",
|
||||
"label.username": "Ім'я користувача",
|
||||
"label.view-details": "Переглянути деталі",
|
||||
"label.websites": "Вебсайти",
|
||||
"label.websites": "Сайти",
|
||||
"message.active-users": "{x} поточних відвідувачів",
|
||||
"message.confirm-delete": "Ви впевнені, що бажаєте видалити {target}?",
|
||||
"message.copied": "Скопійовано!",
|
||||
|
@ -68,19 +68,19 @@
|
|||
"message.log.visitor": "Відвідувач з {country} використовуючи {browser} на {os} {device}",
|
||||
"message.new-version-available": "Нова версія umami {version} доступна!",
|
||||
"message.no-data-available": "Немає даних.",
|
||||
"message.no-websites-configured": "У вас немає налаштованих вебсайтів.",
|
||||
"message.no-websites-configured": "У вас немає налаштованих сайтів.",
|
||||
"message.page-not-found": "Сторінку не знайдено.",
|
||||
"message.powered-by": "На базі {name}",
|
||||
"message.save-success": "Збережено успішно.",
|
||||
"message.share-url": "Це публічне посилання для {target}.",
|
||||
"message.track-stats": "Або відслідковувати статистику для {target}, розмістіть наступний код у {head} секції вашого вебсайту.",
|
||||
"message.track-stats": "Аби відслідковувати статистику для {target}, розмістіть наступний код у {head} секції вашого сайту.",
|
||||
"message.type-delete": "Введіть {delete} у полі нижче щоб підтвердити.",
|
||||
"metrics.actions": "Дії",
|
||||
"metrics.average-visit-time": "Середній час візиту",
|
||||
"metrics.bounce-rate": "Показник відмов",
|
||||
"metrics.browsers": "Браузери",
|
||||
"metrics.countries": "Країни",
|
||||
"metrics.device.desktop": "Настільний комп'ютер",
|
||||
"metrics.device.desktop": "Настільний ПК",
|
||||
"metrics.device.laptop": "Ноутбук",
|
||||
"metrics.device.mobile": "Мобільний",
|
||||
"metrics.device.tablet": "Планшет",
|
||||
|
@ -89,7 +89,7 @@
|
|||
"metrics.filter.combined": "Об'єднані",
|
||||
"metrics.filter.domain-only": "Лише домен",
|
||||
"metrics.filter.raw": "Сирі дані",
|
||||
"metrics.operating-systems": "Операційна система",
|
||||
"metrics.operating-systems": "Операційні системи",
|
||||
"metrics.page-views": "Перегляди сторінок",
|
||||
"metrics.pages": "Сторінки",
|
||||
"metrics.referrers": "Джерела",
|
||||
|
|
|
@ -12,6 +12,7 @@ import {
|
|||
ja,
|
||||
nb,
|
||||
nl,
|
||||
pl,
|
||||
pt,
|
||||
ro,
|
||||
ru,
|
||||
|
@ -43,6 +44,7 @@ import idMessages from 'lang-compiled/id-ID.json';
|
|||
import ukMessages from 'lang-compiled/uk-UA.json';
|
||||
import fiMessages from 'lang-compiled/fi-FI.json';
|
||||
import csMessages from 'lang-compiled/cs-CZ.json';
|
||||
import plMessages from 'lang-compiled/pl-PL.json';
|
||||
|
||||
export const messages = {
|
||||
'en-US': enMessages,
|
||||
|
@ -67,6 +69,7 @@ export const messages = {
|
|||
'uk-UA': ukMessages,
|
||||
'fi-FI': fiMessages,
|
||||
'cs-CZ': csMessages,
|
||||
'pl-PL': plMessages,
|
||||
};
|
||||
|
||||
export const dateLocales = {
|
||||
|
@ -92,6 +95,7 @@ export const dateLocales = {
|
|||
'uk-UA': uk,
|
||||
'fi-FI': fi,
|
||||
'cs-CZ': cs,
|
||||
'pl-PL': pl,
|
||||
};
|
||||
|
||||
export const menuOptions = [
|
||||
|
@ -110,6 +114,7 @@ export const menuOptions = [
|
|||
{ label: 'Монгол', value: 'mn-MN', display: 'mn' },
|
||||
{ label: 'Nederlands', value: 'nl-NL', display: 'nl' },
|
||||
{ label: 'Norsk Bokmål', value: 'nb-NO', display: 'nb' },
|
||||
{ label: 'Polski', value: 'pl-PL', display: 'pl' },
|
||||
{ label: 'Português', value: 'pt-PT', display: 'pt' },
|
||||
{ label: 'Русский', value: 'ru-RU', display: 'ru' },
|
||||
{ label: 'Română', value: 'ro-RO', display: 'ro' },
|
||||
|
|
18
package.json
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "umami",
|
||||
"version": "1.4.0",
|
||||
"version": "1.6.0",
|
||||
"description": "A simple, fast, website analytics alternative to Google Analytics. ",
|
||||
"author": "Mike Cao <mike@mikecao.com>",
|
||||
"license": "MIT",
|
||||
|
@ -56,7 +56,7 @@
|
|||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@prisma/client": "2.10.1",
|
||||
"@prisma/client": "2.11.0",
|
||||
"@reduxjs/toolkit": "^1.4.0",
|
||||
"bcrypt": "^5.0.0",
|
||||
"chalk": "^4.1.0",
|
||||
|
@ -76,18 +76,18 @@
|
|||
"lodash.find": "^4.6.0",
|
||||
"maxmind": "^4.3.1",
|
||||
"moment-timezone": "^0.5.31",
|
||||
"next": "^10.0.0",
|
||||
"next": "^10.0.1",
|
||||
"prompts": "2.4.0",
|
||||
"react": "^17.0.1",
|
||||
"react-dom": "^17.0.1",
|
||||
"react-intl": "^5.8.8",
|
||||
"react-intl": "^5.10.1",
|
||||
"react-loader-spinner": "^3.1.14",
|
||||
"react-redux": "^7.2.2",
|
||||
"react-simple-maps": "^2.3.0",
|
||||
"react-spring": "^8.0.27",
|
||||
"react-table": "^7.6.2",
|
||||
"react-tooltip": "^4.2.10",
|
||||
"react-use-measure": "^2.0.2",
|
||||
"react-use-measure": "^2.0.3",
|
||||
"react-window": "^1.8.6",
|
||||
"redux": "^4.0.5",
|
||||
"redux-thunk": "^2.3.0",
|
||||
|
@ -100,7 +100,7 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@formatjs/cli": "^2.13.5",
|
||||
"@prisma/cli": "2.10.1",
|
||||
"@prisma/cli": "2.11.0",
|
||||
"@rollup/plugin-buble": "^0.21.3",
|
||||
"@rollup/plugin-node-resolve": "^10.0.0",
|
||||
"@rollup/plugin-replace": "^2.3.4",
|
||||
|
@ -108,7 +108,7 @@
|
|||
"cross-env": "^7.0.2",
|
||||
"del": "^6.0.0",
|
||||
"dotenv-cli": "^4.0.0",
|
||||
"eslint": "^7.12.1",
|
||||
"eslint": "^7.13.0",
|
||||
"eslint-config-prettier": "^6.15.0",
|
||||
"eslint-plugin-prettier": "^3.1.3",
|
||||
"eslint-plugin-react": "^7.21.5",
|
||||
|
@ -123,10 +123,10 @@
|
|||
"postcss-preset-env": "^6.7.0",
|
||||
"prettier": "^2.1.2",
|
||||
"prettier-eslint": "^11.0.0",
|
||||
"rollup": "^2.33.0",
|
||||
"rollup": "^2.33.2",
|
||||
"rollup-plugin-hashbang": "^2.2.2",
|
||||
"rollup-plugin-terser": "^7.0.2",
|
||||
"stylelint": "^13.7.2",
|
||||
"stylelint": "^13.8.0",
|
||||
"stylelint-config-css-modules": "^2.2.0",
|
||||
"stylelint-config-prettier": "^8.0.1",
|
||||
"stylelint-config-recommended": "^3.0.0",
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React from 'react';
|
||||
import Head from "next/head";
|
||||
import { IntlProvider } from 'react-intl';
|
||||
import { Provider } from 'react-redux';
|
||||
import { useStore } from 'redux/store';
|
||||
|
@ -9,6 +10,7 @@ import 'styles/variables.css';
|
|||
import 'styles/bootstrap-grid.css';
|
||||
import 'styles/index.css';
|
||||
|
||||
|
||||
const Intl = ({ children }) => {
|
||||
const [locale] = useLocale();
|
||||
|
||||
|
@ -27,6 +29,15 @@ export default function App({ Component, pageProps }) {
|
|||
|
||||
return (
|
||||
<Provider store={store}>
|
||||
<Head>
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png"/>
|
||||
<link rel="manifest" href="/site.webmanifest" />
|
||||
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5" />
|
||||
<meta name="msapplication-TileColor" content="#da532c" />
|
||||
<meta name="theme-color" content="#ffffff" />
|
||||
</Head>
|
||||
<Intl>
|
||||
<Component {...pageProps} />
|
||||
</Intl>
|
||||
|
|
|
@ -1,12 +1,17 @@
|
|||
import { useEffect } from 'react';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { useRouter } from 'next/router';
|
||||
import { get } from 'lib/web';
|
||||
import { updateUser } from 'redux/actions/user';
|
||||
|
||||
export default function LogoutPage() {
|
||||
const dispatch = useDispatch();
|
||||
const router = useRouter();
|
||||
const { basePath } = router;
|
||||
|
||||
useEffect(() => {
|
||||
fetch(`${basePath}/api/auth/logout`).then(() => router.push('/login'));
|
||||
dispatch(updateUser(null));
|
||||
get(`${basePath}/api/auth/logout`).then(() => router.push('/login'));
|
||||
}, []);
|
||||
|
||||
return null;
|
||||
|
|
After Width: | Height: | Size: 7.7 KiB |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 2.0 KiB |
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<browserconfig>
|
||||
<msapplication>
|
||||
<tile>
|
||||
<square150x150logo src="/mstile-150x150.png"/>
|
||||
<TileColor>#da532c</TileColor>
|
||||
</tile>
|
||||
</msapplication>
|
||||
</browserconfig>
|
|
@ -0,0 +1 @@
|
|||
{"AF":"Afganistan","AL":"Albania","DZ":"Algieria","AD":"Andora","AO":"Angola","AI":"Anguilla","AQ":"Antarktyda","AG":"Antigua i Barbuda","SA":"Arabia Saudyjska","AR":"Argentyna","AM":"Armenia","AW":"Aruba","AU":"Australia","AT":"Austria","AZ":"Azerbejd\u017can","BS":"Bahamy","BH":"Bahrajn","BD":"Bangladesz","BB":"Barbados","BE":"Belgia","BZ":"Belize","BJ":"Benin","BM":"Bermudy","BT":"Bhutan","BY":"Bia\u0142oru\u015b","BO":"Boliwia","BA":"Bo\u015bnia i Hercegowina","BW":"Botswana","BR":"Brazylia","BN":"Brunei","IO":"Brytyjskie Terytorium Oceanu Indyjskiego","VG":"Brytyjskie Wyspy Dziewicze","BG":"Bu\u0142garia","BF":"Burkina Faso","BI":"Burundi","CL":"Chile","CN":"Chiny","HR":"Chorwacja","CI":"C\u00f4te d\u2019Ivoire","CW":"Cura\u00e7ao","CY":"Cypr","TD":"Czad","ME":"Czarnog\u00f3ra","CZ":"Czechy","UM":"Dalekie Wyspy Mniejsze Stan\u00f3w Zjednoczonych","DK":"Dania","CD":"Demokratyczna Republika Konga","DM":"Dominika","DO":"Dominikana","DJ":"D\u017cibuti","EG":"Egipt","EC":"Ekwador","ER":"Erytrea","EE":"Estonia","SZ":"Eswatini","ET":"Etiopia","FK":"Falklandy","FJ":"Fid\u017ci","PH":"Filipiny","FI":"Finlandia","FR":"Francja","TF":"Francuskie Terytoria Po\u0142udniowe i Antarktyczne","GA":"Gabon","GM":"Gambia","GS":"Georgia Po\u0142udniowa i Sandwich Po\u0142udniowy","GH":"Ghana","GI":"Gibraltar","GR":"Grecja","GD":"Grenada","GL":"Grenlandia","GE":"Gruzja","GU":"Guam","GG":"Guernsey","GY":"Gujana","GF":"Gujana Francuska","GP":"Gwadelupa","GT":"Gwatemala","GN":"Gwinea","GW":"Gwinea Bissau","GQ":"Gwinea R\u00f3wnikowa","HT":"Haiti","ES":"Hiszpania","NL":"Holandia","HN":"Honduras","IN":"Indie","ID":"Indonezja","IQ":"Irak","IR":"Iran","IE":"Irlandia","IS":"Islandia","IL":"Izrael","JM":"Jamajka","JP":"Japonia","YE":"Jemen","JE":"Jersey","JO":"Jordania","KY":"Kajmany","KH":"Kambod\u017ca","CM":"Kamerun","CA":"Kanada","QA":"Katar","KZ":"Kazachstan","KE":"Kenia","KG":"Kirgistan","KI":"Kiribati","CO":"Kolumbia","KM":"Komory","CG":"Kongo","KR":"Korea Po\u0142udniowa","KP":"Korea P\u00f3\u0142nocna","CR":"Kostaryka","CU":"Kuba","KW":"Kuwejt","LA":"Laos","LS":"Lesotho","LB":"Liban","LR":"Liberia","LY":"Libia","LI":"Liechtenstein","LT":"Litwa","LU":"Luksemburg","LV":"\u0141otwa","MK":"Macedonia P\u00f3\u0142nocna","MG":"Madagaskar","YT":"Majotta","MW":"Malawi","MV":"Malediwy","MY":"Malezja","ML":"Mali","MT":"Malta","MP":"Mariany P\u00f3\u0142nocne","MA":"Maroko","MQ":"Martynika","MR":"Mauretania","MU":"Mauritius","MX":"Meksyk","FM":"Mikronezja","MM":"Mjanma (Birma)","MD":"Mo\u0142dawia","MC":"Monako","MN":"Mongolia","MS":"Montserrat","MZ":"Mozambik","NA":"Namibia","NR":"Nauru","NP":"Nepal","BQ":"Niderlandy Karaibskie","DE":"Niemcy","NE":"Niger","NG":"Nigeria","NI":"Nikaragua","NU":"Niue","NF":"Norfolk","NO":"Norwegia","NC":"Nowa Kaledonia","NZ":"Nowa Zelandia","OM":"Oman","PK":"Pakistan","PW":"Palau","PA":"Panama","PG":"Papua-Nowa Gwinea","PY":"Paragwaj","PE":"Peru","PN":"Pitcairn","PF":"Polinezja Francuska","PL":"Polska","PR":"Portoryko","PT":"Portugalia","ZA":"Republika Po\u0142udniowej Afryki","CF":"Republika \u015arodkowoafryka\u0144ska","CV":"Republika Zielonego Przyl\u0105dka","RE":"Reunion","RU":"Rosja","RO":"Rumunia","RW":"Rwanda","EH":"Sahara Zachodnia","KN":"Saint Kitts i Nevis","LC":"Saint Lucia","VC":"Saint Vincent i Grenadyny","BL":"Saint-Barth\u00e9lemy","MF":"Saint-Martin","PM":"Saint-Pierre i Miquelon","SV":"Salwador","WS":"Samoa","AS":"Samoa Ameryka\u0144skie","SM":"San Marino","SN":"Senegal","RS":"Serbia","SC":"Seszele","SL":"Sierra Leone","SG":"Singapur","SX":"Sint Maarten","SK":"S\u0142owacja","SI":"S\u0142owenia","SO":"Somalia","HK":"SRA Hongkong (Chiny)","MO":"SRA Makau (Chiny)","LK":"Sri Lanka","US":"Stany Zjednoczone","SD":"Sudan","SS":"Sudan Po\u0142udniowy","SR":"Surinam","SJ":"Svalbard i Jan Mayen","SY":"Syria","CH":"Szwajcaria","SE":"Szwecja","TJ":"Tad\u017cykistan","TH":"Tajlandia","TW":"Tajwan","TZ":"Tanzania","PS":"Terytoria Palesty\u0144skie","TL":"Timor Wschodni","TG":"Togo","TK":"Tokelau","TO":"Tonga","TT":"Trynidad i Tobago","TN":"Tunezja","TR":"Turcja","TM":"Turkmenistan","TC":"Turks i Caicos","TV":"Tuvalu","UG":"Uganda","UA":"Ukraina","UY":"Urugwaj","UZ":"Uzbekistan","VU":"Vanuatu","WF":"Wallis i Futuna","VA":"Watykan","VE":"Wenezuela","HU":"W\u0119gry","GB":"Wielka Brytania","VN":"Wietnam","IT":"W\u0142ochy","BV":"Wyspa Bouveta","CX":"Wyspa Bo\u017cego Narodzenia","IM":"Wyspa Man","SH":"Wyspa \u015awi\u0119tej Heleny","AX":"Wyspy Alandzkie","CK":"Wyspy Cooka","VI":"Wyspy Dziewicze Stan\u00f3w Zjednoczonych","HM":"Wyspy Heard i McDonalda","CC":"Wyspy Kokosowe","MH":"Wyspy Marshalla","FO":"Wyspy Owcze","SB":"Wyspy Salomona","ST":"Wyspy \u015awi\u0119tego Tomasza i Ksi\u0105\u017c\u0119ca","ZM":"Zambia","ZW":"Zimbabwe","AE":"Zjednoczone Emiraty Arabskie"}
|
After Width: | Height: | Size: 597 B |
After Width: | Height: | Size: 888 B |
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 2.9 KiB |
|
@ -0,0 +1,75 @@
|
|||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||
width="856.000000pt" height="856.000000pt" viewBox="0 0 856.000000 856.000000"
|
||||
preserveAspectRatio="xMidYMid meet">
|
||||
<metadata>
|
||||
Created by potrace 1.11, written by Peter Selinger 2001-2013
|
||||
</metadata>
|
||||
<g transform="translate(0.000000,856.000000) scale(0.100000,-0.100000)"
|
||||
fill="#000000" stroke="none">
|
||||
<path d="M4027 8163 c-2 -2 -28 -5 -58 -7 -50 -4 -94 -9 -179 -22 -19 -2 -48
|
||||
-6 -65 -9 -47 -6 -236 -44 -280 -55 -22 -6 -49 -12 -60 -15 -34 -6 -58 -13
|
||||
-130 -36 -38 -13 -72 -23 -75 -24 -29 -6 -194 -66 -264 -96 -49 -22 -95 -39
|
||||
-102 -39 -7 0 -19 -7 -28 -15 -8 -9 -18 -15 -21 -14 -7 1 -197 -92 -205 -101
|
||||
-3 -3 -21 -13 -40 -24 -79 -42 -123 -69 -226 -137 -94 -62 -246 -173 -280
|
||||
-204 -6 -5 -29 -25 -52 -43 -136 -111 -329 -305 -457 -462 -21 -25 -41 -47
|
||||
-44 -50 -4 -3 -22 -26 -39 -52 -18 -25 -38 -52 -45 -60 -34 -35 -207 -308
|
||||
-259 -408 -13 -25 -25 -47 -28 -50 -11 -11 -121 -250 -159 -346 -42 -105 -114
|
||||
-321 -126 -374 l-7 -30 -263 0 c-245 0 -268 -2 -321 -21 -94 -35 -171 -122
|
||||
-191 -216 -9 -39 -8 -852 0 -938 9 -87 16 -150 23 -195 3 -19 6 -48 8 -65 3
|
||||
-29 14 -97 22 -140 3 -11 7 -36 10 -55 3 -19 9 -51 14 -70 5 -19 11 -46 14
|
||||
-60 29 -138 104 -401 145 -505 5 -11 23 -58 42 -105 18 -47 42 -105 52 -130
|
||||
11 -25 21 -49 22 -55 3 -10 109 -224 164 -330 18 -33 50 -89 71 -124 22 -34
|
||||
40 -64 40 -66 0 -8 104 -161 114 -167 6 -4 7 -8 3 -8 -4 0 4 -12 18 -27 14
|
||||
-15 25 -32 25 -36 0 -5 6 -14 13 -21 6 -7 21 -25 32 -41 11 -15 34 -44 50 -64
|
||||
17 -21 41 -52 55 -70 13 -18 33 -43 45 -56 11 -13 42 -49 70 -81 100 -118 359
|
||||
-369 483 -469 34 -27 62 -53 62 -57 0 -5 6 -8 13 -8 7 0 19 -9 27 -20 8 -11
|
||||
19 -20 26 -20 6 0 19 -9 29 -20 10 -11 22 -20 27 -20 5 0 23 -13 41 -30 18
|
||||
-16 37 -30 44 -30 6 0 13 -4 15 -8 3 -8 186 -132 194 -132 2 0 27 -15 56 -34
|
||||
132 -83 377 -207 558 -280 36 -15 74 -31 85 -36 62 -26 220 -81 320 -109 79
|
||||
-23 191 -53 214 -57 14 -3 28 -7 31 -9 4 -2 20 -7 36 -9 16 -3 40 -8 54 -11
|
||||
14 -3 36 -8 50 -11 14 -2 36 -7 50 -10 13 -3 40 -8 60 -10 19 -2 46 -7 60 -10
|
||||
54 -10 171 -25 320 -40 90 -9 613 -12 636 -4 11 5 28 4 37 -1 9 -6 17 -6 17
|
||||
-1 0 4 10 8 23 9 29 0 154 12 192 18 17 3 46 7 65 9 70 10 131 20 183 32 16 3
|
||||
38 7 50 9 45 7 165 36 252 60 50 14 100 28 112 30 12 3 34 10 48 15 14 5 25 7
|
||||
25 4 0 -4 6 -2 13 3 6 6 30 16 52 22 22 7 47 15 55 18 8 4 17 7 20 7 10 2 179
|
||||
68 240 94 96 40 342 159 395 191 17 10 53 30 80 46 28 15 81 47 118 71 37 24
|
||||
72 44 76 44 5 0 11 3 13 8 2 4 30 25 63 47 33 22 62 42 65 45 3 3 50 38 105
|
||||
79 55 40 105 79 110 85 6 6 24 22 40 34 85 65 465 430 465 447 0 3 8 13 18 23
|
||||
9 10 35 40 57 66 22 27 47 56 55 65 8 9 42 52 74 96 32 44 71 96 85 115 140
|
||||
183 358 576 461 830 12 30 28 69 36 85 24 56 123 355 117 355 -3 0 -1 6 5 13
|
||||
6 6 14 30 18 52 10 48 9 46 17 65 5 13 37 155 52 230 9 42 35 195 40 231 34
|
||||
235 40 357 40 804 l0 420 -24 44 c-46 87 -143 157 -231 166 -19 2 -144 4 -276
|
||||
4 l-242 1 -36 118 c-21 64 -46 139 -56 166 -11 27 -20 52 -20 57 0 5 -11 33
|
||||
-25 63 -14 30 -25 58 -25 61 0 18 -152 329 -162 333 -5 2 -8 10 -8 18 0 8 -4
|
||||
14 -10 14 -5 0 -9 3 -8 8 3 9 -40 82 -128 217 -63 97 -98 145 -187 259 -133
|
||||
171 -380 420 -559 564 -71 56 -132 102 -138 102 -5 0 -10 3 -10 8 0 4 -25 23
|
||||
-55 42 -30 19 -55 38 -55 43 0 4 -6 7 -13 7 -7 0 -22 8 -33 18 -11 9 -37 26
|
||||
-59 37 -21 11 -44 25 -50 30 -41 37 -413 220 -540 266 -27 9 -61 22 -75 27
|
||||
-14 5 -28 10 -32 11 -4 1 -28 10 -53 21 -25 11 -46 19 -48 18 -2 -1 -109 29
|
||||
-137 40 -13 4 -32 9 -65 16 -5 1 -16 5 -22 9 -7 5 -13 6 -13 3 0 -2 -15 0 -32
|
||||
5 -18 5 -44 11 -58 14 -14 3 -36 7 -50 10 -14 3 -50 9 -80 15 -30 6 -64 12
|
||||
-75 14 -11 2 -45 6 -75 10 -30 4 -71 9 -90 12 -19 3 -53 6 -75 7 -22 1 -44 5
|
||||
-50 8 -11 7 -542 9 -548 2z m57 -404 c7 10 436 8 511 -3 22 -3 60 -8 85 -11
|
||||
25 -2 56 -6 70 -9 14 -2 43 -7 65 -10 38 -5 58 -9 115 -21 14 -3 34 -7 45 -9
|
||||
11 -2 58 -14 105 -26 47 -12 92 -23 100 -25 35 -7 279 -94 308 -109 17 -9 34
|
||||
-16 37 -16 3 1 20 -6 38 -14 17 -8 68 -31 112 -51 44 -20 82 -35 84 -35 2 1 7
|
||||
-3 10 -8 3 -5 43 -28 88 -51 45 -23 87 -48 93 -56 7 -8 17 -15 22 -15 12 0
|
||||
192 -121 196 -132 2 -4 8 -8 13 -8 10 0 119 -86 220 -172 102 -87 256 -244
|
||||
349 -357 25 -30 53 -63 63 -73 9 -10 17 -22 17 -28 0 -5 3 -10 8 -10 4 0 25
|
||||
-27 46 -60 22 -33 43 -60 48 -60 4 0 8 -5 8 -11 0 -6 11 -25 25 -43 14 -18 25
|
||||
-38 25 -44 0 -7 4 -12 8 -12 5 0 16 -15 25 -32 9 -18 30 -55 47 -83 46 -77
|
||||
161 -305 154 -305 -4 0 -2 -6 4 -12 6 -7 23 -47 40 -88 16 -41 33 -84 37 -95
|
||||
5 -11 9 -22 10 -25 0 -3 11 -36 24 -73 13 -38 21 -70 19 -73 -3 -2 -1386 -3
|
||||
-3075 -2 l-3071 3 38 110 c47 137 117 301 182 425 62 118 167 295 191 320 9
|
||||
11 17 22 17 25 0 7 39 63 58 83 6 7 26 35 44 60 18 26 37 52 43 57 6 6 34 37
|
||||
61 70 48 59 271 286 329 335 17 14 53 43 80 65 28 22 52 42 55 45 3 3 21 17
|
||||
40 30 19 14 40 28 45 32 40 32 105 78 109 78 3 0 28 16 55 35 26 19 53 35 58
|
||||
35 5 0 18 8 29 18 17 15 53 35 216 119 118 60 412 176 422 166 3 -4 6 -2 6 4
|
||||
0 6 12 13 28 16 15 3 52 12 82 21 30 9 63 19 73 21 10 2 27 7 37 10 10 3 29 8
|
||||
42 10 13 3 48 10 78 16 30 7 61 12 68 12 6 0 12 4 12 9 0 5 5 6 10 3 6 -4 34
|
||||
-2 63 4 51 11 71 13 197 26 36 4 67 9 69 11 2 2 10 -1 17 -7 8 -6 14 -7 18 0z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 5.0 KiB |
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"name": "",
|
||||
"short_name": "",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/android-chrome-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/android-chrome-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"theme_color": "#ffffff",
|
||||
"background_color": "#ffffff",
|
||||
"display": "standalone"
|
||||
}
|