Merge remote-tracking branch 'origin/dev' into testing-{city,-region}
commit
774b7f9296
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"name": "Umami",
|
||||
"description": "Umami is a simple, fast, website analytics alternative to Google Analytics.",
|
||||
"keywords": [
|
||||
"analytics",
|
||||
"charts",
|
||||
"statistics",
|
||||
"web-analytics"
|
||||
],
|
||||
"website": "https://umami.is",
|
||||
"repository": "https://github.com/mikecao/umami",
|
||||
"addons": [
|
||||
"heroku-postgresql"
|
||||
],
|
||||
"env": {
|
||||
"HASH_SALT": {
|
||||
"description": "Used to generate unique values for your installation",
|
||||
"required": true,
|
||||
"generator": "secret"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"postdeploy": "psql $DATABASE_URL -f sql/schema.postgresql.sql"
|
||||
},
|
||||
"success_url": "/"
|
||||
}
|
|
@ -16,6 +16,7 @@ function MenuButton({
|
|||
menuAlign = 'right',
|
||||
onSelect,
|
||||
renderValue,
|
||||
hideLabel,
|
||||
}) {
|
||||
const [showMenu, setShowMenu] = useState(false);
|
||||
const ref = useRef();
|
||||
|
@ -44,7 +45,9 @@ function MenuButton({
|
|||
onClick={toggleMenu}
|
||||
variant="light"
|
||||
>
|
||||
<div className={styles.text}>{renderValue ? renderValue(selectedOption) : value}</div>
|
||||
{!hideLabel && (
|
||||
<div className={styles.text}>{renderValue ? renderValue(selectedOption) : value}</div>
|
||||
)}
|
||||
</Button>
|
||||
{showMenu && (
|
||||
<Menu
|
||||
|
|
|
@ -5,14 +5,13 @@ import Link from 'components/common/Link';
|
|||
import styles from './Footer.module.css';
|
||||
import useVersion from 'hooks/useVersion';
|
||||
import useLocale from 'hooks/useLocale';
|
||||
import { rtlLocales } from 'lib/lang';
|
||||
|
||||
export default function Footer() {
|
||||
const { current } = useVersion();
|
||||
const { locale } = useLocale();
|
||||
const { dir } = useLocale();
|
||||
|
||||
return (
|
||||
<footer className="container" dir={rtlLocales.includes(locale) ? 'rtl' : 'ltr'}>
|
||||
<footer className="container" dir={dir}>
|
||||
<div className={classNames(styles.footer, 'row')}>
|
||||
<div className="col-12 col-md-4" />
|
||||
<div className="col-12 col-md-4">
|
||||
|
|
|
@ -12,21 +12,20 @@ import Button from 'components/common/Button';
|
|||
import Logo from 'assets/logo.svg';
|
||||
import styles from './Header.module.css';
|
||||
import useLocale from 'hooks/useLocale';
|
||||
import { rtlLocales } from 'lib/lang';
|
||||
import XMark from 'assets/xmark.svg';
|
||||
import Bars from 'assets/bars.svg';
|
||||
|
||||
export default function Header() {
|
||||
const user = useSelector(state => state.user);
|
||||
const [active, setActive] = useState(false);
|
||||
const { locale } = useLocale();
|
||||
const { locale, dir } = useLocale();
|
||||
|
||||
function handleClick() {
|
||||
setActive(state => !state);
|
||||
}
|
||||
|
||||
return (
|
||||
<nav className="container" dir={rtlLocales.includes(locale) ? 'rtl' : 'ltr'}>
|
||||
<nav className="container" dir={dir}>
|
||||
{user?.is_admin && <UpdateNotice />}
|
||||
<div className={classNames(styles.header, 'row align-items-center')}>
|
||||
<div className={styles.nav}>
|
||||
|
|
|
@ -3,11 +3,9 @@ import Head from 'next/head';
|
|||
import Header from 'components/layout/Header';
|
||||
import Footer from 'components/layout/Footer';
|
||||
import useLocale from 'hooks/useLocale';
|
||||
import { rtlLocales } from 'lib/lang';
|
||||
|
||||
export default function Layout({ title, children, header = true, footer = true }) {
|
||||
const { locale } = useLocale();
|
||||
const dir = rtlLocales.includes(locale) ? 'rtl' : 'ltr';
|
||||
const { dir } = useLocale();
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
|
@ -5,4 +5,5 @@
|
|||
align-content: center;
|
||||
min-height: 80px;
|
||||
align-self: stretch;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
|
|
@ -37,8 +37,8 @@ export default function LanguageButton() {
|
|||
options={menuOptions}
|
||||
value={locale}
|
||||
menuClassName={styles.menu}
|
||||
renderValue={option => option?.display}
|
||||
onSelect={handleSelect}
|
||||
hideLabel
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import { setLocale } from 'redux/actions/app';
|
|||
import { useRouter } from 'next/router';
|
||||
import { get, setItem } from 'lib/web';
|
||||
import { LOCALE_CONFIG } from 'lib/constants';
|
||||
import { languages } from 'lib/lang';
|
||||
import useForceUpdate from 'hooks/useForceUpdate';
|
||||
import enUS from 'public/lang/en-US.json';
|
||||
|
||||
|
@ -16,6 +17,7 @@ export default function useLocale() {
|
|||
const dispatch = useDispatch();
|
||||
const { basePath } = useRouter();
|
||||
const forceUpdate = useForceUpdate();
|
||||
const dir = languages[locale]?.dir || 'ltr';
|
||||
|
||||
async function loadMessages(locale) {
|
||||
const { ok, data } = await get(`${basePath}/lang/${locale}.json`);
|
||||
|
@ -45,5 +47,5 @@ export default function useLocale() {
|
|||
}
|
||||
}, [locale]);
|
||||
|
||||
return { locale, saveLocale, messages };
|
||||
return { locale, saveLocale, messages, dir };
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
"label.delete": "حذف",
|
||||
"label.delete-account": "حذف الحساب",
|
||||
"label.delete-website": "حذف الموقع",
|
||||
"label.reset-website": "اعادة تعيين الإحصائيات",
|
||||
"label.dismiss": "اخفاء",
|
||||
"label.domain": "نطاق",
|
||||
"label.edit": "تعديل",
|
||||
|
@ -58,8 +59,10 @@
|
|||
"label.view-details": "عرض التفاصيل",
|
||||
"label.websites": "المواقع",
|
||||
"message.active-users": "{x} حاليا {x, plural, one {زائر واحد} other {زوار}}",
|
||||
"message.confirm-reset": "هل أنت متأكد من اعادة تعيين الإحصائيات لـ {target}؟",
|
||||
"message.confirm-delete": "هل أنت متأكد من حذف {target}?",
|
||||
"message.copied": "تم النسخ!",
|
||||
"message.reset-warning": "سيتم اعادة تعيين كافة الإحصائيات لهذا الموقع، لكن لن يتم تعيير كود التتبع",
|
||||
"message.delete-warning": "كافة البيانات المرتبطة سيم حذفها ايضا.",
|
||||
"message.failure": "حدث خطأ ما.",
|
||||
"message.get-share-url": "احصل على رابط المشاركة",
|
||||
|
|
|
@ -59,8 +59,8 @@
|
|||
"label.view-details": "View details",
|
||||
"label.websites": "Websites",
|
||||
"message.active-users": "{x} current {x, plural, one {visitor} other {visitors}}",
|
||||
"message.confirm-reset": "Are your sure you want to reset {target}'s statistics?",
|
||||
"message.confirm-delete": "Are your sure you want to delete {target}?",
|
||||
"message.confirm-reset": "Are you sure you want to reset {target}'s statistics?",
|
||||
"message.confirm-delete": "Are you sure you want to delete {target}?",
|
||||
"message.copied": "Copied!",
|
||||
"message.reset-warning": "All statistics for this website will be deleted, but your tracking code will remain intact.",
|
||||
"message.delete-warning": "All associated data will be deleted as well.",
|
||||
|
|
|
@ -59,8 +59,8 @@
|
|||
"label.view-details": "View details",
|
||||
"label.websites": "Websites",
|
||||
"message.active-users": "{x} current {x, plural, one {visitor} other {visitors}}",
|
||||
"message.confirm-reset": "Are your sure you want to reset {target}'s statistics?",
|
||||
"message.confirm-delete": "Are your sure you want to delete {target}?",
|
||||
"message.confirm-reset": "Are you sure you want to reset {target}'s statistics?",
|
||||
"message.confirm-delete": "Are you sure you want to delete {target}?",
|
||||
"message.copied": "Copied!",
|
||||
"message.reset-warning": "All statistics for this website will be deleted, but your tracking code will remain intact.",
|
||||
"message.delete-warning": "All associated data will be deleted as well.",
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
"label.administrator": "Pengelola",
|
||||
"label.all": "Semua",
|
||||
"label.all-websites": "Semua website",
|
||||
"label.all-events": "Semua peristiwa",
|
||||
"label.back": "Kembali",
|
||||
"label.cancel": "Batal",
|
||||
"label.change-password": "Ganti kata sandi",
|
||||
|
@ -18,6 +19,7 @@
|
|||
"label.delete": "Hapus",
|
||||
"label.delete-account": "Hapus akun",
|
||||
"label.delete-website": "Hapus situs web",
|
||||
"label.reset-website": "Atur ulang statistik",
|
||||
"label.dismiss": "Tutup",
|
||||
"label.domain": "Domain",
|
||||
"label.edit": "Sunting",
|
||||
|
@ -59,6 +61,7 @@
|
|||
"message.active-users": "{x} pengunjung saat ini",
|
||||
"message.confirm-delete": "Apakah kamu yakin ingin menghapus {target}?",
|
||||
"message.copied": "Tersalin!",
|
||||
"message.reset-warning": "Semua statistik pada website ini akan dihapus, tetapi kode lacak akan tetap terpasang",
|
||||
"message.delete-warning": "Semua data terkait juga akan dihapus.",
|
||||
"message.failure": "Ada yang salah.",
|
||||
"message.get-share-url": "Dapatkan URL berbagi",
|
||||
|
|
|
@ -72,7 +72,7 @@
|
|||
"message.page-not-found": "ページが見つかりません。",
|
||||
"message.powered-by": "このシステムは {name} で実行されています。",
|
||||
"message.save-success": "正常に保存されました。",
|
||||
"message.share-url": "これは {target} の共有リンクです。",
|
||||
"message.share-url": "これは{target}の共有リンクです。",
|
||||
"message.track-stats": "{target}のアクセス解析を開始するには、次のコードをWebサイトの{head}セクションへ追加してください。",
|
||||
"message.type-delete": "確認のため、下のフォームに{delete}と入力してください。",
|
||||
"metrics.actions": "アクション",
|
||||
|
|
|
@ -65,7 +65,7 @@
|
|||
"message.get-tracking-code": "获取跟踪代码",
|
||||
"message.go-to-settings": "去设置",
|
||||
"message.incorrect-username-password": "用户名或密码不正确。",
|
||||
"message.log.visitor": "来自 {country} 的访客在搭载 {os} 的 {device} 上使用 {browser} 浏览器进行访问。",
|
||||
"message.log.visitor": "来自{country}的访客在搭载 {os} 的{device}上使用 {browser} 浏览器进行访问。",
|
||||
"message.new-version-available": "umami 有新版本 {version} 发布啦!",
|
||||
"message.no-data-available": "无可用数据。",
|
||||
"message.no-websites-configured": "你还没有设置任何网站。",
|
||||
|
|
|
@ -65,7 +65,7 @@
|
|||
"message.get-tracking-code": "獲得追蹤代碼",
|
||||
"message.go-to-settings": "去設定",
|
||||
"message.incorrect-username-password": "用户名或密碼不正確。",
|
||||
"message.log.visitor": "自 {country} 的訪客在搭載 {os} 的 {device} 上使用 {browser} 進行訪問。",
|
||||
"message.log.visitor": "自{country}的訪客在搭載 {os} 的{device}上使用 {browser} 進行訪問。",
|
||||
"message.new-version-available": "umami 有新版本 {version} 發佈啦!",
|
||||
"message.no-data-available": "無可用數據。",
|
||||
"message.no-websites-configured": "目前無任何網站設定。",
|
||||
|
|
10
lib/date.js
10
lib/date.js
|
@ -26,7 +26,7 @@ import {
|
|||
format,
|
||||
} from 'date-fns';
|
||||
import { enUS } from 'date-fns/locale';
|
||||
import { dateLocales } from 'lib/lang';
|
||||
import { languages } from 'lib/lang';
|
||||
|
||||
export function getTimezone() {
|
||||
return moment.tz.guess();
|
||||
|
@ -38,7 +38,7 @@ export function getLocalTime(t) {
|
|||
|
||||
export function getDateRange(value, locale = 'en-US') {
|
||||
const now = new Date();
|
||||
const localeOptions = dateLocales[locale];
|
||||
const dateLocale = languages[locale]?.dateLocale || enUS;
|
||||
|
||||
const { num, unit } = value.match(/^(?<num>[0-9]+)(?<unit>hour|day|week|month|year)$/).groups;
|
||||
|
||||
|
@ -53,8 +53,8 @@ export function getDateRange(value, locale = 'en-US') {
|
|||
};
|
||||
case 'week':
|
||||
return {
|
||||
startDate: startOfWeek(now, { locale: localeOptions }),
|
||||
endDate: endOfWeek(now, { locale: localeOptions }),
|
||||
startDate: startOfWeek(now, { locale: dateLocale }),
|
||||
endDate: endOfWeek(now, { locale: dateLocale }),
|
||||
unit: 'day',
|
||||
value,
|
||||
};
|
||||
|
@ -164,6 +164,6 @@ export const customFormats = {
|
|||
|
||||
export function dateFormat(date, str, locale = 'en-US') {
|
||||
return format(date, customFormats?.[locale]?.[str] || str, {
|
||||
locale: dateLocales[locale] || enUS,
|
||||
locale: languages[locale]?.dateLocale || enUS,
|
||||
});
|
||||
}
|
||||
|
|
116
lib/lang.js
116
lib/lang.js
|
@ -38,83 +38,41 @@ import {
|
|||
} from 'date-fns/locale';
|
||||
|
||||
export const languages = {
|
||||
'ar-SA': { label: 'العربية', display: 'ar' },
|
||||
'zh-CN': { label: '中文', display: 'cn' },
|
||||
'zh-TW': { label: '中文(繁體)', display: 'tw' },
|
||||
'ca-ES': { label: 'Català', display: 'ca' },
|
||||
'cs-CZ': { label: 'Čeština', display: 'cs' },
|
||||
'da-DK': { label: 'Dansk', display: 'da' },
|
||||
'de-DE': { label: 'Deutsch', display: 'de' },
|
||||
'en-US': { label: 'English (US)', display: 'en' },
|
||||
'en-GB': { label: 'English (UK)', display: 'en-GB'},
|
||||
'es-MX': { label: 'Español', display: 'es' },
|
||||
'fa-IR': { label: 'فارسی', display: 'fa' },
|
||||
'fo-FO': { label: 'Føroyskt', display: 'fo' },
|
||||
'fr-FR': { label: 'Français', display: 'fr' },
|
||||
'el-GR': { label: 'Ελληνικά', display: 'el' },
|
||||
'he-IL': { label: 'עברית', display: 'he' },
|
||||
'hi-IN': { label: 'हिन्दी', display: 'hi' },
|
||||
'hu-HU': { label: 'Hungarian', display: 'hu' },
|
||||
'it-IT': { label: 'Italiano', display: 'it' },
|
||||
'id-ID': { label: 'Bahasa Indonesia', display: 'id' },
|
||||
'ja-JP': { label: '日本語', display: 'ja' },
|
||||
'ko-KR': { label: '한국어', display: 'ko' },
|
||||
'ms-MY': { label: 'Malay', display: 'ms' },
|
||||
'mn-MN': { label: 'Монгол', display: 'mn' },
|
||||
'nl-NL': { label: 'Nederlands', display: 'nl' },
|
||||
'nb-NO': { label: 'Norsk Bokmål', display: 'nb' },
|
||||
'pl-PL': { label: 'Polski', display: 'pl' },
|
||||
'pt-PT': { label: 'Português', display: 'pt' },
|
||||
'pt-BR': { label: 'Português do Brasil', display: 'pt-BR' },
|
||||
'ru-RU': { label: 'Русский', display: 'ru' },
|
||||
'ro-RO': { label: 'Română', display: 'ro' },
|
||||
'sk-SK': { label: 'Slovenčina', display: 'sk' },
|
||||
'sl-SI': { label: 'Slovenščina', display: 'sl' },
|
||||
'fi-FI': { label: 'Suomi', display: 'fi' },
|
||||
'sv-SE': { label: 'Svenska', display: 'sv' },
|
||||
'ta-IN': { label: 'தமிழ்', display: 'ta' },
|
||||
'tr-TR': { label: 'Türkçe', display: 'tr' },
|
||||
'uk-UA': { label: 'українська', display: 'uk' },
|
||||
};
|
||||
|
||||
export const rtlLocales = ['ar-SA', 'fa-IR'];
|
||||
|
||||
export const dateLocales = {
|
||||
'ar-SA': arSA,
|
||||
'en-US': enUS,
|
||||
'en-GB': enGB,
|
||||
'nl-NL': nl,
|
||||
'zh-CN': zhCN,
|
||||
'zh-TW': zhTW,
|
||||
'de-DE': de,
|
||||
'da-DK': da,
|
||||
'ru-RU': ru,
|
||||
'sv-SE': sv,
|
||||
'tr-TR': tr,
|
||||
'ja-JP': ja,
|
||||
'es-MX': es,
|
||||
'fr-FR': fr,
|
||||
'mn-MN': mn,
|
||||
'el-GR': el,
|
||||
'fo-FO': da,
|
||||
'pt-PT': pt,
|
||||
'pt-BR': ptBR,
|
||||
'ro-RO': ro,
|
||||
'nb-NO': nb,
|
||||
'id-ID': id,
|
||||
'uk-UA': uk,
|
||||
'fi-FI': fi,
|
||||
'cs-CZ': cs,
|
||||
'sk-SK': sk,
|
||||
'pl-PL': pl,
|
||||
'ta-In': ta,
|
||||
'hi-IN': hi,
|
||||
'he-IL': he,
|
||||
'it-IT': it,
|
||||
'fa-IR': faIR,
|
||||
'ms-MY': ms,
|
||||
'ca-ES': ca,
|
||||
'hu-HU': hu,
|
||||
'ko-KR': ko,
|
||||
'sl-SI': sl,
|
||||
'ar-SA': { label: 'العربية', dateLocale: arSA, dir: 'rtl' },
|
||||
'zh-CN': { label: '中文', dateLocale: zhCN },
|
||||
'zh-TW': { label: '中文(繁體)', dateLocale: zhTW },
|
||||
'ca-ES': { label: 'Català', dateLocale: ca },
|
||||
'cs-CZ': { label: 'Čeština', dateLocale: cs },
|
||||
'da-DK': { label: 'Dansk', dateLocale: da },
|
||||
'de-DE': { label: 'Deutsch', dateLocale: de },
|
||||
'en-US': { label: 'English (US)', dateLocale: enUS },
|
||||
'en-GB': { label: 'English (UK)', dateLocale: enGB },
|
||||
'es-MX': { label: 'Español', dateLocale: es },
|
||||
'fa-IR': { label: 'فارسی', dateLocale: faIR, dir: 'rtl' },
|
||||
'fo-FO': { label: 'Føroyskt' },
|
||||
'fr-FR': { label: 'Français', dateLocale: fr },
|
||||
'el-GR': { label: 'Ελληνικά', dateLocale: el },
|
||||
'he-IL': { label: 'עברית', dateLocale: he },
|
||||
'hi-IN': { label: 'हिन्दी', dateLocale: hi },
|
||||
'hu-HU': { label: 'Hungarian', dateLocale: hu },
|
||||
'it-IT': { label: 'Italiano', dateLocale: it },
|
||||
'id-ID': { label: 'Bahasa Indonesia', dateLocale: id },
|
||||
'ja-JP': { label: '日本語', dateLocale: ja },
|
||||
'ko-KR': { label: '한국어', dateLocale: ko },
|
||||
'ms-MY': { label: 'Malay', dateLocale: ms },
|
||||
'mn-MN': { label: 'Монгол', dateLocale: mn },
|
||||
'nl-NL': { label: 'Nederlands', dateLocale: nl },
|
||||
'nb-NO': { label: 'Norsk Bokmål', dateLocale: nb },
|
||||
'pl-PL': { label: 'Polski', dateLocale: pl },
|
||||
'pt-PT': { label: 'Português', dateLocale: pt },
|
||||
'pt-BR': { label: 'Português do Brasil', dateLocale: ptBR },
|
||||
'ru-RU': { label: 'Русский', dateLocale: ru },
|
||||
'ro-RO': { label: 'Română', dateLocale: ro },
|
||||
'sk-SK': { label: 'Slovenčina', dateLocale: sk },
|
||||
'sl-SI': { label: 'Slovenščina', dateLocale: sl },
|
||||
'fi-FI': { label: 'Suomi', dateLocale: fi },
|
||||
'sv-SE': { label: 'Svenska', dateLocale: sv },
|
||||
'ta-IN': { label: 'தமிழ்', dateLocale: ta },
|
||||
'tr-TR': { label: 'Türkçe', dateLocale: tr },
|
||||
'uk-UA': { label: 'українська', dateLocale: uk },
|
||||
};
|
||||
|
|
22
package.json
22
package.json
|
@ -71,7 +71,7 @@
|
|||
"date-fns": "^2.23.0",
|
||||
"date-fns-tz": "^1.1.4",
|
||||
"detect-browser": "^5.2.0",
|
||||
"dotenv": "^8.2.0",
|
||||
"dotenv": "^10.0.0",
|
||||
"formik": "^2.2.9",
|
||||
"immer": "^9.0.6",
|
||||
"ipaddr.js": "^2.0.1",
|
||||
|
@ -80,8 +80,8 @@
|
|||
"jose": "2.0.5",
|
||||
"maxmind": "^4.3.2",
|
||||
"moment-timezone": "^0.5.33",
|
||||
"next": "10.2.2",
|
||||
"prompts": "2.4.1",
|
||||
"next": "12.0.1",
|
||||
"prompts": "2.4.2",
|
||||
"prop-types": "^15.7.2",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
|
@ -110,31 +110,31 @@
|
|||
"cross-env": "^7.0.3",
|
||||
"del": "^6.0.0",
|
||||
"dotenv-cli": "^4.0.0",
|
||||
"eslint": "^7.31.0",
|
||||
"eslint-config-next": "^11.0.1",
|
||||
"eslint": "^8.1.0",
|
||||
"eslint-config-next": "^12.0.1",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-plugin-prettier": "^3.4.0",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"eslint-plugin-react": "^7.24.0",
|
||||
"eslint-plugin-react-hooks": "^4.2.0",
|
||||
"extract-react-intl-messages": "^4.1.1",
|
||||
"husky": "^4.3.8",
|
||||
"husky": "^7.0.4",
|
||||
"lint-staged": "^11.0.0",
|
||||
"loadtest": "5.1.2",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"postcss": "^8.2.15",
|
||||
"postcss-flexbugs-fixes": "^5.0.2",
|
||||
"postcss-import": "^13.0.0",
|
||||
"postcss-import": "^14.0.2",
|
||||
"postcss-preset-env": "^6.7.0",
|
||||
"postcss-rtlcss": "^3.3.2",
|
||||
"prettier": "^2.3.2",
|
||||
"prettier-eslint": "^12.0.0",
|
||||
"prettier-eslint": "^13.0.0",
|
||||
"prisma": "2.29.1",
|
||||
"rollup": "^2.48.0",
|
||||
"rollup-plugin-hashbang": "^2.2.2",
|
||||
"rollup-plugin-terser": "^7.0.2",
|
||||
"stylelint": "^13.13.1",
|
||||
"stylelint": "^14.0.1",
|
||||
"stylelint-config-css-modules": "^2.2.0",
|
||||
"stylelint-config-prettier": "^8.0.1",
|
||||
"stylelint-config-prettier": "^9.0.3",
|
||||
"stylelint-config-recommended": "^5.0.0",
|
||||
"tar": "^6.1.2"
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue