diff --git a/packages/ext/.prettierrc.yaml b/.prettierrc.yaml similarity index 100% rename from packages/ext/.prettierrc.yaml rename to .prettierrc.yaml diff --git a/packages/ext/package.json b/packages/ext/package.json index 6f2d165..a893fff 100644 --- a/packages/ext/package.json +++ b/packages/ext/package.json @@ -6,13 +6,14 @@ "author": "cnwangjie", "license": "MIT", "scripts": { - "dev": "cross-env NODE_ENV=development webpack --watch --config webpack.common.js" + "dev": "cross-env TAILWIND_MODE=watch NODE_ENV=development webpack --watch --config webpack.common.js" }, "dependencies": { "@emotion/react": "^11.5.0", "@emotion/styled": "^11.3.0", "@iconify/react": "^3.0.1", "@mui/material": "^5.0.4", + "dayjs": "^1.10.7", "lodash": "^4.17.21", "pouchdb-adapter-idb": "^7.2.2", "react": "^17.0.2", @@ -20,7 +21,7 @@ "react-router-dom": "^5.3.0", "rxdb": "^10.2.1", "rxjs": "^7.4.0", - "webextension-polyfill-ts": "^0.26.0" + "swr": "^1.0.1" }, "devDependencies": { "@types/history": "^4.7.9", @@ -28,6 +29,7 @@ "@types/react": "^17.0.31", "@types/react-dom": "^17.0.10", "@types/react-router-dom": "^5.3.1", + "@types/webextension-polyfill": "^0.8.1", "autoprefixer": "^10.3.7", "clean-webpack-plugin": "^4.0.0", "copy-webpack-plugin": "^9.0.1", diff --git a/packages/ext/src/app/layout/AppLayout.tsx b/packages/ext/src/app/layout/AppLayout.tsx index 0f8a99e..92dfc46 100644 --- a/packages/ext/src/app/layout/AppLayout.tsx +++ b/packages/ext/src/app/layout/AppLayout.tsx @@ -18,6 +18,7 @@ import { Typography, } from '@mui/material' import React, { FC, useState } from 'react' +import { Link } from 'react-router-dom' const drawerWidth = 240 @@ -112,7 +113,19 @@ const StyledListItemButton = styled(ListItemButton, { }), })) -const AppLayout: FC = ({ children }) => { +interface Tab { + key: string + icon: string + label: string + to: string +} + +interface AppLayoutProps { + tabs: Tab[] + activeTab: string +} + +const AppLayout: FC = ({ tabs, activeTab, children }) => { const [open, setOpen] = useState(false) // TODO: hide shadow scroll Y is 0 @@ -137,27 +150,27 @@ const AppLayout: FC = ({ children }) => { - - - - - - - - - - - - - + {tabs.map(tab => { + return ( + + + + + + + + + ) + })}
- - {children} - + {children}
) diff --git a/packages/ext/src/app/pages/Main/DetailList/ListGroup.tsx b/packages/ext/src/app/pages/Main/DetailList/ListGroup.tsx index d3743f1..a5d6a89 100644 --- a/packages/ext/src/app/pages/Main/DetailList/ListGroup.tsx +++ b/packages/ext/src/app/pages/Main/DetailList/ListGroup.tsx @@ -1,14 +1,46 @@ -import { Accordion, AccordionDetails, AccordionSummary } from '@mui/material' -import React from 'react' +import { + Accordion, + AccordionDetails, + AccordionSummary, + Chip, + IconButton, +} from '@mui/material' +import React, { FC } from 'react' +import __ from 'src/common/util/i18n' +import { useListTabs } from 'src/app/service' +import { formatTime } from 'src/common/util/formatDate' +import { Icon } from '@iconify/react' + +const ListGroup: FC<{ list: any }> = ({ list }) => { + const { data: tabs } = useListTabs(list.id) -const ListGroup = () => { return ( - + - 1 +
+ + {__('ui_created')} {formatTime(list.createdAt)} +
+
e.stopPropagation()} + > + + + + + + + + + +
+
- 2 + {tabs?.map((tab, index) => { + return
{tab.url}
+ })}
) diff --git a/packages/ext/src/app/pages/Main/DetailList/index.tsx b/packages/ext/src/app/pages/Main/DetailList/index.tsx index fb828e6..7574d93 100644 --- a/packages/ext/src/app/pages/Main/DetailList/index.tsx +++ b/packages/ext/src/app/pages/Main/DetailList/index.tsx @@ -1,16 +1,16 @@ import React from 'react' import ListGroup from './ListGroup' +import { useLists } from '../../../service' const DetailList = () => { - const [lists, setLists] = React.useState([ - 1,2,3,4 - ]) + const { data } = useLists() return (
{ - lists.map(list => { - return + data?.result.map(list => { + console.log(list) + return }) }
diff --git a/packages/ext/src/app/pages/Main/index.tsx b/packages/ext/src/app/pages/Main/index.tsx index 091309d..130f6af 100644 --- a/packages/ext/src/app/pages/Main/index.tsx +++ b/packages/ext/src/app/pages/Main/index.tsx @@ -1,12 +1,57 @@ -import React from 'react' -import { Route, Switch } from 'react-router-dom' +import React, { useMemo } from 'react' +import { matchPath, Route, Switch, useRouteMatch } from 'react-router-dom' import AppLayout from '../../layout/AppLayout' import DetailList from './DetailList' +import { history } from '../../App' + +const routes = [ + { + key: 'Tab lists', + label: 'Tab lists', + icon: 'mdi:view-list', + path: '/app/list', + exact: true, + }, + { + key: 'Pinned', + label: 'Pinned', + icon: 'mdi:pin-outline', + path: '/app/list/pinned', + }, +] const Main = () => { + const tabs = useMemo(() => { + return routes.map(({ key, label, icon, path }) => { + return { + key, + label, + icon, + to: path, + } + }) + }, []) + + useRouteMatch() + + const activeTab = useMemo(() => { + return ( + routes.find(({ path, exact }) => { + const match = matchPath(history.location.pathname, { + path, + exact, + }) + return match + }) || routes[0] + ) + }, [history.location.pathname]) + return ( - + + + + diff --git a/packages/ext/src/app/service/index.ts b/packages/ext/src/app/service/index.ts new file mode 100644 index 0000000..e310e83 --- /dev/null +++ b/packages/ext/src/app/service/index.ts @@ -0,0 +1,23 @@ +import storage from 'src/common/storage' +import useSWR from 'swr' + +type ThenArg = T extends PromiseLike ? U : never + +const createSWR = < + F extends (...args: any[]) => Promise, + T = ThenArg> +>( + prefix: string, + fn: F, + requireArgs = false, +) => (...args: any[]) => { + const key = requireArgs && args.every(i => !i) ? null : [prefix, ...args] + + return useSWR(key, (_, ...args: any) => { + return fn(...args) + }) +} + +export const useLists = createSWR('lists', storage.lists.listList) + +export const useListTabs = createSWR('listTab', storage.tabs.getSortedTabsByList, true) diff --git a/packages/ext/src/background/autoReload.ts b/packages/ext/src/background/autoReload.ts index 2181c11..4ab6bfc 100644 --- a/packages/ext/src/background/autoReload.ts +++ b/packages/ext/src/background/autoReload.ts @@ -1,4 +1,4 @@ -import { browser } from 'webextension-polyfill-ts' +import browser from 'webextension-polyfill' const filesInDirectory = (dir: any) => new Promise(resolve => { diff --git a/packages/ext/src/background/browserAction.ts b/packages/ext/src/background/browserAction.ts index d926995..655e0b1 100644 --- a/packages/ext/src/background/browserAction.ts +++ b/packages/ext/src/background/browserAction.ts @@ -2,7 +2,7 @@ import { noop } from 'lodash' import { BrowserAction, NewTabs } from 'src/common/constants' import { browserActionConfigItems, optionsList } from 'src/common/options/list' import { tabsManager } from 'src/common/tabsManager' -import { browser } from 'webextension-polyfill-ts' +import browser from 'webextension-polyfill' const actions = { [BrowserAction.StoreSelected]: tabsManager.storeSelectedTabs, diff --git a/packages/ext/src/background/contextMenus.ts b/packages/ext/src/background/contextMenus.ts index bbb5b74..d66dd66 100644 --- a/packages/ext/src/background/contextMenus.ts +++ b/packages/ext/src/background/contextMenus.ts @@ -4,7 +4,7 @@ import { Options } from 'src/common/options/types' import storage from 'src/common/storage' import { tabsManager } from 'src/common/tabsManager' import { __ } from 'src/common/util/i18n' -import { browser, Menus } from 'webextension-polyfill-ts' +import browser, { Menus } from 'webextension-polyfill' const SHOW_TAB_LIST = 'SHOW_TAB_LIST' const STORE_SELECTED_TABS = 'STORE_SELECTED_TABS' diff --git a/packages/ext/src/background/index.ts b/packages/ext/src/background/index.ts index 64ebd6a..6d5b2ea 100644 --- a/packages/ext/src/background/index.ts +++ b/packages/ext/src/background/index.ts @@ -1,6 +1,6 @@ import storage from 'src/common/storage' import { tabsManager } from 'src/common/tabsManager' -import { browser } from 'webextension-polyfill-ts' +import browser from 'webextension-polyfill' import init from './init' if (DEBUG) { diff --git a/packages/ext/src/background/init.ts b/packages/ext/src/background/init.ts index a37d014..2d1e006 100644 --- a/packages/ext/src/background/init.ts +++ b/packages/ext/src/background/init.ts @@ -1,8 +1,9 @@ import { debounce } from 'lodash' import { getOptions } from 'src/common/options' import storage from 'src/common/storage' -import { registerIpcHandlerDeeply, registerIpcListener } from 'src/common/util/ipc' -import { browser, Tabs } from 'webextension-polyfill-ts' +import { composeListeners } from 'src/common/util/composeListener' +import { createIpcListener, registerIpcHandlerDeeply } from 'src/common/util/ipc' +import browser, { Tabs } from 'webextension-polyfill' import { updateBrowserAction } from './browserAction' import commandHandler from './commandHandler' import { dynamicDisableMenu, setupContextMenus } from './contextMenus' @@ -14,9 +15,17 @@ const tabsChangedHandler = (activeInfo: Tabs.OnActivatedActiveInfoType) => { dynamicDisableMenu() } +const registerRuntimeMessageListener = async () => { + const ipcListener = await createIpcListener() + const listener = composeListeners( + ipcListener, + messageHandler, + ) + await browser.runtime.onMessage.addListener(listener) +} + const init = async () => { - registerIpcHandlerDeeply(storage) - registerIpcListener() + registerIpcHandlerDeeply({ storage }) const opts = window.opts = await getOptions() console.log(opts) @@ -25,7 +34,7 @@ const init = async () => { await Promise.all([ browser.commands.onCommand.addListener(commandHandler), browser.runtime.onMessageExternal.addListener(commandHandler), - browser.runtime.onMessage.addListener(messageHandler), + registerRuntimeMessageListener(), browser.runtime.onUpdateAvailable.addListener(detail => { window.update = detail.version }), browser.contextMenus.onClicked.addListener(info => window.contextMenusClickedHandler(info)), browser.tabs.onActivated.addListener(debounce(tabsChangedHandler, 200)), diff --git a/packages/ext/src/common/storage/index.ts b/packages/ext/src/common/storage/index.ts index 3266746..68d878e 100644 --- a/packages/ext/src/common/storage/index.ts +++ b/packages/ext/src/common/storage/index.ts @@ -5,9 +5,11 @@ import { tabsStorage } from './tabs' export const lists = listStorage export const tabs = tabsStorage -export const storage = wrapBackgroundCommunicationDeeply({ - lists, - tabs, +export const { storage } = wrapBackgroundCommunicationDeeply({ + storage: { + lists, + tabs, + }, }) export default storage diff --git a/packages/ext/src/common/storage/lists.ts b/packages/ext/src/common/storage/lists.ts index 10ba5c6..1fc73d2 100644 --- a/packages/ext/src/common/storage/lists.ts +++ b/packages/ext/src/common/storage/lists.ts @@ -76,7 +76,7 @@ const getLatestList = async () => { const listList = async (opt?: PaginateOpt) => { const db = await getDB() - return paginate(db.lists)(opt) + return paginate(db.lists)(opt) } export const listStorage = { diff --git a/packages/ext/src/common/storage/tabs.ts b/packages/ext/src/common/storage/tabs.ts index 7b7716e..7122752 100644 --- a/packages/ext/src/common/storage/tabs.ts +++ b/packages/ext/src/common/storage/tabs.ts @@ -1,6 +1,6 @@ import { sortBy } from "lodash"; import { RxDocument } from "rxdb"; -import type * as Browser from "webextension-polyfill-ts"; +import type { Tabs } from "webextension-polyfill"; import { genId } from "../util"; import { getDB } from "./db"; @@ -30,7 +30,7 @@ const initTabs = (tabs: any[], listId: string): Tab[] => { }) } -const createTabs = async (tabs: Browser.Tabs.Tab[], listId: string) => { +const createTabs = async (tabs: Tabs.Tab[], listId: string) => { const db = await getDB() const tabsDocs = initTabs(tabs, listId) const result = await db.tabs.bulkInsert(tabsDocs) @@ -39,7 +39,7 @@ const createTabs = async (tabs: Browser.Tabs.Tab[], listId: string) => { } } -const getTabsByList = async (listId: string) => { +const getTabsByList = async (listId: string): Promise => { const db = await getDB() const tabs = await db.tabs.find({ selector: { listId } }).exec() return tabs diff --git a/packages/ext/src/common/tabsManager/index.ts b/packages/ext/src/common/tabsManager/index.ts index 077aa81..ffdb2ec 100644 --- a/packages/ext/src/common/tabsManager/index.ts +++ b/packages/ext/src/common/tabsManager/index.ts @@ -1,11 +1,10 @@ -import { browser } from "webextension-polyfill-ts"; -import type * as Browser from "webextension-polyfill-ts"; +import browser, { Tabs } from "webextension-polyfill"; import { IllegalUrlPrefixes } from "../constants"; import { getOptions } from "../options"; import storage from "../storage"; import { Tab } from "../storage/tabs"; -type BrowserTab = Browser.Tabs.Tab; +type BrowserTab = Tabs.Tab; type BrowserTabs = BrowserTab[] export const getAllInWindow = (windowId: number) => browser.tabs.query({ windowId }) @@ -126,7 +125,7 @@ const storeSelectedTabs = async (listId?: string) => { ]) if (tabs.length === allTabs?.length) { - // TODO: open tab lists + openTabList() } await storeTabs(tabs, listId) @@ -137,7 +136,7 @@ const storeAllTabs = async (listId?: string) => { if (!tabs) return const opts = await getOptions() if (opts.openTabListNoTab) { - // TODO: open tab lists + openTabList() } return storeTabs(tabs, listId) } @@ -188,7 +187,26 @@ const restoreLatestList = async () => { } const openTabList = async () => { - throw new Error('not implemented') + const window = await browser.runtime.getBackgroundPage() + const appTabIds = window.appTabIds = window.appTabIds || {} + const currentWindow = await browser.windows.getCurrent() + const windowId = currentWindow.id + const tabListsUrl = browser.runtime.getURL('index.html#/app/') + if (!windowId) return + const existAppTabId = appTabIds[windowId] + if (existAppTabId) { + const tabs = await getAllInWindow(windowId) + const tab = tabs.find(tab => tab.id === existAppTabId) + if (tab) { + if (tab.url?.startsWith(tabListsUrl)) { + return browser.tabs.update(tab.id, { active: true }) + } + delete window.appTabIds[windowId] + } + } + const createdTab = await browser.tabs.create({ url: tabListsUrl }) + if (!createdTab.id) return + window.appTabIds[windowId] = createdTab.id } export const tabsManager = { diff --git a/packages/ext/src/common/util/composeListener.ts b/packages/ext/src/common/util/composeListener.ts new file mode 100644 index 0000000..4c7c39f --- /dev/null +++ b/packages/ext/src/common/util/composeListener.ts @@ -0,0 +1,12 @@ +import type browser from 'webextension-polyfill' + +export type RuntimeOnMessageListener = Parameters[0] + +export const composeListeners = (...listeners: (RuntimeOnMessageListener | undefined)[]): RuntimeOnMessageListener => { + return (message, sender) => { + for (const listener of listeners) { + const result = listener?.(message, sender) + if (result) return result + } + } +} diff --git a/packages/ext/src/common/util/formatDate.ts b/packages/ext/src/common/util/formatDate.ts new file mode 100644 index 0000000..1a8ac05 --- /dev/null +++ b/packages/ext/src/common/util/formatDate.ts @@ -0,0 +1,14 @@ +import dayjs from 'dayjs' +import localizedFormat from 'dayjs/plugin/localizedFormat' +import relativeTime from 'dayjs/plugin/relativeTime' + +dayjs.extend(localizedFormat) +dayjs.extend(relativeTime) + +export const formatTime = (time: number) => { + const date = dayjs(time) + if (date.add(1, 'day').isBefore(dayjs())) { + return date.format('llll') + } + return date.fromNow() +} diff --git a/packages/ext/src/common/util/i18n.ts b/packages/ext/src/common/util/i18n.ts index e7a8ca5..cda1f09 100644 --- a/packages/ext/src/common/util/i18n.ts +++ b/packages/ext/src/common/util/i18n.ts @@ -1,3 +1,5 @@ -import { browser } from 'webextension-polyfill-ts' +import browser from 'webextension-polyfill' export const __ = (key: string) => browser.i18n.getMessage(key) + +export default __ diff --git a/packages/ext/src/common/util/index.ts b/packages/ext/src/common/util/index.ts index 3040386..c517dba 100644 --- a/packages/ext/src/common/util/index.ts +++ b/packages/ext/src/common/util/index.ts @@ -1,4 +1,4 @@ -import { browser } from 'webextension-polyfill-ts' +import browser from 'webextension-polyfill' export const genId = () => { const timestamp = ((new Date().getTime() / 1000) | 0).toString(16) diff --git a/packages/ext/src/common/util/ipc.ts b/packages/ext/src/common/util/ipc.ts index 4b54fd9..12eb775 100644 --- a/packages/ext/src/common/util/ipc.ts +++ b/packages/ext/src/common/util/ipc.ts @@ -1,8 +1,9 @@ import { isFunction, mapValues, once } from 'lodash' -import { browser } from 'webextension-polyfill-ts' +import browser from 'webextension-polyfill' import { isBackground } from '.' +import { RuntimeOnMessageListener } from './composeListener' -const handlers: Record = {} +const handlers: Record Promise> = {} export const registerIpcHandler = (fn: any, name: string) => { handlers[name] = fn @@ -10,32 +11,38 @@ export const registerIpcHandler = (fn: any, name: string) => { return fn } -export const registerIpcListener = once(async () => { - if (!(await isBackground())) return +export const createIpcListener = once( + async (): Promise => { + if (!(await isBackground())) return - browser.runtime.onMessage.addListener(message => { - if (!message.ipcCall) return - console.log('<- received ipc call', message.ipcCall) - const { name, args } = message.ipcCall + return message => { + if (!message.ipcCall) return + console.log('<- received ipc call', message.ipcCall) + const { name, args } = message.ipcCall - const fn = handlers[name] - if (!fn) return + const fn = handlers[name] + if (!fn) return - return fn(...args).catch((error: any) => { - console.error('-> perform ipc with error', error) - if (error instanceof Error) { - const { message, stack } = error - return { error: { message, stack } } - } - return null - }) - }) - console.log('ipc listener registered') -}) + return fn(...args) + .then(result => { + console.log('-> result', result) + return Promise.resolve(result) + }) + .catch((error: any) => { + console.error('-> perform ipc with error', error) + if (error instanceof Error) { + const { message, stack } = error + return { error: { message, stack } } + } + return null + }) + } + }, +) export const wrapBackgroundCommunication = any>( fn: T, - name: string + name: string, ): T => { const wrapped = async (...args: any[]) => { if (await isBackground()) { @@ -44,7 +51,7 @@ export const wrapBackgroundCommunication = any>( const ipcCall = { name, args } const start = Date.now() - console.log('-> send ipc call', ipcCall) + console.log('-> send ipc call', 'name:', name, 'args:', ...args) const result = await browser.runtime.sendMessage({ ipcCall, @@ -60,19 +67,29 @@ export const wrapBackgroundCommunication = any>( return result } - return wrapped as any as T + return wrapped as T } -export const wrapBackgroundCommunicationDeeply = >(objects: T): T => { - return mapValues(objects, (fn, name) => { - if (isFunction(fn)) return wrapBackgroundCommunication(fn, name) - return wrapBackgroundCommunicationDeeply(fn) - }) as any as T +export const wrapBackgroundCommunicationDeeply = < + T extends Record +>( + objects: T, + path = '', +): T => { + return (mapValues(objects, (fn, name) => { + const fullName = path ? path + '.' + name : name + if (isFunction(fn)) return wrapBackgroundCommunication(fn, fullName) + return wrapBackgroundCommunicationDeeply(fn, fullName) + }) as any) as T } -export const registerIpcHandlerDeeply = >(objects: T) => { +export const registerIpcHandlerDeeply = >( + objects: T, + path = '', +) => { Object.entries(objects).map(([name, fn]) => { - if (isFunction(fn)) return registerIpcHandler(fn, name) - return registerIpcHandlerDeeply(fn) + const fullName = path ? path + '.' + name : name + if (isFunction(fn)) return registerIpcHandler(fn, fullName) + return registerIpcHandlerDeeply(fn, fullName) }) } diff --git a/packages/ext/src/common/util/paginate.ts b/packages/ext/src/common/util/paginate.ts index 3ee563f..b9c73cc 100644 --- a/packages/ext/src/common/util/paginate.ts +++ b/packages/ext/src/common/util/paginate.ts @@ -8,13 +8,19 @@ export interface PaginateOpt { query?: any } +export interface PaginationResult { + result: T[] + hasNext: boolean + next?: string +} + export const paginate = (col: RxCollection) => async ({ after, before, limit = 10, sort = {}, query = {}, -}: PaginateOpt = {}) => { +}: PaginateOpt = {}): Promise> => { const lastId = before || after const last: any = lastId && (await col.findOne({ selector: { id: lastId } }).exec()) diff --git a/packages/ext/src/global.d.ts b/packages/ext/src/global.d.ts index f15c4c6..6447e10 100644 --- a/packages/ext/src/global.d.ts +++ b/packages/ext/src/global.d.ts @@ -1,4 +1,4 @@ -import type Browser, { browser, Menus } from "webextension-polyfill-ts" +import type Browser, { Menus } from "webextension-polyfill" import type { Options } from "./common/options/types" import type { tabsManager } from "./common/tabsManager" import type storage from './common/storage' @@ -9,6 +9,7 @@ declare global { const DEBUG: boolean const PRODUCTION: boolean + // background page store interface Window { currentBrowserAction: string coverBrowserAction: (activeInfo: Browser.Tabs.OnActivatedActiveInfoType) => any @@ -18,6 +19,7 @@ declare global { update?: string tabsManager?: typeof tabsManager storage?: typeof storage - browser?: typeof browser + browser?: typeof Browser + appTabIds?: Record } } diff --git a/packages/ext/tsconfig.json b/packages/ext/tsconfig.json index ecf2472..54ff2e6 100644 --- a/packages/ext/tsconfig.json +++ b/packages/ext/tsconfig.json @@ -17,6 +17,6 @@ "jsx": "react" }, "include": [ - "./src/**/*.ts" + "src" ] } diff --git a/yarn.lock b/yarn.lock index 3d17141..420911a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2402,6 +2402,11 @@ resolved "https://registry.yarnpkg.com/@types/spark-md5/-/spark-md5-3.0.2.tgz#da2e8a778a20335fc4f40b6471c4b0d86b70da55" integrity sha512-82E/lVRaqelV9qmRzzJ1PKTpyrpnT7mwdneKNJB9hUtypZDMggloDfFUCIqRRx3lYRxteCwXSq9c+W71Vf0QnQ== +"@types/webextension-polyfill@^0.8.1": + version "0.8.1" + resolved "https://registry.yarnpkg.com/@types/webextension-polyfill/-/webextension-polyfill-0.8.1.tgz#9f29dbc894128cb8fdeea3d6b083696a418c867a" + integrity sha512-FH1EwaQLzET/Bdy05yIcgMD2nlXchA1vnfC+QvQYMNW0RcTIDrNaVOOqmOY1nGRf0NaHZQmvfMy6cJV4nY7j2w== + "@vue/component-compiler-utils@^3.1.0": version "3.2.2" resolved "https://registry.yarnpkg.com/@vue/component-compiler-utils/-/component-compiler-utils-3.2.2.tgz#2f7ed5feed82ff7f0284acc11d525ee7eff22460" @@ -4590,6 +4595,11 @@ dateformat@^3.0.0: resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q== +dayjs@^1.10.7: + version "1.10.7" + resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.10.7.tgz#2cf5f91add28116748440866a0a1d26f3a6ce468" + integrity sha512-P6twpd70BcPK34K26uJ1KT3wlhpuOAPoMwJzpsIWUxHZ7wpmbdZL/hQqBDfz7hGurYSa5PhzdhDHtt319hL3ig== + de-indent@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/de-indent/-/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d" @@ -4811,6 +4821,11 @@ deprecation@^2.0.0, deprecation@^2.3.1: resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919" integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ== +dequal@2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.2.tgz#85ca22025e3a87e65ef75a7a437b35284a7e319d" + integrity sha512-q9K8BlJVxK7hQYqa6XISGmBZbtQQWVXSrRrWreHC94rMt1QL/Impruc+7p2CYSYuVIUr+YCt6hjrs1kkdJRTug== + des.js@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.1.tgz#5382142e1bdc53f85d86d53e5f4aa7deb91e0843" @@ -11668,6 +11683,13 @@ supports-color@^8.0.0: dependencies: has-flag "^4.0.0" +swr@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/swr/-/swr-1.0.1.tgz#15f62846b87ee000e52fa07812bb65eb62d79483" + integrity sha512-EPQAxSjoD4IaM49rpRHK0q+/NzcwoT8c0/Ylu/u3/6mFj/CWnQVjNJ0MV2Iuw/U+EJSd2TX5czdAwKPYZIG0YA== + dependencies: + dequal "2.0.2" + table@^5.2.3: version "5.4.6" resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" @@ -12539,23 +12561,11 @@ wcwidth@^1.0.0: dependencies: defaults "^1.0.3" -webextension-polyfill-ts@^0.26.0: - version "0.26.0" - resolved "https://registry.yarnpkg.com/webextension-polyfill-ts/-/webextension-polyfill-ts-0.26.0.tgz#80b7063ddaf99abaa1ca73aad0cec09f306612d3" - integrity sha512-XEFL+aYVEsm/d4RajVwP75g56c/w2aSHnPwgtUv8/nCzbLNSzRQIix6aj1xqFkA5yr7OIDkk3OD/QTnPp8ThYA== - dependencies: - webextension-polyfill "^0.8.0" - webextension-polyfill@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/webextension-polyfill/-/webextension-polyfill-0.3.1.tgz#fab2aed917a713a5d8221e41febad81c5d0b080f" integrity sha512-ISB42vlgMyM7xE1u6pREeCqmmXjLsYu/nqAR8Dl/gIAnylb+KpRpvKbVkUYNFePhhXn0Obkkc3jasOII9ztUtg== -webextension-polyfill@^0.8.0: - version "0.8.0" - resolved "https://registry.yarnpkg.com/webextension-polyfill/-/webextension-polyfill-0.8.0.tgz#f80e9f4b7f81820c420abd6ffbebfa838c60e041" - integrity sha512-a19+DzlT6Kp9/UI+mF9XQopeZ+n2ussjhxHJ4/pmIGge9ijCDz7Gn93mNnjpZAk95T4Tae8iHZ6sSf869txqiQ== - webidl-conversions@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"